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.");
+                }
+                else if (on(player, ISDEAF))
+                {
+                    lengthen_fuse(FUSE_HEAR, PHASEDURATION);
+                    msg("You feel your ears burn.");
+                }
+                else
+                {
+                    light_fuse(FUSE_HEAR, 0, PHASEDURATION, AFTER);
+                    turn_on(player, ISDEAF);
+                    msg("You are surrounded by a sudden silence.");
+                }
+            }
+            else
+            {
+                short   duration = (blessed ? 3 : 1);
+
+                if (is_potion)
+                    know_items[TYP_POTION][P_HEAR] = TRUE;
+
+                if (on(player, CANHEAR))
+                    lengthen_fuse(FUSE_UNHEAR, duration * PHASEDURATION);
+                else
+                {
+                    light_fuse(FUSE_UNHEAR, 0, duration * PHASEDURATION, AFTER);
+                    turn_on(player, CANHEAR);
+                }
+                msg("You begin to hear monsters all around you.");
+            }
+            break;
+
+        case P_SHERO:
+            if (cursed)
+            {
+                if (on(player, SUPERHERO))
+                {
+                    msg("You feel ordinary again.");
+                    turn_off(player, SUPERHERO);
+                    extinguish_fuse(FUSE_UNSHERO);
+                    extinguish_fuse(FUSE_UNBHERO);
+                }
+                else if (on(player, ISUNHERO))
+                {
+                    msg("Your feeling of vulnerability increases.");
+                    lengthen_fuse(FUSE_SHERO, 5 + rnd(5));
+                }
+                else
+                {
+                    msg("You feel suddenly vulnerable.");
+
+                    if (curp->s_hpt == 1)
+                    {
+                        death(D_POTION);
+                        return;
+                    }
+
+                    curp->s_hpt /= 2;
+                    chg_str(-2, FALSE, TRUE);
+                    chg_dext(-2, FALSE, TRUE);
+                    no_command = 3 + rnd(HEROTIME);
+                    turn_on(player, ISUNHERO);
+                    light_fuse(FUSE_SHERO, 0, HEROTIME + rnd(HEROTIME), AFTER);
+                }
+            }
+            else
+            {
+                if (on(player, ISFLEE))
+                {
+                    turn_off(player, ISFLEE);
+                    msg("You regain your composure.");
+                }
+
+                if (on(player, ISUNHERO))
+                {
+                    extinguish_fuse(FUSE_SHERO);
+                    shero(NULL);
+                }
+                else if (on(player, SUPERHERO))
+                {
+                    if (find_slot(FUSE_UNBHERO,FUSE))
+                        lengthen_fuse(FUSE_UNBHERO, HEROTIME+2*rnd(HEROTIME));
+                    else if (find_slot(FUSE_UNSHERO,FUSE) && !blessed)
+                        lengthen_fuse(FUSE_UNSHERO,HEROTIME+2*rnd(HEROTIME));
+                    else
+                    {
+                        extinguish_fuse(FUSE_UNSHERO);
+                        unshero(NULL);
+                        light_fuse(FUSE_UNBHERO,0, 2 * (HEROTIME + rnd(HEROTIME)), AFTER);
+                    }
+                    msg("Your feeling of invulnerablity grows stronger.");
+                }
+                else
+                {
+                    turn_on(player, SUPERHERO);
+                    chg_str(10, FALSE, FALSE);
+                    chg_dext(5, FALSE, FALSE);
+                    quaff(quaffer, P_HASTE, ISBLESSED);
+                    quaff(quaffer, P_CLEAR, ISNORMAL);
+
+                    if (blessed)
+                    {
+                        light_fuse(FUSE_UNBHERO, 0, HEROTIME + rnd(HEROTIME), AFTER);
+                        msg("You suddenly feel invincible.");
+                    }
+                    else
+                    {
+                        light_fuse(FUSE_UNSHERO, 0, HEROTIME + rnd(HEROTIME), AFTER);
+                        msg("You suddenly feel invulnerable.");
+                    }
+
+                    if (is_potion)
+                        know_items[TYP_POTION][P_SHERO] = TRUE;
+                }
+            }
+            break;
+
+        case P_DISGUISE:
+            if (off(player, ISDISGUISE) && off(player, ISINVIS))
+            {
+                turn_on(player, ISDISGUISE);
+                msg("Your body shimmers a moment and then changes.");
+                light_fuse(FUSE_UNDISGUISE, 0, blessed ? GONETIME * 3 : GONETIME, AFTER);
+
+                if (rnd(2))
+                    PLAYER = 'a' + ucrnd(26);
+                else
+                    PLAYER = 'A' + ucrnd(26);
+
+                light(&hero);
+
+                if (is_potion)
+                    know_items[TYP_POTION][P_DISGUISE] = TRUE;
+            }
+            else if (off(player, ISINVIS))
+                lengthen_fuse(FUSE_UNDISGUISE,blessed?GONETIME * 3 : GONETIME);
+            else
+                msg("You have an itchy feeling under your skin.");
+
+            break;
+
+        case P_FIRERESIST:
+            if (cursed)
+            {
+                if (!is_wearing(R_FIRERESIST))
+                {
+                    msg("Your teeth start clattering.");
+
+                    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
+                    msg("You feel a brief chill.");
+            }
+            else
+            {
+                if (is_potion)
+                    know_items[TYP_POTION][P_FIRERESIST] = TRUE;
+
+                if (blessed)
+                {
+                    extinguish_fuse(FUSE_UNHOT);
+                    msg("You feel a strong continuous warm glow.");
+                }
+                else
+                {
+                    if (off(player, NOFIRE))
+                    {
+                        light_fuse(FUSE_UNHOT, 0, PHASEDURATION, AFTER);
+                        msg("You feel a warm glow.");
+                    }
+                    else
+                    {
+                        if (find_slot(FUSE_UNHOT,FUSE) == NULL)
+                            msg("Your warm glow continues.");
+                        else
+                        {
+                            lengthen_fuse(FUSE_UNHOT, PHASEDURATION);
+                            msg("Your feel a hot flush.");
+                        }
+                    }
+                }
+
+                turn_on(player, NOFIRE);
+
+                if (on(player, NOCOLD))
+                {
+                    turn_off(player, NOCOLD);
+                    extinguish_fuse(FUSE_UNCOLD);
+                }
+            }
+            break;
+
+        case P_COLDRESIST:
+            if (cursed)
+            {
+                if (!is_wearing(R_COLDRESIST))
+                {
+                    msg("Your feel feverishly hot.");
+
+                    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
+                    msg("You feel a brief touch of heat rash.");
+            }
+            else
+            {
+                if (is_potion)
+                    know_items[TYP_POTION][P_COLDRESIST] = TRUE;
+
+                if (blessed)
+                {
+                    extinguish_fuse(FUSE_UNCOLD);
+                    msg("You feel a strong continuous cool breeze.");
+                }
+                else
+                {
+                    if (off(player, NOCOLD))
+                    {
+                        light_fuse(FUSE_UNCOLD, 0, PHASEDURATION, AFTER);
+                        msg("You feel a cool breeze.");
+                    }
+                    else
+                    {
+                        if (find_slot(FUSE_UNCOLD,FUSE) == NULL)
+                            msg("Your cool feeling continues.");
+                        else
+                        {
+                            lengthen_fuse(FUSE_UNCOLD, PHASEDURATION);
+                            msg("The cool breeze blows more strongly.");
+                        }
+                    }
+                }
+
+                turn_on(player, NOCOLD);
+
+                if (on(player, NOFIRE))
+                {
+                    extinguish_fuse(FUSE_UNHOT);
+                    turn_off(player, NOFIRE);
+                }
+            }
+            break;
+
+        case P_HASOXYGEN:
+            if (cursed)
+            {
+                if (!is_wearing(R_BREATHE))
+                {
+                    msg("You can't breathe.");
+                    no_command = HOLDTIME;
+                }
+                else
+                {
+                    msg("You feel a momentary shortness of breath.");
+                }
+            }
+            else
+            {
+                short   duration = (blessed ? 3 : 1);
+
+                if (is_potion)
+                    know_items[TYP_POTION][P_HASOXYGEN] = TRUE;
+
+                if (on(player, HASOXYGEN))
+                    lengthen_fuse(FUSE_UNBREATHE, duration * PHASEDURATION);
+                else
+                {
+                    light_fuse(FUSE_UNBREATHE, 0, duration * PHASEDURATION, AFTER);
+                    turn_on(player, HASOXYGEN);
+                }
+
+                if (!is_wearing(R_BREATHE))
+                    msg("The air seems %sless polluted.",
+                        blessed ? "much " : "");
+            }
+            break;
+
+        case P_LEVITATION:
+            if (cursed)
+            {
+                msg("You can't move.");
+                no_command = HOLDTIME;
+            }
+            else
+            {
+                short   duration = (blessed ? 3 : 1);
+
+                if (is_potion)
+                    know_items[TYP_POTION][P_LEVITATION] = TRUE;
+
+                if (on(player, CANFLY))
+                    lengthen_fuse(FUSE_UNFLY, duration * WANDERTIME);
+                else
+                {
+                    light_fuse(FUSE_UNFLY, 0, duration * WANDERTIME, AFTER);
+                    turn_on(player, CANFLY);
+                }
+
+                if (!is_wearing(R_LEVITATION))
+                    msg("You %sbegin to float in the air!",
+                        blessed ? "quickly " : "");
+            }
+            break;
+
+        case P_REGENERATE:
+            if (cursed)
+            {
+                quaff(quaffer, P_HEALING, ISCURSED);
+                quaff(quaffer, P_HASTE, ISCURSED);
+            }
+            else
+            {
+                short   duration = (blessed ? 3 : 1) * HUHDURATION;
+
+                if (is_potion)
+                    know_items[TYP_POTION][P_REGENERATE] = TRUE;
+
+                if (on(player, SUPEREAT))
+                    lengthen_fuse(FUSE_UNSUPEREAT, duration);
+                else
+                {
+                    light_fuse(FUSE_UNSUPEREAT, 0, duration, AFTER);
+                    turn_on(player, SUPEREAT);
+                }
+
+                if (on(player, ISREGEN))
+                    lengthen_fuse(FUSE_UNREGEN, duration);
+                else
+                {
+                    light_fuse(FUSE_UNREGEN, 0, duration, AFTER);
+                    turn_on(player, ISREGEN);
+                }
+
+                if (!is_wearing(R_REGEN))
+                    msg("You feel %shealthier!", blessed ? "much " : "");
+            }
+
+        case P_SHIELD:
+        {
+            int adjustment = 0;
+
+            if (on(player, HASSHIELD))      /* cancel old spell */
+            {
+                extinguish_fuse(FUSE_UNSHIELD);
+                unshield(NULL);
+            }
+
+            if (cursed)
+                adjustment = 2;
+            else if (blessed)
+            {
+                msg("Your skin feels very rigid.");
+
+                switch (player.t_ctype)
+                {
+                    case C_FIGHTER:
+                    case C_PALADIN:
+                    case C_RANGER:
+                        adjustment = -3;
+                        break;
+                    default:
+                        adjustment = -5;
+                }
+            }
+            else
+            {
+                msg("Your skin hardens.");
+                adjustment = -2;
+            }
+
+            pstats.s_arm += adjustment;
+            pstats.s_acmod += adjustment;
+            turn_on(player, HASSHIELD);
+            light_fuse(FUSE_UNSHIELD,0,(blessed ? 3 : 1) * SEEDURATION, AFTER);
+
+            if (is_potion)
+                know_items[TYP_POTION][P_SHIELD] = TRUE;
+        }
+        break;
+
+        case P_TRUESEE:
+            if (cursed)
+            {
+                turn_on(player, PERMBLIND);
+
+                if (on(player, ISBLIND))
+                {
+                    msg("The gloom around you thickens.");
+                    lengthen_fuse(FUSE_SIGHT, SEEDURATION);
+                }
+                else
+                {
+                    msg("A mantle of darkness falls around you.");
+                    turn_on(player, ISBLIND);
+                    light_fuse(FUSE_SIGHT, 0, SEEDURATION, AFTER);
+                    look(FALSE);
+                }
+                look(FALSE);
+            }
+            else if (on(player, PERMBLIND))
+            {
+                if (blessed || is_potion)
+                {
+                    turn_off(player, PERMBLIND);
+                    sight(NULL);
+                    goto let_there_be_light;
+                }
+                else
+                    nothing_message(ISBLESSED);
+            }
+            else
+    let_there_be_light:
+                if (off(player, CANSEE))
+                {
+                    turn_on(player, CANSEE);
+                    msg("You feel especially perceptive.");
+                    light_fuse(FUSE_UNTRUESEE, 0, blessed ? SEEDURATION * 3
+                        : SEEDURATION, AFTER);
+                    light(&hero);
+                }
+                else if (find_slot(FUSE_UNSEE,FUSE) != NULL)
+                {
+                    nothing_message(ISNORMAL);
+                    lengthen_fuse(FUSE_UNTRUESEE, blessed ? SEEDURATION * 3
+                        : SEEDURATION);
+                }
+
+            break;
+
+        default:
+            msg("What an odd tasting potion!");
+            return;
+    }
+
+    status(FALSE);
+
+    if (is_potion)
+    {
+        if (!cursed && know_items[TYP_POTION][which] &&
+            guess_items[TYP_POTION][which])
+        {
+            ur_free(guess_items[TYP_POTION][which]);
+            guess_items[TYP_POTION][which] = NULL;
+        }
+        else if (askme && !know_items[TYP_POTION][which] &&
+            guess_items[TYP_POTION][which] == NULL)
+        {
+            msg(terse ? "Call it: " :  "What do you want to call it? ");
+
+            if (get_string(buf, cw) == NORM)
+            {
+                guess_items[TYP_POTION][which] =
+                    new_alloc(strlen(buf) + 1);
+                strcpy(guess_items[TYP_POTION][which], buf);
+            }
+        }
+        food_left += (blessed ? rnd(100) : (cursed ? -rnd(100) : rnd(50)));
+    }
+}
+
+/*
+    lower_level()
+        Lower a level of experience
+*/
+
+void
+lower_level(int who)
+{
+    int fewer, nsides = 0, i;
+
+    if (--pstats.s_lvl == 0)
+    {
+        death(who); /* All levels gone */
+        return;
+    }
+
+    msg("You suddenly feel less skillful.");
+    pstats.s_exp = 1L;
+    init_exp();
+
+    for (i = 2; i <= pstats.s_lvl; i++)
+    {
+        if (max_stats.s_exp < 0x3fffffffL)  /* 2^30 - 1 */
+            max_stats.s_exp *= 2L;  /* twice as many for next */
+    }
+
+    switch (player.t_ctype)
+    {
+        case C_FIGHTER: nsides = 12;break;
+        case C_PALADIN: nsides = 12;break;
+        case C_RANGER: nsides = 12; break;
+        case C_MAGICIAN: nsides = 4;break;
+        case C_ILLUSION: nsides = 4;break;
+        case C_CLERIC: nsides = 8;  break;
+        case C_DRUID: nsides = 8;   break;
+        case C_THIEF: nsides = 6;   break;
+        case C_ASSASIN: nsides = 6; break;
+        case C_NINJA: nsides = 6;   break;
+    }
+
+    fewer = max(1, roll(1, 16 - nsides) + int_wis_bonus());
+    pstats.s_power -= fewer;
+    max_stats.s_power -= fewer;
+
+    fewer = max(1, roll(1, nsides) + const_bonus());
+    pstats.s_hpt -= fewer;
+    max_stats.s_hpt -= fewer;
+
+    if (pstats.s_hpt < 1)
+        pstats.s_hpt = 1;
+
+    if (max_stats.s_hpt < 1)
+    {
+        death(who);
+        return;
+    }
+}
+
+void
+res_dexterity(void)
+{
+    if (lost_dext)
+    {
+        chg_dext(lost_dext, FALSE, FALSE);
+        lost_dext = 0;
+    }
+    else
+    {
+        pstats.s_dext = max_stats.s_dext + ring_value(R_ADDHIT) +
+            (on(player, POWERDEXT) ? 10 : 0) +
+            (on(player, SUPERHERO) ? 5 : 0);
+    }
+
+}
+
+
+/*
+    res_wisdom()
+        Restore player's wisdom
+*/
+
+void
+res_wisdom(void)
+{
+    int ring_str;
+
+    /* Discount the ring value */
+
+    ring_str = ring_value(R_ADDWISDOM) + (on(player, POWERWISDOM) ? 10 : 0);
+    pstats.s_wisdom -= ring_str;
+
+    if (pstats.s_wisdom < max_stats.s_wisdom)
+        pstats.s_wisdom = max_stats.s_wisdom;
+
+    /* Redo the rings */
+
+    pstats.s_wisdom += ring_str;
+}
+
+/*
+    res_intelligence()
+        Restore player's intelligence
+*/
+
+void
+res_intelligence(void)
+{
+    int ring_str;
+
+    /* Discount the ring value */
+
+    ring_str = ring_value(R_ADDINTEL) + (on(player, POWERINTEL) ? 10 : 0);
+    pstats.s_intel -= ring_str;
+
+    if (pstats.s_intel < max_stats.s_intel)
+        pstats.s_intel = max_stats.s_intel;
+
+    /* Redo the rings */
+
+    pstats.s_intel += ring_str;
+}
+
+
+/*
+    add_strength()
+        Increase player's strength
+*/
+
+void
+add_strength(int cursed)
+{
+
+    if (cursed)
+    {
+        msg("You feel slightly weaker now.");
+        chg_str(-1, FALSE, FALSE);
+    }
+    else
+    {
+        msg("You feel stronger now.  What bulging muscles!");
+
+        if (lost_str != 0)
+        {
+            lost_str--;
+            chg_str(1, FALSE, FALSE);
+        }
+        else
+            chg_str(1, TRUE, FALSE);
+    }
+}
+
+
+/*
+    add_intelligence()
+        Increase player's intelligence
+*/
+
+void
+add_intelligence(int cursed)
+{
+    int ring_str;   /* Value of ring strengths */
+
+    /* Undo any ring changes */
+
+    ring_str = ring_value(R_ADDINTEL) + (on(player, POWERINTEL) ? 10 : 0);
+    pstats.s_intel -= ring_str;
+
+    /* Now do the potion */
+
+    if (cursed)
+    {
+        msg("You feel slightly less intelligent now.");
+        pstats.s_intel = max(pstats.s_intel - 1, 3);
+    }
+    else
+    {
+        msg("You feel more intelligent now.  What a mind!");
+        pstats.s_intel = min(pstats.s_intel + 1, 25);
+    }
+
+    /* Adjust the maximum */
+
+    if (max_stats.s_intel < pstats.s_intel)
+        max_stats.s_intel = pstats.s_intel;
+
+    /* Now put back the ring changes */
+    pstats.s_intel += ring_str;
+}
+
+
+/*
+    add_wisdom()
+        Increase player's wisdom
+*/
+
+void
+add_wisdom(int cursed)
+{
+    int ring_str;   /* Value of ring strengths */
+
+    /* Undo any ring changes */
+
+    ring_str = ring_value(R_ADDWISDOM) + (on(player, POWERWISDOM) ? 10 : 0);
+    pstats.s_wisdom -= ring_str;
+
+    /* Now do the potion */
+
+    if (cursed)
+    {
+        msg("You feel slightly less wise now.");
+        pstats.s_wisdom = max(pstats.s_wisdom - 1, 3);
+    }
+    else
+    {
+        msg("You feel wiser now.  What a sage!");
+        pstats.s_wisdom = min(pstats.s_wisdom + 1, 25);
+    }
+
+    /* Adjust the maximum */
+
+    if (max_stats.s_wisdom < pstats.s_wisdom)
+        max_stats.s_wisdom = pstats.s_wisdom;
+
+    /* Now put back the ring changes */
+    pstats.s_wisdom += ring_str;
+}
+
+
+/*
+    add_dexterity()
+        Increase player's dexterity
+*/
+
+void
+add_dexterity(int cursed)
+{
+    /* Now do the potion */
+
+    if (cursed)
+    {
+        msg("You feel less dextrous now.");
+        chg_dext(-1, FALSE, TRUE);
+    }
+    else
+    {
+        msg("You feel more dextrous now.  Watch those hands!");
+
+        if (lost_dext != 0)
+        {
+            lost_dext--;
+            chg_dext(1, FALSE, FALSE);
+        }
+        else
+            chg_dext(1, TRUE, FALSE);
+    }
+}
+
+
+/*
+    Increase player's constitution
+*/
+
+void
+add_const(int cursed)
+{
+    /* Do the potion */
+
+    if (cursed)
+    {
+        msg("You feel slightly less healthy now.");
+        pstats.s_const = max(pstats.s_const - 1, 3) +
+            (on(player, POWERCONST) ? 10 : 0);
+    }
+    else
+    {
+        msg("You feel healthier now.");
+        pstats.s_const = min(pstats.s_const + 1, 25) +
+            (on(player, POWERCONST) ? 10 : 0);
+    }
+
+    /* Adjust the maximum */
+
+    if (max_stats.s_const < pstats.s_const - (on(player, POWERCONST) ? 10 : 0))
+        max_stats.s_const = pstats.s_const;
+}
+
+/*
+    monquaff()
+        monster gets the effect
+*/
+
+void
+monquaff(struct thing *quaffer, int which, int flags)
+{
+    struct stats *curp = &(quaffer->t_stats);
+    struct stats *maxp = &(quaffer->maxstats);
+    int blessed = flags & ISBLESSED;
+    int cursed = flags & ISCURSED;
+
+    switch(which)
+    {
+        case P_SEEINVIS:
+            if (cursed)
+                turn_on(*quaffer, ISHUH);
+            else
+                turn_on(*quaffer, CANSEE);
+            break;
+
+        case P_GAINABIL:
+            if (cursed)
+                curp->s_intel /= 2;
+            else
+                curp->s_power = maxp->s_power;
+            break;
+
+        case P_CLEAR:
+            if (cursed)
+                turn_on(*quaffer, ISHUH);
+            else
+                turn_on(*quaffer, ISHUH);
+            break;
+
+        case P_HEALING:
+            if (cursed)
+            {
+                curp->s_hpt /= 2;
+                curp->s_power /= 2;
+            }
+            else
+            {
+                int nsides = (blessed ? 8 : 4);
+                int hpt_gain = roll(curp->s_lvl, nsides);
+                int power_gain = roll(curp->s_lvl, nsides);
+
+                curp->s_hpt = min(curp->s_hpt + hpt_gain, maxp->s_hpt);
+                curp->s_power = min(curp->s_power + power_gain, maxp->s_power);
+            }
+            break;
+
+        case  P_HASTE:
+            if (cursed)
+            {
+                if (on(*quaffer, ISHASTE))
+                    turn_off(*quaffer, ISHASTE);
+                else
+                    turn_on(*quaffer, ISSLOW);
+            }
+            else
+                turn_on(*quaffer, ISHASTE);
+            break;
+
+        case P_INVIS:
+            turn_on(*quaffer, ISINVIS);
+
+            if (cansee(quaffer->t_pos.y, quaffer->t_pos.x))
+                seemsg("The monster dissappears!");
+
+            break;
+
+        case P_REGENERATE:
+            if (cursed)
+            {
+                quaff(quaffer, P_HEALING, ISCURSED);
+                quaff(quaffer, P_HASTE, ISCURSED);
+            }
+            else
+                turn_on(*quaffer, ISREGEN);
+            break;
+
+        case P_SHERO:
+            if (on(*quaffer, ISFLEE))
+                turn_off(*quaffer, ISFLEE);
+            else
+            {
+                turn_on(*quaffer, SUPERHERO);
+                quaff(quaffer, P_HASTE, ISBLESSED);
+                quaff(quaffer, P_CLEAR, ISNORMAL);
+            }
+            break;
+
+        case P_PHASE:
+            if (cursed)
+                quaffer->t_no_move += HOLDTIME;
+            else
+                turn_on(*quaffer, CANINWALL);
+            break;
+
+        default:
+            debug("'%s' is a strange potion for a monster to quaff!",
+                p_magic[which].mi_name);
+    }
+}