comparison rogue4/chase.c @ 12:9535a08ddc39

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