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