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