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 |
