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 }