Files
Server/src/engine/objects/CharacterItemManager.java
T
MagicBotandClaude Opus 5.5 6b4e9815e0 Switch Item.template and MobLoot to CObjectTemplate
Item.template is now the cache template from CObjectTemplate.lookup
instead of the legacy DB ItemTemplate, so item.template.cacheTemplate.X
becomes item.template.X. MobLoot, LootManager, ItemManager.isTwoHanded/
isShield and CombatManager.getSwingAnimation take a CObjectTemplate.

No value changes: every getter already read the cache template through
the bridge, and the lookup resolves the same 7586 ids as
static_item_templates with the same item_type (offline parity p17.py,
0 differences).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 07:55:28 -04:00

2030 lines
68 KiB
Java

// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
// Magicbane Emulator Project © 2013 - 2026
// https://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.client.ClientConnection;
import engine.net.client.msg.*;
import engine.parsers.objects.CObjectTemplate;
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<Integer, Integer> 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<mbEnums.EquipSlotType, Item> equipped = new ConcurrentHashMap<>(MBServerStatics.CHM_INIT_CAP, MBServerStatics.CHM_LOAD, MBServerStatics.CHM_THREAD_LOW);
private final HashSet<Item> inventory = new HashSet<>();
private final HashSet<Item> bank = new HashSet<>();
private final HashSet<Item> 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<Integer> 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<Item> 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.getItemType().equals(ItemType.GOLD))
this.goldBank = i;
else if (this.bank.contains(i) == false)
this.bank.add(i);
break;
case INVENTORY:
if (i.template.getItemType().equals(ItemType.GOLD))
this.goldInventory = i;
else if (this.inventory.contains(i) == false)
this.inventory.add(i);
break;
case VAULT:
if (i.template.getItemType().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<Item> 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.getItemType().equals(ItemType.GOLD))
this.goldBank = i;
else if (this.bank.contains(i) == false)
this.bank.add(i);
break;
case INVENTORY:
if (i.template.getItemType().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);
DispatchManager.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.SECONDARY);
return success;
}
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);
DispatchManager.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);
DispatchManager.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.SECONDARY);
dispatch = Dispatch.borrow((PlayerCharacter) man2.getOwner(), modify);
DispatchManager.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);
DispatchManager.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.getItemType().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.getItemType().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.getItemType().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.getItemType().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.getItemType().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.getItemWt();
return true;
}
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 scratch 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);
}
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.getItemType().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;
}
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) {
CObjectTemplate template = purchasedItem.template;
if (template == null)
return false;
//test inventory is not full
if (!hasRoomInventory(template.getItemWt()))
return false;
if (!itemMan.inventory.contains(purchasedItem))
return false;
// attempt to transfer item in db
if (!purchasedItem.moveItemToInventory((PlayerCharacter) this.absCharacter))
return false;
// Reset value
purchasedItem.value = (int) (purchasedItem.template.getItemValue() * (purchasedItem.combat_health_current / purchasedItem.template.getCombatHealthFull()));
purchasedItem.magicValue = purchasedItem.template.getItemValue() + purchasedItem.calcMagicValue();
// 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.getItemType().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.getItemType().equals(ItemType.GOLD))
return null;
// get weight of item
if (lootItem.template == null)
return null;
int weight = lootItem.template.getItemWt();
// make sure lootingPlayer has room for item
if (!lootItem.template.getItemType().equals(ItemType.GOLD) && !looterItems.hasRoomInventory(weight))
return null;
if (lootItem.template.getItemType().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.getItemType().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.getItemType().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.getItemType().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<Integer> 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);
this.equipped.remove(slot);
pc.applyBonuses();
}
}
return true;
}
/**
* Note that this method returns a <b>copy</b> of the internally stored
* list.
*
* @return the equipped
*/
public ConcurrentHashMap<mbEnums.EquipSlotType, Item> 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 <b>copy</b> of the internally stored
* list.
*
* @return the inventory
*/
public ArrayList<Item> getInventory() {
return getInventory(false);
}
public ArrayList<Item> getInventory(boolean sendGold) {
synchronized (this.inventory) {
ArrayList<Item> 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<Item> 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<Item> 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.getItemType().equals(ItemType.GOLD))
//only add gold item once
if (!corpse.hasGold())
corpse.setHasGold(true);
newInventory.add(item);
} else //item
if (item.template.getItemType().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 <b>copy</b> of the internally stored
* list.
*
* @return the bank
*/
public ArrayList<Item> getBank() {
synchronized (this.bank) {
ArrayList<Item> 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 <b>copy</b> of the internally stored
* list.
*
* @return the vault
*/
public ArrayList<Item> getVault() {
synchronized (this.vault) {
ArrayList<Item> 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.getItemWt();
}
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.getItemWt();
}
}
public void calculateEquipWeight() {
this.equipWeight = 0;
Collection<Item> c = this.equipped.values();
Iterator<Item> it = c.iterator();
while (it.hasNext()) {
Item item = it.next();
if (item.template != null)
this.equipWeight += item.template.getItemWt();
}
}
public void calculateInventoryWeight() {
this.inventoryWeight = 0;
for (Item item : this.inventory) {
if (item.template != null)
this.inventoryWeight += item.template.getItemWt();
}
}
public void calculateVaultWeight() {
this.vaultWeight = 0;
for (Item item : this.vault) {
if (item.template != null)
this.vaultWeight += item.template.getItemWt();
}
}
public void updateInventory(Item item, boolean add) {
ArrayList<Item> list = new ArrayList<>();
list.add(item);
updateInventory(list, add);
}
private void updateInventory(ArrayList<Item> 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);
DispatchManager.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.getTemplateId());
// 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);
DispatchManager.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.getCombatHealthFull() == 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);
DispatchManager.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<Item> 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;
}
}