Mercurial > hg > early-roguelike
diff xrogue/pack.c @ 133:e6179860cb76
Import XRogue 8.0 from the Roguelike Restoration Project (r1490)
author | John "Elwin" Edwards |
---|---|
date | Tue, 21 Apr 2015 08:55:20 -0400 |
parents | |
children | ce0cf824c192 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xrogue/pack.c Tue Apr 21 08:55:20 2015 -0400 @@ -0,0 +1,1582 @@ +/* + pack.c - Routines to deal with the pack. + + XRogue: Expeditions into the Dungeons of Doom + Copyright (C) 1991 Robert Pietkivitch + All rights reserved. + + Based on "Advanced Rogue" + Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T + 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. +*/ + +#include <curses.h> +#include <ctype.h> +#include "rogue.h" + +/* + * 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 gettting it off the ground. + */ + +bool +add_pack(item, silent) +register struct linked_list *item; +bool silent; +{ + register struct linked_list *ip, *lp = NULL, *ap; + register struct object *obj, *op = NULL; + register bool exact, from_floor; + bool giveflag = 0; + static long cleric = C_CLERIC, + monk = C_MONK, + magician = C_MAGICIAN, + assassin = C_ASSASSIN, + druid = C_DRUID, + thief = C_THIEF, + fighter = C_FIGHTER, + ranger = C_RANGER, + paladin = C_PALADIN; + + if (item == NULL) + { + from_floor = TRUE; + if ((item = find_obj(hero.y, hero.x)) == NULL) + return(FALSE); + } + else + from_floor = FALSE; + obj = OBJPTR(item); + /* + * If it is gold, just add its value to rogue's purse and get rid + * of it. + */ + if (obj->o_type == GOLD) { + register struct linked_list *mitem; + register struct thing *tp; + + if (!silent) { + 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_dest == &obj->o_pos) tp->t_dest = &hero; + } + + purse += obj->o_count; + if (from_floor) { + detach(lvl_obj, item); + if ((ap = find_obj(hero.y, hero.x)) == NULL) + mvaddch(hero.y,hero.x,(roomin(&hero)==NULL ? PASSAGE : FLOOR)); + else + mvaddch(hero.y,hero.x,(OBJPTR(ap))->o_type); + } + o_discard(item); + 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."); + return FALSE; + } + /* + * Link it into the pack. Search the pack for a object of similar type + * if there isn't one, stuff it at the beginning, if there is, look for one + * that is exactly the same and just increment the count if there is. + * it that. Food is always put at the beginning for ease of access, but + * is not ordered so that you can't tell good food from bad. First check + * to see if there is something in thr same group and if there is then + * increment the count. + */ + if (obj->o_group) + { + for (ip = pack; ip != NULL; ip = next(ip)) + { + op = OBJPTR(ip); + if (op->o_group == obj->o_group) + { + /* + * Put it in the pack and notify the user + */ + op->o_count += obj->o_count; + if (from_floor) + { + detach(lvl_obj, item); + if ((ap = find_obj(hero.y, hero.x)) == NULL) + mvaddch(hero.y,hero.x, + (roomin(&hero)==NULL ? PASSAGE : FLOOR)); + else + mvaddch(hero.y,hero.x,(OBJPTR(ap))->o_type); + } + o_discard(item); + item = ip; + goto picked_up; + } + } + } + + /* + * 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."); + detach(lvl_obj, item); + if ((ap = find_obj(hero.y, hero.x)) == NULL) + mvaddch(hero.y,hero.x,(roomin(&hero)==NULL ? PASSAGE : FLOOR)); + else + mvaddch(hero.y,hero.x,(OBJPTR(ap))->o_type); + return(TRUE); + } + + /* + * Search for an object of the same type + */ + exact = FALSE; + for (ip = pack; ip != NULL; ip = next(ip)) + { + op = OBJPTR(ip); + if (obj->o_type == op->o_type) + break; + } + if (ip == NULL) + { + /* + * Put it at the end of the pack since it is a new type + */ + for (ip = pack; ip != NULL; ip = next(ip)) + { + op = OBJPTR(ip); + if (op->o_type != FOOD) + break; + lp = ip; + } + } + else + { + /* + * Search for an object which is exactly the same + */ + while (ip != NULL && op->o_type == obj->o_type) + { + if (op->o_which == obj->o_which) + { + exact = TRUE; + break; + } + lp = ip; + if ((ip = next(ip)) == NULL) + break; + op = OBJPTR(ip); + } + } + /* + * Check if there is room + */ + if (ip == NULL || !exact || !ISMULT(obj->o_type)) { + if (inpack == MAXPACK-1) { + msg(terse ? "No room." : "You can't carry anything else."); + return(FALSE); + } + } + inpack++; + if (from_floor) + { + detach(lvl_obj, item); + if ((ap = find_obj(hero.y, hero.x)) == NULL) + mvaddch(hero.y,hero.x,(roomin(&hero)==NULL ? PASSAGE : FLOOR)); + else + mvaddch(hero.y,hero.x,(OBJPTR(ap))->o_type); + } + if (ip == NULL) + { + /* + * Didn't find an exact match, just stick it here + */ + if (pack == NULL) + pack = item; + else + { + lp->l_next = item; + item->l_prev = lp; + item->l_next = NULL; + } + } + else + { + /* + * If we found an exact match. If it is food, + * increase the count, otherwise put it with its clones. + */ + if (exact && ISMULT(obj->o_type)) + { + op->o_count += obj->o_count; + inpack--; /* adjust for previous addition */ + o_discard(item); + item = ip; + goto picked_up; + } + if ((item->l_prev = prev(ip)) != NULL) + item->l_prev->l_next = item; + else + pack = item; + item->l_next = ip; + ip->l_prev = item; + } +picked_up: + /* + * Notify the user + */ + obj = OBJPTR(item); + if (!silent) + { + if (!terse) + addmsg("You now have "); + msg("%s (%c)", inv_name(obj, !terse), pack_char(pack, obj)); + } + + /* Relics do strange things when you pick them up */ + if (obj->o_type == RELIC) { + switch (obj->o_which) { + /* the ankh of Heil gives you prayers */ + case HEIL_ANKH: + msg("The ankh welds itself into your hand. "); + if (player.t_ctype != C_CLERIC && player.t_ctype != C_PALADIN) + fuse(prayer_recovery, (VOID *)NULL, SPELLTIME, AFTER); + /* start a fuse to change player into a paladin */ + if (quest_item != HEIL_ANKH) { + msg("You hear a strange, distant hypnotic calling... "); + if (player.t_ctype != C_PALADIN && obj->o_which ==HEIL_ANKH) + fuse(changeclass, &paladin, roll(8, 8), AFTER); + } + + /* A cloak must be worn. */ + when EMORI_CLOAK: + if (cur_armor != NULL || cur_misc[WEAR_CLOAK]) { + msg("The cloak insists you remove your current garments."); + if (!dropcheck(cur_armor != NULL ? cur_armor + : cur_misc[WEAR_CLOAK])) { + pstats.s_hpt = -1; + msg("The cloak constricts around you..."); + msg("It draws your life force from you!!! --More--"); + wait_for(' '); + death(D_RELIC); + } + } + if (obj->o_charges < 0) /* should never happen, but.... */ + obj->o_charges = 0; + if (obj->o_charges == 0) + fuse(cloak_charge, obj, CLOAK_TIME, AFTER); + /* start a fuse to change player into a monk */ + if (quest_item != EMORI_CLOAK) { + msg("You suddenly become calm and quiet. "); + if (player.t_ctype != C_MONK && obj->o_which == EMORI_CLOAK) + fuse(changeclass, &monk, roll(8, 8), AFTER); + } + + /* The amulet must be worn. */ + when STONEBONES_AMULET: + case YENDOR_AMULET: + if (cur_misc[WEAR_JEWEL] || cur_relic[STONEBONES_AMULET] || + cur_relic[YENDOR_AMULET]) { + msg("You have an urge to remove your current amulet."); + } + if((cur_misc[WEAR_JEWEL] && !dropcheck(cur_misc[WEAR_JEWEL])) || + cur_relic[STONEBONES_AMULET] || cur_relic[YENDOR_AMULET]) { + pstats.s_hpt = -1; + msg("The %s begins pulsating... ",inv_name(obj, TRUE)); + msg("It fades completely away! --More--"); + wait_for(' '); + death(D_RELIC); + } + msg("The %s welds itself into your chest. ",inv_name(obj,TRUE)); + /* start a fuse to change into a magician */ + if (quest_item != STONEBONES_AMULET) { + if (player.t_ctype != C_MAGICIAN && + obj->o_which == STONEBONES_AMULET) { + msg("You sense approaching etheric forces... "); + fuse(changeclass, &magician, roll(8, 8), AFTER); + } + } + + /* The eye is now inserted in forehead */ + when EYE_VECNA: + msg("The eye forces itself into your forehead! "); + pstats.s_hpt -= (rnd(80)+21); + if (pstats.s_hpt <= 0) { + pstats.s_hpt = -1; + msg ("The pain is too much for you to bear! --More--"); + wait_for(' '); + death(D_RELIC); + } + waste_time(); + msg("The excruciating pain slowly turns into a dull throb."); + /* start a fuse to change player into an assassin */ + if (quest_item != EYE_VECNA) { + msg("Your blood rushes and you begin to sweat profusely... "); + if (player.t_ctype != C_ASSASSIN && obj->o_which == EYE_VECNA) + fuse(changeclass, &assassin, roll(8, 8), AFTER); + } + + when QUILL_NAGROM: + fuse(quill_charge,(VOID *)NULL, 8, AFTER); + /* start a fuse to change player into a druid */ + if (quest_item != QUILL_NAGROM) { + msg("You begin to see things differently... "); + if (player.t_ctype != C_DRUID && obj->o_which == QUILL_NAGROM) + fuse(changeclass, &druid, roll(8, 8), AFTER); + } + + /* Weapons will insist on being wielded. */ + when MUSTY_DAGGER: + case HRUGGEK_MSTAR: + case YEENOGHU_FLAIL: + case AXE_AKLAD: + /* set a daemon to eat gold for daggers and axe */ + if (obj->o_which == MUSTY_DAGGER || obj->o_which == AXE_AKLAD) { + if (purse > 0) msg("Your purse feels lighter! "); + else purse = 1; /* fudge to get right msg from eat_gold() */ + + eat_gold(obj); + daemon(eat_gold, obj, AFTER); + } + /* start a fuse to change player into a thief */ + if (quest_item != MUSTY_DAGGER) { + if (player.t_ctype != C_THIEF && + obj->o_which == MUSTY_DAGGER) { + msg("You look about furtively. "); + fuse(changeclass, &thief, roll(8, 8), AFTER); + } + } + /* start a fuse to change player into a fighter */ + if (quest_item != AXE_AKLAD) { + if (player.t_ctype != C_FIGHTER && + obj->o_which == AXE_AKLAD) { + msg("Your bones feel strengthened. "); + fuse(changeclass, &fighter, roll(8, 8), AFTER); + } + } + if (cur_weapon != NULL) { + msg("The artifact insists you release your current weapon!"); + if (!dropcheck(cur_weapon)) { + pstats.s_hpt = -1; + msg("The artifact forces your weapon into your heart! "); + msg("It hums with satisfaction! --More--"); + wait_for(' '); + death(D_RELIC); + } + } + cur_weapon = obj; + + /* acquire a sense of smell */ + when SURTUR_RING: + msg("The ring forces itself through your nose!"); + pstats.s_hpt -= rnd(40)+1; + if (pstats.s_hpt < 0) { + pstats.s_hpt = -1; + msg("The pain is too much for you to bear! --More--"); + wait_for(' '); + death(D_RELIC); + } + waste_time(); + turn_on(player, NOFIRE); + msg("The pain slowly subsides.. "); + + /* become a wandering musician */ + when BRIAN_MANDOLIN: + msg("You hear an ancient haunting sound... "); + /* start a fuse to change player into a ranger */ + if (quest_item != BRIAN_MANDOLIN) { + msg("You are transfixed with empathy. "); + if (player.t_ctype != C_RANGER && obj->o_which == BRIAN_MANDOLIN) + fuse(changeclass, &ranger, roll(8, 8), AFTER); + } + + /* add to the music */ + when GERYON_HORN: + msg("You begin to hear trumpets!"); + /* start a fuse to change player into a cleric */ + if (quest_item != GERYON_HORN) { + msg("You follow their calling. "); + if (player.t_ctype != C_CLERIC && obj->o_which == GERYON_HORN) + fuse(changeclass, &cleric, roll(8, 8), AFTER); + } + + /* the card can not be picked up, it must be traded for */ + when ALTERAN_CARD: + if (giveflag == FALSE) { + if (!wizard) { + msg("You look at the dark card and it chills you to the bone!! "); + msg("You stand for a moment, face to face with death... --More--"); + wait_for(' '); + pstats.s_hpt = -1; + death(D_CARD); + } + else { + msg("Got it! "); + if (purse > 0) msg("Your purse feels lighter! "); + else purse = 1; /* fudge to get right msg */ + + eat_gold(obj); + daemon(eat_gold, obj, AFTER); + } + } + else { + msg("You accept it hesitantly... "); + if (purse > 0) msg("Your purse feels lighter! "); + else purse = 1; /* fudge to get right msg */ + + eat_gold(obj); + daemon(eat_gold, obj, AFTER); + } + + otherwise: + break; + } + cur_relic[obj->o_which]++; /* Note that we have it */ + } + + updpack(FALSE, &player); + return(TRUE); +} + +/* + * inventory: + * list what is in the pack + */ + +inventory(list, type) +register struct linked_list *list; +register int type; +{ + register struct object *obj; + register char ch; + register int n_objs, cnt, maxx = 0, curx; + char inv_temp[2*LINELEN+1]; + + cnt = 0; + n_objs = 0; + for (ch = 'a'; list != NULL; ch++, list = next(list)) { + obj = OBJPTR(list); + if (!is_type(obj, type)) + continue; + switch (n_objs++) { + /* + * For the first thing in the inventory, just save the string + * in case there is only one. + */ + case 0: + sprintf(inv_temp, "%c) %s", ch, inv_name(obj, FALSE)); + break; + /* + * If there is more than one, clear the screen, print the + * saved message and fall through to ... + */ + case 1: + if (slow_invent) + msg(inv_temp); + else + { + wclear(hw); + waddstr(hw, inv_temp); + waddch(hw, '\n'); + + maxx = strlen(inv_temp); /* Length of the listing */ + } + /* + * Print the line for this object + */ + default: + if (ch > 'z') + ch = 'A'; + if (slow_invent) + msg("%c) %s", ch, inv_name(obj, FALSE)); + else { + if (++cnt >= lines - 2) { /* if bottom of screen */ + dbotline(hw, morestr); + cnt = 0; + wclear(hw); + } + sprintf(inv_temp, "%c) %s\n", ch, inv_name(obj, FALSE)); + curx = strlen(inv_temp) - 1; /* Don't count new-line */ + if (curx > maxx) maxx = curx; + waddstr(hw, inv_temp); + } + } + } + if (n_objs == 0) { + if (terse) + msg(type == ALL ? "Empty-handed." : + "Nothing appropriate"); + else + msg(type == ALL ? "You are empty-handed." : + "You don't have anything appropriate"); + return FALSE; + } + if (n_objs == 1) { + msg(inv_temp); + return TRUE; + } + if (!slow_invent) + { + waddstr(hw, spacemsg); + curx = strlen(spacemsg); + if (curx > maxx) maxx = curx; + + /* + * If we have fewer than half a screenful, don't clear the screen. + * Leave an extra blank line at the bottom and 3 blank columns + * to he right. + */ + if (menu_overlay && n_objs < lines - 3) { + over_win(cw, hw, n_objs + 2, maxx + 3, n_objs, curx, ' '); + return TRUE; + } + + draw(hw); + wait_for(' '); + restscr(cw); + } + return TRUE; +} + +/* + * picky_inven: + * Allow player to inventory a single item + */ + +void +picky_inven() +{ + register struct linked_list *item; + register char ch, mch; + + if (pack == NULL) + msg("You aren't carrying anything"); + else if (next(pack) == NULL) + msg("a) %s", inv_name(OBJPTR(pack), FALSE)); + else + { + msg(terse ? "Item: " : "Which item do you wish to inventory: "); + mpos = 0; + if ((mch = wgetch(cw)) == ESC) + { + msg(""); + return; + } + + /* Check for a special character */ + switch (mch) { + case FOOD: + case SCROLL: + case POTION: + case RING: + case STICK: + case RELIC: + case ARMOR: + case WEAPON: + case MM: + msg(""); + if (get_item(pack, (char *)NULL, mch, FALSE, FALSE) == NULL) { + if (terse) msg("No '%c' in your pack.", mch); + else msg("You have no '%c' in your pack.", mch); + } + return; + } + + for (ch = 'a', item = pack; item != NULL; item = next(item), ch++) + if (ch == mch) + { + msg("%c) %s",ch,inv_name(OBJPTR(item), FALSE)); + return; + } + if (!terse) + msg("'%s' not in pack.", unctrl(mch)); + msg("Range is 'a' to '%c'", --ch); + } +}