// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . // ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· // ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ // ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ // ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ // Magicbane Emulator Project © 2013 - 2022 // www.magicbane.com package engine.objects; import engine.Enum; import engine.Enum.*; import engine.exception.SerializationException; import engine.gameManager.ConfigManager; import engine.gameManager.DbManager; import engine.gameManager.PowersManager; import engine.net.ByteBufferReader; import engine.net.ByteBufferWriter; import engine.net.Dispatch; import engine.net.DispatchMessage; import engine.net.client.ClientConnection; import engine.net.client.msg.DeleteItemMsg; import engine.powers.EffectsBase; import engine.powers.effectmodifiers.AbstractEffectModifier; import engine.powers.poweractions.AbstractPowerAction; import engine.server.MBServerStatics; import org.pmw.tinylog.Logger; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.locks.ReentrantLock; public class Item extends AbstractWorldObject { private static ConcurrentHashMap enchantValues = new ConcurrentHashMap<>(MBServerStatics.CHM_INIT_CAP, MBServerStatics.CHM_LOAD, MBServerStatics.CHM_THREAD_LOW); private final short durabilityMax; private final byte chargesMax; private final ConcurrentHashMap bonuses = new ConcurrentHashMap<>(MBServerStatics.CHM_INIT_CAP, MBServerStatics.CHM_LOAD, MBServerStatics.CHM_THREAD_LOW); private final ArrayList effectNames = new ArrayList<>(); public Enum.ItemContainerType containerType; public ReentrantLock lootLock = new ReentrantLock(); private int ownerID; //may be character, account, npc, mob private int flags; //1 = isIDed private int numberOfItems; private short durabilityCurrent; private byte chargesRemaining; private byte equipSlot; private boolean canDestroy; private boolean rentable; private boolean isRandom = false; private int value; private OwnerType ownerType; private int itemBaseID; private AbstractWorldObject lastOwner; private ArrayList enchants = new ArrayList<>(); private long dateToUpgrade; private String customName = ""; public int magicValue; /** * No Id Constructor */ public Item(ItemBase itemBase, int ownerID, OwnerType ownerType, byte chargesMax, byte chargesRemaining, short durabilityCurrent, short durabilityMax, boolean canDestroy, boolean rentable, Enum.ItemContainerType containerType, byte equipSlot, ArrayList enchants, String name) { super(); this.itemBaseID = itemBase.getUUID(); this.ownerID = ownerID; this.ownerType = ownerType; if (itemBase.getType().getValue() == 20) { this.chargesMax = chargesMax; this.chargesRemaining = chargesRemaining; } else { this.chargesMax = (byte) itemBase.getNumCharges(); this.chargesRemaining = (byte) itemBase.getNumCharges(); } this.durabilityMax = (short) itemBase.getDurability(); this.durabilityCurrent = (short) itemBase.getDurability(); this.containerType = containerType; this.canDestroy = canDestroy; this.rentable = rentable; this.equipSlot = equipSlot; this.enchants = enchants; this.flags = 1; this.value = this.magicValue; this.customName = name; loadEnchantments(); bakeInStats(); } public Item(ItemBase itemBase, int ownerID, OwnerType ownerType, byte chargesMax, byte chargesRemaining, short durabilityCurrent, short durabilityMax, boolean canDestroy, boolean rentable, boolean inBank, boolean inVault, boolean inInventory, boolean isEquipped, boolean isForge, byte equipSlot, ArrayList enchants) { super(); this.itemBaseID = itemBase.getUUID(); this.ownerID = ownerID; this.ownerType = ownerType; this.chargesMax = (byte) itemBase.getNumCharges(); this.chargesRemaining = (byte) itemBase.getNumCharges(); this.durabilityMax = (short) itemBase.getDurability(); this.durabilityCurrent = (short) itemBase.getDurability(); this.canDestroy = canDestroy; this.rentable = rentable; this.equipSlot = equipSlot; this.enchants = enchants; this.flags = 1; this.value = this.magicValue; loadEnchantments(); bakeInStats(); } /** * Normal Constructor */ public Item(ItemBase itemBase, int ownerID, OwnerType ownerType, byte chargesMax, byte chargesRemaining, short durabilityCurrent, short durabilityMax, boolean canDestroy, boolean rentable, boolean inBank, boolean inVault, boolean inInventory, boolean isEquipped, byte equipSlot, ArrayList enchants, int newUUID) { super(newUUID); this.itemBaseID = itemBase.getUUID(); this.ownerID = ownerID; this.ownerType = ownerType; this.customName = ""; this.chargesMax = (byte) itemBase.getNumCharges(); this.chargesRemaining = (byte) itemBase.getNumCharges(); this.durabilityMax = (short) itemBase.getDurability(); this.durabilityCurrent = (short) itemBase.getDurability(); this.canDestroy = canDestroy; this.rentable = rentable; this.equipSlot = equipSlot; this.enchants = enchants; this.flags = 1; this.value = this.magicValue; loadEnchantments(); bakeInStats(); } /** * ResultSet Constructor */ public Item(ResultSet rs) throws SQLException { super(rs); this.itemBaseID = rs.getInt("item_itemBaseID"); // Set container enumeration String container = rs.getString("item_container"); switch (container) { case "inventory": this.containerType = Enum.ItemContainerType.INVENTORY; break; case "bank": this.containerType = Enum.ItemContainerType.BANK; break; case "vault": this.containerType = Enum.ItemContainerType.VAULT; break; case "equip": this.containerType = Enum.ItemContainerType.EQUIPPED; break; case "forge": this.containerType = Enum.ItemContainerType.FORGE; break; case "warehouse": this.containerType = Enum.ItemContainerType.FORGE; break; } this.ownerID = rs.getInt("parent"); if (this.getItemBase() != null) this.chargesMax = (byte) this.getItemBase().getNumCharges(); else this.chargesMax = 0; this.chargesRemaining = rs.getByte("item_chargesRemaining"); this.durabilityCurrent = rs.getShort("item_durabilityCurrent"); this.durabilityMax = rs.getShort("item_durabilityMax"); DbObjectType ownerType; ownerType = DbManager.BuildingQueries.GET_UID_ENUM(this.ownerID); switch (ownerType) { case CHARACTER: this.ownerType = OwnerType.PlayerCharacter; break; case NPC: this.ownerType = OwnerType.Npc; break; case ACCOUNT: this.ownerType = OwnerType.Account; break; } this.canDestroy = true; this.equipSlot = rs.getByte("item_equipSlot"); this.numberOfItems = rs.getInt("item_numberOfItems"); this.flags = rs.getInt("item_flags"); this.dateToUpgrade = rs.getLong("item_dateToUpgrade"); this.value = rs.getInt("item_value"); this.customName = rs.getString("item_name"); } public static void _serializeForClientMsg(Item item, ByteBufferWriter writer) throws SerializationException { Item._serializeForClientMsg(item, writer, true); } public static void serializeForClientMsgWithoutSlot(Item item, ByteBufferWriter writer) { Item._serializeForClientMsg(item, writer, false); } public static void serializeForClientMsgForVendor(Item item, ByteBufferWriter writer, float percent) { Item._serializeForClientMsg(item, writer, true); int baseValue = item.magicValue; writer.putInt(baseValue); writer.putInt((int) (baseValue * percent)); } public static void serializeForClientMsgForVendorWithoutSlot(Item item, ByteBufferWriter writer, float percent) { Item._serializeForClientMsg(item, writer, false); writer.putInt(item.getValue()); writer.putInt(item.getValue()); } public static void _serializeForClientMsg(Item item, ByteBufferWriter writer, boolean includeSlot) { if (includeSlot) writer.putInt(item.equipSlot); writer.putInt(0); // Pad writer.putInt(item.getItemBase().getUUID()); writer.putInt(item.getObjectType().ordinal()); writer.putInt(item.getObjectUUID()); // Unknown statics for (int i = 0; i < 3; i++) { writer.putInt(0); // Pad } for (int i = 0; i < 4; i++) { writer.putInt(0x3F800000); // Static } for (int i = 0; i < 5; i++) { writer.putInt(0); // Pad } for (int i = 0; i < 2; i++) { writer.putInt(0xFFFFFFFF); // Static } // Handle Hair / Beard / horns Color. boolean isHair = (item.equipSlot == (byte) MBServerStatics.SLOT_HAIRSTYLE); boolean isBeard = (item.equipSlot == (byte) MBServerStatics.SLOT_BEARDSTYLE); int itemColor = 0; if (isHair || isBeard) { PlayerCharacter pc = PlayerCharacter.getFromCache(item.ownerID); if (pc != null) if (isHair) itemColor = pc.getHairColor(); else if (isBeard) itemColor = pc.getBeardColor(); } writer.putInt(itemColor); writer.put((byte) 1); // End Datablock byte if (item.customName.isEmpty() || item.customName.isEmpty()) { writer.putInt(0); } else writer.putString(item.customName); // Unknown. pad? writer.put((byte) 1); // End Datablock byte writer.putFloat((float) item.durabilityMax); writer.putFloat((float) item.durabilityCurrent); writer.put((byte) 1); // End Datablock byte writer.putInt(0); // Pad writer.putInt(0); // Pad if (item.getItemBase().equals(ItemBase.GOLD_ITEM_BASE)) { if (item.getOwner() != null && item.getOwner().getObjectType() == GameObjectType.PlayerCharacter) { PlayerCharacter player = (PlayerCharacter) item.getOwner(); int tradingAmount = player.getCharItemManager().getGoldTrading(); writer.putInt(item.numberOfItems - tradingAmount); } else writer.putInt(item.numberOfItems); // Amount of gold } else writer.putInt(item.getItemBase().getBaseValue()); writer.putInt(item.getValue()); int effectsSize = item.effects.size(); ArrayList effs = null; Effect nextE = null; if (effectsSize > 0 && item.isID()) { effs = new ArrayList<>(item.effects.values()); //Don't send effects that have a token of 1 Iterator efi = effs.iterator(); while (efi.hasNext()) { nextE = efi.next(); if (nextE.getEffectToken() == 1 || nextE.bakedInStat()) efi.remove(); } } else effs = new ArrayList<>(); int effectsToSendSize = effs.size(); writer.putInt(effectsToSendSize); for (int i = 0; i < effectsToSendSize; i++) { effs.get(i).serializeForItem(writer, item); } writer.putInt(0x00000000); if (effectsSize > 0) if (item.isID()) writer.putInt(36); //Magical, blue name else writer.putInt(40); //Magical, unidentified else if (item.getItemBase().getBakedInStats().size() > 0) writer.putInt(36); //Magical, blue name else writer.putInt(4); //Non-Magical, grey name writer.putInt(item.chargesRemaining); writer.putInt(0); // Pad writer.putInt(item.numberOfItems); writer.put((byte) 0); if (item.getItemBase().getType().getValue() != 20) { writer.putShort((short) 0); return; } writer.put((byte) 1); // writer.putInt(0); writer.putInt(0); if (item.chargesRemaining == 0) writer.putInt(1); else writer.putInt(item.chargesRemaining); writer.put((byte) 0); } public static void SerializeTradingGold(PlayerCharacter player, ByteBufferWriter writer) { writer.putInt(0); // Pad writer.putInt(7); writer.putInt(GameObjectType.Item.ordinal()); writer.putInt(player.getObjectUUID()); // Unknown statics for (int i = 0; i < 3; i++) { writer.putInt(0); // Pad } for (int i = 0; i < 4; i++) { writer.putInt(0x3F800000); // Static } for (int i = 0; i < 5; i++) { writer.putInt(0); // Pad } for (int i = 0; i < 2; i++) { writer.putInt(0xFFFFFFFF); // Static } // Handle Hair / Beard / horns Color. int itemColor = 0; writer.putInt(itemColor); writer.put((byte) 1); // End Datablock byte writer.putInt(0); writer.put((byte) 1); // End Datablock byte writer.putFloat((float) 1); writer.putFloat((float) 1); writer.put((byte) 1); // End Datablock byte writer.putInt(0); // Pad writer.putInt(0); // Pad writer.putInt(player.getCharItemManager().getGoldTrading()); // Amount of gold writer.putInt(0); writer.putInt(0); writer.putInt(0x00000000); writer.putInt(4); //Non-Magical, grey name writer.putInt(1); writer.putInt(0); // Pad writer.putInt(player.getCharItemManager().getGoldTrading()); writer.put((byte) 0); writer.putShort((short) 0); } public static boolean MakeItemForPlayer(ItemBase toCreate, PlayerCharacter reciever, int amount) { boolean itemWorked = false; Item item = new Item(toCreate, reciever.getObjectUUID(), OwnerType.PlayerCharacter, (byte) 0, (byte) 0, (short) 1, (short) 1, true, false, Enum.ItemContainerType.INVENTORY, (byte) 0, new ArrayList<>(), ""); synchronized (item) { item.numberOfItems = amount; } item.containerType = Enum.ItemContainerType.INVENTORY; try { item = DbManager.ItemQueries.ADD_ITEM(item); itemWorked = true; } catch (Exception e) { Logger.error(e); } if (!itemWorked) return false; reciever.getCharItemManager().addItemToInventory(item); reciever.getCharItemManager().updateInventory(); return true; } public static Item deserializeFromClientMsg(ByteBufferReader reader, boolean includeSlot) { if (includeSlot) reader.getInt(); reader.getInt(); int itemBase = reader.getInt(); //itemBase int objectType = reader.getInt(); //object type; int UUID = reader.getInt(); for (int i = 0; i < 14; i++) { reader.getInt(); // Pads and statics } int unknown = reader.getInt(); byte readString = reader.get(); if (readString == 1) reader.getString(); byte readDurability = reader.get(); if (readDurability == 1) { reader.getInt(); reader.getInt(); } byte readEnchants = reader.get(); if (readEnchants == 1) { reader.getInt(); reader.getInt(); reader.getInt(); reader.getInt(); int enchantSize = reader.getInt(); for (int i = 0; i < enchantSize; i++) { reader.getInt(); //effect token reader.getInt(); //trains int type = reader.getInt(); reader.get(); if (type == 1) reader.getLong(); //item comp else reader.getInt(); //power token reader.getString(); //name reader.getFloat(); //duration } for (int i = 0; i < 5; i++) { reader.getInt(); } } reader.get(); byte isContract = reader.get(); if (isContract == 1) { reader.getInt(); reader.getInt(); reader.getInt(); } reader.get(); if (UUID == 0 || objectType == 0) return null; if (objectType == GameObjectType.MobLoot.ordinal()) return MobLoot.getFromCache(UUID); return Item.getFromCache(UUID); } public static void putListForVendor(ByteBufferWriter writer, ArrayList list, NPC vendor) { putList(writer, list, false, vendor.getObjectUUID(), true, vendor); } public static void putList(ByteBufferWriter writer, ArrayList list, boolean includeSlot, int ownerID) { putList(writer, list, includeSlot, ownerID, false, null); } private static void putList(ByteBufferWriter writer, ArrayList list, boolean includeSlot, int ownerID, boolean forVendor, NPC vendor) { int indexPosition = writer.position(); //reserve 4 bytes for index. writer.putInt(0); int serialized = 0; for (Item item : list) { if (item.getItemBase().getType().equals(ItemType.GOLD)) if (item.numberOfItems == 0) continue; try { if (includeSlot && !forVendor) Item._serializeForClientMsg(item, writer); else if (!includeSlot && !forVendor) Item.serializeForClientMsgWithoutSlot(item, writer); if (!includeSlot && forVendor) //TODO separate for sell/buy percent Item.serializeForClientMsgForVendorWithoutSlot(item, writer, vendor.getSellPercent()); if (includeSlot && forVendor) //TODO separate for sell/buy percent Item.serializeForClientMsgForVendor(item, writer, vendor.getSellPercent()); } catch (SerializationException se) { continue; } ++serialized; } writer.putIntAt(serialized, indexPosition); } public static void putTradingList(PlayerCharacter player, ByteBufferWriter writer, ArrayList list, boolean includeSlot, int ownerID, boolean forVendor, NPC vendor) { int indexPosition = writer.position(); //reserve 4 bytes for index. writer.putInt(0); int serialized = 0; for (Item item : list) { if (item.getItemBase().getType().equals(ItemType.GOLD)) if (item.numberOfItems == 0) continue; try { if (includeSlot && !forVendor) Item._serializeForClientMsg(item, writer); else if (!includeSlot && !forVendor) Item.serializeForClientMsgWithoutSlot(item, writer); if (!includeSlot && forVendor) //TODO separate for sell/buy percent Item.serializeForClientMsgForVendorWithoutSlot(item, writer, vendor.getSellPercent()); if (includeSlot && forVendor) //TODO separate for sell/buy percent Item.serializeForClientMsgForVendor(item, writer, vendor.getSellPercent()); } catch (SerializationException se) { continue; } ++serialized; } if (player.getCharItemManager().getGoldTrading() > 0) { Item.SerializeTradingGold(player, writer); ++serialized; } writer.putIntAt(serialized, indexPosition); } public static Item createItemForPlayer(PlayerCharacter pc, ItemBase ib) { Item item = null; byte charges = 0; charges = (byte) ib.getNumCharges(); short durability = (short) ib.getDurability(); Item temp = new Item(ib, pc.getObjectUUID(), OwnerType.PlayerCharacter, charges, charges, durability, durability, true, false, Enum.ItemContainerType.INVENTORY, (byte) 0, new ArrayList<>(), ""); try { item = DbManager.ItemQueries.ADD_ITEM(temp); } catch (Exception e) { Logger.error(e); } return item; } public static Item createItemForPlayerBank(PlayerCharacter pc, ItemBase ib) { Item item = null; byte charges = 0; charges = (byte) ib.getNumCharges(); short durability = (short) ib.getDurability(); Item temp = new Item(ib, pc.getObjectUUID(), OwnerType.PlayerCharacter, charges, charges, durability, durability, true, false, Enum.ItemContainerType.BANK, (byte) 0, new ArrayList<>(), ""); try { item = DbManager.ItemQueries.ADD_ITEM(temp); } catch (Exception e) { } return item; } public static Item createItemForMob(Mob mob, ItemBase ib) { Item item = null; byte charges = 0; charges = (byte) ib.getNumCharges(); short durability = (short) ib.getDurability(); Item temp = new Item(ib, mob.getObjectUUID(), OwnerType.Mob, charges, charges, durability, durability, true, false, Enum.ItemContainerType.INVENTORY, (byte) 0, new ArrayList<>(), ""); try { item = DbManager.ItemQueries.ADD_ITEM(temp); } catch (Exception e) { Logger.error(e); } return item; } public static Item getFromCache(int id) { return (Item) DbManager.getFromCache(GameObjectType.Item, id); } public static Item newGoldItem(AbstractWorldObject awo, ItemBase ib, Enum.ItemContainerType containerType) { return newGoldItem(awo, ib, containerType, true); } //used for vault! public static Item newGoldItem(int accountID, ItemBase ib, Enum.ItemContainerType containerType) { return newGoldItem(accountID, ib, containerType, true); } private static Item newGoldItem(int accountID, ItemBase ib, Enum.ItemContainerType containerType, boolean persist) { int ownerID; OwnerType ownerType; ownerID = accountID; ownerType = OwnerType.Account; Item newGold = new Item(ib, ownerID, ownerType, (byte) 0, (byte) 0, (short) 0, (short) 0, true, false, containerType, (byte) 0, new ArrayList<>(), ""); synchronized (newGold) { newGold.numberOfItems = 0; } if (persist) { try { newGold = DbManager.ItemQueries.ADD_ITEM(newGold); if (newGold != null) { synchronized (newGold) { newGold.numberOfItems = 0; } } } catch (Exception e) { Logger.error(e); } DbManager.ItemQueries.ZERO_ITEM_STACK(newGold); } return newGold; } private static Item newGoldItem(AbstractWorldObject awo, ItemBase ib, Enum.ItemContainerType containerType, boolean persist) { int ownerID; OwnerType ownerType; if (awo.getObjectType().equals(GameObjectType.Mob)) return null; if (containerType == Enum.ItemContainerType.VAULT) { if (!(awo.getObjectType().equals(GameObjectType.PlayerCharacter))) { Logger.error("AWO is not a PlayerCharacter"); return null; } ownerID = ((PlayerCharacter) awo).getAccount().getObjectUUID(); ownerType = OwnerType.Account; } else { ownerID = awo.getObjectUUID(); switch (awo.getObjectType()) { case NPC: ownerType = OwnerType.Npc; break; case PlayerCharacter: ownerType = OwnerType.PlayerCharacter; break; case Mob: ownerType = OwnerType.Mob; break; default: Logger.error("Unsupported AWO object type."); return null; } } Item newGold = new Item(ib, ownerID, ownerType, (byte) 0, (byte) 0, (short) 0, (short) 0, true, false, containerType, (byte) 0, new ArrayList<>(), ""); synchronized (newGold) { newGold.numberOfItems = 0; } if (persist) { try { newGold = DbManager.ItemQueries.ADD_ITEM(newGold); if (newGold != null) { synchronized (newGold) { newGold.numberOfItems = 0; } } } catch (Exception e) { Logger.error(e); } DbManager.ItemQueries.ZERO_ITEM_STACK(newGold); } newGold.containerType = containerType; return newGold; } // This is to be used for trades - the new item is not stored in the database public static Item newGoldItemTemp(AbstractWorldObject awo, ItemBase ib) { return Item.newGoldItem(awo, ib, Enum.ItemContainerType.NONE, false); } public static Item getItem(int UUID) { if (UUID == 0) return null; Item item = (Item) DbManager.getFromCache(GameObjectType.Item, UUID); if (item != null) return item; return DbManager.ItemQueries.GET_ITEM(UUID); } public static void addEnchantValue(String enchant, int value) { Item.enchantValues.put(enchant, value); } public static int getEnchantValue(String enchant) { if (Item.enchantValues.containsKey(enchant)) return Item.enchantValues.get(enchant); return 0; } public String getCustomName() { return customName; } public ItemBase getItemBase() { return ItemBase.getItemBase(itemBaseID); } public int getItemBaseID() { return this.itemBaseID; } public int getOwnerID() { return ownerID; } //Only to be used for trading public void setOwnerID(int ownerID) { this.ownerID = ownerID; } public OwnerType getOwnerType() { return ownerType; } public AbstractGameObject getOwner() { if (this.ownerType == OwnerType.Npc) return NPC.getFromCache(this.ownerID); else if (this.ownerType == OwnerType.PlayerCharacter) return PlayerCharacter.getFromCache(this.ownerID); else if (this.ownerType == OwnerType.Mob) return Mob.getFromCache(this.ownerID); else if (this.ownerType == OwnerType.Account) return DbManager.AccountQueries.GET_ACCOUNT(this.ownerID); else return null; } public boolean setOwner(AbstractGameObject owner) { if (owner == null) return false; if (owner.getObjectType().equals(GameObjectType.NPC)) this.ownerType = OwnerType.Npc; else if (owner.getObjectType().equals(GameObjectType.PlayerCharacter)) this.ownerType = OwnerType.PlayerCharacter; else if (owner.getObjectType().equals(GameObjectType.Mob)) this.ownerType = OwnerType.Mob; else if (owner.getObjectType().equals(GameObjectType.Account)) this.ownerType = OwnerType.Account; else return false; this.ownerID = owner.getObjectUUID(); return true; } public boolean isOwnerNPC() { return (ownerType == OwnerType.Npc); } public boolean isOwnerCharacter() { return (ownerType == OwnerType.PlayerCharacter); } public boolean isOwnerAccount() { return (ownerType == OwnerType.Account); } public byte getChargesMax() { return chargesMax; } public byte getChargesRemaining() { return chargesRemaining; } public short getDurabilityCurrent() { return durabilityCurrent; } public void setDurabilityCurrent(short value) { this.durabilityCurrent = value; } public short getDurabilityMax() { return durabilityMax; } public boolean isCanDestroy() { if(this.getItemBaseID() == 7)//gold return false; return canDestroy; } public boolean isRentable() { return rentable; } public byte getEquipSlot() { return equipSlot; } public ArrayList getEnchants() { return enchants; } public int getNumOfItems() { return this.numberOfItems; } public synchronized void setNumOfItems(int numberOfItems) { this.numberOfItems = numberOfItems; } public ConcurrentHashMap getBonuses() { return this.bonuses; } public void clearBonuses() { this.bonuses.clear(); } public float getBonus(ModType modType, SourceType sourceType) { int amount = 0; for (AbstractEffectModifier modifier : this.getBonuses().keySet()) { if (modifier.getPercentMod() != 0) continue; if (modifier.modType.equals(modType) == false || modifier.sourceType.equals(sourceType) == false) continue; amount += this.bonuses.get(modifier); } return amount; } public float getBonusPercent(ModType modType, SourceType sourceType) { int amount = 0; for (AbstractEffectModifier modifier : this.getBonuses().keySet()) { if (modifier.getPercentMod() == 0) continue; if (modifier.modType.equals(modType) == false || modifier.sourceType.equals(sourceType) == false) continue; amount += this.bonuses.get(modifier); } return amount; } public boolean isID() { return ((this.flags & 1) > 0); } public void setIsID(boolean value) { if (value) this.flags |= 1; else this.flags &= ~1; } public void setIsComplete(boolean value) { if (value) this.flags |= 2; else this.flags &= ~2; } public boolean isComplete() { return this.dateToUpgrade < System.currentTimeMillis() + 1000; } public String getContainerInfo() { String ret = "OwnerID: " + this.ownerID + ", container: "; ret += this.containerType.toString(); ret += "Equip Slot: " + this.equipSlot; return ret; } public int getFlags() { return this.flags; } public void setFlags(int value) { this.flags = value; } public void addBonus(AbstractEffectModifier key, float amount) { if (this.bonuses.containsKey(key)) this.bonuses.put(key, (this.bonuses.get(key) + amount)); else this.bonuses.put(key, amount); } public void multBonus(AbstractEffectModifier key, float amount) { if (this.bonuses.containsKey(key)) this.bonuses.put(key, (this.bonuses.get(key) * amount)); else this.bonuses.put(key, amount); } public synchronized void decrementChargesRemaining() { this.chargesRemaining -= 1; if (this.chargesRemaining < 0) this.chargesRemaining = 0; DbManager.ItemQueries.UPDATE_REMAINING_CHARGES(this); } protected void validateItemContainer() { if (this.containerType == Enum.ItemContainerType.NONE) if (this.ownerID != 0) // Item has an owner, just somehow the flags got messed up. // Default to bank. // TODO NEED LOG EVENT HERE. this.containerType = Enum.ItemContainerType.BANK; else // This item is on the ground. Nothing to worry about. this.zeroItem(); } // Removes all ownership of item and 'orphans' it. protected synchronized void junk() { DbManager.ItemQueries.UPDATE_OWNER(this, 0, false, false, false, ItemContainerType.NONE, 0); this.zeroItem(); //TODO do we want to delete the item here? this.lastOwner = null; //cleanup item from server. this.removeFromCache(); } public synchronized void zeroItem() { this.ownerID = 0; this.ownerType = null; this.containerType = Enum.ItemContainerType.NONE; this.equipSlot = MBServerStatics.SLOT_UNEQUIPPED; } protected synchronized boolean moveItemToInventory(PlayerCharacter pc) { if (!DbManager.ItemQueries.UPDATE_OWNER(this, pc.getObjectUUID(), //tableID false, //isNPC true, //isPlayer false, //isAccount ItemContainerType.INVENTORY, 0)) //Slot return false; this.zeroItem(); this.ownerID = pc.getObjectUUID(); this.ownerType = OwnerType.PlayerCharacter; this.containerType = ItemContainerType.INVENTORY; return true; } protected synchronized boolean moveItemToInventory(NPC npc) { if (npc.isStatic()) { if (!DbManager.ItemQueries.UPDATE_OWNER(this, 0, false, false, false, ItemContainerType.INVENTORY, 0)) return false; } else if (!DbManager.ItemQueries.UPDATE_OWNER(this, npc.getObjectUUID(), //UUID true, //isNPC false, //isPlayer false, //isAccount ItemContainerType.INVENTORY, 0)) //Slot return false; this.zeroItem(); this.ownerID = npc.getObjectUUID(); this.ownerType = OwnerType.Npc; this.containerType = Enum.ItemContainerType.INVENTORY; return true; } protected synchronized boolean moveItemToInventory(Corpse corpse) { if (!DbManager.ItemQueries.UPDATE_OWNER(this, 0, //no ID for corpse false, //isNPC true, //isPlayer false, //isAccount ItemContainerType.INVENTORY, 0)) //Slot return false; this.zeroItem(); this.ownerID = 0; this.ownerType = null; this.containerType = Enum.ItemContainerType.INVENTORY; return true; } protected synchronized boolean moveItemToBank(PlayerCharacter pc) { if (!DbManager.ItemQueries.UPDATE_OWNER(this, pc.getObjectUUID(), //UUID false, //isNPC true, //isPlayer false, //isAccount ItemContainerType.BANK, 0)) //Slot return false; this.zeroItem(); this.ownerID = pc.getObjectUUID(); this.ownerType = OwnerType.PlayerCharacter; this.containerType = Enum.ItemContainerType.BANK; return true; } protected synchronized boolean moveItemToBank(NPC npc) { if (!DbManager.ItemQueries.UPDATE_OWNER(this, npc.getObjectUUID(), //UUID true, //isNPC false, //isPlayer false, //isAccount ItemContainerType.BANK, 0)) //Slot return false; this.zeroItem(); this.ownerID = npc.getObjectUUID(); this.ownerType = OwnerType.Npc; this.containerType = Enum.ItemContainerType.BANK; return true; } protected synchronized boolean moveItemToVault(Account a) { if (!DbManager.ItemQueries.UPDATE_OWNER(this, a.getObjectUUID(), //UUID false, //isNPC false, //isPlayer true, //isAccount ItemContainerType.VAULT, 0)) //Slot return false; this.zeroItem(); this.ownerID = a.getObjectUUID(); this.ownerType = OwnerType.Account; this.containerType = Enum.ItemContainerType.VAULT; return true; } protected synchronized boolean equipItem(PlayerCharacter pc, byte slot) { if (!DbManager.ItemQueries.UPDATE_OWNER(this, pc.getObjectUUID(), //tableID false, //isNPC true, //isPlayer false, //isAccount ItemContainerType.EQUIPPED, slot)) //Slot return false; this.zeroItem(); this.ownerID = pc.getObjectUUID(); this.ownerType = OwnerType.PlayerCharacter; this.containerType = Enum.ItemContainerType.EQUIPPED; this.equipSlot = slot; return true; } protected synchronized boolean equipItem(NPC npc, byte slot) { if (!DbManager.ItemQueries.UPDATE_OWNER(this, npc.getObjectUUID(), //UUID true, //isNPC false, //isPlayer false, //isAccount ItemContainerType.EQUIPPED, slot)) //Slot return false; this.zeroItem(); this.ownerID = npc.getObjectUUID(); this.ownerType = OwnerType.Npc; this.containerType = Enum.ItemContainerType.EQUIPPED; this.equipSlot = slot; return true; } protected synchronized boolean equipItem(Mob npc, byte slot) { this.zeroItem(); this.ownerID = npc.getObjectUUID(); this.ownerType = OwnerType.Mob; this.containerType = Enum.ItemContainerType.EQUIPPED; this.equipSlot = slot; return true; } public final int getMagicValue() { return this.magicValue; } public int getBaseValue() { if (this.getItemBase() != null) return this.getItemBase().getBaseValue(); return 0; } public AbstractWorldObject getLastOwner() { return this.lastOwner; } public void setLastOwner(AbstractWorldObject value) { this.lastOwner = value; } @Override public String getName() { if (this.customName.isEmpty()) if (this.getItemBase() != null) return this.getItemBase().getName(); return this.customName; } public void setName(String name) { this.customName = name; } private void bakeInStats() { EffectsBase effect; if (ConfigManager.serverType.equals(Enum.ServerType.LOGINSERVER)) return; if (this.getItemBase() != null) if(this.getItemBase().isVorg()){ this.clearEffects(); for(String powerString : this.getItemBase().getVorgStats()){ //AbstractPowerAction apa = PowersManager.getPowerActionByIDString(powerString); //apa.applyBakedInStatsForItem(this, 0); this.addPermanentEnchantment(powerString,0); } this.setName(this.getItemBase().getName()); }else { for (Integer token : this.getItemBase().getBakedInStats().keySet()) { effect = PowersManager.getEffectByToken(token); if (effect == null) { Logger.error("missing effect of token " + token); continue; } AbstractPowerAction apa = PowersManager.getPowerActionByIDString(effect.getIDString()); apa.applyBakedInStatsForItem(this, this.getItemBase().getBakedInStats().get(token)); } } } public final void loadEnchantments() { //dont load mobloot enchantments, they arent in db. if (this.getObjectType().equals(GameObjectType.MobLoot)) { this.magicValue = this.getItemBase().getBaseValue() + calcMagicValue(); return; } ConcurrentHashMap enchantList = DbManager.EnchantmentQueries.GET_ENCHANTMENTS_FOR_ITEM(this.getObjectUUID()); for (String enchant : enchantList.keySet()) { AbstractPowerAction apa = PowersManager.getPowerActionByIDString(enchant); if (apa != null) { apa.applyEffectForItem(this, enchantList.get(enchant)); this.effectNames.add(enchant); } } this.magicValue = this.getItemBase().getBaseValue() + calcMagicValue(); } public HashMap getBakedInStats() { if (this.getItemBase() != null) return this.getItemBase().getBakedInStats(); return null; } public void clearEnchantments() { //Clear permanent enchantment out of database DbManager.EnchantmentQueries.CLEAR_ENCHANTMENTS((long) this.getObjectUUID()); for (String name : this.getEffects().keySet()) { Effect eff = this.getEffects().get(name); if (!eff.bakedInStat()) this.endEffect(name); } this.effectNames.clear(); } public void addPermanentEnchantment(String enchantID, int rank) { AbstractPowerAction apa = PowersManager.getPowerActionByIDString(enchantID); if (apa == null) return; DbManager.EnchantmentQueries.CREATE_ENCHANTMENT_FOR_ITEM((long) this.getObjectUUID(), enchantID, rank); apa.applyEffectForItem(this, rank); this.effectNames.add(enchantID); } public void addPermanentEnchantmentForDev(String enchantID, int rank) { AbstractPowerAction apa = PowersManager.getPowerActionByIDString(enchantID); if (apa == null) return; DbManager.EnchantmentQueries.CREATE_ENCHANTMENT_FOR_ITEM((long) this.getObjectUUID(), enchantID, rank); apa.applyEffectForItem(this, rank); this.effectNames.add(enchantID); } protected int calcMagicValue() { int ret = 0; for (String enchant : this.effectNames) { ret += Item.getEnchantValue(enchant + 'A'); } return ret; } public void addToCache() { DbManager.addToCache(this); } @Override public void updateDatabase() { //DbManager.ItemQueries.updateDatabase(this); } @Override public void runAfterLoad() { loadEnchantments(); bakeInStats(); } public ArrayList getEffectNames() { return effectNames; } public boolean validForItem(long flags) { if (this.getItemBase() == null) return false; return this.getItemBase().validSlotFlag(flags); } public boolean validForInventory(ClientConnection origin, PlayerCharacter pc, CharacterItemManager charItemMan) { if (origin == null || pc == null || charItemMan == null) return false; if (ownerID != pc.getObjectUUID()) { Logger.warn("Inventory Item " + this.getObjectUUID() + " not owned by Character " + charItemMan.getOwner().getObjectUUID()); charItemMan.updateInventory(); return false; } if (!charItemMan.inventoryContains(this)) { charItemMan.updateInventory(); return false; } return true; } public boolean validForBank(ClientConnection origin, PlayerCharacter pc, CharacterItemManager charItemMan) { if (origin == null || pc == null || charItemMan == null) return false; if (!charItemMan.bankContains(this)) return false; else if (ownerID != pc.getObjectUUID()) { Logger.warn("Bank Item " + this.getObjectUUID() + " not owned by Character " + charItemMan.getOwner().getObjectUUID()); return false; } return true; } public boolean validForEquip(ClientConnection origin, PlayerCharacter pc, CharacterItemManager charItemMan) { if (origin == null || pc == null || charItemMan == null) return false; if (!charItemMan.equippedContains(this)) return false; else if (ownerID != pc.getObjectUUID()) { //duped item, cleanup Logger.warn("Duped item id " + this.getObjectUUID() + " removed from PC " + pc.getObjectUUID() + '.'); DeleteItemMsg deleteItemMsg = new DeleteItemMsg(this.getObjectType().ordinal(), this.getObjectUUID()); charItemMan.cleanupDupe(this); Dispatch dispatch = Dispatch.borrow(pc, deleteItemMsg); DispatchMessage.dispatchMsgDispatch(dispatch, Enum.DispatchChannel.SECONDARY); return false; } return true; } public boolean validForVault(ClientConnection origin, PlayerCharacter pc, CharacterItemManager charItemMan) { if (origin == null || pc == null || charItemMan == null) return false; if (pc.getAccount() == null) return false; if (!pc.getAccount().getVault().contains(this)) return false; else if (ownerID != pc.getAccount().getObjectUUID()) { //duped item, cleanup Logger.warn("Duped item id " + this.getObjectUUID() + " removed from PC " + pc.getObjectUUID() + '.'); DeleteItemMsg deleteItemMsg = new DeleteItemMsg(this.getObjectType().ordinal(), this.getObjectUUID()); charItemMan.cleanupDupe(this); Dispatch dispatch = Dispatch.borrow(pc, deleteItemMsg); DispatchMessage.dispatchMsgDispatch(dispatch, Enum.DispatchChannel.SECONDARY); return false; } return true; } public long getDateToUpgrade() { return dateToUpgrade; } public void setDateToUpgrade(long dateToUpgrade) { this.dateToUpgrade = dateToUpgrade; } /** * @return the value */ public int getValue() { if (this.value == 0) if (this.isID()) { return this.getMagicValue(); } else return this.getBaseValue(); return this.value; } /** * @param value the value to set */ public void setValue(int value) { this.value = value; } public boolean isRandom() { return isRandom; } public void setRandom(boolean isRandom) { this.isRandom = isRandom; } public boolean isCustomValue() { if (this.value == 0) return false; return true; } }