Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[dragonfly.git] / games / rogue / monster.c
CommitLineData
984263bc
MD
1/*
2 * Copyright (c) 1988, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Timothy C. Stoehr.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
1de703da
MD
35 *
36 * @(#)monster.c 8.1 (Berkeley) 5/31/93
37 * $FreeBSD: src/games/rogue/monster.c,v 1.6 1999/11/30 03:49:24 billf Exp $
38 * $DragonFly: src/games/rogue/monster.c,v 1.2 2003/06/17 04:25:24 dillon Exp $
984263bc
MD
39 */
40
984263bc
MD
41/*
42 * monster.c
43 *
44 * This source herein may be modified and/or distributed by anybody who
45 * so desires, with the following restrictions:
46 * 1.) No portion of this notice shall be removed.
47 * 2.) Credit shall not be taken for the creation of this source.
48 * 3.) This code is not to be traded, sold, or used for personal
49 * gain or profit.
50 *
51 */
52
53#include "rogue.h"
54
55object level_monsters;
56boolean mon_disappeared;
57
58const char *const m_names[] = {
59 "aquator",
60 "bat",
61 "centaur",
62 "dragon",
63 "emu",
64 "venus fly-trap",
65 "griffin",
66 "hobgoblin",
67 "ice monster",
68 "jabberwock",
69 "kestrel",
70 "leprechaun",
71 "medusa",
72 "nymph",
73 "orc",
74 "phantom",
75 "quagga",
76 "rattlesnake",
77 "snake",
78 "troll",
79 "black unicorn",
80 "vampire",
81 "wraith",
82 "xeroc",
83 "yeti",
84 "zombie"
85};
86
87object mon_tab[MONSTERS] = {
88 {(ASLEEP|WAKENS|WANDERS|RUSTS),"0d0",25,'A',20,9,18,100,0,0,0,0,0},
89 {(ASLEEP|WANDERS|FLITS|FLIES),"1d3",10,'B',2,1,8,60,0,0,0,0,0},
90 {(ASLEEP|WANDERS),"3d3/2d5",32,'C',15,7,16,85,0,10,0,0,0},
91 {(ASLEEP|WAKENS|FLAMES),"4d6/4d9",145,'D',5000,21,126,100,0,90,0,0,0},
92 {(ASLEEP|WAKENS),"1d3",11,'E',2,1,7,65,0,0,0,0,0},
93 {(HOLDS|STATIONARY),"5d5",73,'F',91,12,126,80,0,0,0,0,0},
94 {(ASLEEP|WAKENS|WANDERS|FLIES),"5d5/5d5",115,'G',
95 2000,20,126,85,0,10,0,0,0},
96 {(ASLEEP|WAKENS|WANDERS),"1d3/1d2",15,'H',3,1,10,67,0,0,0,0,0},
97 {(ASLEEP|FREEZES),"0d0",15,'I',5,2,11,68,0,0,0,0,0},
98 {(ASLEEP|WANDERS),"3d10/4d5",132,'J',3000,21,126,100,0,0,0,0,0},
99 {(ASLEEP|WAKENS|WANDERS|FLIES),"1d4",10,'K',2,1,6,60,0,0,0,0,0},
100 {(ASLEEP|STEALS_GOLD),"0d0",25,'L',21,6,16,75,0,0,0,0,0},
101 {(ASLEEP|WAKENS|WANDERS|CONFUSES),"4d4/3d7",97,'M',
102 250,18,126,85,0,25,0,0,0},
103 {(ASLEEP|STEALS_ITEM),"0d0",25,'N',39,10,19,75,0,100,0,0,0},
104 {(ASLEEP|WANDERS|WAKENS|SEEKS_GOLD),"1d6",25,'O',5,4,13,70,0,10,0,0,0},
105 {(ASLEEP|INVISIBLE|WANDERS|FLITS),"5d4",76,'P',120,15,24,80,0,50,0,0,0},
106 {(ASLEEP|WAKENS|WANDERS),"3d5",30,'Q',20,8,17,78,0,20,0,0,0},
107 {(ASLEEP|WAKENS|WANDERS|STINGS),"2d5",19,'R',10,3,12,70,0,0,0,0,0},
108 {(ASLEEP|WAKENS|WANDERS),"1d3",8,'S',2,1,9,50,0,0,0,0,0},
109 {(ASLEEP|WAKENS|WANDERS),"4d6/1d4",75,'T',125,13,22,75,0,33,0,0,0},
110 {(ASLEEP|WAKENS|WANDERS),"4d10",90,'U',
111 200,17,26,85,0,33,0,0,0},
112 {(ASLEEP|WAKENS|WANDERS|DRAINS_LIFE),"1d14/1d4",55,'V',
113 350,19,126,85,0,18,0,0,0},
114 {(ASLEEP|WANDERS|DROPS_LEVEL),"2d8",45,'W',55,14,23,75,0,0,0,0,0},
115 {(ASLEEP|IMITATES),"4d6",42,'X',110,16,25,75,0,0,0,0,0},
116 {(ASLEEP|WANDERS),"3d6",35,'Y',50,11,20,80,0,20,0,0,0},
117 {(ASLEEP|WAKENS|WANDERS),"1d7",21,'Z',8,5,14,69,0,0,0,0,0}
118};
119
120extern short cur_level;
121extern short cur_room, party_room;
122extern short blind, halluc, haste_self;
123extern boolean detect_monster, see_invisible, r_see_invisible;
124extern short stealthy;
125
126put_mons()
127{
128 short i;
129 short n;
130 object *monster;
131 short row, col;
132
133 n = get_rand(4, 6);
134
135 for (i = 0; i < n; i++) {
136 monster = gr_monster((object *) 0, 0);
137 if ((monster->m_flags & WANDERS) && coin_toss()) {
138 wake_up(monster);
139 }
140 gr_row_col(&row, &col, (FLOOR | TUNNEL | STAIRS | OBJECT));
141 put_m_at(row, col, monster);
142 }
143}
144
145object *
146gr_monster(monster, mn)
147object *monster;
148int mn;
149{
150 if (!monster) {
151 monster = alloc_object();
152
153 for (;;) {
154 mn = get_rand(0, MONSTERS-1);
155 if ((cur_level >= mon_tab[mn].first_level) &&
156 (cur_level <= mon_tab[mn].last_level)) {
157 break;
158 }
159 }
160 }
161 *monster = mon_tab[mn];
162 if (monster->m_flags & IMITATES) {
163 monster->disguise = gr_obj_char();
164 }
165 if (cur_level > (AMULET_LEVEL + 2)) {
166 monster->m_flags |= HASTED;
167 }
168 monster->trow = NO_ROOM;
169 return(monster);
170}
171
172mv_mons()
173{
174 object *monster, *next_monster, *test_mons;
175 boolean flew;
176
177 if (haste_self % 2) {
178 return;
179 }
180
181 monster = level_monsters.next_monster;
182
183 while (monster) {
184 next_monster = monster->next_monster;
185 mon_disappeared = 0;
186 if (monster->m_flags & HASTED) {
187 mv_1_monster(monster, rogue.row, rogue.col);
188 if (mon_disappeared) {
189 goto NM;
190 }
191 } else if (monster->m_flags & SLOWED) {
192 monster->slowed_toggle = !monster->slowed_toggle;
193 if (monster->slowed_toggle) {
194 goto NM;
195 }
196 }
197 if ((monster->m_flags & CONFUSED) && move_confused(monster)) {
198 goto NM;
199 }
200 flew = 0;
201 if ( (monster->m_flags & FLIES) &&
202 !(monster->m_flags & NAPPING) &&
203 !mon_can_go(monster, rogue.row, rogue.col)) {
204 flew = 1;
205 mv_1_monster(monster, rogue.row, rogue.col);
206 if (mon_disappeared) {
207 goto NM;
208 }
209 }
210 if (!(flew && mon_can_go(monster, rogue.row, rogue.col))) {
211 mv_1_monster(monster, rogue.row, rogue.col);
212 }
213NM: test_mons = level_monsters.next_monster;
214 monster = NULL;
215 while(test_mons)
216 {
217 if(next_monster == test_mons)
218 {
219 monster = next_monster;
220 break;
221 }
222 test_mons = test_mons->next_monster;
223 }
224 }
225}
226
227party_monsters(rn, n)
228int rn, n;
229{
230 short i, j;
231 short row, col;
232 object *monster;
233 boolean found;
234
235 n += n;
236
237 for (i = 0; i < MONSTERS; i++) {
238 mon_tab[i].first_level -= (cur_level % 3);
239 }
240 for (i = 0; i < n; i++) {
241 if (no_room_for_monster(rn)) {
242 break;
243 }
244 for (j = found = 0; ((!found) && (j < 250)); j++) {
245 row = get_rand(rooms[rn].top_row+1,
246 rooms[rn].bottom_row-1);
247 col = get_rand(rooms[rn].left_col+1,
248 rooms[rn].right_col-1);
249 if ((!(dungeon[row][col] & MONSTER)) &&
250 (dungeon[row][col] & (FLOOR | TUNNEL))) {
251 found = 1;
252 }
253 }
254 if (found) {
255 monster = gr_monster((object *) 0, 0);
256 if (!(monster->m_flags & IMITATES)) {
257 monster->m_flags |= WAKENS;
258 }
259 put_m_at(row, col, monster);
260 }
261 }
262 for (i = 0; i < MONSTERS; i++) {
263 mon_tab[i].first_level += (cur_level % 3);
264 }
265}
266
267gmc_row_col(row, col)
268int row, col;
269{
270 object *monster;
271
272 if (monster = object_at(&level_monsters, row, col)) {
273 if ((!(detect_monster || see_invisible || r_see_invisible) &&
274 (monster->m_flags & INVISIBLE)) || blind) {
275 return(monster->trail_char);
276 }
277 if (monster->m_flags & IMITATES) {
278 return(monster->disguise);
279 }
280 return(monster->m_char);
281 } else {
282 return('&'); /* BUG if this ever happens */
283 }
284}
285
286gmc(monster)
287object *monster;
288{
289 if ((!(detect_monster || see_invisible || r_see_invisible) &&
290 (monster->m_flags & INVISIBLE))
291 || blind) {
292 return(monster->trail_char);
293 }
294 if (monster->m_flags & IMITATES) {
295 return(monster->disguise);
296 }
297 return(monster->m_char);
298}
299
300mv_1_monster(monster, row, col)
301object *monster;
302short row, col;
303{
304 short i, n;
305 boolean tried[6];
306
307 if (monster->m_flags & ASLEEP) {
308 if (monster->m_flags & NAPPING) {
309 if (--monster->nap_length <= 0) {
310 monster->m_flags &= (~(NAPPING | ASLEEP));
311 }
312 return;
313 }
314 if ((monster->m_flags & WAKENS) &&
315 rogue_is_around(monster->row, monster->col) &&
316 rand_percent(((stealthy > 0) ?
317 (WAKE_PERCENT / (STEALTH_FACTOR + stealthy)) :
318 WAKE_PERCENT))) {
319 wake_up(monster);
320 }
321 return;
322 } else if (monster->m_flags & ALREADY_MOVED) {
323 monster->m_flags &= (~ALREADY_MOVED);
324 return;
325 }
326 if ((monster->m_flags & FLITS) && flit(monster)) {
327 return;
328 }
329 if ((monster->m_flags & STATIONARY) &&
330 (!mon_can_go(monster, rogue.row, rogue.col))) {
331 return;
332 }
333 if (monster->m_flags & FREEZING_ROGUE) {
334 return;
335 }
336 if ((monster->m_flags & CONFUSES) && m_confuse(monster)) {
337 return;
338 }
339 if (mon_can_go(monster, rogue.row, rogue.col)) {
340 mon_hit(monster);
341 return;
342 }
343 if ((monster->m_flags & FLAMES) && flame_broil(monster)) {
344 return;
345 }
346 if ((monster->m_flags & SEEKS_GOLD) && seek_gold(monster)) {
347 return;
348 }
349 if ((monster->trow == monster->row) &&
350 (monster->tcol == monster->col)) {
351 monster->trow = NO_ROOM;
352 } else if (monster->trow != NO_ROOM) {
353 row = monster->trow;
354 col = monster->tcol;
355 }
356 if (monster->row > row) {
357 row = monster->row - 1;
358 } else if (monster->row < row) {
359 row = monster->row + 1;
360 }
361 if ((dungeon[row][monster->col] & DOOR) &&
362 mtry(monster, row, monster->col)) {
363 return;
364 }
365 if (monster->col > col) {
366 col = monster->col - 1;
367 } else if (monster->col < col) {
368 col = monster->col + 1;
369 }
370 if ((dungeon[monster->row][col] & DOOR) &&
371 mtry(monster, monster->row, col)) {
372 return;
373 }
374 if (mtry(monster, row, col)) {
375 return;
376 }
377
378 for (i = 0; i <= 5; i++) tried[i] = 0;
379
380 for (i = 0; i < 6; i++) {
381NEXT_TRY: n = get_rand(0, 5);
382 switch(n) {
383 case 0:
384 if (!tried[n] && mtry(monster, row, monster->col-1)) {
385 goto O;
386 }
387 break;
388 case 1:
389 if (!tried[n] && mtry(monster, row, monster->col)) {
390 goto O;
391 }
392 break;
393 case 2:
394 if (!tried[n] && mtry(monster, row, monster->col+1)) {
395 goto O;
396 }
397 break;
398 case 3:
399 if (!tried[n] && mtry(monster, monster->row-1, col)) {
400 goto O;
401 }
402 break;
403 case 4:
404 if (!tried[n] && mtry(monster, monster->row, col)) {
405 goto O;
406 }
407 break;
408 case 5:
409 if (!tried[n] && mtry(monster, monster->row+1, col)) {
410 goto O;
411 }
412 break;
413 }
414 if (!tried[n]) {
415 tried[n] = 1;
416 } else {
417 goto NEXT_TRY;
418 }
419 }
420O:
421 if ((monster->row == monster->o_row) && (monster->col == monster->o_col)) {
422 if (++(monster->o) > 4) {
423 if ((monster->trow == NO_ROOM) &&
424 (!mon_sees(monster, rogue.row, rogue.col))) {
425 monster->trow = get_rand(1, (DROWS - 2));
426 monster->tcol = get_rand(0, (DCOLS - 1));
427 } else {
428 monster->trow = NO_ROOM;
429 monster->o = 0;
430 }
431 }
432 } else {
433 monster->o_row = monster->row;
434 monster->o_col = monster->col;
435 monster->o = 0;
436 }
437}
438
439mtry(monster, row, col)
440object *monster;
441short row, col;
442{
443 if (mon_can_go(monster, row, col)) {
444 move_mon_to(monster, row, col);
445 return(1);
446 }
447 return(0);
448}
449
450move_mon_to(monster, row, col)
451object *monster;
452short row, col;
453{
454 short c;
455 int mrow, mcol;
456
457 mrow = monster->row;
458 mcol = monster->col;
459
460 dungeon[mrow][mcol] &= ~MONSTER;
461 dungeon[row][col] |= MONSTER;
462
463 c = mvinch(mrow, mcol);
464
465 if ((c >= 'A') && (c <= 'Z')) {
466 if (!detect_monster) {
467 mvaddch(mrow, mcol, monster->trail_char);
468 } else {
469 if (rogue_can_see(mrow, mcol)) {
470 mvaddch(mrow, mcol, monster->trail_char);
471 } else {
472 if (monster->trail_char == '.') {
473 monster->trail_char = ' ';
474 }
475 mvaddch(mrow, mcol, monster->trail_char);
476 }
477 }
478 }
479 monster->trail_char = mvinch(row, col);
480 if (!blind && (detect_monster || rogue_can_see(row, col))) {
481 if ((!(monster->m_flags & INVISIBLE) ||
482 (detect_monster || see_invisible || r_see_invisible))) {
483 mvaddch(row, col, gmc(monster));
484 }
485 }
486 if ((dungeon[row][col] & DOOR) &&
487 (get_room_number(row, col) != cur_room) &&
488 (dungeon[mrow][mcol] == FLOOR) && !blind) {
489 mvaddch(mrow, mcol, ' ');
490 }
491 if (dungeon[row][col] & DOOR) {
492 dr_course(monster, ((dungeon[mrow][mcol] & TUNNEL) ? 1 : 0),
493 row, col);
494 } else {
495 monster->row = row;
496 monster->col = col;
497 }
498}
499
500mon_can_go(monster, row, col)
501const object *monster;
502short row, col;
503{
504 object *obj;
505 short dr, dc;
506
507 dr = monster->row - row; /* check if move distance > 1 */
508 if ((dr >= 2) || (dr <= -2)) {
509 return(0);
510 }
511 dc = monster->col - col;
512 if ((dc >= 2) || (dc <= -2)) {
513 return(0);
514 }
515 if ((!dungeon[monster->row][col]) || (!dungeon[row][monster->col])) {
516 return(0);
517 }
518 if ((!is_passable(row, col)) || (dungeon[row][col] & MONSTER)) {
519 return(0);
520 }
521 if ((monster->row!=row)&&(monster->col!=col)&&((dungeon[row][col]&DOOR) ||
522 (dungeon[monster->row][monster->col]&DOOR))) {
523 return(0);
524 }
525 if (!(monster->m_flags & (FLITS | CONFUSED | CAN_FLIT)) &&
526 (monster->trow == NO_ROOM)) {
527 if ((monster->row < rogue.row) && (row < monster->row)) return(0);
528 if ((monster->row > rogue.row) && (row > monster->row)) return(0);
529 if ((monster->col < rogue.col) && (col < monster->col)) return(0);
530 if ((monster->col > rogue.col) && (col > monster->col)) return(0);
531 }
532 if (dungeon[row][col] & OBJECT) {
533 obj = object_at(&level_objects, row, col);
534 if ((obj->what_is == SCROL) && (obj->which_kind == SCARE_MONSTER)) {
535 return(0);
536 }
537 }
538 return(1);
539}
540
541wake_up(monster)
542object *monster;
543{
544 if (!(monster->m_flags & NAPPING)) {
545 monster->m_flags &= (~(ASLEEP | IMITATES | WAKENS));
546 }
547}
548
549wake_room(rn, entering, row, col)
550short rn;
551boolean entering;
552short row, 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
585const char *
586mon_name(monster)
587const object *monster;
588{
589 short ch;
590
591 if (blind || ((monster->m_flags & INVISIBLE) &&
592 !(detect_monster || see_invisible || r_see_invisible))) {
593 return("something");
594 }
595 if (halluc) {
596 ch = get_rand('A', 'Z') - 'A';
597 return(m_names[ch]);
598 }
599 ch = monster->m_char - 'A';
600 return(m_names[ch]);
601}
602
603rogue_is_around(row, col)
604int row, col;
605{
606 short rdif, cdif, retval;
607
608 rdif = row - rogue.row;
609 cdif = col - rogue.col;
610
611 retval = (rdif >= -1) && (rdif <= 1) && (cdif >= -1) && (cdif <= 1);
612 return(retval);
613}
614
615wanderer()
616{
617 object *monster;
618 short row, col, i;
619 boolean found = 0;
620
621 for (i = 0; ((i < 15) && (!found)); i++) {
622 monster = gr_monster((object *) 0, 0);
623 if (!(monster->m_flags & (WAKENS | WANDERS))) {
624 free_object(monster);
625 } else {
626 found = 1;
627 }
628 }
629 if (found) {
630 found = 0;
631 wake_up(monster);
632 for (i = 0; ((i < 25) && (!found)); i++) {
633 gr_row_col(&row, &col, (FLOOR | TUNNEL | STAIRS | OBJECT));
634 if (!rogue_can_see(row, col)) {
635 put_m_at(row, col, monster);
636 found = 1;
637 }
638 }
639 if (!found) {
640 free_object(monster);
641 }
642 }
643}
644
645show_monsters()
646{
647 object *monster;
648
649 detect_monster = 1;
650
651 if (blind) {
652 return;
653 }
654 monster = level_monsters.next_monster;
655
656 while (monster) {
657 mvaddch(monster->row, monster->col, monster->m_char);
658 if (monster->m_flags & IMITATES) {
659 monster->m_flags &= (~IMITATES);
660 monster->m_flags |= WAKENS;
661 }
662 monster = monster->next_monster;
663 }
664}
665
666create_monster()
667{
668 short row, col;
669 short i;
670 boolean found = 0;
671 object *monster;
672
673 row = rogue.row;
674 col = rogue.col;
675
676 for (i = 0; i < 9; i++) {
677 rand_around(i, &row, &col);
678 if (((row == rogue.row) && (col = rogue.col)) ||
679 (row < MIN_ROW) || (row > (DROWS-2)) ||
680 (col < 0) || (col > (DCOLS-1))) {
681 continue;
682 }
683 if ((!(dungeon[row][col] & MONSTER)) &&
684 (dungeon[row][col] & (FLOOR|TUNNEL|STAIRS|DOOR))) {
685 found = 1;
686 break;
687 }
688 }
689 if (found) {
690 monster = gr_monster((object *) 0, 0);
691 put_m_at(row, col, monster);
692 mvaddch(row, col, gmc(monster));
693 if (monster->m_flags & (WANDERS | WAKENS)) {
694 wake_up(monster);
695 }
696 } else {
697 message("you hear a faint cry of anguish in the distance", 0);
698 }
699}
700
701put_m_at(row, col, monster)
702short row, col;
703object *monster;
704{
705 monster->row = row;
706 monster->col = col;
707 dungeon[row][col] |= MONSTER;
708 monster->trail_char = mvinch(row, col);
709 (void) add_to_pack(monster, &level_monsters, 0);
710 aim_monster(monster);
711}
712
713aim_monster(monster)
714object *monster;
715{
716 short i, rn, d, r;
717
718 rn = get_room_number(monster->row, monster->col);
719 r = get_rand(0, 12);
720
721 for (i = 0; i < 4; i++) {
722 d = (r + i) % 4;
723 if (rooms[rn].doors[d].oth_room != NO_ROOM) {
724 monster->trow = rooms[rn].doors[d].door_row;
725 monster->tcol = rooms[rn].doors[d].door_col;
726 break;
727 }
728 }
729}
730
731rogue_can_see(row, col)
732int row, col;
733{
734 int retval;
735
736 retval = !blind &&
737 (((get_room_number(row, col) == cur_room) &&
738 !(rooms[cur_room].is_room & R_MAZE)) ||
739 rogue_is_around(row, col));
740
741 return(retval);
742}
743
744move_confused(monster)
745object *monster;
746{
747 short i, row, col;
748
749 if (!(monster->m_flags & ASLEEP)) {
750 if (--monster->moves_confused <= 0) {
751 monster->m_flags &= (~CONFUSED);
752 }
753 if (monster->m_flags & STATIONARY) {
754 return(coin_toss() ? 1 : 0);
755 } else if (rand_percent(15)) {
756 return(1);
757 }
758 row = monster->row;
759 col = monster->col;
760
761 for (i = 0; i < 9; i++) {
762 rand_around(i, &row, &col);
763 if ((row == rogue.row) && (col == rogue.col)) {
764 return(0);
765 }
766 if (mtry(monster, row, col)) {
767 return(1);
768 }
769 }
770 }
771 return(0);
772}
773
774flit(monster)
775object *monster;
776{
777 short i, row, col;
778
779 if (!rand_percent(FLIT_PERCENT + ((monster->m_flags & FLIES) ? 20 : 0))) {
780 return(0);
781 }
782 if (rand_percent(10)) {
783 return(1);
784 }
785 row = monster->row;
786 col = monster->col;
787
788 for (i = 0; i < 9; i++) {
789 rand_around(i, &row, &col);
790 if ((row == rogue.row) && (col == rogue.col)) {
791 continue;
792 }
793 if (mtry(monster, row, col)) {
794 return(1);
795 }
796 }
797 return(1);
798}
799
800gr_obj_char()
801{
802 short r;
803 const char *rs = "%!?]=/):*";
804
805 r = get_rand(0, 8);
806
807 return(rs[r]);
808}
809
810no_room_for_monster(rn)
811int rn;
812{
813 short i, j;
814
815 for (i = rooms[rn].top_row+1; i < rooms[rn].bottom_row; i++) {
816 for (j = rooms[rn].left_col+1; j < rooms[rn].right_col; j++) {
817 if (!(dungeon[i][j] & MONSTER)) {
818 return(0);
819 }
820 }
821 }
822 return(1);
823}
824
825aggravate()
826{
827 object *monster;
828
829 message("you hear a high pitched humming noise", 0);
830
831 monster = level_monsters.next_monster;
832
833 while (monster) {
834 wake_up(monster);
835 monster->m_flags &= (~IMITATES);
836 if (rogue_can_see(monster->row, monster->col)) {
837 mvaddch(monster->row, monster->col, monster->m_char);
838 }
839 monster = monster->next_monster;
840 }
841}
842
843boolean
844mon_sees(monster, row, col)
845const object *monster;
846int row, col;
847{
848 short rn, rdif, cdif, retval;
849
850 rn = get_room_number(row, col);
851
852 if ( (rn != NO_ROOM) &&
853 (rn == get_room_number(monster->row, monster->col)) &&
854 !(rooms[rn].is_room & R_MAZE)) {
855 return(1);
856 }
857 rdif = row - monster->row;
858 cdif = col - monster->col;
859
860 retval = (rdif >= -1) && (rdif <= 1) && (cdif >= -1) && (cdif <= 1);
861 return(retval);
862}
863
864mv_aquatars()
865{
866 object *monster;
867
868 monster = level_monsters.next_monster;
869
870 while (monster) {
871 if ((monster->m_char == 'A') &&
872 mon_can_go(monster, rogue.row, rogue.col)) {
873 mv_1_monster(monster, rogue.row, rogue.col);
874 monster->m_flags |= ALREADY_MOVED;
875 }
876 monster = monster->next_monster;
877 }
878}