// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . // ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· // ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ // ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ // ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ // Magicbane Emulator Project © 2013 - 2022 // www.magicbane.com package engine.objects; import engine.gameManager.*; import engine.math.Vector3fImmutable; import engine.mbEnums; import engine.mbEnums.GameObjectType; import engine.mbEnums.ItemType; import engine.net.Dispatch; import engine.net.DispatchMessage; import engine.net.client.ClientConnection; import engine.net.client.msg.*; import engine.server.MBServerStatics; import org.pmw.tinylog.Logger; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ThreadLocalRandom; import static engine.math.FastMath.sqr; import static engine.net.client.msg.ErrorPopupMsg.sendErrorPopup; public class CharacterItemManager { private final AbstractCharacter absCharacter; // Mapping of all the items associated with this Manager private final ConcurrentHashMap itemIDtoType = new ConcurrentHashMap<>(MBServerStatics.CHM_INIT_CAP, MBServerStatics.CHM_LOAD, MBServerStatics.CHM_THREAD_LOW); // Mapping of all items equipped in this Manager // Key = Item Slot public ConcurrentHashMap equipped = new ConcurrentHashMap<>(MBServerStatics.CHM_INIT_CAP, MBServerStatics.CHM_LOAD, MBServerStatics.CHM_THREAD_LOW); private final HashSet inventory = new HashSet<>(); private final HashSet bank = new HashSet<>(); private final HashSet vault = new HashSet<>(); public Item goldVault; private Account account; private Item goldInventory; private Item goldBank; private boolean bankOpened; private boolean vaultOpened; private short bankWeight; private short inventoryWeight; private short equipWeight; private short vaultWeight; public ClientConnection tradingWith; private byte tradeCommitted; private boolean tradeSuccess; private HashSet trading; private int goldTradingAmount; public int tradeID = 0; public CharacterItemManager(AbstractCharacter ac) { super(); this.absCharacter = ac; } public void load() { loadForGeneric(); if (this.absCharacter.getObjectType().equals(GameObjectType.PlayerCharacter)) loadForPlayerCharacter(); else if (this.absCharacter.getObjectType().equals(GameObjectType.NPC)) loadForNPC(); } public void loadGoldItems() { if (ConfigManager.serverType.equals(mbEnums.ServerType.LOGINSERVER)) { //other server, just make generic this.goldInventory = new MobLoot(this.absCharacter, 0); this.goldBank = new MobLoot(this.absCharacter, 0); this.goldVault = new MobLoot(this.absCharacter, 0); return; } //create inventory gold if needed if (this.goldInventory == null) if (this.absCharacter != null && (this.absCharacter.getObjectType().equals(GameObjectType.PlayerCharacter) || this.absCharacter.getObjectType().equals(GameObjectType.NPC))) this.goldInventory = Item.newGoldItem(this.absCharacter, mbEnums.ItemContainerType.INVENTORY); else this.goldInventory = new MobLoot(this.absCharacter, 0); //create bank gold if needed if (this.goldBank == null) if (this.absCharacter != null && this.absCharacter.getObjectType().equals(GameObjectType.PlayerCharacter)) this.goldBank = Item.newGoldItem(this.absCharacter, mbEnums.ItemContainerType.BANK); else this.goldBank = new MobLoot(this.absCharacter, 0); //create vault gold if needed if (this.goldVault == null) if (this.absCharacter != null && this.absCharacter.getObjectType().equals(GameObjectType.PlayerCharacter)) { this.goldVault = this.account.vaultGold; } else this.goldVault = new MobLoot(this.absCharacter, 0); this.itemIDtoType.put(this.goldInventory.getObjectUUID(), this.goldInventory.getObjectType().ordinal()); this.itemIDtoType.put(this.goldBank.getObjectUUID(), this.goldBank.getObjectType().ordinal()); this.itemIDtoType.put(this.goldVault.getObjectUUID(), this.goldVault.getObjectType().ordinal()); } private void loadForPlayerCharacter() { ArrayList al = null; // TODO Verify this is an actual account. this.account = ((PlayerCharacter) this.absCharacter).getAccount(); // Get Items for player and vault if (ConfigManager.serverType.equals(mbEnums.ServerType.LOGINSERVER)) //login, only need equipped items al = DbManager.ItemQueries.GET_EQUIPPED_ITEMS(this.absCharacter.getObjectUUID()); else al = DbManager.ItemQueries.GET_ITEMS_FOR_PC(this.absCharacter.getObjectUUID()); for (Item i : al) { i.validateItemContainer(); this.itemIDtoType.put(i.getObjectUUID(), i.getObjectType().ordinal()); switch (i.containerType) { case EQUIPPED: if (this.equipped.containsValue(i) == false) this.equipped.put(i.equipSlot, i); break; case BANK: if (i.template.item_type.equals(ItemType.GOLD)) this.goldBank = i; else if (this.bank.contains(i) == false) this.bank.add(i); break; case INVENTORY: if (i.template.item_type.equals(ItemType.GOLD)) this.goldInventory = i; else if (this.inventory.contains(i) == false) this.inventory.add(i); break; case VAULT: if (i.template.item_type.equals(ItemType.GOLD)) this.goldVault = i; else if (this.vault.contains(i) == false) this.vault.add(i); break; default: i.junk(); break; } } this.goldVault = this.account.vaultGold; //check all gold is created //loadGoldItems(); calculateWeights(); } private void loadForNPC() { ArrayList al = null; // Get all items related to this NPC: al = DbManager.ItemQueries.GET_ITEMS_FOR_NPC(this.absCharacter.getObjectUUID()); for (Item i : al) { i.validateItemContainer(); this.itemIDtoType.put(i.getObjectUUID(), i.getObjectType().ordinal()); switch (i.containerType) { case EQUIPPED: if (this.equipped.containsValue(i) == false) this.equipped.put(i.equipSlot, i); break; case BANK: if (i.template.item_type.equals(ItemType.GOLD)) this.goldBank = i; else if (this.bank.contains(i) == false) this.bank.add(i); break; case INVENTORY: if (i.template.item_type.equals(ItemType.GOLD)) this.goldInventory = i; else if (this.inventory.contains(i) == false) this.inventory.add(i); break; default: i.junk(); break; } } //check all gold is created //loadGoldItems(); } private void loadForGeneric() { this.bankWeight = 0; this.inventoryWeight = 0; this.equipWeight = 0; this.vaultWeight = 0; //check all gold is created //loadGoldItems(); // Always initialize with bank and vault closed bankOpened = false; vaultOpened = false; } //Positve Amount = TO BUILDING; Negative Amount = FROM BUILDING. flip signs for Player inventory. public synchronized boolean transferGoldToFromBuilding(int amount, AbstractWorldObject object) { if (this.absCharacter.getObjectType() != GameObjectType.PlayerCharacter) return false; PlayerCharacter player = (PlayerCharacter) this.absCharacter; switch (object.getObjectType()) { case Building: Building building = (Building) object; if (!this.getGoldInventory().validForInventory(player.getClientConnection(), player, this)) return false; if (amount < 0 && amount > building.getStrongboxValue()) return false; // Not enough gold in inventory to transfer to tree if ((amount > 0) && (this.getGoldInventory().getNumOfItems() - amount < 0)) { sendErrorPopup(player, 28); return false; } if (this.getGoldInventory().getNumOfItems() - amount > MBServerStatics.PLAYER_GOLD_LIMIT) { ErrorPopupMsg.sendErrorPopup(player, 202); return false; } // Not enough gold to transfer to inventory from tree if ((amount < 0) && (building.getStrongboxValue() + amount < 0)) { sendErrorPopup(player, 127); return false; } if (amount < 0) if (!building.hasFunds(-amount)) return false; //Verify player can access building to transfer goldItem if (!BuildingManager.playerCanManage(player, building)) return false; if (building.getStrongboxValue() + amount > building.getMaxGold()) { ErrorPopupMsg.sendErrorPopup(player, 201); return false; } if (this.getOwner().charItemManager.getGoldTrading() > 0) { if (this.getOwner().getObjectType().equals(GameObjectType.PlayerCharacter)) ErrorPopupMsg.sendErrorPopup((PlayerCharacter) this.getOwner(), 195); return false; } if (!this.modifyInventoryGold(-amount)) { Logger.error(player.getName() + " transfer amount = " + amount + " ; Gold Inventory = " + this.getGoldInventory().getNumOfItems()); // ChatManager.chatSystemError(player, "You do not have this Gold."); return false; } if (!building.transferGold(amount, false)) { Logger.error(player.getName() + " transfer amount = " + amount + " ; Gold Inventory = " + this.getGoldInventory().getNumOfItems() + "; Building Strongbox = " + building.getStrongboxValue()); //ChatManager.chatSystemError(player, "Something went terribly wrong. Contact CCR."); return false; } break; case Warehouse: Building warehouseBuilding = (Building) object; Warehouse warehouse = Objects.requireNonNull(warehouseBuilding.getCity()).warehouse; if (amount < 0) { if (!Warehouse.deposit((PlayerCharacter) this.absCharacter, this.getGoldInventory(), amount * -1, true, true, warehouse)) { ErrorPopupMsg.sendErrorPopup((PlayerCharacter) this.absCharacter, 203); return false; } } else { if (!Warehouse.withdraw(warehouse, (PlayerCharacter) this.absCharacter, mbEnums.ResourceType.GOLD, amount * -1, true, true)) { ErrorPopupMsg.sendErrorPopup((PlayerCharacter) this.absCharacter, 203); return false; } } break; } return true; } /* * Item Controls */ public synchronized boolean modifyInventoryGold(int modifyValue) { Item goldItem; PlayerCharacter player; boolean success = false; goldItem = getGoldInventory(); if (goldItem == null) { Logger.error("ModifyInventoryGold", "Could not create gold item"); return success; } if (this.getGoldInventory().getNumOfItems() + modifyValue > MBServerStatics.PLAYER_GOLD_LIMIT) { return false; } if (this.getGoldInventory().getNumOfItems() + modifyValue < 0) return false; // No database update for npc's gold values so we use the player object // for flow control later on. if (this.absCharacter.getObjectType() == GameObjectType.PlayerCharacter) player = (PlayerCharacter) this.absCharacter; else player = null; // If this is an update for a player character update the database if (player != null) try { if (!DbManager.ItemQueries.UPDATE_GOLD(this.getGoldInventory(), this.goldInventory.getNumOfItems() + modifyValue)) { return false; } success = true; } catch (Exception e) { Logger.error("ModifyInventoryGold", "Error writing to database"); } // Update in-game gold values for character goldItem.setNumOfItems(goldItem.getNumOfItems() + modifyValue); UpdateGoldMsg ugm = new UpdateGoldMsg(this.absCharacter); ugm.configure(); Dispatch dispatch = Dispatch.borrow(player, ugm); DispatchMessage.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.SECONDARY); return success; } public synchronized boolean tradeRequest(TradeRequestMsg msg) { PlayerCharacter source = (PlayerCharacter) this.getOwner(); PlayerCharacter target = PlayerCharacter.getFromCache(msg.getPlayerID()); Dispatch dispatch; if (!canTrade(source, target)) { ChatManager.chatSystemError(source, "Can't currently trade with target player"); return false; } // TODO uncomment this block after we determine when we // setBankOpen(false) and setVaultOpen(false) CharacterItemManager cim1 = source.charItemManager; CharacterItemManager cim2 = target.charItemManager; if (cim1 == null) return false; if (cim2 == null) return false; dispatch = Dispatch.borrow(target, msg); DispatchMessage.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.SECONDARY); return true; } public synchronized boolean invalidTradeRequest(InvalidTradeRequestMsg msg) { PlayerCharacter requester = PlayerCharacter.getFromCache(msg.getRequesterID()); Dispatch dispatch; dispatch = Dispatch.borrow(requester, msg); DispatchMessage.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.SECONDARY); return true; } public static synchronized boolean canTrade(PlayerCharacter playerA, PlayerCharacter playerB) { if (playerA == null || playerB == null) return false; //make sure both are alive if (!playerA.isAlive() || !playerB.isAlive()) return false; //distance check Vector3fImmutable aLoc = playerA.getLoc(); Vector3fImmutable bLoc = playerB.getLoc(); if (aLoc.distanceSquared2D(bLoc) > sqr(MBServerStatics.TRADE_RANGE)) return false; //visibility check if (!playerA.canSee(playerB) || !playerB.canSee(playerA)) return false; if (playerA.lastBuildingAccessed != 0) { ManageCityAssetsMsg mca = new ManageCityAssetsMsg(); mca.actionType = 4; mca.setTargetType(mbEnums.GameObjectType.Building.ordinal()); mca.setTargetID(playerA.lastBuildingAccessed); Dispatch dispatch = Dispatch.borrow(playerA, mca); DispatchMessage.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.SECONDARY); playerA.lastBuildingAccessed = 0; } return true; } public synchronized boolean modifyCommitToTrade() { CharacterItemManager man1 = this; if (this.getTradingWith() == null) return false; if (this.getTradingWith().getPlayerCharacter() == null) return false; CharacterItemManager man2 = this.getTradingWith().getPlayerCharacter().charItemManager; Dispatch dispatch; if (man1 == null || man2 == null) return false; ModifyCommitToTradeMsg modify = new ModifyCommitToTradeMsg(this.getOwner(), man2.getOwner(), man1.getTradeCommitted(), man2.getTradeCommitted()); dispatch = Dispatch.borrow((PlayerCharacter) this.getOwner(), modify); DispatchMessage.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.SECONDARY); dispatch = Dispatch.borrow((PlayerCharacter) man2.getOwner(), modify); DispatchMessage.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.SECONDARY); return true; } public synchronized boolean closeTradeWindow(CloseTradeWindowMsg msg, boolean sourceTrade) { Dispatch dispatch; PlayerCharacter source = (PlayerCharacter) this.getOwner(); if (source == null) return false; CharacterItemManager sourceItemMan = source.charItemManager; if (sourceItemMan == null) return false; int tradeID = this.tradeID; CloseTradeWindowMsg closeMsg = new CloseTradeWindowMsg(source, tradeID); dispatch = Dispatch.borrow(source, closeMsg); DispatchMessage.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.SECONDARY); if (!sourceTrade) { sourceItemMan.endTrade(); return true; } ClientConnection cc2 = sourceItemMan.getTradingWith(); if (cc2 == null || cc2.getPlayerCharacter() == null) { sourceItemMan.endTrade(); return true; } sourceItemMan.endTrade(); cc2.getPlayerCharacter().charItemManager.closeTradeWindow(msg, false); return true; } public Item getGoldInventory() { if (this.goldInventory == null) loadGoldItems(); return this.goldInventory; } public Item getGoldBank() { if (this.goldBank == null) loadGoldItems(); return this.goldBank; } public Item getGoldVault() { if (this.goldVault == null) loadGoldItems(); return this.goldVault; } public synchronized boolean doesCharOwnThisItem(int itemID) { return this.itemIDtoType.containsKey(itemID); } public synchronized boolean junk(Item i) { return junk(i, true); } public synchronized boolean recycle(Item i) { if (i.getObjectType() == GameObjectType.Item) return junk(i, false); else { if (this.removeItemFromInventory(i) == false) return false; ((MobLoot) i).recycle((NPC) this.absCharacter); calculateInventoryWeight(); return true; } } // The DeleteItemMsg takes care of updating inventory, so we don't want to do it separately public synchronized boolean delete(Item i) { return junk(i, false); } //cleanup an item from CharacterItemManager if it doesn't belong here public synchronized boolean cleanupDupe(Item i) { if (i == null) return false; if (i.template.item_type.equals(ItemType.GOLD)) { if (this.getGoldInventory() != null) { if (i.getObjectUUID() == this.getGoldInventory().getObjectUUID()) this.goldInventory = null; } else if (this.getGoldBank() != null) { if (i.getObjectUUID() == this.getGoldBank().getObjectUUID()) this.goldBank = null; } return true; } if (this.doesCharOwnThisItem(i.getObjectUUID()) == false) return false; // remove it from other lists: this.remItemFromLists(i); this.itemIDtoType.remove(i.getObjectUUID()); calculateWeights(); return true; } public synchronized boolean consume(Item i) { i.decrementChargesRemaining(); if ((byte) i.chargesRemaining > 0) return true; return junk(i, true); } private synchronized boolean junk(Item i, boolean updateInventory) { if (i.template.item_type.equals(ItemType.GOLD)) { if (this.getGoldInventory().getObjectUUID() == i.getObjectUUID()) if (DbManager.ItemQueries.UPDATE_GOLD(i, 0)) { this.getGoldInventory().setNumOfItems(0); if (updateInventory) updateInventory(); return true; } else { return false; } if (!(this.absCharacter.getObjectType().equals(GameObjectType.Mob))) return false; } if (this.doesCharOwnThisItem(i.getObjectUUID()) == false && this.absCharacter.getObjectType() != GameObjectType.Mob && (i.containerType != mbEnums.ItemContainerType.FORGE)) return false; // remove it from other lists: this.remItemFromLists(i); this.itemIDtoType.remove(i.getObjectUUID()); i.junk(); //Why are we adding junked items?! // if (i.getObjectType() != GameObjectType.MobLoot) // CharacterItemManager.junkedItems.add(i); calculateWeights(); if (updateInventory) // Send the new inventory //updateInventory(i, false); this line was causing entire inventory to disappear updateInventory(this.getInventory(), true); return true; } public synchronized boolean moveItemToInventory(Item item) { boolean fromEquip = false; synchronized (this) { //Skip if NOT in vault. if (item.containerType != mbEnums.ItemContainerType.VAULT) if (this.doesCharOwnThisItem(item.getObjectUUID()) == false) return false; // Only valid from bank, equip and vault if (!bankContains(item) && !equippedContains(item) && !vaultContains(item)) return false; if (equippedContains(item)) { fromEquip = true; if (item.template.item_type.equals(ItemType.GOLD)) this.absCharacter.cancelOnUnEquip(); } // remove it from other lists: this.remItemFromLists(item); // check to see what type of AbstractCharacter subclass we have stored if (this.absCharacter.getClass() == PlayerCharacter.class) { if (!item.moveItemToInventory((PlayerCharacter) this.absCharacter)) return false; } else if (!item.moveItemToInventory((NPC) this.absCharacter)) return false; // add to Inventory this.inventory.add(item); item.addToCache(); this.itemIDtoType.put(item.getObjectUUID(), item.getObjectType().ordinal()); calculateWeights(); } //Apply bonuses if from equip if (fromEquip && this.absCharacter != null) { this.absCharacter.applyBonuses(); if (this.absCharacter.getObjectType().equals(GameObjectType.PlayerCharacter)) this.absCharacter.incVer(); } return true; } public synchronized boolean moveItemToBank(Item i) { if (this.doesCharOwnThisItem(i.getObjectUUID()) == false) return false; // Item must be in inventory to move to bank if (!this.inventory.contains(i)) return false; // check to see what type of AbstractCharacter subclass we have stored if (this.absCharacter.getClass() == PlayerCharacter.class) { if (!i.moveItemToBank((PlayerCharacter) this.absCharacter)) return false; } else if (!i.moveItemToBank((NPC) this.absCharacter)) return false; // remove it from other lists: this.remItemFromLists(i); // add to Bank this.bank.add(i); i.addToCache(); calculateWeights(); return true; } public synchronized boolean moveGoldToBank(Item from, int amt) { if (from == null) return false; if (from.getNumOfItems() - amt < 0) return false; if (this.goldBank.getNumOfItems() + amt > MBServerStatics.BANK_GOLD_LIMIT) { if (this.absCharacter.getObjectType() == GameObjectType.PlayerCharacter) { PlayerCharacter pc = (PlayerCharacter) this.absCharacter; if (pc.getClientConnection() != null) ErrorPopupMsg.sendErrorPopup(pc, 202); return false; } } if (!DbManager.ItemQueries.MOVE_GOLD(from, this.getGoldBank(), amt)) return false; from.setNumOfItems(from.getNumOfItems() - amt); this.goldBank.setNumOfItems(this.goldBank.getNumOfItems() + amt); return true; } public synchronized boolean moveGoldToVault(Item from, int amt) { if (from == null) return false; if (from.getNumOfItems() - amt < 0) return false; if (!DbManager.ItemQueries.MOVE_GOLD(from, this.account.vaultGold, amt)) return false; from.setNumOfItems(from.getNumOfItems() - amt); this.account.vaultGold.setNumOfItems(this.goldVault.getNumOfItems() + amt); return true; } public synchronized boolean moveGoldToInventory(Item from, int amt) { if (from == null) return false; if (from.getNumOfItems() - amt < 0 || amt < 1) return false; if (this.goldInventory.getNumOfItems() + amt > MBServerStatics.PLAYER_GOLD_LIMIT) { if (this.absCharacter.getObjectType() == GameObjectType.PlayerCharacter) { PlayerCharacter pc = (PlayerCharacter) this.absCharacter; if (pc.getClientConnection() != null) ErrorPopupMsg.sendErrorPopup(pc, 202); return false; } } if (from instanceof MobLoot) { if (!DbManager.ItemQueries.UPDATE_GOLD(this.getGoldInventory(), this.goldInventory.getNumOfItems() + amt)) return false; } else if (!DbManager.ItemQueries.MOVE_GOLD(from, this.goldInventory, amt)) return false; from.setNumOfItems(from.getNumOfItems() - amt); this.goldInventory.setNumOfItems(this.goldInventory.getNumOfItems() + amt); return true; } //This is called by the addGold devCmd. public synchronized boolean addGoldToInventory(int amt, boolean fromDevCmd) { if (this.absCharacter == null || (!(this.absCharacter.getObjectType().equals(GameObjectType.PlayerCharacter)))) return false; if (this.getGoldInventory().getNumOfItems() + amt > MBServerStatics.PLAYER_GOLD_LIMIT) { return false; } if (this.getGoldInventory().getNumOfItems() + amt < 0) return false; boolean worked = DbManager.ItemQueries.UPDATE_GOLD(this.getGoldInventory(), this.goldInventory.getNumOfItems() + amt); if (worked) { //log this since it's technically a dupe. Only use on test server! if (fromDevCmd) { String logString = this.absCharacter.getName() + " added " + amt + " gold to their inventory"; Logger.info(logString); } this.goldInventory.setNumOfItems(this.goldInventory.getNumOfItems() + amt); } return worked; } //Used to trainsfer gold from one inventory to another, for steal, etc. public boolean transferGoldToMyInventory(AbstractCharacter tar, int amount) { if (tar == null) return false; CharacterItemManager tarCim = tar.charItemManager; if (tarCim == null) return false; if (this.getGoldInventory().getNumOfItems() + amount < 0) return false; if (this.getGoldInventory().getNumOfItems() + amount > MBServerStatics.PLAYER_GOLD_LIMIT) return false; if (tarCim.getGoldInventory().getNumOfItems() - amount < 0) return false; if (tarCim.getGoldInventory().getNumOfItems() - amount > MBServerStatics.PLAYER_GOLD_LIMIT) return false; synchronized (this) { synchronized (tarCim) { if (!tarCim.addGoldToInventory(0 - amount, false)) //remove gold from target return false; if (!addGoldToInventory(amount, false)) //add to this inventory return false; } } return true; } public synchronized boolean moveItemToVault(Item i) { // if (this.doesCharOwnThisItem(i.getObjectUUID()) == false) // return false; // Item must be in inventory to move to vault if (!this.inventory.contains(i)) return false; // check to see what type of AbstractCharacter subclass we have stored if (this.absCharacter.getClass() == PlayerCharacter.class) { if (!i.moveItemToVault(this.account)) return false; } else return false; // NPC's dont have vaults! // remove it from other lists: this.remItemFromLists(i); // add to Vault i.addToCache(); calculateWeights(); return true; } //Used for buying Item from NPC //Handles the gold transfer aspect // This removes ingame item from inventory for loot. private synchronized boolean removeItemFromInventory(Item i) { if (i.template.item_type.equals(ItemType.GOLD)) { if (i.getObjectUUID() != this.getGoldInventory().getObjectUUID()) return false; if (!DbManager.ItemQueries.UPDATE_GOLD(this.goldInventory, 0)) { return false; } } else { if (this.doesCharOwnThisItem(i.getObjectUUID()) == false) return false; if (this.inventory.contains(i)) { this.inventory.remove(i); this.itemIDtoType.remove(i.getObjectUUID()); return true; } } // tell client we're removing item updateInventory(i, false); return false; } // This adds item to inventory for loot. Validity checks already handled public synchronized boolean addItemToInventory(Item i) { if (i.template.item_type.equals(ItemType.GOLD)) if (this.absCharacter.getObjectType() == GameObjectType.Mob) { if (this.goldInventory == null) loadGoldItems(); this.goldInventory.setNumOfItems(this.goldInventory.getNumOfItems() + i.getNumOfItems()); } else { int amt = i.getNumOfItems(); if (DbManager.ItemQueries.UPDATE_GOLD(this.goldInventory, this.goldInventory.getNumOfItems() + amt)) { updateInventory(); return true; } return false; } this.inventory.add(i); this.itemIDtoType.put(i.getObjectUUID(), i.getObjectType().ordinal()); if (i.template != null) this.inventoryWeight += i.template.item_wt; return true; } //called for adding gold of a specified amount public synchronized boolean addItemToInventory(Item i, int amount) { if (i.template.item_type.equals(ItemType.GOLD)) return DbManager.ItemQueries.UPDATE_GOLD(this.getGoldInventory(), this.goldInventory.getNumOfItems() + amount); return false; } public boolean equipItem(Item i, mbEnums.EquipSlotType slot) { synchronized (this) { if (this.doesCharOwnThisItem(i.getObjectUUID()) == false && this.absCharacter.getObjectType() != GameObjectType.Mob) { Logger.error("Doesnt own item"); return false; } // Item must be in inventory to equip if (!this.inventory.contains(i) && this.absCharacter.getObjectType() != GameObjectType.Mob) return false; if (!ItemManager.canEquip(slot, this, absCharacter, i) && this.absCharacter.getObjectType() != GameObjectType.Mob) return false; // check to see if item is already there. Item old = this.equipped.get(slot); if (old != null) { Logger.error("already equipped"); return false; } // check to see what type of AbstractCharacter subclass we have stored if (this.absCharacter.getClass() == PlayerCharacter.class) { if (!i.equipItem((PlayerCharacter) this.absCharacter, slot)) return false; } else if (this.absCharacter.getObjectType() == GameObjectType.Mob) { if (!i.equipItem((Mob) this.absCharacter, slot)) { Logger.error("Failed to set Equip"); return false; } } else if (!i.equipItem((NPC) this.absCharacter, slot)) return false; // remove it from other lists: this.remItemFromLists(i); // add to Equipped this.equipped.put(slot, i); i.addToCache(); //calculateWeights(); } //Apply Bonuses and update player if (this.absCharacter != null) { this.absCharacter.applyBonuses(); if (this.absCharacter.getObjectType().equals(GameObjectType.PlayerCharacter)) this.absCharacter.incVer(); } return true; } public synchronized boolean buyFromNPC(Building vendorBuilding, int cost, int buildingDeposit) { Item gold = this.getGoldInventory(); if (cost <= 0 || (gold.getNumOfItems() - cost) < 0) return false; if (this.getOwner() != null && this.getOwner().getObjectType().equals(GameObjectType.PlayerCharacter)) { if (this.goldTradingAmount > 0) { ErrorPopupMsg.sendErrorPopup((PlayerCharacter) this.getOwner(), 195); return false; } } // Create gold from screatch instead of building strongbox // if the NPC is not slotted. if (vendorBuilding == null) { return this.modifyInventoryGold(-cost); } if (vendorBuilding.getStrongboxValue() + cost > vendorBuilding.getMaxGold()) { if (this.absCharacter.getObjectType() == GameObjectType.PlayerCharacter) { PlayerCharacter pc = (PlayerCharacter) this.absCharacter; if (pc.getClientConnection() != null) ErrorPopupMsg.sendErrorPopup(pc, 206); } return false; } // Update strongbox and inventory gold if (!this.modifyInventoryGold(-cost)) return false; City buildingCity = vendorBuilding.getCity(); if (buildingCity != null) { buildingCity.transactionLock.writeLock().lock(); try { if (!vendorBuilding.transferGold(buildingDeposit, true)) return false; } catch (Exception e) { Logger.error(e); return false; } finally { buildingCity.transactionLock.writeLock().unlock(); } } else return vendorBuilding.transferGold(buildingDeposit, true); return true; } //Used for selling items to NPC public synchronized boolean sellToNPC(Building building, int cost, Item item) { // Create gold from screatch instead of building strongbox // if the NPC is not slotted. if (this.getGoldInventory().getNumOfItems() + cost < 0) return false; if (this.getGoldInventory().getNumOfItems() + cost > MBServerStatics.PLAYER_GOLD_LIMIT) return false; if (this.getOwner().charItemManager.getGoldTrading() > 0) { if (this.getOwner().getObjectType().equals(GameObjectType.PlayerCharacter)) ErrorPopupMsg.sendErrorPopup((PlayerCharacter) this.getOwner(), 195); return false; } if (building == null) { return this.modifyInventoryGold(cost); } //make sure strongbox can afford gold. if (!building.hasFunds(cost)) return false; if ((building.getStrongboxValue() - cost) < 0) return false; // Update strongbox and inventory gold if (!building.transferGold(-cost, false)) return false; return this.modifyInventoryGold(cost); } /** * This sells an item to an npc * * @return True on success */ public synchronized boolean sellToNPC(Item itemToSell, NPC npc) { CharacterItemManager itemMan; if (itemToSell == null || npc == null) return false; itemMan = npc.charItemManager; if (itemMan == null) return false; //test npc inventory is not full synchronized (this) { synchronized (itemMan) { if (!this.doesCharOwnThisItem(itemToSell.getObjectUUID())) return false; // attempt to transfer item in db boolean eatItem = false; // SDR vendors and potions are not resold if (npc.getContractID() >= 1900 && npc.getContractID() <= 1906) eatItem = true; if (itemToSell.template.item_type.equals(ItemType.POTION)) eatItem = true; if (eatItem) { this.delete(itemToSell); this.updateInventory(); } else if (!itemToSell.moveItemToInventory(npc)) return false; // skip this check if this is a mobLoot item (which is not in any inventory) if (!eatItem) if (!removeItemFromInventory(itemToSell)) return false; // add item to vendor if (!eatItem) if (!itemMan.addItemToInventory(itemToSell)) return false; } } // calculate new weights calculateInventoryWeight(); itemMan.calculateInventoryWeight(); return true; } /** * This buys an item from an npc * Handles transfer of item. * * @return True on success */ public synchronized boolean buyFromNPC(Item purchasedItem, NPC npc) { CharacterItemManager itemMan; if (purchasedItem == null || npc == null) return false; itemMan = npc.charItemManager; if (itemMan == null) return false; synchronized (this) { synchronized (itemMan) { ItemTemplate template = purchasedItem.template; if (template == null) return false; //test inventory is not full if (!hasRoomInventory(template.item_wt)) return false; if (!itemMan.inventory.contains(purchasedItem)) return false; // attempt to transfer item in db if (purchasedItem.getObjectType() == GameObjectType.MobLoot) { Item newItem = ((MobLoot) purchasedItem).promoteToItem((PlayerCharacter) this.absCharacter); if (newItem == null) return false; if (!itemMan.removeItemFromInventory(purchasedItem)) return false; if (!addItemToInventory(newItem)) return false; //Item was created and still a mobloot item, remove from npc production list in db. DbManager.NPCQueries.REMOVE_FROM_PRODUCTION_LIST(purchasedItem.getObjectUUID(), npc.getObjectUUID()); } else { if (!purchasedItem.moveItemToInventory((PlayerCharacter) this.absCharacter)) return false; // Reset value purchasedItem.value = (int) (purchasedItem.template.item_value * (purchasedItem.combat_health_current / purchasedItem.template.combat_health_full)); // db transfer successfully, remove from this character // skip this check if this is a mobLoot item (which is not in any inventory) if (!itemMan.removeItemFromInventory(purchasedItem)) return false; // add item to looter. if (!addItemToInventory(purchasedItem)) return false; } } } // calculate new weights calculateInventoryWeight(); itemMan.calculateInventoryWeight(); return true; } /** * Loot an item from an AbstractCharacter. Call this function on * the CharacterItemManager of the current item owner, not the looter. * This method will verify that the looter can receive the item * (e.g. inventory isn't full). * * @param i Item being looted * @param looter Player looting the item * @param origin ClientConnection * @return True on success */ public synchronized Item lootItemFromMe(Item i, PlayerCharacter looter, ClientConnection origin) { return lootItemFromMe(i, looter, origin, false, -1); } //This function is used for both looting and stealing public synchronized Item lootItemFromMe(Item lootItem, PlayerCharacter lootingPlayer, ClientConnection origin, boolean fromSteal, int amount) { //TODO this function should have more logging // make sure lootingPlayer exists if (lootingPlayer == null) return null; // get looters item manager CharacterItemManager looterItems = lootingPlayer.charItemManager; if (looterItems == null) return null; if (fromSteal) { if (!this.absCharacter.isAlive()) return null; } else if (!this.absCharacter.canBeLooted()) return null; MobLoot mobLoot = null; if (lootItem instanceof MobLoot) { mobLoot = (MobLoot) lootItem; if (mobLoot.isDeleted()) return null; } //Lock both ItemManagers; lower ID first CharacterItemManager lockFirst; CharacterItemManager lockSecond; if (this.absCharacter.getObjectUUID() < looterItems.absCharacter.getObjectUUID()) { lockFirst = this; lockSecond = looterItems; } else { lockFirst = looterItems; lockSecond = this; } synchronized (lockFirst) { synchronized (lockSecond) { // make sure current player has item in inventory if (lootItem.template.item_type.equals(ItemType.GOLD) && lootItem.getObjectUUID() != this.getGoldInventory().getObjectUUID() && !(this.absCharacter.getObjectType().equals(GameObjectType.Mob))) return null; else if (!this.inventory.contains(lootItem) && !this.equipped.containsValue(lootItem) && !lootItem.template.item_type.equals(ItemType.GOLD)) return null; // get weight of item if (lootItem.template == null) return null; int weight = lootItem.template.item_wt; // make sure lootingPlayer has room for item if (!lootItem.template.item_type.equals(ItemType.GOLD) && !looterItems.hasRoomInventory(weight)) return null; if (lootItem.template.item_type.equals(ItemType.GOLD)) if (amount != -1) { //from steal int total = lootItem.getNumOfItems(); amount = (amount > total) ? total : amount; if (!looterItems.moveGoldToInventory(lootItem, amount)) return null; if (mobLoot != null && amount == total) this.delete(mobLoot); } else { //from loot if (!looterItems.moveGoldToInventory(lootItem, lootItem.getNumOfItems())) return null; if (mobLoot != null) // delete mobloot after it has been looted this.delete(mobLoot); } else { //not Gold item boolean created = false; if (mobLoot != null) { lootItem = mobLoot.promoteToItem(lootingPlayer); // delete mobloot after it has been looted this.delete(mobLoot); if (lootItem == null) return null; created = true; } // attempt to transfer item in db if (!lootItem.moveItemToInventory(lootingPlayer)) return null; // db transfer successfull, remove from this character // skip this check if this is a mobLoot item (which is not in any inventory) if (mobLoot == null) if (!removeItemFromInventory(lootItem)) return null; // add item to lootingPlayer. if (!looterItems.addItemToInventory(lootItem)) return null; } } } // calculate new weights calculateInventoryWeight(); looterItems.calculateInventoryWeight(); return lootItem; } private synchronized void remItemFromLists(Item item) { this.equipped.remove(item.equipSlot); this.vault.remove(item); this.bank.remove(item); this.inventory.remove(item); } /* * Delegates */ public synchronized boolean bankContains(Item item) { if (item.template.item_type.equals(ItemType.GOLD)) return (this.getGoldBank() != null && this.goldBank.getObjectUUID() == item.getObjectUUID()); return bank.contains(item); } public synchronized boolean inventoryContains(Item item) { if (item.template.item_type.equals(ItemType.GOLD)) return (this.getGoldInventory() != null && this.goldInventory.getObjectUUID() == item.getObjectUUID()); return inventory.contains(item); } public synchronized boolean vaultContains(Item item) { if (item.template.item_type.equals(ItemType.GOLD)) return (this.getGoldVault() != null && this.goldVault.getObjectUUID() == item.getObjectUUID()); return this.account.getVault().contains(item); } public synchronized boolean equippedContains(Item i) { return equipped.containsValue(i); } public synchronized Item getItemFromEquipped(mbEnums.EquipSlotType slot) { return equipped.get(slot); } public synchronized Item getItemByUUID(int objectUUID) { if (this.itemIDtoType.containsKey(objectUUID)) { Integer integer = this.itemIDtoType.get(objectUUID); if (integer == GameObjectType.Item.ordinal()) { return Item.getFromCache(objectUUID); } else if (integer == GameObjectType.MobLoot.ordinal()) { return MobLoot.getFromCache(objectUUID); } } if (this.getGoldInventory() != null && this.goldInventory.getObjectUUID() == objectUUID) return this.goldInventory; if (this.getGoldBank() != null && this.goldBank.getObjectUUID() == objectUUID) return this.goldBank; if (this.getGoldVault() != null && this.goldVault.getObjectUUID() == objectUUID) return this.goldVault; return null; } public boolean tradingContains(Item i) { if (this.trading == null || i == null) return false; return this.trading.contains(i.getObjectUUID()); } public boolean isBankOpen() { return this.bankOpened; } public synchronized void setBankOpen(boolean bankOpened) { this.bankOpened = bankOpened; } public boolean isVaultOpen() { return this.vaultOpened; } public synchronized void setVaultOpen(boolean vaultOpened) { this.vaultOpened = vaultOpened; } public ClientConnection getTradingWith() { return tradingWith; } public synchronized void setTradingWith(ClientConnection tradingWith) { this.tradingWith = tradingWith; } public synchronized void clearTradingWith() { this.tradingWith = null; } public int getGoldTrading() { return goldTradingAmount; } public byte getTradeCommitted() { return tradeCommitted; } public synchronized void setTradeCommitted(byte tradeCommitted) { this.tradeCommitted = tradeCommitted; } public HashSet getTrading() { return trading; } /* * List Copiers */ public synchronized void addItemToTrade(Item i) { this.trading.add(i.getObjectUUID()); } public boolean getTradeSuccess() { return tradeSuccess; } public synchronized void setTradeSuccess(boolean tradeSuccess) { this.tradeSuccess = tradeSuccess; } public synchronized boolean RemoveEquipmentFromLackOfSkill(PlayerCharacter pc, boolean initialized) { if (pc == null) return false; if (this.equipped == null) return false; for (mbEnums.EquipSlotType slot : this.equipped.keySet()) { if (slot == mbEnums.EquipSlotType.HAIR || slot == mbEnums.EquipSlotType.BEARD) continue; Item item = this.equipped.get(slot); if (item == null) { this.equipped.remove(slot); pc.applyBonuses(); continue; } if (!ItemManager.validForSkills(item, pc.getSkills())) { this.forceToInventory(slot, item, pc, initialized); pc.applyBonuses(); } } return true; } /** * Note that this method returns a copy of the internally stored * list. * * @return the equipped */ public ConcurrentHashMap getEquipped() { synchronized (this.equipped) { return new ConcurrentHashMap<>(this.equipped); } } public Item getEquipped(mbEnums.EquipSlotType slot) { synchronized (this.equipped) { return this.equipped.get(slot); } } /** * Note that this method returns a copy of the internally stored * list. * * @return the inventory */ public ArrayList getInventory() { return getInventory(false); } public ArrayList getInventory(boolean sendGold) { synchronized (this.inventory) { ArrayList ret = new ArrayList<>(this.inventory); if (sendGold && this.getGoldInventory() != null && this.goldInventory.getNumOfItems() > 0) ret.add(this.goldInventory); return ret; } } public int getInventoryCount() { synchronized (this.inventory) { return this.inventory.size(); } } /** * Clears ownership of items. Called when player dies, but before * respawning. * * @return the inventory */ public synchronized void orphanInventory() { PlayerCharacter pc = null; if (this.absCharacter != null && this.absCharacter.getObjectType().equals(GameObjectType.PlayerCharacter)) pc = (PlayerCharacter) this.absCharacter; synchronized (this.inventory) { //dupe check, validate player properly owns all items if (pc != null) { Iterator iter = this.inventory.iterator(); while (iter.hasNext()) { Item item = iter.next(); //this call may remove the item from this.inventory if (!item.validForInventory(pc.getClientConnection(), pc, this)) { } } } if (this.inventory.size() > 0) DbManager.ItemQueries.ORPHAN_INVENTORY(this.inventory); //make a copy of gold inventory for looting //so we don't remove the goldInventory if (this.getGoldInventory().getNumOfItems() > 0) { int amt = this.goldInventory.getNumOfItems(); if (DbManager.ItemQueries.UPDATE_GOLD(this.goldInventory, 0)) { this.goldInventory.setNumOfItems(0); MobLoot gold = new MobLoot(this.absCharacter, amt); this.inventory.add(gold); } } } } /** * This transfers the entire inventory to another list For populating * corpse' inventory when player dies * * @return the inventory */ public synchronized void transferEntireInventory( ArrayList newInventory, Corpse corpse, boolean enterWorld) { PlayerCharacter pc = null; if (this.absCharacter != null && this.absCharacter.getObjectType().equals(GameObjectType.PlayerCharacter)) pc = (PlayerCharacter) this.absCharacter; if (this.getGoldInventory().getNumOfItems() > 0) { int amt = this.goldInventory.getNumOfItems(); if (DbManager.ItemQueries.UPDATE_GOLD(this.goldInventory, 0)) { this.goldInventory.setNumOfItems(0); MobLoot gold = new MobLoot(this.absCharacter, amt); newInventory.add(gold); } } for (Item item : this.inventory) { if (item != null) if (item instanceof MobLoot) { //MobLoot item.zeroItem(); item.containerType = mbEnums.ItemContainerType.INVENTORY; if (item.template.item_type.equals(ItemType.GOLD)) //only add gold item once if (!corpse.hasGold()) corpse.setHasGold(true); newInventory.add(item); } else //item if (item.template.item_type.equals(ItemType.GOLD)) { int amt = item.getNumOfItems(); item.setNumOfItems(0); MobLoot ml = new MobLoot(this.absCharacter, amt); ml.zeroItem(); ml.containerType = mbEnums.ItemContainerType.INVENTORY; if (!corpse.hasGold()) { corpse.setHasGold(true); newInventory.add(ml); } } else { boolean transferred = item.moveItemToInventory(corpse); if (!transferred) Logger.error( "CharItemManager.transferEntireInvetory", "DB Error, Failed to transfer item " + item.getObjectUUID() + " to new owner " + corpse.getObjectUUID()); newInventory.add(item); } } // tell client we're clearing inventory // clear the inventory. this.inventory.clear(); //re-calculate inventory weight calculateInventoryWeight(); if (!enterWorld) updateInventory(this.getInventory(), false); } /** * Note that this method returns a copy of the internally stored * list. * * @return the bank */ public ArrayList getBank() { synchronized (this.bank) { ArrayList ret = new ArrayList<>(this.bank); if (this.getGoldBank() != null && this.goldBank.getNumOfItems() > 0) ret.add(this.goldBank); return ret; } } /** * Note that this method returns a copy of the internally stored * list. * * @return the vault */ public ArrayList getVault() { synchronized (this.vault) { ArrayList ret = new ArrayList<>(this.vault); if (this.getGoldVault() != null && this.goldVault.getNumOfItems() > 0) ret.add(this.goldVault); return ret; } } public boolean hasRoomInventory(int weight) { if (this.absCharacter == null) return false; if (this.absCharacter.getObjectType() == GameObjectType.PlayerCharacter) { PlayerCharacter pc = (PlayerCharacter) this.absCharacter; int newWeight = this.getCarriedWeight() + weight; return newWeight <= (int) pc.statStrBase * 3; } else if (this.absCharacter.getObjectType() == GameObjectType.NPC) { int newWeight = this.getCarriedWeight() + weight; return newWeight <= 1900 + (this.absCharacter.getLevel() * 3); } else return true; // npc's need checked } public boolean hasRoomTrade(int itemWeight) { PlayerCharacter playerCharacter; PlayerCharacter tradeCharacter; int tradeWeight; if (this.absCharacter == null) return false; if (this.absCharacter.getObjectType().equals(GameObjectType.PlayerCharacter) == false) return false; playerCharacter = (PlayerCharacter) this.absCharacter; if ((this.tradingWith == null) || (this.tradingWith.isConnected() == false)) return false; tradeCharacter = this.tradingWith.getPlayerCharacter(); tradeWeight = this.getCarriedWeight() + itemWeight; tradeWeight = tradeWeight + tradeCharacter.charItemManager.getTradingWeight(); tradeWeight = tradeWeight - this.getTradingWeight(); return tradeWeight <= (int) playerCharacter.statStrBase * 3; } public boolean hasRoomBank(int weight) { if (this.absCharacter == null) return false; return weight <= this.absCharacter.getBankCapacityRemaining(); } public boolean hasRoomVault(int weight) { if (this.absCharacter == null) return false; return weight <= this.absCharacter.getVaultCapacityRemaining(); } public int getCarriedWeight() { return getInventoryWeight() + getEquipWeight(); } public int getInventoryWeight() { return this.inventoryWeight; } public int getBankWeight() { return this.bankWeight; } public int getEquipWeight() { return this.equipWeight; } public int getVaultWeight() { return this.vaultWeight; } public int getTradingWeight() { int weight = 0; Item item; for (int i : this.trading) { item = Item.getFromCache(i); if (item == null) continue; weight += item.template.item_wt; } return weight; } public AbstractCharacter getOwner() { return this.absCharacter; } public void calculateWeights() { calculateBankWeight(); calculateInventoryWeight(); calculateEquipWeight(); calculateVaultWeight(); } public void calculateBankWeight() { this.bankWeight = 0; for (Item item : this.bank) { if (item.template != null) this.bankWeight += item.template.item_wt; } } public void calculateEquipWeight() { this.equipWeight = 0; Collection c = this.equipped.values(); Iterator it = c.iterator(); while (it.hasNext()) { Item item = it.next(); if (item.template != null) this.equipWeight += item.template.item_wt; } } public void calculateInventoryWeight() { this.inventoryWeight = 0; for (Item item : this.inventory) { if (item.template != null) this.inventoryWeight += item.template.item_wt; } } public void calculateVaultWeight() { this.vaultWeight = 0; for (Item item : this.vault) { if (item.template != null) this.vaultWeight += item.template.item_wt; } } public void updateInventory(Item item, boolean add) { ArrayList list = new ArrayList<>(); list.add(item); updateInventory(list, add); } private void updateInventory(ArrayList inventory, boolean add) { if (this.absCharacter == null) return; if (this.absCharacter.getObjectType().equals(GameObjectType.PlayerCharacter) == false) return; PlayerCharacter pc = (PlayerCharacter) this.absCharacter; UpdateInventoryMsg updateInventoryMsg = new UpdateInventoryMsg(inventory, this.getBank(), this.getGoldInventory(), add); Dispatch dispatch = Dispatch.borrow(pc, updateInventoryMsg); DispatchMessage.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.SECONDARY); } public void forceToInventory(mbEnums.EquipSlotType slot, Item item, PlayerCharacter player, boolean initialized) { if (item == null || player == null) return; if (!item.moveItemToInventory(player)) Logger.error("templateL " + item.template.template_id); // remove it from other lists: this.remItemFromLists(item); // add to Inventory this.inventory.add(item); item.addToCache(); calculateWeights(); //Update players with unequipped item if (initialized) { TransferItemFromEquipToInventoryMsg back = new TransferItemFromEquipToInventoryMsg(player, slot); DispatchMessage.dispatchMsgToInterestArea(player, back, mbEnums.DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, true, false); } } /** * Update the player's inventory window by resending the entire contents. */ public void updateInventory() { this.updateInventory(this.getInventory(), true); } public synchronized void initializeTrade() { this.trading = new HashSet<>(); } public synchronized boolean commitTrade() { int goldFrom1 = 0; int goldFrom2 = 0; if (this.getTradingWith() == null || this.getTradingWith().isConnected() == false || this.getTradingWith().getPlayerCharacter() == null) { this.endTrade(); return false; } CharacterItemManager tradingWith = this.getTradingWith().getPlayerCharacter().charItemManager; if (tradingWith == null) return false; if (this.goldTradingAmount != 0) { if (tradingWith.goldInventory == null) { Logger.error("Null Gold for player " + this.getOwner().getObjectUUID()); return false; } goldFrom1 = this.goldTradingAmount; } if (tradingWith.goldTradingAmount != 0) { if (this.getGoldInventory() == null) { Logger.error("Null Gold for player " + this.getOwner().getObjectUUID()); return false; } goldFrom2 = tradingWith.goldTradingAmount; } if (this.getGoldInventory().getNumOfItems() + goldFrom2 > 10000000) { PlayerCharacter pc = (PlayerCharacter) this.absCharacter; if (pc.getClientConnection() != null) ErrorPopupMsg.sendErrorPopup(pc, 202); return false; } if (tradingWith.getGoldInventory().getNumOfItems() + goldFrom1 > 10000000) { PlayerCharacter pc = (PlayerCharacter) tradingWith.absCharacter; if (pc.getClientConnection() != null) ErrorPopupMsg.sendErrorPopup(pc, 202); return false; } if (this.trading.size() > 0 || tradingWith.trading.size() > 0 || goldFrom1 > 0 || goldFrom2 > 0) { if (!DbManager.ItemQueries.DO_TRADE(this.trading, tradingWith.trading, this, tradingWith, this.goldInventory, tradingWith.goldInventory, goldFrom1, goldFrom2)) return false; } else return true; for (int i : this.trading) { Item item = Item.getFromCache(i); if (item == null) continue; this.trade(item); tradingWith.tradeForItem(item); } for (int i : tradingWith.trading) { Item item = Item.getFromCache(i); if (item == null) continue; tradingWith.trade(item); this.tradeForItem(item); } //subtract gold your trading from your inventory. if (this.goldTradingAmount > 0) this.getGoldInventory().setNumOfItems(this.getGoldInventory().getNumOfItems() - this.goldTradingAmount); //subtract gold your trading from your inventory. if (tradingWith.goldTradingAmount > 0) tradingWith.getGoldInventory().setNumOfItems(tradingWith.getGoldInventory().getNumOfItems() - tradingWith.goldTradingAmount); if (tradingWith.goldTradingAmount > 0) this.getGoldInventory().setNumOfItems(this.goldInventory.getNumOfItems() + tradingWith.goldTradingAmount); if (this.goldTradingAmount > 0) tradingWith.getGoldInventory().setNumOfItems(tradingWith.goldInventory.getNumOfItems() + this.goldTradingAmount); this.tradeSuccess = true; tradingWith.tradeSuccess = true; return true; } public synchronized void endTrade() { updateInventory(this.getInventory(), true); this.tradeCommitted = (byte) 0; this.tradeSuccess = false; this.tradingWith = null; this.trading = null; this.goldTradingAmount = 0; this.tradeID = 0; } public synchronized void endTrade(boolean fromDeath) { this.tradeCommitted = (byte) 0; this.tradeSuccess = false; this.tradingWith = null; this.trading = null; this.goldTradingAmount = 0; } // Remove item from your possession private synchronized boolean trade(Item i) { if (this.doesCharOwnThisItem(i.getObjectUUID()) == false) return false; // Only valid from inventory if (!inventoryContains(i)) return false; // remove from Inventory this.inventory.remove(i); this.itemIDtoType.remove(i.getObjectUUID()); i.setOwnerID(0); calculateWeights(); return true; } //Damage an equipped item a specified amount public void damageItem(Item item, int amount) { if (item == null || amount < 1 || amount > 5) return; //verify the item is equipped by this player mbEnums.EquipSlotType slot = item.equipSlot; if (!this.equipped.containsKey(slot)) return; Item verify = this.equipped.get(slot); if (verify == null || item.getObjectUUID() != verify.getObjectUUID()) return; //don't damage noob gear, hair or beards. if (item.template.combat_health_full == 0) return; if (!item.isCanDestroy()) return; int dur = (int) (short) item.combat_health_current; if (dur - amount <= 0) { //destroy the item junk(item); //TODO remove item from the client //This may not be correct dur = 0; } else { dur -= amount; if (!DbManager.ItemQueries.SET_DURABILITY(item, dur)) return; item.setCombat_health_current((short) dur); } if (this.absCharacter.getObjectType().equals(GameObjectType.PlayerCharacter) == false) return; //send damage item msg to client PlayerCharacter pc = (PlayerCharacter) this.absCharacter; ItemHealthUpdateMsg itemHealthUpdateMsg = new ItemHealthUpdateMsg(slot.ordinal(), (float) dur); Dispatch dispatch = Dispatch.borrow(pc, itemHealthUpdateMsg); DispatchMessage.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.SECONDARY); } //Damage all equipped gear a random amount between 1 and 5 public void damageAllGear() { for (Item gear : this.equipped.values()) { damageItem(gear, (ThreadLocalRandom.current().nextInt(5) + 1)); } } // Add item to your possession public synchronized boolean tradeForItem(Item i) { // add to Inventory this.inventory.add(i); this.itemIDtoType.put(i.getObjectUUID(), i.getObjectType().ordinal()); i.setOwnerID(this.absCharacter.getObjectUUID()); calculateWeights(); return true; } public synchronized boolean addGoldToTrade(int amount) { if (this.goldTradingAmount + amount > MBServerStatics.PLAYER_GOLD_LIMIT) return false; this.goldTradingAmount += amount; return true; } /** * Completely empties inventory, deleting any items. Use with caution! */ public synchronized void clearInventory() { this.getGoldInventory().setNumOfItems(0); Iterator ii = this.inventory.iterator(); while (ii.hasNext()) { Item itm = ii.next(); ii.remove(); this.delete(itm); } } public synchronized void clearEquip() { this.equipped.clear(); } public int getTradeID() { return tradeID; } public synchronized boolean closeTradeWindow() { if (this.getTradingWith() != null || this.getTradeID() != 0) this.closeTradeWindow(new CloseTradeWindowMsg(this.getOwner(), this.getTradeID()), true); return true; } }