ddb: Some minor adjustments.
[dragonfly.git] / games / rogue / monster.c
blobd8927d67c0b01fd0c8c756d3e37b0fe2788852f7
1 /*-
2 * Copyright (c) 1988, 1993
3 * The Regents of the University of California. All rights reserved.
5 * This code is derived from software contributed to Berkeley by
6 * Timothy C. Stoehr.
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. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
32 * @(#)monster.c 8.1 (Berkeley) 5/31/93
33 * $FreeBSD: src/games/rogue/monster.c,v 1.6 1999/11/30 03:49:24 billf Exp $
37 * monster.c
39 * This source herein may be modified and/or distributed by anybody who
40 * so desires, with the following restrictions:
41 * 1.) No portion of this notice shall be removed.
42 * 2.) Credit shall not be taken for the creation of this source.
43 * 3.) This code is not to be traded, sold, or used for personal
44 * gain or profit.
48 #include "rogue.h"
50 object level_monsters;
51 boolean mon_disappeared;
53 const char *const m_names[] = {
54 "aquator",
55 "bat",
56 "centaur",
57 "dragon",
58 "emu",
59 "venus fly-trap",
60 "griffin",
61 "hobgoblin",
62 "ice monster",
63 "jabberwock",
64 "kestrel",
65 "leprechaun",
66 "medusa",
67 "nymph",
68 "orc",
69 "phantom",
70 "quagga",
71 "rattlesnake",
72 "snake",
73 "troll",
74 "black unicorn",
75 "vampire",
76 "wraith",
77 "xeroc",
78 "yeti",
79 "zombie"
82 static object mon_tab[MONSTERS] = {
83 {(ASLEEP|WAKENS|WANDERS|RUSTS),"0d0",25,'A',20,9,18,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,NULL},
84 {(ASLEEP|WANDERS|FLITS|FLIES),"1d3",10,'B',2,1,8,60,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,NULL},
85 {(ASLEEP|WANDERS),"3d3/2d5",32,'C',15,7,16,85,0,10,0,0,0,0,0,0,0,0,0,0,0,0,0,NULL},
86 {(ASLEEP|WAKENS|FLAMES),"4d6/4d9",145,'D',5000,21,126,100,0,90,0,0,0,0,0,0,0,0,0,0,0,0,0,NULL},
87 {(ASLEEP|WAKENS),"1d3",11,'E',2,1,7,65,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,NULL},
88 {(HOLDS|STATIONARY),"5d5",73,'F',91,12,126,80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,NULL},
89 {(ASLEEP|WAKENS|WANDERS|FLIES),"5d5/5d5",115,'G',
90 2000,20,126,85,0,10,0,0,0,0,0,0,0,0,0,0,0,0,0,NULL},
91 {(ASLEEP|WAKENS|WANDERS),"1d3/1d2",15,'H',3,1,10,67,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,NULL},
92 {(ASLEEP|FREEZES),"0d0",15,'I',5,2,11,68,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,NULL},
93 {(ASLEEP|WANDERS),"3d10/4d5",132,'J',3000,21,126,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,NULL},
94 {(ASLEEP|WAKENS|WANDERS|FLIES),"1d4",10,'K',2,1,6,60,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,NULL},
95 {(ASLEEP|STEALS_GOLD),"0d0",25,'L',21,6,16,75,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,NULL},
96 {(ASLEEP|WAKENS|WANDERS|CONFUSES),"4d4/3d7",97,'M',
97 250,18,126,85,0,25,0,0,0,0,0,0,0,0,0,0,0,0,0,NULL},
98 {(ASLEEP|STEALS_ITEM),"0d0",25,'N',39,10,19,75,0,100,0,0,0,0,0,0,0,0,0,0,0,0,0,NULL},
99 {(ASLEEP|WANDERS|WAKENS|SEEKS_GOLD),"1d6",25,'O',5,4,13,70,0,10,0,0,0,0,0,0,0,0,0,0,0,0,0,NULL},
100 {(ASLEEP|INVISIBLE|WANDERS|FLITS),"5d4",76,'P',120,15,24,80,0,50,0,0,0,0,0,0,0,0,0,0,0,0,0,NULL},
101 {(ASLEEP|WAKENS|WANDERS),"3d5",30,'Q',20,8,17,78,0,20,0,0,0,0,0,0,0,0,0,0,0,0,0,NULL},
102 {(ASLEEP|WAKENS|WANDERS|STINGS),"2d5",19,'R',10,3,12,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,NULL},
103 {(ASLEEP|WAKENS|WANDERS),"1d3",8,'S',2,1,9,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,NULL},
104 {(ASLEEP|WAKENS|WANDERS),"4d6/1d4",75,'T',125,13,22,75,0,33,0,0,0,0,0,0,0,0,0,0,0,0,0,NULL},
105 {(ASLEEP|WAKENS|WANDERS),"4d10",90,'U',
106 200,17,26,85,0,33,0,0,0,0,0,0,0,0,0,0,0,0,0,NULL},
107 {(ASLEEP|WAKENS|WANDERS|DRAINS_LIFE),"1d14/1d4",55,'V',
108 350,19,126,85,0,18,0,0,0,0,0,0,0,0,0,0,0,0,0,NULL},
109 {(ASLEEP|WANDERS|DROPS_LEVEL),"2d8",45,'W',55,14,23,75,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,NULL},
110 {(ASLEEP|IMITATES),"4d6",42,'X',110,16,25,75,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,NULL},
111 {(ASLEEP|WANDERS),"3d6",35,'Y',50,11,20,80,0,20,0,0,0,0,0,0,0,0,0,0,0,0,0,NULL},
112 {(ASLEEP|WAKENS|WANDERS),"1d7",21,'Z',8,5,14,69,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,NULL}
115 static void aim_monster(object *);
116 static boolean flit(object *);
117 static boolean move_confused(object *);
118 static boolean mtry(object *, short, short);
119 static boolean no_room_for_monster(int);
120 static void put_m_at(short, short, object *);
121 static short rogue_is_around(int, int);
123 void
124 put_mons(void)
126 short i;
127 short n;
128 object *monster;
129 short row, col;
131 n = get_rand(4, 6);
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);
138 gr_row_col(&row, &col, (FLOOR | TUNNEL | STAIRS | OBJECT));
139 put_m_at(row, col, monster);
143 object *
144 gr_monster(object *monster, int mn)
146 if (!monster) {
147 monster = alloc_object();
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;
157 *monster = mon_tab[mn];
158 if (monster->m_flags & IMITATES) {
159 monster->disguise = gr_obj_char();
161 if (cur_level > (AMULET_LEVEL + 2)) {
162 monster->m_flags |= HASTED;
164 monster->trow = NO_ROOM;
165 return(monster);
168 void
169 mv_mons(void)
171 object *monster, *next_monster, *test_mons;
172 boolean flew;
174 if (haste_self % 2) {
175 return;
178 monster = level_monsters.next_monster;
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;
188 } else if (monster->m_flags & SLOWED) {
189 monster->slowed_toggle = !monster->slowed_toggle;
190 if (monster->slowed_toggle) {
191 goto NM;
194 if ((monster->m_flags & CONFUSED) && move_confused(monster)) {
195 goto NM;
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;
207 if (!(flew && mon_can_go(monster, rogue.row, rogue.col))) {
208 mv_1_monster(monster, rogue.row, rogue.col);
210 NM: test_mons = level_monsters.next_monster;
211 monster = NULL;
212 while (test_mons)
214 if (next_monster == test_mons)
216 monster = next_monster;
217 break;
219 test_mons = test_mons -> next_monster;
224 void
225 party_monsters(int rn, int n)
227 short i, j;
228 short row, col;
229 object *monster;
230 boolean found;
232 row = col = 0;
233 n += n;
235 for (i = 0; i < MONSTERS; i++) {
236 mon_tab[i].first_level -= (cur_level % 3);
238 for (i = 0; i < n; i++) {
239 if (no_room_for_monster(rn)) {
240 break;
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;
252 if (found) {
253 monster = gr_monster(NULL, 0);
254 if (!(monster->m_flags & IMITATES)) {
255 monster->m_flags |= WAKENS;
257 put_m_at(row, col, monster);
260 for (i = 0; i < MONSTERS; i++) {
261 mon_tab[i].first_level += (cur_level % 3);
265 short
266 gmc_row_col(int row, int col)
268 object *monster;
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);
275 if (monster->m_flags & IMITATES) {
276 return(monster->disguise);
278 return(monster->m_char);
279 } else {
280 return('&'); /* BUG if this ever happens */
284 short
285 gmc(object *monster)
287 if ((!(detect_monster || see_invisible || r_see_invisible) &&
288 (monster->m_flags & INVISIBLE))
289 || blind) {
290 return(monster->trail_char);
292 if (monster->m_flags & IMITATES) {
293 return(monster->disguise);
295 return(monster->m_char);
298 void
299 mv_1_monster(object *monster, short row, short col)
301 short i, n;
302 boolean tried[6];
304 if (monster->m_flags & ASLEEP) {
305 if (monster->m_flags & NAPPING) {
306 if (--monster->nap_length <= 0) {
307 monster->m_flags &= (~(NAPPING | ASLEEP));
309 return;
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);
318 return;
319 } else if (monster->m_flags & ALREADY_MOVED) {
320 monster->m_flags &= (~ALREADY_MOVED);
321 return;
323 if ((monster->m_flags & FLITS) && flit(monster)) {
324 return;
326 if ((monster->m_flags & STATIONARY) &&
327 (!mon_can_go(monster, rogue.row, rogue.col))) {
328 return;
330 if (monster->m_flags & FREEZING_ROGUE) {
331 return;
333 if ((monster->m_flags & CONFUSES) && m_confuse(monster)) {
334 return;
336 if (mon_can_go(monster, rogue.row, rogue.col)) {
337 mon_hit(monster);
338 return;
340 if ((monster->m_flags & FLAMES) && flame_broil(monster)) {
341 return;
343 if ((monster->m_flags & SEEKS_GOLD) && seek_gold(monster)) {
344 return;
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;
353 if (monster->row > row) {
354 row = monster->row - 1;
355 } else if (monster->row < row) {
356 row = monster->row + 1;
358 if ((dungeon[row][monster->col] & DOOR) &&
359 mtry(monster, row, monster->col)) {
360 return;
362 if (monster->col > col) {
363 col = monster->col - 1;
364 } else if (monster->col < col) {
365 col = monster->col + 1;
367 if ((dungeon[monster->row][col] & DOOR) &&
368 mtry(monster, monster->row, col)) {
369 return;
371 if (mtry(monster, row, col)) {
372 return;
375 for (i = 0; i <= 5; i++) tried[i] = 0;
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;
384 break;
385 case 1:
386 if (!tried[n] && mtry(monster, row, monster->col)) {
387 goto O;
389 break;
390 case 2:
391 if (!tried[n] && mtry(monster, row, monster->col+1)) {
392 goto O;
394 break;
395 case 3:
396 if (!tried[n] && mtry(monster, monster->row-1, col)) {
397 goto O;
399 break;
400 case 4:
401 if (!tried[n] && mtry(monster, monster->row, col)) {
402 goto O;
404 break;
405 case 5:
406 if (!tried[n] && mtry(monster, monster->row+1, col)) {
407 goto O;
409 break;
411 if (!tried[n]) {
412 tried[n] = 1;
413 } else {
414 goto NEXT_TRY;
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;
429 } else {
430 monster->o_row = monster->row;
431 monster->o_col = monster->col;
432 monster->o = 0;
436 static boolean
437 mtry(object *monster, short row, short col)
439 if (mon_can_go(monster, row, col)) {
440 move_mon_to(monster, row, col);
441 return(1);
443 return(0);
446 void
447 move_mon_to(object *monster, short row, short col)
449 short c;
450 int mrow, mcol;
452 mrow = monster->row;
453 mcol = monster->col;
455 dungeon[mrow][mcol] &= ~MONSTER;
456 dungeon[row][col] |= MONSTER;
458 c = mvinch(mrow, mcol);
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 = ' ';
470 mvaddch(mrow, mcol, monster->trail_char);
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));
481 if ((dungeon[row][col] & DOOR) &&
482 (get_room_number(row, col) != cur_room) &&
483 (dungeon[mrow][mcol] == FLOOR) && !blind) {
484 mvaddch(mrow, mcol, ' ');
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;
495 boolean
496 mon_can_go(const object *monster, short row, short col)
498 object *obj;
499 short dr, dc;
501 dr = monster->row - row; /* check if move distance > 1 */
502 if ((dr >= 2) || (dr <= -2)) {
503 return(0);
505 dc = monster->col - col;
506 if ((dc >= 2) || (dc <= -2)) {
507 return(0);
509 if ((!dungeon[monster->row][col]) || (!dungeon[row][monster->col])) {
510 return(0);
512 if ((!is_passable(row, col)) || (dungeon[row][col] & MONSTER)) {
513 return(0);
515 if ((monster->row!=row)&&(monster->col!=col)&&((dungeon[row][col]&DOOR) ||
516 (dungeon[monster->row][monster->col]&DOOR))) {
517 return(0);
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);
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);
532 return(1);
535 void
536 wake_up(object *monster)
538 if (!(monster->m_flags & NAPPING)) {
539 monster->m_flags &= (~(ASLEEP | IMITATES | WAKENS));
543 void
544 wake_room(short rn, boolean entering, short row, short col)
546 object *monster;
547 short wake_percent;
548 boolean in_room;
550 wake_percent = (rn == party_room) ? PARTY_WAKE_PERCENT : WAKE_PERCENT;
551 if (stealthy > 0) {
552 wake_percent /= (STEALTH_FACTOR + stealthy);
555 monster = level_monsters.next_monster;
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;
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);
573 monster = monster->next_monster;
577 const char *
578 mon_name(const object *monster)
580 short ch;
582 if (blind || ((monster->m_flags & INVISIBLE) &&
583 !(detect_monster || see_invisible || r_see_invisible))) {
584 return("something");
586 if (halluc) {
587 ch = get_rand('A', 'Z') - 'A';
588 return(m_names[ch]);
590 ch = monster->m_char - 'A';
591 return(m_names[ch]);
594 static short
595 rogue_is_around(int row, int col)
597 short rdif, cdif, retval;
599 rdif = row - rogue.row;
600 cdif = col - rogue.col;
602 retval = (rdif >= -1) && (rdif <= 1) && (cdif >= -1) && (cdif <= 1);
603 return(retval);
606 void
607 wanderer(void)
609 object *monster;
610 short row, col, i;
611 boolean found = 0;
613 for (i = 0; ((i < 15) && (!found)); i++) {
614 monster = gr_monster(NULL, 0);
615 if (!(monster->m_flags & (WAKENS | WANDERS))) {
616 free_object(monster);
617 } else {
618 found = 1;
621 if (found) {
622 found = 0;
623 wake_up(monster);
624 for (i = 0; ((i < 25) && (!found)); i++) {
625 gr_row_col(&row, &col, (FLOOR | TUNNEL | STAIRS | OBJECT));
626 if (!rogue_can_see(row, col)) {
627 put_m_at(row, col, monster);
628 found = 1;
631 if (!found) {
632 free_object(monster);
637 void
638 show_monsters(void)
640 object *monster;
642 detect_monster = 1;
644 if (blind) {
645 return;
647 monster = level_monsters.next_monster;
649 while (monster) {
650 mvaddch(monster->row, monster->col, monster->m_char);
651 if (monster->m_flags & IMITATES) {
652 monster->m_flags &= (~IMITATES);
653 monster->m_flags |= WAKENS;
655 monster = monster->next_monster;
659 void
660 create_monster(void)
662 short row, col;
663 short i;
664 boolean found = 0;
665 object *monster;
667 row = rogue.row;
668 col = rogue.col;
670 for (i = 0; i < 9; i++) {
671 rand_around(i, &row, &col);
672 if (((row == rogue.row) && (col == rogue.col)) ||
673 (row < MIN_ROW) || (row > (DROWS-2)) ||
674 (col < 0) || (col > (DCOLS-1))) {
675 continue;
677 if ((!(dungeon[row][col] & MONSTER)) &&
678 (dungeon[row][col] & (FLOOR|TUNNEL|STAIRS|DOOR))) {
679 found = 1;
680 break;
683 if (found) {
684 monster = gr_monster(NULL, 0);
685 put_m_at(row, col, monster);
686 mvaddch(row, col, gmc(monster));
687 if (monster->m_flags & (WANDERS | WAKENS)) {
688 wake_up(monster);
690 } else {
691 message("you hear a faint cry of anguish in the distance", 0);
695 static void
696 put_m_at(short row, short col, object *monster)
698 monster->row = row;
699 monster->col = col;
700 dungeon[row][col] |= MONSTER;
701 monster->trail_char = mvinch(row, col);
702 add_to_pack(monster, &level_monsters, 0);
703 aim_monster(monster);
706 static void
707 aim_monster(object *monster)
709 short i, rn, d, r;
711 rn = get_room_number(monster->row, monster->col);
712 if (rn == NO_ROOM)
713 clean_up("aim_monster: monster not in room");
714 r = get_rand(0, 12);
716 for (i = 0; i < 4; i++) {
717 d = (r + i) % 4;
718 if (rooms[rn].doors[d].oth_room != NO_ROOM) {
719 monster->trow = rooms[rn].doors[d].door_row;
720 monster->tcol = rooms[rn].doors[d].door_col;
721 break;
727 rogue_can_see(int row, int col)
729 int retval;
731 retval = !blind &&
732 (((get_room_number(row, col) == cur_room) &&
733 !(rooms[cur_room].is_room & R_MAZE)) ||
734 rogue_is_around(row, col));
736 return(retval);
739 static boolean
740 move_confused(object *monster)
742 short i, row, col;
744 if (!(monster->m_flags & ASLEEP)) {
745 if (--monster->moves_confused <= 0) {
746 monster->m_flags &= (~CONFUSED);
748 if (monster->m_flags & STATIONARY) {
749 return(coin_toss() ? 1 : 0);
750 } else if (rand_percent(15)) {
751 return(1);
753 row = monster->row;
754 col = monster->col;
756 for (i = 0; i < 9; i++) {
757 rand_around(i, &row, &col);
758 if ((row == rogue.row) && (col == rogue.col)) {
759 return(0);
761 if (mtry(monster, row, col)) {
762 return(1);
766 return(0);
769 static boolean
770 flit(object *monster)
772 short i, row, col;
774 if (!rand_percent(FLIT_PERCENT + ((monster->m_flags & FLIES) ? 20 : 0))) {
775 return(0);
777 if (rand_percent(10)) {
778 return(1);
780 row = monster->row;
781 col = monster->col;
783 for (i = 0; i < 9; i++) {
784 rand_around(i, &row, &col);
785 if ((row == rogue.row) && (col == rogue.col)) {
786 continue;
788 if (mtry(monster, row, col)) {
789 return(1);
792 return(1);
795 char
796 gr_obj_char(void)
798 short r;
799 const char *rs = "%!?]=/):*";
801 r = get_rand(0, 8);
803 return(rs[r]);
806 static boolean
807 no_room_for_monster(int rn)
809 short i, j;
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);
818 return(1);
821 void
822 aggravate(void)
824 object *monster;
826 message("you hear a high pitched humming noise", 0);
828 monster = level_monsters.next_monster;
830 while (monster) {
831 wake_up(monster);
832 monster->m_flags &= (~IMITATES);
833 if (rogue_can_see(monster->row, monster->col)) {
834 mvaddch(monster->row, monster->col, monster->m_char);
836 monster = monster->next_monster;
840 boolean
841 mon_sees(const object *monster, int row, int col)
843 short rn, rdif, cdif, retval;
845 rn = get_room_number(row, col);
847 if ( (rn != NO_ROOM) &&
848 (rn == get_room_number(monster->row, monster->col)) &&
849 !(rooms[rn].is_room & R_MAZE)) {
850 return(1);
852 rdif = row - monster->row;
853 cdif = col - monster->col;
855 retval = (rdif >= -1) && (rdif <= 1) && (cdif >= -1) && (cdif <= 1);
856 return(retval);
859 void
860 mv_aquatars(void)
862 object *monster;
864 monster = level_monsters.next_monster;
866 while (monster) {
867 if ((monster->m_char == 'A') &&
868 mon_can_go(monster, rogue.row, rogue.col)) {
869 mv_1_monster(monster, rogue.row, rogue.col);
870 monster->m_flags |= ALREADY_MOVED;
872 monster = monster->next_monster;