diff arogue7/chase.c @ 125:adfa37e67084

Import Advanced Rogue 7.7 from the Roguelike Restoration Project (r1490)
author John "Elwin" Edwards
date Fri, 08 May 2015 15:24:40 -0400
parents
children f9ef86cf22b2
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/arogue7/chase.c	Fri May 08 15:24:40 2015 -0400
@@ -0,0 +1,928 @@
+/*
+ * chase.c  -  Code for one object to chase another
+ *
+ * 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.
+ */
+
+/*
+ * Code for one object to chase another
+ *
+ */
+
+#include <ctype.h>
+#include <limits.h>
+#include "curses.h"
+#include "rogue.h"
+#define	MAXINT	INT_MAX
+#define	MININT	INT_MIN
+
+
+/*
+ * Canblink checks if the monster can teleport (blink).  If so, it will
+ * try to blink the monster next to the player.
+ */
+
+bool
+can_blink(tp)
+register struct thing *tp;
+{
+    register int y, x, index=9;
+    coord tryp;	/* To hold the coordinates for use in diag_ok */
+    bool spots[9], found_one=FALSE;
+
+    /*
+     * First, can the monster even blink?  And if so, there is only a 50%
+     * chance that it will do so.  And it won't blink if it is running or
+     * held.
+     */
+    if (off(*tp, CANBLINK) || (on(*tp, ISHELD)) ||
+	on(*tp, ISFLEE) ||
+	tp->t_action == A_FREEZE ||
+	(rnd(12) < 6)) return(FALSE);
+
+
+    /* Initialize the spots as illegal */
+    do {
+	spots[--index] = FALSE;
+    } while (index > 0);
+
+    /* Find a suitable spot next to the player */
+    for (y=hero.y-1; y<hero.y+2; y++)
+	for (x=hero.x-1; x<hero.x+2; x++, index++) {
+	    /* Make sure x coordinate is in range and that we are
+	     * not at the player's position
+	     */
+	    if (x<0 || x >= cols || index == 4) continue;
+
+	    /* Is it OK to move there? */
+	    if (step_ok(y, x, NOMONST, tp) &&
+		(!isatrap(mvwinch(cw, y, x)) ||
+		  rnd(10) >= tp->t_stats.s_intel ||
+		  on(*tp, ISFLY))) {
+		/* OK, we can go here.  But don't go there if
+		 * monster can't get at player from there
+		 */
+		tryp.y = y;
+		tryp.x = x;
+		if (diag_ok(&tryp, &hero, tp)) {
+		    spots[index] = TRUE;
+		    found_one = TRUE;
+		}
+	    }
+	}
+
+    /* If we found one, go to it */
+    if (found_one) {
+	char rch;	/* What's really where the creatures moves to */
+
+	/* Find a legal spot */
+	while (spots[index=rnd(9)] == FALSE) continue;
+
+	/* Get the coordinates */
+	y = hero.y + (index/3) - 1;
+	x = hero.x + (index % 3) - 1;
+
+	/* Move the monster from the old space */
+	mvwaddch(cw, tp->t_pos.y, tp->t_pos.x, tp->t_oldch);
+
+	/* Move it to the new space */
+	tp->t_oldch = CCHAR( mvwinch(cw, y, x) );
+
+	/* Display the creature if our hero can see it */
+	if (cansee(y, x) &&
+	    off(*tp, ISINWALL) &&
+	    !invisible(tp))
+	    mvwaddch(cw, y, x, tp->t_type);
+
+	/* Fix the monster window */
+	mvwaddch(mw, tp->t_pos.y, tp->t_pos.x, ' '); /* Clear old position */
+	mvwaddch(mw, y, x, tp->t_type);
+
+	/* Record the new position */
+	tp->t_pos.y = y;
+	tp->t_pos.x = x;
+
+	/* If the monster is on a trap, trap it */
+	rch = CCHAR( mvinch(y, x) );
+	if (isatrap(rch)) {
+	    if (cansee(y, x)) tp->t_oldch = rch;
+	    be_trapped(tp, &(tp->t_pos));
+	}
+    }
+
+    return(found_one);
+}
+
+/* 
+ * Can_shoot determines if the monster (er) has a direct line of shot 
+ * at the prey (ee).  If so, it returns the direction in which to shoot.
+ */
+
+coord *
+can_shoot(er, ee)
+register coord *er, *ee;
+{
+    static coord shoot_dir;
+
+    /* 
+     * They must be in the same room or very close (at door)
+     */
+    if (roomin(er) != roomin(ee) && DISTANCE(er->y,er->x,ee->y,ee->x) > 1)
+	return(NULL);
+
+    /* Do we have a straight shot? */
+    if (!straight_shot(er->y, er->x, ee->y, ee->x, &shoot_dir)) return(NULL);
+    else return(&shoot_dir);
+}
+
+/*
+ * chase:
+ *	Find the spot for the chaser(er) to move closer to the
+ *	chasee(ee).  Rer is the room of the chaser, and ree is the
+ *	room of the creature being chased (chasee).
+ */
+
+chase(tp, ee, rer, ree, flee)
+register struct thing *tp;
+register coord *ee;
+register struct room *rer, *ree;
+bool flee; /* True if destination (ee) is player and monster is running away
+	    * or the player is in a wall and the monster can't get to it
+	    */
+{
+    int dist, thisdist, monst_dist = MAXINT; 
+    register coord *er = &tp->t_pos; 
+    struct thing *prey;			/* What we are chasing */
+    coord ch_ret;			/* Where chasing takes you */
+    char ch, mch;
+    bool next_player = FALSE;
+
+    /* 
+     * set the distance from the chas(er) to the chas(ee) here and then
+     * we won't have to reset it unless the chas(er) moves (instead of shoots)
+     */
+    dist = DISTANCE(er->y, er->x, ee->y, ee->x);
+
+    /*
+     * See if our destination is a monster or player.  If so, make "prey" point
+     * to it.
+     */
+    if (ce(hero, *ee)) prey = &player;	/* Is it the player? */
+    else if (tp->t_dest && ce(*(tp->t_dest), *ee)) {	/* Is it a monster? */
+	struct linked_list *item;
+
+	/* What is the monster we're chasing? */
+	item = find_mons(ee->y, ee->x);
+	if (item != NULL) prey = THINGPTR(item);
+	else prey = NULL;
+    }
+    else prey = NULL;
+
+    /* We will use at least one movement period */
+    tp->t_no_move = movement(tp);
+    if (on(*tp, ISFLY)) /* If the creature is flying, speed it up */
+	tp->t_no_move /= 2;
+
+    /*
+     * If the thing is confused or it can't see the player,
+     * let it move randomly. 
+     */
+    if ((on(*tp, ISHUH) && rnd(10) < 8) ||
+	(prey && on(*prey, ISINVIS) && off(*tp, CANSEE))) { /* invisible prey */
+	/*
+	 * get a valid random move
+	 */
+	tp->t_newpos = *rndmove(tp);
+	dist = DISTANCE(tp->t_newpos.y, tp->t_newpos.x, ee->y, ee->x);
+    }
+
+    /*
+     * Otherwise, find the empty spot next to the chaser that is
+     * closest to the chasee.
+     */
+    else {
+	register int ey, ex, x, y;
+	int dist_to_old = MININT; /* Dist from goal to old position */
+
+	/*
+	 * This will eventually hold where we move to get closer
+	 * If we can't find an empty spot, we stay where we are.
+	 */
+	dist = flee ? 0 : MAXINT;
+	ch_ret = *er;
+
+	/* Are we at our goal already? */
+	if (!flee && ce(ch_ret, *ee)) {
+	    turn_off(*tp, ISRUN);	/* So stop running! */
+	    return;
+	}
+
+	ey = er->y + 1;
+	ex = er->x + 1;
+
+	/* Check all possible moves */
+	for (x = er->x - 1; x <= ex; x++) {
+	    if (x < 0 || x >= cols) /* Don't try off the board */
+		continue;
+	    for (y = er->y - 1; y <= ey; y++) {
+		coord tryp;
+
+		if ((y < 1) || (y >= lines - 2)) /* Don't try off the board */
+		    continue;
+
+		/* Don't try the player if not going after the player */
+		if ((flee || !ce(hero, *ee) || on(*tp, ISFRIENDLY)) &&
+		    x == hero.x && y == hero.y) {
+		    next_player = TRUE;
+		    continue;
+		}
+
+		tryp.x = x;
+		tryp.y = y;
+
+		/* Is there a monster on this spot closer to our goal?
+		 * Don't look in our spot or where we were.
+		 */
+		if (!ce(tryp, *er) && !ce(tryp, tp->t_oldpos) &&
+		    isalpha(mch = CCHAR( mvwinch(mw, y, x) ) )) {
+		    int test_dist;
+
+		    test_dist = DISTANCE(y, x, ee->y, ee->x);
+		    if (test_dist <= 25 &&   /* Let's be fairly close */
+			test_dist < monst_dist) {
+			/* Could we really move there? */
+			mvwaddch(mw, y, x, ' '); /* Temporarily blank monst */
+			if (diag_ok(er, &tryp, tp)) monst_dist = test_dist;
+			mvwaddch(mw, y, x, mch); /* Restore monster */
+		    }
+		}
+
+		/* Can we move onto the spot? */	
+		if (!diag_ok(er, &tryp, tp)) continue;
+
+		ch = CCHAR( mvwinch(cw, y, x) );	/* Screen character */
+
+		/*
+		 * Stepping on player is NOT okay if we are fleeing.
+		 * If we are friendly to the player and there is a monster
+		 * in the way that is not of our race, it is okay to move
+		 * there.
+		 */
+		if (step_ok(y, x, FIGHTOK, tp) &&
+		    (off(*tp, ISFLEE) || ch != PLAYER))
+		{
+		    /*
+		     * If it is a trap, an intelligent monster may not
+		     * step on it (unless our hero is on top!)
+		     */
+		    if ((isatrap(ch))			&& 
+			(rnd(10) < tp->t_stats.s_intel) &&
+			(!on(*tp, ISFLY))		&&
+			(y != hero.y || x != hero.x)) 
+			    continue;
+
+		    /*
+		     * OK -- this place counts
+		     */
+		    thisdist = DISTANCE(y, x, ee->y, ee->x);
+
+		    /* Adjust distance if we are being shot at */
+		    if (tp->t_wasshot && tp->t_stats.s_intel > 5 &&
+			prey != NULL) {
+			/* Move out of line of sight */
+			if (straight_shot(tryp.y, tryp.x, ee->y, ee->x, NULL)) {
+			    if (flee) thisdist -= SHOTPENALTY;
+			    else thisdist += SHOTPENALTY;
+			}
+
+			/* But do we want to leave the room? */