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 }