]> git.cameronkatri.com Git - bsdgames-darwin.git/blob - rogue/monster.c
Removing trailing spaces.
[bsdgames-darwin.git] / rogue / monster.c
1 /* $NetBSD: monster.c,v 1.10 2005/06/09 12:20:12 tron 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.10 2005/06/09 12:20:12 tron 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 r = get_rand(0, 12);
737
738 for (i = 0; i < 4; i++) {
739 d = (r + i) % 4;
740 if (rooms[rn].doors[d].oth_room != NO_ROOM) {
741 monster->trow = rooms[rn].doors[d].door_row;
742 monster->tcol = rooms[rn].doors[d].door_col;
743 break;
744 }
745 }
746 }
747
748 int
749 rogue_can_see(row, col)
750 int row, col;
751 {
752 int retval;
753
754 retval = !blind &&
755 (((get_room_number(row, col) == cur_room) &&
756 !(rooms[cur_room].is_room & R_MAZE)) ||
757 rogue_is_around(row, col));
758
759 return(retval);
760 }
761
762 int
763 move_confused(monster)
764 object *monster;
765 {
766 short i, row, col;
767
768 if (!(monster->m_flags & ASLEEP)) {
769 if (--monster->moves_confused <= 0) {
770 monster->m_flags &= (~CONFUSED);
771 }
772 if (monster->m_flags & STATIONARY) {
773 return(coin_toss() ? 1 : 0);
774 } else if (rand_percent(15)) {
775 return(1);
776 }
777 row = monster->row;
778 col = monster->col;
779
780 for (i = 0; i < 9; i++) {
781 rand_around(i, &row, &col);
782 if ((row == rogue.row) && (col == rogue.col)) {
783 return(0);
784 }
785 if (mtry(monster, row, col)) {
786 return(1);
787 }
788 }
789 }
790 return(0);
791 }
792
793 int
794 flit(monster)
795 object *monster;
796 {
797 short i, row, col;
798
799 if (!rand_percent(FLIT_PERCENT + ((monster->m_flags & FLIES) ? 20 : 0))) {
800 return(0);
801 }
802 if (rand_percent(10)) {
803 return(1);
804 }
805 row = monster->row;
806 col = monster->col;
807
808 for (i = 0; i < 9; i++) {
809 rand_around(i, &row, &col);
810 if ((row == rogue.row) && (col == rogue.col)) {
811 continue;
812 }
813 if (mtry(monster, row, col)) {
814 return(1);
815 }
816 }
817 return(1);
818 }
819
820 char
821 gr_obj_char()
822 {
823 short r;
824 const char *rs = "%!?]=/):*";
825
826 r = get_rand(0, 8);
827
828 return(rs[r]);
829 }
830
831 int
832 no_room_for_monster(rn)
833 int rn;
834 {
835 short i, j;
836
837 for (i = rooms[rn].top_row+1; i < rooms[rn].bottom_row; i++) {
838 for (j = rooms[rn].left_col+1; j < rooms[rn].right_col; j++) {
839 if (!(dungeon[i][j] & MONSTER)) {
840 return(0);
841 }
842 }
843 }
844 return(1);
845 }
846
847 void
848 aggravate()
849 {
850 object *monster;
851
852 message("you hear a high pitched humming noise", 0);
853
854 monster = level_monsters.next_monster;
855
856 while (monster) {
857 wake_up(monster);
858 monster->m_flags &= (~IMITATES);
859 if (rogue_can_see(monster->row, monster->col)) {
860 mvaddch(monster->row, monster->col, monster->m_char);
861 }
862 monster = monster->next_monster;
863 }
864 }
865
866 boolean
867 mon_sees(monster, row, col)
868 const object *monster;
869 int row, col;
870 {
871 short rn, rdif, cdif, retval;
872
873 rn = get_room_number(row, col);
874
875 if ( (rn != NO_ROOM) &&
876 (rn == get_room_number(monster->row, monster->col)) &&
877 !(rooms[rn].is_room & R_MAZE)) {
878 return(1);
879 }
880 rdif = row - monster->row;
881 cdif = col - monster->col;
882
883 retval = (rdif >= -1) && (rdif <= 1) && (cdif >= -1) && (cdif <= 1);
884 return(retval);
885 }
886
887 void
888 mv_aquatars()
889 {
890 object *monster;
891
892 monster = level_monsters.next_monster;
893
894 while (monster) {
895 if ((monster->m_char == 'A') &&
896 mon_can_go(monster, rogue.row, rogue.col)) {
897 mv_1_monster(monster, rogue.row, rogue.col);
898 monster->m_flags |= ALREADY_MOVED;
899 }
900 monster = monster->next_monster;
901 }
902 }