Mercurial > hg > early-roguelike
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? */
