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) &&
373 (dist > 3 || (rnd(100) > 80)) &&
374 (weapon = get_hurl(tp))) {
375 missile(shoot_dir->y, shoot_dir->x, weapon, tp);
376 ch_ret = *er;
377 }
378
379 /*
380 * Otherwise, find the empty spot next to the chaser that is
381 * closest to the chasee.
382 */
383 else {
384 register int ey, ex, x, y;
385 register struct room *rer, *ree;
386 int dist_to_old = MININT; /* Dist from goal to old position */
387
388 /* Get rooms */
389 rer = roomin(er); /* Room the chasER (monster) is in */
390 ree = roomin(ee); /* Room the chasEE is in */
391
392 /*
393 * This will eventually hold where we move to get closer
394 * If we can't find an empty spot, we stay where we are.
395 */
396 dist = flee ? 0 : MAXINT;
397 ch_ret = *er;
398
399 /* Are we at our goal already? */
400 if (!flee && ce(ch_ret, *ee)) return(FALSE);
401
402 ey = er->y + 1;
403 ex = er->x + 1;
404
405 /* Check all possible moves */
406 for (x = er->x - 1; x <= ex; x++) {
407 if (x < 0 || x >= COLS) /* Don't try off the board */
408 continue;
409 for (y = er->y - 1; y <= ey; y++) {
410 coord tryp;
411
412 if ((y < 1) || (y >= LINES - 2)) /* Don't try off the board */
413 continue;
414
415 /* Don't try the player if not going after the player */
416 if ((flee || !ce(hero, *ee)) && x == hero.x && y == hero.y) {
417 next_player = TRUE;
418 continue;
419 }
420
421 tryp.x = x;
422 tryp.y = y;
423
424 /* Is there a monster on this spot closer to our goal?
425 * Don't look in our spot or where we were.
426 */
427 if (!ce(tryp, *er) && !ce(tryp, tp->t_oldpos) &&
428 isalpha(mch = CCHAR( mvwinch(mw, y, x) ) )) {
429 int test_dist;
430
431 test_dist = DISTANCE(y, x, ee->y, ee->x);
432 if (test_dist <= 25 && /* Let's be fairly close */
433 test_dist < monst_dist) {
434 /* Could we really move there? */
435 mvwaddch(mw, y, x, ' '); /* Temporarily blank monst */
436 if (diag_ok(er, &tryp, tp)) monst_dist = test_dist;
437 mvwaddch(mw, y, x, mch); /* Restore monster */
438 }
439 }
440
441 /* Can we move onto the spot? */
442 if (!diag_ok(er, &tryp, tp)) continue;
443
444 ch = CCHAR( mvwinch(cw, y, x) ); /* Screen character */
445
446 /* Stepping on player is NOT okay if we are fleeing */
447 if (step_ok(y, x, NOMONST, tp) &&
448 (off(*tp, ISFLEE) || ch != PLAYER))
449 {
450 /*
451 * If it is a trap, an intelligent monster may not
452 * step on it (unless our hero is on top!)
453 */
454 if ((isatrap(ch)) &&
455 (rnd(10) < tp->t_stats.s_intel) &&
456 (!on(*tp, ISFLY)) &&
457 (y != hero.y || x != hero.x))
458 continue;
459
460 /*
461 * OK -- this place counts
462 */
463 thisdist = DISTANCE(y, x, ee->y, ee->x);
464
465 /* Adjust distance if we are being shot at */
466 if (tp->t_wasshot && tp->t_stats.s_intel > 5 &&
467 ce(hero, *ee)) {
468 /* Move out of line of sight */
469 if (straight_shot(tryp.y, tryp.x, ee->y, ee->x, NULL)) {
470 if (flee) thisdist -= SHOTPENALTY;
471 else thisdist += SHOTPENALTY;
472 }
473
474 /* But do we want to leave the room? */
475 else if (rer && rer == ree && ch == DOOR)
476 thisdist += DOORPENALTY;
477 }
478
479 /* Don't move to the last position if we can help it
480 * (unless out prey just moved there)
481 */
482 if (ce(tryp, tp->t_oldpos) && (flee || !ce(tryp, hero)))
483 dist_to_old = thisdist;
484
485 else if ((flee && (thisdist > dist)) ||
486 (!flee && (thisdist < dist)))
487 {
488 ch_ret = tryp;
489 dist = thisdist;
490 }
491 }
492 }
493 }
494
495 /* If we aren't trying to get the player, but he is in our way,
496 * hit him (unless we have been turned)
497 */
498 if (next_player && off(*tp, WASTURNED) &&
499 ((flee && ce(ch_ret, *er)) ||
500 (!flee && DISTANCE(er->y, er->x, ee->y, ee->x) < dist)) &&
501 step_ok(tp->t_dest->y, tp->t_dest->x, NOMONST, tp)) {
502 /* Okay to hit player */
503 ch_ret = hero;
504 return(FALSE);
505 }
506
507
508 /* If we can't get closer to the player (if that's our goal)
509 * because other monsters are in the way, just stay put
510 */
511 if (!flee && ce(hero, *ee) && monst_dist < MAXINT &&
512 DISTANCE(er->y, er->x, hero.y, hero.x) < dist)
513 ch_ret = *er;
514
515 /* Do we want to go back to the last position? */
516 else if (dist_to_old != MININT && /* It is possible to move back */
517 ((flee && dist == 0) || /* No other possible moves */
518 (!flee && dist == MAXINT))) {
519 /* Do we move back or just stay put (default)? */
520 dist = DISTANCE(er->y, er->x, ee->y, ee->x); /* Current distance */
521 if (!flee || (flee && (dist_to_old > dist))) ch_ret = tp->t_oldpos;
522 }
523 }
524
525 /* May actually hit here from a confused move */
526 return(!ce(ch_ret, hero));
527 }
528
529 /*
530 * do_chase:
531 * Make one thing chase another.
532 */
533
534 do_chase(th, flee)
535 register struct thing *th;
536 register bool flee; /* True if running away or player is inaccessible in wall */
537 {
538 register struct room *rer, *ree, /* room of chaser, room of chasee */
539 *orig_rer, /* Original room of chaser */
540 *new_room; /* new room of monster */
541 int dist = MININT;
542 int mindist = MAXINT, maxdist = MININT;
543 bool stoprun = FALSE, /* TRUE means we are there */
544 rundoor; /* TRUE means run to a door */
545 bool mdead = 0;
546 char rch, sch;
547 coord *last_door=0, /* Door we just came from */
548 this; /* Temporary destination for chaser */
549
550 /* Make sure the monster can move */
551 if (th->t_no_move != 0) {
552 th->t_no_move--;
553 return;
554 }
555
556 rer = roomin(&th->t_pos); /* Find room of chaser */
557 ree = roomin(th->t_dest); /* Find room of chasee */
558 orig_rer = rer; /* Original room of chaser (including doors) */
559
560 /*
561 * We don't count monsters on doors as inside rooms for this routine
562 */
563 if ((sch = CCHAR( mvwinch(stdscr, th->t_pos.y, th->t_pos.x) )) == DOOR ||
564 sch == PASSAGE) {
565 rer = NULL;
566 }
567 this = *th->t_dest;
568
569 /*
570 * If we are not in a corridor and not a Xorn, then if we are running
571 * after the player, we run to a door if he is not in the same room.
572 * If we are fleeing, we run to a door if he IS in the same room.
573 * Note: We don't bother with doors in mazes.
574 */
575 if (levtype != MAZELEV && rer != NULL && off(*th, CANINWALL)) {
576 if (flee) rundoor = (rer == ree);
577 else rundoor = (rer != ree);
578 }
579 else rundoor = FALSE;
580
581 if (rundoor) {
582 register struct linked_list *exitptr; /* For looping through exits */
583 coord *exit; /* A particular door */
584 int exity, exitx; /* Door's coordinates */
585 char dch='\0'; /* Door character */
586
587 if (th->t_doorgoal)
588 dch = CCHAR( mvwinch(stdscr, th->t_doorgoal->y, th->t_doorgoal->x) );
589
590 /* Do we have a valid goal? */
591 if ((dch == PASSAGE || dch == DOOR) && /* A real door */
592 (!flee || !ce(*th->t_doorgoal, hero))) { /* Player should not
593 * be at door if we are
594 * running away
595 */
596 this = *th->t_doorgoal;
597 dist = 0; /* Indicate that we have our door */
598 }
599
600 /* Go through all the doors */
601 else for (exitptr = rer->r_exit; exitptr; exitptr = next(exitptr)) {
602 exit = DOORPTR(exitptr);
603 exity = exit->y;
604 exitx = exit->x;
605
606 /* Make sure it is a real door */
607 dch = CCHAR( mvwinch(stdscr, exity, exitx) );
608 if (dch == PASSAGE || dch == DOOR) {
609 /* Don't count a door if we are fleeing from the player and
610 * he is standing on it
611 */
612 if (flee && ce(*exit, hero)) continue;
613
614 /* Were we just on this door? */
615 if (ce(*exit, th->t_oldpos)) last_door = exit;
616
617 else {
618 dist = DISTANCE(th->t_dest->y, th->t_dest->x, exity, exitx);
619
620 /* If fleeing, we want to maximize distance from door to
621 * what we flee, and minimize distance from door to us.
622 */
623 if (flee)
624 dist -= DISTANCE(th->t_pos.y, th->t_pos.x, exity, exitx);
625
626 /* Maximize distance if fleeing, otherwise minimize it */
627 if ((flee && (dist > maxdist)) ||
628 (!flee && (dist < mindist))) {
629 th->t_doorgoal = exit; /* Use this door */
630 this = *exit;
631 mindist = maxdist = dist;
632 }
633 }
634 }
635 }
636
637 /* Could we not find a door? */
638 if (dist == MININT) {
639 /* If we were on a door, go ahead and use it */
640 if (last_door) {
641 th->t_doorgoal = last_door;
642 this = th->t_oldpos;
643 dist = 0; /* Indicate that we found a door */
644 }
645 else th->t_doorgoal = NULL; /* No more door goal */
646 }
647
648 /* Indicate that we do not want to flee from the door */
649 if (dist != MININT) flee = FALSE;
650 }
651 else th->t_doorgoal = 0; /* Not going to any door */
652
653 /*
654 * this now contains what we want to run to this time
655 * so we run to it. If we hit it we either want to fight it
656 * or stop running
657 */
658 if (!chase(th, &this, flee, &mdead)) {
659 if (ce(ch_ret, hero)) {
660 /* merchants try to sell something --> others attack */
661 if (on(*th, CANSELL)) sell(th);
662 else attack(th, NULL, FALSE);
663 return;
664 }
665 else if (on(*th, NOMOVE))
666 stoprun = TRUE;
667 }
668
669 if (mdead) return; /* Did monster kill someone? */
670
671 if (on(*th, NOMOVE)) return;
672
673 /* If we have a scavenger, it can pick something up */
674 if (on(*th, ISSCAVENGE)) {
675 register struct linked_list *n_item, *o_item;
676
677 while ((n_item = find_obj(ch_ret.y, ch_ret.x)) != NULL) {
678 char floor = (roomin(&ch_ret) == NULL) ? PASSAGE : FLOOR;
679 register struct object *n_obj, *o_obj;
680
681 /*
682 * see if he's got one of this group already
683 */
684 o_item = NULL;
685 n_obj = OBJPTR(n_item);
686 detach(lvl_obj, n_item);
687 if (n_obj->o_group) {
688 for(o_item = th->t_pack; o_item != NULL; o_item = next(o_item)){
689 o_obj = OBJPTR(o_item);
690 if (o_obj->o_group == n_obj->o_group) {
691 o_obj->o_count += n_obj->o_count;
692 o_discard(n_item);
693 break;
694 }
695 }
696 }
697 if (o_item == NULL) { /* didn't find it */
698 attach(th->t_pack, n_item);
699 }
700 if (cansee(ch_ret.y, ch_ret.x))
701 mvwaddch(cw, ch_ret.y, ch_ret.x, floor);
702 mvaddch(ch_ret.y, ch_ret.x, floor);
703 }
704 }
705
706 mvwaddch(cw, th->t_pos.y, th->t_pos.x, th->t_oldch);
707 sch = CCHAR( mvwinch(cw, ch_ret.y, ch_ret.x) ); /* What player sees */
708 rch = CCHAR( mvwinch(stdscr, ch_ret.y, ch_ret.x) ); /* What's really there */
709
710 /* Get new room of monster */
711 new_room=roomin(&ch_ret);
712
713 /* If we have a tunneling monster, it may be making a tunnel */
714 if (on(*th, CANTUNNEL) &&
715 (rch == SECRETDOOR || rch == WALL || rch == '|' || rch == '-')) {
716 char nch; /* The new look to the tunnel */
717
718 if (rch == WALL) nch = PASSAGE;
719 else if (levtype == MAZELEV) nch = FLOOR;
720 else nch = DOOR;
721 addch(nch);
722
723 if (cansee(ch_ret.y, ch_ret.x)) sch = nch; /* Can player see this? */
724
725 /* Does this make a new exit? */
726 if (rch == '|' || rch == '-') {
727 struct linked_list *newroom;
728 coord *exit;
729
730 newroom = new_item(sizeof(coord));
731 exit = DOORPTR(newroom);
732 *exit = ch_ret;
733 attach(new_room->r_exit, newroom);
734 }
735 }
736
737 /* Mark if the monster is inside a wall */
738 if (isrock(mvinch(ch_ret.y, ch_ret.x))) turn_on(*th, ISINWALL);
739 else turn_off(*th, ISINWALL);
740
741 /* If the monster can illuminate rooms, check for a change */
742 if (on(*th, HASFIRE)) {
743 register struct linked_list *fire_item;
744
745 /* Is monster entering a room? */
746 if (orig_rer != new_room && new_room != NULL) {
747 fire_item = creat_item(); /* Get an item-only structure */
748 ldata(fire_item) = (char *) th;
749
750 attach(new_room->r_fires, fire_item);
751 new_room->r_flags |= HASFIRE;
752
753 if (cansee(ch_ret.y, ch_ret.x) && next(new_room->r_fires) == NULL)
754 light(&hero);
755 }
756
757 /* Is monster leaving a room? */
758 if (orig_rer != new_room && orig_rer != NULL) {
759 /* Find the bugger in the list and delete him */
760 for (fire_item = orig_rer->r_fires; fire_item != NULL;
761 fire_item = next(fire_item)) {
762 if (THINGPTR(fire_item) == th) { /* Found him! */
763 detach(orig_rer->r_fires, fire_item);
764 destroy_item(fire_item);
765 if (orig_rer->r_fires == NULL) {
766 orig_rer->r_flags &= ~HASFIRE;
767 if (cansee(th->t_pos.y, th->t_pos.x))
768 light(&th->t_pos);
769 }
770 break;
771 }
772 }
773 }
774 }
775
776 /* If monster is entering player's room and player can see it,
777 * stop the player's running.
778 */
779 if (new_room != orig_rer && new_room != NULL &&
780 new_room == ree && cansee(unc(ch_ret)) &&
781 (off(*th, ISINVIS) || on(player, CANSEE)) &&
782 (off(*th, ISSHADOW) || on(player, CANSEE)) &&
783 (off(*th, CANSURPRISE) || ISWEARING(R_ALERT)))
784 running = FALSE;
785
786 /*
787 if (rer != NULL && !lit_room(orig_rer) && sch == FLOOR &&
788 DISTANCE(ch_ret.y, ch_ret.x, th->t_pos.y, th->t_pos.x) < 3 &&
789 off(player, ISBLIND))
790 th->t_oldch = ' ';
791 else
792 */
793 th->t_oldch = sch;
794
795 /* Let's display those creatures that we can see. */
796 if (cansee(unc(ch_ret)) &&
797 off(*th, ISINWALL) &&
798 !invisible(th))
799 mvwaddch(cw, ch_ret.y, ch_ret.x, th->t_type);
800
801 /*
802 * Blank out the old position and record the new position --
803 * the blanking must be done first in case the positions are the same.
804 */
805 mvwaddch(mw, th->t_pos.y, th->t_pos.x, ' ');
806 mvwaddch(mw, ch_ret.y, ch_ret.x, th->t_type);
807
808 /* Record monster's last position (if new one is different) */
809 if (!ce(ch_ret, th->t_pos)) th->t_oldpos = th->t_pos;
810 th->t_pos = ch_ret; /* Mark the monster's new position */
811
812 /* If the monster is on a trap, trap it */
813 sch = CCHAR( mvinch(ch_ret.y, ch_ret.x) );
814 if (isatrap(sch)) {
815 if (cansee(ch_ret.y, ch_ret.x)) th->t_oldch = sch;
816 be_trapped(th, &ch_ret);
817 }
818
819
820 /*
821 * And stop running if need be
822 */
823 if (stoprun && ce(th->t_pos, *(th->t_dest)))
824 turn_off(*th, ISRUN);
825 }
826
827
828 /*
829 * Get_hurl returns the weapon that the monster will "throw" if he has one
830 */
831
832 struct linked_list *
833 get_hurl(tp)
834 register struct thing *tp;
835 {
836 struct linked_list *arrow, *bolt, *rock;
837 register struct linked_list *pitem;
838 bool bow=FALSE, crossbow=FALSE, sling=FALSE;
839
840 arrow = bolt = rock = NULL; /* Don't point to anything to begin with */
841 for (pitem=tp->t_pack; pitem; pitem=next(pitem))
842 if ((OBJPTR(pitem))->o_type == WEAPON)
843 switch ((OBJPTR(pitem))->o_which) {
844 case BOW: bow = TRUE;
845 when CROSSBOW: crossbow = TRUE;
846 when SLING: sling = TRUE;
847 when ROCK: rock = pitem;
848 when ARROW: arrow = pitem;
849 when BOLT: bolt = pitem;
850 }
851
852 /* Use crossbow bolt if possible */
853 if (crossbow && bolt) return(bolt);
854 if (bow && arrow) return(arrow);
855 if (sling && rock) return(rock);
856 return(NULL);
857 }
858
859 /*
860 * runners:
861 * Make all the running monsters move.
862 */
863
864 runners()
865 {
866 register struct linked_list *item;
867 register struct thing *tp = NULL;
868
869 /*
870 * loop thru the list of running (wandering) monsters and see what
871 * each one will do this time.
872 *
873 * Note: the special case that one of this buggers kills another.
874 * if this happens than we have to see if the monster killed
875 * himself or someone else. In case its himself we have to get next
876 * one immediately. If it wasn't we have to get next one at very
877 * end in case he killed the next one.
878 */
879
880 for (item = mlist; item != NULL; item = next(item)) {
881 tp = THINGPTR(item);
882 turn_on(*tp, ISREADY);
883 }
884
885 for (;;) {
886 for (item = mlist; item != NULL; item = next(item)) {
887 tp = THINGPTR(item);
888
889 if (on(*tp, ISREADY))
890 break;
891 }
892
893 if (item == NULL)
894 break;
895
896 turn_off(*tp, ISREADY);
897
898 if (on(*tp, ISHELD) && rnd(tp->t_stats.s_lvl) > 11) {
899 turn_off(*tp, ISHELD);
900 turn_on(*tp, ISRUN);
901 turn_off(*tp, ISDISGUISE);
902 tp->t_dest = &hero;
903 if (tp->t_stats.s_hpt < tp->maxstats.s_hpt)
904 turn_on(*tp, ISFLEE);
905 if (cansee(tp->t_pos.y, tp->t_pos.x))
906 msg("The %s breaks free from the hold spell",
907 monsters[tp->t_index].m_name);
908 }
909 if (off(*tp, ISHELD) && on(*tp, ISRUN)) {
910 register bool flee;
911
912 /* Should monster run away? */
913 flee = on(*tp, ISFLEE) ||
914 ((tp->t_dest == &hero) && on(player, ISINWALL) &&
915 off(*tp, CANINWALL));
916
917 if (off(*tp, ISSLOW) || tp->t_turn) {
918 doctor(tp);
919 do_chase(tp, flee);
920 }
921 if (off(*tp, ISDEAD) && off(*tp, ISELSEWHERE) && on(*tp, ISHASTE)) {
922 doctor(tp);
923 do_chase(tp, flee);
924 }
925 if (off(*tp, ISDEAD) && off(*tp, ISELSEWHERE)) {
926 tp->t_turn ^= TRUE;
927 tp->t_wasshot = FALSE; /* Not shot anymore */
928 }
929 }
930 }
931 }
932
933 /*
934 * runto:
935 * Set a monster running after something
936 */
937
938 runto(runner, spot)
939 register struct thing *runner;
940 coord *spot;
941 {
942 /*
943 * Start the beastie running
944 */
945 runner->t_dest = spot;
946 turn_on(*runner, ISRUN);
947 turn_off(*runner, ISDISGUISE);
948 }
949
950
951
952 /*
953 * straight_shot:
954 * See if there is a straight line of sight between the two
955 * given coordinates. If shooting is not NULL, it is a pointer
956 * to a structure which should be filled with the direction
957 * to shoot (if there is a line of sight). If shooting, monsters
958 * get in the way. Otherwise, they do not.
959 */
960
961 bool
962 straight_shot(ery, erx, eey, eex, shooting)
963 register int ery, erx, eey, eex;
964 register coord *shooting;
965 {
966 register int dy, dx; /* Deltas */
967 char ch;
968
969 /* Does the monster have a straight shot at player */
970 if ((ery != eey) && (erx != eex) &&
971 (abs(ery - eey) != abs(erx - eex))) return(FALSE);
972
973 /* Get the direction to shoot */
974 if (eey > ery) dy = 1;
975 else if (eey == ery) dy = 0;
976 else dy = -1;
977
978 if (eex > erx) dx = 1;
979 else if (eex == erx) dx = 0;
980 else dx = -1;
981
982 /* Make sure we have free area all the way to the player */
983 ery += dy;
984 erx += dx;
985 while ((ery != eey) || (erx != eex)) {
986 switch (ch = CCHAR( winat(ery, erx) )) {
987 case '|':
988 case '-':
989 case WALL:
990 case DOOR:
991 case SECRETDOOR:
992 case FOREST:
993 return(FALSE);
994 default:
995 if (shooting && isalpha(ch)) return(FALSE);
996 }
997 ery += dy;
998 erx += dx;
999 }
1000
1001 if (shooting) { /* If we are shooting -- put in the directions */
1002 shooting->y = dy;
1003 shooting->x = dx;
1004 }
1005 return(TRUE);
1006 }
1007
1008