Annotation of early-roguelike/srogue/chase.c, Revision 1.1
1.1 ! rubenllo 1: /*
! 2: * Code for one object to chase another
! 3: *
! 4: * @(#)chase.c 9.0 (rdk) 7/17/84
! 5: *
! 6: * Super-Rogue
! 7: * Copyright (C) 1984 Robert D. Kindelberger
! 8: * All rights reserved.
! 9: *
! 10: * Based on "Rogue: Exploring the Dungeons of Doom"
! 11: * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
! 12: * All rights reserved.
! 13: *
! 14: * See the file LICENSE.TXT for full copyright and licensing information.
! 15: */
! 16:
! 17: #include <stdlib.h>
! 18: #include "rogue.h"
! 19: #include "rogue.ext"
! 20:
! 21: #define FARAWAY 32767
! 22: #define RDIST(a, b) (DISTANCE((a)->y, (a)->x, (b).y, (b).x))
! 23:
! 24: int do_chase(struct linked_list *mon);
! 25: int chase(struct thing *tp, struct coord *ee, bool runaway, bool dofight);
! 26:
! 27: struct coord ch_ret; /* Where chasing takes you */
! 28:
! 29: /*
! 30: * runners:
! 31: * Make all the running monsters move.
! 32: */
! 33: void
! 34: runners(void)
! 35: {
! 36: reg struct thing *tp;
! 37: reg struct linked_list *mon,*nextmon;
! 38:
! 39: for (mon = mlist; mon != NULL; mon = nextmon) {
! 40: tp = THINGPTR(mon);
! 41: nextmon = next(mon);
! 42: if (off(*tp, ISHELD) && on(*tp, ISRUN)) {
! 43: if (tp->t_nomove > 0)
! 44: if (--tp->t_nomove > 0)
! 45: continue;
! 46: if (on(*tp, ISHASTE))
! 47: if (do_chase(mon) == -1)
! 48: continue;
! 49: if (off(*tp, ISSLOW) || tp->t_turn)
! 50: if (do_chase(mon) == -1)
! 51: continue;
! 52: tp->t_turn ^= TRUE;
! 53: }
! 54: }
! 55: }
! 56:
! 57:
! 58: /*
! 59: * do_chase:
! 60: * Make one thing chase another.
! 61: */
! 62: int
! 63: do_chase(struct linked_list *mon)
! 64: {
! 65: reg struct thing *th;
! 66: reg struct room *rer, *ree, *rxx;
! 67: reg int mindist, i, dist;
! 68: struct stats *st;
! 69: bool stoprun = FALSE, ondoor = FALSE, link = FALSE;
! 70: char runaway, dofight, wound, sch, ch;
! 71: struct coord this;
! 72: struct trap *trp;
! 73:
! 74: th = THINGPTR(mon);
! 75: wound = th->t_flags & ISWOUND;
! 76: if (wound)
! 77: mindist = 0;
! 78: else
! 79: mindist = FARAWAY;
! 80: runaway = wound;
! 81: dofight = !runaway;
! 82: rer = th->t_room;
! 83: if (th->t_type == 'V') {
! 84: if (rer != NULL && !rf_on(rer, ISDARK)) {
! 85: /*
! 86: * Vampires can't stand the light
! 87: */
! 88: if (cansee(th->t_pos.y, th->t_pos.x))
! 89: msg("The vampire vaporizes into thin air !");
! 90: killed(mon, FALSE);
! 91: return(-1);
! 92: }
! 93: }
! 94: ree = roomin(th->t_dest); /* room of chasee */
! 95: this = *th->t_dest;
! 96: /*
! 97: * If the object of our desire is in a different
! 98: * room, then run to the door nearest to our goal.
! 99: */
! 100: if (mvinch(th->t_pos.y, th->t_pos.x) == DOOR)
! 101: ondoor = TRUE;
! 102: rxx = NULL;
! 103: if (rer != NULL || ree != NULL) {
! 104: /*
! 105: * Monster not in room, hero in room. Run to closest door
! 106: * in hero's room if not wounded. Run away if wounded.
! 107: */
! 108: if (rer == NULL && ree != NULL) {
! 109: if (!wound)
! 110: rxx = ree;
! 111: }
! 112: /*
! 113: * Monster in a room, hero not in room. If on a door,
! 114: * then use closest distance. If not on a door, then
! 115: * run to closest door in monsters room.
! 116: */
! 117: else if (rer != NULL && ree == NULL) {
! 118: if (!ondoor) {
! 119: rxx = rer;
! 120: if (wound)
! 121: runaway = FALSE;
! 122: }
! 123: }
! 124: /*
! 125: * Both hero and monster in a DIFFERENT room. Set flag to
! 126: * check for links between the monster's and hero's rooms.
! 127: * If no links are found, then the closest door in the
! 128: * monster's room is used.
! 129: */
! 130: else if (rer != ree) {
! 131: if (!wound) {
! 132: link = TRUE;
! 133: if (ondoor)
! 134: rxx = ree; /* if on door, run to heros room */
! 135: else
! 136: rxx = rer; /* else to nearest door this room */
! 137: }
! 138: }
! 139: /*
! 140: * Both hero and monster in same room. If monster is
! 141: * wounded, find the best door to run to.
! 142: */
! 143: else if (wound) {
! 144: struct coord *ex;
! 145: int poss, mdtd, hdtd, ghdtd, nx, gx = 0, best;
! 146:
! 147: best = ghdtd = -FARAWAY;
! 148: for (nx = 0; nx < ree->r_nexits; nx++) {
! 149: ex = &ree->r_exit[nx];
! 150: if (mvinch(ex->y, ex->x) == SECRETDOOR)
! 151: continue;
! 152: gx += 1;
! 153: mdtd = abs(th->t_pos.y - ex->y) + abs(th->t_pos.x - ex->x);
! 154: hdtd = abs(hero.y - ex->y) + abs(hero.x - ex->x);
! 155: poss = hdtd - mdtd; /* possible move */
! 156: if (poss > best) {
! 157: best = poss;
! 158: this = *ex;
! 159: }
! 160: else if (poss == best && hdtd > ghdtd) {
! 161: ghdtd = hdtd;
! 162: best = poss;
! 163: this = *ex;
! 164: }
! 165: }
! 166: runaway = FALSE; /* go for target */
! 167: if (best < 1)
! 168: dofight = TRUE; /* fight if we must */
! 169: mdtd = (gx <= 1 && best < 1);
! 170: if (ondoor || mdtd) {
! 171: this = hero;
! 172: runaway = TRUE;
! 173: if (!mdtd)
! 174: dofight = FALSE;
! 175: }
! 176: }
! 177: if (rxx != NULL) {
! 178: for (i = 0; i < rxx->r_nexits; i += 1) {
! 179: dist = RDIST(th->t_dest, rxx->r_exit[i]);
! 180: if (link && rxx->r_ptr[i] == ree)
! 181: dist = -1;
! 182: if ((!wound && dist < mindist) ||
! 183: (wound && dist > mindist)) {
! 184: this = rxx->r_exit[i];
! 185: mindist = dist;
! 186: }
! 187: }
! 188: }
! 189: }
! 190: else if (DISTANCE(hero.y, hero.x, th->t_pos.y, th->t_pos.x) <= 3)
! 191: dofight = TRUE;
! 192: /*
! 193: * this now contains what we want to run to this time
! 194: * so we run to it. If we hit it we either want to
! 195: * fight it or stop running.
! 196: */
! 197: if (chase(th, &this, runaway, dofight) == FIGHT) {
! 198: return( attack(th) );
! 199: }
! 200: else if ((th->t_flags & (ISSTUCK | ISPARA)))
! 201: return(0); /* if paralyzed or stuck */
! 202: if ((trp = trap_at(ch_ret.y, ch_ret.x)) != NULL) {
! 203: ch = be_trapped(&ch_ret, th);
! 204: if (ch == GONER || nlmove) {
! 205: if (ch == GONER)
! 206: remove_monster(&th->t_pos, mon);
! 207: nlmove = FALSE;
! 208: return((ch == GONER) ? -1 : 0);
! 209: }
! 210: }
! 211: if (pl_off(ISBLIND))
! 212: mvwaddch(cw,th->t_pos.y,th->t_pos.x,th->t_oldch);
! 213: sch = mvwinch(cw, ch_ret.y, ch_ret.x);
! 214: if (rer != NULL && rf_on(rer,ISDARK) && sch == FLOOR &&
! 215: DISTANCE(ch_ret.y,ch_ret.x,th->t_pos.y,th->t_pos.x) < 3 &&
! 216: pl_off(ISBLIND))
! 217: th->t_oldch = ' ';
! 218: else
! 219: th->t_oldch = sch;
! 220: if (cansee(unc(ch_ret)) && off(*th, ISINVIS))
! 221: mvwaddch(cw, ch_ret.y, ch_ret.x, th->t_type);
! 222: mvwaddch(mw, th->t_pos.y, th->t_pos.x, ' ');
! 223: mvwaddch(mw, ch_ret.y, ch_ret.x, th->t_type);
! 224: th->t_oldpos = th->t_pos;
! 225: th->t_pos = ch_ret;
! 226: th->t_room = roomin(&ch_ret);
! 227: i = 5;
! 228: if (th->t_flags & ISREGEN)
! 229: i = 40;
! 230: st = &th->t_stats;
! 231: if (rnd(100) < i) {
! 232: if (++st->s_hpt > st->s_maxhp)
! 233: st->s_hpt = st->s_maxhp;
! 234: if (!monhurt(th))
! 235: th->t_flags &= ~ISWOUND;
! 236: }
! 237: if (stoprun && ce(th->t_pos, *(th->t_dest)))
! 238: th->t_flags &= ~ISRUN;
! 239: return CHASE;
! 240: }
! 241:
! 242:
! 243: /*
! 244: * chase:
! 245: * Find the spot for the chaser to move closer to the
! 246: * chasee. Returns TRUE if we want to keep on chasing
! 247: * later FALSE if we reach the goal.
! 248: */
! 249: int
! 250: chase(struct thing *tp, struct coord *ee, bool runaway, bool dofight)
! 251: {
! 252: reg int x, y, ch;
! 253: reg int dist, thisdist, closest;
! 254: reg struct coord *er = &tp->t_pos;
! 255: struct coord try, closecoord;
! 256: int numsteps, onscare;
! 257:
! 258: /*
! 259: * If the thing is confused, let it move randomly.
! 260: */
! 261: ch = CHASE;
! 262: onscare = FALSE;
! 263: if (on(*tp, ISHUH)) {
! 264: ch_ret = *rndmove(tp);
! 265: dist = DISTANCE(hero.y, hero.x, ch_ret.y, ch_ret.x);
! 266: if (rnd(1000) < 5)
! 267: tp->t_flags &= ~ISHUH;
! 268: if (dist == 0)
! 269: ch = FIGHT;
! 270: }
! 271: else {
! 272: /*
! 273: * Otherwise, find the the best spot to run to
! 274: * in order to get to your goal.
! 275: */
! 276: numsteps = 0;
! 277: if (runaway)
! 278: closest = 0;
! 279: else
! 280: closest = FARAWAY;
! 281: ch_ret = *er;
! 282: closecoord = tp->t_oldpos;
! 283: for (y = er->y - 1; y <= er->y + 1; y += 1) {
! 284: for (x = er->x - 1; x <= er->x + 1; x += 1) {
! 285: if (!cordok(y, x))
! 286: continue;
! 287: try.x = x;
! 288: try.y = y;
! 289: if (!diag_ok(er, &try))
! 290: continue;
! 291: ch = winat(y, x);
! 292: if (step_ok(ch)) {
! 293: struct trap *trp;
! 294:
! 295: if (isatrap(ch)) {
! 296: trp = trap_at(y, x);
! 297: if (trp != NULL && off(*tp, ISHUH)) {
! 298: /*
! 299: * Dont run over found traps unless
! 300: * the hero is standing on it. If confused,
! 301: * then he can run into them.
! 302: */
! 303: if (trp->tr_flags & ISFOUND) {
! 304: if (trp->tr_type == POOL && rnd(100) < 80)
! 305: continue;
! 306: else if (y != hero.y || x != hero.x)
! 307: continue;
! 308: }
! 309: }
! 310: }
! 311: /*
! 312: * Check for scare monster scrolls.
! 313: */
! 314: if (ch == SCROLL) {
! 315: struct linked_list *item;
! 316:
! 317: item = find_obj(y, x);
! 318: if (item != NULL)
! 319: if ((OBJPTR(item))->o_which == S_SCARE) {
! 320: if (ce(hero, try))
! 321: onscare = TRUE;
! 322: continue;
! 323: }
! 324: }
! 325: /*
! 326: * Vampires will not run into a lit room.
! 327: */
! 328: if (tp->t_type == 'V') {
! 329: struct room *lr;
! 330:
! 331: lr = roomin(&try);
! 332: if (lr != NULL && !rf_on(lr, ISDARK))
! 333: continue;
! 334: }
! 335: /*
! 336: * This is a valid place to step
! 337: */
! 338: if (y == hero.y && x == hero.x) {
! 339: if (dofight) {
! 340: ch_ret = try; /* if fighting */
! 341: return FIGHT; /* hit hero */
! 342: }
! 343: else
! 344: continue;
! 345: }
! 346: thisdist = DISTANCE(y, x, ee->y, ee->x);
! 347: if (thisdist <= 0) {
! 348: ch_ret = try; /* got here but */
! 349: return CHASE; /* dont fight */
! 350: }
! 351: numsteps += 1;
! 352: if ((!runaway && thisdist < closest) ||
! 353: (runaway && thisdist > closest)) {
! 354: /*
! 355: * dont count the monsters last position as
! 356: * the closest spot, unless running away and
! 357: * in the same room.
! 358: */
! 359: if (!ce(try, tp->t_oldpos) || (runaway
! 360: && player.t_room == tp->t_room
! 361: && tp->t_room != NULL)) {
! 362: closest = thisdist;
! 363: closecoord = try;
! 364: }
! 365: }
! 366: }
! 367: }
! 368: }
! 369: /*
! 370: * If dead end, then go back from whence you came.
! 371: * Otherwise, pick the closest of the remaining spots.
! 372: */
! 373: if (numsteps > 0) /* move to best spot */
! 374: ch_ret = closecoord;
! 375: else { /* nowhere to go */
! 376: if (DISTANCE(tp->t_pos.y, tp->t_pos.x, hero.y, hero.x) < 2)
! 377: if (!onscare)
! 378: ch_ret = hero;
! 379: }
! 380: if (ce(hero, ch_ret))
! 381: ch = FIGHT;
! 382: }
! 383: return ch;
! 384: }
! 385:
! 386:
! 387: /*
! 388: * runto:
! 389: * Set a monster running after something
! 390: */
! 391: void
! 392: runto(struct coord *runner, struct coord *spot)
! 393: {
! 394: reg struct linked_list *item;
! 395: reg struct thing *tp;
! 396:
! 397: if ((item = find_mons(runner->y, runner->x)) == NULL)
! 398: return;
! 399: tp = THINGPTR(item);
! 400: if (tp->t_flags & ISPARA)
! 401: return;
! 402: tp->t_dest = spot;
! 403: tp->t_flags |= ISRUN;
! 404: tp->t_flags &= ~ISHELD;
! 405: }
! 406:
! 407:
! 408: /*
! 409: * roomin:
! 410: * Find what room some coordinates are in.
! 411: * NULL means they aren't in any room.
! 412: */
! 413: struct room *
! 414: roomin(struct coord *cp)
! 415: {
! 416: reg struct room *rp;
! 417:
! 418: if (cordok(cp->y, cp->x)) {
! 419: for (rp = rooms; rp < &rooms[MAXROOMS]; rp += 1)
! 420: if (inroom(rp, cp))
! 421: return rp;
! 422: }
! 423: return NULL;
! 424: }
! 425:
! 426:
! 427: /*
! 428: * find_mons:
! 429: * Find the monster from his coordinates
! 430: */
! 431: struct linked_list *
! 432: find_mons(int y, int x)
! 433: {
! 434: reg struct linked_list *item;
! 435: reg struct thing *th;
! 436:
! 437: for (item = mlist; item != NULL; item = next(item)) {
! 438: th = THINGPTR(item);
! 439: if (th->t_pos.y == y && th->t_pos.x == x)
! 440: return item;
! 441: }
! 442: return NULL;
! 443: }
! 444:
! 445:
! 446: /*
! 447: * diag_ok:
! 448: * Check to see if the move is legal if it is diagonal
! 449: */
! 450: bool
! 451: diag_ok(struct coord *sp, struct coord *ep)
! 452: {
! 453: if (ep->x == sp->x || ep->y == sp->y)
! 454: return TRUE;
! 455: if (step_ok(mvinch(ep->y,sp->x)) && step_ok(mvinch(sp->y,ep->x)))
! 456: return TRUE;
! 457: return FALSE;
! 458: }
! 459:
! 460:
! 461: /*
! 462: * cansee:
! 463: * returns true if the hero can see a certain coordinate.
! 464: */
! 465: bool
! 466: cansee(int y, int x)
! 467: {
! 468: reg struct room *rer;
! 469: struct coord tp;
! 470:
! 471: if (pl_on(ISBLIND))
! 472: return FALSE;
! 473: /*
! 474: * We can only see if the hero in the same room as
! 475: * the coordinate and the room is lit or if it is close.
! 476: */
! 477: if (DISTANCE(y, x, hero.y, hero.x) < 3)
! 478: return TRUE;
! 479: tp.y = y;
! 480: tp.x = x;
! 481: rer = roomin(&tp);
! 482: if (rer != NULL && levtype != MAZELEV)
! 483: if (rer == player.t_room && !rf_on(rer,ISDARK))
! 484: return TRUE;
! 485: return FALSE;
! 486: }
CVSweb