ManaPlus
inventoryrecv.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 "actormanager.h"
27 #include "notifymanager.h"
28 #include "itemcolormanager.h"
29 #include "itemsoundmanager.h"
30 #include "settings.h"
31 
32 #include "being/localplayer.h"
33 
34 #include "const/net/inventory.h"
35 
36 #include "enums/equipslot.h"
37 
39 
41 
42 #include "gui/popups/itempopup.h"
43 
45 
47 
49 
50 #include "net/inventoryhandler.h"
51 #include "net/messagein.h"
52 
53 #include "net/eathena/itemflags.h"
54 #include "net/eathena/menu.h"
55 
56 #include "net/ea/equipbackend.h"
57 #include "net/ea/inventoryrecv.h"
58 
59 #include "resources/iteminfo.h"
60 
61 #include "utils/checkutils.h"
62 #include "utils/gettext.h"
63 #include "utils/foreach.h"
64 #include "utils/stringutils.h"
65 
66 #include "debug.h"
67 
68 extern int serverVersion;
69 extern int packetVersion;
70 extern int itemIdLen;
71 
72 namespace EAthena
73 {
74 
75 namespace InventoryRecv
76 {
77  // EQP_* to EquipSlot
79  {
80  EquipSlot::LEGS_SLOT, // 0 1 EQP_HEAD_LOW
81  EquipSlot::FIGHT1_SLOT, // 1 2 EQP_HAND_R
82  EquipSlot::GLOVES_SLOT, // 2 4 EQP_GARMENT
83  EquipSlot::RING2_SLOT, // 3 8 EQP_ACC_L
84  EquipSlot::RING1_SLOT, // 4 16 EQP_ARMOR
85  EquipSlot::FIGHT2_SLOT, // 5 32 EQP_HAND_L
86  EquipSlot::FEET_SLOT, // 6 64 EQP_SHOES
87  EquipSlot::NECK_SLOT, // 7 128 EQP_ACC_R
88  EquipSlot::HEAD_SLOT, // 8 256 EQP_HEAD_TOP
89  EquipSlot::TORSO_SLOT, // 9 512 EQP_HEAD_MID
90  EquipSlot::EVOL_RING1_SLOT, // 10 1024 EQP_COSTUME_HEAD_TOP
91  EquipSlot::EVOL_RING2_SLOT, // 11 2048 EQP_COSTUME_HEAD_MID
92  EquipSlot::PROJECTILE_SLOT, // 12 4096 EQP_COSTUME_HEAD_LOW
93  EquipSlot::COSTUME_ROBE_SLOT, // 13 8192 EQP_COSTUME_GARMENT
94  EquipSlot::PROJECTILE_SLOT, // 14 16384 UNUSED_COSTUME_FLOOR
95  EquipSlot::PROJECTILE_SLOT, // 15 32768 EQP_AMMO
96  EquipSlot::SHADOW_ARMOR_SLOT, // 16 65536 EQP_SHADOW_ARMOR
97  EquipSlot::SHADOW_WEAPON_SLOT, // 17 131072 EQP_SHADOW_WEAPON
98  EquipSlot::SHADOW_SHIELD_SLOT, // 18 262144 EQP_SHADOW_SHIELD
99  EquipSlot::SHADOW_SHOES_SLOT, // 19 524288 EQP_SHADOW_SHOES
100  EquipSlot::SHADOW_ACCESSORY2_SLOT, // 20 1048576 EQP_SHADOW_ACC_R
101  EquipSlot::SHADOW_ACCESSORY1_SLOT, // 21 2097152 EQP_SHADOW_ACC_L
102  };
103 
106 } // namespace InventoryRecv
107 
109 {
110  BLOCK_START("InventoryRecv::processPlayerEquipment")
111  Inventory *const inventory = localPlayer != nullptr
112  ? PlayerInfo::getInventory() : nullptr;
113 
114  msg.readInt16("len");
115  Equipment *const equipment = PlayerInfo::getEquipment();
116  if ((equipment != nullptr) && (equipment->getBackend() == nullptr))
117  { // look like SMSG_PLAYER_INVENTORY was not received
120  }
121 
122  int packetLen = 2 + 2 + 1 + 1 + 8;
123  if (msg.getVersion() >= 20120925)
124  packetLen += 4 + 4 + 1;
125  else
126  packetLen += 1 + 2 + 2 + 1;
127  if (msg.getVersion() >= 20071002)
128  packetLen += 4;
129  if (msg.getVersion() >= 20080102)
130  packetLen += 2;
131  if (msg.getVersion() >= 20100629)
132  packetLen += 2;
133  if (msg.getVersion() >= 20150226)
134  packetLen += 26;
135  packetLen += itemIdLen * 5 - 2 * 5; // - 5 items by 2 bytes. + 5 items
136 
137  const int number = (msg.getLength() - 4) / packetLen;
138 
139  for (int loop = 0; loop < number; loop++)
140  {
141  const int index = msg.readInt16("index") - INVENTORY_OFFSET;
142  const int itemId = msg.readItemId("item id");
143  const ItemTypeT itemType = static_cast<ItemTypeT>(
144  msg.readUInt8("item type"));
145  int equipType;
146  if (msg.getVersion() >= 20120925)
147  {
148  msg.readInt32("location");
149  equipType = msg.readInt32("wear state");
150  }
151  else
152  {
153  msg.readUInt8("identified");
154  msg.readInt16("location");
155  equipType = msg.readInt16("wear state");
156  msg.readUInt8("is damaged");
157  }
158  const uint8_t refine = CAST_U8(msg.readInt8("refine"));
159  int cards[maxCards];
160  for (int f = 0; f < maxCards; f++)
161  cards[f] = msg.readItemId("card");
162  if (msg.getVersion() >= 20071002)
163  msg.readInt32("hire expire date (?)");
164  if (msg.getVersion() >= 20080102)
165  msg.readInt16("equip type");
166  if (msg.getVersion() >= 20100629)
167  msg.readInt16("item sprite number");
168  ItemOptionsList *options = nullptr;
169  if (msg.getVersion() >= 20150226)
170  {
171  options = new ItemOptionsList(msg.readUInt8("option count"));
172  for (int f = 0; f < 5; f ++)
173  {
174  const uint16_t idx = msg.readInt16("option index");
175  const uint16_t val = msg.readInt16("option value");
176  msg.readUInt8("option param");
177  options->add(idx, val);
178  }
179  }
180  ItemFlags flags;
181  if (msg.getVersion() >= 20120925)
182  flags.byte = msg.readUInt8("flags");
183  else
184  flags.byte = 0;
185  if (inventory != nullptr)
186  {
187  inventory->setItem(index,
188  itemId,
189  itemType,
190  1,
191  refine,
194  fromBool(flags.bits.isDamaged, Damaged),
196  Equipm_true,
198  inventory->setCards(index, cards, maxCards);
199  inventory->setOptions(index, options);
200  }
201  delete options;
202 
203  if (equipType != 0)
204  {
206  InventoryRecv::getSlot(equipType),
207  index);
208  }
209  }
210  BLOCK_END("InventoryRecv::processPlayerEquipment")
211 }
212 
214 {
215  BLOCK_START("InventoryRecv::processPlayerInventoryAdd")
216  Inventory *const inventory = localPlayer != nullptr
217  ? PlayerInfo::getInventory() : nullptr;
218 
219  if ((PlayerInfo::getEquipment() != nullptr)
220  && (PlayerInfo::getEquipment()->getBackend() == nullptr))
221  { // look like SMSG_PLAYER_INVENTORY was not received
224  }
225  const int index = msg.readInt16("index") - INVENTORY_OFFSET;
226  int amount = msg.readInt16("count");
227  const int itemId = msg.readItemId("item id");
228  const uint8_t identified = msg.readUInt8("identified");
229  const uint8_t damaged = msg.readUInt8("is damaged");
230  const uint8_t refine = msg.readUInt8("refine");
231  Favorite favorite = Favorite_false;
232  int cards[maxCards];
233  for (int f = 0; f < maxCards; f++)
234  cards[f] = msg.readItemId("card");
235  int equipType;
236  if (msg.getVersion() >= 20120925)
237  equipType = msg.readInt32("location");
238  else
239  equipType = msg.readInt16("location");
240  const ItemTypeT itemType = static_cast<ItemTypeT>(
241  msg.readUInt8("item type"));
242  const unsigned char err = msg.readUInt8("result");
243  if (msg.getVersion() >= 20061218)
244  msg.readInt32("hire expire date");
245  if (msg.getVersion() >= 20071002)
246  msg.readInt16("bind on equip");
247  ItemOptionsList *options = nullptr;
248  if (msg.getVersion() >= 20150226)
249  {
250  options = new ItemOptionsList;
251  for (int f = 0; f < 5; f ++)
252  {
253  const uint16_t idx = msg.readInt16("option index");
254  const uint16_t val = msg.readInt16("option value");
255  msg.readUInt8("option param");
256  options->add(idx, val);
257  }
258  }
259  if (msg.getVersion() >= 20160921)
260  {
261  favorite = fromBool(msg.readUInt8("favorite"), Favorite);
262  msg.readInt16("look");
263  }
264 
265  const ItemColor color = ItemColorManager::getColorFromCards(&cards[0]);
266  BeingId floorId;
268  {
269  floorId = BeingId_zero;
270  }
271  else
272  {
273  floorId = Ea::InventoryRecv::mSentPickups.front();
275  }
276 
277  if (err != 0U)
278  {
279  PickupT pickup;
280  switch (err)
281  {
282  case 1:
284  break;
285  case 2:
287  break;
288  case 4:
290  break;
291  case 5:
293  break;
294  case 6:
296  break;
297  case 7:
299  break;
300  default:
303  break;
304  }
305  if (localPlayer != nullptr)
306  {
307  if (itemId == 0)
308  {
310  0,
311  color,
312  floorId,
313  pickup);
314  }
315  else
316  {
318  0,
319  color,
320  floorId,
321  pickup);
322  }
323  }
324  }
325  else
326  {
327  if (localPlayer != nullptr)
328  {
329  if (itemId == 0)
330  {
332  amount,
333  color,
334  floorId,
335  Pickup::OKAY);
336  }
337  else
338  {
340  amount,
341  color,
342  floorId,
343  Pickup::OKAY);
344  }
345  }
346 
347  if (inventory != nullptr)
348  {
349  const Item *const item = inventory->getItem(index);
350 
351  if ((item != nullptr) && item->getId() == itemId)
352  amount += item->getQuantity();
353 
354  inventory->setItem(index,
355  itemId,
356  itemType,
357  amount,
358  refine,
359  color,
360  fromBool(identified, Identified),
361  fromBool(damaged, Damaged),
362  favorite,
363  fromBool(equipType, Equipm),
365  inventory->setCards(index, cards, maxCards);
366  inventory->setOptions(index, options);
367  }
369  }
370  delete options;
371  BLOCK_END("InventoryRecv::processPlayerInventoryAdd")
372 }
373 
375 {
376  BLOCK_START("InventoryRecv::processPlayerInventory")
377  Inventory *const inventory = localPlayer != nullptr
378  ? PlayerInfo::getInventory() : nullptr;
379  if (PlayerInfo::getEquipment() != nullptr)
380  {
381  // Clear inventory - this will be a complete refresh
384  }
385 
386  if (inventory != nullptr)
387  inventory->clear();
388 
389  msg.readInt16("len");
390 
391  int packetLen = 7;
392  if (msg.getVersion() >= 20120925)
393  packetLen += 4 + 1;
394  else
395  packetLen += 1 + 2;
396  if (packetVersion >= 5)
397  packetLen += 8;
398  if (msg.getVersion() >= 20080102)
399  packetLen += 4;
400  packetLen += itemIdLen * 5 - 10;
401 
402  const int number = (msg.getLength() - 4) / packetLen;
403 
404  for (int loop = 0; loop < number; loop++)
405  {
406  const int index = msg.readInt16("item index") - INVENTORY_OFFSET;
407  const int itemId = msg.readItemId("item id");
408  const ItemTypeT itemType = static_cast<ItemTypeT>(
409  msg.readUInt8("item type"));
410  if (msg.getVersion() < 20120925)
411  msg.readUInt8("identified");
412  const int amount = msg.readInt16("count");
413  if (msg.getVersion() >= 20120925)
414  msg.readInt32("wear state / equip");
415  else
416  msg.readInt16("wear state / equip");
417  int cards[maxCards];
418  if (packetVersion >= 5)
419  {
420  for (int f = 0; f < maxCards; f++)
421  cards[f] = msg.readItemId("card");
422  }
423  else
424  {
425  for (int f = 0; f < maxCards; f++)
426  cards[f] = 0;
427  }
428  if (msg.getVersion() >= 20080102)
429  msg.readInt32("hire expire date (?)");
430  ItemFlags flags;
431  if (msg.getVersion() >= 20120925)
432  flags.byte = msg.readUInt8("flags");
433  else
434  flags.byte = 0;
435 
436  if (inventory != nullptr)
437  {
438  inventory->setItem(index,
439  itemId,
440  itemType,
441  amount,
442  0,
445  fromBool(flags.bits.isDamaged, Damaged),
447  Equipm_false,
449  inventory->setCards(index, cards, maxCards);
450  }
451  }
452  BLOCK_END("InventoryRecv::processPlayerInventory")
453 }
454 
456 {
457  BLOCK_START("InventoryRecv::processPlayerInventory")
458 // Ea::InventoryRecv::mStorageItems.clear();
459 
460  msg.readInt16("len");
461 
462  int packetLen = 7;
463  if (msg.getVersion() >= 20120925)
464  packetLen += 4 + 1;
465  else
466  packetLen += 1 + 2;
467  if (packetVersion >= 5)
468  packetLen += 8;
469  if (msg.getVersion() >= 20080102)
470  packetLen += 4;
471  packetLen += itemIdLen * 5 - 10;
472 
473  int number;
474  if (msg.getVersion() >= 20120925)
475  {
476  msg.readString(24, "storage name");
477  number = (msg.getLength() - 4 - 24) / packetLen;
478  }
479  else
480  {
481  number = (msg.getLength() - 4) / packetLen;
482  }
483 
484  for (int loop = 0; loop < number; loop++)
485  {
486  const int index = msg.readInt16("item index") - STORAGE_OFFSET;
487  const int itemId = msg.readItemId("item id");
488  const ItemTypeT itemType = static_cast<ItemTypeT>(
489  msg.readUInt8("item type"));
490  if (msg.getVersion() < 20120925)
491  msg.readUInt8("identified");
492  const int amount = msg.readInt16("count");
493  if (msg.getVersion() >= 20120925)
494  msg.readInt32("wear state / equip");
495  else
496  msg.readInt16("wear state / equip");
497  int cards[maxCards];
498  if (msg.getVersion() >= 5)
499  {
500  for (int f = 0; f < maxCards; f++)
501  cards[f] = msg.readItemId("card");
502  }
503  else
504  {
505  for (int f = 0; f < maxCards; f++)
506  cards[f] = 0;
507  }
508  if (msg.getVersion() >= 20080102)
509  msg.readInt32("hire expire date (?)");
510  ItemFlags flags;
511  if (msg.getVersion() >= 20120925)
512  flags.byte = msg.readUInt8("flags");
513  else
514  flags.byte = 0;
515 
517  index,
518  itemId,
519  itemType,
520  cards,
521  nullptr,
522  amount,
523  0,
526  fromBool(flags.bits.isDamaged, Damaged),
528  Equipm_false,
529  -1));
530  }
531  BLOCK_END("InventoryRecv::processPlayerInventory")
532 }
533 
535 {
536  BLOCK_START("InventoryRecv::processPlayerEquip")
537  const int index = msg.readInt16("index") - INVENTORY_OFFSET;
538  int equipType;
539  if (msg.getVersion() >= 20120925)
540  equipType = msg.readInt32("wear location");
541  else
542  equipType = msg.readInt16("wear location");
543  if (msg.getVersion() >= 20100629)
544  msg.readInt16("sprite");
545  const uint8_t flag = msg.readUInt8("result");
546 
547  switch (flag)
548  {
549  case 0:
551  InventoryRecv::getSlot(equipType),
552  index);
553  break;
554  case 1:
556  break;
557 
558  case 2:
559  default:
561  break;
562  }
563  BLOCK_END("InventoryRecv::processPlayerEquip")
564 }
565 
567 {
568  BLOCK_START("InventoryRecv::processPlayerUnEquip")
569  msg.readInt16("index");
570  int equipType;
571  if (msg.getVersion() >= 20120925)
572  equipType = msg.readInt32("wear location");
573  else
574  equipType = msg.readInt16("wear location");
575  const uint8_t flag = msg.readUInt8("result");
576 
577  if (flag != 0U)
578  {
580  }
581  else
582  {
584  InventoryRecv::getSlot(equipType),
585  -1);
586  }
587  if ((equipType & 0x8000) != 0)
589  BLOCK_END("InventoryRecv::processPlayerUnEquip")
590 }
591 
593 {
594  BLOCK_START("InventoryRecv::processPlayerInventoryRemove2")
595  Inventory *const inventory = localPlayer != nullptr
596  ? PlayerInfo::getInventory() : nullptr;
597 
598  const DeleteItemReasonT reason = static_cast<DeleteItemReasonT>(
599  msg.readInt16("reason"));
600  const int index = msg.readInt16("index") - INVENTORY_OFFSET;
601  const int amount = msg.readInt16("amount");
602 
603  if (inventory != nullptr)
604  {
605  if (Item *const item = inventory->getItem(index))
606  {
607  switch (reason)
608  {
611  item->getName());
612  break;
615  item->getName());
616  break;
619  item->getName());
620  break;
624  item->getName());
625  break;
628  item->getName());
629  break;
632  item->getName());
633  break;
636  item->getName());
637  break;
640  item->getName());
641  break;
642  default:
644  item->getName());
645  break;
646  }
647 
648  item->increaseQuantity(-amount);
649  if (item->getQuantity() == 0)
650  inventory->removeItemAt(index);
652  }
653  }
654  BLOCK_END("InventoryRecv::processPlayerInventoryRemove2")
655 }
656 
658 {
659  BLOCK_START("InventoryRecv::processPlayerStorageEquip")
660  msg.readInt16("len");
661 
662  int packetLen = 2 + 2 + 1 + 1 + 8;
663  if (msg.getVersion() >= 20120925)
664  packetLen += 4 + 4 + 1;
665  else
666  packetLen += 1 + 2 + 2 + 1;
667  if (msg.getVersion() >= 20071002)
668  packetLen += 4;
669  if (msg.getVersion() >= 20080102)
670  packetLen += 2;
671  if (msg.getVersion() >= 20100629)
672  packetLen += 2;
673  if (msg.getVersion() >= 20150226)
674  packetLen += 26;
675  packetLen += itemIdLen * 5 - 10;
676 
677  int number;
678  if (msg.getVersion() >= 20120925)
679  {
680  msg.readString(24, "storage name");
681  number = (msg.getLength() - 4 - 24) / packetLen;
682  }
683  else
684  {
685  number = (msg.getLength() - 4) / packetLen;
686  }
687 
688  for (int loop = 0; loop < number; loop++)
689  {
690  const int index = msg.readInt16("index") - STORAGE_OFFSET;
691  const int itemId = msg.readItemId("item id");
692  const ItemTypeT itemType = static_cast<ItemTypeT>(
693  msg.readUInt8("item type"));
694  const int amount = 1;
695  if (msg.getVersion() >= 20120925)
696  {
697  msg.readInt32("location");
698  msg.readInt32("wear state");
699  }
700  else
701  {
702  msg.readUInt8("identified");
703  msg.readInt16("location");
704  msg.readInt16("wear state");
705  msg.readUInt8("is damaged");
706  }
707  const uint8_t refine = msg.readUInt8("refine level");
708  int cards[maxCards];
709  for (int f = 0; f < maxCards; f++)
710  cards[f] = msg.readItemId("card");
711  if (msg.getVersion() >= 20071002)
712  msg.readInt32("hire expire date");
713  if (msg.getVersion() >= 20080102)
714  msg.readInt16("bind on equip");
715  if (msg.getVersion() >= 20100629)
716  msg.readInt16("sprite");
717  ItemOptionsList *options = nullptr;
718  if (msg.getVersion() >= 20150226)
719  {
720  options = new ItemOptionsList(msg.readUInt8("option count"));
721  for (int f = 0; f < 5; f ++)
722  {
723  const uint16_t idx = msg.readInt16("option index");
724  const uint16_t val = msg.readInt16("option value");
725  msg.readUInt8("option param");
726  options->add(idx, val);
727  }
728  }
729 
730  ItemFlags flags;
731  if (msg.getVersion() >= 20120925)
732  flags.byte = msg.readUInt8("flags");
733  else
734  flags.byte = 0;
735 
737  index,
738  itemId,
739  itemType,
740  cards,
741  options,
742  amount,
743  refine,
746  fromBool(flags.bits.isDamaged, Damaged),
748  Equipm_false,
749  -1));
750  delete options;
751  }
752  BLOCK_END("InventoryRecv::processPlayerStorageEquip")
753 }
754 
756 {
757  BLOCK_START("InventoryRecv::processPlayerStorageAdd")
758  // Move an item into storage
759  const int index = msg.readInt16("index") - STORAGE_OFFSET;
760  const int amount = msg.readInt32("amount");
761  const int itemId = msg.readItemId("item id");
762  ItemTypeT itemType;
763  if (msg.getVersion() >= 5)
764  itemType = static_cast<ItemTypeT>(msg.readUInt8("type"));
765  else
766  itemType = ItemType::Unknown;
767  const unsigned char identified = msg.readUInt8("identify");
768  const Damaged damaged = fromBool(msg.readUInt8("attribute"), Damaged);
769  const uint8_t refine = msg.readUInt8("refine");
770  int cards[maxCards];
771  for (int f = 0; f < maxCards; f++)
772  cards[f] = msg.readItemId("card");
773  ItemOptionsList *options = nullptr;
774  if (msg.getVersion() >= 20150226)
775  {
776  options = new ItemOptionsList;
777  for (int f = 0; f < 5; f ++)
778  {
779  const uint16_t idx = msg.readInt16("option index");
780  const uint16_t val = msg.readInt16("option value");
781  msg.readUInt8("option param");
782  options->add(idx, val);
783  }
784  }
785 
786  const ItemColor color = ItemColorManager::getColorFromCards(&cards[0]);
787  if (Item *const item = Ea::InventoryRecv::mStorage->getItem(index))
788  {
789  item->setId(itemId, color);
790  item->increaseQuantity(amount);
791  }
792  else
793  {
794  if (Ea::InventoryRecv::mStorage != nullptr)
795  {
797  itemId,
798  itemType,
799  amount,
800  refine,
801  color,
802  fromBool(identified, Identified),
803  damaged,
805  Equipm_false,
808  Ea::InventoryRecv::mStorage->setOptions(index, options);
809  }
810  }
811  delete options;
812  BLOCK_END("InventoryRecv::processPlayerStorageAdd")
813 }
814 
816 {
817  const Inventory *const inv = PlayerInfo::getInventory();
818  const int index = inventoryHandler->getItemIndex();
819  const Item *item1 = nullptr;
820  if (inv != nullptr)
821  item1 = inv->getItem(index);
822  SellDialog *const dialog = CREATEWIDGETR(InsertCardDialog,
823  index, item1);
824 
825  const int count = (msg.readInt16("len") - 4) / 2;
826  for (int f = 0; f < count; f ++)
827  {
828  const int itemIndex = msg.readInt16("item index") - INVENTORY_OFFSET;
829  if (inv == nullptr)
830  continue;
831  const Item *const item = inv->getItem(itemIndex);
832  if (item == nullptr)
833  continue;
834  dialog->addItem(item, 0);
835  }
836 }
837 
839 {
840  const int itemIndex = msg.readInt16("item index") - INVENTORY_OFFSET;
841  const int cardIndex = msg.readInt16("card index") - INVENTORY_OFFSET;
842  if (msg.readUInt8("flag") != 0U)
843  {
845  }
846  else
847  {
849  Inventory *const inv = PlayerInfo::getInventory();
850  if (inv == nullptr)
851  return;
852  Item *const card = inv->getItem(cardIndex);
853  int cardId = 0;
854  if (card != nullptr)
855  {
856  cardId = card->getId();
857  card->increaseQuantity(-1);
858  if (card->getQuantity() == 0)
859  inv->removeItemAt(cardIndex);
860  }
861  Item *const item = inv->getItem(itemIndex);
862  if (item != nullptr)
863  {
864  item->addCard(cardId);
865  item->updateColor();
867  }
868  }
869 }
870 
872 {
873  const int id = msg.readItemId("item id");
874  const int seconds = msg.readInt32("seconds");
875  const ItemInfo &info = ItemDB::get(id);
876  const std::string timeStr = timeDiffToString(seconds);
878  // TRANSLATORS: notification message
879  strprintf(_("Left %s rental time for item %s."),
880  timeStr.c_str(), info.getName().c_str()));
881 }
882 
884 {
885  Inventory *const inventory = localPlayer != nullptr
886  ? PlayerInfo::getInventory() : nullptr;
887 
888  const int index = msg.readInt16("index") - INVENTORY_OFFSET;
889  const int id = msg.readItemId("item id");
890  const ItemInfo &info = ItemDB::get(id);
891 
893  info.getName());
894  if (inventory != nullptr)
895  {
896  if (Item *const item = inventory->getItem(index))
897  {
898  item->increaseQuantity(-item->getQuantity());
899  inventory->removeItemAt(index);
901  }
902  }
903 }
904 
906 {
907  BLOCK_START("InventoryRecv::processPlayerStorageRemove")
908  // Move an item out of storage
909  const int index = msg.readInt16("index") - STORAGE_OFFSET;
910  const int amount = msg.readInt32("amount");
911  if (Ea::InventoryRecv::mStorage != nullptr)
912  {
913  if (Item *const item = Ea::InventoryRecv::mStorage->getItem(index))
914  {
915  item->increaseQuantity(-amount);
916  if (item->getQuantity() == 0)
918  }
919  }
920  BLOCK_END("InventoryRecv::processPlayerStorageRemove")
921 }
922 
924 {
925  msg.readInt16("cart items used");
926  const int size = msg.readInt16("max cart items");
928  msg.readInt32("cart weight"),
929  Notify_true);
931  msg.readInt32("max cart weight"),
932  Notify_true);
933  if (mCartItems.empty())
934  return;
935 
937  if (inv == nullptr)
938  return;
939 
940  inv->resize(size);
941 
942  FOR_EACH (Ea::InventoryItems::const_iterator, it, mCartItems)
943  {
944  inv->setItem((*it).slot,
945  (*it).id,
946  (*it).type,
947  (*it).quantity,
948  (*it).refine,
949  (*it).color,
950  (*it).identified,
951  (*it).damaged,
952  (*it).favorite,
953  (*it).equip,
955  }
956  mCartItems.clear();
957 }
958 
960 {
962  // +++ need close or clear cart?
963 }
964 
966 {
967  BLOCK_START("InventoryRecv::processPlayerCartAdd")
968  Inventory *const inventory = localPlayer != nullptr
969  ? PlayerInfo::getCartInventory() : nullptr;
970 
971  const int index = msg.readInt16("index") - INVENTORY_OFFSET;
972  int amount = msg.readInt32("count");
973  const int itemId = msg.readItemId("item id");
974  ItemTypeT itemType = ItemType::Unknown;
975  if (msg.getVersion() >= 5)
976  {
977  itemType = static_cast<ItemTypeT>(
978  msg.readUInt8("item type"));
979  }
980  const uint8_t identified = msg.readUInt8("identified");
981  const Damaged damaged = fromBool(msg.readUInt8("attribute"), Damaged);
982  const uint8_t refine = msg.readUInt8("refine");
983  int cards[maxCards];
984  for (int f = 0; f < maxCards; f++)
985  cards[f] = msg.readItemId("card");
986  ItemOptionsList *options = nullptr;
987  if (msg.getVersion() >= 20150226)
988  {
989  options = new ItemOptionsList;
990  for (int f = 0; f < 5; f ++)
991  {
992  const uint16_t idx = msg.readInt16("option index");
993  const uint16_t val = msg.readInt16("option value");
994  msg.readUInt8("option param");
995  options->add(idx, val);
996  }
997  }
998 
999  // check what cart was created, if not add delayed items
1000  if ((inventory != nullptr) && inventory->getSize() > 0)
1001  {
1002  const Item *const item = inventory->getItem(index);
1003 
1004  if ((item != nullptr) && item->getId() == itemId)
1005  amount += item->getQuantity();
1006 
1007  inventory->setItem(index,
1008  itemId,
1009  itemType,
1010  amount,
1011  refine,
1013  fromBool(identified, Identified),
1014  damaged,
1016  Equipm_false,
1017  Equipped_false);
1018  inventory->setCards(index, cards, maxCards);
1019  inventory->setOptions(index, options);
1020  }
1021  else
1022  {
1023  mCartItems.push_back(Ea::InventoryItem(index,
1024  itemId,
1025  itemType,
1026  cards,
1027  options,
1028  amount,
1029  refine,
1031  fromBool(identified, Identified),
1032  damaged,
1034  Equipm_false,
1035  -1));
1036  }
1037  delete options;
1038  BLOCK_END("InventoryRecv::processPlayerCartAdd")
1039 }
1040 
1042 {
1043  BLOCK_START("InventoryRecv::processPlayerCartEquip")
1044  msg.readInt16("len");
1045 
1046  int packetLen = 2 + 2 + 1 + 1 + 8;
1047  if (msg.getVersion() >= 20120925)
1048  packetLen += 4 + 4 + 1;
1049  else
1050  packetLen += 1 + 2 + 2 + 1;
1051  if (msg.getVersion() >= 20071002)
1052  packetLen += 4;
1053  if (msg.getVersion() >= 20080102)
1054  packetLen += 2;
1055  if (msg.getVersion() >= 20100629)
1056  packetLen += 2;
1057  if (msg.getVersion() >= 20150226)
1058  packetLen += 26;
1059  packetLen += itemIdLen * 5 - 10;
1060 
1061  const int number = (msg.getLength() - 4) / packetLen;
1062  for (int loop = 0; loop < number; loop++)
1063  {
1064  const int index = msg.readInt16("index") - INVENTORY_OFFSET;
1065  const int itemId = msg.readItemId("item id");
1066  const ItemTypeT itemType = static_cast<ItemTypeT>(
1067  msg.readUInt8("item type"));
1068  const int amount = 1;
1069  if (msg.getVersion() >= 20120925)
1070  {
1071  msg.readInt32("location");
1072  msg.readInt32("wear state");
1073  }
1074  else
1075  {
1076  msg.readUInt8("identified");
1077  msg.readInt16("location");
1078  msg.readInt16("wear state");
1079  msg.readUInt8("is damaged");
1080  }
1081  const uint8_t refine = msg.readUInt8("refine level");
1082  int cards[maxCards];
1083  for (int f = 0; f < maxCards; f++)
1084  cards[f] = msg.readItemId("card");
1085  if (msg.getVersion() >= 20071002)
1086  msg.readInt32("hire expire date");
1087  if (msg.getVersion() >= 20080102)
1088  msg.readInt16("bind on equip");
1089  if (msg.getVersion() >= 20100629)
1090  msg.readInt16("sprite");
1091  ItemOptionsList *options = nullptr;
1092  if (msg.getVersion() >= 20150226)
1093  {
1094  options = new ItemOptionsList(msg.readUInt8("option count"));
1095  for (int f = 0; f < 5; f ++)
1096  {
1097  const uint16_t idx = msg.readInt16("option index");
1098  const uint16_t val = msg.readInt16("option value");
1099  msg.readUInt8("option param");
1100  options->add(idx, val);
1101  }
1102  }
1103  ItemFlags flags;
1104  if (msg.getVersion() >= 20120925)
1105  flags.byte = msg.readUInt8("flags");
1106  else
1107  flags.byte = 0;
1108 
1109  mCartItems.push_back(Ea::InventoryItem(index,
1110  itemId,
1111  itemType,
1112  cards,
1113  options,
1114  amount,
1115  refine,
1118  fromBool(flags.bits.isDamaged, Damaged),
1119  fromBool(flags.bits.isFavorite, Favorite),
1120  Equipm_false,
1121  -1));
1122  delete options;
1123  }
1124  BLOCK_END("InventoryRecv::processPlayerCartEquip")
1125 }
1126 
1128 {
1129  BLOCK_START("InventoryRecv::processPlayerCartItems")
1130 // Ea::InventoryRecv::mStorageItems.clear();
1131 
1132  msg.readInt16("len");
1133 
1134  int packetLen = 7;
1135  if (msg.getVersion() >= 20120925)
1136  packetLen += 4 + 1;
1137  else
1138  packetLen += 1 + 2;
1139  if (packetVersion >= 5)
1140  packetLen += 8;
1141  if (msg.getVersion() >= 20080102)
1142  packetLen += 4;
1143  packetLen += itemIdLen * 5 - 10;
1144 
1145  const int number = (msg.getLength() - 4) / packetLen;
1146  for (int loop = 0; loop < number; loop++)
1147  {
1148  const int index = msg.readInt16("item index") - INVENTORY_OFFSET;
1149  const int itemId = msg.readItemId("item id");
1150  const ItemTypeT itemType = static_cast<ItemTypeT>(
1151  msg.readUInt8("item type"));
1152  if (msg.getVersion() < 20120925)
1153  msg.readUInt8("identified");
1154  const int amount = msg.readInt16("count");
1155  if (msg.getVersion() >= 20120925)
1156  msg.readInt32("wear state / equip");
1157  int cards[maxCards];
1158  if (msg.getVersion() >= 5)
1159  {
1160  for (int f = 0; f < maxCards; f++)
1161  cards[f] = msg.readItemId("card");
1162  }
1163  else
1164  {
1165  for (int f = 0; f < maxCards; f++)
1166  cards[f] = 0;
1167  }
1168  if (msg.getVersion() >= 20080102)
1169  msg.readInt32("hire expire date (?)");
1170  ItemFlags flags;
1171  if (msg.getVersion() >= 20120925)
1172  flags.byte = msg.readUInt8("flags");
1173  else
1174  flags.byte = 0;
1175 
1176  mCartItems.push_back(Ea::InventoryItem(index,
1177  itemId,
1178  itemType,
1179  cards,
1180  nullptr,
1181  amount,
1182  0,
1185  fromBool(flags.bits.isDamaged, Damaged),
1186  fromBool(flags.bits.isFavorite, Favorite),
1187  Equipm_false,
1188  -1));
1189  }
1190  BLOCK_END("InventoryRecv::processPlayerCartItems")
1191 }
1192 
1194 {
1195  BLOCK_START("InventoryRecv::processPlayerCartRemove")
1196  const int index = msg.readInt16("index") - INVENTORY_OFFSET;
1197  const int amount = msg.readInt32("amount");
1198 
1199  Inventory *const inv = PlayerInfo::getCartInventory();
1200  if (inv == nullptr)
1201  return;
1202 
1203  if (Item *const item = inv->getItem(index))
1204  {
1205  item->increaseQuantity(-amount);
1206  if (item->getQuantity() == 0)
1207  inv->removeItemAt(index);
1208  }
1209  BLOCK_END("InventoryRecv::processPlayerCartRemove")
1210 }
1211 
1213 {
1215 
1217  const int count = msg.readInt16("len") - 4;
1218  for (int f = 0; f < count; f ++)
1219  msg.readInt16("inv index");
1220 }
1221 
1223 {
1225 
1226  msg.readInt16("inv index");
1227  msg.readUInt8("flag");
1228 }
1229 
1231 {
1232  const int flag = msg.readInt16("flag");
1233  const int index = msg.readInt16("inv index") - INVENTORY_OFFSET;
1234  msg.readInt16("refine");
1235  const Inventory *const inv = PlayerInfo::getInventory();
1236  const Item *item = nullptr;
1237  int notifyType;
1238  std::string itemName;
1239  if (inv != nullptr)
1240  item = inv->getItem(index);
1241  if (item != nullptr)
1242  {
1243  itemName = item->getName();
1244  }
1245  else
1246  {
1247  // TRANSLATORS: unknown item
1248  itemName = _("Unknown item");
1249  }
1250  switch (flag)
1251  {
1252  case 0:
1253  notifyType = NotifyTypes::REFINE_SUCCESS;
1254  break;
1255  case 1:
1256  notifyType = NotifyTypes::REFINE_FAILURE;
1257  break;
1258  case 2:
1259  notifyType = NotifyTypes::REFINE_DOWNGRADE;
1260  break;
1261  default:
1263  notifyType = NotifyTypes::REFINE_UNKNOWN;
1264  break;
1265  }
1266  NotifyManager::notify(notifyType, itemName);
1267 }
1268 
1270 {
1272 
1273  const int count = (msg.readInt16("len") - 4) /
1274  (3 + (1 + maxCards) * itemIdLen);
1275  for (int f = 0; f < count; f ++)
1276  {
1277  msg.readInt16("index");
1278  msg.readItemId("item id");
1279  msg.readUInt8("refine");
1280  for (int d = 0; d < maxCards; d ++)
1281  msg.readItemId("card");
1282  }
1284 }
1285 
1287 {
1289 
1290  msg.readInt16("item index");
1291  msg.readUInt8("flag");
1292 }
1293 
1295 {
1297 
1298  const int count = (msg.readInt16("len") - 4) /
1299  (3 + (1 + maxCards) * itemIdLen);
1300 
1301  for (int f = 0; f < count; f ++)
1302  {
1303  msg.readInt16("item index");
1304  msg.readItemId("item id");
1305  msg.readUInt8("refine");
1306  for (int d = 0; d < maxCards; d ++)
1307  msg.readItemId("card");
1308  }
1310 }
1311 
1313 {
1315 
1316  msg.readInt16("info");
1317 }
1318 
1320 {
1322 
1323  msg.readInt16("result");
1324  msg.readInt16("error count");
1325 }
1326 
1328 {
1330 
1331  const int count = (msg.readInt16("len") - 6) / itemIdLen;
1332  msg.readInt16("list type");
1333  for (int f = 0; f < count; f ++)
1334  msg.readItemId("item id");
1335 }
1336 
1338 {
1340 
1341  msg.readInt16("position");
1342  msg.readBeingId("account id");
1343 }
1344 
1346 {
1348 
1349  msg.readInt16("item index");
1350  msg.readUInt8("favorite (0 - favorite)");
1351 }
1352 
1354 {
1355  switch (msg.readUInt8("flag"))
1356  {
1357  case 0:
1359  break;
1360  case 1:
1362  break;
1363  default:
1364  break;
1365  }
1366 }
1367 
1369 {
1370  const int index = msg.readInt16("item index") - INVENTORY_OFFSET;
1371  const Inventory *const inv = PlayerInfo::getInventory();
1372  if (inv != nullptr)
1373  {
1374  std::string itemName;
1375  const Item *const item = inv->getItem(index);
1376  if (item != nullptr)
1377  {
1378  itemName = item->getName();
1379  }
1380  else
1381  {
1382  // TRANSLATORS: unknown item message
1383  itemName = _("Unknown item");
1384  }
1386  }
1387 }
1388 
1390 {
1391  BLOCK_START("InventoryRecv::processPlayerInventoryRemove")
1392  Inventory *const inventory = localPlayer != nullptr
1393  ? PlayerInfo::getInventory() : nullptr;
1394 
1395  const int index = msg.readInt16("index") - INVENTORY_OFFSET;
1396  const int amount = msg.readInt16("amount");
1397  if (inventory != nullptr)
1398  {
1399  if (Item *const item = inventory->getItem(index))
1400  {
1401  if (amount != 0)
1402  {
1404  item->getName());
1405  }
1406  item->increaseQuantity(-amount);
1407  if (item->getQuantity() == 0)
1408  inventory->removeItemAt(index);
1410  }
1411  }
1412  BLOCK_END("InventoryRecv::processPlayerInventoryRemove")
1413 }
1414 
1416 {
1418 
1419  const int count = msg.readInt16("len") - 8;
1420  msg.readBeingId("account id");
1421  for (int f = 0; f < count; f ++)
1422  msg.readUInt8("cart type");
1423 }
1424 
1425 int InventoryRecv::getSlot(const int eAthenaSlot)
1426 {
1427  if (eAthenaSlot == 0)
1428  return EquipSlot::VECTOREND;
1429 
1430  if ((eAthenaSlot & 0x8000) != 0)
1432 
1433  unsigned int mask = 1;
1434  int position = 0;
1435  while ((eAthenaSlot & mask) == 0U)
1436  {
1437  mask <<= 1;
1438  position++;
1439  }
1440  if (position >= EquipSlot::VECTOREND)
1441  return EquipSlot::VECTOREND;
1442  return CAST_S32(EQUIP_POINTS[position]);
1443 }
1444 
1446 {
1448 
1449  const int count = (msg.readInt16("len") - 4) / 2;
1450  for (int f = 0; f < count; f ++)
1451  msg.readInt16("inv index");
1452 }
1453 
1455 {
1457 
1458  msg.readInt16("inv index");
1459  msg.readInt16("amount");
1460  msg.readUInt8("result");
1461 }
1462 
1464 {
1465  BLOCK_START("InventoryRecv::processPlayerInventoryUse")
1466  Inventory *const inventory = localPlayer != nullptr
1467  ? PlayerInfo::getInventory() : nullptr;
1468 
1469  const int index = msg.readInt16("index") - INVENTORY_OFFSET;
1470  const int itemId = msg.readItemId("item id");
1471  const BeingId id = msg.readBeingId("account id");
1472  const int amount = msg.readInt16("amount");
1473  const uint8_t flag = msg.readUInt8("type");
1474  Being *const dstBeing = actorManager->findBeing(id);
1475 
1476  if (dstBeing == localPlayer)
1477  {
1478  if (flag == 0)
1479  {
1481  return;
1482  }
1483  if (inventory != nullptr)
1484  {
1485  if (Item *const item = inventory->getItem(index))
1486  {
1487  if (amount != 0)
1488  item->setQuantity(amount);
1489  else
1490  inventory->removeItemAt(index);
1491  }
1492  }
1493  }
1494  else
1495  {
1496  // +++ here can count left items in other player slot + id + amount
1498  }
1499  BLOCK_END("InventoryRecv::processPlayerInventoryUse")
1500 }
1501 
1503 {
1504  Inventory *const inventory = localPlayer != nullptr
1505  ? PlayerInfo::getInventory() : nullptr;
1506  const int index = msg.readInt16("index") - INVENTORY_OFFSET;
1507  msg.readInt16("unknown"); // 1
1508  if (inventory != nullptr)
1509  {
1510  if (Item *const item = inventory->getItem(index))
1511  {
1513  item->getName());
1514  }
1515  }
1516 }
1517 
1519 {
1520  settings.overweightPercent = msg.readUInt32("parcent");
1521 }
1522 
1524 {
1525  const std::string name = msg.readString(24, "storage name");
1527 }
1528 
1530 {
1531  const NetInventoryTypeT type = static_cast<NetInventoryTypeT>(
1532  msg.readUInt8("type"));
1533  const std::string name = msg.readString(24, "inventory name");
1534  processInventoryStartContinue(type, name);
1535 }
1536 
1538 {
1539  const int nameLen = msg.readInt16("len") - 5;
1540  const NetInventoryTypeT type = static_cast<NetInventoryTypeT>(
1541  msg.readUInt8("type"));
1542  std::string name;
1543  if (nameLen > 0)
1544  name = msg.readString(nameLen, "inventory name");
1545  processInventoryStartContinue(type, name);
1546 }
1547 
1549  const std::string &name)
1550 {
1551  Inventory *inventory = nullptr;
1552  InventoryWindow *window = nullptr;
1553  switch (type)
1554  {
1556  mInventoryItems.clear();
1557  inventory = PlayerInfo::getInventory();
1558  window = inventoryWindow;
1559  break;
1561  mCartItems.clear();
1562  inventory = PlayerInfo::getCartInventory();
1563  window = cartWindow;
1564  break;
1568  inventory = Ea::InventoryRecv::mStorage;
1569  window = storageWindow;
1570  break;
1571  default:
1572  break;
1573  }
1574  if (window != nullptr)
1575  {
1576  window->setCaption(name);
1577  }
1578  if (inventory != nullptr)
1579  inventory->clear();
1580 }
1581 
1583 {
1584  const uint8_t flag = msg.readUInt8("flag");
1585  if (flag != 0)
1586  {
1588  return;
1589  }
1591 }
1592 
1594 {
1595  const NetInventoryTypeT invType = static_cast<NetInventoryTypeT>(
1596  msg.readUInt8("type"));
1597  const uint8_t flag = msg.readUInt8("flag");
1598  if (flag != 0)
1599  {
1601  return;
1602  }
1603  processInventoryEndContinue(invType);
1604 }
1605 
1607  invType)
1608 {
1609  switch (invType)
1610  {
1612  break;
1614  // insert data in handler processCartInfo
1615  return;
1618  // insert data in processPlayerStorageStatus
1619  return;
1620  default:
1621  return;
1622  }
1623  Inventory *inventory = PlayerInfo::getInventory();
1624  if (PlayerInfo::getEquipment() != nullptr)
1625  {
1629  }
1630  if (inventory == nullptr)
1631  return;
1632 
1633  inventory->clear();
1634  FOR_EACH (Ea::InventoryItems::const_iterator, it, mInventoryItems)
1635  {
1636  const int index = (*it).slot;
1637  const int equipIndex = (*it).equipIndex;
1638  inventory->setItem(index,
1639  (*it).id,
1640  (*it).type,
1641  (*it).quantity,
1642  (*it).refine,
1643  (*it).color,
1644  (*it).identified,
1645  (*it).damaged,
1646  (*it).favorite,
1647  (*it).equip,
1648  Equipped_false);
1649  inventory->setCards(index, (*it).cards, maxCards);
1650  if ((*it).options)
1651  inventory->setOptions(index, (*it).options);
1652  if (equipIndex > 0)
1653  {
1655  InventoryRecv::getSlot(equipIndex),
1656  index);
1657  }
1658  }
1659  mInventoryItems.clear();
1660 }
1661 
1663 {
1664  const int dataLen = msg.readInt16("len") - 4;
1666  dataLen,
1668 }
1669 
1671 {
1672  const int dataLen = msg.readInt16("len") - 5;
1673  const NetInventoryTypeT invType = static_cast<NetInventoryTypeT>(
1674  msg.readUInt8("type"));
1676  dataLen,
1677  invType);
1678 }
1679 
1681  const int len,
1682  const NetInventoryTypeT invType)
1683 {
1684  const int packetLen = 14 + itemIdLen * 5;
1685  const int number = len / packetLen;
1686  int offset = INVENTORY_OFFSET;
1687 
1688  switch (invType)
1689  {
1692  default:
1693  offset = INVENTORY_OFFSET;
1694  break;
1697  offset = STORAGE_OFFSET;
1698  break;
1699  }
1700 
1701  Ea::InventoryItems *items = nullptr;
1702  switch (invType)
1703  {
1705  items = &mInventoryItems;
1706  break;
1708  items = &mCartItems;
1709  break;
1713  break;
1714  default:
1715  reportAlways("Unknown inventory type %d", CAST_S32(invType))
1716  return;
1717  }
1718 
1719  for (int loop = 0; loop < number; loop++)
1720  {
1721  const int index = msg.readInt16("item index") - offset;
1722  const int itemId = msg.readItemId("item id");
1723  const ItemTypeT itemType = static_cast<ItemTypeT>(
1724  msg.readUInt8("item type"));
1725  const int amount = msg.readInt16("amount");
1726  msg.readInt32("wear state / equip");
1727  int cards[maxCards];
1728  for (int f = 0; f < maxCards; f++)
1729  cards[f] = msg.readItemId("card");
1730 
1731  msg.readInt32("hire expire date (?)");
1732  ItemFlags flags;
1733  flags.byte = msg.readUInt8("flags");
1734 
1735  items->push_back(Ea::InventoryItem(index,
1736  itemId,
1737  itemType,
1738  cards,
1739  nullptr,
1740  amount,
1741  0,
1744  fromBool(flags.bits.isDamaged, Damaged),
1745  fromBool(flags.bits.isFavorite, Favorite),
1746  Equipm_false,
1747  -1));
1748  }
1749 }
1750 
1752 {
1753  const int dataLen = msg.readInt16("len") - 4;
1755  dataLen,
1757 }
1758 
1760 {
1761  const int dataLen = msg.readInt16("len") - 5;
1762  const NetInventoryTypeT invType = static_cast<NetInventoryTypeT>(
1763  msg.readUInt8("type"));
1765  dataLen,
1766  invType);
1767 }
1768 
1770  const int len,
1771  const NetInventoryTypeT invType)
1772 {
1773  const int packetLen = 47 + itemIdLen * 5;
1774  const int number = len / packetLen;
1775  int offset = INVENTORY_OFFSET;
1776 
1777  switch (invType)
1778  {
1781  default:
1782  offset = INVENTORY_OFFSET;
1783  break;
1786  offset = STORAGE_OFFSET;
1787  break;
1788  }
1789 
1790  Ea::InventoryItems *items = nullptr;
1791  switch (invType)
1792  {
1794  items = &mInventoryItems;
1795  break;
1797  items = &mCartItems;
1798  break;
1802  break;
1803  default:
1804  reportAlways("Unknown inventory type %d", CAST_S32(invType))
1805  return;
1806  }
1807 
1808  for (int loop = 0; loop < number; loop++)
1809  {
1810  const int index = msg.readInt16("item index") - offset;
1811  const int itemId = msg.readItemId("item id");
1812  const ItemTypeT itemType = static_cast<ItemTypeT>(
1813  msg.readUInt8("item type"));
1814  msg.readInt32("location");
1815  int equipType = msg.readInt32("wear state");
1816  const uint8_t refine = CAST_U8(msg.readInt8("refine"));
1817  int cards[maxCards];
1818  for (int f = 0; f < maxCards; f++)
1819  cards[f] = msg.readItemId("card");
1820  msg.readInt32("hire expire date (?)");
1821  msg.readInt16("equip type");
1822  msg.readInt16("item sprite number");
1823  ItemOptionsList *options = new ItemOptionsList(
1824  msg.readUInt8("option count"));
1825  for (int f = 0; f < 5; f ++)
1826  {
1827  const uint16_t idx = msg.readInt16("option index");
1828  const uint16_t val = msg.readInt16("option value");
1829  msg.readUInt8("option param");
1830  options->add(idx, val);
1831  }
1832  ItemFlags flags;
1833  flags.byte = msg.readUInt8("flags");
1834 
1835  items->push_back(Ea::InventoryItem(index,
1836  itemId,
1837  itemType,
1838  cards,
1839  options,
1840  1,
1841  refine,
1844  fromBool(flags.bits.isDamaged, Damaged),
1845  fromBool(flags.bits.isFavorite, Favorite),
1846  Equipm_true,
1847  equipType));
1848  delete options;
1849  }
1850 }
1851 
1853 {
1855  msg.readInt16("inv index");
1856  msg.readInt16("refine");
1857  for (int f = 0; f < maxCards; f++)
1858  msg.readItemId("card");
1859  for (int f = 0; f < 5; f ++)
1860  {
1861  msg.readInt16("option index");
1862  msg.readInt16("option value");
1863  msg.readUInt8("option param");
1864  }
1865 }
1866 
1868 {
1870  msg.readInt16("inv index");
1871  msg.readUInt8("is damaged");
1872  msg.readInt16("refine");
1873  for (int f = 0; f < maxCards; f++)
1874  msg.readItemId("card");
1875  for (int f = 0; f < 5; f ++)
1876  {
1877  msg.readInt16("option index");
1878  msg.readInt16("option value");
1879  msg.readUInt8("option param");
1880  }
1881 }
1882 
1884 {
1885  const int newSize = msg.readInt16("expansion size") +
1887  Inventory *const inv = PlayerInfo::getInventory();
1888  if (inv != nullptr)
1889  {
1890  inv->resize(newSize);
1891  }
1892 }
1893 
1895 {
1897  msg.readUInt8("result");
1898  msg.readItemId("item id");
1899 }
1900 
1902 {
1904  msg.readUInt8("result");
1905 }
1906 
1908 {
1910  msg.readInt16("wear state");
1911  msg.readInt16("card slot");
1912  msg.readItemId("item id");
1913 }
1914 
1915 } // namespace EAthena
ActorManager * actorManager
int BeingId
Definition: beingid.h:30
const BeingId BeingId_zero
Definition: beingid.h:30
#define fromBool(val, name)
Definition: booldefines.h:49
#define maxCards
Definition: cards.h:25
#define CAST_S32
Definition: cast.h:30
#define CAST_U8
Definition: cast.h:27
#define reportAlways(...)
Definition: checkutils.h:253
Being * findBeing(const BeingId id) const
static void distributeEvent()
Definition: being.h:96
void setEquipment(const int index, const int inventoryIndex)
Definition: equipbackend.h:78
const Backend * getBackend() const
Definition: equipment.h:91
void setBackend(Backend *const backend)
Definition: equipment.h:88
void setCards(const int index, const int *const cards, const int size) const
Definition: inventory.cpp:194
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
unsigned getSize() const
Definition: inventory.h:76
void setOptions(const int index, const ItemOptionsList *const options)
Definition: inventory.cpp:210
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
void resize(const unsigned int newSize)
Definition: inventory.cpp:397
static ItemColor getColorFromCards(const int *const cards)
void resetPopup()
Definition: itempopup.cpp:464
static void playSfx(const int item, const ItemSoundEvent::Type sound)
Definition: item.h:50
int getQuantity() const
Definition: item.h:105
void addCard(const int card)
Definition: item.cpp:177
std::string getName() const
Definition: item.cpp:140
int getId() const
Definition: item.h:81
void increaseQuantity(const int amount)
Definition: item.h:99
void updateColor()
Definition: item.cpp:195
void pickedUp(const ItemInfo &itemInfo, const int amount, const ItemColor color, const BeingId floorItemId, const PickupT fail)
virtual int getProjectileSlot() const =0
virtual int getItemIndex() const =0
void addItem(const Item *const item, const int price)
Definition: selldialog.cpp:238
unsigned int overweightPercent
Definition: settings.h:147
unsigned int fixedInventorySize
Definition: settings.h:148
void setCaption(const std::string &caption)
Definition: window.h:531
static const int STORAGE_OFFSET
Definition: inventory.h:28
static const int INVENTORY_OFFSET
Definition: inventory.h:27
#define CREATEWIDGETR(type,...)
Definition: createwidget.h:36
bool Damaged
Definition: damaged.h:30
DeleteItemReason ::T DeleteItemReasonT
int serverVersion
Definition: client.cpp:124
int itemIdLen
Definition: client.cpp:130
int packetVersion
Definition: client.cpp:125
const bool Equipm_false
Definition: equipm.h:30
const bool Equipm_true
Definition: equipm.h:30
bool Equipm
Definition: equipm.h:30
const bool Equipped_false
Definition: equipped.h:30
bool Favorite
Definition: favorite.h:30
const bool Favorite_false
Definition: favorite.h:30
#define FOR_EACH(type, iter, array)
Definition: foreach.h:25
#define _(s)
Definition: gettext.h:35
bool Identified
Definition: identified.h:30
Net::InventoryHandler * inventoryHandler
Definition: net.cpp:89
InventoryWindow * inventoryWindow
InventoryWindow * cartWindow
InventoryWindow * storageWindow
uint16_t ItemColor
Definition: itemcolor.h:30
ItemPopup * itemPopup
Definition: itempopup.cpp:64
ItemType ::T ItemTypeT
Definition: itemtype.h:43
LocalPlayer * localPlayer
#define UNIMPLEMENTEDPACKETFIELD(field)
Definition: logger.h:59
#define UNIMPLEMENTEDPACKET
Definition: logger.h:56
bool msg(InputEvent &event)
Definition: chat.cpp:39
bool pickup(InputEvent &event)
Definition: actions.cpp:49
bool info(InputEvent &event)
Definition: commands.cpp:57
@ CART_TOTAL_WEIGHT
Definition: attributes.h:64
@ CART_MAX_WEIGHT
Definition: attributes.h:65
void processSelectCart(Net::MessageIn &msg)
void processInventoryEndContinue(const NetInventoryTypeT invType)
void processPlayerStorage(Net::MessageIn &msg)
Ea::InventoryItems mCartItems
void processPlayerInventoryUse(Net::MessageIn &msg)
void processPlayerStorageRemove(Net::MessageIn &msg)
void processInventoryStartContinue(const NetInventoryTypeT type, const std::string &name)
void processPlayerStorageEquip(Net::MessageIn &msg)
void processPlayerCombinedInventory1(Net::MessageIn &msg)
void processInventoryExpansionAck(Net::MessageIn &msg)
void processEnchantEquipment(Net::MessageIn &msg)
void processInventoryEnd1(Net::MessageIn &msg)
void processInventoryStart2(Net::MessageIn &msg)
void processPlayerCombinedEquipment1(Net::MessageIn &msg)
void processPlayerRepairList(Net::MessageIn &msg)
void processPlayerUseCard(Net::MessageIn &msg)
void processPlayerInventoryRemove(Net::MessageIn &msg)
void processPlayerIdentifyList(Net::MessageIn &msg)
void processPlayerIdentified(Net::MessageIn &msg)
void processInventoryStart3(Net::MessageIn &msg)
void processItemDamaged(Net::MessageIn &msg)
void processPlayerItemRentalExpired(Net::MessageIn &msg)
void processPlayerStorageAdd(Net::MessageIn &msg)
void processOverWeightPercent(Net::MessageIn &msg)
void processFavoriteItem(Net::MessageIn &msg)
void processPlayerCombinedInventory2(Net::MessageIn &msg)
void processInventoryContinue(Net::MessageIn &msg, const int len, const NetInventoryTypeT invType)
int getSlot(const int eAthenaSlot)
void processInventoryExpansionResult(Net::MessageIn &msg)
void processBindItem(Net::MessageIn &msg)
void processPlayerCartRemove(Net::MessageIn &msg)
void processInventoryStart1(Net::MessageIn &msg)
void processPlayerCartAdd(Net::MessageIn &msg)
void processPlayerUnEquip(Net::MessageIn &msg)
void processPlayerEquipment(Net::MessageIn &msg)
void processPlayerCombinedEquipment2(Net::MessageIn &msg)
void processItemMoveFailed(Net::MessageIn &msg)
void processPlayerEquip(Net::MessageIn &msg)
void processEquipmentContinue(Net::MessageIn &msg, const int len, const NetInventoryTypeT invType)
void processMergeItem(Net::MessageIn &msg)
void processInventoryExpansionInfo(Net::MessageIn &msg)
void processPlayerInventoryRemove2(Net::MessageIn &msg)
void processInventoryEnd2(Net::MessageIn &msg)
const EquipSlot::Type EQUIP_POINTS[EquipSlot::VECTOREND]
void processPlayerCookingList(Net::MessageIn &msg)
void processCartAddError(Net::MessageIn &msg)
void processPlayerInventory(Net::MessageIn &msg)
void processPlayerRepairEffect(Net::MessageIn &msg)
Ea::InventoryItems mInventoryItems
void processPlayerCartItems(Net::MessageIn &msg)
void processPlayerStoragePassword(Net::MessageIn &msg)
void processPlayerRefine(Net::MessageIn &msg)
void processShowItemPreview2(Net::MessageIn &msg)
void processPlayerStoragePasswordResult(Net::MessageIn &msg)
void processPlayerRefineList(Net::MessageIn &msg)
void processPlayerCartEquip(Net::MessageIn &msg)
void processPlayerItemRentalTime(Net::MessageIn &msg)
void processCartInfo(Net::MessageIn &msg)
void processMergeItemResponse(Net::MessageIn &msg)
void processCartRemove(Net::MessageIn &msg)
void processPlayerInsertCard(Net::MessageIn &msg)
void processPlayerInventoryAdd(Net::MessageIn &msg)
void processShowItemPreview1(Net::MessageIn &msg)
MenuTypeT menu
Definition: menu.cpp:28
EquipBackend mEquips
PickupQueue mSentPickups
Inventory * mStorage
InventoryItems mStorageItems
std::vector< InventoryItem > InventoryItems
int size()
Definition: emotedb.cpp:306
@ FIGHT1_SLOT
Definition: equipslot.h:41
@ EVOL_RING1_SLOT
Definition: equipslot.h:44
@ SHADOW_SHOES_SLOT
Definition: equipslot.h:52
@ COSTUME_ROBE_SLOT
Definition: equipslot.h:46
@ HEAD_SLOT
Definition: equipslot.h:35
@ VECTOREND
Definition: equipslot.h:55
@ LEGS_SLOT
Definition: equipslot.h:36
@ RING1_SLOT
Definition: equipslot.h:38
@ GLOVES_SLOT
Definition: equipslot.h:34
@ PROJECTILE_SLOT
Definition: equipslot.h:43
@ SHADOW_ACCESSORY2_SLOT
Definition: equipslot.h:54
@ NECK_SLOT
Definition: equipslot.h:40
@ TORSO_SLOT
Definition: equipslot.h:33
@ SHADOW_ACCESSORY1_SLOT
Definition: equipslot.h:53
@ FIGHT2_SLOT
Definition: equipslot.h:42
@ SHADOW_ARMOR_SLOT
Definition: equipslot.h:49
@ RING2_SLOT
Definition: equipslot.h:39
@ EVOL_RING2_SLOT
Definition: equipslot.h:45
@ FEET_SLOT
Definition: equipslot.h:37
@ SHADOW_SHIELD_SLOT
Definition: equipslot.h:51
@ SHADOW_WEAPON_SLOT
Definition: equipslot.h:50
const ItemInfo & getEmpty()
Definition: itemdb.cpp:834
const ItemInfo & get(const int id)
Definition: itemdb.cpp:792
@ Unknown
Definition: itemtype.h:30
@ WeaponeRefine
Definition: menutype.h:45
@ Identify
Definition: menutype.h:37
@ RepairWespon
Definition: menutype.h:42
void notify(const unsigned int message)
@ EQUIP_FAILED_LEVEL
Definition: notifytypes.h:58
@ DELETE_ITEM_NORMAL
Definition: notifytypes.h:209
@ CART_ADD_WEIGHT_ERROR
Definition: notifytypes.h:185
@ RENTAL_TIME_EXPIRED
Definition: notifytypes.h:180
@ DELETE_ITEM_ANALYSIS
Definition: notifytypes.h:216
@ DELETE_ITEM_UNKNOWN
Definition: notifytypes.h:217
@ CART_ADD_COUNT_ERROR
Definition: notifytypes.h:186
@ DELETE_ITEM_MATERIAL_CHANGE
Definition: notifytypes.h:212
@ DELETE_ITEM_SKILL_USE
Definition: notifytypes.h:210
@ DELETE_ITEM_DROPPED
Definition: notifytypes.h:218
@ CARD_INSERT_SUCCESS
Definition: notifytypes.h:127
@ DELETE_ITEM_TO_CART
Definition: notifytypes.h:214
@ DELETE_ITEM_TO_STORAGE
Definition: notifytypes.h:213
@ DELETE_ITEM_FAIL_REFINE
Definition: notifytypes.h:211
@ CARD_INSERT_FAILED
Definition: notifytypes.h:126
@ INV_FULL
Definition: pickup.h:38
@ BAD_ITEM
Definition: pickup.h:35
@ UNKNOWN
Definition: pickup.h:34
@ OKAY
Definition: pickup.h:33
@ TOO_FAR
Definition: pickup.h:37
@ MAX_AMOUNT
Definition: pickup.h:41
@ STACK_AMOUNT
Definition: pickup.h:42
@ TOO_HEAVY
Definition: pickup.h:36
Inventory * getInventory()
Definition: playerinfo.cpp:195
Equipment * getEquipment()
Definition: playerinfo.cpp:220
Inventory * getCartInventory()
Definition: playerinfo.cpp:207
void setAttribute(const AttributesT id, const int64_t value, const Notify notify)
Definition: playerinfo.cpp:110
const EquipSlot::Type EQUIP_POINTS[EquipSlot::VECTOREND]
NetInventoryType ::T NetInventoryTypeT
const bool Notify_true
Definition: notify.h:30
#define BLOCK_END(name)
Definition: perfomance.h:80
#define BLOCK_START(name)
Definition: perfomance.h:79
Pickup ::T PickupT
Definition: pickup.h:44
std::string empty
Definition: podict.cpp:26
Settings settings
Definition: settings.cpp:32
std::string strprintf(const char *const format,...)
std::string timeDiffToString(int timeDiff)
unsigned char isIdentified
Definition: itemflags.h:33
unsigned char isDamaged
Definition: itemflags.h:34
unsigned char isFavorite
Definition: itemflags.h:35
void add(const uint16_t index, const uint16_t value)
ItemFlagBits bits
Definition: itemflags.h:41