Annotation of early-roguelike/arogue5/chase.c, Revision 1.1.1.1
1.1 rubenllo 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 <stdlib.h>
16: #include <ctype.h>
17: #include <limits.h>
18: #include "curses.h"
19: #include "rogue.h"
20: #define MAXINT INT_MAX
21: #define MININT INT_MIN
22:
23: coord ch_ret; /* Where chasing takes you */
24:
25: struct linked_list *get_hurl(struct thing *tp);
26: bool straight_shot(int ery, int erx, int eey, int eex, coord *shooting);
27:
28:
29: /*
30: * Canblink checks if the monster can teleport (blink). If so, it will
31: * try to blink the monster next to the player.
32: */
33:
34: bool
35: can_blink(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(coord *er, coord *ee)
132: {
133: static coord shoot_dir;
134:
135: /* Make sure we are chasing the player */
136: if (!ce((*ee), hero)) return(NULL);
137:
138: /*
139: * They must be in the same room or very close (at door)
140: */
141: if (roomin(er) != roomin(&hero) && DISTANCE(er->y,er->x,ee->y,ee->x) > 1)
142: return(NULL);
143:
144: /* Do we have a straight shot? */
145: if (!straight_shot(er->y, er->x, ee->y, ee->x, &shoot_dir)) return(NULL);
146: else return(&shoot_dir);
147: }
148:
149: /*
150: * chase:
151: * Find the spot for the chaser(er) to move closer to the
152: * chasee(ee). Returns TRUE if we want to keep on chasing later
153: * FALSE if we reach the goal.
154: */
155:
156: /* flee: True if destination (ee) is player and monster is running
157: * away or the player is in a wall and the monster can't get to it
158: */
159: bool
160: chase(struct thing *tp, coord *ee, bool flee, bool *mdead)
161: {
162: int damage, dist, thisdist, monst_dist = MAXINT;
163: struct linked_list *weapon;
164: register coord *er = &tp->t_pos;
165: coord *shoot_dir;
166: char ch, mch;
167: bool next_player = FALSE;
168:
169: if (mdead != NULL)
170: *mdead = 0;
171:
172: /*
173: * set the distance from the chas(er) to the chas(ee) here and then
174: * we won't have to reset it unless the chas(er) moves (instead of shoots)
175: */
176: dist = DISTANCE(er->y, er->x, ee->y, ee->x);
177:
178: /*
179: * If the thing is confused or it can't see the player,
180: * let it move randomly.
181: */
182: if ((on(*tp, ISHUH) && rnd(10) < 8) ||
183: (on(player, ISINVIS) && off(*tp, CANSEE))) { /* Player is invisible */
184: /*
185: * get a valid random move
186: */
187: ch_ret = *rndmove(tp);
188: dist = DISTANCE(ch_ret.y, ch_ret.x, ee->y, ee->x);
189: /*
190: * check to see if random move takes creature away from player
191: * if it does then turn off ISHELD
192: */
193: if (dist > 2) {
194: if (on(*tp, DIDHOLD)) {
195: turn_off(*tp, DIDHOLD);
196: turn_on(*tp, CANHOLD);
197: if (--hold_count == 0)
198: turn_off(player, ISHELD);
199: }
200:
201: /* If monster was suffocating, stop it */
202: if (on(*tp, DIDSUFFOCATE)) {
203: turn_off(*tp, DIDSUFFOCATE);
204: turn_on(*tp, CANSUFFOCATE);
205: extinguish(suffocate);
206: }
207: }
208: }
209:
210: /* If we can breathe, we may do so */
211: else if (on(*tp, CANBREATHE) &&
212: (dist < BOLT_LENGTH*BOLT_LENGTH) &&
213: (shoot_dir = can_shoot(er, ee)) &&
214: !on(player, ISINWALL) &&
215: (rnd(100) < 75)) {
216: register char *breath = NULL;
217:
218: damage = tp->t_stats.s_hpt;
219: /* Will it breathe at random */
220: if (on(*tp, CANBRANDOM)) {
221: /* Turn off random breath */
222: turn_off(*tp, CANBRANDOM);
223:
224: /* Select type of breath */
225: switch (rnd(10)) {
226: case 0: breath = "acid";
227: turn_on(*tp, NOACID);
228: when 1: breath = "flame";
229: turn_on(*tp, NOFIRE);
230: when 2: breath = "lightning bolt";
231: turn_on(*tp, NOBOLT);
232: when 3: breath = "chlorine gas";
233: turn_on(*tp, NOGAS);
234: when 4: breath = "ice";
235: turn_on(*tp, NOCOLD);
236: when 5: breath = "nerve gas";
237: turn_on(*tp, NOPARALYZE);
238: when 6: breath = "sleeping gas";
239: turn_on(*tp, NOSLEEP);
240: when 7: breath = "slow gas";
241: turn_on(*tp, NOSLOW);
242: when 8: breath = "confusion gas";
243: turn_on(*tp, ISCLEAR);
244: when 9: breath = "fear gas";
245: turn_on(*tp, NOFEAR);
246: }
247: }
248:
249: /* Or can it breathe acid? */
250: else if (on(*tp, CANBACID)) {
251: turn_off(*tp, CANBACID);
252: breath = "acid";
253: }
254:
255: /* Or can it breathe fire */
256: else if (on(*tp, CANBFIRE)) {
257: turn_off(*tp, CANBFIRE);
258: breath = "flame";
259: }
260:
261: /* Or can it breathe electricity? */
262: else if (on(*tp, CANBBOLT)) {
263: turn_off(*tp, CANBBOLT);
264: breath = "lightning bolt";
265: }
266:
267: /* Or can it breathe gas? */
268: else if (on(*tp, CANBGAS)) {
269: turn_off(*tp, CANBGAS);
270: breath = "chlorine gas";
271: }
272:
273: /* Or can it breathe ice? */
274: else if (on(*tp, CANBICE)) {
275: turn_off(*tp, CANBICE);
276: breath = "ice";
277: }
278:
279: else if (on(*tp, CANBPGAS)) {
280: turn_off(*tp, CANBPGAS);
281: breath = "nerve gas";
282: }
283:
284: /* can it breathe sleeping gas */
285: else if (on(*tp, CANBSGAS)) {
286: turn_off(*tp, CANBSGAS);
287: breath = "sleeping gas";
288: }
289:
290: /* can it breathe slow gas */
291: else if (on(*tp, CANBSLGAS)) {
292: turn_off(*tp, CANBSLGAS);
293: breath = "slow gas";
294: }
295: /* can it breathe confusion gas */
296: else if (on(*tp, CANBCGAS)) {
297: turn_off(*tp, CANBCGAS);
298: breath = "confusion gas";
299: }
300: /* can it breathe fear gas */
301: else {
302: turn_off(*tp, CANBFGAS);
303: breath = "fear gas";
304: }
305:
306: /* Now breathe -- sets "monst_dead" if it kills someone */
307: *mdead = shoot_bolt( tp, *er, *shoot_dir, FALSE,
308: tp->t_index, breath, damage);
309:
310: ch_ret = *er;
311: running = FALSE;
312: if (*mdead) return(TRUE);
313: }
314:
315: /* We may shoot missiles if we can */
316: else if (on(*tp, CANMISSILE) &&
317: (shoot_dir = can_shoot(er, ee)) &&
318: !on(player, ISINWALL) &&
319: (rnd(100) < 75)) {
320: static struct object missile =
321: {
322: MISSILE, {0, 0}, "", 0, "", "0d4 " , NULL, 0, WS_MISSILE, 100, 1
323: };
324:
325: sprintf(missile.o_hurldmg, "%dd4", tp->t_stats.s_lvl);
326: do_motion(&missile, shoot_dir->y, shoot_dir->x, tp);
327: hit_monster(unc(missile.o_pos), &missile, tp);
328: turn_off(*tp, CANMISSILE);
329: ch_ret = *er;
330: running = FALSE;
331: }
332:
333: /* We may use a sonic blast if we can */
334: else if (on(*tp, CANSONIC) &&
335: (dist < BOLT_LENGTH*2) &&
336: (shoot_dir = can_shoot(er, ee)) &&
337: !on(player, ISINWALL) &&
338: (rnd(100) < 50)) {
339: static struct object blast =
340: {
341: MISSILE, {0, 0}, "", 0, "", "150" , NULL, 0, 0, 0, 0
342: };
343:
344: turn_off(*tp, CANSONIC);
345: do_motion(&blast, shoot_dir->y, shoot_dir->x, tp);
346: damage = 150;
347: if (save(VS_BREATH, &player, -3))
348: damage /= 2;
349: msg ("The %s's sonic blast hits you", monsters[tp->t_index].m_name);
350: if ((pstats.s_hpt -= damage) <= 0)
351: death(tp->t_index);
352: ch_ret = *er;
353: running = FALSE;
354: }
355: /*
356: * If we have a special magic item, we might use it. We will restrict
357: * this options to uniques with relics for now.
358: */
359: else if (on(*tp, ISUNIQUE) && m_use_item(tp, er, ee)) {
360: ch_ret = *er;
361: running = FALSE;
362: }
363: /*
364: * If we can shoot or throw something, we might do so.
365: * If next to player, then 80% prob will fight.
366: */
367: else if(on(*tp, CANSHOOT) &&
368: (shoot_dir = can_shoot(er, ee)) &&
369: !on(player, ISINWALL) &&
370: (dist > 3 || (rnd(100) > 80)) &&
371: (weapon = get_hurl(tp))) {
372: missile(shoot_dir->y, shoot_dir->x, weapon, tp);
373: ch_ret = *er;
374: }
375:
376: /*
377: * Otherwise, find the empty spot next to the chaser that is
378: * closest to the chasee.
379: */
380: else {
381: register int ey, ex, x, y;
382: register struct room *rer, *ree;
383: int dist_to_old = MININT; /* Dist from goal to old position */
384:
385: /* Get rooms */
386: rer = roomin(er); /* Room the chasER (monster) is in */
387: ree = roomin(ee); /* Room the chasEE is in */
388:
389: /*
390: * This will eventually hold where we move to get closer
391: * If we can't find an empty spot, we stay where we are.
392: */
393: dist = flee ? 0 : MAXINT;
394: ch_ret = *er;
395:
396: /* Are we at our goal already? */
397: if (!flee && ce(ch_ret, *ee)) return(FALSE);
398:
399: ey = er->y + 1;
400: ex = er->x + 1;
401:
402: /* Check all possible moves */
403: for (x = er->x - 1; x <= ex; x++) {
404: if (x < 0 || x >= COLS) /* Don't try off the board */
405: continue;
406: for (y = er->y - 1; y <= ey; y++) {
407: coord tryp;
408:
409: if ((y < 1) || (y >= LINES - 2)) /* Don't try off the board */
410: continue;
411:
412: /* Don't try the player if not going after the player */
413: if ((flee || !ce(hero, *ee)) && x == hero.x && y == hero.y) {
414: next_player = TRUE;
415: continue;
416: }
417:
418: tryp.x = x;
419: tryp.y = y;
420:
421: /* Is there a monster on this spot closer to our goal?
422: * Don't look in our spot or where we were.
423: */
424: if (!ce(tryp, *er) && !ce(tryp, tp->t_oldpos) &&
425: isalpha(mch = CCHAR( mvwinch(mw, y, x) ) )) {
426: int test_dist;
427:
428: test_dist = DISTANCE(y, x, ee->y, ee->x);
429: if (test_dist <= 25 && /* Let's be fairly close */
430: test_dist < monst_dist) {
431: /* Could we really move there? */
432: mvwaddch(mw, y, x, ' '); /* Temporarily blank monst */
433: if (diag_ok(er, &tryp, tp)) monst_dist = test_dist;
434: mvwaddch(mw, y, x, mch); /* Restore monster */
435: }
436: }
437:
438: /* Can we move onto the spot? */
439: if (!diag_ok(er, &tryp, tp)) continue;
440:
441: ch = CCHAR( mvwinch(cw, y, x) ); /* Screen character */
442:
443: /* Stepping on player is NOT okay if we are fleeing */
444: if (step_ok(y, x, NOMONST, tp) &&
445: (off(*tp, ISFLEE) || ch != PLAYER))
446: {
447: /*
448: * If it is a trap, an intelligent monster may not
449: * step on it (unless our hero is on top!)
450: */
451: if ((isatrap(ch)) &&
452: (rnd(10) < tp->t_stats.s_intel) &&
453: (!on(*tp, ISFLY)) &&
454: (y != hero.y || x != hero.x))
455: continue;
456:
457: /*
458: * OK -- this place counts
459: */
460: thisdist = DISTANCE(y, x, ee->y, ee->x);
461:
462: /* Adjust distance if we are being shot at */
463: if (tp->t_wasshot && tp->t_stats.s_intel > 5 &&
464: ce(hero, *ee)) {
465: /* Move out of line of sight */
466: if (straight_shot(tryp.y, tryp.x, ee->y, ee->x, NULL)) {
467: if (flee) thisdist -= SHOTPENALTY;
468: else thisdist += SHOTPENALTY;
469: }
470:
471: /* But do we want to leave the room? */
472: else if (rer && rer == ree && ch == DOOR)
473: thisdist += DOORPENALTY;
474: }
475:
476: /* Don't move to the last position if we can help it
477: * (unless out prey just moved there)
478: */
479: if (ce(tryp, tp->t_oldpos) && (flee || !ce(tryp, hero)))
480: dist_to_old = thisdist;
481:
482: else if ((flee && (thisdist > dist)) ||
483: (!flee && (thisdist < dist)))
484: {
485: ch_ret = tryp;
486: dist = thisdist;
487: }
488: }
489: }
490: }
491:
492: /* If we aren't trying to get the player, but he is in our way,
493: * hit him (unless we have been turned)
494: */
495: if (next_player && off(*tp, WASTURNED) &&
496: ((flee && ce(ch_ret, *er)) ||
497: (!flee && DISTANCE(er->y, er->x, ee->y, ee->x) < dist)) &&
498: step_ok(tp->t_dest->y, tp->t_dest->x, NOMONST, tp)) {
499: /* Okay to hit player */
500: ch_ret = hero;
501: return(FALSE);
502: }
503:
504:
505: /* If we can't get closer to the player (if that's our goal)
506: * because other monsters are in the way, just stay put
507: */
508: if (!flee && ce(hero, *ee) && monst_dist < MAXINT &&
509: DISTANCE(er->y, er->x, hero.y, hero.x) < dist)
510: ch_ret = *er;
511:
512: /* Do we want to go back to the last position? */
513: else if (dist_to_old != MININT && /* It is possible to move back */
514: ((flee && dist == 0) || /* No other possible moves */
515: (!flee && dist == MAXINT))) {
516: /* Do we move back or just stay put (default)? */
517: dist = DISTANCE(er->y, er->x, ee->y, ee->x); /* Current distance */
518: if (!flee || (flee && (dist_to_old > dist))) ch_ret = tp->t_oldpos;
519: }
520: }
521:
522: /* May actually hit here from a confused move */
523: return(!ce(ch_ret, hero));
524: }
525:
526: /*
527: * do_chase:
528: * Make one thing chase another.
529: */
530: /* flee: True if running away or player is inaccessible in wall */
531:
532: void
533: do_chase(struct thing *th, bool flee)
534: {
535: register struct room *rer, *ree, /* room of chaser, room of chasee */
536: *orig_rer, /* Original room of chaser */
537: *new_room; /* new room of monster */
538: int dist = MININT;
539: int mindist = MAXINT, maxdist = MININT;
540: bool stoprun = FALSE, /* TRUE means we are there */
541: rundoor; /* TRUE means run to a door */
542: bool mdead = 0;
543: char rch, sch;
544: coord *last_door=0, /* Door we just came from */
545: this; /* Temporary destination for chaser */
546:
547: /* Make sure the monster can move */
548: if (th->t_no_move != 0) {
549: th->t_no_move--;
550: return;
551: }
552:
553: rer = roomin(&th->t_pos); /* Find room of chaser */
554: ree = roomin(th->t_dest); /* Find room of chasee */
555: orig_rer = rer; /* Original room of chaser (including doors) */
556:
557: /*
558: * We don't count monsters on doors as inside rooms for this routine
559: */
560: if ((sch = CCHAR( mvwinch(stdscr, th->t_pos.y, th->t_pos.x) )) == DOOR ||
561: sch == PASSAGE) {
562: rer = NULL;
563: }
564: this = *th->t_dest;
565:
566: /*
567: * If we are not in a corridor and not a Xorn, then if we are running
568: * after the player, we run to a door if he is not in the same room.
569: * If we are fleeing, we run to a door if he IS in the same room.
570: * Note: We don't bother with doors in mazes.
571: */
572: if (levtype != MAZELEV && rer != NULL && off(*th, CANINWALL)) {
573: if (flee) rundoor = (rer == ree);
574: else rundoor = (rer != ree);
575: }
576: else rundoor = FALSE;
577:
578: if (rundoor) {
579: register struct linked_list *exitptr; /* For looping through exits */
580: coord *exit; /* A particular door */
581: int exity, exitx; /* Door's coordinates */
582: char dch='\0'; /* Door character */
583:
584: if (th->t_doorgoal)
585: dch = CCHAR( mvwinch(stdscr, th->t_doorgoal->y, th->t_doorgoal->x) );
586:
587: /* Do we have a valid goal? */
588: if ((dch == PASSAGE || dch == DOOR) && /* A real door */
589: (!flee || !ce(*th->t_doorgoal, hero))) { /* Player should not
590: * be at door if we are
591: * running away
592: */
593: this = *th->t_doorgoal;
594: dist = 0; /* Indicate that we have our door */
595: }
596:
597: /* Go through all the doors */
598: else for (exitptr = rer->r_exit; exitptr; exitptr = next(exitptr)) {
599: exit = DOORPTR(exitptr);
600: exity = exit->y;
601: exitx = exit->x;
602:
603: /* Make sure it is a real door */
604: dch = CCHAR( mvwinch(stdscr, exity, exitx) );
605: if (dch == PASSAGE || dch == DOOR) {
606: /* Don't count a door if we are fleeing from the player and
607: * he is standing on it
608: */
609: if (flee && ce(*exit, hero)) continue;
610:
611: /* Were we just on this door? */
612: if (ce(*exit, th->t_oldpos)) last_door = exit;
613:
614: else {
615: dist = DISTANCE(th->t_dest->y, th->t_dest->x, exity, exitx);
616:
617: /* If fleeing, we want to maximize distance from door to
618: * what we flee, and minimize distance from door to us.
619: */
620: if (flee)
621: dist -= DISTANCE(th->t_pos.y, th->t_pos.x, exity, exitx);
622:
623: /* Maximize distance if fleeing, otherwise minimize it */
624: if ((flee && (dist > maxdist)) ||
625: (!flee && (dist < mindist))) {
626: th->t_doorgoal = exit; /* Use this door */
627: this = *exit;
628: mindist = maxdist = dist;
629: }
630: }
631: }
632: }
633:
634: /* Could we not find a door? */
635: if (dist == MININT) {
636: /* If we were on a door, go ahead and use it */
637: if (last_door) {
638: th->t_doorgoal = last_door;
639: this = th->t_oldpos;
640: dist = 0; /* Indicate that we found a door */
641: }
642: else th->t_doorgoal = NULL; /* No more door goal */
643: }
644:
645: /* Indicate that we do not want to flee from the door */
646: if (dist != MININT) flee = FALSE;
647: }
648: else th->t_doorgoal = 0; /* Not going to any door */
649:
650: /*
651: * this now contains what we want to run to this time
652: * so we run to it. If we hit it we either want to fight it
653: * or stop running
654: */
655: if (!chase(th, &this, flee, &mdead)) {
656: if (ce(ch_ret, hero)) {
657: /* merchants try to sell something --> others attack */
658: if (on(*th, CANSELL)) sell(th);
659: else attack(th, NULL, FALSE);
660: return;
661: }
662: else if (on(*th, NOMOVE))
663: stoprun = TRUE;
664: }
665:
666: if (mdead) return; /* Did monster kill someone? */
667:
668: if (on(*th, NOMOVE)) return;
669:
670: /* If we have a scavenger, it can pick something up */
671: if (on(*th, ISSCAVENGE)) {
672: register struct linked_list *n_item, *o_item;
673:
674: while ((n_item = find_obj(ch_ret.y, ch_ret.x)) != NULL) {
675: char floor = (roomin(&ch_ret) == NULL) ? PASSAGE : FLOOR;
676: register struct object *n_obj, *o_obj;
677:
678: /*
679: * see if he's got one of this group already
680: */
681: o_item = NULL;
682: n_obj = OBJPTR(n_item);
683: detach(lvl_obj, n_item);
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: if (cansee(ch_ret.y, ch_ret.x))
698: mvwaddch(cw, ch_ret.y, ch_ret.x, floor);
699: mvaddch(ch_ret.y, ch_ret.x, floor);
700: }
701: }
702:
703: mvwaddch(cw, th->t_pos.y, th->t_pos.x, th->t_oldch);
704: sch = CCHAR( mvwinch(cw, ch_ret.y, ch_ret.x) ); /* What player sees */
705: rch = CCHAR( mvwinch(stdscr, ch_ret.y, ch_ret.x) ); /* What's really there */
706:
707: /* Get new room of monster */
708: new_room=roomin(&ch_ret);
709:
710: /* If we have a tunneling monster, it may be making a tunnel */
711: if (on(*th, CANTUNNEL) &&
712: (rch == SECRETDOOR || rch == WALL || rch == '|' || rch == '-')) {
713: char nch; /* The new look to the tunnel */
714:
715: if (rch == WALL) nch = PASSAGE;
716: else if (levtype == MAZELEV) nch = FLOOR;
717: else nch = DOOR;
718: addch(nch);
719:
720: if (cansee(ch_ret.y, ch_ret.x)) sch = nch; /* Can player see this? */
721:
722: /* Does this make a new exit? */
723: if (rch == '|' || rch == '-') {
724: struct linked_list *newroom;
725: coord *exit;
726:
727: newroom = new_item(sizeof(coord));
728: exit = DOORPTR(newroom);
729: *exit = ch_ret;
730: attach(new_room->r_exit, newroom);
731: }
732: }
733:
734: /* Mark if the monster is inside a wall */
735: if (isrock(mvinch(ch_ret.y, ch_ret.x))) turn_on(*th, ISINWALL);
736: else turn_off(*th, ISINWALL);
737:
738: /* If the monster can illuminate rooms, check for a change */
739: if (on(*th, HASFIRE)) {
740: register struct linked_list *fire_item;
741:
742: /* Is monster entering a room? */
743: if (orig_rer != new_room && new_room != NULL) {
744: fire_item = creat_item(); /* Get an item-only structure */
745: ldata(fire_item) = (char *) th;
746:
747: attach(new_room->r_fires, fire_item);
748: new_room->r_flags |= HASFIRE;
749:
750: if (cansee(ch_ret.y, ch_ret.x) && next(new_room->r_fires) == NULL)
751: light(&hero);
752: }
753:
754: /* Is monster leaving a room? */
755: if (orig_rer != new_room && orig_rer != NULL) {
756: /* Find the bugger in the list and delete him */
757: for (fire_item = orig_rer->r_fires; fire_item != NULL;
758: fire_item = next(fire_item)) {
759: if (THINGPTR(fire_item) == th) { /* Found him! */
760: detach(orig_rer->r_fires, fire_item);
761: destroy_item(fire_item);
762: if (orig_rer->r_fires == NULL) {
763: orig_rer->r_flags &= ~HASFIRE;
764: if (cansee(th->t_pos.y, th->t_pos.x))
765: light(&th->t_pos);
766: }
767: break;
768: }
769: }
770: }
771: }
772:
773: /* If monster is entering player's room and player can see it,
774: * stop the player's running.
775: */
776: if (new_room != orig_rer && new_room != NULL &&
777: new_room == ree && cansee(unc(ch_ret)) &&
778: (off(*th, ISINVIS) || on(player, CANSEE)) &&
779: (off(*th, ISSHADOW) || on(player, CANSEE)) &&
780: (off(*th, CANSURPRISE) || ISWEARING(R_ALERT)))
781: running = FALSE;
782:
783: /*
784: if (rer != NULL && !lit_room(orig_rer) && sch == FLOOR &&
785: DISTANCE(ch_ret.y, ch_ret.x, th->t_pos.y, th->t_pos.x) < 3 &&
786: off(player, ISBLIND))
787: th->t_oldch = ' ';
788: else
789: */
790: th->t_oldch = sch;
791:
792: /* Let's display those creatures that we can see. */
793: if (cansee(unc(ch_ret)) &&
794: off(*th, ISINWALL) &&
795: !invisible(th))
796: mvwaddch(cw, ch_ret.y, ch_ret.x, th->t_type);
797:
798: /*
799: * Blank out the old position and record the new position --
800: * the blanking must be done first in case the positions are the same.
801: */
802: mvwaddch(mw, th->t_pos.y, th->t_pos.x, ' ');
803: mvwaddch(mw, ch_ret.y, ch_ret.x, th->t_type);
804:
805: /* Record monster's last position (if new one is different) */
806: if (!ce(ch_ret, th->t_pos)) th->t_oldpos = th->t_pos;
807: th->t_pos = ch_ret; /* Mark the monster's new position */
808:
809: /* If the monster is on a trap, trap it */
810: sch = CCHAR( mvinch(ch_ret.y, ch_ret.x) );
811: if (isatrap(sch)) {
812: if (cansee(ch_ret.y, ch_ret.x)) th->t_oldch = sch;
813: be_trapped(th, &ch_ret);
814: }
815:
816:
817: /*
818: * And stop running if need be
819: */
820: if (stoprun && ce(th->t_pos, *(th->t_dest)))
821: turn_off(*th, ISRUN);
822: }
823:
824:
825: /*
826: * Get_hurl returns the weapon that the monster will "throw" if he has one
827: */
828:
829: struct linked_list *
830: get_hurl(struct thing *tp)
831: {
832: struct linked_list *arrow, *bolt, *rock;
833: register struct linked_list *pitem;
834: bool bow=FALSE, crossbow=FALSE, sling=FALSE;
835:
836: arrow = bolt = rock = NULL; /* Don't point to anything to begin with */
837: for (pitem=tp->t_pack; pitem; pitem=next(pitem))
838: if ((OBJPTR(pitem))->o_type == WEAPON)
839: switch ((OBJPTR(pitem))->o_which) {
840: case BOW: bow = TRUE;
841: when CROSSBOW: crossbow = TRUE;
842: when SLING: sling = TRUE;
843: when ROCK: rock = pitem;
844: when ARROW: arrow = pitem;
845: when BOLT: bolt = pitem;
846: }
847:
848: /* Use crossbow bolt if possible */
849: if (crossbow && bolt) return(bolt);
850: if (bow && arrow) return(arrow);
851: if (sling && rock) return(rock);
852: return(NULL);
853: }
854:
855: /*
856: * runners:
857: * Make all the running monsters move.
858: */
859:
860: void
861: runners(void)
862: {
863: register struct linked_list *item;
864: register struct thing *tp = NULL;
865:
866: /*
867: * loop thru the list of running (wandering) monsters and see what
868: * each one will do this time.
869: *
870: * Note: the special case that one of this buggers kills another.
871: * if this happens than we have to see if the monster killed
872: * himself or someone else. In case its himself we have to get next
873: * one immediately. If it wasn't we have to get next one at very
874: * end in case he killed the next one.
875: */
876:
877: for (item = mlist; item != NULL; item = next(item)) {
878: tp = THINGPTR(item);
879: turn_on(*tp, ISREADY);
880: }
881:
882: for (;;) {
883: for (item = mlist; item != NULL; item = next(item)) {
884: tp = THINGPTR(item);
885:
886: if (on(*tp, ISREADY))
887: break;
888: }
889:
890: if (item == NULL)
891: break;
892:
893: turn_off(*tp, ISREADY);
894:
895: if (on(*tp, ISHELD) && rnd(tp->t_stats.s_lvl) > 11) {
896: turn_off(*tp, ISHELD);
897: turn_on(*tp, ISRUN);
898: turn_off(*tp, ISDISGUISE);
899: tp->t_dest = &hero;
900: if (tp->t_stats.s_hpt < tp->maxstats.s_hpt)
901: turn_on(*tp, ISFLEE);
902: if (cansee(tp->t_pos.y, tp->t_pos.x))
903: msg("The %s breaks free from the hold spell",
904: monsters[tp->t_index].m_name);
905: }
906: if (off(*tp, ISHELD) && on(*tp, ISRUN)) {
907: register bool flee;
908:
909: /* Should monster run away? */
910: flee = on(*tp, ISFLEE) ||
911: ((tp->t_dest == &hero) && on(player, ISINWALL) &&
912: off(*tp, CANINWALL));
913:
914: if (off(*tp, ISSLOW) || tp->t_turn) {
915: doctor(tp);
916: do_chase(tp, flee);
917: }
918: if (off(*tp, ISDEAD) && off(*tp, ISELSEWHERE) && on(*tp, ISHASTE)) {
919: doctor(tp);
920: do_chase(tp, flee);
921: }
922: if (off(*tp, ISDEAD) && off(*tp, ISELSEWHERE)) {
923: tp->t_turn ^= TRUE;
924: tp->t_wasshot = FALSE; /* Not shot anymore */
925: }
926: }
927: }
928: }
929:
930: /*
931: * runto:
932: * Set a monster running after something
933: */
934:
935: void
936: runto(struct thing *runner, coord *spot)
937: {
938: /*
939: * Start the beastie running
940: */
941: runner->t_dest = spot;
942: turn_on(*runner, ISRUN);
943: turn_off(*runner, ISDISGUISE);
944: }
945:
946:
947:
948: /*
949: * straight_shot:
950: * See if there is a straight line of sight between the two
951: * given coordinates. If shooting is not NULL, it is a pointer
952: * to a structure which should be filled with the direction
953: * to shoot (if there is a line of sight). If shooting, monsters
954: * get in the way. Otherwise, they do not.
955: */
956:
957: bool
958: straight_shot(int ery, int erx, int eey, int eex, coord *shooting)
959: {
960: register int dy, dx; /* Deltas */
961: char ch;
962:
963: /* Does the monster have a straight shot at player */
964: if ((ery != eey) && (erx != eex) &&
965: (abs(ery - eey) != abs(erx - eex))) return(FALSE);
966:
967: /* Get the direction to shoot */
968: if (eey > ery) dy = 1;
969: else if (eey == ery) dy = 0;
970: else dy = -1;
971:
972: if (eex > erx) dx = 1;
973: else if (eex == erx) dx = 0;
974: else dx = -1;
975:
976: /* Make sure we have free area all the way to the player */
977: ery += dy;
978: erx += dx;
979: while ((ery != eey) || (erx != eex)) {
980: switch (ch = CCHAR( winat(ery, erx) )) {
981: case '|':
982: case '-':
983: case WALL:
984: case DOOR:
985: case SECRETDOOR:
986: case FOREST:
987: return(FALSE);
988: default:
989: if (shooting && isalpha(ch)) return(FALSE);
990: }
991: ery += dy;
992: erx += dx;
993: }
994:
995: if (shooting) { /* If we are shooting -- put in the directions */
996: shooting->y = dy;
997: shooting->x = dx;
998: }
999: return(TRUE);
1000: }
1001:
1002:
CVSweb