Mercurial > hg > early-roguelike
comparison srogue/chase.c @ 36:2128c7dc8a40
Import Super-Rogue 9.0 from the Roguelike Restoration Project (r1490)
author | elwin |
---|---|
date | Thu, 25 Nov 2010 12:21:41 +0000 |
parents | |
children | 94a0d9dd5ce1 |
comparison
equal
deleted
inserted
replaced
35:05018c63a721 | 36:2128c7dc8a40 |
---|---|
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 "rogue.h" | |
18 #include "rogue.ext" | |
19 | |
20 #define FARAWAY 32767 | |
21 #define RDIST(a, b) (DISTANCE((a)->y, (a)->x, (b).y, (b).x)) | |
22 | |
23 struct coord ch_ret; /* Where chasing takes you */ | |
24 | |
25 /* | |
26 * runners: | |
27 * Make all the running monsters move. | |
28 */ | |
29 runners() | |
30 { | |
31 reg struct thing *tp; | |
32 reg struct linked_list *mon,*nextmon; | |
33 | |
34 for (mon = mlist; mon != NULL; mon = nextmon) { | |
35 tp = THINGPTR(mon); | |
36 nextmon = next(mon); | |
37 if (off(*tp, ISHELD) && on(*tp, ISRUN)) { | |
38 if (tp->t_nomove > 0) | |
39 if (--tp->t_nomove > 0) | |
40 continue; | |
41 if (on(*tp, ISHASTE)) | |
42 if (do_chase(mon) == -1) | |
43 continue; | |
44 if (off(*tp, ISSLOW) || tp->t_turn) | |
45 if (do_chase(mon) == -1) | |
46 continue; | |
47 tp->t_turn ^= TRUE; | |
48 } | |
49 } | |
50 } | |
51 | |
52 | |
53 /* | |
54 * do_chase: | |
55 * Make one thing chase another. | |
56 */ | |
57 do_chase(mon) | |
58 struct linked_list *mon; | |
59 { | |
60 reg struct thing *th; | |
61 reg struct room *rer, *ree, *rxx; | |
62 reg int mindist, i, dist; | |
63 struct stats *st; | |
64 bool stoprun = FALSE, ondoor = FALSE, link = FALSE; | |
65 char runaway, dofight, wound, sch, ch; | |
66 struct coord this; | |
67 struct trap *trp; | |
68 | |
69 th = THINGPTR(mon); | |
70 wound = th->t_flags & ISWOUND; | |
71 if (wound) | |
72 mindist = 0; | |
73 else | |
74 mindist = FARAWAY; | |
75 runaway = wound; | |
76 dofight = !runaway; | |
77 rer = th->t_room; | |
78 if (th->t_type == 'V') { | |
79 if (rer != NULL && !rf_on(rer, ISDARK)) { | |
80 /* | |
81 * Vampires can't stand the light | |
82 */ | |
83 if (cansee(th->t_pos.y, th->t_pos.x)) | |
84 msg("The vampire vaporizes into thin air !"); | |
85 killed(mon, FALSE); | |
86 return(-1); | |
87 } | |
88 } | |
89 ree = roomin(th->t_dest); /* room of chasee */ | |
90 this = *th->t_dest; | |
91 /* | |
92 * If the object of our desire is in a different | |
93 * room, then run to the door nearest to our goal. | |
94 */ | |
95 if (mvinch(th->t_pos.y, th->t_pos.x) == DOOR) | |
96 ondoor = TRUE; | |
97 rxx = NULL; | |
98 if (rer != NULL || ree != NULL) { | |
99 /* | |
100 * Monster not in room, hero in room. Run to closest door | |
101 * in hero's room if not wounded. Run away if wounded. | |
102 */ | |
103 if (rer == NULL && ree != NULL) { | |
104 if (!wound) | |
105 rxx = ree; | |
106 } | |
107 /* | |
108 * Monster in a room, hero not in room. If on a door, | |
109 * then use closest distance. If not on a door, then | |
110 * run to closest door in monsters room. | |
111 */ | |
112 else if (rer != NULL && ree == NULL) { | |
113 if (!ondoor) { | |
114 rxx = rer; | |
115 if (wound) | |
116 runaway = FALSE; | |
117 } | |
118 } | |
119 /* | |
120 * Both hero and monster in a DIFFERENT room. Set flag to | |
121 * check for links between the monster's and hero's rooms. | |
122 * If no links are found, then the closest door in the | |
123 * monster's room is used. | |
124 */ | |
125 else if (rer != ree) { | |
126 if (!wound) { | |
127 link = TRUE; | |
128 if (ondoor) | |
129 rxx = ree; /* if on door, run to heros room */ | |
130 else | |
131 rxx = rer; /* else to nearest door this room */ | |
132 } | |
133 } | |
134 /* | |
135 * Both hero and monster in same room. If monster is | |
136 * wounded, find the best door to run to. | |
137 */ | |
138 else if (wound) { | |
139 struct coord *ex; | |
140 int poss, mdtd, hdtd, ghdtd, nx, gx = 0, best; | |
141 | |
142 best = ghdtd = -FARAWAY; | |
143 for (nx = 0; nx < ree->r_nexits; nx++) { | |
144 ex = &ree->r_exit[nx]; | |
145 if (mvinch(ex->y, ex->x) == SECRETDOOR) | |
146 continue; | |
147 gx += 1; | |
148 mdtd = abs(th->t_pos.y - ex->y) + abs(th->t_pos.x - ex->x); | |
149 hdtd = abs(hero.y - ex->y) + abs(hero.x - ex->x); | |
150 poss = hdtd - mdtd; /* possible move */ | |
151 if (poss > best) { | |
152 best = poss; | |
153 this = *ex; | |
154 } | |
155 else if (poss == best && hdtd > ghdtd) { | |
156 ghdtd = hdtd; | |
157 best = poss; | |
158 this = *ex; | |
159 } | |
160 } | |
161 runaway = FALSE; /* go for target */ | |
162 if (best < 1) | |
163 dofight = TRUE; /* fight if we must */ | |
164 mdtd = (gx <= 1 && best < 1); | |
165 if (ondoor || mdtd) { | |
166 this = hero; | |
167 runaway = TRUE; | |
168 if (!mdtd) | |
169 dofight = FALSE; | |
170 } | |
171 } | |
172 if (rxx != NULL) { | |
173 for (i = 0; i < rxx->r_nexits; i += 1) { | |
174 dist = RDIST(th->t_dest, rxx->r_exit[i]); | |
175 if (link && rxx->r_ptr[i] == ree) | |
176 dist = -1; | |
177 if ((!wound && dist < mindist) || | |
178 (wound && dist > mindist)) { | |
179 this = rxx->r_exit[i]; | |
180 mindist = dist; | |
181 } | |
182 } | |
183 } | |
184 } | |
185 else if (DISTANCE(hero.y, hero.x, th->t_pos.y, th->t_pos.x) <= 3) | |
186 dofight = TRUE; | |
187 /* | |
188 * this now contains what we want to run to this time | |
189 * so we run to it. If we hit it we either want to | |
190 * fight it or stop running. | |
191 */ | |
192 if (chase(th, &this, runaway, dofight) == FIGHT) { | |
193 return( attack(th) ); | |
194 } | |
195 else if ((th->t_flags & (ISSTUCK | ISPARA))) | |
196 return(0); /* if paralyzed or stuck */ | |
197 if ((trp = trap_at(ch_ret.y, ch_ret.x)) != NULL) { | |
198 ch = be_trapped(&ch_ret, th); | |
199 if (ch == GONER || nlmove) { | |
200 if (ch == GONER) | |
201 remove_monster(&th->t_pos, mon); | |
202 nlmove = FALSE; | |
203 return((ch == GONER) ? -1 : 0); | |
204 } | |
205 } | |
206 if (pl_off(ISBLIND)) | |
207 mvwaddch(cw,th->t_pos.y,th->t_pos.x,th->t_oldch); | |
208 sch = mvwinch(cw, ch_ret.y, ch_ret.x); | |
209 if (rer != NULL && rf_on(rer,ISDARK) && sch == FLOOR && | |
210 DISTANCE(ch_ret.y,ch_ret.x,th->t_pos.y,th->t_pos.x) < 3 && | |
211 pl_off(ISBLIND)) | |
212 th->t_oldch = ' '; | |
213 else | |
214 th->t_oldch = sch; | |
215 if (cansee(unc(ch_ret)) && off(*th, ISINVIS)) | |
216 mvwaddch(cw, ch_ret.y, ch_ret.x, th->t_type); | |
217 mvwaddch(mw, th->t_pos.y, th->t_pos.x, ' '); | |
218 mvwaddch(mw, ch_ret.y, ch_ret.x, th->t_type); | |
219 th->t_oldpos = th->t_pos; | |
220 th->t_pos = ch_ret; | |
221 th->t_room = roomin(&ch_ret); | |
222 i = 5; | |
223 if (th->t_flags & ISREGEN) | |
224 i = 40; | |
225 st = &th->t_stats; | |
226 if (rnd(100) < i) { | |
227 if (++st->s_hpt > st->s_maxhp) | |
228 st->s_hpt = st->s_maxhp; | |
229 if (!monhurt(th)) | |
230 th->t_flags &= ~ISWOUND; | |
231 } | |
232 if (stoprun && ce(th->t_pos, *(th->t_dest))) | |
233 th->t_flags &= ~ISRUN; | |
234 return CHASE; | |
235 } | |
236 | |
237 | |
238 /* | |
239 * chase: | |
240 * Find the spot for the chaser to move closer to the | |
241 * chasee. Returns TRUE if we want to keep on chasing | |
242 * later FALSE if we reach the goal. | |
243 */ | |
244 chase(tp, ee, runaway, dofight) | |
245 struct thing *tp; | |
246 struct coord *ee; | |
247 bool runaway, dofight; | |
248 { | |
249 reg int x, y, ch; | |
250 reg int dist, thisdist, closest; | |
251 reg struct coord *er = &tp->t_pos; | |
252 struct coord try, closecoord; | |
253 int numsteps, onscare; | |
254 | |
255 /* | |
256 * If the thing is confused, let it move randomly. | |
257 */ | |
258 ch = CHASE; | |
259 onscare = FALSE; | |
260 if (on(*tp, ISHUH)) { | |
261 ch_ret = *rndmove(tp); | |
262 dist = DISTANCE(hero.y, hero.x, ch_ret.y, ch_ret.x); | |
263 if (rnd(1000) < 5) | |
264 tp->t_flags &= ~ISHUH; | |
265 if (dist == 0) | |
266 ch = FIGHT; | |
267 } | |
268 else { | |
269 /* | |
270 * Otherwise, find the the best spot to run to | |
271 * in order to get to your goal. | |
272 */ | |
273 numsteps = 0; | |
274 if (runaway) | |
275 closest = 0; | |
276 else | |
277 closest = FARAWAY; | |
278 ch_ret = *er; | |
279 closecoord = tp->t_oldpos; | |
280 for (y = er->y - 1; y <= er->y + 1; y += 1) { | |
281 for (x = er->x - 1; x <= er->x + 1; x += 1) { | |
282 if (!cordok(y, x)) | |
283 continue; | |
284 try.x = x; | |
285 try.y = y; | |
286 if (!diag_ok(er, &try)) | |
287 continue; | |
288 ch = winat(y, x); | |
289 if (step_ok(ch)) { | |
290 struct trap *trp; | |
291 | |
292 if (isatrap(ch)) { | |
293 trp = trap_at(y, x); | |
294 if (trp != NULL && off(*tp, ISHUH)) { | |
295 /* | |
296 * Dont run over found traps unless | |
297 * the hero is standing on it. If confused, | |
298 * then he can run into them. | |
299 */ | |
300 if (trp->tr_flags & ISFOUND) { | |
301 if (trp->tr_type == POOL && rnd(100) < 80) | |
302 continue; | |
303 else if (y != hero.y || x != hero.x) | |
304 continue; | |
305 } | |
306 } | |
307 } | |
308 /* | |
309 * Check for scare monster scrolls. | |
310 */ | |
311 if (ch == SCROLL) { | |
312 struct linked_list *item; | |
313 | |
314 item = find_obj(y, x); | |
315 if (item != NULL) | |
316 if ((OBJPTR(item))->o_which == S_SCARE) { | |
317 if (ce(hero, try)) | |
318 onscare = TRUE; | |
319 continue; | |
320 } | |
321 } | |
322 /* | |
323 * Vampires will not run into a lit room. | |
324 */ | |
325 if (tp->t_type == 'V') { | |
326 struct room *lr; | |
327 | |
328 lr = roomin(&try); | |
329 if (lr != NULL && !rf_on(lr, ISDARK)) | |
330 continue; | |
331 } | |
332 /* | |
333 * This is a valid place to step | |
334 */ | |
335 if (y == hero.y && x == hero.x) { | |
336 if (dofight) { | |
337 ch_ret = try; /* if fighting */ | |
338 return FIGHT; /* hit hero */ | |
339 } | |
340 else | |
341 continue; | |
342 } | |
343 thisdist = DISTANCE(y, x, ee->y, ee->x); | |
344 if (thisdist <= 0) { | |
345 ch_ret = try; /* got here but */ | |
346 return CHASE; /* dont fight */ | |
347 } | |
348 numsteps += 1; | |
349 if ((!runaway && thisdist < closest) || | |
350 (runaway && thisdist > closest)) { | |
351 /* | |
352 * dont count the monsters last position as | |
353 * the closest spot, unless running away and | |
354 * in the same room. | |
355 */ | |
356 if (!ce(try, tp->t_oldpos) || (runaway | |
357 && player.t_room == tp->t_room | |
358 && tp->t_room != NULL)) { | |
359 closest = thisdist; | |
360 closecoord = try; | |
361 } | |
362 } | |
363 } | |
364 } | |
365 } | |
366 /* | |
367 * If dead end, then go back from whence you came. | |
368 * Otherwise, pick the closest of the remaining spots. | |
369 */ | |
370 if (numsteps > 0) /* move to best spot */ | |
371 ch_ret = closecoord; | |
372 else { /* nowhere to go */ | |
373 if (DISTANCE(tp->t_pos.y, tp->t_pos.x, hero.y, hero.x) < 2) | |
374 if (!onscare) | |
375 ch_ret = hero; | |
376 } | |