-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathinventory.gml
More file actions
270 lines (216 loc) · 7.67 KB
/
inventory.gml
File metadata and controls
270 lines (216 loc) · 7.67 KB
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
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
/* GML-INVENTORY-SYSTEM
- A set of functions to create an inventory system for Game Maker Studio 2 written in GML
- Feel free to use however you wish!
- created by Anthony Silva AKA "Burning Eyece"
*/
/* NOTES
- our concept of an "inventory" will be an array of objects where each object represents an item slot
- i.e. [ { id: 2, amt: 10 }, { id: 4, amt: 1 }, ... ]
- "inv" stands for "inventory"
- this could probably be written as an inventory Class instead with methods instead of all these functions
*/
#region standard inventory functions
// returns the given array with empty "inventory" objects to reach the given size
// use this for initializing a new inventory or adding additional size to an existing inventory
function fnInvInit(_inv = [], _extraSize = 4) {
var currentSize = array_length(_inv)
var targetSize = currentSize + _extraSize
// set to empty objects of the "inventory" format
for (var i = currentSize; i < targetSize; i++) {
_inv[@ i] = {
id: -1, // item ID, -1 represent no item, it is an empty slot
amt: 0, // item quantity
}
}
// return the array in the case where an inv has just been created
// this array is now considered an inventory because of its new structure
return _inv
}
// return whether or not every slot in the inventory is empty
function fnInvIsEmpty(_inv) {
for (var i = 0; i < array_length(_inv); i++) {
if (_inv.id > -1)
return false
}
return true
}
// return whether or not every slot in the inventory is NOT empty
function fnInvIsFull(_inv) {
for (var i = 0; i < array_length(_inv); i++) {
if (_inv.id == -1)
return false
}
return true
}
// return the number of items in the given inventory
// this could be used for displaying some info text about how many items are in the inventory vs the total capacity
function fnInvGetItemCount(_inv, _isCountingStacks = false) {
var total = 0
for (var i = 0; i < array_length(_inv); i++) {
// if there is an item in this slot update the total
if (_inv.id > -1) {
total += _isCountingStacks ? _inv.amt : 1
}
}
return total
}
// find the first index that has the given item id, otherwise return -1
// use this for finding where a certain item is in the inventory
function fnInvFindIndex(_inv, _itemId) {
for (var i = 0; i < array_length(_inv); i++) {
if (_inv.id == _itemId)
return i
}
return -1
}
// check if the given inventory has the given item and given amount of that item
// TODO - loop through to count up non stackable items
function fnInvQuery(_inv, _itemId, _itemAmt = 1) {
var index = fnInvFindIndex(_inv, _itemId)
// if we couldn't find the index then the item doesn't exist in the inventory
if (index == -1)
return false
else
// if we have the item and at least as much of the amount as the query is asking for then return true
return _inv[index, 1] >= _itemAmt
}
// add given item to the given index in the given inv
function fnInvAddIndex(_inv, _index, _itemId, _itemAmt = 1) {
var isItemAdded = false
// only add item if this slot is free
if (_inv[_index].id == -1) {
_inv[@_index].id = _itemId
_inv[@_index].amt = _itemAmt
isItemAdded = true
} else {
// show custom error message
cle("that inventory slot it full!")
}
return isItemAdded
}
// add given item and amount to the given inv
function fnInvAdd(_inv, _itemId, _itemAmt = 1) {
// don't bother running this function if the inventory is full
if (fnInvIsFull()) {
// show a custom message
fnFeedWarn("Inventory full!")
exit
}
// this function must be written independently as part of the item system, not the inventory system
var isStackable = fnIsItemStackable(_itemId)
var index = fnInvFindIndex(_inv, _itemId)
var itemsAdded = 0
// add to an existing stack
if (isStackable && fnInvQuery(_inv, _itemId)) {
_inv[@index].amt += _itemAmt
// all the items have been able to be added
return _itemAmt
}
// otherwise, find an empty slot and add it there
for (var i = 0; i < array_length(_inv); i++) {
// stop trying to add an item once the inv is full
if (fnInvIsFull(_inv)) {
break
}
// if an empty slot is found
if (_inv[i].id == -1) {
// non stackable items can only hold 1 for their amt
if (!isStackable) {
_inv[@i].id = _itemId
_inv[@i].amt = 1
itemsAdded++
// stop the loop if we have added enough items
if (itemsAdded == _itemAmt)
break
} else {
_inv[@i].id = _itemId
_inv[@i].amt = _itemAmt
// all the items have been able to be added
return _itemAmt
}
}
}
// return how many items actually were able to be added to the inventory
return itemsAdded
}
// remove the item in the given index of the given inventory
function fnInvRemoveIndex(_inv, _invIndex) {
// remove item at that index
// essentially setting it back to an empty item slot
_inv[@_invIndex] = {
id: -1,
amt: 0,
}
}
// remove the given amount of a given item from the given inventory
function fnInvRemove(_inv, _itemId, _itemAmt = 1) {
// this function must be written independently as part of the item system, not the inventory system
var isStackable = fnIsItemStackable(_itemId)
// continue to remove the given item from the inventory until the amount has been satisfied
// or we no longer have the item
while (_itemAmt > 0 or !fnInvQuery(_inv, _itemId, 1)) {
var thisIndex = fnInvFindIndex(_inv, _itemId)
var thisItem = _inv[thisIndex]
// determine how many items to remove from this slot and remove them
var itemsToRemove = min(thisItem.amt, _itemAmt)
thisItem.amt -= itemsToRemove
_itemAmt -= itemsToRemove
// if we have removed all the amount of the item in this slot then the item needs to be removed
if (_inv[index].amt <= 0) {
fnInvRemoveIndex(_inv, index)
}
}
}
// removes all items in the given inventory
function fnInvClear(_inv) {
for (var i = 0; i < array_length(_inv); i++) {
fnInvRemoveIndex(_inv, i)
}
}
// takes an inv, creates a sorted inv and then assigns the inv to the newly sorted inv using the Bubble Sort method
// sorts by item tiers and then by item id
function fnInvSort(_inv) {
var sorted = false
while (!sorted) {
sorted = true
for (var i = 1; i < array_length(_inv); i++) {
var first = _inv[i - 1, 0]
var second = _inv.id
// get the tier of both items
var firstTier = fnGetItemTier(first)
var secondTier = fnGetItemTier(second)
// check if both items are the same tier
var isSameTier = firstTier == secondTier
// if both items are same tier use their item ids to compare them instead
var firstValue = isSameTier ? first : firstTier
var secondValue = isSameTier ? second : secondTier
// sort zeros to the end (empty spaces)
// if items are the same and stackable, add them together in the same stack
var edgeCase1 = (first != 0 && first == second) && fnIsItemStackable(first)
// always swap if the first is a 0 and second is a non-zero
var edgeCase2 = first == 0 && second > 0
// always swap if first is greater than a non-zero
var normalCase = second != 0 && firstValue > secondValue
// combine these two items into one stack in the slot of the first
if (edgeCase1) {
_inv[@i - 1].amt += _inv.amt
_inv[@i].id = 0
_inv[@i].amt = 0
sorted = false
break
}
// swap items between the two slots
if (edgeCase2 || normalCase) {
var temp = {}
temp.id = _inv.id
temp.amt = _inv.amt
_inv[@i].id = _inv[i - 1].id
_inv[@i].amt = _inv[i - 1].amt
_inv[@i - 1].id = temp.id
_inv[@i - 1].amt = temp.amt
sorted = false
}
}
}
}
#endregion