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