summaryrefslogtreecommitdiff
path: root/src/net/tmwa
diff options
context:
space:
mode:
authorAndrei Karas <akaras@inbox.ru>2011-07-30 21:36:51 +0300
committerAndrei Karas <akaras@inbox.ru>2011-07-30 22:20:09 +0300
commitcfede1d7d50541cf64b191844d537cb55880ce09 (patch)
treecfdaba05d4951b7b3522d2ea6844bd3e99fb37fc /src/net/tmwa
parent19738d5a2d5d96aef78e51da99061a22d7cf15bb (diff)
downloadplus-cfede1d7d50541cf64b191844d537cb55880ce09.tar.gz
plus-cfede1d7d50541cf64b191844d537cb55880ce09.tar.bz2
plus-cfede1d7d50541cf64b191844d537cb55880ce09.tar.xz
plus-cfede1d7d50541cf64b191844d537cb55880ce09.zip
Extract shared logic from inventoryhandler netcode to ea namespace.
Diffstat (limited to 'src/net/tmwa')
-rw-r--r--src/net/tmwa/buysellhandler.cpp2
-rw-r--r--src/net/tmwa/inventoryhandler.cpp515
-rw-r--r--src/net/tmwa/inventoryhandler.h128
-rw-r--r--src/net/tmwa/npchandler.cpp2
-rw-r--r--src/net/tmwa/protocol.h3
-rw-r--r--src/net/tmwa/tradehandler.cpp2
6 files changed, 26 insertions, 626 deletions
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"