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; | |
369 } | |
370 } | |
371 } | |
372 } | |
373 | |
374 /* Are we next to a bad guy? */ | |
375 if (dist <= 2) { /* Get him! */ | |
376 tp->t_newpos = ch_ret; | |
377 tp->t_action = A_MOVE; | |
378 } | |
379 | |
380 /* Try to move to the bad guy */ | |
381 else if (dist < MAXINT) | |
382 chase(tp, &ch_ret, | |
383 roomin(&tp->t_pos), roomin(&ch_ret), FALSE); | |
384 | |
385 else tp->t_action = A_NIL; | |
386 | |
387 return; | |
388 } | |
389 } | |
390 | |
391 | |
392 /* | |
393 * If we have decided that we can move onto a monster (we are | |
394 * friendly to the player, go to it. | |
395 */ | |
396 if (!ce(ch_ret, *er) && isalpha(mvwinch(mw, ch_ret.y, ch_ret.x))) { | |
397 debug("Attack monster"); | |
398 tp->t_newpos = ch_ret; | |
399 tp->t_action = A_MOVE; | |
400 return; | |
401 } | |
402 | |
403 /* If we can't get closer to the player (if that's our goal) | |
404 * because other monsters are in the way, just stay put | |
405 */ | |
406 if (!flee && ce(hero, *ee) && monst_dist < MAXINT && | |
407 DISTANCE(er->y, er->x, hero.y, hero.x) < dist) { | |
408 tp->t_action = A_NIL; /* do nothing for awhile */ | |
409 return; | |
410 } | |
411 | |
412 /* Do we want to go back to the last position? */ | |
413 else if (dist_to_old != MININT && /* It is possible to move back */ | |
414 ((flee && dist == 0) || /* No other possible moves */ | |
415 (!flee && dist == MAXINT))) { | |
416 /* Do we move back or just stay put (default)? */ | |
417 dist = DISTANCE(er->y, er->x, ee->y, ee->x); /* Current distance */ | |
418 if (!flee || (flee && (dist_to_old > dist))) ch_ret = tp->t_oldpos; | |
419 } | |
420 | |
421 /* Record the new destination */ | |
422 tp->t_newpos = ch_ret; | |
423 } | |
424 | |
425 /* | |
426 * Do we want to fight or move? If our selected destination (ch_ret) | |
427 * is our hero, then we want to fight. Otherwise, we want to move. | |
428 */ | |
429 if (ce(tp->t_newpos, hero)) { | |
430 /* Fight! (or sell) */ | |
431 if (on(*tp, CANSELL)) { | |
432 tp->t_action = A_SELL; | |
433 tp->t_no_move += movement(tp); /* takes a little time to sell */ | |
434 } | |
435 else { | |
436 tp->t_action = A_ATTACK; | |
437 | |
438 /* | |
439 * Try to find a weapon to wield. Wield_weap will return a | |
440 * projector if weapon is a projectile (eg. bow for arrow). | |
441 * If weapon is NULL (the case here), it will try to find | |
442 * a suitable weapon. | |
443 * | |
444 * Add in rest of time. Fight is | |
445 * movement() + weap_move() + FIGHTBASE | |
446 */ | |
447 tp->t_using = wield_weap(NULL, tp); | |
448 if (tp->t_using == NULL) | |
449 tp->t_no_move += weap_move(tp, NULL); | |
450 else | |
451 tp->t_no_move += weap_move(tp, OBJPTR(tp->t_using)); | |
452 | |
453 if (on(*tp, ISHASTE)) | |
454 tp->t_no_move += FIGHTBASE/2; | |
455 else if (on(*tp, ISSLOW)) | |
456 tp->t_no_move += FIGHTBASE*2; | |
457 else | |
458 tp->t_no_move += FIGHTBASE; | |
459 } | |
460 } | |
461 else { | |
462 /* Move */ | |
463 tp->t_action = A_MOVE; | |
464 | |
465 /* | |
466 * Check if the creature is not next to the player. If it | |
467 * is not and has held or suffocated the player, then stop it! | |
468 * Note that this code should more appropriately appear in | |
469 * the area that actually moves the monster, but for now it | |
470 * is okay here because the player can't move while held or | |
471 * suffocating. | |
472 */ | |
473 if (dist > 2) { | |
474 if (on(*tp, DIDHOLD)) { | |
475 turn_off(*tp, DIDHOLD); | |
476 turn_on(*tp, CANHOLD); | |
477 if (--hold_count == 0) | |
478 turn_off(player, ISHELD); | |
479 } | |
480 | |
481 /* If monster was suffocating, stop it */ | |
482 if (on(*tp, DIDSUFFOCATE)) { | |
483 turn_off(*tp, DIDSUFFOCATE); | |
484 turn_on(*tp, CANSUFFOCATE); | |
485 extinguish(suffocate); | |
486 msg("You can breathe again.....Whew!"); | |
487 } | |
488 } | |
489 } | |
490 } | |
491 | |
492 /* | |
493 * do_chase: | |
494 * Make one thing chase another. | |
495 */ | |
496 | |
497 do_chase(th) | |
498 register struct thing *th; | |
499 { | |
500 register struct room *orig_rer, /* Original room of chaser */ | |
501 *new_room; /* new room of monster */ | |
502 char floor, rch, sch; | |
503 coord old_pos, /* Old position of monster */ | |
504 ch_ret; /* Where we want to go */ | |
505 | |
506 if (on(*th, NOMOVE)) return; | |
507 | |
508 ch_ret = th->t_newpos; /* Record our desired new position */ | |
509 | |
510 /* | |
511 * Make sure we have an open spot (no other monster's gotten in our way, | |
512 * someone didn't just drop a scare monster there, our prey didn't just | |
513 * get there, etc.) | |
514 */ | |
515 if (!step_ok(th->t_newpos.y, th->t_newpos.x, FIGHTOK, th)) { | |
516 /* | |
517 * Most monsters get upset now. Guardians are all friends, | |
518 * and we don't want to see 50 messages in a row! | |
519 */ | |
520 if (th->t_stats.s_intel > 4 && | |
521 off(*th, ISUNDEAD) && | |
522 off(*th, ISGUARDIAN) && | |
523 off(*th, AREMANY) && | |
524 off(*th, ISHUH) && | |
525 off(player, ISBLIND) && | |
526 cansee(unc(th->t_pos)) && | |
527 !invisible(th)) | |
528 msg("%s motions angrily.", prname(monster_name(th), TRUE)); | |
529 return; | |
530 } | |
531 else if (ce(th->t_newpos, hero) || /* Player just got in our way */ | |
532 isalpha(mvwinch(mw, th->t_newpos.y, th->t_newpos.x))) { | |
533 bool fightplayer = ce(th->t_newpos, hero); | |
534 | |
535 /* If we were turned or are friendly, we just have to sit here! */ | |
536 if (fightplayer && (on(*th, WASTURNED) || on(*th, ISFRIENDLY))) return; | |
537 | |
538 /* Do we want to sell something? */ | |
539 if (fightplayer && on(*th, CANSELL)) { | |
540 th->t_action = A_SELL; | |
541 th->t_no_move += movement(th); /* takes a little time to sell */ | |
542 return; | |
543 } | |
544 | |
545 /* Let's hit him */ | |
546 th->t_action = A_ATTACK; | |
547 | |
548 /* | |
549 * Try to find a weapon to wield. Wield_weap will return a | |
550 * projector if weapon is a projectile (eg. bow for arrow). | |
551 * If weapon is NULL (the case here), it will try to find | |
552 * a suitable weapon. | |
553 */ | |
554 th->t_using = wield_weap(NULL, th); | |
555 /* | |
556 * add in rest of time | |
557 */ | |
558 if (th->t_using == NULL) | |
559 th->t_no_move += weap_move(th, NULL); | |
560 else | |
561 th->t_no_move += weap_move(th, OBJPTR(th->t_using)); | |
562 if (on(*th, ISHASTE)) | |
563 th->t_no_move += FIGHTBASE/2; | |
564 else if (on(*th, ISSLOW)) | |
565 th->t_no_move += FIGHTBASE*2; | |
566 else | |
567 th->t_no_move += FIGHTBASE; | |
568 return; | |
569 } | |
570 | |
571 /* | |
572 * Blank out the old position and record the new position -- | |
573 * the blanking must be done first in case the positions are the same. | |
574 */ | |
575 mvwaddch(mw, th->t_pos.y, th->t_pos.x, ' '); | |
576 mvwaddch(mw, ch_ret.y, ch_ret.x, th->t_type); | |
577 | |
578 /* Get new and old rooms of monster */ | |
579 new_room = roomin(&ch_ret); | |
580 orig_rer = roomin(&th->t_pos); | |
581 | |
582 /* Store the critter's old position and update the current one */ | |
583 old_pos = th->t_pos; | |
584 th->t_pos = ch_ret; | |
585 floor = (roomin(&ch_ret) == NULL) ? PASSAGE : FLOOR; | |
586 | |
587 /* If we have a scavenger, it can pick something up */ | |
588 if (off(*th, ISGUARDIAN)) { | |
589 register struct linked_list *n_item, *o_item; | |
590 register int item_count = 0; | |
591 bool want_something = FALSE; | |
592 | |
593 while ((n_item = find_obj(ch_ret.y, ch_ret.x)) != NULL) { | |
594 register struct object *n_obj, *o_obj; | |
595 bool wants_it; | |
596 | |
597 /* Does this monster want anything? */ | |
598 if (want_something == FALSE) { | |
599 if (on(*th, ISSCAVENGE) || on(*th, CARRYFOOD) || | |
600 on(*th, CARRYGOLD) || on(*th, CARRYSCROLL) || | |
601 on(*th, CARRYPOTION) || on(*th, CARRYRING) || | |
602 on(*th, CARRYSTICK) || on(*th, CARRYMISC) || | |
603 on(*th, CARRYWEAPON) || on(*th, CARRYARMOR) || | |
604 on(*th, CARRYDAGGER)) { | |
605 want_something = TRUE; | |
606 | |
607 /* | |
608 * Blank the area. We have to do it only before the | |
609 * first item in case an item gets dropped in same | |
610 * place. We don't want to blank it out after it get | |
611 * dropped. | |
612 */ | |
613 mvaddch(ch_ret.y, ch_ret.x, floor); | |
614 | |
615 /* Were we specifically after something here? */ | |
616 if (ce(*th->t_dest, ch_ret)) { | |
617 /* If we're mean, we go after the hero */ | |
618 if (on(*th, ISMEAN)) runto(th, &hero); | |
619 | |
620 /* Otherwise just go back to sleep */ | |
621 else { | |
622 turn_off(*th, ISRUN); | |
623 th->t_dest = NULL; | |
624 } | |
625 } | |
626 } | |
627 else break; | |
628 } | |
629 | |
630 item_count++; /* Count the number of items */ | |
631 | |
632 /* | |
633 * see if he's got one of this group already | |
634 */ | |
635 o_item = NULL; | |
636 n_obj = OBJPTR(n_item); | |
637 detach(lvl_obj, n_item); | |
638 | |
639 /* See if he wants it */ | |
640 if (n_obj->o_type == SCROLL && n_obj->o_which == S_SCARE && | |
641 th->t_stats.s_intel < 16) | |
642 wants_it = FALSE; /* Most monsters don't want a scare monster */ | |
643 else if (on(*th, ISSCAVENGE)) wants_it = TRUE; | |
644 else { | |
645 wants_it = FALSE; /* Default case */ | |
646 switch (n_obj->o_type) { | |
647 case FOOD: if(on(*th, CARRYFOOD)) wants_it = TRUE; | |
648 when GOLD: if(on(*th, CARRYGOLD)) wants_it = TRUE; | |
649 when SCROLL:if(on(*th, CARRYSCROLL)) wants_it = TRUE; | |
650 when POTION:if(on(*th, CARRYPOTION)) wants_it = TRUE; | |
651 when RING: if(on(*th, CARRYRING)) wants_it = TRUE; | |
652 when STICK: if(on(*th, CARRYSTICK)) wants_it = TRUE; | |
653 when MM: if(on(*th, CARRYMISC)) wants_it = TRUE; | |
654 when ARMOR: if(on(*th, CARRYARMOR)) wants_it = TRUE; | |
655 when WEAPON:if(on(*th, CARRYWEAPON) || | |
656 (on(*th,CARRYDAGGER)&&n_obj->o_which==DAGGER)) | |
657 wants_it = TRUE; | |
658 } | |
659 } | |
660 /* | |
661 * The quartermaster doesn't sell cursed stuff so he won't | |
662 * pick it up | |
663 */ | |
664 if (on(*th, CANSELL) && (n_obj->o_flags & ISCURSED)) | |
665 wants_it = FALSE; | |
666 | |
667 /* If he doesn't want it, throw it away */ | |
668 if (wants_it == FALSE) { | |
669 fall(n_item, FALSE); | |
670 continue; | |
671 } | |
672 | |
673 /* Otherwise, let's pick it up */ | |
674 if (n_obj->o_group) { | |
675 for(o_item = th->t_pack; o_item != NULL; o_item = next(o_item)){ | |
676 o_obj = OBJPTR(o_item); | |
677 if (o_obj->o_group == n_obj->o_group) { | |
678 o_obj->o_count += n_obj->o_count; | |
679 o_discard(n_item); | |
680 break; | |
681 } | |
682 } | |
683 } | |
684 if (o_item == NULL) { /* didn't find it */ | |
685 attach(th->t_pack, n_item); | |
686 } | |
687 } | |
688 | |
689 /* If there was anything here, we may have to update the screen */ | |
690 if (item_count) { | |
691 if (cansee(ch_ret.y, ch_ret.x)) | |
692 mvwaddch(cw, ch_ret.y, ch_ret.x, mvinch(ch_ret.y, ch_ret.x)); | |
693 updpack(TRUE, th); /* Update the monster's encumberance, too */ | |
694 } | |
695 } | |
696 | |
697 | |
698 rch = CCHAR( mvwinch(stdscr, old_pos.y, old_pos.x) ); | |
699 if (th->t_oldch == floor && rch != floor && !isatrap(rch)) | |
700 mvwaddch(cw, old_pos.y, old_pos.x, rch); | |
701 else | |
702 mvwaddch(cw, old_pos.y, old_pos.x, th->t_oldch); | |
703 sch = CCHAR( mvwinch(cw, ch_ret.y, ch_ret.x) ); /* What player sees */ | |
704 rch = CCHAR( mvwinch(stdscr, ch_ret.y, ch_ret.x) ); /* What's really there */ | |
705 | |
706 /* If we have a tunneling monster, it may be making a tunnel */ | |
707 if (on(*th, CANTUNNEL) && | |
708 (rch == SECRETDOOR || rch == WALL || rch == '|' || rch == '-')) { | |
709 char nch; /* The new look to the tunnel */ | |
710 | |
711 if (rch == WALL) nch = PASSAGE; | |
712 else if (levtype == MAZELEV) nch = FLOOR; | |
713 else nch = DOOR; | |
714 addch(nch); | |
715 | |
716 if (cansee(ch_ret.y, ch_ret.x)) sch = nch; /* Can player see this? */ | |
717 | |
718 /* Does this make a new exit? */ | |
719 if (rch == '|' || rch == '-') { | |
720 struct linked_list *newroom; | |
721 coord *exit; | |
722 | |
723 newroom = new_item(sizeof(coord)); | |
724 exit = DOORPTR(newroom); | |
725 *exit = ch_ret; | |
726 attach(new_room->r_exit, newroom); | |
727 } | |
728 } | |
729 | |
730 /* Mark if the monster is inside a wall */ | |
731 if (isrock(mvinch(ch_ret.y, ch_ret.x))) turn_on(*th, ISINWALL); | |
732 else turn_off(*th, ISINWALL); | |
733 | |
734 /* If the monster can illuminate rooms, check for a change */ | |
735 if (on(*th, HASFIRE)) { | |
736 register struct linked_list *fire_item; | |
737 | |
738 /* Is monster entering a room? */ | |
739 if (orig_rer != new_room && new_room != NULL) { | |
740 fire_item = creat_item(); /* Get an item-only structure */ | |
741 ldata(fire_item) = (char *) th; | |
742 | |
743 attach(new_room->r_fires, fire_item); | |
744 new_room->r_flags |= HASFIRE; | |
745 | |
746 if (cansee(ch_ret.y, ch_ret.x) && next(new_room->r_fires) == NULL) | |
747 light(&hero); | |
748 } | |
749 | |
750 /* Is monster leaving a room? */ | |
751 if (orig_rer != new_room && orig_rer != NULL) { | |
752 /* Find the bugger in the list and delete him */ | |
753 for (fire_item = orig_rer->r_fires; fire_item != NULL; | |
754 fire_item = next(fire_item)) { | |
755 if (THINGPTR(fire_item) == th) { /* Found him! */ | |
756 detach(orig_rer->r_fires, fire_item); | |
757 destroy_item(fire_item); | |
758 if (orig_rer->r_fires == NULL) { | |
759 orig_rer->r_flags &= ~HASFIRE; | |
760 if (cansee(old_pos.y, old_pos.x)) | |
761 light(&old_pos); | |
762 } | |
763 break; | |
764 } | |
765 } | |
766 } | |
767 } | |
768 | |
769 /* If monster is entering player's room and player can see it, | |
770 * stop the player's running. | |
771 */ | |
772 if (new_room != orig_rer && new_room != NULL && | |
773 new_room == roomin(th->t_dest) && cansee(unc(ch_ret)) && | |
774 (off(*th, ISINVIS) || on(player, CANSEE)) && | |
775 (off(*th, ISSHADOW) || on(player, CANSEE)) && | |
776 (off(*th, CANSURPRISE) || ISWEARING(R_ALERT))) { | |
777 running = FALSE; | |
778 if (fight_flush) md_flushinp(); | |
779 } | |
780 | |
781 th->t_oldch = sch; | |
782 | |
783 /* Let's display those creatures that we can see. */ | |
784 if (cansee(unc(ch_ret)) && | |
785 off(*th, ISINWALL) && | |
786 !invisible(th)) | |
787 mvwaddch(cw, ch_ret.y, ch_ret.x, th->t_type); | |
788 | |
789 /* Record monster's last position (if new one is different) */ | |
790 if (!ce(ch_ret, old_pos)) th->t_oldpos = old_pos; | |
791 | |
792 /* If the monster is on a trap, trap it */ | |
793 sch = CCHAR( mvinch(ch_ret.y, ch_ret.x) ); | |
794 if (isatrap(sch)) { | |
795 if (cansee(ch_ret.y, ch_ret.x)) th->t_oldch = sch; | |
796 be_trapped(th, &ch_ret); | |
797 } | |
798 } | |
799 | |
800 | |
801 /* | |
802 * Get_hurl returns the weapon that the monster will "throw" if he has one | |
803 */ | |
804 | |
805 struct linked_list * | |
806 get_hurl(tp) | |
807 register struct thing *tp; | |
808 { | |
809 struct linked_list *arrow=NULL, *bolt=NULL, *rock=NULL, | |
810 *spear = NULL, *dagger=NULL, *dart=NULL, *aklad=NULL; | |
811 register struct linked_list *pitem; | |
812 register struct object *obj; | |
813 bool bow=FALSE, crossbow=FALSE, sling=FALSE; | |
814 | |
815 for (pitem=tp->t_pack; pitem; pitem=next(pitem)) { | |
816 obj = OBJPTR(pitem); | |
817 if (obj->o_type == WEAPON) | |
818 switch (obj->o_which) { | |
819 case BOW: bow = TRUE; | |
820 when CROSSBOW: crossbow = TRUE; | |
821 when SLING: sling = TRUE; | |
822 when ROCK: rock = pitem; | |
823 when ARROW: arrow = pitem; | |
824 when BOLT: bolt = pitem; | |
825 when SPEAR: spear = pitem; | |
826 when DAGGER: | |
827 /* Don't throw the dagger if it's our last one */ | |
828 if (obj->o_count > 1) dagger = pitem; | |
829 when DART: dart = pitem; | |
830 } | |
831 else if (obj->o_type == RELIC && | |
832 obj->o_which == AXE_AKLAD) | |
833 aklad = pitem; | |
834 } | |
835 | |
836 /* Do we have that all-powerful Aklad Axe? */ | |
837 if (aklad) return(aklad); | |
838 | |
839 /* Use crossbow bolt if possible */ | |
840 if (crossbow && bolt) return(bolt); | |
841 if (bow && arrow) return(arrow); | |
842 if (spear) return(spear); | |
843 if (dagger) return(dagger); | |
844 if (sling && rock) return(rock); | |
845 if (dart) return(dart); | |
846 return(NULL); | |
847 } | |
848 | |
849 /* | |
850 * runto: | |
851 * Set a monster running after something | |
852 */ | |
853 | |
854 runto(runner, spot) | |
855 register struct thing *runner; | |
856 coord *spot; | |
857 { | |
858 if (on(*runner, ISSTONE)) | |
859 return; | |
860 | |
861 /* If we are chasing a new creature, forget about thrown weapons */ | |
862 if (runner->t_dest && !ce(*runner->t_dest, *spot)) runner->t_wasshot=FALSE; | |
863 | |
864 /* | |
865 * Start the beastie running | |
866 */ | |
867 runner->t_dest = spot; | |
868 turn_on(*runner, ISRUN); | |
869 turn_off(*runner, ISDISGUISE); | |
870 } | |
871 | |
872 | |
873 | |
874 /* | |
875 * straight_shot: | |
876 * See if there is a straight line of sight between the two | |
877 * given coordinates. If shooting is not NULL, it is a pointer | |
878 * to a structure which should be filled with the direction | |
879 * to shoot (if there is a line of sight). If shooting, monsters | |
880 * get in the way. Otherwise, they do not. | |
881 */ | |
882 | |
883 bool | |
884 straight_shot(ery, erx, eey, eex, shooting) | |
885 register int ery, erx, eey, eex; | |
886 register coord *shooting; | |
887 { | |
888 register int dy, dx; /* Deltas */ | |
889 char ch; | |
890 | |
891 /* Does the monster have a straight shot at prey */ | |
892 if ((ery != eey) && (erx != eex) && | |
893 (abs(ery - eey) != abs(erx - eex))) return(FALSE); | |
894 | |
895 /* Get the direction to shoot */ | |
896 if (eey > ery) dy = 1; | |
897 else if (eey == ery) dy = 0; | |
898 else dy = -1; | |
899 | |
900 if (eex > erx) dx = 1; | |
901 else if (eex == erx) dx = 0; | |
902 else dx = -1; | |
903 | |
904 /* Make sure we have free area all the way to the player */ | |
905 ery += dy; | |
906 erx += dx; | |
907 while ((ery != eey) || (erx != eex)) { | |
908 switch (ch = CCHAR( winat(ery, erx) )) { | |
909 case '|': | |
910 case '-': | |
911 case WALL: | |
912 case DOOR: | |
913 case SECRETDOOR: | |
914 case FOREST: | |
915 return(FALSE); | |
916 default: | |
917 if (shooting && isalpha(ch)) return(FALSE); | |
918 } | |
919 ery += dy; | |
920 erx += dx; | |
921 } | |
922 | |
923 if (shooting) { /* If we are shooting -- put in the directions */ | |
924 shooting->y = dy; | |
925 shooting->x = dx; | |
926 } | |
927 return(TRUE); | |
928 } |