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