comparison xrogue/chase.c @ 133:e6179860cb76

Import XRogue 8.0 from the Roguelike Restoration Project (r1490)
author John "Elwin" Edwards
date Tue, 21 Apr 2015 08:55:20 -0400
parents
children f54901b9c39b
comparison
equal deleted inserted replaced
124:d10fc4a065ac 133:e6179860cb76
1 /*
2 chase.c - Code for one object to chase another
3
4 XRogue: Expeditions into the Dungeons of Doom
5 Copyright (C) 1991 Robert Pietkivitch
6 All rights reserved.
7
8 Based on "Advanced Rogue"
9 Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T
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 <ctype.h>
20 #include <curses.h>
21 #include <limits.h>
22 #include "rogue.h"
23
24 /*
25 * Canblink checks if the monster can teleport (blink). If so, it will
26 * try to blink the monster next to the player.
27 */
28
29 bool
30 can_blink(tp)
31 register struct thing *tp;
32 {
33 register int y, x, index=9;
34 coord tryp; /* To hold the coordinates for use in diag_ok */
35 bool spots[9], found_one=FALSE;
36
37 /*
38 * First, can the monster even blink? And if so, there is only a 50%
39 * chance that it will do so. And it won't blink if it is running or
40 * held.
41 */
42 if (off(*tp, CANBLINK) || (on(*tp, ISHELD)) ||
43 on(*tp, ISFLEE) ||
44 tp->t_action == A_FREEZE ||
45 (rnd(12) < 6)) return(FALSE);
46
47
48 /* Initialize the spots as illegal */
49 do {
50 spots[--index] = FALSE;
51 } while (index > 0);
52
53 /* Find a suitable spot next to the player */
54 for (y=hero.y-1; y<hero.y+2; y++)
55 for (x=hero.x-1; x<hero.x+2; x++, index++) {
56 /* Make sure x coordinate is in range and that we are
57 * not at the player's position
58 */
59 if (x<0 || x >= cols || index == 4) continue;
60
61 /* Is it OK to move there? */
62 if (step_ok(y, x, NOMONST, tp) &&
63 (!isatrap(mvwinch(cw, y, x)) ||
64 rnd(10) >= tp->t_stats.s_intel ||
65 on(*tp, ISFLY))) {
66 /* OK, we can go here. But don't go there if
67 * monster can't get at player from there
68 */
69 tryp.y = y;
70 tryp.x = x;
71 if (diag_ok(&tryp, &hero, tp)) {
72 spots[index] = TRUE;
73 found_one = TRUE;
74 }
75 }
76 }
77
78 /* If we found one, go to it */
79 if (found_one) {
80 unsigned char rch; /* What's really where the creatures moves to */
81
82 /* Find a legal spot */
83 while (spots[index=rnd(9)] == FALSE) continue;
84
85 /* Get the coordinates */
86 y = hero.y + (index/3) - 1;
87 x = hero.x + (index % 3) - 1;
88
89 /* Move the monster from the old space */
90 mvwaddch(cw, tp->t_pos.y, tp->t_pos.x, tp->t_oldch);
91
92 /* Move it to the new space */
93 tp->t_oldch = mvwinch(cw, y, x);
94
95 /* Display the creature if our hero can see it */
96 if (cansee(y, x) &&
97 off(*tp, ISINWALL) &&
98 !invisible(tp))
99 mvwaddch(cw, y, x, tp->t_type);
100
101 /* Fix the monster window */
102 mvwaddch(mw, tp->t_pos.y, tp->t_pos.x, ' '); /* Clear old position */
103 mvwaddch(mw, y, x, tp->t_type);
104
105 /* Record the new position */
106 tp->t_pos.y = y;
107 tp->t_pos.x = x;
108
109 /* If the monster is on a trap, trap it */
110 rch = mvinch(y, x);
111 if (isatrap(rch)) {
112 if (cansee(y, x)) tp->t_oldch = rch;
113 be_trapped(tp, &(tp->t_pos));
114 }
115 }
116
117 return(found_one);
118 }
119
120 /*
121 * Can_shoot determines if the monster (er) has a direct line of shot
122 * at the prey (ee). If so, it returns the direction in which to shoot.
123 */
124
125 int
126 can_shoot(er, ee, shoot_dir)
127 register coord *er, *ee, *shoot_dir;
128 {
129 /*
130 * They must be in the same room or very close (at door)
131 */
132 if (roomin(er) != roomin(ee) && DISTANCE(er->y,er->x,ee->y,ee->x) > 1)
133 {
134 shoot_dir->x = shoot_dir->y = 0;
135 return(-1);
136 }
137
138 /* Do we have a straight shot? */
139 if (!straight_shot(er->y, er->x, ee->y, ee->x, shoot_dir))
140 {
141 shoot_dir->x = shoot_dir->y = 0;
142 return(-2);
143 }
144 else
145 return(0);
146 }
147
148 /*
149 * chase:
150 * Find the spot for the chaser(er) to move closer to the
151 * chasee(ee). Rer is the room of the chaser, and ree is the
152 * room of the creature being chased (chasee).
153 */
154
155 chase(tp, ee, rer, ree, flee)
156 register struct thing *tp;
157 register coord *ee;
158 register struct room *rer, *ree;
159 bool flee; /* True if destination (ee) is player and monster is running away
160 * or the player is in a wall and the monster can't get to it
161 */
162 {
163 int dist, thisdist, monst_dist = INT_MAX;
164 register coord *er = &tp->t_pos;
165 struct thing *prey; /* What we are chasing */
166 coord ch_ret; /* Where chasing takes you */
167 unsigned char ch, mch;
168 bool next_player = FALSE;
169
170 /*
171 * set the distance from the chas(er) to the chas(ee) here and then
172 * we won't have to reset it unless the chas(er) moves (instead of shoots)
173 */
174 dist = DISTANCE(er->y, er->x, ee->y, ee->x);
175
176 /*
177 * See if our destination is a monster or player. If so, make "prey" point
178 * to it.
179 */
180 if (ce(hero, *ee)) prey = &player; /* Is it the player? */
181 else if (tp->t_dest && ce(*(tp->t_dest), *ee)) { /* Is it a monster? */
182 struct linked_list *item;
183
184 /* What is the monster we're chasing? */
185 item = find_mons(ee->y, ee->x);
186 if (item != NULL) prey = THINGPTR(item);
187 else prey = NULL;
188 }
189 else prey = NULL;
190
191 /* We will use at least one movement period */
192 tp->t_no_move = movement(tp);
193 if (on(*tp, ISFLY)) /* If the creature is flying, speed it up */
194 tp->t_no_move /= 2;
195
196 /*
197 * If the thing is confused or it can't see the player,
198 * let it move randomly.
199 */
200 if ((on(*tp, ISHUH) && rnd(10) < 8) ||
201 (prey && on(*prey, ISINVIS) && off(*tp, CANSEE))) { /* invisible prey */
202 /*
203 * get a valid random move
204 */
205 tp->t_newpos = rndmove(tp);
206 dist = DISTANCE(tp->t_newpos.y, tp->t_newpos.x, ee->y, ee->x);
207 }
208
209 /*
210 * Otherwise, find the empty spot next to the chaser that is
211 * closest to the chasee.
212 */
213 else {
214 register int ey, ex, x, y;
215 int dist_to_old = INT_MIN; /* Dist from goal to old position */
216
217 /*
218 * This will eventually hold where we move to get closer
219 * If we can't find an empty spot, we stay where we are.
220 */
221 dist = flee ? 0 : INT_MAX;
222 ch_ret = *er;
223
224 /* Are we at our goal already? */
225 if (!flee && ce(ch_ret, *ee)) {
226 turn_off(*tp, ISRUN); /* So stop running! */
227 return;
228 }
229
230 ey = er->y + 1;
231 ex = er->x + 1;
232
233 /* Check all possible moves */
234 for (x = er->x - 1; x <= ex; x++) {
235 if (x < 0 || x >= cols) /* Don't try off the board */
236 continue;
237 for (y = er->y - 1; y <= ey; y++) {
238 coord tryp;
239
240 if ((y < 1) || (y >= lines - 2)) /* Don't try off the board */
241 continue;
242
243 /* Don't try the player if not going after the player */
244 if ((flee || !ce(hero, *ee) || on(*tp, ISFRIENDLY)) &&
245 x == hero.x && y == hero.y) {
246 next_player = TRUE;
247 continue;
248 }
249
250 tryp.x = x;
251 tryp.y = y;
252
253 /* Is there a monster on this spot closer to our goal?
254 * Don't look in our spot or where we were.
255 */
256 if (!ce(tryp, *er) && !ce(tryp, tp->t_oldpos) &&
257 isalpha(mch = mvwinch(mw, y, x))) {
258 int test_dist;
259
260 test_dist = DISTANCE(y, x, ee->y, ee->x);
261 if (test_dist <= 25 && /* Let's be fairly close */
262 test_dist < monst_dist) {
263 /* Could we really move there? */
264 mvwaddch(mw, y, x, ' '); /* Temporarily blank monst */
265 if (diag_ok(er, &tryp, tp)) monst_dist = test_dist;
266 mvwaddch(mw, y, x, mch); /* Restore monster */
267 }
268 }
269
270 /* Can we move onto the spot? */
271 if (!diag_ok(er, &tryp, tp)) continue;
272
273 ch = mvwinch(cw, y, x); /* Screen character */
274
275 /*
276 * Stepping on player is NOT okay if we are fleeing.
277 * If we are friendly to the player and there is a monster
278 * in the way that is not of our race, it is okay to move
279 * there.
280 */
281 if (step_ok(y, x, FIGHTOK, tp) &&
282 (off(*tp, ISFLEE) || ch != PLAYER))
283 {
284 /*
285 * If it is a trap, an intelligent monster may not
286 * step on it (unless our hero is on top!)
287 */
288 if ((isatrap(ch)) &&
289 (rnd(10) < tp->t_stats.s_intel) &&
290 (!on(*tp, ISFLY)) &&
291 (y != hero.y || x != hero.x))
292 continue;
293
294 /*
295 * OK -- this place counts
296 */
297 thisdist = DISTANCE(y, x, ee->y, ee->x);
298
299 /* Adjust distance if we are being shot at */
300 if (tp->t_wasshot && tp->t_stats.s_intel > 5 &&
301 prey != NULL) {
302 /* Move out of line of sight */
303 if (straight_shot(tryp.y, tryp.x, ee->y, ee->x, (coord *)NULL)) {
304 if (flee) thisdist -= SHOTPENALTY;
305 else thisdist += SHOTPENALTY;
306 }
307
308 /* But do we want to leave the room? */
309 else if (rer && rer == ree && ch == DOOR)
310 thisdist += DOORPENALTY;
311 }
312
313 /* Don't move to the last position if we can help it
314 * (unless out prey just moved there)
315 */
316 if (ce(tryp, tp->t_oldpos) && (flee || !ce(tryp, hero)))
317 dist_to_old = thisdist;
318
319 else if ((flee && (thisdist > dist)) ||
320 (!flee && (thisdist < dist)))
321 {
322 ch_ret = tryp;
323 dist = thisdist;
324 }
325 }
326 }
327 }
328
329 /* If we aren't trying to get the player, but he is in our way,
330 * hit him (unless we have been turned or are friendly). next_player
331 * being TRUE -> we are next to the player but don't want to hit him.
332 *
333 * If we are friendly to the player, following him, and standing next
334 * to him, we will try to help him out in battle.
335 */
336 if (next_player && off(*tp, WASTURNED)) {
337 if (off(*tp, ISFRIENDLY) &&
338 ((flee && ce(ch_ret, *er)) ||
339 (!flee && DISTANCE(er->y, er->x, ee->y, ee->x) < dist)) &&
340 step_ok(tp->t_dest->y, tp->t_dest->x, NOMONST, tp)) {
341 /* Okay to hit player */
342 debug("Switching to hero.");
343 tp->t_newpos = hero;
344 tp->t_action = A_MOVE;
345 return;
346 }
347 else if (on(*tp, ISFRIENDLY) && !flee && ce(*ee, hero)) {
348 /*
349 * Look all around the player. If there is a fightable
350 * creature next to both of us, hit it. Otherwise, if
351 * there is a fightable creature next to the player, try
352 * to move next to it.
353 */
354 dist = INT_MAX;
355 for (x = hero.x - 1; x <= hero.x + 1; x++) {
356 if (x < 0 || x >= cols) /* Don't try off the board */
357 continue;
358 for (y = hero.y - 1; y <= hero.y + 1; y++) {
359 if ((y < 1) || (y >= lines - 2)) /* Stay on the board */
360 continue;
361
362 /* Is there a fightable monster here? */
363 if (isalpha(mvwinch(mw, y, x)) &&
364 step_ok(y, x, FIGHTOK, tp) &&
365 off(*tp, ISSTONE)) {
366 thisdist = DISTANCE(er->y, er->x, y, x);
367 if (thisdist < dist) {
368 dist = thisdist;
369 ch_ret.y = y;
370 ch_ret.x = x;
371 }
372 }
373 }
374 }
375
376 /* Are we next to a bad guy? */
377 if (dist <= 2) { /* Get him! */
378 tp->t_newpos = ch_ret;
379 tp->t_action = A_MOVE;
380 }
381
382 /* Try to move to the bad guy */
383 else if (dist < INT_MAX)
384 chase(tp, &ch_ret,
385 roomin(&tp->t_pos), roomin(&ch_ret), FALSE);
386
387 else tp->t_action = A_NIL;
388
389 return;
390 }
391 }
392
393 /*
394 * If we have decided that we can move onto a monster (we are
395 * friendly to the player, go to it.
396 */
397 if (!ce(ch_ret, *er) && isalpha(mvwinch(mw, ch_ret.y, ch_ret.x))) {
398 debug("Attack monster");
399 tp->t_newpos = ch_ret;
400 tp->t_action = A_MOVE;
401 return;
402 }
403
404 /* If we can't get closer to the player (if that's our goal)
405 * because other monsters are in the way, just stay put
406 */
407 if (!flee && ce(hero, *ee) && monst_dist < INT_MAX &&
408 DISTANCE(er->y, er->x, hero.y, hero.x) < dist) {
409 tp->t_action = A_NIL; /* do nothing for awhile */
410 return;
411 }
412
413 /* Do we want to go back to the last position? */
414 else if (dist_to_old != INT_MIN && /* It is possible to move back */
415 ((flee && dist == 0) || /* No other possible moves */
416 (!flee && dist == INT_MAX))) {
417 /* Do we move back or just stay put (default)? */
418 dist = DISTANCE(er->y, er->x, ee->y, ee->x); /* Current distance */
419 if (!flee || (flee && (dist_to_old > dist))) ch_ret = tp->t_oldpos;
420 }
421
422 /* Record the new destination */
423 tp->t_newpos = ch_ret;
424 }
425
426 /*
427 * Do we want to fight or move? If our selected destination (ch_ret)
428 * is our hero, then we want to fight. Otherwise, we want to move.
429 */
430 if (ce(tp->t_newpos, hero)) {
431 /* Fight! (or sell) */
432 if (on(*tp, CANSELL)) {
433 tp->t_action = A_SELL;
434 tp->t_no_move += movement(tp); /* takes a little time to sell */
435 }
436 else {
437 tp->t_action = A_ATTACK;
438
439 /*
440 * Try to find a weapon to wield. Wield_weap will return a
441 * projector if weapon is a projectile (eg. bow for arrow).
442 * If weapon is NULL (the case here), it will try to find
443 * a suitable weapon.
444 *
445 * Add in rest of time. Fight is
446 * movement() + weap_move() + FIGHTBASE
447 */
448 tp->t_using = wield_weap((struct object *)NULL, tp);
449 if (tp->t_using == NULL)
450 tp->t_no_move += weap_move(tp, (struct object *)NULL);
451 else
452 tp->t_no_move += weap_move(tp, OBJPTR(tp->t_using));
453
454 if (on(*tp, ISHASTE))
455 tp->t_no_move += FIGHTBASE/2;
456 else if (on(*tp, ISSLOW))
457 tp->t_no_move += FIGHTBASE*2;
458 else
459 tp->t_no_move += FIGHTBASE;
460 }
461 }
462 else {
463 /* Move */
464 tp->t_action = A_MOVE;
465
466 /*
467 * Check if the creature is not next to the player. If it
468 * is not and has held or suffocated the player, then stop it!
469 * Note that this code should more appropriately appear in
470 * the area that actually moves the monster, but for now it
471 * is okay here because the player can't move while held or
472 * suffocating.
473 */
474 if (dist > 2) {
475 if (on(*tp, DIDHOLD)) {
476 turn_off(*tp, DIDHOLD);
477 turn_on(*tp, CANHOLD);
478 if (--hold_count == 0)
479 turn_off(player, ISHELD);
480 }
481
482 /* If monster was suffocating, stop it */
483 if (on(*tp, DIDSUFFOCATE)) {
484 turn_off(*tp, DIDSUFFOCATE);
485 turn_on(*tp, CANSUFFOCATE);
486 extinguish(suffocate);
487 msg("You can breathe again.....Whew!");
488 }
489 }
490 }
491 }
492
493 /*
494 * do_chase:
495 * Make one thing chase another.
496 */
497
498 do_chase(th)
499 register struct thing *th;
500 {
501 register struct room *orig_rer, /* Original room of chaser */
502 *new_room; /* new room of monster */
503 unsigned char floor, rch, sch;
504 coord old_pos, /* Old position of monster */
505 ch_ret; /* Where we want to go */
506
507 if (on(*th, NOMOVE)) return;
508
509 ch_ret = th->t_newpos; /* Record our desired new position */
510
511 /*
512 * Make sure we have an open spot (no other monster's gotten in our way,
513 * someone didn't just drop a scare monster there, our prey didn't just
514 * get there, etc.)
515 */
516 if (!step_ok(th->t_newpos.y, th->t_newpos.x, FIGHTOK, th)) {
517 /*
518 * Most monsters get upset now. Guardians are all friends,
519 * and we don't want to see 50 messages in a row!
520 */
521 if (th->t_stats.s_intel > 4 &&
522 off(*th, ISUNDEAD) &&
523 off(*th, ISGUARDIAN) &&
524 off(*th, AREMANY) &&
525 off(*th, ISHUH) &&
526 off(*th, ISCHARMED) &&
527 off(player, ISBLIND) &&
528 cansee(unc(th->t_pos)) &&
529 !invisible(th) && (rnd(15) < 5)) {
530 switch (rnd(10)) {
531 case 0: case 1:
532 msg("%s lashes out at you! ",prname(monster_name(th),TRUE));
533 when 2: case 3:
534 msg("%s scrambles around. ",prname(monster_name(th), TRUE));
535 otherwise:
536 msg("%s motions angrily. ", prname(monster_name(th), TRUE));
537 }
538 }
539 return;
540 }
541 else if (ce(th->t_newpos, hero) || /* Player just got in our way */
542 isalpha(mvwinch(mw, th->t_newpos.y, th->t_newpos.x))) {
543 bool fightplayer = ce(th->t_newpos, hero);
544
545 /* If we were turned or are friendly, we just have to sit here! */
546 if (fightplayer && (on(*th, WASTURNED) || on(*th, ISFRIENDLY))) return;
547
548 /* Do we want to sell something? */
549 if (fightplayer && on(*th, CANSELL)) {
550 th->t_action = A_SELL;
551 th->t_no_move += movement(th); /* takes a little time to sell */
552 return;
553 }
554
555 /* Let's hit him */
556 th->t_action = A_ATTACK;
557
558 /*
559 * Try to find a weapon to wield. Wield_weap will return a
560 * projector if weapon is a projectile (eg. bow for arrow).
561 * If weapon is NULL (the case here), it will try to find
562 * a suitable weapon.
563 */
564 th->t_using = wield_weap((struct object *)NULL, th);
565 /*
566 * add in rest of time
567 */
568 if (th->t_using == NULL)
569 th->t_no_move += weap_move(th, (struct object *)NULL);
570 else
571 th->t_no_move += weap_move(th, OBJPTR(th->t_using));
572 if (on(*th, ISHASTE))
573 th->t_no_move += FIGHTBASE/2;
574 else if (on(*th, ISSLOW))
575 th->t_no_move += FIGHTBASE*2;
576 else
577 th->t_no_move += FIGHTBASE;
578 return;
579 }
580
581 /*
582 * Blank out the old position and record the new position --
583 * the blanking must be done first in case the positions are the same.
584 */
585 mvwaddch(mw, th->t_pos.y, th->t_pos.x, ' ');
586 mvwaddch(mw, ch_ret.y, ch_ret.x, th->t_type);
587
588 /* Get new and old rooms of monster */
589 new_room = roomin(&ch_ret);
590 orig_rer = roomin(&th->t_pos);
591
592 /* Store the critter's old position and update the current one */
593 old_pos = th->t_pos;
594 th->t_pos = ch_ret;
595 floor = (roomin(&ch_ret) == NULL) ? PASSAGE : FLOOR;
596
597 /* If we have a scavenger, it can pick something up */
598 if (off(*th, ISGUARDIAN)) {
599 register struct linked_list *n_item, *o_item;
600 register int item_count = 0;
601 bool want_something = FALSE;
602
603 while ((n_item = find_obj(ch_ret.y, ch_ret.x)) != NULL) {
604 register struct object *n_obj, *o_obj;
605 bool wants_it;
606
607 /* Does this monster want anything? */
608 if (want_something == FALSE) {
609 if (on(*th, ISSCAVENGE) || on(*th, CARRYFOOD) ||
610 on(*th, CARRYGOLD) || on(*th, CARRYSCROLL) ||
611 on(*th, CARRYPOTION) || on(*th, CARRYRING) ||
612 on(*th, CARRYSTICK) || on(*th, CARRYMISC) ||
613 on(*th, CARRYWEAPON) || on(*th, CARRYARMOR) ||
614 on(*th, CARRYDAGGER)) {
615 want_something = TRUE;
616
617 /*
618 * Blank the area. We have to do it only before the
619 * first item in case an item gets dropped in same
620 * place. We don't want to blank it out after it get
621 * dropped.
622 */
623 mvaddch(ch_ret.y, ch_ret.x, floor);
624
625 /* Were we specifically after something here? */
626 if (ce(*th->t_dest, ch_ret)) {
627 /* If we're mean, we go after the hero */
628 if (on(*th, ISMEAN)) runto(th, &hero);
629
630 /* Otherwise just go back to sleep */
631 else {
632 turn_off(*th, ISRUN);
633 th->t_dest = NULL;
634 }
635 }
636 }
637 else break;
638 }
639
640 item_count++; /* Count the number of items */
641
642 /*
643 * see if he's got one of this group already
644 */
645 o_item = NULL;
646 n_obj = OBJPTR(n_item);
647 detach(lvl_obj, n_item);
648
649 /* See if he wants it */
650 if (n_obj->o_type == SCROLL && n_obj->o_which == S_SCARE &&
651 th->t_stats.s_intel < 16)
652 wants_it = FALSE; /* Most monsters don't want a scare monster */
653 else if (on(*th, ISSCAVENGE)) wants_it = TRUE;
654 else {
655 wants_it = FALSE; /* Default case */
656 switch (n_obj->o_type) {
657 case FOOD: if(on(*th, CARRYFOOD)) wants_it = TRUE;
658 when GOLD: if(on(*th, CARRYGOLD)) wants_it = TRUE;
659 when SCROLL:if(on(*th, CARRYSCROLL)) wants_it = TRUE;
660 when POTION:if(on(*th, CARRYPOTION)) wants_it = TRUE;
661 when RING: if(on(*th, CARRYRING)) wants_it = TRUE;
662 when STICK: if(on(*th, CARRYSTICK)) wants_it = TRUE;
663 when MM: if(on(*th, CARRYMISC)) wants_it = TRUE;
664 when ARMOR: if(on(*th, CARRYARMOR)) wants_it = TRUE;
665 when WEAPON:if(on(*th, CARRYWEAPON) ||
666 (on(*th,CARRYDAGGER)&&n_obj->o_which==DAGGER))
667 wants_it = TRUE;
668 }
669 }
670 /*
671 * The quartermaster doesn't sell cursed stuff so he won't
672 * pick it up
673 */
674 if (on(*th, CANSELL) && (n_obj->o_flags & ISCURSED))
675 wants_it = FALSE;
676
677 /* If he doesn't want it, throw it away */
678 if (wants_it == FALSE) {
679 fall(n_item, FALSE);
680 continue;
681 }
682
683 /* Otherwise, let's pick it up */
684 if (n_obj->o_group) {
685 for(o_item = th->t_pack; o_item != NULL; o_item = next(o_item)){
686 o_obj = OBJPTR(o_item);
687 if (o_obj->o_group == n_obj->o_group) {
688 o_obj->o_count += n_obj->o_count;
689 o_discard(n_item);
690 break;
691 }
692 }
693 }
694 if (o_item == NULL) { /* didn't find it */
695 attach(th->t_pack, n_item);
696 }
697 }
698
699 /* If there was anything here, we may have to update the screen */
700 if (item_count) {
701 if (cansee(ch_ret.y, ch_ret.x))
702 mvwaddch(cw, ch_ret.y, ch_ret.x, mvinch(ch_ret.y, ch_ret.x));
703 updpack(TRUE, th); /* Update the monster's encumberance, too */
704 }
705 }
706
707 rch = mvwinch(stdscr, old_pos.y, old_pos.x);
708 if (th->t_oldch == floor && rch != floor && !isatrap(rch))
709 mvwaddch(cw, old_pos.y, old_pos.x, rch);
710 else
711 mvwaddch(cw, old_pos.y, old_pos.x, th->t_oldch);
712 sch = mvwinch(cw, ch_ret.y, ch_ret.x); /* What player sees */
713 rch = mvwinch(stdscr, ch_ret.y, ch_ret.x); /* What's really there */
714
715 /* If we have a tunneling monster, it may be making a tunnel */
716 if (on(*th, CANTUNNEL) &&
717 (rch==SECRETDOOR || rch==WALL || rch==VERTWALL || rch==HORZWALL)) {
718 unsigned char nch; /* The new look to the tunnel */
719
720 if (rch == WALL && levtype == OUTSIDE) nch = FLOOR;
721 else if (rch == WALL) nch = PASSAGE;
722 else if (levtype == MAZELEV || levtype == OUTSIDE) nch = FLOOR;
723 else nch = DOOR;
724 addch(nch);
725
726 if (cansee(ch_ret.y, ch_ret.x)) sch = nch; /* Can player see this? */
727
728 /* Does this make a new exit? */
729 if (rch == VERTWALL || rch == HORZWALL) {
730 struct linked_list *newroom;
731 coord *exit;
732
733 newroom = new_item(sizeof(coord));
734 exit = DOORPTR(newroom);
735 *exit = ch_ret;
736 attach(new_room->r_exit, newroom);
737 }
738 }
739
740 /* Mark if the monster is inside a wall */
741 if (isrock(mvinch(ch_ret.y, ch_ret.x))) turn_on(*th, ISINWALL);
742 else turn_off(*th, ISINWALL);
743
744 /* If the monster can illuminate rooms, check for a change */
745 if (on(*th, HASFIRE)) {
746 register struct linked_list *fire_item;
747
748 /* Is monster entering a room? */
749 if (orig_rer != new_room && new_room != NULL) {
750 fire_item = creat_item(); /* Get an item-only structure */
751 ldata(fire_item) = (char *) th;
752
753 attach(new_room->r_fires, fire_item);
754 new_room->r_flags |= HASFIRE;
755
756 if (cansee(ch_ret.y, ch_ret.x) && next(new_room->r_fires) == NULL)
757 light(&hero);
758 }
759
760 /* Is monster leaving a room? */
761 if (orig_rer != new_room && orig_rer != NULL) {
762 /* Find the bugger in the list and delete him */
763 for (fire_item = orig_rer->r_fires; fire_item != NULL;
764 fire_item = next(fire_item)) {
765 if (THINGPTR(fire_item) == th) { /* Found him! */
766 detach(orig_rer->r_fires, fire_item);
767 destroy_item(fire_item);
768 if (orig_rer->r_fires == NULL) {
769 orig_rer->r_flags &= ~HASFIRE;
770 if (cansee(old_pos.y, old_pos.x))
771 light(&old_pos);
772 }
773 break;
774 }
775 }
776 }
777 }
778
779 /* If monster is entering player's room and player can see it,
780 * stop the player's running.
781 */
782 if (new_room != orig_rer && new_room != NULL &&
783 new_room == roomin(th->t_dest) && cansee(unc(ch_ret)) &&
784 (off(*th, ISINVIS) || on(player, CANSEE)) &&
785 (off(*th, ISSHADOW) || on(player, CANSEE)) &&
786 (off(*th, CANSURPRISE) || ISWEARING(R_ALERT))) {
787 running = FALSE;
788 if (fight_flush) flushinp();
789 }
790
791 th->t_oldch = sch;
792
793 /* Let's display those creatures that we can see. */
794 if (cansee(unc(ch_ret)) &&
795 off(*th, ISINWALL) &&
796 !invisible(th))
797 mvwaddch(cw, ch_ret.y, ch_ret.x, th->t_type);
798
799 /* Record monster's last position (if new one is different) */
800 if (!ce(ch_ret, old_pos)) th->t_oldpos = old_pos;
801
802 /* If the monster is on a trap, trap it */
803 sch = mvinch(ch_ret.y, ch_ret.x);
804 if (isatrap(sch)) {
805 if (cansee(ch_ret.y, ch_ret.x)) th->t_oldch = sch;
806 be_trapped(th, &ch_ret);
807 }
808 }
809
810 /*
811 * Get_hurl returns the weapon that the monster will "throw" if he has one
812 */
813
814 struct linked_list *
815 get_hurl(tp)
816 register struct thing *tp;
817 {
818 struct linked_list *arrow=NULL, *bolt=NULL, *rock=NULL,
819 *spear = NULL, *dagger=NULL, *dart=NULL, *aklad=NULL;
820 register struct linked_list *pitem;
821 register struct object *obj;
822 bool bow=FALSE, crossbow=FALSE, sling=FALSE;
823
824 for (pitem=tp->t_pack; pitem; pitem=next(pitem)) {
825 obj = OBJPTR(pitem);
826 if (obj->o_type == WEAPON)
827 switch (obj->o_which) {
828 case BOW: bow = TRUE;
829 when CROSSBOW: crossbow = TRUE;
830 when SLING: sling = TRUE;
831 when ROCK: rock = pitem;
832 when ARROW: arrow = pitem;
833 when BOLT: bolt = pitem;
834 when SPEAR: spear = pitem;
835 when DAGGER:
836 /* Don't throw the dagger if it's our last one */
837 if (obj->o_count > 1) dagger = pitem;
838 when DART: dart = pitem;
839 }
840 else if (obj->o_type == RELIC &&
841 obj->o_which == AXE_AKLAD)
842 aklad = pitem;
843 }
844
845 /* Do we have that all-powerful Aklad Axe? */
846 if (aklad) return(aklad);
847
848 /* Use crossbow bolt if possible */
849 if (crossbow && bolt) return(bolt);
850 if (bow && arrow) return(arrow);
851 if (spear) return(spear);
852 if (dagger) return(dagger);
853 if (sling && rock) return(rock);
854 if (dart) return(dart);
855 return(NULL);
856 }
857
858 /*
859 * runto:
860 * Set a monster running after something
861 */
862
863 runto(runner, spot)
864 register struct thing *runner;
865 coord *spot;
866 {
867 if (on(*runner, ISSTONE))
868 return;
869
870 /* If we are chasing a new creature, forget about thrown weapons */
871 if (runner->t_dest && !ce(*runner->t_dest, *spot)) runner->t_wasshot=FALSE;
872
873 /*
874 * Start the beastie running
875 */
876 runner->t_dest = spot;
877 turn_on(*runner, ISRUN);
878 turn_off(*runner, ISDISGUISE);
879 }
880
881 /*
882 * straight_shot:
883 * See if there is a straight line of sight between the two
884 * given coordinates. If shooting is not NULL, it is a pointer
885 * to a structure which should be filled with the direction
886 * to shoot (if there is a line of sight). If shooting, monsters
887 * get in the way. Otherwise, they do not.
888 */
889
890 bool
891 straight_shot(ery, erx, eey, eex, shooting)
892 register int ery, erx, eey, eex;
893 register coord *shooting;
894 {
895 register int dy, dx; /* Deltas */
896 unsigned char ch;
897
898 /* Does the monster have a straight shot at prey */
899 if ((ery != eey) && (erx != eex) &&
900 (abs(ery - eey) != abs(erx - eex))) return(FALSE);
901
902 /* Get the direction to shoot */
903 if (eey > ery) dy = 1;
904 else if (eey == ery) dy = 0;
905 else dy = -1;
906
907 if (eex > erx) dx = 1;
908 else if (eex == erx) dx = 0;
909 else dx = -1;
910
911 /* Make sure we have free area all the way to the player */
912 ery += dy;
913 erx += dx;
914 while ((ery != eey) || (erx != eex)) {
915 switch (ch = winat(ery, erx)) {
916 case VERTWALL:
917 case HORZWALL:
918 case WALL:
919 case DOOR:
920 case SECRETDOOR:
921 case FOREST:
922 return(FALSE);
923 default:
924 if (shooting && isalpha(ch)) return(FALSE);
925 }
926 ery += dy;
927 erx += dx;
928 }
929
930 if (shooting) { /* If we are shooting -- put in the directions */
931 shooting->y = dy;
932 shooting->x = dx;
933 }
934 return(TRUE);
935 }
936