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