1 /* 2 * misc.c Phantasia miscellaneous support routines 3 */ 4 5 #include "include.h" 6 7 /************************************************************************ 8 / 9 / FUNCTION NAME: movelevel() 10 / 11 / FUNCTION: move player to new level 12 / 13 / AUTHOR: E. A. Estes, 12/4/85 14 / 15 / ARGUMENTS: none 16 / 17 / RETURN VALUE: none 18 / 19 / MODULES CALLED: death(), floor(), wmove(), drandom(), waddstr(), explevel() 20 / 21 / GLOBAL INPUTS: Player, *stdscr, *Statptr, Stattable[] 22 / 23 / GLOBAL OUTPUTS: Player, Changed 24 / 25 / DESCRIPTION: 26 / Use lookup table to increment important statistics when 27 / progressing to new experience level. 28 / Players are rested to maximum as a bonus for making a new 29 / level. 30 / Check for council of wise, and being too big to be king. 31 / 32 /************************************************************************/ 33 34 movelevel() 35 { 36 register struct charstats *statptr; /* for pointing into Stattable */ 37 double new; /* new level */ 38 double inc; /* increment between new and old levels */ 39 40 Changed = TRUE; 41 42 if (Player.p_type == C_EXPER) 43 /* roll a type to use for increment */ 44 statptr = &Stattable[(int) ROLL(C_MAGIC, C_HALFLING - C_MAGIC + 1)]; 45 else 46 statptr = Statptr; 47 48 new = explevel(Player.p_experience); 49 inc = new - Player.p_level; 50 Player.p_level = new; 51 52 /* add increments to statistics */ 53 Player.p_strength += statptr->c_strength.increase * inc; 54 Player.p_mana += statptr->c_mana.increase * inc; 55 Player.p_brains += statptr->c_brains.increase * inc; 56 Player.p_magiclvl += statptr->c_magiclvl.increase * inc; 57 Player.p_maxenergy += statptr->c_energy.increase * inc; 58 59 /* rest to maximum upon reaching new level */ 60 Player.p_energy = Player.p_maxenergy + Player.p_shield; 61 62 if (Player.p_crowns > 0 && Player.p_level >= 1000.0) 63 /* no longer able to be king -- turn crowns into cash */ 64 { 65 Player.p_gold += ((double) Player.p_crowns) * 5000.0; 66 Player.p_crowns = 0; 67 } 68 69 if (Player.p_level >= 3000.0 && Player.p_specialtype < SC_COUNCIL) 70 /* make a member of the council */ 71 { 72 mvaddstr(6, 0, "You have made it to the Council of the Wise.\n"); 73 addstr("Good Luck on your search for the Holy Grail.\n"); 74 75 Player.p_specialtype = SC_COUNCIL; 76 77 /* no rings for council and above */ 78 Player.p_ring.ring_type = R_NONE; 79 Player.p_ring.ring_duration = 0; 80 81 Player.p_lives = 3; /* three extra lives */ 82 } 83 84 if (Player.p_level > 9999.0 && Player.p_specialtype != SC_VALAR) 85 death("Old age"); 86 } 87 /**/ 88 /************************************************************************ 89 / 90 / FUNCTION NAME: descrlocation() 91 / 92 / FUNCTION: return a formatted description of location 93 / 94 / AUTHOR: E. A. Estes, 12/4/85 95 / 96 / ARGUMENTS: 97 / struct player playerp - pointer to player structure 98 / bool shortflag - set if short form is desired 99 / 100 / RETURN VALUE: pointer to string containing result 101 / 102 / MODULES CALLED: fabs(), floor(), sprintf(), distance() 103 / 104 / GLOBAL INPUTS: Databuf[] 105 / 106 / GLOBAL OUTPUTS: none 107 / 108 / DESCRIPTION: 109 / Look at coordinates and return an appropriately formatted 110 / string. 111 / 112 /************************************************************************/ 113 114 char * 115 descrlocation(playerp, shortflag) 116 struct player *playerp; 117 bool shortflag; 118 { 119 double circle; /* corresponding circle for coordinates */ 120 register int quadrant; /* quandrant of grid */ 121 register char *label; /* pointer to place name */ 122 static char *nametable[4][4] = /* names of places */ 123 { 124 "Anorien", "Ithilien", "Rohan", "Lorien", 125 "Gondor", "Mordor", "Dunland", "Rovanion", 126 "South Gondor", "Khand", "Eriador", "The Iron Hills", 127 "Far Harad", "Near Harad", "The Northern Waste", "Rhun" 128 }; 129 130 if (playerp->p_specialtype == SC_VALAR) 131 return(" is in Valhala"); 132 else if ((circle = CIRCLE(playerp->p_x, playerp->p_y)) >= 1000.0) 133 { 134 if (MAX(fabs(playerp->p_x), fabs(playerp->p_y)) > D_BEYOND) 135 label = "The Point of No Return"; 136 else 137 label = "The Ashen Mountains"; 138 } 139 else if (circle >= 55) 140 label = "Morannon"; 141 else if (circle >= 35) 142 label = "Kennaquahair"; 143 else if (circle >= 20) 144 label = "The Dead Marshes"; 145 else if (circle >= 9) 146 label = "The Outer Waste"; 147 else if (circle >= 5) 148 label = "The Moors Adventurous"; 149 else 150 { 151 if (playerp->p_x == 0.0 && playerp->p_y == 0.0) 152 label = "The Lord's Chamber"; 153 else 154 { 155 /* this expression is split to prevent compiler loop with some compilers */ 156 quadrant = ((playerp->p_x > 0.0) ? 1 : 0); 157 quadrant += ((playerp->p_y >= 0.0) ? 2 : 0); 158 label = nametable[((int) circle) - 1][quadrant]; 159 } 160 } 161 162 if (shortflag) 163 sprintf(Databuf, "%.29s", label); 164 else 165 sprintf(Databuf, " is in %s (%.0f,%.0f)", label, playerp->p_x, playerp->p_y); 166 167 return(Databuf); 168 } 169 /**/ 170 /************************************************************************ 171 / 172 / FUNCTION NAME: tradingpost() 173 / 174 / FUNCTION: do trading post stuff 175 / 176 / AUTHOR: E. A. Estes, 12/4/85 177 / 178 / ARGUMENTS: none 179 / 180 / RETURN VALUE: none 181 / 182 / MODULES CALLED: writerecord(), adjuststats(), fabs(), more(), sqrt(), 183 / sleep(), floor(), wmove(), drandom(), wclear(), printw(), 184 / altercoordinates(), infloat(), waddstr(), wrefresh(), mvprintw(), getanswer(), 185 / wclrtoeol(), wclrtobot() 186 / 187 / GLOBAL INPUTS: Menu[], Circle, Player, *stdscr, Fileloc, Nobetter[] 188 / 189 / GLOBAL OUTPUTS: Player 190 / 191 / DESCRIPTION: 192 / Different trading posts have different items. 193 / Merchants cannot be cheated, but they can be dishonest 194 / themselves. 195 / 196 / Shields, swords, and quicksilver are not cumulative. This is 197 / one major area of complaint, but there are two reasons for this: 198 / 1) It becomes MUCH too easy to make very large versions 199 / of these items. 200 / 2) In the real world, one cannot simply weld two swords 201 / together to make a bigger one. 202 / 203 / At one time, it was possible to sell old weapons at half the purchase 204 / price. This resulted in huge amounts of gold floating around, 205 / and the game lost much of its challenge. 206 / 207 / Also, purchasing gems defeats the whole purpose of gold. Gold 208 / is small change for lower level players. They really shouldn't 209 / be able to accumulate more than enough gold for a small sword or 210 / a few books. Higher level players shouldn't even bother to pick 211 / up gold, except maybe to buy mana once in a while. 212 / 213 /************************************************************************/ 214 215 tradingpost() 216 { 217 double numitems; /* number of items to purchase */ 218 double cost; /* cost of purchase */ 219 double blessingcost; /* cost of blessing */ 220 int ch; /* input */ 221 register int size; /* size of the trading post */ 222 register int loop; /* loop counter */ 223 int cheat = 0; /* number of times player has tried to cheat */ 224 bool dishonest = FALSE;/* set when merchant is dishonest */ 225 226 Player.p_status = S_TRADING; 227 writerecord(&Player, Fileloc); 228 229 clear(); 230 addstr("You are at a trading post. All purchases must be made with gold."); 231 232 size = sqrt(fabs(Player.p_x / 100)) + 1; 233 size = MIN(7, size); 234 235 /* set up cost of blessing */ 236 blessingcost = 1000.0 * (Player.p_level + 5.0); 237 238 /* print Menu */ 239 move(7, 0); 240 for (loop = 0; loop < size; ++loop) 241 /* print Menu */ 242 { 243 if (loop == 6) 244 cost = blessingcost; 245 else 246 cost = Menu[loop].cost; 247 printw("(%d) %-12s: %6.0f\n", loop + 1, Menu[loop].item, cost); 248 } 249 250 mvprintw(5, 0, "L:Leave P:Purchase S:Sell Gems ? "); 251 252 for (;;) 253 { 254 adjuststats(); /* truncate any bad values */ 255 256 /* print some important statistics */ 257 mvprintw(1, 0, "Gold: %9.0f Gems: %9.0f Level: %6.0f Charms: %6d\n", 258 Player.p_gold, Player.p_gems, Player.p_level, Player.p_charms); 259 printw("Shield: %9.0f Sword: %9.0f Quicksilver:%3.0f Blessed: %s\n", 260 Player.p_shield, Player.p_sword, Player.p_quksilver, 261 (Player.p_blessing ? " True" : "False")); 262 printw("Brains: %9.0f Mana: %9.0f", Player.p_brains, Player.p_mana); 263 264 move(5, 36); 265 ch = getanswer("LPS", FALSE); 266 move(15, 0); 267 clrtobot(); 268 switch(ch) 269 { 270 case 'L': /* leave */ 271 case '\n': 272 altercoordinates(0.0, 0.0, A_NEAR); 273 return; 274 275 case 'P': /* make purchase */ 276 mvaddstr(15, 0, "What what would you like to buy ? "); 277 ch = getanswer(" 1234567", FALSE); 278 move(15, 0); 279 clrtoeol(); 280 281 if (ch - '0' > size) 282 addstr("Sorry, this merchant doesn't have that."); 283 else 284 switch (ch) 285 { 286 case '1': 287 printw("Mana is one per %.0f gold piece. How many do you want (%.0f max) ? ", 288 Menu[0].cost, floor(Player.p_gold / Menu[0].cost)); 289 cost = (numitems = floor(infloat())) * Menu[0].cost; 290 291 if (cost > Player.p_gold || numitems < 0) 292 ++cheat; 293 else 294 { 295 cheat = 0; 296 Player.p_gold -= cost; 297 if (drandom() < 0.02) 298 dishonest = TRUE; 299 else 300 Player.p_mana += numitems; 301 } 302 break; 303 304 case '2': 305 printw("Shields are %.0f per +1. How many do you want (%.0f max) ? ", 306 Menu[1].cost, floor(Player.p_gold / Menu[1].cost)); 307 cost = (numitems = floor(infloat())) * Menu[1].cost; 308 309 if (numitems == 0.0) 310 break; 311 else if (cost > Player.p_gold || numitems < 0) 312 ++cheat; 313 else if (numitems < Player.p_shield) 314 NOBETTER(); 315 else 316 { 317 cheat = 0; 318 Player.p_gold -= cost; 319 if (drandom() < 0.02) 320 dishonest = TRUE; 321 else 322 Player.p_shield = numitems; 323 } 324 break; 325 326 case '3': 327 printw("A book costs %.0f gp. How many do you want (%.0f max) ? ", 328 Menu[2].cost, floor(Player.p_gold / Menu[2].cost)); 329 cost = (numitems = floor(infloat())) * Menu[2].cost; 330 331 if (cost > Player.p_gold || numitems < 0) 332 ++cheat; 333 else 334 { 335 cheat = 0; 336 Player.p_gold -= cost; 337 if (drandom() < 0.02) 338 dishonest = TRUE; 339 else if (drandom() * numitems > Player.p_level / 10.0 340 && numitems != 1) 341 { 342 printw("\nYou blew your mind!\n"); 343 Player.p_brains /= 5; 344 } 345 else 346 { 347 Player.p_brains += floor(numitems) * ROLL(20, 8); 348 } 349 } 350 break; 351 352 case '4': 353 printw("Swords are %.0f gp per +1. How many + do you want (%.0f max) ? ", 354 Menu[3].cost, floor(Player.p_gold / Menu[3].cost)); 355 cost = (numitems = floor(infloat())) * Menu[3].cost; 356 357 if (numitems == 0.0) 358 break; 359 else if (cost > Player.p_gold || numitems < 0) 360 ++cheat; 361 else if (numitems < Player.p_sword) 362 NOBETTER(); 363 else 364 { 365 cheat = 0; 366 Player.p_gold -= cost; 367 if (drandom() < 0.02) 368 dishonest = TRUE; 369 else 370 Player.p_sword = numitems; 371 } 372 break; 373 374 case '5': 375 printw("A charm costs %.0f gp. How many do you want (%.0f max) ? ", 376 Menu[4].cost, floor(Player.p_gold / Menu[4].cost)); 377 cost = (numitems = floor(infloat())) * Menu[4].cost; 378 379 if (cost > Player.p_gold || numitems < 0) 380 ++cheat; 381 else 382 { 383 cheat = 0; 384 Player.p_gold -= cost; 385 if (drandom() < 0.02) 386 dishonest = TRUE; 387 else 388 Player.p_charms += numitems; 389 } 390 break; 391 392 case '6': 393 printw("Quicksilver is %.0f gp per +1. How many + do you want (%.0f max) ? ", 394 Menu[5].cost, floor(Player.p_gold / Menu[5].cost)); 395 cost = (numitems = floor(infloat())) * Menu[5].cost; 396 397 if (numitems == 0.0) 398 break; 399 else if (cost > Player.p_gold || numitems < 0) 400 ++cheat; 401 else if (numitems < Player.p_quksilver) 402 NOBETTER(); 403 else 404 { 405 cheat = 0; 406 Player.p_gold -= cost; 407 if (drandom() < 0.02) 408 dishonest = TRUE; 409 else 410 Player.p_quksilver = numitems; 411 } 412 break; 413 414 case '7': 415 if (Player.p_blessing) 416 { 417 addstr("You already have a blessing."); 418 break; 419 } 420 421 printw("A blessing requires a %.0f gp donation. Still want one ? ", blessingcost); 422 ch = getanswer("NY", FALSE); 423 424 if (ch == 'Y') 425 if (Player.p_gold < blessingcost) 426 ++cheat; 427 else 428 { 429 cheat = 0; 430 Player.p_gold -= blessingcost; 431 if (drandom() < 0.02) 432 dishonest = TRUE; 433 else 434 Player.p_blessing = TRUE; 435 } 436 break; 437 } 438 break; 439 440 case 'S': /* sell gems */ 441 mvprintw(15, 0, "A gem is worth %.0f gp. How many do you want to sell (%.0f max) ? ", 442 (double) N_GEMVALUE, Player.p_gems); 443 numitems = floor(infloat()); 444 445 if (numitems > Player.p_gems || numitems < 0) 446 ++cheat; 447 else 448 { 449 cheat = 0; 450 Player.p_gems -= numitems; 451 Player.p_gold += numitems * N_GEMVALUE; 452 } 453 } 454 455 if (cheat == 1) 456 mvaddstr(17, 0, "Come on, merchants aren't stupid. Stop cheating.\n"); 457 else if (cheat == 2) 458 { 459 mvaddstr(17, 0, "You had your chance. This merchant happens to be\n"); 460 printw("a %.0f level magic user, and you made %s mad!\n", 461 ROLL(Circle * 20.0, 40.0), (drandom() < 0.5) ? "him" : "her"); 462 altercoordinates(0.0, 0.0, A_FAR); 463 Player.p_energy /= 2.0; 464 ++Player.p_sin; 465 more(23); 466 return; 467 } 468 else if (dishonest) 469 { 470 mvaddstr(17, 0, "The merchant stole your money!"); 471 refresh(); 472 altercoordinates(Player.p_x - Player.p_x / 10.0, 473 Player.p_y - Player.p_y / 10.0, A_SPECIFIC); 474 sleep(2); 475 return; 476 } 477 } 478 } 479 /**/ 480 /************************************************************************ 481 / 482 / FUNCTION NAME: displaystats() 483 / 484 / FUNCTION: print out important player statistics 485 / 486 / AUTHOR: E. A. Estes, 12/4/85 487 / 488 / ARGUMENTS: none 489 / 490 / RETURN VALUE: none 491 / 492 / MODULES CALLED: descrstatus(), descrlocation(), mvprintw() 493 / 494 / GLOBAL INPUTS: Users, Player 495 / 496 / GLOBAL OUTPUTS: none 497 / 498 / DESCRIPTION: 499 / Important player statistics are printed on the screen. 500 / 501 /************************************************************************/ 502 503 displaystats() 504 { 505 mvprintw(0, 0, "%s%s\n", Player.p_name, descrlocation(&Player, FALSE)); 506 mvprintw(1, 0, "Level :%7.0f Energy :%9.0f(%9.0f) Mana :%9.0f Users:%3d\n", 507 Player.p_level, Player.p_energy, Player.p_maxenergy + Player.p_shield, 508 Player.p_mana, Users); 509 mvprintw(2, 0, "Quick :%3.0f(%3.0f) Strength:%9.0f(%9.0f) Gold :%9.0f %s\n", 510 Player.p_speed, Player.p_quickness + Player.p_quksilver, Player.p_might, 511 Player.p_strength + Player.p_sword, Player.p_gold, descrstatus(&Player)); 512 } 513 /**/ 514 /************************************************************************ 515 / 516 / FUNCTION NAME: allstatslist() 517 / 518 / FUNCTION: show player items 519 / 520 / AUTHOR: E. A. Estes, 12/4/85 521 / 522 / ARGUMENTS: none 523 / 524 / RETURN VALUE: none 525 / 526 / MODULES CALLED: mvprintw(), descrtype() 527 / 528 / GLOBAL INPUTS: Player 529 / 530 / GLOBAL OUTPUTS: none 531 / 532 / DESCRIPTION: 533 / Print out some player statistics of lesser importance. 534 / 535 /************************************************************************/ 536 537 allstatslist() 538 { 539 static char *flags[] = /* to print value of some bools */ 540 { 541 "False", 542 " True" 543 }; 544 545 mvprintw( 8, 0, "Type: %s\n", descrtype(&Player, FALSE)); 546 547 mvprintw(10, 0, "Experience: %9.0f", Player.p_experience); 548 mvprintw(11, 0, "Brains : %9.0f", Player.p_brains); 549 mvprintw(12, 0, "Magic Lvl : %9.0f", Player.p_magiclvl); 550 mvprintw(13, 0, "Sin : %9.5f", Player.p_sin); 551 mvprintw(14, 0, "Poison : %9.5f", Player.p_poison); 552 mvprintw(15, 0, "Gems : %9.0f", Player.p_gems); 553 mvprintw(16, 0, "Age : %9d", Player.p_age); 554 mvprintw(10, 40, "Holy Water: %9d", Player.p_holywater); 555 mvprintw(11, 40, "Amulets : %9d", Player.p_amulets); 556 mvprintw(12, 40, "Charms : %9d", Player.p_charms); 557 mvprintw(13, 40, "Crowns : %9d", Player.p_crowns); 558 mvprintw(14, 40, "Shield : %9.0f", Player.p_shield); 559 mvprintw(15, 40, "Sword : %9.0f", Player.p_sword); 560 mvprintw(16, 40, "Quickslver: %9.0f", Player.p_quksilver); 561 562 mvprintw(18, 0, "Blessing: %s Ring: %s Virgin: %s Palantir: %s", 563 flags[Player.p_blessing], flags[Player.p_ring.ring_type != R_NONE], 564 flags[Player.p_virgin], flags[Player.p_palantir]); 565 } 566 /**/ 567 /************************************************************************ 568 / 569 / FUNCTION NAME: descrtype() 570 / 571 / FUNCTION: return a string specifying player type 572 / 573 / AUTHOR: E. A. Estes, 12/4/85 574 / 575 / ARGUMENTS: 576 / struct player playerp - pointer to structure for player 577 / bool shortflag - set if short form is desired 578 / 579 / RETURN VALUE: pointer to string describing player type 580 / 581 / MODULES CALLED: strcpy() 582 / 583 / GLOBAL INPUTS: Databuf[] 584 / 585 / GLOBAL OUTPUTS: Databuf[] 586 / 587 / DESCRIPTION: 588 / Return a string describing the player type. 589 / King, council, valar, supercedes other types. 590 / The first character of the string is '*' if the player 591 / has a crown. 592 / If 'shortflag' is TRUE, return a 3 character string. 593 / 594 /************************************************************************/ 595 596 char * 597 descrtype(playerp, shortflag) 598 struct player *playerp; 599 bool shortflag; 600 { 601 register int type; /* for caluculating result subscript */ 602 static char *results[] = /* description table */ 603 { 604 " Magic User", " MU", 605 " Fighter", " F ", 606 " Elf", " E ", 607 " Dwarf", " D ", 608 " Halfling", " H ", 609 " Experimento", " EX", 610 " Super", " S ", 611 " King", " K ", 612 " Council of Wise", " CW", 613 " Ex-Valar", " EV", 614 " Valar", " V ", 615 " ? ", " ? " 616 }; 617 618 type = playerp->p_type; 619 620 switch (playerp->p_specialtype) 621 { 622 case SC_NONE: 623 type = playerp->p_type; 624 break; 625 626 case SC_KING: 627 type = 7; 628 break; 629 630 case SC_COUNCIL: 631 type = 8; 632 break; 633 634 case SC_EXVALAR: 635 type = 9; 636 break; 637 638 case SC_VALAR: 639 type = 10; 640 break; 641 } 642 643 type *= 2; /* calculate offset */ 644 645 if (type > 20) 646 /* error */ 647 type = 22; 648 649 if (shortflag) 650 /* use short descriptions */ 651 ++type; 652 653 if (playerp->p_crowns > 0) 654 { 655 strcpy(Databuf, results[type]); 656 Databuf[0] = '*'; 657 return(Databuf); 658 } 659 else 660 return(results[type]); 661 } 662 /**/ 663 /************************************************************************ 664 / 665 / FUNCTION NAME: findname() 666 / 667 / FUNCTION: find location in player file of given name 668 / 669 / AUTHOR: E. A. Estes, 12/4/85 670 / 671 / ARGUMENTS: 672 / char *name - name of character to look for 673 / struct player *playerp - pointer of structure to fill 674 / 675 / RETURN VALUE: location of player if found, -1 otherwise 676 / 677 / MODULES CALLED: fread(), fseek(), strcmp() 678 / 679 / GLOBAL INPUTS: Wizard, *Playersfp 680 / 681 / GLOBAL OUTPUTS: none 682 / 683 / DESCRIPTION: 684 / Search the player file for the player of the given name. 685 / If player is found, fill structure with player data. 686 / 687 /************************************************************************/ 688 689 long 690 findname(name, playerp) 691 register char *name; 692 register struct player *playerp; 693 { 694 long loc = 0; /* location in the file */ 695 696 fseek(Playersfp, 0L, 0); 697 while (fread((char *) playerp, SZ_PLAYERSTRUCT, 1, Playersfp) == 1) 698 { 699 if (strcmp(playerp->p_name, name) == 0) 700 { 701 if (playerp->p_status != S_NOTUSED || Wizard) 702 /* found it */ 703 return(loc); 704 } 705 loc += SZ_PLAYERSTRUCT; 706 } 707 708 return(-1); 709 } 710 /**/ 711 /************************************************************************ 712 / 713 / FUNCTION NAME: allocrecord() 714 / 715 / FUNCTION: find space in the player file for a new character 716 / 717 / AUTHOR: E. A. Estes, 12/4/85 718 / 719 / ARGUMENTS: none 720 / 721 / RETURN VALUE: location of free space in file 722 / 723 / MODULES CALLED: initplayer(), writerecord(), fread(), fseek() 724 / 725 / GLOBAL INPUTS: Other, *Playersfp 726 / 727 / GLOBAL OUTPUTS: Player 728 / 729 / DESCRIPTION: 730 / Search the player file for an unused entry. If none are found, 731 / make one at the end of the file. 732 / 733 /************************************************************************/ 734 735 long 736 allocrecord() 737 { 738 long loc = 0L; /* location in file */ 739 740 fseek(Playersfp, 0L, 0); 741 while (fread((char *) &Other, SZ_PLAYERSTRUCT, 1, Playersfp) == 1) 742 { 743 if (Other.p_status == S_NOTUSED) 744 /* found an empty record */ 745 return(loc); 746 else 747 loc += SZ_PLAYERSTRUCT; 748 } 749 750 /* make a new record */ 751 initplayer(&Other); 752 Player.p_status = S_OFF; 753 writerecord(&Other, loc); 754 755 return(loc); 756 } 757 /**/ 758 /************************************************************************ 759 / 760 / FUNCTION NAME: freerecord() 761 / 762 / FUNCTION: free up a record on the player file 763 / 764 / AUTHOR: E. A. Estes, 2/7/86 765 / 766 / ARGUMENTS: 767 / struct player playerp - pointer to structure to free 768 / long loc - location in file to free 769 / 770 / RETURN VALUE: none 771 / 772 / MODULES CALLED: writerecord() 773 / 774 / GLOBAL INPUTS: none 775 / 776 / GLOBAL OUTPUTS: none 777 / 778 / DESCRIPTION: 779 / Mark structure as not used, and update player file. 780 / 781 /************************************************************************/ 782 783 freerecord(playerp, loc) 784 struct player *playerp; 785 long loc; 786 { 787 playerp->p_name[0] = CH_MARKDELETE; 788 playerp->p_status = S_NOTUSED; 789 writerecord(playerp, loc); 790 } 791 /**/ 792 /************************************************************************ 793 / 794 / FUNCTION NAME: leavegame() 795 / 796 / FUNCTION: leave game 797 / 798 / AUTHOR: E. A. Estes, 12/4/85 799 / 800 / ARGUMENTS: none 801 / 802 / RETURN VALUE: none 803 / 804 / MODULES CALLED: freerecord(), writerecord(), cleanup() 805 / 806 / GLOBAL INPUTS: Player, Fileloc 807 / 808 / GLOBAL OUTPUTS: Player 809 / 810 / DESCRIPTION: 811 / Mark player as inactive, and cleanup. 812 / Do not save players below level 1. 813 / 814 /************************************************************************/ 815 816 leavegame() 817 { 818 819 if (Player.p_level < 1.0) 820 /* delete character */ 821 freerecord(&Player, Fileloc); 822 else 823 { 824 Player.p_status = S_OFF; 825 writerecord(&Player, Fileloc); 826 } 827 828 cleanup(TRUE); 829 /*NOTREACHED*/ 830 } 831 /**/ 832 /************************************************************************ 833 / 834 / FUNCTION NAME: death() 835 / 836 / FUNCTION: death routine 837 / 838 / AUTHOR: E. A. Estes, 12/4/85 839 / 840 / ARGUMENTS: 841 / char *how - pointer to string describing cause of death 842 / 843 / RETURN VALUE: none 844 / 845 / MODULES CALLED: freerecord(), enterscore(), more(), exit(), fread(), 846 / fseek(), execl(), fopen(), floor(), wmove(), drandom(), wclear(), strcmp(), 847 / fwrite(), fflush(), printw(), strcpy(), fclose(), waddstr(), cleanup(), 848 / fprintf(), wrefresh(), getanswer(), descrtype() 849 / 850 / GLOBAL INPUTS: Curmonster, Wizard, Player, *stdscr, Fileloc, *Monstfp, 851 / Lastdead[], Gameprog[], Messfile[] 852 / 853 / GLOBAL OUTPUTS: Player 854 / 855 / DESCRIPTION: 856 / Kill off current player. 857 / Handle rings, and multiple lives. 858 / Print an appropriate message. 859 / Update scoreboard, lastdead, and let other players know about 860 / the demise of their comrade. 861 / 862 /************************************************************************/ 863 864 death(how) 865 char *how; 866 { 867 FILE *fp; /* for updating various files */ 868 int ch; /* input */ 869 static char *deathmesg[] = 870 /* add more messages here, if desired */ 871 { 872 "You have been wounded beyond repair. ", 873 "You have been disemboweled. ", 874 "You've been mashed, mauled, and spit upon. (You're dead.)\n", 875 "You died! ", 876 "You're a complete failure -- you've died!!\n", 877 "You have been dealt a fatal blow! " 878 }; 879 880 clear(); 881 882 if (strcmp(how, "Stupidity") != 0) 883 { 884 if (Player.p_level > 9999.0) 885 /* old age */ 886 addstr("Characters must be retired upon reaching level 10000. Sorry."); 887 else if (Player.p_lives > 0) 888 /* extra lives */ 889 { 890 addstr("You should be more cautious. You've been killed.\n"); 891 printw("You only have %d more chance(s).\n", --Player.p_lives); 892 more(3); 893 Player.p_energy = Player.p_maxenergy; 894 return; 895 } 896 else if (Player.p_specialtype == SC_VALAR) 897 { 898 addstr("You had your chances, but Valar aren't totally\n"); 899 addstr("immortal. You are now left to wither and die . . .\n"); 900 more(3); 901 Player.p_brains = Player.p_level / 25.0; 902 Player.p_energy = Player.p_maxenergy /= 5.0; 903 Player.p_quksilver = Player.p_sword = 0.0; 904 Player.p_specialtype = SC_COUNCIL; 905 return; 906 } 907 else if (Player.p_ring.ring_inuse && 908 (Player.p_ring.ring_type == R_DLREG || Player.p_ring.ring_type == R_NAZREG)) 909 /* good ring in use - saved from death */ 910 { 911 mvaddstr(4, 0, "Your ring saved you from death!\n"); 912 refresh(); 913 Player.p_ring.ring_type = R_NONE; 914 Player.p_energy = Player.p_maxenergy / 12.0 + 1.0; 915 if (Player.p_crowns > 0) 916 --Player.p_crowns; 917 return; 918 } 919 else if (Player.p_ring.ring_type == R_BAD 920 || Player.p_ring.ring_type == R_SPOILED) 921 /* bad ring in possession; name idiot after player */ 922 { 923 mvaddstr(4, 0, 924 "Your ring has taken control of you and turned you into a monster!\n"); 925 fseek(Monstfp, 13L * SZ_MONSTERSTRUCT, 0); 926 fread((char *) &Curmonster, SZ_MONSTERSTRUCT, 1, Monstfp); 927 strcpy(Curmonster.m_name, Player.p_name); 928 fseek(Monstfp, 13L * SZ_MONSTERSTRUCT, 0); 929 fwrite((char *) &Curmonster, SZ_MONSTERSTRUCT, 1, Monstfp); 930 fflush(Monstfp); 931 } 932 } 933 934 enterscore(); /* update score board */ 935 936 /* put info in last dead file */ 937 fp = fopen(Lastdead, "w"); 938 fprintf(fp,"%s (%s, run by %s, level %.0f, killed by %s)", 939 Player.p_name, descrtype(&Player, TRUE), 940 Player.p_login, Player.p_level, how); 941 fclose(fp); 942 943 /* let other players know */ 944 fp = fopen(Messfile, "w"); 945 fprintf(fp, "%s was killed by %s.", Player.p_name, how); 946 fclose(fp); 947 948 freerecord(&Player, Fileloc); 949 950 clear(); 951 move(10, 0); 952 addstr(deathmesg[(int) ROLL(0.0, (double) sizeof(deathmesg) / sizeof(char *))]); 953 addstr("Care to give it another try ? "); 954 ch = getanswer("NY", FALSE); 955 956 if (ch == 'Y') 957 { 958 cleanup(FALSE); 959 execl(Gameprog, "phantasia", "-s", (Wizard ? "-S": (char *) NULL), 0); 960 exit(0); 961 /*NOTREACHED*/ 962 } 963 964 cleanup(TRUE); 965 /*NOTREACHED*/ 966 } 967 /**/ 968 /************************************************************************ 969 / 970 / FUNCTION NAME: writerecord() 971 / 972 / FUNCTION: update structure in player file 973 / 974 / AUTHOR: E. A. Estes, 12/4/85 975 / 976 / ARGUMENTS: 977 / struct player *playerp - pointer to structure to write out 978 / long place - location in file to updata 979 / 980 / RETURN VALUE: none 981 / 982 / MODULES CALLED: fseek(), fwrite(), fflush() 983 / 984 / GLOBAL INPUTS: *Playersfp 985 / 986 / GLOBAL OUTPUTS: none 987 / 988 / DESCRIPTION: 989 / Update location in player file with given structure. 990 / 991 /************************************************************************/ 992 993 writerecord(playerp, place) 994 register struct player *playerp; 995 long place; 996 { 997 fseek(Playersfp, place, 0); 998 fwrite((char *) playerp, SZ_PLAYERSTRUCT, 1, Playersfp); 999 fflush(Playersfp); 1000 } 1001 /**/ 1002 /************************************************************************ 1003 / 1004 / FUNCTION NAME: explevel() 1005 / 1006 / FUNCTION: calculate level based upon experience 1007 / 1008 / AUTHOR: E. A. Estes, 12/4/85 1009 / 1010 / ARGUMENTS: 1011 / double experience - experience to calculate experience level from 1012 / 1013 / RETURN VALUE: experience level 1014 / 1015 / MODULES CALLED: pow(), floor() 1016 / 1017 / GLOBAL INPUTS: none 1018 / 1019 / GLOBAL OUTPUTS: none 1020 / 1021 / DESCRIPTION: 1022 / Experience level is a geometric progression. This has been finely 1023 / tuned over the years, and probably should not be changed. 1024 / 1025 /************************************************************************/ 1026 1027 double 1028 explevel(experience) 1029 double experience; 1030 { 1031 if (experience < 1.1e7) 1032 return(floor(pow((experience / 1000.0), 0.4875))); 1033 else 1034 return(floor(pow((experience / 1250.0), 0.4865))); 1035 } 1036 /**/ 1037 /************************************************************************ 1038 / 1039 / FUNCTION NAME: truncstring() 1040 / 1041 / FUNCTION: truncate trailing blanks off a string 1042 / 1043 / AUTHOR: E. A. Estes, 12/4/85 1044 / 1045 / ARGUMENTS: 1046 / char *string - pointer to null terminated string 1047 / 1048 / RETURN VALUE: none 1049 / 1050 / MODULES CALLED: strlen() 1051 / 1052 / GLOBAL INPUTS: none 1053 / 1054 / GLOBAL OUTPUTS: none 1055 / 1056 / DESCRIPTION: 1057 / Put nul characters in place of spaces at the end of the string. 1058 / 1059 /************************************************************************/ 1060 1061 truncstring(string) 1062 register char *string; 1063 { 1064 register int length; /* length of string */ 1065 1066 length = strlen(string); 1067 while (string[--length] == ' ') 1068 string[length] = '\0'; 1069 } 1070 /**/ 1071 /************************************************************************ 1072 / 1073 / FUNCTION NAME: altercoordinates() 1074 / 1075 / FUNCTION: Alter x, y coordinates and set/check location flags 1076 / 1077 / AUTHOR: E. A. Estes, 12/16/85 1078 / 1079 / ARGUMENTS: 1080 / double xnew, ynew - new x, y coordinates 1081 / int operation - operation to perform with coordinates 1082 / 1083 / RETURN VALUE: none 1084 / 1085 / MODULES CALLED: fabs(), floor(), drandom(), distance() 1086 / 1087 / GLOBAL INPUTS: Circle, Beyond, Player 1088 / 1089 / GLOBAL OUTPUTS: Marsh, Circle, Beyond, Throne, Player, Changed 1090 / 1091 / DESCRIPTION: 1092 / This module is called whenever the player's coordinates are altered. 1093 / If the player is beyond the point of no return, he/she is forced 1094 / to stay there. 1095 / 1096 /************************************************************************/ 1097 1098 altercoordinates(xnew, ynew, operation) 1099 double xnew; 1100 double ynew; 1101 int operation; 1102 { 1103 switch (operation) 1104 { 1105 case A_FORCED: /* move with no checks */ 1106 break; 1107 1108 case A_NEAR: /* pick random coordinates near */ 1109 xnew = Player.p_x + ROLL(1.0, 5.0); 1110 ynew = Player.p_y - ROLL(1.0, 5.0); 1111 /* fall through for check */ 1112 1113 case A_SPECIFIC: /* just move player */ 1114 if (Beyond && fabs(xnew) < D_BEYOND && fabs(ynew) < D_BEYOND) 1115 /* 1116 * cannot move back from point of no return 1117 * pick the largest coordinate to remain unchanged 1118 */ 1119 { 1120 if (fabs(xnew) > fabs(ynew)) 1121 xnew = SGN(Player.p_x) * MAX(fabs(Player.p_x), D_BEYOND); 1122 else 1123 ynew = SGN(Player.p_y) * MAX(fabs(Player.p_y), D_BEYOND); 1124 } 1125 break; 1126 1127 case A_FAR: /* pick random coordinates far */ 1128 xnew = Player.p_x + SGN(Player.p_x) * ROLL(50 * Circle, 250 * Circle); 1129 ynew = Player.p_y + SGN(Player.p_y) * ROLL(50 * Circle, 250 * Circle); 1130 break; 1131 } 1132 1133 /* now set location flags and adjust coordinates */ 1134 Circle = CIRCLE(Player.p_x = floor(xnew), Player.p_y = floor(ynew)); 1135 1136 /* set up flags based upon location */ 1137 Throne = Marsh = Beyond = FALSE; 1138 1139 if (Player.p_x == 0.0 && Player.p_y == 0.0) 1140 Throne = TRUE; 1141 else if (Circle < 35 && Circle >= 20) 1142 Marsh = TRUE; 1143 else if (MAX(fabs(Player.p_x), fabs(Player.p_y)) >= D_BEYOND) 1144 Beyond = TRUE; 1145 1146 Changed = TRUE; 1147 } 1148 /**/ 1149 /************************************************************************ 1150 / 1151 / FUNCTION NAME: readrecord() 1152 / 1153 / FUNCTION: read a player structure from file 1154 / 1155 / AUTHOR: E. A. Estes, 12/4/85 1156 / 1157 / ARGUMENTS: 1158 / struct player *playerp - pointer to structure to fill 1159 / int loc - location of record to read 1160 / 1161 / RETURN VALUE: none 1162 / 1163 / MODULES CALLED: fread(), fseek() 1164 / 1165 / GLOBAL INPUTS: *Playersfp 1166 / 1167 / GLOBAL OUTPUTS: none 1168 / 1169 / DESCRIPTION: 1170 / Read structure information from player file. 1171 / 1172 /************************************************************************/ 1173 1174 readrecord(playerp, loc) 1175 register struct player *playerp; 1176 long loc; 1177 { 1178 fseek(Playersfp, loc, 0); 1179 fread((char *) playerp, SZ_PLAYERSTRUCT, 1, Playersfp); 1180 } 1181 /**/ 1182 /************************************************************************ 1183 / 1184 / FUNCTION NAME: adjuststats() 1185 / 1186 / FUNCTION: adjust player statistics 1187 / 1188 / AUTHOR: E. A. Estes, 12/4/85 1189 / 1190 / ARGUMENTS: none 1191 / 1192 / RETURN VALUE: none 1193 / 1194 / MODULES CALLED: death(), floor(), drandom(), explevel(), movelevel() 1195 / 1196 / GLOBAL INPUTS: Player, *Statptr 1197 / 1198 / GLOBAL OUTPUTS: Circle, Player, Timeout 1199 / 1200 / DESCRIPTION: 1201 / Handle adjustment and maximums on various player characteristics. 1202 / 1203 /************************************************************************/ 1204 1205 adjuststats() 1206 { 1207 double dtemp; /* for temporary calculations */ 1208 1209 if (explevel(Player.p_experience) > Player.p_level) 1210 /* move one or more levels */ 1211 { 1212 movelevel(); 1213 if (Player.p_level > 5.0) 1214 Timeout = TRUE; 1215 } 1216 1217 if (Player.p_specialtype == SC_VALAR) 1218 /* valar */ 1219 Circle = Player.p_level / 5.0; 1220 1221 /* calculate effective quickness */ 1222 dtemp = ((Player.p_gold + Player.p_gems / 2.0) - 1000.0) / Statptr->c_goldtote 1223 - Player.p_level;; 1224 dtemp = MAX(0.0, dtemp); /* gold slows player down */ 1225 Player.p_speed = Player.p_quickness + Player.p_quksilver - dtemp; 1226 1227 /* calculate effective strength */ 1228 if (Player.p_poison > 0.0) 1229 /* poison makes player weaker */ 1230 { 1231 dtemp = 1.0 - Player.p_poison * Statptr->c_weakness / 800.0; 1232 dtemp = MAX(0.1, dtemp); 1233 } 1234 else 1235 dtemp = 1.0; 1236 Player.p_might = dtemp * Player.p_strength + Player.p_sword; 1237 1238 /* insure that important things are within limits */ 1239 Player.p_quksilver = MIN(99.0, Player.p_quksilver); 1240 Player.p_mana = MIN(Player.p_mana, 1241 Player.p_level * Statptr->c_maxmana + 1000.0); 1242 Player.p_brains = MIN(Player.p_brains, 1243 Player.p_level * Statptr->c_maxbrains + 200.0); 1244 Player.p_charms = MIN(Player.p_charms, Player.p_level + 10.0); 1245 1246 /* 1247 * some implementations have problems with floating point compare 1248 * we work around it with this stuff 1249 */ 1250 Player.p_gold = floor(Player.p_gold) + 0.1; 1251 Player.p_gems = floor(Player.p_gems) + 0.1; 1252 Player.p_mana = floor(Player.p_mana) + 0.1; 1253 1254 if (Player.p_ring.ring_type != R_NONE) 1255 /* do ring things */ 1256 { 1257 /* rest to max */ 1258 Player.p_energy = Player.p_maxenergy + Player.p_shield; 1259 1260 if (Player.p_ring.ring_duration <= 0) 1261 /* clean up expired rings */ 1262 switch (Player.p_ring.ring_type) 1263 { 1264 case R_BAD: /* ring drives player crazy */ 1265 Player.p_ring.ring_type = R_SPOILED; 1266 Player.p_ring.ring_duration = (short) ROLL(10.0, 25.0); 1267 break; 1268 1269 case R_NAZREG: /* ring disappears */ 1270 Player.p_ring.ring_type = R_NONE; 1271 break; 1272 1273 case R_SPOILED: /* ring kills player */ 1274 death("A cursed ring"); 1275 break; 1276 1277 case R_DLREG: /* this ring doesn't expire */ 1278 Player.p_ring.ring_duration = 0; 1279 break; 1280 } 1281 } 1282 1283 if (Player.p_age / N_AGE > Player.p_degenerated) 1284 /* age player slightly */ 1285 { 1286 ++Player.p_degenerated; 1287 if (Player.p_quickness > 23.0) 1288 Player.p_quickness *= 0.99; 1289 Player.p_strength *= 0.97; 1290 Player.p_brains *= 0.95; 1291 Player.p_magiclvl *= 0.97; 1292 Player.p_maxenergy *= 0.95; 1293 Player.p_quksilver *= 0.95; 1294 Player.p_sword *= 0.93; 1295 Player.p_shield *= 0.93; 1296 } 1297 } 1298 /**/ 1299 /************************************************************************ 1300 / 1301 / FUNCTION NAME: initplayer() 1302 / 1303 / FUNCTION: initialize a character 1304 / 1305 / AUTHOR: E. A. Estes, 12/4/85 1306 / 1307 / ARGUMENTS: 1308 / struct player *playerp - pointer to structure to init 1309 / 1310 / RETURN VALUE: none 1311 / 1312 / MODULES CALLED: floor(), drandom() 1313 / 1314 / GLOBAL INPUTS: none 1315 / 1316 / GLOBAL OUTPUTS: none 1317 / 1318 / DESCRIPTION: 1319 / Put a bunch of default values in the given structure. 1320 / 1321 /************************************************************************/ 1322 1323 initplayer(playerp) 1324 register struct player *playerp; 1325 { 1326 playerp->p_experience = 1327 playerp->p_level = 1328 playerp->p_strength = 1329 playerp->p_sword = 1330 playerp->p_might = 1331 playerp->p_energy = 1332 playerp->p_maxenergy = 1333 playerp->p_shield = 1334 playerp->p_quickness = 1335 playerp->p_quksilver = 1336 playerp->p_speed = 1337 playerp->p_magiclvl = 1338 playerp->p_mana = 1339 playerp->p_brains = 1340 playerp->p_poison = 1341 playerp->p_gems = 1342 playerp->p_sin = 1343 playerp->p_1scratch = 1344 playerp->p_2scratch = 0.0; 1345 1346 playerp->p_gold = ROLL(50.0, 75.0) + 0.1; /* give some gold */ 1347 1348 playerp->p_x = ROLL(-125.0, 251.0); 1349 playerp->p_y = ROLL(-125.0, 251.0); /* give random x, y */ 1350 1351 /* clear ring */ 1352 playerp->p_ring.ring_type = R_NONE; 1353 playerp->p_ring.ring_duration = 0; 1354 playerp->p_ring.ring_inuse = FALSE; 1355 1356 playerp->p_age = 0L; 1357 1358 playerp->p_degenerated = 1; /* don't degenerate initially */ 1359 1360 playerp->p_type = C_FIGHTER; /* default */ 1361 playerp->p_specialtype = SC_NONE; 1362 playerp->p_lives = 1363 playerp->p_crowns = 1364 playerp->p_charms = 1365 playerp->p_amulets = 1366 playerp->p_holywater = 1367 playerp->p_lastused = 0; 1368 playerp->p_status = S_NOTUSED; 1369 playerp->p_tampered = T_OFF; 1370 playerp->p_istat = I_OFF; 1371 1372 playerp->p_palantir = 1373 playerp->p_blessing = 1374 playerp->p_virgin = 1375 playerp->p_blindness = FALSE; 1376 1377 playerp->p_name[0] = 1378 playerp->p_password[0] = 1379 playerp->p_login[0] = '\0'; 1380 } 1381 /**/ 1382 /************************************************************************ 1383 / 1384 / FUNCTION NAME: readmessage() 1385 / 1386 / FUNCTION: read message from other players 1387 / 1388 / AUTHOR: E. A. Estes, 12/4/85 1389 / 1390 / ARGUMENTS: none 1391 / 1392 / RETURN VALUE: none 1393 / 1394 / MODULES CALLED: fseek(), fgets(), wmove(), waddstr(), wclrtoeol() 1395 / 1396 / GLOBAL INPUTS: *stdscr, Databuf[], *Messagefp 1397 / 1398 / GLOBAL OUTPUTS: none 1399 / 1400 / DESCRIPTION: 1401 / If there is a message from other players, print it. 1402 / 1403 /************************************************************************/ 1404 1405 readmessage() 1406 { 1407 move(3, 0); 1408 clrtoeol(); 1409 fseek(Messagefp, 0L, 0); 1410 if (fgets(Databuf, SZ_DATABUF, Messagefp) != NULL) 1411 addstr(Databuf); 1412 } 1413 /**/ 1414 /************************************************************************ 1415 / 1416 / FUNCTION NAME: error() 1417 / 1418 / FUNCTION: process evironment error 1419 / 1420 / AUTHOR: E. A. Estes, 12/4/85 1421 / 1422 / ARGUMENTS: 1423 / char *whichfile - pointer to name of file which caused error 1424 / 1425 / RETURN VALUE: none 1426 / 1427 / MODULES CALLED: wclear(), cleanup() 1428 / 1429 / GLOBAL INPUTS: errno, *stdscr, printw(), printf(), Windows 1430 / 1431 / GLOBAL OUTPUTS: none 1432 / 1433 / DESCRIPTION: 1434 / Print message about offending file, and exit. 1435 / 1436 /************************************************************************/ 1437 1438 error(whichfile) 1439 char *whichfile; 1440 { 1441 extern int errno; 1442 extern printw(), printf(); 1443 int (*funcp)(); 1444 1445 if (Windows) 1446 { 1447 funcp = printw; 1448 clear(); 1449 } 1450 else 1451 funcp = printf; 1452 1453 (*funcp)("An unrecoverable error has occurred reading %s. (errno = %d)\n", whichfile, errno); 1454 (*funcp)("Please run 'setup' to determine the problem.\n"); 1455 cleanup(TRUE); 1456 /*NOTREACHED*/ 1457 } 1458 /**/ 1459 /************************************************************************ 1460 / 1461 / FUNCTION NAME: distance() 1462 / 1463 / FUNCTION: calculate distance between two points 1464 / 1465 / AUTHOR: E. A. Estes, 12/4/85 1466 / 1467 / ARGUMENTS: 1468 / double x1, y1 - x, y coordinates of first point 1469 / double x2, y2 - x, y coordinates of second point 1470 / 1471 / RETURN VALUE: distance between the two points 1472 / 1473 / MODULES CALLED: sqrt() 1474 / 1475 / GLOBAL INPUTS: none 1476 / 1477 / GLOBAL OUTPUTS: none 1478 / 1479 / DESCRIPTION: 1480 / This function is provided because someone's hypot() library function 1481 / fails if x1 == x2 && y1 == y2. 1482 / 1483 /************************************************************************/ 1484 1485 double 1486 distance(x1, x2, y1, y2) 1487 double x1, x2, y1, y2; 1488 { 1489 double deltax, deltay; 1490 1491 deltax = x1 - x2; 1492 deltay = y1 - y2; 1493 return(sqrt(deltax * deltax + deltay * deltay)); 1494 } 1495 1496 /**/ 1497 /************************************************************************ 1498 / 1499 / FUNCTION NAME: ill_sig() 1500 / 1501 / FUNCTION: exit upon trapping an illegal signal 1502 / 1503 / AUTHOR: E. A. Estes, 12/4/85 1504 / 1505 / ARGUMENTS: 1506 / int whichsig - signal which occured to cause jump to here 1507 / 1508 / RETURN VALUE: none 1509 / 1510 / MODULES CALLED: wclear(), printw(), cleanup() 1511 / 1512 / GLOBAL INPUTS: *stdscr 1513 / 1514 / GLOBAL OUTPUTS: none 1515 / 1516 / DESCRIPTION: 1517 / When an illegal signal is caught, print a message, and cleanup. 1518 / 1519 /************************************************************************/ 1520 1521 ill_sig(whichsig) 1522 int whichsig; 1523 { 1524 clear(); 1525 if (!(whichsig == SIGINT || whichsig == SIGQUIT)) 1526 printw("Error: caught signal # %d.\n", whichsig); 1527 cleanup(TRUE); 1528 /*NOTREACHED*/ 1529 } 1530 /**/ 1531 /************************************************************************ 1532 / 1533 / FUNCTION NAME: descrstatus() 1534 / 1535 / FUNCTION: return a string describing the player status 1536 / 1537 / AUTHOR: E. A. Estes, 3/3/86 1538 / 1539 / ARGUMENTS: 1540 / struct player playerp - pointer to player structure to describe 1541 / 1542 / RETURN VALUE: string describing player's status 1543 / 1544 / MODULES CALLED: none 1545 / 1546 / GLOBAL INPUTS: none 1547 / 1548 / GLOBAL OUTPUTS: none 1549 / 1550 / DESCRIPTION: 1551 / Return verbal description of player status. 1552 / If player status is S_PLAYING, check for low energy and blindness. 1553 / 1554 /************************************************************************/ 1555 1556 char * 1557 descrstatus(playerp) 1558 register struct player *playerp; 1559 { 1560 switch (playerp->p_status) 1561 { 1562 case S_PLAYING: 1563 if (playerp->p_energy < 0.2 * (playerp->p_maxenergy + playerp->p_shield)) 1564 return("Low Energy"); 1565 else if (playerp->p_blindness) 1566 return("Blind"); 1567 else 1568 return("In game"); 1569 1570 case S_CLOAKED: 1571 return("Cloaked"); 1572 1573 case S_INBATTLE: 1574 return("In Battle"); 1575 1576 case S_MONSTER: 1577 return("Encounter"); 1578 1579 case S_TRADING: 1580 return("Trading"); 1581 1582 case S_OFF: 1583 return("Off"); 1584 1585 case S_HUNGUP: 1586 return("Hung up"); 1587 1588 default: 1589 return(""); 1590 } 1591 } 1592 /**/ 1593 /************************************************************************ 1594 / 1595 / FUNCTION NAME: drandom() 1596 / 1597 / FUNCTION: return a random floating point number from 0.0 < 1.0 1598 / 1599 / AUTHOR: E. A. Estes, 2/7/86 1600 / 1601 / ARGUMENTS: none 1602 / 1603 / RETURN VALUE: none 1604 / 1605 / MODULES CALLED: random() 1606 / 1607 / GLOBAL INPUTS: none 1608 / 1609 / GLOBAL OUTPUTS: none 1610 / 1611 / DESCRIPTION: 1612 / Convert random integer from library routine into a floating 1613 / point number, and divide by the largest possible random number. 1614 / We mask large integers with 32767 to handle sites that return 1615 / 31 bit random integers. 1616 / 1617 /************************************************************************/ 1618 1619 double 1620 drandom() 1621 { 1622 if (sizeof(int) != 2) 1623 /* use only low bits */ 1624 return((double) (random() & 0x7fff) / 32768.0); 1625 else 1626 return((double) random() / 32768.0); 1627 } 1628 /**/ 1629 /************************************************************************ 1630 / 1631 / FUNCTION NAME: collecttaxes() 1632 / 1633 / FUNCTION: collect taxes from current player 1634 / 1635 / AUTHOR: E. A. Estes, 2/7/86 1636 / 1637 / ARGUMENTS: 1638 / double gold - amount of gold to tax 1639 / double gems - amount of gems to tax 1640 / 1641 / RETURN VALUE: none 1642 / 1643 / MODULES CALLED: fread(), fseek(), fopen(), floor(), fwrite(), fclose() 1644 / 1645 / GLOBAL INPUTS: Player, Goldfile[] 1646 / 1647 / GLOBAL OUTPUTS: Player 1648 / 1649 / DESCRIPTION: 1650 / Pay taxes on gold and gems. If the player does not have enough 1651 / gold to pay taxes on the added gems, convert some gems to gold. 1652 / Add taxes to tax data base; add remaining gold and gems to 1653 / player's cache. 1654 / 1655 /************************************************************************/ 1656 1657 collecttaxes(gold, gems) 1658 double gold; 1659 double gems; 1660 { 1661 FILE *fp; /* to update Goldfile */ 1662 double dtemp; /* for temporary calculations */ 1663 double taxes; /* tax liability */ 1664 1665 /* add to cache */ 1666 Player.p_gold += gold; 1667 Player.p_gems += gems; 1668 1669 /* calculate tax liability */ 1670 taxes = N_TAXAMOUNT / 100.0 * (N_GEMVALUE * gems + gold); 1671 1672 if (Player.p_gold < taxes) 1673 /* not enough gold to pay taxes, must convert some gems to gold */ 1674 { 1675 dtemp = floor(taxes / N_GEMVALUE + 1.0); /* number of gems to convert */ 1676 1677 if (Player.p_gems >= dtemp) 1678 /* player has enough to convert */ 1679 { 1680 Player.p_gems -= dtemp; 1681 Player.p_gold += dtemp * N_GEMVALUE; 1682 } 1683 else 1684 /* take everything; this should never happen */ 1685 { 1686 Player.p_gold += Player.p_gems * N_GEMVALUE; 1687 Player.p_gems = 0.0; 1688 taxes = Player.p_gold; 1689 } 1690 } 1691 1692 Player.p_gold -= taxes; 1693 1694 if ((fp = fopen(Goldfile, "r+")) != NULL) 1695 /* update taxes */ 1696 { 1697 dtemp = 0.0; 1698 fread((char *) &dtemp, sizeof(double), 1, fp); 1699 dtemp += floor(taxes); 1700 fseek(fp, 0L, 0); 1701 fwrite((char *) &dtemp, sizeof(double), 1, fp); 1702 fclose(fp); 1703 } 1704 } 1705