/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package com.aionemu.gameserver.model.gameobjects.player; import java.util.ArrayList; import java.util.List; import java.util.SortedMap; import java.util.TreeMap; import org.apache.log4j.Logger; import com.aionemu.commons.database.dao.DAOManager; import com.aionemu.gameserver.dao.InventoryDAO; import com.aionemu.gameserver.model.DescriptionId; import com.aionemu.gameserver.model.gameobjects.Item; import com.aionemu.gameserver.model.gameobjects.PersistentState; import com.aionemu.gameserver.model.gameobjects.state.CreatureState; import com.aionemu.gameserver.model.gameobjects.stats.listeners.ItemEquipmentListener; import com.aionemu.gameserver.model.items.ItemSlot; import com.aionemu.gameserver.model.templates.item.ArmorType; import com.aionemu.gameserver.model.templates.item.WeaponType; import com.aionemu.gameserver.model.templates.itemset.ItemSetTemplate; import com.aionemu.gameserver.network.aion.serverpackets.SM_DELETE_ITEM; import com.aionemu.gameserver.network.aion.serverpackets.SM_EMOTION; import com.aionemu.gameserver.network.aion.serverpackets.SM_SYSTEM_MESSAGE; import com.aionemu.gameserver.network.aion.serverpackets.SM_UPDATE_ITEM; import com.aionemu.gameserver.utils.PacketSendUtility; /** * * @author Avol, ATracer, kosyachok */ public class Equipment { private SortedMap<Integer, Item> equipment = new TreeMap<Integer, Item>(); private Player owner; private static final Logger log = Logger.getLogger(Equipment.class); private PersistentState persistentState = PersistentState.UPDATED; public Equipment(Player player) { this.owner = player; } /** * * @param itemUniqueId * @param slot * @return item or null in case of failure */ public Item equipItem(int itemUniqueId, int slot) { synchronized(equipment) { Item item = owner.getInventory().getItemByObjId(itemUniqueId); if(item == null) return null; //don't allow to wear items of higher level if(item.getItemTemplate().getLevel() > owner.getCommonData().getLevel()) { PacketSendUtility.sendPacket(owner, SM_SYSTEM_MESSAGE.STR_CANNOT_USE_ITEM_TOO_LOW_LEVEL_MUST_BE_THIS_LEVEL( item.getItemTemplate().getLevel(), new DescriptionId(Integer.parseInt(item.getName())))); return null; } int itemSlotToEquip = 0; switch(item.getEquipmentType()) { case ARMOR: if(!validateEquippedArmor(item)) return null; break; case WEAPON: if(!validateEquippedWeapon(item)) return null; break; } //check whether there is already item in specified slot int itemSlotMask = 0 ; switch(item.getEquipmentType()) { case STIGMA: itemSlotMask = slot; break; default: itemSlotMask = item.getItemTemplate().getItemSlot(); break; } List<ItemSlot> possibleSlots = ItemSlot.getSlotsFor(itemSlotMask); for(ItemSlot possibleSlot : possibleSlots) { if(equipment.get(possibleSlot.getSlotIdMask()) == null) { itemSlotToEquip = possibleSlot.getSlotIdMask(); break; } } // equip first occupied slot if there is no free if(itemSlotToEquip == 0) { itemSlotToEquip = possibleSlots.get(0).getSlotIdMask(); } if(itemSlotToEquip == 0) return null; //remove item first from inventory to have at least one slot free owner.getInventory().removeFromBag(item, false); Item equippedItem = equipment.get(itemSlotToEquip); if(equippedItem != null) unEquip(itemSlotToEquip); equip(itemSlotToEquip, item); setPersistentState(PersistentState.UPDATE_REQUIRED); return item; } } private void equip(int slot, Item item) { if(equipment.get(slot) != null) { log.error("CHECKPOINT : putting item to already equiped slot. Info slot: " + slot + " new item: " + item.getItemTemplate().getTemplateId() + " old item: " + equipment.get(slot).getItemTemplate().getTemplateId()); return; } equipment.put(slot, item); item.setEquipped(true); item.setEquipmentSlot(slot); PacketSendUtility.sendPacket(owner, new SM_UPDATE_ITEM(item)); ItemEquipmentListener.onItemEquipment(item, owner); owner.getObserveController().notifyItemEquip(item, owner); owner.getLifeStats().updateCurrentStats(); } /** * Called when CM_EQUIP_ITEM packet arrives with action 1 * * @param itemUniqueId * @param slot * @return item or null in case of failure */ public Item unEquipItem(int itemUniqueId, int slot) { //if inventory is full unequip action is disabled if(owner.getInventory().isFull()) return null; synchronized(equipment) { Item itemToUnequip = null; for(Item item : equipment.values()) { if(item.getObjectId() == itemUniqueId) { itemToUnequip = item; } } if(itemToUnequip == null || !itemToUnequip.isEquipped()) return null; //if unequip bow - unequip arrows also if(itemToUnequip.getItemTemplate().getWeaponType() == WeaponType.BOW) { Item possibleArrows = equipment.get(ItemSlot.SUB_HAND.getSlotIdMask()); if(possibleArrows != null && possibleArrows.getItemTemplate().getArmorType() == ArmorType.ARROW) { //TODO more wise check here is needed if(owner.getInventory().getNumberOfFreeSlots() < 1) return null; unEquip(ItemSlot.SUB_HAND.getSlotIdMask()); } } if(itemToUnequip.getEquipmentSlot() == ItemSlot.MAIN_HAND.getSlotIdMask()) { Item ohWeapon = equipment.get(ItemSlot.SUB_HAND.getSlotIdMask()); if(ohWeapon != null && ohWeapon.getItemTemplate().isWeapon()) { if(owner.getInventory().getNumberOfFreeSlots() < 2) return null; else unEquip(ItemSlot.SUB_HAND.getSlotIdMask()); } } //if unequip power shard if(itemToUnequip.getItemTemplate().isArmor() && itemToUnequip.getItemTemplate().getArmorType() == ArmorType.SHARD) { owner.unsetState(CreatureState.POWERSHARD); PacketSendUtility.sendPacket(owner, new SM_EMOTION(owner, 32, 0, 0)); } unEquip(itemToUnequip.getEquipmentSlot()); return itemToUnequip; } } private void unEquip(int slot) { Item item = equipment.remove(slot); item.setEquipped(false); ItemEquipmentListener.onItemUnequipment(item, owner); owner.getObserveController().notifyItemUnEquip(item, owner); owner.getLifeStats().updateCurrentStats(); owner.getInventory().putToBag(item); PacketSendUtility.sendPacket(owner, new SM_UPDATE_ITEM(item)); } /** * Used during equip process and analyzes equipped slots * * @param item * @param itemInMainHand * @param itemInSubHand * @return */ private boolean validateEquippedWeapon(Item item) { // check present skill int[] requiredSkills = item.getItemTemplate().getWeaponType().getRequiredSkills(); if(!checkAvaialbeEquipSkills(requiredSkills)) return false; Item itemInMainHand = equipment.get(ItemSlot.MAIN_HAND.getSlotIdMask()); Item itemInSubHand = equipment.get(ItemSlot.SUB_HAND.getSlotIdMask()); switch(item.getItemTemplate().getWeaponType().getRequiredSlots()) { case 2: switch(item.getItemTemplate().getWeaponType()) { //if bow and arrows are equipped + new item is bow - dont uneqiup arrows case BOW: if(itemInSubHand != null && itemInSubHand.getItemTemplate().getArmorType() != ArmorType.ARROW) { //TODO more wise check here is needed if(owner.getInventory().getNumberOfFreeSlots() < 1) return false; unEquip(ItemSlot.SUB_HAND.getSlotIdMask()); } break; //if new item is not bow - unequip arrows default: if(itemInSubHand != null) { //TODO more wise check here is needed if(owner.getInventory().getNumberOfFreeSlots() < 1) return false; //remove 2H weapon unEquip(ItemSlot.SUB_HAND.getSlotIdMask()); } }//no break case 1: //check dual skill if(itemInMainHand != null && !owner.getSkillList().isSkillPresent(19)) { if(owner.getInventory().getNumberOfFreeSlots() < 1) return false; unEquip(ItemSlot.MAIN_HAND.getSlotIdMask()); } //check 2h weapon in main hand else if(itemInMainHand != null && itemInMainHand.getItemTemplate().getWeaponType().getRequiredSlots() == 2) { if(owner.getInventory().getNumberOfFreeSlots() < 1) return false; unEquip(ItemSlot.MAIN_HAND.getSlotIdMask()); } //unequip arrows if bow+arrows were equipeed Item possibleArrows = equipment.get(ItemSlot.SUB_HAND.getSlotIdMask()); if(possibleArrows != null && possibleArrows.getItemTemplate().getArmorType() == ArmorType.ARROW) { //TODO more wise check here is needed if(owner.getInventory().getNumberOfFreeSlots() < 1) return false; unEquip(ItemSlot.SUB_HAND.getSlotIdMask()); } break; } return true; } /** * * @param requiredSkills * @return */ private boolean checkAvaialbeEquipSkills(int[] requiredSkills) { boolean isSkillPresent = false; //if no skills required - validate as true if(requiredSkills.length == 0) return true; for(int skill : requiredSkills) { if(owner.getSkillList().isSkillPresent(skill)) { isSkillPresent = true; break; } } return isSkillPresent; } /** * Used during equip process and analyzes equipped slots * * @param item * @param itemInMainHand * @return */ private boolean validateEquippedArmor(Item item) { //allow wearing of jewelry etc stuff ArmorType armorType = item.getItemTemplate().getArmorType(); if(armorType == null) return true; // check present skill int[] requiredSkills = armorType.getRequiredSkills(); if(!checkAvaialbeEquipSkills(requiredSkills)) return false; Item itemInMainHand = equipment.get(ItemSlot.MAIN_HAND.getSlotIdMask()); switch(item.getItemTemplate().getArmorType()) { case ARROW: if(itemInMainHand == null || itemInMainHand.getItemTemplate().getWeaponType() != WeaponType.BOW) return false; break; case SHIELD: if(itemInMainHand != null && itemInMainHand.getItemTemplate().getWeaponType().getRequiredSlots() == 2) { //TODO more wise check here is needed if(owner.getInventory().isFull()) return false; //remove 2H weapon unEquip(ItemSlot.MAIN_HAND.getSlotIdMask()); } break; } return true; } /** * Will look item in equipment item set * * @param value * @return Item */ public Item getEquippedItemByObjId(int value) { synchronized(equipment) { for(Item item : equipment.values()) { if(item.getObjectId() == value) return item; } } return null; } /** * * @param value * @return List<Item> */ public List<Item> getEquippedItemsByItemId(int value) { List<Item> equippedItemsById = new ArrayList<Item>(); synchronized(equipment) { for(Item item : equipment.values()) { if(item.getItemTemplate().getTemplateId() == value) equippedItemsById.add(item); } } return equippedItemsById; } /** * * @return List<Item> */ public List<Item> getEquippedItems() { List<Item> equippedItems = new ArrayList<Item>(); equippedItems.addAll(equipment.values()); return equippedItems; } /** * * @return List<Item> */ public List<Item> getEquippedItemsWithoutStigma() { List<Item> equippedItems = new ArrayList<Item>(); for(Item item : equipment.values()) { if(item.getEquipmentSlot() < ItemSlot.STIGMA1.getSlotIdMask()) equippedItems.add(item); } return equippedItems; } /** * @return Number of parts equipped belonging to requested itemset */ public int itemSetPartsEquipped(int itemSetTemplateId) { int number = 0; for(Item item : equipment.values()) { ItemSetTemplate setTemplate = item.getItemTemplate().getItemSet(); if(setTemplate != null && setTemplate.getId() == itemSetTemplateId) { ++number; } } return number; } /** * Should be called only when loading from DB for items isEquipped=1 * * @param item */ public void onLoadHandler(Item item) { if(equipment.containsKey(item.getEquipmentSlot())) { log.warn("Duplicate equipped item in slot : " + item.getEquipmentSlot() + " " + owner.getObjectId()); return; } equipment.put(item.getEquipmentSlot(), item); } /** * Should be called only when equipment object totaly constructed on player loading * Applies every equipped item stats modificators */ public void onLoadApplyEquipmentStats() { for(Item item : equipment.values()) { if (owner.getGameStats() != null) { if(item.getEquipmentSlot() != ItemSlot.MAIN_OFF_HAND.getSlotIdMask() && item.getEquipmentSlot() != ItemSlot.SUB_OFF_HAND.getSlotIdMask()) ItemEquipmentListener.onItemEquipment(item, owner); } if(owner.getLifeStats() != null) { if(item.getEquipmentSlot() != ItemSlot.MAIN_OFF_HAND.getSlotIdMask() && item.getEquipmentSlot() != ItemSlot.SUB_OFF_HAND.getSlotIdMask()) owner.getLifeStats().synchronizeWithMaxStats(); } } } /** * @return true or false */ public boolean isShieldEquipped() { Item subHandItem = equipment.get(ItemSlot.SUB_HAND.getSlotIdMask()); return subHandItem != null && subHandItem.getItemTemplate().getArmorType() == ArmorType.SHIELD; } /** * * @return <tt>WeaponType</tt> of current weapon in main hand or null */ public WeaponType getMainHandWeaponType() { Item mainHandItem = equipment.get(ItemSlot.MAIN_HAND.getSlotIdMask()); if(mainHandItem == null) return null; return mainHandItem.getItemTemplate().getWeaponType(); } /** * * @return <tt>WeaponType</tt> of current weapon in off hand or null */ public WeaponType getOffHandWeaponType() { Item offHandItem = equipment.get(ItemSlot.SUB_HAND.getSlotIdMask()); if(offHandItem != null && offHandItem.getItemTemplate().isWeapon()) return offHandItem.getItemTemplate().getWeaponType(); return null; } public boolean isPowerShardEquipped() { Item leftPowershard = equipment.get(ItemSlot.POWER_SHARD_LEFT.getSlotIdMask()); if(leftPowershard != null) return true; Item rightPowershard = equipment.get(ItemSlot.POWER_SHARD_RIGHT.getSlotIdMask()); if(rightPowershard != null) return true; return false; } public Item getMainHandPowerShard() { Item mainHandPowerShard = equipment.get(ItemSlot.POWER_SHARD_RIGHT.getSlotIdMask()); if(mainHandPowerShard != null) return mainHandPowerShard; return null; } public Item getOffHandPowerShard() { Item offHandPowerShard = equipment.get(ItemSlot.POWER_SHARD_LEFT.getSlotIdMask()); if(offHandPowerShard != null) return offHandPowerShard; return null; } /** * @param powerShardItem * @param count */ public void usePowerShard(Item powerShardItem, int count) { decreaseEquippedItemCount(powerShardItem.getObjectId(), count); if(powerShardItem.getItemCount() <= 0) {// Search for next same power shards stack List<Item> powerShardStacks = owner.getInventory().getItemsByItemId(powerShardItem.getItemTemplate().getTemplateId()); if(powerShardStacks.size() != 0) { equipItem(powerShardStacks.get(0).getObjectId(), powerShardItem.getEquipmentSlot()); } else { PacketSendUtility.sendPacket(owner, SM_SYSTEM_MESSAGE.NO_POWER_SHARD_LEFT()); owner.unsetState(CreatureState.POWERSHARD); } } } public void useArrow() { Item arrow = equipment.get(ItemSlot.SUB_HAND.getSlotIdMask()); if(arrow == null || !arrow.getItemTemplate().isArmor() && arrow.getItemTemplate().getArmorType() != ArmorType.ARROW) return; decreaseEquippedItemCount(arrow.getObjectId(), 1); } private void decreaseEquippedItemCount(int itemObjId, int count) { Item equippedItem = getEquippedItemByObjId(itemObjId); // Only Arrows and Shards can be decreased if(equippedItem.getItemTemplate().getArmorType() != ArmorType.SHARD && equippedItem.getItemTemplate().getArmorType() != ArmorType.ARROW) return; if(equippedItem.getItemCount() >= count) equippedItem.decreaseItemCount(count); else equippedItem.decreaseItemCount(equippedItem.getItemCount()); if(equippedItem.getItemCount() == 0) { equipment.remove(equippedItem.getEquipmentSlot()); PacketSendUtility.sendPacket(owner, new SM_DELETE_ITEM(equippedItem.getObjectId())); DAOManager.getDAO(InventoryDAO.class).store(equippedItem, owner.getObjectId()); } PacketSendUtility.sendPacket(owner, new SM_UPDATE_ITEM(equippedItem)); setPersistentState(PersistentState.UPDATE_REQUIRED); } /** * Switch OFF and MAIN hands */ public void switchHands() { Item mainHandItem = equipment.get(ItemSlot.MAIN_HAND.getSlotIdMask()); Item subHandItem = equipment.get(ItemSlot.SUB_HAND.getSlotIdMask()); Item mainOffHandItem = equipment.get(ItemSlot.MAIN_OFF_HAND.getSlotIdMask()); Item subOffHandItem = equipment.get(ItemSlot.SUB_OFF_HAND.getSlotIdMask()); List<Item> equippedWeapon = new ArrayList<Item>(); if(mainHandItem != null) equippedWeapon.add(mainHandItem); if(subHandItem != null) equippedWeapon.add(subHandItem); if(mainOffHandItem != null) equippedWeapon.add(mainOffHandItem); if(subOffHandItem != null) equippedWeapon.add(subOffHandItem); for(Item item : equippedWeapon) { equipment.remove(item.getEquipmentSlot()); item.setEquipped(false); PacketSendUtility.sendPacket(owner, new SM_UPDATE_ITEM(item, true)); } if (owner.getGameStats() != null) { for(Item item : equippedWeapon) { if(item.getEquipmentSlot() == ItemSlot.MAIN_HAND.getSlotIdMask() || item.getEquipmentSlot() == ItemSlot.SUB_HAND.getSlotIdMask()) ItemEquipmentListener.onItemUnequipment(item, owner); } } for(Item item : equippedWeapon) { if(item.getEquipmentSlot() == ItemSlot.MAIN_HAND.getSlotIdMask()) item.setEquipmentSlot(ItemSlot.MAIN_OFF_HAND.getSlotIdMask()); else if(item.getEquipmentSlot() == ItemSlot.SUB_HAND.getSlotIdMask()) item.setEquipmentSlot(ItemSlot.SUB_OFF_HAND.getSlotIdMask()); else if(item.getEquipmentSlot() == ItemSlot.MAIN_OFF_HAND.getSlotIdMask()) item.setEquipmentSlot(ItemSlot.MAIN_HAND.getSlotIdMask()); else if(item.getEquipmentSlot() == ItemSlot.SUB_OFF_HAND.getSlotIdMask()) item.setEquipmentSlot(ItemSlot.SUB_HAND.getSlotIdMask()); } for(Item item : equippedWeapon) { equipment.put(item.getEquipmentSlot(), item); item.setEquipped(true); PacketSendUtility.sendPacket(owner, new SM_UPDATE_ITEM(item, true)); } if (owner.getGameStats() != null) { for(Item item : equippedWeapon) { if(item.getEquipmentSlot() == ItemSlot.MAIN_HAND.getSlotIdMask() || item.getEquipmentSlot() == ItemSlot.SUB_HAND.getSlotIdMask()) ItemEquipmentListener.onItemEquipment(item, owner); } } owner.getLifeStats().updateCurrentStats(); setPersistentState(PersistentState.UPDATE_REQUIRED); } /** * @param weaponType */ public boolean isWeaponEquipped(WeaponType weaponType) { if(equipment.get(ItemSlot.MAIN_HAND.getSlotIdMask()) != null && equipment.get(ItemSlot.MAIN_HAND.getSlotIdMask()).getItemTemplate().getWeaponType() == weaponType) { return true; } if(equipment.get(ItemSlot.SUB_HAND.getSlotIdMask()) != null && equipment.get(ItemSlot.SUB_HAND.getSlotIdMask()).getItemTemplate().getWeaponType() == weaponType) { return true; } return false; } /** * @param armorType */ public boolean isArmorEquipped(ArmorType armorType) { int[] armorSlots = new int[]{ItemSlot.BOOTS.getSlotIdMask(), ItemSlot.GLOVES.getSlotIdMask(), ItemSlot.HELMET.getSlotIdMask(), ItemSlot.PANTS.getSlotIdMask(), ItemSlot.SHOULDER.getSlotIdMask(), ItemSlot.TORSO.getSlotIdMask()}; for(int slot : armorSlots) { if(equipment.get(slot) != null && equipment.get(slot).getItemTemplate().getArmorType() == armorType) return true; } return false; } public Item getMainHandWeapon() { return equipment.get(ItemSlot.MAIN_HAND.getSlotIdMask()); } public Item getOffHandWeapon() { return equipment.get(ItemSlot.SUB_HAND.getSlotIdMask()); } /** * @return the persistentState */ public PersistentState getPersistentState() { return persistentState; } /** * @param persistentState the persistentState to set */ public void setPersistentState(PersistentState persistentState) { this.persistentState = persistentState; } /** * @param player */ public void setOwner(Player player) { this.owner = player; } }