summaryrefslogtreecommitdiffstats
path: root/src/ItemGrid.h
blob: 090649c4411553336a8f663bf4c3be11e547d3ce (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

// ItemGrid.h

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




#pragma once

#include "Item.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);

	~cItemGrid();

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

	/** 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;

	// 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_PrioritarySlot is set to a positive value, then the corresponding slot will be used in
	first (if empty or compatible with added items)
	if a_PrioritarySlot is set to -1, regular order apply
	Returns the number of items that fit.
	*/
	int AddItem(cItem & a_ItemStack, bool a_AllowNewStacks = true, int a_PrioritarySlot = -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_PrioritarySlot is set to a positive value, then the corresponding slot will be used in
	first (if empty or compatible with added items)
	if a_PrioritarySlot is set to -1, regular order apply
	Returns the total number of items that fit.
	*/
	int AddItems(cItems & a_ItemStackList, bool a_AllowNewStacks = true, int a_PrioritarySlot = -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. */
	int RemoveItem(const cItem & a_ItemStack);

	/** 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.
	*/
	int ChangeSlotCount(int a_SlotNum, int 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.
	*/
	int ChangeSlotCount(int a_X, int a_Y, int 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


	/** 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;
	int     m_NumSlots;  // m_Width * m_Height, for easier validity checking in the access functions
	cItem * m_Slots;     // x + m_Width * y

	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.
	*/
	int AddItemToSlot(const cItem & a_ItemStack, int a_Slot, int a_Num, int a_MaxStack);
} ;
// tolua_end