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

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

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

1148 lines
38 KiB
Java

// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
// Magicbane Emulator Project © 2013 - 2026
// https://www.magicbane.com
package engine.objects;
import engine.gameManager.ConfigManager;
import engine.gameManager.DbManager;
import engine.gameManager.DispatchManager;
import engine.gameManager.PowersManager;
import engine.mbEnums;
import engine.mbEnums.*;
import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter;
import engine.net.Dispatch;
import engine.net.client.ClientConnection;
import engine.net.client.msg.DeleteItemMsg;
import engine.parsers.objects.CObjectTemplate;
import engine.parsers.objects.UserPowerAction;
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.LinkedHashMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;
public class Item extends AbstractWorldObject {
private static ConcurrentHashMap<String, Integer> enchantValues = new ConcurrentHashMap<>(MBServerStatics.CHM_INIT_CAP, MBServerStatics.CHM_LOAD, MBServerStatics.CHM_THREAD_LOW);
private final ConcurrentHashMap<AbstractEffectModifier, Float> bonuses = new ConcurrentHashMap<>(MBServerStatics.CHM_INIT_CAP, MBServerStatics.CHM_LOAD, MBServerStatics.CHM_THREAD_LOW);
private final ArrayList<String> effectNames = new ArrayList<>();
public mbEnums.ItemContainerType containerType;
public ReentrantLock lootLock = new ReentrantLock();
public int ownerID; //may be character, account, npc, mob
public float drop_chance;
public EnumSet<mbEnums.ItemFlags> flags = EnumSet.noneOf(ItemFlags.class);
public int numberOfItems;
public float combat_health_current;
public int chargesRemaining;
public mbEnums.EquipSlotType equipSlot;
private boolean canDestroy;
public int value;
public OwnerType ownerType;
public int templateID;
private long dateToUpgrade;
public int magicValue;
public CObjectTemplate template;
public String name = "";
public int prefixToken; // Forge support
public int suffixToken; // Forge support
/**
* In Memory constructor
* Set values and call PERSIST();
*/
public Item(int templateID) {
super();
this.templateID = templateID;
this.template = CObjectTemplate.lookup(templateID);
this.chargesRemaining = this.template.getItemInitialCharges();
this.combat_health_current = this.template.getCombatHealthFull();
this.equipSlot = EquipSlotType.NONE;
this.containerType = ItemContainerType.NONE;
this.numberOfItems = 1;
this.flags.addAll(this.template.getItemFlags());
this.value = this.template.getItemValue();
this.magicValue = this.value + calcMagicValue();
loadTemplateEnchantments();
}
/**
* ResultSet Constructor
*/
public Item(ResultSet rs) throws SQLException {
super(rs);
this.templateID = rs.getInt("templateID");
this.template = CObjectTemplate.lookup(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 = mbEnums.ItemContainerType.INVENTORY;
break;
case "bank":
this.containerType = mbEnums.ItemContainerType.BANK;
break;
case "vault":
this.containerType = mbEnums.ItemContainerType.VAULT;
break;
case "equip":
this.containerType = mbEnums.ItemContainerType.EQUIPPED;
break;
case "forge":
this.containerType = mbEnums.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;
String equipString = rs.getString("equipSlot");
if (equipString.isEmpty())
this.equipSlot = EquipSlotType.NONE;
else
this.equipSlot = EquipSlotType.valueOf(equipString);
this.numberOfItems = rs.getInt("numberOfItems");
String flagString = rs.getString("flags");
if (flagString.isEmpty() == false)
for (String itemFlag : flagString.split(";"))
this.flags.add(mbEnums.ItemFlags.valueOf(itemFlag));
this.dateToUpgrade = rs.getLong("dateToUpgrade");
this.value = rs.getInt("value");
if (this.value == 0) {
this.value = this.template.getItemValue();
this.magicValue = this.value + calcMagicValue();
} else
this.magicValue = this.value; // Value was overridden in vendor inventory
}
public static void _serializeForClientMsg(Item item, ByteBufferWriter writer) {
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.getCombatHealthFull());
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.template.getItemValue());
writer.putInt(item.getValue());
int effectsSize = item.effects.size();
ArrayList<Effect> 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<Effect> 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.getItemUserPowerAction().isEmpty() == false)
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.getItemType().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 Item deserializeFromClientMsg(ByteBufferReader reader,
boolean includeSlot) {
if (includeSlot)
reader.getInt();
reader.getInt();
int templateID = 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<Item> list, NPC vendor) {
putList(writer, list, false, vendor.getObjectUUID(), true, vendor);
}
public static void putList(ByteBufferWriter writer, ArrayList<Item> list, boolean includeSlot, int ownerID) {
putList(writer, list, includeSlot, ownerID, false, null);
}
private static void putList(ByteBufferWriter writer, ArrayList<Item> 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.getItemType().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 (Exception se) {
continue;
}
++serialized;
}
writer.putIntAt(serialized, indexPosition);
}
public static void putTradingList(PlayerCharacter player, ByteBufferWriter writer, ArrayList<Item> 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.getItemType().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 (Exception 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, mbEnums.ItemContainerType containerType) {
return newGoldItem(awo, containerType, true);
}
//used for vault!
public static Item newGoldItem(int accountID, mbEnums.ItemContainerType containerType) {
return newGoldItem(accountID, containerType, true);
}
private static Item newGoldItem(int accountID, mbEnums.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, mbEnums.ItemContainerType containerType, boolean persist) {
int ownerID;
OwnerType ownerType;
if (awo.getObjectType().equals(GameObjectType.Mob))
return null;
if (containerType == mbEnums.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 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<AbstractEffectModifier, Float> 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 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 = mbEnums.ItemContainerType.NONE;
this.equipSlot = EquipSlotType.NONE;
}
protected void validateItemContainer() {
if (this.containerType == mbEnums.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 = mbEnums.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, ItemContainerType.NONE, EquipSlotType.NONE);
this.zeroItem();
//cleanup item from server.
this.removeFromCache();
}
protected synchronized boolean moveItemToInventory(PlayerCharacter pc) {
if (!DbManager.ItemQueries.UPDATE_OWNER(this,
pc.getObjectUUID(), //tableID
//isNPC
//isPlayer
//isAccount
ItemContainerType.INVENTORY,
EquipSlotType.NONE)) //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, ItemContainerType.INVENTORY, EquipSlotType.NONE))
return false;
} else if (!DbManager.ItemQueries.UPDATE_OWNER(this,
npc.getObjectUUID(), //UUID
//isNPC
//isPlayer
//isAccount
ItemContainerType.INVENTORY,
EquipSlotType.NONE)) //Slot
return false;
this.zeroItem();
this.ownerID = npc.getObjectUUID();
this.ownerType = OwnerType.Npc;
this.containerType = mbEnums.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
//isNPC
//isPlayer
//isAccount
ItemContainerType.INVENTORY,
EquipSlotType.NONE)) //Slot
return false;
this.zeroItem();
this.ownerID = 0;
this.ownerType = null;
this.containerType = mbEnums.ItemContainerType.INVENTORY;
this.equipSlot = EquipSlotType.NONE;
return true;
}
protected synchronized boolean moveItemToBank(PlayerCharacter pc) {
if (!DbManager.ItemQueries.UPDATE_OWNER(this,
pc.getObjectUUID(), //UUID
//isNPC
//isPlayer
//isAccount
ItemContainerType.BANK,
EquipSlotType.NONE)) //Slot
return false;
this.zeroItem();
this.ownerID = pc.getObjectUUID();
this.ownerType = OwnerType.PlayerCharacter;
this.containerType = mbEnums.ItemContainerType.BANK;
this.equipSlot = EquipSlotType.NONE;
return true;
}
protected synchronized boolean moveItemToBank(NPC npc) {
if (!DbManager.ItemQueries.UPDATE_OWNER(this,
npc.getObjectUUID(), //UUID
//isNPC
//isPlayer
//isAccount
ItemContainerType.BANK,
EquipSlotType.NONE)) //Slot
return false;
this.zeroItem();
this.ownerID = npc.getObjectUUID();
this.ownerType = OwnerType.Npc;
this.containerType = mbEnums.ItemContainerType.BANK;
this.equipSlot = EquipSlotType.NONE;
return true;
}
protected synchronized boolean moveItemToVault(Account a) {
if (!DbManager.ItemQueries.UPDATE_OWNER(this,
a.getObjectUUID(), //UUID
//isNPC
//isPlayer
//isAccount
ItemContainerType.VAULT,
EquipSlotType.NONE)) //Slot
return false;
this.zeroItem();
this.ownerID = a.getObjectUUID();
this.ownerType = OwnerType.Account;
this.containerType = mbEnums.ItemContainerType.VAULT;
this.equipSlot = EquipSlotType.NONE;
return true;
}
protected synchronized boolean equipItem(PlayerCharacter pc, mbEnums.EquipSlotType slot) {
if (!DbManager.ItemQueries.UPDATE_OWNER(this,
pc.getObjectUUID(), //tableID
//isNPC
//isPlayer
//isAccount
ItemContainerType.EQUIPPED,
slot)) //Slot
return false;
this.zeroItem();
this.ownerID = pc.getObjectUUID();
this.ownerType = OwnerType.PlayerCharacter;
this.containerType = mbEnums.ItemContainerType.EQUIPPED;
this.equipSlot = slot;
return true;
}
protected synchronized boolean equipItem(NPC npc, mbEnums.EquipSlotType slot) {
this.zeroItem();
this.ownerID = npc.getObjectUUID();
this.ownerType = OwnerType.Npc;
this.containerType = mbEnums.ItemContainerType.EQUIPPED;
this.equipSlot = slot;
return true;
}
protected synchronized boolean equipItem(Mob mobile, mbEnums.EquipSlotType slot) {
this.zeroItem();
this.ownerID = mobile.getObjectUUID();
this.ownerType = OwnerType.Mob;
this.containerType = mbEnums.ItemContainerType.EQUIPPED;
this.equipSlot = slot;
return true;
}
private void loadTemplateEnchantments() {
EffectsBase effect;
LinkedHashMap<String, int[]> templateEnchantments = new LinkedHashMap<>();
if (ConfigManager.serverType.equals(mbEnums.ServerType.LOGINSERVER))
return;
// Duplicate powers collapse to the last entry; applying one twice would double its magic value.
for (UserPowerAction userPowerAction : this.template.getItemUserPowerAction())
templateEnchantments.put(userPowerAction.power, userPowerAction.arguments);
for (String effectID : templateEnchantments.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, templateEnchantments.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.getItemValue() + calcMagicValue();
return;
}
ConcurrentHashMap<String, Integer> 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);
}
}
// Value is overridden the db
if (this.value == this.template.getItemValue())
this.magicValue = this.template.getItemValue() + 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);
}
public 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<String> 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);
DispatchManager.dispatchMsgDispatch(dispatch, mbEnums.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);
DispatchManager.dispatchMsgDispatch(dispatch, mbEnums.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.getItemInitialCharges() > 0)
modifiedValue = modifiedValue * (this.chargesRemaining / this.template.getItemInitialCharges());
if (this.template.getCombatHealthFull() > 0)
modifiedValue = (int) (modifiedValue * (this.combat_health_current / this.template.getCombatHealthFull()));
return modifiedValue;
}
/**
* @param value the value to set
*/
public void setValue(int value) {
this.value = value;
}
public boolean isCustomValue() {
if (this.value == 0)
return false;
return true;
}
}