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