Mercurial > hg > early-roguelike
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 { | |