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