view arogue7/actions.c @ 167:a0a57cf42810

ARogue family: don't hide messages caused by moving to a new level. new_level() redraws the whole screen, including the message line, so if msg() has just been called, the message will likely not last long enough to be noticed. These cases have been changed so that msg() is called after new_level(). If a fall through a trapdoor is fatal, "You fall into a trap!" is no longer printed, but the tombstone should make things clear.
author John "Elwin" Edwards
date Mon, 29 Jun 2015 20:37:32 -0400
parents adfa37e67084
children 1cd604c827a3
line wrap: on
line source

/*
 * actions.c  -  functions for dealing with monster actions
 *
 * 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.
 */

#include <ctype.h>
#include <limits.h>
#include "curses.h"
#include "rogue.h"
#define	MAXINT	INT_MAX
#define	MININT	INT_MIN
/* 
 * Did we disrupt a spell? 
 */
dsrpt_monster(tp, always, see_him)
register struct thing *tp;
bool always, see_him;
{
    switch (tp->t_action) {
    case A_SUMMON:
    case A_MISSILE:
    case A_SLOW:
	tp->t_action = A_NIL; /* Just make the old fellow start over again */
	tp->t_no_move = movement(tp);
	tp->t_using = NULL;/* Just to be on the safe side */
	turn_on(*tp, WASDISRUPTED);
	if (see_him)
	    msg("%s's spell has been disrupted.",prname(monster_name(tp),TRUE));
	/*
	 * maybe choose something else to do next time since player
	 * is disrupting us
	 */
	tp->t_summon *= 2;
	tp->t_cast /= 2;
	return;
    }

    /* We may want to disrupt other actions, too */
    if (always) {
	tp->t_action = A_NIL; /* Just make the old fellow start over again */
	tp->t_no_move = movement(tp);
	tp->t_using = NULL;/* Just to be on the safe side */
    }
}

dsrpt_player()
{
    int which, action;
    struct linked_list *item;
    struct object *obj;
    
    action = player.t_action;
    which = player.t_selection;

    switch (action) {
    case C_CAST: /* Did we disrupt a spell? */
    case C_PRAY:
    case C_CHANT:
    {
	msg("Your %s was disrupted!", action == C_CAST ? "spell" : "prayer");

	/* Charge him anyway */
	if (action == C_CAST)
	    spell_power += magic_spells[which].s_cost;
	else if (action == C_PRAY)
	    pray_time += cleric_spells[which].s_cost;
	else if (action == C_CHANT)
	    chant_time += druid_spells[which].s_cost;
    }
    when C_COUNT: /* counting of gold? */
    {
	if (purse > 0) {
	    msg("Your gold goes flying everywhere!");
	    do {
		item = spec_item(GOLD, NULL, NULL, NULL);
		obj = OBJPTR(item);
		obj->o_count = min(purse, rnd(10)+1);
		purse -= obj->o_count;
		obj->o_pos = hero;
		fall(item, FALSE);
	    } while (purse > 0 && rnd(10) != 1);
	}
    }
    when C_EAT:
	msg("You gag on your food for a moment.");
	del_pack(player.t_using);
	
    when A_PICKUP:
	msg("You drop what you are picking up!");

    when C_SEARCH:	/* searching for traps and secret doors... */
	msg("Oww....You decide to stop searching.");
	count = 0;	/* don't search again */

    when C_SETTRAP:
	msg("Oww....You can't get a trap set.");

    when A_NIL:
    default:
	return;
    }
    player.t_no_move = movement(&player); /* disoriented for a while */
    player.t_action = A_NIL;
    player.t_selection = 0;
    player.t_using = NULL;
}

/*
 * m_act:
 *	If the critter isn't doing anything, choose an action for it.
 *	Otherwise, let it perform its chosen action.
 */

m_act(tp)
register struct thing *tp;
{
    struct object *obj;
    bool flee;	/* Are we scared? */

    /* What are we planning to do? */
    switch (tp->t_action) {
	default:
	    /* An unknown action! */
	    msg("Unknown monster action (%d)", tp->t_action);

	    /* Fall through */

	case A_NIL:
	    /* If the monster is fairly intelligent and about to die, it
	     * may turn tail and run.  But if we are a FRIENDLY creature
	     * in the hero's service, don't run.
	     */
	    if (off(*tp, ISFLEE)					&&
		tp->t_stats.s_hpt < tp->maxstats.s_hpt			&&
		tp->t_stats.s_hpt < max(10, tp->maxstats.s_hpt/6)	&&
		(off(*tp, ISFRIENDLY) || tp->t_dest != &hero)		&&
		rnd(25) < tp->t_stats.s_intel) {
		    turn_on(*tp, ISFLEE);

		    /* It is okay to turn tail */
		    tp->t_oldpos = tp->t_pos;
		}

	    /* Should the monster run away? */
	    flee = on(*tp, ISFLEE) ||
		((tp->t_dest == &hero) && on(player, ISINWALL) &&
		 off(*tp, CANINWALL));

	    m_select(tp, flee);	/* Select an action */
	    return;

	when A_ATTACK:
	    /* 
	     * We're trying to attack the player or monster at t_newpos 
	     * if the prey moved, do nothing
	     */
	    obj = tp->t_using ? OBJPTR(tp->t_using) : NULL;
	    if (ce(tp->t_newpos, hero)) {
		attack(tp, obj, FALSE);
	    }
	    else if (mvwinch(mw, tp->t_newpos.y, tp->t_newpos.x) &&
		     step_ok(tp->t_newpos.y, tp->t_newpos.x, FIGHTOK, tp)) {
		skirmish(tp, &tp->t_newpos, obj, FALSE);
	    }

	when A_SELL:
	    /* Is the player still next to us? */
	    if (ce(tp->t_newpos, hero)) sell(tp);

	    /* The darned player moved away */
	    else if (off(player, ISBLIND) &&
		cansee(unc(tp->t_pos)) &&
		(off(*tp, ISINVIS)     || on(player, CANSEE)) &&
		(off(*tp, ISSHADOW)    || on(player, CANSEE)) &&
		(off(*tp, CANSURPRISE) || ISWEARING(R_ALERT)))
		msg("%s grunts with frustration",prname(monster_name(tp),TRUE));

	when A_MOVE:
	    /* Let's try to move */
	    do_chase(tp);

	    /* If t_no_move > 0, we found that we have to fight! */
	    if (tp->t_no_move > 0) return;

	when A_BREATHE:
	    /* Breathe on the critter */
	    m_breathe(tp);

	when A_SLOW:
	    /* make him move slower */
	    add_slow();
	    turn_off(*tp, CANSLOW);

	when A_MISSILE:
	    /* Start up a magic missile spell */
	    m_spell(tp);

	when A_SONIC:
	    /* Let out a sonic blast! */
	    m_sonic(tp);

	when A_THROW:
	    /* We're throwing something (like an arrow) */
	    missile(tp->t_newpos.y, tp->t_newpos.x, tp->t_using, tp);

	when A_SUMMON:
	    /* We're summoning help */
	    m_summon(tp);

	when A_USERELIC:
	    /* Use our relic */
	    m_use_relic(tp);

	when A_USEWAND:
	    /* use the wand we have */
	    m_use_wand(tp);
    }

    /* No action now */
    tp->t_action = A_NIL;
    tp->t_using = NULL;
}

/*
 * m_breathe:
 *	Breathe in the chosen direction.
 */

m_breathe(tp)
register struct thing *tp;
{
    register int damage;
    register char *breath;

    damage = tp->t_stats.s_hpt;
    turn_off(*tp, CANSURPRISE);

    /* Will it breathe at random */
    if (on(*tp, CANBRANDOM)) {
	/* Turn off random breath */
	turn_off(*tp, CANBRANDOM);

	/* Select type of breath */
	switch (rnd(10)) {
	    case 0: breath = "acid";
		    turn_on(*tp, NOACID);
	    when 1: breath = "flame";
		    turn_on(*tp, NOFIRE);
	    when 2: breath = "lightning bolt";
		    turn_on(*tp, NOBOLT);
	    when 3: breath = "chlorine gas";
		    turn_on(*tp, NOGAS);
	    when 4: breath = "ice";
		    turn_on(*tp, NOCOLD);
	    when 5: breath = "nerve gas";
		    turn_on(*tp, NOPARALYZE);
	    when 6: breath = "sleeping gas";
		    turn_on(*tp, NOSLEEP);
	    when 7: breath = "slow gas";
		    turn_on(*tp, NOSLOW);
	    when 8: breath = "confusion gas";
		    turn_on(*tp, ISCLEAR);
	    when 9: breath = "fear gas";
		    turn_on(*tp, NOFEAR);
	}
    }

    /* Or can it breathe acid? */
    else if (on(*tp, CANBACID)) {
	turn_off(*tp, CANBACID);
	breath = "acid";
    }

    /* Or can it breathe fire */
    else if (on(*tp, CANBFIRE)) {
	turn_off(*tp, CANBFIRE);
	breath = "flame";
    }

    /* Or can it breathe electricity? */
    else if (on(*tp, CANBBOLT)) {
	turn_off(*tp, CANBBOLT);
	breath = "lightning bolt";
    }

    /* Or can it breathe gas? */
    else if (on(*tp, CANBGAS)) {
	turn_off(*tp, CANBGAS);
	breath = "chlorine gas";
    }

    /* Or can it breathe ice? */
    else if (on(*tp, CANBICE)) {
	turn_off(*tp, CANBICE);
	breath = "ice";
    }

    else if (on(*tp, CANBPGAS)) {
	turn_off(*tp, CANBPGAS);
	breath = "nerve gas";
    }

    /* can it breathe sleeping gas */
    else if (on(*tp, CANBSGAS)) {
	turn_off(*tp, CANBSGAS);
	breath = "sleeping gas";
    }

    /* can it breathe slow gas */
    else if (on(*tp, CANBSLGAS)) {
	turn_off(*tp, CANBSLGAS);
	breath = "slow gas";
    }

    /* can it breathe confusion gas */
    else if (on(*tp, CANBCGAS)) {
	turn_off(*tp, CANBCGAS);
	breath = "confusion gas";
    }

    /* can it breathe fear gas */
    else {
	turn_off(*tp, CANBFGAS);
	breath = "fear gas";
    }

    /* Now breathe -- sets "monst_dead" if it kills someone */
    shoot_bolt(tp, tp->t_pos, tp->t_newpos, FALSE, 
		    tp->t_index, breath, damage);

    running = FALSE;
    if (fight_flush) md_flushinp();
}

/*
 * m_select:
 *	Select an action for the monster.
 */

m_select(th, flee)
register struct thing *th;
register bool flee; /* True if running away or player is inaccessible in wall */
{
    register struct room *rer, *ree;	/* room of chaser, room of chasee */
    int dist = MININT;
    int mindist = MAXINT, maxdist = MININT;
    bool rundoor;			/* TRUE means run to a door */
    char sch;
    coord *last_door=0,			/* Door we just came from */
	   this;			/* Temporary destination for chaser */

    rer = roomin(&th->t_pos);	/* Find room of chaser */
    ree = roomin(th->t_dest);	/* Find room of chasee */

    /* First see if we want to use an ability or weapon */
    if (m_use_it(th, flee, rer, ree)) return;

    /*
     * We don't count monsters on doors as inside rooms here because when
     * a monster is in a room and the player is not in that room, the
     * monster looks for the best door out.  If we counted doors as part
     * of the room, the monster would already be on the best door out;
     * so he would never move.
     */
    if ((sch = CCHAR( mvwinch(stdscr, th->t_pos.y, th->t_pos.x) )) == DOOR ||
	sch == SECRETDOOR || sch == PASSAGE) {
	rer = NULL;
    }
    this = *th->t_dest;

    /*
     * If we are in a room heading for the player and the player is not
     * in the room with us, we run to the "best" door.
     * If we are in a room fleeing from the player, then we run to the
     * "best" door if he IS in the same room.
     *
     * Note:  We don't bother with doors in mazes or if we can walk
     * through walls.
     */
    if (rer != NULL && levtype != MAZELEV && off(*th, CANINWALL)) {
	if (flee) rundoor = (rer == ree);
	else rundoor = (rer != ree);
    }
    else rundoor = FALSE;

    if (rundoor) {
	register struct linked_list *exitptr;	/* For looping through exits */
	coord *exit,				/* A particular door */
	      *entrance;			/* Place just inside doorway */
	int exity, exitx;			/* Door's coordinates */
	char dch='\0';				/* Door character */