MFC: Make apps using '#define _POSIX_C_SOURCE' compile.
[dragonfly.git] / games / rogue / monster.c
blob0e150755e2e0cf6f2999f00a8eafea3ca231fb5b
1 /*
2 * Copyright (c) 1988, 1993
3 * The Regents of the University of California. All rights reserved.
5 * This code is derived from software contributed to Berkeley by
6 * Timothy C. Stoehr.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
36 * @(#)monster.c 8.1 (Berkeley) 5/31/93
37 * $FreeBSD: src/games/rogue/monster.c,v 1.6 1999/11/30 03:49:24 billf Exp $
38 * $DragonFly: src/games/rogue/monster.c,v 1.3 2006/09/02 19:31:07 pavalos Exp $
42 * monster.c
44 * This source herein may be modified and/or distributed by anybody who
45 * so desires, with the following restrictions:
46 * 1.) No portion of this notice shall be removed.
47 * 2.) Credit shall not be taken for the creation of this source.
48 * 3.) This code is not to be traded, sold, or used for personal
49 * gain or profit.
53 #include "rogue.h"
55 static boolean mtry(object *, short, short);
56 static short rogue_is_around(int, int);
57 static void put_m_at(short, short, object *);
58 static void aim_monster(object *);
59 static boolean move_confused(object *);
60 static boolean flit(object *);
61 static boolean no_room_for_monster(int);
63 object level_monsters;
64 boolean mon_disappeared;
66 const char *const m_names[] = {
67 "aquator",
68 "bat",
69 "centaur",
70 "dragon",
71 "emu",
72 "venus fly-trap",
73 "griffin",
74 "hobgoblin",
75 "ice monster",
76 "jabberwock",
77 "kestrel",
78 "leprechaun",
79 "medusa",
80 "nymph",
81 "orc",
82 "phantom",
83 "quagga",
84 "rattlesnake",
85 "snake",
86 "troll",
87 "black unicorn",
88 "vampire",
89 "wraith",
90 "xeroc",
91 "yeti",
92 "zombie"
95 object mon_tab[MONSTERS] = {
96 {(ASLEEP|WAKENS|WANDERS|RUSTS),"0d0",25,'A',20,9,18,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,NULL},
97 {(ASLEEP|WANDERS|FLITS|FLIES),"1d3",10,'B',2,1,8,60,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,NULL},
98 {(ASLEEP|WANDERS),"3d3/2d5",32,'C',15,7,16,85,0,10,0,0,0,0,0,0,0,0,0,0,0,0,0,NULL},
99 {(ASLEEP|WAKENS|FLAMES),"4d6/4d9",145,'D',5000,21,126,100,0,90,0,0,0,0,0,0,0,0,0,0,0,0,0,NULL},
100 {(ASLEEP|WAKENS),"1d3",11,'E',2,1,7,65,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,NULL},
101 {(HOLDS|STATIONARY),"5d5",73,'F',91,12,126,80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,NULL},
102 {(ASLEEP|WAKENS|WANDERS|FLIES),"5d5/5d5",115,'G',
103 2000,20,126,85,0,10,0,0,0,0,0,0,0,0,0,0,0,0,0,NULL},
104 {(ASLEEP|WAKENS|WANDERS),"1d3/1d2",15,'H',3,1,10,67,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,NULL},
105 {(ASLEEP|FREEZES),"0d0",15,'I',5,2,11,68,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,NULL},
106 {(ASLEEP|WANDERS),"3d10/4d5",132,'J',3000,21,126,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,NULL},
107 {(ASLEEP|WAKENS|WANDERS|FLIES),"1d4",10,'K',2,1,6,60,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,NULL},
108 {(ASLEEP|STEALS_GOLD),"0d0",25,'L',21,6,16,75,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,NULL},
109 {(ASLEEP|WAKENS|WANDERS|CONFUSES),"4d4/3d7",97,'M',
110 250,18,126,85,0,25,0,0,0,0,0,0,0,0,0,0,0,0,0,NULL},
111 {(ASLEEP|STEALS_ITEM),"0d0",25,'N',39,10,19,75,0,100,0,0,0,0,0,0,0,0,0,0,0,0,0,NULL},
112 {(ASLEEP|WANDERS|WAKENS|SEEKS_GOLD),"1d6",25,'O',5,4,13,70,0,10,0,0,0,0,0,0,0,0,0,0,0,0,0,NULL},
113 {(ASLEEP|INVISIBLE|WANDERS|FLITS),"5d4",76,'P',120,15,24,80,0,50,0,0,0,0,0,0,0,0,0,0,0,0,0,NULL},
114 {(ASLEEP|WAKENS|WANDERS),"3d5",30,'Q',20,8,17,78,0,20,0,0,0,0,0,0,0,0,0,0,0,0,0,NULL},
115 {(ASLEEP|WAKENS|WANDERS|STINGS),"2d5",19,'R',10,3,12,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,NULL},
116 {(ASLEEP|WAKENS|WANDERS),"1d3",8,'S',2,1,9,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,NULL},
117 {(ASLEEP|WAKENS|WANDERS),"4d6/1d4",75,'T',125,13,22,75,0,33,0,0,0,0,0,0,0,0,0,0,0,0,0,NULL},
118 {(ASLEEP|WAKENS|WANDERS),"4d10",90,'U',
119 200,17,26,85,0,33,0,0,0,0,0,0,0,0,0,0,0,0,0,NULL},
120 {(ASLEEP|WAKENS|WANDERS|DRAINS_LIFE),"1d14/1d4",55,'V',
121 350,19,126,85,0,18,0,0,0,0,0,0,0,0,0,0,0,0,0,NULL},
122 {(ASLEEP|WANDERS|DROPS_LEVEL),"2d8",45,'W',55,14,23,75,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,NULL},
123 {(ASLEEP|IMITATES),"4d6",42,'X',110,16,25,75,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,NULL},
124 {(ASLEEP|WANDERS),"3d6",35,'Y',50,11,20,80,0,20,0,0,0,0,0,0,0,0,0,0,0,0,0,NULL},
125 {(ASLEEP|WAKENS|WANDERS),"1d7",21,'Z',8,5,14,69,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,NULL}
128 extern short cur_level;
129 extern short cur_room, party_room;
130 extern short blind, halluc, haste_self;
131 extern boolean detect_monster, see_invisible, r_see_invisible;
132 extern short stealthy;
134 void
135 put_mons(void)
137 short i;
138 short n;
139 object *monster;
140 short row, col;
142 n = get_rand(4, 6);
144 for (i = 0; i < n; i++) {
145 monster = gr_monster((object *) 0, 0);
146 if ((monster->m_flags & WANDERS) && coin_toss()) {
147 wake_up(monster);
149 gr_row_col(&row, &col, (FLOOR | TUNNEL | STAIRS | OBJECT));
150 put_m_at(row, col, monster);
154 object *
155 gr_monster(object *monster, int mn)
157 if (!monster) {
158 monster = alloc_object();
160 for (;;) {
161 mn = get_rand(0, MONSTERS-1);
162 if ((cur_level >= mon_tab[mn].first_level) &&
163 (cur_level <= mon_tab[mn].last_level)) {
164 break;
168 *monster = mon_tab[mn];
169 if (monster->m_flags & IMITATES) {
170 monster->disguise = gr_obj_char();
172 if (cur_level > (AMULET_LEVEL + 2)) {
173 monster->m_flags |= HASTED;
175 monster->trow = NO_ROOM;
176 return(monster);
179 void
180 mv_mons(void)
182 object *monster, *next_monster, *test_mons;
183 boolean flew;
185 if (haste_self % 2) {
186 return;
189 monster = level_monsters.next_monster;
191 while (monster) {
192 next_monster = monster->next_monster;
193 mon_disappeared = 0;
194 if (monster->m_flags & HASTED) {
195 mv_1_monster(monster, rogue.row, rogue.col);
196 if (mon_disappeared) {
197 goto NM;
199 } else if (monster->m_flags & SLOWED) {
200 monster->slowed_toggle = !monster->slowed_toggle;
201 if (monster->slowed_toggle) {
202 goto NM;
205 if ((monster->m_flags & CONFUSED) && move_confused(monster)) {
206 goto NM;
208 flew = 0;
209 if ( (monster->m_flags & FLIES) &&
210 !(monster->m_flags & NAPPING) &&
211 !mon_can_go(monster, rogue.row, rogue.col)) {
212 flew = 1;
213 mv_1_monster(monster, rogue.row, rogue.col);
214 if (mon_disappeared) {
215 goto NM;
218 if (!(flew && mon_can_go(monster, rogue.row, rogue.col))) {
219 mv_1_monster(monster, rogue.row, rogue.col);
221 NM: test_mons = level_monsters.next_monster;
222 monster = NULL;
223 while(test_mons)
225 if(next_monster == test_mons)
227 monster = next_monster;
228 break;
230 test_mons = test_mons->next_monster;
235 void
236 party_monsters(int rn, int n)
238 short i, j;
239 short row, col;
240 object *monster;
241 boolean found;
243 n += n;
245 for (i = 0; i < MONSTERS; i++) {
246 mon_tab[i].first_level -= (cur_level % 3);
248 for (i = 0; i < n; i++) {
249 if (no_room_for_monster(rn)) {
250 break;
252 for (j = found = 0; ((!found) && (j < 250)); j++) {
253 row = get_rand(rooms[rn].top_row+1,
254 rooms[rn].bottom_row-1);
255 col = get_rand(rooms[rn].left_col+1,
256 rooms[rn].right_col-1);
257 if ((!(dungeon[row][col] & MONSTER)) &&
258 (dungeon[row][col] & (FLOOR | TUNNEL))) {
259 found = 1;
262 if (found) {
263 monster = gr_monster((object *) 0, 0);
264 if (!(monster->m_flags & IMITATES)) {
265 monster->m_flags |= WAKENS;
267 put_m_at(row, col, monster);
270 for (i = 0; i < MONSTERS; i++) {
271 mon_tab[i].first_level += (cur_level % 3);
275 short
276 gmc_row_col(int row, int col)
278 object *monster;
280 if ((monster = object_at(&level_monsters, row, col))) {
281 if ((!(detect_monster || see_invisible || r_see_invisible) &&
282 (monster->m_flags & INVISIBLE)) || blind) {
283 return(monster->trail_char);
285 if (monster->m_flags & IMITATES) {
286 return(monster->disguise);
288 return(monster->m_char);
289 } else {
290 return('&'); /* BUG if this ever happens */
294 short
295 gmc(object *monster)
297 if ((!(detect_monster || see_invisible || r_see_invisible) &&
298 (monster->m_flags & INVISIBLE))
299 || blind) {
300 return(monster->trail_char);
302 if (monster->m_flags & IMITATES) {
303 return(monster->disguise);
305 return(monster->m_char);
308 void
309 mv_1_monster(object *monster, short row, short col)
311 short i, n;
312 boolean tried[6];
314 if (monster->m_flags & ASLEEP) {
315 if (monster->m_flags & NAPPING) {
316 if (--monster->nap_length <= 0) {
317 monster->m_flags &= (~(NAPPING | ASLEEP));
319 return;
321 if ((monster->m_flags & WAKENS) &&
322 rogue_is_around(monster->row, monster->col) &&
323 rand_percent(((stealthy > 0) ?
324 (WAKE_PERCENT / (STEALTH_FACTOR + stealthy)) :
325 WAKE_PERCENT))) {
326 wake_up(monster);
328 return;
329 } else if (monster->m_flags & ALREADY_MOVED) {
330 monster->m_flags &= (~ALREADY_MOVED);
331 return;
333 if ((monster->m_flags & FLITS) && flit(monster)) {
334 return;
336 if ((monster->m_flags & STATIONARY) &&
337 (!mon_can_go(monster, rogue.row, rogue.col))) {
338 return;
340 if (monster->m_flags & FREEZING_ROGUE) {
341 return;
343 if ((monster->m_flags & CONFUSES) && m_confuse(monster)) {
344 return;
346 if (mon_can_go(monster, rogue.row, rogue.col)) {
347 mon_hit(monster);
348 return;
350 if ((monster->m_flags & FLAMES) && flame_broil(monster)) {
351 return;
353 if ((monster->m_flags & SEEKS_GOLD) && seek_gold(monster)) {
354 return;
356 if ((monster->trow == monster->row) &&
357 (monster->tcol == monster->col)) {
358 monster->trow = NO_ROOM;
359 } else if (monster->trow != NO_ROOM) {
360 row = monster->trow;
361 col = monster->tcol;
363 if (monster->row > row) {
364 row = monster->row - 1;
365 } else if (monster->row < row) {
366 row = monster->row + 1;
368 if ((dungeon[row][monster->col] & DOOR) &&
369 mtry(monster, row, monster->col)) {
370 return;
372 if (monster->col > col) {
373 col = monster->col - 1;
374 } else if (monster->col < col) {
375 col = monster->col + 1;
377 if ((dungeon[monster->row][col] & DOOR) &&
378 mtry(monster, monster->row, col)) {
379 return;
381 if (mtry(monster, row, col)) {
382 return;
385 for (i = 0; i <= 5; i++) tried[i] = 0;
387 for (i = 0; i < 6; i++) {
388 NEXT_TRY: n = get_rand(0, 5);
389 switch(n) {
390 case 0:
391 if (!tried[n] && mtry(monster, row, monster->col-1)) {
392 goto O;
394 break;
395 case 1:
396 if (!tried[n] && mtry(monster, row, monster->col)) {
397 goto O;
399 break;
400 case 2:
401 if (!tried[n] && mtry(monster, row, monster->col+1)) {
402 goto O;
404 break;
405 case 3:
406 if (!tried[n] && mtry(monster, monster->row-1, col)) {
407 goto O;
409 break;
410 case 4:
411 if (!tried[n] && mtry(monster, monster->row, col)) {
412 goto O;
414 break;
415 case 5:
416 if (!tried[n] && mtry(monster, monster->row+1, col)) {
417 goto O;
419 break;
421 if (!tried[n]) {
422 tried[n] = 1;
423 } else {
424 goto NEXT_TRY;
428 if ((monster->row == monster->o_row) && (monster->col == monster->o_col)) {
429 if (++(monster->o) > 4) {
430 if ((monster->trow == NO_ROOM) &&
431 (!mon_sees(monster, rogue.row, rogue.col))) {
432 monster->trow = get_rand(1, (DROWS - 2));
433 monster->tcol = get_rand(0, (DCOLS - 1));
434 } else {
435 monster->trow = NO_ROOM;
436 monster->o = 0;
439 } else {
440 monster->o_row = monster->row;
441 monster->o_col = monster->col;
442 monster->o = 0;
446 static boolean
447 mtry(object *monster, short row, short col)
449 if (mon_can_go(monster, row, col)) {
450 move_mon_to(monster, row, col);
451 return(1);
453 return(0);
456 void
457 move_mon_to(object *monster, short row, short col)
459 short c;
460 int mrow, mcol;
462 mrow = monster->row;
463 mcol = monster->col;
465 dungeon[mrow][mcol] &= ~MONSTER;
466 dungeon[row][col] |= MONSTER;
468 c = mvinch(mrow, mcol);
470 if ((c >= 'A') && (c <= 'Z')) {
471 if (!detect_monster) {
472 mvaddch(mrow, mcol, monster->trail_char);
473 } else {
474 if (rogue_can_see(mrow, mcol)) {
475 mvaddch(mrow, mcol, monster->trail_char);
476 } else {
477 if (monster->trail_char == '.') {
478 monster->trail_char = ' ';
480 mvaddch(mrow, mcol, monster->trail_char);
484 monster->trail_char = mvinch(row, col);
485 if (!blind && (detect_monster || rogue_can_see(row, col))) {
486 if ((!(monster->m_flags & INVISIBLE) ||
487 (detect_monster || see_invisible || r_see_invisible))) {
488 mvaddch(row, col, gmc(monster));
491 if ((dungeon[row][col] & DOOR) &&
492 (get_room_number(row, col) != cur_room) &&
493 (dungeon[mrow][mcol] == FLOOR) && !blind) {
494 mvaddch(mrow, mcol, ' ');
496 if (dungeon[row][col] & DOOR) {
497 dr_course(monster, ((dungeon[mrow][mcol] & TUNNEL) ? 1 : 0),
498 row, col);
499 } else {
500 monster->row = row;
501 monster->col = col;
505 boolean
506 mon_can_go(const object *monster, short row, short col)
508 object *obj;
509 short dr, dc;
511 dr = monster->row - row; /* check if move distance > 1 */
512 if ((dr >= 2) || (dr <= -2)) {
513 return(0);
515 dc = monster->col - col;
516 if ((dc >= 2) || (dc <= -2)) {
517 return(0);
519 if ((!dungeon[monster->row][col]) || (!dungeon[row][monster->col])) {
520 return(0);
522 if ((!is_passable(row, col)) || (dungeon[row][col] & MONSTER)) {
523 return(0);
525 if ((monster->row!=row)&&(monster->col!=col)&&((dungeon[row][col]&DOOR) ||
526 (dungeon[monster->row][monster->col]&DOOR))) {
527 return(0);
529 if (!(monster->m_flags & (FLITS | CONFUSED | CAN_FLIT)) &&
530 (monster->trow == NO_ROOM)) {
531 if ((monster->row < rogue.row) && (row < monster->row)) return(0);
532 if ((monster->row > rogue.row) && (row > monster->row)) return(0);
533 if ((monster->col < rogue.col) && (col < monster->col)) return(0);
534 if ((monster->col > rogue.col) && (col > monster->col)) return(0);
536 if (dungeon[row][col] & OBJECT) {
537 obj = object_at(&level_objects, row, col);
538 if ((obj->what_is == SCROL) && (obj->which_kind == SCARE_MONSTER)) {
539 return(0);
542 return(1);
545 void
546 wake_up(object *monster)
548 if (!(monster->m_flags & NAPPING)) {
549 monster->m_flags &= (~(ASLEEP | IMITATES | WAKENS));
553 void
554 wake_room(short rn, boolean entering, short row, short col)
556 object *monster;
557 short wake_percent;
558 boolean in_room;
560 wake_percent = (rn == party_room) ? PARTY_WAKE_PERCENT : WAKE_PERCENT;
561 if (stealthy > 0) {
562 wake_percent /= (STEALTH_FACTOR + stealthy);
565 monster = level_monsters.next_monster;
567 while (monster) {
568 in_room = (rn == get_room_number(monster->row, monster->col));
569 if (in_room) {
570 if (entering) {
571 monster->trow = NO_ROOM;
572 } else {
573 monster->trow = row;
574 monster->tcol = col;
577 if ((monster->m_flags & WAKENS) &&
578 (rn == get_room_number(monster->row, monster->col))) {
579 if (rand_percent(wake_percent)) {
580 wake_up(monster);
583 monster = monster->next_monster;
587 const char *
588 mon_name(const object *monster)
590 short ch;
592 if (blind || ((monster->m_flags & INVISIBLE) &&
593 !(detect_monster || see_invisible || r_see_invisible))) {
594 return("something");
596 if (halluc) {
597 ch = get_rand('A', 'Z') - 'A';
598 return(m_names[ch]);
600 ch = monster->m_char - 'A';
601 return(m_names[ch]);
604 static short
605 rogue_is_around(int row, int col)
607 short rdif, cdif, retval;
609 rdif = row - rogue.row;
610 cdif = col - rogue.col;
612 retval = (rdif >= -1) && (rdif <= 1) && (cdif >= -1) && (cdif <= 1);
613 return(retval);
616 void
617 wanderer(void)
619 object *monster;
620 short row, col, i;
621 boolean found = 0;
623 for (i = 0; ((i < 15) && (!found)); i++) {
624 monster = gr_monster((object *) 0, 0);
625 if (!(monster->m_flags & (WAKENS | WANDERS))) {
626 free_object(monster);
627 } else {
628 found = 1;
631 if (found) {
632 found = 0;
633 wake_up(monster);
634 for (i = 0; ((i < 25) && (!found)); i++) {
635 gr_row_col(&row, &col, (FLOOR | TUNNEL | STAIRS | OBJECT));
636 if (!rogue_can_see(row, col)) {
637 put_m_at(row, col, monster);
638 found = 1;
641 if (!found) {
642 free_object(monster);
647 void
648 show_monsters(void)
650 object *monster;
652 detect_monster = 1;
654 if (blind) {
655 return;
657 monster = level_monsters.next_monster;
659 while (monster) {
660 mvaddch(monster->row, monster->col, monster->m_char);
661 if (monster->m_flags & IMITATES) {
662 monster->m_flags &= (~IMITATES);
663 monster->m_flags |= WAKENS;
665 monster = monster->next_monster;
669 void
670 create_monster(void)
672 short row, col;
673 short i;
674 boolean found = 0;
675 object *monster;
677 row = rogue.row;
678 col = rogue.col;
680 for (i = 0; i < 9; i++) {
681 rand_around(i, &row, &col);
682 if (((row == rogue.row) && (col = rogue.col)) ||
683 (row < MIN_ROW) || (row > (DROWS-2)) ||
684 (col < 0) || (col > (DCOLS-1))) {
685 continue;
687 if ((!(dungeon[row][col] & MONSTER)) &&
688 (dungeon[row][col] & (FLOOR|TUNNEL|STAIRS|DOOR))) {
689 found = 1;
690 break;
693 if (found) {
694 monster = gr_monster((object *) 0, 0);
695 put_m_at(row, col, monster);
696 mvaddch(row, col, gmc(monster));
697 if (monster->m_flags & (WANDERS | WAKENS)) {
698 wake_up(monster);
700 } else {
701 message("you hear a faint cry of anguish in the distance", 0);
705 static void
706 put_m_at(short row, short col, object *monster)
708 monster->row = row;
709 monster->col = col;
710 dungeon[row][col] |= MONSTER;
711 monster->trail_char = mvinch(row, col);
712 add_to_pack(monster, &level_monsters, 0);
713 aim_monster(monster);
716 static void
717 aim_monster(object *monster)
719 short i, rn, d, r;
721 rn = get_room_number(monster->row, monster->col);
722 r = get_rand(0, 12);
724 for (i = 0; i < 4; i++) {
725 d = (r + i) % 4;
726 if (rooms[rn].doors[d].oth_room != NO_ROOM) {
727 monster->trow = rooms[rn].doors[d].door_row;
728 monster->tcol = rooms[rn].doors[d].door_col;
729 break;
735 rogue_can_see(int row, int col)
737 int retval;
739 retval = !blind &&
740 (((get_room_number(row, col) == cur_room) &&
741 !(rooms[cur_room].is_room & R_MAZE)) ||
742 rogue_is_around(row, col));
744 return(retval);
747 static boolean
748 move_confused(object *monster)
750 short i, row, col;
752 if (!(monster->m_flags & ASLEEP)) {
753 if (--monster->moves_confused <= 0) {
754 monster->m_flags &= (~CONFUSED);
756 if (monster->m_flags & STATIONARY) {
757 return(coin_toss() ? 1 : 0);
758 } else if (rand_percent(15)) {
759 return(1);
761 row = monster->row;
762 col = monster->col;
764 for (i = 0; i < 9; i++) {
765 rand_around(i, &row, &col);
766 if ((row == rogue.row) && (col == rogue.col)) {
767 return(0);
769 if (mtry(monster, row, col)) {
770 return(1);
774 return(0);
777 static boolean
778 flit(object *monster)
780 short i, row, col;
782 if (!rand_percent(FLIT_PERCENT + ((monster->m_flags & FLIES) ? 20 : 0))) {
783 return(0);
785 if (rand_percent(10)) {
786 return(1);
788 row = monster->row;
789 col = monster->col;
791 for (i = 0; i < 9; i++) {
792 rand_around(i, &row, &col);
793 if ((row == rogue.row) && (col == rogue.col)) {
794 continue;
796 if (mtry(monster, row, col)) {
797 return(1);
800 return(1);
803 char
804 gr_obj_char(void)
806 short r;
807 const char *rs = "%!?]=/):*";
809 r = get_rand(0, 8);
811 return(rs[r]);
814 static boolean
815 no_room_for_monster(int rn)
817 short i, j;
819 for (i = rooms[rn].top_row+1; i < rooms[rn].bottom_row; i++) {
820 for (j = rooms[rn].left_col+1; j < rooms[rn].right_col; j++) {
821 if (!(dungeon[i][j] & MONSTER)) {
822 return(0);
826 return(1);
829 void
830 aggravate(void)
832 object *monster;
834 message("you hear a high pitched humming noise", 0);
836 monster = level_monsters.next_monster;
838 while (monster) {
839 wake_up(monster);
840 monster->m_flags &= (~IMITATES);
841 if (rogue_can_see(monster->row, monster->col)) {
842 mvaddch(monster->row, monster->col, monster->m_char);
844 monster = monster->next_monster;
848 boolean
849 mon_sees(const object *monster, int row, int col)
851 short rn, rdif, cdif, retval;
853 rn = get_room_number(row, col);
855 if ( (rn != NO_ROOM) &&
856 (rn == get_room_number(monster->row, monster->col)) &&
857 !(rooms[rn].is_room & R_MAZE)) {
858 return(1);
860 rdif = row - monster->row;
861 cdif = col - monster->col;
863 retval = (rdif >= -1) && (rdif <= 1) && (cdif >= -1) && (cdif <= 1);
864 return(retval);
867 void
868 mv_aquatars(void)
870 object *monster;
872 monster = level_monsters.next_monster;
874 while (monster) {
875 if ((monster->m_char == 'A') &&
876 mon_can_go(monster, rogue.row, rogue.col)) {
877 mv_1_monster(monster, rogue.row, rogue.col);
878 monster->m_flags |= ALREADY_MOVED;
880 monster = monster->next_monster;