Cuberite
A lightweight, fast and extensible game server for Minecraft
HopperEntity.cpp
Go to the documentation of this file.
1 
2 // HopperEntity.cpp
3 
4 // Implements the cHopperEntity representing a hopper block entity
5 
6 #include "Globals.h"
7 #include "HopperEntity.h"
8 #include "../Chunk.h"
9 #include "../Entities/Player.h"
10 #include "../Entities/Pickup.h"
11 #include "../Bindings/PluginManager.h"
12 #include "../UI/HopperWindow.h"
13 #include "ChestEntity.h"
14 #include "FurnaceEntity.h"
15 
16 
17 
18 
19 
20 // How many ticks at minimum between two item transfers to or from the hopper.
21 #define TICKS_PER_TRANSFER 8_tick
22 
23 
24 
25 
26 
27 cHopperEntity::cHopperEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos, cWorld * a_World):
28  Super(a_BlockType, a_BlockMeta, a_Pos, ContentsWidth, ContentsHeight, a_World),
29  m_LastMoveItemsInTick(0),
30  m_LastMoveItemsOutTick(0),
31  m_Locked(false)
32 {
33  ASSERT(a_BlockType == E_BLOCK_HOPPER);
34 }
35 
36 
37 
38 
39 
40 void cHopperEntity::SetLocked(bool a_Value)
41 {
42  m_Locked = a_Value;
43 }
44 
45 
46 
47 
48 
49 std::pair<bool, Vector3i> cHopperEntity::GetOutputBlockPos(NIBBLETYPE a_BlockMeta)
50 {
51  auto pos = GetPos();
52  switch (a_BlockMeta)
53  {
54  case E_META_HOPPER_FACING_XM: return {true, pos.addedX(-1)};
55  case E_META_HOPPER_FACING_XP: return {true, pos.addedX( 1)};
56  case E_META_HOPPER_FACING_YM: return {true, pos.addedY(-1)};
57  case E_META_HOPPER_FACING_ZM: return {true, pos.addedZ(-1)};
58  case E_META_HOPPER_FACING_ZP: return {true, pos.addedZ( 1)};
59  default:
60  {
61  // Not attached
62  return {false, pos};
63  }
64  }
65 }
66 
67 
68 
69 
70 
72 {
73  Super::CopyFrom(a_Src);
74  auto & src = static_cast<const cHopperEntity &>(a_Src);
75  m_LastMoveItemsInTick = src.m_LastMoveItemsInTick;
76  m_LastMoveItemsOutTick = src.m_LastMoveItemsOutTick;
77 }
78 
79 
80 
81 
82 
83 bool cHopperEntity::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
84 {
85  UNUSED(a_Dt);
86 
87  bool isDirty = false;
88  if (!m_Locked)
89  {
90  const auto CurrentTick = a_Chunk.GetWorld()->GetWorldAge();
91  isDirty = MoveItemsIn(a_Chunk, CurrentTick) || isDirty;
92  isDirty = MovePickupsIn(a_Chunk) || isDirty;
93  isDirty = MoveItemsOut(a_Chunk, CurrentTick) || isDirty;
94  }
95  return isDirty;
96 }
97 
98 
99 
100 
101 
103 {
104  // The hopper entity doesn't need anything sent to the client when it's created / gets in the viewdistance
105  // All the actual handling is in the cWindow UI code that gets called when the hopper is right-clicked
106 
107  UNUSED(a_Client);
108 }
109 
110 
111 
112 
113 
115 {
117 
118  // If the window is not created, open it anew:
119  cWindow * Window = GetWindow();
120  if (Window == nullptr)
121  {
122  OpenNewWindow();
123  Window = GetWindow();
124  }
125 
126  // Open the window for the player:
127  if (Window != nullptr)
128  {
129  if (a_Player->GetWindow() != Window)
130  {
131  a_Player->OpenWindow(*Window);
132  }
133  }
134 
135  return true;
136 }
137 
138 
139 
140 
141 
143 {
144  OpenWindow(new cHopperWindow(this));
145 }
146 
147 
148 
149 
150 
151 bool cHopperEntity::MoveItemsIn(cChunk & a_Chunk, const cTickTimeLong a_CurrentTick)
152 {
153  if (m_Pos.y >= cChunkDef::Height)
154  {
155  // This hopper is at the top of the world, no more blocks above
156  return false;
157  }
158 
159  if ((a_CurrentTick - m_LastMoveItemsInTick) < TICKS_PER_TRANSFER)
160  {
161  // Too early after the previous transfer
162  return false;
163  }
164 
165  // Try moving an item in:
166  bool res = false;
167  switch (a_Chunk.GetBlock(GetRelPos().addedY(1)))
168  {
169  case E_BLOCK_CHEST:
171  {
172  // Chests have special handling because of double-chests
173  res = MoveItemsFromChest(a_Chunk);
174  break;
175  }
176  case E_BLOCK_FURNACE:
177  case E_BLOCK_LIT_FURNACE:
178  {
179  // Furnaces have special handling because only the output and leftover fuel buckets shall be moved
180  res = MoveItemsFromFurnace(a_Chunk);
181  break;
182  }
183  case E_BLOCK_DISPENSER:
184  case E_BLOCK_DROPPER:
185  case E_BLOCK_HOPPER:
186  {
187  res = MoveItemsFromGrid(*static_cast<cBlockEntityWithItems *>(a_Chunk.GetBlockEntity(this->GetPos().addedY(1))));
188  break;
189  }
190  }
191 
192  // If the item has been moved, reset the last tick:
193  if (res)
194  {
195  m_LastMoveItemsInTick = a_CurrentTick;
196  }
197 
198  return res;
199 }
200 
201 
202 
203 
204 
206 {
207  class cHopperPickupSearchCallback
208  {
209  public:
210  cHopperPickupSearchCallback(Vector3i a_Pos, cItemGrid & a_Contents) :
211  m_Pos(a_Pos),
212  m_bFoundPickupsAbove(false),
213  m_Contents(a_Contents)
214  {
215  }
216 
217  bool operator () (cEntity & a_Entity)
218  {
219  if (!a_Entity.IsPickup())
220  {
221  return false;
222  }
223 
224  Vector3f EntityPos = a_Entity.GetPosition();
225  Vector3f BlockPos(m_Pos.x + 0.5f, static_cast<float>(m_Pos.y) + 1, m_Pos.z + 0.5f); // One block above hopper, and search from center outwards
226  double Distance = (EntityPos - BlockPos).Length();
227 
228  if (Distance < 0.5)
229  {
230  if (TrySuckPickupIn(static_cast<cPickup &>(a_Entity)))
231  {
232  return false;
233  }
234  }
235 
236  return false;
237  }
238 
239  bool TrySuckPickupIn(cPickup & a_Pickup)
240  {
241  cItem & Item = a_Pickup.GetItem();
242 
243  for (int i = 0; i < ContentsWidth * ContentsHeight; i++)
244  {
245  if (m_Contents.IsSlotEmpty(i))
246  {
247  m_bFoundPickupsAbove = true;
248  m_Contents.SetSlot(i, Item);
249  a_Pickup.Destroy(); // Kill pickup
250 
251  return true;
252  }
254  {
255  m_bFoundPickupsAbove = true;
256 
257  auto PreviousCount = m_Contents.GetSlot(i).m_ItemCount;
258 
259  Item.m_ItemCount -= m_Contents.ChangeSlotCount(i, Item.m_ItemCount) - PreviousCount; // Set count to however many items were added
260 
261  if (Item.IsEmpty())
262  {
263  a_Pickup.Destroy(); // Kill pickup if all items were added
264  }
265  return true;
266  }
267  }
268  return false;
269  }
270 
271  bool FoundPickupsAbove(void) const
272  {
273  return m_bFoundPickupsAbove;
274  }
275 
276  protected:
277  Vector3i m_Pos;
278  bool m_bFoundPickupsAbove;
280  };
281 
282  cHopperPickupSearchCallback HopperPickupSearchCallback(Vector3i(GetPosX(), GetPosY(), GetPosZ()), m_Contents);
283  a_Chunk.ForEachEntity(HopperPickupSearchCallback);
284 
285  return HopperPickupSearchCallback.FoundPickupsAbove();
286 }
287 
288 
289 
290 
291 
292 bool cHopperEntity::MoveItemsOut(cChunk & a_Chunk, const cTickTimeLong a_CurrentTick)
293 {
294  if ((a_CurrentTick - m_LastMoveItemsOutTick) < TICKS_PER_TRANSFER)
295  {
296  // Too early after the previous transfer
297  return false;
298  }
299 
300  // Get the coords of the block where to output items:
301  auto meta = a_Chunk.GetMeta(GetRelPos());
302  auto out = GetOutputBlockPos(meta);
303  if (!out.first)
304  {
305  // Not attached to another container
306  return false;
307  }
308  if (out.second.y < 0)
309  {
310  // Cannot output below the zero-th block level
311  return false;
312  }
313 
314  // Convert coords to relative:
315  auto relCoord = cChunkDef::AbsoluteToRelative(out.second);
316  auto destChunk = a_Chunk.GetRelNeighborChunkAdjustCoords(relCoord);
317  if (destChunk == nullptr)
318  {
319  // The destination chunk has been unloaded, don't tick
320  return false;
321  }
322 
323  // Call proper moving function, based on the blocktype present at the coords:
324  bool res = false;
325  auto absCoord = destChunk->RelativeToAbsolute(relCoord);
326  switch (destChunk->GetBlock(relCoord))
327  {
328  case E_BLOCK_CHEST:
330  {
331  // Chests have special handling because of double-chests
332  res = MoveItemsToChest(*destChunk, absCoord);
333  break;
334  }
335  case E_BLOCK_FURNACE:
336  case E_BLOCK_LIT_FURNACE:
337  {
338  // Furnaces have special handling because of the direction-to-slot relation
339  res = MoveItemsToFurnace(*destChunk, absCoord, meta);
340  break;
341  }
342  case E_BLOCK_DISPENSER:
343  case E_BLOCK_DROPPER:
344  case E_BLOCK_HOPPER:
345  {
346  auto blockEntity = static_cast<cBlockEntityWithItems *>(destChunk->GetBlockEntity(absCoord));
347  if (blockEntity == nullptr)
348  {
349  FLOGWARNING("{0}: A block entity was not found where expected at {1}", __FUNCTION__, absCoord);
350  return false;
351  }
352  res = MoveItemsToGrid(*blockEntity);
353  break;
354  }
355  }
356 
357  // If the item has been moved, reset the last tick:
358  if (res)
359  {
360  m_LastMoveItemsOutTick = a_CurrentTick;
361  }
362 
363  return res;
364 }
365 
366 
367 
368 
369 
371 {
372  const auto ConnectedBlockEntity = a_Chunk.GetBlockEntityRel(GetRelPos().addedY(1));
373 
374  if (ConnectedBlockEntity == nullptr)
375  {
376  return false;
377  }
378 
379  const auto ConnectedChest = static_cast<cChestEntity *>(ConnectedBlockEntity);
380 
381  if (MoveItemsFromGrid(ConnectedChest->GetPrimaryChest()))
382  {
383  return true;
384  }
385 
386  const auto SecondaryChest = ConnectedChest->GetSecondaryChest();
387  return (SecondaryChest != nullptr) && MoveItemsFromGrid(*SecondaryChest);
388 }
389 
390 
391 
392 
393 
395 {
396  auto furnace = static_cast<cFurnaceEntity *>(a_Chunk.GetBlockEntity(m_Pos.addedY(1)));
397  if (furnace == nullptr)
398  {
399  FLOGWARNING("{0}: A furnace entity was not found where expected, at {1}", __FUNCTION__, m_Pos.addedY(1));
400  return false;
401  }
402 
403  // Try move from the output slot:
405  {
406  cItem NewOutput(furnace->GetOutputSlot());
407  furnace->SetOutputSlot(NewOutput.AddCount(-1));
408  return true;
409  }
410 
411  // No output moved, check if we can move an empty bucket out of the fuel slot:
412  if (furnace->GetFuelSlot().m_ItemType == E_ITEM_BUCKET)
413  {
415  {
416  furnace->SetFuelSlot(cItem());
417  return true;
418  }
419  }
420 
421  // Nothing can be moved
422  return false;
423 }
424 
425 
426 
427 
428 
430 {
431  auto & Grid = a_Entity.GetContents();
432  int NumSlots = Grid.GetNumSlots();
433 
434  for (int i = 0; i < NumSlots; i++)
435  {
436  if (Grid.IsSlotEmpty(i))
437  {
438  continue;
439  }
440  if (MoveItemsFromSlot(a_Entity, i))
441  {
442  Grid.ChangeSlotCount(i, -1);
443  return true;
444  }
445  }
446  return false;
447 }
448 
449 
450 
451 
452 
454 {
455  cItem One(a_Entity.GetSlot(a_SlotNum).CopyOne());
456  for (int i = 0; i < ContentsWidth * ContentsHeight; i++)
457  {
458  if (m_Contents.IsSlotEmpty(i))
459  {
460  if (cPluginManager::Get()->CallHookHopperPullingItem(*m_World, *this, i, a_Entity, a_SlotNum))
461  {
462  // Plugin disagrees with the move
463  continue;
464  }
465 
466  m_Contents.SetSlot(i, One);
467  return true;
468  }
469  else if (m_Contents.GetSlot(i).IsEqual(One))
470  {
471  if (cPluginManager::Get()->CallHookHopperPullingItem(*m_World, *this, i, a_Entity, a_SlotNum))
472  {
473  // Plugin disagrees with the move
474  continue;
475  }
476 
477  auto PreviousCount = m_Contents.GetSlot(i).m_ItemCount;
479 
480  if (PreviousCount + 1 == m_Contents.GetSlot(i).m_ItemCount)
481  {
482  // Successfully added a new item. (Failure condition consistutes: stack full)
483  return true;
484  }
485  }
486  }
487  return false;
488 }
489 
490 
491 
492 
493 
495 {
496  const auto ConnectedBlockEntity = a_Chunk.GetBlockEntity(a_Coords);
497 
498  if (ConnectedBlockEntity == nullptr)
499  {
500  return false;
501  }
502 
503  const auto ConnectedChest = static_cast<cChestEntity *>(ConnectedBlockEntity);
504 
505  if (MoveItemsToGrid(ConnectedChest->GetPrimaryChest()))
506  {
507  return true;
508  }
509 
510  const auto SecondaryChest = ConnectedChest->GetSecondaryChest();
511  return (SecondaryChest != nullptr) && MoveItemsToGrid(*SecondaryChest);
512 }
513 
514 
515 
516 
517 
518 bool cHopperEntity::MoveItemsToFurnace(cChunk & a_Chunk, Vector3i a_Coords, NIBBLETYPE a_HopperMeta)
519 {
520  auto furnace = static_cast<cFurnaceEntity *>(a_Chunk.GetBlockEntity(a_Coords));
521  if (a_HopperMeta == E_META_HOPPER_FACING_YM)
522  {
523  // Feed the input slot of the furnace
524  return MoveItemsToSlot(*furnace, cFurnaceEntity::fsInput);
525  }
526  else
527  {
528  // Feed the fuel slot of the furnace
529  return MoveItemsToSlot(*furnace, cFurnaceEntity::fsFuel);
530  }
531 }
532 
533 
534 
535 
536 
538 {
539  // Iterate through our slots, try to move from each one:
540  int NumSlots = a_Entity.GetContents().GetNumSlots();
541  for (int i = 0; i < NumSlots; i++)
542  {
543  if (MoveItemsToSlot(a_Entity, i))
544  {
545  return true;
546  }
547  }
548  return false;
549 }
550 
551 
552 
553 
554 
555 bool cHopperEntity::MoveItemsToSlot(cBlockEntityWithItems & a_Entity, int a_DstSlotNum)
556 {
557  cItemGrid & Grid = a_Entity.GetContents();
558  if (Grid.IsSlotEmpty(a_DstSlotNum))
559  {
560  // The slot is empty, move the first non-empty slot from our contents:
561  for (int i = 0; i < ContentsWidth * ContentsHeight; i++)
562  {
563  if (!m_Contents.IsSlotEmpty(i))
564  {
565  if (cPluginManager::Get()->CallHookHopperPushingItem(*m_World, *this, i, a_Entity, a_DstSlotNum))
566  {
567  // A plugin disagrees with the move
568  continue;
569  }
570  Grid.SetSlot(a_DstSlotNum, m_Contents.GetSlot(i).CopyOne());
572  return true;
573  }
574  }
575  return false;
576  }
577  else
578  {
579  // The slot is taken, try to top it up:
580  const cItem & DestSlot = Grid.GetSlot(a_DstSlotNum);
581  if (DestSlot.IsFullStack())
582  {
583  return false;
584  }
585  for (int i = 0; i < ContentsWidth * ContentsHeight; i++)
586  {
587  if (m_Contents.GetSlot(i).IsEqual(DestSlot))
588  {
589  if (cPluginManager::Get()->CallHookHopperPushingItem(*m_World, *this, i, a_Entity, a_DstSlotNum))
590  {
591  // A plugin disagrees with the move
592  continue;
593  }
594  Grid.ChangeSlotCount(a_DstSlotNum, 1);
596  return true;
597  }
598  }
599  return false;
600  }
601 }
#define TICKS_PER_TRANSFER
@ E_META_HOPPER_FACING_XM
Definition: BlockType.h:698
@ E_META_HOPPER_FACING_ZM
Definition: BlockType.h:696
@ E_META_HOPPER_FACING_ZP
Definition: BlockType.h:697
@ E_META_HOPPER_FACING_XP
Definition: BlockType.h:699
@ E_META_HOPPER_FACING_YM
Definition: BlockType.h:694
@ E_BLOCK_FURNACE
Definition: BlockType.h:73
@ E_BLOCK_CHEST
Definition: BlockType.h:64
@ E_BLOCK_LIT_FURNACE
Definition: BlockType.h:74
@ E_BLOCK_TRAPPED_CHEST
Definition: BlockType.h:161
@ E_BLOCK_HOPPER
Definition: BlockType.h:171
@ E_BLOCK_DROPPER
Definition: BlockType.h:176
@ E_BLOCK_DISPENSER
Definition: BlockType.h:33
@ E_ITEM_BUCKET
Definition: BlockType.h:369
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
std::chrono::duration< signed long long int, cTickTime::period > cTickTimeLong
Definition: Globals.h:367
#define ASSERT(x)
Definition: Globals.h:276
#define UNUSED
Definition: Globals.h:72
void FLOGWARNING(std::string_view a_Format, const Args &... args)
Definition: LoggerSimple.h:41
Item
Definition: Items.h:4
Vector3< int > Vector3i
Definition: Vector3.h:487
unsigned char Distance(const BlockState Block)
static cPluginManager * Get(void)
Returns the instance of the Plugin Manager (there is only ever one)
int GetPosZ() const
Definition: BlockEntity.h:93
Vector3i GetPos() const
Definition: BlockEntity.h:90
int GetPosY() const
Definition: BlockEntity.h:92
int GetPosX() const
Definition: BlockEntity.h:91
Vector3i GetRelPos() const
Definition: BlockEntity.h:95
Vector3i m_Pos
Position in absolute block coordinates.
Definition: BlockEntity.h:113
cWorld * m_World
Definition: BlockEntity.h:126
cItemGrid & GetContents(void)
Returns the ItemGrid used for storing the contents.
virtual void CopyFrom(const cBlockEntity &a_Src) override
Copies all properties of a_Src into this entity, except for its m_World and location.
const cItem & GetSlot(int a_SlotNum) const
cChestEntity * GetSecondaryChest()
Returns the associated secondary chest, if any.
Definition: ChestEntity.cpp:46
bool MoveItemsIn(cChunk &a_Chunk, cTickTimeLong a_CurrentTick)
Moves items from the container above it into this hopper.
virtual void SendTo(cClientHandle &a_Client) override
Sends the packet defining the block entity to the client specified.
bool MoveItemsToGrid(cBlockEntityWithItems &a_Entity)
Moves items to the specified ItemGrid.
cHopperEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos, cWorld *a_World)
Constructor used for normal operation.
void SetLocked(bool a_Value)
bool MoveItemsToSlot(cBlockEntityWithItems &a_Entity, int a_DstSlotNum)
Moves one piece to the specified entity's contents' slot.
bool MoveItemsToChest(cChunk &a_Chunk, Vector3i a_Coords)
Moves items to the chest at the specified absolute coords.
bool MoveItemsToFurnace(cChunk &a_Chunk, Vector3i a_Coords, NIBBLETYPE a_HopperMeta)
Moves items to the furnace at the specified absolute coords.
bool MoveItemsOut(cChunk &a_Chunk, cTickTimeLong a_CurrentTick)
Moves items out from this hopper into the destination.
void OpenNewWindow(void)
Opens a new chest window for this chest.
bool MoveItemsFromFurnace(cChunk &a_Chunk)
Moves items from a furnace above the hopper into this hopper.
cTickTimeLong m_LastMoveItemsInTick
Definition: HopperEntity.h:50
virtual bool UsedBy(cPlayer *a_Player) override
Called when a player uses this entity; should open the UI window.
bool MovePickupsIn(cChunk &a_Chunk)
Moves pickups from above this hopper into it.
bool MoveItemsFromChest(cChunk &a_Chunk)
Moves items from a chest (dblchest) above the hopper into this hopper.
std::pair< bool, Vector3i > GetOutputBlockPos(NIBBLETYPE a_BlockMeta)
Returns the block coords of the block receiving the output items, based on the meta Returns <false,...
virtual void CopyFrom(const cBlockEntity &a_Src) override
Copies all properties of a_Src into this entity, except for its m_World and location.
cTickTimeLong m_LastMoveItemsOutTick
Definition: HopperEntity.h:51
bool MoveItemsFromSlot(cBlockEntityWithItems &a_Entity, int a_SrcSlotNum)
Moves one piece from the specified itemstack into this hopper.
virtual bool Tick(std::chrono::milliseconds a_Dt, cChunk &a_Chunk) override
Ticks the entity; returns true if the chunk should be marked as dirty as a result of this ticking.
bool MoveItemsFromGrid(cBlockEntityWithItems &a_Entity)
Moves items from the specified a_Entity's Contents into this hopper.
Definition: Chunk.h:36
NIBBLETYPE GetMeta(int a_RelX, int a_RelY, int a_RelZ) const
Definition: Chunk.h:279
bool ForEachEntity(cEntityCallback a_Callback) const
Calls the callback for each entity; returns true if all entities processed, false if the callback abo...
Definition: Chunk.cpp:1657
BLOCKTYPE GetBlock(int a_RelX, int a_RelY, int a_RelZ) const
Definition: Chunk.h:146
Vector3i RelativeToAbsolute(Vector3i a_RelBlockPosition) const
Converts the coord relative to this chunk into an absolute coord.
Definition: Chunk.h:450
cChunk * GetRelNeighborChunkAdjustCoords(Vector3i &a_RelPos) const
Returns the chunk into which the relatively-specified block belongs.
Definition: Chunk.cpp:1885
cBlockEntity * GetBlockEntity(Vector3i a_AbsPos)
Returns the block entity at the specified (absolute) coords.
Definition: Chunk.cpp:1418
cWorld * GetWorld(void) const
Definition: Chunk.h:135
cBlockEntity * GetBlockEntityRel(Vector3i a_RelPos)
Returns the block entity at the specified (relative) coords.
Definition: Chunk.cpp:1436
static void AbsoluteToRelative(int &a_X, int &a_Y, int &a_Z, int &a_ChunkX, int &a_ChunkZ)
Converts absolute block coords into relative (chunk + block) coords:
Definition: ChunkDef.h:147
static const int Height
Definition: ChunkDef.h:125
Definition: Entity.h:76
bool IsPickup(void) const
Definition: Entity.h:161
void Destroy()
Destroys the entity, schedules it for memory freeing and broadcasts the DestroyEntity packet.
Definition: Entity.cpp:243
const Vector3d & GetPosition(void) const
Exported in ManualBindings.
Definition: Entity.h:297
Definition: Pickup.h:20
cItem & GetItem(void)
Definition: Pickup.h:31
Definition: Player.h:29
StatisticsManager & GetStatistics()
Return the associated statistic and achievement manager.
Definition: Player.h:237
void OpenWindow(cWindow &a_Window)
Opens the specified window; closes the current one first using CloseWindow()
Definition: Player.cpp:1123
cWindow * GetWindow(void)
Definition: Player.h:262
Definition: Item.h:37
cItem & AddCount(char a_AmountToAdd)
Adds the specified count to this object and returns the reference to self (useful for chaining)
Definition: Item.cpp:104
char m_ItemCount
Definition: Item.h:164
bool IsEqual(const cItem &a_Item) const
Definition: Item.h:76
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
bool IsSlotEmpty(int a_SlotNum) const
Returns true if the specified slot is empty or the slot doesn't exist.
Definition: ItemGrid.cpp:203
char ChangeSlotCount(int a_SlotNum, char a_AddToCount)
Adds (or subtracts, if a_AddToCount is negative) to the count of items in the specified slot.
Definition: ItemGrid.cpp:468
void SetSlot(int a_X, int a_Y, const cItem &a_Item)
Definition: ItemGrid.cpp:121
const cItem & GetSlot(int a_X, int a_Y) const
Definition: ItemGrid.cpp:96
int GetNumSlots(void) const
Definition: ItemGrid.h:40
std::unordered_map< CustomStatistic, StatValue > Custom
Represents a UI window.
Definition: Window.h:54
cWindow * GetWindow(void) const
Definition: WindowOwner.h:40
void OpenWindow(cWindow *a_Window)
Definition: WindowOwner.h:34
Vector3< T > addedY(T a_AddY) const
Returns a copy of this vector moved by the specified amount on the y axis.
Definition: Vector3.h:314
T x
Definition: Vector3.h:17
T y
Definition: Vector3.h:17
T z
Definition: Vector3.h:17
Definition: World.h:53
virtual cTickTimeLong GetWorldAge(void) const override
Definition: World.cpp:491