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