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