diff urogue/potions.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 0250220d8cdd
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/potions.c	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,1516 @@
+/*
+    potions.c - Functions for dealing with potions
+      
+    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 <stdlib.h>
+#include "rogue.h"
+
+/*
+    quaff - drink a potion (or effect a potion-like spell)
+
+    quaffer: who does it
+    which:   which P_POTION (-1 means ask from pack)
+    flags:   ISBLESSED, ISCURSED
+*/
+
+void
+quaff(struct thing *quaffer, int which, int flags)
+{
+    struct object   *obj;
+    struct thing    *th;
+    struct stats    *curp = &(quaffer->t_stats);
+    struct stats    *maxp = &(quaffer->maxstats);
+    int    blessed = flags & ISBLESSED;
+    int    cursed = flags & ISCURSED;
+    int    is_potion = (which < 0 ? TRUE : FALSE);
+
+    struct linked_list  *item, *titem;
+    char    buf[2 * LINELEN];
+
+    if (quaffer != &player)
+    {
+        monquaff(quaffer, which, flags);
+        return;
+    }
+
+    if (is_potion)      /* A regular potion */
+    {
+        if ((item = get_item("quaff", POTION)) == NULL)
+            return;
+
+        obj = OBJPTR(item);
+
+        if (obj->o_type != POTION)
+        {
+            msg("You can't drink that!");
+            return;
+        }
+
+        /* Calculate its effect */
+
+        flags = obj->o_flags;
+        cursed = obj->o_flags & ISCURSED;
+        blessed = obj->o_flags & ISBLESSED;
+        which = obj->o_which;
+
+        /* remove it from the pack */
+
+        rem_pack(obj);
+        discard(item);
+        updpack();
+    }
+
+    switch(which)
+    {
+        case P_CLEAR:
+            if (cursed)
+            {
+                if (off(player, ISCLEAR))
+                {
+                    msg("Wait, what's going on here. Huh? What? Who?");
+
+                    if (on(player, ISHUH))
+                        lengthen_fuse(FUSE_UNCONFUSE, rnd(8) + HUHDURATION);
+                    else
+                        light_fuse(FUSE_UNCONFUSE, 0, rnd(8) + HUHDURATION, AFTER);
+
+                    turn_on(player, ISHUH);
+                }
+                else
+                    msg("You feel dizzy for a moment, but it passes.");
+            }
+            else
+            {
+                if (blessed) /* Make player immune for the whole game */
+                {
+                    extinguish_fuse(FUSE_UNCLRHEAD);  /* If we have a fuse, put it out */
+                    msg("A strong blue aura surrounds your head.");
+                }
+                else  /* Just light a fuse for how long player is safe */
+                {
+                    if (off(player, ISCLEAR))
+                    {
+                        light_fuse(FUSE_UNCLRHEAD, 0, CLRDURATION, AFTER);
+                        msg("A faint blue aura surrounds your head.");
+                    }
+                    else  /* If have fuse lengthen, else permanently clear */
+                    {
+                        if (find_slot(FUSE_UNCLRHEAD,FUSE) == NULL)
+                            msg("Your blue aura continues to glow strongly.");
+                        else
+                        {
+                            lengthen_fuse(FUSE_UNCLRHEAD, CLRDURATION);
+                            msg("Your blue aura brightens for a moment.");
+                        }
+                    }
+                }
+
+                turn_on(player, ISCLEAR);
+
+                /* If player is confused, unconfuse him */
+
+                if (on(player, ISHUH))
+                {
+                    extinguish_fuse(FUSE_UNCONFUSE);
+                    unconfuse(NULL);
+                }
+            }
+            break;
+
+        case P_HEALING:
+            if (cursed)
+            {
+                if (player.t_ctype != C_PALADIN
+                    && !(player.t_ctype == C_NINJA
+                    && curp->s_lvl > 12)
+                    && !save(VS_POISON))
+                {
+                    feel_message();
+                    curp->s_hpt /= 2;
+                    curp->s_power /= 2;
+
+                    if ((curp->s_hpt -= 1) <= 0)
+                    {
+                        death(D_POISON);
+                        return;
+                    }
+                }
+                else
+                    msg("You feel momentarily sick.");
+            }
+            else
+            {
+                int nsides = (blessed ? 8 : 4);
+                int hpt_gain = roll(curp->s_lvl, nsides);
+                int power_gain = roll(curp->s_lvl, nsides);
+
+                if (blessed && on(player, ISHUH))
+                {
+                    extinguish_fuse(FUSE_UNCONFUSE);
+                    unconfuse(NULL);
+                }
+
+                curp->s_hpt = min(curp->s_hpt + hpt_gain, maxp->s_hpt);
+
+                if (is_potion)  /* Do not bump power or maximums if spell */
+                {
+                    know_items[TYP_POTION][P_HEALING] = TRUE;
+                    curp->s_power = min(curp->s_power + power_gain, maxp->s_power);
+
+                    if (maxp->s_hpt == curp->s_hpt)
+                        maxp->s_hpt = curp->s_hpt += roll(1, nsides);
+
+                    if (maxp->s_power == curp->s_power)
+                        maxp->s_power = curp->s_power += roll(1, nsides);
+                }
+
+                msg("You begin to feel %sbetter.", blessed ? "much " : "");
+
+                if (off(player, PERMBLIND))
+                    sight(NULL);
+            }
+            break;
+
+        case P_GAINABIL:
+        {
+            int   ctype;
+
+            if (!is_potion || pstats.s_arm <= 0)
+                feel_message();
+            else
+            {
+                if (blessed)    /* add to all attributes */
+                {
+                    add_intelligence(FALSE);
+                    add_dexterity(FALSE);
+                    add_strength(FALSE);
+                    add_wisdom(FALSE);
+                    add_const(FALSE);
+                }
+                else
+                {
+                    if (rnd(100) < 70)
+                    /* probably change own ability */
+                        ctype = player.t_ctype;
+                    else
+                        switch(rnd(4))
+                        {
+                            case 0: ctype = C_FIGHTER;  break;
+                            case 1: ctype = C_MAGICIAN; break;
+                            case 2: ctype = C_CLERIC;   break;
+                            case 3: ctype = C_THIEF;    break;
+                        }
+                        switch (ctype)
+                        {
+                            case C_FIGHTER:add_strength(cursed);        break;
+                            case C_PALADIN:add_strength(cursed);        break;
+                            case C_RANGER:add_strength(cursed);         break;
+                            case C_MAGICIAN:add_intelligence(cursed);   break;
+                            case C_ILLUSION:add_intelligence(cursed);   break;
+                            case C_CLERIC:add_wisdom(cursed);           break;
+                            case C_DRUID:add_wisdom(cursed);            break;
+                            case C_THIEF:add_dexterity(cursed);         break;
+                            case C_ASSASIN:add_dexterity(cursed);       break;
+                            case C_NINJA:add_dexterity(cursed);         break;
+                            default: msg("You're a strange type!");     break;
+                        }
+                    }
+
+                    if (rnd(100) < 10)
+                        add_const(cursed);
+
+                    if (rnd(100) < 60)
+                        curp->s_arm += (cursed ? 1 : -1);
+
+                    if (!cursed)
+                        know_items[TYP_POTION][P_GAINABIL] = TRUE;
+                }
+            }
+            break;
+
+        case P_MONSTDET:
+
+            /*
+             * Potion of monster detection, if there are monsters,
+             * detect them
+             */
+
+            if (is_potion)
+                know_items[TYP_POTION][P_MONSTDET] = TRUE;
+
+            if (cursed)
+            {
+                int nm = roll(3, 6);
+                int i;
+                char    ch;
+                struct room *rp;
+                coord   pos;
+
+                msg("You begin to sense the presence of monsters.");
+                wclear(hw);
+
+                for (i = 1; i < nm; i++)
+                {
+                    rp = &rooms[rnd_room()];
+                    rnd_pos(rp, &pos);
+
+                    if (rnd(2))
+                        ch = 'a' + ucrnd(26);
+                    else
+                        ch = 'A' + ucrnd(26);
+
+                    mvwaddch(hw, pos.y, pos.x, ch);
+                }
+                waddstr(cw, morestr);
+                overlay(hw, cw);
+                wrefresh(cw);
+                wait_for(' ');
+                msg("");
+            }
+            else if (mlist != NULL)
+            {
+                msg("You begin to sense the presence of monsters.");
+                waddstr(cw, morestr);
+                overlay(mw, cw);
+                wrefresh(cw);
+                wait_for(' ');
+                msg("");
+
+                if (blessed)
+                    turn_on(player, BLESSMONS);
+            }
+            else
+                nothing_message(flags);
+            break;
+
+        case P_TREASDET:
+
+            /* Potion of magic detection.  Show the potions and scrolls */
+
+            if (cursed)
+            {
+                int nm = roll(3, 3);
+                int i;
+                char    ch;
+                struct room *rp;
+                coord   pos;
+
+                msg("You sense the presence of magic on this level.");
+                wclear(hw);
+
+                for (i = 1; i < nm; i++)
+                {
+                    rp = &rooms[rnd_room()];
+                    rnd_pos(rp, &pos);
+
+                    if (rnd(9) == 0)
+                        ch = BMAGIC;
+                    else if (rnd(9) == 0)
+                        ch = CMAGIC;
+                    else
+                        ch = MAGIC;
+
+                    mvwaddch(hw, pos.y, pos.x, ch);
+                }
+                waddstr(cw, morestr);
+
+                overlay(hw, cw);
+                wrefresh(cw);
+                wait_for(' ');
+                msg("");
+
+                if (is_potion)
+                    know_items[TYP_POTION][P_TREASDET] = TRUE;
+
+                break;
+            }
+
+            if (blessed)
+                turn_on(player, BLESSMAGIC);
+
+            if (lvl_obj != NULL)
+            {
+                struct linked_list  *mobj;
+                struct object   *tp;
+                int showit;
+
+                showit = FALSE;
+                wclear(hw);
+
+                for (mobj = lvl_obj; mobj != NULL; mobj = next(mobj))
+                {
+                    tp = OBJPTR(mobj);
+
+                    if (is_magic(tp))
+                    {
+                        char    mag_type = MAGIC;
+
+                        if (blessed)
+                            if (tp->o_flags & ISCURSED)
+                                mag_type = CMAGIC;
+                            else if (tp->o_flags & ISBLESSED)
+                                mag_type = BMAGIC;
+
+                        showit = TRUE;
+                        mvwaddch(hw, tp->o_pos.y, tp->o_pos.x, mag_type);
+                    }
+                }
+
+                for (titem = mlist; titem != NULL; titem = next(titem))
+                {
+                    struct linked_list  *pitem;
+
+                    th = THINGPTR(titem);
+
+                    for (pitem = th->t_pack; pitem != NULL; pitem = next(pitem))
+                    {
+                        if (is_magic(OBJPTR(pitem)))
+                        {
+                            showit = TRUE;
+                            mvwaddch(hw, th->t_pos.y, th->t_pos.x,MAGIC);
+                        }
+                    }
+                }
+
+                if (showit)
+                {
+                    msg("You sense the presence of magic on this level.");
+
+                    if (is_potion)
+                        know_items[TYP_POTION][P_TREASDET] = TRUE;
+
+                    waddstr(cw, morestr);
+                    overlay(hw, cw);
+                    wrefresh(cw);
+                    wait_for(' ');
+                    msg("");
+                    break;
+                }
+            }
+            nothing_message(flags);
+            break;
+
+        case P_SEEINVIS:
+            if (cursed)
+            {
+                if (off(player, ISBLIND) && !is_wearing(R_SEEINVIS))
+                {
+                    msg("A cloak of darkness falls around you.");
+                    turn_on(player, ISBLIND);
+                    light_fuse(FUSE_SIGHT, 0, SEEDURATION, AFTER);
+                    look(FALSE);
+                }
+                else
+                    msg("Your eyes stop tingling for a moment.");
+            }
+            else if (off(player, PERMBLIND))
+            {
+                if (is_potion)
+                    know_items[TYP_POTION][P_SEEINVIS] = TRUE;
+
+                if (off(player, CANSEE))
+                {
+                    turn_on(player, CANSEE);
+                    msg("Your eyes begin to tingle.");
+                    light_fuse(FUSE_UNSEE, 0, blessed ? SEEDURATION * 3 : SEEDURATION, AFTER);
+                    light(&hero);
+                }
+                else if (find_slot(FUSE_UNSEE,FUSE) != NULL)
+                {
+                    nothing_message(ISNORMAL);
+                    lengthen_fuse(FUSE_UNSEE, blessed ? SEEDURATION * 3 : SEEDURATION);
+                }
+                sight(NULL);
+            }
+            break;
+
+        case P_PHASE:
+
+            if (cursed)
+            {
+                msg("You can't move.");
+                no_command = HOLDTIME;
+            }
+            else
+            {
+                short   duration = (blessed ? 3 : 1);
+
+                if (is_potion)
+                    know_items[TYP_POTION][P_PHASE] = TRUE;
+
+                if (on(player, CANINWALL))
+                    lengthen_fuse(FUSE_UNPHASE, duration * PHASEDURATION);
+                else
+                {
+                    light_fuse(FUSE_UNPHASE, 0, duration * PHASEDURATION, AFTER);
+                    turn_on(player, CANINWALL);
+                }
+                msg("You feel %slight-headed!", blessed ? "very " : "");
+            }
+            break;
+
+        case P_RAISELEVEL:
+
+            if (cursed || (!is_potion && pstats.s_lvl > 20))
+                lower_level(D_POTION);
+            else
+            {
+                msg("You suddenly feel %smore skillful.", blessed ? "much " : "");
+                know_items[TYP_POTION][P_RAISELEVEL] = TRUE;
+                raise_level();
+
+                if (blessed)
+                    raise_level();
+            }
+            break;
+
+        case P_HASTE:
+            if (cursed)     /* Slow player down */
+            {
+                if (on(player, ISHASTE))
+                {
+                    extinguish_fuse(FUSE_NOHASTE);
+                    nohaste(NULL);
+                }
+                else
+                {
+                    msg("You feel yourself moving %sslower.",
+                        on(player, ISSLOW) ? "even " : "");
+
+                    if (on(player, ISSLOW))
+                        lengthen_fuse(FUSE_NOSLOW, rnd(4) + 4);
+                    else if (!is_wearing(R_FREEDOM))
+                    {
+                        turn_on(player, ISSLOW);
+                        player.t_turn = TRUE;
+                        light_fuse(FUSE_NOSLOW, 0, rnd(4) + 4, AFTER);
+                    }
+                }
+            }
+            else
+            {
+                if (off(player, ISSLOW))
+                    msg("You feel yourself moving %sfaster.",
+                        blessed ? "much " : "");
+
+                add_haste(blessed);
+
+                if (is_potion)
+                    know_items[TYP_POTION][P_HASTE] = TRUE;
+            }
+            break;
+
+        case P_RESTORE:
+        {
+            int i;
+
+            msg("You are surrounded by an orange mist.");
+
+            if (is_potion)
+                know_items[TYP_POTION][P_RESTORE] = TRUE;
+
+            if (lost_str)
+            {
+                for (i = 0; i < lost_str; i++)
+                    extinguish_fuse(FUSE_RES_STRENGTH);
+
+                lost_str = 0;
+            }
+            res_strength(NULL);
+
+            if (lost_dext)
+            {
+                for (i = 0; i < lost_dext; i++)
+                    extinguish_fuse(FUSE_UNITCH);
+
+                lost_dext = 0;
+            }
+
+            res_dexterity();
+            res_wisdom();
+            res_intelligence();
+            curp->s_const = maxp->s_const;
+        }
+        break;
+
+        case P_INVIS:
+
+            if (cursed)
+            {
+                msg("You feel very noticable.");
+                quaff(&player, P_SHIELD, ISCURSED);
+            }
+            else if (off(player, ISINVIS))
+            {
+                turn_on(player, ISINVIS);
+
+                if (on(player, ISDISGUISE))
+                {
+                    turn_off(player, ISDISGUISE);
+                    extinguish_fuse(FUSE_UNDISGUISE);
+                    msg("Your skin feels itchy for a moment.");
+                }
+                msg("You have a tingling feeling all over your body.");
+                light_fuse(FUSE_APPEAR, 0, blessed ? WANDERTIME * 3 : WANDERTIME, AFTER);
+                PLAYER = IPLAYER;
+                light(&hero);
+
+                if (is_potion)
+                    know_items[TYP_POTION][P_INVIS] = TRUE;
+            }
+            else
+                lengthen_fuse(FUSE_APPEAR, blessed ? WANDERTIME * 3 : WANDERTIME);
+
+            break;
+
+        case P_SMELL:
+
+            if (cursed)
+            {
+                if (on(player, CANSCENT))
+                {
+                    turn_off(player, CANSCENT);
+                    extinguish_fuse(FUSE_UNSCENT);
+                    msg("You no longer smell monsters around you.");
+                }
+                else if (on(player, ISUNSMELL))
+                {
+                    lengthen_fuse(FUSE_UNSCENT, PHASEDURATION);
+                    msg("You feel your nose tingle.");
+                }
+                else
+                {
+                    turn_on(player, ISUNSMELL);
+                    light_fuse(FUSE_SCENT, 0, PHASEDURATION, AFTER);
+                    msg("You can't smell anything now.");
+                }
+            }
+            else
+            {
+                short   duration = (blessed ? 3 : 1);
+
+                if (is_potion)
+                    know_items[TYP_POTION][P_SMELL] = TRUE;
+
+                if (on(player, CANSCENT))
+                    lengthen_fuse(FUSE_UNSCENT, duration * PHASEDURATION);
+                else
+                {
+                    light_fuse(FUSE_UNSCENT, 0, duration * PHASEDURATION, AFTER);
+                    turn_on(player, CANSCENT);
+                }
+                msg("You begin to smell monsters all around you.");
+            }
+            break;
+
+        case P_HEAR:
+
+            if (cursed)
+            {
+                if (on(player, CANHEAR))
+                {
+                    turn_off(player, CANHEAR);
+                    extinguish_fuse(FUSE_HEAR);
+                    msg("You no longer hear monsters around you.");
+                }