comparison xrogue/chase.c @ 133:e6179860cb76

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