Home | History | Annotate | Line # | Download | only in rogue
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