comparison arogue5/chase.c @ 63:0ed67132cf10

Import Advanced Rogue 5.8 from the Roguelike Restoration Project (r1490)
author elwin
date Thu, 09 Aug 2012 22:58:48 +0000
parents
children 56e748983fa8
comparison
equal deleted inserted replaced
62:0ef99244acb8 63:0ed67132cf10
1 /*
2 * Code for one object to chase another
3 *
4 * Advanced Rogue
5 * Copyright (C) 1984, 1985 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 #include <ctype.h>
16 #include <limits.h>
17 #include "curses.h"
18 #include "rogue.h"
19 #define MAXINT INT_MAX
20 #define MININT INT_MIN
21
22 coord ch_ret; /* Where chasing takes you */
23
24
25
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 (on(*tp, ISSLOW) && off(*tp, ISHASTE) && !(tp->t_turn)) ||
49 tp->t_no_move ||
50 (rnd(12) < 6)) return(FALSE);
51
52
53 /* Initialize the spots as illegal */
54 do {
55 spots[--index] = FALSE;
56 } while (index > 0);
57
58 /* Find a suitable spot next to the player */
59 for (y=hero.y-1; y<hero.y+2; y++)
60 for (x=hero.x-1; x<hero.x+2; x++, index++) {
61 /* Make sure x coordinate is in range and that we are
62 * not at the player's position
63 */
64 if (x<0 || x >= COLS || index == 4) continue;
65
66 /* Is it OK to move there? */
67 if (step_ok(y, x, NOMONST, tp) &&
68 (!isatrap(mvwinch(cw, y, x)) ||
69 rnd(10) >= tp->t_stats.s_intel ||
70 on(*tp, ISFLY))) {
71 /* OK, we can go here. But don't go there if
72 * monster can't get at player from there
73 */
74 tryp.y = y;
75 tryp.x = x;
76 if (diag_ok(&tryp, &hero, tp)) {
77 spots[index] = TRUE;
78 found_one = TRUE;
79 }
80 }
81 }
82
83 /* If we found one, go to it */
84 if (found_one) {
85 char rch; /* What's really where the creatures moves to */
86
87 /* Find a legal spot */
88 while (spots[index=rnd(9)] == FALSE) continue;
89
90 /* Get the coordinates */
91 y = hero.y + (index/3) - 1;
92 x = hero.x + (index % 3) - 1;
93
94 /* Move the monster from the old space */
95 mvwaddch(cw, tp->t_pos.y, tp->t_pos.x, tp->t_oldch);
96
97 /* Move it to the new space */
98 tp->t_oldch = CCHAR( mvwinch(cw, y, x) );
99
100 /* Display the creature if our hero can see it */
101 if (cansee(y, x) &&
102 off(*tp, ISINWALL) &&
103 !invisible(tp))
104 mvwaddch(cw, y, x, tp->t_type);
105
106 /* Fix the monster window */
107 mvwaddch(mw, tp->t_pos.y, tp->t_pos.x, ' '); /* Clear old position */
108 mvwaddch(mw, y, x, tp->t_type);
109
110 /* Record the new position */
111 tp->t_pos.y = y;
112 tp->t_pos.x = x;
113
114 /* If the monster is on a trap, trap it */
115 rch = CCHAR( mvinch(y, x) );
116 if (isatrap(rch)) {
117 if (cansee(y, x)) tp->t_oldch = rch;
118 be_trapped(tp, &(tp->t_pos));
119 }
120 }
121
122 return(found_one);
123 }
124
125 /*
126 * Can_shoot determines if the monster (er) has a direct line of shot
127 * at the player (ee). If so, it returns the direction in which to shoot.
128 */
129
130 coord *
131 can_shoot(er, ee)
132 register coord *er, *ee;
133 {
134 static coord shoot_dir;
135
136 /* Make sure we are chasing the player */
137 if (!ce((*ee), hero)) return(NULL);
138
139 /*
140 * They must be in the same room or very close (at door)
141 */
142 if (roomin(er) != roomin(&hero) && DISTANCE(er->y,er->x,ee->y,ee->x) > 1)
143 return(NULL);
144
145 /* Do we have a straight shot? */
146 if (!straight_shot(er->y, er->x, ee->y, ee->x, &shoot_dir)) return(NULL);
147 else return(&shoot_dir);
148 }
149
150 /*
151 * chase:
152 * Find the spot for the chaser(er) to move closer to the
153 * chasee(ee). Returns TRUE if we want to keep on chasing later
154 * FALSE if we reach the goal.
155 */
156
157 chase(tp, ee, flee, mdead)
158 register struct thing *tp;
159 register coord *ee;
160 bool flee; /* True if destination (ee) is player and monster is running away
161 * or the player is in a wall and the monster can't get to it
162 */
163 bool *mdead;
164 {
165 int damage, dist, thisdist, monst_dist = MAXINT;
166 struct linked_list *weapon;
167 register coord *er = &tp->t_pos;
168 coord *shoot_dir;
169 char ch, mch;
170 bool next_player = FALSE;
171
172 if (mdead != NULL)
173 *mdead = 0;
174
175 /*
176 * set the distance from the chas(er) to the chas(ee) here and then
177 * we won't have to reset it unless the chas(er) moves (instead of shoots)
178 */
179 dist = DISTANCE(er->y, er->x, ee->y, ee->x);
180
181 /*
182 * If the thing is confused or it can't see the player,
183 * let it move randomly.
184 */
185 if ((on(*tp, ISHUH) && rnd(10) < 8) ||
186 (on(player, ISINVIS) && off(*tp, CANSEE))) { /* Player is invisible */
187 /*
188 * get a valid random move
189 */
190 ch_ret = *rndmove(tp);
191 dist = DISTANCE(ch_ret.y, ch_ret.x, ee->y, ee->x);
192 /*
193 * check to see if random move takes creature away from player
194 * if it does then turn off ISHELD
195 */
196 if (dist > 2) {
197 if (on(*tp, DIDHOLD)) {
198 turn_off(*tp, DIDHOLD);
199 turn_on(*tp, CANHOLD);
200 if (--hold_count == 0)
201 turn_off(player, ISHELD);
202 }
203
204 /* If monster was suffocating, stop it */
205 if (on(*tp, DIDSUFFOCATE)) {
206 turn_off(*tp, DIDSUFFOCATE);
207 turn_on(*tp, CANSUFFOCATE);
208 extinguish(suffocate);
209 }
210 }
211 }
212
213 /* If we can breathe, we may do so */
214 else if (on(*tp, CANBREATHE) &&
215 (dist < BOLT_LENGTH*BOLT_LENGTH) &&
216 (shoot_dir = can_shoot(er, ee)) &&
217 !on(player, ISINWALL) &&
218 (rnd(100) < 75)) {
219 register char *breath = NULL;
220
221 damage = tp->t_stats.s_hpt;
222 /* Will it breathe at random */
223 if (on(*tp, CANBRANDOM)) {
224 /* Turn off random breath */
225 turn_off(*tp, CANBRANDOM);
226
227 /* Select type of breath */
228 switch (rnd(10)) {
229 case 0: breath = "acid";
230 turn_on(*tp, NOACID);
231 when 1: breath = "flame";
232 turn_on(*tp, NOFIRE);
233 when 2: breath = "lightning bolt";
234 turn_on(*tp, NOBOLT);
235 when 3: breath = "chlorine gas";
236 turn_on(*tp, NOGAS);
237 when 4: breath = "ice";
238 turn_on(*tp, NOCOLD);
239 when 5: breath = "nerve gas";
240 turn_on(*tp, NOPARALYZE);
241 when 6: breath = "sleeping gas";
242 turn_on(*tp, NOSLEEP);
243 when 7: breath = "slow gas";
244 turn_on(*tp, NOSLOW);
245 when 8: breath = "confusion gas";
246 turn_on(*tp, ISCLEAR);
247 when 9: breath = "fear gas";
248 turn_on(*tp, NOFEAR);
249 }
250 }
251
252 /* Or can it breathe acid? */
253 else if (on(*tp, CANBACID)) {
254 turn_off(*tp, CANBACID);
255 breath = "acid";
256 }
257
258 /* Or can it breathe fire */
259 else if (on(*tp, CANBFIRE)) {
260 turn_off(*tp, CANBFIRE);
261 breath = "flame";
262 }
263
264 /* Or can it breathe electricity? */
265 else if (on(*tp, CANBBOLT)) {
266 turn_off(*tp, CANBBOLT);
267 breath = "lightning bolt";
268 }
269
270 /* Or can it breathe gas? */
271 else if (on(*tp, CANBGAS)) {
272 turn_off(*tp, CANBGAS);
273 breath = "chlorine gas";
274 }
275
276 /* Or can it breathe ice? */
277 else if (on(*tp, CANBICE)) {
278 turn_off(*tp, CANBICE);
279 breath = "ice";
280 }
281
282 else if (on(*tp, CANBPGAS)) {
283 turn_off(*tp, CANBPGAS);
284 breath = "nerve gas";
285 }
286
287 /* can it breathe sleeping gas */
288 else if (on(*tp, CANBSGAS)) {
289 turn_off(*tp, CANBSGAS);
290 breath = "sleeping gas";
291 }
292
293 /* can it breathe slow gas */
294 else if (on(*tp, CANBSLGAS)) {
295 turn_off(*tp, CANBSLGAS);
296 breath = "slow gas";
297 }
298 /* can it breathe confusion gas */
299 else if (on(*tp, CANBCGAS)) {
300 turn_off(*tp, CANBCGAS);
301 breath = "confusion gas";
302 }
303 /* can it breathe fear gas */
304 else {
305 turn_off(*tp, CANBFGAS);
306 breath = "fear gas";
307 }
308
309 /* Now breathe -- sets "monst_dead" if it kills someone */
310 *mdead = shoot_bolt( tp, *er, *shoot_dir, FALSE,
311 tp->t_index, breath, damage);
312
313 ch_ret = *er;
314 running = FALSE;
315 if (*mdead) return(TRUE);
316 }
317
318 /* We may shoot missiles if we can */
319 else if (on(*tp, CANMISSILE) &&
320 (shoot_dir = can_shoot(er, ee)) &&
321 !on(player, ISINWALL) &&
322 (rnd(100) < 75)) {
323 static struct object missile =
324 {
325 MISSILE, {0, 0}, "", 0, "", "0d4 " , NULL, 0, WS_MISSILE, 100, 1
326 };
327
328 sprintf(missile.o_hurldmg, "%dd4", tp->t_stats.s_lvl);
329 do_motion(&missile, shoot_dir->y, shoot_dir->x, tp);
330 hit_monster(unc(missile.o_pos), &missile, tp);
331 turn_off(*tp, CANMISSILE);
332 ch_ret = *er;
333 running = FALSE;
334 }
335
336 /* We may use a sonic blast if we can */
337 else if (on(*tp, CANSONIC) &&
338 (dist < BOLT_LENGTH*2) &&
339 (shoot_dir = can_shoot(er, ee)) &&
340 !on(player, ISINWALL) &&
341 (rnd(100) < 50)) {
342 static struct object blast =
343 {
344 MISSILE, {0, 0}, "", 0, "", "150" , NULL, 0, 0, 0, 0
345 };
346
347 turn_off(*tp, CANSONIC);
348 do_motion(&blast, shoot_dir->y, shoot_dir->x, tp);
349 damage = 150;
350 if (save(VS_BREATH, &player, -3))
351 damage /= 2;
352 msg ("The %s's sonic blast hits you", monsters[tp->t_index].m_name);
353 if ((pstats.s_hpt -= damage) <= 0)
354 death(tp->t_index);
355 ch_ret = *er;
356 running = FALSE;
357 }
358 /*
359 * If we have a special magic item, we might use it. We will restrict
360 * this options to uniques with relics for now.
361 */
362 else if (on(*tp, ISUNIQUE) && m_use_item(tp, er, ee)) {
363 ch_ret = *er;
364 running = FALSE;
365 }
366 /*
367 * If we can shoot or throw something, we might do so.
368 * If next to player, then 80% prob will fight.
369 */
370 else if(on(*tp, CANSHOOT) &&
371 (shoot_dir = can_shoot(er, ee)) &&
372 !on(player, ISINWALL) &&