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