view arogue7/actions.c @ 162:600873555ec0

Don't swap signal handlers in md_shellescape(). md_shellescape() sets SIGINT and SIGQUIT to be ignored, storing the previous handlers, and restores them after the shell exits. But it mixed up the two handlers. Since the signals were usually handled by the same function, this fix doesn't have much effect, but anything that makes signal code less confusing is a good thing.
author John "Elwin" Edwards
date Mon, 08 Jun 2015 10:01:25 -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 */

	if (th->t_doorgoal)
	    dch = CCHAR( mvwinch(stdscr, th->t_doorgoal->y, th->t_doorgoal->x) );
	    
	/* Do we have a valid goal? */
	if ((dch == PASSAGE || dch == DOOR) &&  /* A real door */
	    (!flee || !ce(*th->t_doorgoal, *th->t_dest))) { /* Prey should not
						             * be at door if
							     * we are running
							     * away
							     */
	    /* Make sure the player is not in the doorway, either */
	    entrance = doorway(rer, th->t_doorgoal);
	    if (!flee || entrance == NULL || !ce(*entrance, *th->t_dest)) {
		this = *th->t_doorgoal;
		dist = 0;	/* Indicate that we have our door */
	    }
	}

	/* Go through all the doors */
	else for (exitptr = rer->r_exit; exitptr; exitptr = next(exitptr)) {
	    exit = DOORPTR(exitptr);
	    exity = exit->y;
	    exitx = exit->x;

	    /* Make sure it is a real door */
	    dch = CCHAR( mvwinch(stdscr, exity, exitx) );
	    if (dch == PASSAGE || dch == DOOR) {
		/* Don't count a door if we are fleeing from someone and
		 * he is standing on it.  Also, don't count it if he is
		 * standing in the doorway.
		 */
		if (flee) {
		    if (ce(*exit, *th->t_dest)) continue;

		    entrance = doorway(rer, exit);
		    if (entrance != NULL && ce(*entrance, *th->t_dest))
			continue;
		}
		
		/* Were we just on this door? */
		if (ce(*exit, th->t_oldpos)) last_door = exit;

		else {
		    dist = DISTANCE(th->t_dest->y, th->t_dest->x, exity, exitx);

		    /* If fleeing, we want to maximize distance from door to
		     * what we flee, and minimize distance from door to us.
		     */
		    if (flee)
		       dist -= DISTANCE(th->t_pos.y, th->t_pos.x, exity, exitx);

		    /* Maximize distance if fleeing, otherwise minimize it */
		    if ((flee && (dist > maxdist)) ||
			(!flee && (dist < mindist))) {
			th->t_doorgoal = exit;	/* Use this door */
			this = *exit;
			mindist = maxdist = dist;
		    }
		}
	    }
	}

	/* Could we not find a door? */
	if (dist == MININT) {
	    /* If we were on a door, go ahead and use it */
	    if (last_door) {
		th->t_doorgoal = last_door;
		this = th->t_oldpos;
		dist = 0;	/* Indicate that we found a door */
	    }
	    else th->t_doorgoal = NULL;	/* No more door goal */
	}

	/* Indicate that we do not want to flee from the door */
	if (dist != MININT) flee = FALSE;
    }
    else th->t_doorgoal = 0;	/* Not going to any door */

    /* Now select someplace to go and start the action */
    chase(th, &this, rer, ree, flee);
}

/*
 * m_sonic:
 *	The monster is sounding a sonic blast.
 */

m_sonic(tp)
register struct thing *tp;
{
    register int damage;
    static struct object blast =
    {
	MISSILE, {0, 0}, "", 0, "", "150" , NULL, 0, 0, 0, 0
    };

    turn_off(*tp, CANSONIC);
    turn_off(*tp, CANSURPRISE);
    do_motion(&blast, tp->t_newpos.y, tp->t_newpos.x, tp);
    damage = 150;
    if (save(VS_BREATH, &player, -3))
	damage /= 2;
    msg ("%s's sonic blast hits you", prname(monster_name(tp), TRUE));
    if ((pstats.s_hpt -= damage) <= 0)
	death(tp->t_index);

    running = FALSE;
    if (fight_flush) md_flushinp();
    dsrpt_player();
}

/*
 * m_spell:
 *	The monster casts a spell.  Currently this is limited to
 *	magic missile.
 */
m_spell(tp)
register struct thing *tp;
{
    static struct object missile =
    {
	MISSILE, {0, 0}, "", 0, "", "0d4 " , NULL, 0, WS_MISSILE, 100, 1
    };

    sprintf(missile.o_hurldmg, "%dd4", tp->t_stats.s_lvl);
    do_motion(&missile, tp->t_newpos.y, tp->t_newpos.x, tp);
    hit_monster(unc(missile.o_pos), &missile, tp);
    turn_off(*tp, CANMISSILE);
    turn_off(*tp, CANSURPRISE);

    running = FALSE;
    if (fight_flush) md_flushinp();
}

/*
 * m_summon:
 *	Summon aid.
 */

m_summon(tp)
register struct thing *tp;
{
    register char *helpname, *mname;
    int fail, numsum;
    register int which, i;

    /* Let's make sure our prey is still here */
    if (!cansee(unc(tp->t_pos)) || fallpos(&hero, FALSE, 2) == NULL) return;

    /*
     * Non-uniques can only summon once.  Uniques get fewer
     * creatures with each successive summoning. Also, the
     * probability of summoning goes down
     */
    if (off(*tp, ISUNIQUE))
	    turn_off(*tp, CANSUMMON);

    turn_off(*tp, CANSURPRISE);
    mname = monster_name(tp);
    helpname = monsters[tp->t_index].m_typesum;
    which = findmindex(helpname);

    if ((off(*tp, ISINVIS)     || on(player, CANSEE)) &&
	(off(*tp, ISSHADOW)    || on(player, CANSEE)) &&
	(off(*tp, CANSURPRISE) || ISWEARING(R_ALERT))) {
	if (monsters[which].m_normal == FALSE) { /* genocided? */
	    msg("%s appears dismayed", prname(mname, TRUE));
	    monsters[tp->t_index].m_numsum = 0;
	}
	else {
	    msg("%s summons %ss for help", prname(mname, TRUE), helpname);
	}
    }
    else {
	if (monsters[which].m_normal == FALSE) /* genocided? */
	    monsters[tp->t_index].m_numsum = 0;
	else {
	    msg("%ss seem to appear from nowhere!", helpname);
	}
    }
    numsum = monsters[tp->t_index].m_numsum;
    if (numsum && on(*tp, ISUNIQUE)) {   /* UNIQUEs summon less each time */
	monsters[tp->t_index].m_numsum--; 
	tp->t_summon *= 2; /* cut probability in half */
    }

    /*
     * try to make all the creatures around player but remember
     * if unsuccessful
     */
    for (i=0, fail=0; i<numsum; i++) {
	 if (!creat_mons(&player, which, FALSE))
	     fail++;	/* remember the failures */
    }

    /*
     * try once again to make the buggers
     */
    for (i=0; i<fail; i++)
	 creat_mons(tp, which, FALSE);
    
    /* Now let the poor fellow see all the trouble */
    light(&hero);
    turn_on(*tp, HASSUMMONED);
}

/*
 * m_use_it:
 *	See if the monster (tp) has anything useful it can do
 *	(ie. an ability or a weapon) other than just move.
 */

bool
m_use_it(tp, flee, rer, ree)
register struct thing *tp;
bool flee;
register struct room *rer, *ree;
{
    int dist;
    register coord *ee = tp->t_dest, *er = &tp->t_pos; 
    coord *shoot_dir;
    struct linked_list *weapon;
    struct thing *prey;
    bool dest_player;	/* Are we after the player? */

    /*
     * If we are fleeing, there's a chance, depending on our
     * intelligence, that we'll just run in terror.
     */
    if (flee && rnd(25) >= tp->t_stats.s_intel) return(FALSE);

    /*
     * Make sure that we have a living destination, and record whether
     * it is the player.
     */
    if (ee != NULL) {
        if (ce(*ee, hero)) {
	    dest_player = TRUE;
	    prey = &player;
	}
	else {
	    struct linked_list *item;

	    dest_player = FALSE;

	    /* What is the monster we're chasing? */
	    item = find_mons(ee->y, ee->x);
	    if (item != NULL) prey = THINGPTR(item);
	    else return(FALSE);
	}
    }
    else return(FALSE);

    /*
     * If we are friendly to the hero, we don't do anything.
     */
    if (on(*tp, ISFRIENDLY) && dest_player) return(FALSE);

    /*
     * Also, for now, if our prey is in a wall, we won't do
     * anything.  The prey must be in the same room as we are OR
     * we must have a straight shot at him.  Note that
     * shoot_dir must get set before rer is checked so
     * that we get a valid value.
     */
    if (on(*prey, ISINWALL) ||
	((shoot_dir = can_shoot(er, ee)) == NULL &&
	(rer == NULL || rer != ree)))
	return(FALSE);

    /*
     * If we can't see the prey then forget it
     */
    if (on(*prey, ISINVIS) && off(*tp, CANSEE))
	return(FALSE);

    /* How far are we from our prey? */
    dist = DISTANCE(er->y, er->x, ee->y, ee->x);

    /* 
     * Shall we summon aid so we don't have to get our hands dirty? 
     * For now, we will only summon aid against the player.
     * We'll wait until he's within 2 dots of a missile length.
     */
    if (on(*tp, CANSUMMON) && dest_player 			&&
	dist < (BOLT_LENGTH+2)*(BOLT_LENGTH+2)			&&
	rnd(tp->t_summon) < tp->t_stats.s_lvl			&&
	monsters[tp->t_index].m_numsum > 0			&&
	fallpos(&hero, FALSE, 2) != NULL) {
	tp->t_action = A_SUMMON;	/* We're going to summon help */
	tp->t_no_move = movement(tp); /* It takes time! */
	return(TRUE);
    }

    /*
     * If the creature can cast a slow spell and if the prey is within
     * 2 dots of a missile fire, then see whether we will cast it.
     * if next to player, lessen chance because we don't like being
     * disrupted
     */
    if (on(*tp, CANSLOW) && dest_player			&& 
	dist < (BOLT_LENGTH+5)*(BOLT_LENGTH+5)		&&
	rnd(100) < (dist > 3 ? tp->t_cast : tp->t_cast/2)) {
	    tp->t_action = A_SLOW;		/* We're going to slow him */
	    tp->t_no_move = 3 * movement(tp);	/* Takes time! */
	    debug("casting slow spell!");
	    return(TRUE);
    }

    /*
     * If we have a special magic item, we might use it.  We will restrict
     * this options to uniques with relics and creatures with wands for now.  
     * Also check for the quartermaster. Don't want him shooting wands....
     */
    if ((on(*tp, ISUNIQUE) || on(*tp, CARRYSTICK)) && 
	off(*tp, CANSELL) && dest_player	   &&
	m_use_pack(tp, er, ee, dist, shoot_dir)) {
	    return(TRUE);
    }

    /* From now on, we must have a direct shot at the prey */
    if (shoot_dir == NULL) return(FALSE);

    /* We may use a sonic blast if we can, only on the player */
    if (on(*tp, CANSONIC)		&& 
	dest_player			&&
	(dist < BOLT_LENGTH*2)		&&
	(rnd(100) < tp->t_breathe)) {
	tp->t_newpos = *shoot_dir;	/* Save the direction */
	tp->t_action = A_SONIC;	/* We're going to sonic blast */
	tp->t_no_move = 2 * movement(tp); /* Takes 2 movement periods */
    }

    /* If we can breathe, we may do so */
    else if (on(*tp, CANBREATHE)		&&
	 (dist < BOLT_LENGTH*BOLT_LENGTH)	&&
	 (rnd(100) < tp->t_breathe)) {
	    tp->t_newpos = *shoot_dir;	/* Save the direction */
	    tp->t_action = A_BREATHE;	/* We're going to breathe */
	    tp->t_no_move = movement(tp); /* It takes 1 movement period */
    }

    /* 
     * We may shoot missiles if we can 
     * if next to player, lessen chance so we don't get disrupted as often
     */
    else if (on(*tp,CANMISSILE) && 
	     rnd(100) < (dist > 3 ? tp->t_cast : tp->t_cast/2)){
	    tp->t_newpos = *shoot_dir;	/* Save the direction */
	    tp->t_action = A_MISSILE;	/* We're going to shoot MM's */
	    tp->t_no_move = 3 * movement(tp); /* Takes time! */
    }

    /* 
     * If we can shoot or throw something, we might do so.
     * If next to player, then forget it
     */
    else if ((on(*tp,CANSHOOT)		|| on(*tp,CARRYWEAPON) || 
	      on(*tp,CARRYDAGGER)	|| on(*tp, CARRYAXE))		&&
	      dist > 3							&&
	      off(*tp, CANSELL)						&&
	     (weapon = get_hurl(tp))) {
	    tp->t_newpos = *shoot_dir;	/* Save the direction */
	    tp->t_action = A_THROW;	/* We're going to throw something */
	    tp->t_using = weapon;	/* Save our weapon */
	    tp->t_no_move = 2 * movement(tp); /* Takes 2 movement periods */
    }
    
    /* We couldn't find anything to do */
    else return(FALSE);

    return(TRUE);

}

/*
 * runners:
 *	Make all the awake monsters try to do something.
 */

runners(segments)
int segments;    /* Number of segments since last called */
{
    register struct linked_list *item;
    register struct thing *tp;
    register min_time = 20;	/* Minimum time until a monster can act */

    /*
     * loop thru the list of running (wandering) monsters and see what
     * each one will do this time. 
     *
     * Note: the special case that one of this buggers kills another.
     *	     if this happens than we have to see if the monster killed
     *	     himself or someone else. In case its himself we have to get next
     *	     one immediately. If it wasn't we have to get next one at very
     *	     end in case he killed the next one.
     */

    for (item = mlist; item != NULL; item = next(item))	{
	tp = THINGPTR(item);
	turn_on(*tp, ISREADY);
    }

    for (;;) {

	for (item = mlist; item != NULL; item = next(item)) {
	    tp = THINGPTR(item);

	    if (on(*tp, ISREADY))
		break;
	}

	if (item == NULL)
	    break;

	turn_off(*tp, ISREADY);

	/* If we are not awake, just skip us */
	if (off(*tp, ISRUN) && off(*tp, ISHELD)) continue;

	/* See if it's our turn */
	tp->t_no_move -= segments;
	if (tp->t_no_move > 0) {
	    if (tp->t_no_move < min_time) min_time = tp->t_no_move;
	    continue;
	}

	/* If we were frozen, we're moving now */
	if (tp->t_action == A_FREEZE) tp->t_action = A_NIL;

	if (on(*tp, ISHELD)) {
	    /* Make sure the action and using are nil */
	    tp->t_action = A_NIL;
	    tp->t_using = NULL;

	    /* Can we break free? */
	    if (rnd(tp->t_stats.s_lvl) > 11) {
		turn_off(*tp, ISHELD);
		runto(tp, &hero);
		if (cansee(tp->t_pos.y, tp->t_pos.x))
		    msg("%s breaks free from the hold spell", 
			prname(monster_name(tp), TRUE));
	    }

	    /* Too bad -- try again later */
	    else tp->t_no_move = movement(tp);
	}

	/* Heal the creature if it's not in the middle of some action */