Annotation of early-roguelike/rogue4/chase.c, Revision 1.1
1.1 ! rubenllo 1: /*
! 2: * Code for one creature to chase another
! 3: *
! 4: * @(#)chase.c 4.25 (Berkeley) 5/5/82
! 5: *
! 6: * Rogue: Exploring the Dungeons of Doom
! 7: * Copyright (C) 1980, 1981, 1982 Michael Toy, Ken Arnold and Glenn Wichman
! 8: * All rights reserved.
! 9: *
! 10: * See the file LICENSE.TXT for full copyright and licensing information.
! 11: */
! 12:
! 13: #include <stdlib.h>
! 14: #include <curses.h>
! 15: #include "rogue.h"
! 16:
! 17: #define DRAGONSHOT 5 /* one chance in DRAGONSHOT that a dragon will flame */
! 18:
! 19: coord ch_ret; /* Where chasing takes you */
! 20:
! 21: bool chase(THING *tp, coord *ee);
! 22: int do_chase(THING *th);
! 23: coord *find_dest(THING *tp);
! 24:
! 25: /*
! 26: * runners:
! 27: * Make all the running monsters move.
! 28: */
! 29: void
! 30: runners(void)
! 31: {
! 32: register THING *tp;
! 33: register THING *ntp;
! 34:
! 35: for (tp = mlist; tp != NULL; tp = ntp)
! 36: {
! 37: ntp = next(tp);
! 38: if (!on(*tp, ISHELD) && on(*tp, ISRUN))
! 39: {
! 40: if (!on(*tp, ISSLOW) || tp->t_turn)
! 41: if (do_chase(tp) == -1)
! 42: continue;
! 43: if (on(*tp, ISHASTE))
! 44: if (do_chase(tp) == -1)
! 45: continue;
! 46: tp->t_turn ^= TRUE;
! 47: }
! 48: }
! 49: }
! 50:
! 51: /*
! 52: * do_chase:
! 53: * Make one thing chase another.
! 54: */
! 55: int
! 56: do_chase(THING *th)
! 57: {
! 58: register struct room *rer, *ree; /* room of chaser, room of chasee */
! 59: register int mindist = 32767, i, dist;
! 60: register bool stoprun = FALSE; /* TRUE means we are there */
! 61: register char sch;
! 62: register bool door;
! 63: register THING *obj;
! 64: register struct room *oroom;
! 65: coord this; /* Temporary destination for chaser */
! 66:
! 67: rer = th->t_room; /* Find room of chaser */
! 68: if (on(*th, ISGREED) && rer->r_goldval == 0)
! 69: th->t_dest = &hero; /* If gold has been taken, run after hero */
! 70: if (th->t_dest == &hero) /* Find room of chasee */
! 71: ree = proom;
! 72: else
! 73: ree = roomin(th->t_dest);
! 74: /*
! 75: * We don't count doors as inside rooms for this routine
! 76: */
! 77: door = (chat(th->t_pos.y, th->t_pos.x) == DOOR);
! 78: /*
! 79: * If the object of our desire is in a different room,
! 80: * and we are not in a corridor, run to the door nearest to
! 81: * our goal.
! 82: */
! 83: over:
! 84: if (rer != ree)
! 85: {
! 86: for (i = 0; i < rer->r_nexits; i++) /* loop through doors */
! 87: {
! 88: dist = DISTANCE(th->t_dest->y, th->t_dest->x,
! 89: rer->r_exit[i].y, rer->r_exit[i].x);
! 90: if (dist < mindist)
! 91: {
! 92: this = rer->r_exit[i];
! 93: mindist = dist;
! 94: }
! 95: }
! 96: if (door)
! 97: {
! 98: rer = &passages[flat(th->t_pos.y, th->t_pos.x) & F_PNUM];
! 99: door = FALSE;
! 100: goto over;
! 101: }
! 102: }
! 103: else
! 104: {
! 105: this = *th->t_dest;
! 106: /*
! 107: * For dragons check and see if (a) the hero is on a straight
! 108: * line from it, and (b) that it is within shooting distance,
! 109: * but outside of striking range.
! 110: */
! 111: if (th->t_type == 'D' && (th->t_pos.y == hero.y || th->t_pos.x == hero.x
! 112: || abs(th->t_pos.y - hero.y) == abs(th->t_pos.x - hero.x))
! 113: && DISTANCE(th->t_pos.y, th->t_pos.x, hero.y, hero.x) <= BOLT_LENGTH * BOLT_LENGTH
! 114: && !on(*th, ISCANC) && rnd(DRAGONSHOT) == 0)
! 115: {
! 116: delta.y = sign(hero.y - th->t_pos.y);
! 117: delta.x = sign(hero.x - th->t_pos.x);
! 118: fire_bolt(&th->t_pos, &delta, "flame");
! 119: running = FALSE;
! 120: count = quiet = 0;
! 121: return 0;
! 122: }
! 123: }
! 124: /*
! 125: * This now contains what we want to run to this time
! 126: * so we run to it. If we hit it we either want to fight it
! 127: * or stop running
! 128: */
! 129: if (!chase(th, &this))
! 130: {
! 131: if (ce(this, hero))
! 132: {
! 133: return ( attack(th) );
! 134: }
! 135: else if (ce(this, *th->t_dest))
! 136: {
! 137: for (obj = lvl_obj; obj != NULL; obj = next(obj))
! 138: if (th->t_dest == &obj->o_pos)
! 139: {
! 140: detach(lvl_obj, obj);
! 141: attach(th->t_pack, obj);
! 142: chat(obj->o_pos.y, obj->o_pos.x) =
! 143: (th->t_room->r_flags & ISGONE) ? PASSAGE : FLOOR;
! 144: th->t_dest = find_dest(th);
! 145: break;
! 146: }
! 147: if (th->t_type != 'F')
! 148: stoprun = TRUE;
! 149: }
! 150: }
! 151: else if (th->t_type == 'F')
! 152: return(0);
! 153: mvaddch(th->t_pos.y, th->t_pos.x, th->t_oldch);
! 154: if (!ce(ch_ret, th->t_pos))
! 155: {
! 156: sch = mvinch(ch_ret.y, ch_ret.x);
! 157: if (sch == FLOOR && (th->t_room->r_flags & ISDARK)
! 158: && DISTANCE(th->t_pos.y, th->t_pos.x, hero.y, hero.x)
! 159: && !on(player, ISBLIND))
! 160: th->t_oldch = ' ';
! 161: else
! 162: th->t_oldch = sch;
! 163: oroom = th->t_room;
! 164: th->t_room = roomin(&ch_ret);
! 165: if (oroom != th->t_room)
! 166: th->t_dest = find_dest(th);
! 167:
! 168: moat(th->t_pos.y, th->t_pos.x) = NULL;
! 169: moat(ch_ret.y, ch_ret.x) = th;
! 170: th->t_pos = ch_ret;
! 171: }
! 172: if (see_monst(th))
! 173: mvaddch(ch_ret.y, ch_ret.x, th->t_disguise);
! 174: else if (on(player, SEEMONST))
! 175: {
! 176: standout();
! 177: mvaddch(ch_ret.y, ch_ret.x, th->t_type);
! 178: standend();
! 179: }
! 180: /*
! 181: * And stop running if need be
! 182: */
! 183: if (stoprun && ce(th->t_pos, *(th->t_dest)))
! 184: th->t_flags &= ~ISRUN;
! 185:
! 186: return(0);
! 187: }
! 188:
! 189: /*
! 190: * see_monst:
! 191: * Return TRUE if the hero can see the monster
! 192: */
! 193: bool
! 194: see_monst(THING *mp)
! 195: {
! 196: if (on(player, ISBLIND))
! 197: return FALSE;
! 198: if (on(*mp, ISINVIS) && !on(player, CANSEE))
! 199: return FALSE;
! 200: if (DISTANCE(mp->t_pos.y, mp->t_pos.x, hero.y, hero.x) < LAMPDIST)
! 201: return TRUE;
! 202: if (mp->t_room != proom)
! 203: return FALSE;
! 204: return (!(mp->t_room->r_flags & ISDARK));
! 205: }
! 206:
! 207: /*
! 208: * runto:
! 209: * Set a mosnter running after something or stop it from running
! 210: * (for when it dies)
! 211: */
! 212: void
! 213: runto(coord *runner, coord *spot)
! 214: {
! 215: register THING *tp;
! 216:
! 217: /*
! 218: * If we couldn't find him, something is funny
! 219: */
! 220: #ifdef WIZARD
! 221: if ((tp = moat(runner->y, runner->x)) == NULL)
! 222: msg("couldn't find monster in runto at (%d,%d)", runner->y, runner->x);
! 223: #else
! 224: tp = moat(runner->y, runner->x);
! 225: #endif
! 226: /*
! 227: * Start the beastie running
! 228: */
! 229: if (tp == NULL)
! 230: return;
! 231: tp->t_flags |= ISRUN;
! 232: tp->t_flags &= ~ISHELD;
! 233: tp->t_dest = find_dest(tp);
! 234: }
! 235:
! 236: /*
! 237: * chase:
! 238: * Find the spot for the chaser(er) to move closer to the
! 239: * chasee(ee). Returns TRUE if we want to keep on chasing later
! 240: * FALSE if we reach the goal.
! 241: */
! 242: bool
! 243: chase(THING *tp, coord *ee)
! 244: {
! 245: register int x, y;
! 246: register int dist, thisdist;
! 247: register THING *obj;
! 248: register coord *er = &tp->t_pos;
! 249: register char ch;
! 250: register int plcnt = 1;
! 251:
! 252: /*
! 253: * If the thing is confused, let it move randomly. Invisible
! 254: * Stalkers are slightly confused all of the time, and bats are
! 255: * quite confused all the time
! 256: */
! 257: if ((on(*tp, ISHUH) && rnd(5) != 0) || (tp->t_type == 'I' && rnd(5) == 0)
! 258: || (tp->t_type == 'B' && rnd(2) == 0))
! 259: {
! 260: /*
! 261: * get a valid random move
! 262: */
! 263: ch_ret = *rndmove(tp);
! 264: dist = DISTANCE(ch_ret.y, ch_ret.x, ee->y, ee->x);
! 265: /*
! 266: * Small chance that it will become un-confused
! 267: */
! 268: if (rnd(20) == 0)
! 269: tp->t_flags &= ~ISHUH;
! 270: }
! 271: /*
! 272: * Otherwise, find the empty spot next to the chaser that is
! 273: * closest to the chasee.
! 274: */
! 275: else
! 276: {
! 277: register int ey, ex;
! 278: /*
! 279: * This will eventually hold where we move to get closer
! 280: * If we can't find an empty spot, we stay where we are.
! 281: */
! 282: dist = DISTANCE(er->y, er->x, ee->y, ee->x);
! 283: ch_ret = *er;
! 284:
! 285: ey = er->y + 1;
! 286: ex = er->x + 1;
! 287: for (x = er->x - 1; x <= ex; x++)
! 288: for (y = er->y - 1; y <= ey; y++)
! 289: {
! 290: coord tryp;
! 291:
! 292: tryp.x = x;
! 293: tryp.y = y;
! 294: if (!diag_ok(er, &tryp))
! 295: continue;
! 296: ch = winat(y, x);
! 297: if (step_ok(ch))
! 298: {
! 299: /*
! 300: * If it is a scroll, it might be a scare monster scroll
! 301: * so we need to look it up to see what type it is.
! 302: */
! 303: if (ch == SCROLL)
! 304: {
! 305: for (obj = lvl_obj; obj != NULL; obj = next(obj))
! 306: {
! 307: if (y == obj->o_pos.y && x == obj->o_pos.x)
! 308: break;
! 309: }
! 310: if (obj != NULL && obj->o_which == S_SCARE)
! 311: continue;
! 312: }
! 313: /*
! 314: * It can also be a Mimic, which we shouldn't step on
! 315: */
! 316: if ((obj = moat(y, x)) != NULL && obj->t_type == 'M')
! 317: continue;
! 318: /*
! 319: * If we didn't find any scrolls at this place or it
! 320: * wasn't a scare scroll, then this place counts
! 321: */
! 322: thisdist = DISTANCE(y, x, ee->y, ee->x);
! 323: if (thisdist < dist)
! 324: {
! 325: plcnt = 1;
! 326: ch_ret = tryp;
! 327: dist = thisdist;
! 328: }
! 329: else if (thisdist == dist && rnd(++plcnt) == 0)
! 330: {
! 331: ch_ret = tryp;
! 332: dist = thisdist;
! 333: }
! 334: }
! 335: }
! 336: }
! 337: return (dist != 0 && !ce(ch_ret, hero));
! 338: }
! 339:
! 340: /*
! 341: * roomin:
! 342: * Find what room some coordinates are in. NULL means they aren't
! 343: * in any room.
! 344: */
! 345: struct room *
! 346: roomin(coord *cp)
! 347: {
! 348: register struct room *rp;
! 349: register char *fp;
! 350:
! 351: for (rp = rooms; rp < &rooms[MAXROOMS]; rp++)
! 352: if (cp->x < rp->r_pos.x + rp->r_max.x && rp->r_pos.x <= cp->x
! 353: && cp->y < rp->r_pos.y + rp->r_max.y && rp->r_pos.y <= cp->y)
! 354: return rp;
! 355: fp = &flat(cp->y, cp->x);
! 356: if (*fp & F_PASS)
! 357: return &passages[*fp & F_PNUM];
! 358: msg("in some bizarre place (%d, %d)", unc(*cp));
! 359: return NULL;
! 360: }
! 361:
! 362: /*
! 363: * diag_ok:
! 364: * Check to see if the move is legal if it is diagonal
! 365: */
! 366: bool
! 367: diag_ok(coord *sp, coord *ep)
! 368: {
! 369: if (ep->x == sp->x || ep->y == sp->y)
! 370: return TRUE;
! 371: return (step_ok(chat(ep->y, sp->x)) && step_ok(chat(sp->y, ep->x)));
! 372: }
! 373:
! 374: /*
! 375: * cansee:
! 376: * Returns true if the hero can see a certain coordinate.
! 377: */
! 378: bool
! 379: cansee(int y, int x)
! 380: {
! 381: register struct room *rer;
! 382: coord tp;
! 383:
! 384: if (on(player, ISBLIND))
! 385: return FALSE;
! 386: if (DISTANCE(y, x, hero.y, hero.x) < LAMPDIST)
! 387: return TRUE;
! 388: /*
! 389: * We can only see if the hero in the same room as
! 390: * the coordinate and the room is lit or if it is close.
! 391: */
! 392: tp.y = y;
! 393: tp.x = x;
! 394: return ((rer = roomin(&tp)) == proom && !(rer->r_flags & ISDARK));
! 395: }
! 396:
! 397: /*
! 398: * find_dest:
! 399: * find the proper destination for the monster
! 400: */
! 401: coord *
! 402: find_dest(THING *tp)
! 403: {
! 404: register THING *obj;
! 405: register int prob;
! 406: register struct room *rp;
! 407:
! 408: if ((prob = monsters[tp->t_type - 'A'].m_carry) <= 0 || tp->t_room == proom
! 409: || see_monst(tp))
! 410: return &hero;
! 411: rp = tp->t_room;
! 412: for (obj = lvl_obj; obj != NULL; obj = next(obj))
! 413: {
! 414: if (obj->o_type == SCROLL && obj->o_which == S_SCARE)
! 415: continue;
! 416: if (roomin(&obj->o_pos) == rp && rnd(100) < prob)
! 417: {
! 418: for (tp = mlist; tp != NULL; tp = next(tp))
! 419: if (tp->t_dest == &obj->o_pos)
! 420: break;
! 421: if (tp == NULL)
! 422: return &obj->o_pos;
! 423: }
! 424: }
! 425: return &hero;
! 426: }
CVSweb