// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . // ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· // ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ // ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ // ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ // 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.EnumSet; 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 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(); public int ownerID; //may be character, account, npc, mob public float drop_chance; public EnumSet flags = EnumSet.noneOf(ItemFlags.class); public int numberOfItems; public float combat_health_current; public int chargesRemaining; public Enum.EquipSlotType equipSlot; private boolean canDestroy; private boolean isRandom = false; public int value; public OwnerType ownerType; public int templateID; private long dateToUpgrade; public int magicValue; public ItemTemplate template; public String name = ""; /** * In Memory constructor * Set values and call PERSIST(); */ public Item(int templateID) { super(); this.templateID = templateID; this.template = ItemTemplate.templates.get(templateID); this.chargesRemaining = this.template.item_initial_charges; this.combat_health_current = this.template.combat_health_full; this.equipSlot = EquipSlotType.NONE; this.containerType = ItemContainerType.NONE; this.numberOfItems = 1; this.flags.addAll(this.template.item_flags); this.value = this.template.item_value; this.magicValue = this.value + calcMagicValue(); loadTemplateEnchantments(); } /** * ResultSet Constructor */ public Item(ResultSet rs) throws SQLException { super(rs); this.templateID = rs.getInt("templateID"); this.template = ItemTemplate.templates.get(this.templateID); if (this.template == null) Logger.error("Null template of " + this.templateID); // Name override in db. this.name = rs.getString("name"); if (this.name == null) this.name = ""; // Set container enumeration String container = rs.getString("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 = ItemContainerType.WAREHOUSE; break; } this.ownerID = rs.getInt("parent"); this.chargesRemaining = rs.getByte("chargesRemaining"); this.combat_health_current = rs.getShort("combat_health_current"); 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 = EquipSlotType.values()[rs.getByte("equipSlot")]; this.numberOfItems = rs.getInt("numberOfItems"); String flagString = rs.getString("flags"); if (flagString.isEmpty() == false) for (String itemFlag : flagString.split(";")) this.flags.add(Enum.ItemFlags.valueOf(itemFlag)); this.dateToUpgrade = rs.getLong("dateToUpgrade"); this.value = rs.getInt("value"); if (this.value == 0) this.value = this.template.item_value; } 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.ordinal()); writer.putInt(0); // Pad writer.putInt(item.templateID); 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.equals(EquipSlotType.HAIR)); boolean isBeard = (item.equipSlot.equals(EquipSlotType.BEARD)); 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 writer.putString(item.name); // Unknown. pad? writer.put((byte) 1); // End Datablock byte writer.putFloat(item.template.combat_health_full); writer.putFloat((float) item.combat_health_current); writer.put((byte) 1); // End Datablock byte writer.putInt(0); // Pad writer.putInt(0); // Pad if (item.templateID == ResourceType.GOLD.templateID) { if (item.getOwner() != null && item.getOwner().getObjectType() == GameObjectType.PlayerCharacter) { PlayerCharacter player = (PlayerCharacter) item.getOwner(); int tradingAmount = player.charItemManager.getGoldTrading(); writer.putInt(item.numberOfItems - tradingAmount); } else writer.putInt(item.numberOfItems); // Amount of gold } else writer.putInt(item.value); writer.putInt(item.getValue()); int effectsSize = item.effects.size(); ArrayList effs = null; Effect nextE = null; if (effectsSize > 0 && item.flags.contains(ItemFlags.Identified)) { 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.flags.contains(ItemFlags.Identified)) writer.putInt(36); //Magical, blue name else writer.putInt(40); //Magical, unidentified else if (item.template.item_user_power_action.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.template.item_type.equals(ItemType.EMPLOYMENTCONTRACT) == false) { 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.charItemManager.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.charItemManager.getGoldTrading()); writer.put((byte) 0); writer.putShort((short) 0); } public static boolean MakeItemForPlayer(int templateID, PlayerCharacter reciever, int amount) { boolean itemWorked = false; Item item = new Item(templateID); item.ownerID = reciever.getObjectUUID(); item.ownerType = OwnerType.PlayerCharacter; item.containerType = Enum.ItemContainerType.INVENTORY; item.numberOfItems = amount; try { item = DbManager.ItemQueries.PERSIST(item); itemWorked = true; } catch (Exception e) { Logger.error(e); } if (!itemWorked) return false; reciever.charItemManager.addItemToInventory(item); reciever.charItemManager.updateInventory(); return true; } public static Item deserializeFromClientMsg(ByteBufferReader reader, boolean includeSlot) { if (includeSlot) reader.getInt(); reader.getInt(); 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.template.item_type.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.template.item_type.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.charItemManager.getGoldTrading() > 0) { Item.SerializeTradingGold(player, writer); ++serialized; } writer.putIntAt(serialized, indexPosition); } public static Item getFromCache(int id) { return (Item) DbManager.getFromCache(GameObjectType.Item, id); } public static Item newGoldItem(AbstractWorldObject awo, Enum.ItemContainerType containerType) { return newGoldItem(awo, containerType, true); } //used for vault! public static Item newGoldItem(int accountID, Enum.ItemContainerType containerType) { return newGoldItem(accountID, containerType, true); } private static Item newGoldItem(int accountID, Enum.ItemContainerType containerType, boolean persist) { int ownerID; OwnerType ownerType; ownerID = accountID; ownerType = OwnerType.Account; Item newGold = new Item(ResourceType.GOLD.templateID); newGold.ownerID = ownerID; newGold.ownerType = ownerType; newGold.containerType = containerType; newGold.numberOfItems = 0; if (persist) { try { newGold = DbManager.ItemQueries.PERSIST(newGold); DbManager.ItemQueries.ZERO_ITEM_STACK(newGold); } catch (Exception e) { Logger.error(e); } } return newGold; } private static Item newGoldItem(AbstractWorldObject awo, 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(ResourceType.GOLD.templateID); newGold.ownerID = ownerID; newGold.ownerType = ownerType; newGold.containerType = containerType; newGold.numberOfItems = 0; if (persist) { try { newGold = DbManager.ItemQueries.PERSIST(newGold); } catch (Exception e) { Logger.error(e); } DbManager.ItemQueries.ZERO_ITEM_STACK(newGold); } return newGold; } 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 int getTemplateID() { return this.templateID; } public int getOwnerID() { return ownerID; } //Only to be used for trading public void setOwnerID(int ownerID) { this.ownerID = ownerID; } 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 void setCombat_health_current(float value) { this.combat_health_current = value; } public boolean isCanDestroy() { return canDestroy; } 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 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 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); } public void zeroItem() { this.ownerID = 0; this.ownerType = null; this.containerType = Enum.ItemContainerType.NONE; this.equipSlot = EquipSlotType.NONE; } 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(); //cleanup item from server. this.removeFromCache(); } 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.ownerID = pc.getObjectUUID(); this.ownerType = OwnerType.PlayerCharacter; this.containerType = ItemContainerType.INVENTORY; this.equipSlot = EquipSlotType.NONE; 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; this.equipSlot = EquipSlotType.NONE; 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; this.equipSlot = EquipSlotType.NONE; 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; this.equipSlot = EquipSlotType.NONE; 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; this.equipSlot = EquipSlotType.NONE; 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; this.equipSlot = EquipSlotType.NONE; return true; } protected synchronized boolean equipItem(PlayerCharacter pc, Enum.EquipSlotType slot) { if (!DbManager.ItemQueries.UPDATE_OWNER(this, pc.getObjectUUID(), //tableID false, //isNPC true, //isPlayer false, //isAccount ItemContainerType.EQUIPPED, slot.ordinal())) //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, Enum.EquipSlotType slot) { if (!DbManager.ItemQueries.UPDATE_OWNER(this, npc.getObjectUUID(), //UUID true, //isNPC false, //isPlayer false, //isAccount ItemContainerType.EQUIPPED, slot.ordinal())) //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, Enum.EquipSlotType slot) { this.zeroItem(); this.ownerID = npc.getObjectUUID(); this.ownerType = OwnerType.Mob; this.containerType = Enum.ItemContainerType.EQUIPPED; this.equipSlot = slot; return true; } private void loadTemplateEnchantments() { EffectsBase effect; if (ConfigManager.serverType.equals(Enum.ServerType.LOGINSERVER)) return; for (String effectID : this.template.item_user_power_action.keySet()) { effect = PowersManager.getEffectByIDString(effectID); if (effect == null) { Logger.error("missing effect of type: " + effectID); continue; } AbstractPowerAction apa = PowersManager.getPowerActionByIDString(effect.getIDString()); apa.applyBakedInStatsForItem(this, this.template.item_user_power_action.get(effectID)[0]); } } public final void loadEnchantments() { // No enchantments for negative id items in the db. Early exit. if (this.objectUUID < 0) { this.magicValue = this.template.item_value + 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.template.item_value + calcMagicValue(); } 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(); loadTemplateEnchantments(); } public ArrayList getEffectNames() { return effectNames; } 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() { int modifiedValue; if (this.flags.contains(ItemFlags.Identified)) modifiedValue = this.magicValue; else modifiedValue = this.value; if (this.template.item_initial_charges > 0) modifiedValue = modifiedValue * (this.chargesRemaining / this.template.item_initial_charges); if (this.template.combat_health_full > 0) modifiedValue = (int) (modifiedValue * (this.combat_health_current / this.template.combat_health_full)); return modifiedValue; } /** * @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; } }