Mercurial > hg > early-roguelike
comparison rogue5/chase.c @ 33:f502bf60e6e4
Import Rogue 5.4 from the Roguelike Restoration Project (r1490)
author | elwin |
---|---|
date | Mon, 24 May 2010 20:10:59 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
32:2dcd75e6a736 | 33:f502bf60e6e4 |
---|---|
1 /* | |
2 * Code for one creature to chase another | |
3 * | |
4 * @(#)chase.c 4.57 (Berkeley) 02/05/99 | |
5 * | |
6 * Rogue: Exploring the Dungeons of Doom | |
7 * Copyright (C) 1980-1983, 1985, 1999 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 static coord ch_ret; /* Where chasing takes you */ | |
20 | |
21 /* | |
22 * runners: | |
23 * Make all the running monsters move. | |
24 */ | |
25 void | |
26 runners(void) | |
27 { | |
28 THING *tp; | |
29 THING *next; | |
30 int wastarget; | |
31 coord orig_pos; | |
32 | |
33 for (tp = mlist; tp != NULL; tp = next) | |
34 { | |
35 /* remember this in case the monster's "next" is changed */ | |
36 next = next(tp); | |
37 if (!on(*tp, ISHELD) && on(*tp, ISRUN)) | |
38 { | |
39 orig_pos = tp->t_pos; | |
40 wastarget = on(*tp, ISTARGET); | |
41 if (move_monst(tp) == -1) | |
42 continue; | |
43 if (on(*tp, ISFLY) && dist_cp(&hero, &tp->t_pos) >= 3) | |
44 move_monst(tp); | |
45 if (wastarget && !ce(orig_pos, tp->t_pos)) | |
46 { | |
47 tp->t_flags &= ~ISTARGET; | |
48 to_death = FALSE; | |
49 } | |
50 } | |
51 } | |
52 if (has_hit) | |
53 { | |
54 endmsg(); | |
55 has_hit = FALSE; | |
56 } | |
57 } | |
58 | |
59 /* | |
60 * move_monst: | |
61 * Execute a single turn of running for a monster | |
62 */ | |
63 int | |
64 move_monst(THING *tp) | |
65 { | |
66 if (!on(*tp, ISSLOW) || tp->t_turn) | |
67 if (do_chase(tp) == -1) | |
68 return(-1); | |
69 if (on(*tp, ISHASTE)) | |
70 if (do_chase(tp) == -1) | |
71 return(-1); | |
72 tp->t_turn ^= TRUE; | |
73 return(0); | |
74 } | |
75 | |
76 /* | |
77 * relocate: | |
78 * Make the monster's new location be the specified one, updating | |
79 * all the relevant state. | |
80 */ | |
81 void | |
82 relocate(THING *th, const coord *new_loc) | |
83 { | |
84 struct room *oroom; | |
85 | |
86 if (!ce(*new_loc, th->t_pos)) | |
87 { | |
88 mvaddch(th->t_pos.y, th->t_pos.x, th->t_oldch); | |
89 th->t_room = roomin(new_loc); | |
90 set_oldch(th, new_loc); | |
91 oroom = th->t_room; | |
92 moat(th->t_pos.y, th->t_pos.x) = NULL; | |
93 | |
94 if (oroom != th->t_room) | |
95 th->t_dest = find_dest(th); | |
96 th->t_pos = *new_loc; | |
97 moat(new_loc->y, new_loc->x) = th; | |
98 } | |
99 move(new_loc->y, new_loc->x); | |
100 if (see_monst(th)) | |
101 addch(th->t_disguise); | |
102 else if (on(player, SEEMONST)) | |
103 { | |
104 standout(); | |
105 addch(th->t_type); | |
106 standend(); | |
107 } | |
108 } | |
109 | |
110 /* | |
111 * do_chase: | |
112 * Make one thing chase another. | |
113 */ | |
114 int | |
115 do_chase(THING *th) | |
116 { | |
117 coord *cp; | |
118 struct room *rer, *ree; /* room of chaser, room of chasee */ | |
119 int mindist = 32767, curdist; | |
120 int stoprun = FALSE; /* TRUE means we are there */ | |
121 int door; | |
122 THING *obj; | |
123 coord this; /* Temporary destination for chaser */ | |
124 | |
125 rer = th->t_room; /* Find room of chaser */ | |
126 if (on(*th, ISGREED) && rer->r_goldval == 0) | |
127 th->t_dest = &hero; /* If gold has been taken, run after hero */ | |
128 if (th->t_dest == &hero) /* Find room of chasee */ | |
129 ree = proom; | |
130 else | |
131 ree = roomin(th->t_dest); | |
132 /* | |
133 * We don't count doors as inside rooms for this routine | |
134 */ | |
135 door = (chat(th->t_pos.y, th->t_pos.x) == DOOR); | |
136 /* | |
137 * If the object of our desire is in a different room, | |
138 * and we are not in a corridor, run to the door nearest to | |
139 * our goal. | |
140 */ | |
141 over: | |
142 if (rer != ree) | |
143 { | |
144 for (cp = rer->r_exit; cp < &rer->r_exit[rer->r_nexits]; cp++) | |
145 { | |
146 curdist = dist_cp(th->t_dest, cp); | |
147 if (curdist < mindist) | |
148 { | |
149 this = *cp; | |
150 mindist = curdist; | |
151 } | |
152 } | |
153 if (door) | |
154 { | |
155 rer = &passages[flat(th->t_pos.y, th->t_pos.x) & F_PNUM]; | |
156 door = FALSE; | |
157 goto over; | |
158 } | |
159 } | |
160 else | |
161 { | |
162 this = *th->t_dest; | |
163 /* | |
164 * For dragons check and see if (a) the hero is on a straight | |
165 * line from it, and (b) that it is within shooting distance, | |
166 * but outside of striking range. | |
167 */ | |
168 if (th->t_type == 'D' && (th->t_pos.y == hero.y || th->t_pos.x == hero.x | |
169 || abs(th->t_pos.y - hero.y) == abs(th->t_pos.x - hero.x)) | |
170 && dist_cp(&th->t_pos, &hero) <= BOLT_LENGTH * BOLT_LENGTH | |
171 && !on(*th, ISCANC) && rnd(DRAGONSHOT) == 0) | |
172 { | |
173 delta.y = sign(hero.y - th->t_pos.y); | |
174 delta.x = sign(hero.x - th->t_pos.x); | |
175 if (has_hit) | |
176 endmsg(); | |
177 fire_bolt(&th->t_pos, &delta, "flame"); | |
178 running = FALSE; | |
179 count = 0; | |
180 quiet = 0; | |
181 if (to_death && !on(*th, ISTARGET)) | |
182 { | |
183 to_death = FALSE; | |
184 kamikaze = FALSE; | |
185 } | |
186 return(0); | |
187 } | |
188 } | |
189 /* | |
190 * This now contains what we want to run to this time | |
191 * so we run to it. If we hit it we either want to fight it | |
192 * or stop running | |
193 */ | |
194 if (!chase(th, &this)) | |
195 { | |
196 if (ce(this, hero)) | |
197 { | |
198 return( attack(th) ); | |
199 } | |
200 else if (ce(this, *th->t_dest)) | |
201 { | |
202 for (obj = lvl_obj; obj != NULL; obj = next(obj)) | |
203 if (th->t_dest == &obj->o_pos) | |
204 { | |
205 detach(lvl_obj, obj); | |
206 attach(th->t_pack, obj); | |
207 chat(obj->o_pos.y, obj->o_pos.x) = | |
208 (th->t_room->r_flags & ISGONE) ? PASSAGE : FLOOR; | |
209 th->t_dest = find_dest(th); | |
210 break; | |
211 } | |
212 if (th->t_type != 'F') | |
213 stoprun = TRUE; | |
214 } | |
215 } | |
216 else | |
217 { | |
218 if (th->t_type == 'F') | |
219 return(0); | |
220 } | |
221 relocate(th, &ch_ret); | |
222 /* | |
223 * And stop running if need be | |
224 */ | |
225 if (stoprun && ce(th->t_pos, *(th->t_dest))) | |
226 th->t_flags &= ~ISRUN; | |
227 return(0); | |
228 } | |
229 | |
230 /* | |
231 * set_oldch: | |
232 * Set the oldch character for the monster | |
233 */ | |
234 void | |
235 set_oldch(THING *tp, const coord *cp) | |
236 { | |
237 int sch; | |
238 | |
239 if (ce(tp->t_pos, *cp)) | |
240 return; | |
241 | |
242 sch = tp->t_oldch; | |
243 tp->t_oldch = CCHAR( mvinch(cp->y,cp->x) ); | |
244 if (!on(player, ISBLIND)) | |
245 { | |
246 if ((sch == FLOOR || tp->t_oldch == FLOOR) && | |
247 (tp->t_room->r_flags & ISDARK)) | |
248 tp->t_oldch = ' '; | |
249 else if (dist_cp(cp, &hero) <= LAMPDIST && see_floor) | |
250 tp->t_oldch = chat(cp->y, cp->x); | |
251 } | |
252 } | |
253 | |
254 /* | |
255 * see_monst: | |
256 * Return TRUE if the hero can see the monster | |
257 */ | |
258 int | |
259 see_monst(const THING *mp) | |
260 { | |
261 int y, x; | |
262 | |
263 if (on(player, ISBLIND)) | |
264 return FALSE; | |
265 if (on(*mp, ISINVIS) && !on(player, CANSEE)) | |
266 return FALSE; | |
267 y = mp->t_pos.y; | |
268 x = mp->t_pos.x; | |
269 if (dist(y, x, hero.y, hero.x) < LAMPDIST) | |
270 { | |
271 if (y != hero.y && x != hero.x && | |
272 !step_ok(chat(y, hero.x)) && !step_ok(chat(hero.y, x))) | |
273 return FALSE; | |
274 return TRUE; | |
275 } | |
276 if (mp->t_room != proom) | |
277 return FALSE; | |
278 return (!(mp->t_room->r_flags & ISDARK)); | |
279 } | |
280 | |
281 /* | |
282 * runto: | |
283 * Set a monster running after the hero. | |
284 */ | |
285 void | |
286 runto(const coord *runner) | |
287 { | |
288 THING *tp; | |
289 | |
290 /* | |
291 * If we couldn't find him, something is funny | |
292 */ | |
293 if ((tp = moat(runner->y, runner->x)) == NULL) | |
294 { | |
295 #ifdef MASTER | |
296 msg("couldn't find monster in runto at (%d,%d)", runner->y, runner->x); | |
297 #endif | |
298 return; | |
299 } | |
300 | |
301 /* | |
302 * Start the beastie running | |
303 */ | |
304 tp->t_flags |= ISRUN; | |
305 tp->t_flags &= ~ISHELD; | |
306 tp->t_dest = find_dest(tp); | |
307 } | |
308 | |
309 /* | |
310 * chase: | |
311 * Find the spot for the chaser(er) to move closer to the | |
312 * chasee(ee). Returns TRUE if we want to keep on chasing later | |
313 * FALSE if we reach the goal. | |
314 */ | |
315 int | |
316 chase(THING *tp, const coord *ee) | |
317 { | |
318 THING *obj; | |
319 int x, y; | |
320 int curdist, thisdist; | |
321 const coord *er = &tp->t_pos; | |
322 int ch; | |
323 int plcnt = 1; | |
324 coord tryp; | |
325 | |
326 /* | |
327 * If the thing is confused, let it move randomly. Invisible | |
328 * Stalkers are slightly confused all of the time, and bats are | |
329 * quite confused all the time | |
330 */ | |
331 if ((on(*tp, ISHUH) && rnd(5) != 0) || (tp->t_type == 'P' && rnd(5) == 0) | |
332 || (tp->t_type == 'B' && rnd(2) == 0)) | |
333 { | |
334 /* | |
335 * get a valid random move | |
336 */ | |
337 ch_ret = rndmove(tp); | |
338 curdist = dist_cp(&ch_ret, ee); | |
339 /* | |
340 * Small chance that it will become un-confused | |
341 */ | |
342 if (rnd(20) == 0) | |
343 tp->t_flags &= ~ISHUH; | |
344 } | |
345 /* | |
346 * Otherwise, find the empty spot next to the chaser that is | |
347 * closest to the chasee. | |
348 */ | |
349 else | |
350 { | |
351 int ey, ex; | |
352 /* | |
353 * This will eventually hold where we move to get closer | |
354 * If we can't find an empty spot, we stay where we are. | |
355 */ | |
356 curdist = dist_cp(er, ee); | |
357 ch_ret = *er; | |
358 | |
359 ey = er->y + 1; | |
360 if (ey >= NUMLINES - 1) | |
361 ey = NUMLINES - 2; | |
362 ex = er->x + 1; | |
363 if (ex >= NUMCOLS) | |
364 ex = NUMCOLS - 1; | |
365 | |
366 for (x = er->x - 1; x <= ex; x++) | |
367 { | |
368 if (x < 0) | |
369 continue; | |
370 tryp.x = x; | |
371 for (y = er->y - 1; y <= ey; y++) | |
372 { | |
373 tryp.y = y; | |
374 if (!diag_ok(er, &tryp)) | |
375 continue; | |
376 ch = winat(y, x); | |
377 if (step_ok(ch)) | |
378 { | |
379 /* | |
380 * If it is a scroll, it might be a scare monster scroll | |
381 * so we need to look it up to see what type it is. | |
382 */ | |