/* * 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); } } } }