view arogue5/daemons.c @ 251:e7862a021609

Fix the perpetual haste cheat. Rogue V3 allowed the player to gain perpetual haste by quaffing a potion of haste while already hasted. This is supposed to remove the haste effect and cause temporary paralysis. Super-Rogue removed haste correctly, but gave confusing messages.
author John "Elwin" Edwards
date Sat, 28 Jan 2017 11:45:36 -0500
parents 56e748983fa8
children
line wrap: on
line source

/*
 * All the daemon and fuse functions are in here
 *
 * 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 "curses.h"
#include "rogue.h"

int between = 0;

/*
 * doctor:
 *	A healing daemon that restors hit points after rest
 */

void
doctor(struct thing *tp)
{
    register int ohp;
    register int limit, new_points;
    register struct stats *curp; /* current stats pointer */
    register struct stats *maxp; /* max stats pointer */

    curp = &(tp->t_stats);
    maxp = &(tp->maxstats);
    if (curp->s_hpt == maxp->s_hpt) {
	tp->t_quiet = 0;
	return;
    }
    tp->t_quiet++;
    switch (tp->t_ctype) {
	case C_MAGICIAN:
	    limit = 8 - curp->s_lvl;
	    new_points = curp->s_lvl - 3;
	when C_THIEF:
	    limit = 8 - curp->s_lvl;
	    new_points = curp->s_lvl - 2;
	when C_CLERIC:
	    limit = 8 - curp->s_lvl;
	    new_points = curp->s_lvl - 3;
	when C_FIGHTER:
	    limit = 16 - curp->s_lvl*2;
	    new_points = curp->s_lvl - 5;
	when C_MONSTER:
	    limit = 16 - curp->s_lvl;
	    new_points = curp->s_lvl - 6;
	otherwise:
	    debug("what a strange character you are!");
	    return;
    }
    ohp = curp->s_hpt;
    if (off(*tp, HASDISEASE) && off(*tp, DOROT)) {
	if (curp->s_lvl < 8) {
	    if (tp->t_quiet > limit) {
		curp->s_hpt++;
		tp->t_quiet = 0;
	    }
	}
	else {
	    if (tp->t_quiet >= 3) {
		curp->s_hpt += rnd(new_points)+1;
		tp->t_quiet = 0;
	    }
	}
    }
    if (tp == &player) {
	if (ISRING(LEFT_1, R_REGEN)) curp->s_hpt++;
	if (ISRING(LEFT_2, R_REGEN)) curp->s_hpt++;
	if (ISRING(LEFT_3, R_REGEN)) curp->s_hpt++;
	if (ISRING(LEFT_4, R_REGEN)) curp->s_hpt++;
	if (ISRING(RIGHT_1, R_REGEN)) curp->s_hpt++;
	if (ISRING(RIGHT_2, R_REGEN)) curp->s_hpt++;
	if (ISRING(RIGHT_3, R_REGEN)) curp->s_hpt++;
	if (ISRING(RIGHT_4, R_REGEN)) curp->s_hpt++;
    }
    if (on(*tp, ISREGEN))
	curp->s_hpt += curp->s_lvl/10 + 1;
    if (ohp != curp->s_hpt) {
	if (curp->s_hpt >= maxp->s_hpt) {
	    curp->s_hpt = maxp->s_hpt;
	    if (off(*tp, WASTURNED) && on(*tp, ISFLEE) && tp != &player) {
		turn_off(*tp, ISFLEE);
		tp->t_oldpos = tp->t_pos;	/* Start our trek over */
	    }
	}
    }
}

/*
 * Swander:
 *	Called when it is time to start rolling for wandering monsters
 */

void
swander(void)
{
    start_daemon(rollwand, 0, BEFORE);
}

/*
 * rollwand:
 *	Called to roll to see if a wandering monster starts up
 */

void
rollwand(void)
{
    if (++between >= 4)
    {
	/* Theives may not awaken a monster */
	if ((roll(1, 6) == 4) &&
	   ((player.t_ctype != C_THIEF) || (rnd(30) >= dex_compute()))) {
	    if (levtype != POSTLEV)
	        wanderer();
	    kill_daemon(rollwand);
	    fuse(swander, 0, WANDERTIME, BEFORE);
	}
	between = 0;
    }
}
/*
 * this function is a daemon called each turn when the character is a thief
 */
void
trap_look(void)
{
    if (rnd(100) < (2*dex_compute() + 5*pstats.s_lvl))
	search(TRUE, FALSE);
}

/*
 * unconfuse:
 *	Release the poor player from his confusion
 */

void
unconfuse(void)
{
    turn_off(player, ISHUH);
    msg("You feel less confused now");
}


/*
 * unsee:
 *	He lost his see invisible power
 */

void
unsee(void)
{
    if (!ISWEARING(R_SEEINVIS)) {
	turn_off(player, CANSEE);
	msg("The tingling feeling leaves your eyes");
    }
}

/*
 * unstink:
 *	Remove to-hit handicap from player
 */

void
unstink(void)
{
    turn_off(player, HASSTINK);
}

/*
 * unclrhead:
 *	Player is no longer immune to confusion
 */

void
unclrhead(void)
{
    turn_off(player, ISCLEAR);
    msg("The blue aura about your head fades away.");
}

/*
 * unphase:
 *	Player can no longer walk through walls
 */

void
unphase(void)
{
    turn_off(player, CANINWALL);
    msg("Your dizzy feeling leaves you.");
    if (!step_ok(hero.y, hero.x, NOMONST, &player)) death(D_PETRIFY);
}

/*
 * land:
 *	Player can no longer fly
 */

void
land(void)
{
    turn_off(player, ISFLY);
    msg("You regain your normal weight");
    running = FALSE;
}

/*
 * sight:
 *	He gets his sight back
 */

void
sight(void)
{
    if (on(player, ISBLIND))
    {
	extinguish(sight);
	turn_off(player, ISBLIND);
	light(&hero);
	msg("The veil of darkness lifts");
    }
}

/*
 * res_strength:
 *	Restore player's strength
 */

void
res_strength(void)
{

    /* If lost_str is non-zero, restore that amount of strength,
     * else all of it 
     */
    if (lost_str) {
	chg_str(lost_str);
	lost_str = 0;
    }

    /* Otherwise, put player at the maximum strength */
    else {
	pstats.s_str = max_stats.s_str + ring_value(R_ADDSTR);
    }

    updpack(TRUE);
}

/*
 * nohaste:
 *	End the hasting
 */

void
nohaste(void)
{
    turn_off(player, ISHASTE);
    msg("You feel yourself slowing down.");
}

/*
 * noslow:
 *	End the slowing
 */

void
noslow(void)
{
    turn_off(player, ISSLOW);
    msg("You feel yourself speeding up.");
}

/*
 * suffocate:
 *	If this gets called, the player has suffocated
 */

void
suffocate(void)
{
    death(D_SUFFOCATION);
}

/*
 * digest the hero's food
 */
void
stomach(void)
{
    register int oldfood, old_hunger, food_use, i;

    old_hunger = hungry_state;
    if (food_left <= 0)
    {
	/*
	 * the hero is fainting
	 */
	if (no_command || rnd(100) > 20)
	    return;
	no_command = rnd(8)+4;
	if (!terse)
	    addmsg("You feel too weak from lack of food.  ");
	msg("You faint");
	running = FALSE;
	count = 0;
	hungry_state = F_FAINT;
    }
    else
    {
	oldfood = food_left;
	food_use = 0;
	for (i=0; i<MAXRELIC; i++) { /* each relic eats an additional food */
	    if (cur_relic[i])
		food_use++;
	}
	food_use +=    (ring_eat(LEFT_1)  + ring_eat(LEFT_2)  +
			ring_eat(LEFT_3)  + ring_eat(LEFT_4)  +
	    		ring_eat(RIGHT_1) + ring_eat(RIGHT_2) +
			ring_eat(RIGHT_3) + ring_eat(RIGHT_4) + 
			foodlev);
	if (food_use < 1)
	    food_use = 1;
	food_left -= food_use;
	if (food_left < MORETIME && oldfood >= MORETIME) {
	    msg("You are starting to feel weak");
	    running = FALSE;
	    hungry_state = F_WEAK;
	}
	else if (food_left < 2 * MORETIME && oldfood >= 2 * MORETIME)
	{
	    msg(terse ? "Getting hungry" : "You are starting to get hungry");
	    running = FALSE;
	    hungry_state = F_HUNGRY;
	}

    }
    if (old_hunger != hungry_state) 
	updpack(TRUE);
    wghtchk();
}
/*
 * daemon for curing the diseased
 */
void
cure_disease(void)
{
    turn_off(player, HASDISEASE);
    if (off (player, HASINFEST))
	msg(terse ? "You feel yourself improving"
		: "You begin to feel yourself improving again");
}

/*
 * daemon for adding back dexterity
 */
void
un_itch(void)
{
    if (--lost_dext < 1) {
	lost_dext = 0;
	turn_off(player, HASITCH);
    }
    res_dexterity(1);
}
/*
 * appear:
 *	Become visible again
 */
void
appear(void)
{
    turn_off(player, ISINVIS);
    PLAYER = VPLAYER;
    msg("The tingling feeling leaves your body");
    light(&hero);
}
/*
 * dust_appear:
 *	dust of disappearance wears off
 */
void
dust_appear(void)
{
    turn_off(player, ISINVIS);
    PLAYER = VPLAYER;
    msg("You become visible again");
    light(&hero);
}
/*
 * unchoke:
 * 	the effects of "dust of choking and sneezing" wear off
 */
void
unchoke(void)
{
    if (!find_slot(unconfuse))
	turn_off(player, ISHUH);
    if (!find_slot(sight))
	turn_off(player, ISBLIND);
    light(&hero);
    msg("Your throat and eyes return to normal");
}
/*
 * make some potion for the guy in the Alchemy jug
 */
void
alchemy(struct object *obj)
{
    register struct object *tobj = NULL;
    register struct linked_list *item;

    /*
     * verify that the object pointer we have still points to an alchemy
     * jug (hopefully the right one!) because the hero could have thrown
     * it away
     */
    for (item = pack; item != NULL; item = next(item)) {
	tobj = OBJPTR(item);
	if (tobj	 == obj		&& 
	    tobj->o_type == MM		&& 
	    tobj->o_which== MM_JUG	&&
	    tobj->o_ac   == JUG_EMPTY	)
		break;
    }
    if (item == NULL) { 	/* not in the pack, check the level */
	for (item = lvl_obj; item != NULL; item = next(item)) {
	    tobj = OBJPTR(item);
	    if (tobj	     == obj		&& 
		tobj->o_type == MM		&& 
		tobj->o_which== MM_JUG		&&
		tobj->o_ac   == JUG_EMPTY	)
		    break;
	}
    }
    if (item == NULL)	/* can't find it.....too bad */
	return;
    
    switch(rnd(9)) {
	case 0: tobj->o_ac = P_PHASE;
	when 1: tobj->o_ac = P_CLEAR;
	when 2: tobj->o_ac = P_SEEINVIS;
	when 3: tobj->o_ac = P_HEALING;
	when 4: tobj->o_ac = P_MFIND;
	when 5: tobj->o_ac = P_TFIND;
	when 6: tobj->o_ac = P_HASTE;
	when 7: tobj->o_ac = P_RESTORE;
	when 8: tobj->o_ac = P_FLY;
    }
}
/*
 * otto's irresistable dance wears off 
 */

void
undance(void)
{
    turn_off(player, ISDANCE);
    msg ("Your feet take a break.....whew!");
}

/* 
 * if he has our favorite necklace of strangulation then take damage every turn
 */
void
strangle(void)
{
     if ((pstats.s_hpt -= 6) <= 0) death(D_STRANGLE);
}
/*
 * if he has on the gauntlets of fumbling he might drop his weapon each turn
 */
void
fumble(void)
{
    register struct linked_list *item;

    if(cur_weapon!=NULL && cur_weapon->o_type!=RELIC && rnd(100)<3) {
	for (item = pack; item != NULL; item = next(item)) {
	    if (OBJPTR(item) == cur_weapon)
		break;
	}
	if (item != NULL) {
	    drop(item);
	    running = FALSE;
	}
    }
}
/*
 * this is called each turn the hero has the ring of searching on
 */
void
ring_search(void)
{
    search(FALSE, FALSE);
}
/*
 * this is called each turn the hero has the ring of teleportation on
 */
void
ring_teleport(void)
{
    if (rnd(100) < 2) teleport();
}