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