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