xref: /csrg-svn/games/rogue/monster.c (revision 60842)
132689Sbostic /*
2*60842Sbostic  * Copyright (c) 1988, 1993
3*60842Sbostic  *	The Regents of the University of California.  All rights reserved.
436704Sbostic  *
536704Sbostic  * This code is derived from software contributed to Berkeley by
636704Sbostic  * Timothy C. Stoehr.
736704Sbostic  *
842597Sbostic  * %sccs.include.redist.c%
936704Sbostic  */
1036704Sbostic 
1136704Sbostic #ifndef lint
12*60842Sbostic static char sccsid[] = "@(#)monster.c	8.1 (Berkeley) 05/31/93";
1336704Sbostic #endif /* not lint */
1436704Sbostic 
1536704Sbostic /*
1632689Sbostic  * monster.c
1732689Sbostic  *
1832689Sbostic  * This source herein may be modified and/or distributed by anybody who
1932689Sbostic  * so desires, with the following restrictions:
2032689Sbostic  *    1.)  No portion of this notice shall be removed.
2132689Sbostic  *    2.)  Credit shall not be taken for the creation of this source.
2232689Sbostic  *    3.)  This code is not to be traded, sold, or used for personal
2332689Sbostic  *         gain or profit.
2432689Sbostic  *
2532689Sbostic  */
2632689Sbostic 
2732689Sbostic #include "rogue.h"
2832689Sbostic 
2932689Sbostic object level_monsters;
3032689Sbostic boolean mon_disappeared;
3132689Sbostic 
3232689Sbostic char *m_names[] = {
3332689Sbostic 	"aquator",
3432689Sbostic 	"bat",
3532689Sbostic 	"centaur",
3632689Sbostic 	"dragon",
3732689Sbostic 	"emu",
3832689Sbostic 	"venus fly-trap",
3932689Sbostic 	"griffin",
4032689Sbostic 	"hobgoblin",
4132689Sbostic 	"ice monster",
4232689Sbostic 	"jabberwock",
4332689Sbostic 	"kestrel",
4432689Sbostic 	"leprechaun",
4532689Sbostic 	"medusa",
4632689Sbostic 	"nymph",
4732689Sbostic 	"orc",
4832689Sbostic 	"phantom",
4932689Sbostic 	"quagga",
5032689Sbostic 	"rattlesnake",
5132689Sbostic 	"snake",
5232689Sbostic 	"troll",
5332689Sbostic 	"black unicorn",
5432689Sbostic 	"vampire",
5532689Sbostic 	"wraith",
5632689Sbostic 	"xeroc",
5732689Sbostic 	"yeti",
5832689Sbostic 	"zombie"
5932689Sbostic };
6032689Sbostic 
6132689Sbostic object mon_tab[MONSTERS] = {
6232689Sbostic 	{(ASLEEP|WAKENS|WANDERS|RUSTS),"0d0",25,'A',20,9,18,100,0,0,0,0,0},
6332689Sbostic 	{(ASLEEP|WANDERS|FLITS|FLIES),"1d3",10,'B',2,1,8,60,0,0,0,0,0},
6432689Sbostic 	{(ASLEEP|WANDERS),"3d3/2d5",32,'C',15,7,16,85,0,10,0,0,0},
6532689Sbostic 	{(ASLEEP|WAKENS|FLAMES),"4d6/4d9",145,'D',5000,21,126,100,0,90,0,0,0},
6632689Sbostic 	{(ASLEEP|WAKENS),"1d3",11,'E',2,1,7,65,0,0,0,0,0},
6732689Sbostic 	{(HOLDS|STATIONARY),"5d5",73,'F',91,12,126,80,0,0,0,0,0},
6832689Sbostic 	{(ASLEEP|WAKENS|WANDERS|FLIES),"5d5/5d5",115,'G',
6932689Sbostic 			2000,20,126,85,0,10,0,0,0},
7032689Sbostic 	{(ASLEEP|WAKENS|WANDERS),"1d3/1d2",15,'H',3,1,10,67,0,0,0,0,0},
7132689Sbostic 	{(ASLEEP|FREEZES),"0d0",15,'I',5,2,11,68,0,0,0,0,0},
7232689Sbostic 	{(ASLEEP|WANDERS),"3d10/4d5",132,'J',3000,21,126,100,0,0,0,0,0},
7332689Sbostic 	{(ASLEEP|WAKENS|WANDERS|FLIES),"1d4",10,'K',2,1,6,60,0,0,0,0,0},
7432689Sbostic 	{(ASLEEP|STEALS_GOLD),"0d0",25,'L',21,6,16,75,0,0,0,0,0},
7532689Sbostic 	{(ASLEEP|WAKENS|WANDERS|CONFUSES),"4d4/3d7",97,'M',
7632689Sbostic 			250,18,126,85,0,25,0,0,0},
7732689Sbostic 	{(ASLEEP|STEALS_ITEM),"0d0",25,'N',39,10,19,75,0,100,0,0,0},
7832689Sbostic 	{(ASLEEP|WANDERS|WAKENS|SEEKS_GOLD),"1d6",25,'O',5,4,13,70,0,10,0,0,0},
7932689Sbostic 	{(ASLEEP|INVISIBLE|WANDERS|FLITS),"5d4",76,'P',120,15,24,80,0,50,0,0,0},
8032689Sbostic 	{(ASLEEP|WAKENS|WANDERS),"3d5",30,'Q',20,8,17,78,0,20,0,0,0},
8132689Sbostic 	{(ASLEEP|WAKENS|WANDERS|STINGS),"2d5",19,'R',10,3,12,70,0,0,0,0,0},
8232689Sbostic 	{(ASLEEP|WAKENS|WANDERS),"1d3",8,'S',2,1,9,50,0,0,0,0,0},
8332689Sbostic 	{(ASLEEP|WAKENS|WANDERS),"4d6/1d4",75,'T',125,13,22,75,0,33,0,0,0},
8432689Sbostic 	{(ASLEEP|WAKENS|WANDERS),"4d10",90,'U',
8532689Sbostic 			200,17,26,85,0,33,0,0,0},
8632689Sbostic 	{(ASLEEP|WAKENS|WANDERS|DRAINS_LIFE),"1d14/1d4",55,'V',
8732689Sbostic 			350,19,126,85,0,18,0,0,0},
8832689Sbostic 	{(ASLEEP|WANDERS|DROPS_LEVEL),"2d8",45,'W',55,14,23,75,0,0,0,0,0},
8932689Sbostic 	{(ASLEEP|IMITATES),"4d6",42,'X',110,16,25,75,0,0,0,0,0},
9032689Sbostic 	{(ASLEEP|WANDERS),"3d6",35,'Y',50,11,20,80,0,20,0,0,0},
9132689Sbostic 	{(ASLEEP|WAKENS|WANDERS),"1d7",21,'Z',8,5,14,69,0,0,0,0,0}
9232689Sbostic };
9332689Sbostic 
9432689Sbostic extern short cur_level;
9532689Sbostic extern short cur_room, party_room;
9632689Sbostic extern short blind, halluc, haste_self;
9732689Sbostic extern boolean detect_monster, see_invisible, r_see_invisible;
9832689Sbostic extern short stealthy;
9932689Sbostic 
put_mons()10032689Sbostic put_mons()
10132689Sbostic {
10232689Sbostic 	short i;
10332689Sbostic 	short n;
10432689Sbostic 	object *monster;
10532689Sbostic 	short row, col;
10632689Sbostic 
10732689Sbostic 	n = get_rand(4, 6);
10832689Sbostic 
10932689Sbostic 	for (i = 0; i < n; i++) {
11032689Sbostic 		monster = gr_monster((object *) 0, 0);
11132689Sbostic 		if ((monster->m_flags & WANDERS) && coin_toss()) {
11232689Sbostic 			wake_up(monster);
11332689Sbostic 		}
11432689Sbostic 		gr_row_col(&row, &col, (FLOOR | TUNNEL | STAIRS | OBJECT));
11532689Sbostic 		put_m_at(row, col, monster);
11632689Sbostic 	}
11732689Sbostic }
11832689Sbostic 
11932689Sbostic object *
gr_monster(monster,mn)12032689Sbostic gr_monster(monster, mn)
12132689Sbostic register object *monster;
12232689Sbostic register mn;
12332689Sbostic {
12432689Sbostic 	if (!monster) {
12532689Sbostic 		monster = alloc_object();
12632689Sbostic 
12732689Sbostic 		for (;;) {
12832689Sbostic 			mn = get_rand(0, MONSTERS-1);
12932689Sbostic 			if ((cur_level >= mon_tab[mn].first_level) &&
13032689Sbostic 			(cur_level <= mon_tab[mn].last_level)) {
13132689Sbostic 				break;
13232689Sbostic 			}
13332689Sbostic 		}
13432689Sbostic 	}
13532689Sbostic 	*monster = mon_tab[mn];
13632689Sbostic 	if (monster->m_flags & IMITATES) {
13732689Sbostic 		monster->disguise = gr_obj_char();
13832689Sbostic 	}
13932689Sbostic 	if (cur_level > (AMULET_LEVEL + 2)) {
14032689Sbostic 		monster->m_flags |= HASTED;
14132689Sbostic 	}
14232689Sbostic 	monster->trow = NO_ROOM;
14332689Sbostic 	return(monster);
14432689Sbostic }
14532689Sbostic 
mv_mons()14632689Sbostic mv_mons()
14732689Sbostic {
14832689Sbostic 	register object *monster, *next_monster;
14932689Sbostic 	boolean flew;
15032689Sbostic 
15132689Sbostic 	if (haste_self % 2) {
15232689Sbostic 		return;
15332689Sbostic 	}
15432689Sbostic 
15532689Sbostic 	monster = level_monsters.next_monster;
15632689Sbostic 
15732689Sbostic 	while (monster) {
15832689Sbostic 		next_monster = monster->next_monster;
15932689Sbostic 		mon_disappeared = 0;
16032689Sbostic 		if (monster->m_flags & HASTED) {
16132689Sbostic 			mv_1_monster(monster, rogue.row, rogue.col);
16232689Sbostic 			if (mon_disappeared) {
16332689Sbostic 				goto NM;
16432689Sbostic 			}
16532689Sbostic 		} else if (monster->m_flags & SLOWED) {
16632689Sbostic 			monster->slowed_toggle = !monster->slowed_toggle;
16732689Sbostic 			if (monster->slowed_toggle) {
16832689Sbostic 				goto NM;
16932689Sbostic 			}
17032689Sbostic 		}
17132689Sbostic 		if ((monster->m_flags & CONFUSED) && move_confused(monster)) {
17232689Sbostic 			goto NM;
17332689Sbostic 		}
17432689Sbostic 		flew = 0;
17532689Sbostic 		if (	(monster->m_flags & FLIES) &&
17632689Sbostic 				!(monster->m_flags & NAPPING) &&
17732689Sbostic 				!mon_can_go(monster, rogue.row, rogue.col)) {
17832689Sbostic 			flew = 1;
17932689Sbostic 			mv_1_monster(monster, rogue.row, rogue.col);
18032689Sbostic 			if (mon_disappeared) {
18132689Sbostic 				goto NM;
18232689Sbostic 			}
18332689Sbostic 		}
18432689Sbostic 		if (!(flew && mon_can_go(monster, rogue.row, rogue.col))) {
18532689Sbostic 			mv_1_monster(monster, rogue.row, rogue.col);
18632689Sbostic 		}
18732689Sbostic NM:		monster = next_monster;
18832689Sbostic 	}
18932689Sbostic }
19032689Sbostic 
party_monsters(rn,n)19132689Sbostic party_monsters(rn, n)
19232689Sbostic int rn, n;
19332689Sbostic {
19432689Sbostic 	short i, j;
19532689Sbostic 	short row, col;
19632689Sbostic 	object *monster;
19732689Sbostic 	boolean found;
19832689Sbostic 
19932689Sbostic 	n += n;
20032689Sbostic 
20132689Sbostic 	for (i = 0; i < MONSTERS; i++) {
20232689Sbostic 		mon_tab[i].first_level -= (cur_level % 3);
20332689Sbostic 	}
20432689Sbostic 	for (i = 0; i < n; i++) {
20532689Sbostic 		if (no_room_for_monster(rn)) {
20632689Sbostic 			break;
20732689Sbostic 		}
20832689Sbostic 		for (j = found = 0; ((!found) && (j < 250)); j++) {
20932689Sbostic 			row = get_rand(rooms[rn].top_row+1,
21032689Sbostic 				rooms[rn].bottom_row-1);
21132689Sbostic 			col = get_rand(rooms[rn].left_col+1,
21232689Sbostic 				rooms[rn].right_col-1);
21332689Sbostic 			if ((!(dungeon[row][col] & MONSTER)) &&
21432689Sbostic 				(dungeon[row][col] & (FLOOR | TUNNEL))) {
21532689Sbostic 				found = 1;
21632689Sbostic 			}
21732689Sbostic 		}
21832689Sbostic 		if (found) {
21932689Sbostic 			monster = gr_monster((object *) 0, 0);
22032689Sbostic 			if (!(monster->m_flags & IMITATES)) {
22132689Sbostic 				monster->m_flags |= WAKENS;
22232689Sbostic 			}
22332689Sbostic 			put_m_at(row, col, monster);
22432689Sbostic 		}
22532689Sbostic 	}
22632689Sbostic 	for (i = 0; i < MONSTERS; i++) {
22732689Sbostic 		mon_tab[i].first_level += (cur_level % 3);
22832689Sbostic 	}
22932689Sbostic }
23032689Sbostic 
gmc_row_col(row,col)23132689Sbostic gmc_row_col(row, col)
23232689Sbostic register row, col;
23332689Sbostic {
23432689Sbostic 	register object *monster;
23532689Sbostic 
23632689Sbostic 	if (monster = object_at(&level_monsters, row, col)) {
23732689Sbostic 		if ((!(detect_monster || see_invisible || r_see_invisible) &&
23832689Sbostic 			(monster->m_flags & INVISIBLE)) || blind) {
23932689Sbostic 			return(monster->trail_char);
24032689Sbostic 		}
24132689Sbostic 		if (monster->m_flags & IMITATES) {
24232689Sbostic 			return(monster->disguise);
24332689Sbostic 		}
24432689Sbostic 		return(monster->m_char);
24532689Sbostic 	} else {
24632689Sbostic 		return('&');	/* BUG if this ever happens */
24732689Sbostic 	}
24832689Sbostic }
24932689Sbostic 
gmc(monster)25032689Sbostic gmc(monster)
25132689Sbostic object *monster;
25232689Sbostic {
25332689Sbostic 	if ((!(detect_monster || see_invisible || r_see_invisible) &&
25432689Sbostic 		(monster->m_flags & INVISIBLE))
25532689Sbostic 		|| blind) {
25632689Sbostic 		return(monster->trail_char);
25732689Sbostic 	}
25832689Sbostic 	if (monster->m_flags & IMITATES) {
25932689Sbostic 		return(monster->disguise);
26032689Sbostic 	}
26132689Sbostic 	return(monster->m_char);
26232689Sbostic }
26332689Sbostic 
mv_1_monster(monster,row,col)26432689Sbostic mv_1_monster(monster, row, col)
26532689Sbostic register object *monster;
26632689Sbostic short row, col;
26732689Sbostic {
26832689Sbostic 	short i, n;
26932689Sbostic 	boolean tried[6];
27032689Sbostic 
27132689Sbostic 	if (monster->m_flags & ASLEEP) {
27232689Sbostic 		if (monster->m_flags & NAPPING) {
27332689Sbostic 			if (--monster->nap_length <= 0) {
27432689Sbostic 				monster->m_flags &= (~(NAPPING | ASLEEP));
27532689Sbostic 			}
27632689Sbostic 			return;
27732689Sbostic 		}
27832689Sbostic 		if ((monster->m_flags & WAKENS) &&
27932689Sbostic 			 rogue_is_around(monster->row, monster->col) &&
28032689Sbostic 			 rand_percent(((stealthy > 0) ?
28132689Sbostic 			 	(WAKE_PERCENT / (STEALTH_FACTOR + stealthy)) :
28232689Sbostic 				WAKE_PERCENT))) {
28332689Sbostic 			wake_up(monster);
28432689Sbostic 		}
28532689Sbostic 		return;
28632689Sbostic 	} else if (monster->m_flags & ALREADY_MOVED) {
28732689Sbostic 		monster->m_flags &= (~ALREADY_MOVED);
28832689Sbostic 		return;
28932689Sbostic 	}
29032689Sbostic 	if ((monster->m_flags & FLITS) && flit(monster)) {
29132689Sbostic 		return;
29232689Sbostic 	}
29332689Sbostic 	if ((monster->m_flags & STATIONARY) &&
29432689Sbostic 		(!mon_can_go(monster, rogue.row, rogue.col))) {
29532689Sbostic 		return;
29632689Sbostic 	}
29732689Sbostic 	if (monster->m_flags & FREEZING_ROGUE) {
29832689Sbostic 		return;
29932689Sbostic 	}
30032689Sbostic 	if ((monster->m_flags & CONFUSES) && m_confuse(monster)) {
30132689Sbostic 		return;
30232689Sbostic 	}
30332689Sbostic 	if (mon_can_go(monster, rogue.row, rogue.col)) {
30432689Sbostic 		mon_hit(monster);
30532689Sbostic 		return;
30632689Sbostic 	}
30732689Sbostic 	if ((monster->m_flags & FLAMES) && flame_broil(monster)) {
30832689Sbostic 		return;
30932689Sbostic 	}
31032689Sbostic 	if ((monster->m_flags & SEEKS_GOLD) && seek_gold(monster)) {
31132689Sbostic 		return;
31232689Sbostic 	}
31332689Sbostic 	if ((monster->trow == monster->row) &&
31432689Sbostic 		   (monster->tcol == monster->col)) {
31532689Sbostic 		monster->trow = NO_ROOM;
31632689Sbostic 	} else if (monster->trow != NO_ROOM) {
31732689Sbostic 		row = monster->trow;
31832689Sbostic 		col = monster->tcol;
31932689Sbostic 	}
32032689Sbostic 	if (monster->row > row) {
32132689Sbostic 		row = monster->row - 1;
32232689Sbostic 	} else if (monster->row < row) {
32332689Sbostic 		row = monster->row + 1;
32432689Sbostic 	}
32532689Sbostic 	if ((dungeon[row][monster->col] & DOOR) &&
32632689Sbostic 		 mtry(monster, row, monster->col)) {
32732689Sbostic 		return;
32832689Sbostic 	}
32932689Sbostic 	if (monster->col > col) {
33032689Sbostic 		col = monster->col - 1;
33132689Sbostic 	} else if (monster->col < col) {
33232689Sbostic 		col = monster->col + 1;
33332689Sbostic 	}
33432689Sbostic 	if ((dungeon[monster->row][col] & DOOR) &&
33532689Sbostic 		 mtry(monster, monster->row, col)) {
33632689Sbostic 		return;
33732689Sbostic 	}
33832689Sbostic 	if (mtry(monster, row, col)) {
33932689Sbostic 		return;
34032689Sbostic 	}
34132689Sbostic 
34232689Sbostic 	for (i = 0; i <= 5; i++) tried[i] = 0;
34332689Sbostic 
34432689Sbostic 	for (i = 0; i < 6; i++) {
34532689Sbostic NEXT_TRY:	n = get_rand(0, 5);
34632689Sbostic 		switch(n) {
34732689Sbostic 		case 0:
34832689Sbostic 			if (!tried[n] && mtry(monster, row, monster->col-1)) {
34932689Sbostic 				goto O;
35032689Sbostic 			}
35132689Sbostic 			break;
35232689Sbostic 		case 1:
35332689Sbostic 			if (!tried[n] && mtry(monster, row, monster->col)) {
35432689Sbostic 				goto O;
35532689Sbostic 			}
35632689Sbostic 			break;
35732689Sbostic 		case 2:
35832689Sbostic 			if (!tried[n] && mtry(monster, row, monster->col+1)) {
35932689Sbostic 				goto O;
36032689Sbostic 			}
36132689Sbostic 			break;
36232689Sbostic 		case 3:
36332689Sbostic 			if (!tried[n] && mtry(monster, monster->row-1, col)) {
36432689Sbostic 				goto O;
36532689Sbostic 			}
36632689Sbostic 			break;
36732689Sbostic 		case 4:
36832689Sbostic 			if (!tried[n] && mtry(monster, monster->row, col)) {
36932689Sbostic 				goto O;
37032689Sbostic 			}
37132689Sbostic 			break;
37232689Sbostic 		case 5:
37332689Sbostic 			if (!tried[n] && mtry(monster, monster->row+1, col)) {
37432689Sbostic 				goto O;
37532689Sbostic 			}
37632689Sbostic 			break;
37732689Sbostic 		}
37832689Sbostic 		if (!tried[n]) {
37932689Sbostic 			tried[n] = 1;
38032689Sbostic 		} else {
38132689Sbostic 			goto NEXT_TRY;
38232689Sbostic 		}
38332689Sbostic 	}
38432689Sbostic O:
38532689Sbostic 	if ((monster->row == monster->o_row) && (monster->col == monster->o_col)) {
38632689Sbostic 		if (++(monster->o) > 4) {
38732689Sbostic 			if ((monster->trow == NO_ROOM) &&
38832689Sbostic 					(!mon_sees(monster, rogue.row, rogue.col))) {
38932689Sbostic 				monster->trow = get_rand(1, (DROWS - 2));
39032689Sbostic 				monster->tcol = get_rand(0, (DCOLS - 1));
39132689Sbostic 			} else {
39232689Sbostic 				monster->trow = NO_ROOM;
39332689Sbostic 				monster->o = 0;
39432689Sbostic 			}
39532689Sbostic 		}
39632689Sbostic 	} else {
39732689Sbostic 		monster->o_row = monster->row;
39832689Sbostic 		monster->o_col = monster->col;
39932689Sbostic 		monster->o = 0;
40032689Sbostic 	}
40132689Sbostic }
40232689Sbostic 
mtry(monster,row,col)40332689Sbostic mtry(monster, row, col)
40432689Sbostic register object *monster;
40532689Sbostic register short row, col;
40632689Sbostic {
40732689Sbostic 	if (mon_can_go(monster, row, col)) {
40832689Sbostic 		move_mon_to(monster, row, col);
40932689Sbostic 		return(1);
41032689Sbostic 	}
41132689Sbostic 	return(0);
41232689Sbostic }
41332689Sbostic 
move_mon_to(monster,row,col)41432689Sbostic move_mon_to(monster, row, col)
41532689Sbostic register object *monster;
41632689Sbostic register short row, col;
41732689Sbostic {
41832689Sbostic 	short c;
41932689Sbostic 	register mrow, mcol;
42032689Sbostic 
42132689Sbostic 	mrow = monster->row;
42232689Sbostic 	mcol = monster->col;
42332689Sbostic 
42432689Sbostic 	dungeon[mrow][mcol] &= ~MONSTER;
42532689Sbostic 	dungeon[row][col] |= MONSTER;
42632689Sbostic 
42732689Sbostic 	c = mvinch(mrow, mcol);
42832689Sbostic 
42932689Sbostic 	if ((c >= 'A') && (c <= 'Z')) {
43032689Sbostic 		if (!detect_monster) {
43132689Sbostic 			mvaddch(mrow, mcol, monster->trail_char);
43232689Sbostic 		} else {
43332689Sbostic 			if (rogue_can_see(mrow, mcol)) {
43432689Sbostic 				mvaddch(mrow, mcol, monster->trail_char);
43532689Sbostic 			} else {
43632689Sbostic 				if (monster->trail_char == '.') {
43732689Sbostic 					monster->trail_char = ' ';
43832689Sbostic 				}
43932689Sbostic 				mvaddch(mrow, mcol, monster->trail_char);
44032689Sbostic 			}
44132689Sbostic 		}
44232689Sbostic 	}
44332689Sbostic 	monster->trail_char = mvinch(row, col);
44432689Sbostic 	if (!blind && (detect_monster || rogue_can_see(row, col))) {
44532689Sbostic 		if ((!(monster->m_flags & INVISIBLE) ||
44632689Sbostic 			(detect_monster || see_invisible || r_see_invisible))) {
44732689Sbostic 			mvaddch(row, col, gmc(monster));
44832689Sbostic 		}
44932689Sbostic 	}
45032689Sbostic 	if ((dungeon[row][col] & DOOR) &&
45132689Sbostic 		(get_room_number(row, col) != cur_room) &&
45232689Sbostic 		(dungeon[mrow][mcol] == FLOOR) && !blind) {
45332689Sbostic 			mvaddch(mrow, mcol, ' ');
45432689Sbostic 	}
45532689Sbostic 	if (dungeon[row][col] & DOOR) {
45632689Sbostic 			dr_course(monster, ((dungeon[mrow][mcol] & TUNNEL) ? 1 : 0),
45732689Sbostic 				row, col);
45832689Sbostic 	} else {
45932689Sbostic 		monster->row = row;
46032689Sbostic 		monster->col = col;
46132689Sbostic 	}
46232689Sbostic }
46332689Sbostic 
mon_can_go(monster,row,col)46432689Sbostic mon_can_go(monster, row, col)
46532689Sbostic register object *monster;
46632689Sbostic register short row, col;
46732689Sbostic {
46832689Sbostic 	object *obj;
46932689Sbostic 	short dr, dc;
47032689Sbostic 
47132689Sbostic 	dr = monster->row - row;	/* check if move distance > 1 */
47232689Sbostic 	if ((dr >= 2) || (dr <= -2)) {
47332689Sbostic 		return(0);
47432689Sbostic 	}
47532689Sbostic 	dc = monster->col - col;
47632689Sbostic 	if ((dc >= 2) || (dc <= -2)) {
47732689Sbostic 		return(0);
47832689Sbostic 	}
47932689Sbostic 	if ((!dungeon[monster->row][col]) || (!dungeon[row][monster->col])) {
48032689Sbostic 		return(0);
48132689Sbostic 	}
48232689Sbostic 	if ((!is_passable(row, col)) || (dungeon[row][col] & MONSTER)) {
48332689Sbostic 		return(0);
48432689Sbostic 	}
48532689Sbostic 	if ((monster->row!=row)&&(monster->col!=col)&&((dungeon[row][col]&DOOR) ||
48632689Sbostic 		(dungeon[monster->row][monster->col]&DOOR))) {
48732689Sbostic 		return(0);
48832689Sbostic 	}
48932689Sbostic 	if (!(monster->m_flags & (FLITS | CONFUSED | CAN_FLIT)) &&
49032689Sbostic 		(monster->trow == NO_ROOM)) {
49132689Sbostic 		if ((monster->row < rogue.row) && (row < monster->row)) return(0);
49232689Sbostic 		if ((monster->row > rogue.row) && (row > monster->row)) return(0);
49332689Sbostic 		if ((monster->col < rogue.col) && (col < monster->col)) return(0);
49432689Sbostic 		if ((monster->col > rogue.col) && (col > monster->col)) return(0);
49532689Sbostic 	}
49632689Sbostic 	if (dungeon[row][col] & OBJECT) {
49732689Sbostic 		obj = object_at(&level_objects, row, col);
49832689Sbostic 		if ((obj->what_is == SCROL) && (obj->which_kind == SCARE_MONSTER)) {
49932689Sbostic 			return(0);
50032689Sbostic 		}
50132689Sbostic 	}
50232689Sbostic 	return(1);
50332689Sbostic }
50432689Sbostic 
wake_up(monster)50532689Sbostic wake_up(monster)
50632689Sbostic object *monster;
50732689Sbostic {
50832689Sbostic 	if (!(monster->m_flags & NAPPING)) {
50932689Sbostic 		monster->m_flags &= (~(ASLEEP | IMITATES | WAKENS));
51032689Sbostic 	}
51132689Sbostic }
51232689Sbostic 
wake_room(rn,entering,row,col)51332689Sbostic wake_room(rn, entering, row, col)
51432689Sbostic short rn;
51532689Sbostic boolean entering;
51632689Sbostic short row, col;
51732689Sbostic {
51832689Sbostic 	object *monster;
51932689Sbostic 	short wake_percent;
52032689Sbostic 	boolean in_room;
52132689Sbostic 
52232689Sbostic 	wake_percent = (rn == party_room) ? PARTY_WAKE_PERCENT : WAKE_PERCENT;
52332689Sbostic 	if (stealthy > 0) {
52432689Sbostic 		wake_percent /= (STEALTH_FACTOR + stealthy);
52532689Sbostic 	}
52632689Sbostic 
52732689Sbostic 	monster = level_monsters.next_monster;
52832689Sbostic 
52932689Sbostic 	while (monster) {
53032689Sbostic 		in_room = (rn == get_room_number(monster->row, monster->col));
53132689Sbostic 		if (in_room) {
53232689Sbostic 			if (entering) {
53332689Sbostic 				monster->trow = NO_ROOM;
53432689Sbostic 			} else {
53532689Sbostic 				monster->trow = row;
53632689Sbostic 				monster->tcol = col;
53732689Sbostic 			}
53832689Sbostic 		}
53932689Sbostic 		if ((monster->m_flags & WAKENS) &&
54032689Sbostic 			(rn == get_room_number(monster->row, monster->col))) {
54132689Sbostic 			if (rand_percent(wake_percent)) {
54232689Sbostic 				wake_up(monster);
54332689Sbostic 			}
54432689Sbostic 		}
54532689Sbostic 		monster = monster->next_monster;
54632689Sbostic 	}
54732689Sbostic }
54832689Sbostic 
54932689Sbostic char *
mon_name(monster)55032689Sbostic mon_name(monster)
55132689Sbostic object *monster;
55232689Sbostic {
55332689Sbostic 	short ch;
55432689Sbostic 
55532689Sbostic 	if (blind || ((monster->m_flags & INVISIBLE) &&
55632689Sbostic 		!(detect_monster || see_invisible || r_see_invisible))) {
55732689Sbostic 		return("something");
55832689Sbostic 	}
55932689Sbostic 	if (halluc) {
56032689Sbostic 		ch = get_rand('A', 'Z') - 'A';
56132689Sbostic 		return(m_names[ch]);
56232689Sbostic 	}
56332689Sbostic 	ch = monster->m_char - 'A';
56432689Sbostic 	return(m_names[ch]);
56532689Sbostic }
56632689Sbostic 
rogue_is_around(row,col)56732689Sbostic rogue_is_around(row, col)
56832689Sbostic register row, col;
56932689Sbostic {
57032689Sbostic 	short rdif, cdif, retval;
57132689Sbostic 
57232689Sbostic 	rdif = row - rogue.row;
57332689Sbostic 	cdif = col - rogue.col;
57432689Sbostic 
57532689Sbostic 	retval = (rdif >= -1) && (rdif <= 1) && (cdif >= -1) && (cdif <= 1);
57632689Sbostic 	return(retval);
57732689Sbostic }
57832689Sbostic 
wanderer()57932689Sbostic wanderer()
58032689Sbostic {
58132689Sbostic 	object *monster;
58232689Sbostic 	short row, col, i;
58332689Sbostic 	boolean found = 0;
58432689Sbostic 
58532689Sbostic 	for (i = 0; ((i < 15) && (!found)); i++) {
58632689Sbostic 		monster = gr_monster((object *) 0, 0);
58732689Sbostic 		if (!(monster->m_flags & (WAKENS | WANDERS))) {
58832689Sbostic 			free_object(monster);
58932689Sbostic 		} else {
59032689Sbostic 			found = 1;
59132689Sbostic 		}
59232689Sbostic 	}
59332689Sbostic 	if (found) {
59432689Sbostic 		found = 0;
59532689Sbostic 		wake_up(monster);
59632689Sbostic 		for (i = 0; ((i < 25) && (!found)); i++) {
59732689Sbostic 			gr_row_col(&row, &col, (FLOOR | TUNNEL | STAIRS | OBJECT));
59832689Sbostic 			if (!rogue_can_see(row, col)) {
59932689Sbostic 				put_m_at(row, col, monster);
60032689Sbostic 				found = 1;
60132689Sbostic 			}
60232689Sbostic 		}
60332689Sbostic 		if (!found) {
60432689Sbostic 			free_object(monster);
60532689Sbostic 		}
60632689Sbostic 	}
60732689Sbostic }
60832689Sbostic 
show_monsters()60932689Sbostic show_monsters()
61032689Sbostic {
61132689Sbostic 	object *monster;
61232689Sbostic 
61332689Sbostic 	detect_monster = 1;
61432689Sbostic 
61532689Sbostic 	if (blind) {
61632689Sbostic 		return;
61732689Sbostic 	}
61832689Sbostic 	monster = level_monsters.next_monster;
61932689Sbostic 
62032689Sbostic 	while (monster) {
62132689Sbostic 		mvaddch(monster->row, monster->col, monster->m_char);
62232689Sbostic 		if (monster->m_flags & IMITATES) {
62332689Sbostic 			monster->m_flags &= (~IMITATES);
62432689Sbostic 			monster->m_flags |= WAKENS;
62532689Sbostic 		}
62632689Sbostic 		monster = monster->next_monster;
62732689Sbostic 	}
62832689Sbostic }
62932689Sbostic 
create_monster()63032689Sbostic create_monster()
63132689Sbostic {
63232689Sbostic 	short row, col;
63332689Sbostic 	short i;
63432689Sbostic 	boolean found = 0;
63532689Sbostic 	object *monster;
63632689Sbostic 
63732689Sbostic 	row = rogue.row;
63832689Sbostic 	col = rogue.col;
63932689Sbostic 
64032689Sbostic 	for (i = 0; i < 9; i++) {
64132689Sbostic 		rand_around(i, &row, &col);
64232689Sbostic 		if (((row == rogue.row) && (col = rogue.col)) ||
64332689Sbostic 				(row < MIN_ROW) || (row > (DROWS-2)) ||
64432689Sbostic 				(col < 0) || (col > (DCOLS-1))) {
64532689Sbostic 			continue;
64632689Sbostic 		}
64732689Sbostic 		if ((!(dungeon[row][col] & MONSTER)) &&
64832689Sbostic 			  (dungeon[row][col] & (FLOOR|TUNNEL|STAIRS|DOOR))) {
64932689Sbostic 			found = 1;
65032689Sbostic 			break;
65132689Sbostic 		}
65232689Sbostic 	}
65332689Sbostic 	if (found) {
65432689Sbostic 		monster = gr_monster((object *) 0, 0);
65532689Sbostic 		put_m_at(row, col, monster);
65632689Sbostic 		mvaddch(row, col, gmc(monster));
65732689Sbostic 		if (monster->m_flags & (WANDERS | WAKENS)) {
65832689Sbostic 			wake_up(monster);
65932689Sbostic 		}
66032689Sbostic 	} else {
66132689Sbostic 		message("you hear a faint cry of anguish in the distance", 0);
66232689Sbostic 	}
66332689Sbostic }
66432689Sbostic 
put_m_at(row,col,monster)66532689Sbostic put_m_at(row, col, monster)
66632689Sbostic short row, col;
66732689Sbostic object *monster;
66832689Sbostic {
66932689Sbostic 	monster->row = row;
67032689Sbostic 	monster->col = col;
67132689Sbostic 	dungeon[row][col] |= MONSTER;
67232689Sbostic 	monster->trail_char = mvinch(row, col);
67332689Sbostic 	(void) add_to_pack(monster, &level_monsters, 0);
67432689Sbostic 	aim_monster(monster);
67532689Sbostic }
67632689Sbostic 
aim_monster(monster)67732689Sbostic aim_monster(monster)
67832689Sbostic object *monster;
67932689Sbostic {
68032689Sbostic 	short i, rn, d, r;
68132689Sbostic 
68232689Sbostic 	rn = get_room_number(monster->row, monster->col);
68332689Sbostic 	r = get_rand(0, 12);
68432689Sbostic 
68532689Sbostic 	for (i = 0; i < 4; i++) {
68632689Sbostic 		d = (r + i) % 4;
68732689Sbostic 		if (rooms[rn].doors[d].oth_room != NO_ROOM) {
68832689Sbostic 			monster->trow = rooms[rn].doors[d].door_row;
68932689Sbostic 			monster->tcol = rooms[rn].doors[d].door_col;
69032689Sbostic 			break;
69132689Sbostic 		}
69232689Sbostic 	}
69332689Sbostic }
69432689Sbostic 
rogue_can_see(row,col)69532689Sbostic rogue_can_see(row, col)
69632689Sbostic register row, col;
69732689Sbostic {
69832689Sbostic 	register retval;
69932689Sbostic 
70032689Sbostic 	retval = !blind &&
70132689Sbostic 			(((get_room_number(row, col) == cur_room) &&
70232689Sbostic 					!(rooms[cur_room].is_room & R_MAZE)) ||
70332689Sbostic 			rogue_is_around(row, col));
70432689Sbostic 
70532689Sbostic 	return(retval);
70632689Sbostic }
70732689Sbostic 
move_confused(monster)70832689Sbostic move_confused(monster)
70932689Sbostic object *monster;
71032689Sbostic {
71132689Sbostic 	short i, row, col;
71232689Sbostic 
71332689Sbostic 	if (!(monster->m_flags & ASLEEP)) {
71432689Sbostic 		if (--monster->moves_confused <= 0) {
71532689Sbostic 			monster->m_flags &= (~CONFUSED);
71632689Sbostic 		}
71732689Sbostic 		if (monster->m_flags & STATIONARY) {
71832689Sbostic 			return(coin_toss() ? 1 : 0);
71932689Sbostic 		} else if (rand_percent(15)) {
72032689Sbostic 			return(1);
72132689Sbostic 		}
72232689Sbostic 		row = monster->row;
72332689Sbostic 		col = monster->col;
72432689Sbostic 
72532689Sbostic 		for (i = 0; i < 9; i++) {
72632689Sbostic 			rand_around(i, &row, &col);
72732689Sbostic 			if ((row == rogue.row) && (col == rogue.col)) {
72832689Sbostic 				return(0);
72932689Sbostic 			}
73032689Sbostic 			if (mtry(monster, row, col)) {
73132689Sbostic 				return(1);
73232689Sbostic 			}
73332689Sbostic 		}
73432689Sbostic 	}
73532689Sbostic 	return(0);
73632689Sbostic }
73732689Sbostic 
flit(monster)73832689Sbostic flit(monster)
73932689Sbostic object *monster;
74032689Sbostic {
74132689Sbostic 	short i, row, col;
74232689Sbostic 
74332689Sbostic 	if (!rand_percent(FLIT_PERCENT + ((monster->m_flags & FLIES) ? 20 : 0))) {
74432689Sbostic 		return(0);
74532689Sbostic 	}
74632689Sbostic 	if (rand_percent(10)) {
74732689Sbostic 		return(1);
74832689Sbostic 	}
74932689Sbostic 	row = monster->row;
75032689Sbostic 	col = monster->col;
75132689Sbostic 
75232689Sbostic 	for (i = 0; i < 9; i++) {
75332689Sbostic 		rand_around(i, &row, &col);
75432689Sbostic 		if ((row == rogue.row) && (col == rogue.col)) {
75532689Sbostic 			continue;
75632689Sbostic 		}
75732689Sbostic 		if (mtry(monster, row, col)) {
75832689Sbostic 			return(1);
75932689Sbostic 		}
76032689Sbostic 	}
76132689Sbostic 	return(1);
76232689Sbostic }
76332689Sbostic 
gr_obj_char()76432689Sbostic gr_obj_char()
76532689Sbostic {
76632689Sbostic 	short r;
76732689Sbostic 	char *rs = "%!?]=/):*";
76832689Sbostic 
76932689Sbostic 	r = get_rand(0, 8);
77032689Sbostic 
77132689Sbostic 	return(rs[r]);
77232689Sbostic }
77332689Sbostic 
no_room_for_monster(rn)77432689Sbostic no_room_for_monster(rn)
77532689Sbostic int rn;
77632689Sbostic {
77732689Sbostic 	short i, j;
77832689Sbostic 
77932689Sbostic 	for (i = rooms[rn].top_row+1; i < rooms[rn].bottom_row; i++) {
78032689Sbostic 		for (j = rooms[rn].left_col+1; j < rooms[rn].right_col; j++) {
78132689Sbostic 			if (!(dungeon[i][j] & MONSTER)) {
78232689Sbostic 				return(0);
78332689Sbostic 			}
78432689Sbostic 		}
78532689Sbostic 	}
78632689Sbostic 	return(1);
78732689Sbostic }
78832689Sbostic 
aggravate()78932689Sbostic aggravate()
79032689Sbostic {
79132689Sbostic 	object *monster;
79232689Sbostic 
79332689Sbostic 	message("you hear a high pitched humming noise", 0);
79432689Sbostic 
79532689Sbostic 	monster = level_monsters.next_monster;
79632689Sbostic 
79732689Sbostic 	while (monster) {
79832689Sbostic 		wake_up(monster);
79932689Sbostic 		monster->m_flags &= (~IMITATES);
80032689Sbostic 		if (rogue_can_see(monster->row, monster->col)) {
80132689Sbostic 			mvaddch(monster->row, monster->col, monster->m_char);
80232689Sbostic 		}
80332689Sbostic 		monster = monster->next_monster;
80432689Sbostic 	}
80532689Sbostic }
80632689Sbostic 
80732689Sbostic boolean
mon_sees(monster,row,col)80832689Sbostic mon_sees(monster, row, col)
80932689Sbostic object *monster;
81032689Sbostic {
81132689Sbostic 	short rn, rdif, cdif, retval;
81232689Sbostic 
81332689Sbostic 	rn = get_room_number(row, col);
81432689Sbostic 
81532689Sbostic 	if (	(rn != NO_ROOM) &&
81632689Sbostic 			(rn == get_room_number(monster->row, monster->col)) &&
81732689Sbostic 			!(rooms[rn].is_room & R_MAZE)) {
81832689Sbostic 		return(1);
81932689Sbostic 	}
82032689Sbostic 	rdif = row - monster->row;
82132689Sbostic 	cdif = col - monster->col;
82232689Sbostic 
82332689Sbostic 	retval = (rdif >= -1) && (rdif <= 1) && (cdif >= -1) && (cdif <= 1);
82432689Sbostic 	return(retval);
82532689Sbostic }
82632689Sbostic 
mv_aquatars()82732689Sbostic mv_aquatars()
82832689Sbostic {
82932689Sbostic 	object *monster;
83032689Sbostic 
83132689Sbostic 	monster = level_monsters.next_monster;
83232689Sbostic 
83332689Sbostic 	while (monster) {
83432689Sbostic 		if ((monster->m_char == 'A') &&
83532689Sbostic 			mon_can_go(monster, rogue.row, rogue.col)) {
83632689Sbostic 			mv_1_monster(monster, rogue.row, rogue.col);
83732689Sbostic 			monster->m_flags |= ALREADY_MOVED;
83832689Sbostic 		}
83932689Sbostic 		monster = monster->next_monster;
84032689Sbostic 	}
84132689Sbostic }
842