view arogue7/potions.c @ 176:db1c9a21a7c3

srogue: prevent overflowing the score file name. If SCOREFILE is not defined, roguehome() is called to find a directory for the score file. It copies up to PATH_MAX-20 bytes from an environment variable to a static buffer. Later these are strcpy()'d to scorefile, which is of size LINLEN. Unfortunately LINLEN is 80 and PATH_MAX is at least 256. On Linux, it happens to be 4096. I haven't yet managed to crash or exploit it, but there are surely no beneficial consequences, so roguehome() has been modified to check the length, and the string it returns is also checked in main().
author John "Elwin" Edwards
date Sun, 02 Aug 2015 12:14:47 -0400
parents 80c060734f51
children f057f09e9945
line wrap: on
line source

/*
 * potions.c  -  Function(s) for dealing with potions
 *
 * Advanced Rogue
 * Copyright (C) 1984, 1985, 1986 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.
 */

/*
 * Function(s) for dealing with potions
 */

#include <stdlib.h>
#include "curses.h"
#include "rogue.h"


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

void (*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
 */

void
add_constitution(change)
int change;
{
    /* Do the potion */
    if (change < 0) {
	msg("You feel less healthy now.");
	pstats.s_const += change;
	if (pstats.s_const <= 0)
	    death(D_CONSTITUTION);
    }
    else {
	msg("You feel healthier now.");
	pstats.s_const = min(pstats.s_const + change, 25);
    }

    /* Adjust the maximum */
    if (max_stats.s_const < pstats.s_const)
	max_stats.s_const = pstats.s_const;
}

/*
 * Increase player's charisma
 */

void
add_charisma(change)
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 > 25) pstats.s_charisma = 25;
    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;
}

/*
 * Increase player's dexterity
 */

void
add_dexterity(change)
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 > 25) pstats.s_dext = 25;
    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;
}

/*
 * add_haste:
 *	add a haste to the player
 */

add_haste(blessed)
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, 0, roll(hasttime, hasttime), AFTER);
    }
}

/*
 * Increase player's intelligence
 */
void
add_intelligence(change)
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 > 25) pstats.s_intel = 25;
    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;
}

/*
 * this routine makes the hero move slower 
 */
add_slow()
{
    /* 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, 0, roll(HASTETIME,HASTETIME), AFTER);
	}
    }
}

/*
 * Increase player's strength
 */

void
add_strength(change)
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);
    }
}

/*
 * Increase player's wisdom
 */

void
add_wisdom(change)
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 > 25) pstats.s_wisdom = 25;
    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;
}

quaff(which, kind, flags, is_potion)
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, 0, 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 <= 0) 
		    death(D_POISON);
	    }
	    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;
		    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;

		msg("You begin to sense the presence of monsters.");
		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);
		}