forked from MagicBane/Server
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.
1171 lines
38 KiB
1171 lines
38 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.EnumSet; |
|
import java.util.Iterator; |
|
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 Enum.ItemContainerType containerType; |
|
public ReentrantLock lootLock = new ReentrantLock(); |
|
public int ownerID; //may be character, account, npc, mob |
|
public float drop_chance; |
|
public EnumSet<Enum.ItemFlags> flags = EnumSet.noneOf(ItemFlags.class); |
|
public int numberOfItems; |
|
public float combat_health_current; |
|
public int chargesRemaining; |
|
public Enum.EquipSlotType equipSlot; |
|
private boolean canDestroy; |
|
private boolean isRandom = false; |
|
public int value; |
|
public OwnerType ownerType; |
|
public int templateID; |
|
private long dateToUpgrade; |
|
public int magicValue; |
|
public ItemTemplate template; |
|
public String name = ""; |
|
|
|
/** |
|
* In Memory constructor |
|
* Set values and call PERSIST(); |
|
*/ |
|
|
|
public Item(int templateID) { |
|
super(); |
|
this.templateID = templateID; |
|
this.template = ItemTemplate.templates.get(templateID); |
|
this.chargesRemaining = this.template.item_initial_charges; |
|
this.combat_health_current = this.template.combat_health_full; |
|
this.equipSlot = EquipSlotType.NONE; |
|
this.containerType = ItemContainerType.NONE; |
|
this.numberOfItems = 1; |
|
this.flags.addAll(this.template.item_flags); |
|
this.value = this.template.item_value; |
|
this.magicValue = this.value + calcMagicValue(); |
|
loadTemplateEnchantments(); |
|
} |
|
|
|
/** |
|
* ResultSet Constructor |
|
*/ |
|
public Item(ResultSet rs) throws SQLException { |
|
super(rs); |
|
|
|
this.templateID = rs.getInt("templateID"); |
|
this.template = ItemTemplate.templates.get(this.templateID); |
|
|
|
if (this.template == null) |
|
Logger.error("Null template of " + this.templateID); |
|
|
|
// Name override in db. |
|
|
|
this.name = rs.getString("name"); |
|
|
|
if (this.name == null) |
|
this.name = ""; |
|
|
|
// Set container enumeration |
|
|
|
String container = rs.getString("container"); |
|
|
|
switch (container) { |
|
case "inventory": |
|
this.containerType = Enum.ItemContainerType.INVENTORY; |
|
break; |
|
case "bank": |
|
this.containerType = Enum.ItemContainerType.BANK; |
|
break; |
|
case "vault": |
|
this.containerType = Enum.ItemContainerType.VAULT; |
|
break; |
|
case "equip": |
|
this.containerType = Enum.ItemContainerType.EQUIPPED; |
|
break; |
|
case "forge": |
|
this.containerType = Enum.ItemContainerType.FORGE; |
|
break; |
|
case "warehouse": |
|
this.containerType = ItemContainerType.WAREHOUSE; |
|
break; |
|
} |
|
|
|
this.ownerID = rs.getInt("parent"); |
|
|
|
this.chargesRemaining = rs.getByte("chargesRemaining"); |
|
|
|
this.combat_health_current = rs.getShort("combat_health_current"); |
|
|
|
DbObjectType ownerType; |
|
ownerType = DbManager.BuildingQueries.GET_UID_ENUM(this.ownerID); |
|
|
|
switch (ownerType) { |
|
case CHARACTER: |
|
this.ownerType = OwnerType.PlayerCharacter; |
|
break; |
|
case NPC: |
|
this.ownerType = OwnerType.Npc; |
|
break; |
|
case ACCOUNT: |
|
this.ownerType = OwnerType.Account; |
|
break; |
|
} |
|
|
|
this.canDestroy = true; |
|
|
|
this.equipSlot = EquipSlotType.values()[rs.getByte("equipSlot")]; |
|
|
|
this.numberOfItems = rs.getInt("numberOfItems"); |
|
|
|
String flagString = rs.getString("flags"); |
|
|
|
if (flagString.isEmpty() == false) |
|
for (String itemFlag : flagString.split(";")) |
|
this.flags.add(Enum.ItemFlags.valueOf(itemFlag)); |
|
|
|
this.dateToUpgrade = rs.getLong("dateToUpgrade"); |
|
this.value = rs.getInt("value"); |
|
|
|
if (this.value == 0) |
|
this.value = this.template.item_value; |
|
|
|
} |
|
|
|
public static void _serializeForClientMsg(Item item, ByteBufferWriter writer) |
|
throws SerializationException { |
|
Item._serializeForClientMsg(item, writer, true); |
|
} |
|
|
|
public static void serializeForClientMsgWithoutSlot(Item item, ByteBufferWriter writer) { |
|
Item._serializeForClientMsg(item, writer, false); |
|
} |
|
|
|
public static void serializeForClientMsgForVendor(Item item, ByteBufferWriter writer, float percent) { |
|
Item._serializeForClientMsg(item, writer, true); |
|
int baseValue = item.magicValue; |
|
writer.putInt(baseValue); |
|
writer.putInt((int) (baseValue * percent)); |
|
} |
|
|
|
public static void serializeForClientMsgForVendorWithoutSlot(Item item, ByteBufferWriter writer, float percent) { |
|
Item._serializeForClientMsg(item, writer, false); |
|
writer.putInt(item.getValue()); |
|
writer.putInt(item.getValue()); |
|
} |
|
|
|
public static void _serializeForClientMsg(Item item, ByteBufferWriter writer, |
|
boolean includeSlot) { |
|
if (includeSlot) |
|
writer.putInt(item.equipSlot.ordinal()); |
|
writer.putInt(0); // Pad |
|
writer.putInt(item.templateID); |
|
|
|
writer.putInt(item.getObjectType().ordinal()); |
|
writer.putInt(item.getObjectUUID()); |
|
|
|
// Unknown statics |
|
for (int i = 0; i < 3; i++) { |
|
writer.putInt(0); // Pad |
|
} |
|
for (int i = 0; i < 4; i++) { |
|
writer.putInt(0x3F800000); // Static |
|
} |
|
for (int i = 0; i < 5; i++) { |
|
writer.putInt(0); // Pad |
|
} |
|
for (int i = 0; i < 2; i++) { |
|
writer.putInt(0xFFFFFFFF); // Static |
|
} |
|
|
|
// Handle Hair / Beard / horns Color. |
|
boolean isHair = (item.equipSlot.equals(EquipSlotType.HAIR)); |
|
boolean isBeard = (item.equipSlot.equals(EquipSlotType.BEARD)); |
|
|
|
int itemColor = 0; |
|
|
|
if (isHair || isBeard) { |
|
PlayerCharacter pc = PlayerCharacter.getFromCache(item.ownerID); |
|
if (pc != null) |
|
if (isHair) |
|
itemColor = pc.getHairColor(); |
|
else if (isBeard) |
|
itemColor = pc.getBeardColor(); |
|
} |
|
writer.putInt(itemColor); |
|
|
|
writer.put((byte) 1); // End Datablock byte |
|
writer.putString(item.name); // Unknown. pad? |
|
writer.put((byte) 1); // End Datablock byte |
|
|
|
writer.putFloat(item.template.combat_health_full); |
|
writer.putFloat((float) item.combat_health_current); |
|
|
|
writer.put((byte) 1); // End Datablock byte |
|
|
|
writer.putInt(0); // Pad |
|
writer.putInt(0); // Pad |
|
|
|
if (item.templateID == ResourceType.GOLD.templateID) { |
|
|
|
if (item.getOwner() != null && item.getOwner().getObjectType() == GameObjectType.PlayerCharacter) { |
|
PlayerCharacter player = (PlayerCharacter) item.getOwner(); |
|
int tradingAmount = player.charItemManager.getGoldTrading(); |
|
writer.putInt(item.numberOfItems - tradingAmount); |
|
} else |
|
writer.putInt(item.numberOfItems); // Amount of gold |
|
} else |
|
writer.putInt(item.template.item_value); |
|
|
|
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.item_user_power_action.size() > 0) |
|
writer.putInt(36); //Magical, blue name |
|
else |
|
writer.putInt(4); //Non-Magical, grey name |
|
writer.putInt(item.chargesRemaining); |
|
writer.putInt(0); // Pad |
|
writer.putInt(item.numberOfItems); |
|
writer.put((byte) 0); |
|
|
|
|
|
if (item.template.item_type.equals(ItemType.EMPLOYMENTCONTRACT) == false) { |
|
writer.putShort((short) 0); |
|
return; |
|
} |
|
writer.put((byte) 1); // |
|
writer.putInt(0); |
|
writer.putInt(0); |
|
if (item.chargesRemaining == 0) |
|
writer.putInt(1); |
|
else |
|
writer.putInt(item.chargesRemaining); |
|
writer.put((byte) 0); |
|
} |
|
|
|
public static void SerializeTradingGold(PlayerCharacter player, ByteBufferWriter writer) { |
|
|
|
writer.putInt(0); // Pad |
|
writer.putInt(7); |
|
|
|
writer.putInt(GameObjectType.Item.ordinal()); |
|
writer.putInt(player.getObjectUUID()); |
|
|
|
// Unknown statics |
|
for (int i = 0; i < 3; i++) { |
|
writer.putInt(0); // Pad |
|
} |
|
for (int i = 0; i < 4; i++) { |
|
writer.putInt(0x3F800000); // Static |
|
} |
|
for (int i = 0; i < 5; i++) { |
|
writer.putInt(0); // Pad |
|
} |
|
for (int i = 0; i < 2; i++) { |
|
writer.putInt(0xFFFFFFFF); // Static |
|
} |
|
|
|
// Handle Hair / Beard / horns Color. |
|
|
|
int itemColor = 0; |
|
writer.putInt(itemColor); |
|
|
|
writer.put((byte) 1); // End Datablock byte |
|
writer.putInt(0); |
|
writer.put((byte) 1); // End Datablock byte |
|
|
|
writer.putFloat((float) 1); |
|
writer.putFloat((float) 1); |
|
|
|
writer.put((byte) 1); // End Datablock byte |
|
|
|
writer.putInt(0); // Pad |
|
writer.putInt(0); // Pad |
|
|
|
|
|
writer.putInt(player.charItemManager.getGoldTrading()); // Amount of gold |
|
|
|
|
|
writer.putInt(0); |
|
|
|
|
|
writer.putInt(0); |
|
|
|
writer.putInt(0x00000000); |
|
|
|
writer.putInt(4); //Non-Magical, grey name |
|
writer.putInt(1); |
|
writer.putInt(0); // Pad |
|
writer.putInt(player.charItemManager.getGoldTrading()); |
|
writer.put((byte) 0); |
|
|
|
writer.putShort((short) 0); |
|
|
|
} |
|
|
|
public static boolean MakeItemForPlayer(int templateID, PlayerCharacter reciever, int amount) { |
|
|
|
boolean itemWorked = false; |
|
|
|
Item item = new Item(templateID); |
|
|
|
item.ownerID = reciever.getObjectUUID(); |
|
item.ownerType = OwnerType.PlayerCharacter; |
|
item.containerType = Enum.ItemContainerType.INVENTORY; |
|
item.numberOfItems = amount; |
|
|
|
try { |
|
item = DbManager.ItemQueries.PERSIST(item); |
|
itemWorked = true; |
|
} catch (Exception e) { |
|
Logger.error(e); |
|
} |
|
|
|
if (!itemWorked) |
|
return false; |
|
|
|
reciever.charItemManager.addItemToInventory(item); |
|
reciever.charItemManager.updateInventory(); |
|
|
|
return true; |
|
} |
|
|
|
public static Item deserializeFromClientMsg(ByteBufferReader reader, |
|
boolean includeSlot) { |
|
if (includeSlot) |
|
reader.getInt(); |
|
reader.getInt(); |
|
int objectType = reader.getInt(); //object type; |
|
int UUID = reader.getInt(); |
|
for (int i = 0; i < 14; i++) { |
|
reader.getInt(); // Pads and statics |
|
} |
|
int unknown = reader.getInt(); |
|
|
|
byte readString = reader.get(); |
|
if (readString == 1) |
|
reader.getString(); |
|
byte readDurability = reader.get(); |
|
if (readDurability == 1) { |
|
reader.getInt(); |
|
reader.getInt(); |
|
} |
|
|
|
byte readEnchants = reader.get(); |
|
if (readEnchants == 1) { |
|
reader.getInt(); |
|
reader.getInt(); |
|
reader.getInt(); |
|
reader.getInt(); |
|
int enchantSize = reader.getInt(); |
|
for (int i = 0; i < enchantSize; i++) { |
|
reader.getInt(); //effect token |
|
reader.getInt(); //trains |
|
int type = reader.getInt(); |
|
reader.get(); |
|
if (type == 1) |
|
reader.getLong(); //item comp |
|
else |
|
reader.getInt(); //power token |
|
reader.getString(); //name |
|
reader.getFloat(); //duration |
|
} |
|
for (int i = 0; i < 5; i++) { |
|
reader.getInt(); |
|
} |
|
} |
|
|
|
reader.get(); |
|
byte isContract = reader.get(); |
|
if (isContract == 1) { |
|
reader.getInt(); |
|
reader.getInt(); |
|
reader.getInt(); |
|
} |
|
reader.get(); |
|
|
|
if (UUID == 0 || objectType == 0) |
|
return null; |
|
if (objectType == GameObjectType.MobLoot.ordinal()) |
|
return MobLoot.getFromCache(UUID); |
|
return Item.getFromCache(UUID); |
|
} |
|
|
|
public static void putListForVendor(ByteBufferWriter writer, ArrayList<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.item_type.equals(ItemType.GOLD)) |
|
if (item.numberOfItems == 0) |
|
continue; |
|
try { |
|
if (includeSlot && !forVendor) |
|
Item._serializeForClientMsg(item, writer); |
|
else if (!includeSlot && !forVendor) |
|
Item.serializeForClientMsgWithoutSlot(item, writer); |
|
|
|
if (!includeSlot && forVendor) //TODO separate for sell/buy percent |
|
|
|
Item.serializeForClientMsgForVendorWithoutSlot(item, writer, vendor.getSellPercent()); |
|
|
|
if (includeSlot && forVendor) //TODO separate for sell/buy percent |
|
|
|
Item.serializeForClientMsgForVendor(item, writer, vendor.getSellPercent()); |
|
|
|
} catch (SerializationException se) { |
|
continue; |
|
} |
|
++serialized; |
|
} |
|
|
|
writer.putIntAt(serialized, indexPosition); |
|
} |
|
|
|
public static void putTradingList(PlayerCharacter player, ByteBufferWriter writer, ArrayList<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.item_type.equals(ItemType.GOLD)) |
|
if (item.numberOfItems == 0) |
|
continue; |
|
try { |
|
if (includeSlot && !forVendor) |
|
Item._serializeForClientMsg(item, writer); |
|
else if (!includeSlot && !forVendor) |
|
Item.serializeForClientMsgWithoutSlot(item, writer); |
|
|
|
if (!includeSlot && forVendor) //TODO separate for sell/buy percent |
|
|
|
Item.serializeForClientMsgForVendorWithoutSlot(item, writer, vendor.getSellPercent()); |
|
|
|
if (includeSlot && forVendor) //TODO separate for sell/buy percent |
|
|
|
Item.serializeForClientMsgForVendor(item, writer, vendor.getSellPercent()); |
|
|
|
} catch (SerializationException se) { |
|
continue; |
|
} |
|
++serialized; |
|
} |
|
if (player.charItemManager.getGoldTrading() > 0) { |
|
Item.SerializeTradingGold(player, writer); |
|
++serialized; |
|
} |
|
|
|
|
|
writer.putIntAt(serialized, indexPosition); |
|
} |
|
|
|
public static Item getFromCache(int id) { |
|
return (Item) DbManager.getFromCache(GameObjectType.Item, id); |
|
} |
|
|
|
public static Item newGoldItem(AbstractWorldObject awo, Enum.ItemContainerType containerType) { |
|
return newGoldItem(awo, containerType, true); |
|
} |
|
|
|
//used for vault! |
|
public static Item newGoldItem(int accountID, Enum.ItemContainerType containerType) { |
|
return newGoldItem(accountID, containerType, true); |
|
} |
|
|
|
private static Item newGoldItem(int accountID, Enum.ItemContainerType containerType, boolean persist) { |
|
|
|
int ownerID; |
|
OwnerType ownerType; |
|
|
|
ownerID = accountID; |
|
ownerType = OwnerType.Account; |
|
|
|
Item newGold = new Item(ResourceType.GOLD.templateID); |
|
newGold.ownerID = ownerID; |
|
newGold.ownerType = ownerType; |
|
newGold.containerType = containerType; |
|
newGold.numberOfItems = 0; |
|
|
|
if (persist) { |
|
try { |
|
newGold = DbManager.ItemQueries.PERSIST(newGold); |
|
DbManager.ItemQueries.ZERO_ITEM_STACK(newGold); |
|
} catch (Exception e) { |
|
Logger.error(e); |
|
} |
|
} |
|
|
|
return newGold; |
|
} |
|
|
|
private static Item newGoldItem(AbstractWorldObject awo, Enum.ItemContainerType containerType, boolean persist) { |
|
|
|
int ownerID; |
|
OwnerType ownerType; |
|
|
|
if (awo.getObjectType().equals(GameObjectType.Mob)) |
|
return null; |
|
|
|
if (containerType == Enum.ItemContainerType.VAULT) { |
|
if (!(awo.getObjectType().equals(GameObjectType.PlayerCharacter))) { |
|
Logger.error("AWO is not a PlayerCharacter"); |
|
return null; |
|
} |
|
ownerID = ((PlayerCharacter) awo).getAccount().getObjectUUID(); |
|
ownerType = OwnerType.Account; |
|
} else { |
|
|
|
ownerID = awo.getObjectUUID(); |
|
|
|
switch (awo.getObjectType()) { |
|
|
|
case NPC: |
|
ownerType = OwnerType.Npc; |
|
break; |
|
case PlayerCharacter: |
|
ownerType = OwnerType.PlayerCharacter; |
|
break; |
|
case Mob: |
|
ownerType = OwnerType.Mob; |
|
break; |
|
default: |
|
Logger.error("Unsupported AWO object type."); |
|
return null; |
|
} |
|
} |
|
|
|
Item newGold = new Item(ResourceType.GOLD.templateID); |
|
newGold.ownerID = ownerID; |
|
newGold.ownerType = ownerType; |
|
newGold.containerType = containerType; |
|
newGold.numberOfItems = 0; |
|
|
|
if (persist) { |
|
try { |
|
newGold = DbManager.ItemQueries.PERSIST(newGold); |
|
} catch (Exception e) { |
|
Logger.error(e); |
|
} |
|
DbManager.ItemQueries.ZERO_ITEM_STACK(newGold); |
|
} |
|
|
|
return newGold; |
|
} |
|
|
|
public static void addEnchantValue(String enchant, int value) { |
|
Item.enchantValues.put(enchant, value); |
|
} |
|
|
|
public static int getEnchantValue(String enchant) { |
|
if (Item.enchantValues.containsKey(enchant)) |
|
return Item.enchantValues.get(enchant); |
|
return 0; |
|
} |
|
|
|
public int getTemplateID() { |
|
return this.templateID; |
|
} |
|
|
|
public int getOwnerID() { |
|
return ownerID; |
|
} |
|
|
|
//Only to be used for trading |
|
public void setOwnerID(int ownerID) { |
|
this.ownerID = ownerID; |
|
} |
|
|
|
public AbstractGameObject getOwner() { |
|
if (this.ownerType == OwnerType.Npc) |
|
return NPC.getFromCache(this.ownerID); |
|
else if (this.ownerType == OwnerType.PlayerCharacter) |
|
return PlayerCharacter.getFromCache(this.ownerID); |
|
else if (this.ownerType == OwnerType.Mob) |
|
return Mob.getFromCache(this.ownerID); |
|
else if (this.ownerType == OwnerType.Account) |
|
return DbManager.AccountQueries.GET_ACCOUNT(this.ownerID); |
|
else |
|
return null; |
|
} |
|
|
|
public boolean setOwner(AbstractGameObject owner) { |
|
if (owner == null) |
|
return false; |
|
if (owner.getObjectType().equals(GameObjectType.NPC)) |
|
this.ownerType = OwnerType.Npc; |
|
else if (owner.getObjectType().equals(GameObjectType.PlayerCharacter)) |
|
this.ownerType = OwnerType.PlayerCharacter; |
|
else if (owner.getObjectType().equals(GameObjectType.Mob)) |
|
this.ownerType = OwnerType.Mob; |
|
else if (owner.getObjectType().equals(GameObjectType.Account)) |
|
this.ownerType = OwnerType.Account; |
|
else |
|
return false; |
|
this.ownerID = owner.getObjectUUID(); |
|
return true; |
|
} |
|
|
|
public void setCombat_health_current(float value) { |
|
this.combat_health_current = value; |
|
} |
|
|
|
public boolean isCanDestroy() { |
|
return canDestroy; |
|
} |
|
|
|
public int getNumOfItems() { |
|
return this.numberOfItems; |
|
} |
|
|
|
public synchronized void setNumOfItems(int numberOfItems) { |
|
this.numberOfItems = numberOfItems; |
|
} |
|
|
|
public ConcurrentHashMap<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 void multBonus(AbstractEffectModifier key, float amount) { |
|
if (this.bonuses.containsKey(key)) |
|
this.bonuses.put(key, (this.bonuses.get(key) * amount)); |
|
else |
|
this.bonuses.put(key, amount); |
|
} |
|
|
|
public synchronized void decrementChargesRemaining() { |
|
this.chargesRemaining -= 1; |
|
if (this.chargesRemaining < 0) |
|
this.chargesRemaining = 0; |
|
DbManager.ItemQueries.UPDATE_REMAINING_CHARGES(this); |
|
} |
|
|
|
public void zeroItem() { |
|
this.ownerID = 0; |
|
|
|
this.ownerType = null; |
|
this.containerType = Enum.ItemContainerType.NONE; |
|
this.equipSlot = EquipSlotType.NONE; |
|
} |
|
|
|
protected void validateItemContainer() { |
|
|
|
if (this.containerType == Enum.ItemContainerType.NONE) |
|
|
|
if (this.ownerID != 0) |
|
// Item has an owner, just somehow the flags got messed up. |
|
// Default to bank. |
|
// TODO NEED LOG EVENT HERE. |
|
this.containerType = Enum.ItemContainerType.BANK; |
|
else |
|
// This item is on the ground. Nothing to worry about. |
|
this.zeroItem(); |
|
} |
|
|
|
// Removes all ownership of item and 'orphans' it. |
|
protected synchronized void junk() { |
|
|
|
DbManager.ItemQueries.UPDATE_OWNER(this, 0, false, false, false, ItemContainerType.NONE, 0); |
|
this.zeroItem(); |
|
|
|
//cleanup item from server. |
|
|
|
this.removeFromCache(); |
|
} |
|
|
|
protected synchronized boolean moveItemToInventory(PlayerCharacter pc) { |
|
|
|
if (!DbManager.ItemQueries.UPDATE_OWNER(this, |
|
pc.getObjectUUID(), //tableID |
|
false, //isNPC |
|
true, //isPlayer |
|
false, //isAccount |
|
ItemContainerType.INVENTORY, |
|
0)) //Slot |
|
return false; |
|
|
|
this.ownerID = pc.getObjectUUID(); |
|
this.ownerType = OwnerType.PlayerCharacter; |
|
this.containerType = ItemContainerType.INVENTORY; |
|
this.equipSlot = EquipSlotType.NONE; |
|
return true; |
|
} |
|
|
|
protected synchronized boolean moveItemToInventory(NPC npc) { |
|
if (npc.isStatic()) { |
|
if (!DbManager.ItemQueries.UPDATE_OWNER(this, 0, false, false, false, ItemContainerType.INVENTORY, 0)) |
|
return false; |
|
} else if (!DbManager.ItemQueries.UPDATE_OWNER(this, |
|
npc.getObjectUUID(), //UUID |
|
true, //isNPC |
|
false, //isPlayer |
|
false, //isAccount |
|
ItemContainerType.INVENTORY, |
|
0)) //Slot |
|
|
|
return false; |
|
this.zeroItem(); |
|
this.ownerID = npc.getObjectUUID(); |
|
this.ownerType = OwnerType.Npc; |
|
this.containerType = Enum.ItemContainerType.INVENTORY; |
|
this.equipSlot = EquipSlotType.NONE; |
|
return true; |
|
} |
|
|
|
protected synchronized boolean moveItemToInventory(Corpse corpse) { |
|
if (!DbManager.ItemQueries.UPDATE_OWNER(this, |
|
0, //no ID for corpse |
|
false, //isNPC |
|
true, //isPlayer |
|
false, //isAccount |
|
ItemContainerType.INVENTORY, |
|
0)) //Slot |
|
|
|
return false; |
|
this.zeroItem(); |
|
this.ownerID = 0; |
|
this.ownerType = null; |
|
this.containerType = Enum.ItemContainerType.INVENTORY; |
|
this.equipSlot = EquipSlotType.NONE; |
|
return true; |
|
} |
|
|
|
protected synchronized boolean moveItemToBank(PlayerCharacter pc) { |
|
if (!DbManager.ItemQueries.UPDATE_OWNER(this, |
|
pc.getObjectUUID(), //UUID |
|
false, //isNPC |
|
true, //isPlayer |
|
false, //isAccount |
|
ItemContainerType.BANK, |
|
0)) //Slot |
|
|
|
return false; |
|
this.zeroItem(); |
|
this.ownerID = pc.getObjectUUID(); |
|
this.ownerType = OwnerType.PlayerCharacter; |
|
this.containerType = Enum.ItemContainerType.BANK; |
|
this.equipSlot = EquipSlotType.NONE; |
|
return true; |
|
} |
|
|
|
protected synchronized boolean moveItemToBank(NPC npc) { |
|
if (!DbManager.ItemQueries.UPDATE_OWNER(this, |
|
npc.getObjectUUID(), //UUID |
|
true, //isNPC |
|
false, //isPlayer |
|
false, //isAccount |
|
ItemContainerType.BANK, |
|
0)) //Slot |
|
|
|
return false; |
|
this.zeroItem(); |
|
this.ownerID = npc.getObjectUUID(); |
|
this.ownerType = OwnerType.Npc; |
|
this.containerType = Enum.ItemContainerType.BANK; |
|
this.equipSlot = EquipSlotType.NONE; |
|
return true; |
|
} |
|
|
|
protected synchronized boolean moveItemToVault(Account a) { |
|
if (!DbManager.ItemQueries.UPDATE_OWNER(this, |
|
a.getObjectUUID(), //UUID |
|
false, //isNPC |
|
false, //isPlayer |
|
true, //isAccount |
|
ItemContainerType.VAULT, |
|
0)) //Slot |
|
|
|
return false; |
|
this.zeroItem(); |
|
this.ownerID = a.getObjectUUID(); |
|
this.ownerType = OwnerType.Account; |
|
this.containerType = Enum.ItemContainerType.VAULT; |
|
this.equipSlot = EquipSlotType.NONE; |
|
return true; |
|
} |
|
|
|
protected synchronized boolean equipItem(PlayerCharacter pc, Enum.EquipSlotType slot) { |
|
|
|
if (!DbManager.ItemQueries.UPDATE_OWNER(this, |
|
pc.getObjectUUID(), //tableID |
|
false, //isNPC |
|
true, //isPlayer |
|
false, //isAccount |
|
ItemContainerType.EQUIPPED, |
|
slot.ordinal())) //Slot |
|
|
|
return false; |
|
this.zeroItem(); |
|
this.ownerID = pc.getObjectUUID(); |
|
this.ownerType = OwnerType.PlayerCharacter; |
|
this.containerType = Enum.ItemContainerType.EQUIPPED; |
|
this.equipSlot = slot; |
|
return true; |
|
} |
|
|
|
protected synchronized boolean equipItem(NPC npc, Enum.EquipSlotType slot) { |
|
if (!DbManager.ItemQueries.UPDATE_OWNER(this, |
|
npc.getObjectUUID(), //UUID |
|
true, //isNPC |
|
false, //isPlayer |
|
false, //isAccount |
|
ItemContainerType.EQUIPPED, |
|
slot.ordinal())) //Slot |
|
|
|
return false; |
|
this.zeroItem(); |
|
this.ownerID = npc.getObjectUUID(); |
|
this.ownerType = OwnerType.Npc; |
|
this.containerType = Enum.ItemContainerType.EQUIPPED; |
|
this.equipSlot = slot; |
|
return true; |
|
} |
|
|
|
protected synchronized boolean equipItem(Mob npc, Enum.EquipSlotType slot) { |
|
|
|
this.zeroItem(); |
|
this.ownerID = npc.getObjectUUID(); |
|
this.ownerType = OwnerType.Mob; |
|
this.containerType = Enum.ItemContainerType.EQUIPPED; |
|
this.equipSlot = slot; |
|
return true; |
|
} |
|
|
|
private void loadTemplateEnchantments() { |
|
|
|
EffectsBase effect; |
|
|
|
if (ConfigManager.serverType.equals(Enum.ServerType.LOGINSERVER)) |
|
return; |
|
|
|
|
|
for (String effectID : this.template.item_user_power_action.keySet()) { |
|
|
|
effect = PowersManager.getEffectByIDString(effectID); |
|
|
|
if (effect == null) { |
|
Logger.error("missing effect of type: " + effectID); |
|
continue; |
|
} |
|
|
|
AbstractPowerAction apa = PowersManager.getPowerActionByIDString(effect.getIDString()); |
|
apa.applyBakedInStatsForItem(this, this.template.item_user_power_action.get(effectID)[0]); |
|
} |
|
} |
|
|
|
public final void loadEnchantments() { |
|
|
|
// No enchantments for negative id items in the db. Early exit. |
|
|
|
if (this.objectUUID < 0) { |
|
this.magicValue = this.template.item_value + calcMagicValue(); |
|
return; |
|
} |
|
|
|
ConcurrentHashMap<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.template.item_value + calcMagicValue(); |
|
} |
|
|
|
public void addPermanentEnchantment(String enchantID, int rank) { |
|
AbstractPowerAction apa = PowersManager.getPowerActionByIDString(enchantID); |
|
if (apa == null) |
|
return; |
|
|
|
DbManager.EnchantmentQueries.CREATE_ENCHANTMENT_FOR_ITEM((long) this.getObjectUUID(), enchantID, rank); |
|
apa.applyEffectForItem(this, rank); |
|
this.effectNames.add(enchantID); |
|
} |
|
|
|
public void addPermanentEnchantmentForDev(String enchantID, int rank) { |
|
AbstractPowerAction apa = PowersManager.getPowerActionByIDString(enchantID); |
|
if (apa == null) |
|
return; |
|
|
|
DbManager.EnchantmentQueries.CREATE_ENCHANTMENT_FOR_ITEM((long) this.getObjectUUID(), enchantID, rank); |
|
apa.applyEffectForItem(this, rank); |
|
this.effectNames.add(enchantID); |
|
} |
|
|
|
protected int calcMagicValue() { |
|
int ret = 0; |
|
for (String enchant : this.effectNames) { |
|
ret += Item.getEnchantValue(enchant + 'A'); |
|
} |
|
return ret; |
|
} |
|
|
|
public void addToCache() { |
|
DbManager.addToCache(this); |
|
} |
|
|
|
@Override |
|
public void updateDatabase() { |
|
//DbManager.ItemQueries.updateDatabase(this); |
|
} |
|
|
|
@Override |
|
public void runAfterLoad() { |
|
loadEnchantments(); |
|
loadTemplateEnchantments(); |
|
} |
|
|
|
|
|
public ArrayList<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); |
|
DispatchMessage.dispatchMsgDispatch(dispatch, Enum.DispatchChannel.SECONDARY); |
|
|
|
return false; |
|
} |
|
return true; |
|
} |
|
|
|
public boolean validForVault(ClientConnection origin, PlayerCharacter pc, CharacterItemManager charItemMan) { |
|
if (origin == null || pc == null || charItemMan == null) |
|
return false; |
|
|
|
if (pc.getAccount() == null) |
|
return false; |
|
|
|
if (!pc.getAccount().getVault().contains(this)) |
|
return false; |
|
else if (ownerID != pc.getAccount().getObjectUUID()) { |
|
//duped item, cleanup |
|
Logger.warn("Duped item id " |
|
+ this.getObjectUUID() + " removed from PC " + pc.getObjectUUID() + '.'); |
|
DeleteItemMsg deleteItemMsg = new DeleteItemMsg(this.getObjectType().ordinal(), this.getObjectUUID()); |
|
charItemMan.cleanupDupe(this); |
|
Dispatch dispatch = Dispatch.borrow(pc, deleteItemMsg); |
|
DispatchMessage.dispatchMsgDispatch(dispatch, Enum.DispatchChannel.SECONDARY); |
|
return false; |
|
} |
|
return true; |
|
} |
|
|
|
public long getDateToUpgrade() { |
|
return dateToUpgrade; |
|
} |
|
|
|
public void setDateToUpgrade(long dateToUpgrade) { |
|
this.dateToUpgrade = dateToUpgrade; |
|
} |
|
|
|
/** |
|
* @return the value |
|
*/ |
|
public int getValue() { |
|
|
|
int modifiedValue; |
|
|
|
if (this.flags.contains(ItemFlags.Identified)) |
|
modifiedValue = this.magicValue; |
|
else |
|
modifiedValue = this.value; |
|
|
|
if (this.template.item_initial_charges > 0) |
|
modifiedValue = modifiedValue * (this.chargesRemaining / this.template.item_initial_charges); |
|
|
|
if (this.template.combat_health_full > 0) |
|
modifiedValue = (int) (modifiedValue * (this.combat_health_current / this.template.combat_health_full)); |
|
|
|
return modifiedValue; |
|
} |
|
|
|
/** |
|
* @param value the value to set |
|
*/ |
|
public void setValue(int value) { |
|
this.value = value; |
|
} |
|
|
|
public boolean isRandom() { |
|
return isRandom; |
|
} |
|
|
|
public void setRandom(boolean isRandom) { |
|
this.isRandom = isRandom; |
|
} |
|
|
|
public boolean isCustomValue() { |
|
if (this.value == 0) |
|
return false; |
|
return true; |
|
} |
|
}
|
|
|