Mercurial > hg > early-roguelike
diff urogue/pack.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 | 74351bf23e5e |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/urogue/pack.c Tue Jan 31 19:56:04 2017 -0500 @@ -0,0 +1,683 @@ +/* + pack.c - Routines to deal with the pack. + + UltraRogue: The Ultimate Adventure in the Dungeons of Doom + Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong + All rights reserved. + + Based on "Advanced Rogue" + Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka + All rights reserved. + + Based on "Rogue: Exploring the Dungeons of Doom" + Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman + All rights reserved. + + See the file LICENSE.TXT for full copyright and licensing information. +*/ + +/* + Notes + + The new pack is implemented through the use of bags, + and items are classed by their types (see rogue.h) which also + happen to be their display character. +*/ + +#include <stdlib.h> +#include <ctype.h> +#include "rogue.h" + +#define ESCAPE_EXIT(x) if (x == ESCAPE) {after = FALSE; msg(""); return(NULL);} +#define BAD_NEWS -1 +#define BAD_LIST ((struct linked_list *) BAD_NEWS) +#define GOOD_NEWS 0 + +static char type_list[] = "!?])/=:,"; /* things to inventory */ + +/* + swap_top() + Takes an stacked object and exchanges places with the top + object. <node> must belong to the <top>'s stacked object list. +*/ + +void +swap_top(struct linked_list *top, struct linked_list *node) +{ + struct object *obt, *obn; + + obt = OBJPTR(top); + obn = OBJPTR(node); + + detach((obt->next_obj), node); /* Take it out of the stack */ + attach(lvl_obj, node); /* and put it into the level */ + detach(lvl_obj, top); /* Remove item from level */ + + obn->next_obj = obt->next_obj; + + if (obn->next_obj) + obn->next_obj->l_prev = NULL; + + attach((obn->next_obj), top); +} + + +/* + get_all() + Get as many stacked items as possible. +*/ + +void +get_all(struct linked_list *top) +{ + struct linked_list *node; + struct object *obt; + + while (top) + { + obt = OBJPTR(top); + node = obt->next_obj; + + rem_obj(top, FALSE); + + if (!add_pack(top, FALSE)) + return; + + top = node; + } +} + + +/* + get_stack() + Allows the user to chose from a stack of items. +*/ + +struct linked_list * +get_stack(struct linked_list *item) +{ + struct object *obj; + char buf[2 * LINELEN]; + int i = 0, j; + struct linked_list *ll; +mpos = 0; + obj = OBJPTR(item); + + ll = obj->next_obj; + + sprintf(buf, "You are standing on top of the following items: "); + add_line(buf); + sprintf(buf, "%d) -- %s", i, inv_name(obj, TRUE)); + add_line(buf); + + while (ll) + { + i++; + obj = OBJPTR(ll); + sprintf(buf, "%d) -- %s", i, inv_name(obj, TRUE)); + add_line(buf); + ll = next(ll); + } + + end_line(); + + msg("Which one do you want to pick up? [* for all] "); + + switch(get_string(buf, cw)) + { + case NORM: + break; + case QUIT: /* pick up nothing */ + msg(""); + return (NULL); + } + + if (buf[0] == '*') + { + get_all(item); + msg(""); + return(NULL); + } + else + { + i = atoi(buf); + + if (i) + { + obj = OBJPTR(item); + ll = obj->next_obj; + j = 1; + + while (ll && (j != i)) + { + ll = next(ll); + j++; + } + + if (ll) + { + swap_top(item, ll); + return(ll); + } + else + { + debug("Got past last item while picking up."); + return(item); + } + } + else + return (item); + } +} + +/* + add_pack() + Pick up an object and add it to the pack. If the argument is + non-null use it as the linked_list pointer instead of getting it off the + ground. +*/ + +int +add_pack(struct linked_list *item, int print_message) +{ + struct object *obj, *op; + int from_floor; + + if (item == NULL) + { + from_floor = TRUE; + + if ((item = find_obj(hero.y, hero.x)) == NULL) + { + msg("Nothing to pick up."); + return(FALSE); + } + } + else + from_floor = FALSE; + + if (from_floor) + { + item = get_stack(item); + + if (!item) + return(FALSE); + } + + obj = OBJPTR(item); + + /* If it is gold, just add its value to rogue's purse and get rid of */ + + if (obj->o_type == GOLD) + { + struct linked_list *mitem; + struct thing *tp; + + if (print_message) + { + if (!terse) + addmsg("You found "); + + msg("%d gold pieces.", obj->o_count); + } + + /* + * First make sure no greedy monster is after this gold. If + * so, make the monster run after the rogue instead. + */ + + for (mitem = mlist; mitem != NULL; mitem = next(mitem)) + { + tp = THINGPTR(mitem); + + if (tp->t_horde==obj) + { + tp->t_ischasing = TRUE; + tp->t_chasee = &player; + tp->t_horde = NULL; + } + } + + /* + * This will cause problems if people are able to drop and + * pick up gold, or when GOLDSTEAL monsters are killed. + */ + + /* Thieves get EXP for gold they pick up */ + + if (player.t_ctype == C_THIEF) + { + pstats.s_exp += obj->o_count / 4; + check_level(); + } + + purse += obj->o_count; + + if (from_floor) + rem_obj(item, TRUE); /* Remove object from the level */ + + return (TRUE); + } + + /* see if he can carry any more weight */ + + if (itemweight(obj) + pstats.s_pack > pstats.s_carry) + { + msg("Too much for you to carry."); + + if (print_message) + { + msg("%s onto %s", terse ? "Moved" : "You moved", + inv_name(obj, LOWERCASE)); + } + + return(FALSE); + } + + /* + * Link it into the pack. If the item can be grouped, try to find its + * neighbors and bump the count. A special case is food, which can't + * be grouped, but an exact match allows the count to get + * incremented. + */ + + if ((op = apply_to_bag(pack, obj->o_type, bff_group, NULL, obj)) != NULL) + { + op->o_count += obj->o_count; /* add it to the rest */ + + if (from_floor) + rem_obj(item, FALSE); + + pack_report(op, print_message, "You now have "); + + return(TRUE); + } + + /* Check for and deal with scare monster scrolls */ + + if (obj->o_type == SCROLL && obj->o_which == S_SCARE) + if (obj->o_flags & ISCURSED) + { + msg("The scroll turns to dust as you pick it up."); + rem_obj(item, TRUE); + return(TRUE); + } + + /* Check if there is room */ + + if (count_bag(pack, obj->o_type, NULL) == max_print()) + { + msg("You have no room for more %s.", name_type(obj->o_type)); + + if (print_message) + { + obj = OBJPTR(item); + msg("%s onto %s.", terse ? "Moved" : "You moved", + inv_name(obj, LOWERCASE)); + } + + return(FALSE); + } + + /* + * finally, add the new item to the bag, and free up the linked list + * on top of it. + */ + + if (from_floor) + rem_obj(item, FALSE); + + push_bag(&pack, obj); + pack_report(obj, print_message, "You now have "); + ur_free(item); + + return(TRUE); /* signal success */ +} + +/* + pack_report() + Notify the user about the results of the pack operation and do some + post processing. +*/ + +void +pack_report(object *obj, int print_message, char *message) +{ + /* Notify the user */ + + if (print_message) + { + if (!terse) + addmsg(message); + + msg("(%c%c) %s.", obj->o_type, print_letters[get_ident(obj)], + inv_name(obj, !terse)); + } + + if (obj->o_type == ARTIFACT) + { + has_artifact |= (1 << obj->o_which); + picked_artifact |= (1 << obj->o_which); + + if (!(obj->ar_flags & ISUSED)) + { + obj->ar_flags |= ISUSED; + pstats.s_exp += arts[obj->o_which].ar_worth / 10; + check_level(); + } + } + + updpack(); + + return; +} + +/* + inventory() + list what is in the pack +*/ + +void +inventory(struct linked_list *container, int type) +{ + int cnt; + + if (type == 0) + { + msg("What kind of item <%s> to inventory (* for all)?", type_list); + + type = readchar(); + + if (type == ESCAPE) + { + after = FALSE; + msg(""); + return; + } + } + + /* + * Get a list of items to print out. If the user selects '*', list + * them all. + */ + + if (type == '*') + type = 0; /* no type passed ->use them all */ + + mpos = 0; + + if ((cnt = count_bag(container, type, NULL)) == 0) + msg("You don't have any %s.", name_type(type)); + else + { + apply_to_bag(container, type, NULL, baf_print_item, &type); + end_line(); + msg(""); + } + + return; +} + +/* + pick_up() + Add something to characters pack. +*/ + +void +pick_up(char ch) +{ + switch(ch) + { + default: + debug("Where did you pick that up???"); + break; + + case GOLD: + case ARMOR: + case POTION: + case FOOD: + case WEAPON: + case SCROLL: + case ARTIFACT: + case RING: + case STICK: + add_pack(NULL, MESSAGE); + break; + } +} + +/* + get_object() + + Pick something out of a pack for a purpose. The basic idea is to + list all the possibilities, let the user select one, get that item + from the container, and pass it back to the calling routine. +*/ + +struct object * +get_object(struct linked_list *container, char *purpose, int type, int (*bff_p)(struct object *obj, bag_arg *junk)) +/* char *container; what container has what we want */ +/* char *purpose; a message (verb) to print if we cant find any */ +/* char type; type (o_type) to pick out (NULL = any) */ +/* int (*bff_p) (); bag filter function to test item */ +{ + struct object *obj_p = NULL; + char sel_id; /* selected type and id */ + int sel_type; + char response; + + if (container == NULL) + { + msg("There isn't anything in there."); + after = FALSE; + return(NULL); + } + + /* Make sure we have at least one item that qualifies! */ + + if (apply_to_bag(container, type, bff_p, NULL, NULL) == NULL) + { + msg("You seem to have nothing to %s.", purpose); + after = FALSE; + return(NULL); + } + + while (obj_p == NULL) + { + if (type == 0) + { + msg("What kind of item <%s> do you want to %s (* for list)?", type_list, purpose); + + response = readchar(); + ESCAPE_EXIT(response); + msg(""); + + if (response == '*') + { + add_line("! Potion"); + add_line("? Scroll"); + add_line("= Ring"); + add_line("/ Stick"); + add_line("] Armor"); + add_line(") Weapon"); + add_line(": Food"); + end_line(); + continue; + } + + + if (!is_member(type_list, response)) { beep(); + continue; } + + + if (count_bag(container, response, NULL) == 0) + { + msg("You don't have any %s.", name_type(response)); + continue; + } + + type = response; + } + + while(obj_p == NULL) + { + msg("What item do you want to %s (* for list)?", purpose); + response = readchar(); + msg(""); + ESCAPE_EXIT(response); + + if (response == '*') + { + mpos = 0; + apply_to_bag(container, type, bff_p, baf_print_item, &type); + end_line(); + continue; + } + + sel_type = type; + sel_id = response; + + obj_p = scan_bag(container, sel_type,unprint_id(&sel_id)); + } + } + + mpos = 0; + msg(""); + return(obj_p); +} + +/* + get_item() + + This is only an interim function that serves as an interface to + the old function get_item and its replacement get_object. It + assumes a NULL action routine and allocates a linked_list + structure on top of the object pointer. +*/ + +struct linked_list * +get_item(char *purpose, int type) +{ + struct object *obj_p; + + if ((obj_p = get_object(pack, purpose, type, NULL)) == NULL) + return(NULL); + + return(make_item(obj_p)); +} + +/* + del_pack() + Take something out of the hero's pack and throw it away. +*/ + +void +del_pack(struct linked_list *what) +{ + rem_pack(OBJPTR(what)); + discard(what); +} + +/* + discard_pack + take an object from the pack and throw it away (like del_pack, + but without the linked_list structure) +*/ + +void +discard_pack(struct object *obj_p) +{ + rem_pack(obj_p); + throw_away(obj_p); +} + +/* + rem_pack() + Removes an item from the pack. +*/ + +void +rem_pack(struct object *obj_p) +{ + cur_null(obj_p); /* check for current stuff */ + pop_bag(&pack, obj_p); + updpack(); + return; /* tell caller an item has been removed */ +} + +/* + cur_null() + This updates cur_weapon etc for dropping things +*/ + +void +cur_null(struct object *op) +{ + if (op == cur_weapon) + cur_weapon = NULL; + else if (op == cur_armor) + cur_armor = NULL; + else if (op == cur_ring[LEFT_1]) + cur_ring[LEFT_1] = NULL; + else if (op == cur_ring[LEFT_2]) + cur_ring[LEFT_2] = NULL; + else if (op == cur_ring[LEFT_3]) + cur_ring[LEFT_3] = NULL; + else if (op == cur_ring[LEFT_4]) + cur_ring[LEFT_4] = NULL; + else if (op == cur_ring[LEFT_5]) + cur_ring[LEFT_5] = NULL; + else if (op == cur_ring[RIGHT_1]) + cur_ring[RIGHT_1] = NULL; + else if (op == cur_ring[RIGHT_2]) + cur_ring[RIGHT_2] = NULL; + else if (op == cur_ring[RIGHT_3]) + cur_ring[RIGHT_3] = NULL; + else if (op == cur_ring[RIGHT_4]) + cur_ring[RIGHT_4] = NULL; + else if (op == cur_ring[RIGHT_5]) + cur_ring[RIGHT_5] = NULL; +} + +/* + idenpack() + Identify all the items in the pack +*/ + +void +idenpack(void) +{ + apply_to_bag(pack, 0, NULL, baf_identify, NULL); +} + +/* + show_floor() + Print out the item on the floor. Used by the move command. +*/ + +void +show_floor(void) +{ + struct linked_list *item; + struct object *obj; + + item = find_obj(hero.y, hero.x); + + if (item != NULL) + { + addmsg("%s onto ", terse ? "Moved" : "You moved"); + + obj = OBJPTR(item); + + if (obj->next_obj != NULL) + msg("a stack of things."); + else if (obj->o_type == GOLD) + msg("%d gold pieces.", obj->o_count); + else + { + addmsg(inv_name(obj, TRUE)); + addmsg("."); + endmsg(); + } + } +}