diff options
-rw-r--r-- | src/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/Makefile.am | 4 | ||||
-rw-r--r-- | src/net/ea/eaprotocol.h | 3 | ||||
-rw-r--r-- | src/net/ea/inventoryhandler.cpp | 624 | ||||
-rw-r--r-- | src/net/ea/inventoryhandler.h | 204 | ||||
-rw-r--r-- | src/net/ea/partyhandler.cpp | 2 | ||||
-rw-r--r-- | src/net/tmwa/buysellhandler.cpp | 2 | ||||
-rw-r--r-- | src/net/tmwa/inventoryhandler.cpp | 515 | ||||
-rw-r--r-- | src/net/tmwa/inventoryhandler.h | 128 | ||||
-rw-r--r-- | src/net/tmwa/npchandler.cpp | 2 | ||||
-rw-r--r-- | src/net/tmwa/protocol.h | 3 | ||||
-rw-r--r-- | src/net/tmwa/tradehandler.cpp | 2 |
12 files changed, 863 insertions, 628 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 27067bc92..ace8ad10b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -695,6 +695,8 @@ SET(SRCS_EVOL net/ea/gamehandler.h net/ea/guildhandler.cpp net/ea/guildhandler.h + net/ea/inventoryhandler.cpp + net/ea/inventoryhandler.h net/ea/loginhandler.cpp net/ea/loginhandler.h net/ea/partyhandler.cpp diff --git a/src/Makefile.am b/src/Makefile.am index ab935904d..25e796d3d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -674,11 +674,13 @@ manaplus_SOURCES += \ net/ea/charserverhandler.h \ net/ea/chathandler.cpp \ net/ea/chathandler.h \ + net/ea/eaprotocol.h \ net/ea/gamehandler.cpp \ net/ea/gamehandler.h \ net/ea/guildhandler.cpp \ net/ea/guildhandler.h \ - net/ea/eaprotocol.h \ + net/ea/inventoryhandler.cpp \ + net/ea/inventoryhandler.h \ net/ea/loginhandler.cpp \ net/ea/loginhandler.h \ net/ea/partyhandler.cpp \ diff --git a/src/net/ea/eaprotocol.h b/src/net/ea/eaprotocol.h index 11cc0180d..fae3651a8 100644 --- a/src/net/ea/eaprotocol.h +++ b/src/net/ea/eaprotocol.h @@ -42,4 +42,7 @@ enum EA_SPRITE_VECTOREND }; +static const int INVENTORY_OFFSET = 2; +static const int STORAGE_OFFSET = 1; + #endif diff --git a/src/net/ea/inventoryhandler.cpp b/src/net/ea/inventoryhandler.cpp new file mode 100644 index 000000000..1b13b1121 --- /dev/null +++ b/src/net/ea/inventoryhandler.cpp @@ -0,0 +1,624 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011 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 <http://www.gnu.org/licenses/>. + */ + +#include "net/ea/inventoryhandler.h" + +#include "inventory.h" +#include "localplayer.h" +#include "log.h" + +#include "gui/ministatus.h" + +#include "net/messagein.h" + +#include "net/ea/eaprotocol.h" + +#include "utils/gettext.h" + +#include "debug.h" + +const Equipment::Slot EQUIP_POINTS[Equipment::EQUIP_VECTOREND] = +{ + Equipment::EQUIP_LEGS_SLOT, + Equipment::EQUIP_FIGHT1_SLOT, + Equipment::EQUIP_GLOVES_SLOT, + Equipment::EQUIP_RING2_SLOT, + Equipment::EQUIP_RING1_SLOT, + Equipment::EQUIP_FIGHT2_SLOT, + Equipment::EQUIP_FEET_SLOT, + Equipment::EQUIP_NECK_SLOT, + Equipment::EQUIP_HEAD_SLOT, + Equipment::EQUIP_TORSO_SLOT, + Equipment::EQUIP_EVOL_RING1_SLOT, + Equipment::EQUIP_EVOL_RING2_SLOT, + Equipment::EQUIP_PROJECTILE_SLOT, +}; + +// missing EQUIP_RING1_SLOT +const Equipment::Slot EQUIP_CONVERT[] = +{ + Equipment::EQUIP_PROJECTILE_SLOT, // 0 + Equipment::EQUIP_FEET_SLOT, // SPRITE_SHOE + Equipment::EQUIP_LEGS_SLOT, // SPRITE_BOTTOMCLOTHES + Equipment::EQUIP_TORSO_SLOT, // SPRITE_TOPCLOTHES + Equipment::EQUIP_PROJECTILE_SLOT, // 0 + Equipment::EQUIP_NECK_SLOT, // SPRITE_RING + Equipment::EQUIP_PROJECTILE_SLOT, // 0 + Equipment::EQUIP_HEAD_SLOT, // SPRITE_HAT + Equipment::EQUIP_RING2_SLOT, // 0 + Equipment::EQUIP_GLOVES_SLOT, // SPRITE_GLOVES + Equipment::EQUIP_FIGHT1_SLOT, // SPRITE_WEAPON + Equipment::EQUIP_FIGHT2_SLOT, // SPRITE_SHIELD + Equipment::EQUIP_EVOL_RING1_SLOT, // SPRITE_EVOL1 + Equipment::EQUIP_EVOL_RING2_SLOT, // SPRITE_EVOL2 + Equipment::EQUIP_PROJECTILE_SLOT, // 0 +}; + +namespace Ea +{ + +InventoryHandler::InventoryHandler() +{ + mStorage = 0; + mStorageWindow = 0; + mDebugInventory = true; +} + +InventoryHandler::~InventoryHandler() +{ + if (mStorageWindow) + { + mStorageWindow->close(); + mStorageWindow = 0; + } + + delete mStorage; + mStorage = 0; +} + +bool InventoryHandler::canSplit(const Item *item A_UNUSED) const +{ + return false; +} + +void InventoryHandler::splitItem(const Item *item A_UNUSED, + int amount A_UNUSED) +{ + // Not implemented for eAthena (possible?) +} + +void InventoryHandler::moveItem(int oldIndex A_UNUSED, int newIndex A_UNUSED) +{ + // Not implemented for eAthena (possible?) +} + +void InventoryHandler::openStorage(int type A_UNUSED) +{ + // Doesn't apply to eAthena, since opening happens through NPCs? +} + +size_t InventoryHandler::getSize(int type) const +{ + switch (type) + { + case Inventory::INVENTORY: + return 100; + case Inventory::STORAGE: + return 0; // Comes from server after items + case Inventory::TRADE: + return 12; + case GUILD_STORAGE: + return 0; // Comes from server after items + default: + return 0; + } +} +int InventoryHandler::convertFromServerSlot(int serverSlot) const +{ + if (serverSlot < 0 || serverSlot > 13) + return 0; + + return EQUIP_CONVERT[serverSlot]; +} + +int InventoryHandler::getSlot(int eAthenaSlot) +{ + if (eAthenaSlot == 0) + return Equipment::EQUIP_VECTOREND; + + if (eAthenaSlot & 0x8000) + return Equipment::EQUIP_PROJECTILE_SLOT; + + int mask = 1; + int position = 0; + while (!(eAthenaSlot & mask)) + { + mask <<= 1; + position++; + } + return EQUIP_POINTS[position]; +} + +void InventoryHandler::processPlayerInventory(Net::MessageIn &msg, bool playerInvintory) +{ + int index, amount, itemId, arrow; + int cards[4], itemType; + unsigned char identified; + Inventory *inventory = 0; + + if (player_node) + inventory = PlayerInfo::getInventory(); + + if (playerInvintory) + { + if (PlayerInfo::getEquipment()) + { + // Clear inventory - this will be a complete refresh + mEquips.clear(); + PlayerInfo::getEquipment()->setBackend(&mEquips); + } + + if (inventory) + inventory->clear(); + } + else + { + mInventoryItems.clear(); + } + + msg.readInt16(); // length + int number = (msg.getLength() - 4) / 18; + + for (int loop = 0; loop < number; loop++) + { + index = msg.readInt16(); + itemId = msg.readInt16(); + itemType = msg.readInt8(); + identified = msg.readInt8(); + amount = msg.readInt16(); + arrow = msg.readInt16(); + for (int i = 0; i < 4; i++) + cards[i] = msg.readInt16(); + + index -= ((msg.getId() == playerInvintory) ? + INVENTORY_OFFSET : STORAGE_OFFSET); + + if (mDebugInventory) + { + logger->log("Index: %d, ID: %d, Type: %d, Identified: %d, " + "Qty: %d, Cards: %d, %d, %d, %d", + index, itemId, itemType, identified, amount, + cards[0], cards[1], cards[2], cards[3]); + } + + if (serverVersion < 1 && identified > 1) + identified = 1; + + if (playerInvintory) + { + // Trick because arrows are not considered equipment + bool isEquipment = arrow & 0x8000; + + if (inventory) + { + inventory->setItem(index, itemId, amount, + 0, identified, isEquipment); + } + } + else + { + mInventoryItems.push_back(Ea::InventoryItem(index, itemId, + amount, 0, identified, false)); + } + } +} + +void InventoryHandler::processPlayerStorageEquip(Net::MessageIn &msg) +{ + int index, amount, itemId, refine; + int cards[4], itemType; + unsigned char identified; + + msg.readInt16(); // length + int number = (msg.getLength() - 4) / 20; + + for (int loop = 0; loop < number; loop++) + { + index = msg.readInt16() - STORAGE_OFFSET; + itemId = msg.readInt16(); + itemType = msg.readInt8(); + identified = msg.readInt8(); + amount = 1; + msg.readInt16(); // Equip Point? + msg.readInt16(); // Another Equip Point? + msg.readInt8(); // Attribute (broken) + refine = msg.readInt8(); + for (int i = 0; i < 4; i++) + cards[i] = msg.readInt16(); + + if (mDebugInventory) + { + logger->log("Index: %d, ID: %d, Type: %d, Identified: %d, " + "Qty: %d, Cards: %d, %d, %d, %d, Refine: %d", + index, itemId, itemType, identified, amount, + cards[0], cards[1], cards[2], cards[3], + refine); + } + + if (serverVersion < 1 && identified > 1) + identified = 1; + + mInventoryItems.push_back(Ea::InventoryItem(index, + itemId, amount, refine, identified, false)); + } +} + +void InventoryHandler::processPlayerInventoryAdd(Net::MessageIn &msg) +{ + int index, amount, itemId, equipType, refine; + int cards[4], itemType; + unsigned char identified; + int floorId; + + Inventory *inventory = 0; + if (player_node) + inventory = PlayerInfo::getInventory(); + + if (PlayerInfo::getEquipment() + && !PlayerInfo::getEquipment()->getBackend()) + { // look like SMSG_PLAYER_INVENTORY was not received + mEquips.clear(); + PlayerInfo::getEquipment()->setBackend(&mEquips); + } + index = msg.readInt16() - INVENTORY_OFFSET; + amount = msg.readInt16(); + itemId = msg.readInt16(); + identified = msg.readInt8(); + msg.readInt8(); // attribute + refine = msg.readInt8(); + for (int i = 0; i < 4; i++) + cards[i] = msg.readInt16(); + equipType = msg.readInt16(); + itemType = msg.readInt8(); + + const ItemInfo &itemInfo = ItemDB::get(itemId); + + unsigned char err = msg.readInt8(); + if (mSentPickups.empty()) + { + floorId = 0; + } + else + { + floorId = mSentPickups.front(); + mSentPickups.pop(); + } + + if (err) + { + if (player_node) + { + player_node->pickedUp(itemInfo, 0, identified, + floorId, err); + } + } + else + { + if (player_node) + { + player_node->pickedUp(itemInfo, amount, + identified, floorId, PICKUP_OKAY); + } + + if (inventory) + { + Item *item = inventory->getItem(index); + + if (item && item->getId() == itemId) + amount += inventory->getItem(index)->getQuantity(); + + if (serverVersion < 1 && identified > 1) + identified = 1; + + inventory->setItem(index, itemId, amount, refine, + identified, equipType != 0); + } + } +} + +void InventoryHandler::processPlayerInventoryRemove(Net::MessageIn &msg) +{ + int index, amount; + Inventory *inventory = 0; + if (player_node) + inventory = PlayerInfo::getInventory(); + + index = msg.readInt16() - INVENTORY_OFFSET; + amount = msg.readInt16(); + if (inventory) + { + if (Item *item = inventory->getItem(index)) + { + item->increaseQuantity(-amount); + if (item->getQuantity() == 0) + inventory->removeItemAt(index); + if (miniStatusWindow) + miniStatusWindow->updateArrows(); + } + } +} + +void InventoryHandler::processPlayerInventoryUse(Net::MessageIn &msg) +{ + int index, amount; + Inventory *inventory = 0; + if (player_node) + inventory = PlayerInfo::getInventory(); + + index = msg.readInt16() - INVENTORY_OFFSET; + msg.readInt16(); // item id + msg.readInt32(); // id + amount = msg.readInt16(); + msg.readInt8(); // type + + if (inventory) + { + if (Item *item = inventory->getItem(index)) + { + if (amount) + item->setQuantity(amount); + else + inventory->removeItemAt(index); + } + } +} + +void InventoryHandler::processItemUseResponse(Net::MessageIn &msg) +{ + int index, amount; + Inventory *inventory = 0; + if (player_node) + inventory = PlayerInfo::getInventory(); + + index = msg.readInt16() - INVENTORY_OFFSET; + amount = msg.readInt16(); + + if (msg.readInt8() == 0) + { + SERVER_NOTICE(_("Failed to use item.")) + } + else + { + if (inventory) + { + if (Item *item = inventory->getItem(index)) + { + if (amount) + item->setQuantity(amount); + else + inventory->removeItemAt(index); + } + } + } +} + +void InventoryHandler::processPlayerStorageStatus(Net::MessageIn &msg) +{ + /* + * This is the closest we get to an "Open Storage" packet from the + * server. It always comes after the two SMSG_PLAYER_STORAGE_... + * packets that update storage contents. + */ + msg.readInt16(); // Used count + int size = msg.readInt16(); // Max size + + if (!mStorage) + mStorage = new Inventory(Inventory::STORAGE, size); + + Ea::InventoryItems::iterator it = mInventoryItems.begin(); + Ea::InventoryItems::iterator it_end = mInventoryItems.end(); + for (; it != it_end; ++it) + { + mStorage->setItem((*it).slot, (*it).id, (*it).quantity, + (*it).refine, (*it).color, (*it).equip); + } + mInventoryItems.clear(); + + if (!mStorageWindow) + mStorageWindow = new InventoryWindow(mStorage); +} + +void InventoryHandler::processPlayerStorageAdd(Net::MessageIn &msg) +{ + int index, amount, itemId, refine; + unsigned char identified; + int cards[4]; + + // Move an item into storage + index = msg.readInt16() - STORAGE_OFFSET; + amount = msg.readInt32(); + itemId = msg.readInt16(); + identified = msg.readInt8(); + msg.readInt8(); // attribute + refine = msg.readInt8(); + for (int i = 0; i < 4; i++) + cards[i] = msg.readInt16(); + + if (Item *item = mStorage->getItem(index)) + { + item->setId(itemId, identified); + item->increaseQuantity(amount); + } + else + { + if (mStorage) + { + if (serverVersion < 1 && identified > 1) + identified = 1; + + mStorage->setItem(index, itemId, amount, refine, + identified, false); + } + } +} + +void InventoryHandler::processPlayerStorageRemove(Net::MessageIn &msg) +{ + int index, amount; + + // Move an item out of storage + index = msg.readInt16() - STORAGE_OFFSET; + amount = msg.readInt16(); + if (mStorage) + { + if (Item *item = mStorage->getItem(index)) + { + item->increaseQuantity(-amount); + if (item->getQuantity() == 0) + mStorage->removeItemAt(index); + } + } +} + +void InventoryHandler::processPlayerStorageClose(Net::MessageIn &msg A_UNUSED) +{ + // Storage access has been closed + + // Storage window deletes itself + mStorageWindow = 0; + + if (mStorage) + mStorage->clear(); + + delete mStorage; + mStorage = 0; +} + +void InventoryHandler::processPlayerEquipment(Net::MessageIn &msg) +{ + int index, itemId, equipType, refine; + int number; + unsigned char identified; + + Inventory *inventory = 0; + if (player_node) + inventory = PlayerInfo::getInventory(); + + msg.readInt16(); // length + if (PlayerInfo::getEquipment() + && !PlayerInfo::getEquipment()->getBackend()) + { // look like SMSG_PLAYER_INVENTORY was not received + mEquips.clear(); + PlayerInfo::getEquipment()->setBackend(&mEquips); + } + number = (msg.getLength() - 4) / 20; + + for (int loop = 0; loop < number; loop++) + { + index = msg.readInt16() - INVENTORY_OFFSET; + itemId = msg.readInt16(); + int itemType = msg.readInt8(); // type + identified = msg.readInt8(); // identify flag + + msg.readInt16(); // equip type + equipType = msg.readInt16(); + msg.readInt8(); // attribute + refine = msg.readInt8(); + msg.skip(8); // card + + + if (mDebugInventory) + { + logger->log("Index: %d, ID: %d, Type: %d, Identified: %d", + index, itemId, itemType, identified); + } + + if (serverVersion < 1 && identified > 1) + identified = 1; + + if (inventory) + { + inventory->setItem(index, itemId, 1, refine, + identified, true); + } + + if (equipType) + mEquips.setEquipment(getSlot(equipType), index); + + } +} + +void InventoryHandler::processPlayerEquip(Net::MessageIn &msg) +{ + int index, equipType; + int flag; + + index = msg.readInt16() - INVENTORY_OFFSET; + equipType = msg.readInt16(); + flag = msg.readInt8(); + + if (!flag) + SERVER_NOTICE(_("Unable to equip.")) + else + mEquips.setEquipment(getSlot(equipType), index); +} + +void InventoryHandler::processPlayerUnEquip(Net::MessageIn &msg) +{ + int index, equipType; + int flag; + + index = msg.readInt16() - INVENTORY_OFFSET; + equipType = msg.readInt16(); + flag = msg.readInt8(); + + if (flag) + mEquips.setEquipment(getSlot(equipType), -1); + if (miniStatusWindow && equipType & 0x8000) + miniStatusWindow->updateArrows(); +} + +void InventoryHandler::processPlayerAttackRange(Net::MessageIn &msg) +{ + int range = msg.readInt16(); + if (player_node) + player_node->setAttackRange(range); + PlayerInfo::setStatBase(ATTACK_RANGE, range); + PlayerInfo::setStatMod(ATTACK_RANGE, 0); +} + +void InventoryHandler::processPlayerArrowEquip(Net::MessageIn &msg) +{ + int index = msg.readInt16(); + + if (index <= 1) + return; + + index -= INVENTORY_OFFSET; + + mEquips.setEquipment(Equipment::EQUIP_PROJECTILE_SLOT, index); + + if (miniStatusWindow) + miniStatusWindow->updateArrows(); +} + +} // namespace Ea diff --git a/src/net/ea/inventoryhandler.h b/src/net/ea/inventoryhandler.h new file mode 100644 index 000000000..1f1f8d296 --- /dev/null +++ b/src/net/ea/inventoryhandler.h @@ -0,0 +1,204 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef NET_EA_INVENTORYHANDLER_H +#define NET_EA_INVENTORYHANDLER_H + +#include "equipment.h" +#include "inventory.h" +#include "log.h" +#include "playerinfo.h" + +#include "gui/inventorywindow.h" + +#include "net/inventoryhandler.h" +#include "net/messagein.h" +#include "net/net.h" + +#include <vector> +#include <queue> + +#ifdef __GNUC__ +#define A_UNUSED __attribute__ ((unused)) +#else +#define A_UNUSED +#endif + +namespace Ea +{ + +class EquipBackend : public Equipment::Backend +{ + public: + EquipBackend() + { + memset(mEquipment, -1, sizeof(mEquipment)); + } + + Item *getEquipment(int index) const + { + int invyIndex = mEquipment[index]; + if (invyIndex == -1) + return NULL; + + return PlayerInfo::getInventory()->getItem(invyIndex); + } + + void clear() + { + for (int i = 0; i < EQUIPMENT_SIZE; i++) + { + if (mEquipment[i] != -1) + { + Item* item = PlayerInfo::getInventory()->getItem(i); + if (item) + item->setEquipped(false); + } + + mEquipment[i] = -1; + } + } + + void setEquipment(int index, int inventoryIndex) + { + // Unequip existing item + Item* item = PlayerInfo::getInventory() + ->getItem(mEquipment[index]); + + if (item) + item->setEquipped(false); + + mEquipment[index] = inventoryIndex; + + item = PlayerInfo::getInventory()->getItem(inventoryIndex); + if (item) + item->setEquipped(true); + + if (inventoryWindow) + inventoryWindow->updateButtons(); + } + + private: + int mEquipment[EQUIPMENT_SIZE]; +}; + +/** + * Used to cache storage data until we get size data for it. + */ +class InventoryItem +{ + public: + int slot; + int id; + int quantity; + unsigned char color; + int refine; + bool equip; + + InventoryItem(int slot, int id, int quantity, int refine, + unsigned char color, bool equip) + { + this->slot = slot; + this->id = id; + this->quantity = quantity; + this->refine = refine; + this->color = color; + this->equip = equip; + } +}; + +typedef std::vector<InventoryItem> InventoryItems; + +class InventoryHandler : public Net::InventoryHandler +{ + public: + enum + { + GUILD_STORAGE = Inventory::TYPE_END, + CART + }; + + InventoryHandler(); + + ~InventoryHandler(); + + bool canSplit(const Item *item) const; + + void splitItem(const Item *item, int amount); + + void moveItem(int oldIndex, int newIndex); + + void openStorage(int type); + + size_t getSize(int type) const; + + int convertFromServerSlot(int serverSlot) const; + + void pushPickup(int floorId) + { mSentPickups.push(floorId); } + + int getSlot(int eAthenaSlot); + + void processPlayerInventory(Net::MessageIn &msg, bool playerInvintory); + + void processPlayerStorageEquip(Net::MessageIn &msg); + + void processPlayerInventoryAdd(Net::MessageIn &msg); + + void processPlayerInventoryRemove(Net::MessageIn &msg); + + void processPlayerInventoryUse(Net::MessageIn &msg); + + void processItemUseResponse(Net::MessageIn &msg); + + void processPlayerStorageStatus(Net::MessageIn &msg); + + void processPlayerStorageAdd(Net::MessageIn &msg); + + void processPlayerStorageRemove(Net::MessageIn &msg); + + void processPlayerStorageClose(Net::MessageIn &msg); + + void processPlayerEquipment(Net::MessageIn &msg); + + void processPlayerEquip(Net::MessageIn &msg); + + void processPlayerUnEquip(Net::MessageIn &msg); + + void processPlayerAttackRange(Net::MessageIn &msg); + + void processPlayerArrowEquip(Net::MessageIn &msg); + + protected: + EquipBackend mEquips; + InventoryItems mInventoryItems; + Inventory *mStorage; + InventoryWindow *mStorageWindow; + bool mDebugInventory; + + typedef std::queue<int> PickupQueue; + PickupQueue mSentPickups; +}; + +} // namespace Ea + +#endif // NET_EA_INVENTORYHANDLER_H diff --git a/src/net/ea/partyhandler.cpp b/src/net/ea/partyhandler.cpp index 1878bb567..f720f9f96 100644 --- a/src/net/ea/partyhandler.cpp +++ b/src/net/ea/partyhandler.cpp @@ -448,4 +448,4 @@ void PartyHandler::processPartyMessage(Net::MessageIn &msg) } } -} // namespace TmwAthena +} // namespace Ea diff --git a/src/net/tmwa/buysellhandler.cpp b/src/net/tmwa/buysellhandler.cpp index fa509ffec..552aa1d51 100644 --- a/src/net/tmwa/buysellhandler.cpp +++ b/src/net/tmwa/buysellhandler.cpp @@ -42,6 +42,8 @@ #include "net/messagein.h" #include "net/net.h" +#include "net/ea/eaprotocol.h" + #include "net/tmwa/chathandler.h" #include "net/tmwa/protocol.h" diff --git a/src/net/tmwa/inventoryhandler.cpp b/src/net/tmwa/inventoryhandler.cpp index 43f04d2dc..ae79f6842 100644 --- a/src/net/tmwa/inventoryhandler.cpp +++ b/src/net/tmwa/inventoryhandler.cpp @@ -22,100 +22,21 @@ #include "net/tmwa/inventoryhandler.h" -#include "configuration.h" -#include "equipment.h" -#include "event.h" -#include "inventory.h" -#include "item.h" -#include "itemshortcut.h" -#include "localplayer.h" #include "log.h" -#include "gui/ministatus.h" - -#include "gui/widgets/chattab.h" - #include "net/messagein.h" -#include "net/messageout.h" #include "net/tmwa/protocol.h" -#include "resources/iteminfo.h" - -#include "utils/gettext.h" -#include "utils/stringutils.h" - -#include <SDL_types.h> +#include "net/ea/eaprotocol.h" #include "debug.h" extern Net::InventoryHandler *inventoryHandler; -const Equipment::Slot EQUIP_POINTS[Equipment::EQUIP_VECTOREND] = -{ - Equipment::EQUIP_LEGS_SLOT, - Equipment::EQUIP_FIGHT1_SLOT, - Equipment::EQUIP_GLOVES_SLOT, - Equipment::EQUIP_RING2_SLOT, - Equipment::EQUIP_RING1_SLOT, - Equipment::EQUIP_FIGHT2_SLOT, - Equipment::EQUIP_FEET_SLOT, - Equipment::EQUIP_NECK_SLOT, - Equipment::EQUIP_HEAD_SLOT, - Equipment::EQUIP_TORSO_SLOT, - Equipment::EQUIP_EVOL_RING1_SLOT, - Equipment::EQUIP_EVOL_RING2_SLOT, - Equipment::EQUIP_PROJECTILE_SLOT, -}; - -// missing EQUIP_RING1_SLOT -const Equipment::Slot EQUIP_CONVERT[] = -{ - Equipment::EQUIP_PROJECTILE_SLOT, // 0 - Equipment::EQUIP_FEET_SLOT, // SPRITE_SHOE - Equipment::EQUIP_LEGS_SLOT, // SPRITE_BOTTOMCLOTHES - Equipment::EQUIP_TORSO_SLOT, // SPRITE_TOPCLOTHES - Equipment::EQUIP_PROJECTILE_SLOT, // 0 - Equipment::EQUIP_NECK_SLOT, // SPRITE_RING - Equipment::EQUIP_PROJECTILE_SLOT, // 0 - Equipment::EQUIP_HEAD_SLOT, // SPRITE_HAT - Equipment::EQUIP_RING2_SLOT, // 0 - Equipment::EQUIP_GLOVES_SLOT, // SPRITE_GLOVES - Equipment::EQUIP_FIGHT1_SLOT, // SPRITE_WEAPON - Equipment::EQUIP_FIGHT2_SLOT, // SPRITE_SHIELD - Equipment::EQUIP_EVOL_RING1_SLOT, // SPRITE_EVOL1 - Equipment::EQUIP_EVOL_RING2_SLOT, // SPRITE_EVOL2 - Equipment::EQUIP_PROJECTILE_SLOT, // 0 -}; - namespace TmwAthena { -int getSlot(int eAthenaSlot); - -int getSlot(int eAthenaSlot) -{ - if (eAthenaSlot == 0) - return Equipment::EQUIP_VECTOREND; - - if (eAthenaSlot & 0x8000) - return Equipment::EQUIP_PROJECTILE_SLOT; - - int mask = 1; - int position = 0; - while (!(eAthenaSlot & mask)) - { - mask <<= 1; - position++; - } - return EQUIP_POINTS[position]; -} - -enum -{ - debugInventory = 1 -}; - InventoryHandler::InventoryHandler() { static const Uint16 _messages[] = @@ -140,433 +61,75 @@ InventoryHandler::InventoryHandler() }; handledMessages = _messages; inventoryHandler = this; - - mStorage = 0; - mStorageWindow = 0; } InventoryHandler::~InventoryHandler() { - if (mStorageWindow) - { - mStorageWindow->close(); - mStorageWindow = 0; - } - - delete mStorage; - mStorage = 0; } void InventoryHandler::handleMessage(Net::MessageIn &msg) { - int number, flag; - int index, amount, itemId, equipType, arrow, refine; - int cards[4], itemType; - int floorId; - unsigned char identified; - Inventory *inventory = 0; - if (player_node) - inventory = PlayerInfo::getInventory(); - switch (msg.getId()) { case SMSG_PLAYER_INVENTORY: case SMSG_PLAYER_STORAGE_ITEMS: - if (msg.getId() == SMSG_PLAYER_INVENTORY) - { - if (PlayerInfo::getEquipment()) - { - // Clear inventory - this will be a complete refresh - mEquips.clear(); - PlayerInfo::getEquipment()->setBackend(&mEquips); - } - - if (inventory) - inventory->clear(); - } - else - { - mInventoryItems.clear(); - } - - msg.readInt16(); // length - number = (msg.getLength() - 4) / 18; - - for (int loop = 0; loop < number; loop++) - { - index = msg.readInt16(); - itemId = msg.readInt16(); - itemType = msg.readInt8(); - identified = msg.readInt8(); - amount = msg.readInt16(); - arrow = msg.readInt16(); - for (int i = 0; i < 4; i++) - cards[i] = msg.readInt16(); - - index -= ((msg.getId() == SMSG_PLAYER_INVENTORY) ? - INVENTORY_OFFSET : STORAGE_OFFSET); - - if (debugInventory) - { - logger->log("Index: %d, ID: %d, Type: %d, Identified: %d, " - "Qty: %d, Cards: %d, %d, %d, %d", - index, itemId, itemType, identified, amount, - cards[0], cards[1], cards[2], cards[3]); - } - - if (serverVersion < 1 && identified > 1) - identified = 1; - - if (msg.getId() == SMSG_PLAYER_INVENTORY) - { - // Trick because arrows are not considered equipment - bool isEquipment = arrow & 0x8000; - - if (inventory) - { - inventory->setItem(index, itemId, amount, - 0, identified, isEquipment); - } - } - else - { - mInventoryItems.push_back(InventoryItem(index, itemId, - amount, 0, identified, false)); - } - } + processPlayerInventory(msg, msg.getId() == SMSG_PLAYER_INVENTORY); break; case SMSG_PLAYER_STORAGE_EQUIP: - msg.readInt16(); // length - number = (msg.getLength() - 4) / 20; - - for (int loop = 0; loop < number; loop++) - { - index = msg.readInt16() - STORAGE_OFFSET; - itemId = msg.readInt16(); - itemType = msg.readInt8(); - identified = msg.readInt8(); - amount = 1; - msg.readInt16(); // Equip Point? - msg.readInt16(); // Another Equip Point? - msg.readInt8(); // Attribute (broken) - refine = msg.readInt8(); - for (int i = 0; i < 4; i++) - cards[i] = msg.readInt16(); - - if (debugInventory) - { - logger->log("Index: %d, ID: %d, Type: %d, Identified: %d, " - "Qty: %d, Cards: %d, %d, %d, %d, Refine: %d", - index, itemId, itemType, identified, amount, - cards[0], cards[1], cards[2], cards[3], - refine); - } - - if (serverVersion < 1 && identified > 1) - identified = 1; - - mInventoryItems.push_back(InventoryItem(index, itemId, amount, - refine, identified, false)); - } + processPlayerStorageEquip(msg); break; case SMSG_PLAYER_INVENTORY_ADD: - if (PlayerInfo::getEquipment() - && !PlayerInfo::getEquipment()->getBackend()) - { // look like SMSG_PLAYER_INVENTORY was not received - mEquips.clear(); - PlayerInfo::getEquipment()->setBackend(&mEquips); - } - index = msg.readInt16() - INVENTORY_OFFSET; - amount = msg.readInt16(); - itemId = msg.readInt16(); - identified = msg.readInt8(); - msg.readInt8(); // attribute - refine = msg.readInt8(); - for (int i = 0; i < 4; i++) - cards[i] = msg.readInt16(); - equipType = msg.readInt16(); - itemType = msg.readInt8(); - - { - const ItemInfo &itemInfo = ItemDB::get(itemId); - - unsigned char err = msg.readInt8(); - if (mSentPickups.empty()) - { - floorId = 0; - } - else - { - floorId = mSentPickups.front(); - mSentPickups.pop(); - } - - if (err) - { - if (player_node) - { - player_node->pickedUp(itemInfo, 0, identified, - floorId, err); - } - } - else - { - if (player_node) - { - player_node->pickedUp(itemInfo, amount, - identified, floorId, PICKUP_OKAY); - } - - if (inventory) - { - Item *item = inventory->getItem(index); - - if (item && item->getId() == itemId) - amount += inventory->getItem(index)->getQuantity(); - - if (serverVersion < 1 && identified > 1) - identified = 1; - - inventory->setItem(index, itemId, amount, refine, - identified, equipType != 0); - } - } - } break; + processPlayerInventoryAdd(msg); + break; case SMSG_PLAYER_INVENTORY_REMOVE: - index = msg.readInt16() - INVENTORY_OFFSET; - amount = msg.readInt16(); - if (inventory) - { - if (Item *item = inventory->getItem(index)) - { - item->increaseQuantity(-amount); - if (item->getQuantity() == 0) - inventory->removeItemAt(index); - if (miniStatusWindow) - miniStatusWindow->updateArrows(); - } - } + processPlayerInventoryRemove(msg); break; case SMSG_PLAYER_INVENTORY_USE: - index = msg.readInt16() - INVENTORY_OFFSET; - msg.readInt16(); // item id - msg.readInt32(); // id - amount = msg.readInt16(); - msg.readInt8(); // type - - if (inventory) - { - if (Item *item = inventory->getItem(index)) - { - if (amount) - item->setQuantity(amount); - else - inventory->removeItemAt(index); - } - } + processPlayerInventoryUse(msg); break; case SMSG_ITEM_USE_RESPONSE: - index = msg.readInt16() - INVENTORY_OFFSET; - amount = msg.readInt16(); - - if (msg.readInt8() == 0) - { - SERVER_NOTICE(_("Failed to use item.")) - } - else - { - if (inventory) - { - if (Item *item = inventory->getItem(index)) - { - if (amount) - item->setQuantity(amount); - else - inventory->removeItemAt(index); - } - } - } + processItemUseResponse(msg); break; case SMSG_PLAYER_STORAGE_STATUS: - /* - * This is the closest we get to an "Open Storage" packet from the - * server. It always comes after the two SMSG_PLAYER_STORAGE_... - * packets that update storage contents. - */ - { - msg.readInt16(); // Used count - int size = msg.readInt16(); // Max size - - if (!mStorage) - mStorage = new Inventory(Inventory::STORAGE, size); - - InventoryItems::iterator it = mInventoryItems.begin(); - InventoryItems::iterator it_end = mInventoryItems.end(); - for (; it != it_end; ++it) - { - mStorage->setItem((*it).slot, (*it).id, (*it).quantity, - (*it).refine, (*it).color, (*it).equip); - } - mInventoryItems.clear(); - - if (!mStorageWindow) - mStorageWindow = new InventoryWindow(mStorage); - } + processPlayerStorageStatus(msg); break; case SMSG_PLAYER_STORAGE_ADD: - // Move an item into storage - index = msg.readInt16() - STORAGE_OFFSET; - amount = msg.readInt32(); - itemId = msg.readInt16(); - identified = msg.readInt8(); - msg.readInt8(); // attribute - refine = msg.readInt8(); - for (int i = 0; i < 4; i++) - cards[i] = msg.readInt16(); - - if (Item *item = mStorage->getItem(index)) - { - item->setId(itemId, identified); - item->increaseQuantity(amount); - } - else - { - if (mStorage) - { - if (serverVersion < 1 && identified > 1) - identified = 1; - - mStorage->setItem(index, itemId, amount, refine, - identified, false); - } - } + processPlayerStorageAdd(msg); break; case SMSG_PLAYER_STORAGE_REMOVE: - // Move an item out of storage - index = msg.readInt16() - STORAGE_OFFSET; - amount = msg.readInt16(); - if (mStorage) - { - if (Item *item = mStorage->getItem(index)) - { - item->increaseQuantity(-amount); - if (item->getQuantity() == 0) - mStorage->removeItemAt(index); - } - } + processPlayerStorageRemove(msg); break; case SMSG_PLAYER_STORAGE_CLOSE: - // Storage access has been closed - - // Storage window deletes itself - mStorageWindow = 0; - - if (mStorage) - mStorage->clear(); - - delete mStorage; - mStorage = 0; + processPlayerStorageClose(msg); break; case SMSG_PLAYER_EQUIPMENT: - msg.readInt16(); // length - if (PlayerInfo::getEquipment() - && !PlayerInfo::getEquipment()->getBackend()) - { // look like SMSG_PLAYER_INVENTORY was not received - mEquips.clear(); - PlayerInfo::getEquipment()->setBackend(&mEquips); - } - number = (msg.getLength() - 4) / 20; - - for (int loop = 0; loop < number; loop++) - { - index = msg.readInt16() - INVENTORY_OFFSET; - itemId = msg.readInt16(); - int itemType = msg.readInt8(); // type - identified = msg.readInt8(); // identify flag - - msg.readInt16(); // equip type - equipType = msg.readInt16(); - msg.readInt8(); // attribute - refine = msg.readInt8(); - msg.skip(8); // card - - - if (debugInventory) - { - logger->log("Index: %d, ID: %d, Type: %d, Identified: %d", - index, itemId, itemType, identified); - } - - if (serverVersion < 1 && identified > 1) - identified = 1; - - if (inventory) - { - inventory->setItem(index, itemId, 1, refine, - identified, true); - } - - if (equipType) - mEquips.setEquipment(getSlot(equipType), index); - - } + processPlayerEquipment(msg); break; case SMSG_PLAYER_EQUIP: - index = msg.readInt16() - INVENTORY_OFFSET; - equipType = msg.readInt16(); - flag = msg.readInt8(); - - if (!flag) - SERVER_NOTICE(_("Unable to equip.")) - else - mEquips.setEquipment(getSlot(equipType), index); + processPlayerEquip(msg); break; case SMSG_PLAYER_UNEQUIP: - index = msg.readInt16() - INVENTORY_OFFSET; - equipType = msg.readInt16(); - flag = msg.readInt8(); - - if (flag) - mEquips.setEquipment(getSlot(equipType), -1); - if (miniStatusWindow && equipType & 0x8000) - miniStatusWindow->updateArrows(); - + processPlayerUnEquip(msg); break; case SMSG_PLAYER_ATTACK_RANGE: - { - int range = msg.readInt16(); - if (player_node) - player_node->setAttackRange(range); - PlayerInfo::setStatBase(ATTACK_RANGE, range); - PlayerInfo::setStatMod(ATTACK_RANGE, 0); + processPlayerAttackRange(msg); break; - } case SMSG_PLAYER_ARROW_EQUIP: - index = msg.readInt16(); - - if (index <= 1) - break; - - index -= INVENTORY_OFFSET; - - mEquips.setEquipment(Equipment::EQUIP_PROJECTILE_SLOT, index); - - if (miniStatusWindow) - miniStatusWindow->updateArrows(); + processPlayerArrowEquip(msg); break; default: @@ -618,27 +181,6 @@ void InventoryHandler::dropItem(const Item *item, int amount) outMsg.writeInt16(static_cast<Sint16>(amount)); } -bool InventoryHandler::canSplit(const Item *item A_UNUSED) const -{ - return false; -} - -void InventoryHandler::splitItem(const Item *item A_UNUSED, - int amount A_UNUSED) -{ - // Not implemented for eAthena (possible?) -} - -void InventoryHandler::moveItem(int oldIndex A_UNUSED, int newIndex A_UNUSED) -{ - // Not implemented for eAthena (possible?) -} - -void InventoryHandler::openStorage(int type A_UNUSED) -{ - // Doesn't apply to eAthena, since opening happens through NPCs? -} - void InventoryHandler::closeStorage(int type A_UNUSED) { MessageOut outMsg(CMSG_CLOSE_STORAGE); @@ -662,27 +204,4 @@ void InventoryHandler::moveItem(int source, int slot, int amount, } } -size_t InventoryHandler::getSize(int type) const -{ - switch (type) - { - case Inventory::INVENTORY: - return 100; - case Inventory::STORAGE: - return 0; // Comes from server after items - case Inventory::TRADE: - return 12; - case GUILD_STORAGE: - return 0; // Comes from server after items - default: - return 0; - } -} -int InventoryHandler::convertFromServerSlot(int serverSlot) const -{ - if (serverSlot < 0 || serverSlot > 13) - return 0; - - return EQUIP_CONVERT[serverSlot]; -} } // namespace TmwAthena diff --git a/src/net/tmwa/inventoryhandler.h b/src/net/tmwa/inventoryhandler.h index f831f7a78..405bacc43 100644 --- a/src/net/tmwa/inventoryhandler.h +++ b/src/net/tmwa/inventoryhandler.h @@ -23,21 +23,13 @@ #ifndef NET_TA_INVENTORYHANDLER_H #define NET_TA_INVENTORYHANDLER_H -#include "equipment.h" -#include "inventory.h" #include "log.h" -#include "playerinfo.h" -#include "gui/inventorywindow.h" - -#include "net/inventoryhandler.h" #include "net/net.h" -#include "net/tmwa/messagehandler.h" +#include "net/ea/inventoryhandler.h" -#include <list> -#include <vector> -#include <queue> +#include "net/tmwa/messagehandler.h" #ifdef __GNUC__ #define A_UNUSED __attribute__ ((unused)) @@ -48,97 +40,9 @@ namespace TmwAthena { -class EquipBackend : public Equipment::Backend -{ - public: - EquipBackend() - { - memset(mEquipment, -1, sizeof(mEquipment)); - } - - Item *getEquipment(int index) const - { - int invyIndex = mEquipment[index]; - if (invyIndex == -1) - return NULL; - - return PlayerInfo::getInventory()->getItem(invyIndex); - } - - void clear() - { - for (int i = 0; i < EQUIPMENT_SIZE; i++) - { - if (mEquipment[i] != -1) - { - Item* item = PlayerInfo::getInventory()->getItem(i); - if (item) - item->setEquipped(false); - } - - mEquipment[i] = -1; - } - } - - void setEquipment(int index, int inventoryIndex) - { - // Unequip existing item - Item* item = PlayerInfo::getInventory() - ->getItem(mEquipment[index]); - - if (item) - item->setEquipped(false); - - mEquipment[index] = inventoryIndex; - - item = PlayerInfo::getInventory()->getItem(inventoryIndex); - if (item) - item->setEquipped(true); - - if (inventoryWindow) - inventoryWindow->updateButtons(); - } - - private: - int mEquipment[EQUIPMENT_SIZE]; -}; - -/** - * Used to cache storage data until we get size data for it. - */ -class InventoryItem -{ - public: - int slot; - int id; - int quantity; - unsigned char color; - int refine; - bool equip; - - InventoryItem(int slot, int id, int quantity, int refine, - unsigned char color, bool equip) - { - this->slot = slot; - this->id = id; - this->quantity = quantity; - this->refine = refine; - this->color = color; - this->equip = equip; - } -}; - -typedef std::vector<InventoryItem> InventoryItems; - -class InventoryHandler : public MessageHandler, public Net::InventoryHandler +class InventoryHandler : public MessageHandler, public Ea::InventoryHandler { public: - enum - { - GUILD_STORAGE = Inventory::TYPE_END, - CART - }; - InventoryHandler(); ~InventoryHandler(); @@ -153,38 +57,12 @@ class InventoryHandler : public MessageHandler, public Net::InventoryHandler void dropItem(const Item *item, int amount); - bool canSplit(const Item *item) const; - - void splitItem(const Item *item, int amount); - - void moveItem(int oldIndex, int newIndex); - - void openStorage(int type); - void closeStorage(int type); void moveItem(int source, int slot, int amount, int destination); - - size_t getSize(int type) const; - - int convertFromServerSlot(int serverSlot) const; - - void pushPickup(int floorId) - { mSentPickups.push(floorId); } - - private: - EquipBackend mEquips; - InventoryItems mInventoryItems; - Inventory *mStorage; - InventoryWindow *mStorageWindow; - - typedef std::queue<int> PickupQueue; - PickupQueue mSentPickups; }; } // namespace TmwAthena -int getSlot(int eAthenaSlot); - #endif // NET_TA_INVENTORYHANDLER_H diff --git a/src/net/tmwa/npchandler.cpp b/src/net/tmwa/npchandler.cpp index 69b4b880a..9bcc640a1 100644 --- a/src/net/tmwa/npchandler.cpp +++ b/src/net/tmwa/npchandler.cpp @@ -34,6 +34,8 @@ #include "net/tmwa/protocol.h" +#include "net/ea/eaprotocol.h" + #include <SDL_types.h> #include "debug.h" diff --git a/src/net/tmwa/protocol.h b/src/net/tmwa/protocol.h index 696f83646..3a753e351 100644 --- a/src/net/tmwa/protocol.h +++ b/src/net/tmwa/protocol.h @@ -65,9 +65,6 @@ enum SPRITE_VECTOREND }; -static const int INVENTORY_OFFSET = 2; -static const int STORAGE_OFFSET = 1; - /********************************* * Packets from server to client * *********************************/ diff --git a/src/net/tmwa/tradehandler.cpp b/src/net/tmwa/tradehandler.cpp index e1bff1634..083ff5154 100644 --- a/src/net/tmwa/tradehandler.cpp +++ b/src/net/tmwa/tradehandler.cpp @@ -39,6 +39,8 @@ #include "net/tmwa/protocol.h" +#include "net/ea/eaprotocol.h" + #include "utils/gettext.h" #include "utils/stringutils.h" |