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