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