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