/* OrpheusMS: MapleStory Private Server based on OdinMS Copyright (C) 2012 Aaron Weiss <aaron@deviant-core.net> Patrick Huy <patrick.huy@frz.cc> Matthias Butz <matze@odinms.de> Jan Christian Meyer <vimes@odinms.de> This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ package server; import java.awt.Point; import java.util.Iterator; import java.util.List; import client.Equip; import client.IItem; import client.Item; import client.MapleBuffStat; import client.MapleCharacter; import client.MapleClient; import client.MapleInventoryType; import constants.ItemConstants; import constants.ServerConstants; import tools.MaplePacketCreator; import tools.Output; /** * * @author Matze */ public class MapleInventoryManipulator { public static boolean addRing(MapleCharacter chr, int itemId, int ringId) { MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance(); MapleInventoryType type = ii.getInventoryType(itemId); IItem nEquip = ii.getEquipById(itemId, ringId); byte newSlot = chr.getInventory(type).addItem(nEquip); if (newSlot == -1) { return false; } chr.getClient().announce(MaplePacketCreator.addInventorySlot(type, nEquip)); return true; } public static boolean addById(MapleClient c, int itemId, short quantity) { return addById(c, itemId, quantity, null, -1, -1); } public static boolean addById(MapleClient c, int itemId, short quantity, long expiration) { return addById(c, itemId, quantity, null, -1, (byte) 0, expiration); } public static boolean addById(MapleClient c, int itemId, short quantity, String owner, int petid) { return addById(c, itemId, quantity, owner, petid, -1); } public static boolean addById(MapleClient c, int itemId, short quantity, String owner, int petid, long expiration) { return addById(c, itemId, quantity, owner, petid, (byte) 0, expiration); } public static boolean addById(MapleClient c, int itemId, short quantity, String owner, int petid, byte flag, long expiration) { MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance(); MapleInventoryType type = ii.getInventoryType(itemId); if (!type.equals(MapleInventoryType.EQUIP)) { short slotMax = ii.getSlotMax(c, itemId); List<IItem> existing = c.getPlayer().getInventory(type).listById(itemId); if (!ItemConstants.isRechargable(itemId)) { if (existing.size() > 0) { // first update all existing slots to // slotMax Iterator<IItem> i = existing.iterator(); while (quantity > 0) { if (i.hasNext()) { Item eItem = (Item) i.next(); short oldQ = eItem.getQuantity(); if (oldQ < slotMax && (eItem.getOwner().equals(owner) || owner == null)) { short newQ = (short) Math.min(oldQ + quantity, slotMax); quantity -= (newQ - oldQ); eItem.setQuantity(newQ); eItem.setExpiration(expiration); c.announce(MaplePacketCreator.updateInventorySlot(type, eItem)); } } else { break; } } } while (quantity > 0 || ItemConstants.isRechargable(itemId)) { short newQ = (short) Math.min(quantity, slotMax); if (newQ != 0) { quantity -= newQ; Item nItem = new Item(itemId, (byte) 0, newQ, petid); nItem.setFlag(flag); nItem.setExpiration(expiration); byte newSlot = c.getPlayer().getInventory(type).addItem(nItem); if (newSlot == -1) { c.announce(MaplePacketCreator.getInventoryFull()); c.announce(MaplePacketCreator.getShowInventoryFull()); return false; } if (owner != null) { nItem.setOwner(owner); } c.announce(MaplePacketCreator.addInventorySlot(type, nItem)); if ((ItemConstants.isRechargable(itemId)) && quantity == 0) { break; } } else { c.announce(MaplePacketCreator.enableActions()); return false; } } } else { Item nItem = new Item(itemId, (byte) 0, quantity, petid); nItem.setFlag(flag); nItem.setExpiration(expiration); byte newSlot = c.getPlayer().getInventory(type).addItem(nItem); if (newSlot == -1) { c.announce(MaplePacketCreator.getInventoryFull()); c.announce(MaplePacketCreator.getShowInventoryFull()); return false; } c.announce(MaplePacketCreator.addInventorySlot(type, nItem)); c.announce(MaplePacketCreator.enableActions()); } } else if (quantity == 1) { IItem nEquip = ii.getEquipById(itemId); nEquip.setFlag(flag); nEquip.setExpiration(expiration); if (owner != null) { nEquip.setOwner(owner); } byte newSlot = c.getPlayer().getInventory(type).addItem(nEquip); if (newSlot == -1) { c.announce(MaplePacketCreator.getInventoryFull()); c.announce(MaplePacketCreator.getShowInventoryFull()); return false; } c.announce(MaplePacketCreator.addInventorySlot(type, nEquip)); } else { throw new RuntimeException("Trying to create equip with non-one quantity"); } return true; } public static boolean addFromDrop(MapleClient c, IItem item, boolean show) { MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance(); MapleInventoryType type = ii.getInventoryType(item.getItemId()); if (ii.isPickupRestricted(item.getItemId()) && c.getPlayer().getItemQuantity(item.getItemId(), true) > 0) { c.announce(MaplePacketCreator.getInventoryFull()); c.announce(MaplePacketCreator.showItemUnavailable()); return false; } short quantity = item.getQuantity(); if (!type.equals(MapleInventoryType.EQUIP)) { short slotMax = ii.getSlotMax(c, item.getItemId()); List<IItem> existing = c.getPlayer().getInventory(type).listById(item.getItemId()); if (!ItemConstants.isRechargable(item.getItemId())) { if (existing.size() > 0) { // first update all existing slots to // slotMax Iterator<IItem> i = existing.iterator(); while (quantity > 0) { if (i.hasNext()) { Item eItem = (Item) i.next(); short oldQ = eItem.getQuantity(); if (oldQ < slotMax && item.getOwner().equals(eItem.getOwner())) { short newQ = (short) Math.min(oldQ + quantity, slotMax); quantity -= (newQ - oldQ); eItem.setQuantity(newQ); c.announce(MaplePacketCreator.updateInventorySlot(type, eItem, true)); } } else { break; } } } while (quantity > 0 || ItemConstants.isRechargable(item.getItemId())) { short newQ = (short) Math.min(quantity, slotMax); quantity -= newQ; Item nItem = new Item(item.getItemId(), (byte) 0, newQ); nItem.setExpiration(item.getExpiration()); nItem.setOwner(item.getOwner()); byte newSlot = c.getPlayer().getInventory(type).addItem(nItem); if (newSlot == -1) { c.announce(MaplePacketCreator.getInventoryFull()); c.announce(MaplePacketCreator.getShowInventoryFull()); item.setQuantity((short) (quantity + newQ)); return false; } c.announce(MaplePacketCreator.addInventorySlot(type, nItem, true)); if ((ItemConstants.isRechargable(item.getItemId())) && quantity == 0) { break; } } } else { Item nItem = new Item(item.getItemId(), (byte) 0, quantity); byte newSlot = c.getPlayer().getInventory(type).addItem(nItem); if (newSlot == -1) { c.announce(MaplePacketCreator.getInventoryFull()); c.announce(MaplePacketCreator.getShowInventoryFull()); return false; } c.announce(MaplePacketCreator.addInventorySlot(type, nItem)); c.announce(MaplePacketCreator.enableActions()); } } else if (quantity == 1) { byte newSlot = c.getPlayer().getInventory(type).addItem(item); if (newSlot == -1) { c.announce(MaplePacketCreator.getInventoryFull()); c.announce(MaplePacketCreator.getShowInventoryFull()); return false; } c.announce(MaplePacketCreator.addInventorySlot(type, item, true)); } else { return false; } if (show) { c.announce(MaplePacketCreator.getShowItemGain(item.getItemId(), item.getQuantity())); } return true; } public static boolean checkSpace(MapleClient c, int itemid, int quantity, String owner) { MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance(); MapleInventoryType type = ii.getInventoryType(itemid); if (!type.equals(MapleInventoryType.EQUIP)) { short slotMax = ii.getSlotMax(c, itemid); List<IItem> existing = c.getPlayer().getInventory(type).listById(itemid); if (!ItemConstants.isRechargable(itemid)) { if (existing.size() > 0) // first update all existing slots to // slotMax { for (IItem eItem : existing) { short oldQ = eItem.getQuantity(); if (oldQ < slotMax && owner.equals(eItem.getOwner())) { short newQ = (short) Math.min(oldQ + quantity, slotMax); quantity -= (newQ - oldQ); } if (quantity <= 0) { break; } } } } final int numSlotsNeeded; if (slotMax > 0) { numSlotsNeeded = (int) (Math.ceil(((double) quantity) / slotMax)); } else if (ItemConstants.isRechargable(itemid)) { numSlotsNeeded = 1; } else { numSlotsNeeded = 1; Output.print("checkSpace error"); } return !c.getPlayer().getInventory(type).isFull(numSlotsNeeded - 1); } else { return !c.getPlayer().getInventory(type).isFull(); } } public static void removeFromSlot(MapleClient c, MapleInventoryType type, byte slot, short quantity, boolean fromDrop) { removeFromSlot(c, type, slot, quantity, fromDrop, false); } public static void removeFromSlot(MapleClient c, MapleInventoryType type, byte slot, short quantity, boolean fromDrop, boolean consume) { IItem item = c.getPlayer().getInventory(type).getItem(slot); boolean allowZero = consume && ItemConstants.isRechargable(item.getItemId()); c.getPlayer().getInventory(type).removeItem(slot, quantity, allowZero); if (item.getQuantity() == 0 && !allowZero) { c.announce(MaplePacketCreator.clearInventoryItem(type, item.getPosition(), fromDrop)); } else { c.announce(MaplePacketCreator.updateInventorySlot(type, (Item) item, fromDrop)); } } public static void removeById(MapleClient c, MapleInventoryType type, int itemId, int quantity, boolean fromDrop, boolean consume) { List<IItem> items = c.getPlayer().getInventory(type).listById(itemId); int remremove = quantity; for (IItem item : items) { if (remremove <= item.getQuantity()) { removeFromSlot(c, type, item.getPosition(), (short) remremove, fromDrop, consume); remremove = 0; break; } else { remremove -= item.getQuantity(); removeFromSlot(c, type, item.getPosition(), item.getQuantity(), fromDrop, consume); } } if (remremove > 0) { throw new RuntimeException("[h4x] Not enough items available (" + itemId + ", " + (quantity - remremove) + "/" + quantity + ")"); } } public static void move(MapleClient c, MapleInventoryType type, byte src, byte dst) { if (src < 0 || dst < 0) { return; } MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance(); IItem source = c.getPlayer().getInventory(type).getItem(src); IItem initialTarget = c.getPlayer().getInventory(type).getItem(dst); if (source == null) { return; } short olddstQ = -1; if (initialTarget != null) { olddstQ = initialTarget.getQuantity(); } short oldsrcQ = source.getQuantity(); short slotMax = ii.getSlotMax(c, source.getItemId()); c.getPlayer().getInventory(type).move(src, dst, slotMax); if (!type.equals(MapleInventoryType.EQUIP) && initialTarget != null && initialTarget.getItemId() == source.getItemId() && !ItemConstants.isRechargable(source.getItemId())) { if ((olddstQ + oldsrcQ) > slotMax) { c.announce(MaplePacketCreator.moveAndMergeWithRestInventoryItem(type, src, dst, (short) ((olddstQ + oldsrcQ) - slotMax), slotMax)); } else { c.announce(MaplePacketCreator.moveAndMergeInventoryItem(type, src, dst, ((Item) c.getPlayer().getInventory(type).getItem(dst)).getQuantity())); } } else { c.announce(MaplePacketCreator.moveInventoryItem(type, src, dst)); } } public static void equip(MapleClient c, byte src, byte dst) { Equip source = (Equip) c.getPlayer().getInventory(MapleInventoryType.EQUIP).getItem(src); Equip target = (Equip) c.getPlayer().getInventory(MapleInventoryType.EQUIPPED).getItem(dst); if (source == null || !MapleItemInformationProvider.getInstance().canWearEquipment(c.getPlayer(), source)) { c.announce(MaplePacketCreator.enableActions()); return; } else if ((((source.getItemId() >= 1902000 && source.getItemId() <= 1902002) || source.getItemId() == 1912000) && c.getPlayer().isCygnus()) || ((source.getItemId() >= 1902005 && source.getItemId() <= 1902007) || source.getItemId() == 1912005) && !c.getPlayer().isCygnus()) {// Adventurer // taming // equipment return; } if (MapleItemInformationProvider.getInstance().isUntradeableOnEquip(source.getItemId())) { source.setFlag((byte) ItemConstants.UNTRADEABLE); } if (source.getRingId() > -1) { c.getPlayer().getRingById(source.getRingId()).equip(); } if (dst == -6) { // unequip the overall IItem top = c.getPlayer().getInventory(MapleInventoryType.EQUIPPED).getItem((byte) -5); if (top != null && isOverall(top.getItemId())) { if (c.getPlayer().getInventory(MapleInventoryType.EQUIP).isFull()) { c.announce(MaplePacketCreator.getInventoryFull()); c.announce(MaplePacketCreator.getShowInventoryFull()); return; } unequip(c, (byte) -5, c.getPlayer().getInventory(MapleInventoryType.EQUIP).getNextFreeSlot()); } } else if (dst == -5) { final IItem bottom = c.getPlayer().getInventory(MapleInventoryType.EQUIPPED).getItem((byte) -6); if (bottom != null && isOverall(source.getItemId())) { if (c.getPlayer().getInventory(MapleInventoryType.EQUIP).isFull()) { c.announce(MaplePacketCreator.getInventoryFull()); c.announce(MaplePacketCreator.getShowInventoryFull()); return; } unequip(c, (byte) -6, c.getPlayer().getInventory(MapleInventoryType.EQUIP).getNextFreeSlot()); } } else if (dst == -10) {// check if weapon is two-handed IItem weapon = c.getPlayer().getInventory(MapleInventoryType.EQUIPPED).getItem((byte) -11); if (weapon != null && MapleItemInformationProvider.getInstance().isTwoHanded(weapon.getItemId())) { if (c.getPlayer().getInventory(MapleInventoryType.EQUIP).isFull()) { c.announce(MaplePacketCreator.getInventoryFull()); c.announce(MaplePacketCreator.getShowInventoryFull()); return; } unequip(c, (byte) -11, c.getPlayer().getInventory(MapleInventoryType.EQUIP).getNextFreeSlot()); } } else if (dst == -11) { IItem shield = c.getPlayer().getInventory(MapleInventoryType.EQUIPPED).getItem((byte) -10); if (shield != null && MapleItemInformationProvider.getInstance().isTwoHanded(source.getItemId())) { if (c.getPlayer().getInventory(MapleInventoryType.EQUIP).isFull()) { c.announce(MaplePacketCreator.getInventoryFull()); c.announce(MaplePacketCreator.getShowInventoryFull()); return; } unequip(c, (byte) -10, c.getPlayer().getInventory(MapleInventoryType.EQUIP).getNextFreeSlot()); } } if (dst == -18) { if (c.getPlayer().getMount() != null) { c.getPlayer().getMount().setItemId(source.getItemId()); } } if (source.getItemId() == 1122017) { c.getPlayer().equipPendantOfSpirit(); } // 1112413, 1112414, 1112405 (Lilin's Ring) source = (Equip) c.getPlayer().getInventory(MapleInventoryType.EQUIP).getItem(src); target = (Equip) c.getPlayer().getInventory(MapleInventoryType.EQUIPPED).getItem(dst); c.getPlayer().getInventory(MapleInventoryType.EQUIP).removeSlot(src); if (target != null) { c.getPlayer().getInventory(MapleInventoryType.EQUIPPED).removeSlot(dst); } source.setPosition(dst); c.getPlayer().getInventory(MapleInventoryType.EQUIPPED).addFromDB(source); if (target != null) { target.setPosition(src); c.getPlayer().getInventory(MapleInventoryType.EQUIP).addFromDB(target); } if (c.getPlayer().getBuffedValue(MapleBuffStat.BOOSTER) != null && isWeapon(source.getItemId())) { c.getPlayer().cancelBuffStats(MapleBuffStat.BOOSTER); } c.announce(MaplePacketCreator.moveInventoryItem(MapleInventoryType.EQUIP, src, dst, (byte) 2)); c.getPlayer().forceUpdateItem(MapleInventoryType.EQUIPPED, source); c.getPlayer().equipChanged(); } public static void unequip(MapleClient c, byte src, byte dst) { Equip source = (Equip) c.getPlayer().getInventory(MapleInventoryType.EQUIPPED).getItem(src); Equip target = (Equip) c.getPlayer().getInventory(MapleInventoryType.EQUIP).getItem(dst); if (dst < 0) { Output.print("Unequipping to negative slot."); } if (source == null) { return; } if (target != null && src <= 0) { c.announce(MaplePacketCreator.getInventoryFull()); return; } if (source.getItemId() == 1122017) { c.getPlayer().unequipPendantOfSpirit(); } if (source.getRingId() > -1) { c.getPlayer().getRingById(source.getRingId()).unequip(); } c.getPlayer().getInventory(MapleInventoryType.EQUIPPED).removeSlot(src); if (target != null) { c.getPlayer().getInventory(MapleInventoryType.EQUIP).removeSlot(dst); } source.setPosition(dst); c.getPlayer().getInventory(MapleInventoryType.EQUIP).addFromDB(source); if (target != null) { target.setPosition(src); c.getPlayer().getInventory(MapleInventoryType.EQUIPPED).addFromDB(target); } c.announce(MaplePacketCreator.moveInventoryItem(MapleInventoryType.EQUIP, src, dst, (byte) 1)); c.getPlayer().equipChanged(); } public static void drop(MapleClient c, MapleInventoryType type, byte src, short quantity) { MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance(); if (src < 0) { type = MapleInventoryType.EQUIPPED; } IItem source = c.getPlayer().getInventory(type).getItem(src); int itemId = source.getItemId(); if (itemId >= 5000000 && itemId <= 5000100) { return; } if (type == MapleInventoryType.EQUIPPED && itemId == 1122017) { c.getPlayer().unequipPendantOfSpirit(); } if (c.getPlayer().getItemEffect() == itemId && source.getQuantity() == 1) { c.getPlayer().setItemEffect(0); c.getPlayer().getMap().broadcastMessage(MaplePacketCreator.itemEffect(c.getPlayer().getId(), 0)); } else if (itemId == 5370000 || itemId == 5370001) { if (c.getPlayer().getItemQuantity(itemId, false) == 1) { c.getPlayer().setChalkboard(null); } } if (c.getPlayer().getItemQuantity(itemId, true) < quantity || quantity < 0 || source == null || quantity == 0 && !ItemConstants.isRechargable(itemId)) { return; } Point dropPos = new Point(c.getPlayer().getPosition()); if (quantity < source.getQuantity() && !ItemConstants.isRechargable(itemId)) { IItem target = source.copy(); target.setQuantity(quantity); source.setQuantity((short) (source.getQuantity() - quantity)); c.announce(MaplePacketCreator.dropInventoryItemUpdate(type, source)); boolean weddingRing = source.getItemId() == 1112803 || source.getItemId() == 1112806 || source.getItemId() == 1112807 || source.getItemId() == 1112809; if (weddingRing) { c.getPlayer().getMap().disappearingItemDrop(c.getPlayer(), c.getPlayer(), target, dropPos); } else if (c.getPlayer().getMap().getEverlast()) { if ((ii.isDropRestricted(target.getItemId()) && !ServerConstants.DROP_UNTRADEABLE_ITEMS) || MapleItemInformationProvider.getInstance().isCash(target.getItemId())) { c.getPlayer().getMap().disappearingItemDrop(c.getPlayer(), c.getPlayer(), target, dropPos); } else { c.getPlayer().getMap().spawnItemDrop(c.getPlayer(), c.getPlayer(), target, dropPos, true, false); } } else if ((ii.isDropRestricted(target.getItemId()) && !ServerConstants.DROP_UNTRADEABLE_ITEMS) || MapleItemInformationProvider.getInstance().isCash(target.getItemId())) { c.getPlayer().getMap().disappearingItemDrop(c.getPlayer(), c.getPlayer(), target, dropPos); } else { c.getPlayer().getMap().spawnItemDrop(c.getPlayer(), c.getPlayer(), target, dropPos, true, true); } } else { c.getPlayer().getInventory(type).removeSlot(src); c.announce(MaplePacketCreator.dropInventoryItem((src < 0 ? MapleInventoryType.EQUIP : type), src)); if (src < 0) { c.getPlayer().equipChanged(); } if (c.getPlayer().getMap().getEverlast()) { if ((ii.isDropRestricted(itemId) && !ServerConstants.DROP_UNTRADEABLE_ITEMS)) { c.getPlayer().getMap().disappearingItemDrop(c.getPlayer(), c.getPlayer(), source, dropPos); } else { c.getPlayer().getMap().spawnItemDrop(c.getPlayer(), c.getPlayer(), source, dropPos, true, false); } } else if ((ii.isDropRestricted(itemId) && !ServerConstants.DROP_UNTRADEABLE_ITEMS)) { c.getPlayer().getMap().disappearingItemDrop(c.getPlayer(), c.getPlayer(), source, dropPos); } else { c.getPlayer().getMap().spawnItemDrop(c.getPlayer(), c.getPlayer(), source, dropPos, true, true); } } } private static boolean isOverall(int itemId) { return itemId / 10000 == 105; } private static boolean isWeapon(int itemId) { return itemId >= 1302000 && itemId < 1492024; } }