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 }