diff urogue/things.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 5a94c9b3181e
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/things.c	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,935 @@
+/*
+    things.c - functions for dealing with things like potions and scrolls
+                    
+    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.
+*/
+
+#include <string.h>
+#include <ctype.h>
+#include "rogue.h"
+
+/*
+    inv_name()
+        return the name of something as it would appear in an inventory.
+*/
+
+char *
+inv_name(struct object *obj, int lowercase)
+{
+    char *pb;
+    char buf[1024];
+
+    switch(obj->o_type)
+    {
+        case SCROLL:
+            if (obj->o_count == 1)
+                sprintf(prbuf, "A %s%sscroll ",
+                    obj->o_flags & CANRETURN ? "claimed " : "",
+                    blesscurse(obj->o_flags));
+            else
+                sprintf(prbuf, "%d %s%sscrolls ",
+                    obj->o_count,
+                    obj->o_flags & CANRETURN ? "claimed " : "",
+                    blesscurse(obj->o_flags));
+
+            pb = &prbuf[strlen(prbuf)];
+
+            if (know_items[TYP_SCROLL][obj->o_which])
+                sprintf(pb, "of %s", s_magic[obj->o_which].mi_name);
+            else if (guess_items[TYP_SCROLL][obj->o_which])
+                sprintf(pb, "called %s", guess_items[TYP_SCROLL][obj->o_which]);
+            else
+                sprintf(pb, "titled '%s'", s_names[obj->o_which]);
+            break;
+
+        case POTION:
+            if (obj->o_count == 1)
+                sprintf(prbuf, "A %s%spotion ",
+                    obj->o_flags & CANRETURN ? "claimed " : "",
+                    blesscurse(obj->o_flags));
+            else
+                sprintf(prbuf, "%d %s%spotions ",
+                    obj->o_count,
+                    obj->o_flags & CANRETURN ? "claimed " : "",
+                    blesscurse(obj->o_flags));
+
+            pb = &prbuf[strlen(prbuf)];
+
+            if (know_items[TYP_POTION][obj->o_which])
+                sprintf(pb, "of %s(%s)", p_magic[obj->o_which].mi_name,
+                    p_colors[obj->o_which]);
+            else if (guess_items[TYP_POTION][obj->o_which])
+                sprintf(pb, "called %s(%s)", guess_items[TYP_POTION][obj->o_which],
+                    p_colors[obj->o_which]);
+            else
+            {
+                if (obj->o_count == 1)
+                    sprintf(prbuf, "A%s %s potion",
+                         obj->o_flags & CANRETURN ? " claimed" :
+                        (char *) vowelstr(p_colors[obj->o_which]),
+                        p_colors[obj->o_which]);
+                else
+                    sprintf(prbuf, "%d %s%s potions",
+                        obj->o_count,
+                     obj->o_flags & CANRETURN ? "claimed " : "",
+                        (char *) p_colors[obj->o_which]);
+            }
+            break;
+
+        case FOOD:
+            if (obj->o_count == 1)
+                sprintf(prbuf, "A%s %s",
+                    obj->o_flags & CANRETURN ? " claimed" :
+                    (char *) vowelstr(fd_data[obj->o_which].mi_name),
+                    fd_data[obj->o_which].mi_name);
+            else
+                sprintf(prbuf, "%d %s%ss", obj->o_count,
+                    obj->o_flags & CANRETURN ? "claimed " : "",
+                    fd_data[obj->o_which].mi_name);
+            break;
+
+        case WEAPON:
+            if (obj->o_count > 1)
+                sprintf(prbuf, "%d ", obj->o_count);
+            else if ((obj->o_flags & (ISZAPPED | CANRETURN | ISPOISON | ISSILVER | ISTWOH)) ||
+                 ((obj->o_flags & (ISKNOW | ISZAPPED)) == (ISKNOW | ISZAPPED)))
+                strcpy(prbuf, "A ");
+            else
+                sprintf(prbuf, "A%s ", vowelstr(weaps[obj->o_which].w_name));
+
+            pb = &prbuf[strlen(prbuf)];
+
+            if ((obj->o_flags & ISKNOW) && (obj->o_flags & ISZAPPED))
+                sprintf(pb, "charged%s ", charge_str(obj,buf));
+
+            pb = &prbuf[strlen(prbuf)];
+
+            if (obj->o_flags & CANRETURN)
+                sprintf(pb, "claimed ");
+
+            pb = &prbuf[strlen(prbuf)];
+
+            if (obj->o_flags & ISPOISON)
+                sprintf(pb, "poisoned ");
+
+            pb = &prbuf[strlen(prbuf)];
+
+            if (obj->o_flags & ISSILVER)
+                sprintf(pb, "silver ");
+
+            if (obj->o_flags & ISTWOH)
+                sprintf(pb, "two-handed ");
+
+            pb = &prbuf[strlen(prbuf)];
+
+            if (obj->o_flags & ISKNOW)
+                sprintf(pb, "%s %s", num(obj->o_hplus, obj->o_dplus, buf),
+                weaps[obj->o_which].w_name);
+            else
+                sprintf(pb, "%s", weaps[obj->o_which].w_name);
+
+            if (obj->o_count > 1)
+                strcat(prbuf, "s");
+
+            break;
+
+        case ARMOR:
+            if (obj->o_flags & ISKNOW)
+                sprintf(prbuf, "%s%s %s",
+                    obj->o_flags & CANRETURN ? "claimed " : "",
+                   num(armors[obj->o_which].a_class - obj->o_ac, 0, buf),
+                    armors[obj->o_which].a_name);
+            else
+                sprintf(prbuf, "%s%s",
+                    obj->o_flags & CANRETURN ? "claimed " : "",
+                    armors[obj->o_which].a_name);
+
+            break;
+
+        case ARTIFACT:
+            sprintf(prbuf, "the %s", arts[obj->o_which].ar_name);
+
+            if (obj->o_flags & CANRETURN)
+                strcat(prbuf, " (claimed)");
+
+            break;
+
+        case STICK:
+            sprintf(prbuf, "A %s%s%s ",
+                obj->o_flags & CANRETURN ? "claimed " : "",
+                blesscurse(obj->o_flags), ws_type[obj->o_which]);
+
+            pb = &prbuf[strlen(prbuf)];
+
+            if (know_items[TYP_STICK][obj->o_which])
+                sprintf(pb, "of %s%s(%s)", ws_magic[obj->o_which].mi_name,
+                    charge_str(obj,buf), ws_made[obj->o_which]);
+            else if (guess_items[TYP_STICK][obj->o_which])
+                sprintf(pb, "called %s(%s)", guess_items[TYP_STICK][obj->o_which],
+                    ws_made[obj->o_which]);
+            else
+                sprintf(&prbuf[2], "%s%s %s",
+                    obj->o_flags & CANRETURN ? "claimed " : "",
+                    ws_made[obj->o_which],
+                    ws_type[obj->o_which]);
+
+            break;
+
+        case RING:
+            if (know_items[TYP_RING][obj->o_which])
+                sprintf(prbuf, "A%s%s ring of %s(%s)",
+                    obj->o_flags & CANRETURN ? " claimed" : "", ring_num(obj,buf),
+                    r_magic[obj->o_which].mi_name, r_stones[obj->o_which]);
+            else if (guess_items[TYP_RING][obj->o_which])
+                sprintf(prbuf, "A %sring called %s(%s)",
+                    obj->o_flags & CANRETURN ? "claimed " : "",
+                    guess_items[TYP_RING][obj->o_which], r_stones[obj->o_which]);
+            else
+                sprintf(prbuf, "A%s %s ring",
+                    obj->o_flags & CANRETURN ? "claimed " :
+                    (char *)vowelstr(r_stones[obj->o_which]),
+                    r_stones[obj->o_which]);
+            break;
+
+        case GOLD:
+            sprintf(prbuf, "%d gold pieces", obj->o_count);
+            break;
+
+        default:
+            debug("Picked up something funny.");
+            sprintf(prbuf, "Something bizarre %s", unctrl(obj->o_type));
+            break;
+    }
+
+    /* Is it marked? */
+
+    if (obj->o_mark[0])
+    {
+        pb = &prbuf[strlen(prbuf)];
+        sprintf(pb, " <%s>", obj->o_mark);
+    }
+
+    if (obj == cur_armor)
+        strcat(prbuf, " (being worn)");
+
+    if (obj == cur_weapon)
+        strcat(prbuf, " (weapon in hand)");
+
+    if (obj == cur_ring[LEFT_1])
+        strcat(prbuf, " (on left hand)");
+    else if (obj == cur_ring[LEFT_2])
+        strcat(prbuf, " (on left hand)");
+    else if (obj == cur_ring[LEFT_3])
+        strcat(prbuf, " (on left hand)");
+    else if (obj == cur_ring[LEFT_4])
+        strcat(prbuf, " (on left hand)");
+    else if (obj == cur_ring[LEFT_5])
+        strcat(prbuf, " (on left hand)");
+    else if (obj == cur_ring[RIGHT_1])
+        strcat(prbuf, " (on right hand)");
+    else if (obj == cur_ring[RIGHT_2])
+        strcat(prbuf, " (on right hand)");
+    else if (obj == cur_ring[RIGHT_3])
+        strcat(prbuf, " (on right hand)");
+    else if (obj == cur_ring[RIGHT_4])
+        strcat(prbuf, " (on right hand)");
+    else if (obj == cur_ring[RIGHT_5])
+        strcat(prbuf, " (on right hand)");
+
+    if (obj->o_flags & ISPROT)
+        strcat(prbuf, " [protected]");
+
+    if (lowercase && isupper(prbuf[0]))
+        prbuf[0] = (char) tolower(prbuf[0]);
+    else if (!lowercase && islower(*prbuf))
+        *prbuf = (char) toupper(*prbuf);
+
+    if (!lowercase)
+        strcat(prbuf, ".");
+
+    return(prbuf);
+}
+
+/*
+    rem_obj()
+        Remove an object from the level.
+*/
+
+void
+rem_obj(struct linked_list *item, int dis)
+{
+    struct linked_list  *llptr;
+    struct object *objptr, *op;
+    int x, y;
+
+    if (item == NULL)
+        return;
+
+    detach(lvl_obj, item);
+    objptr = OBJPTR(item);
+
+    if ( (llptr = objptr->next_obj) != NULL )
+    {
+        detach((objptr->next_obj), llptr);
+        attach(lvl_obj, llptr);
+
+        op = OBJPTR(llptr);
+	
+	op->next_obj = objptr->next_obj;
+        
+	if (op->next_obj)
+            objptr->next_obj->l_prev = NULL;
+
+        y = op->o_pos.y;
+        x = op->o_pos.x;
+
+        if (cansee(y, x))
+            mvwaddch(cw, y, x, op->o_type);
+
+        mvaddch(y, x, op->o_type);
+    }
+    else
+    {
+        y = objptr->o_pos.y;
+        x = objptr->o_pos.x;
+
+        /* problems if dropped in rock */
+
+        mvaddch(y,x,(roomin((objptr->o_pos)) == NULL ? PASSAGE : FLOOR));
+    }
+
+    if (dis)
+        discard(item);
+}
+
+/*
+    add_obj()
+        adds an object to the level
+*/
+
+void
+add_obj(struct linked_list *item, int y, int x)
+{
+    struct linked_list  *llptr;
+    struct object*objptr;
+
+    llptr = find_obj(y, x);
+
+    if (llptr)
+    {
+        objptr = OBJPTR(llptr);
+        attach((objptr->next_obj), item);
+    }
+    else
+    {
+        attach(lvl_obj, item);
+        objptr = OBJPTR(item);
+        objptr->next_obj = NULL;
+        objptr->o_pos.y = y;
+        objptr->o_pos.x = x;
+        mvaddch(y, x, objptr->o_type);
+    }
+}
+
+/*
+    drop()
+        put something down
+*/
+
+int
+drop(struct linked_list *item)
+{
+    char    ch = CCHAR( mvwinch(stdscr, hero.y, hero.x) );
+    struct object   *obj;
+
+    switch (ch)
+    {
+        case GOLD:
+        case POTION:
+        case SCROLL:
+        case FOOD:
+        case WEAPON:
+        case ARMOR:
+        case RING:
+        case STICK:
+        case FLOOR:
+        case PASSAGE:
+        case POOL:
+        case ARTIFACT:
+            if (item == NULL && (item = get_item("drop", 0)) == NULL)
+                return(FALSE);
+            break;
+
+        default:
+            msg("You can't drop something here.");
+            return(FALSE);
+    }
+
+    obj = OBJPTR(item);
+
+    if (!dropcheck(obj))
+        return(FALSE);
+
+    /* Curse a dropped scare monster scroll */
+
+    if (obj->o_type == SCROLL && obj->o_which == S_SCARE)
+    {
+        if (obj->o_flags & ISBLESSED)
+            obj->o_flags &= ~ISBLESSED;
+        else
+            obj->o_flags |= ISCURSED;
+    }
+
+    /* Take it out of the pack */
+
+    if (obj->o_count >= 2 && obj->o_group == 0)
+    {
+        struct linked_list  *nitem = new_item(sizeof *obj);
+
+        obj->o_count--;
+        obj = OBJPTR(nitem);
+        *obj = *(OBJPTR(item));
+        obj->o_count = 1;
+        item = nitem;
+    }
+    else
+        rem_pack(obj);
+
+    if (ch == POOL)
+    {
+        msg("The pool bubbles briefly as your %s sinks out of sight.",
+            inv_name(obj, TRUE));
+        discard(item);
+        item = NULL;
+    }
+    else            /* Link it into the level object list */
+    {
+        add_obj(item, hero.y, hero.x);
+        mvaddch(hero.y, hero.x, obj->o_type);
+    }
+
+    if (obj->o_type == ARTIFACT)
+        has_artifact &= ~(1 << obj->o_which);
+
+    updpack();
+    return(TRUE);
+}
+
+/*
+    dropcheck()
+        do special checks for dropping or unweilding|unwearing|unringing
+*/
+
+int
+dropcheck(struct object *op)
+{
+    if (op == NULL)
+        return(TRUE);
+
+    if (op != cur_armor && op != cur_weapon &&
+        op != cur_ring[LEFT_1] && op != cur_ring[LEFT_2] &&
+        op != cur_ring[LEFT_3] && op != cur_ring[LEFT_4] &&
+        op != cur_ring[LEFT_5] &&
+        op != cur_ring[RIGHT_1] && op != cur_ring[RIGHT_2] &&
+        op != cur_ring[RIGHT_3] && op != cur_ring[RIGHT_4] &&
+        op != cur_ring[RIGHT_5])
+        return(TRUE);
+
+    if (op->o_flags & ISCURSED)
+    {
+        msg("You can't.  It appears to be cursed.");
+        return(FALSE);
+    }
+
+    if (op == cur_weapon)
+        cur_weapon = NULL;
+    else if (op == cur_armor)
+    {
+        waste_time();
+        cur_armor = NULL;
+    }
+    else if (op == cur_ring[LEFT_1] || op == cur_ring[LEFT_2] ||
+         op == cur_ring[LEFT_3] || op == cur_ring[LEFT_4] ||
+         op == cur_ring[LEFT_5] ||
+         op == cur_ring[RIGHT_1] || op == cur_ring[RIGHT_2] ||
+         op == cur_ring[RIGHT_3] || op == cur_ring[RIGHT_4] ||
+         op == cur_ring[RIGHT_5])
+    {
+        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;
+
+        switch (op->o_which)
+        {
+            case R_ADDSTR:
+                chg_str(-op->o_ac, FALSE, FALSE);
+                break;
+            case R_ADDHIT:
+                chg_dext(-op->o_ac, FALSE, FALSE);
+                break;
+            case R_ADDINTEL:
+                pstats.s_intel -= op->o_ac;
+                break;
+            case R_ADDWISDOM:
+                pstats.s_wisdom -= op->o_ac;
+                break;
+
+            case R_SEEINVIS:
+                if (find_slot(FUSE_UNSEE,FUSE) == NULL)
+                {
+                    turn_off(player, CANSEE);
+                    msg("The tingling feeling leaves your eyes.");
+                }
+
+                light(&hero);
+                mvwaddch(cw, hero.y, hero.x, PLAYER);
+                break;
+
+            case R_LIGHT:
+                if (roomin(hero) != NULL)
+                {
+                    light(&hero);
+                    mvwaddch(cw, hero.y, hero.x, PLAYER);
+                }
+                break;
+        }
+    }
+    return(TRUE);
+}
+
+/*
+    new_thing()
+        return a new thing
+*/
+
+struct linked_list *
+new_thing(void)
+{
+    int j, k;
+    struct linked_list  *item;
+    struct object   *cur;
+    short   blesschance = srnd(100);
+    short   cursechance = srnd(100);
+
+    item = new_item(sizeof *cur);
+    cur = OBJPTR(item);
+    cur->o_hplus = cur->o_dplus = 0;
+    cur->o_damage = cur->o_hurldmg = "0d0";
+    cur->o_ac = 11;
+    cur->o_count = 1;
+    cur->o_group = 0;
+    cur->o_flags = 0;
+    cur->o_weight = 0;
+    cur->o_mark[0] = '\0';
+
+    /*
+     * Decide what kind of object it will be If we haven't had food for a
+     * while, let it be food.
+     */
+
+    switch (no_food > 3 ? TYP_FOOD : pick_one(things, numthings))
+    {
+        case TYP_POTION:
+            cur->o_type = POTION;
+            cur->o_which = pick_one(p_magic, maxpotions);
+            cur->o_weight = things[TYP_POTION].mi_wght;
+
+            if (cursechance < p_magic[cur->o_which].mi_curse)
+                cur->o_flags |= ISCURSED;
+            else if (blesschance < p_magic[cur->o_which].mi_bless)
+                cur->o_flags |= ISBLESSED;
+            break;
+
+        case TYP_SCROLL:
+            cur->o_type = SCROLL;
+            cur->o_which = pick_one(s_magic, maxscrolls);
+            cur->o_weight = things[TYP_SCROLL].mi_wght;
+
+            if (cursechance < s_magic[cur->o_which].mi_curse)
+                cur->o_flags |= ISCURSED;
+            else if (blesschance < s_magic[cur->o_which].mi_bless)
+                cur->o_flags |= ISBLESSED;
+            break;
+
+        case TYP_FOOD:
+            no_food = 0;
+            cur->o_type = FOOD;
+            cur->o_which = pick_one(fd_data, maxfoods);
+            cur->o_weight = 2;
+            cur->o_count += extras();
+            break;
+
+        case TYP_WEAPON:
+            cur->o_type = WEAPON;
+            cur->o_which = rnd(maxweapons);
+            init_weapon(cur, cur->o_which);
+
+            if (cursechance < 10)
+            {
+                short   bad = (rnd(10) < 1) ? 2 : 1;
+
+                cur->o_flags |= ISCURSED;
+                cur->o_hplus -= bad;
+                cur->o_dplus -= bad;
+            }
+            else if (blesschance < 15)
+            {
+                short   good = (rnd(10) < 1) ? 2 : 1;
+
+                cur->o_hplus += good;
+                cur->o_dplus += good;
+            }
+            break;
+
+        case TYP_ARMOR:
+            cur->o_type = ARMOR;
+
+            for (j = 0; j < maxarmors; j++)
+                if (blesschance < armors[j].a_prob)
+                    break;
+
+            if (j == maxarmors)
+            {
+                debug("Picked a bad armor %d", blesschance);
+                j = 0;
+            }
+
+            cur->o_which = j;
+            cur->o_ac = armors[j].a_class;
+
+            if (((k = rnd(100)) < 20) && j != MITHRIL)
+            {
+                cur->o_flags |= ISCURSED;
+                cur->o_ac += rnd(3) + 1;
+            }
+            else if (k < 28 || j == MITHRIL)
+                cur->o_ac -= rnd(3) + 1;
+