Cuberite
A lightweight, fast and extensible game server for Minecraft
Inventory.cpp
Go to the documentation of this file.
1 
2 #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
3 
4 #include "Inventory.h"
5 #include "Entities/Player.h"
6 #include "ClientHandle.h"
7 #include "UI/Window.h"
8 #include "Item.h"
9 #include "Root.h"
10 #include "World.h"
11 
12 #include "json/json.h"
13 
14 #include "Items/ItemHandler.h"
15 
16 
17 
18 
19 
21  m_ArmorSlots (1, 4), // 1 x 4 slots
22  m_InventorySlots(9, 3), // 9 x 3 slots
23  m_HotbarSlots (9, 1), // 9 x 1 slots
24  m_ShieldSlots (1, 1), // 1 x 1 slots
25  m_Owner(a_Owner)
26 {
27  // Ask each ItemGrid to report changes to us:
32 
34 }
35 
36 
37 
38 
39 
41 {
46 }
47 
48 
49 
50 
51 
52 int cInventory::HowManyCanFit(const cItem & a_ItemStack, bool a_ConsiderEmptySlots)
53 {
54  return HowManyCanFit(a_ItemStack, 0, invNumSlots - 1, a_ConsiderEmptySlots);
55 }
56 
57 
58 
59 
60 
61 int cInventory::HowManyCanFit(const cItem & a_ItemStack, int a_BeginSlotNum, int a_EndSlotNum, bool a_ConsiderEmptySlots)
62 {
63 
64  UNUSED(a_ConsiderEmptySlots);
65  if ((a_BeginSlotNum < 0) || (a_BeginSlotNum >= invNumSlots))
66  {
67  LOGWARNING("%s: Bad BeginSlotNum, got %d, there are %d slots; correcting to 0.", __FUNCTION__, a_BeginSlotNum, invNumSlots - 1);
68  a_BeginSlotNum = 0;
69  }
70  if ((a_EndSlotNum < 0) || (a_EndSlotNum >= invNumSlots))
71  {
72  LOGWARNING("%s: Bad EndSlotNum, got %d, there are %d slots; correcting to %d.", __FUNCTION__, a_BeginSlotNum, invNumSlots, invNumSlots - 1);
73  a_EndSlotNum = invNumSlots - 1;
74  }
75  if (a_BeginSlotNum > a_EndSlotNum)
76  {
77  std::swap(a_BeginSlotNum, a_EndSlotNum);
78  }
79 
80  char NumLeft = a_ItemStack.m_ItemCount;
81  char MaxStack = a_ItemStack.GetMaxStackSize();
82  for (int i = a_BeginSlotNum; i <= a_EndSlotNum; i++)
83  {
84  const cItem & Slot = GetSlot(i);
85  if (Slot.IsEmpty())
86  {
87  NumLeft -= MaxStack;
88  }
89  else if (Slot.IsEqual(a_ItemStack))
90  {
91  NumLeft -= MaxStack - Slot.m_ItemCount;
92  }
93  if (NumLeft <= 0)
94  {
95  // All items fit
96  return a_ItemStack.m_ItemCount;
97  }
98  } // for i - m_Slots[]
99  return a_ItemStack.m_ItemCount - NumLeft;
100 }
101 
102 
103 
104 
105 
106 char cInventory::AddItem(const cItem & a_Item, bool a_AllowNewStacks)
107 {
108  m_Owner.AddKnownItem(a_Item);
109 
110  cItem ToAdd(a_Item);
111  char res = 0;
112 
113  // When the item is a armor, try to set it directly to the armor slot.
114  if (ItemCategory::IsArmor(a_Item.m_ItemType))
115  {
116  for (int i = 0; i < m_ArmorSlots.GetNumSlots(); i++)
117  {
119  {
120  m_ArmorSlots.SetSlot(i, a_Item);
121  return a_Item.m_ItemCount;
122  }
123  }
124  }
125 
126  // Add to existing stacks in the hotbar.
127  res += m_HotbarSlots.AddItem(ToAdd, false);
128  ToAdd.m_ItemCount = static_cast<char>(a_Item.m_ItemCount - res);
129  if (ToAdd.m_ItemCount == 0)
130  {
131  return res;
132  }
133 
134  // Add to existing stacks in main inventory.
135  res += m_InventorySlots.AddItem(ToAdd, false);
136  ToAdd.m_ItemCount = static_cast<char>(a_Item.m_ItemCount - res);
137  if (ToAdd.m_ItemCount == 0)
138  {
139  return res;
140  }
141 
142  // All existing stacks are now filled.
143  if (!a_AllowNewStacks)
144  {
145  return res;
146  }
147 
148  // Try adding new stacks to the hotbar.
149  res += m_HotbarSlots.AddItem(ToAdd, true);
150  ToAdd.m_ItemCount = static_cast<char>(a_Item.m_ItemCount - res);
151  if (ToAdd.m_ItemCount == 0)
152  {
153  return res;
154  }
155 
156  // Try adding new stacks to the main inventory.
157  res += m_InventorySlots.AddItem(ToAdd, true);
158  return res;
159 }
160 
161 
162 
163 
164 
165 char cInventory::AddItems(cItems & a_ItemStackList, bool a_AllowNewStacks)
166 {
167  char TotalAdded = 0;
168  for (cItems::iterator itr = a_ItemStackList.begin(); itr != a_ItemStackList.end();)
169  {
170  char NumAdded = AddItem(*itr, a_AllowNewStacks);
171  if (itr->m_ItemCount == NumAdded)
172  {
173  itr = a_ItemStackList.erase(itr);
174  }
175  else
176  {
177  itr->m_ItemCount -= NumAdded;
178  ++itr;
179  }
180  TotalAdded += NumAdded;
181  }
182  return TotalAdded;
183 }
184 
185 
186 
187 
188 
189 int cInventory::RemoveItem(const cItem & a_ItemStack)
190 {
191  char RemovedItems = m_ShieldSlots.RemoveItem(a_ItemStack);
192 
193  if (RemovedItems < a_ItemStack.m_ItemCount)
194  {
195  RemovedItems += m_HotbarSlots.RemoveItem(a_ItemStack);
196  }
197 
198  if (RemovedItems < a_ItemStack.m_ItemCount)
199  {
200  cItem Temp(a_ItemStack);
201  Temp.m_ItemCount -= RemovedItems;
202  RemovedItems += m_InventorySlots.RemoveItem(Temp);
203  }
204 
205  return RemovedItems;
206 }
207 
208 
209 
210 
211 
212 cItem * cInventory::FindItem(const cItem & a_RecipeItem)
213 {
214  cItem * Item = m_ShieldSlots.FindItem(a_RecipeItem);
215  if (Item != nullptr)
216  {
217  return Item;
218  }
219  Item = m_HotbarSlots.FindItem(a_RecipeItem);
220  if (Item != nullptr)
221  {
222  return Item;
223  }
224 
225  return m_InventorySlots.FindItem(a_RecipeItem);
226 }
227 
228 
229 
230 
231 
233 {
235  {
236  return false;
237  }
238 
240  return true;
241 }
242 
243 
244 
245 
246 
247 int cInventory::ReplaceOneEquippedItem(const cItem & a_Item, bool a_TryOtherSlots)
248 {
249  // Ignore whether there was an item in the slot to remove.
251 
252  auto EquippedItem = GetEquippedItem();
253  if (EquippedItem.IsEmpty())
254  {
255  SetEquippedItem(a_Item);
256  return a_Item.m_ItemCount;
257  }
258 
259  // Handle case when equipped item is the same as the replacement item.
260  cItem ItemsToAdd = a_Item;
261  if (EquippedItem.IsEqual(ItemsToAdd))
262  {
263  auto AmountToAdd = std::min(static_cast<char>(ItemsToAdd.GetMaxStackSize() - EquippedItem.m_ItemCount), ItemsToAdd.m_ItemCount);
264 
265  EquippedItem.m_ItemCount += AmountToAdd;
266  SetEquippedItem(EquippedItem);
267  ItemsToAdd.m_ItemCount -= AmountToAdd;
268  }
269 
270  auto ItemsAdded = a_Item.m_ItemCount - ItemsToAdd.m_ItemCount;
271 
272  if (ItemsToAdd.m_ItemCount == 0)
273  {
274  return ItemsAdded;
275  }
276 
277  if (!a_TryOtherSlots)
278  {
279  return ItemsAdded;
280  }
281 
282  // Try the rest of the inventory.
283  return AddItem(ItemsToAdd) + ItemsAdded;
284 }
285 
286 
287 
288 
289 
290 int cInventory::HowManyItems(const cItem & a_Item)
291 {
292  return
293  m_ArmorSlots.HowManyItems(a_Item) +
295  m_HotbarSlots.HowManyItems(a_Item) +
296  m_ShieldSlots.HowManyItems(a_Item);
297 }
298 
299 
300 
301 
302 
303 bool cInventory::HasItems(const cItem & a_ItemStack)
304 {
305  int CurrentlyHave = HowManyItems(a_ItemStack);
306  return (CurrentlyHave >= a_ItemStack.m_ItemCount);
307 }
308 
309 
310 
311 
312 
313 void cInventory::SetSlot(int a_SlotNum, const cItem & a_Item)
314 {
315  if ((a_SlotNum < 0) || (a_SlotNum >= invNumSlots))
316  {
317  LOGWARNING("%s: requesting an invalid slot index: %d out of %d. Ignoring.", __FUNCTION__, a_SlotNum, invNumSlots - 1);
318  return;
319  }
320 
321  int GridSlotNum = 0;
322  cItemGrid * Grid = GetGridForSlotNum(a_SlotNum, GridSlotNum);
323  if (Grid == nullptr)
324  {
325  LOGWARNING("%s(%d): requesting an invalid itemgrid. Ignoring.", __FUNCTION__, a_SlotNum);
326  return;
327  }
328  Grid->SetSlot(GridSlotNum, a_Item);
329 }
330 
331 
332 
333 
334 
335 void cInventory::SetArmorSlot(int a_ArmorSlotNum, const cItem & a_Item)
336 {
337  m_ArmorSlots.SetSlot(a_ArmorSlotNum, a_Item);
338 }
339 
340 
341 
342 
343 
344 void cInventory::SetInventorySlot(int a_InventorySlotNum, const cItem & a_Item)
345 {
346  m_InventorySlots.SetSlot(a_InventorySlotNum, a_Item);
347 }
348 
349 
350 
351 
352 
353 void cInventory::SetHotbarSlot(int a_HotBarSlotNum, const cItem & a_Item)
354 {
355  m_HotbarSlots.SetSlot(a_HotBarSlotNum, a_Item);
356 }
357 
358 
359 
360 
361 
362 void cInventory::SetShieldSlot(const cItem & a_Item)
363 {
364  m_ShieldSlots.SetSlot(0, a_Item);
365 }
366 
367 
368 
369 
370 
371 void cInventory::SetEquippedItem(const cItem & a_Item)
372 {
374 }
375 
376 
377 
378 
379 
381 {
383  SendSlot(EquippedSlotNum);
384 }
385 
386 
387 
388 
389 
390 const cItem & cInventory::GetSlot(int a_SlotNum) const
391 {
392  if ((a_SlotNum < 0) || (a_SlotNum >= invNumSlots))
393  {
394  LOGWARNING("%s: requesting an invalid slot index: %d out of %d. Returning the first inventory slot instead.", __FUNCTION__, a_SlotNum, invNumSlots - 1);
395  return m_InventorySlots.GetSlot(0);
396  }
397  int GridSlotNum = 0;
398  const cItemGrid * Grid = GetGridForSlotNum(a_SlotNum, GridSlotNum);
399  if (Grid == nullptr)
400  {
401  // Something went wrong, but we don't know what. We must return a value, so return the first inventory slot
402  LOGWARNING("%s(%d): requesting an invalid ItemGrid, returning the first inventory slot instead.", __FUNCTION__, a_SlotNum);
403  return m_InventorySlots.GetSlot(0);
404  }
405  return Grid->GetSlot(GridSlotNum);
406 }
407 
408 
409 
410 
411 
412 const cItem & cInventory::GetArmorSlot(int a_ArmorSlotNum) const
413 {
414  if ((a_ArmorSlotNum < 0) || (a_ArmorSlotNum >= invArmorCount))
415  {
416  LOGWARNING("%s: requesting an invalid slot index: %d out of %d. Returning the first one instead", __FUNCTION__, a_ArmorSlotNum, invArmorCount - 1);
417  return m_ArmorSlots.GetSlot(0);
418  }
419  return m_ArmorSlots.GetSlot(a_ArmorSlotNum);
420 }
421 
422 
423 
424 
425 
426 const cItem & cInventory::GetInventorySlot(int a_InventorySlotNum) const
427 {
428  if ((a_InventorySlotNum < 0) || (a_InventorySlotNum >= invInventoryCount))
429  {
430  LOGWARNING("%s: requesting an invalid slot index: %d out of %d. Returning the first one instead", __FUNCTION__, a_InventorySlotNum, invInventoryCount - 1);
431  return m_InventorySlots.GetSlot(0);
432  }
433  return m_InventorySlots.GetSlot(a_InventorySlotNum);
434 }
435 
436 
437 
438 
439 
440 const cItem & cInventory::GetHotbarSlot(int a_SlotNum) const
441 {
442  if ((a_SlotNum < 0) || (a_SlotNum >= invHotbarCount))
443  {
444  LOGWARNING("%s: requesting an invalid slot index: %d out of %d. Returning the first one instead", __FUNCTION__, a_SlotNum, invHotbarCount - 1);
445  return m_HotbarSlots.GetSlot(0);
446  }
447  return m_HotbarSlots.GetSlot(a_SlotNum);
448 }
449 
450 
451 
452 
453 
455 {
456  return m_ShieldSlots.GetSlot(0);
457 }
458 
459 
460 
461 
462 
464 {
466 }
467 
468 
469 
470 
471 
473 {
474  if ((a_SlotNum < 0) || (a_SlotNum >= invHotbarCount))
475  {
476  LOGWARNING("%s: requesting invalid slot index: %d out of %d. Setting 0 instead.", __FUNCTION__, a_SlotNum, invHotbarCount - 1);
477  m_EquippedSlotNum = 0;
478  }
479  else
480  {
481  m_EquippedSlotNum = a_SlotNum;
482  }
483 }
484 
485 
486 
487 
488 
489 bool cInventory::DamageEquippedItem(short a_Amount)
490 {
491  return DamageItem(invHotbarOffset + m_EquippedSlotNum, a_Amount);
492 }
493 
494 
495 
496 
497 
498 char cInventory::ChangeSlotCount(int a_SlotNum, char a_AddToCount)
499 {
500  int GridSlotNum = 0;
501  cItemGrid * Grid = GetGridForSlotNum(a_SlotNum, GridSlotNum);
502  if (Grid == nullptr)
503  {
504  LOGWARNING("%s: invalid slot number, expected 0 .. %d, got %d; ignoring", __FUNCTION__, invNumSlots, a_SlotNum);
505  return -1;
506  }
507  return Grid->ChangeSlotCount(GridSlotNum, a_AddToCount);
508 }
509 
510 
511 
512 
513 
514 bool cInventory::DamageItem(int a_SlotNum, short a_Amount)
515 {
516  if ((a_SlotNum < 0) || (a_SlotNum >= invNumSlots))
517  {
518  LOGWARNING("%s: requesting an invalid slot index: %d out of %d", __FUNCTION__, a_SlotNum, invNumSlots - 1);
519  return false;
520  }
521  if (a_Amount <= 0)
522  {
523  return false;
524  }
525 
526  int GridSlotNum = 0;
527  cItemGrid * Grid = GetGridForSlotNum(a_SlotNum, GridSlotNum);
528  if (Grid == nullptr)
529  {
530  LOGWARNING("%s(%d, %d): requesting an invalid grid, ignoring.", __FUNCTION__, a_SlotNum, a_Amount);
531  return false;
532  }
533  if (!Grid->DamageItem(GridSlotNum, a_Amount))
534  {
535  // The item has been damaged, but did not break yet
536  SendSlot(a_SlotNum);
537  return false;
538  }
539 
540  // The item has broken, remove it:
541  Grid->EmptySlot(GridSlotNum);
542  return true;
543 }
544 
545 
546 
547 
548 
550 {
551  m_ArmorSlots.CopyToItems(a_Items);
552  m_InventorySlots.CopyToItems(a_Items);
553  m_HotbarSlots.CopyToItems(a_Items);
554 }
555 
556 
557 
558 
559 
560 void cInventory::SendSlot(int a_SlotNum)
561 {
562  cItem Item(GetSlot(a_SlotNum));
563  if (Item.IsEmpty())
564  {
565  // Sanitize items that are not completely empty (ie. count == 0, but type != empty)
566  Item.Empty();
567  }
568  m_Owner.GetClientHandle()->SendInventorySlot(0, static_cast<short>(a_SlotNum + 5), Item); // Slots in the client are numbered "+ 5" because of crafting grid and result
569 }
570 
571 
572 
573 
574 
575 /*
576 int cInventory::MoveItem(short a_ItemType, short a_ItemDamage, int a_Count, int a_BeginSlot, int a_EndSlot)
577 {
578  int res = 0;
579  for (int i = a_BeginSlot; i <= a_EndSlot; i++)
580  {
581  if (
582  m_Slots[i].IsEmpty() ||
583  ((m_Slots[i].m_ItemType == a_ItemType) && (m_Slots[i].m_ItemDamage == a_ItemDamage))
584  )
585  {
586  int MaxCount = ItemHandler(a_ItemType)->GetMaxStackSize();
587  ASSERT(m_Slots[i].m_ItemCount <= MaxCount);
588  int NumToMove = std::min(a_Count, MaxCount - m_Slots[i].m_ItemCount);
589  m_Slots[i].m_ItemCount += NumToMove;
590  m_Slots[i].m_ItemDamage = a_ItemDamage;
591  m_Slots[i].m_ItemType = a_ItemType;
592  SendSlot(i);
593  res += NumToMove;
594  a_Count -= NumToMove;
595  if (a_Count <= 0)
596  {
597  // No more items to distribute
598  return res;
599  }
600  }
601  } // for i - m_Slots[]
602  // No more space to distribute to
603  return res;
604 }
605 */
606 
607 
608 
609 
610 
612 {
613  switch (a_ArmorSlotNum)
614  {
615  case 0: return 4; // Helmet
616  case 1: return 3; // Chestplate
617  case 2: return 2; // Leggings
618  case 3: return 1; // Boots
619  }
620  LOGWARN("%s: invalid armor slot number: %d", __FUNCTION__, a_ArmorSlotNum);
621  return 0;
622 }
623 
624 
625 
626 
627 
628 #if 0
629 bool cInventory::AddToBar(cItem & a_Item, const int a_Offset, const int a_Size, bool * a_bChangedSlots, int a_Mode /* = 0 */)
630 {
631  // Fill already present stacks
632  if (a_Mode < 2)
633  {
634  int MaxStackSize = cItemHandler::GetItemHandler(a_Item.m_ItemType)->GetMaxStackSize();
635  for (int i = 0; i < a_Size; i++)
636  {
637  if (
638  (m_Slots[i + a_Offset].m_ItemType == a_Item.m_ItemType) &&
639  (m_Slots[i + a_Offset].m_ItemCount < MaxStackSize) &&
640  (m_Slots[i + a_Offset].m_ItemDamage == a_Item.m_ItemDamage)
641  )
642  {
643  int NumFree = MaxStackSize - m_Slots[i + a_Offset].m_ItemCount;
644  if (NumFree >= a_Item.m_ItemCount)
645  {
646 
647  // printf("1. Adding %i items ( free: %i)\n", a_Item.m_ItemCount, NumFree);
648  m_Slots[i + a_Offset].m_ItemCount += a_Item.m_ItemCount;
649  a_Item.m_ItemCount = 0;
650  a_bChangedSlots[i + a_Offset] = true;
651  break;
652  }
653  else
654  {
655  // printf("2. Adding %i items\n", NumFree);
656  m_Slots[i + a_Offset].m_ItemCount += (char)NumFree;
657  a_Item.m_ItemCount -= (char)NumFree;
658  a_bChangedSlots[i + a_Offset] = true;
659  }
660  }
661  }
662  }
663 
664  if (a_Mode > 0)
665  {
666  // If we got more left, find first empty slot
667  for (int i = 0; (i < a_Size) && (a_Item.m_ItemCount > 0); i++)
668  {
669  if (m_Slots[i + a_Offset].m_ItemType == -1)
670  {
671  m_Slots[i + a_Offset] = a_Item;
672  a_Item.m_ItemCount = 0;
673  a_bChangedSlots[i + a_Offset] = true;
674  }
675  }
676  }
677 
678  return true;
679 }
680 #endif
681 
682 
683 
684 
685 
687 {
688  const cItem & Slot = GetEquippedItem();
689  if (!Slot.IsEmpty())
690  {
691  Slot.GetHandler().OnUpdate(m_Owner.GetWorld(), &m_Owner, Slot);
692  }
693 }
694 
695 
696 
697 
698 
699 void cInventory::SaveToJson(Json::Value & a_Value)
700 {
701  // The JSON originally included the 4 crafting slots and the result, so we have to put empty items there, too:
702  cItem EmptyItem;
703  Json::Value EmptyItemJson;
704  EmptyItem.GetJson(EmptyItemJson);
705  for (int i = 0; i < 5; i++)
706  {
707  a_Value.append(EmptyItemJson);
708  }
709 
710  // The 4 armor slots follow:
711  for (int i = 0; i < invArmorCount; i++)
712  {
713  Json::Value JSON_Item;
714  m_ArmorSlots.GetSlot(i).GetJson(JSON_Item);
715  a_Value.append(JSON_Item);
716  }
717 
718  // Next comes the main inventory:
719  for (int i = 0; i < invInventoryCount; i++)
720  {
721  Json::Value JSON_Item;
722  m_InventorySlots.GetSlot(i).GetJson(JSON_Item);
723  a_Value.append(JSON_Item);
724  }
725 
726  // The hotbar:
727  for (int i = 0; i < invHotbarCount; i++)
728  {
729  Json::Value JSON_Item;
730  m_HotbarSlots.GetSlot(i).GetJson(JSON_Item);
731  a_Value.append(JSON_Item);
732  }
733 
734  // Shield slot is the last
735  Json::Value JSON_Item;
736  m_ShieldSlots.GetSlot(0).GetJson(JSON_Item);
737  a_Value.append(JSON_Item);
738 }
739 
740 
741 
742 
743 
744 bool cInventory::LoadFromJson(Json::Value & a_Value)
745 {
746  int SlotIdx = 0;
747 
748  for (Json::Value::iterator itr = a_Value.begin(); itr != a_Value.end(); ++itr, SlotIdx++)
749  {
750  cItem Item;
751  Item.FromJson(*itr);
752 
753  // The JSON originally included the 4 crafting slots and the result slot, so we need to skip the first 5 items:
754  if (SlotIdx < 5)
755  {
756  continue;
757  }
758 
759  // If we loaded all the slots, stop now, even if the JSON has more:
760  if (SlotIdx - 5 >= invNumSlots)
761  {
762  break;
763  }
764 
765  int GridSlotNum = 0;
766  cItemGrid * Grid = GetGridForSlotNum(SlotIdx - 5, GridSlotNum);
767  ASSERT(Grid != nullptr);
768  Grid->SetSlot(GridSlotNum, Item);
769  } // for itr - a_Value[]
770  return true;
771 }
772 
773 
774 
775 
776 
777 const cItemGrid * cInventory::GetGridForSlotNum(int a_SlotNum, int & a_GridSlotNum) const
778 {
779  ASSERT(a_SlotNum >= 0);
780 
781  if (a_SlotNum < invArmorCount)
782  {
783  a_GridSlotNum = a_SlotNum;
784  return &m_ArmorSlots;
785  }
786  a_SlotNum -= invArmorCount;
787  if (a_SlotNum < invInventoryCount)
788  {
789  a_GridSlotNum = a_SlotNum;
790  return &m_InventorySlots;
791  }
792  a_SlotNum -= invInventoryCount;
793  if (a_SlotNum < invHotbarCount)
794  {
795  a_GridSlotNum = a_SlotNum;
796  return &m_HotbarSlots;
797  }
798  a_GridSlotNum = a_SlotNum - invHotbarCount;
799  return &m_ShieldSlots;
800 }
801 
802 
803 
804 
805 
806 cItemGrid * cInventory::GetGridForSlotNum(int a_SlotNum, int & a_GridSlotNum)
807 {
808  ASSERT(a_SlotNum >= 0);
809 
810  if (a_SlotNum < invArmorCount)
811  {
812  a_GridSlotNum = a_SlotNum;
813  return &m_ArmorSlots;
814  }
815  a_SlotNum -= invArmorCount;
816  if (a_SlotNum < invInventoryCount)
817  {
818  a_GridSlotNum = a_SlotNum;
819  return &m_InventorySlots;
820  }
821  a_SlotNum -= invInventoryCount;
822  if (a_SlotNum < invHotbarCount)
823  {
824  a_GridSlotNum = a_SlotNum;
825  return &m_HotbarSlots;
826  }
827  a_GridSlotNum = a_SlotNum - invHotbarCount;
828  return &m_ShieldSlots;
829 }
830 
831 
832 
833 
834 
835 void cInventory::OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum)
836 {
837  // Send the neccessary updates to whoever needs them
838 
839  if (!m_Owner.IsTicking())
840  {
841  // Owner is not (yet) valid, skip for now
842  return;
843  }
844 
845  // Armor update needs broadcast to other players:
847  if ((a_ItemGrid == &m_ArmorSlots) && (World != nullptr))
848  {
849  World->BroadcastEntityEquipment(
850  m_Owner, static_cast<short>(ArmorSlotNumToEntityEquipmentID(static_cast<short>(a_SlotNum))),
852  );
853  }
854 
855  // Broadcast the Equipped Item, if the Slot is changed.
856  if ((a_ItemGrid == &m_HotbarSlots) && (m_EquippedSlotNum == a_SlotNum))
857  {
859  }
860 
861  // Convert the grid-local a_SlotNum to our global SlotNum:
862  int Base = 0;
863  if (a_ItemGrid == &m_ArmorSlots)
864  {
865  Base = invArmorOffset;
866  }
867  else if (a_ItemGrid == &m_InventorySlots)
868  {
869  Base = invInventoryOffset;
870  }
871  else if (a_ItemGrid == &m_HotbarSlots)
872  {
873  Base = invHotbarOffset;
874  }
875  else if (a_ItemGrid == &m_ShieldSlots)
876  {
877  Base = invShieldOffset;
878  }
879  else
880  {
881  ASSERT(!"Unknown ItemGrid calling OnSlotChanged()");
882  return;
883  }
884 
885  SendSlot(Base + a_SlotNum);
886 }
#define ASSERT(x)
Definition: Globals.h:276
#define UNUSED
Definition: Globals.h:72
void LOGWARNING(std::string_view a_Format, const Args &... args)
Definition: LoggerSimple.h:67
#define LOGWARN
Definition: LoggerSimple.h:88
Item
Definition: Items.h:4
bool IsArmor(short a_ItemType)
Definition: Defines.cpp:588
Utilities to allow casting a cWorld to one of its interfaces without including World....
Definition: OpaqueWorld.h:13
void SendInventorySlot(char a_WindowID, short a_SlotNum, const cItem &a_Item)
bool IsTicking(void) const
Returns true if the entity is valid and ticking.
Definition: Entity.cpp:2259
cWorld * GetWorld(void) const
Definition: Entity.h:190
Definition: Player.h:29
cClientHandle * GetClientHandle(void) const
Definition: Player.h:276
void AddKnownItem(const cItem &a_Item)
Adds an Item to the list of known items.
Definition: Player.cpp:2708
char AddItem(const cItem &a_ItemStack, bool a_AllowNewStacks=true)
Adds as many items out of a_ItemStack as can fit.
Definition: Inventory.cpp:106
int m_EquippedSlotNum
Definition: Inventory.h:203
const cItem & GetHotbarSlot(int a_HotBarSlotNum) const
Returns current item in a_ArmorSlotNum in hotbar slots.
Definition: Inventory.cpp:440
bool LoadFromJson(Json::Value &a_Value)
Definition: Inventory.cpp:744
void UpdateItems(void)
Update items (e.g.
Definition: Inventory.cpp:686
cItemGrid m_ArmorSlots
Definition: Inventory.h:198
virtual void OnSlotChanged(cItemGrid *a_ItemGrid, int a_SlotNum) override
Called whenever a slot changes.
Definition: Inventory.cpp:835
cItemGrid m_InventorySlots
Definition: Inventory.h:199
cInventory(cPlayer &a_Owner)
Definition: Inventory.cpp:20
void CopyToItems(cItems &a_Items)
Copies the non-empty slots into a_ItemStacks; preserves the original a_Items contents.
Definition: Inventory.cpp:549
static int ArmorSlotNumToEntityEquipmentID(short a_ArmorSlotNum)
Converts an armor slot number into the ID for the EntityEquipment packet.
Definition: Inventory.cpp:611
bool HasItems(const cItem &a_ItemStack)
Returns true if there are at least as many items of type a_ItemStack as in a_ItemStack.
Definition: Inventory.cpp:303
cItemGrid m_ShieldSlots
Definition: Inventory.h:201
bool DamageEquippedItem(short a_Amount=1)
Adds the specified damage to the currently held item; deletes the item and returns true if the item b...
Definition: Inventory.cpp:489
const cItem & GetArmorSlot(int a_ArmorSlotNum) const
Returns current item in a_ArmorSlotNum in armor slots.
Definition: Inventory.cpp:412
char AddItems(cItems &a_ItemStackList, bool a_AllowNewStacks)
Same as AddItem, but works on an entire list of item stacks.
Definition: Inventory.cpp:165
cItem * FindItem(const cItem &a_RecipeItem)
Finds an item based on ItemType and ItemDamage (<- defines the itemType, too)
Definition: Inventory.cpp:212
@ invNumSlots
Definition: Inventory.h:51
@ invArmorOffset
Definition: Inventory.h:47
@ invInventoryOffset
Definition: Inventory.h:48
@ invHotbarCount
Definition: Inventory.h:44
@ invShieldOffset
Definition: Inventory.h:50
@ invInventoryCount
Definition: Inventory.h:43
@ invHotbarOffset
Definition: Inventory.h:49
@ invArmorCount
Definition: Inventory.h:42
void SetEquippedSlotNum(int a_SlotNum)
Sets equiped item to the a_SlotNum slot number.
Definition: Inventory.cpp:472
void SaveToJson(Json::Value &a_Value)
Definition: Inventory.cpp:699
cItemGrid m_HotbarSlots
Definition: Inventory.h:200
void SendSlot(int a_SlotNum)
Sends the slot contents to the owner.
Definition: Inventory.cpp:560
void SetSlot(int a_SlotNum, const cItem &a_Item)
Puts a_Item item in a_SlotNum slot number.
Definition: Inventory.cpp:313
const cItem & GetSlot(int a_SlotNum) const
Returns current item in a_SlotNum slot.
Definition: Inventory.cpp:390
void SendEquippedSlot()
Sends the equipped item slot to the client.
Definition: Inventory.cpp:380
char ChangeSlotCount(int a_SlotNum, char a_AddToCount)
Adds (or subtracts, if a_AddToCount is negative) to the count of items in the specified slot.
Definition: Inventory.cpp:498
bool AddToBar(cItem &a_Item, const int a_Offset, const int a_Size, bool *a_bChangedSlots, int a_Mode=0)
void SetShieldSlot(const cItem &a_Item)
Sets current item in shield slot.
Definition: Inventory.cpp:362
int HowManyItems(const cItem &a_Item)
Returns the number of items of type a_Item that are stored.
Definition: Inventory.cpp:290
void SetInventorySlot(int a_InventorySlotNum, const cItem &a_Item)
Puts a_Item item in a_InventorySlotNum slot number in inventory slots.
Definition: Inventory.cpp:344
void Clear(void)
Removes all items from the entire inventory.
Definition: Inventory.cpp:40
int ReplaceOneEquippedItem(const cItem &a_Item, bool a_TryOtherSlots=true)
Removes one item from the the current equipped item stack, and attempts to add the specified item sta...
Definition: Inventory.cpp:247
bool DamageItem(int a_SlotNum, short a_Amount)
Adds the specified damage to the specified item; deletes the item and returns true if the item broke.
Definition: Inventory.cpp:514
const cItem & GetInventorySlot(int a_InventorySlotNum) const
Returns current item in a_ArmorSlotNum in inventory slots.
Definition: Inventory.cpp:426
void SetArmorSlot(int a_ArmorSlotNum, const cItem &a_Item)
Puts a_Item item in a_ArmorSlotNum slot number in armor slots.
Definition: Inventory.cpp:335
int GetEquippedSlotNum(void)
Returns slot number of equiped item.
Definition: Inventory.h:162
void SetHotbarSlot(int a_HotBarSlotNum, const cItem &a_Item)
Puts a_Item item in a_HotBarSlotNum slot number in hotbar slots.
Definition: Inventory.cpp:353
const cItemGrid * GetGridForSlotNum(int a_SlotNum, int &a_GridSlotNum) const
Returns the ItemGrid and the (grid-local) slot number for a (global) slot number; return nullptr for ...
Definition: Inventory.cpp:777
cPlayer & m_Owner
Definition: Inventory.h:205
bool RemoveOneEquippedItem(void)
Removes one item out of the currently equipped item stack, returns true if successful,...
Definition: Inventory.cpp:232
const cItem & GetEquippedItem(void) const
Returns current equiped item.
Definition: Inventory.cpp:463
int HowManyCanFit(const cItem &a_ItemStack, bool a_ConsiderEmptySlots=true)
Returns number of items out of a_ItemStack that can fit in the storage.
Definition: Inventory.cpp:52
int RemoveItem(const cItem &a_ItemStack)
Removes the specified item from the inventory, as many as possible, up to a_ItemStack....
Definition: Inventory.cpp:189
const cItem & GetShieldSlot() const
Returns current item in shield slot.
Definition: Inventory.cpp:454
void SetEquippedItem(const cItem &a_Item)
Sets current item in the equipped hotbar slot.
Definition: Inventory.cpp:371
Definition: Item.h:37
const cItemHandler & GetHandler(void) const
Returns the cItemHandler responsible for this item type.
Definition: Item.cpp:216
char m_ItemCount
Definition: Item.h:164
void GetJson(Json::Value &a_OutValue) const
Saves the item data into JSON representation.
Definition: Item.cpp:225
char GetMaxStackSize(void) const
Returns the maximum amount of stacked items of this type.
Definition: Item.cpp:207
bool IsEmpty(void) const
Returns true if the item represents an empty stack - either the type is invalid, or count is zero.
Definition: Item.h:69
bool IsEqual(const cItem &a_Item) const
Definition: Item.h:76
short m_ItemType
Definition: Item.h:163
short m_ItemDamage
Definition: Item.h:165
This class bridges a vector of cItem for safe access via Lua.
Definition: Item.h:215
char ChangeSlotCount(int a_SlotNum, char a_AddToCount)
Adds (or subtracts, if a_AddToCount is negative) to the count of items in the specified slot.
Definition: ItemGrid.cpp:468
void SetSlot(int a_X, int a_Y, const cItem &a_Item)
Definition: ItemGrid.cpp:121
cItem * FindItem(const cItem &a_RecipeItem)
Finds an item based on ItemType and ItemDamage (<- defines the itemType, too)
Definition: ItemGrid.cpp:443
const cItem & GetSlot(int a_X, int a_Y) const
Definition: ItemGrid.cpp:96
void Clear(void)
Sets all items as empty.
Definition: ItemGrid.cpp:228
void EmptySlot(int a_X, int a_Y)
Definition: ItemGrid.cpp:169
int GetNumSlots(void) const
Definition: ItemGrid.h:40
void AddListener(cListener &a_Listener)
Adds a callback that gets called whenever a slot changes.
Definition: ItemGrid.cpp:809
int HowManyItems(const cItem &a_Item)
Returns the number of items of type a_Item that are stored.
Definition: ItemGrid.cpp:563
char RemoveItem(const cItem &a_ItemStack)
Removes the specified item from the grid, as many as possible, up to a_ItemStack.m_ItemCount.
Definition: ItemGrid.cpp:405
bool DamageItem(int a_SlotNum, short a_Amount)
Adds the specified damage to the specified item; returns true if the item broke (but the item is left...
Definition: ItemGrid.cpp:723
char AddItem(cItem &a_ItemStack, bool a_AllowNewStacks=true, int a_PrioritySlot=-1)
Adds as many items out of a_ItemStack as can fit.
Definition: ItemGrid.cpp:313
void CopyToItems(cItems &a_Items) const
Copies the contents into a cItems object; preserves the original a_Items contents.
Definition: ItemGrid.cpp:703
virtual void OnUpdate(cWorld *a_World, cPlayer *a_Player, const cItem &a_Item) const
Called every tick while the item is on the player's inventory (used by maps, for example) - For now,...
Definition: ItemHandler.h:68
static bool CanPlaceArmorInSlot(int a_SlotNum, const cItem &a_Item)
Definition: SlotArea.cpp:2585
Definition: World.h:53
virtual void BroadcastEntityEquipment(const cEntity &a_Entity, short a_SlotNum, const cItem &a_Item, const cClientHandle *a_Exclude=nullptr) override