summaryrefslogtreecommitdiffstats
path: root/src/ItemGrid.h
blob: 28f45cfeb4fa568eb4cc4527ea693ad106e84f4d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212

// ItemGrid.h

// Declares the cItemGrid class representing a storage for items in a XY grid (chests, dispensers, inventory etc.)




#pragma once

#include "Item.h"
#include "LazyArray.h"





// tolua_begin
class cItemGrid
{
  public:
	// tolua_end

	/** This class is used as a callback for when a slot changes */
	class cListener
	{
	  public:
		virtual ~cListener() {}

		/** Called whenever a slot changes */
		virtual void OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum) = 0;
	};
	typedef std::vector<cListener *> cListeners;

	cItemGrid(int a_Width, int a_Height);

	// tolua_begin
	int GetWidth(void) const { return m_Width; }
	int GetHeight(void) const { return m_Height; }
	int GetNumSlots(void) const { return m_Slots.size(); }

	/** Converts XY coords into slot number; returns -1 on invalid coords */
	int GetSlotNum(int a_X, int a_Y) const;

	// tolua_end

	/** Converts slot number into XY coords; sets coords to -1 on invalid slot number. Exported in ManualBindings.cpp */
	void GetSlotCoords(int a_SlotNum, int & a_X, int & a_Y) const;

	/** Copies all items from a_Src to this grid.
	Doesn't copy the listeners. */
	void CopyFrom(const cItemGrid & a_Src);

	// tolua_begin

	// Retrieve slots by coords or slot number; Logs warning and returns the first slot on invalid coords / slotnum
	const cItem & GetSlot(int a_X, int a_Y) const;
	const cItem & GetSlot(int a_SlotNum) const;

	// Set slot by coords or slot number; Logs warning and doesn't set on invalid coords / slotnum
	void SetSlot(int a_X, int a_Y, const cItem & a_Item);
	void SetSlot(int a_X, int a_Y, short a_ItemType, char a_ItemCount, short a_ItemDamage);
	void SetSlot(int a_SlotNum, const cItem & a_Item);
	void SetSlot(int a_SlotNum, short a_ItemType, char a_ItemCount, short a_ItemDamage);

	// Empty the specified slot; Logs warning and doesn't set on invalid coords / slotnum
	void EmptySlot(int a_X, int a_Y);
	void EmptySlot(int a_SlotNum);

	/** Returns true if the specified slot is empty or the slot doesn't exist */
	bool IsSlotEmpty(int a_SlotNum) const;

	/** Returns true if the specified slot is empty or the slot doesn't exist */
	bool IsSlotEmpty(int a_X, int a_Y) const;

	/** Sets all items as empty */
	void Clear(void);

	/** Returns number of items out of a_ItemStack that can fit in the storage */
	int HowManyCanFit(const cItem & a_ItemStack, bool a_AllowNewStacks = true);

	/** Adds as many items out of a_ItemStack as can fit.
	If a_AllowNewStacks is set to false, only existing stacks can be topped up;
	If a_AllowNewStacks is set to true, empty slots can be used for the rest.
	If a_PrioritySlot is set to a positive value, then the corresponding slot will be used  first (if empty or
	compatible with added items). If a_PrioritySlot is set to -1, regular order applies. Returns the number of items
	that fit.
	*/
	char AddItem(cItem & a_ItemStack, bool a_AllowNewStacks = true, int a_PrioritySlot = -1);

	/** Same as AddItem, but works on an entire list of item stacks.
	The a_ItemStackList is modified to reflect the leftover items.
	If a_AllowNewStacks is set to false, only existing stacks can be topped up;
	If a_AllowNewStacks is set to true, empty slots can be used for the rest.
	If a_PrioritySlot is set to a positive value, then the corresponding slot will be used first (if empty or compatible
	with added items). If a_PrioritySlot is set to -1, regular order applies. Returns the total number of items that
	fit.
	*/
	char AddItems(cItems & a_ItemStackList, bool a_AllowNewStacks = true, int a_PrioritySlot = -1);

	/** Removes the specified item from the grid, as many as possible, up to a_ItemStack.m_ItemCount.
	Returns the number of items that were removed. */
	char RemoveItem(const cItem & a_ItemStack);

	/** Finds an item based on ItemType and ItemDamage (<- defines the itemType, too) */
	cItem * FindItem(const cItem & a_RecipeItem);

	/** Adds (or subtracts, if a_AddToCount is negative) to the count of items in the specified slot.
	If the slot is empty, ignores the call.
	Returns the new count.
	*/
	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.
	If the slot is empty, ignores the call.
	Returns the new count.
	*/
	char ChangeSlotCount(int a_X, int a_Y, char a_AddToCount);

	/** Removes one item from the stack in the specified slot, and returns it.
	If the slot was empty, returns an empty item
	*/
	cItem RemoveOneItem(int a_SlotNum);

	/** Removes one item from the stack in the specified slot, and returns it.
	If the slot was empty, returns an empty item
	*/
	cItem RemoveOneItem(int a_X, int a_Y);

	/** Returns the number of items of type a_Item that are stored */
	int HowManyItems(const cItem & a_Item);

	/** Returns true if there are at least as many items of type a_ItemStack as in a_ItemStack */
	bool HasItems(const cItem & a_ItemStack);

	/** Returns the index of the first empty slot; -1 if all full */
	int GetFirstEmptySlot(void) const;

	/** Returns the index of the first non-empty slot; -1 if all empty */
	int GetFirstUsedSlot(void) const;

	/** Returns the index of the last empty slot; -1 if all full */
	int GetLastEmptySlot(void) const;

	/** Returns the index of the last used slot; -1 if all empty */
	int GetLastUsedSlot(void) const;

	/** Returns the index of the first empty slot following a_StartFrom (a_StartFrom is not checked) */
	int GetNextEmptySlot(int a_StartFrom) const;

	/** Returns the index of the first used slot following a_StartFrom (a_StartFrom is not checked) */
	int GetNextUsedSlot(int a_StartFrom) const;

	/** Copies the contents into a cItems object; preserves the original a_Items contents */
	void CopyToItems(cItems & a_Items) const;

	/** Adds the specified damage to the specified item; returns true if the item broke (but the item is left intact) */
	bool DamageItem(int a_SlotNum, short a_Amount);

	/** Adds the specified damage to the specified item; returns true if the item broke (but the item is left intact) */
	bool DamageItem(int a_X, int a_Y, short a_Amount);

	// tolua_end


	/** Returns true if slot coordinates lie within the grid. */
	bool IsValidSlotCoords(int a_X, int a_Y) const;

	/** Returns true if slot number is within the grid. */
	bool IsValidSlotNum(int a_SlotNum) const;

	/** Generates random loot from the specified loot probability table, with a chance of enchanted books added.
	A total of a_NumSlots are taken by the loot.
	Cannot export to Lua due to raw array a_LootProbabs. TODO: Make this exportable / export through ManualBindings.cpp
	with a Lua table as LootProbabs
	*/
	void GenerateRandomLootWithBooks(
		const cLootProbab * a_LootProbabs,
		size_t a_CountLootProbabs,
		int a_NumSlots,
		int a_Seed
	);

	/** Adds a callback that gets called whenever a slot changes. Must not be called from within the listener callback!
	 */
	void AddListener(cListener & a_Listener);

	/** Removes a slot-change-callback. Must not be called from within the listener callback! */
	void RemoveListener(cListener & a_Listener);

	// tolua_begin

  protected:
	int m_Width;
	int m_Height;
	cLazyArray<cItem> m_Slots;

	cListeners
		m_Listeners;  ///< Listeners which should be notified on slot changes; the pointers are not owned by this object
	cCriticalSection m_CSListeners;  ///< CS that guards the m_Listeners against multi-thread access
	bool m_IsInTriggerListeners;  ///< Set to true while TriggerListeners is running, to detect attempts to manipulate
								  ///< listener list while triggerring

	/** Calls all m_Listeners for the specified slot number */
	void TriggerListeners(int a_SlotNum);

	/** Adds up to a_Num items out of a_ItemStack, as many as can fit, in specified slot
	Returns the number of items that did fit.
	*/
	char AddItemToSlot(const cItem & a_ItemStack, int a_Slot, int a_Num, int a_MaxStack);
};
// tolua_end