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