Mercurial > hg > early-roguelike
diff rogue3/chase.c @ 0:527e2150eaf0
Import Rogue 3.6 from the Roguelike Restoration Project (r1490)
author | edwarj4 |
---|---|
date | Tue, 13 Oct 2009 13:33:34 +0000 |
parents | |
children | d9e44e18eeec |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rogue3/chase.c Tue Oct 13 13:33:34 2009 +0000 @@ -0,0 +1,319 @@ +/* + * Code for one object to chase another + * + * @(#)chase.c 3.17 (Berkeley) 6/15/81 + * + * 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" + +coord ch_ret; /* Where chasing takes you */ + +/* + * runners: + * Make all the running monsters move. + */ + +void +runners() +{ + struct linked_list *item; + struct thing *tp; + + for (item = mlist; item != NULL;) + { + tp = (struct thing *) ldata(item); + item = next(item); + if (off(*tp, ISHELD) && on(*tp, ISRUN)) + { + if (off(*tp, ISSLOW) || tp->t_turn) + if (do_chase(tp) == -1) + continue; + if (on(*tp, ISHASTE)) + if (do_chase(tp) == -1) + continue; + tp->t_turn ^= TRUE; + } + } +} + +/* + * do_chase: + * Make one thing chase another. + */ + +int +do_chase(struct thing *th) +{ + struct room *rer, *ree; /* room of chaser, room of chasee */ + int mindist = 32767, i, dist; + int stoprun = FALSE; /* TRUE means we are there */ + int sch; + coord this; /* Temporary destination for chaser */ + + rer = roomin(&th->t_pos); /* Find room of chaser */ + ree = roomin(th->t_dest); /* Find room of chasee */ + /* + * We don't count doors as inside rooms for this routine + */ + if (mvwinch(stdscr, th->t_pos.y, th->t_pos.x) == DOOR) + rer = NULL; + this = *th->t_dest; + /* + * If the object of our desire is in a different room, + * than we are and we ar not in a corridor, run to the + * door nearest to our goal. + */ + if (rer != NULL && rer != ree) + for (i = 0; i < rer->r_nexits; i++) /* loop through doors */ + { + dist = DISTANCE(th->t_dest->y, th->t_dest->x, + rer->r_exit[i].y, rer->r_exit[i].x); + if (dist < mindist) /* minimize distance */ + { + this = rer->r_exit[i]; + mindist = dist; + } + } + /* + * this now contains what we want to run to this time + * so we run to it. If we hit it we either want to fight it + * or stop running + */ + if (!chase(th, &this)) + { + if (ce(this, hero)) + { + return( attack(th) ); + } + else if (th->t_type != 'F') + stoprun = TRUE; + } + else if (th->t_type == 'F') + return(0); + mvwaddch(cw, th->t_pos.y, th->t_pos.x, th->t_oldch); + sch = mvwinch(cw, ch_ret.y, ch_ret.x); + if (rer != NULL && (rer->r_flags & ISDARK) && sch == FLOOR + && DISTANCE(ch_ret.y, ch_ret.x, th->t_pos.y, th->t_pos.x) < 3 + && off(player, ISBLIND)) + th->t_oldch = ' '; + else + th->t_oldch = sch; + + if (cansee(unc(ch_ret)) && !on(*th, ISINVIS)) + mvwaddch(cw, ch_ret.y, ch_ret.x, th->t_type); + mvwaddch(mw, th->t_pos.y, th->t_pos.x, ' '); + mvwaddch(mw, ch_ret.y, ch_ret.x, th->t_type); + th->t_pos = ch_ret; + /* + * And stop running if need be + */ + if (stoprun && ce(th->t_pos, *(th->t_dest))) + th->t_flags &= ~ISRUN; + + return(0); +} + +/* + * runto: + * Set a mosnter running after something + * or stop it from running (for when it dies) + */ + +void +runto(coord *runner, coord *spot) +{ + struct linked_list *item; + struct thing *tp; + + /* + * If we couldn't find him, something is funny + */ + if ((item = find_mons(runner->y, runner->x)) == NULL) + { + msg("CHASER '%s'", unctrl(winat(runner->y, runner->x))); + return; + } + tp = (struct thing *) ldata(item); + /* + * Start the beastie running + */ + tp->t_dest = spot; + tp->t_flags |= ISRUN; + tp->t_flags &= ~ISHELD; +} + +/* + * chase: + * Find the spot for the chaser(er) to move closer to the + * chasee(ee). Returns TRUE if we want to keep on chasing later + * FALSE if we reach the goal. + */ + +int +chase(struct thing *tp, coord *ee) +{ + int x, y; + int dist, thisdist; + struct linked_list *item; + struct object *obj; + coord *er = &tp->t_pos; + int ch; + + /* + * If the thing is confused, let it move randomly. Invisible + * Stalkers are slightly confused all of the time, and bats are + * quite confused all the time + */ + if ((on(*tp, ISHUH) && rnd(10) < 8) || (tp->t_type == 'I' && rnd(100) < 20) + || (tp->t_type == 'B' && rnd(100) < 50)) + { + /* + * get a valid random move + */ + ch_ret = *rndmove(tp); + dist = DISTANCE(ch_ret.y, ch_ret.x, ee->y, ee->x); + /* + * Small chance that it will become un-confused + */ + if (rnd(1000) < 50) + tp->t_flags &= ~ISHUH; + } + /* + * Otherwise, find the empty spot next to the chaser that is + * closest to the chasee. + */ + else + { + int ey, ex; + /* + * This will eventually hold where we move to get closer + * If we can't find an empty spot, we stay where we are. + */ + dist = DISTANCE(er->y, er->x, ee->y, ee->x); + ch_ret = *er; + + ey = er->y + 1; + ex = er->x + 1; + for (x = er->x - 1; x <= ex; x++) + for (y = er->y - 1; y <= ey; y++) + { + coord tryp; + + tryp.x = x; + tryp.y = y; + if (!diag_ok(er, &tryp)) + continue; + ch = winat(y, x); + if (step_ok(ch)) + { + /* + * If it is a scroll, it might be a scare monster scroll + * so we need to look it up to see what type it is. + */ + if (ch == SCROLL) + { + for (item = lvl_obj; item != NULL; item = next(item)) + { + obj = (struct object *) ldata(item); + if (y == obj->o_pos.y && x == obj->o_pos.x) + break; + } + if (item != NULL && obj->o_which == S_SCARE) + continue; + } + /* + * If we didn't find any scrolls at this place or it + * wasn't a scare scroll, then this place counts + */ + thisdist = DISTANCE(y, x, ee->y, ee->x); + if (thisdist < dist) + { + ch_ret = tryp; + dist = thisdist; + } + } + } + } + return (dist != 0); +} + +/* + * roomin: + * Find what room some coordinates are in. NULL means they aren't + * in any room. + */ + +struct room * +roomin(coord *cp) +{ + struct room *rp; + + for (rp = rooms; rp <= &rooms[MAXROOMS-1]; rp++) + if (inroom(rp, cp)) + return rp; + return NULL; +} + +/* + * find_mons: + * Find the monster from his corrdinates + */ + +struct linked_list * +find_mons(int y, int x) +{ + struct linked_list *item; + struct thing *th; + + for (item = mlist; item != NULL; item = next(item)) + { + th = (struct thing *) ldata(item); + if (th->t_pos.y == y && th->t_pos.x == x) + return item; + } + return NULL; +} + +/* + * diag_ok: + * Check to see if the move is legal if it is diagonal + */ + +int +diag_ok(coord *sp, coord *ep) +{ + if (ep->x == sp->x || ep->y == sp->y) + return TRUE; + return (step_ok(mvinch(ep->y, sp->x)) && step_ok(mvinch(sp->y, ep->x))); +} + +/* + * cansee: + * returns true if the hero can see a certain coordinate. + */ + +int +cansee(int y, int x) +{ + struct room *rer; + coord tp; + + if (on(player, ISBLIND)) + return FALSE; + tp.y = y; + tp.x = x; + rer = roomin(&tp); + /* + * We can only see if the hero in the same room as + * the coordinate and the room is lit or if it is close. + */ + return (rer != NULL && rer == roomin(&hero) && !(rer->r_flags&ISDARK)) || + DISTANCE(y, x, hero.y, hero.x) < 3; +}