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