/* * The ManaPlus Client * Copyright (C) 2004-2009 The Mana World Development Team * Copyright (C) 2009-2010 The Mana Developers * Copyright (C) 2011-2015 The ManaPlus Developers * * This file is part of The ManaPlus Client. * * 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 2 of the License, or * 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 . */ #include "net/eathena/inventoryhandler.h" #include "notifymanager.h" #include "itemcolormanager.h" #include "being/localplayer.h" #include "enums/equipslot.h" #include "enums/resources/notifytypes.h" #include "gui/popups/itempopup.h" #include "gui/widgets/createwidget.h" #include "gui/windows/insertcarddialog.h" #include "listeners/arrowslistener.h" #include "net/ea/inventoryrecv.h" #include "net/eathena/inventoryrecv.h" #include "net/eathena/itemflags.h" #include "net/eathena/menu.h" #include "net/eathena/messageout.h" #include "net/eathena/protocol.h" #include "net/ea/eaprotocol.h" #include "net/ea/equipbackend.h" #include "resources/iteminfo.h" #include "utils/gettext.h" #include "utils/stringutils.h" #include "debug.h" extern Net::InventoryHandler *inventoryHandler; // missing EQUIP_RING1_SLOT const EquipSlot::Type EQUIP_CONVERT[] = { EquipSlot::PROJECTILE_SLOT, // 0 0 EquipSlot::FEET_SLOT, // 1 SPRITE_HAIR EquipSlot::LEGS_SLOT, // 2 SPRITE_WEAPON EquipSlot::TORSO_SLOT, // 3 SPRITE_HEAD_BOTTOM EquipSlot::GLOVES_SLOT, // 4 0 EquipSlot::EVOL_RING1_SLOT, // 5 EquipSlot::PROJECTILE_SLOT, // 6 0 EquipSlot::HEAD_SLOT, // 7 SPRITE_CLOTHES_COLOR EquipSlot::RING2_SLOT, // 8 0 EquipSlot::PROJECTILE_SLOT, // 9 SPRITE_SHOES EquipSlot::FIGHT1_SLOT, // 10 SPRITE_BODY EquipSlot::FIGHT2_SLOT, // 11 SPRITE_FLOOR EquipSlot::EVOL_RING2_SLOT, // 12 EquipSlot::PROJECTILE_SLOT, // 13 SPRITE_EVOL2 EquipSlot::COSTUME_ROBE_SLOT, // 14 SPRITE_EVOL3 EquipSlot::RING1_SLOT, // 15 SPRITE_EVOL4 }; namespace EAthena { InventoryHandler::InventoryHandler() : MessageHandler(), Ea::InventoryHandler(), mItemIndex(0) { static const uint16_t _messages[] = { SMSG_PLAYER_INVENTORY, SMSG_PLAYER_INVENTORY_ADD, SMSG_PLAYER_INVENTORY_REMOVE, SMSG_PLAYER_INVENTORY_REMOVE2, SMSG_PLAYER_INVENTORY_USE, SMSG_ITEM_USE_RESPONSE, SMSG_PLAYER_STORAGE_ITEMS, SMSG_PLAYER_STORAGE_EQUIP, SMSG_PLAYER_STORAGE_STATUS, SMSG_PLAYER_STORAGE_ADD, SMSG_PLAYER_STORAGE_REMOVE, SMSG_PLAYER_STORAGE_CLOSE, SMSG_PLAYER_EQUIPMENT, SMSG_PLAYER_EQUIP, SMSG_PLAYER_UNEQUIP, SMSG_PLAYER_ARROW_EQUIP, SMSG_PLAYER_ATTACK_RANGE, SMSG_PLAYER_USE_CARD, SMSG_PLAYER_INSERT_CARD, SMSG_PLAYER_ITEM_RENTAL_TIME, SMSG_PLAYER_ITEM_RENTAL_EXPIRED, SMSG_CART_INFO, SMSG_CART_REMOVE, SMSG_PLAYER_CART_ADD, SMSG_PLAYER_CART_EQUIP, SMSG_PLAYER_CART_ITEMS, SMSG_PLAYER_CART_REMOVE, SMSG_PLAYER_IDENTIFY_LIST, SMSG_PLAYER_IDENTIFIED, SMSG_PLAYER_REFINE, SMSG_PLAYER_REPAIR_LIST, SMSG_PLAYER_REPAIR_EFFECT, SMSG_PLAYER_REFINE_LIST, SMSG_PLAYER_STORAGE_PASSWORD, SMSG_PLAYER_STORAGE_PASSWORD_RESULT, SMSG_PLAYER_COOKING_LIST, SMSG_ITEM_DAMAGED, SMSG_PLAYER_FAVORITE_ITEM, SMSG_PLAYER_CART_ADD_ERROR, SMSG_BIND_ITEM, 0 }; handledMessages = _messages; inventoryHandler = this; InventoryRecv::mCartItems.clear(); } InventoryHandler::~InventoryHandler() { } void InventoryHandler::handleMessage(Net::MessageIn &msg) { switch (msg.getId()) { case SMSG_PLAYER_INVENTORY: InventoryRecv::processPlayerInventory(msg); break; case SMSG_PLAYER_STORAGE_ITEMS: InventoryRecv::processPlayerStorage(msg); break; case SMSG_PLAYER_STORAGE_EQUIP: InventoryRecv::processPlayerStorageEquip(msg); break; case SMSG_PLAYER_INVENTORY_ADD: InventoryRecv::processPlayerInventoryAdd(msg); break; case SMSG_PLAYER_INVENTORY_REMOVE: Ea::InventoryRecv::processPlayerInventoryRemove(msg); break; case SMSG_PLAYER_INVENTORY_REMOVE2: InventoryRecv::processPlayerInventoryRemove2(msg); break; case SMSG_PLAYER_INVENTORY_USE: Ea::InventoryRecv::processPlayerInventoryUse(msg); break; case SMSG_ITEM_USE_RESPONSE: Ea::InventoryRecv::processItemUseResponse(msg); break; case SMSG_PLAYER_STORAGE_STATUS: Ea::InventoryRecv::processPlayerStorageStatus(msg); break; case SMSG_PLAYER_STORAGE_ADD: InventoryRecv::processPlayerStorageAdd(msg); break; case SMSG_PLAYER_STORAGE_REMOVE: InventoryRecv::processPlayerStorageRemove(msg); break; case SMSG_PLAYER_STORAGE_CLOSE: Ea::InventoryRecv::processPlayerStorageClose(msg); break; case SMSG_PLAYER_EQUIPMENT: InventoryRecv::processPlayerEquipment(msg); break; case SMSG_PLAYER_EQUIP: InventoryRecv::processPlayerEquip(msg); break; case SMSG_PLAYER_UNEQUIP: InventoryRecv::processPlayerUnEquip(msg); break; case SMSG_PLAYER_ATTACK_RANGE: Ea::InventoryRecv::processPlayerAttackRange(msg); break; case SMSG_PLAYER_ARROW_EQUIP: Ea::InventoryRecv::processPlayerArrowEquip(msg); break; case SMSG_PLAYER_USE_CARD: InventoryRecv::processPlayerUseCard(msg); break; case SMSG_PLAYER_INSERT_CARD: InventoryRecv::processPlayerInsertCard(msg); break; case SMSG_PLAYER_ITEM_RENTAL_TIME: InventoryRecv::processPlayerItemRentalTime(msg); break; case SMSG_PLAYER_ITEM_RENTAL_EXPIRED: InventoryRecv::processPlayerItemRentalExpired(msg); break; case SMSG_CART_INFO: InventoryRecv::processCartInfo(msg); break; case SMSG_CART_REMOVE: InventoryRecv::processCartRemove(msg); break; case SMSG_PLAYER_CART_ADD: InventoryRecv::processPlayerCartAdd(msg); break; case SMSG_PLAYER_CART_EQUIP: InventoryRecv::processPlayerCartEquip(msg); break; case SMSG_PLAYER_CART_ITEMS: InventoryRecv::processPlayerCartItems(msg); break; case SMSG_PLAYER_CART_REMOVE: InventoryRecv::processPlayerCartRemove(msg); break; case SMSG_PLAYER_IDENTIFY_LIST: InventoryRecv::processPlayerIdentifyList(msg); break; case SMSG_PLAYER_IDENTIFIED: InventoryRecv::processPlayerIdentified(msg); break; case SMSG_PLAYER_REFINE: InventoryRecv::processPlayerRefine(msg); break; case SMSG_PLAYER_REPAIR_LIST: InventoryRecv::processPlayerRepairList(msg); break; case SMSG_PLAYER_REPAIR_EFFECT: InventoryRecv::processPlayerRepairEffect(msg); break; case SMSG_PLAYER_REFINE_LIST: InventoryRecv::processPlayerRefineList(msg); break; case SMSG_PLAYER_STORAGE_PASSWORD: InventoryRecv::processPlayerStoragePassword(msg); break; case SMSG_PLAYER_STORAGE_PASSWORD_RESULT: InventoryRecv::processPlayerStoragePasswordResult(msg); break; case SMSG_PLAYER_COOKING_LIST: InventoryRecv::processPlayerCookingList(msg); break; case SMSG_ITEM_DAMAGED: InventoryRecv::processItemDamaged(msg); break; case SMSG_PLAYER_FAVORITE_ITEM: InventoryRecv::processFavoriteItem(msg); break; case SMSG_PLAYER_CART_ADD_ERROR: InventoryRecv::processCartAddError(msg); break; case SMSG_BIND_ITEM: InventoryRecv::processBindItem(msg); break; default: break; } } void InventoryHandler::equipItem(const Item *const item) const { if (!item) return; createOutPacket(CMSG_PLAYER_EQUIP); outMsg.writeInt16(static_cast( item->getInvIndex() + INVENTORY_OFFSET), "index"); // here we set flag for any slots, // probably better set to slot from item properties outMsg.writeInt32(0xFFFFFFFFU, "wear location"); } void InventoryHandler::unequipItem(const Item *const item) const { if (!item) return; createOutPacket(CMSG_PLAYER_UNEQUIP); outMsg.writeInt16(static_cast( item->getInvIndex() + INVENTORY_OFFSET), "index"); } void InventoryHandler::useItem(const Item *const item) const { if (!item) return; createOutPacket(CMSG_PLAYER_INVENTORY_USE); outMsg.writeInt16(static_cast( item->getInvIndex() + INVENTORY_OFFSET), "index"); outMsg.writeInt32(item->getId(), "unused"); } void InventoryHandler::dropItem(const Item *const item, const int amount) const { if (!item) return; createOutPacket(CMSG_PLAYER_INVENTORY_DROP); outMsg.writeInt16(static_cast( item->getInvIndex() + INVENTORY_OFFSET), "index"); outMsg.writeInt16(static_cast(amount), "amount"); } void InventoryHandler::closeStorage(const int type A_UNUSED) const { createOutPacket(CMSG_CLOSE_STORAGE); } void InventoryHandler::moveItem2(const int source, const int slot, const int amount, const int destination) const { int packet = 0; int offset = INVENTORY_OFFSET; if (source == InventoryType::INVENTORY) { if (destination == InventoryType::STORAGE) packet = CMSG_MOVE_TO_STORAGE; else if (destination == InventoryType::CART) packet = CMSG_MOVE_TO_CART; } else if (source == InventoryType::STORAGE) { offset = STORAGE_OFFSET; if (destination == InventoryType::INVENTORY) packet = CMSG_MOVE_FROM_STORAGE; else if (destination == InventoryType::CART) packet = CMSG_MOVE_FROM_STORAGE_TO_CART; } else if (source == InventoryType::CART) { if (destination == InventoryType::INVENTORY) packet = CMSG_MOVE_FROM_CART; else if (destination == InventoryType::STORAGE) packet = CMSG_MOVE_FROM_CART_TO_STORAGE; } if (packet) { createOutPacket(packet); outMsg.writeInt16(static_cast(slot + offset), "index"); outMsg.writeInt32(amount, "amount"); } } void InventoryHandler::useCard(const Item *const item) { if (!item) return; mItemIndex = item->getInvIndex(); createOutPacket(CMSG_PLAYER_USE_CARD); outMsg.writeInt16(static_cast( mItemIndex + INVENTORY_OFFSET), "index"); } void InventoryHandler::insertCard(const int cardIndex, const int itemIndex) const { createOutPacket(CMSG_PLAYER_INSERT_CARD); outMsg.writeInt16(static_cast(cardIndex + INVENTORY_OFFSET), "card index"); outMsg.writeInt16(static_cast(itemIndex + INVENTORY_OFFSET), "item index"); } void InventoryHandler::favoriteItem(const Item *const item, const bool favorite) const { if (!item) return; createOutPacket(CMSG_PLAYER_FAVORITE_ITEM); outMsg.writeInt16(static_cast(item->getInvIndex() + INVENTORY_OFFSET), "item index"); outMsg.writeInt8(favorite, "favorite flag"); } void InventoryHandler::selectEgg(const Item *const item) const { if (!item) return; createOutPacket(CMSG_PET_SELECT_EGG); outMsg.writeInt16(static_cast( item->getInvIndex() + INVENTORY_OFFSET), "index"); menu = MenuType::Unknown; } int InventoryHandler::convertFromServerSlot(const int serverSlot) const { if (serverSlot < 0 || serverSlot > 15) return 0; return static_cast(EQUIP_CONVERT[serverSlot]); } } // namespace EAthena