// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . // ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· // ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ // ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ // ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ // Magicbane Emulator Project © 2013 - 2022 // www.magicbane.com package engine.net.client; import engine.Enum.*; import engine.InterestManagement.WorldGrid; import engine.ai.MobileFSM.STATE; import engine.exception.MsgSendException; import engine.gameManager.*; import engine.job.JobContainer; import engine.job.JobScheduler; import engine.jobs.RefreshGroupJob; import engine.jobs.StuckJob; import engine.math.Vector3fImmutable; import engine.net.Dispatch; import engine.net.DispatchMessage; import engine.net.NetMsgHandler; import engine.net.client.handlers.AbstractClientMsgHandler; import engine.net.client.msg.*; import engine.net.client.msg.chat.AbstractChatMsg; import engine.net.client.msg.commands.ClientAdminCommandMsg; import engine.objects.*; import engine.powers.effectmodifiers.AbstractEffectModifier; import engine.server.MBServerStatics; import engine.server.world.WorldServer; import engine.session.Session; import engine.util.StringUtils; import org.pmw.tinylog.Logger; import java.sql.SQLException; import java.util.ArrayList; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ThreadLocalRandom; import static engine.math.FastMath.sqr; /** * @author: * @summary: This class is the mainline router for application protocol * messages received by the client. */ public class ClientMessagePump implements NetMsgHandler { // Instance variable declaration private final WorldServer server; public ClientMessagePump(WorldServer server) { super(); this.server = server; } /* * Incoming client protocol message are processed here */ @Override public boolean handleClientMsg(ClientNetMsg msg) { if (msg == null) { Logger.error("handleClientMsg", "Recieved null msg. Returning."); return false; } ClientConnection origin; Protocol protocolMsg = Protocol.NONE; Session s; try { // Try registered opcodes first as we take a hatchet to this GodObject AbstractClientMsgHandler msgHandler = msg.getProtocolMsg().handler; if (msgHandler != null) return msgHandler.handleNetMsg(msg); // Any remaining opcodes fall through and are routed // through this ungodly switch of doom. origin = (ClientConnection) msg.getOrigin(); s = SessionManager.getSession(origin); protocolMsg = msg.getProtocolMsg(); switch (protocolMsg) { case SETSELECTEDOBECT: ClientMessagePump.targetObject((TargetObjectMsg) msg, origin); break; /* * Chat */ // Simplify by fall through. Route in ChatManager case CHATSAY: case CHATSHOUT: case CHATTELL: case CHATGUILD: case CHATGROUP: case CHATPVP: case CHATIC: case CHATCITY: case CHATINFO: case SYSTEMBROADCASTCHANNEL: case CHATCSR: case SYSTEMCHANNEL: case GLOBALCHANNELMESSAGE: case LEADERCHANNELMESSAGE: ChatManager.handleChatMsg(s, (AbstractChatMsg) msg); break; case UPDATESTATE: UpdateStateMsg rwss = (UpdateStateMsg) msg; runWalkSitStand(rwss, origin); break; case ACTIVATECHARTER: UseCharterMsg ucm = (UseCharterMsg) msg; ucm.setUnknown02(1); ucm.configure(); Dispatch dispatch = Dispatch.borrow(origin.getPlayerCharacter(), ucm); DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY); break; case CHECKUNIQUEGUILD: break; case CREATEPETITION: break; case CANCELGUILDCREATION: break; case LEAVEREQUEST: origin.disconnect(); break; case POWER: PowersManager.usePower((PerformActionMsg) msg, origin, false); break; case REQUESTMELEEATTACK: CombatManager.setAttackTarget((AttackCmdMsg) msg, origin); break; case READYTOENTER: break; case OPENVAULT: break; case WHOREQUEST: WhoRequest((WhoRequestMsg) msg, origin); break; case CLIENTADMINCOMMAND: ChatManager.HandleClientAdminCmd((ClientAdminCommandMsg) msg, origin); break; case SOCIALCHANNEL: social((SocialMsg) msg, origin); break; case COMBATMODE: CombatManager.toggleCombat((ToggleCombatMsg) msg, origin); break; case ARCCOMBATMODEATTACKING: CombatManager.toggleCombat((SetCombatModeMsg) msg, origin); break; case MODIFYGUILDSTATE: ToggleLfgRecruitingMsg tlrm = (ToggleLfgRecruitingMsg) msg; toggleLfgRecruiting(tlrm, origin); break; case TOGGLESITSTAND: ToggleSitStandMsg tssm = (ToggleSitStandMsg) msg; toggleSitStand(tssm, origin); break; case GUILDTREESTATUS: GuildTreeStatusMsg((GuildTreeStatusMsg) msg, origin); break; case CUSTOMERPETITION: Logger.info("CCR Petition received: " + msg.toString()); // TODO need to send something back to client // TODO what to do with petition? break; case IGNORE: ((IgnoreMsg) msg).handleRequest(origin); break; case UNEQUIP: TransferItemFromEquipToInventory((TransferItemFromEquipToInventoryMsg) msg, origin); break; case EQUIP: TransferItemFromInventoryToEquip((TransferItemFromInventoryToEquipMsg) msg, origin); break; case DELETEOBJECT: DeleteItem((DeleteItemMsg) msg, origin); break; case VIEWRESOURCES: ViewResourcesMessage((ViewResourcesMessage) msg, origin); break; case RAISEATTR: modifyStat((ModifyStatMsg) msg, origin); break; case COSTTOOPENBANK: ackBankWindowOpened((AckBankWindowOpenedMsg) msg, origin); break; case RESETAFTERDEATH: respawn((RespawnMsg) msg, origin); break; case REQUESTCONTENTS: lootWindowRequest((LootWindowRequestMsg) msg, origin); break; case MOVEOBJECTTOCONTAINER: loot((LootMsg) msg, origin); break; case SHOWCOMBATINFO: show((ShowMsg) msg, origin); break; case TRANSFERITEMTOBANK: transferItemFromInventoryToBank((TransferItemFromInventoryToBankMsg) msg, origin); break; case TRANSFERITEMFROMBANK: transferItemFromBankToInventory((TransferItemFromBankToInventoryMsg) msg, origin); break; case TRANSFERITEMFROMVAULTTOINVENTORY: transferItemFromVaultToInventory((TransferItemFromVaultToInventoryMsg) msg, origin); break; case ITEMTOVAULT: transferItemFromInventoryToVault((TransferItemFromInventoryToVaultMsg) msg, origin); break; case TRANSFERGOLDFROMVAULTTOINVENTORY: transferGoldFromVaultToInventory((TransferGoldFromVaultToInventoryMsg) msg, origin); break; case GOLDTOVAULT: transferGoldFromInventoryToVault((TransferGoldFromInventoryToVaultMsg) msg, origin); break; case REQUESTTOTRADE: TradeManager.tradeRequest((TradeRequestMsg) msg, origin); break; case REQUESTTRADEOK: TradeManager.acceptTradeRequest((AcceptTradeRequestMsg) msg, origin); break; case REQUESTTRADECANCEL: TradeManager.rejectTradeRequest((RejectTradeRequestMsg) msg, origin); break; case TRADEADDOBJECT: TradeManager.addItemToTradeWindow((AddItemToTradeWindowMsg) msg, origin); break; case TRADEADDGOLD: TradeManager.addGoldToTradeWindow((AddGoldToTradeWindowMsg) msg, origin); break; case TRADECONFIRM: TradeManager.commitToTrade((CommitToTradeMsg) msg, origin); break; case TRADEUNCONFIRM: TradeManager.uncommitToTrade((UncommitToTradeMsg) msg, origin); break; case TRADECLOSE: TradeManager.closeTradeWindow((CloseTradeWindowMsg) msg, origin); break; case ARCREQUESTTRADEBUSY: TradeManager.invalidTradeRequest((InvalidTradeRequestMsg) msg); break; case VENDORDIALOG: VendorDialogMsg.replyDialog((VendorDialogMsg) msg, origin); break; case SHOPLIST: openBuyFromNPCWindow((BuyFromNPCWindowMsg) msg, origin); break; case BUYFROMNPC: buyFromNPC((BuyFromNPCMsg) msg, origin); break; case SHOPINFO: openSellToNPCWindow((SellToNPCWindowMsg) msg, origin); break; case SELLOBJECT: sellToNPC((SellToNPCMsg) msg, origin); break; case REPAIROBJECT: Repair((RepairMsg) msg, origin); break; case TRAINERLIST: WorldServer.trainerInfo((TrainerInfoMsg) msg, origin); break; case ARCUNTRAINLIST: WorldServer.refinerScreen((RefinerScreenMsg) msg, origin); break; case TRAINSKILL: TrainMsg.train((TrainMsg) msg, origin); break; case ARCUNTRAINABILITY: RefineMsg.refine((RefineMsg) msg, origin); break; case POWERTARGNAME: PowersManager.summon((SendSummonsRequestMsg) msg, origin); break; case ARCSUMMON: PowersManager.recvSummon((RecvSummonsRequestMsg) msg, origin); break; case ARCTRACKINGLIST: PowersManager.trackWindow((TrackWindowMsg) msg, origin); break; case STUCK: stuck(origin); break; case RANDOM: ClientMessagePump.randomRoll((RandomMsg) msg, origin); break; case ARCPETATTACK: petAttack((PetAttackMsg) msg, origin); break; case ARCPETCMD: petCmd((PetCmdMsg) msg, origin); break; case MANAGENPC: ManageNPCCmd((ManageNPCMsg) msg, origin); break; case ARCPROMPTRECALL: HandlePromptRecall((PromptRecallMsg) msg, origin); break; case CHANNELMUTE: break; case KEEPALIVESERVERCLIENT: break; case UNKNOWN: break; case CONFIRMPROMOTE: break; default: String ocHex = StringUtils.toHexString(protocolMsg.opcode); Logger.error("Cannot handle Opcode: " + ocHex + " " + protocolMsg.name()); return false; } } catch (MsgSendException | SQLException e) { Logger.error("handler for " + protocolMsg + " failed: " + e); return false; } return true; } // *** Refactor need to figure this out. // Commented out for some reson or another. //TODO what is this used for? private void ManageNPCCmd(ManageNPCMsg msg, ClientConnection origin) { } private static void WhoRequest(WhoRequestMsg msg, ClientConnection origin) { // Handle /who request PlayerCharacter pc = origin.getPlayerCharacter(); if (pc == null) return; if (pc.getTimeStamp("WHO") > System.currentTimeMillis()) { ErrorPopupMsg.sendErrorMsg(pc, "Who too fast! Please wait 3 seconds."); return; } WhoResponseMsg.HandleResponse(msg.getSet(), msg.getFilterType(), msg.getFilter(), origin); pc.getTimestamps().put("WHO", System.currentTimeMillis() + 3000); } private static void runWalkSitStand(UpdateStateMsg msg, ClientConnection origin) throws MsgSendException { PlayerCharacter pc = SessionManager.getPlayerCharacter(origin); if (pc == null) return; pc.update(); if (msg.getSpeed() == 2) pc.setWalkMode(false); else pc.setWalkMode(true); DispatchMessage.dispatchMsgToInterestArea(pc, msg, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, true, false); } private static void toggleLfgRecruiting(ToggleLfgRecruitingMsg msg, ClientConnection origin) throws MsgSendException { PlayerCharacter pc = SessionManager.getPlayerCharacter(origin); if (pc == null) return; int num = msg.toggleLfgRecruiting(); if (num == 1) pc.toggleLFGroup(); else if (num == 2) pc.toggleLFGuild(); else if (num == 3) pc.toggleRecruiting(); UpdateStateMsg rwss = new UpdateStateMsg(); rwss.setPlayer(pc); DispatchMessage.dispatchMsgToInterestArea(pc, rwss, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, true, false); } private static void toggleSitStand(ToggleSitStandMsg msg, ClientConnection origin) throws MsgSendException { PlayerCharacter pc = SessionManager.getPlayerCharacter(origin); if (pc == null) return; pc.update(); pc.setSit(msg.toggleSitStand()); // cancel effects that break on sit if (pc.isSit()) { pc.setCombat(false); pc.cancelOnSit(); } UpdateStateMsg rwss = new UpdateStateMsg(); if (pc.isSit()) { pc.setCombat(false); rwss.setAware(1); } rwss.setPlayer(pc); DispatchMessage.dispatchMsgToInterestArea(pc, rwss, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, true, false); } private static void targetObject(TargetObjectMsg msg, ClientConnection origin) { PlayerCharacter pc = SessionManager.getPlayerCharacter(origin); if (pc == null) return; // TODO improve this later. hacky way to make sure player ingame is // active. if (!pc.isActive()) pc.setActive(true); pc.setLastTarget(GameObjectType.values()[msg.getTargetType()], msg.getTargetID()); } private static void social(SocialMsg msg, ClientConnection origin) throws MsgSendException { PlayerCharacter pc = SessionManager.getPlayerCharacter(origin); if (pc == null) return; DispatchMessage.dispatchMsgToInterestArea(pc, msg, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, true, true); } private static void TransferItemFromEquipToInventory(TransferItemFromEquipToInventoryMsg msg, ClientConnection origin) { PlayerCharacter pc = origin.getPlayerCharacter(); if (pc == null) return; CharacterItemManager itemManager = pc.getCharItemManager(); if (itemManager == null) return; int slot = msg.getSlotNumber(); Item i = itemManager.getItemFromEquipped(slot); if (i == null) return; if (!itemManager.doesCharOwnThisItem(i.getObjectUUID())) return; //dupe check if (!i.validForEquip(origin, pc, itemManager)) return; if (i.containerType == ItemContainerType.EQUIPPED) itemManager.moveItemToInventory(i); int ItemType = i.getObjectType().ordinal(); int ItemID = i.getObjectUUID(); for (String name : i.getEffects().keySet()) { Effect eff = i.getEffects().get(name); if (eff == null) return; ApplyEffectMsg pum = new ApplyEffectMsg(); pum.setEffectID(eff.getEffectToken()); pum.setSourceType(pc.getObjectType().ordinal()); pum.setSourceID(pc.getObjectUUID()); pum.setTargetType(pc.getObjectType().ordinal()); pum.setTargetID(pc.getObjectUUID()); pum.setNumTrains(eff.getTrains()); pum.setUnknown05(1); pum.setUnknown02(2); pum.setUnknown06((byte) 1); pum.setEffectSourceType(ItemType); pum.setEffectSourceID(ItemID); pum.setDuration(-1); DispatchMessage.dispatchMsgToInterestArea(pc, pum, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, true, false);; } // Update player formulas pc.applyBonuses(); DispatchMessage.dispatchMsgToInterestArea(pc, msg, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, false, false); } //call this if the transfer fails server side to kick the item back to inventory from equip private void forceTransferFromInventoryToEquip(TransferItemFromEquipToInventoryMsg msg, ClientConnection origin, String reason) { //TODO add this later //PATCHED CODEZZ } private static void TransferItemFromInventoryToEquip(TransferItemFromInventoryToEquipMsg msg, ClientConnection origin) { PlayerCharacter pc = origin.getPlayerCharacter(); if (pc == null) return; CharacterItemManager itemManager = pc.getCharItemManager(); if (itemManager == null) { forceTransferFromEquipToInventory(msg, origin, "Can't find your item manager"); return; } int uuid = msg.getUUID(); int slot = msg.getSlotNumber(); //System.out.println("loading to slot: " + slot); Item i = itemManager.getItemByUUID(uuid); if (i == null) { forceTransferFromEquipToInventory(msg, origin, "Item not found in your item manager"); return; } if (!itemManager.doesCharOwnThisItem(i.getObjectUUID())) { forceTransferFromEquipToInventory(msg, origin, "You do not own this item"); return; } //dupe check if (!i.validForInventory(origin, pc, itemManager)) return; if (i.containerType == ItemContainerType.INVENTORY) { if (!itemManager.equipItem(i, (byte) slot)) { forceTransferFromEquipToInventory(msg, origin, "Failed to transfer item."); return; } } else { forceTransferFromEquipToInventory(msg, origin, "This item is not in your inventory"); return; } // Update player formulas pc.applyBonuses(); DispatchMessage.dispatchMsgToInterestArea(pc, msg, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, false, false); for (String name : i.getEffects().keySet()) { Effect eff = i.getEffects().get(name); if (eff == null) return; ApplyEffectMsg pum = new ApplyEffectMsg(); pum.setEffectID(eff.getEffectToken()); pum.setSourceType(pc.getObjectType().ordinal()); pum.setSourceID(pc.getObjectUUID()); pum.setTargetType(pc.getObjectType().ordinal()); pum.setTargetID(pc.getObjectUUID()); pum.setNumTrains(eff.getTrains()); pum.setUnknown05(1); pum.setUnknown06((byte) 1); pum.setEffectSourceType(i.getObjectType().ordinal()); pum.setEffectSourceID(i.getObjectUUID()); pum.setDuration(-1); DispatchMessage.dispatchMsgToInterestArea(pc, pum, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, false, false);; } } //call this if the transfer fails server side to kick the item back to inventory from equip private static void forceTransferFromEquipToInventory(TransferItemFromInventoryToEquipMsg msg, ClientConnection origin, String reason) { PlayerCharacter pc = origin.getPlayerCharacter(); if (pc == null) return; TransferItemFromEquipToInventoryMsg back = new TransferItemFromEquipToInventoryMsg(pc, msg.getSlotNumber()); Dispatch dispatch = Dispatch.borrow(pc, back); DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY); ChatManager.chatInfoError(pc, "Can't equip item: " + reason); } public static Boolean NPCVaultBankRangeCheck(PlayerCharacter pc, ClientConnection origin, String bankorvault) { if (pc == null) return false; NPC npc = pc.getLastNPCDialog(); if (npc == null) return false; // System.out.println(npc.getContract().getName()); // last npc must be either a banker or vault keeper if (bankorvault.equals("vault")) { if (npc.getContract().getContractID() != 861) return false; } else // assuming banker if (!npc.getContract().getName().equals("Bursar")) return false; if (pc.getLoc().distanceSquared2D(npc.getLoc()) > MBServerStatics.NPC_TALK_RANGE * MBServerStatics.NPC_TALK_RANGE) { ErrorPopupMsg.sendErrorPopup(pc, 14); return false; } else return true; } private static void transferItemFromInventoryToBank(TransferItemFromInventoryToBankMsg msg, ClientConnection origin) { PlayerCharacter player = origin.getPlayerCharacter(); Dispatch dispatch; if (player == null) return; if (!NPCVaultBankRangeCheck(player, origin, "bank")) return; CharacterItemManager itemManager = player.getCharItemManager(); if (itemManager == null) return; if (itemManager.getBankWeight() > 500) { ErrorPopupMsg.sendErrorPopup(player, 21); return; } int uuid = msg.getUUID(); Item item = itemManager.getItemByUUID(uuid); if (item == null) return; //dupe check WTF CHECK BUT NO LOGGING? if (!item.validForInventory(origin, player, itemManager)) return; if (item.containerType == ItemContainerType.INVENTORY && itemManager.isBankOpen()) if (item.getItemBase().getType().equals(engine.Enum.ItemType.GOLD)) { if (!itemManager.moveGoldToBank(item, msg.getNumItems())) return; UpdateGoldMsg goldMes = new UpdateGoldMsg(player); goldMes.configure(); dispatch = Dispatch.borrow(player, goldMes); DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY); } else { if (!itemManager.hasRoomBank(item.getItemBase().getWeight())) return; if (!itemManager.moveItemToBank(item)) return; dispatch = Dispatch.borrow(player, msg); DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY); } } private static void transferItemFromBankToInventory(TransferItemFromBankToInventoryMsg msg, ClientConnection origin) { PlayerCharacter player = origin.getPlayerCharacter(); Dispatch dispatch; if (player == null) return; if (!NPCVaultBankRangeCheck(player, origin, "bank")) return; CharacterItemManager itemManager = player.getCharItemManager(); if (itemManager == null) return; int uuid = msg.getUUID(); Item item = itemManager.getItemByUUID(uuid); if (item == null) return; //dupe check // WTF Checking but not logging? if (!item.validForBank(origin, player, itemManager)) return; if (item.containerType == ItemContainerType.BANK && itemManager.isBankOpen() == false) return; if (item.getItemBase().getType().equals(engine.Enum.ItemType.GOLD)) { if (!itemManager.moveGoldToInventory(item, msg.getNumItems())) return; UpdateGoldMsg goldMes = new UpdateGoldMsg(player); goldMes.configure(); dispatch = Dispatch.borrow(player, goldMes); DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY); return; } // Not gold, process update here if (!itemManager.hasRoomInventory(item.getItemBase().getWeight())) return; if (itemManager.moveItemToInventory(item) == false) return; dispatch = Dispatch.borrow(player, msg); DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY); } private static void transferItemFromVaultToInventory(TransferItemFromVaultToInventoryMsg msg, ClientConnection origin) { PlayerCharacter player = origin.getPlayerCharacter(); Dispatch dispatch; if (player == null) return; if (player.getAccount() == null) return; player.getAccount().transferItemFromVaultToInventory(msg, origin); } //call this if the transfer fails server side to kick the item back to inventory from vault public static void forceTransferFromInventoryToVault(TransferItemFromVaultToInventoryMsg msg, ClientConnection origin, String reason) { PlayerCharacter player = origin.getPlayerCharacter(); Dispatch dispatch; if (player == null) return; TransferItemFromInventoryToVaultMsg back = new TransferItemFromInventoryToVaultMsg(msg); dispatch = Dispatch.borrow(player, back); DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY); ChatManager.chatInfoError(player, "Can't transfer to inventory: " + reason); } private static void transferItemFromInventoryToVault(TransferItemFromInventoryToVaultMsg msg, ClientConnection origin) { PlayerCharacter player = origin.getPlayerCharacter(); Dispatch dispatch; if (player == null) return; if (player.getAccount() == null) return; player.getAccount().transferItemFromInventoryToVault(msg, origin); } //call this if the transfer fails server side to kick the item back to vault from inventory public static void forceTransferFromVaultToInventory(TransferItemFromInventoryToVaultMsg msg, ClientConnection origin, String reason) { PlayerCharacter player = origin.getPlayerCharacter(); Dispatch dispatch; if (player == null) return; TransferItemFromVaultToInventoryMsg back = new TransferItemFromVaultToInventoryMsg(msg); dispatch = Dispatch.borrow(player, back); DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY); ChatManager.chatInfoError(player, "Can't transfer to vault: " + reason); } private static void transferGoldFromVaultToInventory(TransferGoldFromVaultToInventoryMsg msg, ClientConnection origin) { PlayerCharacter player = origin.getPlayerCharacter(); if (player == null) return; Account account = player.getAccount(); if (account == null) return; account.transferGoldFromVaultToInventory(msg, origin); } private static void transferGoldFromInventoryToVault(TransferGoldFromInventoryToVaultMsg msg, ClientConnection origin) { PlayerCharacter player = origin.getPlayerCharacter(); Dispatch dispatch; if (player == null) return; Account account = player.getAccount(); if (account == null) return; account.transferGoldFromInventoryToVault(msg, origin); } private static void DeleteItem(DeleteItemMsg msg, ClientConnection origin) { CharacterItemManager itemManager = origin.getPlayerCharacter().getCharItemManager(); int uuid = msg.getUUID(); PlayerCharacter sourcePlayer = origin.getPlayerCharacter(); if (sourcePlayer == null) return; if (!sourcePlayer.isAlive()) return; Item i = Item.getFromCache(msg.getUUID()); if (i == null) return; if (!itemManager.doesCharOwnThisItem(i.getObjectUUID())) return; if (!itemManager.inventoryContains(i)) return; if (i.isCanDestroy()) if (itemManager.delete(i) == true) { Dispatch dispatch = Dispatch.borrow(sourcePlayer, msg); DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY); } } private static void ackBankWindowOpened(AckBankWindowOpenedMsg msg, ClientConnection origin) { // According to the Wiki, the client should not send this message. // Log the instance to investigate, and modify Wiki accordingly. Logger.error( msg.toString()); } private static void modifyStat(ModifyStatMsg msg, ClientConnection origin) { PlayerCharacter pc = SessionManager.getPlayerCharacter(origin); if (pc == null) return; int type = msg.getType(); switch (type) { case MBServerStatics.STAT_STR_ID: pc.addStr(msg.getAmount()); break; case MBServerStatics.STAT_DEX_ID: pc.addDex(msg.getAmount()); break; case MBServerStatics.STAT_CON_ID: pc.addCon(msg.getAmount()); break; case MBServerStatics.STAT_INT_ID: pc.addInt(msg.getAmount()); break; case MBServerStatics.STAT_SPI_ID: pc.addSpi(msg.getAmount()); break; } } // called when player clicks respawn button private static void respawn(RespawnMsg msg, ClientConnection origin) throws MsgSendException { PlayerCharacter sourcePlayer = SessionManager.getPlayerCharacter(origin); if (sourcePlayer == null) return; if (msg.getObjectType() != sourcePlayer.getObjectType().ordinal() || msg.getObjectID() != sourcePlayer.getObjectUUID()) { Logger.error( "Player " + sourcePlayer.getObjectUUID() + " respawning character of id " + msg.getObjectType() + ' ' + msg.getObjectID()); return; } if (sourcePlayer.isAlive()) { Logger.error( "Player " + sourcePlayer.getObjectUUID() + " respawning while alive"); return; } // ResetAfterDeath player sourcePlayer.respawnLock.writeLock().lock(); try{ sourcePlayer.respawn(true, false, true); }catch(Exception e){ Logger.error(e); }finally{ sourcePlayer.respawnLock.writeLock().unlock(); } // Echo ResetAfterDeath message back msg.setPlayerHealth(sourcePlayer.getHealth()); // TODO calculate any experience loss before this point msg.setPlayerExp(sourcePlayer.getExp() + sourcePlayer.getOverFlowEXP()); Dispatch dispatch = Dispatch.borrow(sourcePlayer, msg); DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.PRIMARY); MoveToPointMsg moveMsg = new MoveToPointMsg(); moveMsg.setPlayer(sourcePlayer); moveMsg.setStartCoord(sourcePlayer.getLoc()); moveMsg.setEndCoord(sourcePlayer.getLoc()); moveMsg.setInBuilding(-1); moveMsg.setUnknown01(-1); dispatch = Dispatch.borrow(sourcePlayer, moveMsg); DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.PRIMARY); MovementManager.sendRWSSMsg(sourcePlayer); // refresh the whole group with what just happened JobScheduler.getInstance().scheduleJob(new RefreshGroupJob(sourcePlayer), MBServerStatics.LOAD_OBJECT_DELAY); } private static void lootWindowRequest(LootWindowRequestMsg msg, ClientConnection origin) throws MsgSendException { PlayerCharacter pc = SessionManager.getPlayerCharacter(origin); if (pc == null) return; if (!pc.isAlive()) return; if (msg.getSourceType() != pc.getObjectType().ordinal() || msg.getSourceID() != pc.getObjectUUID()) { Logger.error("Player " + pc.getObjectUUID() + " looting from character of id " + msg.getSourceType() + ' ' + msg.getSourceID()); return; } if (pc.getAltitude() > 0) return; if (!pc.isAlive()) { return; } LootWindowResponseMsg lwrm = null; GameObjectType targetType = GameObjectType.values()[msg.getTargetType()]; AbstractCharacter characterTarget = null; Corpse corpseTarget = null; switch (targetType) { case PlayerCharacter: characterTarget = PlayerCharacter.getFromCache(msg.getTargetID()); if (characterTarget == null) return; if (characterTarget.isAlive()) return; if (pc.getLoc().distanceSquared2D(characterTarget.getLoc()) > sqr(MBServerStatics.LOOT_RANGE)){ ErrorPopupMsg.sendErrorMsg(pc, "You are too far away to loot this corpse."); Logger.info(pc.getFirstName() + " tried looting at " + pc.getLoc().distance2D(characterTarget.getLoc()) + " distance." ); return; } lwrm = new LootWindowResponseMsg(characterTarget.getObjectType().ordinal(), characterTarget.getObjectUUID(), characterTarget.getInventory(true)); break; case NPC: characterTarget = NPC.getFromCache(msg.getTargetID()); if (characterTarget == null) return; break; case Mob: characterTarget = Mob.getFromCache(msg.getTargetID()); if ((characterTarget == null) || characterTarget.isAlive()) { return; } if (pc.getLoc().distanceSquared2D(characterTarget.getLoc()) > sqr(MBServerStatics.LOOT_RANGE)){ ErrorPopupMsg.sendErrorMsg(pc, "You are too far away to loot this corpse."); Logger.info(pc.getFirstName() + " tried looting at " + pc.getLoc().distance2D(characterTarget.getLoc()) + " distance." ); if (!((Mob)characterTarget).isLootSync()){ ((Mob)characterTarget).setLootSync(true); WorldGrid.updateObject(characterTarget, pc); } return; } lwrm = new LootWindowResponseMsg(characterTarget.getObjectType().ordinal(), characterTarget.getObjectUUID(), characterTarget.getInventory()); break; case Corpse: corpseTarget = Corpse.getCorpse(msg.getTargetID()); if ((corpseTarget == null)) { return; } if (pc.getLoc().distanceSquared(corpseTarget.getLoc()) > sqr(MBServerStatics.LOOT_RANGE)){ ErrorPopupMsg.sendErrorMsg(pc, "You are too far away to loot this corpse."); Logger.info(pc.getFirstName() + " tried looting at " + pc.getLoc().distance2D(characterTarget.getLoc()) + " distance." ); return; } lwrm = new LootWindowResponseMsg(corpseTarget.getObjectType().ordinal(), msg.getTargetID(), corpseTarget.getInventory()); break; } if (lwrm == null) return; DispatchMessage.dispatchMsgToInterestArea(pc, msg, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, false, false); Dispatch dispatch = Dispatch.borrow(pc, lwrm); DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.PRIMARY); } private static void loot(LootMsg msg, ClientConnection origin) throws MsgSendException { PlayerCharacter player = SessionManager.getPlayerCharacter(origin); if (player == null) return; if (!player.isAlive()) return; Item item = msg.getItem(); if (item == null) return; if (item.lootLock.tryLock()) { try { Item itemRet = null; // get current owner int targetType = msg.getTargetType(); int targetID = msg.getTargetID(); if (targetType == GameObjectType.PlayerCharacter.ordinal() || targetType == GameObjectType.Mob.ordinal() || targetType == GameObjectType.Corpse.ordinal()) { } else { //needed for getting contracts for some reason targetType = msg.getSourceID2(); targetID = msg.getUnknown01(); } //can't loot while flying if (player.getAltitude() > 0) return; AbstractCharacter tar = null; Corpse corpse = null; if (targetType == GameObjectType.PlayerCharacter.ordinal() || targetType == GameObjectType.Mob.ordinal()) { if (targetType == GameObjectType.PlayerCharacter.ordinal()) { tar = PlayerCharacter.getFromCache(targetID); if (tar == null) return; if (player.getObjectUUID() != tar.getObjectUUID() && ((PlayerCharacter) tar).isInSafeZone()) return; } else if (targetType == GameObjectType.NPC.ordinal()) tar = NPC.getFromCache(targetID); else if (targetType == GameObjectType.Mob.ordinal()) tar = Mob.getFromCache(targetID); if (tar == null) return; if (tar.equals(player)){ ErrorPopupMsg.sendErrorMsg(player, "Cannot loot this item."); return; } if (player.getLoc().distanceSquared2D(tar.getLoc()) > sqr(MBServerStatics.LOOT_RANGE)){ ErrorPopupMsg.sendErrorMsg(player, "You are too far away to loot this corpse."); Logger.info( player.getFirstName() + " tried looting at " + player.getLoc().distance2D(tar.getLoc()) + " distance." ); return; } //can't loot from someone who is alive. if (AbstractWorldObject.IsAbstractCharacter(tar)) { if (tar.isAlive()) return; // Logger.error("WorldServer.loot", "Looting from live player"); } if (!GroupManager.goldSplit(player, item, origin, tar)) { if (tar.getCharItemManager() != null) { itemRet = tar.getCharItemManager().lootItemFromMe(item, player, origin); //Take equipment off mob if (tar.getObjectType() == GameObjectType.Mob && itemRet != null){ Mob mobTarget = (Mob)tar; if (item != null && item.getObjectType() == GameObjectType.MobLoot){ for (MobEquipment equip: mobTarget.getEquip().values()){ TransferItemFromEquipToInventoryMsg back = new TransferItemFromEquipToInventoryMsg(mobTarget, equip.getSlot()); DispatchMessage.dispatchMsgToInterestArea(mobTarget, back, DispatchChannel.SECONDARY, MBServerStatics.CHARACTER_LOAD_RANGE, false, false); LootMsg lootMsg = new LootMsg(0,0,tar.getObjectType().ordinal(), tar.getObjectUUID(), equip); Dispatch dispatch = Dispatch.borrow(player, lootMsg); DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY); break; } } } } } } else if (targetType == GameObjectType.Corpse.ordinal()) { corpse = Corpse.getCorpse(targetID); if (corpse == null) return; if (player.getLoc().distanceSquared2D(corpse.getLoc()) > sqr(MBServerStatics.LOOT_RANGE)){ ErrorPopupMsg.sendErrorMsg(player, "You are too far away to loot this corpse."); Logger.info( player.getFirstName() + " tried looting at " + player.getLoc().distance2D(corpse.getLoc()) + " distance." ); return; } //can't loot other players in safe zone. if (corpse.getBelongsToType() == GameObjectType.PlayerCharacter.ordinal()){ if (player.getObjectUUID() == corpse.getBelongsToID()) itemRet = corpse.lootItem(item, player); else if (!GroupManager.goldSplit(player, item, origin, corpse)) { itemRet = corpse.lootItem(item, player); } if (itemRet == null) return; if (item.getItemBase().getType().equals(engine.Enum.ItemType.GOLD)) { // this is done to prevent the temporary goldItem item // (from the mob) from appearing in player's inventory. // It also updates the goldItem quantity display UpdateGoldMsg updateTargetGold = null; if (corpse != null) updateTargetGold = new UpdateGoldMsg(corpse); updateTargetGold.configure(); DispatchMessage.dispatchMsgToInterestArea(corpse, updateTargetGold, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, false, false); UpdateGoldMsg ugm = new UpdateGoldMsg(player); ugm.configure(); Dispatch dispatch = Dispatch.borrow(player, ugm); DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY); // respond back loot message. Try sending to everyone. } else { DispatchMessage.dispatchMsgToInterestArea(corpse, msg, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, false, true); //player.getCharItemManager().updateInventory(); } //TODO send group loot message if player is grouped and visible Group group = GroupManager.getGroup(player); if (group != null && group.getSplitGold() && (item.getItemBase().getType().equals(engine.Enum.ItemType.GOLD) == false)) { String name = item.getName(); String text = player.getFirstName() + " has looted " + name + '.'; ChatManager.chatGroupInfoCanSee(player, text); } return; } } else return; if (itemRet == null) { return; } if (item.getItemBase().getType().equals(engine.Enum.ItemType.GOLD)) { // this is done to prevent the temporary goldItem item // (from the mob) from appearing in player's inventory. // It also updates the goldItem quantity display UpdateGoldMsg updateTargetGold = null; if (tar != null) updateTargetGold = new UpdateGoldMsg(tar); else if (corpse != null) updateTargetGold = new UpdateGoldMsg(corpse); updateTargetGold.configure(); DispatchMessage.dispatchMsgToInterestArea(tar, updateTargetGold, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, true, false); UpdateGoldMsg ugm = new UpdateGoldMsg(player); ugm.configure(); Dispatch dispatch = Dispatch.borrow(player, ugm); DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY); // respond back loot message. Try sending to everyone. } else { msg.setSourceType1(0); msg.setSourceType2(0); msg.setSourceID1(0); msg.setSourceID2(0); Dispatch dispatch = Dispatch.borrow(player, msg); //DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.PRIMARY); DispatchMessage.dispatchMsgToInterestArea(tar, msg, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, false, true); LootMsg newItemMsg = new LootMsg(GameObjectType.PlayerCharacter.ordinal(), player.getObjectUUID(),0,0, itemRet); dispatch = Dispatch.borrow(player, newItemMsg); DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.PRIMARY); //player.getCharItemManager().updateInventory(); } //TODO send group loot message if player is grouped and visible Group group = GroupManager.getGroup(player); if (group != null && group.getSplitGold() && (item.getItemBase().getType().equals(engine.Enum.ItemType.GOLD) == false)) { String name = item.getName(); String text = player.getFirstName() + " has looted " + name + '.'; ChatManager.chatGroupInfoCanSee(player, text); } } catch (Exception e) { Logger.info( e.getMessage()); } finally { item.lootLock.unlock(); } } } //returns true if looted item is goldItem and is split. Otherwise returns false // called when player types /show private static void show(ShowMsg msg, ClientConnection origin) throws MsgSendException { PlayerCharacter pc = SessionManager.getPlayerCharacter(origin); if (pc == null) return; int targetType = msg.getTargetType(); AbstractCharacter tar = null; if (targetType == GameObjectType.PlayerCharacter.ordinal()) tar = PlayerCharacter.getFromCache(msg.getTargetID()); else if (targetType == GameObjectType.NPC.ordinal()) tar = NPC.getFromCache(msg.getTargetID()); else if (targetType == GameObjectType.Mob.ordinal()) tar = Mob.getFromCache(msg.getTargetID()); if (tar == null || !tar.isAlive() || !tar.isActive()) return; msg.setUnknown01(pc.getLoc()); msg.setUnknown02(pc.getLoc()); msg.setRange01(pc.getRange()); msg.setUnknown03(tar.getLoc()); msg.setUnknown04(tar.getLoc()); msg.setRange01(tar.getRange()); Dispatch dispatch = Dispatch.borrow(pc, msg); DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY); } private static void ViewResourcesMessage(ViewResourcesMessage msg, ClientConnection origin) throws SQLException { PlayerCharacter player = SessionManager.getPlayerCharacter(origin); if (player == null) return; Guild guild = player.getGuild(); City city = guild.getOwnedCity(); if (city == null) return; Building warehouse = BuildingManager.getBuilding(city.getWarehouseBuildingID()); if (warehouse == null) return; ViewResourcesMessage vrm = new ViewResourcesMessage(player); vrm.setWarehouseBuilding(warehouse); vrm.setGuild(player.getGuild()); vrm.configure(); Dispatch dispatch = Dispatch.borrow(player, vrm); DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY); } private static void randomRoll(RandomMsg msg, ClientConnection origin) throws MsgSendException { PlayerCharacter source = origin.getPlayerCharacter(); if (source == null || !source.isAlive()) return; //2 second cooldown on random rolls long lastRandom = source.getTimeStamp("RandomRoll"); if (System.currentTimeMillis() - lastRandom < 2000) return; source.setTimeStamp("RandomRoll", System.currentTimeMillis()); //handle random roll int max = msg.getMax(); if (max > 0) msg.setRoll(ThreadLocalRandom.current().nextInt(max) + 1); else if (max < 0) { max = 1 - max; msg.setRoll((ThreadLocalRandom.current().nextInt(max) - max) + 1); } msg.setSourceType(source.getObjectType().ordinal()); msg.setSourceID(source.getObjectUUID()); //send to all in range DispatchMessage.dispatchMsgToInterestArea(source, msg, DispatchChannel.SECONDARY, MBServerStatics.CHARACTER_LOAD_RANGE, true, true); } private static void stuck(ClientConnection origin) { PlayerCharacter sourcePlayer = origin.getPlayerCharacter(); if (sourcePlayer == null) return; if (sourcePlayer.getTimers().containsKey("Stuck")) return; StuckJob sj = new StuckJob(sourcePlayer); JobContainer jc = JobScheduler.getInstance().scheduleJob(sj, 10000); // Convert ConcurrentHashMap timers = sourcePlayer.getTimers(); if (timers != null) { if (timers.containsKey("Stuck")) { timers.get("Stuck").cancelJob(); timers.remove("Stuck"); } timers.put("Stuck", jc); } } private static void GuildTreeStatusMsg(GuildTreeStatusMsg msg, ClientConnection origin) throws SQLException { PlayerCharacter player = SessionManager.getPlayerCharacter(origin); Dispatch dispatch; if (player == null) return; if (origin.guildtreespam > System.currentTimeMillis()) { return; } origin.guildtreespam = System.currentTimeMillis() + 5000; Building b = BuildingManager.getBuildingFromCache(msg.getTargetID()); if (b == null) return; GuildTreeStatusMsg gtsm = new GuildTreeStatusMsg(b, player); gtsm.configure(); dispatch = Dispatch.borrow(player, gtsm); DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY); } private static void openSellToNPCWindow(SellToNPCWindowMsg msg, ClientConnection origin) { PlayerCharacter sourcePlayer = SessionManager.getPlayerCharacter(origin); Dispatch dispatch; if (sourcePlayer == null) return; NPC npc = NPC.getFromCache(msg.getNPCID()); if (npc == null) return; // test within talking range if (sourcePlayer.getLoc().distanceSquared2D(npc.getLoc()) > MBServerStatics.NPC_TALK_RANGE * MBServerStatics.NPC_TALK_RANGE) { ErrorPopupMsg.sendErrorPopup(sourcePlayer, 14); return; } Contract con = npc.getContract(); if (con == null) return; float bargain = sourcePlayer.getBargain(); float profit = npc.getBuyPercent(sourcePlayer) + bargain; if (profit > 1) profit = 1; msg.setupOutput(); msg.setUnknown05(profit); msg.setUnknown06(500000); //TODO set goldItem on npc later msg.setItemType(con.getBuyItemType()); msg.setSkillTokens(con.getBuySkillToken()); msg.setUnknownArray(con.getBuyUnknownToken()); dispatch = Dispatch.borrow(sourcePlayer, msg); DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY); } private static void sellToNPC(SellToNPCMsg msg, ClientConnection origin) { PlayerCharacter player = SessionManager.getPlayerCharacter(origin); Dispatch dispatch; if (player == null) return; CharacterItemManager itemMan = player.getCharItemManager(); if (itemMan == null) return; NPC npc = NPC.getFromCache(msg.getNPCID()); if (npc == null) return; Item gold = itemMan.getGoldInventory(); if (gold == null) return; if (origin.sellLock.tryLock()) { try { Item sell; int cost = 0; if (npc.getCharItemManager().getInventoryCount() > 150) { if (npc.getParentZone() != null && npc.getParentZone().getPlayerCityUUID() == 0) { ArrayList inv = npc.getInventory(); for (int i = 0; i < 20; i++) { try { Item toRemove = inv.get(i); if (toRemove != null) npc.getCharItemManager().delete(toRemove); } catch (Exception e) { break; } } } } // Early exit sanity check if (msg.getItemType() == GameObjectType.Item.ordinal() == false) return; sell = Item.getFromCache(msg.getItemID()); if (sell == null) return; //get item to sell ItemBase ib = sell.getItemBase(); if (ib == null) return; if (npc.getParentZone() != null && npc.getParentZone().getPlayerCityUUID() != 0) if (!npc.getCharItemManager().hasRoomInventory(ib.getWeight())){ ErrorPopupMsg.sendErrorPopup(player, 21); return; } if (!sell.validForInventory(origin, player, itemMan)) return; //get goldItem cost to sell cost = sell.getBaseValue(); float bargain = player.getBargain(); float profit = npc.getBuyPercent(player) + bargain; if (profit > 1) profit = 1; cost *= profit; if (gold.getNumOfItems() + cost > 10000000) { return; } if (gold.getNumOfItems() + cost < 0) return; //TODO make sure npc can buy item type //test room available for item on npc // if (!npc.isStatic() && npc.getCharItemManager().getInventoryCount() > 150) { // // chatMan.chatSystemInfo(pc, "This vendor's inventory is full"); // return; // } //make sure item is in player inventory Building building = (!npc.isStatic()) ? npc.getBuilding() : null; if (building != null && building.getProtectionState().equals(ProtectionState.NPC)) building = null; if (npc.getParentZone().getPlayerCityUUID() == 0) building = null; //make sure npc can afford item if (building != null && !building.hasFunds(cost)){ ErrorPopupMsg.sendErrorPopup(player, 17); return; } if (building != null && (building.getStrongboxValue() - cost) < 0){ ErrorPopupMsg.sendErrorPopup(player, 17); return; } //TODO transfer item and goldItem transfer should be handled together incase failure //transfer the item if (!itemMan.sellToNPC(sell, npc)) return; if (!itemMan.sellToNPC(building, cost, sell)) return; //handle goldItem transfer if (sell == null) return; // ***REFACTOR: SellToNpc sends this message, is this a duplicate? //update player's goldItem count UpdateGoldMsg ugm = new UpdateGoldMsg(player); ugm.configure(); dispatch = Dispatch.borrow(player, ugm); DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY); //send the sell message back to update player msg.setItemType(sell.getObjectType().ordinal()); msg.setItemID(sell.getObjectUUID()); msg.setUnknown01(cost); //not sure if this is correct dispatch = Dispatch.borrow(player, msg); DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY); } finally { origin.sellLock.unlock(); } } else { ErrorPopupMsg.sendErrorPopup(player, 12); } } private static void openBuyFromNPCWindow(BuyFromNPCWindowMsg msg, ClientConnection origin) { PlayerCharacter sourcePlayer = SessionManager.getPlayerCharacter(origin); Dispatch dispatch; if (sourcePlayer == null) return; NPC npc = NPC.getFromCache(msg.getNpcID()); if (npc == null) return; // test within talking range if (sourcePlayer.getLoc().distanceSquared2D(npc.getLoc()) > MBServerStatics.NPC_TALK_RANGE * MBServerStatics.NPC_TALK_RANGE) { ErrorPopupMsg.sendErrorPopup(sourcePlayer, 14); return; } dispatch = Dispatch.borrow(sourcePlayer, msg); DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY); } private static void buyFromNPC(BuyFromNPCMsg msg, ClientConnection origin) { PlayerCharacter sourcePlayer = SessionManager.getPlayerCharacter(origin); if (sourcePlayer == null) return; if (origin.buyLock.tryLock()) { try { CharacterItemManager itemMan = sourcePlayer.getCharItemManager(); if (itemMan == null) return; NPC npc = NPC.getFromCache(msg.getNPCID()); if (npc == null) return; Item gold = itemMan.getGoldInventory(); if (gold == null) return; Item buy = null; if (msg.getItemType() == GameObjectType.MobEquipment.ordinal()) { ArrayList sellInventory = npc.getContract().getSellInventory(); if (sellInventory == null) return; for (MobEquipment me : sellInventory) { if (me.getObjectUUID() == msg.getItemID()) { ItemBase ib = me.getItemBase(); if (ib == null) return; //test room available for item if (!itemMan.hasRoomInventory(ib.getWeight())) return; int cost = me.getMagicValue(); float bargain = sourcePlayer.getBargain(); float profit = npc.getSellPercent(sourcePlayer) - bargain; if (profit < 1) profit = 1; cost *= profit; if (gold.getNumOfItems() - cost < 0) { //dont' have enough goldItem exit! // chatMan.chatSystemInfo(pc, "" + "You dont have enough gold."); return; } Building b = (!npc.isStatic()) ? npc.getBuilding() : null; if (b != null && b.getProtectionState().equals(ProtectionState.NPC)) b = null; int buildingDeposit = cost - me.getMagicValue(); if (b != null && (b.getStrongboxValue() + buildingDeposit) > b.getMaxGold()) { ErrorPopupMsg.sendErrorPopup(sourcePlayer, 206); return; } if (!itemMan.buyFromNPC(b, cost, buildingDeposit)) { // chatMan.chatSystemInfo(pc, "" + "You Failed to buy the item."); return; } buy = Item.createItemForPlayer(sourcePlayer, ib); if (buy != null) { me.transferEnchants(buy); itemMan.addItemToInventory(buy); //itemMan.updateInventory(); } } } } else if (msg.getItemType() == GameObjectType.Item.ordinal()) { CharacterItemManager npcCim = npc.getCharItemManager(); if (npcCim == null) return; buy = Item.getFromCache(msg.getItemID()); if (buy == null) return; ItemBase ib = buy.getItemBase(); if (ib == null) return; if (!npcCim.inventoryContains(buy)) return; //test room available for item if (!itemMan.hasRoomInventory(ib.getWeight())) return; //TODO test cost and subtract goldItem //TODO CHnage this if we ever put NPc city npcs in buildings. int cost = buy.getBaseValue(); if (buy.isID() || buy.isCustomValue()) cost = buy.getMagicValue(); float bargain = sourcePlayer.getBargain(); float profit = npc.getSellPercent(sourcePlayer) - bargain; if (profit < 1) profit = 1; if (!buy.isCustomValue()) cost *= profit; else cost = buy.getValue(); if (gold.getNumOfItems() - cost < 0) { ErrorPopupMsg.sendErrorPopup(sourcePlayer, 128); // Insufficient Gold return; } Building b = (!npc.isStatic()) ? npc.getBuilding() : null; if (b != null) if (b.getProtectionState().equals(ProtectionState.NPC)) b = null; int buildingDeposit = cost; if (b != null && (b.getStrongboxValue() + buildingDeposit) > b.getMaxGold()) { ErrorPopupMsg.sendErrorPopup(sourcePlayer, 206); return; } if (!itemMan.buyFromNPC(b, cost, buildingDeposit)) { ErrorPopupMsg.sendErrorPopup(sourcePlayer, 110); return; } if (buy != null) itemMan.buyFromNPC(buy, npc); }else if (msg.getItemType() == GameObjectType.MobLoot.ordinal()) { CharacterItemManager npcCim = npc.getCharItemManager(); if (npcCim == null) return; buy = MobLoot.getFromCache(msg.getItemID()); if (buy == null) return; ItemBase ib = buy.getItemBase(); if (ib == null) return; if (!npcCim.inventoryContains(buy)) return; //test room available for item if (!itemMan.hasRoomInventory(ib.getWeight())) return; //TODO test cost and subtract goldItem //TODO CHnage this if we ever put NPc city npcs in buildings. int cost = buy.getMagicValue(); cost *= npc.getSellPercent(sourcePlayer); if (gold.getNumOfItems() - cost < 0) { ErrorPopupMsg.sendErrorPopup(sourcePlayer, 128); // Insufficient Gold return; } Building b = (!npc.isStatic()) ? npc.getBuilding() : null; if (b != null && b.getProtectionState().equals(ProtectionState.NPC)) b = null; int buildingDeposit = cost; if (b != null && (b.getStrongboxValue() + buildingDeposit) > b.getMaxGold()) { ErrorPopupMsg.sendErrorPopup(sourcePlayer, 206); return; } if (!itemMan.buyFromNPC(b, cost, buildingDeposit)) return; if (buy != null) itemMan.buyFromNPC(buy, npc); } else return; if (buy != null) { msg.setItem(buy); //send the buy message back to update player // msg.setItemType(buy.getObjectType().ordinal()); // msg.setItemID(buy.getObjectUUID()); Dispatch dispatch = Dispatch.borrow(sourcePlayer, msg); DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY); itemMan.updateInventory(); } } finally { origin.buyLock.unlock(); } } else { ErrorPopupMsg.sendErrorPopup(origin.getPlayerCharacter(), 12); // All production slots taken } } //Handle RepairObject Window and RepairObject Requests private static void Repair(RepairMsg msg, ClientConnection origin) { PlayerCharacter player = SessionManager.getPlayerCharacter(origin); Dispatch dispatch; if (player == null) return; NPC npc = NPC.getFromCache(msg.getNPCID()); if (npc == null) return; if (msg.getMsgType() == 1) { //Open RepairObject Window if (player.getLoc().distanceSquared2D(npc.getLoc()) > MBServerStatics.NPC_TALK_RANGE * MBServerStatics.NPC_TALK_RANGE) { ErrorPopupMsg.sendErrorPopup(player, 14); return; } //send open repair window response msg.setRepairWindowAck(npc); dispatch = Dispatch.borrow(player, msg); DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY); } else if (msg.getMsgType() == 0) { //Request RepairObject CharacterItemManager itemMan = player.getCharItemManager(); if (itemMan == null) return; Item gold = itemMan.getGoldInventory(); if (gold == null) return; Item toRepair = Item.getFromCache(msg.getItemID()); if (toRepair == null) return; if (toRepair.getItemBase().isGlass()) return; //make sure item is in player's inventory or equipment if (!itemMan.inventoryContains(toRepair) && !itemMan.equippedContains(toRepair)) return; //make sure item is damaged and not destroyed short dur = toRepair.getDurabilityCurrent(); short max = toRepair.getDurabilityMax(); //account for durability modifications float durMod = toRepair.getBonusPercent(ModType.Durability,SourceType.None); max *= (1 + (durMod * 0.01f)); if (dur >= max || dur < 1) { //redundancy message to clear item from window in client toRepair.setDurabilityCurrent(max); msg.setupRepairAck(max - dur); dispatch = Dispatch.borrow(player, msg); DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY); return; } //TODO get cost to repair int cost = (int) ((max - dur) * 80.1); Building b = (!npc.isStatic()) ? npc.getBuilding() : null; if (b != null) if (b.getProtectionState().equals(ProtectionState.NPC)) b = null; if (b != null && (b.getStrongboxValue() + cost) > b.getMaxGold()) { ErrorPopupMsg.sendErrorPopup(player, 206); return; } if (player.getCharItemManager().getGoldInventory().getNumOfItems() - cost < 0) return; if (player.getCharItemManager().getGoldInventory().getNumOfItems() - cost > MBServerStatics.PLAYER_GOLD_LIMIT) return; if (!itemMan.buyFromNPC(b, cost, cost)) { ErrorPopupMsg.sendErrorPopup(player, 128); return; } //update player's goldItem count UpdateGoldMsg ugm = new UpdateGoldMsg(player); ugm.configure(); dispatch = Dispatch.borrow(player, ugm); DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY); //update durability to database if (!DbManager.ItemQueries.SET_DURABILITY(toRepair, max)) return; //repair the item toRepair.setDurabilityCurrent(max); //send repair msg msg.setupRepairAck(max - dur); dispatch = Dispatch.borrow(player, msg); DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY); } } protected static void petAttack(PetAttackMsg msg, ClientConnection conn) throws MsgSendException { PlayerCharacter pc = SessionManager.getPlayerCharacter(conn); if (pc == null) return; Mob pet = pc.getPet(); if (pet == null) return; if (!pet.isAlive()) return; if ((pc.inSafeZone()) && (msg.getTargetType() == GameObjectType.PlayerCharacter.ordinal())) return; CombatManager.setAttackTarget(msg, conn); if (pet.getCombatTarget() == null) return; pet.setState(STATE.Attack); } protected static void petCmd(PetCmdMsg msg, ClientConnection conn) throws MsgSendException { PlayerCharacter pc = SessionManager.getPlayerCharacter(conn); if (pc == null) return; Mob pet = pc.getPet(); if (pet == null) return; if (!pet.isAlive()) return; if (pet.getState() == STATE.Disabled) return; int type = msg.getType(); if (type == 1) { //stop attack pet.setCombatTarget(null); pc.setCombat(false); pet.setState(STATE.Awake); } else if (type == 2) { //dismiss pet.dismiss(); pc.dismissPet(); if (pet.isAlive()) WorldGrid.updateObject(pet); } else if (type == 3) //toggle assist pet.toggleAssist(); else if (type == 5) { //rest boolean sit = (!(pet.isSit())); pet.setSit(sit); // cancel effects that break on sit if (pet.isSit()) pet.cancelOnSit(); UpdateStateMsg rwss = new UpdateStateMsg(); rwss.setPlayer(pet); DispatchMessage.sendToAllInRange(pet, rwss); } } protected static void HandlePromptRecall(PromptRecallMsg msg, ClientConnection origin) throws MsgSendException { PlayerCharacter player = SessionManager.getPlayerCharacter(origin); boolean recallAccepted; if (player == null) return; boolean confirmed = msg.getConfirmed(); if (confirmed == true) { long timeElapsed = System.currentTimeMillis() - player.getTimeStamp("PromptRecall"); //send fail message recallAccepted = timeElapsed < 15000; } else recallAccepted = false; if (recallAccepted == true) { //handle recall long type = player.getTimeStamp("LastRecallType"); if (type == 1) { //recall to bind player.teleport(player.getBindLoc()); player.setSafeMode(); } else { //recall to rg float dist = 9999999999f; Building rg = null; Vector3fImmutable rgLoc; for (Runegate runegate : Runegate._runegates.values()) { rgLoc = runegate.gateBuilding.getLoc(); float distanceSquaredToRunegate = player.getLoc().distanceSquared2D(rgLoc); if (distanceSquaredToRunegate < sqr(dist)) rg = runegate.gateBuilding; } //nearest runegate found. teleport characterTarget if (rg != null) { player.teleport(rg.getLoc()); player.setSafeMode(); } } } } }