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