// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . // ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· // ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ // ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ // ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ // 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 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 private int flags; //1 = isIDed public int numberOfItems; public float durabilityCurrent; public int chargesRemaining; public byte equipSlot; private boolean canDestroy; private boolean isRandom = false; private int value; public OwnerType ownerType; public int templsteID; private AbstractWorldObject lastOwner; private long dateToUpgrade; private String customName = ""; private int magicValue; public ItemTemplate template; public String name; /** * In Memory constructor * Set values and call PERSIST(); */ public Item(int templateID) { super(); this.template = ItemTemplate.itemTemplates.get(templateID); this.chargesRemaining = this.template.item_initial_charges; this.durabilityCurrent = this.template.combat_health_full; this.equipSlot = 0; this.containerType = ItemContainerType.NONE; this.numberOfItems = 1; loadEnchantments(); bakeInStats(); } /** * ResultSet Constructor */ public Item(ResultSet rs) throws SQLException { super(rs); this.templsteID = rs.getInt("item_itemBaseID"); this.template = ItemTemplate.itemTemplates.get(this.templsteID); if (this.template == null) Logger.error("Null template of " + this.templsteID) ; // 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"); this.chargesRemaining = rs.getByte("item_chargesRemaining"); this.durabilityCurrent = rs.getShort("item_durabilityCurrent"); 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(item.template.item_health_full); 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.getUUID()); 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.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 = new Item(ib.getUUID()); item.ownerID = pc.getObjectUUID(); item.ownerType = OwnerType.PlayerCharacter; try { item = DbManager.ItemQueries.PERSIST(item); } 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.getUUID()); 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, 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.getUUID()); 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; } // 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(templsteID); } public int getTemplsteID() { return this.templsteID; } 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 setDurabilityCurrent(float value) { this.durabilityCurrent = value; } public boolean isCanDestroy() { return canDestroy; } public byte getEquipSlot() { return equipSlot; } 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() == false) return this.customName; ItemTemplate template = ItemTemplate.itemTemplates.get(this.getTemplsteID()); return template.item_base_name; } 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) 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; } }