comparison urogue/bag.c @ 256:c495a4f288c6

Import UltraRogue from the Roguelike Restoration Project (r1490)
author John "Elwin" Edwards
date Tue, 31 Jan 2017 19:56:04 -0500
parents
children 0250220d8cdd
comparison
equal deleted inserted replaced
253:d9badb9c0179 256:c495a4f288c6
1 /*
2 bag.c - functions for dealing with bags
3
4 UltraRogue: The Ultimate Adventure in the Dungeons of Doom
5 Copyright (C) 1986, 1992, 1993, 1995 Herb Chong
6 All rights reserved.
7
8 See the file LICENSE.TXT for full copyright and licensing information.
9 */
10
11 /*
12 * new bag functions
13 *
14 * This is a simple version of bag.c that uses linked lists to perform the bag
15 * functions. The bag is just a linked list of objects (struct object) to be
16 * specific, but most of that is supposed to be hidden from the user, who
17 * should access the bag only through the functions presented here.
18 */
19
20 #include <stdlib.h>
21 #include "rogue.h"
22
23 /*
24 * apply_to_bag
25 *
26 * This is the general bag manipulation routine. The bag is subjected to
27 * selection criteria and those objects which pass are processed by an action
28 * routine. The two criteria are type and filter function. The filter
29 * function returns TRUE if the object passes and FALSE otherwise. The filter
30 * function is passed the object and the user-supplied argument. This gives
31 * the user plenty of flexibility in determining which items will be
32 * processed. The action routine is passed the object, the id, and the
33 * user-supplied argument given to apply_to_bag. Specifying NULL for either
34 * the type or filter function means that criterion always selects. A NULL
35 * action routine means no processing is done and the first object which
36 * passes the filter is returned to the user. The action routine returns TRUE
37 * if processing should continue or FALSE if the current item should be
38 * returned to the caller.
39 *
40 * Returns NULL if the bag is empty or if nothing qualified.
41 *
42 * linked_list *bag_p; // linked list of objects
43 * int type; // what is its type (ARMOR, ...)
44 * int (*bff_p)(); // bag filter function
45 * int (*baf_p)(); // bag action routine
46 * long user_arg; // user argument for filter, action
47 *
48 */
49
50 struct object *
51 apply_to_bag(struct linked_list *bag_p,
52 int type,
53 int (*bff_p)(struct object *obj, bag_arg *user_arg),
54 int (*baf_p)(struct object *obj, bag_arg *user_arg, int id),
55 void *user_arg)
56 {
57 struct object *bag_obj_p = NULL; /* qualifying object */
58 struct object *cur_obj_p; /* current object */
59 bag_arg arg;
60
61 arg.varg = user_arg;
62
63 if (bag_p == NULL)
64 return (NULL);
65
66 for (; bag_p != NULL; bag_p = next(bag_p))
67 {
68 cur_obj_p = OBJPTR(bag_p);
69
70 if (type != 0 && type != cur_obj_p->o_type)
71 continue;
72
73 if (bff_p != NULL && !(*bff_p)(cur_obj_p, &arg))
74 continue;
75
76 /*
77 * At this point, we have an object which qualifies for
78 * processing
79 */
80
81 bag_obj_p = cur_obj_p; /* in case the user wants it */
82
83 if (baf_p != NULL && (*baf_p)(cur_obj_p, &arg, identifier(bag_obj_p)))
84 continue;
85
86 /*
87 * We have an object which qualifies, quit now!
88 */
89
90 break;
91 }
92
93 if (bag_p == NULL)
94 return (NULL);
95
96 return (bag_obj_p);
97 }
98
99 /*
100 count_bag()
101
102 Counts up all bag items which meet the selection criteria
103 */
104
105 int
106 count_bag(linked_list *bag_p,
107 int type,
108 int (*bff_p)(struct object *obj, bag_arg *junk))
109 {
110 int cnt = 0;
111 apply_to_bag(bag_p, type, bff_p, baf_increment, &cnt);
112
113 return(cnt);
114 }
115
116 /*
117 del_bag()
118
119 Removes an object from a bag and throws it away.
120 */
121
122 void
123 del_bag(linked_list *bag_p, object *obj_p)
124 {
125 pop_bag(&bag_p, obj_p); /* get the thing from the bag */
126 ur_free(obj_p); /* release the memory */
127 }
128
129 /*
130 pop_bag()
131
132 Removes an item from a bag and returns it to the user. If the item is
133 not in the bag, return NULL.
134 */
135
136 struct object *
137 pop_bag(linked_list **bag_pp, object *obj_p)
138 {
139 linked_list *item_p;
140
141 for (item_p = *bag_pp; item_p != NULL && OBJPTR(item_p) != obj_p;
142 item_p = next(item_p));
143
144 if (item_p == NULL)
145 return (NULL);
146
147 _detach(bag_pp, item_p);
148
149 return (obj_p);
150 }
151
152 /*
153 push_bag()
154
155 stuff another item into the bag
156 */
157
158 void
159 push_bag(linked_list **bag_pp, object *obj_p)
160 {
161 struct linked_list *item_p = NULL;
162 struct linked_list *new_p = NULL;
163 struct linked_list *best_p = NULL;
164
165 new_p = new_list();
166 new_p->data.obj = obj_p; /* attach our object */
167 identifier(obj_p) = get_ident(obj_p); /* tag this object for */
168 /* inventory */
169 /*
170 * Find a place in the bag - try to match the type, then sort by
171 * identifier
172 */
173
174 for (item_p = *bag_pp; item_p != NULL; item_p = next(item_p))
175 {
176 if ((OBJPTR(item_p))->o_type == obj_p->o_type)
177 {
178 if (best_p == NULL)
179 best_p = item_p;
180 else if (identifier((OBJPTR(item_p))) >
181 identifier((OBJPTR(best_p))) &&
182 identifier((OBJPTR(item_p))) <
183 identifier(obj_p))
184 best_p = item_p;
185 }
186 }
187
188 _attach_after(bag_pp, best_p, new_p); /* stuff it in the list */
189
190 return;
191 }
192
193 /*
194 scan_bag()
195
196 Gets the object from the bag that matches the type and id. The object
197 is not removed from the bag.
198 */
199
200 struct object *
201 scan_bag(linked_list *bag_p, int type, int id)
202 {
203 object *obj_p = NULL;
204
205 for (; bag_p != NULL; bag_p = next(bag_p))
206 {
207 obj_p = OBJPTR(bag_p);
208
209 if (obj_p->o_type == type && identifier(obj_p) == id)
210 break;
211 }
212
213 if (bag_p == NULL)
214 return(NULL);
215
216 return(obj_p);
217 }
218
219 /*
220 baf_decrement_test()
221
222 Assumes the argument is a pointer to int and it just decrements it.
223 Returns TRUE, except when the count goes to zero.
224 */
225
226 int
227 baf_decrement_test(struct object *obj_p, bag_arg *count_p, int id)
228 {
229 NOOP(obj_p);
230 NOOP(id);
231
232 if (*count_p->iarg > 0)
233 return(TRUE);
234
235 return(FALSE);
236 }
237
238 /*
239 baf_identify()
240
241 Bag action function to identify an object. This is needed to conform
242 to bag action routine calling conventions and to put the linked list
243 structure on top of the object before calling whatis()
244 */
245
246 int
247 baf_identify(struct object *obj_p, bag_arg *junk, int id)
248 {
249 linked_list l;
250 linked_list *lp = &l;
251
252 NOOP(junk);
253 NOOP(id);
254
255 lp->data.obj = obj_p; /* stuff object in the right place */
256 whatis(lp);
257
258 return(TRUE);
259 }
260
261 /*
262 baf_increment()
263
264 Assumes the argument is a pointer to int and it just increments it and
265 returns TRUE
266 */
267
268 int
269 baf_increment(object *obj_p, bag_arg *count_p, int id)
270 {
271 NOOP(obj_p);
272 NOOP(id);
273
274 (*count_p->iarg)++;
275
276 return(TRUE);
277 }
278
279 /*
280 baf_print_item()
281 Bag action function to print a single item, inventory style.
282 */
283
284 int
285 baf_print_item(struct object *obj_p, bag_arg *type, int id)
286 {
287 char inv_temp[3 * LINELEN]; /* plenty of space for paranoid programmers */
288
289 if (*type->iarg == 0)
290 sprintf(inv_temp, "%c%c) %s", obj_p->o_type,
291 print_letters[id], inv_name(obj_p, LOWERCASE), FALSE);
292 else
293 sprintf(inv_temp, "%c) %s", print_letters[id],
294 inv_name(obj_p, LOWERCASE), FALSE);
295
296 add_line(inv_temp);
297 return(TRUE);
298 }
299
300 /*
301 bff_group()
302 This bag filter function checks to see if two items can be combined by
303 adjusting the count. Grouped items can be combined if the group numbers
304 match. The only other item that is allowed to have a count is food, and
305 there an exact match is required.
306 */
307
308 int
309 bff_group(struct object *obj_p, bag_arg *arg)
310 {
311 struct object *new_obj_p = arg->obj;
312
313 if (new_obj_p->o_group > 0 && new_obj_p->o_group == obj_p->o_group)
314 return(TRUE);
315
316 if (new_obj_p->o_type == FOOD &&
317 obj_p->o_type == new_obj_p->o_type &&
318 obj_p->o_which == new_obj_p->o_which)
319 return(TRUE);
320
321 return(FALSE);
322 }
323
324 /*
325 bff_callable
326 Figures out which items can be callable: current rules are:
327 potions, scrolls, staffs, and rings.
328 */
329
330 int
331 bff_callable(struct object *obj_p, bag_arg *junk)
332 {
333 NOOP(junk);
334
335 if (obj_p->o_type == POTION || obj_p->o_type == RING ||
336 obj_p->o_type == STICK || obj_p->o_type == SCROLL)
337 return(TRUE);
338
339 return(FALSE);
340 }
341
342 /*
343 bff_markable()
344 Selects which items can be marked. Current rules exclude only gold.
345 */
346
347 int
348 bff_markable(struct object *obj_p, bag_arg *junk)
349 {
350 NOOP(junk);
351
352 if (obj_p->o_type == GOLD)
353 return(FALSE);
354
355 return(TRUE);
356 }
357
358 /*
359 bffron()
360 returns TRUE if hero is wearing this ring
361 */
362
363 int
364 bffron(object *obj_p, bag_arg *junk)
365 {
366 NOOP(junk);
367
368 return(cur_ring[LEFT_1] == obj_p || cur_ring[LEFT_2] == obj_p ||
369 cur_ring[LEFT_3] == obj_p || cur_ring[LEFT_4] == obj_p ||
370 cur_ring[LEFT_5] ||
371 cur_ring[RIGHT_1] == obj_p || cur_ring[RIGHT_2] == obj_p ||
372 cur_ring[RIGHT_3] == obj_p || cur_ring[RIGHT_4] == obj_p ||
373 cur_ring[RIGHT_5]);
374 }
375
376 /*
377 bff_zappable()
378 Selects which items can be zapped. This includes both sticks and
379