ManaPlus
inventory.cpp
Go to the documentation of this file.
1 /*
2  * The ManaPlus Client
3  * Copyright (C) 2004-2009 The Mana World Development Team
4  * Copyright (C) 2009-2010 The Mana Developers
5  * Copyright (C) 2011-2019 The ManaPlus Developers
6  * Copyright (C) 2019-2021 Andrei Karas
7  *
8  * This file is part of The ManaPlus Client.
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program. If not, see <http://www.gnu.org/licenses/>.
22  */
23 
25 
26 #include "being/playerinfo.h"
27 
28 #include "net/inventoryhandler.h"
29 
30 #include "resources/iteminfo.h"
31 
32 #include "resources/item/item.h"
33 
35 
36 #include "utils/checkutils.h"
37 #include "utils/delete2.h"
38 #include "utils/foreach.h"
39 #include "utils/gettext.h"
40 #include "utils/stringutils.h"
41 
42 #include <algorithm>
43 
44 #include "debug.h"
45 
46 namespace
47 {
48  struct SlotUsed final
49  {
51 
52  bool operator()(const Item *const item) const
53  {
54  return (item != nullptr) && item->mId >= 0 && item->mQuantity > 0;
55  }
56  typedef Item *argument_type;
57  };
58 } // namespace
59 
61  const int size1) :
62  mInventoryListeners(),
63  mVirtualRemove(),
64  mType(type),
65  mSize(size1 == -1 ? CAST_U32(
66  inventoryHandler->getSize(type))
67  : CAST_U32(size1)),
68  mItems(new Item*[mSize]),
69  mUsed(0)
70 {
71  std::fill_n(mItems, mSize, static_cast<Item*>(nullptr));
72 }
73 
75 {
76  for (unsigned i = 0; i < mSize; i++)
77  delete mItems[i];
78 
79  delete [] mItems;
80  mItems = nullptr;
81 }
82 
83 Item *Inventory::getItem(const int index) const
84 {
85  if (index < 0 || index >= CAST_S32(mSize) || (mItems[index] == nullptr)
86  || mItems[index]->mQuantity <= 0)
87  {
88  return nullptr;
89  }
90 
91  return mItems[index];
92 }
93 
94 Item *Inventory::findItem(const int itemId,
95  const ItemColor color) const
96 {
97  for (unsigned i = 0; i < mSize; i++)
98  {
99  Item *const item = mItems[i];
100  if ((item != nullptr) && item->mId == itemId)
101  {
102  if (color == ItemColor_zero ||
103  item->mColor == color ||
104  (color == ItemColor_one &&
105  item->mColor <= ItemColor_one))
106  {
107  return item;
108  }
109  }
110  }
111 
112  return nullptr;
113 }
114 
115 int Inventory::addItem(const int id,
116  const ItemTypeT type,
117  const int quantity,
118  const uint8_t refine,
119  const ItemColor color,
120  const Identified identified,
121  const Damaged damaged,
122  const Favorite favorite,
123  const Equipm equipment,
124  const Equipped equipped)
125 {
126  const int slot = getFreeSlot();
127  setItem(slot,
128  id,
129  type,
130  quantity,
131  refine,
132  color,
133  identified,
134  damaged,
135  favorite,
136  equipment,
137  equipped);
138  return slot;
139 }
140 
141 void Inventory::setItem(const int index,
142  const int id,
143  const ItemTypeT type,
144  const int quantity,
145  const uint8_t refine,
146  const ItemColor color,
147  const Identified identified,
148  const Damaged damaged,
149  const Favorite favorite,
150  const Equipm equipment,
151  const Equipped equipped)
152 {
153  if (index < 0 || index >= CAST_S32(mSize))
154  {
155  reportAlways("Warning: invalid inventory index: %d",
156  index)
157  return;
158  }
159 
160  Item *const item1 = mItems[index];
161  if ((item1 == nullptr) && id > 0)
162  {
163  Item *const item = new Item(id,
164  type,
165  quantity,
166  refine,
167  color,
168  identified,
169  damaged,
170  favorite,
171  equipment,
172  equipped);
173  item->setInvIndex(index);
174  mItems[index] = item;
175  mUsed++;
177  }
178  else if (id > 0 && (item1 != nullptr))
179  {
180  item1->setId(id, color);
181  item1->setQuantity(quantity);
182  item1->setRefine(refine);
183  item1->setEquipment(equipment);
184  item1->setIdentified(identified);
185  item1->setDamaged(damaged);
186  item1->setFavorite(favorite);
187  }
188  else if (item1 != nullptr)
189  {
190  removeItemAt(index);
191  }
192 }
193 
194 void Inventory::setCards(const int index,
195  const int *const cards,
196  const int size) const
197 {
198  if (index < 0 || index >= CAST_S32(mSize))
199  {
200  reportAlways("Warning: invalid inventory index: %d",
201  index)
202  return;
203  }
204 
205  Item *const item1 = mItems[index];
206  if (item1 != nullptr)
207  item1->setCards(cards, size);
208 }
209 
210 void Inventory::setOptions(const int index,
211  const ItemOptionsList *const options)
212 {
213  if (index < 0 || index >= CAST_S32(mSize))
214  {
215  reportAlways("Warning: invalid inventory index: %d",
216  index)
217  return;
218  }
219  Item *const item1 = mItems[index];
220  if (item1 != nullptr)
221  item1->setOptions(options);
222 }
223 
224 void Inventory::setTag(const int index,
225  const int tag)
226 {
227  if (index < 0 || index >= CAST_S32(mSize))
228  {
229  reportAlways("Warning: invalid inventory index: %d",
230  index)
231  return;
232  }
233  Item *const item1 = mItems[index];
234  if (item1 != nullptr)
235  item1->setTag(tag);
236 }
237 
239 {
240  for (unsigned i = 0; i < mSize; i++)
241  removeItemAt(i);
242 }
243 
244 void Inventory::removeItem(const int id)
245 {
246  for (unsigned i = 0; i < mSize; i++)
247  {
248  const Item *const item = mItems[i];
249  if ((item != nullptr) && item->mId == id)
250  removeItemAt(i);
251  }
252 }
253 
254 void Inventory::removeItemAt(const int index)
255 {
256  if (mItems[index] == nullptr)
257  return;
258  delete2(mItems[index])
259  mUsed--;
260  if (mUsed < 0) // Already at 0, no need to distribute event
261  mUsed = 0;
262  else
264 }
265 
266 bool Inventory::contains(const Item *const item) const
267 {
268  if (item == nullptr)
269  return false;
270 
271  const int id = item->mId;
272  for (unsigned i = 0; i < mSize; i++)
273  {
274  const Item *const item1 = mItems[i];
275  if ((item1 != nullptr) && item1->mId == id)
276  return true;
277  }
278 
279  return false;
280 }
281 
283 {
284  Item *const *const i = std::find_if(mItems,
285  mItems + mSize,
286  std::not1(SlotUsed()));
287  return (i == mItems + mSize) ? -1
288  : CAST_S32(i - mItems);
289 }
290 
292 {
293  for (int i = mSize - 1; i >= 0; i--)
294  {
295  if (SlotUsed()(mItems[i]))
296  return i;
297  }
298 
299  return -1;
300 }
301 
303 {
304  mInventoryListeners.push_back(listener);
305 }
306 
308 {
310 }
311 
313 {
314  FOR_EACH (InventoryListenerList::const_iterator, i, mInventoryListeners)
315  (*i)->slotsChanged(this);
316 }
317 
318 const Item *Inventory::findItemBySprite(std::string spritePath,
319  const GenderT gender,
320  const BeingTypeId race) const
321 {
322  spritePath = removeSpriteIndex(spritePath);
323 
324  const std::string spritePathShort = extractNameFromSprite(spritePath);
325  int partialIndex = -1;
326 
327  for (unsigned i = 0; i < mSize; i++)
328  {
329  const Item *const item = mItems[i];
330  if (item != nullptr)
331  {
332  std::string path = item->getInfo().getSprite(gender, race);
333  if (!path.empty())
334  {
335  path = removeSpriteIndex(path);
336  if (spritePath == path)
337  return item;
338 
339  path = extractNameFromSprite(path);
340  if (spritePathShort == path)
341  partialIndex = i;
342  }
343  }
344  }
345  if (partialIndex != -1)
346  return mItems[partialIndex];
347 
348  return nullptr;
349 }
350 
351 std::string Inventory::getName() const
352 {
353  switch (mType)
354  {
358  default:
359  {
360  // TRANSLATORS: inventory type name
361  return N_("Inventory");
362  }
364  {
365  // TRANSLATORS: inventory type name
366  return N_("Storage");
367  }
368  case InventoryType::Npc:
369  {
370  // TRANSLATORS: inventory type name
371  return N_("Npc");
372  }
373  case InventoryType::Cart:
374  {
375  // TRANSLATORS: inventory type name
376  return N_("Cart");
377  }
380  {
381  // TRANSLATORS: inventory type name
382  return N_("Mail");
383  }
385  {
386  // TRANSLATORS: inventory type name
387  return N_("Craft");
388  }
390  {
391  // TRANSLATORS: inventory type name
392  return N_("Trade");
393  }
394  }
395 }
396 
397 void Inventory::resize(const unsigned int newSize)
398 {
399  clear();
400  if (mSize == newSize)
401  return;
402 
403  for (unsigned i = 0; i < mSize; i++)
404  delete mItems[i];
405  delete [] mItems;
406 
407  mSize = newSize;
408  mItems = new Item*[CAST_SIZE(mSize)];
409  std::fill_n(mItems, mSize, static_cast<Item*>(nullptr));
410 }
411 
412 int Inventory::findIndexByTag(const int tag) const
413 {
414  for (unsigned i = 0; i < mSize; i++)
415  {
416  const Item *const item = mItems[i];
417  if ((item != nullptr) && item->mTag == tag)
418  return i;
419  }
420 
421  return -1;
422 }
423 
424 Item *Inventory::findItemByTag(const int tag) const
425 {
426  for (unsigned i = 0; i < mSize; i++)
427  {
428  Item *const item = mItems[i];
429  if (item != nullptr &&
430  item->mTag == tag)
431  {
432  return item;
433  }
434  }
435 
436  return nullptr;
437 }
438 
439 bool Inventory::addVirtualItem(const Item *const item,
440  int index,
441  const int amount)
442 {
443  if ((item != nullptr) && !PlayerInfo::isItemProtected(item->getId()))
444  {
445  if (index >= 0 && index < CAST_S32(mSize))
446  {
447  if (mItems[index] != nullptr)
448  return false;
449  setItem(index,
450  item->getId(),
451  item->getType(),
452  amount,
453  1,
454  item->getColor(),
455  item->getIdentified(),
456  item->getDamaged(),
457  item->getFavorite(),
458  Equipm_false,
460  }
461  else
462  {
463  index = addItem(item->getId(),
464  item->getType(),
465  amount,
466  1,
467  item->getColor(),
468  item->getIdentified(),
469  item->getDamaged(),
470  item->getFavorite(),
471  Equipm_false,
473  }
474  if (index == -1)
475  return false;
476 
477  Item *const item2 = getItem(index);
478  if (item2 != nullptr)
479  item2->setTag(item->getInvIndex());
480  return true;
481  }
482  return false;
483 }
484 
486  const int amount)
487 {
488  if ((item == nullptr) || item->mQuantity < amount)
489  return;
490 
491  const int index = item->getInvIndex();
492  const IntMapCIter it = mVirtualRemove.find(index);
493  if (it == mVirtualRemove.end())
494  mVirtualRemove[index] = amount;
495  else
496  mVirtualRemove[index] += amount;
497  item->mQuantity -= amount;
498 }
499 
501 {
502  const int sz = CAST_S32(mSize);
503 
505  {
506  const int index = (*it).first;
507  if (index < 0 || index >= sz)
508  continue;
509  Item *const item = mItems[index];
510  if (item == nullptr)
511  continue;
512  item->mQuantity += (*it).second;
513  }
514  mVirtualRemove.clear();
515 }
516 
517 void Inventory::virtualRestore(const Item *const item,
518  const int amount)
519 {
520  const int index = item->getTag();
521  const IntMapCIter it = mVirtualRemove.find(index);
522  if (it != mVirtualRemove.end())
523  {
524  mVirtualRemove[index] -= amount;
525  if (mVirtualRemove[index] < 0)
526  mVirtualRemove.erase(index);
527  if (index < 0 ||
528  index >= CAST_S32(mSize) ||
529  mItems[index] == nullptr)
530  {
531  return;
532  }
533  mItems[index]->mQuantity += amount;
534  }
535 }
536 
537 void Inventory::moveItem(const int index1,
538  const int index2)
539 {
540  if (index1 < 0 ||
541  index1 >= CAST_S32(mSize) ||
542  index2 < 0 ||
543  index2 >= CAST_S32(mSize))
544  {
545  return;
546  }
547 
548  Item *const item1 = mItems[index1];
549  Item *const item2 = mItems[index2];
550  if (item1 != nullptr)
551  item1->setInvIndex(index2);
552  if (item2 != nullptr)
553  item2->setInvIndex(index1);
554  mItems[index1] = item2;
555  mItems[index2] = item1;
557 }
std::map< int, int >::const_iterator IntMapCIter
Definition: being.cpp:150
int BeingTypeId
Definition: beingtypeid.h:30
#define CAST_S32
Definition: cast.h:30
#define CAST_U32
Definition: cast.h:31
#define CAST_SIZE
Definition: cast.h:34
#define reportAlways(...)
Definition: checkutils.h:253
void virtualRemove(Item *const item, const int amount)
Definition: inventory.cpp:485
unsigned mSize
Definition: inventory.h:215
void setCards(const int index, const int *const cards, const int size) const
Definition: inventory.cpp:194
int findIndexByTag(const int tag) const
Definition: inventory.cpp:412
void clear()
Definition: inventory.cpp:238
void removeItemAt(const int index)
Definition: inventory.cpp:254
Item * getItem(const int index) const
Definition: inventory.cpp:83
Inventory(const InventoryTypeT type, const int size)
Definition: inventory.cpp:60
void setTag(const int index, const int tag)
Definition: inventory.cpp:224
virtual bool addVirtualItem(const Item *const item, int index, const int amount)
Definition: inventory.cpp:439
int mUsed
Definition: inventory.h:217
void distributeSlotsChangedEvent()
Definition: inventory.cpp:312
const Item * findItemBySprite(std::string spritePath, const GenderT gender, const BeingTypeId race) const
Definition: inventory.cpp:318
virtual ~Inventory()
Definition: inventory.cpp:74
Item * findItemByTag(const int tag) const
Definition: inventory.cpp:424
bool contains(const Item *const item) const
Definition: inventory.cpp:266
void setOptions(const int index, const ItemOptionsList *const options)
Definition: inventory.cpp:210
void moveItem(const int index1, const int index2)
Definition: inventory.cpp:537
Item * findItem(const int itemId, const ItemColor color) const
Definition: inventory.cpp:94
int getLastUsedSlot() const
Definition: inventory.cpp:291
void restoreVirtuals()
Definition: inventory.cpp:500
std::string getName() const
Definition: inventory.cpp:351
IntMap mVirtualRemove
Definition: inventory.h:213
int addItem(const int id, const ItemTypeT type, const int quantity, const uint8_t refine, const ItemColor color, const Identified identified, const Damaged damaged, const Favorite favorite, const Equipm equipment, const Equipped equipped)
Definition: inventory.cpp:115
InventoryTypeT mType
Definition: inventory.h:214
InventoryListenerList mInventoryListeners
Definition: inventory.h:209
virtual void setItem(const int index, const int id, const ItemTypeT type, const int quantity, const uint8_t refine, const ItemColor color, const Identified identified, const Damaged damaged, const Favorite favorite, const Equipm equipment, const Equipped equipped)
Definition: inventory.cpp:141
Item ** mItems
Definition: inventory.h:216
void removeInventoyListener(InventoryListener *const listener)
Definition: inventory.cpp:307
void resize(const unsigned int newSize)
Definition: inventory.cpp:397
void virtualRestore(const Item *const item, const int amount)
Definition: inventory.cpp:517
int getFreeSlot() const
Definition: inventory.cpp:282
void removeItem(const int id)
Definition: inventory.cpp:244
void addInventoyListener(InventoryListener *const listener)
Definition: inventory.cpp:302
const std::string & getSprite(const GenderT gender, const BeingTypeId race) const
Definition: iteminfo.cpp:100
Definition: item.h:50
int mQuantity
Definition: item.h:248
void setQuantity(const int quantity)
Definition: item.h:93
int mTag
Definition: item.h:249
int getTag() const
Definition: item.h:231
void setIdentified(const Identified b)
Definition: item.h:190
void setInvIndex(const int index)
Definition: item.h:159
ItemColor mColor
Definition: item.h:247
void setRefine(const uint8_t refine)
Definition: item.h:135
int getInvIndex() const
Definition: item.h:165
int mId
Definition: item.h:246
int getId() const
Definition: item.h:81
Favorite getFavorite() const
Definition: item.h:205
void setDamaged(const Damaged b)
Definition: item.h:196
void setId(const int id, const ItemColor color)
Definition: item.cpp:91
void setTag(const int tag)
Definition: item.h:228
ItemColor getColor() const
Definition: item.h:181
Identified getIdentified() const
Definition: item.h:193
ItemTypeT getType() const
Definition: item.h:225
Damaged getDamaged() const
Definition: item.h:199
void setEquipment(const Equipm equipment)
Definition: item.h:111
void setOptions(const ItemOptionsList *const options)
Definition: item.cpp:189
void setCards(const int *const cards, const int size)
Definition: item.cpp:166
void setFavorite(const Favorite b)
Definition: item.h:202
const ItemInfo & getInfo() const
Definition: item.h:171
bool Damaged
Definition: damaged.h:30
#define new
Definition: debug_new.h:147
#define delete2(var)
Definition: delete2.h:25
const bool Equipm_false
Definition: equipm.h:30
bool Equipm
Definition: equipm.h:30
const bool Equipped_false
Definition: equipped.h:30
bool Equipped
Definition: equipped.h:30
bool Favorite
Definition: favorite.h:30
#define FOR_EACH(type, iter, array)
Definition: foreach.h:25
Gender ::T GenderT
Definition: gender.h:35
#define N_(s)
Definition: gettext.h:36
bool Identified
Definition: identified.h:30
Net::InventoryHandler * inventoryHandler
Definition: net.cpp:89
InventoryType ::T InventoryTypeT
Definition: inventorytype.h:42
const ItemColor ItemColor_one
Definition: itemcolor.h:30
uint16_t ItemColor
Definition: itemcolor.h:30
const ItemColor ItemColor_zero
Definition: itemcolor.h:30
ItemType ::T ItemTypeT
Definition: itemtype.h:43
#define final
Definition: localconsts.h:46
#define A_DEFAULT_COPY(func)
Definition: localconsts.h:41
int size()
Definition: emotedb.cpp:306
bool isItemProtected(const int id)
Definition: playerinfo.cpp:515
std::string removeSpriteIndex(std::string str)
std::string extractNameFromSprite(std::string str)