1 /*
2 * inventory.c
3 * Copyright (C) 2009-2018 Joachim de Groot <jdegroot@web.de>
4 *
5 * NLarn is free software: you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * NLarn is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * See the GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include <glib.h>
20
21 #include "amulets.h"
22 #include "game.h"
23 #include "inventory.h"
24 #include "items.h"
25 #include "extdefs.h"
26 #include "potions.h"
27
28 /* functions */
29
inv_new(gconstpointer owner)30 inventory *inv_new(gconstpointer owner)
31 {
32 inventory *ninv;
33
34 ninv = g_malloc0(sizeof(inventory));
35 ninv->content = g_ptr_array_new();
36
37 ninv->owner = owner;
38
39 return ninv;
40 }
41
inv_destroy(inventory * inv,gboolean special)42 void inv_destroy(inventory *inv, gboolean special)
43 {
44 g_assert(inv != NULL);
45
46 while (inv_length(inv) > 0)
47 {
48 item *it = inv_get(inv, inv_length(inv) - 1);
49
50 if (special)
51 {
52 /* Mark potion of cure dianthroritis and eye of larn
53 as never having been created. */
54 if (it->type == IT_POTION && it->id == PO_CURE_DIANTHR)
55 nlarn->cure_dianthr_created = FALSE;
56 else if (it->type == IT_AMULET && it->id == AM_LARN)
57 nlarn->amulet_created[AM_LARN] = FALSE;
58 }
59 g_ptr_array_remove(inv->content, it->oid);
60 item_destroy(it);
61 }
62
63 g_ptr_array_free(inv->content, TRUE);
64
65 g_free(inv);
66 }
67
inv_serialize(inventory * inv)68 cJSON *inv_serialize(inventory *inv)
69 {
70 cJSON *sinv = cJSON_CreateArray();
71
72 for (guint idx = 0; idx < inv_length(inv); idx++)
73 {
74 item *it = inv_get(inv, idx);
75 cJSON_AddItemToArray(sinv, cJSON_CreateNumber(GPOINTER_TO_UINT(it->oid)));
76 }
77
78 return sinv;
79 }
80
inv_deserialize(cJSON * iser)81 inventory *inv_deserialize(cJSON *iser)
82 {
83 inventory *inv = g_malloc0(sizeof(inventory));
84 inv->content = g_ptr_array_new();
85
86 for (int idx = 0; idx < cJSON_GetArraySize(iser); idx++)
87 {
88 guint oid = cJSON_GetArrayItem(iser, idx)->valueint;
89 g_ptr_array_add(inv->content, GUINT_TO_POINTER(oid));
90 }
91
92 return inv;
93 }
94
inv_callbacks_set(inventory * inv,inv_callback_bool pre_add,inv_callback_void post_add,inv_callback_bool pre_del,inv_callback_void post_del)95 void inv_callbacks_set(inventory *inv, inv_callback_bool pre_add,
96 inv_callback_void post_add, inv_callback_bool pre_del,
97 inv_callback_void post_del)
98 {
99 g_assert (inv != NULL);
100
101 inv->pre_add = pre_add;
102 inv->post_add = post_add;
103 inv->pre_del = pre_del;
104 inv->post_del = post_del;
105 }
106
inv_add(inventory ** inv,item * it)107 int inv_add(inventory **inv, item *it)
108 {
109 g_assert(inv != NULL && it != NULL && it->oid != NULL);
110
111 /* create inventory if necessary */
112 if (!(*inv))
113 {
114 *inv = inv_new(NULL);
115 }
116
117 /* check if pre_add callback is set */
118 if ((*inv)->pre_add)
119 {
120 /* call pre_add callback */
121 if (!(*inv)->pre_add(*inv, it))
122 {
123 return FALSE;
124 }
125 }
126
127 /* stack stackable items */
128 if (item_is_stackable(it->type))
129 {
130 /* loop through items in the target inventory to find a similar item */
131 for (guint idx = 0; idx < inv_length(*inv); idx++)
132 {
133 item *i = inv_get(*inv, idx);
134 /* compare the current item with the one which is to be added */
135 if (item_compare(i, it))
136 {
137 /* just increase item count and release the original */
138 i->count += it->count;
139 item_destroy(it);
140
141 it = NULL;
142
143 break;
144 }
145 }
146 }
147
148 if (it != NULL)
149 {
150 /* add the item to the inventory if it has not already been added */
151 g_ptr_array_add((*inv)->content, it->oid);
152 }
153
154 /* call post_add callback */
155 if ((*inv)->post_add)
156 {
157 (*inv)->post_add(*inv, it);
158 }
159
160 return inv_length(*inv);
161 }
162
inv_get(inventory * inv,guint idx)163 item *inv_get(inventory *inv, guint idx)
164 {
165 g_assert (inv != NULL && idx < inv->content->len);
166 gpointer oid = g_ptr_array_index(inv->content, idx);
167
168 return game_item_get(nlarn, oid);
169 }
170
inv_del(inventory ** inv,guint idx)171 item *inv_del(inventory **inv, guint idx)
172 {
173 item *itm;
174
175 g_assert(*inv != NULL && (*inv)->content != NULL && idx < inv_length(*inv));
176
177 itm = inv_get(*inv, idx);
178
179 if ((*inv)->pre_del)
180 {
181 if (!(*inv)->pre_del(*inv, itm))
182 {
183 return NULL;
184 }
185 }
186
187 g_ptr_array_remove_index((*inv)->content, idx);
188
189 if ((*inv)->post_del)
190 {
191 (*inv)->post_del(*inv, itm);
192 }
193
194 /* destroy inventory if empty and not owned by anybody */
195 if (!inv_length(*inv) && !(*inv)->owner)
196 {
197 inv_destroy(*inv, FALSE);
198 *inv = NULL;
199 }
200
201 return itm;
202 }
203
inv_del_element(inventory ** inv,item * it)204 int inv_del_element(inventory **inv, item *it)
205 {
206 g_assert(*inv != NULL && (*inv)->content != NULL && it != NULL);
207
208 if ((*inv)->pre_del)
209 {
210 if (!(*inv)->pre_del(*inv, it))
211 {
212 return FALSE;
213 }
214 }
215
216 g_ptr_array_remove((*inv)->content, it->oid);
217
218 if ((*inv)->post_del)
219 {
220 (*inv)->post_del(*inv, it);
221 }
222
223 /* destroy inventory if empty and not owned by anybody */
224 if (!inv_length(*inv) && !(*inv)->owner)
225 {
226 inv_destroy(*inv, FALSE);
227 *inv = NULL;
228 }
229
230 return TRUE;
231 }
232
inv_del_oid(inventory ** inv,gpointer oid)233 int inv_del_oid(inventory **inv, gpointer oid)
234 {
235 g_assert(*inv != NULL && (*inv)->content != NULL && oid != NULL);
236
237 if (!g_ptr_array_remove((*inv)->content, oid))
238 {
239 return FALSE;
240 }
241
242 /* destroy inventory if empty and not owned by anybody */
243 if (!inv_length(*inv) && !(*inv)->owner)
244 {
245 inv_destroy(*inv, FALSE);
246 *inv = NULL;
247 }
248
249 return TRUE;
250 }
251
inv_erode(inventory ** inv,item_erosion_type iet,gboolean visible,int (* ifilter)(item *))252 void inv_erode(inventory **inv, item_erosion_type iet,
253 gboolean visible, int (*ifilter)(item *))
254 {
255 g_assert(inv != NULL);
256
257 for (guint idx = 0; idx < inv_length(*inv); idx++)
258 {
259 item *it = inv_get(*inv, idx);
260
261 /*
262 * If no filter was given, erode all items, otherwise
263 * those which are agreed on by the filter function.
264 */
265 if (ifilter == NULL || ifilter(it))
266 {
267 item_erode(inv, it, iet, visible);
268 }
269 }
270 }
271
inv_length(inventory * inv)272 guint inv_length(inventory *inv)
273 {
274 return (inv == NULL) ? 0 : inv->content->len;
275 }
276
inv_sort(inventory * inv,GCompareDataFunc compare_func,gpointer user_data)277 void inv_sort(inventory *inv, GCompareDataFunc compare_func, gpointer user_data)
278 {
279 g_assert(inv != NULL && inv->content != NULL);
280
281 g_ptr_array_sort_with_data(inv->content, compare_func, user_data);
282 }
283
inv_weight(inventory * inv)284 int inv_weight(inventory *inv)
285 {
286 int sum = 0;
287
288 if (inv == NULL)
289 {
290 return 0;
291 }
292
293 /* add contents weight */
294 for (guint idx = 0; idx < inv_length(inv); idx++)
295 {
296 sum += item_weight(inv_get(inv, idx));
297 }
298
299 return sum;
300 }
301
inv_length_filtered(inventory * inv,int (* ifilter)(item *))302 guint inv_length_filtered(inventory *inv, int (*ifilter)(item *))
303 {
304 int count = 0;
305
306 if (inv == NULL)
307 {
308 /* check for non-existent inventories */
309 return 0;
310 }
311
312 /* return the inventory length if no filter has been set */
313 if (!ifilter)
314 {
315 return inv_length(inv);
316 }
317
318 for (guint pos = 0; pos < inv_length(inv); pos++)
319 {
320 item *i = inv_get(inv, pos);
321
322 if (ifilter(i))
323 {
324 count++;
325 }
326 }
327
328 return count;
329 }
330
inv_get_filtered(inventory * inv,guint idx,int (* ifilter)(item *))331 item *inv_get_filtered(inventory *inv, guint idx, int (*ifilter)(item *))
332 {
333 guint curr = 0;
334
335 /* return the inventory length if no filter has been set */
336 if (!ifilter)
337 {
338 return inv_get(inv, idx);
339 }
340
341 for (guint num = 0; num < inv_length(inv); num++)
342 {
343 item *i = inv_get(inv, num);
344
345 if (ifilter(i))
346 {
347 /* filter matches */
348 if (curr == idx)
349 {
350 /* this is the requested item */
351 return i;
352 }
353 else
354 {
355 curr++;
356 }
357 }
358 }
359
360 /* not found */
361 return NULL;
362 }
363