1 /* 2 * All sorts of miscellaneous routines 3 * 4 * misc.c 1.4 (A.I. Design) 12/14/84 5 */ 6 7 #include "rogue.h" 8 #include "curses.h" 9 10 /* 11 * tr_name: 12 * Print the name of a trap 13 */ 14 char * 15 tr_name(type) 16 byte type; 17 { 18 switch (type) 19 { 20 case T_DOOR: 21 return "a trapdoor"; 22 case T_BEAR: 23 return "a beartrap"; 24 case T_SLEEP: 25 return "a sleeping gas trap"; 26 case T_ARROW: 27 return "an arrow trap"; 28 case T_TELEP: 29 return "a teleport trap"; 30 case T_DART: 31 return "a poison dart trap"; 32 } 33 msg("wierd trap: %d", type); 34 return NULL; 35 } 36 37 /* 38 * look: 39 * A quick glance all around the player 40 */ 41 look(wakeup) 42 bool wakeup; 43 { 44 register int x, y; 45 register byte ch, pch; 46 register int index; 47 register THING *tp; 48 register struct room *rp; 49 register int ey, ex; 50 register int passcount = 0; 51 register byte pfl, *fp; 52 register int sy, sx, sumhero, diffhero; 53 54 rp = proom; 55 index = INDEX(hero.y, hero.x); 56 pfl = _flags[index]; 57 pch = _level[index]; 58 /* 59 * if the hero has moved 60 */ 61 if (!ce(oldpos, hero)) { 62 if (!on(player,ISBLIND)) { 63 for (x = oldpos.x - 1; x <= (oldpos.x + 1); x++) 64 for (y = oldpos.y - 1; y <= (oldpos.y + 1); y++) { 65 if ((y == hero.y && x == hero.x) || offmap(y,x)) 66 continue; 67 move(y,x); 68 ch = inch(); 69 if (ch == FLOOR) { 70 if ((oldrp->r_flags & (ISGONE|ISDARK)) == ISDARK) 71 addch(' '); 72 } else { 73 fp = &_flags[INDEX(y,x)]; 74 /* 75 * if the maze or passage (that the hero is in!!) 76 * needs to be redrawn (passages once draw always 77 * stay on) do it now. 78 */ 79 if (((*fp&F_MAZE) || (*fp&F_PASS)) && (ch!=PASSAGE) 80 && (ch != STAIRS) && 81 ((*fp & F_PNUM) == (pfl & F_PNUM)) ) 82 addch(PASSAGE); 83 } 84 } 85 } 86 oldpos = hero; 87 oldrp = rp; 88 } 89 ey = hero.y + 1; 90 ex = hero.x + 1; 91 sx = hero.x - 1; 92 sy = hero.y - 1; 93 if (door_stop && !firstmove && running) { 94 sumhero = hero.y + hero.x; 95 diffhero = hero.y - hero.x; 96 } 97 for (y = sy; y <= ey; y++) 98 if (y > 0 && y < maxrow) for (x = sx; x <= ex; x++) { 99 if (x <= 0 || x >= COLS) 100 continue; 101 if (!on(player, ISBLIND)) { 102 if (y == hero.y && x == hero.x) 103 continue; 104 } else if (y != hero.y || x != hero.x) 105 continue; 106 107 index = INDEX(y, x); 108 /* 109 * THIS REPLICATES THE moat() MACRO. IF MOAT IS CHANGED, 110 * THIS MUST BE CHANGED ALSO ?? What does this really mean ?? 111 */ 112 fp = &_flags[index]; 113 ch = _level[index]; 114 /* 115 * No Doors 116 */ 117 if (pch != DOOR && ch != DOOR) 118 /* 119 * Either hero or other in a passage 120 */ 121 if ((pfl & F_PASS) != (*fp & F_PASS)) { 122 /* 123 * Neither is in a maze 124 */ 125 if ( ! (pfl & F_MAZE) && ! (*fp & F_MAZE)) 126 continue; 127 } 128 /* 129 * Not in same passage 130 */ 131 else if ((*fp & F_PASS) && (*fp & F_PNUM) != (pfl & F_PNUM)) 132 continue; 133 134 if ((tp = moat(y,x)) != NULL) 135 if (on(player, SEEMONST) && on(*tp, ISINVIS)) { 136 if (door_stop && !firstmove) 137 running = FALSE; 138 continue; 139 } else { 140 if (wakeup) 141 wake_monster(y, x); 142 if (tp->t_oldch != ' ' || 143 (!(rp->r_flags & ISDARK) && !on(player, ISBLIND))) 144 tp->t_oldch = _level[index]; 145 if (see_monst(tp)) 146 ch = tp->t_disguise; 147 } 148 149 if ((ch!=PASSAGE) && (*fp & (F_PASS | F_MAZE))) 150 /* 151 * The current character used for IBM ARMOR doesn't 152 * look right in Inverse 153 */ 154 if (ch != ARMOR) 155 standout(); 156 157 move(y, x); 158 addch(ch); 159 standend(); 160 161 if (door_stop && !firstmove && running) { 162 switch (runch) { 163 when 'h': 164 if (x == ex) 165 continue; 166 when 'j': 167 if (y == sy) 168 continue; 169 when 'k': 170 if (y == ey) 171 continue; 172 when 'l': 173 if (x == sx) 174 continue; 175 when 'y': 176 if ((y + x) - sumhero >= 1) 177 continue; 178 when 'u': 179 if ((y - x) - diffhero >= 1) 180 continue; 181 when 'n': 182 if ((y + x) - sumhero <= -1) 183 continue; 184 when 'b': 185 if ((y - x) - diffhero <= -1) 186 continue; 187 } 188 switch (ch) { 189 case DOOR: 190 if (x == hero.x || y == hero.y) 191 running = FALSE; 192 break; 193 case PASSAGE: 194 if (x == hero.x || y == hero.y) 195 passcount++; 196 break; 197 case FLOOR: 198 case VWALL: 199 case HWALL: 200 case ULWALL: 201 case URWALL: 202 case LLWALL: 203 case LRWALL: 204 case ' ': 205 break; 206 default: 207 running = FALSE; 208 break; 209 } 210 } 211 } 212 if (door_stop && !firstmove && passcount > 1) 213 running = FALSE; 214 move(hero.y, hero.x); 215 if ((flat(hero.y,hero.x) & F_PASS) || (was_trapped > TRUE) 216 || (flat(hero.y,hero.x) & F_MAZE)) 217 standout(); 218 addch(PLAYER); 219 standend(); 220 if (was_trapped) { 221 beep(); 222 was_trapped = FALSE; 223 } 224 } 225 226 /* 227 * find_obj: 228 * Find the unclaimed object at y, x 229 */ 230 THING * 231 find_obj(y, x) 232 register int y, x; 233 { 234 register THING *op; 235 236 for (op = lvl_obj; op != NULL; op = next(op)) 237 if (op->o_pos.y == y && op->o_pos.x == x) 238 return op; 239 #ifdef DEBUG 240 debug(sprintf(prbuf, "Non-object %c %d,%d", chat(y, x), y, x)); 241 return NULL; 242 #else 243 /* NOTREACHED */ 244 #endif 245 } 246 247 /* 248 * eat: 249 * She wants to eat something, so let her try 250 */ 251 eat() 252 { 253 register THING *obj; 254 255 if ((obj = get_item("eat", FOOD)) == NULL) 256 return; 257 if (obj->o_type != FOOD) 258 { 259 msg("ugh, you would get ill if you ate that"); 260 return; 261 } 262 inpack--; 263 if (--obj->o_count < 1) 264 { 265 detach(pack, obj); 266 discard(obj); 267 } 268 if (food_left < 0) 269 food_left = 0; 270 if (food_left > (STOMACHSIZE - 20)) 271 no_command += 2 + rnd(5); 272 if ((food_left += HUNGERTIME - 200 + rnd(400)) > STOMACHSIZE) 273 food_left = STOMACHSIZE; 274 hungry_state = 0; 275 if (obj == cur_weapon) 276 cur_weapon = NULL; 277 if (obj->o_which == 1) 278 msg("my, that was a yummy %s", fruit); 279 else 280 if (rnd(100) > 70) 281 { 282 pstats.s_exp++; 283 msg("yuk, this food tastes awful"); 284 check_level(); 285 } 286 else 287 msg("yum, that tasted good"); 288 if (no_command) 289 msg("You feel bloated and fall asleep"); 290 } 291 292 /* 293 * chg_str: 294 * Used to modify the player's strength. It keeps track of the 295 * highest it has been, just in case 296 */ 297 chg_str(amt) 298 register int amt; 299 { 300 str_t comp; 301 302 if (amt == 0) 303 return; 304 add_str(&pstats.s_str, amt); 305 comp = pstats.s_str; 306 if (ISRING(LEFT, R_ADDSTR)) 307 add_str(&comp, -cur_ring[LEFT]->o_ac); 308 if (ISRING(RIGHT, R_ADDSTR)) 309 add_str(&comp, -cur_ring[RIGHT]->o_ac); 310 if (comp > max_stats.s_str) 311 max_stats.s_str = comp; 312 } 313 314 /* 315 * add_str: 316 * Perform the actual add, checking upper and lower bound 317 */ 318 add_str(sp, amt) 319 register str_t *sp; 320 int amt; 321 { 322 if ((*sp += amt) < 3) 323 *sp = 3; 324 else if (*sp > 31) 325 *sp = 31; 326 } 327 328 /* 329 * add_haste: 330 * Add a haste to the player 331 */ 332 add_haste(potion) 333 bool potion; 334 { 335 if (on(player, ISHASTE)) 336 { 337 no_command += rnd(8); 338 player.t_flags &= ~ISRUN; 339 extinguish(nohaste); 340 player.t_flags &= ~ISHASTE; 341 msg("you faint from exhaustion"); 342 return FALSE; 343 } 344 else 345 { 346 player.t_flags |= ISHASTE; 347 if (potion) 348 fuse(nohaste, 0, rnd(4)+10); 349 return TRUE; 350 } 351 } 352 353 /* 354 * aggravate: 355 * Aggravate all the monsters on this level 356 */ 357 aggravate() 358 { 359 register THING *mi; 360 361 for (mi = mlist; mi != NULL; mi = next(mi)) 362 start_run(&mi->t_pos); 363 } 364 365 /* 366 * vowelstr: 367 * For printfs: if string starts with a vowel, return "n" for an 368 * "an". 369 */ 370 char * 371 vowelstr(str) 372 register char *str; 373 { 374 switch (*str) 375 { 376 case 'a': case 'A': 377 case 'e': case 'E': 378 case 'i': case 'I': 379 case 'o': case 'O': 380 case 'u': case 'U': 381 return "n"; 382 default: 383 return ""; 384 } 385 } 386 387 /* 388 * is_current: 389 * See if the object is one of the currently used items 390 */ 391 is_current(obj) 392 register THING *obj; 393 { 394 if (obj == NULL) 395 return FALSE; 396 if (obj == cur_armor || obj == cur_weapon || obj == cur_ring[LEFT] 397 || obj == cur_ring[RIGHT]) { 398 msg("That's already in use"); 399 return TRUE; 400 } 401 return FALSE; 402 } 403 404 /* 405 * get_dir: 406 * Set up the direction co_ordinate for use in varios "prefix" 407 * commands 408 */ 409 get_dir() 410 { 411 register char *prompt; 412 bool gotit; 413 register int ch; 414 415 if (again) 416 return TRUE; 417 msg("which direction? "); 418 do 419 if ((ch = readchar()) == ESCAPE) { 420 msg(""); 421 return FALSE; 422 } 423 while (find_dir(ch, &delta) == 0); 424 msg(""); 425 if (on(player, ISHUH) && rnd(5) == 0) 426 do { 427 delta.y = rnd(3) - 1; 428 delta.x = rnd(3) - 1; 429 } while (delta.y == 0 && delta.x == 0); 430 return TRUE; 431 } 432 433 find_dir(ch, cp) 434 byte ch; 435 coord *cp; 436 { 437 bool gotit; 438 439 gotit = TRUE; 440 switch (ch) { 441 when 'h': case'H': cp->y = 0; cp->x = -1; 442 when 'j': case'J': cp->y = 1; cp->x = 0; 443 when 'k': case'K': cp->y = -1; cp->x = 0; 444 when 'l': case'L': cp->y = 0; cp->x = 1; 445 when 'y': case'Y': cp->y = -1; cp->x = -1; 446 when 'u': case'U': cp->y = -1; cp->x = 1; 447 when 'b': case'B': cp->y = 1; cp->x = -1; 448 when 'n': case'N': cp->y = 1; cp->x = 1; 449 otherwise: gotit = FALSE; 450 } 451 return gotit; 452 } 453 454 /* 455 * sign: 456 * Return the sign of the number 457 */ 458 sign(nm) 459 register int nm; 460 { 461 if (nm < 0) 462 return -1; 463 else 464 return (nm > 0); 465 } 466 467 /* 468 * spread: 469 * Give a spread around a given number (+/- 10%) 470 */ 471 spread(nm) 472 register int nm; 473 { 474 register int r = nm - nm / 10 + rnd(nm / 5); 475 return r; 476 } 477 478 /* 479 * call_it: 480 * Call an object something after use. 481 */ 482 call_it(know, guess) 483 register bool know; 484 register char **guess; 485 { 486 if (know && **guess) 487 **guess = NULL; 488 else if (!know && **guess == NULL) { 489 msg("%scall it? ",noterse("what do you want to ")); 490 getinfo(prbuf,MAXNAME); 491 if (*prbuf != ESCAPE) 492 strcpy(*guess, prbuf); 493 msg(""); 494 } 495 } 496 497 /* 498 * step_ok: 499 * Returns true if it is ok to step on ch 500 */ 501 step_ok(ch) 502 { 503 switch (ch) 504 { 505 case ' ': 506 case VWALL: 507 case HWALL: 508 case ULWALL: 509 case URWALL: 510 case LLWALL: 511 case LRWALL: 512 return FALSE; 513 default: 514 return ((ch < 'A') || (ch > 'Z')); 515 } 516 } 517 518 /* 519 * goodch: 520 * Decide how good an object is and return the correct character for 521 * printing. 522 */ 523 524 goodch(obj) 525 register THING *obj; 526 { 527 register int ch = MAGIC; 528 529 if (obj->o_flags & ISCURSED) 530 ch = BMAGIC; 531 switch (obj->o_type) { 532 when ARMOR: 533 if (obj->o_ac > a_class[obj->o_which]) 534 ch = BMAGIC; 535 when WEAPON: 536 if (obj->o_hplus < 0 || obj->o_dplus < 0) 537 ch = BMAGIC; 538 when SCROLL: 539 switch (obj->o_which) { 540 when S_SLEEP: 541 case S_CREATE: 542 case S_AGGR: 543 ch = BMAGIC; 544 } 545 when POTION: 546 switch (obj->o_which) { 547 when P_CONFUSE: 548 case P_PARALYZE: 549 case P_POISON: 550 case P_BLIND: 551 ch = BMAGIC; 552 } 553 when STICK: 554 switch (obj->o_which) { 555 when WS_HASTE_M: 556 case WS_TELTO: 557 ch = BMAGIC; 558 } 559 when RING: 560 switch (obj->o_which) { 561 when R_PROTECT: 562 case R_ADDSTR: 563 case R_ADDDAM: 564 case R_ADDHIT: 565 if (obj->o_ac < 0) 566 ch = BMAGIC; 567 when R_AGGR: 568 case R_TELEPORT: 569 ch = BMAGIC; 570 } 571 } 572 return ch; 573 } 574 575 /* 576 * help: prints out help screens 577 */ 578 help(helpscr) 579 char **helpscr; 580 { 581 #ifdef HELP 582 register int hcount = 0; 583 register int hrow, hcol; 584 int isfull; 585 byte answer; 586 587 wdump(); 588 while (*helpscr && answer != ESCAPE) 589 { 590 isfull = FALSE; 591 if ((hcount % (terse?23:46)) == 0) 592 clear(); 593 /* 594 * determine row and column 595 */ 596 hcol = 0; 597 if (terse) 598 { 599 hrow = hcount % 23; 600 if (hrow == 22) 601 isfull = TRUE; 602 } 603 else 604 { 605 hrow = (hcount % 46) / 2; 606 if (hcount % 2) 607 hcol = 40; 608 if (hrow == 22 && hcol == 40) 609 isfull = TRUE; 610 } 611 612 move (hrow,hcol); 613 614 addstr(*helpscr++); 615 616 /* 617 * decide if we need print a continue type message 618 */ 619 if ( (*helpscr == 0) || isfull) 620 { 621 if (*helpscr == 0) 622 mvaddstr (24,0,"--press space to continue--"); 623 else if (terse) 624 mvaddstr (24,0,"--Space for more, Esc to continue--"); 625 else 626 mvaddstr (24,0,"--Press space for more, Esc to continue--"); 627 do 628 answer = readchar(); 629 while (answer != ' ' && answer != ESCAPE) ; 630 } 631 hcount++; 632 } 633 wrestor(); 634 #endif HELP 635 } 636 637 #ifndef UNIX 638 639 DISTANCE(y1, x1, y2, x2) 640 int y1, x1, y2, x2; 641 { 642 register int dx, dy; 643 644 dx = (x1 - x2); 645 dy = (y1 - y2); 646 return dx * dx + dy * dy; 647 } 648 649 _ce(a,b) 650 coord *a, *b; 651 { 652 return(a->x == b->x && a->y == b->y); 653 } 654 655 INDEX(y,x) 656 { 657 #ifdef DEBUG 658 if (offmap(y,x) && me()) 659 fatal("BAD INDEX"); 660 #endif DEBUG 661 return((x * (maxrow-1)) + y - 1); 662 } 663 664 offmap(y,x) 665 { 666 return (y < 1 || y >= maxrow || x < 0 || x >= COLS) ; 667 } 668 669 winat(y,x) 670 int y, x; 671 { 672 return(moat(y,x) != NULL ? moat(y,x)->t_disguise : chat(y,x)); 673 } 674 #endif 675 676 /* 677 * search: 678 * Player gropes about him to find hidden things. 679 */ 680 search() 681 { 682 register int y, x; 683 register byte *fp; 684 register int ey, ex; 685 686 if (on(player, ISBLIND)) 687 return; 688 ey = hero.y + 1; 689 ex = hero.x + 1; 690 for (y = hero.y - 1; y <= ey; y++) 691 for (x = hero.x - 1; x <= ex; x++) 692 { 693 if ((y == hero.y && x == hero.x) || offmap(y, x)) 694 continue; 695 fp = &flat(y, x); 696 if (!(*fp & F_REAL)) 697 switch (chat(y, x)) 698 { 699 case VWALL: 700 case HWALL: 701 case ULWALL: 702 case URWALL: 703 case LLWALL: 704 case LRWALL: 705 if (rnd(5) != 0) 706 break; 707 chat(y, x) = DOOR; 708 *fp |= F_REAL; 709 count = running = FALSE; 710 break; 711 case FLOOR: 712 if (rnd(2) != 0) 713 break; 714 chat(y, x) = TRAP; 715 *fp |= F_REAL; 716 count = running = FALSE; 717 msg("you found %s", tr_name(*fp & F_TMASK)); 718 break; 719 } 720 } 721 } 722 723 724 /* 725 * d_level: 726 * He wants to go down a level 727 */ 728 d_level() 729 { 730 if (chat(hero.y, hero.x) != STAIRS) 731 msg("I see no way down"); 732 else { 733 level++; 734 new_level(); 735 } 736 } 737 738 /* 739 * u_level: 740 * He wants to go up a level 741 */ 742 u_level() 743 { 744 if (chat(hero.y, hero.x) == STAIRS) 745 if (amulet) { 746 level--; 747 if (level == 0) 748 total_winner(); 749 new_level(); 750 msg("you feel a wrenching sensation in your gut"); 751 } else 752 msg("your way is magically blocked"); 753 else 754 msg("I see no way up"); 755 } 756 757 /* 758 * call: 759 * Allow a user to call a potion, scroll, or ring something 760 */ 761 call() 762 { 763 register THING *obj; 764 register char **guess, *elsewise; 765 register bool *know; 766 767 obj = get_item("call", CALLABLE); 768 /* 769 * Make certain that it is somethings that we want to wear 770 */ 771 if (obj == NULL) 772 return; 773 switch (obj->o_type) 774 { 775 when RING: 776 guess = (char **)r_guess; 777 know = r_know; 778 elsewise = (*guess[obj->o_which] != NULL ? 779 guess[obj->o_which] : r_stones[obj->o_which]); 780 when POTION: 781 guess = (char **)p_guess; 782 know = p_know; 783 elsewise = (*guess[obj->o_which] != NULL ? 784 guess[obj->o_which] : p_colors[obj->o_which]); 785 when SCROLL: 786 guess = (char **)s_guess; 787 know = s_know; 788 elsewise = (*guess[obj->o_which] != NULL ? 789 guess[obj->o_which] : (char *)(&s_names[obj->o_which])); 790 when STICK: 791 guess = (char **)ws_guess; 792 know = ws_know; 793 elsewise = (*guess[obj->o_which] != NULL ? 794 guess[obj->o_which] : ws_made[obj->o_which]); 795 otherwise: 796 msg("you can't call that anything"); 797 return; 798 } 799 if (know[obj->o_which]) 800 { 801 msg("that has already been identified"); 802 return; 803 } 804 msg("Was called \"%s\"", elsewise); 805 msg("what do you want to call it? "); 806 getinfo(prbuf,MAXNAME); 807 if (*prbuf && *prbuf != ESCAPE) 808 strcpy(guess[obj->o_which], prbuf); 809 msg(""); 810 } 811 812 /* 813 * prompt player for definition of macro 814 */ 815 do_macro(buf,sz) 816 char *buf; 817 int sz; 818 { 819 register char *cp = prbuf; 820 821 msg("F9 was %s, enter new macro: ",buf); 822 if (getinfo(prbuf,sz-1) != ESCAPE) 823 do { 824 if (*cp != CTRL(F)) 825 *buf++ = *cp; 826 } while (*cp++) ; 827 msg(""); 828 flush_type(); 829 } 830 831 #ifdef ME 832 me() 833 { 834 return is_me; 835 } 836 #endif ME 837 838 839 #ifdef TEST 840 istest() 841 { 842 return (!strcmp("debug",fruit)); 843 } 844 #endif TEST 845 ÿ