Annotation of early-roguelike/srogue/chase.c, Revision 1.1.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