Home | History | Annotate | Line # | Download | only in rogue
monster.c revision 1.3
      1 /*	$NetBSD: monster.c,v 1.3 1995/04/22 10:27:45 cgd 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 #ifndef lint
     40 #if 0
     41 static char sccsid[] = "@(#)monster.c	8.1 (Berkeley) 5/31/93";
     42 #else
     43 static char rcsid[] = "$NetBSD: monster.c,v 1.3 1995/04/22 10:27:45 cgd Exp $";
     44 #endif
     45 #endif /* not lint */
     46 
     47 /*
     48  * monster.c
     49  *
     50  * This source herein may be modified and/or distributed by anybody who
     51  * so desires, with the following restrictions:
     52  *    1.)  No portion of this notice shall be removed.
     53  *    2.)  Credit shall not be taken for the creation of this source.
     54  *    3.)  This code is not to be traded, sold, or used for personal
     55  *         gain or profit.
     56  *
     57  */
     58 
     59 #include "rogue.h"
     60 
     61 object level_monsters;
     62 boolean mon_disappeared;
     63 
     64 char *m_names[] = {
     65 	"aquator",
     66 	"bat",
     67 	"centaur",
     68 	"dragon",
     69 	"emu",
     70 	"venus fly-trap",
     71 	"griffin",
     72 	"hobgoblin",
     73 	"ice monster",
     74 	"jabberwock",
     75 	"kestrel",
     76 	"leprechaun",
     77 	"medusa",
     78 	"nymph",
     79 	"orc",
     80 	"phantom",
     81 	"quagga",
     82 	"rattlesnake",
     83 	"snake",
     84 	"troll",
     85 	"black unicorn",
     86 	"vampire",
     87 	"wraith",
     88 	"xeroc",
     89 	"yeti",
     90 	"zombie"
     91 };
     92 
     93 object mon_tab[MONSTERS] = {
     94 	{(ASLEEP|WAKENS|WANDERS|RUSTS),"0d0",25,'A',20,9,18,100,0,0,0,0,0},
     95 	{(ASLEEP|WANDERS|FLITS|FLIES),"1d3",10,'B',2,1,8,60,0,0,0,0,0},
     96 	{(ASLEEP|WANDERS),"3d3/2d5",32,'C',15,7,16,85,0,10,0,0,0},
     97 	{(ASLEEP|WAKENS|FLAMES),"4d6/4d9",145,'D',5000,21,126,100,0,90,0,0,0},
     98 	{(ASLEEP|WAKENS),"1d3",11,'E',2,1,7,65,0,0,0,0,0},
     99 	{(HOLDS|STATIONARY),"5d5",73,'F',91,12,126,80,0,0,0,0,0},
    100 	{(ASLEEP|WAKENS|WANDERS|FLIES),"5d5/5d5",115,'G',
    101 			2000,20,126,85,0,10,0,0,0},
    102 	{(ASLEEP|WAKENS|WANDERS),"1d3/1d2",15,'H',3,1,10,67,0,0,0,0,0},
    103 	{(ASLEEP|FREEZES),"0d0",15,'I',5,2,11,68,0,0,0,0,0},
    104 	{(ASLEEP|WANDERS),"3d10/4d5",132,'J',3000,21,126,100,0,0,0,0,0},
    105 	{(ASLEEP|WAKENS|WANDERS|FLIES),"1d4",10,'K',2,1,6,60,0,0,0,0,0},
    106 	{(ASLEEP|STEALS_GOLD),"0d0",25,'L',21,6,16,75,0,0,0,0,0},
    107 	{(ASLEEP|WAKENS|WANDERS|CONFUSES),"4d4/3d7",97,'M',
    108 			250,18,126,85,0,25,0,0,0},
    109 	{(ASLEEP|STEALS_ITEM),"0d0",25,'N',39,10,19,75,0,100,0,0,0},
    110 	{(ASLEEP|WANDERS|WAKENS|SEEKS_GOLD),"1d6",25,'O',5,4,13,70,0,10,0,0,0},
    111 	{(ASLEEP|INVISIBLE|WANDERS|FLITS),"5d4",76,'P',120,15,24,80,0,50,0,0,0},
    112 	{(ASLEEP|WAKENS|WANDERS),"3d5",30,'Q',20,8,17,78,0,20,0,0,0},
    113 	{(ASLEEP|WAKENS|WANDERS|STINGS),"2d5",19,'R',10,3,12,70,0,0,0,0,0},
    114 	{(ASLEEP|WAKENS|WANDERS),"1d3",8,'S',2,1,9,50,0,0,0,0,0},
    115 	{(ASLEEP|WAKENS|WANDERS),"4d6/1d4",75,'T',125,13,22,75,0,33,0,0,0},
    116 	{(ASLEEP|WAKENS|WANDERS),"4d10",90,'U',
    117 			200,17,26,85,0,33,0,0,0},
    118 	{(ASLEEP|WAKENS|WANDERS|DRAINS_LIFE),"1d14/1d4",55,'V',
    119 			350,19,126,85,0,18,0,0,0},
    120 	{(ASLEEP|WANDERS|DROPS_LEVEL),"2d8",45,'W',55,14,23,75,0,0,0,0,0},
    121 	{(ASLEEP|IMITATES),"4d6",42,'X',110,16,25,75,0,0,0,0,0},
    122 	{(ASLEEP|WANDERS),"3d6",35,'Y',50,11,20,80,0,20,0,0,0},
    123 	{(ASLEEP|WAKENS|WANDERS),"1d7",21,'Z',8,5,14,69,0,0,0,0,0}
    124 };
    125 
    126 extern short cur_level;
    127 extern short cur_room, party_room;
    128 extern short blind, halluc, haste_self;
    129 extern boolean detect_monster, see_invisible, r_see_invisible;
    130 extern short stealthy;
    131 
    132 put_mons()
    133 {
    134 	short i;
    135 	short n;
    136 	object *monster;
    137 	short row, col;
    138 
    139 	n = get_rand(4, 6);
    140 
    141 	for (i = 0; i < n; i++) {
    142 		monster = gr_monster((object *) 0, 0);
    143 		if ((monster->m_flags & WANDERS) && coin_toss()) {
    144 			wake_up(monster);
    145 		}
    146 		gr_row_col(&row, &col, (FLOOR | TUNNEL | STAIRS | OBJECT));
    147 		put_m_at(row, col, monster);
    148 	}
    149 }
    150 
    151 object *
    152 gr_monster(monster, mn)
    153 register object *monster;
    154 register mn;
    155 {
    156 	if (!monster) {
    157 		monster = alloc_object();
    158 
    159 		for (;;) {
    160 			mn = get_rand(0, MONSTERS-1);
    161 			if ((cur_level >= mon_tab[mn].first_level) &&
    162 			(cur_level <= mon_tab[mn].last_level)) {
    163 				break;
    164 			}
    165 		}
    166 	}
    167 	*monster = mon_tab[mn];
    168 	if (monster->m_flags & IMITATES) {
    169 		monster->disguise = gr_obj_char();
    170 	}
    171 	if (cur_level > (AMULET_LEVEL + 2)) {
    172 		monster->m_flags |= HASTED;
    173 	}
    174 	monster->trow = NO_ROOM;
    175 	return(monster);
    176 }
    177 
    178 mv_mons()
    179 {
    180 	register object *monster, *next_monster;
    181 	boolean flew;
    182 
    183 	if (haste_self % 2) {
    184 		return;
    185 	}
    186 
    187 	monster = level_monsters.next_monster;
    188 
    189 	while (monster) {
    190 		next_monster = monster->next_monster;
    191 		mon_disappeared = 0;
    192 		if (monster->m_flags & HASTED) {
    193 			mv_1_monster(monster, rogue.row, rogue.col);
    194 			if (mon_disappeared) {
    195 				goto NM;
    196 			}
    197 		} else if (monster->m_flags & SLOWED) {
    198 			monster->slowed_toggle = !monster->slowed_toggle;
    199 			if (monster->slowed_toggle) {
    200 				goto NM;
    201 			}
    202 		}
    203 		if ((monster->m_flags & CONFUSED) && move_confused(monster)) {
    204 			goto NM;
    205 		}
    206 		flew = 0;
    207 		if (	(monster->m_flags & FLIES) &&
    208 				!(monster->m_flags & NAPPING) &&
    209 				!mon_can_go(monster, rogue.row, rogue.col)) {
    210 			flew = 1;
    211 			mv_1_monster(monster, rogue.row, rogue.col);
    212 			if (mon_disappeared) {
    213 				goto NM;
    214 			}
    215 		}
    216 		if (!(flew && mon_can_go(monster, rogue.row, rogue.col))) {
    217 			mv_1_monster(monster, rogue.row, rogue.col);
    218 		}
    219 NM:		monster = next_monster;
    220 	}
    221 }
    222 
    223 party_monsters(rn, n)
    224 int rn, n;
    225 {
    226 	short i, j;
    227 	short row, col;
    228 	object *monster;
    229 	boolean found;
    230 
    231 	n += n;
    232 
    233 	for (i = 0; i < MONSTERS; i++) {
    234 		mon_tab[i].first_level -= (cur_level % 3);
    235 	}
    236 	for (i = 0; i < n; i++) {
    237 		if (no_room_for_monster(rn)) {
    238 			break;
    239 		}
    240 		for (j = found = 0; ((!found) && (j < 250)); j++) {
    241 			row = get_rand(rooms[rn].top_row+1,
    242 				rooms[rn].bottom_row-1);
    243 			col = get_rand(rooms[rn].left_col+1,
    244 				rooms[rn].right_col-1);
    245 			if ((!(dungeon[row][col] & MONSTER)) &&
    246 				(dungeon[row][col] & (FLOOR | TUNNEL))) {
    247 				found = 1;
    248 			}
    249 		}
    250 		if (found) {
    251 			monster = gr_monster((object *) 0, 0);
    252 			if (!(monster->m_flags & IMITATES)) {
    253 				monster->m_flags |= WAKENS;
    254 			}
    255 			put_m_at(row, col, monster);
    256 		}
    257 	}
    258 	for (i = 0; i < MONSTERS; i++) {
    259 		mon_tab[i].first_level += (cur_level % 3);
    260 	}
    261 }
    262 
    263 gmc_row_col(row, col)
    264 register row, col;
    265 {
    266 	register object *monster;
    267 
    268 	if (monster = object_at(&level_monsters, row, col)) {
    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 gmc(monster)
    283 object *monster;
    284 {
    285 	if ((!(detect_monster || see_invisible || r_see_invisible) &&
    286 		(monster->m_flags & INVISIBLE))
    287 		|| blind) {
    288 		return(monster->trail_char);
    289 	}
    290 	if (monster->m_flags & IMITATES) {
    291 		return(monster->disguise);
    292 	}
    293 	return(monster->m_char);
    294 }
    295 
    296 mv_1_monster(monster, row, col)
    297 register object *monster;
    298 short row, col;
    299 {
    300 	short i, n;
    301 	boolean tried[6];
    302 
    303 	if (monster->m_flags & ASLEEP) {
    304 		if (monster->m_flags & NAPPING) {
    305 			if (--monster->nap_length <= 0) {
    306 				monster->m_flags &= (~(NAPPING | ASLEEP));
    307 			}
    308 			return;
    309 		}
    310 		if ((monster->m_flags & WAKENS) &&
    311 			 rogue_is_around(monster->row, monster->col) &&
    312 			 rand_percent(((stealthy > 0) ?
    313 			 	(WAKE_PERCENT / (STEALTH_FACTOR + stealthy)) :
    314 				WAKE_PERCENT))) {
    315 			wake_up(monster);
    316 		}
    317 		return;
    318 	} else if (monster->m_flags & ALREADY_MOVED) {
    319 		monster->m_flags &= (~ALREADY_MOVED);
    320 		return;
    321 	}
    322 	if ((monster->m_flags & FLITS) && flit(monster)) {
    323 		return;
    324 	}
    325 	if ((monster->m_flags & STATIONARY) &&
    326 		(!mon_can_go(monster, rogue.row, rogue.col))) {
    327 		return;
    328 	}
    329 	if (monster->m_flags & FREEZING_ROGUE) {
    330 		return;
    331 	}
    332 	if ((monster->m_flags & CONFUSES) && m_confuse(monster)) {
    333 		return;
    334 	}
    335 	if (mon_can_go(monster, rogue.row, rogue.col)) {
    336 		mon_hit(monster);
    337 		return;
    338 	}
    339 	if ((monster->m_flags & FLAMES) && flame_broil(monster)) {
    340 		return;
    341 	}
    342 	if ((monster->m_flags & SEEKS_GOLD) && seek_gold(monster)) {
    343 		return;
    344 	}
    345 	if ((monster->trow == monster->row) &&
    346 		   (monster->tcol == monster->col)) {
    347 		monster->trow = NO_ROOM;
    348 	} else if (monster->trow != NO_ROOM) {
    349 		row = monster->trow;
    350 		col = monster->tcol;
    351 	}
    352 	if (monster->row > row) {
    353 		row = monster->row - 1;
    354 	} else if (monster->row < row) {
    355 		row = monster->row + 1;
    356 	}
    357 	if ((dungeon[row][monster->col] & DOOR) &&
    358 		 mtry(monster, row, monster->col)) {
    359 		return;
    360 	}
    361 	if (monster->col > col) {
    362 		col = monster->col - 1;
    363 	} else if (monster->col < col) {
    364 		col = monster->col + 1;
    365 	}
    366 	if ((dungeon[monster->row][col] & DOOR) &&
    367 		 mtry(monster, monster->row, col)) {
    368 		return;
    369 	}
    370 	if (mtry(monster, row, col)) {
    371 		return;
    372 	}
    373 
    374 	for (i = 0; i <= 5; i++) tried[i] = 0;
    375 
    376 	for (i = 0; i < 6; i++) {
    377 NEXT_TRY:	n = get_rand(0, 5);
    378 		switch(n) {
    379 		case 0:
    380 			if (!tried[n] && mtry(monster, row, monster->col-1)) {
    381 				goto O;
    382 			}
    383 			break;
    384 		case 1:
    385 			if (!tried[n] && mtry(monster, row, monster->col)) {
    386 				goto O;
    387 			}
    388 			break;
    389 		case 2:
    390 			if (!tried[n] && mtry(monster, row, monster->col+1)) {
    391 				goto O;
    392 			}
    393 			break;
    394 		case 3:
    395 			if (!tried[n] && mtry(monster, monster->row-1, col)) {
    396 				goto O;
    397 			}
    398 			break;
    399 		case 4:
    400 			if (!tried[n] && mtry(monster, monster->row, col)) {
    401 				goto O;
    402 			}
    403 			break;
    404 		case 5:
    405 			if (!tried[n] && mtry(monster, monster->row+1, col)) {
    406 				goto O;
    407 			}
    408 			break;
    409 		}
    410 		if (!tried[n]) {
    411 			tried[n] = 1;
    412 		} else {
    413 			goto NEXT_TRY;
    414 		}
    415 	}
    416 O:
    417 	if ((monster->row == monster->o_row) && (monster->col == monster->o_col)) {
    418 		if (++(monster->o) > 4) {
    419 			if ((monster->trow == NO_ROOM) &&
    420 					(!mon_sees(monster, rogue.row, rogue.col))) {
    421 				monster->trow = get_rand(1, (DROWS - 2));
    422 				monster->tcol = get_rand(0, (DCOLS - 1));
    423 			} else {
    424 				monster->trow = NO_ROOM;
    425 				monster->o = 0;
    426 			}
    427 		}
    428 	} else {
    429 		monster->o_row = monster->row;
    430 		monster->o_col = monster->col;
    431 		monster->o = 0;
    432 	}
    433 }
    434 
    435 mtry(monster, row, col)
    436 register object *monster;
    437 register short row, col;
    438 {
    439 	if (mon_can_go(monster, row, col)) {
    440 		move_mon_to(monster, row, col);
    441 		return(1);
    442 	}
    443 	return(0);
    444 }
    445 
    446 move_mon_to(monster, row, col)
    447 register object *monster;
    448 register short row, col;
    449 {
    450 	short c;
    451 	register mrow, mcol;
    452 
    453 	mrow = monster->row;
    454 	mcol = monster->col;
    455 
    456 	dungeon[mrow][mcol] &= ~MONSTER;
    457 	dungeon[row][col] |= MONSTER;
    458 
    459 	c = mvinch(mrow, mcol);
    460 
    461 	if ((c >= 'A') && (c <= 'Z')) {
    462 		if (!detect_monster) {
    463 			mvaddch(mrow, mcol, monster->trail_char);
    464 		} else {
    465 			if (rogue_can_see(mrow, mcol)) {
    466 				mvaddch(mrow, mcol, monster->trail_char);
    467 			} else {
    468 				if (monster->trail_char == '.') {
    469 					monster->trail_char = ' ';
    470 				}
    471 				mvaddch(mrow, mcol, monster->trail_char);
    472 			}
    473 		}
    474 	}
    475 	monster->trail_char = mvinch(row, col);
    476 	if (!blind && (detect_monster || rogue_can_see(row, col))) {
    477 		if ((!(monster->m_flags & INVISIBLE) ||
    478 			(detect_monster || see_invisible || r_see_invisible))) {
    479 			mvaddch(row, col, gmc(monster));
    480 		}
    481 	}
    482 	if ((dungeon[row][col] & DOOR) &&
    483 		(get_room_number(row, col) != cur_room) &&
    484 		(dungeon[mrow][mcol] == FLOOR) && !blind) {
    485 			mvaddch(mrow, mcol, ' ');
    486 	}
    487 	if (dungeon[row][col] & DOOR) {
    488 			dr_course(monster, ((dungeon[mrow][mcol] & TUNNEL) ? 1 : 0),
    489 				row, col);
    490 	} else {
    491 		monster->row = row;
    492 		monster->col = col;
    493 	}
    494 }
    495 
    496 mon_can_go(monster, row, col)
    497 register object *monster;
    498 register short row, col;
    499 {
    500 	object *obj;
    501 	short dr, dc;
    502 
    503 	dr = monster->row - row;	/* check if move distance > 1 */
    504 	if ((dr >= 2) || (dr <= -2)) {
    505 		return(0);
    506 	}
    507 	dc = monster->col - col;
    508 	if ((dc >= 2) || (dc <= -2)) {
    509 		return(0);
    510 	}
    511 	if ((!dungeon[monster->row][col]) || (!dungeon[row][monster->col])) {
    512 		return(0);
    513 	}
    514 	if ((!is_passable(row, col)) || (dungeon[row][col] & MONSTER)) {
    515 		return(0);
    516 	}
    517 	if ((monster->row!=row)&&(monster->col!=col)&&((dungeon[row][col]&DOOR) ||
    518 		(dungeon[monster->row][monster->col]&DOOR))) {
    519 		return(0);
    520 	}
    521 	if (!(monster->m_flags & (FLITS | CONFUSED | CAN_FLIT)) &&
    522 		(monster->trow == NO_ROOM)) {
    523 		if ((monster->row < rogue.row) && (row < monster->row)) return(0);
    524 		if ((monster->row > rogue.row) && (row > monster->row)) return(0);
    525 		if ((monster->col < rogue.col) && (col < monster->col)) return(0);
    526 		if ((monster->col > rogue.col) && (col > monster->col)) return(0);
    527 	}
    528 	if (dungeon[row][col] & OBJECT) {
    529 		obj = object_at(&level_objects, row, col);
    530 		if ((obj->what_is == SCROL) && (obj->which_kind == SCARE_MONSTER)) {
    531 			return(0);
    532 		}
    533 	}
    534 	return(1);
    535 }
    536 
    537 wake_up(monster)
    538 object *monster;
    539 {
    540 	if (!(monster->m_flags & NAPPING)) {
    541 		monster->m_flags &= (~(ASLEEP | IMITATES | WAKENS));
    542 	}
    543 }
    544 
    545 wake_room(rn, entering, row, col)
    546 short rn;
    547 boolean entering;
    548 short row, col;
    549 {
    550 	object *monster;
    551 	short wake_percent;
    552 	boolean in_room;
    553 
    554 	wake_percent = (rn == party_room) ? PARTY_WAKE_PERCENT : WAKE_PERCENT;
    555 	if (stealthy > 0) {
    556 		wake_percent /= (STEALTH_FACTOR + stealthy);
    557 	}
    558 
    559 	monster = level_monsters.next_monster;
    560 
    561 	while (monster) {
    562 		in_room = (rn == get_room_number(monster->row, monster->col));
    563 		if (in_room) {
    564 			if (entering) {
    565 				monster->trow = NO_ROOM;
    566 			} else {
    567 				monster->trow = row;
    568 				monster->tcol = col;
    569 			}
    570 		}
    571 		if ((monster->m_flags & WAKENS) &&
    572 			(rn == get_room_number(monster->row, monster->col))) {
    573 			if (rand_percent(wake_percent)) {
    574 				wake_up(monster);
    575 			}
    576 		}
    577 		monster = monster->next_monster;
    578 	}
    579 }
    580 
    581 char *
    582 mon_name(monster)
    583 object *monster;
    584 {
    585 	short ch;
    586 
    587 	if (blind || ((monster->m_flags & INVISIBLE) &&
    588 		!(detect_monster || see_invisible || r_see_invisible))) {
    589 		return("something");
    590 	}
    591 	if (halluc) {
    592 		ch = get_rand('A', 'Z') - 'A';
    593 		return(m_names[ch]);
    594 	}
    595 	ch = monster->m_char - 'A';
    596 	return(m_names[ch]);
    597 }
    598 
    599 rogue_is_around(row, col)
    600 register row, col;
    601 {
    602 	short rdif, cdif, retval;
    603 
    604 	rdif = row - rogue.row;
    605 	cdif = col - rogue.col;
    606 
    607 	retval = (rdif >= -1) && (rdif <= 1) && (cdif >= -1) && (cdif <= 1);
    608 	return(retval);
    609 }
    610 
    611 wanderer()
    612 {
    613 	object *monster;
    614 	short row, col, i;
    615 	boolean found = 0;
    616 
    617 	for (i = 0; ((i < 15) && (!found)); i++) {
    618 		monster = gr_monster((object *) 0, 0);
    619 		if (!(monster->m_flags & (WAKENS | WANDERS))) {
    620 			free_object(monster);
    621 		} else {
    622 			found = 1;
    623 		}
    624 	}
    625 	if (found) {
    626 		found = 0;
    627 		wake_up(monster);
    628 		for (i = 0; ((i < 25) && (!found)); i++) {
    629 			gr_row_col(&row, &col, (FLOOR | TUNNEL | STAIRS | OBJECT));
    630 			if (!rogue_can_see(row, col)) {
    631 				put_m_at(row, col, monster);
    632 				found = 1;
    633 			}
    634 		}
    635 		if (!found) {
    636 			free_object(monster);
    637 		}
    638 	}
    639 }
    640 
    641 show_monsters()
    642 {
    643 	object *monster;
    644 
    645 	detect_monster = 1;
    646 
    647 	if (blind) {
    648 		return;
    649 	}
    650 	monster = level_monsters.next_monster;
    651 
    652 	while (monster) {
    653 		mvaddch(monster->row, monster->col, monster->m_char);
    654 		if (monster->m_flags & IMITATES) {
    655 			monster->m_flags &= (~IMITATES);
    656 			monster->m_flags |= WAKENS;
    657 		}
    658 		monster = monster->next_monster;
    659 	}
    660 }
    661 
    662 create_monster()
    663 {
    664 	short row, col;
    665 	short i;
    666 	boolean found = 0;
    667 	object *monster;
    668 
    669 	row = rogue.row;
    670 	col = rogue.col;
    671 
    672 	for (i = 0; i < 9; i++) {
    673 		rand_around(i, &row, &col);
    674 		if (((row == rogue.row) && (col = rogue.col)) ||
    675 				(row < MIN_ROW) || (row > (DROWS-2)) ||
    676 				(col < 0) || (col > (DCOLS-1))) {
    677 			continue;
    678 		}
    679 		if ((!(dungeon[row][col] & MONSTER)) &&
    680 			  (dungeon[row][col] & (FLOOR|TUNNEL|STAIRS|DOOR))) {
    681 			found = 1;
    682 			break;
    683 		}
    684 	}
    685 	if (found) {
    686 		monster = gr_monster((object *) 0, 0);
    687 		put_m_at(row, col, monster);
    688 		mvaddch(row, col, gmc(monster));
    689 		if (monster->m_flags & (WANDERS | WAKENS)) {
    690 			wake_up(monster);
    691 		}
    692 	} else {
    693 		message("you hear a faint cry of anguish in the distance", 0);
    694 	}
    695 }
    696 
    697 put_m_at(row, col, monster)
    698 short row, col;
    699 object *monster;
    700 {
    701 	monster->row = row;
    702 	monster->col = col;
    703 	dungeon[row][col] |= MONSTER;
    704 	monster->trail_char = mvinch(row, col);
    705 	(void) add_to_pack(monster, &level_monsters, 0);
    706 	aim_monster(monster);
    707 }
    708 
    709 aim_monster(monster)
    710 object *monster;
    711 {
    712 	short i, rn, d, r;
    713 
    714 	rn = get_room_number(monster->row, monster->col);
    715 	r = get_rand(0, 12);
    716 
    717 	for (i = 0; i < 4; i++) {
    718 		d = (r + i) % 4;
    719 		if (rooms[rn].doors[d].oth_room != NO_ROOM) {
    720 			monster->trow = rooms[rn].doors[d].door_row;
    721 			monster->tcol = rooms[rn].doors[d].door_col;
    722 			break;
    723 		}
    724 	}
    725 }
    726 
    727 rogue_can_see(row, col)
    728 register row, col;
    729 {
    730 	register retval;
    731 
    732 	retval = !blind &&
    733 			(((get_room_number(row, col) == cur_room) &&
    734 					!(rooms[cur_room].is_room & R_MAZE)) ||
    735 			rogue_is_around(row, col));
    736 
    737 	return(retval);
    738 }
    739 
    740 move_confused(monster)
    741 object *monster;
    742 {
    743 	short i, row, col;
    744 
    745 	if (!(monster->m_flags & ASLEEP)) {
    746 		if (--monster->moves_confused <= 0) {
    747 			monster->m_flags &= (~CONFUSED);
    748 		}
    749 		if (monster->m_flags & STATIONARY) {
    750 			return(coin_toss() ? 1 : 0);
    751 		} else if (rand_percent(15)) {
    752 			return(1);
    753 		}
    754 		row = monster->row;
    755 		col = monster->col;
    756 
    757 		for (i = 0; i < 9; i++) {
    758 			rand_around(i, &row, &col);
    759 			if ((row == rogue.row) && (col == rogue.col)) {
    760 				return(0);
    761 			}
    762 			if (mtry(monster, row, col)) {
    763 				return(1);
    764 			}
    765 		}
    766 	}
    767 	return(0);
    768 }
    769 
    770 flit(monster)
    771 object *monster;
    772 {
    773 	short i, row, col;
    774 
    775 	if (!rand_percent(FLIT_PERCENT + ((monster->m_flags & FLIES) ? 20 : 0))) {
    776 		return(0);
    777 	}
    778 	if (rand_percent(10)) {
    779 		return(1);
    780 	}
    781 	row = monster->row;
    782 	col = monster->col;
    783 
    784 	for (i = 0; i < 9; i++) {
    785 		rand_around(i, &row, &col);
    786 		if ((row == rogue.row) && (col == rogue.col)) {
    787 			continue;
    788 		}
    789 		if (mtry(monster, row, col)) {
    790 			return(1);
    791 		}
    792 	}
    793 	return(1);
    794 }
    795 
    796 gr_obj_char()
    797 {
    798 	short r;
    799 	char *rs = "%!?]=/):*";
    800 
    801 	r = get_rand(0, 8);
    802 
    803 	return(rs[r]);
    804 }
    805 
    806 no_room_for_monster(rn)
    807 int rn;
    808 {
    809 	short i, j;
    810 
    811 	for (i = rooms[rn].top_row+1; i < rooms[rn].bottom_row; i++) {
    812 		for (j = rooms[rn].left_col+1; j < rooms[rn].right_col; j++) {
    813 			if (!(dungeon[i][j] & MONSTER)) {
    814 				return(0);
    815 			}
    816 		}
    817 	}
    818 	return(1);
    819 }
    820 
    821 aggravate()
    822 {
    823 	object *monster;
    824 
    825 	message("you hear a high pitched humming noise", 0);
    826 
    827 	monster = level_monsters.next_monster;
    828 
    829 	while (monster) {
    830 		wake_up(monster);
    831 		monster->m_flags &= (~IMITATES);
    832 		if (rogue_can_see(monster->row, monster->col)) {
    833 			mvaddch(monster->row, monster->col, monster->m_char);
    834 		}
    835 		monster = monster->next_monster;
    836 	}
    837 }
    838 
    839 boolean
    840 mon_sees(monster, row, col)
    841 object *monster;
    842 {
    843 	short rn, rdif, cdif, retval;
    844 
    845 	rn = get_room_number(row, col);
    846 
    847 	if (	(rn != NO_ROOM) &&
    848 			(rn == get_room_number(monster->row, monster->col)) &&
    849 			!(rooms[rn].is_room & R_MAZE)) {
    850 		return(1);
    851 	}
    852 	rdif = row - monster->row;
    853 	cdif = col - monster->col;
    854 
    855 	retval = (rdif >= -1) && (rdif <= 1) && (cdif >= -1) && (cdif <= 1);
    856 	return(retval);
    857 }
    858 
    859 mv_aquatars()
    860 {
    861 	object *monster;
    862 
    863 	monster = level_monsters.next_monster;
    864 
    865 	while (monster) {
    866 		if ((monster->m_char == 'A') &&
    867 			mon_can_go(monster, rogue.row, rogue.col)) {
    868 			mv_1_monster(monster, rogue.row, rogue.col);
    869 			monster->m_flags |= ALREADY_MOVED;
    870 		}
    871 		monster = monster->next_monster;
    872 	}
    873 }
    874