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