Mana
Loading...
Searching...
No Matches
inventoryhandler.cpp
Go to the documentation of this file.
1/*
2 * The Mana Client
3 * Copyright (C) 2004-2009 The Mana World Development Team
4 * Copyright (C) 2009-2012 The Mana Developers
5 *
6 * This file is part of The Mana Client.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
23
24#include "equipment.h"
25#include "inventory.h"
26#include "item.h"
27#include "log.h"
28#include "playerinfo.h"
29
30#include "gui/equipmentwindow.h"
31#include "gui/inventorywindow.h"
32
37
38#include "utils/stringutils.h"
39
40#define EQUIP_FILE "equip.xml"
41
43
44namespace ManaServ {
45
46extern Connection *gameServerConnection;
47
53
54Item *EquipBackend::getEquipment(int slotIndex) const
55{
56 auto it = mSlots.find(slotIndex);
57 if (it == mSlots.end())
58 return nullptr;
59
60 return PlayerInfo::getInventory()->getItem(it->second.inventorySlot);
61}
62
63std::string EquipBackend::getSlotName(int slotIndex) const
64{
65 auto it = mSlots.find(slotIndex);
66 return it == mSlots.end() ? std::string() : it->second.name;
67}
68
69void EquipBackend::triggerUnequip(int slotIndex) const
70{
71 auto item = getEquipment(slotIndex);
72 if (!item)
73 return;
74
76 event.setItem("item", item);
77 event.trigger(Event::ItemChannel);
78}
79
81{
82 for (auto &[_, slot] : mSlots)
83 slot.inventorySlot = -1;
84}
85
86void EquipBackend::equip(int inventorySlot, int equipmentSlot)
87{
88 auto slotIt = mSlots.find(equipmentSlot);
89 if (slotIt == mSlots.end())
90 {
91 Log::info("ManaServ::EquipBackend: Equipment slot %i"
92 " is not existing.", equipmentSlot);
93 return;
94 }
95
96 slotIt->second.inventorySlot = inventorySlot;
97
98 if (auto item = PlayerInfo::getInventory()->getItem(inventorySlot))
99 item->setEquipped(true);
100}
101
102void EquipBackend::unequip(int inventorySlot)
103{
104 for (auto &[_, slot] : mSlots)
105 {
106 if (slot.inventorySlot == inventorySlot)
107 {
108 slot.inventorySlot = -1;
109
110 if (auto item = PlayerInfo::getInventory()->getItem(inventorySlot))
111 item->setEquipped(false);
112
113 return;
114 }
115 }
116
117 Log::info("ManaServ::EquipBackend: No equipped item found at inventory "
118 "slot %i!", inventorySlot);
119}
120
122{
123 if (event.getType() == Event::LoadingDatabases)
125}
126
128{
129 mSlots.clear();
130
132 XML::Node rootNode = doc.rootNode();
133
134 if (!rootNode || rootNode.name() != "equip-slots")
135 {
136 Log::info("ManaServ::EquipBackend: Error while reading "
137 EQUIP_FILE "!");
138 return;
139 }
140
141 // The current client slot index
142 unsigned int slotIndex = 0;
143 mVisibleSlots = 0;
144
145 for (auto slotNode : rootNode.children())
146 {
147 if (slotNode.name() != "slot")
148 continue;
149
150 Slot slot;
151 slot.slotTypeId = slotNode.getProperty("id", 0);
152 std::string name = slotNode.getProperty("name", std::string());
153 const int capacity = slotNode.getProperty("capacity", 1);
154 slot.weaponSlot = slotNode.getBoolProperty("weapon", false);
155 slot.ammoSlot = slotNode.getBoolProperty("ammo", false);
156
157 if (slotNode.getBoolProperty("visible", false))
159
160 if (slot.slotTypeId > 0 && capacity > 0)
161 {
162 if (name.empty())
163 slot.name = toString(slot.slotTypeId);
164 else
165 slot.name = name;
166
167 // The map is filled until the capacity is reached
168 for (int i = 1; i < capacity + 1; ++i)
169 {
170 // Add the capacity part in the name
171 // when there is more than one slot unit. i.e: 1/3, 2/3
172 if (capacity > 1)
173 {
174 slot.name = name + " " + toString(i)
175 + "/" + toString(capacity);
176 }
177
178 slot.subId = i;
179 mSlots.insert(std::make_pair(slotIndex, std::move(slot)));
180 ++slotIndex;
181 }
182 }
183
184 // Read the box properties
185 readBoxNode(slotNode);
186 }
187}
188
190{
191 for (auto boxNode : slotNode.children())
192 {
193 if (boxNode.name() != "box")
194 continue;
195
196 const int x = boxNode.getProperty("x" , 0);
197 const int y = boxNode.getProperty("y" , 0);
198
199 mBoxPositions.emplace_back(x, y);
200
201 const auto icon = boxNode.getProperty("icon", std::string());
202 mBoxIcons.push_back(icon);
203 }
204}
205
206bool EquipBackend::isWeaponSlot(int slotTypeId) const
207{
208 for (const auto &[_, slot] : mSlots)
209 {
210 if (slot.slotTypeId == (unsigned)slotTypeId)
211 return slot.weaponSlot;
212 }
213 return false;
214}
215
216bool EquipBackend::isAmmoSlot(int slotTypeId) const
217{
218 for (const auto &[_, slot] : mSlots)
219 {
220 if (slot.slotTypeId == (unsigned)slotTypeId)
221 return slot.ammoSlot;
222 }
223 return false;
224}
225
226Position EquipBackend::getBoxPosition(unsigned int slotIndex) const
227{
228 if (slotIndex < mBoxPositions.size())
229 return mBoxPositions.at(slotIndex);
230 return Position(0, 0);
231}
232
233const std::string &EquipBackend::getBoxIcon(unsigned int slotIndex) const
234{
235 if (slotIndex < mBoxIcons.size())
236 return mBoxIcons.at(slotIndex);
237 return Net::empty;
238}
239
241{
242 static const Uint16 _messages[] = {
247 0
248 };
249 handledMessages = _messages;
250 inventoryHandler = this;
251
253}
254
256{
257 switch (msg.getId())
258 {
260 {
262 int count = msg.readInt16();
263 while (count--)
264 {
265 const int slot = msg.readInt16();
266 const int itemId = msg.readInt16();
267 const int amount = msg.readInt16();
268 const int equipmentSlot = msg.readInt16();
269 PlayerInfo::setInventoryItem(slot, itemId, amount);
270
271 if (equipmentSlot > 0)
272 mEquipBackend.equip(slot, equipmentSlot);
273 }
274
276 }
277 break;
278
279 case GPMSG_INVENTORY:
280 while (msg.getUnreadLength())
281 {
282 const unsigned int slot = msg.readInt16();
283 const int id = msg.readInt16();
284 const unsigned int amount = id ? msg.readInt16() : 0;
285 PlayerInfo::setInventoryItem(slot, id, amount);
286 }
287 break;
288
289 case GPMSG_EQUIP:
290 {
291 const int inventorySlot = msg.readInt16();
292 const int equipmentSlot = msg.readInt16();
293 mEquipBackend.equip(inventorySlot, equipmentSlot);
295 }
296
297 case GPMSG_UNEQUIP:
298 {
299 const int inventorySlot = msg.readInt16();
300 mEquipBackend.unequip(inventorySlot);
302 }
303 break;
304 }
305}
306
308 const Event &event)
309{
310 if (channel == Event::ItemChannel)
311 {
312 Item *item = event.getItem("item");
313 if (!item)
314 return;
315
316 int index = item->getInvIndex();
317
318 if (event.getType() == Event::DoEquip)
319 {
321 msg.writeInt16(index);
323 }
324 else if (event.getType() == Event::DoUnequip)
325 {
327 msg.writeInt16(index);
329 }
330 else if (event.getType() == Event::DoUse)
331 {
333 msg.writeInt16(index);
335 }
336 else if (event.getType() == Event::DoDrop)
337 {
338 int amount = event.getInt("amount", 1);
339
341 msg.writeInt16(index);
342 msg.writeInt16(amount);
344 }
345 }
346}
347
348size_t InventoryHandler::getSize(int type) const
349{
350 switch (type)
351 {
353 case Inventory::TRADE:
354 return 50;
356 return 300;
357 default:
358 return 0;
359 }
360}
361
362} // namespace ManaServ
void listen(Event::Channel channel)
Definition event.h:42
@ DoUse
Definition event.h:79
@ LoadingDatabases
Definition event.h:70
@ DoDrop
Definition event.h:75
@ DoEquip
Definition event.h:76
@ DoUnequip
Definition event.h:78
Channel
Definition event.h:45
@ ClientChannel
Definition event.h:50
@ ItemChannel
Definition event.h:53
void updateButtons()
Updates the buttons.
Item * getItem(int index) const
Returns the item at the specified index.
Definition inventory.cpp:44
Represents one or more instances of a certain item type.
Definition item.h:35
int getInvIndex() const
Returns the inventory index of this item.
Definition item.h:94
void send(const ManaServ::MessageOut &msg)
Sends a message.
std::string getSlotName(int slotIndex) const override
Position getBoxPosition(unsigned int slotIndex) const
void event(Event::Channel channel, const Event &event) override
std::map< unsigned int, Slot > mSlots
bool isWeaponSlot(int slotTypeId) const
std::vector< std::string > mBoxIcons
std::vector< Position > mBoxPositions
void unequip(int inventorySlot)
const std::string & getBoxIcon(unsigned int slotIndex) const
void equip(int inventorySlot, int equipmentSlot)
void readBoxNode(XML::Node slotNode)
bool isAmmoSlot(int slotTypeId) const
Item * getEquipment(int slotIndex) const override
void triggerUnequip(int slotIndex) const override
size_t getSize(int type) const override
void event(Event::Channel channel, const Event &event) override
void handleMessage(MessageIn &msg) override
Used for parsing an incoming message from manaserv.
Definition messagein.h:37
uint16_t readInt16()
Reads an unsigned 16-bit integer from the message.
Definition messagein.cpp:58
unsigned int getUnreadLength() const
Returns the length of unread data.
Definition messagein.h:54
uint16_t getId() const
Returns the message ID.
Definition messagein.h:44
Used for building an outgoing message to manaserv.
Definition messageout.h:37
void writeInt16(uint16_t value)
Writes an unsigned 16-bit integer to the message.
const uint16_t * handledMessages
A helper class for parsing an XML document, which also cleans it up again (RAII).
Definition xml.h:190
Node rootNode() const
Returns the root node of the document (or NULL if there was a load error).
Definition xml.h:213
std::string_view name() const
Definition xml.h:46
Children children() const
Definition xml.h:97
InventoryWindow * inventoryWindow
Definition game.cpp:96
#define _(s)
Definition gettext.h:38
#define EQUIP_FILE
Net::InventoryHandler * inventoryHandler
Definition net.cpp:50
void info(const char *log_text,...) LOG_PRINTF_ATTR
Connection * gameServerConnection
Inventory * getInventory()
Returns the player's inventory.
void clearInventory()
Clears the player's inventory and equipment.
void setInventoryItem(int index, int id, int amount)
Changes the inventory item at the given slot.
std::string toString(const T &arg)
Converts the given value to a string using std::stringstream.
Definition stringutils.h:68
A position along a being's path.
Definition position.h:31