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;