Public Repository for the Magicbane Shadowbane Emulator
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1464 lines
39 KiB

// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
// 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 int ownerID; //may be character, account, npc, mob
private int flags; //1 = isIDed
private int numberOfItems;
private short durabilityCurrent;
private final short durabilityMax;
private final byte chargesMax;
private byte chargesRemaining;
private byte equipSlot;
private boolean canDestroy;
private boolean rentable;
private boolean isRandom = false;
private int value;
public Enum.ItemContainerType containerType;
private OwnerType ownerType;
private int itemBaseID;
private AbstractWorldObject lastOwner;
private ArrayList<EnchantmentBase> enchants = new ArrayList<>();
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<>();
private static ConcurrentHashMap<String, Integer> enchantValues = new ConcurrentHashMap<>(MBServerStatics.CHM_INIT_CAP, MBServerStatics.CHM_LOAD, MBServerStatics.CHM_THREAD_LOW);
private long dateToUpgrade;
public ReentrantLock lootLock = new ReentrantLock();
private String customName = "";
private 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<EnchantmentBase> 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<EnchantmentBase> 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<EnchantmentBase> 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");
String ot = DbManager.ItemQueries.GET_OWNER(this.ownerID);
if (ot.equals("character"))
this.ownerType = OwnerType.PlayerCharacter;
else if (ot.equals("npc"))
this.ownerType = OwnerType.Npc;
else if (ot.equals("account"))
this.ownerType = OwnerType.Account;
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 String getCustomName() {
return customName;
}
public void setName(String name) {
this.customName = name;
}
public ItemBase getItemBase() {
return ItemBase.getItemBase(itemBaseID);
}
public int getItemBaseID() {
return this.itemBaseID;
}
public int getOwnerID() {
return 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;
}
//Only to be used for trading
public void setOwnerID(int ownerID) {
this.ownerID = ownerID;
}
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 short getDurabilityMax() {return durabilityMax;}
public void setDurabilityCurrent(short value) {
this.durabilityCurrent = value;
}
public boolean isCanDestroy() {
return canDestroy;
}
public boolean isRentable() {
return rentable;
}
public byte getEquipSlot() {
return equipSlot;
}
public ArrayList<EnchantmentBase> getEnchants() {
return enchants;
}
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 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 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<Effect> 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<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.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 final int getMagicValue() {
return this.magicValue;
}
public int getBaseValue() {
if (this.getItemBase() != null)
return this.getItemBase().getBaseValue();
return 0;
}
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.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<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.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 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;
}
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<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);
}
}
this.magicValue = this.getItemBase().getBaseValue() + calcMagicValue();
}
public HashMap<Integer, Integer> 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 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 void addToCache() {
DbManager.addToCache(this);
}
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);
}
@Override
public void updateDatabase() {
//DbManager.ItemQueries.updateDatabase(this);
}
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;
}
@Override
public void runAfterLoad() {
loadEnchantments();
bakeInStats();
}
public ArrayList<String> 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;
}
}