Mercurial > hg > early-roguelike
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 |