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