Cuberite
A lightweight, fast and extensible game server for Minecraft
SlotArea.cpp
Go to the documentation of this file.
1 
2 // SlotArea.cpp
3 
4 // Implements the cSlotArea class and its descendants
5 
6 #include "Globals.h"
7 #include "SlotArea.h"
8 #include "../Entities/Player.h"
9 #include "../BlockEntities/BeaconEntity.h"
10 #include "../BlockEntities/BrewingstandEntity.h"
11 #include "../BlockEntities/ChestEntity.h"
12 #include "../BlockEntities/DropSpenserEntity.h"
13 #include "../BlockEntities/EnderChestEntity.h"
14 #include "../BlockEntities/FurnaceEntity.h"
15 #include "../Entities/Minecart.h"
16 #include "../Items/ItemHandler.h"
17 #include "AnvilWindow.h"
18 #include "../CraftingRecipes.h"
19 #include "../Root.h"
20 #include "../FastRandom.h"
21 #include "../BlockArea.h"
22 #include "../EffectID.h"
23 #include "../ClientHandle.h"
24 #include "../Mobs/Horse.h"
25 
26 
27 
28 
29 
31 // cSlotArea:
32 
33 cSlotArea::cSlotArea(int a_NumSlots, cWindow & a_ParentWindow) :
34  m_NumSlots(a_NumSlots),
35  m_ParentWindow(a_ParentWindow)
36 {
37 }
38 
39 
40 
41 
42 
43 void cSlotArea::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem)
44 {
45  /*
46  LOGD("Slot area with %d slots clicked at slot number %d, clicked item %s, slot item %s",
47  GetNumSlots(), a_SlotNum,
48  ItemToFullString(a_ClickedItem).c_str(),
49  ItemToFullString(*GetSlot(a_SlotNum, a_Player)).c_str()
50  );
51  */
52 
53  ASSERT((a_SlotNum >= 0) && (a_SlotNum < GetNumSlots()));
54 
55  bool bAsync = false;
56  if (GetSlot(a_SlotNum, a_Player) == nullptr)
57  {
58  LOGWARNING("GetSlot(%d) returned nullptr! Ignoring click", a_SlotNum);
59  return;
60  }
61 
62  if (a_Player.IsGameModeSpectator())
63  {
64  // Block the action of the player and make sure, the inventory doesn't get out of sync
65  a_Player.GetClientHandle()->SendInventorySlot(-1, -1, cItem()); // Reset the dragged item
66  SetSlot(a_SlotNum, a_Player, *GetSlot(a_SlotNum, a_Player)); // Update the current slot
67  return;
68  }
69 
70  switch (a_ClickAction)
71  {
72  case caShiftLeftClick:
73  case caShiftRightClick:
74  {
75  ShiftClicked(a_Player, a_SlotNum, a_ClickedItem);
76  return;
77  }
78  case caDblClick:
79  {
80  DblClicked(a_Player, a_SlotNum);
81  return;
82  }
83  case caMiddleClick:
84  {
85  MiddleClicked(a_Player, a_SlotNum);
86  return;
87  }
88  case caDropKey:
89  case caCtrlDropKey:
90  {
91  DropClicked(a_Player, a_SlotNum, (a_ClickAction == caCtrlDropKey));
92  return;
93  }
94  case caNumber1:
95  case caNumber2:
96  case caNumber3:
97  case caNumber4:
98  case caNumber5:
99  case caNumber6:
100  case caNumber7:
101  case caNumber8:
102  case caNumber9:
103  {
104  NumberClicked(a_Player, a_SlotNum, a_ClickAction);
105  return;
106  }
107  default:
108  {
109  break;
110  }
111  }
112 
113  cItem Slot(*GetSlot(a_SlotNum, a_Player));
114  if (!Slot.IsSameType(a_ClickedItem))
115  {
116  LOGWARNING("*** Window lost sync at item %d in SlotArea with %d items ***", a_SlotNum, m_NumSlots);
117  LOGWARNING("My item: %s", ItemToFullString(Slot).c_str());
118  LOGWARNING("Their item: %s", ItemToFullString(a_ClickedItem).c_str());
119  bAsync = true;
120  }
121  cItem & DraggingItem = a_Player.GetDraggingItem();
122  switch (a_ClickAction)
123  {
124  case caRightClick:
125  {
126  if (DraggingItem.m_ItemType <= 0) // Empty-handed?
127  {
128  DraggingItem = Slot.CopyOne(); // Obtain copy of slot to preserve lore, enchantments, etc.
129 
130  DraggingItem.m_ItemCount = static_cast<char>(static_cast<float>(Slot.m_ItemCount) / 2.f + 0.5f);
131  Slot.m_ItemCount -= DraggingItem.m_ItemCount;
132 
133  if (Slot.m_ItemCount <= 0)
134  {
135  Slot.Empty();
136  }
137  }
138  else if ((Slot.m_ItemType <= 0) || DraggingItem.IsEqual(Slot))
139  {
140  // Drop one item in slot
141  if ((DraggingItem.m_ItemCount > 0) && (Slot.m_ItemCount < Slot.GetMaxStackSize()))
142  {
143  char OldSlotCount = Slot.m_ItemCount;
144 
145  Slot = DraggingItem.CopyOne(); // See above
146  OldSlotCount++;
147  Slot.m_ItemCount = OldSlotCount;
148 
149  DraggingItem.m_ItemCount--;
150  }
151  if (DraggingItem.m_ItemCount <= 0)
152  {
153  DraggingItem.Empty();
154  }
155  }
156  else if (!DraggingItem.IsEqual(Slot))
157  {
158  // Swap contents
159  cItem tmp(DraggingItem);
160  DraggingItem = Slot;
161  Slot = tmp;
162  }
163  break;
164  }
165 
166  case caLeftClick:
167  {
168  // Left-clicked
169  if (!DraggingItem.IsEqual(Slot))
170  {
171  // Switch contents
172  cItem tmp(DraggingItem);
173  DraggingItem = Slot;
174  Slot = tmp;
175  }
176  else
177  {
178  // Same type, add items:
179  int FreeSlots = DraggingItem.GetMaxStackSize() - Slot.m_ItemCount;
180  if (FreeSlots < 0)
181  {
182  ASSERT(!"Bad item stack size - where did we get more items in a slot than allowed?");
183  FreeSlots = 0;
184  }
185  char Filling = static_cast<char>((FreeSlots > DraggingItem.m_ItemCount) ? DraggingItem.m_ItemCount : FreeSlots);
186 
187  Slot.m_ItemCount += Filling;
188  DraggingItem.m_ItemCount -= Filling;
189  if (DraggingItem.m_ItemCount <= 0)
190  {
191  DraggingItem.Empty();
192  }
193  }
194  break;
195  }
196  default:
197  {
198  LOGWARNING("SlotArea: Unhandled click action: %d (%s)", a_ClickAction, ClickActionToString(a_ClickAction));
200  return;
201  }
202  } // switch (a_ClickAction
203 
204  SetSlot(a_SlotNum, a_Player, Slot);
205  if (bAsync)
206  {
208  }
209 }
210 
211 
212 
213 
214 
215 void cSlotArea::ShiftClicked(cPlayer & a_Player, int a_SlotNum, const cItem & a_ClickedItem)
216 {
217  // Make a copy of the slot, distribute it among the other areas, then update the slot to contain the leftover:
218  cItem Slot(*GetSlot(a_SlotNum, a_Player));
219  m_ParentWindow.DistributeStack(Slot, a_SlotNum, a_Player, this, true);
220  if (Slot.IsEmpty())
221  {
222  // Empty the slot completely, the client doesn't like left-over ItemType with zero count
223  Slot.Empty();
224  }
225  SetSlot(a_SlotNum, a_Player, Slot);
226 
227  // Some clients try to guess our actions and not always right (armor slots in 1.2.5), so we fix them:
229 }
230 
231 
232 
233 
234 
235 void cSlotArea::DblClicked(cPlayer & a_Player, int a_SlotNum)
236 {
237  cItem & Dragging = a_Player.GetDraggingItem();
238  if (Dragging.IsEmpty())
239  {
240  // Move the item in the dblclicked slot into hand:
241  Dragging = *GetSlot(a_SlotNum, a_Player);
242  cItem EmptyItem;
243  SetSlot(a_SlotNum, a_Player, EmptyItem);
244  }
245  if (Dragging.IsEmpty())
246  {
247  LOGD("%s DblClicked with an empty hand over empty slot, ignoring", a_Player.GetName().c_str());
248  return;
249  }
250 
251  // Add as many items from the surrounding area into hand as possible:
252  // First skip full stacks, then if there's still space, process full stacks as well:
253  if (!m_ParentWindow.CollectItemsToHand(Dragging, *this, a_Player, false))
254  {
255  m_ParentWindow.CollectItemsToHand(Dragging, *this, a_Player, true);
256  }
257 
258  m_ParentWindow.BroadcastWholeWindow(); // We need to broadcast, in case the window was a chest opened by multiple players
259 }
260 
261 
262 
263 
264 
265 void cSlotArea::MiddleClicked(cPlayer & a_Player, int a_SlotNum)
266 {
267  cItem Slot(*GetSlot(a_SlotNum, a_Player));
268  cItem & DraggingItem = a_Player.GetDraggingItem();
269 
270  if (!a_Player.IsGameModeCreative() || Slot.IsEmpty() || !DraggingItem.IsEmpty())
271  {
272  return;
273  }
274 
275  DraggingItem = Slot;
276  DraggingItem.m_ItemCount = DraggingItem.GetMaxStackSize();
277 }
278 
279 
280 
281 
282 
283 void cSlotArea::DropClicked(cPlayer & a_Player, int a_SlotNum, bool a_DropStack)
284 {
285  cItem Slot(*GetSlot(a_SlotNum, a_Player));
286  if (Slot.IsEmpty())
287  {
288  return;
289  }
290 
291  cItem ItemToDrop = Slot.CopyOne();
292  if (a_DropStack)
293  {
294  ItemToDrop.m_ItemCount = Slot.m_ItemCount;
295  }
296 
297  Slot.m_ItemCount -= ItemToDrop.m_ItemCount;
298  if (Slot.m_ItemCount <= 0)
299  {
300  Slot.Empty();
301  }
302  SetSlot(a_SlotNum, a_Player, Slot);
303 
304  a_Player.TossPickup(ItemToDrop);
305 }
306 
307 
308 
309 
310 
311 void cSlotArea::NumberClicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction)
312 {
313  if ((a_ClickAction < caNumber1) || (a_ClickAction > caNumber9))
314  {
315  return;
316  }
317 
318  int HotbarSlot = static_cast<int>(a_ClickAction - caNumber1);
319  cItem ItemInHotbar(a_Player.GetInventory().GetHotbarSlot(HotbarSlot));
320  cItem ItemInSlot(*GetSlot(a_SlotNum, a_Player));
321 
322  // The items are equal. Do nothing.
323  if (ItemInHotbar.IsEqual(ItemInSlot))
324  {
325  return;
326  }
327 
328  a_Player.GetInventory().SetHotbarSlot(HotbarSlot, ItemInSlot);
329  SetSlot(a_SlotNum, a_Player, ItemInHotbar);
330 }
331 
332 
333 
334 
335 
337 {
338  UNUSED(a_Player);
339 }
340 
341 
342 
343 
344 
346 {
347  UNUSED(a_Player);
348 }
349 
350 
351 
352 
353 
354 void cSlotArea::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots, bool a_BackFill)
355 {
356  for (int i = 0; i < m_NumSlots; i++)
357  {
358  int SlotNum = (a_BackFill) ? (m_NumSlots - 1 - i) : i;
359 
360  const cItem * Slot = GetSlot(SlotNum, a_Player);
361  if (!Slot->IsEqual(a_ItemStack) && (!Slot->IsEmpty() || a_KeepEmptySlots))
362  {
363  // Different items
364  continue;
365  }
366  char NumFit = Slot->GetMaxStackSize() - Slot->m_ItemCount;
367  if (NumFit <= 0)
368  {
369  // Full stack already
370  continue;
371  }
372  NumFit = std::min(NumFit, a_ItemStack.m_ItemCount);
373 
374  if (a_ShouldApply)
375  {
376  cItem NewSlot(a_ItemStack);
377  NewSlot.m_ItemCount = Slot->m_ItemCount + NumFit;
378  SetSlot(SlotNum, a_Player, NewSlot);
379  }
380  a_ItemStack.m_ItemCount -= NumFit;
381  if (a_ItemStack.IsEmpty())
382  {
383  return;
384  }
385  } // for i - Slots
386 }
387 
388 
389 
390 
391 
392 bool cSlotArea::CollectItemsToHand(cItem & a_Dragging, cPlayer & a_Player, bool a_CollectFullStacks)
393 {
394  int NumSlots = GetNumSlots();
395  for (int i = 0; i < NumSlots; i++)
396  {
397  const cItem & SlotItem = *GetSlot(i, a_Player);
398  if (!SlotItem.IsEqual(a_Dragging))
399  {
400  continue;
401  }
402  char ToMove = a_Dragging.GetMaxStackSize() - a_Dragging.m_ItemCount;
403  if (ToMove > SlotItem.m_ItemCount)
404  {
405  ToMove = SlotItem.m_ItemCount;
406  }
407  a_Dragging.m_ItemCount += ToMove;
408  cItem NewSlot(SlotItem);
409  NewSlot.m_ItemCount -= ToMove;
410  SetSlot(i, a_Player, NewSlot);
411  if (!NewSlot.IsEmpty())
412  {
413  // There are leftovers in the slot, so a_Dragging must be full
414  return true;
415  }
416  } // for i - Slots[]
417  // a_Dragging may be full if there were exactly the number of items needed to fill it
418  return a_Dragging.IsFullStack();
419 }
420 
421 
422 
423 
424 
426 // cSlotAreaChest:
427 
429  cSlotArea(27, a_ParentWindow),
430  m_Chest(a_Chest)
431 {
432 }
433 
434 
435 
436 
437 
438 const cItem * cSlotAreaChest::GetSlot(int a_SlotNum, cPlayer & a_Player) const
439 {
440  // a_SlotNum ranges from 0 to 26, use that to index the chest entity's inventory directly:
441  return &(m_Chest->GetSlot(a_SlotNum));
442 }
443 
444 
445 
446 
447 
448 void cSlotAreaChest::SetSlot(int a_SlotNum, cPlayer & a_Player, const cItem & a_Item)
449 {
450  m_Chest->SetSlot(a_SlotNum, a_Item);
451 }
452 
453 
454 
455 
456 
458 // cSlotAreaDoubleChest:
459 
460 cSlotAreaDoubleChest::cSlotAreaDoubleChest(cChestEntity * a_TopChest, cChestEntity * a_BottomChest, cWindow & a_ParentWindow) :
461  cSlotArea(54, a_ParentWindow),
462  m_TopChest(a_TopChest),
463  m_BottomChest(a_BottomChest)
464 {
465 }
466 
467 
468 
469 
470 
471 const cItem * cSlotAreaDoubleChest::GetSlot(int a_SlotNum, cPlayer & a_Player) const
472 {
473  // a_SlotNum ranges from 0 to 53, use that to index the correct chest's inventory:
474  if (a_SlotNum < 27)
475  {
476  return &(m_TopChest->GetSlot(a_SlotNum));
477  }
478  else
479  {
480  return &(m_BottomChest->GetSlot(a_SlotNum - 27));
481  }
482 }
483 
484 
485 
486 
487 
488 void cSlotAreaDoubleChest::SetSlot(int a_SlotNum, cPlayer & a_Player, const cItem & a_Item)
489 {
490  if (a_SlotNum < 27)
491  {
492  m_TopChest->SetSlot(a_SlotNum, a_Item);
493  }
494  else
495  {
496  m_BottomChest->SetSlot(a_SlotNum - 27, a_Item);
497  }
498 }
499 
500 
501 
502 
503 
505 // cSlotAreaCrafting:
506 
507 cSlotAreaCrafting::cSlotAreaCrafting(int a_GridSize, cWindow & a_ParentWindow) :
508  cSlotAreaTemporary(1 + a_GridSize * a_GridSize, a_ParentWindow),
509  m_GridSize(a_GridSize)
510 {
511  ASSERT((a_GridSize == 2) || (a_GridSize == 3));
512 }
513 
514 
515 
516 
517 
518 void cSlotAreaCrafting::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem)
519 {
520  if (a_ClickAction == caMiddleClick)
521  {
522  MiddleClicked(a_Player, a_SlotNum);
523  return;
524  }
525 
526  // Override for craft result slot
527  if (a_SlotNum == 0)
528  {
529  if ((a_ClickAction == caShiftLeftClick) || (a_ClickAction == caShiftRightClick))
530  {
531  ShiftClickedResult(a_Player);
532  }
533  else if ((a_ClickAction == caDropKey) || (a_ClickAction == caCtrlDropKey))
534  {
535  DropClickedResult(a_Player);
536  }
537  else
538  {
539  ClickedResult(a_Player);
540  }
541  return;
542  }
543 
544  Super::Clicked(a_Player, a_SlotNum, a_ClickAction, a_ClickedItem);
545  UpdateRecipe(a_Player);
546 }
547 
548 
549 
550 
551 
552 void cSlotAreaCrafting::DblClicked(cPlayer & a_Player, int a_SlotNum)
553 {
554  if (a_SlotNum == 0)
555  {
556  // Dbl-clicking the crafting result slot shouldn't collect items to hand
557  return;
558  }
559  Super::DblClicked(a_Player, a_SlotNum);
560 }
561 
562 
563 
564 
565 
567 {
568  // Toss all items on the crafting grid:
569  TossItems(a_Player, 1, m_NumSlots);
570 
571  // Remove the current recipe from the player -> recipe map:
572  for (cRecipeMap::iterator itr = m_Recipes.begin(), end = m_Recipes.end(); itr != end; ++itr)
573  {
574  if (itr->first == a_Player.GetUniqueID())
575  {
576  // Remove the player from the recipe map:
577  m_Recipes.erase(itr);
578  return;
579  }
580  } // for itr - m_Recipes[]
581  // Player not found - that is acceptable
582 }
583 
584 
585 
586 
587 
588 void cSlotAreaCrafting::SetSlot(int a_SlotNum, cPlayer & a_Player, const cItem & a_Item)
589 {
590  // Update the recipe after setting the slot, if the slot is not the result slot:
591  Super::SetSlot(a_SlotNum, a_Player, a_Item);
592  if (a_SlotNum != 0)
593  {
594  UpdateRecipe(a_Player);
595  }
596 }
597 
598 
599 
600 
601 
602 void cSlotAreaCrafting::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots, bool a_BackFill)
603 {
604  UNUSED(a_ItemStack);
605  UNUSED(a_Player);
606  UNUSED(a_ShouldApply);
607  UNUSED(a_KeepEmptySlots);
608  UNUSED(a_BackFill);
609 }
610 
611 
612 
613 
614 
616 {
617  cItem & DraggingItem = a_Player.GetDraggingItem();
618 
619  // Get the current recipe:
620  cCraftingRecipe & Recipe = GetRecipeForPlayer(a_Player);
621  const cItem & Result = Recipe.GetResult();
622 
623  cItem * PlayerSlots = GetPlayerSlots(a_Player) + 1;
624  cCraftingGrid Grid(PlayerSlots, m_GridSize, m_GridSize);
625 
626  // If possible, craft:
627  if (DraggingItem.IsEmpty())
628  {
629  DraggingItem = Result;
630  Recipe.ConsumeIngredients(Grid);
631  Grid.CopyToItems(PlayerSlots);
632 
633  HandleCraftItem(Result, a_Player);
634  }
635  else if (DraggingItem.IsEqual(Result))
636  {
637  if (DraggingItem.m_ItemCount + Result.m_ItemCount <= Result.GetMaxStackSize())
638  {
639  DraggingItem.m_ItemCount += Result.m_ItemCount;
640  Recipe.ConsumeIngredients(Grid);
641  Grid.CopyToItems(PlayerSlots);
642 
643  HandleCraftItem(Result, a_Player);
644  }
645  }
646 
647  // Get the new recipe and update the result slot:
648  UpdateRecipe(a_Player);
649 
650  // We're done. Send all changes to the client and bail out:
652 }
653 
654 
655 
656 
657 
659 {
660  cItem Result(*GetSlot(0, a_Player));
661  if (Result.IsEmpty())
662  {
663  return;
664  }
665  a_Player.AddKnownItem(Result);
666  cItem * PlayerSlots = GetPlayerSlots(a_Player) + 1;
667  for (;;)
668  {
669  // Try distributing the result. If it fails, bail out:
670  cItem ResultCopy(Result);
671  m_ParentWindow.DistributeStack(ResultCopy, 0, a_Player, this, false);
672  if (!ResultCopy.IsEmpty())
673  {
674  // Couldn't distribute all of it. Bail out
675  return;
676  }
677 
678  // Distribute the result, this time for real:
679  ResultCopy = Result;
680  m_ParentWindow.DistributeStack(ResultCopy, 0, a_Player, this, true);
681 
682  // Remove the ingredients from the crafting grid and update the recipe:
683  cCraftingRecipe & Recipe = GetRecipeForPlayer(a_Player);
684  cCraftingGrid Grid(PlayerSlots, m_GridSize, m_GridSize);
685  Recipe.ConsumeIngredients(Grid);
686  Grid.CopyToItems(PlayerSlots);
687  UpdateRecipe(a_Player);
688 
689  // Broadcast the window, we sometimes move items to different locations than Vanilla, causing needless desyncs:
691 
692  // Added achievements processing
693  HandleCraftItem(Result, a_Player);
694 
695  // If the recipe has changed, bail out:
696  if (!Recipe.GetResult().IsEqual(Result))
697  {
698  return;
699  }
700  }
701 }
702 
703 
704 
705 
706 
708 {
709  // Get the current recipe:
710  cCraftingRecipe & Recipe = GetRecipeForPlayer(a_Player);
711  const cItem & Result = Recipe.GetResult();
712 
713  cItem * PlayerSlots = GetPlayerSlots(a_Player) + 1;
714  cCraftingGrid Grid(PlayerSlots, m_GridSize, m_GridSize);
715 
716  a_Player.TossPickup(Result);
717  Recipe.ConsumeIngredients(Grid);
718  Grid.CopyToItems(PlayerSlots);
719 
720  HandleCraftItem(Result, a_Player);
721  UpdateRecipe(a_Player);
722 }
723 
724 
725 
726 
727 
729 {
730  cCraftingGrid Grid(GetPlayerSlots(a_Player) + 1, m_GridSize, m_GridSize);
731  cCraftingRecipe & Recipe = GetRecipeForPlayer(a_Player);
732  cRoot::Get()->GetCraftingRecipes()->GetRecipe(a_Player, Grid, Recipe);
733  SetSlot(0, a_Player, Recipe.GetResult());
734 }
735 
736 
737 
738 
739 
741 {
742  for (cRecipeMap::iterator itr = m_Recipes.begin(), end = m_Recipes.end(); itr != end; ++itr)
743  {
744  if (itr->first == a_Player.GetUniqueID())
745  {
746  return itr->second;
747  }
748  } // for itr - m_Recipes[]
749 
750  // Not found. Add a new one:
751  cCraftingGrid Grid(GetPlayerSlots(a_Player) + 1, m_GridSize, m_GridSize);
752  cCraftingRecipe Recipe(Grid);
753  cRoot::Get()->GetCraftingRecipes()->GetRecipe(a_Player, Grid, Recipe);
754  m_Recipes.emplace_back(a_Player.GetUniqueID(), Recipe);
755  return m_Recipes.back().second;
756 }
757 
758 
759 
760 
761 
762 void cSlotAreaCrafting::HandleCraftItem(const cItem & a_Result, cPlayer & a_Player)
763 {
764  switch (a_Result.m_ItemType)
765  {
776  default: break;
777  }
778 }
779 
780 
781 
782 
783 
784 void cSlotAreaCrafting::LoadRecipe(cPlayer & a_Player, UInt32 a_RecipeId)
785 {
786  if (a_RecipeId == 0)
787  {
788  return;
789  }
790  auto Recipe = cRoot::Get()->GetCraftingRecipes()->GetRecipeById(a_RecipeId);
791 
792  int NumItems = 0;
793  ClearCraftingGrid(a_Player);
794 
795  for (auto itrS = Recipe->m_Ingredients.begin(); itrS != Recipe->m_Ingredients.end(); ++itrS)
796  {
797  cItem * FoundItem = a_Player.GetInventory().FindItem(itrS->m_Item);
798  if (FoundItem == nullptr)
799  {
800  ClearCraftingGrid(a_Player);
801  break;
802  }
803  cItem Item = FoundItem->CopyOne();
804  ++NumItems;
805  int pos = 1 + itrS->x + m_GridSize * itrS->y;
806  // Assuming there are ether shaped or unshaped recipes, no mixed ones
807  if ((itrS->x == -1) && (itrS->y == -1))
808  {
809  pos = NumItems;
810  }
811  // Handle x wildcard
812  else if (itrS->x == -1)
813  {
814  for (int i = 0; i < m_GridSize; i++)
815  {
816  pos = 1 + i + m_GridSize * itrS->y;
817  auto itemCheck = GetSlot(pos, a_Player);
818  if (itemCheck->IsEmpty())
819  {
820  break;
821  }
822  }
823  }
824  SetSlot(pos, a_Player, Item);
825  a_Player.GetInventory().RemoveItem(Item);
826  }
827 }
828 
829 
830 
831 
832 
834 {
835  for (int pos = 1; pos <= m_GridSize * m_GridSize; pos++)
836  {
837  auto Item = GetSlot(pos, a_Player);
838  if (Item->m_ItemCount > 0)
839  {
840  a_Player.GetInventory().AddItem(*Item);
841  SetSlot(pos, a_Player, cItem());
842  }
843  }
844 }
845 
846 
847 
849 // cSlotAreaAnvil:
850 
852  cSlotAreaTemporary(3, a_ParentWindow),
853  m_MaximumCost(0),
854  m_StackSizeToBeUsedInRepair(0)
855 {
856 }
857 
858 
859 
860 
861 
862 void cSlotAreaAnvil::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem)
863 {
864  ASSERT((a_SlotNum >= 0) && (a_SlotNum < GetNumSlots()));
865  if (a_SlotNum != 2)
866  {
867  Super::Clicked(a_Player, a_SlotNum, a_ClickAction, a_ClickedItem);
868  UpdateResult(a_Player);
869  return;
870  }
871 
872  bool bAsync = false;
873  if (GetSlot(a_SlotNum, a_Player) == nullptr)
874  {
875  LOGWARNING("GetSlot(%d) returned nullptr! Ignoring click", a_SlotNum);
876  return;
877  }
878 
879  switch (a_ClickAction)
880  {
881  case caDblClick:
882  {
883  return;
884  }
885  case caShiftLeftClick:
886  case caShiftRightClick:
887  {
888  ShiftClicked(a_Player, a_SlotNum, a_ClickedItem);
889  return;
890  }
891  case caMiddleClick:
892  {
893  MiddleClicked(a_Player, a_SlotNum);
894  return;
895  }
896  case caDropKey:
897  case caCtrlDropKey:
898  {
899  if (CanTakeResultItem(a_Player))
900  {
901  DropClicked(a_Player, a_SlotNum, true);
902  OnTakeResult(a_Player);
903  }
904  return;
905  }
906  default:
907  {
908  break;
909  }
910  }
911 
912  cItem Slot(*GetSlot(a_SlotNum, a_Player));
913  if (!Slot.IsSameType(a_ClickedItem))
914  {
915  LOGWARNING("*** Window lost sync at item %d in SlotArea with %d items ***", a_SlotNum, m_NumSlots);
916  LOGWARNING("My item: %s", ItemToFullString(Slot).c_str());
917  LOGWARNING("Their item: %s", ItemToFullString(a_ClickedItem).c_str());
918  bAsync = true;
919  }
920  cItem & DraggingItem = a_Player.GetDraggingItem();
921 
922  if (Slot.IsEmpty())
923  {
924  return;
925  }
926  if (!DraggingItem.IsEmpty())
927  {
928  if (!(DraggingItem.IsEqual(Slot) && ((DraggingItem.m_ItemCount + Slot.m_ItemCount) <= Slot.GetMaxStackSize())))
929  {
930  return;
931  }
932  }
933 
934  if (!CanTakeResultItem(a_Player))
935  {
936  return;
937  }
938 
939  cItem NewItem = cItem(Slot);
940  NewItem.m_ItemCount += DraggingItem.m_ItemCount;
941 
942  Slot.Empty();
943  DraggingItem.Empty();
944  SetSlot(a_SlotNum, a_Player, Slot);
945 
946  DraggingItem = NewItem;
947  OnTakeResult(a_Player);
948 
949  if (bAsync)
950  {
952  }
953 }
954 
955 
956 
957 
958 
959 void cSlotAreaAnvil::ShiftClicked(cPlayer & a_Player, int a_SlotNum, const cItem & a_ClickedItem)
960 {
961  if (a_SlotNum != 2)
962  {
963  Super::ShiftClicked(a_Player, a_SlotNum, a_ClickedItem);
964  UpdateResult(a_Player);
965  return;
966  }
967 
968  // Make a copy of the slot, distribute it among the other areas, then update the slot to contain the leftover:
969  cItem Slot(*GetSlot(a_SlotNum, a_Player));
970 
971  if (Slot.IsEmpty() || !CanTakeResultItem(a_Player))
972  {
973  return;
974  }
975 
976  m_ParentWindow.DistributeStack(Slot, a_SlotNum, a_Player, this, true);
977  if (Slot.IsEmpty())
978  {
979  Slot.Empty();
980  OnTakeResult(a_Player);
981  }
982  SetSlot(a_SlotNum, a_Player, Slot);
983 
984  // Some clients try to guess our actions and not always right (armor slots in 1.2.5), so we fix them:
986 }
987 
988 
989 
990 
991 
992 void cSlotAreaAnvil::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots, bool a_BackFill)
993 {
994  for (int i = 0; i < 2; i++)
995  {
996  int SlotNum = (a_BackFill) ? (2 - 1 - i) : i;
997 
998  const cItem * Slot = GetSlot(SlotNum, a_Player);
999  if (!Slot->IsEqual(a_ItemStack) && (!Slot->IsEmpty() || a_KeepEmptySlots))
1000  {
1001  // Different items
1002  continue;
1003  }
1004  char NumFit = Slot->GetMaxStackSize() - Slot->m_ItemCount;
1005  if (NumFit <= 0)
1006  {
1007  // Full stack already
1008  continue;
1009  }
1010  NumFit = std::min(NumFit, a_ItemStack.m_ItemCount);
1011 
1012  if (a_ShouldApply)
1013  {
1014  cItem NewSlot(a_ItemStack);
1015  NewSlot.m_ItemCount = Slot->m_ItemCount + NumFit;
1016  SetSlot(SlotNum, a_Player, NewSlot);
1017  }
1018  a_ItemStack.m_ItemCount -= NumFit;
1019  if (a_ItemStack.IsEmpty())
1020  {
1021  UpdateResult(a_Player);
1022  return;
1023  }
1024  } // for i - Slots
1025  UpdateResult(a_Player);
1026 }
1027 
1028 
1029 
1030 
1031 
1033 {
1034  if (!a_Player.IsGameModeCreative())
1035  {
1037  }
1038  SetSlot(0, a_Player, cItem());
1039 
1041  {
1042  const cItem * Item = GetSlot(1, a_Player);
1043  if (!Item->IsEmpty() && (Item->m_ItemCount > m_StackSizeToBeUsedInRepair))
1044  {
1045  cItem NewSecondItem(*Item);
1046  NewSecondItem.m_ItemCount -= m_StackSizeToBeUsedInRepair;
1048  SetSlot(1, a_Player, NewSecondItem);
1049  }
1050  else
1051  {
1052  SetSlot(1, a_Player, cItem());
1053  }
1054  }
1055  else
1056  {
1057  SetSlot(1, a_Player, cItem());
1058  }
1059  m_ParentWindow.SetProperty(0, static_cast<short>(m_MaximumCost));
1060 
1061  m_MaximumCost = 0;
1062  static_cast<cAnvilWindow &>(m_ParentWindow).SetRepairedItemName("", nullptr);
1063 
1064  const Vector3i BlockPos = static_cast<cAnvilWindow &>(m_ParentWindow).GetBlockPos();
1065 
1066  BLOCKTYPE Block;
1067  NIBBLETYPE BlockMeta;
1068  a_Player.GetWorld()->GetBlockTypeMeta(BlockPos, Block, BlockMeta);
1069 
1070  if (!a_Player.IsGameModeCreative() && (Block == E_BLOCK_ANVIL) && GetRandomProvider().RandBool(0.12))
1071  {
1072  NIBBLETYPE Orientation = BlockMeta & 0x3;
1073  NIBBLETYPE AnvilDamage = BlockMeta >> 2;
1074  ++AnvilDamage;
1075 
1076  if (AnvilDamage > 2)
1077  {
1078  // Anvil will break
1079  a_Player.GetWorld()->SetBlock(BlockPos, E_BLOCK_AIR, 0);
1081  a_Player.CloseWindow(false);
1082  }
1083  else
1084  {
1085  a_Player.GetWorld()->SetBlockMeta(BlockPos, static_cast<NIBBLETYPE>(Orientation | (AnvilDamage << 2)));
1087  }
1088  }
1089  else
1090  {
1092  }
1093 }
1094 
1095 
1096 
1097 
1098 
1100 {
1101  return (
1102  (
1103  a_Player.IsGameModeCreative() || // Is the player in gamemode?
1104  (a_Player.GetXpLevel() >= m_MaximumCost) // or the player have enough exp?
1105  ) &&
1106  (!GetSlot(2, a_Player)->IsEmpty()) && // Is a item in the result slot?
1107  (m_MaximumCost > 0) // When no maximum cost is set, the item isn't set from the UpdateResult() method and can't be a valid enchanting result.
1108  );
1109 }
1110 
1111 
1112 
1113 
1114 
1116 {
1117  TossItems(a_Player, 0, 2);
1118  Super::OnPlayerRemoved(a_Player);
1119 }
1120 
1121 
1122 
1123 
1124 
1126 {
1127  const cItem Target(*GetSlot(0, a_Player));
1128  const cItem Sacrifice(*GetSlot(1, a_Player));
1129 
1130  // Output initialised as copy of target.
1131  cItem Output(Target);
1132 
1133  if (Target.IsEmpty())
1134  {
1135  Output.Empty();
1136  SetSlot(2, a_Player, Output);
1138  m_MaximumCost = 0;
1139  return;
1140  }
1141 
1142  m_MaximumCost = 0;
1144  int RepairCost = Target.m_RepairCost;
1145  int NeedExp = 0;
1146  if (!Sacrifice.IsEmpty())
1147  {
1148  RepairCost += Sacrifice.m_RepairCost;
1149 
1150  // Can we repair with sacrifce material?
1151  if (Target.IsDamageable() && Target.GetHandler().CanRepairWithRawMaterial(Sacrifice.m_ItemType))
1152  {
1153  // Tool and armor repair with special item (iron / gold / diamond / ...)
1154  int DamageDiff = std::min(static_cast<int>(Target.m_ItemDamage), static_cast<int>(Target.GetMaxDamage()) / 4);
1155  if (DamageDiff <= 0)
1156  {
1157  // No enchantment
1158  Output.Empty();
1159  SetSlot(2, a_Player, Output);
1161  m_MaximumCost = 0;
1162  return;
1163  }
1164 
1165  char NumItemsConsumed = 0;
1166 
1167  // Repair until out of materials, or fully repaired:
1168  while ((DamageDiff > 0) && (NumItemsConsumed < Sacrifice.m_ItemCount))
1169  {
1170  Output.m_ItemDamage -= static_cast<char>(DamageDiff);
1171  NeedExp += std::max(1, DamageDiff / 100) + static_cast<int>(Target.m_Enchantments.Count());
1172  DamageDiff = std::min(static_cast<int>(Output.m_ItemDamage), static_cast<int>(Target.GetMaxDamage()) / 4);
1173 
1174  ++NumItemsConsumed;
1175  }
1176  m_StackSizeToBeUsedInRepair = NumItemsConsumed;
1177  }
1178  else // Combining tools / armour
1179  {
1180  const bool IsEnchantBook = (Sacrifice.m_ItemType == E_ITEM_ENCHANTED_BOOK);
1181 
1182  // No result if we can't combine the items
1183  if (!IsEnchantBook && (!Target.IsSameType(Sacrifice) || !Target.IsDamageable()))
1184  {
1185  // No enchantment
1186  Output.Empty();
1187  SetSlot(2, a_Player, Output);
1189  m_MaximumCost = 0;
1190  return;
1191  }
1192 
1193  // Can we repair with sacrifice tool / armour?
1194  if (Target.IsDamageable() && !IsEnchantBook && (Target.m_ItemDamage!=0))
1195  {
1196  // Durability = MaxDamage - m_ItemDamage = how far from broken
1197  const short TargetDurability = Target.GetMaxDamage() - Target.m_ItemDamage;
1198  const short SacrificeDurability = Sacrifice.GetMaxDamage() - Sacrifice.m_ItemDamage;
1199 
1200  // How much durability to repair by.
1201  const short RepairDurability = SacrificeDurability + Target.GetMaxDamage() * 12 / 100;
1202 
1203  // Don't give item a negative damage:
1204  short NewItemDamage = std::max<short>(Target.GetMaxDamage() - (TargetDurability + RepairDurability), 0);
1205 
1206  if (NewItemDamage < Target.m_ItemDamage)
1207  {
1208  Output.m_ItemDamage = NewItemDamage;
1209  NeedExp += std::max(1, RepairDurability / 100);
1210  }
1211  }
1212 
1213  // Add the enchantments from the sacrifice to the target
1214  int EnchantmentCost = Output.AddEnchantmentsFromItem(Sacrifice);
1215  NeedExp += EnchantmentCost;
1216  }
1217  }
1218 
1219  int NameChangeExp = 0;
1220  const AString & RepairedItemName = static_cast<cAnvilWindow*>(&m_ParentWindow)->GetRepairedItemName();
1221  if (RepairedItemName.empty())
1222  {
1223  // Remove custom name
1224  if (!Target.m_CustomName.empty())
1225  {
1226  NameChangeExp = (Target.IsDamageable()) ? 7 : (Target.m_ItemCount * 5);
1227  NeedExp += NameChangeExp;
1228  Output.m_CustomName = "";
1229  }
1230  }
1231  else if (RepairedItemName != Target.m_CustomName)
1232  {
1233  // Change custom name
1234  NameChangeExp = (Target.IsDamageable()) ? 7 : (Target.m_ItemCount * 5);
1235  NeedExp += NameChangeExp;
1236 
1237  if (!Target.m_CustomName.empty())
1238  {
1239  RepairCost += NameChangeExp / 2;
1240  }
1241 
1242  Output.m_CustomName = RepairedItemName;
1243  }
1244 
1245  m_MaximumCost = RepairCost + NeedExp;
1246 
1247  if (NeedExp < 0)
1248  {
1249  Output.Empty();
1250  }
1251 
1252  if ((NameChangeExp == NeedExp) && (NameChangeExp > 0) && (m_MaximumCost >= 40))
1253  {
1254  m_MaximumCost = 39;
1255  }
1256  if ((m_MaximumCost >= 40) && !a_Player.IsGameModeCreative())
1257  {
1258  Output.Empty();
1259  }
1260 
1261  if (!Output.IsEmpty())
1262  {
1263  RepairCost = std::max(Target.m_RepairCost, Sacrifice.m_RepairCost);
1264  if (!Output.m_CustomName.empty())
1265  {
1266  RepairCost -= 9;
1267  }
1268  RepairCost = std::max(RepairCost, 0);
1269  RepairCost += 2;
1270  Output.m_RepairCost = RepairCost;
1271  }
1272 
1273  // If after everything, output will be the same then no point enchanting:
1274  if (Target.IsEqual(Output))
1275  {
1276  Output.Empty();
1277  m_MaximumCost = 0;
1278  }
1279 
1280  SetSlot(2, a_Player, Output);
1281  m_ParentWindow.SetProperty(0, static_cast<Int16>(m_MaximumCost));
1282 }
1283 
1284 
1285 
1286 
1287 
1289 // cSlotAreaBeacon:
1290 
1292  cSlotArea(1, a_ParentWindow),
1293  m_Beacon(a_Beacon)
1294 {
1295  m_Beacon->GetContents().AddListener(*this);
1296 }
1297 
1298 
1299 
1300 
1301 
1303 {
1305 }
1306 
1307 
1308 
1309 
1310 
1311 bool cSlotAreaBeacon::IsPlaceableItem(short a_ItemType)
1312 {
1313  switch (a_ItemType)
1314  {
1315  case E_ITEM_EMERALD:
1316  case E_ITEM_DIAMOND:
1317  case E_ITEM_GOLD:
1318  case E_ITEM_IRON:
1319  {
1320  return true;
1321  }
1322  default:
1323  {
1324  return false;
1325  }
1326  }
1327 }
1328 
1329 
1330 
1331 
1332 
1333 void cSlotAreaBeacon::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem)
1334 {
1335  ASSERT((a_SlotNum >= 0) && (a_SlotNum < GetNumSlots()));
1336 
1337  bool bAsync = false;
1338  if (GetSlot(a_SlotNum, a_Player) == nullptr)
1339  {
1340  LOGWARNING("GetSlot(%d) returned nullptr! Ignoring click", a_SlotNum);
1341  return;
1342  }
1343 
1344  switch (a_ClickAction)
1345  {
1346  case caShiftLeftClick:
1347  case caShiftRightClick:
1348  {
1349  ShiftClicked(a_Player, a_SlotNum, a_ClickedItem);
1350  return;
1351  }
1352  case caMiddleClick:
1353  {
1354  MiddleClicked(a_Player, a_SlotNum);
1355  return;
1356  }
1357  case caDropKey:
1358  case caCtrlDropKey:
1359  {
1360  DropClicked(a_Player, a_SlotNum, false);
1361  return;
1362  }
1363  case caNumber1:
1364  case caNumber2:
1365  case caNumber3:
1366  case caNumber4:
1367  case caNumber5:
1368  case caNumber6:
1369  case caNumber7:
1370  case caNumber8:
1371  case caNumber9:
1372  {
1373  NumberClicked(a_Player, a_SlotNum, a_ClickAction);
1374  return;
1375  }
1376  default:
1377  {
1378  break;
1379  }
1380  }
1381 
1382  cItem Slot(*GetSlot(a_SlotNum, a_Player));
1383  if (!Slot.IsSameType(a_ClickedItem))
1384  {
1385  LOGWARNING("*** Window lost sync at item %d in SlotArea with %d items ***", a_SlotNum, m_NumSlots);
1386  LOGWARNING("My item: %s", ItemToFullString(Slot).c_str());
1387  LOGWARNING("Their item: %s", ItemToFullString(a_ClickedItem).c_str());
1388  bAsync = true;
1389  }
1390  cItem & DraggingItem = a_Player.GetDraggingItem();
1391 
1392  if (DraggingItem.IsEmpty())
1393  {
1394  DraggingItem = Slot;
1395  Slot.Empty();
1396  }
1397  else if (Slot.IsEmpty())
1398  {
1399  if (!IsPlaceableItem(DraggingItem.m_ItemType))
1400  {
1401  return;
1402  }
1403 
1404  Slot = DraggingItem.CopyOne();
1405  DraggingItem.m_ItemCount -= 1;
1406  if (DraggingItem.m_ItemCount <= 0)
1407  {
1408  DraggingItem.Empty();
1409  }
1410  }
1411  else if (DraggingItem.m_ItemCount == 1)
1412  {
1413  if (!IsPlaceableItem(DraggingItem.m_ItemCount))
1414  {
1415  return;
1416  }
1417 
1418  // Switch contents
1419  cItem tmp(DraggingItem);
1420  DraggingItem = Slot;
1421  Slot = tmp;
1422  }
1423 
1424  SetSlot(a_SlotNum, a_Player, Slot);
1425  if (bAsync)
1426  {
1428  }
1429 }
1430 
1431 
1432 
1433 
1434 
1435 void cSlotAreaBeacon::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots, bool a_BackFill)
1436 {
1437  const cItem * Slot = GetSlot(0, a_Player);
1438  if (!Slot->IsEmpty() || !IsPlaceableItem(a_ItemStack.m_ItemType) || (a_ItemStack.m_ItemCount != 1))
1439  {
1440  return;
1441  }
1442 
1443  if (a_ShouldApply)
1444  {
1445  SetSlot(0, a_Player, a_ItemStack.CopyOne());
1446  }
1447  a_ItemStack.Empty();
1448 }
1449 
1450 
1451 
1452 
1453 
1454 const cItem * cSlotAreaBeacon::GetSlot(int a_SlotNum, cPlayer & a_Player) const
1455 {
1456  UNUSED(a_Player);
1457  return &(m_Beacon->GetSlot(a_SlotNum));
1458 }
1459 
1460 
1461 
1462 
1463 
1464 void cSlotAreaBeacon::SetSlot(int a_SlotNum, cPlayer & a_Player, const cItem & a_Item)
1465 {
1466  UNUSED(a_Player);
1467  m_Beacon->SetSlot(a_SlotNum, a_Item);
1468 }
1469 
1470 
1471 
1472 
1473 
1474 void cSlotAreaBeacon::OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum)
1475 {
1476  UNUSED(a_SlotNum);
1477  // Something has changed in the window, broadcast the entire window to all clients
1478  ASSERT(a_ItemGrid == &(m_Beacon->GetContents()));
1479 
1481 }
1482 
1483 
1484 
1485 
1486 
1488 // cSlotAreaEnchanting:
1489 
1491  cSlotAreaTemporary(2, a_ParentWindow),
1492  m_BlockPos(a_BlockPos)
1493 {
1494 }
1495 
1496 
1497 
1498 
1499 
1500 void cSlotAreaEnchanting::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem)
1501 {
1502  ASSERT((a_SlotNum >= 0) && (a_SlotNum < GetNumSlots()));
1503 
1504  bool bAsync = false;
1505  if (GetSlot(a_SlotNum, a_Player) == nullptr)
1506  {
1507  LOGWARNING("GetSlot(%d) returned nullptr! Ignoring click", a_SlotNum);
1508  return;
1509  }
1510 
1511  switch (a_ClickAction)
1512  {
1513  case caShiftLeftClick:
1514  case caShiftRightClick:
1515  {
1516  ShiftClicked(a_Player, a_SlotNum, a_ClickedItem);
1517  return;
1518  }
1519  case caDblClick:
1520  {
1521  DblClicked(a_Player, a_SlotNum);
1522  return;
1523  }
1524  case caMiddleClick:
1525  {
1526  MiddleClicked(a_Player, a_SlotNum);
1527  return;
1528  }
1529  case caDropKey:
1530  case caCtrlDropKey:
1531  {
1532  DropClicked(a_Player, a_SlotNum, false);
1533  return;
1534  }
1535  case caNumber1:
1536  case caNumber2:
1537  case caNumber3:
1538  case caNumber4:
1539  case caNumber5:
1540  case caNumber6:
1541  case caNumber7:
1542  case caNumber8:
1543  case caNumber9:
1544  {
1545  NumberClicked(a_Player, a_SlotNum, a_ClickAction);
1546  return;
1547  }
1548  default:
1549  {
1550  break;
1551  }
1552  }
1553 
1554  cItem Slot(*GetSlot(a_SlotNum, a_Player));
1555  if (!Slot.IsSameType(a_ClickedItem))
1556  {
1557  LOGWARNING("*** Window lost sync at item %d in SlotArea with %d items ***", a_SlotNum, m_NumSlots);
1558  LOGWARNING("My item: %s", ItemToFullString(Slot).c_str());
1559  LOGWARNING("Their item: %s", ItemToFullString(a_ClickedItem).c_str());
1560  bAsync = true;
1561  }
1562  cItem & DraggingItem = a_Player.GetDraggingItem();
1563  if (a_SlotNum == 1)
1564  {
1565  // Lapis slot can have a full stack handle it normally, also check for empty hand
1566  if ((DraggingItem.IsEmpty()) || ((DraggingItem.m_ItemType == E_ITEM_DYE) && (DraggingItem.m_ItemDamage == E_META_DYE_BLUE)))
1567  {
1568  return cSlotArea::Clicked(a_Player, a_SlotNum, a_ClickAction, a_ClickedItem);
1569  }
1570 
1571  if (bAsync)
1572  {
1574  }
1575  return;
1576  }
1577  // Slot 0 is where the item to enhance goes.
1578  if (DraggingItem.IsEmpty())
1579  {
1580  // DraggingItem is empty -> Switch draggingitem and slot
1581  if (!Slot.IsEmpty())
1582  {
1583  std::swap(DraggingItem, Slot);
1584  }
1585  }
1586  else if (Slot.IsEmpty())
1587  {
1588  // DraggingItem isn't empty and slot is empty -> Set one dragging item in the slot
1589  Slot = DraggingItem.CopyOne();
1590  DraggingItem.m_ItemCount -= 1;
1591 
1592  if (DraggingItem.m_ItemCount <= 0)
1593  {
1594  DraggingItem.Empty();
1595  }
1596  }
1597  else if ((DraggingItem.m_ItemCount == 1) && !DraggingItem.IsEqual(Slot))
1598  {
1599  // DraggingItem and slot aren't empty -> Switch items
1600  std::swap(DraggingItem, Slot);
1601  }
1602 
1603  SetSlot(a_SlotNum, a_Player, Slot);
1604  if (bAsync)
1605  {
1607  }
1608 }
1609 
1610 
1611 
1612 
1613 
1614 void cSlotAreaEnchanting::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_Apply, bool a_KeepEmptySlots, bool a_BackFill)
1615 {
1616  if ((a_ItemStack.m_ItemType == E_ITEM_DYE) && (a_ItemStack.m_ItemDamage == E_META_DYE_BLUE))
1617  {
1618  // It's lapis, put it in the lapis spot.
1619  const cItem * Slot = GetSlot(1, a_Player);
1620  char NumFit = Slot->GetMaxStackSize() - Slot->m_ItemCount;
1621  if (NumFit <= 0)
1622  {
1623  // Full stack already
1624  return;
1625  }
1626  NumFit = std::min(NumFit, a_ItemStack.m_ItemCount);
1627 
1628  if (a_Apply)
1629  {
1630  cItem NewSlot(a_ItemStack);
1631  NewSlot.m_ItemCount = Slot->m_ItemCount + NumFit;
1632  SetSlot(1, a_Player, NewSlot);
1633  }
1634  a_ItemStack.m_ItemCount -= NumFit;
1635  // Return so we don't put overflow into the enchantment slot
1636  return;
1637  }
1638  const cItem * Slot = GetSlot(0, a_Player);
1639  if (!Slot->IsEmpty())
1640  {
1641  return;
1642  }
1643 
1644  if (a_Apply)
1645  {
1646  SetSlot(0, a_Player, a_ItemStack.CopyOne());
1647  }
1648  a_ItemStack.m_ItemCount -= 1;
1649  if (a_ItemStack.m_ItemCount <= 0)
1650  {
1651  a_ItemStack.Empty();
1652  }
1653 }
1654 
1655 
1656 
1657 
1658 
1660 {
1661  Super::OnPlayerAdded(a_Player);
1662  UpdateResult(a_Player);
1663 }
1664 
1665 
1666 
1667 
1668 
1670 {
1671  // Toss the item in the enchanting slot, as well as lapis
1672  TossItems(a_Player, 0, m_NumSlots);
1673 
1674  Super::OnPlayerRemoved(a_Player);
1675 }
1676 
1677 
1678 
1679 
1680 
1681 void cSlotAreaEnchanting::SetSlot(int a_SlotNum, cPlayer & a_Player, const cItem & a_Item)
1682 {
1683  Super::SetSlot(a_SlotNum, a_Player, a_Item);
1684  UpdateResult(a_Player);
1685 }
1686 
1687 
1688 
1689 
1690 
1692 {
1693  cItem Item = *GetSlot(0, a_Player);
1694 
1695  if (!cItem::IsEnchantable(Item.m_ItemType) || !Item.m_Enchantments.IsEmpty())
1696  {
1697  return;
1698  }
1699 
1700  // Pseudocode found at: https://minecraft.wiki/w/Enchanting_mechanics
1701  const auto Bookshelves = std::min(GetBookshelvesCount(*a_Player.GetWorld()), 15U);
1702 
1703  // A PRNG initialised using the player's enchantment seed.
1704  auto Random = a_Player.GetEnchantmentRandomProvider();
1705 
1706  // Calculate the levels for the offered enchantment options:
1707  const auto Base = (Random.RandInt(1U, 8U) + (Bookshelves / 2) + Random.RandInt(0U, Bookshelves));
1708  const std::array<unsigned, 3> OptionLevels
1709  {
1710  std::max(Base / 3, 1U),
1711  (Base * 2) / 3 + 1,
1712  std::max(Base, Bookshelves * 2)
1713  };
1714 
1715  // Properties set according to: https://wiki.vg/Protocol#Window_Property
1716  // Fake a "seed" for the client to draw Standard Galactic Alphabet glyphs:
1717  m_ParentWindow.SetProperty(3, Random.RandInt<short>());
1718 
1719  // Calculate an enchanting possibility for each option (top, middle and bottom) and send details to window:
1720  for (size_t i = 0; i != OptionLevels.size(); i++)
1721  {
1722  // A copy of the item.
1723  cItem EnchantedItem = Item.CopyOne();
1724 
1725  // Enchant based on the number of levels:
1726  EnchantedItem.EnchantByXPLevels(OptionLevels[i], Random);
1727 
1728  LOGD("Generated enchanted item %d with enchantments: %s", i, EnchantedItem.m_Enchantments.ToString());
1729 
1730  // Send the level requirement for the enchantment option:
1731  m_ParentWindow.SetProperty(i, static_cast<short>(OptionLevels[i]));
1732 
1733  // Get the first enchantment ID, which must exist:
1734  ASSERT(EnchantedItem.m_Enchantments.begin() != EnchantedItem.m_Enchantments.end());
1735  const auto EnchantmentID = static_cast<short>(EnchantedItem.m_Enchantments.begin()->first);
1736 
1737  // Send the enchantment ID of the first enchantment on our item:
1738  m_ParentWindow.SetProperty(4 + i, EnchantmentID);
1739 
1740  const auto EnchantmentLevel = static_cast<short>(EnchantedItem.m_Enchantments.GetLevel(EnchantmentID));
1741  ASSERT(EnchantmentLevel > 0);
1742 
1743  // Send the level for the first enchantment on our item:
1744  m_ParentWindow.SetProperty(7 + i, EnchantmentLevel);
1745 
1746  // Store the item we've enchanted as an option to be retrieved later:
1747  m_EnchantedItemOptions[i] = std::move(EnchantedItem);
1748  }
1749 }
1750 
1751 
1752 
1753 
1754 
1756 {
1757  cBlockArea Area;
1758  Area.Read(a_World, m_BlockPos - Vector3i(2, 0, 2), m_BlockPos + Vector3i(2, 1, 2));
1759 
1760  static const struct
1761  {
1762  int m_BookX, m_BookY, m_BookZ; // Coords to check for bookcases
1763  int m_AirX, m_AirY, m_AirZ; // Coords to check for air; if not air, the bookcase won't be counted
1764  } CheckCoords[] =
1765  {
1766  { 0, 0, 0, 1, 0, 1 }, // Bookcase at {0, 0, 0}, air at {1, 0, 1}
1767  { 0, 0, 1, 1, 0, 1 }, // Bookcase at {0, 0, 1}, air at {1, 0, 1}
1768  { 0, 0, 2, 1, 0, 2 }, // Bookcase at {0, 0, 2}, air at {1, 0, 2}
1769  { 0, 0, 3, 1, 0, 3 }, // Bookcase at {0, 0, 3}, air at {1, 0, 3}
1770  { 0, 0, 4, 1, 0, 3 }, // Bookcase at {0, 0, 4}, air at {1, 0, 3}
1771  { 1, 0, 4, 1, 0, 3 }, // Bookcase at {1, 0, 4}, air at {1, 0, 3}
1772  { 2, 0, 4, 2, 0, 3 }, // Bookcase at {2, 0, 4}, air at {2, 0, 3}
1773  { 3, 0, 4, 3, 0, 3 }, // Bookcase at {3, 0, 4}, air at {3, 0, 3}
1774  { 4, 0, 4, 3, 0, 3 }, // Bookcase at {4, 0, 4}, air at {3, 0, 3}
1775  { 4, 0, 3, 3, 0, 3 }, // Bookcase at {4, 0, 3}, air at {3, 0, 3}
1776  { 4, 0, 2, 3, 0, 2 }, // Bookcase at {4, 0, 2}, air at {3, 0, 2}
1777  { 4, 0, 1, 3, 0, 1 }, // Bookcase at {4, 0, 1}, air at {3, 0, 1}
1778  { 4, 0, 0, 3, 0, 1 }, // Bookcase at {4, 0, 0}, air at {3, 0, 1}
1779  { 3, 0, 0, 3, 0, 1 }, // Bookcase at {3, 0, 0}, air at {3, 0, 1}
1780  { 2, 0, 0, 2, 0, 1 }, // Bookcase at {2, 0, 0}, air at {2, 0, 1}
1781  { 1, 0, 0, 1, 0, 1 }, // Bookcase at {1, 0, 0}, air at {1, 0, 1}
1782 
1783  { 0, 1, 0, 1, 1, 1 }, // Bookcase at {0, 1, 0}, air at {1, 1, 1}
1784  { 0, 1, 1, 1, 1, 1 }, // Bookcase at {0, 1, 1}, air at {1, 1, 1}
1785  { 0, 1, 2, 1, 1, 2 }, // Bookcase at {0, 1, 2}, air at {1, 1, 2}
1786  { 0, 1, 3, 1, 1, 3 }, // Bookcase at {0, 1, 3}, air at {1, 1, 3}
1787  { 0, 1, 4, 1, 1, 3 }, // Bookcase at {0, 1, 4}, air at {1, 1, 3}
1788  { 1, 1, 4, 1, 1, 3 }, // Bookcase at {1, 1, 4}, air at {1, 1, 3}
1789  { 2, 1, 4, 2, 1, 3 }, // Bookcase at {2, 1, 4}, air at {2, 1, 3}
1790  { 3, 1, 4, 3, 1, 3 }, // Bookcase at {3, 1, 4}, air at {3, 1, 3}
1791  { 4, 1, 4, 3, 1, 3 }, // Bookcase at {4, 1, 4}, air at {3, 1, 3}
1792  { 4, 1, 3, 3, 1, 3 }, // Bookcase at {4, 1, 3}, air at {3, 1, 3}
1793  { 4, 1, 2, 3, 1, 2 }, // Bookcase at {4, 1, 2}, air at {3, 1, 2}
1794  { 4, 1, 1, 3, 1, 1 }, // Bookcase at {4, 1, 1}, air at {3, 1, 1}
1795  { 4, 1, 0, 3, 1, 1 }, // Bookcase at {4, 1, 0}, air at {3, 1, 1}
1796  { 3, 1, 0, 3, 1, 1 }, // Bookcase at {3, 1, 0}, air at {3, 1, 1}
1797  { 2, 1, 0, 2, 1, 1 }, // Bookcase at {2, 1, 0}, air at {2, 1, 1}
1798  { 1, 1, 0, 1, 1, 1 }, // Bookcase at {1, 1, 0}, air at {1, 1, 1}
1799  };
1800 
1801  unsigned Bookshelves = 0;
1802 
1803  for (size_t i = 0; i < ARRAYCOUNT(CheckCoords); i++)
1804  {
1805  if (
1806  (Area.GetRelBlockType(CheckCoords[i].m_AirX, CheckCoords[i].m_AirY, CheckCoords[i].m_AirZ) == E_BLOCK_AIR) && // There's air in the checkspot
1807  (Area.GetRelBlockType(CheckCoords[i].m_BookX, CheckCoords[i].m_BookY, CheckCoords[i].m_BookZ) == E_BLOCK_BOOKCASE) // There's bookcase in the wanted place
1808  )
1809  {
1810  Bookshelves++;
1811  }
1812  } // for i - CheckCoords
1813 
1814  return Bookshelves;
1815 }
1816 
1817 
1818 
1819 
1820 
1822 {
1823  ASSERT(a_EnchantOption < m_EnchantedItemOptions.size());
1824  return std::move(m_EnchantedItemOptions[a_EnchantOption]);
1825 }
1826 
1827 
1828 
1829 
1830 
1832 // cSlotAreaEnderChest:
1833 
1835  cSlotArea(27, a_ParentWindow),
1836  m_EnderChest(a_EnderChest)
1837 {
1838 }
1839 
1840 
1841 
1842 
1843 
1844 const cItem * cSlotAreaEnderChest::GetSlot(int a_SlotNum, cPlayer & a_Player) const
1845 {
1846  return &(a_Player.GetEnderChestContents().GetSlot(a_SlotNum));
1847 }
1848 
1849 
1850 
1851 
1852 
1853 void cSlotAreaEnderChest::SetSlot(int a_SlotNum, cPlayer & a_Player, const cItem & a_Item)
1854 {
1855  a_Player.GetEnderChestContents().SetSlot(a_SlotNum, a_Item);
1856 }
1857 
1858 
1859 
1860 
1861 
1863 // cSlotAreaFurnace:
1864 
1866  cSlotArea(3, a_ParentWindow),
1867  m_Furnace(a_Furnace)
1868 {
1869  m_Furnace->GetContents().AddListener(*this);
1870 }
1871 
1872 
1873 
1874 
1875 
1877 {
1879 }
1880 
1881 
1882 
1883 
1884 
1885 void cSlotAreaFurnace::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem)
1886 {
1887  if (m_Furnace == nullptr)
1888  {
1889  LOGERROR("cSlotAreaFurnace::Clicked(): m_Furnace == nullptr");
1890  ASSERT(!"cSlotAreaFurnace::Clicked(): m_Furnace == nullptr");
1891  return;
1892  }
1893 
1894  if (a_SlotNum == 1)
1895  {
1896  cItem & DraggingItem = a_Player.GetDraggingItem();
1897  cFurnaceRecipe * FurnaceRecipes = cRoot::Get()->GetFurnaceRecipe();
1898 
1899  // Do not allow non-fuels to be placed in the fuel slot:
1900  if (!DraggingItem.IsEmpty() && !FurnaceRecipes->IsFuel(DraggingItem) && (a_ClickAction != caShiftLeftClick) && (a_ClickAction != caShiftRightClick))
1901  {
1902  return;
1903  }
1904  }
1905  else if (a_SlotNum == 2)
1906  {
1907  bool bAsync = false;
1908  if (GetSlot(a_SlotNum, a_Player) == nullptr)
1909  {
1910  LOGWARNING("GetSlot(%d) returned nullptr! Ignoring click", a_SlotNum);
1911  return;
1912  }
1913 
1914  cItem Slot(*GetSlot(a_SlotNum, a_Player));
1915  if (!Slot.IsSameType(a_ClickedItem))
1916  {
1917  LOGWARNING("*** Window lost sync at item %d in SlotArea with %d items ***", a_SlotNum, m_NumSlots);
1918  LOGWARNING("My item: %s", ItemToFullString(Slot).c_str());
1919  LOGWARNING("Their item: %s", ItemToFullString(a_ClickedItem).c_str());
1920  bAsync = true;
1921  }
1922 
1923  switch (a_ClickAction)
1924  {
1925  case caShiftLeftClick:
1926  case caShiftRightClick:
1927  {
1928  HandleSmeltItem(Slot, a_Player);
1929  ShiftClicked(a_Player, a_SlotNum, Slot);
1930  return;
1931  }
1932  case caMiddleClick:
1933  {
1934  MiddleClicked(a_Player, a_SlotNum);
1935  return;
1936  }
1937  case caDropKey:
1938  case caCtrlDropKey:
1939  {
1940  DropClicked(a_Player, a_SlotNum, (a_SlotNum == caCtrlDropKey));
1941  Slot.m_ItemCount = Slot.m_ItemCount - GetSlot(a_SlotNum, a_Player)->m_ItemCount;
1942  HandleSmeltItem(Slot, a_Player);
1943  return;
1944  }
1945  default:
1946  {
1947  break;
1948  }
1949  }
1950 
1951  cItem & DraggingItem = a_Player.GetDraggingItem();
1952  if (!DraggingItem.IsEmpty())
1953  {
1954  if (a_ClickAction == caDblClick)
1955  {
1956  return;
1957  }
1958  if (!DraggingItem.IsEqual(Slot))
1959  {
1960  return;
1961  }
1962  if ((DraggingItem.m_ItemCount + Slot.m_ItemCount) > Slot.GetMaxStackSize())
1963  {
1964  return;
1965  }
1966 
1967  DraggingItem.m_ItemCount += Slot.m_ItemCount;
1968  HandleSmeltItem(Slot, a_Player);
1969  Slot.Empty();
1970  }
1971  else
1972  {
1973  switch (a_ClickAction)
1974  {
1975  case caDblClick:
1976  {
1977  DblClicked(a_Player, a_SlotNum);
1978  return;
1979  }
1980  case caLeftClick:
1981  {
1982  DraggingItem = Slot;
1983  HandleSmeltItem(Slot, a_Player);
1984  Slot.Empty();
1985  break;
1986  }
1987  case caRightClick:
1988  {
1989  DraggingItem = Slot.CopyOne();
1990  DraggingItem.m_ItemCount = static_cast<char>(static_cast<float>(Slot.m_ItemCount) / 2.f + 0.5f);
1991  Slot.m_ItemCount -= DraggingItem.m_ItemCount;
1992 
1993  if (Slot.m_ItemCount <= 0)
1994  {
1995  Slot.Empty();
1996  }
1997  HandleSmeltItem(DraggingItem, a_Player);
1998  break;
1999  }
2000  default:
2001  {
2002  ASSERT(!"Unhandled click type!");
2003  }
2004  }
2005  }
2006 
2007  SetSlot(a_SlotNum, a_Player, Slot);
2008  if (bAsync)
2009  {
2011  }
2012  return;
2013  }
2014 
2015  Super::Clicked(a_Player, a_SlotNum, a_ClickAction, a_ClickedItem);
2016 }
2017 
2018 
2019 
2020 
2021 
2022 void cSlotAreaFurnace::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots, bool a_BackFill)
2023 {
2024  int SlotNum;
2025  cFurnaceRecipe * FurnaceRecipes = cRoot::Get()->GetFurnaceRecipe();
2026 
2027  if (FurnaceRecipes->GetRecipeFrom(a_ItemStack) != nullptr)
2028  {
2029  SlotNum = 0;
2030  }
2031  else if (FurnaceRecipes->IsFuel(a_ItemStack))
2032  {
2033  SlotNum = 1;
2034  }
2035  else
2036  {
2037  return;
2038  }
2039 
2040  const cItem * Slot = GetSlot(SlotNum, a_Player);
2041  if (!Slot->IsEqual(a_ItemStack) && (!Slot->IsEmpty() || a_KeepEmptySlots))
2042  {
2043  // Different items
2044  return;
2045  }
2046 
2047  char NumFit = Slot->GetMaxStackSize() - Slot->m_ItemCount;
2048  if (NumFit <= 0)
2049  {
2050  // Full stack already
2051  return;
2052  }
2053  NumFit = std::min(NumFit, a_ItemStack.m_ItemCount);
2054 
2055  if (a_ShouldApply)
2056  {
2057  cItem NewSlot(a_ItemStack);
2058  NewSlot.m_ItemCount = Slot->m_ItemCount + NumFit;
2059  SetSlot(SlotNum, a_Player, NewSlot);
2060  }
2061  a_ItemStack.m_ItemCount -= NumFit;
2062  if (a_ItemStack.IsEmpty())
2063  {
2064  return;
2065  }
2066 }
2067 
2068 
2069 
2070 
2071 
2072 const cItem * cSlotAreaFurnace::GetSlot(int a_SlotNum, cPlayer & a_Player) const
2073 {
2074  UNUSED(a_Player);
2075  // a_SlotNum ranges from 0 to 2, query the items from the underlying furnace:
2076  return &(m_Furnace->GetSlot(a_SlotNum));
2077 }
2078 
2079 
2080 
2081 
2082 
2083 void cSlotAreaFurnace::SetSlot(int a_SlotNum, cPlayer & a_Player, const cItem & a_Item)
2084 {
2085  m_Furnace->SetSlot(a_SlotNum, a_Item);
2086 }
2087 
2088 
2089 
2090 
2091 
2092 void cSlotAreaFurnace::OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum)
2093 {
2094  UNUSED(a_SlotNum);
2095  // Something has changed in the window, broadcast the entire window to all clients
2096  ASSERT(a_ItemGrid == &(m_Furnace->GetContents()));
2097 
2099 }
2100 
2101 
2102 
2103 
2104 
2105 void cSlotAreaFurnace::HandleSmeltItem(const cItem & a_Result, cPlayer & a_Player)
2106 {
2107  int Reward = m_Furnace->GetAndResetReward();
2108  if (Reward > 0)
2109  {
2110  a_Player.GetWorld()->SpawnSplitExperienceOrbs(a_Player.GetPosX(), a_Player.GetPosY(), a_Player.GetPosZ(), Reward);
2111  }
2112 
2114  switch (a_Result.m_ItemType)
2115  {
2118  default: break;
2119  }
2120 }
2121 
2122 
2123 
2124 
2125 
2127 // cSlotAreaBrewingstand:
2129  cSlotArea(5, a_ParentWindow),
2130  m_Brewingstand(a_Brewingstand)
2131 {
2133 }
2134 
2135 
2136 
2137 
2138 
2140 {
2142 }
2143 
2144 
2145 
2146 
2147 
2148 void cSlotAreaBrewingstand::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem)
2149 {
2150  if (m_Brewingstand == nullptr)
2151  {
2152  LOGERROR("cSlotAreaBrewingstand::Clicked(): m_Brewingstand == nullptr");
2153  ASSERT(!"cSlotAreaBrewingstand::Clicked(): m_Brewingstand == nullptr");
2154  return;
2155  }
2156 
2157  if (GetSlot(a_SlotNum, a_Player) == nullptr)
2158  {
2159  LOGWARNING("GetSlot(%d) returned nullptr! Ignoring click", a_SlotNum);
2160  return;
2161  }
2162 
2163  cItem Slot(*GetSlot(a_SlotNum, a_Player));
2164  cItem & DraggingItem = a_Player.GetDraggingItem();
2166 
2167  if ((a_SlotNum >= 0) && (a_SlotNum <= 2))
2168  {
2169  // Bottle slots
2170  switch (a_ClickAction)
2171  {
2172  case caLeftClick:
2173  case caRightClick:
2174  {
2175  if (BR->IsBottle(Slot))
2176  {
2177  HandleBrewedItem(a_Player, Slot);
2178  }
2179  if (!DraggingItem.IsEmpty() && !BR->IsBottle(DraggingItem))
2180  {
2181  // Deny placing a invalid item into the bottle slot
2182  return;
2183  }
2184  break;
2185  }
2186  case caShiftLeftClick:
2187  case caShiftRightClick:
2188  {
2189  if (BR->IsBottle(Slot))
2190  {
2191  HandleBrewedItem(a_Player, Slot);
2192  }
2193  Super::ShiftClicked(a_Player, a_SlotNum, Slot);
2194  break;
2195  }
2196  default:
2197  {
2198  if (!DraggingItem.IsEmpty() && !BR->IsBottle(DraggingItem))
2199  {
2200  // Deny placing a invalid item into the bottle slot
2201  return;
2202  }
2203  break;
2204  }
2205  }
2206  }
2207 
2208  if ((a_SlotNum == 3) && !DraggingItem.IsEmpty())
2209  {
2210  // Ingredient slot
2211  switch (a_ClickAction)
2212  {
2213  case caShiftLeftClick:
2214  case caShiftRightClick:
2215  {
2216  Super::ShiftClicked(a_Player, a_SlotNum, Slot);
2217  break;
2218  }
2219  default:
2220  {
2221  if (!BR->IsIngredient(DraggingItem))
2222  {
2223  // Deny placing a invalid item into the ingredient slot
2224  return;
2225  }
2226  break;
2227  }
2228  }
2229  }
2230 
2231  if ((a_SlotNum == 4) && !DraggingItem.IsEmpty())
2232  {
2233  // Fuel slot
2234  switch (a_ClickAction)
2235  {
2236  case caShiftLeftClick:
2237  case caShiftRightClick:
2238  {
2239  Super::ShiftClicked(a_Player, a_SlotNum, Slot);
2240  break;
2241  }
2242  default:
2243  {
2244  if (!BR->IsFuel(DraggingItem))
2245  {
2246  // Deny placing a invalid item into the fuel slot
2247  return;
2248  }
2249  break;
2250  }
2251  }
2252  }
2253 
2254  Super::Clicked(a_Player, a_SlotNum, a_ClickAction, a_ClickedItem);
2255 }
2256 
2257 
2258 
2259 
2260 
2261 void cSlotAreaBrewingstand::HandleBrewedItem(cPlayer & a_Player, const cItem & a_ClickedItem)
2262 {
2263  // Award an achievement if the item is not a water bottle (is a real brewed potion)
2264  if (a_ClickedItem.m_ItemDamage > 0)
2265  {
2267  }
2268 }
2269 
2270 
2271 
2272 
2273 
2274 void cSlotAreaBrewingstand::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots, bool a_BackFill)
2275 {
2276  int SlotNum = -1;
2278  if (BR->IsBottle(a_ItemStack))
2279  {
2280  for (int i = 0;i < 3;i++)
2281  {
2282  if (GetSlot(i, a_Player)->IsEmpty())
2283  {
2284  SlotNum = i;
2285  break;
2286  }
2287  }
2288 
2289  if (SlotNum == -1)
2290  {
2291  // All slots are full
2292  return;
2293  }
2294  }
2295  else if (BR->IsIngredient(a_ItemStack))
2296  {
2297  SlotNum = 3;
2298  }
2299  else
2300  {
2301  return;
2302  }
2303 
2304  const cItem * Slot = GetSlot(SlotNum, a_Player);
2305  if (!Slot->IsEqual(a_ItemStack) && (!Slot->IsEmpty() || a_KeepEmptySlots))
2306  {
2307  // Different items
2308  return;
2309  }
2310 
2311  char NumFit = Slot->GetMaxStackSize() - Slot->m_ItemCount;
2312  if (NumFit <= 0)
2313  {
2314  // Full stack already
2315  return;
2316  }
2317  NumFit = std::min(NumFit, a_ItemStack.m_ItemCount);
2318 
2319  if (a_ShouldApply)
2320  {
2321  cItem NewSlot(a_ItemStack);
2322  NewSlot.m_ItemCount = Slot->m_ItemCount + NumFit;
2323  SetSlot(SlotNum, a_Player, NewSlot);
2324  }
2325  a_ItemStack.m_ItemCount -= NumFit;
2326  if (a_ItemStack.IsEmpty())
2327  {
2328  return;
2329  }
2330 }
2331 
2332 
2333 
2334 
2335 
2336 const cItem * cSlotAreaBrewingstand::GetSlot(int a_SlotNum, cPlayer & a_Player) const
2337 {
2338  UNUSED(a_Player);
2339  // a_SlotNum ranges from 0 to 3, query the items from the underlying brewing stand:
2340  return &(m_Brewingstand->GetSlot(a_SlotNum));
2341 }
2342 
2343 
2344 
2345 
2346 
2347 void cSlotAreaBrewingstand::SetSlot(int a_SlotNum, cPlayer & a_Player, const cItem & a_Item)
2348 {
2349  UNUSED(a_Player);
2350  m_Brewingstand->SetSlot(a_SlotNum, a_Item);
2351 }
2352 
2353 
2354 
2355 
2356 
2357 void cSlotAreaBrewingstand::OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum)
2358 {
2359  UNUSED(a_SlotNum);
2360  // Something has changed in the window, broadcast the entire window to all clients
2361  ASSERT(a_ItemGrid == &(m_Brewingstand->GetContents()));
2362 
2364 }
2365 
2366 
2367 
2368 
2369 
2371 // cSlotAreaMinecartWithChest:
2372 
2374  cSlotArea(27, a_ParentWindow),
2375  m_Chest(a_Chest)
2376 {
2377 }
2378 
2379 
2380 
2381 
2382 
2383 const cItem * cSlotAreaMinecartWithChest::GetSlot(int a_SlotNum, cPlayer & a_Player) const
2384 {
2385  // a_SlotNum ranges from 0 to 26, use that to index the minecart chest entity's inventory directly:
2386  UNUSED(a_Player);
2387  return &(m_Chest->GetSlot(a_SlotNum));
2388 }
2389 
2390 
2391 
2392 
2393 
2394 void cSlotAreaMinecartWithChest::SetSlot(int a_SlotNum, cPlayer & a_Player, const cItem & a_Item)
2395 {
2396  UNUSED(a_Player);
2397  m_Chest->SetSlot(a_SlotNum, a_Item);
2398 }
2399 
2400 
2401 
2402 
2403 
2405 // cSlotAreaInventoryBase:
2406 
2407 cSlotAreaInventoryBase::cSlotAreaInventoryBase(int a_NumSlots, int a_SlotOffset, cWindow & a_ParentWindow) :
2408  cSlotArea(a_NumSlots, a_ParentWindow),
2409  m_SlotOffset(a_SlotOffset)
2410 {
2411 }
2412 
2413 
2414 
2415 
2416 
2417 void cSlotAreaInventoryBase::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem)
2418 {
2420  {
2421  if ((a_ClickAction == caDropKey) || (a_ClickAction == caCtrlDropKey))
2422  {
2423  DropClicked(a_Player, a_SlotNum, (a_ClickAction == caCtrlDropKey));
2424  return;
2425  }
2426 
2427  // Creative inventory must treat a_ClickedItem as a DraggedItem instead, replacing the inventory slot with it
2428  SetSlot(a_SlotNum, a_Player, a_ClickedItem);
2429  return;
2430  }
2431 
2432  // Survival inventory and all other windows' inventory has the same handling as normal slot areas
2433  Super::Clicked(a_Player, a_SlotNum, a_ClickAction, a_ClickedItem);
2434 }
2435 
2436 
2437 
2438 
2439 
2440 const cItem * cSlotAreaInventoryBase::GetSlot(int a_SlotNum, cPlayer & a_Player) const
2441 {
2442  // a_SlotNum ranges from 0 to 35, map that to the player's inventory slots according to the internal offset
2443  return &a_Player.GetInventory().GetSlot(a_SlotNum + m_SlotOffset);
2444 }
2445 
2446 
2447 
2448 
2449 
2450 void cSlotAreaInventoryBase::SetSlot(int a_SlotNum, cPlayer & a_Player, const cItem & a_Item)
2451 {
2452  a_Player.GetInventory().SetSlot(a_SlotNum + m_SlotOffset, a_Item);
2453 }
2454 
2455 
2456 
2457 
2458 
2460 // cSlotAreaArmor:
2461 
2462 void cSlotAreaArmor::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots, bool a_BackFill)
2463 {
2464  if (ItemCategory::IsHelmet(a_ItemStack.m_ItemType) && GetSlot(0, a_Player)->IsEmpty())
2465  {
2466  if (a_ShouldApply)
2467  {
2468  SetSlot(0, a_Player, a_ItemStack.CopyOne());
2469  }
2470  a_ItemStack.m_ItemCount -= 1;
2471  }
2472  else if (ItemCategory::IsChestPlate(a_ItemStack.m_ItemType) && GetSlot(1, a_Player)->IsEmpty())
2473  {
2474  if (a_ShouldApply)
2475  {
2476  SetSlot(1, a_Player, a_ItemStack.CopyOne());
2477  }
2478  a_ItemStack.m_ItemCount -= 1;
2479  }
2480  else if (ItemCategory::IsLeggings(a_ItemStack.m_ItemType) && GetSlot(2, a_Player)->IsEmpty())
2481  {
2482  if (a_ShouldApply)
2483  {
2484  SetSlot(2, a_Player, a_ItemStack.CopyOne());
2485  }
2486  a_ItemStack.m_ItemCount -= 1;
2487  }
2488  else if (ItemCategory::IsBoots(a_ItemStack.m_ItemType) && GetSlot(3, a_Player)->IsEmpty())
2489  {
2490  if (a_ShouldApply)
2491  {
2492  SetSlot(3, a_Player, a_ItemStack.CopyOne());
2493  }
2494  a_ItemStack.m_ItemCount -= 1;
2495  }
2496 }
2497 
2498 
2499 
2500 
2501 
2502 void cSlotAreaArmor::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem)
2503 {
2504  ASSERT((a_SlotNum >= 0) && (a_SlotNum < GetNumSlots()));
2505 
2506  // When the player is in creative mode, the client sends the new item as a_ClickedItem, not the current item in the slot.
2508  {
2509  if ((a_ClickAction == caDropKey) || (a_ClickAction == caCtrlDropKey))
2510  {
2511  DropClicked(a_Player, a_SlotNum, (a_ClickAction == caCtrlDropKey));
2512  return;
2513  }
2514 
2515  SetSlot(a_SlotNum, a_Player, a_ClickedItem);
2516  return;
2517  }
2518 
2519  bool bAsync = false;
2520  if (GetSlot(a_SlotNum, a_Player) == nullptr)
2521  {
2522  LOGWARNING("GetSlot(%d) returned nullptr! Ignoring click", a_SlotNum);
2523  return;
2524  }
2525 
2526  switch (a_ClickAction)
2527  {
2528  case caDblClick:
2529  {
2530  // Armors haven't a dbl click
2531  return;
2532  }
2533  case caShiftLeftClick:
2534  case caShiftRightClick:
2535  {
2536  ShiftClicked(a_Player, a_SlotNum, a_ClickedItem);
2537  return;
2538  }
2539  case caMiddleClick:
2540  {
2541  MiddleClicked(a_Player, a_SlotNum);
2542  return;
2543  }
2544  default:
2545  {
2546  break;
2547  }
2548  }
2549 
2550  cItem Slot(*GetSlot(a_SlotNum, a_Player));
2551  if (!Slot.IsSameType(a_ClickedItem))
2552  {
2553  LOGWARNING("*** Window lost sync at item %d in SlotArea with %d items ***", a_SlotNum, m_NumSlots);
2554  LOGWARNING("My item: %s", ItemToFullString(Slot).c_str());
2555  LOGWARNING("Their item: %s", ItemToFullString(a_ClickedItem).c_str());
2556  bAsync = true;
2557  }
2558  cItem & DraggingItem = a_Player.GetDraggingItem();
2559  if ((a_ClickAction != caRightClick) && (a_ClickAction != caLeftClick))
2560  {
2561  LOGWARNING("SlotArea: Unhandled click action: %d (%s)", a_ClickAction, ClickActionToString(a_ClickAction));
2563  return;
2564  }
2565 
2566  if (DraggingItem.IsEmpty() || CanPlaceArmorInSlot(a_SlotNum, DraggingItem))
2567  {
2568  // Swap contents
2569  cItem tmp(DraggingItem);
2570  DraggingItem = Slot;
2571  Slot = tmp;
2572  }
2573 
2574  SetSlot(a_SlotNum, a_Player, Slot);
2575  if (bAsync)
2576  {
2578  }
2579 }
2580 
2581 
2582 
2583 
2584 
2585 bool cSlotAreaArmor::CanPlaceArmorInSlot(int a_SlotNum, const cItem & a_Item)
2586 {
2587  switch (a_SlotNum)
2588  {
2589  case 0: return (ItemCategory::IsHelmet(a_Item.m_ItemType) || (a_Item.m_ItemType == E_BLOCK_PUMPKIN));
2590  case 1: return ItemCategory::IsChestPlate(a_Item.m_ItemType);
2591  case 2: return ItemCategory::IsLeggings(a_Item.m_ItemType);
2592  case 3: return ItemCategory::IsBoots(a_Item.m_ItemType);
2593  default: return false;
2594  }
2595 }
2596 
2597 
2598 
2599 
2600 
2602 // cSlotAreaItemGrid:
2603 
2604 cSlotAreaItemGrid::cSlotAreaItemGrid(cItemGrid & a_ItemGrid, cWindow & a_ParentWindow) :
2605  Super(a_ItemGrid.GetNumSlots(), a_ParentWindow),
2606  m_ItemGrid(a_ItemGrid)
2607 {
2608  m_ItemGrid.AddListener(*this);
2609 }
2610 
2611 
2612 
2613 
2614 
2616 {
2617  m_ItemGrid.RemoveListener(*this);
2618 }
2619 
2620 
2621 
2622 
2623 
2624 const cItem * cSlotAreaItemGrid::GetSlot(int a_SlotNum, cPlayer & a_Player) const
2625 {
2626  return &m_ItemGrid.GetSlot(a_SlotNum);
2627 }
2628 
2629 
2630 
2631 
2632 
2633 void cSlotAreaItemGrid::SetSlot(int a_SlotNum, cPlayer & a_Player, const cItem & a_Item)
2634 {
2635  m_ItemGrid.SetSlot(a_SlotNum, a_Item);
2636 }
2637 
2638 
2639 
2640 
2641 
2642 void cSlotAreaItemGrid::OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum)
2643 {
2644  ASSERT(a_ItemGrid == &m_ItemGrid);
2645  m_ParentWindow.BroadcastSlot(this, a_SlotNum);
2646 }
2647 
2648 
2649 
2650 
2651 
2653 // cSlotAreaTemporary:
2654 
2655 cSlotAreaTemporary::cSlotAreaTemporary(int a_NumSlots, cWindow & a_ParentWindow) :
2656  cSlotArea(a_NumSlots, a_ParentWindow)
2657 {
2658 }
2659 
2660 
2661 
2662 
2663 
2664 const cItem * cSlotAreaTemporary::GetSlot(int a_SlotNum, cPlayer & a_Player) const
2665 {
2666  cItemMap::const_iterator itr = m_Items.find(a_Player.GetUniqueID());
2667  if (itr == m_Items.end())
2668  {
2669  LOGERROR("cSlotAreaTemporary: player \"%s\" not found for slot %d!", a_Player.GetName().c_str(), a_SlotNum);
2670  ASSERT(!"cSlotAreaTemporary: player not found!");
2671 
2672  // Player not found, this should not happen, ever! Return nullptr, but things may break by this.
2673  return nullptr;
2674  }
2675 
2676  if (a_SlotNum >= static_cast<int>(itr->second.size()))
2677  {
2678  LOGERROR("cSlotAreaTemporary: asking for more slots than actually stored!");
2679  ASSERT(!"cSlotAreaTemporary: asking for more slots than actually stored!");
2680  return nullptr;
2681  }
2682 
2683  return &(itr->second[static_cast<size_t>(a_SlotNum)]);
2684 }
2685 
2686 
2687 
2688 
2689 
2690 void cSlotAreaTemporary::SetSlot(int a_SlotNum, cPlayer & a_Player, const cItem & a_Item)
2691 {
2692  cItemMap::iterator itr = m_Items.find(a_Player.GetUniqueID());
2693  if (itr == m_Items.end())
2694  {
2695  // Player not found
2696  LOGWARNING("cSlotAreaTemporary: player not found!");
2697  return;
2698  }
2699 
2700  if (a_SlotNum >= static_cast<int>(itr->second.size()))
2701  {
2702  LOGERROR("cSlotAreaTemporary: asking for more slots than actually stored!");
2703  return;
2704  }
2705 
2706  itr->second[static_cast<size_t>(a_SlotNum)] = a_Item;
2707 
2708  m_ParentWindow.SendSlot(a_Player, this, a_SlotNum);
2709 }
2710 
2711 
2712 
2713 
2714 
2716 {
2717  ASSERT(m_Items.find(a_Player.GetUniqueID()) == m_Items.end()); // The player shouldn't be in the itemmap, otherwise we probably have a leak
2718  m_Items[a_Player.GetUniqueID()].resize(static_cast<size_t>(m_NumSlots)); // Make the vector the specified size of empty items
2719 }
2720 
2721 
2722 
2723 
2724 
2726 {
2727  cItemMap::iterator itr = m_Items.find(a_Player.GetUniqueID());
2728  ASSERT(itr != m_Items.end()); // The player should be in the list, otherwise a call to OnPlayerAdded() was mismatched
2729  m_Items.erase(itr);
2730 }
2731 
2732 
2733 
2734 
2735 
2736 void cSlotAreaTemporary::TossItems(cPlayer & a_Player, int a_Begin, int a_End)
2737 {
2738  cItemMap::iterator itr = m_Items.find(a_Player.GetUniqueID());
2739  if (itr == m_Items.end())
2740  {
2741  LOGWARNING("Player tossing items (%s) not found in the item map", a_Player.GetName().c_str());
2742  return;
2743  }
2744 
2745  cItems Drops;
2746  for (int i = a_Begin; i < a_End; i++)
2747  {
2748  cItem & Item = itr->second[static_cast<size_t>(i)];
2749  if (!Item.IsEmpty())
2750  {
2751  Drops.push_back(Item);
2752  }
2753  Item.Empty();
2754  } // for i - itr->second[]
2755 
2756  a_Player.TossItems(Drops);
2757 }
2758 
2759 
2760 
2761 
2762 
2764 {
2765  cItemMap::iterator itr = m_Items.find(a_Player.GetUniqueID());
2766  if (itr == m_Items.end())
2767  {
2768  return nullptr;
2769  }
2770  return itr->second.data();
2771 }
2772 
2773 
2774 
2775 
2776 
2778 // cSlotAreaHorse:
2779 
2780 cSlotAreaHorse::cSlotAreaHorse(cHorse & a_Horse, cWindow & a_ParentWindow) :
2781  cSlotArea(2, a_ParentWindow),
2782  m_Horse(a_Horse)
2783 {
2784 }
2785 
2786 
2787 
2788 
2789 
2790 void cSlotAreaHorse::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem)
2791 {
2792  cItem & DraggingItem = a_Player.GetDraggingItem();
2793 
2794  switch (a_ClickAction)
2795  {
2796  case caLeftClick:
2797  case caRightClick:
2798  case caDblClick:
2799  {
2800  // Check for invalid item types
2801  if (DraggingItem.IsEmpty())
2802  {
2803  break;
2804  }
2805 
2806  switch (a_SlotNum)
2807  {
2808  case SaddleSlot:
2809  {
2810  if (DraggingItem.m_ItemType != E_ITEM_SADDLE)
2811  {
2812  return;
2813  }
2814  break;
2815  }
2816  case ArmorSlot:
2817  {
2818  if (!ItemCategory::IsHorseArmor(DraggingItem.m_ItemType))
2819  {
2820  return;
2821  }
2822  break;
2823  }
2824  default: break;
2825  }
2826  }
2827  default: break;
2828  }
2829 
2830  cSlotArea::Clicked(a_Player, a_SlotNum, a_ClickAction, a_ClickedItem);
2831 }
2832 
2833 
2834 
2835 
2836 
2837 const cItem * cSlotAreaHorse::GetSlot(int a_SlotNum, cPlayer & a_Player) const
2838 {
2839  static const cItem InvalidItem;
2840  switch (a_SlotNum)
2841  {
2842  case SaddleSlot: return &m_Horse.GetHorseSaddle();
2843  case ArmorSlot: return &m_Horse.GetHorseArmorItem();
2844  default:
2845  {
2846  LOGWARN("cSlotAreaHorse::GetSlot: Invalid slot number %d", a_SlotNum);
2847  return &InvalidItem;
2848  }
2849  }
2850 }
2851 
2852 
2853 
2854 
2855 
2856 void cSlotAreaHorse::SetSlot(int a_SlotNum, cPlayer & a_Player, const cItem & a_Item)
2857 {
2858  switch (a_SlotNum)
2859  {
2860  case SaddleSlot: m_Horse.SetHorseSaddle(a_Item); break;
2861  case ArmorSlot: m_Horse.SetHorseArmor(a_Item); break;
2862  default:
2863  {
2864  LOGWARN("cSlotAreaHorse::SetSlot: Invalid slot number %d", a_SlotNum);
2865  }
2866  }
2867 }
2868 
2869 
2870 
2871 
2872 
2873 void cSlotAreaHorse::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots, bool a_BackFill)
2874 {
2876  {
2877  if (a_ShouldApply)
2878  {
2879  m_Horse.SetHorseArmor(a_ItemStack.CopyOne());
2880  }
2881  --a_ItemStack.m_ItemCount;
2882  }
2883  else if ((a_ItemStack.m_ItemType == E_ITEM_SADDLE) && !m_Horse.IsSaddled())
2884  {
2885  if (a_ShouldApply)
2886  {
2887  m_Horse.SetHorseSaddle(a_ItemStack.CopyOne());
2888  }
2889  --a_ItemStack.m_ItemCount;
2890  }
2891 }
AString ItemToFullString(const cItem &a_Item)
Translates a full item into a fully-specified string (including meta and count).
Definition: BlockType.cpp:261
@ E_BLOCK_AIR
Definition: BlockType.h:10
@ E_BLOCK_ENCHANTMENT_TABLE
Definition: BlockType.h:131
@ E_BLOCK_FURNACE
Definition: BlockType.h:73
@ E_BLOCK_CAKE
Definition: BlockType.h:107
@ E_BLOCK_WORKBENCH
Definition: BlockType.h:69
@ E_BLOCK_BOOKCASE
Definition: BlockType.h:57
@ E_BLOCK_PUMPKIN
Definition: BlockType.h:101
@ E_BLOCK_ANVIL
Definition: BlockType.h:160
@ E_ITEM_WOODEN_PICKAXE
Definition: BlockType.h:314
@ E_ITEM_IRON
Definition: BlockType.h:309
@ E_ITEM_STONE_PICKAXE
Definition: BlockType.h:318
@ E_ITEM_EMERALD
Definition: BlockType.h:434
@ E_ITEM_GOLD
Definition: BlockType.h:310
@ E_ITEM_DYE
Definition: BlockType.h:396
@ E_ITEM_WOODEN_HOE
Definition: BlockType.h:334
@ E_ITEM_COOKED_FISH
Definition: BlockType.h:395
@ E_ITEM_DIAMOND
Definition: BlockType.h:308
@ E_ITEM_SADDLE
Definition: BlockType.h:373
@ E_ITEM_BREAD
Definition: BlockType.h:341
@ E_ITEM_ENCHANTED_BOOK
Definition: BlockType.h:449
@ E_ITEM_WOODEN_SWORD
Definition: BlockType.h:312
@ E_META_DYE_BLUE
Definition: BlockType.h:1049
unsigned char NIBBLETYPE
The datatype used by nibbledata (meta, light, skylight)
Definition: ChunkDef.h:44
unsigned char BLOCKTYPE
The datatype used by blockdata.
Definition: ChunkDef.h:41
const char * ClickActionToString(int a_ClickAction)
Returns a textual representation of the click action.
Definition: Defines.cpp:10
eClickAction
Individual actions sent in the WindowClick packet.
Definition: Defines.h:82
@ caDblClick
Definition: Defines.h:113
@ caNumber6
Definition: Defines.h:93
@ caNumber8
Definition: Defines.h:95
@ caMiddleClick
Definition: Defines.h:97
@ caCtrlDropKey
Definition: Defines.h:99
@ caDropKey
Definition: Defines.h:98
@ caShiftRightClick
Definition: Defines.h:87
@ caNumber7
Definition: Defines.h:94
@ caRightClick
Definition: Defines.h:85
@ caNumber4
Definition: Defines.h:91
@ caNumber1
Definition: Defines.h:88
@ caNumber3
Definition: Defines.h:90
@ caNumber9
Definition: Defines.h:96
@ caNumber2
Definition: Defines.h:89
@ caShiftLeftClick
Definition: Defines.h:86
@ caNumber5
Definition: Defines.h:92
@ caLeftClick
Definition: Defines.h:84
@ SFX_RANDOM_ANVIL_BREAK
@ SFX_RANDOM_ANVIL_USE
MTRand & GetRandomProvider()
Returns the current thread's random number source.
Definition: FastRandom.cpp:12
#define ARRAYCOUNT(X)
Evaluates to the number of elements in an array (compile-time!)
Definition: Globals.h:231
unsigned int UInt32
Definition: Globals.h:157
signed short Int16
Definition: Globals.h:153
#define ASSERT(x)
Definition: Globals.h:276
#define UNUSED
Definition: Globals.h:72
void LOGERROR(std::string_view a_Format, const Args &... args)
Definition: LoggerSimple.h:73
void LOGWARNING(std::string_view a_Format, const Args &... args)
Definition: LoggerSimple.h:67
#define LOGWARN
Definition: LoggerSimple.h:88
#define LOGD
Definition: LoggerSimple.h:83
Item
Definition: Items.h:4
std::string AString
Definition: StringUtils.h:11
Vector3< int > Vector3i
Definition: Vector3.h:487
bool IsHelmet(short a_ItemType)
Definition: Defines.cpp:512
bool IsLeggings(short a_ItemType)
Definition: Defines.cpp:543
bool IsChestPlate(short a_ItemType)
Definition: Defines.cpp:527
bool IsBoots(short a_ItemType)
Definition: Defines.cpp:558
bool IsHorseArmor(short a_ItemType)
Definition: Defines.cpp:602
BLOCKTYPE GetRelBlockType(int a_RelX, int a_RelY, int a_RelZ) const
Definition: BlockArea.cpp:1710
bool Read(cForEachChunkProvider &a_ForEachChunkProvider, int a_MinBlockX, int a_MaxBlockX, int a_MinBlockY, int a_MaxBlockY, int a_MinBlockZ, int a_MaxBlockZ, int a_DataTypes=baTypes|baMetas|baBlockEntities)
Reads an area of blocks specified.
Definition: BlockArea.cpp:445
cItemGrid & GetContents(void)
Returns the ItemGrid used for storing the contents.
const cItem & GetSlot(int a_SlotNum) const
void SetSlot(int a_SlotNum, const cItem &a_Item)
int GetAndResetReward(void)
Calculates, resets, and returns the experience reward in this furnace.
bool IsIngredient(const cItem &a_Ingredient) const
Returns true if the item is a ingredient, false if not.
bool IsBottle(const cItem &a_Item) const
Returns true if the item is a bottle / potion, false if not.
bool IsFuel(const cItem &a_Item) const
Returns true if the item is the fuel, false if not.
void SendInventorySlot(char a_WindowID, short a_SlotNum, const cItem &a_Item)
void CopyToItems(cItem *a_Items) const
Copies internal contents into the item array specified.
void ConsumeIngredients(cCraftingGrid &a_CraftingGrid)
Consumes ingredients from the crafting grid specified.
const cItem & GetResult(void) const
void GetRecipe(cPlayer &a_Player, cCraftingGrid &a_CraftingGrid, cCraftingRecipe &a_Recipe)
Returns the recipe for current crafting grid.
cRecipe * GetRecipeById(UInt32 a_RecipeId)
Returns the recipe by id.
unsigned int GetLevel(int a_EnchantmentID) const
Returns the level for the specified enchantment; 0 if not stored.
AString ToString(void) const
Serializes all the enchantments into a string.
cMap::const_iterator end() const
Definition: Enchantments.h:170
cMap::const_iterator begin() const
Make this class iterable.
Definition: Enchantments.h:169
double GetPosX(void) const
Definition: Entity.h:195
double GetPosZ(void) const
Definition: Entity.h:197
UInt32 GetUniqueID(void) const
Definition: Entity.h:253
double GetPosY(void) const
Definition: Entity.h:196
cWorld * GetWorld(void) const
Definition: Entity.h:190
const cItem & GetSlot(int a_Idx) const
Definition: Minecart.h:145
void SetSlot(int a_Idx, const cItem &a_Item)
Definition: Minecart.h:146
Definition: Player.h:29
cClientHandle * GetClientHandle(void) const
Definition: Player.h:276
const AString & GetName(void) const
Definition: Player.cpp:1299
void AwardAchievement(CustomStatistic a_Ach)
Awards the player an achievement.
Definition: Player.cpp:1372
void CloseWindow(bool a_CanRefuse=true)
Closes the current window, resets current window to m_InventoryWindow.
Definition: Player.cpp:1144
void TossItems(const cItems &a_Items)
Tosses a list of items.
Definition: Player.cpp:478
void AddKnownItem(const cItem &a_Item)
Adds an Item to the list of known items.
Definition: Player.cpp:2708
void TossPickup(const cItem &a_Item)
tosses a pickup newly created from a_Item
Definition: Player.cpp:1791
int DeltaExperience(int a_Xp_delta)
Definition: Player.cpp:279
int GetXpLevel(void) const
Gets the current level - XpLevel.
Definition: Player.cpp:237
bool IsGameModeCreative(void) const
Returns true if the player is in Creative mode, either explicitly, or by inheriting from current worl...
Definition: Player.cpp:1025
cInventory & GetInventory(void)
Definition: Player.h:156
cItem & GetDraggingItem(void)
In UI windows, get the item that the player is dragging.
Definition: Player.h:448
bool IsGameModeSpectator(void) const
Returns true if the player is in Spectator mode, either explicitly, or by inheriting from current wor...
Definition: Player.cpp:1052
cItemGrid & GetEnderChestContents(void)
Gets the contents of the player's associated enderchest.
Definition: Player.h:160
MTRand GetEnchantmentRandomProvider()
Get a copy of the PRNG for enchanting related generation, don't use this for other purposes.
Definition: Player.cpp:1567
static int XpForLevel(int a_Level)
Calculates the amount of XP needed for a given level Ref: https://minecraft.wiki/w/XP.
Definition: Player.cpp:215
bool RandBool(double a_TrueProbability=0.5)
Return a random bool with the given probability of being true.
Definition: FastRandom.h:158
const cRecipe * GetRecipeFrom(const cItem &a_Ingredient) const
Returns a recipe for the specified input, nullptr if no recipe found.
bool IsFuel(const cItem &a_Item) const
Returns true if the item is a fuel, false if not.
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
const cItem & GetHotbarSlot(int a_HotBarSlotNum) const
Returns current item in a_ArmorSlotNum in hotbar slots.
Definition: Inventory.cpp:440
cItem * FindItem(const cItem &a_RecipeItem)
Finds an item based on ItemType and ItemDamage (<- defines the itemType, too)
Definition: Inventory.cpp:212
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 SetHotbarSlot(int a_HotBarSlotNum, const cItem &a_Item)
Puts a_Item item in a_HotBarSlotNum slot number in hotbar slots.
Definition: Inventory.cpp:353
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
Definition: Item.h:37
static bool IsEnchantable(short a_ItemType, bool a_FromBook=false)
Returns true if the specified item type is enchantable.
Definition: Item.cpp:322
cEnchantments m_Enchantments
Definition: Item.h:166
bool EnchantByXPLevels(unsigned a_NumXPLevels, MTRand &a_Random)
Randomly enchants the item using the specified number of XP levels.
Definition: Item.cpp:431
char m_ItemCount
Definition: Item.h:164
AString m_CustomName
Definition: Item.h:167
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
int AddEnchantmentsFromItem(const cItem &a_Other)
Adds the enchantments on a_Other to this item, returning the XP cost of the transfer.
Definition: Item.cpp:675
int m_RepairCost
Definition: Item.h:200
void Empty(void)
Empties the item and frees up any dynamic storage used by the internals.
Definition: Item.cpp:63
short GetMaxDamage(void) const
Returns the maximum damage value that this item can have; zero if damage is not applied.
Definition: Item.cpp:118
bool IsFullStack(void) const
Returns true if the item is stacked up to its maximum stacking.
Definition: Item.cpp:198
cItem CopyOne(void) const
Returns a copy of this item with m_ItemCount set to 1.
Definition: Item.cpp:93
short m_ItemDamage
Definition: Item.h:165
bool IsSameType(const cItem &a_Item) const
Definition: Item.h:89
This class bridges a vector of cItem for safe access via Lua.
Definition: Item.h:215
void SetSlot(int a_X, int a_Y, const cItem &a_Item)
Definition: ItemGrid.cpp:121
const cItem & GetSlot(int a_X, int a_Y) const
Definition: ItemGrid.cpp:96
void AddListener(cListener &a_Listener)
Adds a callback that gets called whenever a slot changes.
Definition: ItemGrid.cpp:809
void RemoveListener(cListener &a_Listener)
Removes a slot-change-callback.
Definition: ItemGrid.cpp:820
Definition: Horse.h:14
const cItem & GetHorseArmorItem() const
Definition: Horse.h:50
void SetHorseSaddle(cItem a_SaddleItem)
Set the horse's saddle to the given item.
Definition: Horse.cpp:195
bool IsSaddled(void) const
Definition: Horse.h:30
void SetHorseArmor(cItem a_ArmorItem)
Set the horse's armor slot to the given item.
Definition: Horse.cpp:214
const cItem & GetHorseSaddle() const
Definition: Horse.h:49
static cRoot * Get()
Definition: Root.h:52
cFurnaceRecipe * GetFurnaceRecipe(void)
Definition: Root.h:94
cBrewingRecipes * GetBrewingRecipes(void)
Definition: Root.h:95
cCraftingRecipes * GetCraftingRecipes(void)
Definition: Root.h:92
virtual void NumberClicked(cPlayer &a_Player, int a_SlotNum, eClickAction a_ClickAction)
Called from Clicked when the action is a number click.
Definition: SlotArea.cpp:311
cWindow & m_ParentWindow
Definition: SlotArea.h:86
virtual void OnPlayerAdded(cPlayer &a_Player)
Called when a new player opens the same parent window.
Definition: SlotArea.cpp:336
int m_NumSlots
Definition: SlotArea.h:85
virtual void DistributeStack(cItem &a_ItemStack, cPlayer &a_Player, bool a_ShouldApply, bool a_KeepEmptySlots, bool a_BackFill)
Called to store as much of a_ItemStack in the area as possible.
Definition: SlotArea.cpp:354
virtual void Clicked(cPlayer &a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem &a_ClickedItem)
Called when a player clicks in the window.
Definition: SlotArea.cpp:43
cSlotArea(int a_NumSlots, cWindow &a_ParentWindow)
Definition: SlotArea.cpp:33
virtual void DblClicked(cPlayer &a_Player, int a_SlotNum)
Called from Clicked when the action is a caDblClick.
Definition: SlotArea.cpp:235
virtual void DropClicked(cPlayer &a_Player, int a_SlotNum, bool a_DropStack)
Called from Clicked when the action is a drop click.
Definition: SlotArea.cpp:283
virtual void SetSlot(int a_SlotNum, cPlayer &a_Player, const cItem &a_Item)=0
Called to set an item in the specified slot for the specified player.
int GetNumSlots(void) const
Definition: SlotArea.h:39
virtual void OnPlayerRemoved(cPlayer &a_Player)
Called when one of the players closes the parent window.
Definition: SlotArea.cpp:345
virtual void MiddleClicked(cPlayer &a_Player, int a_SlotNum)
Called from Clicked when the action is a middleclick.
Definition: SlotArea.cpp:265
virtual bool CollectItemsToHand(cItem &a_Dragging, cPlayer &a_Player, bool a_CollectFullStacks)
Called on DblClicking to collect all stackable items into hand.
Definition: SlotArea.cpp:392
virtual const cItem * GetSlot(int a_SlotNum, cPlayer &a_Player) const =0
Called to retrieve an item in the specified slot for the specified player.
virtual void ShiftClicked(cPlayer &a_Player, int a_SlotNum, const cItem &a_ClickedItem)
Called from Clicked when the action is a shiftclick (left or right)
Definition: SlotArea.cpp:215
virtual void Clicked(cPlayer &a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem &a_ClickedItem) override
Called when a player clicks in the window.
Definition: SlotArea.cpp:2417
cSlotAreaInventoryBase(int a_NumSlots, int a_SlotOffset, cWindow &a_ParentWindow)
Definition: SlotArea.cpp:2407
virtual void SetSlot(int a_SlotNum, cPlayer &a_Player, const cItem &a_Item) override
Called to set an item in the specified slot for the specified player.
Definition: SlotArea.cpp:2450
virtual const cItem * GetSlot(int a_SlotNum, cPlayer &a_Player) const override
Called to retrieve an item in the specified slot for the specified player.
Definition: SlotArea.cpp:2440
static bool CanPlaceArmorInSlot(int a_SlotNum, const cItem &a_Item)
Definition: SlotArea.cpp:2585
virtual void Clicked(cPlayer &a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem &a_ClickedItem) override
Called when a player clicks in the window.
Definition: SlotArea.cpp:2502
virtual void DistributeStack(cItem &a_ItemStack, cPlayer &a_Player, bool a_ShouldApply, bool a_KeepEmptySlots, bool a_BackFill) override
Distributing the stack is allowed only for compatible items (helmets into helmet slot etc....
Definition: SlotArea.cpp:2462
virtual void OnSlotChanged(cItemGrid *a_ItemGrid, int a_SlotNum) override
Called whenever a slot changes.
Definition: SlotArea.cpp:2642
cSlotAreaItemGrid(cItemGrid &a_ItemGrid, cWindow &a_ParentWindow)
Definition: SlotArea.cpp:2604
virtual ~cSlotAreaItemGrid() override
Definition: SlotArea.cpp:2615
virtual void SetSlot(int a_SlotNum, cPlayer &a_Player, const cItem &a_Item) override
Called to set an item in the specified slot for the specified player.
Definition: SlotArea.cpp:2633
cItemGrid & m_ItemGrid
Definition: SlotArea.h:213
virtual const cItem * GetSlot(int a_SlotNum, cPlayer &a_Player) const override
Called to retrieve an item in the specified slot for the specified player.
Definition: SlotArea.cpp:2624
A cSlotArea with items layout that is private to each player and is temporary, such as a crafting gri...
Definition: SlotArea.h:228
void TossItems(cPlayer &a_Player, int a_Begin, int a_End)
Tosses the player's items in slots [a_Begin, a_End) (ie.
Definition: SlotArea.cpp:2736
cSlotAreaTemporary(int a_NumSlots, cWindow &a_ParentWindow)
Definition: SlotArea.cpp:2655
virtual const cItem * GetSlot(int a_SlotNum, cPlayer &a_Player) const override
Called to retrieve an item in the specified slot for the specified player.
Definition: SlotArea.cpp:2664
cItemMap m_Items
Definition: SlotArea.h:247
virtual void SetSlot(int a_SlotNum, cPlayer &a_Player, const cItem &a_Item) override
Called to set an item in the specified slot for the specified player.
Definition: SlotArea.cpp:2690
virtual void OnPlayerRemoved(cPlayer &a_Player) override
Called when one of the players closes the parent window.
Definition: SlotArea.cpp:2725
cItem * GetPlayerSlots(cPlayer &a_Player)
Returns the pointer to the slot array for the player specified.
Definition: SlotArea.cpp:2763
virtual void OnPlayerAdded(cPlayer &a_Player) override
Called when a new player opens the same parent window.
Definition: SlotArea.cpp:2715
virtual void OnPlayerRemoved(cPlayer &a_Player) override
Called when one of the players closes the parent window.
Definition: SlotArea.cpp:566
void UpdateRecipe(cPlayer &a_Player)
Updates the current recipe and result slot based on the ingredients currently in the crafting grid of...
Definition: SlotArea.cpp:728
virtual void DistributeStack(cItem &a_ItemStack, cPlayer &a_Player, bool a_ShouldApply, bool a_KeepEmptySlots, bool a_BackFill) override
Called to store as much of a_ItemStack in the area as possible.
Definition: SlotArea.cpp:602
cRecipeMap m_Recipes
Definition: SlotArea.h:288
void ClearCraftingGrid(cPlayer &a_Player)
Clear the crafting grid.
Definition: SlotArea.cpp:833
virtual void DblClicked(cPlayer &a_Player, int a_SlotNum) override
Called from Clicked when the action is a caDblClick.
Definition: SlotArea.cpp:552
virtual void SetSlot(int a_SlotNum, cPlayer &a_Player, const cItem &a_Item) override
Called to set an item in the specified slot for the specified player.
Definition: SlotArea.cpp:588
void DropClickedResult(cPlayer &a_Player)
Handles a drop-click in the result slot.
Definition: SlotArea.cpp:707
cSlotAreaCrafting(int a_GridSize, cWindow &a_ParentWindow)
a_GridSize is allowed to be only 2 or 3
Definition: SlotArea.cpp:507
virtual void Clicked(cPlayer &a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem &a_ClickedItem) override
Called when a player clicks in the window.
Definition: SlotArea.cpp:518
void ClickedResult(cPlayer &a_Player)
Handles a click in the result slot.
Definition: SlotArea.cpp:615
void HandleCraftItem(const cItem &a_Result, cPlayer &a_Player)
Called after an item has been crafted to handle statistics e.t.c.
Definition: SlotArea.cpp:762
cCraftingRecipe & GetRecipeForPlayer(cPlayer &a_Player)
Retrieves the recipe for the specified player from the map, or creates one if not found.
Definition: SlotArea.cpp:740
void LoadRecipe(cPlayer &a_Player, UInt32 a_RecipeId)
Loads the given Recipe into the crafting grid.
Definition: SlotArea.cpp:784
void ShiftClickedResult(cPlayer &a_Player)
Handles a shift-click in the result slot.
Definition: SlotArea.cpp:658
virtual void DistributeStack(cItem &a_ItemStack, cPlayer &a_Player, bool a_ShouldApply, bool a_KeepEmptySlots, bool a_BackFill) override
Called to store as much of a_ItemStack in the area as possible.
Definition: SlotArea.cpp:992
virtual void OnPlayerRemoved(cPlayer &a_Player) override
Called when one of the players closes the parent window.
Definition: SlotArea.cpp:1115
cSlotAreaAnvil(cWindow &a_ParentWindow)
Definition: SlotArea.cpp:851
char m_StackSizeToBeUsedInRepair
The stack size of the second item where was used for repair.
Definition: SlotArea.h:346
int m_MaximumCost
The maximum cost of repairing / renaming in the anvil.
Definition: SlotArea.h:343
void OnTakeResult(cPlayer &a_Player)
This function will call, when the player take the item from the slot.
Definition: SlotArea.cpp:1032
bool CanTakeResultItem(cPlayer &a_Player)
Can the player take the item from the slot?
Definition: SlotArea.cpp:1099
virtual void ShiftClicked(cPlayer &a_Player, int a_SlotNum, const cItem &a_ClickedItem) override
Called from Clicked when the action is a shiftclick (left or right)
Definition: SlotArea.cpp:959
virtual void Clicked(cPlayer &a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem &a_ClickedItem) override
Called when a player clicks in the window.
Definition: SlotArea.cpp:862
void UpdateResult(cPlayer &a_Player)
Handles a click in the item slot.
Definition: SlotArea.cpp:1125
virtual void SetSlot(int a_SlotNum, cPlayer &a_Player, const cItem &a_Item) override
Called to set an item in the specified slot for the specified player.
Definition: SlotArea.cpp:1464
static bool IsPlaceableItem(short a_ItemType)
Definition: SlotArea.cpp:1311
cBeaconEntity * m_Beacon
Definition: SlotArea.h:372
virtual const cItem * GetSlot(int a_SlotNum, cPlayer &a_Player) const override
Called to retrieve an item in the specified slot for the specified player.
Definition: SlotArea.cpp:1454
cSlotAreaBeacon(cBeaconEntity *a_Beacon, cWindow &a_ParentWindow)
Definition: SlotArea.cpp:1291
virtual void OnSlotChanged(cItemGrid *a_ItemGrid, int a_SlotNum) override
Called whenever a slot changes.
Definition: SlotArea.cpp:1474
virtual void DistributeStack(cItem &a_ItemStack, cPlayer &a_Player, bool a_ShouldApply, bool a_KeepEmptySlots, bool a_BackFill) override
Called to store as much of a_ItemStack in the area as possible.
Definition: SlotArea.cpp:1435
virtual ~cSlotAreaBeacon() override
Definition: SlotArea.cpp:1302
virtual void Clicked(cPlayer &a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem &a_ClickedItem) override
Called when a player clicks in the window.
Definition: SlotArea.cpp:1333
virtual void OnPlayerRemoved(cPlayer &a_Player) override
Called when one of the players closes the parent window.
Definition: SlotArea.cpp:1669
void UpdateResult(cPlayer &a_Player)
Handles a click in the item slot.
Definition: SlotArea.cpp:1691
std::array< cItem, 3 > m_EnchantedItemOptions
Definition: SlotArea.h:413
virtual void SetSlot(int a_SlotNum, cPlayer &a_Player, const cItem &a_Item) override
Called to set an item in the specified slot for the specified player.
Definition: SlotArea.cpp:1681
unsigned GetBookshelvesCount(cWorld &a_World)
Definition: SlotArea.cpp:1755
cSlotAreaEnchanting(cWindow &a_ParentWindow, Vector3i a_BlockPos)
Definition: SlotArea.cpp:1490
cItem SelectEnchantedOption(size_t a_EnchantOption)
Definition: SlotArea.cpp:1821
Vector3i m_BlockPos
Definition: SlotArea.h:412
virtual void DistributeStack(cItem &a_ItemStack, cPlayer &a_Player, bool a_ShouldApply, bool a_KeepEmptySlots, bool a_BackFill) override
Called to store as much of a_ItemStack in the area as possible.
Definition: SlotArea.cpp:1614
virtual void Clicked(cPlayer &a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem &a_ClickedItem) override
Called when a player clicks in the window.
Definition: SlotArea.cpp:1500
virtual void OnPlayerAdded(cPlayer &a_Player) override
Called when a new player opens the same parent window.
Definition: SlotArea.cpp:1659
cChestEntity * m_Chest
Definition: SlotArea.h:430
virtual void SetSlot(int a_SlotNum, cPlayer &a_Player, const cItem &a_Item) override
Called to set an item in the specified slot for the specified player.
Definition: SlotArea.cpp:448
virtual const cItem * GetSlot(int a_SlotNum, cPlayer &a_Player) const override
Called to retrieve an item in the specified slot for the specified player.
Definition: SlotArea.cpp:438
cSlotAreaChest(cChestEntity *a_Chest, cWindow &a_ParentWindow)
Definition: SlotArea.cpp:428
cSlotAreaDoubleChest(cChestEntity *a_TopChest, cChestEntity *a_BottomChest, cWindow &a_ParentWindow)
Definition: SlotArea.cpp:460
virtual const cItem * GetSlot(int a_SlotNum, cPlayer &a_Player) const override
Called to retrieve an item in the specified slot for the specified player.
Definition: SlotArea.cpp:471
virtual void SetSlot(int a_SlotNum, cPlayer &a_Player, const cItem &a_Item) override
Called to set an item in the specified slot for the specified player.
Definition: SlotArea.cpp:488
cChestEntity * m_BottomChest
Definition: SlotArea.h:448
cChestEntity * m_TopChest
Definition: SlotArea.h:447
cSlotAreaEnderChest(cEnderChestEntity *a_EnderChest, cWindow &a_ParentWindow)
Definition: SlotArea.cpp:1834
virtual const cItem * GetSlot(int a_SlotNum, cPlayer &a_Player) const override
Called to retrieve an item in the specified slot for the specified player.
Definition: SlotArea.cpp:1844
virtual void SetSlot(int a_SlotNum, cPlayer &a_Player, const cItem &a_Item) override
Called to set an item in the specified slot for the specified player.
Definition: SlotArea.cpp:1853
virtual void SetSlot(int a_SlotNum, cPlayer &a_Player, const cItem &a_Item) override
Called to set an item in the specified slot for the specified player.
Definition: SlotArea.cpp:2083
void HandleSmeltItem(const cItem &a_Result, cPlayer &a_Player)
Called after an item has been smelted to handle statistics etc.
Definition: SlotArea.cpp:2105
virtual void DistributeStack(cItem &a_ItemStack, cPlayer &a_Player, bool a_ShouldApply, bool a_KeepEmptySlots, bool a_BackFill) override
Called to store as much of a_ItemStack in the area as possible.
Definition: SlotArea.cpp:2022
cFurnaceEntity * m_Furnace
Definition: SlotArea.h:490
virtual void OnSlotChanged(cItemGrid *a_ItemGrid, int a_SlotNum) override
Called whenever a slot changes.
Definition: SlotArea.cpp:2092
virtual const cItem * GetSlot(int a_SlotNum, cPlayer &a_Player) const override
Called to retrieve an item in the specified slot for the specified player.
Definition: SlotArea.cpp:2072
virtual ~cSlotAreaFurnace() override
Definition: SlotArea.cpp:1876
virtual void Clicked(cPlayer &a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem &a_ClickedItem) override
Called when a player clicks in the window.
Definition: SlotArea.cpp:1885
cSlotAreaFurnace(cFurnaceEntity *a_Furnace, cWindow &a_ParentWindow)
Definition: SlotArea.cpp:1865
virtual ~cSlotAreaBrewingstand() override
Definition: SlotArea.cpp:2139
cSlotAreaBrewingstand(cBrewingstandEntity *a_Brewingstand, cWindow &a_ParentWindow)
Definition: SlotArea.cpp:2128
virtual void OnSlotChanged(cItemGrid *a_ItemGrid, int a_SlotNum) override
Called whenever a slot changes.
Definition: SlotArea.cpp:2357
virtual void SetSlot(int a_SlotNum, cPlayer &a_Player, const cItem &a_Item) override
Called to set an item in the specified slot for the specified player.
Definition: SlotArea.cpp:2347
cBrewingstandEntity * m_Brewingstand
Definition: SlotArea.h:520
virtual void Clicked(cPlayer &a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem &a_ClickedItem) override
Called when a player clicks in the window.
Definition: SlotArea.cpp:2148
virtual void DistributeStack(cItem &a_ItemStack, cPlayer &a_Player, bool a_ShouldApply, bool a_KeepEmptySlots, bool a_BackFill) override
Called to store as much of a_ItemStack in the area as possible.
Definition: SlotArea.cpp:2274
void HandleBrewedItem(cPlayer &a_Player, const cItem &a_ClickedItem)
Called after an item has been brewed to handle statistics etc.
Definition: SlotArea.cpp:2261
virtual const cItem * GetSlot(int a_SlotNum, cPlayer &a_Player) const override
Called to retrieve an item in the specified slot for the specified player.
Definition: SlotArea.cpp:2336
virtual const cItem * GetSlot(int a_SlotNum, cPlayer &a_Player) const override
Called to retrieve an item in the specified slot for the specified player.
Definition: SlotArea.cpp:2383
cSlotAreaMinecartWithChest(cMinecartWithChest *a_ChestCart, cWindow &a_ParentWindow)
Definition: SlotArea.cpp:2373
virtual void SetSlot(int a_SlotNum, cPlayer &a_Player, const cItem &a_Item) override
Called to set an item in the specified slot for the specified player.
Definition: SlotArea.cpp:2394
cMinecartWithChest * m_Chest
Definition: SlotArea.h:543
virtual const cItem * GetSlot(int a_SlotNum, cPlayer &a_Player) const override
Called to retrieve an item in the specified slot for the specified player.
Definition: SlotArea.cpp:2837
virtual void DistributeStack(cItem &a_ItemStack, cPlayer &a_Player, bool a_ShouldApply, bool a_KeepEmptySlots, bool a_BackFill) override
Called to store as much of a_ItemStack in the area as possible.
Definition: SlotArea.cpp:2873
virtual void SetSlot(int a_SlotNum, cPlayer &a_Player, const cItem &a_Item) override
Called to set an item in the specified slot for the specified player.
Definition: SlotArea.cpp:2856
virtual void Clicked(cPlayer &a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem &a_ClickedItem) override
Called when a player clicks in the window.
Definition: SlotArea.cpp:2790
cHorse & m_Horse
Definition: SlotArea.h:567
cSlotAreaHorse(cHorse &a_Horse, cWindow &a_ParentWindow)
Definition: SlotArea.cpp:2780
Represents a UI window.
Definition: Window.h:54
virtual void SetProperty(size_t a_Property, short a_Value)
Updates a numerical property associated with the window.
Definition: Window.cpp:406
void BroadcastWholeWindow(void)
Sends the contents of the whole window to all clients of this window.
Definition: Window.cpp:393
@ wtInventory
Definition: Window.h:58
virtual void DistributeStack(cItem &a_ItemStack, int a_Slot, cPlayer &a_Player, cSlotArea *a_ClickedArea, bool a_ShouldApply)=0
Called on shift-clicking to distribute the stack into other areas; Modifies a_ItemStack as it is dist...
bool CollectItemsToHand(cItem &a_Dragging, cSlotArea &a_Area, cPlayer &a_Player, bool a_CollectFullStacks)
Called on DblClicking to collect all stackable items from all areas into hand.
Definition: Window.cpp:490
void SendSlot(cPlayer &a_Player, cSlotArea *a_SlotArea, int a_RelativeSlotNum)
Used by cSlotAreas to send individual slots to clients, a_RelativeSlotNum is the slot number relative...
Definition: Window.cpp:507
int GetWindowType(void) const
Definition: Window.h:81
void BroadcastSlot(cSlotArea *a_Area, int a_LocalSlotNum)
Sends the specified slot's contents to all clients of this window; the slot is specified as local in ...
Definition: Window.cpp:350
Definition: World.h:53
bool GetBlockTypeMeta(Vector3i a_BlockPos, BLOCKTYPE &a_BlockType, NIBBLETYPE &a_BlockMeta) const
Retrieves the block type and meta at the specified coords.
Definition: World.cpp:1779
virtual void BroadcastSoundParticleEffect(const EffectID a_EffectID, Vector3i a_SrcPos, int a_Data, const cClientHandle *a_Exclude=nullptr) override
virtual std::vector< UInt32 > SpawnSplitExperienceOrbs(Vector3d a_Pos, int a_Reward) override
Spawns experience orbs of the specified total value at the given location.
Definition: World.cpp:1915
void SetBlockMeta(Vector3i a_BlockPos, NIBBLETYPE a_MetaData)
Sets the meta for the specified block, while keeping the blocktype.
Definition: World.cpp:1752
void SetBlock(Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
Sets the block at the specified coords to the specified value.
Definition: World.cpp:1743