add manual page, Berkeley specific copyright
[unix-history] / usr / src / games / rogue / monster.c
CommitLineData
b3afadef
KB
1/*
2 * monster.c
3 *
4 * This source herein may be modified and/or distributed by anybody who
5 * so desires, with the following restrictions:
6 * 1.) No portion of this notice shall be removed.
7 * 2.) Credit shall not be taken for the creation of this source.
8 * 3.) This code is not to be traded, sold, or used for personal
9 * gain or profit.
10 *
11 */
12
13#ifndef lint
14static char sccsid[] = "@(#)monster.c 5.1 (Berkeley) %G%";
15#endif /* not lint */
16
17#include "rogue.h"
18
19object level_monsters;
20boolean mon_disappeared;
21
22char *m_names[] = {
23 "aquator",
24 "bat",
25 "centaur",
26 "dragon",
27 "emu",
28 "venus fly-trap",
29 "griffin",
30 "hobgoblin",
31 "ice monster",
32 "jabberwock",
33 "kestrel",
34 "leprechaun",
35 "medusa",
36 "nymph",
37 "orc",
38 "phantom",
39 "quagga",
40 "rattlesnake",
41 "snake",
42 "troll",
43 "black unicorn",
44 "vampire",
45 "wraith",
46 "xeroc",
47 "yeti",
48 "zombie"
49};
50
51object mon_tab[MONSTERS] = {
52 {(ASLEEP|WAKENS|WANDERS|RUSTS),"0d0",25,'A',20,9,18,100,0,0,0,0,0},
53 {(ASLEEP|WANDERS|FLITS|FLIES),"1d3",10,'B',2,1,8,60,0,0,0,0,0},
54 {(ASLEEP|WANDERS),"3d3/2d5",32,'C',15,7,16,85,0,10,0,0,0},
55 {(ASLEEP|WAKENS|FLAMES),"4d6/4d9",145,'D',5000,21,126,100,0,90,0,0,0},
56 {(ASLEEP|WAKENS),"1d3",11,'E',2,1,7,65,0,0,0,0,0},
57 {(HOLDS|STATIONARY),"5d5",73,'F',91,12,126,80,0,0,0,0,0},
58 {(ASLEEP|WAKENS|WANDERS|FLIES),"5d5/5d5",115,'G',
59 2000,20,126,85,0,10,0,0,0},
60 {(ASLEEP|WAKENS|WANDERS),"1d3/1d2",15,'H',3,1,10,67,0,0,0,0,0},
61 {(ASLEEP|FREEZES),"0d0",15,'I',5,2,11,68,0,0,0,0,0},
62 {(ASLEEP|WANDERS),"3d10/4d5",132,'J',3000,21,126,100,0,0,0,0,0},
63 {(ASLEEP|WAKENS|WANDERS|FLIES),"1d4",10,'K',2,1,6,60,0,0,0,0,0},
64 {(ASLEEP|STEALS_GOLD),"0d0",25,'L',21,6,16,75,0,0,0,0,0},
65 {(ASLEEP|WAKENS|WANDERS|CONFUSES),"4d4/3d7",97,'M',
66 250,18,126,85,0,25,0,0,0},
67 {(ASLEEP|STEALS_ITEM),"0d0",25,'N',39,10,19,75,0,100,0,0,0},
68 {(ASLEEP|WANDERS|WAKENS|SEEKS_GOLD),"1d6",25,'O',5,4,13,70,0,10,0,0,0},
69 {(ASLEEP|INVISIBLE|WANDERS|FLITS),"5d4",76,'P',120,15,24,80,0,50,0,0,0},
70 {(ASLEEP|WAKENS|WANDERS),"3d5",30,'Q',20,8,17,78,0,20,0,0,0},
71 {(ASLEEP|WAKENS|WANDERS|STINGS),"2d5",19,'R',10,3,12,70,0,0,0,0,0},
72 {(ASLEEP|WAKENS|WANDERS),"1d3",8,'S',2,1,9,50,0,0,0,0,0},
73 {(ASLEEP|WAKENS|WANDERS),"4d6/1d4",75,'T',125,13,22,75,0,33,0,0,0},
74 {(ASLEEP|WAKENS|WANDERS),"4d10",90,'U',
75 200,17,26,85,0,33,0,0,0},
76 {(ASLEEP|WAKENS|WANDERS|DRAINS_LIFE),"1d14/1d4",55,'V',
77 350,19,126,85,0,18,0,0,0},
78 {(ASLEEP|WANDERS|DROPS_LEVEL),"2d8",45,'W',55,14,23,75,0,0,0,0,0},
79 {(ASLEEP|IMITATES),"4d6",42,'X',110,16,25,75,0,0,0,0,0},
80 {(ASLEEP|WANDERS),"3d6",35,'Y',50,11,20,80,0,20,0,0,0},
81 {(ASLEEP|WAKENS|WANDERS),"1d7",21,'Z',8,5,14,69,0,0,0,0,0}
82};
83
84extern short cur_level;
85extern short cur_room, party_room;
86extern short blind, halluc, haste_self;
87extern boolean detect_monster, see_invisible, r_see_invisible;
88extern short stealthy;
89
90put_mons()
91{
92 short i;
93 short n;
94 object *monster;
95 short row, col;
96
97 n = get_rand(4, 6);
98
99 for (i = 0; i < n; i++) {
100 monster = gr_monster((object *) 0, 0);
101 if ((monster->m_flags & WANDERS) && coin_toss()) {
102 wake_up(monster);
103 }
104 gr_row_col(&row, &col, (FLOOR | TUNNEL | STAIRS | OBJECT));
105 put_m_at(row, col, monster);
106 }
107}
108
109object *
110gr_monster(monster, mn)
111register object *monster;
112register mn;
113{
114 if (!monster) {
115 monster = alloc_object();
116
117 for (;;) {
118 mn = get_rand(0, MONSTERS-1);
119 if ((cur_level >= mon_tab[mn].first_level) &&
120 (cur_level <= mon_tab[mn].last_level)) {
121 break;
122 }
123 }
124 }
125 *monster = mon_tab[mn];
126 if (monster->m_flags & IMITATES) {
127 monster->disguise = gr_obj_char();
128 }
129 if (cur_level > (AMULET_LEVEL + 2)) {
130 monster->m_flags |= HASTED;
131 }
132 monster->trow = NO_ROOM;
133 return(monster);
134}
135
136mv_mons()
137{
138 register object *monster, *next_monster;
139 boolean flew;
140
141 if (haste_self % 2) {
142 return;
143 }
144
145 monster = level_monsters.next_monster;
146
147 while (monster) {
148 next_monster = monster->next_monster;
149 mon_disappeared = 0;
150 if (monster->m_flags & HASTED) {
151 mv_1_monster(monster, rogue.row, rogue.col);
152 if (mon_disappeared) {
153 goto NM;
154 }
155 } else if (monster->m_flags & SLOWED) {
156 monster->slowed_toggle = !monster->slowed_toggle;
157 if (monster->slowed_toggle) {
158 goto NM;
159 }
160 }
161 if ((monster->m_flags & CONFUSED) && move_confused(monster)) {
162 goto NM;
163 }
164 flew = 0;
165 if ( (monster->m_flags & FLIES) &&
166 !(monster->m_flags & NAPPING) &&
167 !mon_can_go(monster, rogue.row, rogue.col)) {
168 flew = 1;
169 mv_1_monster(monster, rogue.row, rogue.col);
170 if (mon_disappeared) {
171 goto NM;
172 }
173 }
174 if (!(flew && mon_can_go(monster, rogue.row, rogue.col))) {
175 mv_1_monster(monster, rogue.row, rogue.col);
176 }
177NM: monster = next_monster;
178 }
179}
180
181party_monsters(rn, n)
182int rn, n;
183{
184 short i, j;
185 short row, col;
186 object *monster;
187 boolean found;
188
189 n += n;
190
191 for (i = 0; i < MONSTERS; i++) {
192 mon_tab[i].first_level -= (cur_level % 3);
193 }
194 for (i = 0; i < n; i++) {
195 if (no_room_for_monster(rn)) {
196 break;
197 }
198 for (j = found = 0; ((!found) && (j < 250)); j++) {
199 row = get_rand(rooms[rn].top_row+1,
200 rooms[rn].bottom_row-1);
201 col = get_rand(rooms[rn].left_col+1,
202 rooms[rn].right_col-1);
203 if ((!(dungeon[row][col] & MONSTER)) &&
204 (dungeon[row][col] & (FLOOR | TUNNEL))) {
205 found = 1;
206 }
207 }
208 if (found) {
209 monster = gr_monster((object *) 0, 0);
210 if (!(monster->m_flags & IMITATES)) {
211 monster->m_flags |= WAKENS;
212 }
213 put_m_at(row, col, monster);
214 }
215 }
216 for (i = 0; i < MONSTERS; i++) {
217 mon_tab[i].first_level += (cur_level % 3);
218 }
219}
220
221gmc_row_col(row, col)
222register row, col;
223{
224 register object *monster;
225
226 if (monster = object_at(&level_monsters, row, col)) {
227 if ((!(detect_monster || see_invisible || r_see_invisible) &&
228 (monster->m_flags & INVISIBLE)) || blind) {
229 return(monster->trail_char);
230 }
231 if (monster->m_flags & IMITATES) {
232 return(monster->disguise);
233 }
234 return(monster->m_char);
235 } else {
236 return('&'); /* BUG if this ever happens */
237 }
238}
239
240gmc(monster)
241object *monster;
242{
243 if ((!(detect_monster || see_invisible || r_see_invisible) &&
244 (monster->m_flags & INVISIBLE))
245 || blind) {
246 return(monster->trail_char);
247 }
248 if (monster->m_flags & IMITATES) {
249 return(monster->disguise);
250 }
251 return(monster->m_char);
252}
253
254mv_1_monster(monster, row, col)
255register object *monster;
256short row, col;
257{
258 short i, n;
259 boolean tried[6];
260
261 if (monster->m_flags & ASLEEP) {
262 if (monster->m_flags & NAPPING) {
263 if (--monster->nap_length <= 0) {
264 monster->m_flags &= (~(NAPPING | ASLEEP));
265 }
266 return;
267 }
268 if ((monster->m_flags & WAKENS) &&
269 rogue_is_around(monster->row, monster->col) &&
270 rand_percent(((stealthy > 0) ?
271 (WAKE_PERCENT / (STEALTH_FACTOR + stealthy)) :
272 WAKE_PERCENT))) {
273 wake_up(monster);
274 }
275 return;
276 } else if (monster->m_flags & ALREADY_MOVED) {
277 monster->m_flags &= (~ALREADY_MOVED);
278 return;
279 }
280 if ((monster->m_flags & FLITS) && flit(monster)) {
281 return;
282 }
283 if ((monster->m_flags & STATIONARY) &&
284 (!mon_can_go(monster, rogue.row, rogue.col))) {
285 return;
286 }
287 if (monster->m_flags & FREEZING_ROGUE) {
288 return;
289 }
290 if ((monster->m_flags & CONFUSES) && m_confuse(monster)) {
291 return;
292 }
293 if (mon_can_go(monster, rogue.row, rogue.col)) {
294 mon_hit(monster);
295 return;
296 }
297 if ((monster->m_flags & FLAMES) && flame_broil(monster)) {
298 return;
299 }
300 if ((monster->m_flags & SEEKS_GOLD) && seek_gold(monster)) {
301 return;
302 }
303 if ((monster->trow == monster->row) &&
304 (monster->tcol == monster->col)) {
305 monster->trow = NO_ROOM;
306 } else if (monster->trow != NO_ROOM) {
307 row = monster->trow;
308 col = monster->tcol;
309 }
310 if (monster->row > row) {
311 row = monster->row - 1;
312 } else if (monster->row < row) {
313 row = monster->row + 1;
314 }
315 if ((dungeon[row][monster->col] & DOOR) &&
316 mtry(monster, row, monster->col)) {
317 return;
318 }
319 if (monster->col > col) {
320 col = monster->col - 1;
321 } else if (monster->col < col) {
322 col = monster->col + 1;
323 }
324 if ((dungeon[monster->row][col] & DOOR) &&
325 mtry(monster, monster->row, col)) {
326 return;
327 }
328 if (mtry(monster, row, col)) {
329 return;
330 }
331
332 for (i = 0; i <= 5; i++) tried[i] = 0;
333
334 for (i = 0; i < 6; i++) {
335NEXT_TRY: n = get_rand(0, 5);
336 switch(n) {
337 case 0:
338 if (!tried[n] && mtry(monster, row, monster->col-1)) {
339 goto O;
340 }
341 break;
342 case 1:
343 if (!tried[n] && mtry(monster, row, monster->col)) {
344 goto O;
345 }
346 break;
347 case 2:
348 if (!tried[n] && mtry(monster, row, monster->col+1)) {
349 goto O;
350 }
351 break;
352 case 3:
353 if (!tried[n] && mtry(monster, monster->row-1, col)) {
354 goto O;
355 }
356 break;
357 case 4:
358 if (!tried[n] && mtry(monster, monster->row, col)) {
359 goto O;
360 }
361 break;
362 case 5:
363 if (!tried[n] && mtry(monster, monster->row+1, col)) {
364 goto O;
365 }
366 break;
367 }
368 if (!tried[n]) {
369 tried[n] = 1;
370 } else {
371 goto NEXT_TRY;
372 }
373 }
374O:
375 if ((monster->row == monster->o_row) && (monster->col == monster->o_col)) {
376 if (++(monster->o) > 4) {
377 if ((monster->trow == NO_ROOM) &&
378 (!mon_sees(monster, rogue.row, rogue.col))) {
379 monster->trow = get_rand(1, (DROWS - 2));
380 monster->tcol = get_rand(0, (DCOLS - 1));
381 } else {
382 monster->trow = NO_ROOM;
383 monster->o = 0;
384 }
385 }
386 } else {
387 monster->o_row = monster->row;
388 monster->o_col = monster->col;
389 monster->o = 0;
390 }
391}
392
393mtry(monster, row, col)
394register object *monster;
395register short row, col;
396{
397 if (mon_can_go(monster, row, col)) {
398 move_mon_to(monster, row, col);
399 return(1);
400 }
401 return(0);
402}
403
404move_mon_to(monster, row, col)
405register object *monster;
406register short row, col;
407{
408 short c;
409 register mrow, mcol;
410
411 mrow = monster->row;
412 mcol = monster->col;
413
414 dungeon[mrow][mcol] &= ~MONSTER;
415 dungeon[row][col] |= MONSTER;
416
417 c = mvinch(mrow, mcol);
418
419 if ((c >= 'A') && (c <= 'Z')) {
420 if (!detect_monster) {
421 mvaddch(mrow, mcol, monster->trail_char);
422 } else {
423 if (rogue_can_see(mrow, mcol)) {
424 mvaddch(mrow, mcol, monster->trail_char);
425 } else {
426 if (monster->trail_char == '.') {
427 monster->trail_char = ' ';
428 }
429 mvaddch(mrow, mcol, monster->trail_char);
430 }
431 }
432 }
433 monster->trail_char = mvinch(row, col);
434 if (!blind && (detect_monster || rogue_can_see(row, col))) {
435 if ((!(monster->m_flags & INVISIBLE) ||
436 (detect_monster || see_invisible || r_see_invisible))) {
437 mvaddch(row, col, gmc(monster));
438 }
439 }
440 if ((dungeon[row][col] & DOOR) &&
441 (get_room_number(row, col) != cur_room) &&
442 (dungeon[mrow][mcol] == FLOOR) && !blind) {
443 mvaddch(mrow, mcol, ' ');
444 }
445 if (dungeon[row][col] & DOOR) {
446 dr_course(monster, ((dungeon[mrow][mcol] & TUNNEL) ? 1 : 0),
447 row, col);
448 } else {
449 monster->row = row;
450 monster->col = col;
451 }
452}
453
454mon_can_go(monster, row, col)
455register object *monster;
456register short row, col;
457{
458 object *obj;
459 short dr, dc;
460
461 dr = monster->row - row; /* check if move distance > 1 */
462 if ((dr >= 2) || (dr <= -2)) {
463 return(0);
464 }
465 dc = monster->col - col;
466 if ((dc >= 2) || (dc <= -2)) {
467 return(0);
468 }
469 if ((!dungeon[monster->row][col]) || (!dungeon[row][monster->col])) {
470 return(0);
471 }
472 if ((!is_passable(row, col)) || (dungeon[row][col] & MONSTER)) {
473 return(0);
474 }
475 if ((monster->row!=row)&&(monster->col!=col)&&((dungeon[row][col]&DOOR) ||
476 (dungeon[monster->row][monster->col]&DOOR))) {
477 return(0);
478 }
479 if (!(monster->m_flags & (FLITS | CONFUSED | CAN_FLIT)) &&
480 (monster->trow == NO_ROOM)) {
481 if ((monster->row < rogue.row) && (row < monster->row)) return(0);
482 if ((monster->row > rogue.row) && (row > monster->row)) return(0);
483 if ((monster->col < rogue.col) && (col < monster->col)) return(0);
484 if ((monster->col > rogue.col) && (col > monster->col)) return(0);
485 }
486 if (dungeon[row][col] & OBJECT) {
487 obj = object_at(&level_objects, row, col);
488 if ((obj->what_is == SCROL) && (obj->which_kind == SCARE_MONSTER)) {
489 return(0);
490 }
491 }
492 return(1);
493}
494
495wake_up(monster)
496object *monster;
497{
498 if (!(monster->m_flags & NAPPING)) {
499 monster->m_flags &= (~(ASLEEP | IMITATES | WAKENS));
500 }
501}
502
503wake_room(rn, entering, row, col)
504short rn;
505boolean entering;
506short row, col;
507{
508 object *monster;
509 short wake_percent;
510 boolean in_room;
511
512 wake_percent = (rn == party_room) ? PARTY_WAKE_PERCENT : WAKE_PERCENT;
513 if (stealthy > 0) {
514 wake_percent /= (STEALTH_FACTOR + stealthy);
515 }
516
517 monster = level_monsters.next_monster;
518
519 while (monster) {
520 in_room = (rn == get_room_number(monster->row, monster->col));
521 if (in_room) {
522 if (entering) {
523 monster->trow = NO_ROOM;
524 } else {
525 monster->trow = row;
526 monster->tcol = col;
527 }
528 }
529 if ((monster->m_flags & WAKENS) &&
530 (rn == get_room_number(monster->row, monster->col))) {
531 if (rand_percent(wake_percent)) {
532 wake_up(monster);
533 }
534 }
535 monster = monster->next_monster;
536 }
537}
538
539char *
540mon_name(monster)
541object *monster;
542{
543 short ch;
544
545 if (blind || ((monster->m_flags & INVISIBLE) &&
546 !(detect_monster || see_invisible || r_see_invisible))) {
547 return("something");
548 }
549 if (halluc) {
550 ch = get_rand('A', 'Z') - 'A';
551 return(m_names[ch]);
552 }
553 ch = monster->m_char - 'A';
554 return(m_names[ch]);
555}
556
557rogue_is_around(row, col)
558register row, col;
559{
560 short rdif, cdif, retval;
561
562 rdif = row - rogue.row;
563 cdif = col - rogue.col;
564
565 retval = (rdif >= -1) && (rdif <= 1) && (cdif >= -1) && (cdif <= 1);
566 return(retval);
567}
568
569wanderer()
570{
571 object *monster;
572 short row, col, i;
573 boolean found = 0;
574
575 for (i = 0; ((i < 15) && (!found)); i++) {
576 monster = gr_monster((object *) 0, 0);
577 if (!(monster->m_flags & (WAKENS | WANDERS))) {
578 free_object(monster);
579 } else {
580 found = 1;
581 }
582 }
583 if (found) {
584 found = 0;
585 wake_up(monster);
586 for (i = 0; ((i < 25) && (!found)); i++) {
587 gr_row_col(&row, &col, (FLOOR | TUNNEL | STAIRS | OBJECT));
588 if (!rogue_can_see(row, col)) {
589 put_m_at(row, col, monster);
590 found = 1;
591 }
592 }
593 if (!found) {
594 free_object(monster);
595 }
596 }
597}
598
599show_monsters()
600{
601 object *monster;
602
603 detect_monster = 1;
604
605 if (blind) {
606 return;
607 }
608 monster = level_monsters.next_monster;
609
610 while (monster) {
611 mvaddch(monster->row, monster->col, monster->m_char);
612 if (monster->m_flags & IMITATES) {
613 monster->m_flags &= (~IMITATES);
614 monster->m_flags |= WAKENS;
615 }
616 monster = monster->next_monster;
617 }
618}
619
620create_monster()
621{
622 short row, col;
623 short i;
624 boolean found = 0;
625 object *monster;
626
627 row = rogue.row;
628 col = rogue.col;
629
630 for (i = 0; i < 9; i++) {
631 rand_around(i, &row, &col);
632 if (((row == rogue.row) && (col = rogue.col)) ||
633 (row < MIN_ROW) || (row > (DROWS-2)) ||
634 (col < 0) || (col > (DCOLS-1))) {
635 continue;
636 }
637 if ((!(dungeon[row][col] & MONSTER)) &&
638 (dungeon[row][col] & (FLOOR|TUNNEL|STAIRS|DOOR))) {
639 found = 1;
640 break;
641 }
642 }
643 if (found) {
644 monster = gr_monster((object *) 0, 0);
645 put_m_at(row, col, monster);
646 mvaddch(row, col, gmc(monster));
647 if (monster->m_flags & (WANDERS | WAKENS)) {
648 wake_up(monster);
649 }
650 } else {
651 message("you hear a faint cry of anguish in the distance", 0);
652 }
653}
654
655put_m_at(row, col, monster)
656short row, col;
657object *monster;
658{
659 monster->row = row;
660 monster->col = col;
661 dungeon[row][col] |= MONSTER;
662 monster->trail_char = mvinch(row, col);
663 (void) add_to_pack(monster, &level_monsters, 0);
664 aim_monster(monster);
665}
666
667aim_monster(monster)
668object *monster;
669{
670 short i, rn, d, r;
671
672 rn = get_room_number(monster->row, monster->col);
673 r = get_rand(0, 12);
674
675 for (i = 0; i < 4; i++) {
676 d = (r + i) % 4;
677 if (rooms[rn].doors[d].oth_room != NO_ROOM) {
678 monster->trow = rooms[rn].doors[d].door_row;
679 monster->tcol = rooms[rn].doors[d].door_col;
680 break;
681 }
682 }
683}
684
685rogue_can_see(row, col)
686register row, col;
687{
688 register retval;
689
690 retval = !blind &&
691 (((get_room_number(row, col) == cur_room) &&
692 !(rooms[cur_room].is_room & R_MAZE)) ||
693 rogue_is_around(row, col));
694
695 return(retval);
696}
697
698move_confused(monster)
699object *monster;
700{
701 short i, row, col;
702
703 if (!(monster->m_flags & ASLEEP)) {
704 if (--monster->moves_confused <= 0) {
705 monster->m_flags &= (~CONFUSED);
706 }
707 if (monster->m_flags & STATIONARY) {
708 return(coin_toss() ? 1 : 0);
709 } else if (rand_percent(15)) {
710 return(1);
711 }
712 row = monster->row;
713 col = monster->col;
714
715 for (i = 0; i < 9; i++) {
716 rand_around(i, &row, &col);
717 if ((row == rogue.row) && (col == rogue.col)) {
718 return(0);
719 }
720 if (mtry(monster, row, col)) {
721 return(1);
722 }
723 }
724 }
725 return(0);
726}
727
728flit(monster)
729object *monster;
730{
731 short i, row, col;
732
733 if (!rand_percent(FLIT_PERCENT + ((monster->m_flags & FLIES) ? 20 : 0))) {
734 return(0);
735 }
736 if (rand_percent(10)) {
737 return(1);
738 }
739 row = monster->row;
740 col = monster->col;
741
742 for (i = 0; i < 9; i++) {
743 rand_around(i, &row, &col);
744 if ((row == rogue.row) && (col == rogue.col)) {
745 continue;
746 }
747 if (mtry(monster, row, col)) {
748 return(1);
749 }
750 }
751 return(1);
752}
753
754gr_obj_char()
755{
756 short r;
757 char *rs = "%!?]=/):*";
758
759 r = get_rand(0, 8);
760
761 return(rs[r]);
762}
763
764no_room_for_monster(rn)
765int rn;
766{
767 short i, j;
768
769 for (i = rooms[rn].top_row+1; i < rooms[rn].bottom_row; i++) {
770 for (j = rooms[rn].left_col+1; j < rooms[rn].right_col; j++) {
771 if (!(dungeon[i][j] & MONSTER)) {
772 return(0);
773 }
774 }
775 }
776 return(1);
777}
778
779aggravate()
780{
781 object *monster;
782
783 message("you hear a high pitched humming noise", 0);
784
785 monster = level_monsters.next_monster;
786
787 while (monster) {
788 wake_up(monster);
789 monster->m_flags &= (~IMITATES);
790 if (rogue_can_see(monster->row, monster->col)) {
791 mvaddch(monster->row, monster->col, monster->m_char);
792 }
793 monster = monster->next_monster;
794 }
795}
796
797boolean
798mon_sees(monster, row, col)
799object *monster;
800{
801 short rn, rdif, cdif, retval;
802
803 rn = get_room_number(row, col);
804
805 if ( (rn != NO_ROOM) &&
806 (rn == get_room_number(monster->row, monster->col)) &&
807 !(rooms[rn].is_room & R_MAZE)) {
808 return(1);
809 }
810 rdif = row - monster->row;
811 cdif = col - monster->col;
812
813 retval = (rdif >= -1) && (rdif <= 1) && (cdif >= -1) && (cdif <= 1);
814 return(retval);
815}
816
817mv_aquatars()
818{
819 object *monster;
820
821 monster = level_monsters.next_monster;
822
823 while (monster) {
824 if ((monster->m_char == 'A') &&
825 mon_can_go(monster, rogue.row, rogue.col)) {
826 mv_1_monster(monster, rogue.row, rogue.col);
827 monster->m_flags |= ALREADY_MOVED;
828 }
829 monster = monster->next_monster;
830 }
831}