]> git.cameronkatri.com Git - bsdgames-darwin.git/blob - rogue/monster.c
typo in comment
[bsdgames-darwin.git] / rogue / monster.c
1 /* $NetBSD: monster.c,v 1.16 2009/10/19 02:34:40 dholland 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.16 2009/10/19 02:34:40 dholland 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 static 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 static void aim_monster(object *);
124 static int flit(object *);
125 static int move_confused(object *);
126 static int mtry(object *, short, short);
127 static int no_room_for_monster(int);
128 static void put_m_at(short, short, object *);
129 static int rogue_is_around(int, int);
130
131 void
132 put_mons(void)
133 {
134 short i;
135 short n;
136 object *monster;
137 short row, col;
138
139 n = get_rand(4, 6);
140
141 for (i = 0; i < n; i++) {
142 monster = gr_monster(NULL, 0);
143 if ((monster->m_flags & WANDERS) && coin_toss()) {
144 wake_up(monster);
145 }
146 gr_row_col(&row, &col, (FLOOR | TUNNEL | STAIRS | OBJECT));
147 put_m_at(row, col, monster);
148 }
149 }
150
151 object *
152 gr_monster(object *monster, int mn)
153 {
154 if (!monster) {
155 monster = alloc_object();
156
157 for (;;) {
158 mn = get_rand(0, MONSTERS-1);
159 if ((cur_level >= mon_tab[mn].first_level) &&
160 (cur_level <= mon_tab[mn].last_level)) {
161 break;
162 }
163 }
164 }
165 *monster = mon_tab[mn];
166 if (monster->m_flags & IMITATES) {
167 monster->disguise = gr_obj_char();
168 }
169 if (cur_level > (AMULET_LEVEL + 2)) {
170 monster->m_flags |= HASTED;
171 }
172 monster->trow = NO_ROOM;
173 return(monster);
174 }
175
176 void
177 mv_mons(void)
178 {
179 object *monster, *next_monster, *test_mons;
180 boolean flew;
181
182 if (haste_self % 2) {
183 return;
184 }
185
186 monster = level_monsters.next_monster;
187
188 while (monster) {
189 next_monster = monster->next_monster;
190 mon_disappeared = 0;
191 if (monster->m_flags & HASTED) {
192 mv_1_monster(monster, rogue.row, rogue.col);
193 if (mon_disappeared) {
194 goto NM;
195 }
196 } else if (monster->m_flags & SLOWED) {
197 monster->slowed_toggle = !monster->slowed_toggle;
198 if (monster->slowed_toggle) {
199 goto NM;
200 }
201 }
202 if ((monster->m_flags & CONFUSED) && move_confused(monster)) {
203 goto NM;
204 }
205 flew = 0;
206 if ( (monster->m_flags & FLIES) &&
207 !(monster->m_flags & NAPPING) &&
208 !mon_can_go(monster, rogue.row, rogue.col)) {
209 flew = 1;
210 mv_1_monster(monster, rogue.row, rogue.col);
211 if (mon_disappeared) {
212 goto NM;
213 }
214 }
215 if (!(flew && mon_can_go(monster, rogue.row, rogue.col))) {
216 mv_1_monster(monster, rogue.row, rogue.col);
217 }
218 NM: test_mons = level_monsters.next_monster;
219 monster = NULL;
220 while (test_mons)
221 {
222 if (next_monster == test_mons)
223 {
224 monster = next_monster;
225 break;
226 }
227 test_mons = test_mons -> next_monster;
228 }
229 }
230 }
231
232 void
233 party_monsters(int rn, int n)
234 {
235 short i, j;
236 short row, col;
237 object *monster;
238 boolean found;
239
240 row = col = 0;
241 n += n;
242
243 for (i = 0; i < MONSTERS; i++) {
244 mon_tab[i].first_level -= (cur_level % 3);
245 }
246 for (i = 0; i < n; i++) {
247 if (no_room_for_monster(rn)) {
248 break;
249 }
250 for (j = found = 0; ((!found) && (j < 250)); j++) {
251 row = get_rand(rooms[rn].top_row+1,
252 rooms[rn].bottom_row-1);
253 col = get_rand(rooms[rn].left_col+1,
254 rooms[rn].right_col-1);
255 if ((!(dungeon[row][col] & MONSTER)) &&
256 (dungeon[row][col] & (FLOOR | TUNNEL))) {
257 found = 1;
258 }
259 }
260 if (found) {
261 monster = gr_monster((object *)0, 0);
262 if (!(monster->m_flags & IMITATES)) {
263 monster->m_flags |= WAKENS;
264 }
265 put_m_at(row, col, monster);
266 }
267 }
268 for (i = 0; i < MONSTERS; i++) {
269 mon_tab[i].first_level += (cur_level % 3);
270 }
271 }
272
273 char
274 gmc_row_col(int row, int 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(object *monster)
294 {
295 if ((!(detect_monster || see_invisible || r_see_invisible) &&
296 (monster->m_flags & INVISIBLE))
297 || blind) {
298 return(monster->trail_char);
299 }
300 if (monster->m_flags & IMITATES) {
301 return(monster->disguise);
302 }
303 return(monster->m_char);
304 }
305
306 void
307 mv_1_monster(object *monster, short row, short col)
308 {
309 short i, n;
310 boolean tried[6];
311
312 if (monster->m_flags & ASLEEP) {
313 if (monster->m_flags & NAPPING) {
314 if (--monster->nap_length <= 0) {
315 monster->m_flags &= (~(NAPPING | ASLEEP));
316 }
317 return;
318 }
319 if ((monster->m_flags & WAKENS) &&
320 rogue_is_around(monster->row, monster->col) &&
321 rand_percent(((stealthy > 0) ?
322 (WAKE_PERCENT / (STEALTH_FACTOR + stealthy)) :
323 WAKE_PERCENT))) {
324 wake_up(monster);
325 }
326 return;
327 } else if (monster->m_flags & ALREADY_MOVED) {
328 monster->m_flags &= (~ALREADY_MOVED);
329 return;
330 }
331 if ((monster->m_flags & FLITS) && flit(monster)) {
332 return;
333 }
334 if ((monster->m_flags & STATIONARY) &&
335 (!mon_can_go(monster, rogue.row, rogue.col))) {
336 return;
337 }
338 if (monster->m_flags & FREEZING_ROGUE) {
339 return;
340 }
341 if ((monster->m_flags & CONFUSES) && m_confuse(monster)) {
342 return;
343 }
344 if (mon_can_go(monster, rogue.row, rogue.col)) {
345 mon_hit(monster);
346 return;
347 }
348 if ((monster->m_flags & FLAMES) && flame_broil(monster)) {
349 return;
350 }
351 if ((monster->m_flags & SEEKS_GOLD) && seek_gold(monster)) {
352 return;
353 }
354 if ((monster->trow == monster->row) &&
355 (monster->tcol == monster->col)) {
356 monster->trow = NO_ROOM;
357 } else if (monster->trow != NO_ROOM) {
358 row = monster->trow;
359 col = monster->tcol;
360 }
361 if (monster->row > row) {
362 row = monster->row - 1;
363 } else if (monster->row < row) {
364 row = monster->row + 1;
365 }
366 if ((dungeon[row][monster->col] & DOOR) &&
367 mtry(monster, row, monster->col)) {
368 return;
369 }
370 if (monster->col > col) {
371 col = monster->col - 1;
372 } else if (monster->col < col) {
373 col = monster->col + 1;
374 }
375 if ((dungeon[monster->row][col] & DOOR) &&
376 mtry(monster, monster->row, col)) {
377 return;
378 }
379 if (mtry(monster, row, col)) {
380 return;
381 }
382
383 for (i = 0; i <= 5; i++) tried[i] = 0;
384
385 for (i = 0; i < 6; i++) {
386 NEXT_TRY: n = get_rand(0, 5);
387 switch(n) {
388 case 0:
389 if (!tried[n] && mtry(monster, row, monster->col-1)) {
390 goto O;
391 }
392 break;
393 case 1:
394 if (!tried[n] && mtry(monster, row, monster->col)) {
395 goto O;
396 }
397 break;
398 case 2:
399 if (!tried[n] && mtry(monster, row, monster->col+1)) {
400 goto O;
401 }
402 break;
403 case 3:
404 if (!tried[n] && mtry(monster, monster->row-1, col)) {
405 goto O;
406 }
407 break;
408 case 4:
409 if (!tried[n] && mtry(monster, monster->row, col)) {
410 goto O;
411 }
412 break;
413 case 5:
414 if (!tried[n] && mtry(monster, monster->row+1, col)) {
415 goto O;
416 }
417 break;
418 }
419 if (!tried[n]) {
420 tried[n] = 1;
421 } else {
422 goto NEXT_TRY;
423 }
424 }
425 O:
426 if ((monster->row == monster->o_row) && (monster->col == monster->o_col)) {
427 if (++(monster->o) > 4) {
428 if ((monster->trow == NO_ROOM) &&
429 (!mon_sees(monster, rogue.row, rogue.col))) {
430 monster->trow = get_rand(1, (DROWS - 2));
431 monster->tcol = get_rand(0, (DCOLS - 1));
432 } else {
433 monster->trow = NO_ROOM;
434 monster->o = 0;
435 }
436 }
437 } else {
438 monster->o_row = monster->row;
439 monster->o_col = monster->col;
440 monster->o = 0;
441 }
442 }
443
444 static int
445 mtry(object *monster, short row, short col)
446 {
447 if (mon_can_go(monster, row, col)) {
448 move_mon_to(monster, row, col);
449 return(1);
450 }
451 return(0);
452 }
453
454 void
455 move_mon_to(object *monster, short row, short col)
456 {
457 short c;
458 int mrow, mcol;
459
460 mrow = monster->row;
461 mcol = monster->col;
462
463 dungeon[mrow][mcol] &= ~MONSTER;
464 dungeon[row][col] |= MONSTER;
465
466 c = mvinch(mrow, mcol);
467
468 if ((c >= 'A') && (c <= 'Z')) {
469 if (!detect_monster) {
470 mvaddch(mrow, mcol, monster->trail_char);
471 } else {
472 if (rogue_can_see(mrow, mcol)) {
473 mvaddch(mrow, mcol, monster->trail_char);
474 } else {
475 if (monster->trail_char == '.') {
476 monster->trail_char = ' ';
477 }
478 mvaddch(mrow, mcol, monster->trail_char);
479 }
480 }
481 }
482 monster->trail_char = mvinch(row, col);
483 if (!blind && (detect_monster || rogue_can_see(row, col))) {
484 if ((!(monster->m_flags & INVISIBLE) ||
485 (detect_monster || see_invisible || r_see_invisible))) {
486 mvaddch(row, col, gmc(monster));
487 }
488 }
489 if ((dungeon[row][col] & DOOR) &&
490 (get_room_number(row, col) != cur_room) &&
491 (dungeon[mrow][mcol] == FLOOR) && !blind) {
492 mvaddch(mrow, mcol, ' ');
493 }
494 if (dungeon[row][col] & DOOR) {
495 dr_course(monster, ((dungeon[mrow][mcol] & TUNNEL) ? 1 : 0),
496 row, col);
497 } else {
498 monster->row = row;
499 monster->col = col;
500 }
501 }
502
503 int
504 mon_can_go(const object *monster, short row, short col)
505 {
506 object *obj;
507 short dr, dc;
508
509 dr = monster->row - row; /* check if move distance > 1 */
510 if ((dr >= 2) || (dr <= -2)) {
511 return(0);
512 }
513 dc = monster->col - col;
514 if ((dc >= 2) || (dc <= -2)) {
515 return(0);
516 }
517 if ((!dungeon[monster->row][col]) || (!dungeon[row][monster->col])) {
518 return(0);
519 }
520 if ((!is_passable(row, col)) || (dungeon[row][col] & MONSTER)) {
521 return(0);
522 }
523 if ((monster->row!=row)&&(monster->col!=col)&&((dungeon[row][col]&DOOR) ||
524 (dungeon[monster->row][monster->col]&DOOR))) {
525 return(0);
526 }
527 if (!(monster->m_flags & (FLITS | CONFUSED | CAN_FLIT)) &&
528 (monster->trow == NO_ROOM)) {
529 if ((monster->row < rogue.row) && (row < monster->row)) return(0);
530 if ((monster->row > rogue.row) && (row > monster->row)) return(0);
531 if ((monster->col < rogue.col) && (col < monster->col)) return(0);
532 if ((monster->col > rogue.col) && (col > monster->col)) return(0);
533 }
534 if (dungeon[row][col] & OBJECT) {
535 obj = object_at(&level_objects, row, col);
536 if ((obj->what_is == SCROL) && (obj->which_kind == SCARE_MONSTER)) {
537 return(0);
538 }
539 }
540 return(1);
541 }
542
543 void
544 wake_up(object *monster)
545 {
546 if (!(monster->m_flags & NAPPING)) {
547 monster->m_flags &= (~(ASLEEP | IMITATES | WAKENS));
548 }
549 }
550
551 void
552 wake_room(short rn, boolean entering, short row, short col)
553 {
554 object *monster;
555 short wake_percent;
556 boolean in_room;
557
558 wake_percent = (rn == party_room) ? PARTY_WAKE_PERCENT : WAKE_PERCENT;
559 if (stealthy > 0) {
560 wake_percent /= (STEALTH_FACTOR + stealthy);
561 }
562
563 monster = level_monsters.next_monster;
564
565 while (monster) {
566 in_room = (rn == get_room_number(monster->row, monster->col));
567 if (in_room) {
568 if (entering) {
569 monster->trow = NO_ROOM;
570 } else {
571 monster->trow = row;
572 monster->tcol = col;
573 }
574 }
575 if ((monster->m_flags & WAKENS) &&
576 (rn == get_room_number(monster->row, monster->col))) {
577 if (rand_percent(wake_percent)) {
578 wake_up(monster);
579 }
580 }
581 monster = monster->next_monster;
582 }
583 }
584
585 const char *
586 mon_name(const object *monster)
587 {
588 short ch;
589
590 if (blind || ((monster->m_flags & INVISIBLE) &&
591 !(detect_monster || see_invisible || r_see_invisible))) {
592 return("something");
593 }
594 if (halluc) {
595 ch = get_rand('A', 'Z') - 'A';
596 return(m_names[ch]);
597 }
598 ch = monster->m_char - 'A';
599 return(m_names[ch]);
600 }
601
602 static int
603 rogue_is_around(int row, int col)
604 {
605 short rdif, cdif, retval;
606
607 rdif = row - rogue.row;
608 cdif = col - rogue.col;
609
610 retval = (rdif >= -1) && (rdif <= 1) && (cdif >= -1) && (cdif <= 1);
611 return(retval);
612 }
613
614 void
615 wanderer(void)
616 {
617 object *monster;
618 short row, col, i;
619 boolean found = 0;
620
621 monster = NULL; /* XXXGCC -Wuninitialized [powerpc] */
622
623 for (i = 0; ((i < 15) && (!found)); i++) {
624 monster = gr_monster(NULL, 0);
625 if (!(monster->m_flags & (WAKENS | WANDERS))) {
626 free_object(monster);
627 } else {
628 found = 1;
629 }
630 }
631 if (found) {
632 found = 0;
633 wake_up(monster);
634 for (i = 0; ((i < 25) && (!found)); i++) {
635 gr_row_col(&row, &col, (FLOOR | TUNNEL | STAIRS | OBJECT));
636 if (!rogue_can_see(row, col)) {
637 put_m_at(row, col, monster);
638 found = 1;
639 }
640 }
641 if (!found) {
642 free_object(monster);
643 }
644 }
645 }
646
647 void
648 show_monsters(void)
649 {
650 object *monster;
651
652 detect_monster = 1;
653
654 if (blind) {
655 return;
656 }
657 monster = level_monsters.next_monster;
658
659 while (monster) {
660 mvaddch(monster->row, monster->col, monster->m_char);
661 if (monster->m_flags & IMITATES) {
662 monster->m_flags &= (~IMITATES);
663 monster->m_flags |= WAKENS;
664 }
665 monster = monster->next_monster;
666 }
667 }
668
669 void
670 create_monster(void)
671 {
672 short row, col;
673 short i;
674 boolean found = 0;
675 object *monster;
676
677 row = rogue.row;
678 col = rogue.col;
679
680 for (i = 0; i < 9; i++) {
681 rand_around(i, &row, &col);
682 if (((row == rogue.row) && (col == rogue.col)) ||
683 (row < MIN_ROW) || (row > (DROWS-2)) ||
684 (col < 0) || (col > (DCOLS-1))) {
685 continue;
686 }
687 if ((!(dungeon[row][col] & MONSTER)) &&
688 (dungeon[row][col] & (FLOOR|TUNNEL|STAIRS|DOOR))) {
689 found = 1;
690 break;
691 }
692 }
693 if (found) {
694 monster = gr_monster((object *)0, 0);
695 put_m_at(row, col, monster);
696 mvaddch(row, col, gmc(monster));
697 if (monster->m_flags & (WANDERS | WAKENS)) {
698 wake_up(monster);
699 }
700 } else {
701 messagef(0, "you hear a faint cry of anguish in the distance");
702 }
703 }
704
705 static void
706 put_m_at(short row, short col, object *monster)
707 {
708 monster->row = row;
709 monster->col = col;
710 dungeon[row][col] |= MONSTER;
711 monster->trail_char = mvinch(row, col);
712 (void)add_to_pack(monster, &level_monsters, 0);
713 aim_monster(monster);
714 }
715
716 static void
717 aim_monster(object *monster)
718 {
719 short i, rn, d, r;
720
721 rn = get_room_number(monster->row, monster->col);
722 if (rn == NO_ROOM)
723 clean_up("aim_monster: monster not in room");
724 r = get_rand(0, 12);
725
726 for (i = 0; i < 4; i++) {
727 d = (r + i) % 4;
728 if (rooms[rn].doors[d].oth_room != NO_ROOM) {
729 monster->trow = rooms[rn].doors[d].door_row;
730 monster->tcol = rooms[rn].doors[d].door_col;
731 break;
732 }
733 }
734 }
735
736 int
737 rogue_can_see(int row, int col)
738 {
739 int retval;
740
741 retval = !blind &&
742 (((get_room_number(row, col) == cur_room) &&
743 !(rooms[cur_room].is_room & R_MAZE)) ||
744 rogue_is_around(row, col));
745
746 return(retval);
747 }
748
749 static int
750 move_confused(object *monster)
751 {
752 short i, row, col;
753
754 if (!(monster->m_flags & ASLEEP)) {
755 if (--monster->moves_confused <= 0) {
756 monster->m_flags &= (~CONFUSED);
757 }
758 if (monster->m_flags & STATIONARY) {
759 return(coin_toss() ? 1 : 0);
760 } else if (rand_percent(15)) {
761 return(1);
762 }
763 row = monster->row;
764 col = monster->col;
765
766 for (i = 0; i < 9; i++) {
767 rand_around(i, &row, &col);
768 if ((row == rogue.row) && (col == rogue.col)) {
769 return(0);
770 }
771 if (mtry(monster, row, col)) {
772 return(1);
773 }
774 }
775 }
776 return(0);
777 }
778
779 static int
780 flit(object *monster)
781 {
782 short i, row, col;
783
784 if (!rand_percent(FLIT_PERCENT + ((monster->m_flags & FLIES) ? 20 : 0))) {
785 return(0);
786 }
787 if (rand_percent(10)) {
788 return(1);
789 }
790 row = monster->row;
791 col = monster->col;
792
793 for (i = 0; i < 9; i++) {
794 rand_around(i, &row, &col);
795 if ((row == rogue.row) && (col == rogue.col)) {
796 continue;
797 }
798 if (mtry(monster, row, col)) {
799 return(1);
800 }
801 }
802 return(1);
803 }
804
805 char
806 gr_obj_char(void)
807 {
808 short r;
809 const char *rs = "%!?]=/):*";
810
811 r = get_rand(0, 8);
812
813 return(rs[r]);
814 }
815
816 static int
817 no_room_for_monster(int rn)
818 {
819 short i, j;
820
821 for (i = rooms[rn].top_row+1; i < rooms[rn].bottom_row; i++) {
822 for (j = rooms[rn].left_col+1; j < rooms[rn].right_col; j++) {
823 if (!(dungeon[i][j] & MONSTER)) {
824 return(0);
825 }
826 }
827 }
828 return(1);
829 }
830
831 void
832 aggravate(void)
833 {
834 object *monster;
835
836 messagef(0, "you hear a high pitched humming noise");
837
838 monster = level_monsters.next_monster;
839
840 while (monster) {
841 wake_up(monster);
842 monster->m_flags &= (~IMITATES);
843 if (rogue_can_see(monster->row, monster->col)) {
844 mvaddch(monster->row, monster->col, monster->m_char);
845 }
846 monster = monster->next_monster;
847 }
848 }
849
850 boolean
851 mon_sees(const object *monster, int row, int col)
852 {
853 short rn, rdif, cdif, retval;
854
855 rn = get_room_number(row, col);
856
857 if ( (rn != NO_ROOM) &&
858 (rn == get_room_number(monster->row, monster->col)) &&
859 !(rooms[rn].is_room & R_MAZE)) {
860 return(1);
861 }
862 rdif = row - monster->row;
863 cdif = col - monster->col;
864
865 retval = (rdif >= -1) && (rdif <= 1) && (cdif >= -1) && (cdif <= 1);
866 return(retval);
867 }
868
869 void
870 mv_aquatars(void)
871 {
872 object *monster;
873
874 monster = level_monsters.next_monster;
875
876 while (monster) {
877 if ((monster->m_char == 'A') &&
878 mon_can_go(monster, rogue.row, rogue.col)) {
879 mv_1_monster(monster, rogue.row, rogue.col);
880 monster->m_flags |= ALREADY_MOVED;
881 }
882 monster = monster->next_monster;
883 }
884 }