Home | History | Annotate | Line # | Download | only in rogue
monster.c revision 1.9
      1 /*	$NetBSD: monster.c,v 1.9 2005/06/09 09:36:19 he 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.9 2005/06/09 09:36:19 he 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 [pmppc] */
    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 		message("you hear a faint cry of anguish in the distance", 0);
    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 	r = get_rand(0, 12);
    737 
    738 	for (i = 0; i < 4; i++) {
    739 		d = (r + i) % 4;
    740 		if (rooms[rn].doors[d].oth_room != NO_ROOM) {
    741 			monster->trow = rooms[rn].doors[d].door_row;
    742 			monster->tcol = rooms[rn].doors[d].door_col;
    743 			break;
    744 		}
    745 	}
    746 }
    747 
    748 int
    749 rogue_can_see(row, col)
    750 	int row, col;
    751 {
    752 	int retval;
    753 
    754 	retval = !blind &&
    755 			(((get_room_number(row, col) == cur_room) &&
    756 					!(rooms[cur_room].is_room & R_MAZE)) ||
    757 			rogue_is_around(row, col));
    758 
    759 	return(retval);
    760 }
    761 
    762 int
    763 move_confused(monster)
    764 	object *monster;
    765 {
    766 	short i, row, col;
    767 
    768 	if (!(monster->m_flags & ASLEEP)) {
    769 		if (--monster->moves_confused <= 0) {
    770 			monster->m_flags &= (~CONFUSED);
    771 		}
    772 		if (monster->m_flags & STATIONARY) {
    773 			return(coin_toss() ? 1 : 0);
    774 		} else if (rand_percent(15)) {
    775 			return(1);
    776 		}
    777 		row = monster->row;
    778 		col = monster->col;
    779 
    780 		for (i = 0; i < 9; i++) {
    781 			rand_around(i, &row, &col);
    782 			if ((row == rogue.row) && (col == rogue.col)) {
    783 				return(0);
    784 			}
    785 			if (mtry(monster, row, col)) {
    786 				return(1);
    787 			}
    788 		}
    789 	}
    790 	return(0);
    791 }
    792 
    793 int
    794 flit(monster)
    795 	object *monster;
    796 {
    797 	short i, row, col;
    798 
    799 	if (!rand_percent(FLIT_PERCENT + ((monster->m_flags & FLIES) ? 20 : 0))) {
    800 		return(0);
    801 	}
    802 	if (rand_percent(10)) {
    803 		return(1);
    804 	}
    805 	row = monster->row;
    806 	col = monster->col;
    807 
    808 	for (i = 0; i < 9; i++) {
    809 		rand_around(i, &row, &col);
    810 		if ((row == rogue.row) && (col == rogue.col)) {
    811 			continue;
    812 		}
    813 		if (mtry(monster, row, col)) {
    814 			return(1);
    815 		}
    816 	}
    817 	return(1);
    818 }
    819 
    820 char
    821 gr_obj_char()
    822 {
    823 	short r;
    824 	const char *rs = "%!?]=/):*";
    825 
    826 	r = get_rand(0, 8);
    827 
    828 	return(rs[r]);
    829 }
    830 
    831 int
    832 no_room_for_monster(rn)
    833 	int rn;
    834 {
    835 	short i, j;
    836 
    837 	for (i = rooms[rn].top_row+1; i < rooms[rn].bottom_row; i++) {
    838 		for (j = rooms[rn].left_col+1; j < rooms[rn].right_col; j++) {
    839 			if (!(dungeon[i][j] & MONSTER)) {
    840 				return(0);
    841 			}
    842 		}
    843 	}
    844 	return(1);
    845 }
    846 
    847 void
    848 aggravate()
    849 {
    850 	object *monster;
    851 
    852 	message("you hear a high pitched humming noise", 0);
    853 
    854 	monster = level_monsters.next_monster;
    855 
    856 	while (monster) {
    857 		wake_up(monster);
    858 		monster->m_flags &= (~IMITATES);
    859 		if (rogue_can_see(monster->row, monster->col)) {
    860 			mvaddch(monster->row, monster->col, monster->m_char);
    861 		}
    862 		monster = monster->next_monster;
    863 	}
    864 }
    865 
    866 boolean
    867 mon_sees(monster, row, col)
    868 	const object *monster;
    869 	int row, col;
    870 {
    871 	short rn, rdif, cdif, retval;
    872 
    873 	rn = get_room_number(row, col);
    874 
    875 	if (	(rn != NO_ROOM) &&
    876 			(rn == get_room_number(monster->row, monster->col)) &&
    877 			!(rooms[rn].is_room & R_MAZE)) {
    878 		return(1);
    879 	}
    880 	rdif = row - monster->row;
    881 	cdif = col - monster->col;
    882 
    883 	retval = (rdif >= -1) && (rdif <= 1) && (cdif >= -1) && (cdif <= 1);
    884 	return(retval);
    885 }
    886 
    887 void
    888 mv_aquatars()
    889 {
    890 	object *monster;
    891 
    892 	monster = level_monsters.next_monster;
    893 
    894 	while (monster) {
    895 		if ((monster->m_char == 'A') &&
    896 			mon_can_go(monster, rogue.row, rogue.col)) {
    897 			mv_1_monster(monster, rogue.row, rogue.col);
    898 			monster->m_flags |= ALREADY_MOVED;
    899 		}
    900 		monster = monster->next_monster;
    901 	}
    902 }
    903