Mercurial > hg > early-roguelike
comparison arogue7/chase.c @ 125:adfa37e67084
Import Advanced Rogue 7.7 from the Roguelike Restoration Project (r1490)
author | John "Elwin" Edwards |
---|---|
date | Fri, 08 May 2015 15:24:40 -0400 |
parents | |
children | f9ef86cf22b2 |
comparison
equal
deleted
inserted
replaced
124:d10fc4a065ac | 125:adfa37e67084 |
---|---|
1 /* | |
2 * chase.c - Code for one object to chase another | |
3 * | |
4 * Advanced Rogue | |
5 * Copyright (C) 1984, 1985, 1986 Michael Morgan, Ken Dalka and AT&T | |
6 * All rights reserved. | |
7 * | |
8 * Based on "Rogue: Exploring the Dungeons of Doom" | |
9 * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman | |
10 * All rights reserved. | |
11 * | |
12 * See the file LICENSE.TXT for full copyright and licensing information. | |
13 */ | |
14 | |
15 /* | |
16 * Code for one object to chase another | |
17 * | |
18 */ | |
19 | |
20 #include <ctype.h> | |
21 #include <limits.h> | |
22 #include "curses.h" | |
23 #include "rogue.h" | |
24 #define MAXINT INT_MAX | |
25 #define MININT INT_MIN | |
26 | |
27 | |
28 /* | |
29 * Canblink checks if the monster can teleport (blink). If so, it will | |
30 * try to blink the monster next to the player. | |
31 */ | |
32 | |
33 bool | |
34 can_blink(tp) | |
35 register struct thing *tp; | |
36 { | |
37 register int y, x, index=9; | |
38 coord tryp; /* To hold the coordinates for use in diag_ok */ | |
39 bool spots[9], found_one=FALSE; | |
40 | |
41 /* | |
42 * First, can the monster even blink? And if so, there is only a 50% | |
43 * chance that it will do so. And it won't blink if it is running or | |
44 * held. | |
45 */ | |
46 if (off(*tp, CANBLINK) || (on(*tp, ISHELD)) || | |
47 on(*tp, ISFLEE) || | |
48 tp->t_action == A_FREEZE || | |
49 (rnd(12) < 6)) return(FALSE); | |
50 | |
51 | |
52 /* Initialize the spots as illegal */ | |
53 do { | |
54 spots[--index] = FALSE; | |
55 } while (index > 0); | |
56 | |
57 /* Find a suitable spot next to the player */ | |
58 for (y=hero.y-1; y<hero.y+2; y++) | |
59 for (x=hero.x-1; x<hero.x+2; x++, index++) { | |
60 /* Make sure x coordinate is in range and that we are | |
61 * not at the player's position | |
62 */ | |
63 if (x<0 || x >= cols || index == 4) continue; | |
64 | |
65 /* Is it OK to move there? */ | |
66 if (step_ok(y, x, NOMONST, tp) && | |
67 (!isatrap(mvwinch(cw, y, x)) || | |
68 rnd(10) >= tp->t_stats.s_intel || | |
69 on(*tp, ISFLY))) { | |
70 /* OK, we can go here. But don't go there if | |
71 * monster can't get at player from there | |
72 */ | |
73 tryp.y = y; | |
74 tryp.x = x; | |
75 if (diag_ok(&tryp, &hero, tp)) { | |
76 spots[index] = TRUE; | |
77 found_one = TRUE; | |
78 } | |
79 } | |
80 } | |
81 | |
82 /* If we found one, go to it */ | |
83 if (found_one) { | |
84 char rch; /* What's really where the creatures moves to */ | |
85 | |
86 /* Find a legal spot */ | |
87 while (spots[index=rnd(9)] == FALSE) continue; | |
88 | |
89 /* Get the coordinates */ | |
90 y = hero.y + (index/3) - 1; | |
91 x = hero.x + (index % 3) - 1; | |
92 | |
93 /* Move the monster from the old space */ | |
94 mvwaddch(cw, tp->t_pos.y, tp->t_pos.x, tp->t_oldch); | |
95 | |
96 /* Move it to the new space */ | |
97 tp->t_oldch = CCHAR( mvwinch(cw, y, x) ); | |
98 | |
99 /* Display the creature if our hero can see it */ | |
100 if (cansee(y, x) && | |
101 off(*tp, ISINWALL) && | |
102 !invisible(tp)) | |
103 mvwaddch(cw, y, x, tp->t_type); | |
104 | |
105 /* Fix the monster window */ | |
106 mvwaddch(mw, tp->t_pos.y, tp->t_pos.x, ' '); /* Clear old position */ | |
107 mvwaddch(mw, y, x, tp->t_type); | |
108 | |
109 /* Record the new position */ | |
110 tp->t_pos.y = y; | |
111 tp->t_pos.x = x; | |
112 | |
113 /* If the monster is on a trap, trap it */ | |
114 rch = CCHAR( mvinch(y, x) ); | |
115 if (isatrap(rch)) { | |
116 if (cansee(y, x)) tp->t_oldch = rch; | |
117 be_trapped(tp, &(tp->t_pos)); | |
118 } | |
119 } | |
120 | |
121 return(found_one); | |
122 } | |
123 | |
124 /* | |
125 * Can_shoot determines if the monster (er) has a direct line of shot | |
126 * at the prey (ee). If so, it returns the direction in which to shoot. | |
127 */ | |
128 | |
129 coord * | |
130 can_shoot(er, ee) | |
131 register coord *er, *ee; | |
132 { | |
133 static coord shoot_dir; | |
134 | |
135 /* | |
136 * They must be in the same room or very close (at door) | |
137 */ | |
138 if (roomin(er) != roomin(ee) && DISTANCE(er->y,er->x,ee->y,ee->x) > 1) | |
139 return(NULL); | |
140 | |
141 /* Do we have a straight shot? */ | |
142 if (!straight_shot(er->y, er->x, ee->y, ee->x, &shoot_dir)) return(NULL); | |
143 else return(&shoot_dir); | |
144 } | |
145 | |
146 /* | |
147 * chase: | |
148 * Find the spot for the chaser(er) to move closer to the | |
149 * chasee(ee). Rer is the room of the chaser, and ree is the | |
150 * room of the creature being chased (chasee). | |
151 */ | |
152 | |
153 chase(tp, ee, rer, ree, flee) | |
154 register struct thing *tp; | |
155 register coord *ee; | |
156 register struct room *rer, *ree; | |
157 bool flee; /* True if destination (ee) is player and monster is running away | |
158 * or the player is in a wall and the monster can't get to it | |
159 */ | |
160 { | |
161 int dist, thisdist, monst_dist = MAXINT; | |
162 register coord *er = &tp->t_pos; | |
163 struct thing *prey; /* What we are chasing */ | |
164 coord ch_ret; /* Where chasing takes you */ | |
165 char ch, mch; | |
166 bool next_player = FALSE; | |
167 | |
168 /* | |
169 * set the distance from the chas(er) to the chas(ee) here and then | |
170 * we won't have to reset it unless the chas(er) moves (instead of shoots) | |
171 */ | |
172 dist = DISTANCE(er->y, er->x, ee->y, ee->x); | |
173 | |
174 /* | |
175 * See if our destination is a monster or player. If so, make "prey" point | |
176 * to it. | |
177 */ | |
178 if (ce(hero, *ee)) prey = &player; /* Is it the player? */ | |
179 else if (tp->t_dest && ce(*(tp->t_dest), *ee)) { /* Is it a monster? */ | |
180 struct linked_list *item; | |
181 | |
182 /* What is the monster we're chasing? */ | |
183 item = find_mons(ee->y, ee->x); | |
184 if (item != NULL) prey = THINGPTR(item); | |
185 else prey = NULL; | |
186 } | |
187 else prey = NULL; | |
188 | |
189 /* We will use at least one movement period */ | |
190 tp->t_no_move = movement(tp); | |
191 if (on(*tp, ISFLY)) /* If the creature is flying, speed it up */ | |
192 tp->t_no_move /= 2; | |
193 | |
194 /* | |
195 * If the thing is confused or it can't see the player, | |
196 * let it move randomly. | |
197 */ | |
198 if ((on(*tp, ISHUH) && rnd(10) < 8) || | |
199 (prey && on(*prey, ISINVIS) && off(*tp, CANSEE))) { /* invisible prey */ | |
200 /* | |
201 * get a valid random move | |
202 */ | |
203 tp->t_newpos = *rndmove(tp); | |
204 dist = DISTANCE(tp->t_newpos.y, tp->t_newpos.x, ee->y, ee->x); | |
205 } | |
206 | |
207 /* | |
208 * Otherwise, find the empty spot next to the chaser that is | |
209 * closest to the chasee. | |
210 */ | |
211 else { | |
212 register int ey, ex, x, y; | |
213 int dist_to_old = MININT; /* Dist from goal to old position */ | |
214 | |
215 /* | |
216 * This will eventually hold where we move to get closer | |
217 * If we can't find an empty spot, we stay where we are. | |
218 */ | |
219 dist = flee ? 0 : MAXINT; | |
220 ch_ret = *er; | |
221 | |
222 /* Are we at our goal already? */ | |
223 if (!flee && ce(ch_ret, *ee)) { | |
224 turn_off(*tp, ISRUN); /* So stop running! */ | |
225 return; | |
226 } | |
227 | |
228 ey = er->y + 1; | |
229 ex = er->x + 1; | |
230 | |
231 /* Check all possible moves */ | |
232 for (x = er->x - 1; x <= ex; x++) { | |
233 if (x < 0 || x >= cols) /* Don't try off the board */ | |
234 continue; | |
235 for (y = er->y - 1; y <= ey; y++) { | |
236 coord tryp; | |
237 | |
238 if ((y < 1) || (y >= lines - 2)) /* Don't try off the board */ | |
239 continue; | |
240 | |
241 /* Don't try the player if not going after the player */ | |
242 if ((flee || !ce(hero, *ee) || on(*tp, ISFRIENDLY)) && | |
243 x == hero.x && y == hero.y) { | |
244 next_player = TRUE; | |
245 continue; | |
246 } | |
247 | |
248 tryp.x = x; | |
249 tryp.y = y; | |
250 | |
251 /* Is there a monster on this spot closer to our goal? | |
252 * Don't look in our spot or where we were. | |
253 */ | |
254 if (!ce(tryp, *er) && !ce(tryp, tp->t_oldpos) && | |
255 isalpha(mch = CCHAR( mvwinch(mw, y, x) ) )) { | |
256 int test_dist; | |
257 | |
258 test_dist = DISTANCE(y, x, ee->y, ee->x); | |
259 if (test_dist <= 25 && /* Let's be fairly close */ | |
260 test_dist < monst_dist) { | |
261 /* Could we really move there? */ | |
262 mvwaddch(mw, y, x, ' '); /* Temporarily blank monst */ | |
263 if (diag_ok(er, &tryp, tp)) monst_dist = test_dist; | |
264 mvwaddch(mw, y, x, mch); /* Restore monster */ | |
265 } | |
266 } | |
267 | |
268 /* Can we move onto the spot? */ | |
269 if (!diag_ok(er, &tryp, tp)) continue; | |
270 | |
271 ch = CCHAR( mvwinch(cw, y, x) ); /* Screen character */ | |
272 | |
273 /* | |
274 * Stepping on player is NOT okay if we are fleeing. | |
275 * If we are friendly to the player and there is a monster | |
276 * in the way that is not of our race, it is okay to move | |
277 * there. | |
278 */ | |
279 if (step_ok(y, x, FIGHTOK, tp) && | |
280 (off(*tp, ISFLEE) || ch != PLAYER)) | |
281 { | |
282 /* | |
283 * If it is a trap, an intelligent monster may not | |
284 * step on it (unless our hero is on top!) | |
285 */ | |
286 if ((isatrap(ch)) && | |
287 (rnd(10) < tp->t_stats.s_intel) && | |
288 (!on(*tp, ISFLY)) && | |
289 (y != hero.y || x != hero.x)) | |
290 continue; | |
291 | |
292 /* | |
293 * OK -- this place counts | |
294 */ | |
295 thisdist = DISTANCE(y, x, ee->y, ee->x); | |
296 | |
297 /* Adjust distance if we are being shot at */ | |
298 if (tp->t_wasshot && tp->t_stats.s_intel > 5 && | |
299 prey != NULL) { | |
300 /* Move out of line of sight */ | |
301 if (straight_shot(tryp.y, tryp.x, ee->y, ee->x, NULL)) { | |
302 if (flee) thisdist -= SHOTPENALTY; | |
303 else thisdist += SHOTPENALTY; | |
304 } | |
305 | |
306 /* But do we want to leave the room? */ | |
307 else if (rer && rer == ree && ch == DOOR) | |
308 thisdist += DOORPENALTY; | |
309 } | |
310 | |
311 /* Don't move to the last position if we can help it | |
312 * (unless out prey just moved there) | |
313 */ | |
314 if (ce(tryp, tp->t_oldpos) && (flee || !ce(tryp, hero))) | |
315 dist_to_old = thisdist; | |
316 | |
317 else if ((flee && (thisdist > dist)) || | |
318 (!flee && (thisdist < dist))) | |
319 { | |
320 ch_ret = tryp; | |
321 dist = thisdist; | |
322 } | |
323 } | |
324 } | |
325 } | |
326 | |
327 /* If we aren't trying to get the player, but he is in our way, | |
328 * hit him (unless we have been turned or are friendly). next_player | |
329 * being TRUE -> we are next to the player but don't want to hit him. | |
330 * | |
331 * If we are friendly to the player, following him, and standing next | |
332 * to him, we will try to help him out in battle. | |
333 */ | |
334 if (next_player && off(*tp, WASTURNED)) { | |
335 if (off(*tp, ISFRIENDLY) && | |
336 ((flee && ce(ch_ret, *er)) || | |
337 (!flee && DISTANCE(er->y, er->x, ee->y, ee->x) < dist)) && | |
338 step_ok(tp->t_dest->y, tp->t_dest->x, NOMONST, tp)) { | |
339 /* Okay to hit player */ | |
340 debug("Switching to hero."); | |
341 tp->t_newpos = hero; | |
342 tp->t_action = A_MOVE; | |
343 return; | |
344 } | |
345 else if (on(*tp, ISFRIENDLY) && !flee && ce(*ee, hero)) { | |
346 /* | |
347 * Look all around the player. If there is a fightable | |
348 * creature next to both of us, hit it. Otherwise, if | |
349 * there is a fightable creature next to the player, try | |
350 * to move next to it. | |
351 */ | |
352 dist = MAXINT; | |
353 for (x = hero.x - 1; x <= hero.x + 1; x++) { | |
354 if (x < 0 || x >= cols) /* Don't try off the board */ | |
355 continue; | |
356 for (y = hero.y - 1; y <= hero.y + 1; y++) { | |
357 if ((y < 1) || (y >= lines - 2)) /* Stay on the board */ | |
358 continue; | |
359 | |
360 /* Is there a fightable monster here? */ | |
361 if (isalpha(mvwinch(mw, y, x)) && | |
362 step_ok(y, x, FIGHTOK, tp) && | |
363 off(*tp, ISSTONE)) { | |
364 thisdist = DISTANCE(er->y, er->x, y, x); | |
365 if (thisdist < dist) { | |
366 dist = thisdist; | |
367 ch_ret.y = y; | |
368 ch_ret.x = x; | |