Mercurial > hg > early-roguelike
comparison urogue/chase.c @ 256:c495a4f288c6
Import UltraRogue from the Roguelike Restoration Project (r1490)
author | John "Elwin" Edwards |
---|---|
date | Tue, 31 Jan 2017 19:56:04 -0500 |
parents | |
children | 0250220d8cdd |
comparison
equal
deleted
inserted
replaced
253:d9badb9c0179 | 256:c495a4f288c6 |
---|---|
1 /* | |
2 chase.c - Code for one creature to chase another | |
3 | |
4 UltraRogue: The Ultimate Adventure in the Dungeons of Doom | |
5 Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong | |
6 All rights reserved. | |
7 | |
8 Based on "Advanced Rogue" | |
9 Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka | |
10 All rights reserved. | |
11 | |
12 Based on "Rogue: Exploring the Dungeons of Doom" | |
13 Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman | |
14 All rights reserved. | |
15 | |
16 See the file LICENSE.TXT for full copyright and licensing information. | |
17 */ | |
18 | |
19 #include <stdlib.h> | |
20 #include <ctype.h> | |
21 #include <limits.h> | |
22 #include "rogue.h" | |
23 | |
24 /* | |
25 do_chase() | |
26 Make one thing chase another. | |
27 */ | |
28 | |
29 void | |
30 do_chase(struct thing *th, int flee) | |
31 { | |
32 struct room *rer; /* room of chaser */ | |
33 struct room *ree; /* room of chasee */ | |
34 struct room *old_room; /* old room of monster */ | |
35 struct room *new_room; /* new room of monster */ | |
36 | |
37 int i, mindist = INT_MAX, maxdist = INT_MIN, dist = INT_MIN; | |
38 | |
39 int last_door = -1; /* Door we just came from */ | |
40 int stoprun = FALSE; /* TRUE means we are there */ | |
41 int rundoor; /* TRUE means run to a door */ | |
42 int hit_bad = FALSE; /* TRUE means hit bad monster */ | |
43 int mon_attack; /* TRUE means find a monster to hit */ | |
44 | |
45 char sch; | |
46 struct linked_list *item; | |
47 coord this; /* Temporary destination for chaser */ | |
48 | |
49 if (!th->t_ischasing) | |
50 return; | |
51 | |
52 /* Make sure the monster can move */ | |
53 | |
54 if (th->t_no_move != 0) | |
55 { | |
56 th->t_no_move--; | |
57 return; | |
58 } | |
59 | |
60 /* | |
61 * Bad monsters check for a good monster to hit, friendly monsters | |
62 * check for a bad monster to hit. | |
63 */ | |
64 | |
65 mon_attack = FALSE; | |
66 | |
67 if (good_monster(*th)) | |
68 { | |
69 hit_bad = TRUE; | |
70 mon_attack = TRUE; | |
71 } | |
72 else if (on(*th, ISMEAN)) | |
73 { | |
74 hit_bad = FALSE; | |
75 mon_attack = TRUE; | |
76 } | |
77 | |
78 if (mon_attack) | |
79 { | |
80 struct linked_list *mon_to_hit; | |
81 | |
82 mon_to_hit = f_mons_a(th->t_pos.y, th->t_pos.x, hit_bad); | |
83 | |
84 if (mon_to_hit) | |
85 { | |
86 mon_mon_attack(th, mon_to_hit, pick_weap(th), NOTHROWN); | |
87 return; | |
88 } | |
89 } | |
90 | |
91 /* no nearby monster to hit */ | |
92 | |
93 rer = roomin(th->t_pos); /* Find room of chaser */ | |
94 ree = roomin(th->t_chasee->t_pos); /* Find room of chasee */ | |
95 | |
96 /* | |
97 * We don't count doors as inside rooms for this routine | |
98 */ | |
99 | |
100 if (mvwinch(stdscr, th->t_pos.y, th->t_pos.x) == DOOR) | |
101 rer = NULL; | |
102 | |
103 this = th->t_chasee->t_pos; | |
104 | |
105 /* | |
106 * If we are not in a corridor and not a phasing monster, then if we | |
107 * are running after the player, we run to a door if he is not in the | |
108 * same room. If we are fleeing, we run to a door if he IS in the | |
109 * same room. Note: We don't bother with doors in mazes. Phasing | |
110 * monsters don't need to look for doors. There are no doors in mazes | |
111 * and throne rooms. | |
112 */ | |
113 | |
114 if (levtype != MAZELEV && levtype != THRONE && rer != NULL && off(*th, CANINWALL)) | |
115 { | |
116 if (flee) | |
117 rundoor = (rer == ree); | |
118 else | |
119 rundoor = (rer != ree); | |
120 } | |
121 else | |
122 rundoor = FALSE; | |
123 | |
124 if (rundoor) | |
125 { | |
126 coord d_exit; /* A particular door */ | |
127 int exity, exitx; /* Door's coordinates */ | |
128 | |
129 if (th->t_doorgoal != -1) | |
130 { /* Do we already have the goal? */ | |
131 this = rer->r_exit[th->t_doorgoal]; | |
132 dist = 0; /* Indicate that we have our door */ | |
133 } | |
134 else | |
135 for (i = 0; i < rer->r_nexits; i++) | |
136 { /* Loop through doors */ | |
137 d_exit = rer->r_exit[i]; | |
138 exity = d_exit.y; | |
139 exitx = d_exit.x; | |
140 | |
141 /* Avoid secret doors */ | |
142 if (mvwinch(stdscr, exity, exitx) == DOOR) | |
143 { | |
144 /* Were we just on this door? */ | |
145 if (ce(d_exit, th->t_oldpos)) | |
146 last_door = i; | |
147 else | |
148 { | |
149 dist = DISTANCE(th->t_chasee->t_pos, d_exit); | |
150 | |
151 /* | |
152 * If fleeing, we want to | |
153 * maximize distance from | |
154 * door to what we flee, and | |
155 * minimize distance from | |
156 * door to us. | |
157 */ | |
158 | |
159 if (flee) | |
160 dist-=DISTANCE(th->t_pos,d_exit); | |
161 | |
162 /* | |
163 * Maximize distance if | |
164 * fleeing, otherwise | |
165 * minimize it | |
166 */ | |
167 | |
168 if ((flee && (dist > maxdist)) || | |
169 (!flee && (dist < mindist))) | |
170 { | |
171 th->t_doorgoal = i; /* Use this door */ | |
172 this = d_exit; | |
173 mindist = maxdist = dist; | |
174 } | |
175 } | |
176 } | |
177 } | |
178 | |
179 /* Could we not find a door? */ | |
180 if (dist == INT_MIN) | |
181 { | |
182 /* If we were on a door, go ahead and use it */ | |
183 if (last_door != -1) | |
184 { | |
185 th->t_doorgoal = last_door; | |
186 this = th->t_oldpos; | |
187 dist = 0; /* Indicate that we found a door */ | |
188 } | |
189 } | |
190 | |
191 /* Indicate that we do not want to flee from the door */ | |
192 if (dist != INT_MIN) | |
193 flee = FALSE; | |
194 } | |
195 else | |
196 th->t_doorgoal = -1; /* Not going to any door */ | |
197 | |
198 /* | |
199 * this now contains what we want to run to this time so we run to | |
200 * it. If we hit it we either want to fight it or stop running | |
201 */ | |
202 | |
203 if (!chase(th, &this, flee)) | |
204 { | |
205 if (ce(th->t_nxtpos, hero)) | |
206 { | |
207 /* merchants try to sell something */ | |
208 | |
209 if (on(*th, CANSELL)) | |
210 { | |
211 sell(th); | |
212 return; | |
213 } | |
214 else if (off(*th, ISFRIENDLY) && off(*th, ISCHARMED) | |
215 && (off(*th, CANFLY) || (on(*th, CANFLY) && rnd(2)))) | |
216 attack(th, pick_weap(th), FALSE); | |
217 return; | |
218 } | |
219 else if (on(*th, NOMOVE)) | |
220 stoprun = TRUE; | |
221 } | |
222 | |
223 if (!curr_mons) | |
224 return; /* Did monster get itself killed? */ | |
225 | |
226 if (on(*th, NOMOVE)) | |
227 return; | |
228 | |
229 /* If we have a scavenger, it can pick something up */ | |
230 | |
231 if ((item = find_obj(th->t_nxtpos.y, th->t_nxtpos.x)) != NULL) | |
232 { | |
233 struct linked_list *node, *top = item; | |
234 struct object *obt; | |
235 | |
236 while(top) | |
237 { | |
238 /* grab all objects that qualify */ | |
239 | |
240 struct object *obj = OBJPTR(item); | |
241 | |
242 obt = OBJPTR(top); | |
243 node = obt->next_obj; | |
244 | |
245 if (on(*th, ISSCAVENGE) || | |
246 ((on(*th, CANWIELD) || on(*th, CANSHOOT)) && | |
247 (obj->o_type == WEAPON || obj->o_type == ARMOR)) || | |
248 (on(*th, CANCAST) && is_magic(obj))) | |
249 { | |
250 rem_obj(top, FALSE); | |
251 attach(th->t_pack, top); | |
252 } | |
253 | |
254 top = node; | |
255 } | |
256 | |
257 light(&hero); | |
258 } | |
259 | |
260 mvwaddch(cw, th->t_pos.y, th->t_pos.x, th->t_oldch); | |
261 sch = CCHAR( mvwinch(cw, th->t_nxtpos.y, th->t_nxtpos.x) ); | |
262 | |
263 /* Get old and new room of monster */ | |
264 old_room = roomin(th->t_pos); | |
265 new_room = roomin(th->t_nxtpos); | |
266 | |
267 /* If the monster can illuminate rooms, check for a change */ | |
268 if (on(*th, HASFIRE)) | |
269 { | |
270 /* Is monster entering a room? */ | |
271 if (old_room != new_room && new_room != NULL) | |
272 { | |
273 new_room->r_flags |= HASFIRE; | |
274 new_room->r_fires++; | |
275 if (cansee(th->t_nxtpos.y, th->t_nxtpos.x) && new_room->r_fires==1) | |
276 light(&hero); | |
277 } | |
278 | |
279 /* Is monster leaving a room? */ | |
280 if (old_room != new_room && old_room != NULL) | |
281 { | |
282 if (--(old_room->r_fires) <= 0) | |
283 { | |
284 old_room->r_flags &= ~HASFIRE; | |
285 if (cansee(th->t_pos.y, th->t_pos.x)) | |
286 light(&th->t_pos); | |
287 } | |
288 } | |
289 } | |
290 | |
291 /* | |
292 * If monster is entering player's room and player can see it, stop | |
293 * the player's running. | |
294 */ | |
295 | |
296 if (new_room != old_room && new_room != NULL && | |
297 new_room == ree && cansee(th->t_nxtpos.y, th->t_nxtpos.x) && | |
298 (off(*th, ISINVIS) || (off(*th, ISSHADOW) || rnd(10) == 0) || | |
299 on(player, CANSEE)) && off(*th, CANSURPRISE)) | |
300 running = FALSE; | |
301 | |
302 if (rer != NULL && (rer->r_flags & ISDARK) && | |
303 !(rer->r_flags & HASFIRE) && sch == FLOOR && | |
304 DISTANCE(th->t_nxtpos, th->t_pos) < see_dist && | |
305 off(player, ISBLIND)) | |
306 th->t_oldch = ' '; | |
307 else | |
308 th->t_oldch = sch; | |
309 | |
310 if (cansee(th->t_nxtpos.y, th->t_nxtpos.x) && | |
311 off(*th, ISINWALL) && | |
312 ((off(*th, ISINVIS) && (off(*th, ISSHADOW) || rnd(100) < 10)) || | |
313 on(player, CANSEE)) && | |
314 off(*th, CANSURPRISE)) | |
315 mvwaddch(cw, th->t_nxtpos.y, th->t_nxtpos.x, th->t_type); | |
316 | |
317 mvwaddch(mw, th->t_pos.y, th->t_pos.x, ' '); | |
318 mvwaddch(mw, th->t_nxtpos.y, th->t_nxtpos.x, th->t_type); | |
319 | |
320 /* Record monster's last position (if new one is different) */ | |
321 | |
322 if (!ce(th->t_nxtpos, th->t_pos)) | |
323 th->t_oldpos = th->t_pos; | |
324 | |
325 th->t_pos = th->t_nxtpos; /* Mark the monster's new position */ | |
326 | |
327 /* If the monster is on a trap, trap it */ | |
328 | |
329 sch = CCHAR(mvinch(th->t_nxtpos.y, th->t_nxtpos.x)); | |
330 | |
331 if (isatrap(sch)) | |
332 { | |
333 debug("Monster trapped by %c.", sch); | |
334 | |
335 if (cansee(th->t_nxtpos.y, th->t_nxtpos.x)) | |
336 th->t_oldch = sch; | |
337 | |
338 be_trapped(th, th->t_nxtpos); | |
339 } | |
340 | |
341 /* And stop running if need be */ | |
342 | |
343 if (stoprun && ce(th->t_pos, th->t_chasee->t_pos)) | |
344 { | |
345 th->t_ischasing = FALSE; | |
346 turn_off(*th, ISRUN); | |
347 } | |
348 } | |
349 | |
350 /* | |
351 chase_it() | |
352 Set a monster running after something or stop it from running (for | |
353 when it dies) | |
354 */ | |
355 | |
356 void | |
357 chase_it(coord *runner, struct thing *th) | |
358 { | |
359 struct linked_list *item; | |
360 struct thing *tp; | |
361 | |
362 /* If we couldn't find him, something is funny */ | |
363 | |
364 if ((item = find_mons(runner->y, runner->x)) == NULL) | |
365 { | |
366 debug("CHASER '%s'", unctrl(winat(runner->y, runner->x))); | |
367 return; | |
368 } |