Mercurial > hg > early-roguelike
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/urogue/bag.c Tue Jan 31 19:56:04 2017 -0500 @@ -0,0 +1,448 @@ +/* + bag.c - functions for dealing with bags + + UltraRogue: The Ultimate Adventure in the Dungeons of Doom + Copyright (C) 1986, 1992, 1993, 1995 Herb Chong + All rights reserved. + + See the file LICENSE.TXT for full copyright and licensing information. +*/ + +/* + * new bag functions + * + * This is a simple version of bag.c that uses linked lists to perform the bag + * functions. The bag is just a linked list of objects (struct object) to be + * specific, but most of that is supposed to be hidden from the user, who + * should access the bag only through the functions presented here. + */ + +#include <stdlib.h> +#include "rogue.h" + +/* + * apply_to_bag + * + * This is the general bag manipulation routine. The bag is subjected to + * selection criteria and those objects which pass are processed by an action + * routine. The two criteria are type and filter function. The filter + * function returns TRUE if the object passes and FALSE otherwise. The filter + * function is passed the object and the user-supplied argument. This gives + * the user plenty of flexibility in determining which items will be + * processed. The action routine is passed the object, the id, and the + * user-supplied argument given to apply_to_bag. Specifying NULL for either + * the type or filter function means that criterion always selects. A NULL + * action routine means no processing is done and the first object which + * passes the filter is returned to the user. The action routine returns TRUE + * if processing should continue or FALSE if the current item should be + * returned to the caller. + * + * Returns NULL if the bag is empty or if nothing qualified. + * + * linked_list *bag_p; // linked list of objects + * int type; // what is its type (ARMOR, ...) + * int (*bff_p)(); // bag filter function + * int (*baf_p)(); // bag action routine + * long user_arg; // user argument for filter, action + * + */ + +struct object * +apply_to_bag(struct linked_list *bag_p, + int type, + int (*bff_p)(struct object *obj, bag_arg *user_arg), + int (*baf_p)(struct object *obj, bag_arg *user_arg, int id), + void *user_arg) +{ + struct object *bag_obj_p = NULL; /* qualifying object */ + struct object *cur_obj_p; /* current object */ + bag_arg arg; + + arg.varg = user_arg; + + if (bag_p == NULL) + return (NULL); + + for (; bag_p != NULL; bag_p = next(bag_p)) + { + cur_obj_p = OBJPTR(bag_p); + + if (type != 0 && type != cur_obj_p->o_type) + continue; + + if (bff_p != NULL && !(*bff_p)(cur_obj_p, &arg)) + continue; + + /* + * At this point, we have an object which qualifies for + * processing + */ + + bag_obj_p = cur_obj_p; /* in case the user wants it */ + + if (baf_p != NULL && (*baf_p)(cur_obj_p, &arg, identifier(bag_obj_p))) + continue; + + /* + * We have an object which qualifies, quit now! + */ + + break; + } + + if (bag_p == NULL) + return (NULL); + + return (bag_obj_p); +} + +/* + count_bag() + + Counts up all bag items which meet the selection criteria +*/ + +int +count_bag(linked_list *bag_p, + int type, + int (*bff_p)(struct object *obj, bag_arg *junk)) +{ + int cnt = 0; + apply_to_bag(bag_p, type, bff_p, baf_increment, &cnt); + + return(cnt); +} + +/* + del_bag() + + Removes an object from a bag and throws it away. +*/ + +void +del_bag(linked_list *bag_p, object *obj_p) +{ + pop_bag(&bag_p, obj_p); /* get the thing from the bag */ + ur_free(obj_p); /* release the memory */ +} + +/* + pop_bag() + + Removes an item from a bag and returns it to the user. If the item is + not in the bag, return NULL. +*/ + +struct object * +pop_bag(linked_list **bag_pp, object *obj_p) +{ + linked_list *item_p; + + for (item_p = *bag_pp; item_p != NULL && OBJPTR(item_p) != obj_p; + item_p = next(item_p)); + + if (item_p == NULL) + return (NULL); + + _detach(bag_pp, item_p); + + return (obj_p); +} + +/* + push_bag() + + stuff another item into the bag +*/ + +void +push_bag(linked_list **bag_pp, object *obj_p) +{ + struct linked_list *item_p = NULL; + struct linked_list *new_p = NULL; + struct linked_list *best_p = NULL; + + new_p = new_list(); + new_p->data.obj = obj_p; /* attach our object */ + identifier(obj_p) = get_ident(obj_p); /* tag this object for */ + /* inventory */ + /* + * Find a place in the bag - try to match the type, then sort by + * identifier + */ + + for (item_p = *bag_pp; item_p != NULL; item_p = next(item_p)) + { + if ((OBJPTR(item_p))->o_type == obj_p->o_type) + { + if (best_p == NULL) + best_p = item_p; + else if (identifier((OBJPTR(item_p))) > + identifier((OBJPTR(best_p))) && + identifier((OBJPTR(item_p))) < + identifier(obj_p)) + best_p = item_p; + } + } + + _attach_after(bag_pp, best_p, new_p); /* stuff it in the list */ + + return; +} + +/* + scan_bag() + + Gets the object from the bag that matches the type and id. The object + is not removed from the bag. +*/ + +struct object * +scan_bag(linked_list *bag_p, int type, int id) +{ + object *obj_p = NULL; + + for (; bag_p != NULL; bag_p = next(bag_p)) + { + obj_p = OBJPTR(bag_p); + + if (obj_p->o_type == type && identifier(obj_p) == id) + break; + } + + if (bag_p == NULL) + return(NULL); + + return(obj_p); +} + +/* + baf_decrement_test() + + Assumes the argument is a pointer to int and it just decrements it. + Returns TRUE, except when the count goes to zero. +*/ + +int +baf_decrement_test(struct object *obj_p, bag_arg *count_p, int id) +{ + NOOP(obj_p); + NOOP(id); + + if (*count_p->iarg > 0) + return(TRUE); + + return(FALSE); +} + +/* + baf_identify() + + Bag action function to identify an object. This is needed to conform + to bag action routine calling conventions and to put the linked list + structure on top of the object before calling whatis() +*/ + +int +baf_identify(struct object *obj_p, bag_arg *junk, int id) +{ + linked_list l; + linked_list *lp = &l; + + NOOP(junk); + NOOP(id); + + lp->data.obj = obj_p; /* stuff object in the right place */ + whatis(lp); + + return(TRUE); +} + +/* + baf_increment() + + Assumes the argument is a pointer to int and it just increments it and + returns TRUE +*/ + +int +baf_increment(object *obj_p, bag_arg *count_p, int id) +{ + NOOP(obj_p); + NOOP(id); + + (*count_p->iarg)++; + + return(TRUE); +} + +/* + baf_print_item() + Bag action function to print a single item, inventory style. +*/ + +int +baf_print_item(struct object *obj_p, bag_arg *type, int id) +{ + char inv_temp[3 * LINELEN]; /* plenty of space for paranoid programmers */ + + if (*type->iarg == 0) + sprintf(inv_temp, "%c%c) %s", obj_p->o_type, + print_letters[id], inv_name(obj_p, LOWERCASE), FALSE); + else + sprintf(inv_temp, "%c) %s", print_letters[id], + inv_name(obj_p, LOWERCASE), FALSE); + + add_line(inv_temp); + return(TRUE); +} + +/* + bff_group() + This bag filter function checks to see if two items can be combined by + adjusting the count. Grouped items can be combined if the group numbers + match. The only other item that is allowed to have a count is food, and + there an exact match is required. +*/ + +int +bff_group(struct object *obj_p, bag_arg *arg) +{ + struct object *new_obj_p = arg->obj; + + if (new_obj_p->o_group > 0 && new_obj_p->o_group == obj_p->o_group) + return(TRUE); + + if (new_obj_p->o_type == FOOD && + obj_p->o_type == new_obj_p->o_type && + obj_p->o_which == new_obj_p->o_which) + return(TRUE); + + return(FALSE); +} + +/* + bff_callable + Figures out which items can be callable: current rules are: + potions, scrolls, staffs, and rings. +*/ + +int +bff_callable(struct object *obj_p, bag_arg *junk) +{ + NOOP(junk); + + if (obj_p->o_type == POTION || obj_p->o_type == RING || + obj_p->o_type == STICK || obj_p->o_type == SCROLL) + return(TRUE); + + return(FALSE); +} + +/* + bff_markable() + Selects which items can be marked. Current rules exclude only gold. +*/ + +int +bff_markable(struct object *obj_p, bag_arg *junk) +{ + NOOP(junk); + + if (obj_p->o_type == GOLD) + return(FALSE); + + return(TRUE); +} + +/* + bffron() + returns TRUE if hero is wearing this ring +*/ + +int +bffron(object *obj_p, bag_arg *junk) +{ + NOOP(junk); + + return(cur_ring[LEFT_1] == obj_p || cur_ring[LEFT_2] == obj_p || + cur_ring[LEFT_3] == obj_p || cur_ring[LEFT_4] == obj_p || + cur_ring[LEFT_5] || + cur_ring[RIGHT_1] == obj_p || cur_ring[RIGHT_2] == obj_p || + cur_ring[RIGHT_3] == obj_p || cur_ring[RIGHT_4] == obj_p || + cur_ring[RIGHT_5]); +} + +/* + bff_zappable() + Selects which items can be zapped. This includes both sticks and + magically enhanced weapons with lightning ability. +*/ + +int +bff_zappable(struct object *obj_p, bag_arg *junk) +{ + NOOP(junk); + + if (obj_p->o_type == STICK) + return(TRUE); + + if (obj_p->o_type == WEAPON && obj_p->o_flags & ISZAPPED) + return(TRUE); + + return (FALSE); +} + +/* + baf_curse() + Curse all non-artifact items in the player's pack +*/ + +int +baf_curse(struct object *obj_p, bag_arg *junk, int id) +{ + NOOP(junk); + NOOP(id); + + if (obj_p->o_type != ARTIFACT && rnd(8) == 0) + { + obj_p->o_flags |= ISCURSED; + obj_p->o_flags &= ~ISBLESSED; + } + + return(TRUE); +} + +/* + bafcweapon() + bag action routine to fetch the current weapon +*/ + +int +bafcweapon(struct object *obj_p, bag_arg *junk, int id) +{ + NOOP(junk); + NOOP(id); + + if (obj_p == cur_weapon) + return(FALSE); /* found what we wanted - stop and return it */ + + return(TRUE); +} + +/* + bafcarmor() + bag action routine to fetch the current armor +*/ + +int +bafcarmor(struct object *obj_p, bag_arg *junk, int id) +{ + NOOP(junk); + NOOP(id); + + if (obj_p == cur_armor) + return(FALSE); /* found what we wanted - stop and return it */ + + return(TRUE); +}