diff xrogue/things.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/things.c	Tue Apr 21 08:55:20 2015 -0400
@@ -0,0 +1,951 @@
+/*
+    things.c - functions for dealing with things like potions and scrolls
+    
+    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"
+
+/*
+ * print out the number of charges on a stick
+ */
+
+char *
+charge_str(obj)
+register struct object *obj;
+{
+    static char buf[20];
+
+    if (!(obj->o_flags & ISKNOW))
+        buf[0] = '\0';
+    else if (terse)
+        sprintf(buf, " [%d]", obj->o_charges);
+    else
+        sprintf(buf, " [%d charges]", obj->o_charges);
+    return buf;
+}
+
+/*
+ * inv_name:
+ *      return the name of something as it would appear in an
+ *      inventory.
+ */
+
+char *
+inv_name(obj, drop)
+register struct object *obj;
+bool drop;
+{
+    register char *pb;
+
+    pb = prbuf;
+    pb[0] = '\0';
+    switch(obj->o_type) {
+        case SCROLL:
+            if (obj->o_count == 1)
+                 sprintf(pb, "A %sscroll ", blesscurse(obj->o_flags));
+            else
+                 sprintf(pb, "%d %sscrolls ", 
+                        obj->o_count, blesscurse(obj->o_flags));
+            pb = &pb[strlen(pb)];
+            if (s_know[obj->o_which] || (obj->o_flags & ISPOST))
+                sprintf(pb, "of %s", s_magic[obj->o_which].mi_name);
+            else if (s_guess[obj->o_which])
+                sprintf(pb, "named %s", s_guess[obj->o_which]);
+            else
+                sprintf(pb, "titled '%s'", s_names[obj->o_which]);
+        when POTION:
+            if (obj->o_count == 1)
+                 sprintf(pb, "A %spotion ", blesscurse(obj->o_flags));
+            else
+                 sprintf(pb, "%d %spotions ", 
+                        obj->o_count, blesscurse(obj->o_flags));
+            pb = &pb[strlen(pb)];
+            if (p_know[obj->o_which])
+                sprintf(pb, "of %s (%s)", p_magic[obj->o_which].mi_name,
+                    p_kind(obj));
+            else if (obj->o_flags & ISPOST)
+                sprintf(pb, "of %s", p_magic[obj->o_which].mi_name);
+            else if (p_guess[obj->o_which])
+                sprintf(pb, "named %s (%s)", p_guess[obj->o_which],
+                    p_colors[obj->o_which]);
+            else {
+                pb = prbuf;
+                if (obj->o_count == 1)
+                    sprintf(pb, "A%s %s potion",
+                            vowelstr(p_colors[obj->o_which]),
+                            p_colors[obj->o_which]);
+                else
+                    sprintf(pb, "%d %s potions",
+                            obj->o_count, p_colors[obj->o_which]);
+            }
+        when FOOD:
+            if (obj->o_count == 1)
+                sprintf(pb, "A%s %s", vowelstr(foods[obj->o_which].mi_name), 
+                        foods[obj->o_which].mi_name);
+            else
+                sprintf(pb, "%d %ss", obj->o_count,foods[obj->o_which].mi_name);
+        when WEAPON:
+            if (obj->o_count > 1)
+                sprintf(pb, "%d ", obj->o_count);
+            else
+                strcpy(pb, "A ");
+            pb = &pb[strlen(pb)];
+            if (obj->o_flags & ISKNOW) {
+                strcat(pb, num(obj->o_hplus, obj->o_dplus));
+                strcat (pb, " ");
+            }
+            strcat(pb, weaps[obj->o_which].w_name);
+            if (obj->o_count > 1)
+                strcat(pb, "s");
+            if (obj == cur_weapon)
+                strcat(pb, " (weapon in hand)");
+            if (obj->o_flags & ISPOISON)
+                strcat(pb, " {Poisoned}");
+        when ARMOR:
+            if (obj->o_flags & ISKNOW) {
+                strcat(pb, num(armors[obj->o_which].a_class - obj->o_ac, 0));
+                strcat(pb, " ");
+            }
+            strcat(pb, armors[obj->o_which].a_name);
+            if (obj == cur_armor)
+                strcat(pb, " (being worn)");
+        when STICK:
+            sprintf(pb, "A %s%s ", 
+                blesscurse(obj->o_flags), ws_type[obj->o_which]);
+            pb = &pb[strlen(pb)];
+            if (ws_know[obj->o_which] || obj->o_flags & ISKNOW)
+                sprintf(pb, "of %s%s (%s)", ws_magic[obj->o_which].mi_name,
+                    charge_str(obj), ws_made[obj->o_which]);
+            else if (obj->o_flags & ISPOST)
+                sprintf(pb, "of %s", ws_magic[obj->o_which].mi_name);
+            else if (ws_guess[obj->o_which])
+                sprintf(pb, "named %s (%s)", ws_guess[obj->o_which],
+                    ws_made[obj->o_which]);
+            else {
+                pb = prbuf;
+                sprintf(pb, "A %s %s", ws_made[obj->o_which],
+                    ws_type[obj->o_which]);
+            }
+            if (obj == cur_weapon)
+                strcat(prbuf, " (weapon in hand)");
+        when RING:
+            if (r_know[obj->o_which] || obj->o_flags & ISKNOW)
+                sprintf(pb, "A%s ring of %s (%s)", ring_num(obj),
+                    r_magic[obj->o_which].mi_name, r_stones[obj->o_which]);
+            else if (obj->o_flags & ISPOST)
+                sprintf(pb, "A ring of %s", r_magic[obj->o_which].mi_name);
+            else if (r_guess[obj->o_which])
+                sprintf(pb, "A ring named %s (%s)",
+                    r_guess[obj->o_which], r_stones[obj->o_which]);
+            else
+                sprintf(pb, "A%s %s ring", vowelstr(r_stones[obj->o_which]),
+                    r_stones[obj->o_which]);
+            if     (obj == cur_ring[LEFT_1] || obj == cur_ring[LEFT_2]  ||
+                    obj == cur_ring[LEFT_3] || obj == cur_ring[LEFT_4])
+            strcat(pb, " (on left hand)");
+            if     (obj == cur_ring[RIGHT_1] || obj == cur_ring[RIGHT_2]  ||
+                    obj == cur_ring[RIGHT_3] || obj == cur_ring[RIGHT_4])
+            strcat(pb, " (on right hand)");
+        when RELIC:
+            if (obj->o_flags & ISKNOW)
+                switch(obj->o_which) {
+                case QUILL_NAGROM:
+                    sprintf(pb, "%s%s", rel_magic[obj->o_which].mi_name, 
+                            charge_str(obj));
+                otherwise:
+                    strcpy(pb, rel_magic[obj->o_which].mi_name);
+            }
+            else switch(obj->o_which) {
+                case MUSTY_DAGGER:
+                    strcpy(pb, "Two very fine daggers marked MDDE");
+                when EMORI_CLOAK:
+                    strcpy(pb, "A silk cloak");
+                when HEIL_ANKH:
+                    strcpy(pb, "A golden ankh");
+                when MING_STAFF:
+                    strcpy(pb, "A finely carved staff");
+                when ORCUS_WAND:
+                    strcpy(pb, "A sparkling ivory wand");
+                when ASMO_ROD:
+                    strcpy(pb, "A glistening ebony rod");
+                when YENDOR_AMULET:
+                    strcpy(pb, "A silver amulet");
+                when STONEBONES_AMULET:
+                    strcpy(pb, "A stone amulet");
+                when BRIAN_MANDOLIN:
+                    strcpy(pb, "A gleaming mandolin");
+                when HRUGGEK_MSTAR:
+                    strcpy(pb, "A silvery morning star");
+                when AXE_AKLAD:
+                    strcpy(pb, "A jewel encrusted axe");
+                when QUILL_NAGROM:
+                    strcpy(pb, "A bright white feather");
+                when GERYON_HORN:
+                    strcpy(pb, "A jet black horn");
+                when YEENOGHU_FLAIL:
+                    strcpy(pb, "A shimmering flail");
+                when SURTUR_RING:
+                    strcpy(pb, "A fiery red ring");
+                when ALTERAN_CARD:
+                    strcpy(pb, "A rectangular piece of wood");
+                otherwise:
+                    strcpy(pb, "A wholly magical item");
+            }
+
+            /* Take care of wielding and wearing */
+            switch (obj->o_which) {
+                case EMORI_CLOAK:
+                    if (cur_armor == NULL && cur_misc[WEAR_CLOAK] == NULL)
+                        strcat(pb, " (being worn)");
+                    if (obj->o_charges)
+                        strcat(pb, " [charged]");
+                    else
+                        strcat(pb, " [discharged]");
+                when HEIL_ANKH:
+                    if (cur_relic[HEIL_ANKH]) strcat(pb, " (in palm)");
+                when EYE_VECNA:
+                    if (cur_relic[EYE_VECNA]) strcat(pb, " (in forehead)");
+                when STONEBONES_AMULET:
+                    if (cur_relic[STONEBONES_AMULET])
+                        strcat(pb, " (in chest)");
+                when YENDOR_AMULET:
+                    if (cur_relic[YENDOR_AMULET])
+                        strcat(pb, " (in chest)");
+                when MUSTY_DAGGER:
+                case HRUGGEK_MSTAR:
+                case AXE_AKLAD:
+                case YEENOGHU_FLAIL:
+                case MING_STAFF:
+                case ASMO_ROD:
+                case ORCUS_WAND:
+                    if (cur_weapon == obj) strcat(pb, " (weapon in hand)");
+                when SURTUR_RING:
+                    if (cur_relic[SURTUR_RING])
+                        strcat(pb, " (in nose)");
+            }
+        when MM:
+            if (m_know[obj->o_which])
+            { 
+                misc_name(pb,obj);
+            }
+            else {
+                switch (obj->o_which) {
+                    case MM_JUG:
+                    case MM_BEAKER:
+                    case MM_KEOGHTOM:
+                        strcpy(pb, "A crystalline jar");
+                    when MM_BOOK:
+                    case MM_SKILLS:
+                        strcpy(pb, "A dusty book");
+                    when MM_ELF_BOOTS:
+                    case MM_DANCE:
+                        strcpy(pb, "A pair of old boots");
+                    when MM_BRACERS:
+                        strcpy(pb, "A set of bracers");
+                    when MM_OPEN:
+                    case MM_HUNGER:
+                        strcpy(pb, "A mysterious chime");
+                    when MM_DISP:
+                    case MM_R_POWERLESS:
+                    case MM_PROTECT:
+                        strcpy(pb, "A dark looking cloak");
+                    when MM_DRUMS:
+                        strcpy(pb, "A drum set");
+                    when MM_DISAPPEAR:
+                    case MM_CHOKE:
+                        strcpy(pb, "A small pouch of dust");
+                    when MM_G_DEXTERITY:
+                    case MM_G_OGRE:
+                    case MM_FUMBLE:
+                        strcpy(pb, "A set of gauntlets");
+                    when MM_ADAPTION:
+                    case MM_JEWEL:
+                    case MM_STRANGLE:
+                        strcpy(pb, "A little necklace");
+            when MM_CRYSTAL:
+            strcpy(pb, "An unusual looking rock");
+                    otherwise:
+                        strcpy(pb, "A magical item");
+                }
+                if (m_guess[obj->o_which]) {
+                    strcat(pb, " named: ");
+                    strcat(pb, m_guess[obj->o_which]);
+                }
+            }
+            if (obj == cur_misc[WEAR_BOOTS]     ||
+                obj == cur_misc[WEAR_BRACERS]   ||
+                obj == cur_misc[WEAR_CLOAK]     ||
+                obj == cur_misc[WEAR_GAUNTLET]  ||
+                obj == cur_misc[WEAR_NECKLACE]  ||
+                obj == cur_misc[WEAR_JEWEL]) 
+                    strcat(pb, " (being worn)");
+        when GOLD:
+                sprintf(pb, "%d Pieces of Gold", obj->o_count);
+        otherwise:
+            debug("Picked up something funny");
+            sprintf(pb, "Something totally bizarre %s", unctrl(obj->o_type));
+        wait_for(' ');
+    }
+
+    /* Is it marked? */
+    if (obj->o_mark[0]) {
+        pb = &pb[strlen(pb)];
+        sprintf(pb, " <%s>", obj->o_mark);
+    }
+
+    if (obj->o_flags & ISPROT)
+        strcat(pb, " [protected]");
+    if (drop && isupper(prbuf[0]))
+        prbuf[0] = tolower(prbuf[0]);
+    else if (!drop && islower(*prbuf))
+        *prbuf = toupper(*prbuf);
+    if (!drop)
+        strcat(pb, ".");
+    /* 
+     * Truncate if long. Use cols-4 to offset the "pack letter" of a normal
+     * inventory listing.
+     */
+    prbuf[cols-4] = '\0';       
+    return prbuf;
+}
+
+/*
+ * weap_name:
+ *      Return the name of a weapon.
+ */
+
+char *
+weap_name(obj)
+register struct object *obj;
+{
+    switch (obj->o_type) {
+        case WEAPON:
+            return(weaps[obj->o_which].w_name);
+        when MISSILE:
+            return(ws_magic[obj->o_which].mi_name);
+        when RELIC:
+            switch (obj->o_which) {
+                case MUSTY_DAGGER:
+                    return("daggers");
+                when YEENOGHU_FLAIL:
+                    return("flail");
+                when AXE_AKLAD:
+                    return("axe");
+                when HRUGGEK_MSTAR:
+                    return("morning star");
+                when MING_STAFF:
+                    return("staff");
+                when ORCUS_WAND:
+                    return("wand");
+                when ASMO_ROD:
+                    return("rod");
+            }
+    }
+    return("weapon");
+}
+
+/*
+ * drop:
+ *      put something down
+ */
+
+drop(item)
+struct linked_list *item;
+{
+    register char ch = 0;
+    register struct linked_list *obj, *nobj;
+    register struct object *op;
+
+    if (item == NULL) {
+        /* We charge 2 movement times to drop something */
+        if (player.t_action == C_DROP && player.t_using != NULL) {
+            obj = player.t_using;
+            player.t_using = NULL;
+            player.t_action = A_NIL;
+        }
+
+        /* t_action == C_DROP always when called from command() */
+        else {
+            if ((obj = get_item(pack, "drop", ALL, FALSE, FALSE)) == NULL) {
+                player.t_action = A_NIL;
+                player.t_using = NULL;
+                return(FALSE);
+            }
+            if (player.t_action == C_DROP) {
+                player.t_using = obj;
+                player.t_no_move = 2 * movement(&player);
+                return(FALSE);  /* We'll come back after we've waited */
+            }
+        }
+
+        switch(ch = mvwinch(stdscr, hero.y, hero.x)) {
+        case PASSAGE: 
+        case SCROLL:
+        case POTION:
+        case WEAPON:
+        case FLOOR:
+        case STICK:
+        case ARMOR:
+        case POOL:
+        case RELIC:
+        case GOLD:
+        case FOOD:
+        case RING:
+        case MM:
+            break;
+        default:
+            msg("You can't leave it here");
+            return(FALSE);
+        }
+    }
+    else {
+        obj = item;
+    }
+    op = OBJPTR(obj);
+    if (!dropcheck(op))
+        return(FALSE);
+
+    /*
+     * If it is a scare monster scroll, curse it
+     */
+    if (op->o_type == SCROLL && op->o_which == S_SCARE) {
+        if (op->o_flags & ISBLESSED)
+            op->o_flags &= ~ISBLESSED;
+        else op->o_flags |= ISCURSED;
+    }
+
+    /*
+     * Take it out of the pack
+     */
+    if (op->o_count >= 2 && op->o_group == 0)
+    {
+        nobj = new_item(sizeof *op);
+        op->o_count--;
+        op = OBJPTR(nobj);
+        *op = *(OBJPTR(obj));
+        op->o_count = 1;
+        obj = nobj;
+    }
+    else {
+        detach(pack, obj);
+        inpack--;
+    }
+    if(ch == POOL) {
+        msg("Gloop... Your %s sinks out of sight. ",inv_name(op,TRUE));
+        o_discard(obj);
+    }
+    else if (levtype == POSTLEV) {
+        op->o_pos = hero;       /* same place as hero */
+        fall(obj,FALSE);
+        if (item == NULL)       /* if item wasn't sold */
+            msg("Thanks for your donation to the Fiend's flea market.");
+    }
+    else {
+        /*
+         * Link it into the level object list
+         */
+        attach(lvl_obj, obj);
+        mvaddch(hero.y, hero.x, op->o_type);
+        op->o_pos = hero;
+        msg("Dropped %s", inv_name(op, TRUE));
+    }
+    updpack(FALSE, &player);
+    return (TRUE);
+}
+
+/*
+ * do special checks for dropping or unweilding|unwearing|unringing
+ */
+
+dropcheck(op)
+register struct object *op;
+{
+    int save_max;
+
+    if (op == NULL)
+        return TRUE;
+    if (levtype == POSTLEV) {
+        if ((op->o_flags & ISCURSED) && (op->o_flags & ISKNOW)) {
+            msg("The trader does not accept shoddy merchandise.");
+            return(FALSE);
+        }
+    }
+
+    /* Player will not drop a relic */
+    if (op->o_type == RELIC) {
+        /*
+         * There is a 1% cumulative chance per relic that trying to get
+         * rid of it will cause the relic to turn on the player.
+         */
+        if (rnd(150) < cur_relic[op->o_which]++) {
+            msg("The artifact turns on you! ");
+            msg("It crushes your mind!!!  --More--");
+            pstats.s_hpt = -1;
+            wait_for (' ');
+            death(D_RELIC);
+        }
+        else {
+            if (terse) msg("You can't release it.");
+            else msg("You cannot bring yourself to release it.");
+            return FALSE;
+        }
+    }
+
+    /* If we aren't wearing it, we can drop it */
+    if (!is_current(op)) return TRUE;
+
+    /* At this point, we know we are wearing the item */
+    if (op->o_flags & ISCURSED) {
+        msg("You can't.  It appears to be cursed.");
+        return FALSE;
+    }
+    if (op->o_type == RING && cur_misc[WEAR_GAUNTLET] != NULL) {
+        msg ("You have to remove your gauntlets first!");
+        return FALSE;
+    }
+    cur_null(op);       /* set current to NULL */
+    if (op->o_type == RING) {
+        switch (op->o_which) {
+        case R_ADDSTR:    save_max = max_stats.s_str;
+                          chg_str(-op->o_ac);
+                          max_stats.s_str = save_max;
+        when R_ADDHIT:    pstats.s_dext -= op->o_ac;
+        when R_ADDINTEL:  pstats.s_intel -= op->o_ac;
+        when R_ADDWISDOM: pstats.s_wisdom -= op->o_ac;
+        when R_SEEINVIS:  if (!ISWEARING(R_SEEINVIS) &&
+                              find_slot(unsee) == 0) {
+                                turn_off(player, CANSEE);
+                                msg("The tingling feeling leaves your eyes. ");
+                          }
+                          light(&hero);
+                          mvwaddch(cw, hero.y, hero.x, PLAYER);
+        when R_WARMTH:    if (!ISWEARING(R_WARMTH) && !find_slot(nocold)) 
+                                turn_off(player, NOCOLD);
+        when R_FIRE:      if (!ISWEARING(R_FIRE)        && 
+                              !cur_relic[SURTUR_RING]   &&
+                              !find_slot(nofire))
+                                turn_off(player, NOFIRE);
+        when R_LIGHT: {
+                          if(roomin(&hero) != NULL) {
+                                light(&hero);
+                                mvwaddch(cw, hero.y, hero.x, PLAYER);
+                          }
+                      }
+        when R_SEARCH:    kill_daemon(ring_search);
+        when R_TELEPORT:  kill_daemon(ring_teleport);
+        }
+    }
+    else if (op->o_type == MM) {
+        switch (op->o_which) {
+            case MM_ADAPTION:
+                turn_off(player, NOGAS);
+                turn_off(player, NOACID);
+
+            when MM_STRANGLE:
+                msg("You can breathe again.....whew!");
+                kill_daemon(strangle);
+
+            when MM_DANCE:
+                turn_off(player, ISDANCE);
+                msg ("Your feet take a break.....whew!");
+
+            when MM_FUMBLE:
+                kill_daemon(fumble);
+
+            when MM_G_OGRE:
+            case MM_G_DEXTERITY:
+                save_max = max_stats.s_str;
+                chg_str(-op->o_ac);
+                max_stats.s_str = save_max;
+        }
+    }
+    return TRUE;
+}
+
+/*
+ * return a new thing
+ */
+
+struct linked_list *
+new_thing(thing_type, allow_curse)
+int thing_type;
+bool allow_curse;
+{
+    register struct linked_list *item;
+    register struct object *cur;
+    register int j;
+    register int blesschance, cursechance;
+
+    item = new_item(sizeof *cur);
+    cur = OBJPTR(item);
+    cur->o_hplus = cur->o_dplus = 0;
+    strcpy(cur->o_damage,"0d0");
+    strcpy(cur->o_hurldmg,"0d0");
+    cur->o_ac = 0;
+    cur->o_count = 1;
+    cur->o_group = 0;
+    cur->contents = NULL;
+    cur->o_flags = 0;