Home | History | Annotate | Line # | Download | only in rogue
monster.c revision 1.13
      1 /*	$NetBSD: monster.c,v 1.13 2008/01/14 00:23:52 dholland 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.13 2008/01/14 00:23:52 dholland 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 	monster = NULL;		/* XXXGCC -Wuninitialized [powerpc] */
    633 
    634 	for (i = 0; ((i < 15) && (!found)); i++) {
    635 		monster = gr_monster((object *)0, 0);
    636 		if (!(monster->m_flags & (WAKENS | WANDERS))) {
    637 			free_object(monster);
    638 		} else {
    639 			found = 1;
    640 		}
    641 	}
    642 	if (found) {
    643 		found = 0;
    644 		wake_up(monster);
    645 		for (i = 0; ((i < 25) && (!found)); i++) {
    646 			gr_row_col(&row, &col, (FLOOR | TUNNEL | STAIRS | OBJECT));
    647 			if (!rogue_can_see(row, col)) {
    648 				put_m_at(row, col, monster);
    649 				found = 1;
    650 			}
    651 		}
    652 		if (!found) {
    653 			free_object(monster);
    654 		}
    655 	}
    656 }
    657 
    658 void
    659 show_monsters()
    660 {
    661 	object *monster;
    662 
    663 	detect_monster = 1;
    664 
    665 	if (blind) {
    666 		return;
    667 	}
    668 	monster = level_monsters.next_monster;
    669 
    670 	while (monster) {
    671 		mvaddch(monster->row, monster->col, monster->m_char);
    672 		if (monster->m_flags & IMITATES) {
    673 			monster->m_flags &= (~IMITATES);
    674 			monster->m_flags |= WAKENS;
    675 		}
    676 		monster = monster->next_monster;
    677 	}
    678 }
    679 
    680 void
    681 create_monster()
    682 {
    683 	short row, col;
    684 	short i;
    685 	boolean found = 0;
    686 	object *monster;
    687 
    688 	row = rogue.row;
    689 	col = rogue.col;
    690 
    691 	for (i = 0; i < 9; i++) {
    692 		rand_around(i, &row, &col);
    693 		if (((row == rogue.row) && (col = rogue.col)) ||
    694 				(row < MIN_ROW) || (row > (DROWS-2)) ||
    695 				(col < 0) || (col > (DCOLS-1))) {
    696 			continue;
    697 		}
    698 		if ((!(dungeon[row][col] & MONSTER)) &&
    699 			  (dungeon[row][col] & (FLOOR|TUNNEL|STAIRS|DOOR))) {
    700 			found = 1;
    701 			break;
    702 		}
    703 	}
    704 	if (found) {
    705 		monster = gr_monster((object *)0, 0);
    706 		put_m_at(row, col, monster);
    707 		mvaddch(row, col, gmc(monster));
    708 		if (monster->m_flags & (WANDERS | WAKENS)) {
    709 			wake_up(monster);
    710 		}
    711 	} else {
    712 		messagef(0, "you hear a faint cry of anguish in the distance");
    713 	}
    714 }
    715 
    716 void
    717 put_m_at(row, col, monster)
    718 	short row, col;
    719 	object *monster;
    720 {
    721 	monster->row = row;
    722 	monster->col = col;
    723 	dungeon[row][col] |= MONSTER;
    724 	monster->trail_char = mvinch(row, col);
    725 	(void)add_to_pack(monster, &level_monsters, 0);
    726 	aim_monster(monster);
    727 }
    728 
    729 void
    730 aim_monster(monster)
    731 	object *monster;
    732 {
    733 	short i, rn, d, r;
    734 
    735 	rn = get_room_number(monster->row, monster->col);
    736 	if (rn == NO_ROOM)
    737 		clean_up("aim_monster: monster not in room");
    738 	r = get_rand(0, 12);
    739 
    740 	for (i = 0; i < 4; i++) {
    741 		d = (r + i) % 4;
    742 		if (rooms[rn].doors[d].oth_room != NO_ROOM) {
    743 			monster->trow = rooms[rn].doors[d].door_row;
    744 			monster->tcol = rooms[rn].doors[d].door_col;
    745 			break;
    746 		}
    747 	}
    748 }
    749 
    750 int
    751 rogue_can_see(row, col)
    752 	int row, col;
    753 {
    754 	int retval;
    755 
    756 	retval = !blind &&
    757 			(((get_room_number(row, col) == cur_room) &&
    758 					!(rooms[cur_room].is_room & R_MAZE)) ||
    759 			rogue_is_around(row, col));
    760 
    761 	return(retval);
    762 }
    763 
    764 int
    765 move_confused(monster)
    766 	object *monster;
    767 {
    768 	short i, row, col;
    769 
    770 	if (!(monster->m_flags & ASLEEP)) {
    771 		if (--monster->moves_confused <= 0) {
    772 			monster->m_flags &= (~CONFUSED);
    773 		}
    774 		if (monster->m_flags & STATIONARY) {
    775 			return(coin_toss() ? 1 : 0);
    776 		} else if (rand_percent(15)) {
    777 			return(1);
    778 		}
    779 		row = monster->row;
    780 		col = monster->col;
    781 
    782 		for (i = 0; i < 9; i++) {
    783 			rand_around(i, &row, &col);
    784 			if ((row == rogue.row) && (col == rogue.col)) {
    785 				return(0);
    786 			}
    787 			if (mtry(monster, row, col)) {
    788 				return(1);
    789 			}
    790 		}
    791 	}
    792 	return(0);
    793 }
    794 
    795 int
    796 flit(monster)
    797 	object *monster;
    798 {
    799 	short i, row, col;
    800 
    801 	if (!rand_percent(FLIT_PERCENT + ((monster->m_flags & FLIES) ? 20 : 0))) {
    802 		return(0);
    803 	}
    804 	if (rand_percent(10)) {
    805 		return(1);
    806 	}
    807 	row = monster->row;
    808 	col = monster->col;
    809 
    810 	for (i = 0; i < 9; i++) {
    811 		rand_around(i, &row, &col);
    812 		if ((row == rogue.row) && (col == rogue.col)) {
    813 			continue;
    814 		}
    815 		if (mtry(monster, row, col)) {
    816 			return(1);
    817 		}
    818 	}
    819 	return(1);
    820 }
    821 
    822 char
    823 gr_obj_char()
    824 {
    825 	short r;
    826 	const char *rs = "%!?]=/):*";
    827 
    828 	r = get_rand(0, 8);
    829 
    830 	return(rs[r]);
    831 }
    832 
    833 int
    834 no_room_for_monster(rn)
    835 	int rn;
    836 {
    837 	short i, j;
    838 
    839 	for (i = rooms[rn].top_row+1; i < rooms[rn].bottom_row; i++) {
    840 		for (j = rooms[rn].left_col+1; j < rooms[rn].right_col; j++) {
    841 			if (!(dungeon[i][j] & MONSTER)) {
    842 				return(0);
    843 			}
    844 		}
    845 	}
    846 	return(1);
    847 }
    848 
    849 void
    850 aggravate()
    851 {
    852 	object *monster;
    853 
    854 	messagef(0, "you hear a high pitched humming noise");
    855 
    856 	monster = level_monsters.next_monster;
    857 
    858 	while (monster) {
    859 		wake_up(monster);
    860 		monster->m_flags &= (~IMITATES);
    861 		if (rogue_can_see(monster->row, monster->col)) {
    862 			mvaddch(monster->row, monster->col, monster->m_char);
    863 		}
    864 		monster = monster->next_monster;
    865 	}
    866 }
    867 
    868 boolean
    869 mon_sees(monster, row, col)
    870 	const object *monster;
    871 	int row, col;
    872 {
    873 	short rn, rdif, cdif, retval;
    874 
    875 	rn = get_room_number(row, col);
    876 
    877 	if (	(rn != NO_ROOM) &&
    878 			(rn == get_room_number(monster->row, monster->col)) &&
    879 			!(rooms[rn].is_room & R_MAZE)) {
    880 		return(1);
    881 	}
    882 	rdif = row - monster->row;
    883 	cdif = col - monster->col;
    884 
    885 	retval = (rdif >= -1) && (rdif <= 1) && (cdif >= -1) && (cdif <= 1);
    886 	return(retval);
    887 }
    888 
    889 void
    890 mv_aquatars()
    891 {
    892 	object *monster;
    893 
    894 	monster = level_monsters.next_monster;
    895 
    896 	while (monster) {
    897 		if ((monster->m_char == 'A') &&
    898 			mon_can_go(monster, rogue.row, rogue.col)) {
    899 			mv_1_monster(monster, rogue.row, rogue.col);
    900 			monster->m_flags |= ALREADY_MOVED;
    901 		}
    902 		monster = monster->next_monster;
    903 	}
    904 }
    905