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);
+    }
+}