games: Massive style(9) cleanup commit. Reduces differences to NetBSD.
[dragonfly.git] / games / rogue / monster.c
blob02a137be6c51e3622b3d3e18726d856082461d36
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. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
32 * @(#)monster.c 8.1 (Berkeley) 5/31/93
33 * $FreeBSD: src/games/rogue/monster.c,v 1.6 1999/11/30 03:49:24 billf Exp $
34 * $DragonFly: src/games/rogue/monster.c,v 1.3 2006/09/02 19:31:07 pavalos Exp $
38 * monster.c
40 * This source herein may be modified and/or distributed by anybody who
41 * so desires, with the following restrictions:
42 * 1.) No portion of this notice shall be removed.
43 * 2.) Credit shall not be taken for the creation of this source.
44 * 3.) This code is not to be traded, sold, or used for personal
45 * gain or profit.
49 #include "rogue.h"
51 object level_monsters;
52 boolean mon_disappeared;
54 const char *const m_names[] = {
55 "aquator",
56 "bat",
57 "centaur",
58 "dragon",
59 "emu",
60 "venus fly-trap",
61 "griffin",
62 "hobgoblin",
63 "ice monster",
64 "jabberwock",
65 "kestrel",
66 "leprechaun",
67 "medusa",
68 "nymph",
69 "orc",
70 "phantom",
71 "quagga",
72 "rattlesnake",
73 "snake",
74 "troll",
75 "black unicorn",
76 "vampire",
77 "wraith",
78 "xeroc",
79 "yeti",
80 "zombie"
83 object mon_tab[MONSTERS] = {
84 {(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},
85 {(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},
86 {(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},
87 {(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},
88 {(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},
89 {(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},
90 {(ASLEEP|WAKENS|WANDERS|FLIES),"5d5/5d5",115,'G',
91 2000,20,126,85,0,10,0,0,0,0,0,0,0,0,0,0,0,0,0,NULL},
92 {(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},
93 {(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},
94 {(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},
95 {(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},
96 {(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},
97 {(ASLEEP|WAKENS|WANDERS|CONFUSES),"4d4/3d7",97,'M',
98 250,18,126,85,0,25,0,0,0,0,0,0,0,0,0,0,0,0,0,NULL},
99 {(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},
100 {(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},
101 {(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},
102 {(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},
103 {(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},
104 {(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},
105 {(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},
106 {(ASLEEP|WAKENS|WANDERS),"4d10",90,'U',
107 200,17,26,85,0,33,0,0,0,0,0,0,0,0,0,0,0,0,0,NULL},
108 {(ASLEEP|WAKENS|WANDERS|DRAINS_LIFE),"1d14/1d4",55,'V',
109 350,19,126,85,0,18,0,0,0,0,0,0,0,0,0,0,0,0,0,NULL},
110 {(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},
111 {(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},
112 {(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},
113 {(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}
116 static void aim_monster(object *);
117 static boolean flit(object *);
118 static boolean move_confused(object *);
119 static boolean mtry(object *, short, short);
120 static boolean no_room_for_monster(int);
121 static void put_m_at(short, short, object *);
122 static short rogue_is_around(int, int);
124 extern short cur_level;
125 extern short cur_room, party_room;
126 extern short blind, halluc, haste_self;
127 extern boolean detect_monster, see_invisible, r_see_invisible;
128 extern short stealthy;
130 void
131 put_mons(void)
133 short i;
134 short n;
135 object *monster;
136 short row, col;
138 n = get_rand(4, 6);
140 for (i = 0; i < n; i++) {
141 monster = gr_monster(NULL, 0);
142 if ((monster->m_flags & WANDERS) && coin_toss()) {
143 wake_up(monster);
145 gr_row_col(&row, &col, (FLOOR | TUNNEL | STAIRS | OBJECT));
146 put_m_at(row, col, monster);
150 object *
151 gr_monster(object *monster, int mn)
153 if (!monster) {
154 monster = alloc_object();
156 for (;;) {
157 mn = get_rand(0, MONSTERS-1);
158 if ((cur_level >= mon_tab[mn].first_level) &&
159 (cur_level <= mon_tab[mn].last_level)) {
160 break;
164 *monster = mon_tab[mn];
165 if (monster->m_flags & IMITATES) {
166 monster->disguise = gr_obj_char();
168 if (cur_level > (AMULET_LEVEL + 2)) {
169 monster->m_flags |= HASTED;
171 monster->trow = NO_ROOM;
172 return(monster);
175 void
176 mv_mons(void)
178 object *monster, *next_monster, *test_mons;
179 boolean flew;
181 if (haste_self % 2) {
182 return;
185 monster = level_monsters.next_monster;
187 while (monster) {
188 next_monster = monster->next_monster;
189 mon_disappeared = 0;
190 if (monster->m_flags & HASTED) {
191 mv_1_monster(monster, rogue.row, rogue.col);
192 if (mon_disappeared) {
193 goto NM;
195 } else if (monster->m_flags & SLOWED) {
196 monster->slowed_toggle = !monster->slowed_toggle;
197 if (monster->slowed_toggle) {
198 goto NM;
201 if ((monster->m_flags & CONFUSED) && move_confused(monster)) {
202 goto NM;
204 flew = 0;
205 if ( (monster->m_flags & FLIES) &&
206 !(monster->m_flags & NAPPING) &&
207 !mon_can_go(monster, rogue.row, rogue.col)) {
208 flew = 1;
209 mv_1_monster(monster, rogue.row, rogue.col);
210 if (mon_disappeared) {
211 goto NM;
214 if (!(flew && mon_can_go(monster, rogue.row, rogue.col))) {
215 mv_1_monster(monster, rogue.row, rogue.col);
217 NM: test_mons = level_monsters.next_monster;
218 monster = NULL;
219 while (test_mons)
221 if (next_monster == test_mons)
223 monster = next_monster;
224 break;
226 test_mons = test_mons->next_monster;
231 void
232 party_monsters(int rn, int n)
234 short i, j;
235 short row, col;
236 object *monster;
237 boolean found;
239 n += n;
241 for (i = 0; i < MONSTERS; i++) {
242 mon_tab[i].first_level -= (cur_level % 3);
244 for (i = 0; i < n; i++) {
245 if (no_room_for_monster(rn)) {
246 break;
248 for (j = found = 0; ((!found) && (j < 250)); j++) {
249 row = get_rand(rooms[rn].top_row+1,
250 rooms[rn].bottom_row-1);
251 col = get_rand(rooms[rn].left_col+1,
252 rooms[rn].right_col-1);
253 if ((!(dungeon[row][col] & MONSTER)) &&
254 (dungeon[row][col] & (FLOOR | TUNNEL))) {
255 found = 1;
258 if (found) {
259 monster = gr_monster(NULL, 0);
260 if (!(monster->m_flags & IMITATES)) {
261 monster->m_flags |= WAKENS;
263 put_m_at(row, col, monster);
266 for (i = 0; i < MONSTERS; i++) {
267 mon_tab[i].first_level += (cur_level % 3);
271 short
272 gmc_row_col(int row, int col)
274 object *monster;
276 if ((monster = object_at(&level_monsters, row, col)) != NULL) {
277 if ((!(detect_monster || see_invisible || r_see_invisible) &&
278 (monster->m_flags & INVISIBLE)) || blind) {
279 return(monster->trail_char);
281 if (monster->m_flags & IMITATES) {
282 return(monster->disguise);
284 return(monster->m_char);
285 } else {
286 return('&'); /* BUG if this ever happens */
290 short
291 gmc(object *monster)
293 if ((!(detect_monster || see_invisible || r_see_invisible) &&
294 (monster->m_flags & INVISIBLE))
295 || blind) {
296 return(monster->trail_char);
298 if (monster->m_flags & IMITATES) {
299 return(monster->disguise);
301 return(monster->m_char);
304 void
305 mv_1_monster(object *monster, short row, short col)
307 short i, n;
308 boolean tried[6];
310 if (monster->m_flags & ASLEEP) {
311 if (monster->m_flags & NAPPING) {
312 if (--monster->nap_length <= 0) {
313 monster->m_flags &= (~(NAPPING | ASLEEP));
315 return;
317 if ((monster->m_flags & WAKENS) &&
318 rogue_is_around(monster->row, monster->col) &&
319 rand_percent(((stealthy > 0) ?
320 (WAKE_PERCENT / (STEALTH_FACTOR + stealthy)) :
321 WAKE_PERCENT))) {
322 wake_up(monster);
324 return;
325 } else if (monster->m_flags & ALREADY_MOVED) {
326 monster->m_flags &= (~ALREADY_MOVED);
327 return;
329 if ((monster->m_flags & FLITS) && flit(monster)) {
330 return;
332 if ((monster->m_flags & STATIONARY) &&
333 (!mon_can_go(monster, rogue.row, rogue.col))) {
334 return;
336 if (monster->m_flags & FREEZING_ROGUE) {
337 return;
339 if ((monster->m_flags & CONFUSES) && m_confuse(monster)) {
340 return;
342 if (mon_can_go(monster, rogue.row, rogue.col)) {
343 mon_hit(monster);
344 return;
346 if ((monster->m_flags & FLAMES) && flame_broil(monster)) {
347 return;
349 if ((monster->m_flags & SEEKS_GOLD) && seek_gold(monster)) {
350 return;
352 if ((monster->trow == monster->row) &&
353 (monster->tcol == monster->col)) {
354 monster->trow = NO_ROOM;
355 } else if (monster->trow != NO_ROOM) {
356 row = monster->trow;
357 col = monster->tcol;
359 if (monster->row > row) {
360 row = monster->row - 1;
361 } else if (monster->row < row) {
362 row = monster->row + 1;
364 if ((dungeon[row][monster->col] & DOOR) &&
365 mtry(monster, row, monster->col)) {
366 return;
368 if (monster->col > col) {
369 col = monster->col - 1;
370 } else if (monster->col < col) {
371 col = monster->col + 1;
373 if ((dungeon[monster->row][col] & DOOR) &&
374 mtry(monster, monster->row, col)) {
375 return;
377 if (mtry(monster, row, col)) {
378 return;
381 for (i = 0; i <= 5; i++) tried[i] = 0;
383 for (i = 0; i < 6; i++) {
384 NEXT_TRY: n = get_rand(0, 5);
385 switch(n) {
386 case 0:
387 if (!tried[n] && mtry(monster, row, monster->col-1)) {
388 goto O;
390 break;
391 case 1:
392 if (!tried[n] && mtry(monster, row, monster->col)) {
393 goto O;
395 break;
396 case 2:
397 if (!tried[n] && mtry(monster, row, monster->col+1)) {
398 goto O;
400 break;
401 case 3:
402 if (!tried[n] && mtry(monster, monster->row-1, col)) {
403 goto O;
405 break;
406 case 4:
407 if (!tried[n] && mtry(monster, monster->row, col)) {
408 goto O;
410 break;
411 case 5:
412 if (!tried[n] && mtry(monster, monster->row+1, col)) {
413 goto O;
415 break;
417 if (!tried[n]) {
418 tried[n] = 1;
419 } else {
420 goto NEXT_TRY;
424 if ((monster->row == monster->o_row) && (monster->col == monster->o_col)) {
425 if (++(monster->o) > 4) {
426 if ((monster->trow == NO_ROOM) &&
427 (!mon_sees(monster, rogue.row, rogue.col))) {
428 monster->trow = get_rand(1, (DROWS - 2));
429 monster->tcol = get_rand(0, (DCOLS - 1));
430 } else {
431 monster->trow = NO_ROOM;
432 monster->o = 0;
435 } else {
436 monster->o_row = monster->row;
437 monster->o_col = monster->col;
438 monster->o = 0;
442 static boolean
443 mtry(object *monster, short row, short col)
445 if (mon_can_go(monster, row, col)) {
446 move_mon_to(monster, row, col);
447 return(1);
449 return(0);
452 void
453 move_mon_to(object *monster, short row, short col)
455 short c;
456 int mrow, mcol;
458 mrow = monster->row;
459 mcol = monster->col;
461 dungeon[mrow][mcol] &= ~MONSTER;
462 dungeon[row][col] |= MONSTER;
464 c = mvinch(mrow, mcol);
466 if ((c >= 'A') && (c <= 'Z')) {
467 if (!detect_monster) {
468 mvaddch(mrow, mcol, monster->trail_char);
469 } else {
470 if (rogue_can_see(mrow, mcol)) {
471 mvaddch(mrow, mcol, monster->trail_char);
472 } else {
473 if (monster->trail_char == '.') {
474 monster->trail_char = ' ';
476 mvaddch(mrow, mcol, monster->trail_char);
480 monster->trail_char = mvinch(row, col);
481 if (!blind && (detect_monster || rogue_can_see(row, col))) {
482 if ((!(monster->m_flags & INVISIBLE) ||
483 (detect_monster || see_invisible || r_see_invisible))) {
484 mvaddch(row, col, gmc(monster));
487 if ((dungeon[row][col] & DOOR) &&
488 (get_room_number(row, col) != cur_room) &&
489 (dungeon[mrow][mcol] == FLOOR) && !blind) {
490 mvaddch(mrow, mcol, ' ');
492 if (dungeon[row][col] & DOOR) {
493 dr_course(monster, ((dungeon[mrow][mcol] & TUNNEL) ? 1 : 0),
494 row, col);
495 } else {
496 monster->row = row;
497 monster->col = col;
501 boolean
502 mon_can_go(const object *monster, short row, short col)
504 object *obj;
505 short dr, dc;
507 dr = monster->row - row; /* check if move distance > 1 */
508 if ((dr >= 2) || (dr <= -2)) {
509 return(0);
511 dc = monster->col - col;
512 if ((dc >= 2) || (dc <= -2)) {
513 return(0);
515 if ((!dungeon[monster->row][col]) || (!dungeon[row][monster->col])) {
516 return(0);
518 if ((!is_passable(row, col)) || (dungeon[row][col] & MONSTER)) {
519 return(0);
521 if ((monster->row!=row)&&(monster->col!=col)&&((dungeon[row][col]&DOOR) ||
522 (dungeon[monster->row][monster->col]&DOOR))) {
523 return(0);
525 if (!(monster->m_flags & (FLITS | CONFUSED | CAN_FLIT)) &&
526 (monster->trow == NO_ROOM)) {
527 if ((monster->row < rogue.row) && (row < monster->row)) return(0);
528 if ((monster->row > rogue.row) && (row > monster->row)) return(0);
529 if ((monster->col < rogue.col) && (col < monster->col)) return(0);
530 if ((monster->col > rogue.col) && (col > monster->col)) return(0);
532 if (dungeon[row][col] & OBJECT) {
533 obj = object_at(&level_objects, row, col);
534 if ((obj->what_is == SCROL) && (obj->which_kind == SCARE_MONSTER)) {
535 return(0);
538 return(1);
541 void
542 wake_up(object *monster)
544 if (!(monster->m_flags & NAPPING)) {
545 monster->m_flags &= (~(ASLEEP | IMITATES | WAKENS));
549 void
550 wake_room(short rn, boolean entering, short row, short col)
552 object *monster;
553 short wake_percent;
554 boolean in_room;
556 wake_percent = (rn == party_room) ? PARTY_WAKE_PERCENT : WAKE_PERCENT;
557 if (stealthy > 0) {
558 wake_percent /= (STEALTH_FACTOR + stealthy);
561 monster = level_monsters.next_monster;
563 while (monster) {
564 in_room = (rn == get_room_number(monster->row, monster->col));
565 if (in_room) {
566 if (entering) {
567 monster->trow = NO_ROOM;
568 } else {
569 monster->trow = row;
570 monster->tcol = col;
573 if ((monster->m_flags & WAKENS) &&
574 (rn == get_room_number(monster->row, monster->col))) {
575 if (rand_percent(wake_percent)) {
576 wake_up(monster);
579 monster = monster->next_monster;
583 const char *
584 mon_name(const object *monster)
586 short ch;
588 if (blind || ((monster->m_flags & INVISIBLE) &&
589 !(detect_monster || see_invisible || r_see_invisible))) {
590 return("something");
592 if (halluc) {
593 ch = get_rand('A', 'Z') - 'A';
594 return(m_names[ch]);
596 ch = monster->m_char - 'A';
597 return(m_names[ch]);
600 static short
601 rogue_is_around(int row, int col)
603 short rdif, cdif, retval;
605 rdif = row - rogue.row;
606 cdif = col - rogue.col;
608 retval = (rdif >= -1) && (rdif <= 1) && (cdif >= -1) && (cdif <= 1);
609 return(retval);
612 void
613 wanderer(void)
615 object *monster;
616 short row, col, i;
617 boolean found = 0;
619 for (i = 0; ((i < 15) && (!found)); i++) {
620 monster = gr_monster(NULL, 0);
621 if (!(monster->m_flags & (WAKENS | WANDERS))) {
622 free_object(monster);
623 } else {
624 found = 1;
627 if (found) {
628 found = 0;
629 wake_up(monster);
630 for (i = 0; ((i < 25) && (!found)); i++) {
631 gr_row_col(&row, &col, (FLOOR | TUNNEL | STAIRS | OBJECT));
632 if (!rogue_can_see(row, col)) {
633 put_m_at(row, col, monster);
634 found = 1;
637 if (!found) {
638 free_object(monster);
643 void
644 show_monsters(void)
646 object *monster;
648 detect_monster = 1;
650 if (blind) {
651 return;
653 monster = level_monsters.next_monster;
655 while (monster) {
656 mvaddch(monster->row, monster->col, monster->m_char);
657 if (monster->m_flags & IMITATES) {
658 monster->m_flags &= (~IMITATES);
659 monster->m_flags |= WAKENS;
661 monster = monster->next_monster;
665 void
666 create_monster(void)
668 short row, col;
669 short i;
670 boolean found = 0;
671 object *monster;
673 row = rogue.row;
674 col = rogue.col;
676 for (i = 0; i < 9; i++) {
677 rand_around(i, &row, &col);
678 if (((row == rogue.row) && (col = rogue.col)) ||
679 (row < MIN_ROW) || (row > (DROWS-2)) ||
680 (col < 0) || (col > (DCOLS-1))) {
681 continue;
683 if ((!(dungeon[row][col] & MONSTER)) &&
684 (dungeon[row][col] & (FLOOR|TUNNEL|STAIRS|DOOR))) {
685 found = 1;
686 break;
689 if (found) {
690 monster = gr_monster(NULL, 0);
691 put_m_at(row, col, monster);
692 mvaddch(row, col, gmc(monster));
693 if (monster->m_flags & (WANDERS | WAKENS)) {
694 wake_up(monster);
696 } else {
697 message("you hear a faint cry of anguish in the distance", 0);
701 static void
702 put_m_at(short row, short col, object *monster)
704 monster->row = row;
705 monster->col = col;
706 dungeon[row][col] |= MONSTER;
707 monster->trail_char = mvinch(row, col);
708 add_to_pack(monster, &level_monsters, 0);
709 aim_monster(monster);
712 static void
713 aim_monster(object *monster)
715 short i, rn, d, r;
717 rn = get_room_number(monster->row, monster->col);
718 r = get_rand(0, 12);
720 for (i = 0; i < 4; i++) {
721 d = (r + i) % 4;
722 if (rooms[rn].doors[d].oth_room != NO_ROOM) {
723 monster->trow = rooms[rn].doors[d].door_row;
724 monster->tcol = rooms[rn].doors[d].door_col;
725 break;
731 rogue_can_see(int row, int col)
733 int retval;
735 retval = !blind &&
736 (((get_room_number(row, col) == cur_room) &&
737 !(rooms[cur_room].is_room & R_MAZE)) ||
738 rogue_is_around(row, col));
740 return(retval);
743 static boolean
744 move_confused(object *monster)
746 short i, row, col;
748 if (!(monster->m_flags & ASLEEP)) {
749 if (--monster->moves_confused <= 0) {
750 monster->m_flags &= (~CONFUSED);
752 if (monster->m_flags & STATIONARY) {
753 return(coin_toss() ? 1 : 0);
754 } else if (rand_percent(15)) {
755 return(1);
757 row = monster->row;
758 col = monster->col;
760 for (i = 0; i < 9; i++) {
761 rand_around(i, &row, &col);
762 if ((row == rogue.row) && (col == rogue.col)) {
763 return(0);
765 if (mtry(monster, row, col)) {
766 return(1);
770 return(0);
773 static boolean
774 flit(object *monster)
776 short i, row, col;
778 if (!rand_percent(FLIT_PERCENT + ((monster->m_flags & FLIES) ? 20 : 0))) {
779 return(0);
781 if (rand_percent(10)) {
782 return(1);
784 row = monster->row;
785 col = monster->col;
787 for (i = 0; i < 9; i++) {
788 rand_around(i, &row, &col);
789 if ((row == rogue.row) && (col == rogue.col)) {
790 continue;
792 if (mtry(monster, row, col)) {
793 return(1);
796 return(1);
799 char
800 gr_obj_char(void)
802 short r;
803 const char *rs = "%!?]=/):*";
805 r = get_rand(0, 8);
807 return(rs[r]);
810 static boolean
811 no_room_for_monster(int rn)
813 short i, j;
815 for (i = rooms[rn].top_row+1; i < rooms[rn].bottom_row; i++) {
816 for (j = rooms[rn].left_col+1; j < rooms[rn].right_col; j++) {
817 if (!(dungeon[i][j] & MONSTER)) {
818 return(0);
822 return(1);
825 void
826 aggravate(void)
828 object *monster;
830 message("you hear a high pitched humming noise", 0);
832 monster = level_monsters.next_monster;
834 while (monster) {
835 wake_up(monster);
836 monster->m_flags &= (~IMITATES);
837 if (rogue_can_see(monster->row, monster->col)) {
838 mvaddch(monster->row, monster->col, monster->m_char);
840 monster = monster->next_monster;
844 boolean
845 mon_sees(const object *monster, int row, int col)
847 short rn, rdif, cdif, retval;
849 rn = get_room_number(row, col);
851 if ( (rn != NO_ROOM) &&
852 (rn == get_room_number(monster->row, monster->col)) &&
853 !(rooms[rn].is_room & R_MAZE)) {
854 return(1);
856 rdif = row - monster->row;
857 cdif = col - monster->col;
859 retval = (rdif >= -1) && (rdif <= 1) && (cdif >= -1) && (cdif <= 1);
860 return(retval);
863 void
864 mv_aquatars(void)
866 object *monster;
868 monster = level_monsters.next_monster;
870 while (monster) {
871 if ((monster->m_char == 'A') &&
872 mon_can_go(monster, rogue.row, rogue.col)) {
873 mv_1_monster(monster, rogue.row, rogue.col);
874 monster->m_flags |= ALREADY_MOVED;
876 monster = monster->next_monster;