view xrogue/potions.c @ 265:7fcb2f9f57e6

Mention UltraRogue in the top-level README.
author John "Elwin" Edwards
date Sun, 19 Feb 2017 19:54:17 -0500
parents 7c1cb43f346e
children 0250220d8cdd
line wrap: on
line source

/*
    potions.c - Functions for dealing with potions

    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 <stdlib.h>
#include <curses.h>
#include "rogue.h"

int add_charisma(int change);
int add_constitution(int change);
int add_dexterity(int change);
int add_intelligence(int change);
int add_strength(int change);
int add_wisdom(int change);

void res_charisma(int howmuch);
void res_constitution(int howmuch);
void res_dexterity(int howmuch);
void res_intelligence(int howmuch);
void res_wisdom(int howmuch);

/*
 * add_abil is an array of functions used to change attributes.  It must be
 * ordered according to the attribute definitions in rogue.h.
 */

int (*add_abil[NUMABILITIES])() = {
    add_intelligence, add_strength, add_wisdom, add_dexterity,
    add_constitution, add_charisma
};

/*
 * res_abil is an array of functions used to change attributes.  It must be
 * ordered according to the attribute definitions in rogue.h.
 */

void (*res_abil[NUMABILITIES])() = {
    res_intelligence, res_strength, res_wisdom, res_dexterity,
    res_constitution, res_charisma
};

/*
 * Increase player's constitution
 */

int
add_constitution(int change)
{
    /* Do the potion */
    if (change < 0) {
        msg("You feel less healthy now.");
        pstats.s_const += change;
        if (pstats.s_const < 1) {
        pstats.s_hpt = -1;
        msg("You collapse!  --More--");
        wait_for(' ');
            death(D_CONSTITUTION);
    }
    }
    else {
        msg("You feel healthier now.");
        pstats.s_const = min(pstats.s_const + change, MAXATT);
    }

    /* Adjust the maximum */
    if (max_stats.s_const < pstats.s_const)
        max_stats.s_const = pstats.s_const;

    return(0);
}

/*
 * Increase player's charisma
 */

int
add_charisma(int change)
{
    /* Do the potion */
    if (change < 0) msg("You feel less attractive now.");
    else msg("You feel more attractive now.");

    pstats.s_charisma += change;
    if (pstats.s_charisma > MAXATT) pstats.s_charisma = MAXATT;
    else if (pstats.s_charisma < 3) pstats.s_charisma = 3;

    /* Adjust the maximum */
    if (max_stats.s_charisma < pstats.s_charisma)
        max_stats.s_charisma = pstats.s_charisma;

    return(0);
}

/*
 * Increase player's dexterity
 */

int
add_dexterity(int change)
{
    int ring_str;       /* Value of ring strengths */

    /* Undo any ring changes */
    ring_str = ring_value(R_ADDHIT);
    pstats.s_dext -= ring_str;

    /* Now do the potion */
    if (change < 0) msg("You feel less dextrous now.");
    else msg("You feel more dextrous now.  Watch those hands!");

    pstats.s_dext += change;
    if (pstats.s_dext > MAXATT) pstats.s_dext = MAXATT;
    else if (pstats.s_dext < 3) pstats.s_dext = 3;

    /* Adjust the maximum */
    if (max_stats.s_dext < pstats.s_dext)
        max_stats.s_dext = pstats.s_dext;

    /* Now put back the ring changes */
    if (ring_str)
        pstats.s_dext += ring_str;

    return(0);
}

/*
 * add_haste:
 *      add a haste to the player
 */

void
add_haste(bool blessed)
{
    int hasttime;

    if (player.t_ctype == C_MONK) { /* monks cannot be slowed or hasted */
        msg(nothing);
        return;
    }

    if (blessed) hasttime = HASTETIME*2;
    else hasttime = HASTETIME;

    if (on(player, ISSLOW)) { /* Is person slow? */
        extinguish(noslow);
        noslow();

        if (blessed) hasttime = HASTETIME/2;
        else return;
    }

    if (on(player, ISHASTE)) {
        msg("You faint from exhaustion.");
        player.t_no_move += movement(&player) * rnd(hasttime);
        player.t_action = A_FREEZE;
        lengthen(nohaste, roll(hasttime,hasttime));
    }
    else {
        msg("You feel yourself moving %sfaster.", blessed ? "much " : "");
        turn_on(player, ISHASTE);
        fuse(nohaste, NULL, roll(hasttime, hasttime), AFTER);
    }
}

/*
 * Increase player's intelligence
 */

int
add_intelligence(int change)
{
    int ring_str;       /* Value of ring strengths */

    /* Undo any ring changes */
    ring_str = ring_value(R_ADDINTEL);
    pstats.s_intel -= ring_str;

    /* Now do the potion */
    if (change < 0) msg("You feel slightly less intelligent now.");
    else msg("You feel more intelligent now.  What a mind!");

    pstats.s_intel += change;
    if (pstats.s_intel > MAXATT) pstats.s_intel = MAXATT;
    else if (pstats.s_intel < 3) pstats.s_intel = 3;

    /* Adjust the maximum */
    if (max_stats.s_intel < pstats.s_intel)
            max_stats.s_intel = pstats.s_intel;

    /* Now put back the ring changes */
    if (ring_str)
        pstats.s_intel += ring_str;

    return(0);
}

/*
 * this routine makes the hero move slower 
 */

void
add_slow(void)
{
    /* monks cannot be slowed or hasted */
    if (player.t_ctype == C_MONK || ISWEARING(R_FREEDOM)) { 
        msg(nothing);
        return;
    }

    if (on(player, ISHASTE)) { /* Already sped up */
        extinguish(nohaste);
        nohaste();
    }
    else {
        msg("You feel yourself moving %sslower.",
                on(player, ISSLOW) ? "even " : "");
        if (on(player, ISSLOW))
            lengthen(noslow, roll(HASTETIME,HASTETIME));
        else {
            turn_on(player, ISSLOW);
            fuse(noslow, NULL, roll(HASTETIME,HASTETIME), AFTER);
        }
    }
}

/*
 * Increase player's strength
 */

int
add_strength(int change)
{

    if (change < 0) {
        msg("You feel slightly weaker now.");
        chg_str(change);
    }
    else {
        msg("You feel stronger now.  What bulging muscles!");
        chg_str(change);
    }
    return(0);
}

/*
 * Increase player's wisdom
 */

int
add_wisdom(int change)
{
    int ring_str;       /* Value of ring strengths */

    /* Undo any ring changes */
    ring_str = ring_value(R_ADDWISDOM);
    pstats.s_wisdom -= ring_str;

    /* Now do the potion */
    if (change < 0) msg("You feel slightly less wise now.");
    else msg("You feel wiser now.  What a sage!");

    pstats.s_wisdom += change;
    if (pstats.s_wisdom > MAXATT) pstats.s_wisdom = MAXATT;
    else if (pstats.s_wisdom < 3) pstats.s_wisdom = 3;

    /* Adjust the maximum */
    if (max_stats.s_wisdom < pstats.s_wisdom)
        max_stats.s_wisdom = pstats.s_wisdom;

    /* Now put back the ring changes */
    if (ring_str)
        pstats.s_wisdom += ring_str;

    return(0);
}

void
quaff(int which, int kind, int flags, bool is_potion)
{
    register struct object *obj;
    register struct linked_list *item, *titem;
    register struct thing *th;
    bool cursed, blessed;

    blessed = FALSE;
    cursed = FALSE;
    item = NULL;

    if (which < 0) {    /* figure out which ourselves */
        /* This is a potion.  */
        if (player.t_action != C_QUAFF) {
            int units;

            item = get_item(pack, "quaff", QUAFFABLE, FALSE, FALSE);

            /*
             * Make certain that it is somethings that we want to drink
             */
            if (item == NULL)
                return;

            /* How long does it take to quaff? */
            units = usage_time(item);
            if (units < 0) return;

            player.t_using = item;      /* Remember what it is */
            player.t_no_move = units * movement(&player);
            if ((OBJPTR(item))->o_type == POTION) player.t_action = C_QUAFF;
            else player.t_action = C_USE;
            return;
        }

        /* We have waited our time, let's quaff the potion */
        item = player.t_using;
        player.t_using = NULL;
        player.t_action = A_NIL;

        obj = OBJPTR(item);
        /* remove it from the pack */
        inpack--;
        detach(pack, item);

        flags = obj->o_flags;
        which = obj->o_which;
        kind = obj->o_kind;
    }
    cursed = flags & ISCURSED;
    blessed = flags & ISBLESSED;

    switch(which) {
        case P_CLEAR:
            if (cursed) {
                confus_player();
            }
            else {
                if (blessed) {  /* Make player immune for the whole game */
                    extinguish(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)) {
                        fuse(unclrhead, NULL, CLRDURATION, AFTER);
                        msg("A faint blue aura surrounds your head.");
                    }
                    else {  /* If we have a fuse lengthen it, else we
                             * are permanently clear.
                             */
                        if (find_slot(unclrhead) == 0)
                            msg("Your blue aura continues to glow strongly.");
                        else {
                            lengthen(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(unconfuse);
                    unconfuse();
                }
            }
        when P_HEALING:
            if (cursed) {
                msg("You feel worse now.");
                pstats.s_hpt -= roll(pstats.s_lvl, char_class[player.t_ctype].hit_pts);
                if (pstats.s_hpt < 1) {
            pstats.s_hpt = -1;
            msg("You're life passes before your eyes..  --More--");
            wait_for(' ');
                    death(D_POTION);
        }
            }
            else {
                if (blessed) {
                    pstats.s_hpt += roll(pstats.s_lvl+1, char_class[player.t_ctype].hit_pts);
                    if (pstats.s_hpt > max_stats.s_hpt) {
                        pstats.s_hpt = ++max_stats.s_hpt;
                        pstats.s_hpt = ++max_stats.s_hpt;
            }
                    if (on(player, ISHUH)) {
                        extinguish(unconfuse);
                        unconfuse();
                    }
                }
                else {
                    pstats.s_hpt += roll(pstats.s_lvl+1, char_class[player.t_ctype].hit_pts/2);
                    if (pstats.s_hpt > max_stats.s_hpt)
                        pstats.s_hpt = ++max_stats.s_hpt;
                }
                msg("You begin to feel %sbetter.",
                        blessed ? "much " : "");
                sight();
                if (is_potion) p_know[P_HEALING] = TRUE;
            }
        when P_ABIL:
            /* If it is cursed, we take a point away */
            if (cursed) {
                if (ISWEARING(R_SUSABILITY)) {
                    msg(nothing);
                    break;
                }
                else (*add_abil[kind])(-1);
            }

            /* Otherwise we add points */
            else (*add_abil[kind])(blessed ? 3 : 1);

            if (is_potion) p_know[P_ABIL] = TRUE;
        when P_MFIND:
            /*
             * Potion of monster detection, if there are monters, detect them
             */
            if (mlist != NULL)
            {
                register struct thing *tp;
                register struct linked_list *item;

                wclear(hw);
                for (item=mlist; item!=NULL; item=next(item)) {
                    tp = THINGPTR(item);
                    if (on(*tp, NODETECT))
                        continue;
                    if (off(*tp, ISRUN))/* turn off only on sleeping ones */
                        turn_off(*tp, CANSURPRISE);
                    mvwaddch(hw, tp->t_pos.y, tp->t_pos.x, 
                             monsters[tp->t_index].m_appear);
                }
                rmmsg();
                overlay(hw,cw);
                draw(cw);
                msg("You begin to sense the presence of monsters.");
                if (is_potion) p_know[P_MFIND] = TRUE;
            }
            else
                msg("You have a strange feeling for a moment, then it passes.");
        when P_TFIND:
            /*
             * Potion of magic detection.  Show the potions and scrolls
             */
            {
                register struct linked_list *mobj;
                register struct object *tp;
                bool show;

                show = FALSE;
                wclear(hw);
                for (mobj = lvl_obj; mobj != NULL; mobj = next(mobj)) {
                    tp = OBJPTR(mobj);
                    if (is_magic(tp)) {
                        char mag_type=MAGIC;

                        /* Mark cursed items or bad weapons */
                        if ((tp->o_flags & ISCURSED) ||
                            (tp->o_type == WEAPON &&
                             (tp->o_hplus < 0 || tp->o_dplus < 0)))
                                mag_type = CMAGIC;
                        else if ((tp->o_flags & ISBLESSED) ||
                                 (tp->o_type == WEAPON &&
                                  (tp->o_hplus > 0 || tp->o_dplus > 0)))
                                        mag_type = BMAGIC;
                        show = TRUE;
                        mvwaddch(hw, tp->o_pos.y, tp->o_pos.x, mag_type);
                    }
                }
                for (titem = mlist; titem != NULL; titem = next(titem)) {
                    register struct linked_list *pitem;

                    th = THINGPTR(titem);
                    if (on(*th, NODETECT)) continue;
                    for(pitem = th->t_pack; pitem != NULL; pitem = next(pitem)){
                        tp = OBJPTR(pitem);
                        if (is_magic(tp)) {
                            char mag_type=MAGIC;

                            /* Mark cursed items or bad weapons */
                            if ((tp->o_flags & ISCURSED) ||
                                (tp->o_type == WEAPON &&
                                 (tp->o_hplus < 0 || tp->o_dplus < 0)))
                                    mag_type = CMAGIC;
                            else if ((tp->o_flags & ISBLESSED) ||
                                     (tp->o_type == WEAPON &&
                                      (tp->o_hplus > 0 || tp->o_dplus > 0)))
                                            mag_type = BMAGIC;
                            show = TRUE;
                            mvwaddch(hw, th->t_pos.y, th->t_pos.x, mag_type);
                        }
                    }
                }
                if (show) {
                    if (is_potion) p_know[P_TFIND] = TRUE;
                    rmmsg();
                    overlay(hw,cw);
                    draw(cw);
                    msg("You sense the presence of magic on this level.");
                    break;
                }
                else
                    msg("You have a strange feeling for a moment, then it passes.");
            }
        when P_SEEINVIS:
            if (cursed) {
                if (!find_slot(sight))
                {
                    msg("A cloak of darkness falls around you.");
                    turn_on(player, ISBLIND);
                    fuse(sight, NULL, SEEDURATION, AFTER);
                    light(&hero);
                }
                else
                    msg("The darkness around you thickens. ");
                    lengthen(sight, SEEDURATION);
            }
            else {
                if (off(player, CANSEE)) {
                    turn_on(player, CANSEE);
                    msg("Your eyes begin to tingle.");
                    fuse(unsee, NULL, blessed ? SEEDURATION*3 :SEEDURATION, AFTER);
                    light(&hero);
                }
                else if (find_slot(unsee) != 0) {
                    msg("You eyes continue to tingle.");
                    lengthen(unsee, blessed ? SEEDURATION*3 : SEEDURATION);
        }
                sight();
            }
        when P_PHASE:
            if (cursed) {
                msg("You can't move.");
                player.t_no_move = movement(&player) * FREEZETIME;
                player.t_action = A_FREEZE;
            }
            else {
                int duration;

                if (blessed) duration = 3;
                else duration = 1;

                if (on(player, CANINWALL))
                    lengthen(unphase, duration*PHASEDURATION);
                else {
                    fuse(unphase, NULL, duration*PHASEDURATION, AFTER);
                    turn_on(player, CANINWALL);
                }
                msg("You feel %slight-headed!",
                    blessed ? "very " : "");
            }
        when P_FLY: {
            int duration;
            bool say_message;

            say_message = TRUE;

            if (blessed) duration = 3;
            else duration = 1;

            if (on(player, ISFLY)) {
                if (find_slot(land))
                    lengthen(land, duration*FLYTIME);
                else {
                    msg("Nothing happens.");    /* Flying by cloak */
                    say_message = FALSE;
                }
            }
            else {
                fuse(land, NULL, duration*FLYTIME, AFTER);
                turn_on(player, ISFLY);
            }
            if (say_message) {
                if (is_potion) p_know[P_FLY] = TRUE;
                msg("You feel %slighter than air!", blessed ? "much " : "");
            }
        }
        when P_RAISE:
            if (cursed) lower_level(D_POTION);
            else {
                msg("You suddenly feel %smore skillful",
                        blessed ? "much " : "");
                p_know[P_RAISE] = TRUE;
                raise_level();
                do_panic(0);         /* this startles them */
                if (blessed) raise_level();
            }
        when P_HASTE:
            if (cursed) {       /* Slow player down */
                add_slow();
            }
            else {
                add_haste(blessed);
                if (is_potion) p_know[P_HASTE] = TRUE;
            }
        when P_RESTORE: {
            register int i, howmuch, strength_tally;

            msg("Hey, this tastes great.  It make you feel %swarm all over.",
                blessed ? "really " : "");
            howmuch = blessed ? 3 : 1;

            for (i=0; i<NUMABILITIES; i++) {
                if (i == A_STRENGTH) {
                    if (lost_str) {
                        if (lost_str > howmuch) {
                            lost_str -= howmuch;

                            /*
                             * Save the lost strength.  We have to set
                             * temporarilty set it to 0 so that res_strength
                             * will not restore it.
                             */
                            strength_tally = lost_str;
                            lost_str = 0;
                            res_strength(howmuch);
                            lost_str = strength_tally;
                        }
                        else {
                        lost_str = 0;
                            extinguish(res_strength);
                            res_strength(howmuch);
                        }
                    }
                    else res_strength(howmuch);
                }
                else (*res_abil[i])(howmuch);
            }
        }
        when P_INVIS:
            if (off(player, ISINVIS)) {
                turn_on(player, ISINVIS);
                msg("You have a tingling feeling all over your body");
                fuse(appear, NULL, blessed ? GONETIME*3 : GONETIME, AFTER);
                PLAYER = IPLAYER;
                light(&hero);
            }
            else {
                if (find_slot(appear)) {
                    msg("Your tingling feeling surges.");
                    lengthen(appear, blessed ? GONETIME*3 : GONETIME);
                }
                else msg("Nothing happens.");   /* Using cloak */
            }

        when P_FFIND:
            {
                register struct linked_list *nitem;
                register struct object *nobj;
                bool show;

                show = FALSE;
                wclear(hw);
                for (nitem = lvl_obj; nitem != NULL; nitem = next(nitem)) {
                    nobj = OBJPTR(nitem);
                    if (nobj->o_type == FOOD) {
                        show = TRUE;
                        mvwaddch(hw, nobj->o_pos.y, nobj->o_pos.x, FOOD);
                    }
                }
                for (nitem = mlist; nitem != NULL; nitem = next(nitem)) {
                    register struct linked_list *pitem;
                    register struct thing *th;

                    th = THINGPTR(nitem);
                    if (on(*th, NODETECT)) continue;
                    for(pitem = th->t_pack; pitem != NULL; pitem = next(pitem)){
                        nobj = OBJPTR(pitem);
                        if (nobj->o_type == FOOD) {
                            show = TRUE;
                            mvwaddch(hw, th->t_pos.y, th->t_pos.x, FOOD);
                        }
                    }
                }
                if (is_potion) p_know[P_FFIND] = TRUE;
                if (show) {
                    rmmsg();
                    msg("Your nose tingles.");
                    rmmsg();
                    overlay(hw,cw);
                    draw(cw);
                    msg("You sense the presence of food on this level.");
                }
                else
                    msg("You have a strange feeling for a moment, then it passes.");
            }

        when P_SKILL:
            if (cursed) {
                msg("You feel less skillful.");

                /* Does he currently have an artifical skill? */
                if (!find_slot(unskill)) {      /* No skill */
                    pstats.s_lvladj = -2;
                    pstats.s_lvl += pstats.s_lvladj;
                    fuse(unskill, NULL, SKILLDURATION, AFTER);
                }
                else {  /* Has an artifical skill */
                    /* Is the skill beneficial? */
                    if (pstats.s_lvladj > 0) {
                        /* Decrease the previous skill advantage */
                        pstats.s_lvl -= 2;
                        pstats.s_lvladj -= 2;

                        /* If there is now a negative skill, lengthen time */
                        if (pstats.s_lvladj < 0)
                            lengthen(unskill, SKILLDURATION);

                        /* If there is no skill advantage, unfuse us */
                        else if (pstats.s_lvladj == 0) extinguish(unskill);
                    }
                    else {      /* Already bad */
                        /* Make it a little worse, and lengthen it */
                        pstats.s_lvl--;
                        pstats.s_lvladj--;
                        lengthen(unskill, SKILLDURATION);
                    }
                }

                /* Is our level too low now? */
                if (pstats.s_lvl < 1) {
            pstats.s_hpt = -1;
            msg("You cough, choke, and finally die.  --More--");
            wait_for(' ');
            death(D_POTION);
        }
            }
            else {
                int adjust;

                msg("You feel more skillful.");
                max_stats.s_hpt++;
                pstats.s_hpt++;

                /* Get the adjustment */
                if (blessed)
                    adjust = rnd(4) + 2;
                else
                    adjust = rnd(2) + 1;

        /* The Fighter likes this */
            if (player.t_ctype == C_FIGHTER) {
                    max_stats.s_hpt++;
                    pstats.s_hpt++;
                    adjust = rnd(2) + 1;
            }

                /* Does he currently have an artifical skill? */
                if (!find_slot(unskill)) {
                    pstats.s_lvladj = adjust;
                    pstats.s_lvl += pstats.s_lvladj;
                    fuse(unskill, NULL, 
                         blessed ? SKILLDURATION*2 : SKILLDURATION, AFTER);
                }
                else {  /* Has an artifical skill */
                    /* Is the skill detrimental? */
                    if (pstats.s_lvladj < 0) {
                        /* Decrease the previous skill advantage */
                        pstats.s_lvl += adjust;
                        pstats.s_lvladj += adjust;

                        /* If there is now a positive skill, lengthen time */
                        if (pstats.s_lvladj < 0)
                            lengthen(unskill, SKILLDURATION);

                        /* If there is no skill advantage, unfuse us */
                        else if (pstats.s_lvladj == 0) extinguish(unskill);
                    }
                    else {      /* Already good */
                        /*
                         * Make the skill the maximum of the current good
                         * skill and what the adjust would give him.
                         */
                        pstats.s_lvl -= pstats.s_lvladj;
                        pstats.s_lvladj = max(pstats.s_lvladj, adjust);
                        pstats.s_lvl += pstats.s_lvladj;
                        lengthen(unskill,
                                 blessed ? SKILLDURATION*2 : SKILLDURATION);
                    }
                }
            }

        when P_FIRE: {
            int duration;
            bool say_message;

            say_message = TRUE;