/*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that
* it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If
* not, see <http://www.gnu.org/licenses/>.
*/
package silentium.gameserver.model.itemcontainer;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
import javolution.util.FastList;
import silentium.commons.database.DatabaseFactory;
import silentium.gameserver.data.xml.ArmorSetsData;
import silentium.gameserver.model.L2ArmorSet;
import silentium.gameserver.model.L2ItemInstance;
import silentium.gameserver.model.L2ItemInstance.ItemLocation;
import silentium.gameserver.model.L2Object;
import silentium.gameserver.model.L2Skill;
import silentium.gameserver.model.L2World;
import silentium.gameserver.model.actor.instance.L2PcInstance;
import silentium.gameserver.network.serverpackets.SkillCoolTime;
import silentium.gameserver.skills.SkillHolder;
import silentium.gameserver.tables.ItemTable;
import silentium.gameserver.tables.SkillTable;
import silentium.gameserver.templates.item.L2ArmorType;
import silentium.gameserver.templates.item.L2EtcItemType;
import silentium.gameserver.templates.item.L2Item;
import silentium.gameserver.templates.item.L2Weapon;
import silentium.gameserver.templates.item.L2WeaponType;
/**
* This class manages inventory
*
* @author Advi
*/
public abstract class Inventory extends ItemContainer
{
public interface PaperdollListener
{
public void notifyEquipped(int slot, L2ItemInstance inst, Inventory inventory);
public void notifyUnequipped(int slot, L2ItemInstance inst, Inventory inventory);
}
public static final int PAPERDOLL_UNDER = 0;
public static final int PAPERDOLL_LEAR = 1;
public static final int PAPERDOLL_REAR = 2;
public static final int PAPERDOLL_NECK = 3;
public static final int PAPERDOLL_LFINGER = 4;
public static final int PAPERDOLL_RFINGER = 5;
public static final int PAPERDOLL_HEAD = 6;
public static final int PAPERDOLL_RHAND = 7;
public static final int PAPERDOLL_LHAND = 8;
public static final int PAPERDOLL_GLOVES = 9;
public static final int PAPERDOLL_CHEST = 10;
public static final int PAPERDOLL_LEGS = 11;
public static final int PAPERDOLL_FEET = 12;
public static final int PAPERDOLL_BACK = 13;
public static final int PAPERDOLL_FACE = 14;
public static final int PAPERDOLL_HAIR = 15;
public static final int PAPERDOLL_HAIRALL = 16;
public static final int PAPERDOLL_TOTALSLOTS = 17;
// Speed percentage mods
public static final double MAX_ARMOR_WEIGHT = 12000;
private final L2ItemInstance[] _paperdoll;
private final List<PaperdollListener> _paperdollListeners;
// protected to be accessed from child classes only
protected int _totalWeight;
// used to quickly check for using of items of special type
private int _wearedMask;
// Recorder of alterations in inventory
private static final class ChangeRecorder implements PaperdollListener
{
private final Inventory _inventory;
private final List<L2ItemInstance> _changed;
/**
* Constructor of the ChangeRecorder
*
* @param inventory
*/
ChangeRecorder(Inventory inventory)
{
_inventory = inventory;
_changed = new FastList<>();
_inventory.addPaperdollListener(this);
}
/**
* Add alteration in inventory when item equipped
*/
@Override
public void notifyEquipped(int slot, L2ItemInstance item, Inventory inventory)
{
if (!_changed.contains(item))
_changed.add(item);
}
/**
* Add alteration in inventory when item unequipped
*/
@Override
public void notifyUnequipped(int slot, L2ItemInstance item, Inventory inventory)
{
if (!_changed.contains(item))
_changed.add(item);
}
/**
* Returns alterations in inventory
*
* @return L2ItemInstance[] : array of alterated items
*/
public L2ItemInstance[] getChangedItems()
{
return _changed.toArray(new L2ItemInstance[_changed.size()]);
}
}
private static final class BowRodListener implements PaperdollListener
{
private static BowRodListener instance = new BowRodListener();
public static BowRodListener getInstance()
{
return instance;
}
@Override
public void notifyUnequipped(int slot, L2ItemInstance item, Inventory inventory)
{
if (slot != PAPERDOLL_RHAND)
return;
if (item.getItemType() == L2WeaponType.BOW)
{
L2ItemInstance arrow = inventory.getPaperdollItem(PAPERDOLL_LHAND);
if (arrow != null)
inventory.setPaperdollItem(PAPERDOLL_LHAND, null);
}
else if (item.getItemType() == L2WeaponType.FISHINGROD)
{
L2ItemInstance lure = inventory.getPaperdollItem(PAPERDOLL_LHAND);
if (lure != null)
inventory.setPaperdollItem(PAPERDOLL_LHAND, null);
}
}
@Override
public void notifyEquipped(int slot, L2ItemInstance item, Inventory inventory)
{
if (slot != PAPERDOLL_RHAND)
return;
if (item.getItemType() == L2WeaponType.BOW)
{
L2ItemInstance arrow = inventory.findArrowForBow(item.getItem());
if (arrow != null)
inventory.setPaperdollItem(PAPERDOLL_LHAND, arrow);
}
}
}
private static final class StatsListener implements PaperdollListener
{
private static StatsListener instance = new StatsListener();
public static StatsListener getInstance()
{
return instance;
}
@Override
public void notifyUnequipped(int slot, L2ItemInstance item, Inventory inventory)
{
inventory.getOwner().removeStatsOwner(item);
}
@Override
public void notifyEquipped(int slot, L2ItemInstance item, Inventory inventory)
{
inventory.getOwner().addStatFuncs(item.getStatFuncs(inventory.getOwner()));
}
}
private static final class ItemPassiveSkillsListener implements PaperdollListener
{
private static ItemPassiveSkillsListener instance = new ItemPassiveSkillsListener();
public static ItemPassiveSkillsListener getInstance()
{
return instance;
}
@Override
public void notifyUnequipped(int slot, L2ItemInstance item, Inventory inventory)
{
if (!(inventory.getOwner() instanceof L2PcInstance))
return;
final L2PcInstance player = (L2PcInstance) inventory.getOwner();
final L2Item it = item.getItem();
boolean update = false;
if (it instanceof L2Weapon)
{
// Remove augmentation bonuses on unequip
if (item.isAugmented())
item.getAugmentation().removeBonus(player);
// Remove skills bestowed from +4 Duals
if (item.getEnchantLevel() >= 4)
{
L2Skill enchant4Skill = ((L2Weapon) it).getEnchant4Skill();
if (enchant4Skill != null)
{
player.removeSkill(enchant4Skill, false, enchant4Skill.isPassive());
update = true;
}
}
}
final SkillHolder[] skills = it.getSkills();
if (skills != null)
{
for (SkillHolder skillInfo : skills)
{
if (skillInfo == null)
continue;
L2Skill itemSkill = skillInfo.getSkill();
if (itemSkill != null)
{
player.removeSkill(itemSkill, false, itemSkill.isPassive());
update = true;
}
else
_log.warn("Inventory.ItemSkillsListener.Weapon: Incorrect skill: " + skillInfo + ".");
}
}
if (update)
player.sendSkillList();
}
@Override
public void notifyEquipped(int slot, L2ItemInstance item, Inventory inventory)
{
if (!(inventory.getOwner() instanceof L2PcInstance))
return;
final L2PcInstance player = (L2PcInstance) inventory.getOwner();
final L2Item it = item.getItem();
boolean update = false;
boolean updateTimeStamp = false;
if (it instanceof L2Weapon)
{
// Apply augmentation bonuses on equip
if (item.isAugmented())
item.getAugmentation().applyBonus(player);
// Add skills bestowed from +4 Rapiers/Duals
if (item.getEnchantLevel() >= 4)
{
L2Skill enchant4Skill = ((L2Weapon) it).getEnchant4Skill();
if (enchant4Skill != null)
{
player.addSkill(enchant4Skill, false);
update = true;
}
}
}
final SkillHolder[] skills = it.getSkills();
if (skills != null)
{
for (SkillHolder skillInfo : skills)
{
if (skillInfo == null)
continue;
L2Skill itemSkill = skillInfo.getSkill();
if (itemSkill != null)
{
player.addSkill(itemSkill, false);
if (itemSkill.isActive())
{
if (player.getReuseTimeStamp().isEmpty() || !player.getReuseTimeStamp().containsKey(itemSkill.getReuseHashCode()))
{
int equipDelay = itemSkill.getEquipDelay();
if (equipDelay > 0)
{
player.addTimeStamp(itemSkill, equipDelay);
player.disableSkill(itemSkill, equipDelay);
}
}
updateTimeStamp = true;
}
update = true;
}
else
_log.warn("Inventory.ItemSkillsListener.Weapon: Incorrect skill: " + skillInfo + ".");
}
}
if (update)
{
player.sendSkillList();
if (updateTimeStamp)
player.sendPacket(new SkillCoolTime(player));
}
}
}
private static final class ArmorSetListener implements PaperdollListener
{
private static ArmorSetListener instance = new ArmorSetListener();
public static ArmorSetListener getInstance()
{
return instance;
}
@Override
public void notifyEquipped(int slot, L2ItemInstance item, Inventory inventory)
{
if (!(inventory.getOwner() instanceof L2PcInstance))
return;
final L2PcInstance player = (L2PcInstance) inventory.getOwner();
// Checks if player is wearing a chest item
final L2ItemInstance chestItem = inventory.getPaperdollItem(PAPERDOLL_CHEST);
if (chestItem == null)
return;
// checks if there is armorset for chest item that player worns
final L2ArmorSet armorSet = ArmorSetsData.getInstance().getSet(chestItem.getItemId());
if (armorSet == null)
return;
// checks if equipped item is part of set
if (armorSet.containItem(slot, item.getItemId()))
{
if (armorSet.containAll(player))
{
L2Skill skill = SkillTable.getInstance().getInfo(armorSet.getSkillId(), 1);
if (skill != null)
{
player.addSkill(SkillTable.getInstance().getInfo(3006, 1), false);
player.addSkill(skill, false);
player.sendSkillList();
}
else
_log.warn("Inventory.ArmorSetListener: Incorrect skill: " + armorSet.getSkillId() + ".");
if (armorSet.containShield(player)) // has shield from set
{
L2Skill skills = SkillTable.getInstance().getInfo(armorSet.getShieldSkillId(), 1);
if (skills != null)
{
player.addSkill(skills, false);
player.sendSkillList();
}
else
_log.warn("Inventory.ArmorSetListener: Incorrect skill: " + armorSet.getShieldSkillId() + ".");
}
if (armorSet.isEnchanted6(player)) // has all parts of set enchanted to 6 or more
{
int skillId = armorSet.getEnchant6skillId();
if (skillId > 0)
{
L2Skill skille = SkillTable.getInstance().getInfo(skillId, 1);
if (skille != null)
{
player.addSkill(skille, false);
player.sendSkillList();
}
else
_log.warn("Inventory.ArmorSetListener: Incorrect skill: " + armorSet.getEnchant6skillId() + ".");
}
}
}
}
else if (armorSet.containShield(item.getItemId()))
{
if (armorSet.containAll(player))
{
L2Skill skills = SkillTable.getInstance().getInfo(armorSet.getShieldSkillId(), 1);
if (skills != null)
{
player.addSkill(skills, false);
player.sendSkillList();
}
else
_log.warn("Inventory.ArmorSetListener: Incorrect skill: " + armorSet.getShieldSkillId() + ".");
}
}
}
@Override
public void notifyUnequipped(int slot, L2ItemInstance item, Inventory inventory)
{
if (!(inventory.getOwner() instanceof L2PcInstance))
return;
final L2PcInstance player = (L2PcInstance) inventory.getOwner();
boolean remove = false;
int removeSkillId1 = 0; // set skill
int removeSkillId2 = 0; // shield skill
int removeSkillId3 = 0; // enchant +6 skill
if (slot == PAPERDOLL_CHEST)
{
final L2ArmorSet armorSet = ArmorSetsData.getInstance().getSet(item.getItemId());
if (armorSet == null)
return;
remove = true;
removeSkillId1 = armorSet.getSkillId();
removeSkillId2 = armorSet.getShieldSkillId();
removeSkillId3 = armorSet.getEnchant6skillId();
}
else
{
final L2ItemInstance chestItem = inventory.getPaperdollItem(PAPERDOLL_CHEST);
if (chestItem == null)
return;
final L2ArmorSet armorSet = ArmorSetsData.getInstance().getSet(chestItem.getItemId());
if (armorSet == null)
return;
if (armorSet.containItem(slot, item.getItemId())) // removed part of set
{
remove = true;
removeSkillId1 = armorSet.getSkillId();
removeSkillId2 = armorSet.getShieldSkillId();
removeSkillId3 = armorSet.getEnchant6skillId();
}
else if (armorSet.containShield(item.getItemId())) // removed shield
{
remove = true;
removeSkillId2 = armorSet.getShieldSkillId();
}
}
if (remove)
{
if (removeSkillId1 != 0)
{
L2Skill skill = SkillTable.getInstance().getInfo(removeSkillId1, 1);
if (skill != null)
{
player.removeSkill(SkillTable.getInstance().getInfo(3006, 1));
player.removeSkill(skill);
}
else
_log.warn("Inventory.ArmorSetListener: Incorrect skill: " + removeSkillId1 + ".");
}
if (removeSkillId2 != 0)
{
L2Skill skill = SkillTable.getInstance().getInfo(removeSkillId2, 1);
if (skill != null)
player.removeSkill(skill);
else
_log.warn("Inventory.ArmorSetListener: Incorrect skill: " + removeSkillId2 + ".");
}
if (removeSkillId3 != 0)
{
L2Skill skill = SkillTable.getInstance().getInfo(removeSkillId3, 1);
if (skill != null)
player.removeSkill(skill);
else
_log.warn("Inventory.ArmorSetListener: Incorrect skill: " + removeSkillId3 + ".");
}
player.sendSkillList();
}
}
}
/**
* Constructor of the inventory
*/
protected Inventory()
{
_paperdoll = new L2ItemInstance[PAPERDOLL_TOTALSLOTS];
_paperdollListeners = new ArrayList<>();
if (this instanceof PcInventory)
{
addPaperdollListener(ArmorSetListener.getInstance());
addPaperdollListener(BowRodListener.getInstance());
addPaperdollListener(ItemPassiveSkillsListener.getInstance());
}
// common
addPaperdollListener(StatsListener.getInstance());
}
protected abstract ItemLocation getEquipLocation();
/**
* Returns the instance of new ChangeRecorder
*
* @return ChangeRecorder
*/
public ChangeRecorder newRecorder()
{
return new ChangeRecorder(this);
}
/**
* Drop item from inventory and updates database
*
* @param process
* : String Identifier of process triggering this action
* @param item
* : L2ItemInstance to be dropped
* @param actor
* : L2PcInstance Player requesting the item drop
* @param reference
* : L2Object Object referencing current action like NPC selling item or previous item in transformation
* @return L2ItemInstance corresponding to the destroyed item or the updated item in inventory
*/
public L2ItemInstance dropItem(String process, L2ItemInstance item, L2PcInstance actor, L2Object reference)
{
if (item == null)
return null;
synchronized (item)
{
if (!_items.contains(item))
return null;
removeItem(item);
item.setOwnerId(process, 0, actor, reference);
item.setLocation(ItemLocation.VOID);
item.setLastChange(L2ItemInstance.REMOVED);
item.updateDatabase();
refreshWeight();
}
return item;
}
/**
* Drop item from inventory by using its <B>objectID</B> and updates database
*
* @param process
* : String Identifier of process triggering this action
* @param objectId
* : int Item Instance identifier of the item to be dropped
* @param count
* : int Quantity of items to be dropped
* @param actor
* : L2PcInstance Player requesting the item drop
* @param reference
* : L2Object Object referencing current action like NPC selling item or previous item in transformation
* @return L2ItemInstance corresponding to the destroyed item or the updated item in inventory
*/
public L2ItemInstance dropItem(String process, int objectId, int count, L2PcInstance actor, L2Object reference)
{
L2ItemInstance item = getItemByObjectId(objectId);
if (item == null)
return null;
synchronized (item)
{
if (!_items.contains(item))
return null;
// Adjust item quantity and create new instance to drop
// Directly drop entire item
if (item.getCount() > count)
{
item.changeCount(process, -count, actor, reference);
item.setLastChange(L2ItemInstance.MODIFIED);
item.updateDatabase();
item = ItemTable.getInstance().createItem(process, item.getItemId(), count, actor, reference);
item.updateDatabase();
refreshWeight();
return item;
}
}
return dropItem(process, item, actor, reference);
}
/**
* Adds item to inventory for further adjustments and Equip it if necessary (itemlocation defined)<BR>
* <BR>
*
* @param item
* : L2ItemInstance to be added from inventory
*/
@Override
protected void addItem(L2ItemInstance item)
{
super.addItem(item);
if (item.isEquipped())
equipItem(item);
}
/**
* Removes item from inventory for further adjustments.
*
* @param item
* : L2ItemInstance to be removed from inventory
*/
@Override
protected boolean removeItem(L2ItemInstance item)
{
// Unequip item if equipped
for (int i = 0; i < _paperdoll.length; i++)
{
if (_paperdoll[i] == item)
unEquipItemInSlot(i);
}
return super.removeItem(item);
}
/**
* @param slot
* The slot to check.
* @return The L2ItemInstance item in the paperdoll slot.
*/
public L2ItemInstance getPaperdollItem(int slot)
{
return _paperdoll[slot];
}
public static int getPaperdollIndex(int slot)
{
switch (slot)
{
case L2Item.SLOT_UNDERWEAR:
return PAPERDOLL_UNDER;
case L2Item.SLOT_R_EAR:
return PAPERDOLL_REAR;
case L2Item.SLOT_L_EAR:
return PAPERDOLL_LEAR;
case L2Item.SLOT_NECK:
return PAPERDOLL_NECK;
case L2Item.SLOT_R_FINGER:
return PAPERDOLL_RFINGER;
case L2Item.SLOT_L_FINGER:
return PAPERDOLL_LFINGER;
case L2Item.SLOT_HEAD:
return PAPERDOLL_HEAD;
case L2Item.SLOT_R_HAND:
case L2Item.SLOT_LR_HAND:
return PAPERDOLL_RHAND;
case L2Item.SLOT_L_HAND:
return PAPERDOLL_LHAND;
case L2Item.SLOT_GLOVES:
return PAPERDOLL_GLOVES;
case L2Item.SLOT_CHEST:
case L2Item.SLOT_FULL_ARMOR:
case L2Item.SLOT_ALLDRESS:
return PAPERDOLL_CHEST;
case L2Item.SLOT_LEGS:
return PAPERDOLL_LEGS;
case L2Item.SLOT_FEET:
return PAPERDOLL_FEET;
case L2Item.SLOT_BACK:
return PAPERDOLL_BACK;
case L2Item.SLOT_FACE:
case L2Item.SLOT_HAIRALL:
return PAPERDOLL_FACE;
case L2Item.SLOT_HAIR:
return PAPERDOLL_HAIR;
}
return -1;
}
/**
* @param slot
* L2Item slot identifier
* @return the L2ItemInstance item in the paperdoll L2Item slot
*/
public L2ItemInstance getPaperdollItemByL2ItemId(int slot)
{
int index = getPaperdollIndex(slot);
if (index == -1)
return null;
return _paperdoll[index];
}
/**
* Returns the ID of the item in the paperdol slot
*
* @param slot
* : int designating the slot
* @return int designating the ID of the item
*/
public int getPaperdollItemId(int slot)
{
L2ItemInstance item = _paperdoll[slot];
if (item != null)
return item.getItemId();
return 0;
}
public int getPaperdollAugmentationId(int slot)
{
L2ItemInstance item = _paperdoll[slot];
if (item != null)
{
if (item.getAugmentation() != null)
return item.getAugmentation().getAugmentationId();
}
return 0;
}
/**
* Returns the objectID associated to the item in the paperdoll slot
*
* @param slot
* : int pointing out the slot
* @return int designating the objectID
*/
public int getPaperdollObjectId(int slot)
{
L2ItemInstance item = _paperdoll[slot];
if (item != null)
return item.getObjectId();
return 0;
}
/**
* Adds new inventory's paperdoll listener
*
* @param listener
* PaperdollListener pointing out the listener
*/
public synchronized void addPaperdollListener(PaperdollListener listener)
{
assert !_paperdollListeners.contains(listener);
_paperdollListeners.add(listener);
}
/**
* Removes a paperdoll listener
*
* @param listener
* PaperdollListener pointing out the listener to be deleted
*/
public synchronized void removePaperdollListener(PaperdollListener listener)
{
_paperdollListeners.remove(listener);
}
/**
* Equips an item in the given slot of the paperdoll. <U><I>Remark :</I></U> The item <B>HAS TO BE</B> already in the inventory
*
* @param slot
* : int pointing out the slot of the paperdoll
* @param item
* : L2ItemInstance pointing out the item to add in slot
* @return L2ItemInstance designating the item placed in the slot before
*/
public synchronized L2ItemInstance setPaperdollItem(int slot, L2ItemInstance item)
{
L2ItemInstance old = _paperdoll[slot];
if (old != item)
{
if (old != null)
{
_paperdoll[slot] = null;
// Put old item from paperdoll slot to base location
old.setLocation(getBaseLocation());
old.setLastChange(L2ItemInstance.MODIFIED);
// Get the mask for paperdoll
int mask = 0;
for (int i = 0; i < PAPERDOLL_TOTALSLOTS; i++)
{
L2ItemInstance pi = _paperdoll[i];
if (pi != null)
mask |= pi.getItem().getItemMask();
}
_wearedMask = mask;
// Notify all paperdoll listener in order to unequip old item in slot
for (PaperdollListener listener : _paperdollListeners)
{
if (listener == null)
continue;
listener.notifyUnequipped(slot, old, this);
}
old.updateDatabase();
}
// Add new item in slot of paperdoll
if (item != null)
{
_paperdoll[slot] = item;
item.setLocation(getEquipLocation(), slot);
item.setLastChange(L2ItemInstance.MODIFIED);
_wearedMask |= item.getItem().getItemMask();
for (PaperdollListener listener : _paperdollListeners)
{
if (listener == null)
continue;
listener.notifyEquipped(slot, item, this);
}
item.updateDatabase();
}
}
return old;
}
/**
* Return the mask of weared item
*
* @return int
*/
public int getWearedMask()
{
return _wearedMask;
}
public int getSlotFromItem(L2ItemInstance item)
{
int slot = -1;
int location = item.getLocationSlot();
switch (location)
{
case PAPERDOLL_UNDER:
slot = L2Item.SLOT_UNDERWEAR;
break;
case PAPERDOLL_LEAR:
slot = L2Item.SLOT_L_EAR;
break;
case PAPERDOLL_REAR:
slot = L2Item.SLOT_R_EAR;
break;
case PAPERDOLL_NECK:
slot = L2Item.SLOT_NECK;
break;
case PAPERDOLL_RFINGER:
slot = L2Item.SLOT_R_FINGER;
break;
case PAPERDOLL_LFINGER:
slot = L2Item.SLOT_L_FINGER;
break;
case PAPERDOLL_HAIR:
slot = L2Item.SLOT_HAIR;
break;
case PAPERDOLL_FACE:
slot = L2Item.SLOT_FACE;
break;
case PAPERDOLL_HEAD:
slot = L2Item.SLOT_HEAD;
break;
case PAPERDOLL_RHAND:
slot = L2Item.SLOT_R_HAND;
break;
case PAPERDOLL_LHAND:
slot = L2Item.SLOT_L_HAND;
break;
case PAPERDOLL_GLOVES:
slot = L2Item.SLOT_GLOVES;
break;
case PAPERDOLL_CHEST:
slot = item.getItem().getBodyPart();
break;// fall through
case PAPERDOLL_LEGS:
slot = L2Item.SLOT_LEGS;
break;
case PAPERDOLL_BACK:
slot = L2Item.SLOT_BACK;
break;
case PAPERDOLL_FEET:
slot = L2Item.SLOT_FEET;
break;
}
return slot;
}
/**
* Unequips item in body slot and returns alterations.
*
* @param slot
* : int designating the slot of the paperdoll
* @return L2ItemInstance[] : list of changes
*/
public L2ItemInstance[] unEquipItemInBodySlotAndRecord(int slot)
{
Inventory.ChangeRecorder recorder = newRecorder();
try
{
unEquipItemInBodySlot(slot);
}
finally
{
removePaperdollListener(recorder);
}
return recorder.getChangedItems();
}
/**
* Sets item in slot of the paperdoll to null value
*
* @param pdollSlot
* : int designating the slot
* @return L2ItemInstance designating the item in slot before change
*/
public L2ItemInstance unEquipItemInSlot(int pdollSlot)
{
return setPaperdollItem(pdollSlot, null);
}
/**
* Unepquips item in slot and returns alterations
*
* @param slot
* : int designating the slot
* @return L2ItemInstance[] : list of items altered
*/
public L2ItemInstance[] unEquipItemInSlotAndRecord(int slot)
{
Inventory.ChangeRecorder recorder = newRecorder();
try
{
unEquipItemInSlot(slot);
if (getOwner() instanceof L2PcInstance)
((L2PcInstance) getOwner()).refreshExpertisePenalty();
}
finally
{
removePaperdollListener(recorder);
}
return recorder.getChangedItems();
}
/**
* Unequips item in slot (i.e. equips with default value)
*
* @param slot
* : int designating the slot
* @return the instance of the item.
*/
public L2ItemInstance unEquipItemInBodySlot(int slot)
{
_log.trace("--- unequip body slot:" + slot);
int pdollSlot = -1;
switch (slot)
{
case L2Item.SLOT_L_EAR:
pdollSlot = PAPERDOLL_LEAR;
break;
case L2Item.SLOT_R_EAR:
pdollSlot = PAPERDOLL_REAR;
break;
case L2Item.SLOT_NECK:
pdollSlot = PAPERDOLL_NECK;
break;
case L2Item.SLOT_R_FINGER:
pdollSlot = PAPERDOLL_RFINGER;
break;
case L2Item.SLOT_L_FINGER:
pdollSlot = PAPERDOLL_LFINGER;
break;
case L2Item.SLOT_HAIR:
pdollSlot = PAPERDOLL_HAIR;
break;
case L2Item.SLOT_FACE:
pdollSlot = PAPERDOLL_FACE;
break;
case L2Item.SLOT_HAIRALL:
setPaperdollItem(PAPERDOLL_FACE, null);
pdollSlot = PAPERDOLL_FACE;
break;
case L2Item.SLOT_HEAD:
pdollSlot = PAPERDOLL_HEAD;
break;
case L2Item.SLOT_R_HAND:
case L2Item.SLOT_LR_HAND:
pdollSlot = PAPERDOLL_RHAND;
break;
case L2Item.SLOT_L_HAND:
pdollSlot = PAPERDOLL_LHAND;
break;
case L2Item.SLOT_GLOVES:
pdollSlot = PAPERDOLL_GLOVES;
break;
case L2Item.SLOT_CHEST:
case L2Item.SLOT_FULL_ARMOR:
case L2Item.SLOT_ALLDRESS:
pdollSlot = PAPERDOLL_CHEST;
break;
case L2Item.SLOT_LEGS:
pdollSlot = PAPERDOLL_LEGS;
break;
case L2Item.SLOT_BACK:
pdollSlot = PAPERDOLL_BACK;
break;
case L2Item.SLOT_FEET:
pdollSlot = PAPERDOLL_FEET;
break;
case L2Item.SLOT_UNDERWEAR:
pdollSlot = PAPERDOLL_UNDER;
break;
default:
_log.info("Unhandled slot type: " + slot);
}
if (pdollSlot >= 0)
{
L2ItemInstance old = setPaperdollItem(pdollSlot, null);
if (old != null)
{
if (getOwner() instanceof L2PcInstance)
((L2PcInstance) getOwner()).refreshExpertisePenalty();
}
return old;
}
return null;
}
/**
* Equips item and returns list of alterations<BR>
* <B>If you dont need return value use {@link Inventory#equipItem(L2ItemInstance)} instead</B>
*
* @param item
* : L2ItemInstance corresponding to the item
* @return L2ItemInstance[] : list of alterations
*/
public L2ItemInstance[] equipItemAndRecord(L2ItemInstance item)
{
Inventory.ChangeRecorder recorder = newRecorder();
try
{
equipItem(item);
}
finally
{
removePaperdollListener(recorder);
}
return recorder.getChangedItems();
}
/**
* Equips item in slot of paperdoll.
*
* @param item
* : L2ItemInstance designating the item and slot used.
*/
public void equipItem(L2ItemInstance item)
{
if (getOwner() instanceof L2PcInstance)
{
// Can't equip item if you are in shop mod or hero item and you're not hero.
if ((((L2PcInstance) getOwner()).getPrivateStoreType() != 0) || (!((L2PcInstance) getOwner()).isHero() && item.isHeroItem()))
return;
}
int targetSlot = item.getItem().getBodyPart();
// check if player wear formal
L2ItemInstance formal = getPaperdollItem(PAPERDOLL_CHEST);
if (formal != null && formal.getItem().getBodyPart() == L2Item.SLOT_ALLDRESS)
{
// only chest target can pass this
switch (targetSlot)
{
case L2Item.SLOT_LR_HAND:
case L2Item.SLOT_L_HAND:
case L2Item.SLOT_R_HAND:
case L2Item.SLOT_LEGS:
case L2Item.SLOT_FEET:
case L2Item.SLOT_GLOVES:
case L2Item.SLOT_HEAD:
return;
}
}
switch (targetSlot)
{
case L2Item.SLOT_LR_HAND:
{
setPaperdollItem(PAPERDOLL_LHAND, null);
setPaperdollItem(PAPERDOLL_RHAND, item);
break;
}
case L2Item.SLOT_L_HAND:
{
L2ItemInstance rh = getPaperdollItem(PAPERDOLL_RHAND);
if (rh != null && rh.getItem().getBodyPart() == L2Item.SLOT_LR_HAND && !((rh.getItemType() == L2WeaponType.BOW && item.getItemType() == L2EtcItemType.ARROW) || (rh.getItemType() == L2WeaponType.FISHINGROD && item.getItemType() == L2EtcItemType.LURE)))
{
setPaperdollItem(PAPERDOLL_RHAND, null);
}
setPaperdollItem(PAPERDOLL_LHAND, item);
break;
}
case L2Item.SLOT_R_HAND:
{
// dont care about arrows, listener will unequip them (hopefully)
setPaperdollItem(PAPERDOLL_RHAND, item);
break;
}
case L2Item.SLOT_L_EAR:
case L2Item.SLOT_R_EAR:
case L2Item.SLOT_L_EAR | L2Item.SLOT_R_EAR:
{
if (_paperdoll[PAPERDOLL_LEAR] == null)
setPaperdollItem(PAPERDOLL_LEAR, item);
else if (_paperdoll[PAPERDOLL_REAR] == null)
setPaperdollItem(PAPERDOLL_REAR, item);
else
setPaperdollItem(PAPERDOLL_LEAR, item);
break;
}
case L2Item.SLOT_L_FINGER:
case L2Item.SLOT_R_FINGER:
case L2Item.SLOT_L_FINGER | L2Item.SLOT_R_FINGER:
{
if (_paperdoll[PAPERDOLL_LFINGER] == null)
setPaperdollItem(PAPERDOLL_LFINGER, item);
else if (_paperdoll[PAPERDOLL_RFINGER] == null)
setPaperdollItem(PAPERDOLL_RFINGER, item);
else
setPaperdollItem(PAPERDOLL_LFINGER, item);
break;
}
case L2Item.SLOT_NECK:
setPaperdollItem(PAPERDOLL_NECK, item);
break;
case L2Item.SLOT_FULL_ARMOR:
setPaperdollItem(PAPERDOLL_LEGS, null);
setPaperdollItem(PAPERDOLL_CHEST, item);
break;
case L2Item.SLOT_CHEST:
setPaperdollItem(PAPERDOLL_CHEST, item);
break;
case L2Item.SLOT_LEGS:
{
// handle full armor
L2ItemInstance chest = getPaperdollItem(PAPERDOLL_CHEST);
if (chest != null && chest.getItem().getBodyPart() == L2Item.SLOT_FULL_ARMOR)
setPaperdollItem(PAPERDOLL_CHEST, null);
setPaperdollItem(PAPERDOLL_LEGS, item);
break;
}
case L2Item.SLOT_FEET:
setPaperdollItem(PAPERDOLL_FEET, item);
break;
case L2Item.SLOT_GLOVES:
setPaperdollItem(PAPERDOLL_GLOVES, item);
break;
case L2Item.SLOT_HEAD:
setPaperdollItem(PAPERDOLL_HEAD, item);
break;
case L2Item.SLOT_FACE:
L2ItemInstance hair = getPaperdollItem(PAPERDOLL_HAIR);
if (hair != null && hair.getItem().getBodyPart() == L2Item.SLOT_HAIRALL)
setPaperdollItem(PAPERDOLL_HAIR, null);
setPaperdollItem(PAPERDOLL_FACE, item);
break;
case L2Item.SLOT_HAIR:
L2ItemInstance face = getPaperdollItem(PAPERDOLL_FACE);
if (face != null && face.getItem().getBodyPart() == L2Item.SLOT_HAIRALL)
setPaperdollItem(PAPERDOLL_FACE, null);
setPaperdollItem(PAPERDOLL_HAIR, item);
break;
case L2Item.SLOT_HAIRALL:
setPaperdollItem(PAPERDOLL_FACE, null);
setPaperdollItem(PAPERDOLL_HAIR, item);
break;
case L2Item.SLOT_UNDERWEAR:
setPaperdollItem(PAPERDOLL_UNDER, item);
break;
case L2Item.SLOT_BACK:
setPaperdollItem(PAPERDOLL_BACK, item);
break;
case L2Item.SLOT_ALLDRESS:
// formal dress
setPaperdollItem(PAPERDOLL_LEGS, null);
setPaperdollItem(PAPERDOLL_LHAND, null);
setPaperdollItem(PAPERDOLL_RHAND, null);
setPaperdollItem(PAPERDOLL_HEAD, null);
setPaperdollItem(PAPERDOLL_FEET, null);
setPaperdollItem(PAPERDOLL_GLOVES, null);
setPaperdollItem(PAPERDOLL_CHEST, item);
break;
default:
_log.warn("Unknown body slot " + targetSlot + " for Item ID:" + item.getItemId());
}
}
/**
* Equips pet item in slot of paperdoll. Concerning pets, armors go to chest location, and weapon to R-hand.
*
* @param item
* : L2ItemInstance designating the item and slot used.
*/
public void equipPetItem(L2ItemInstance item)
{
if (getOwner() instanceof L2PcInstance)
{
// Can't equip item if you are in shop mod or hero item and you're not hero.
if (((L2PcInstance) getOwner()).getPrivateStoreType() != 0)
return;
}
// Verify first if item is a pet item.
if (item.isPetItem())
{
// Check then about type of item : armor or weapon. Feed the correct slot.
if (item.getItemType() == L2WeaponType.PET)
setPaperdollItem(PAPERDOLL_RHAND, item);
else if (item.getItemType() == L2ArmorType.PET)
setPaperdollItem(PAPERDOLL_CHEST, item);
}
}
/**
* Refresh the weight of equipment loaded
*/
@Override
protected void refreshWeight()
{
int weight = 0;
for (L2ItemInstance item : _items)
{
if (item != null && item.getItem() != null)
weight += item.getItem().getWeight() * item.getCount();
}
_totalWeight = weight;
}
/**
* Returns the totalWeight.
*
* @return int
*/
public int getTotalWeight()
{
return _totalWeight;
}
/**
* Return the L2ItemInstance of the arrows needed for this bow.<BR>
* <BR>
*
* @param bow
* : L2Item designating the bow
* @return L2ItemInstance pointing out arrows for bow
*/
public L2ItemInstance findArrowForBow(L2Item bow)
{
if (bow == null)
return null;
int arrowsId = 0;
switch (bow.getCrystalType())
{
default:
case L2Item.CRYSTAL_NONE:
arrowsId = 17;
break; // Wooden arrow
case L2Item.CRYSTAL_D:
arrowsId = 1341;
break; // Bone arrow
case L2Item.CRYSTAL_C:
arrowsId = 1342;
break; // Fine steel arrow
case L2Item.CRYSTAL_B:
arrowsId = 1343;
break; // Silver arrow
case L2Item.CRYSTAL_A:
arrowsId = 1344;
break; // Mithril arrow
case L2Item.CRYSTAL_S:
arrowsId = 1345;
break; // Shining arrow
}
// Get the L2ItemInstance corresponding to the item identifier and return it
return getItemByItemId(arrowsId);
}
/**
* Get back items in inventory from database
*/
@Override
public void restore()
{
try (Connection con = DatabaseFactory.getConnection())
{
PreparedStatement statement = con.prepareStatement("SELECT object_id, item_id, count, enchant_level, loc, loc_data, custom_type1, custom_type2, mana_left, time FROM items WHERE owner_id=? AND (loc=? OR loc=?) ORDER BY loc_data");
statement.setInt(1, getOwnerId());
statement.setString(2, getBaseLocation().name());
statement.setString(3, getEquipLocation().name());
ResultSet inv = statement.executeQuery();
while (inv.next())
{
L2ItemInstance item = L2ItemInstance.restoreFromDb(getOwnerId(), inv);
if (item == null)
continue;
if (getOwner() instanceof L2PcInstance)
{
if (!((L2PcInstance) getOwner()).isHero() && item.isHeroItem())
item.setLocation(ItemLocation.INVENTORY);
}
L2World.getInstance().storeObject(item);
// If stackable item is found in inventory just add to current quantity
if (item.isStackable() && getItemByItemId(item.getItemId()) != null)
addItem("Restore", item, getOwner().getActingPlayer(), null);
else
addItem(item);
}
inv.close();
statement.close();
refreshWeight();
}
catch (Exception e)
{
_log.warn("Could not restore inventory: " + e.getMessage(), e);
}
}
/**
* Re-notify to paperdoll listeners every equipped item
*/
public void reloadEquippedItems()
{
for (L2ItemInstance element : _paperdoll)
{
L2ItemInstance item = element;
if (item == null)
continue;
int slot = item.getLocationSlot();
for (PaperdollListener listener : _paperdollListeners)
{
if (listener == null)
continue;
listener.notifyUnequipped(slot, item, this);
listener.notifyEquipped(slot, item, this);
}
}
}
}