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