1 /* $NetBSD: global.c,v 1.15 2021/05/02 12:50:45 rillig Exp $ */ 2 3 /* 4 * global.c Larn is copyrighted 1986 by Noah Morgan. 5 * 6 * raiselevel() subroutine to raise the player one level 7 * loselevel() subroutine to lower the player by one level 8 * raiseexperience(x) subroutine to increase experience points 9 * loseexperience(x) subroutine to lose experience points 10 * losehp(x) subroutine to remove hit points from the player 11 * losemhp(x) subroutine to remove max # hit points from the player 12 * raisehp(x) subroutine to gain hit points 13 * raisemhp(x) subroutine to gain maximum hit points 14 * losemspells(x) subroutine to lose maximum spells 15 * raisemspells(x) subroutine to gain maximum spells 16 * makemonst(lev) function to return monster number for a randomly 17 * selected monster 18 * positionplayer() function to be sure player is not in a wall 19 * recalc() function to recalculate the armor class of the player 20 * quit() subroutine to ask if the player really wants to quit 21 */ 22 #include <sys/cdefs.h> 23 #ifndef lint 24 __RCSID("$NetBSD: global.c,v 1.15 2021/05/02 12:50:45 rillig Exp $"); 25 #endif /* not lint */ 26 27 #include <string.h> 28 #include <unistd.h> 29 #include "header.h" 30 #include "extern.h" 31 extern int score[], dropflag; 32 extern char *what[], *who[]; 33 extern char winner[]; 34 extern char sciv[SCORESIZE + 1][26][2]; 35 extern const char *password; 36 37 /* 38 raiselevel() 39 40 subroutine to raise the player one level 41 uses the skill[] array to find level boundarys 42 uses c[EXPERIENCE] c[LEVEL] 43 */ 44 void 45 raiselevel(void) 46 { 47 if (c[LEVEL] < MAXPLEVEL) 48 raiseexperience((long) (skill[c[LEVEL]] - c[EXPERIENCE])); 49 } 50 51 /* 52 loselevel() 53 54 subroutine to lower the players character level by one 55 */ 56 void 57 loselevel(void) 58 { 59 if (c[LEVEL] > 1) 60 loseexperience((long) (c[EXPERIENCE] - skill[c[LEVEL] - 1] + 1)); 61 } 62 63 /* 64 raiseexperience(x) 65 66 subroutine to increase experience points 67 */ 68 void 69 raiseexperience(long x) 70 { 71 int i, tmp; 72 i = c[LEVEL]; 73 c[EXPERIENCE] += x; 74 while (c[EXPERIENCE] >= skill[c[LEVEL]] && (c[LEVEL] < MAXPLEVEL)) { 75 tmp = (c[CONSTITUTION] - c[HARDGAME]) >> 1; 76 c[LEVEL]++; 77 raisemhp((int) (rnd(3) + rnd((tmp > 0) ? tmp : 1))); 78 raisemspells((int) rund(3)); 79 if (c[LEVEL] < 7 - c[HARDGAME]) 80 raisemhp((int) (c[CONSTITUTION] >> 2)); 81 } 82 if (c[LEVEL] != i) { 83 cursors(); 84 beep(); 85 lprintf("\nWelcome to level %ld", (long) c[LEVEL]); /* if we changed levels */ 86 } 87 bottomline(); 88 } 89 90 /* 91 loseexperience(x) 92 93 subroutine to lose experience points 94 */ 95 void 96 loseexperience(long x) 97 { 98 int i, tmp; 99 i = c[LEVEL]; 100 c[EXPERIENCE] -= x; 101 if (c[EXPERIENCE] < 0) 102 c[EXPERIENCE] = 0; 103 while (c[EXPERIENCE] < skill[c[LEVEL] - 1]) { 104 if (--c[LEVEL] <= 1) 105 c[LEVEL] = 1; /* down one level */ 106 tmp = (c[CONSTITUTION] - c[HARDGAME]) >> 1; /* lose hpoints */ 107 losemhp((int) rnd((tmp > 0) ? tmp : 1)); /* lose hpoints */ 108 if (c[LEVEL] < 7 - c[HARDGAME]) 109 losemhp((int) (c[CONSTITUTION] >> 2)); 110 losemspells((int) rund(3)); /* lose spells */ 111 } 112 if (i != c[LEVEL]) { 113 cursors(); 114 beep(); 115 lprintf("\nYou went down to level %ld!", (long) c[LEVEL]); 116 } 117 bottomline(); 118 } 119 120 /* 121 losehp(x) 122 losemhp(x) 123 124 subroutine to remove hit points from the player 125 warning -- will kill player if hp goes to zero 126 */ 127 void 128 losehp(int x) 129 { 130 if ((c[HP] -= x) <= 0) { 131 beep(); 132 lprcat("\n"); 133 nap(3000); 134 died(lastnum); 135 } 136 } 137 138 void 139 losemhp(int x) 140 { 141 c[HP] -= x; 142 if (c[HP] < 1) 143 c[HP] = 1; 144 c[HPMAX] -= x; 145 if (c[HPMAX] < 1) 146 c[HPMAX] = 1; 147 } 148 149 /* 150 raisehp(x) 151 raisemhp(x) 152 153 subroutine to gain maximum hit points 154 */ 155 void 156 raisehp(int x) 157 { 158 if ((c[HP] += x) > c[HPMAX]) 159 c[HP] = c[HPMAX]; 160 } 161 162 void 163 raisemhp(int x) 164 { 165 c[HPMAX] += x; 166 c[HP] += x; 167 } 168 169 /* 170 raisemspells(x) 171 172 subroutine to gain maximum spells 173 */ 174 void 175 raisemspells(int x) 176 { 177 c[SPELLMAX] += x; 178 c[SPELLS] += x; 179 } 180 181 /* 182 losemspells(x) 183 184 subroutine to lose maximum spells 185 */ 186 void 187 losemspells(int x) 188 { 189 if ((c[SPELLMAX] -= x) < 0) 190 c[SPELLMAX] = 0; 191 if ((c[SPELLS] -= x) < 0) 192 c[SPELLS] = 0; 193 } 194 195 /* 196 makemonst(lev) 197 int lev; 198 199 function to return monster number for a randomly selected monster 200 for the given cave level 201 */ 202 int 203 makemonst(int lev) 204 { 205 int tmp, x; 206 if (lev < 1) 207 lev = 1; 208 if (lev > 12) 209 lev = 12; 210 tmp = WATERLORD; 211 if (lev < 5) 212 while (tmp == WATERLORD) 213 tmp = rnd((x = monstlevel[lev - 1]) ? x : 1); 214 else 215 while (tmp == WATERLORD) 216 tmp = rnd((x = monstlevel[lev - 1] - monstlevel[lev - 4]) ? x : 1) + monstlevel[lev - 4]; 217 218 while (monster[tmp].genocided && tmp < MAXMONST) 219 tmp++; /* genocided? */ 220 return (tmp); 221 } 222 223 /* 224 positionplayer() 225 226 function to be sure player is not in a wall 227 */ 228 void 229 positionplayer(void) 230 { 231 int try; 232 try = 2; 233 while ((item[playerx][playery] || mitem[playerx][playery]) && (try)) 234 if (++playerx >= MAXX - 1) { 235 playerx = 1; 236 if (++playery >= MAXY - 1) { 237 playery = 1; 238 --try; 239 } 240 } 241 if (try == 0) 242 lprcat("Failure in positionplayer\n"); 243 } 244 245 /* 246 recalc() function to recalculate the armor class of the player 247 */ 248 void 249 recalc(void) 250 { 251 int i, j, k; 252 c[AC] = c[MOREDEFENSES]; 253 if (c[WEAR] >= 0) 254 switch (iven[c[WEAR]]) { 255 case OSHIELD: 256 c[AC] += 2 + ivenarg[c[WEAR]]; 257 break; 258 case OLEATHER: 259 c[AC] += 2 + ivenarg[c[WEAR]]; 260 break; 261 case OSTUDLEATHER: 262 c[AC] += 3 + ivenarg[c[WEAR]]; 263 break; 264 case ORING: 265 c[AC] += 5 + ivenarg[c[WEAR]]; 266 break; 267 case OCHAIN: 268 c[AC] += 6 + ivenarg[c[WEAR]]; 269 break; 270 case OSPLINT: 271 c[AC] += 7 + ivenarg[c[WEAR]]; 272 break; 273 case OPLATE: 274 c[AC] += 9 + ivenarg[c[WEAR]]; 275 break; 276 case OPLATEARMOR: 277 c[AC] += 10 + ivenarg[c[WEAR]]; 278 break; 279 case OSSPLATE: 280 c[AC] += 12 + ivenarg[c[WEAR]]; 281 break; 282 } 283 284 if (c[SHIELD] >= 0) 285 if (iven[c[SHIELD]] == OSHIELD) 286 c[AC] += 2 + ivenarg[c[SHIELD]]; 287 if (c[WIELD] < 0) 288 c[WCLASS] = 0; 289 else { 290 i = ivenarg[c[WIELD]]; 291 switch (iven[c[WIELD]]) { 292 case ODAGGER: 293 c[WCLASS] = 3 + i; 294 break; 295 case OBELT: 296 c[WCLASS] = 7 + i; 297 break; 298 case OSHIELD: 299 c[WCLASS] = 8 + i; 300 break; 301 case OSPEAR: 302 c[WCLASS] = 10 + i; 303 break; 304 case OFLAIL: 305 c[WCLASS] = 14 + i; 306 break; 307 case OBATTLEAXE: 308 c[WCLASS] = 17 + i; 309 break; 310 case OLANCE: 311 c[WCLASS] = 19 + i; 312 break; 313 case OLONGSWORD: 314 c[WCLASS] = 22 + i; 315 break; 316 case O2SWORD: 317 c[WCLASS] = 26 + i; 318 break; 319 case OSWORD: 320 c[WCLASS] = 32 + i; 321 break; 322 case OSWORDofSLASHING: 323 c[WCLASS] = 30 + i; 324 break; 325 case OHAMMER: 326 c[WCLASS] = 35 + i; 327 break; 328 default: 329 c[WCLASS] = 0; 330 } 331 } 332 c[WCLASS] += c[MOREDAM]; 333 334 /* now for regeneration abilities based on rings */ 335 c[REGEN] = 1; 336 c[ENERGY] = 0; 337 j = 0; 338 for (k = 25; k > 0; k--) 339 if (iven[k]) { 340 j = k; 341 k = 0; 342 } 343 for (i = 0; i <= j; i++) { 344 switch (iven[i]) { 345 case OPROTRING: 346 c[AC] += ivenarg[i] + 1; 347 break; 348 case ODAMRING: 349 c[WCLASS] += ivenarg[i] + 1; 350 break; 351 case OBELT: 352 c[WCLASS] += ((ivenarg[i] << 1)) + 2; 353 break; 354 355 case OREGENRING: 356 c[REGEN] += ivenarg[i] + 1; 357 break; 358 case ORINGOFEXTRA: 359 c[REGEN] += 5 * (ivenarg[i] + 1); 360 break; 361 case OENERGYRING: 362 c[ENERGY] += ivenarg[i] + 1; 363 break; 364 } 365 } 366 } 367 368 369 /* 370 quit() 371 372 subroutine to ask if the player really wants to quit 373 */ 374 void 375 quit(void) 376 { 377 int i; 378 cursors(); 379 strcpy(lastmonst, ""); 380 lprcat("\n\nDo you really want to quit?"); 381 while (1) { 382 i = ttgetch(); 383 if (i == 'y') { 384 died(300); 385 return; 386 } 387 if ((i == 'n') || (i == '\33')) { 388 lprcat(" no"); 389 lflush(); 390 return; 391 } 392 lprcat("\n"); 393 setbold(); 394 lprcat("Yes"); 395 resetbold(); 396 lprcat(" or "); 397 setbold(); 398 lprcat("No"); 399 resetbold(); 400 lprcat(" please? Do you want to quit? "); 401 } 402 } 403 404 /* 405 function to ask --more-- then the user must enter a space 406 */ 407 void 408 more(void) 409 { 410 lprcat("\n --- press "); 411 standout("space"); 412 lprcat(" to continue --- "); 413 while (ttgetch() != ' '); 414 } 415 416 /* 417 function to put something in the players inventory 418 returns 0 if success, 1 if a failure 419 */ 420 int 421 take(int theitem, int arg) 422 { 423 int i, limit; 424 /* cursors(); */ 425 if ((limit = 15 + (c[LEVEL] >> 1)) > 26) 426 limit = 26; 427 for (i = 0; i < limit; i++) 428 if (iven[i] == 0) { 429 iven[i] = theitem; 430 ivenarg[i] = arg; 431 limit = 0; 432 switch (theitem) { 433 case OPROTRING: 434 case ODAMRING: 435 case OBELT: 436 limit = 1; 437 break; 438 case ODEXRING: 439 c[DEXTERITY] += ivenarg[i] + 1; 440 limit = 1; 441 break; 442 case OSTRRING: 443 c[STREXTRA] += ivenarg[i] + 1; 444 limit = 1; 445 break; 446 case OCLEVERRING: 447 c[INTELLIGENCE] += ivenarg[i] + 1; 448 limit = 1; 449 break; 450 case OHAMMER: 451 c[DEXTERITY] += 10; 452 c[STREXTRA] += 10; 453 c[INTELLIGENCE] -= 10; 454 limit = 1; 455 break; 456 457 case OORBOFDRAGON: 458 c[SLAYING]++; 459 break; 460 case OSPIRITSCARAB: 461 c[NEGATESPIRIT]++; 462 break; 463 case OCUBEofUNDEAD: 464 c[CUBEofUNDEAD]++; 465 break; 466 case ONOTHEFT: 467 c[NOTHEFT]++; 468 break; 469 case OSWORDofSLASHING: 470 c[DEXTERITY] += 5; 471 limit = 1; 472 break; 473 }; 474 lprcat("\nYou pick up:"); 475 srcount = 0; 476 show3(i); 477 if (limit) 478 bottomline(); 479 return (0); 480 } 481 lprcat("\nYou can't carry anything else"); 482 return (1); 483 } 484 485 /* 486 subroutine to drop an object 487 returns 1 if something there already else 0 488 */ 489 int 490 drop_object(int k) 491 { 492 int theitem; 493 if ((k < 0) || (k > 25)) 494 return (0); 495 theitem = iven[k]; 496 cursors(); 497 if (theitem == 0) { 498 lprintf("\nYou don't have item %c! ", k + 'a'); 499 return (1); 500 } 501 if (item[playerx][playery]) { 502 beep(); 503 lprcat("\nThere's something here already"); 504 return (1); 505 } 506 if (playery == MAXY - 1 && playerx == 33) 507 return (1); /* not in entrance */ 508 item[playerx][playery] = theitem; 509 iarg[playerx][playery] = ivenarg[k]; 510 srcount = 0; 511 lprcat("\n You drop:"); 512 show3(k); /* show what item you dropped */ 513 know[playerx][playery] = 0; 514 iven[k] = 0; 515 if (c[WIELD] == k) 516 c[WIELD] = -1; 517 if (c[WEAR] == k) 518 c[WEAR] = -1; 519 if (c[SHIELD] == k) 520 c[SHIELD] = -1; 521 adjustcvalues(theitem, ivenarg[k]); 522 dropflag = 1; /* say dropped an item so wont ask to pick it 523 * up right away */ 524 return (0); 525 } 526 527 /* 528 function to enchant armor player is currently wearing 529 */ 530 void 531 enchantarmor(void) 532 { 533 int tmp; 534 if (c[WEAR] < 0) { 535 if (c[SHIELD] < 0) { 536 cursors(); 537 beep(); 538 lprcat("\nYou feel a sense of loss"); 539 return; 540 } else { 541 tmp = iven[c[SHIELD]]; 542 if (tmp != OSCROLL) 543 if (tmp != OPOTION) { 544 ivenarg[c[SHIELD]]++; 545 bottomline(); 546 } 547 } 548 } 549 tmp = iven[c[WEAR]]; 550 if (tmp != OSCROLL) 551 if (tmp != OPOTION) { 552 ivenarg[c[WEAR]]++; 553 bottomline(); 554 } 555 } 556 557 /* 558 function to enchant a weapon presently being wielded 559 */ 560 void 561 enchweapon(void) 562 { 563 int tmp; 564 if (c[WIELD] < 0) { 565 cursors(); 566 beep(); 567 lprcat("\nYou feel a sense of loss"); 568 return; 569 } 570 tmp = iven[c[WIELD]]; 571 if (tmp != OSCROLL) 572 if (tmp != OPOTION) { 573 ivenarg[c[WIELD]]++; 574 if (tmp == OCLEVERRING) 575 c[INTELLIGENCE]++; 576 else if (tmp == OSTRRING) 577 c[STREXTRA]++; 578 else if (tmp == ODEXRING) 579 c[DEXTERITY]++; 580 bottomline(); 581 } 582 } 583 584 /* 585 routine to tell if player can carry one more thing 586 returns 1 if pockets are full, else 0 587 */ 588 int 589 pocketfull(void) 590 { 591 int i, limit; 592 if ((limit = 15 + (c[LEVEL] >> 1)) > 26) 593 limit = 26; 594 for (i = 0; i < limit; i++) 595 if (iven[i] == 0) 596 return (0); 597 return (1); 598 } 599 600 /* 601 function to return 1 if a monster is next to the player else returns 0 602 */ 603 int 604 nearbymonst(void) 605 { 606 int tmp, tmp2; 607 for (tmp = playerx - 1; tmp < playerx + 2; tmp++) 608 for (tmp2 = playery - 1; tmp2 < playery + 2; tmp2++) 609 if (mitem[tmp][tmp2]) 610 return (1); /* if monster nearby */ 611 return (0); 612 } 613 614 /* 615 function to steal an item from the players pockets 616 returns 1 if steals something else returns 0 617 */ 618 int 619 stealsomething(void) 620 { 621 int i, j; 622 j = 100; 623 while (1) { 624 i = rund(26); 625 if (iven[i]) 626 if (c[WEAR] != i) 627 if (c[WIELD] != i) 628 if (c[SHIELD] != i) { 629 srcount = 0; 630 show3(i); 631 adjustcvalues(iven[i], ivenarg[i]); 632 iven[i] = 0; 633 return (1); 634 } 635 if (--j <= 0) 636 return (0); 637 } 638 } 639 640 /* 641 function to return 1 is player carrys nothing else return 0 642 */ 643 int 644 emptyhanded(void) 645 { 646 int i; 647 for (i = 0; i < 26; i++) 648 if (iven[i]) 649 if (i != c[WIELD]) 650 if (i != c[WEAR]) 651 if (i != c[SHIELD]) 652 return (0); 653 return (1); 654 } 655 656 /* 657 function to create a gem on a square near the player 658 */ 659 void 660 creategem(void) 661 { 662 int i, j; 663 switch (rnd(4)) { 664 case 1: 665 i = ODIAMOND; 666 j = 50; 667 break; 668 case 2: 669 i = ORUBY; 670 j = 40; 671 break; 672 case 3: 673 i = OEMERALD; 674 j = 30; 675 break; 676 default: 677 i = OSAPPHIRE; 678 j = 20; 679 break; 680 }; 681 createitem(i, rnd(j) + j / 10); 682 } 683 684 /* 685 function to change character levels as needed when dropping an object 686 that affects these characteristics 687 */ 688 void 689 adjustcvalues(int theitem, int arg) 690 { 691 int flag; 692 flag = 0; 693 switch (theitem) { 694 case ODEXRING: 695 c[DEXTERITY] -= arg + 1; 696 flag = 1; 697 break; 698 case OSTRRING: 699 c[STREXTRA] -= arg + 1; 700 flag = 1; 701 break; 702 case OCLEVERRING: 703 c[INTELLIGENCE] -= arg + 1; 704 flag = 1; 705 break; 706 case OHAMMER: 707 c[DEXTERITY] -= 10; 708 c[STREXTRA] -= 10; 709 c[INTELLIGENCE] += 10; 710 flag = 1; 711 break; 712 case OSWORDofSLASHING: 713 c[DEXTERITY] -= 5; 714 flag = 1; 715 break; 716 case OORBOFDRAGON: 717 --c[SLAYING]; 718 return; 719 case OSPIRITSCARAB: 720 --c[NEGATESPIRIT]; 721 return; 722 case OCUBEofUNDEAD: 723 --c[CUBEofUNDEAD]; 724 return; 725 case ONOTHEFT: 726 --c[NOTHEFT]; 727 return; 728 case OLANCE: 729 c[LANCEDEATH] = 0; 730 return; 731 case OPOTION: 732 case OSCROLL: 733 return; 734 735 default: 736 flag = 1; 737 }; 738 if (flag) 739 bottomline(); 740 } 741 742 /* 743 function to ask user for a password (no echo) 744 returns 1 if entered correctly, 0 if not 745 */ 746 static char gpwbuf[33]; 747 int 748 getpassword(void) 749 { 750 int i, j; 751 char *gpwp; 752 scbr(); /* system("stty -echo cbreak"); */ 753 gpwp = gpwbuf; 754 lprcat("\nEnter Password: "); 755 lflush(); 756 i = strlen(password); 757 for (j = 0; j < i; j++) 758 *gpwp++ = ttgetch(); 759 gpwbuf[i] = 0; 760 sncbr(); /* system("stty echo -cbreak"); */ 761 if (strcmp(gpwbuf, password) != 0) { 762 lprcat("\nSorry\n"); 763 lflush(); 764 return (0); 765 } else 766 return (1); 767 } 768 769 /* 770 subroutine to get a yes or no response from the user 771 returns y or n 772 */ 773 int 774 getyn(void) 775 { 776 int i; 777 i = 0; 778 while (i != 'y' && i != 'n' && i != '\33') 779 i = ttgetch(); 780 return (i); 781 } 782 783 /* 784 function to calculate the pack weight of the player 785 returns the number of pounds the player is carrying 786 */ 787 int 788 packweight(void) 789 { 790 int i, j, k; 791 k = c[GOLD] / 1000; 792 j = 25; 793 while ((iven[j] == 0) && (j > 0)) 794 --j; 795 for (i = 0; i <= j; i++) 796 switch (iven[i]) { 797 case 0: 798 break; 799 case OSSPLATE: 800 case OPLATEARMOR: 801 k += 40; 802 break; 803 case OPLATE: 804 k += 35; 805 break; 806 case OHAMMER: 807 k += 30; 808 break; 809 case OSPLINT: 810 k += 26; 811 break; 812 case OSWORDofSLASHING: 813 case OCHAIN: 814 case OBATTLEAXE: 815 case O2SWORD: 816 k += 23; 817 break; 818 case OLONGSWORD: 819 case OSWORD: 820 case ORING: 821 case OFLAIL: 822 k += 20; 823 break; 824 case OLANCE: 825 case OSTUDLEATHER: 826 k += 15; 827 break; 828 case OLEATHER: 829 case OSPEAR: 830 k += 8; 831 break; 832 case OORBOFDRAGON: 833 case OBELT: 834 k += 4; 835 break; 836 case OSHIELD: 837 k += 7; 838 break; 839 case OCHEST: 840 k += 30 + ivenarg[i]; 841 break; 842 default: 843 k++; 844 }; 845 return (k); 846 } 847 848 #ifndef MACRORND 849 /* macros to generate random numbers 1<=rnd(N)<=N 0<=rund(N)<=N-1 */ 850 int 851 rnd(int x) 852 { 853 return ((((randx = randx * 1103515245 + 12345) >> 7) % (x)) + 1); 854 } 855 856 int 857 rund(int x) 858 { 859 return ((((randx = randx * 1103515245 + 12345) >> 7) % (x))); 860 } 861 #endif /* MACRORND */ 862