comparison urogue/chase.c @ 256:c495a4f288c6

Import UltraRogue from the Roguelike Restoration Project (r1490)
author John "Elwin" Edwards
date Tue, 31 Jan 2017 19:56:04 -0500
parents
children 0250220d8cdd
comparison
equal deleted inserted replaced
253:d9badb9c0179 256:c495a4f288c6
1 /*
2 chase.c - Code for one creature to chase another
3
4 UltraRogue: The Ultimate Adventure in the Dungeons of Doom
5 Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
6 All rights reserved.
7
8 Based on "Advanced Rogue"
9 Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
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 <stdlib.h>
20 #include <ctype.h>
21 #include <limits.h>
22 #include "rogue.h"
23
24 /*
25 do_chase()
26 Make one thing chase another.
27 */
28
29 void
30 do_chase(struct thing *th, int flee)
31 {
32 struct room *rer; /* room of chaser */
33 struct room *ree; /* room of chasee */
34 struct room *old_room; /* old room of monster */
35 struct room *new_room; /* new room of monster */
36
37 int i, mindist = INT_MAX, maxdist = INT_MIN, dist = INT_MIN;
38
39 int last_door = -1; /* Door we just came from */
40 int stoprun = FALSE; /* TRUE means we are there */
41 int rundoor; /* TRUE means run to a door */
42 int hit_bad = FALSE; /* TRUE means hit bad monster */
43 int mon_attack; /* TRUE means find a monster to hit */
44
45 char sch;
46 struct linked_list *item;
47 coord this; /* Temporary destination for chaser */
48
49 if (!th->t_ischasing)
50 return;
51
52 /* Make sure the monster can move */
53
54 if (th->t_no_move != 0)
55 {
56 th->t_no_move--;
57 return;
58 }
59
60 /*
61 * Bad monsters check for a good monster to hit, friendly monsters
62 * check for a bad monster to hit.
63 */
64
65 mon_attack = FALSE;
66
67 if (good_monster(*th))
68 {
69 hit_bad = TRUE;
70 mon_attack = TRUE;
71 }
72 else if (on(*th, ISMEAN))
73 {
74 hit_bad = FALSE;
75 mon_attack = TRUE;
76 }
77
78 if (mon_attack)
79 {
80 struct linked_list *mon_to_hit;
81
82 mon_to_hit = f_mons_a(th->t_pos.y, th->t_pos.x, hit_bad);
83
84 if (mon_to_hit)
85 {
86 mon_mon_attack(th, mon_to_hit, pick_weap(th), NOTHROWN);
87 return;
88 }
89 }
90
91 /* no nearby monster to hit */
92
93 rer = roomin(th->t_pos); /* Find room of chaser */
94 ree = roomin(th->t_chasee->t_pos); /* Find room of chasee */
95
96 /*
97 * We don't count doors as inside rooms for this routine
98 */
99
100 if (mvwinch(stdscr, th->t_pos.y, th->t_pos.x) == DOOR)
101 rer = NULL;
102
103 this = th->t_chasee->t_pos;
104
105 /*
106 * If we are not in a corridor and not a phasing monster, then if we
107 * are running after the player, we run to a door if he is not in the
108 * same room. If we are fleeing, we run to a door if he IS in the
109 * same room. Note: We don't bother with doors in mazes. Phasing
110 * monsters don't need to look for doors. There are no doors in mazes
111 * and throne rooms.
112 */
113
114 if (levtype != MAZELEV && levtype != THRONE && rer != NULL && off(*th, CANINWALL))
115 {
116 if (flee)
117 rundoor = (rer == ree);
118 else
119 rundoor = (rer != ree);
120 }
121 else
122 rundoor = FALSE;
123
124 if (rundoor)
125 {
126 coord d_exit; /* A particular door */
127 int exity, exitx; /* Door's coordinates */
128
129 if (th->t_doorgoal != -1)
130 { /* Do we already have the goal? */
131 this = rer->r_exit[th->t_doorgoal];
132 dist = 0; /* Indicate that we have our door */
133 }
134 else
135 for (i = 0; i < rer->r_nexits; i++)
136 { /* Loop through doors */
137 d_exit = rer->r_exit[i];
138 exity = d_exit.y;
139 exitx = d_exit.x;
140
141 /* Avoid secret doors */
142 if (mvwinch(stdscr, exity, exitx) == DOOR)
143 {
144 /* Were we just on this door? */
145 if (ce(d_exit, th->t_oldpos))
146 last_door = i;
147 else
148 {
149 dist = DISTANCE(th->t_chasee->t_pos, d_exit);
150
151 /*
152 * If fleeing, we want to
153 * maximize distance from
154 * door to what we flee, and
155 * minimize distance from
156 * door to us.
157 */
158
159 if (flee)
160 dist-=DISTANCE(th->t_pos,d_exit);
161
162 /*
163 * Maximize distance if
164 * fleeing, otherwise
165 * minimize it
166 */
167
168 if ((flee && (dist > maxdist)) ||
169 (!flee && (dist < mindist)))
170 {
171 th->t_doorgoal = i; /* Use this door */
172 this = d_exit;
173 mindist = maxdist = dist;
174 }
175 }
176 }
177 }
178
179 /* Could we not find a door? */
180 if (dist == INT_MIN)
181 {
182 /* If we were on a door, go ahead and use it */
183 if (last_door != -1)
184 {
185 th->t_doorgoal = last_door;
186 this = th->t_oldpos;
187 dist = 0; /* Indicate that we found a door */
188 }
189 }
190
191 /* Indicate that we do not want to flee from the door */
192 if (dist != INT_MIN)
193 flee = FALSE;
194 }
195 else
196 th->t_doorgoal = -1; /* Not going to any door */
197
198 /*
199 * this now contains what we want to run to this time so we run to
200 * it. If we hit it we either want to fight it or stop running
201 */
202
203 if (!chase(th, &this, flee))
204 {
205 if (ce(th->t_nxtpos, hero))
206 {
207 /* merchants try to sell something */
208
209 if (on(*th, CANSELL))
210 {
211 sell(th);
212 return;
213 }
214 else if (off(*th, ISFRIENDLY) && off(*th, ISCHARMED)
215 && (off(*th, CANFLY) || (on(*th, CANFLY) && rnd(2))))
216 attack(th, pick_weap(th), FALSE);
217 return;
218 }
219 else if (on(*th, NOMOVE))
220 stoprun = TRUE;
221 }
222
223 if (!curr_mons)
224 return; /* Did monster get itself killed? */
225
226 if (on(*th, NOMOVE))
227 return;
228
229 /* If we have a scavenger, it can pick something up */
230
231 if ((item = find_obj(th->t_nxtpos.y, th->t_nxtpos.x)) != NULL)
232 {
233 struct linked_list *node, *top = item;
234 struct object *obt;
235
236 while(top)
237 {
238 /* grab all objects that qualify */
239
240 struct object *obj = OBJPTR(item);
241
242 obt = OBJPTR(top);
243 node = obt->next_obj;
244
245 if (on(*th, ISSCAVENGE) ||
246 ((on(*th, CANWIELD) || on(*th, CANSHOOT)) &&
247 (obj->o_type == WEAPON || obj->o_type == ARMOR)) ||
248 (on(*th, CANCAST) && is_magic(obj)))
249 {
250 rem_obj(top, FALSE);
251 attach(th->t_pack, top);
252 }
253
254 top = node;
255 }
256
257 light(&hero);
258 }
259
260 mvwaddch(cw, th->t_pos.y, th->t_pos.x, th->t_oldch);
261 sch = CCHAR( mvwinch(cw, th->t_nxtpos.y, th->t_nxtpos.x) );
262
263 /* Get old and new room of monster */
264 old_room = roomin(th->t_pos);
265 new_room = roomin(th->t_nxtpos);
266
267 /* If the monster can illuminate rooms, check for a change */
268 if (on(*th, HASFIRE))
269 {
270 /* Is monster entering a room? */
271 if (old_room != new_room && new_room != NULL)
272 {
273 new_room->r_flags |= HASFIRE;
274 new_room->r_fires++;
275 if (cansee(th->t_nxtpos.y, th->t_nxtpos.x) && new_room->r_fires==1)
276 light(&hero);
277 }
278
279 /* Is monster leaving a room? */
280 if (old_room != new_room && old_room != NULL)
281 {
282 if (--(old_room->r_fires) <= 0)
283 {
284 old_room->r_flags &= ~HASFIRE;
285 if (cansee(th->t_pos.y, th->t_pos.x))
286 light(&th->t_pos);
287 }
288 }
289 }
290
291 /*
292 * If monster is entering player's room and player can see it, stop
293 * the player's running.
294 */
295
296 if (new_room != old_room && new_room != NULL &&
297 new_room == ree && cansee(th->t_nxtpos.y, th->t_nxtpos.x) &&
298 (off(*th, ISINVIS) || (off(*th, ISSHADOW) || rnd(10) == 0) ||
299 on(player, CANSEE)) && off(*th, CANSURPRISE))
300 running = FALSE;
301
302 if (rer != NULL && (rer->r_flags & ISDARK) &&
303 !(rer->r_flags & HASFIRE) && sch == FLOOR &&
304 DISTANCE(th->t_nxtpos, th->t_pos) < see_dist &&
305 off(player, ISBLIND))
306 th->t_oldch = ' ';
307 else
308 th->t_oldch = sch;
309
310 if (cansee(th->t_nxtpos.y, th->t_nxtpos.x) &&
311 off(*th, ISINWALL) &&
312 ((off(*th, ISINVIS) && (off(*th, ISSHADOW) || rnd(100) < 10)) ||
313 on(player, CANSEE)) &&
314 off(*th, CANSURPRISE))
315 mvwaddch(cw, th->t_nxtpos.y, th->t_nxtpos.x, th->t_type);
316
317 mvwaddch(mw, th->t_pos.y, th->t_pos.x, ' ');
318 mvwaddch(mw, th->t_nxtpos.y, th->t_nxtpos.x, th->t_type);
319
320 /* Record monster's last position (if new one is different) */
321
322 if (!ce(th->t_nxtpos, th->t_pos))
323 th->t_oldpos = th->t_pos;
324
325 th->t_pos = th->t_nxtpos; /* Mark the monster's new position */
326
327 /* If the monster is on a trap, trap it */
328
329 sch = CCHAR(mvinch(th->t_nxtpos.y, th->t_nxtpos.x));
330
331 if (isatrap(sch))
332 {
333 debug("Monster trapped by %c.", sch);
334
335 if (cansee(th->t_nxtpos.y, th->t_nxtpos.x))
336 th->t_oldch = sch;
337
338 be_trapped(th, th->t_nxtpos);
339 }
340
341 /* And stop running if need be */
342
343 if (stoprun && ce(th->t_pos, th->t_chasee->t_pos))
344 {
345 th->t_ischasing = FALSE;
346 turn_off(*th, ISRUN);
347 }
348 }
349
350 /*
351 chase_it()
352 Set a monster running after something or stop it from running (for
353 when it dies)
354 */
355
356 void
357 chase_it(coord *runner, struct thing *th)
358 {
359 struct linked_list *item;
360 struct thing *tp;
361
362 /* If we couldn't find him, something is funny */
363
364 if ((item = find_mons(runner->y, runner->x)) == NULL)
365 {
366 debug("CHASER '%s'", unctrl(winat(runner->y, runner->x)));
367 return;
368 }
369
370 tp = THINGPTR(item);
371
372 /* Start the beastie running */
373
374 tp->t_ischasing = TRUE;
375 tp->t_chasee = th;
376
377 turn_on(*tp, ISRUN);
378 turn_off(*tp, ISDISGUISE);
379
380 return;
381 }
382
383 /*
384 chase()
385 Find the spot for the chaser(er) to move closer to the chasee(ee).
386 Returns TRUE if we want to keep on chasing later, FALSE if we reach the
387 goal.
388 */
389
390 int
391 chase(struct thing *tp, coord *ee, int flee)
392 {
393 int x, y;
394 int dist, thisdist, monst_dist = INT_MAX;
395 struct linked_list *weapon;
396 coord *er = &tp->t_pos;
397 coord shoot;
398 coord *shootit_dir = NULL;
399 int ch;
400 char mch;
401 int next_player = FALSE;
402
403 /* Take care of shooting directions */
404
405 if (on(*tp, CANBREATHE) || on(*tp, CANSHOOT) || on(*tp, CANCAST))
406 {
407 if (good_monster(*tp))
408 {
409 shootit_dir = find_shoot(tp, &shoot); /* find a mean monster */
410
411 if (wizard && shootit_dir)
412 msg("Found monster to attack towards (%d,%d).",
413 shootit_dir->x, shootit_dir->y);
414 }
415 else
416 shootit_dir = can_shoot(er, ee, &shoot); /* shoot hero */
417 }
418
419 /*
420 * If the thing is confused, let it move randomly. Some monsters are
421 * slightly confused all of the time.
422 */
423
424 if ((on(*tp, ISHUH) && rnd(10) < 8) ||
425 ((on(*tp, ISINVIS) || on(*tp, ISSHADOW)) && rnd(100) < 20) ||
426 (on(player, ISINVIS) && off(*tp, CANSEE)))
427 { /* Player is invisible */
428
429 /* get a valid random move */
430
431 tp->t_nxtpos = rndmove(tp);
432
433 dist = DISTANCE(tp->t_nxtpos, *ee);
434
435 if (on(*tp, ISHUH) && rnd(20) == 0) /* monster might lose confusion */
436 turn_off(*tp, ISHUH);
437
438 /*
439 * check to see if random move takes creature away from
440 * player if it does then turn off ISHELD
441 */
442
443 if (dist > 1 && on(*tp, DIDHOLD))
444 {
445 turn_off(*tp, DIDHOLD);
446 turn_on(*tp, CANHOLD);
447
448 if (--hold_count == 0)
449 turn_off(player, ISHELD);
450 }
451 } /* If we can breathe, we may do so */
452 else if (on(*tp, CANBREATHE) && (shootit_dir) && (rnd(100) < 67) &&
453 (off(player, ISDISGUISE) || (rnd(tp->t_stats.s_lvl) > 6)) &&
454 (DISTANCE(*er, *ee) < BOLT_LENGTH * BOLT_LENGTH))
455 {
456 int chance;
457 char *breath;
458
459 /* Will it breathe at random */
460
461 if (on(*tp, CANBRANDOM))
462 {
463 if (rnd(level / 20) == 0 && tp->t_index != nummonst + 1
464 && !(good_monster(*tp)))
465 turn_off(*tp, CANBRANDOM);
466
467 /* Select type of breath */
468
469 chance = rnd(100);
470
471 if (chance < 11)
472 breath = "acid";
473 else if (chance < 22)
474 breath = "flame";
475 else if (chance < 33)
476 breath = "lightning bolt";
477 else if (chance < 44)
478 breath = "chlorine gas";
479 else if (chance < 55)
480 breath = "ice";
481 else if (chance < 66)
482 breath = "nerve gas";
483 else if (chance < 77)
484 breath = "sleeping gas";
485 else if (chance < 88)
486 breath = "slow gas";
487 else
488 breath = "fear gas";
489 } /* Or can it breathe acid? */
490 else if (on(*tp, CANBACID))
491 {
492 if (!good_monster(*tp) && rnd(level / 15) == 0)
493 turn_off(*tp, CANBACID);
494
495 breath = "acid";
496 } /* Or can it breathe fire */
497 else if (on(*tp, CANBFIRE))
498 {
499 if (!good_monster(*tp) && rnd(level / 15) == 0)
500 turn_off(*tp, CANBFIRE);
501
502 breath = "flame";
503 } /* Or can it breathe electricity? */
504 else if (on(*tp, CANBBOLT))
505 {
506 if (!good_monster(*tp) && rnd(level / 15) == 0)
507 turn_off(*tp, CANBBOLT);
508
509 breath = "lightning bolt";
510 } /* Or can it breathe gas? */
511 else if (on(*tp, CANBGAS))
512 {
513 if (!good_monster(*tp) && rnd(level / 15) == 0)
514 turn_off(*tp, CANBGAS);
515
516 breath = "chlorine gas";
517 } /* Or can it breathe ice? */
518 else if (on(*tp, CANBICE))
519 {
520 if (!good_monster(*tp) && rnd(level / 15) == 0)
521 turn_off(*tp, CANBICE);
522
523 breath = "ice";
524 }
525 else if (on(*tp, CANBPGAS))
526 {
527 if (!good_monster(*tp) && rnd(level / 15) == 0)
528 turn_off(*tp, CANBPGAS);
529
530 breath = "nerve gas";
531 }
532 else if (on(*tp, CANBSGAS))
533 {
534 if (!good_monster(*tp) && rnd(level / 15) == 0)
535 turn_off(*tp, CANBSGAS);
536
537 breath = "sleeping gas";
538 }
539 else if (on(*tp, CANBSLGAS))
540 {
541 if (!good_monster(*tp) && rnd(level / 15) == 0)
542 turn_off(*tp, CANBSLGAS);
543
544 breath = "slow gas";
545 }
546 else
547 {
548 if (!good_monster(*tp) && rnd(level / 15) == 0)
549 turn_off(*tp, CANBFGAS);
550
551 breath = "fear gas";
552 }
553
554 shoot_bolt(tp, *er, *shootit_dir, (tp == THINGPTR(fam_ptr)),
555 tp->t_index, breath, roll(tp->t_stats.s_lvl, 6));
556
557 tp->t_nxtpos = *er;
558
559 dist = DISTANCE(tp->t_nxtpos, *ee);
560
561 if (!curr_mons)
562 return (TRUE);
563 }
564 else if (shootit_dir && on(*tp, CANCAST) &&
565 (off(player, ISDISGUISE) || (rnd(tp->t_stats.s_lvl) > 6)))
566 {
567 /*
568 If we can cast spells we might do so - even if adjacent fleeing
569 monsters are restricted to certain spells
570 */
571
572 incant(tp, *shootit_dir);
573 tp->t_nxtpos = *er;
574 dist = DISTANCE(tp->t_nxtpos, *ee);
575 }
576 else if (shootit_dir && on(*tp, CANSHOOT))
577 {
578 weapon = get_hurl(tp);
579
580 if (weapon &&
581 (off(*tp, ISFLEE) || rnd(DISTANCE(*er, *ee)) > 2) &&
582 (off(player, ISDISGUISE) || (rnd(tp->t_stats.s_lvl) > 6)))
583 {
584 /*
585 Should we shoot or throw something? fleeing monsters
586 may to shoot anyway if far enough away
587 */
588
589 missile(shootit_dir->y, shootit_dir->x, weapon, tp);
590 tp->t_nxtpos = *er;
591 dist = DISTANCE(tp->t_nxtpos, *ee);
592 }
593 }
594 else
595 {
596 /*
597 Otherwise, find the empty spot next to the chaser that is closest
598 to the chasee.
599 */
600 int ey, ex;
601 struct room *rer, *ree;
602 int dist_to_old = INT_MIN; /* Dist from goal to old position */
603
604 /* Get rooms */
605 rer = roomin(*er);
606 ree = roomin(*ee);
607
608 /*
609 * This will eventually hold where we move to get closer. If
610 * we can't find an empty spot, we stay where we are.
611 */
612
613 dist = flee ? 0 : INT_MAX;
614 tp->t_nxtpos = *er;
615
616 /* Are we at our goal already? */
617
618 if (!flee && ce(tp->t_nxtpos, *ee))
619 return (FALSE);
620
621 ey = er->y + 1;
622 ex = er->x + 1;
623
624 for (x = er->x - 1; x <= ex; x++)
625 for (y = er->y - 1; y <= ey; y++)
626 {
627 coord tryp; /* test position */
628
629 /* Don't try off the screen */
630
631 if ((x < 0) || (x >= COLS) || (y < 1) || (y >= LINES - 2))
632 continue;
633
634 /*
635 * Don't try the player if not going after
636 * the player or he's disguised and monster is dumb
637 */
638
639 if (((off(*tp, ISFLEE) && !ce(hero, *ee)) ||
640 (on(player, ISDISGUISE) && (rnd(tp->t_stats.s_lvl) < 6))
641 || good_monster(*tp))
642 && x == hero.x && y == hero.y)
643 continue;
644
645 tryp.x = x;
646 tryp.y = y;
647
648 /*
649 * Is there a monster on this spot closer to
650 * our goal? Don't look in our spot or where
651 * we were.
652 */
653
654 if (!ce(tryp, *er) && !ce(tryp, tp->t_oldpos) &&
655 isalpha( (mch = CCHAR(mvwinch(mw, y, x))) ) )
656 {
657 int test_dist;
658
659 test_dist = DISTANCE(tryp,*ee);
660 if (test_dist <= 25 && /* Let's be fairly close */
661 test_dist < monst_dist)
662 {
663
664 /* Could we really move there? */
665
666 mvwaddch(mw, y, x, ' '); /* Temp blank monst */
667
668 if (diag_ok(er, &tryp, tp))
669 monst_dist = test_dist;
670
671 mvwaddch(mw, y, x, mch); /* Restore monster */
672 }
673 }
674
675 if (!diag_ok(er, &tryp, tp))
676 continue;
677
678 ch = mvwinch(cw, y, x); /* Screen character */
679
680 /*
681 * Stepping on player is NOT okay if we are
682 * fleeing
683 */
684
685 if (on(*tp, ISFLEE) && (ch == PLAYER))
686 next_player = TRUE;
687
688 if (step_ok(y, x, NOMONST, tp) &&
689 (off(*tp, ISFLEE) || ch != PLAYER))
690 {
691
692 /*
693 * If it is a trap, an intelligent
694 * monster may not step on it (unless
695 * our hero is on top!)
696 */
697
698 if (isatrap(ch))
699 {
700 if (!(ch == RUSTTRAP) &&
701 !(ch == FIRETRAP && on(*tp, NOFIRE)) &&
702 rnd(10) < tp->t_stats.s_intel &&
703 (y != hero.y || x != hero.x))
704 continue;
705 }
706
707 /*
708 * OK -- this place counts
709 */
710
711 thisdist = DISTANCE(tryp, *ee);
712
713 /*
714 * Adjust distance if we are being
715 * shot at to moving out of line of sight.
716 */
717
718 if (tp->t_wasshot && tp->t_stats.s_intel > 5 &&
719 ce(hero, *ee))
720 {
721 /* Move out of line of sight */
722 if (straight_shot(tryp.y, tryp.x, ee->y, ee->x, NULL))
723 {
724 if (flee)
725 thisdist -= SHOTPENALTY;
726 else
727 thisdist += SHOTPENALTY;
728 }
729
730 /*
731 * But do we want to leave
732 * the room?
733 */
734 else if (rer && rer == ree && ch == DOOR)
735 thisdist += DOORPENALTY;
736 }
737
738 /*
739 * Don't move to the last position if
740 * we can help it
741 */
742
743 if (ce(tryp, tp->t_oldpos))
744 dist_to_old = thisdist;
745 else if ((flee && (thisdist > dist)) ||
746 (!flee && (thisdist < dist)))
747 {
748 tp->t_nxtpos = tryp;
749 dist = thisdist;
750 }
751 }
752 }
753
754 /*
755 * If we are running from the player and he is in our way, go
756 * ahead and slug him.
757 */
758
759 if (next_player && DISTANCE(*er,*ee) < dist &&
760 step_ok(tp->t_chasee->t_pos.y, tp->t_chasee->t_pos.x, NOMONST, tp))
761 {
762 tp->t_nxtpos = tp->t_chasee->t_pos; /* Okay to hit player */
763 return(FALSE);
764 }
765
766
767 /*
768 * If we can't get closer to the player (if that's our goal)
769 * because other monsters are in the way, just stay put
770 */
771
772 if (!flee && ce(hero, *ee) && monst_dist < INT_MAX &&
773 DISTANCE(*er, hero) < dist)
774 tp->t_nxtpos = *er;
775
776 /* Do we want to go back to the last position? */
777 else if (dist_to_old != INT_MIN && /* It is possible to move back */
778 ((flee && dist == 0) || /* No other possible moves */
779 (!flee && dist == INT_MAX)))
780 {
781 /* Do we move back or just stay put (default)? */
782
783 dist = DISTANCE(*er,*ee); /* Current distance */
784
785 if (!flee || (flee && (dist_to_old > dist)))
786 tp->t_nxtpos = tp->t_oldpos;
787 }
788 }
789
790 /* Make sure we have the real distance now */
791 dist = DISTANCE(tp->t_nxtpos, *ee);
792
793 /* Mark monsters in a wall */
794
795 switch(mvinch(tp->t_nxtpos.y, tp->t_nxtpos.x))
796 {
797 case WALL:
798 case '-':
799 case '|':
800 turn_on(*tp, ISINWALL);
801 break;
802 default:
803 turn_off(*tp, ISINWALL);
804 }
805
806 if (off(*tp, ISFLEE) &&
807 !(!SAME_POS((tp->t_chasee->t_pos),hero) || off(player, ISINWALL) || on(*tp, CANINWALL)))
808 return(dist != 0);
809 else /* May actually hit here from a confused move */
810 return(!ce(tp->t_nxtpos, hero));
811 }
812
813 /*
814 roomin(coord *cp)
815
816 Find what room some coordinates are in.
817 NULL means they aren't in any room.
818 */
819
820 struct room *
821 roomin(coord cp)
822 {
823 struct room *rp;
824 int i;
825
826 for (i = 0; i < MAXROOMS; i++)
827 {
828 rp = &rooms[i];
829
830 if ((cp.x <= (rp->r_pos.x + (rp->r_max.x - 1))) &&
831 (cp.y <= (rp->r_pos.y + (rp->r_max.y - 1))) &&
832 (cp.x >= rp->r_pos.x) &&
833 (cp.y >= rp->r_pos.y))
834 {
835 return(rp);
836 }
837 }
838
839 return(NULL);
840 }
841
842 /*
843 * find_mons: Find the monster from his corrdinates
844 */
845
846 struct linked_list *
847 find_mons(int y, int x)
848 {
849 struct linked_list *item;
850
851 for (item = mlist; item != NULL; item = next(item))
852 {
853 struct thing *th = THINGPTR(item);
854
855 if (th->t_pos.y == y && th->t_pos.x == x)
856 return item;
857 }
858 return NULL;
859 }
860
861 /*
862 * Find an unfriendly monster around us to hit
863 */
864
865 struct linked_list *
866 f_mons_a(int y, int x, int hit_bad)
867 {
868 int row, col;
869 struct linked_list *item;
870 struct thing *tp;
871
872 for (row = x - 1; row <= x + 1; row++)
873 for (col = y - 1; col <= y + 1; col++)
874 if (row == x && col == y)
875 continue;
876 else if (col > 0 && row > 0 &&
877 isalpha(mvwinch(mw, col, row)) &&
878 ((item = find_mons(col, row)) != NULL))
879 {
880 tp = THINGPTR(item);
881 if ((good_monster(*tp) && !hit_bad) ||
882 (!good_monster(*tp) && hit_bad))
883 return (item);
884 }
885
886 return (NULL);
887 }
888
889
890 /*
891 diag_ok()
892 Check to see if the move is legal if it is diagonal
893 */
894
895 int
896 diag_ok(coord *sp, coord *ep, struct thing *flgptr)
897 {
898 if (ep->x == sp->x || ep->y == sp->y)
899 return TRUE;
900
901 return (step_ok(ep->y, sp->x, MONSTOK, flgptr) &&
902 step_ok(sp->y, ep->x, MONSTOK, flgptr));
903 }
904
905 /*
906 cansee()
907 returns true if the hero can see a certain coordinate.
908 */
909
910 int
911 cansee(int y, int x)
912 {
913 struct room *rer;
914 coord tp;
915
916 if (on(player, ISBLIND))
917 return FALSE;
918
919 tp.y = y;
920 tp.x = x;
921 rer = roomin(tp);
922
923 /*
924 * We can only see if the hero in the same room as the coordinate and
925 * the room is lit or if it is close.
926 */
927
928 return ((rer != NULL &&
929 rer == roomin(hero) &&
930 (!(rer->r_flags & ISDARK) || (rer->r_flags & HASFIRE)) &&
931 (levtype != MAZELEV || /* Maze level needs direct line */
932 maze_view(tp.y, tp.x))) ||
933 DISTANCE(tp,hero) < see_dist);
934 }
935
936 coord *
937 find_shoot(struct thing *tp, coord *dir)
938 {
939 struct room *rtp;
940 int ulx, uly, xmx, ymx, xmon, ymon, tpx, tpy, row, col;
941 struct linked_list *mon;
942 struct thing *ick;
943
944 rtp = roomin(tp->t_pos); /* Find room of chaser */
945
946 if (rtp == NULL)
947 return NULL;
948
949 ulx = rtp->r_pos.x;
950 uly = rtp->r_pos.y;
951 xmx = rtp->r_max.x;
952 ymx = rtp->r_max.y;
953
954 tpx = tp->t_pos.x;
955 tpy = tp->t_pos.y;
956
957 for (col = ulx; col < (ulx + xmx); col++)
958 for (row = uly; row < (uly + ymx); row++)
959 {
960 if (row > 0 && col > 0 && isalpha(mvwinch(mw, row, col)))
961 {
962 mon = find_mons(row, col);
963
964 if (mon)
965 {
966 ick = THINGPTR(mon);
967 xmon = ick->t_pos.x;
968 ymon = ick->t_pos.y;
969
970 if (!(good_monster(*ick)))
971 {
972 if (straight_shot(tpy, tpx, ymon, xmon, dir))
973 return(dir);
974 }
975 }
976 }
977 }
978
979 return(NULL);
980 }
981
982 /*
983 can_shoot()
984 determines if the monster (er) has a direct line of shot at the
985 player (ee). If so, it returns the direction in which to shoot.
986 */
987
988 coord *
989 can_shoot(coord *er, coord *ee, coord *dir)
990 {
991 int ery, erx, eey, eex;
992
993 /* Make sure we are chasing the player */
994
995 if (!ce((*ee), hero))
996 return(NULL);
997
998 /* They must be in the same room */
999
1000 if (roomin(*er) != roomin(hero))
1001 return(NULL);
1002
1003 ery = er->y;
1004 erx = er->x;
1005 eey = ee->y;
1006 eex = ee->x;
1007
1008 /* Will shoot unless next to player, then 80% prob will fight */
1009
1010 if ((DISTANCE(*er,*ee) < 4) && (rnd(100) < 80))
1011 return(NULL);
1012
1013 /* Do we have a straight shot? */
1014
1015 if (!straight_shot(ery, erx, eey, eex, dir))
1016 return(NULL);
1017 else
1018 return(dir);
1019 }
1020
1021 /*
1022 straight_shot()
1023 See if there is a straight line of sight between the two
1024 given coordinates. If shooting is not NULL, it is a pointer to a
1025 structure which should be filled with the direction to shoot (if
1026 there is a line of sight). If shooting, monsters get in the way.
1027 Otherwise, they do not.
1028 */
1029
1030 int
1031 straight_shot(int ery, int erx, int eey, int eex, coord *dir)
1032 {
1033 int dy, dx; /* Deltas */
1034 int ch;
1035
1036 /* Does the monster have a straight shot at player */
1037
1038 if ((ery != eey) && (erx != eex) &&
1039 (abs(ery - eey) != abs(erx - eex)))
1040 return (FALSE);
1041
1042 /* Get the direction to shoot */
1043
1044 if (eey > ery)
1045 dy = 1;
1046 else if (eey == ery)
1047 dy = 0;
1048 else
1049 dy = -1;
1050
1051 if (eex > erx)
1052 dx = 1;
1053 else if (eex == erx)
1054 dx = 0;
1055 else
1056 dx = -1;
1057
1058 /* Make sure we have free area all the way to the player */
1059
1060 ery += dy;
1061 erx += dx;
1062
1063 while ((ery != eey) || (erx != eex))
1064 {
1065 switch(ch = winat(ery, erx))
1066 {
1067 case '|':
1068 case '-':
1069 case WALL:
1070 case DOOR:
1071 case SECRETDOOR:
1072 return(FALSE);
1073 default:
1074 if (dir && isalpha(ch))
1075 return(FALSE);
1076 }
1077
1078 ery += dy;
1079 erx += dx;
1080 }
1081
1082 if (dir)
1083 { /* If we are shooting -- put in the directions */
1084 dir->y = dy;
1085 dir->x = dx;
1086 }
1087
1088 return(TRUE);
1089 }
1090
1091 /*
1092 get_hurl
1093 returns the weapon that the monster will "throw" if it has one
1094 */
1095
1096 struct linked_list *
1097 get_hurl(struct thing *tp)
1098 {
1099 struct linked_list *arrow, *bolt, *rock, *silverarrow, *fbbolt;
1100 struct linked_list *bullet, *firearrow, *dart, *dagger, *shuriken;
1101 struct linked_list *oil, *grenade;
1102
1103 struct linked_list *pitem;
1104 int bow = FALSE, crossbow = FALSE, sling = FALSE, footbow = FALSE;
1105
1106 /* Don't point to anything to begin with */
1107
1108 arrow = bolt = rock = silverarrow = fbbolt = NULL;
1109 bullet = firearrow = dart = dagger = shuriken = NULL;
1110 oil = grenade = NULL;
1111
1112 for (pitem = tp->t_pack; pitem != NULL; pitem = next(pitem))
1113 if ((OBJPTR(pitem))->o_type == WEAPON)
1114 switch ((OBJPTR(pitem))->o_which)
1115 {
1116 case BOW:bow = TRUE; break;
1117 case CROSSBOW:crossbow = TRUE; break;
1118 case SLING:sling = TRUE; break;
1119 case FOOTBOW:footbow = TRUE; break;
1120 case ROCK:rock = pitem; break;
1121 case ARROW:arrow = pitem; break;
1122 case SILVERARROW:silverarrow = pitem; break;
1123 case BOLT:bolt = pitem; break;
1124 case FBBOLT:fbbolt = pitem; break;
1125 case BULLET:bullet = pitem; break;
1126 case FLAMEARROW:firearrow = pitem; break;
1127 case DART:dart = pitem; break;
1128 case DAGGER:dagger = pitem; break;
1129 case SHURIKEN:shuriken = pitem; break;
1130 case MOLOTOV:oil = pitem; break;
1131 case GRENADE:shuriken = pitem; break;
1132 }
1133
1134 if (bow && silverarrow)
1135 return(silverarrow);
1136
1137 if (crossbow && bolt)
1138 return(bolt);
1139
1140 if (bow && firearrow)
1141 return(firearrow);
1142
1143 if (off(*tp, ISCHARMED) && oil)
1144 return(oil);
1145
1146 if (off(*tp, ISCHARMED) && grenade)
1147 return(grenade);
1148
1149 if (footbow && fbbolt)
1150 return(fbbolt);
1151
1152 if (bow && arrow)
1153 return(arrow);
1154
1155 if (sling && bullet)
1156 return(bullet);
1157
1158 if (sling && rock)
1159 return(rock);
1160
1161 if (shuriken)
1162 return(shuriken);
1163
1164 if (dagger)
1165 return(dagger);
1166
1167 if (silverarrow)
1168 return(silverarrow);
1169
1170 if (firearrow)
1171 return(firearrow);
1172
1173 if (fbbolt)
1174 return(fbbolt);
1175
1176 if (bolt)
1177 return(bolt);
1178
1179 if (bullet)
1180 return(bullet);
1181
1182 if (dart)
1183 return(dart);
1184
1185 if (rock)
1186 return(rock);
1187
1188 return(NULL);
1189 }
1190
1191 /*
1192 pick_weap()
1193 returns the biggest weapon that the monster will wield if it
1194 has a non-launching or non-missile weapon returns NULL if no weapon, or
1195 bare hands is better
1196 */
1197
1198 struct object *
1199 pick_weap(struct thing *tp)
1200 {
1201 int weap_dam = maxdamage(tp->t_stats.s_dmg);
1202 struct object *ret_obj = NULL;
1203 struct linked_list *pitem;
1204
1205 if (on(*tp, CANWIELD))
1206 {
1207 for (pitem = tp->t_pack; pitem != NULL; pitem = next(pitem))
1208 {
1209 struct object *obj = OBJPTR(pitem);
1210
1211 if (obj->o_type != WEAPON && !(obj->o_flags&(ISLAUNCHER|ISMISL)) &&
1212 maxdamage(obj->o_damage) > weap_dam)
1213 {
1214 weap_dam = maxdamage(obj->o_damage);
1215 ret_obj = obj;
1216 }
1217 }
1218 }
1219
1220 return (ret_obj);
1221 }
1222
1223 /*
1224 canblink()
1225 checks if the monster can teleport (blink). If so, it will try
1226 to blink the monster next to the player.
1227 */
1228
1229 int
1230 can_blink(struct thing *tp)
1231 {
1232 int y, x, index = 9;
1233 coord tryp; /* To hold the coordinates for use in diag_ok */
1234 int spots[9], found_one = FALSE;
1235
1236 /*
1237 * First, can the monster even blink? And if so, there is only a 30%
1238 * chance that it will do so. And it won't blink if it is running.
1239 */
1240
1241 if (off(*tp, CANBLINK) || (on(*tp, ISHELD)) ||
1242 on(*tp, ISFLEE) ||
1243 (on(*tp, ISSLOW) && off(*tp, ISHASTE) && !(tp->t_turn)) ||
1244 (rnd(10) < 9))
1245 return (FALSE);
1246
1247 /* Initialize the spots as illegal */
1248
1249 do
1250 {
1251 spots[--index] = FALSE;
1252 }
1253 while (index > 0);
1254
1255 /* Find a suitable spot next to the player */
1256
1257 for (y = hero.y - 1; y < hero.y + 2; y++)
1258 for (x = hero.x - 1; x < hero.x + 2; x++, index++)
1259 {
1260 /*
1261 * Make sure x coordinate is in range and that we are
1262 * not at the player's position
1263 */
1264
1265 if (x < 0 || x >= COLS || index == 4)
1266 continue;
1267
1268 /* Is it OK to move there? */
1269
1270 if (!step_ok(y, x, NOMONST, tp))
1271 spots[index] = FALSE;
1272 else
1273 {
1274
1275 /*
1276 * OK, we can go here. But don't go there if
1277 * monster can't get at player from there
1278 */
1279
1280 tryp.y = y;
1281 tryp.x = x;
1282 if (diag_ok(&tryp, &hero, tp))
1283 {
1284 spots[index] = TRUE;
1285 found_one = TRUE;
1286 }
1287 }
1288 }
1289
1290 /* If we found one, go to it */
1291
1292 if (found_one)
1293 {
1294 /* Find a legal spot */
1295
1296 while (spots[index = rnd(9)] == FALSE)
1297 continue;
1298
1299 /* Get the coordinates */
1300
1301 y = hero.y + (index / 3) - 1;
1302 x = hero.x + (index % 3) - 1;
1303
1304 /* Move the monster from the old space */
1305
1306 mvwaddch(cw, tp->t_pos.y, tp->t_pos.x, tp->t_oldch);
1307
1308 /* Move it to the new space */
1309
1310 tp->t_oldch = CCHAR( mvwinch(cw, y, x) );
1311
1312 if (cansee(y, x) &&
1313 off(*tp, ISINWALL) &&
1314 ((off(*tp, ISINVIS) &&
1315 (off(*tp, ISSHADOW) || rnd(100) < 10)) || on(player, CANSEE)) &&
1316 off(*tp, CANSURPRISE))
1317 mvwaddch(cw, y, x, tp->t_type);
1318
1319 mvwaddch(mw, tp->t_pos.y,tp->t_pos.x,' '); /*Clear old position */
1320 mvwaddch(mw, y, x, tp->t_type);
1321 tp->t_pos.y = y;
1322 tp->t_pos.x = x;
1323 }
1324
1325 return (found_one);
1326 }