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.7 2006/09/09 02:21:49 pavalos 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", (Wizard ? "-S": NULL), NULL); 1000 exit(0); 1001 /*NOTREACHED*/ 1002 } 1003 1004 cleanup(TRUE); 1005 /*NOTREACHED*/ 1006 } 1007 /**/ 1008 /************************************************************************ 1009 / 1010 / FUNCTION NAME: writerecord() 1011 / 1012 / FUNCTION: update structure in player file 1013 / 1014 / AUTHOR: E. A. Estes, 12/4/85 1015 / 1016 / ARGUMENTS: 1017 / struct player *playerp - pointer to structure to write out 1018 / long place - location in file to updata 1019 / 1020 / RETURN VALUE: none 1021 / 1022 / MODULES CALLED: fseek(), fwrite(), fflush() 1023 / 1024 / GLOBAL INPUTS: *Playersfp 1025 / 1026 / GLOBAL OUTPUTS: none 1027 / 1028 / DESCRIPTION: 1029 / Update location in player file with given structure. 1030 / 1031 *************************************************************************/ 1032 1033 void 1034 writerecord(struct player *playerp, long place) 1035 { 1036 fseek(Playersfp, place, 0); 1037 fwrite((char *) playerp, SZ_PLAYERSTRUCT, 1, Playersfp); 1038 fflush(Playersfp); 1039 } 1040 /**/ 1041 /************************************************************************ 1042 / 1043 / FUNCTION NAME: explevel() 1044 / 1045 / FUNCTION: calculate level based upon experience 1046 / 1047 / AUTHOR: E. A. Estes, 12/4/85 1048 / 1049 / ARGUMENTS: 1050 / double experience - experience to calculate experience level from 1051 / 1052 / RETURN VALUE: experience level 1053 / 1054 / MODULES CALLED: pow(), floor() 1055 / 1056 / GLOBAL INPUTS: none 1057 / 1058 / GLOBAL OUTPUTS: none 1059 / 1060 / DESCRIPTION: 1061 / Experience level is a geometric progression. This has been finely 1062 / tuned over the years, and probably should not be changed. 1063 / 1064 *************************************************************************/ 1065 1066 double 1067 explevel(double experience) 1068 { 1069 if (experience < 1.1e7) 1070 return(floor(pow((experience / 1000.0), 0.4875))); 1071 else 1072 return(floor(pow((experience / 1250.0), 0.4865))); 1073 } 1074 /**/ 1075 /************************************************************************ 1076 / 1077 / FUNCTION NAME: truncstring() 1078 / 1079 / FUNCTION: truncate trailing blanks off a string 1080 / 1081 / AUTHOR: E. A. Estes, 12/4/85 1082 / 1083 / ARGUMENTS: 1084 / char *string - pointer to null terminated string 1085 / 1086 / RETURN VALUE: none 1087 / 1088 / MODULES CALLED: strlen() 1089 / 1090 / GLOBAL INPUTS: none 1091 / 1092 / GLOBAL OUTPUTS: none 1093 / 1094 / DESCRIPTION: 1095 / Put nul characters in place of spaces at the end of the string. 1096 / 1097 *************************************************************************/ 1098 1099 void 1100 truncstring(char *string) 1101 { 1102 size_t length; /* length of string */ 1103 1104 length = strlen(string); 1105 while (string[--length] == ' ') 1106 string[length] = '\0'; 1107 } 1108 /**/ 1109 /************************************************************************ 1110 / 1111 / FUNCTION NAME: altercoordinates() 1112 / 1113 / FUNCTION: Alter x, y coordinates and set/check location flags 1114 / 1115 / AUTHOR: E. A. Estes, 12/16/85 1116 / 1117 / ARGUMENTS: 1118 / double xnew, ynew - new x, y coordinates 1119 / int operation - operation to perform with coordinates 1120 / 1121 / RETURN VALUE: none 1122 / 1123 / MODULES CALLED: fabs(), floor(), drandom(), distance() 1124 / 1125 / GLOBAL INPUTS: Circle, Beyond, Player 1126 / 1127 / GLOBAL OUTPUTS: Marsh, Circle, Beyond, Throne, Player, Changed 1128 / 1129 / DESCRIPTION: 1130 / This module is called whenever the player's coordinates are altered. 1131 / If the player is beyond the point of no return, he/she is forced 1132 / to stay there. 1133 / 1134 *************************************************************************/ 1135 1136 void 1137 altercoordinates(double xnew, double ynew, int operation) 1138 { 1139 switch (operation) 1140 { 1141 case A_FORCED: /* move with no checks */ 1142 break; 1143 1144 case A_NEAR: /* pick random coordinates near */ 1145 xnew = Player.p_x + ROLL(1.0, 5.0); 1146 ynew = Player.p_y - ROLL(1.0, 5.0); 1147 /* fall through for check */ 1148 1149 case A_SPECIFIC: /* just move player */ 1150 if (Beyond && fabs(xnew) < D_BEYOND && fabs(ynew) < D_BEYOND) 1151 /* 1152 * cannot move back from point of no return 1153 * pick the largest coordinate to remain unchanged 1154 */ 1155 { 1156 if (fabs(xnew) > fabs(ynew)) 1157 xnew = SGN(Player.p_x) * MAX(fabs(Player.p_x), D_BEYOND); 1158 else 1159 ynew = SGN(Player.p_y) * MAX(fabs(Player.p_y), D_BEYOND); 1160 } 1161 break; 1162 1163 case A_FAR: /* pick random coordinates far */ 1164 xnew = Player.p_x + SGN(Player.p_x) * ROLL(50 * Circle, 250 * Circle); 1165 ynew = Player.p_y + SGN(Player.p_y) * ROLL(50 * Circle, 250 * Circle); 1166 break; 1167 } 1168 1169 /* now set location flags and adjust coordinates */ 1170 Circle = CIRCLE(Player.p_x = floor(xnew), Player.p_y = floor(ynew)); 1171 1172 /* set up flags based upon location */ 1173 Throne = Marsh = Beyond = FALSE; 1174 1175 if (Player.p_x == 0.0 && Player.p_y == 0.0) 1176 Throne = TRUE; 1177 else if (Circle < 35 && Circle >= 20) 1178 Marsh = TRUE; 1179 else if (MAX(fabs(Player.p_x), fabs(Player.p_y)) >= D_BEYOND) 1180 Beyond = TRUE; 1181 1182 Changed = TRUE; 1183 } 1184 /**/ 1185 /************************************************************************ 1186 / 1187 / FUNCTION NAME: readrecord() 1188 / 1189 / FUNCTION: read a player structure from file 1190 / 1191 / AUTHOR: E. A. Estes, 12/4/85 1192 / 1193 / ARGUMENTS: 1194 / struct player *playerp - pointer to structure to fill 1195 / int loc - location of record to read 1196 / 1197 / RETURN VALUE: none 1198 / 1199 / MODULES CALLED: fread(), fseek() 1200 / 1201 / GLOBAL INPUTS: *Playersfp 1202 / 1203 / GLOBAL OUTPUTS: none 1204 / 1205 / DESCRIPTION: 1206 / Read structure information from player file. 1207 / 1208 *************************************************************************/ 1209 1210 void 1211 readrecord(struct player *playerp, long loc) 1212 { 1213 fseek(Playersfp, loc, 0); 1214 fread((char *) playerp, SZ_PLAYERSTRUCT, 1, Playersfp); 1215 } 1216 /**/ 1217 /************************************************************************ 1218 / 1219 / FUNCTION NAME: adjuststats() 1220 / 1221 / FUNCTION: adjust player statistics 1222 / 1223 / AUTHOR: E. A. Estes, 12/4/85 1224 / 1225 / ARGUMENTS: none 1226 / 1227 / RETURN VALUE: none 1228 / 1229 / MODULES CALLED: death(), floor(), drandom(), explevel(), movelevel() 1230 / 1231 / GLOBAL INPUTS: Player, *Statptr 1232 / 1233 / GLOBAL OUTPUTS: Circle, Player, Timeout 1234 / 1235 / DESCRIPTION: 1236 / Handle adjustment and maximums on various player characteristics. 1237 / 1238 *************************************************************************/ 1239 1240 void 1241 adjuststats(void) 1242 { 1243 double dtemp; /* for temporary calculations */ 1244 1245 if (explevel(Player.p_experience) > Player.p_level) 1246 /* move one or more levels */ 1247 { 1248 movelevel(); 1249 if (Player.p_level > 5.0) 1250 Timeout = TRUE; 1251 } 1252 1253 if (Player.p_specialtype == SC_VALAR) 1254 /* valar */ 1255 Circle = Player.p_level / 5.0; 1256 1257 /* calculate effective quickness */ 1258 dtemp = ((Player.p_gold + Player.p_gems / 2.0) - 1000.0) / Statptr->c_goldtote 1259 - Player.p_level; 1260 dtemp = MAX(0.0, dtemp); /* gold slows player down */ 1261 Player.p_speed = Player.p_quickness + Player.p_quksilver - dtemp; 1262 1263 /* calculate effective strength */ 1264 if (Player.p_poison > 0.0) 1265 /* poison makes player weaker */ 1266 { 1267 dtemp = 1.0 - Player.p_poison * Statptr->c_weakness / 800.0; 1268 dtemp = MAX(0.1, dtemp); 1269 } 1270 else 1271 dtemp = 1.0; 1272 Player.p_might = dtemp * Player.p_strength + Player.p_sword; 1273 1274 /* insure that important things are within limits */ 1275 Player.p_quksilver = MIN(99.0, Player.p_quksilver); 1276 Player.p_mana = MIN(Player.p_mana, 1277 Player.p_level * Statptr->c_maxmana + 1000.0); 1278 Player.p_brains = MIN(Player.p_brains, 1279 Player.p_level * Statptr->c_maxbrains + 200.0); 1280 Player.p_charms = MIN(Player.p_charms, Player.p_level + 10.0); 1281 1282 /* 1283 * some implementations have problems with floating point compare 1284 * we work around it with this stuff 1285 */ 1286 Player.p_gold = floor(Player.p_gold) + 0.1; 1287 Player.p_gems = floor(Player.p_gems) + 0.1; 1288 Player.p_mana = floor(Player.p_mana) + 0.1; 1289 1290 if (Player.p_ring.ring_type != R_NONE) 1291 /* do ring things */ 1292 { 1293 /* rest to max */ 1294 Player.p_energy = Player.p_maxenergy + Player.p_shield; 1295 1296 if (Player.p_ring.ring_duration <= 0) 1297 /* clean up expired rings */ 1298 switch (Player.p_ring.ring_type) 1299 { 1300 case R_BAD: /* ring drives player crazy */ 1301 Player.p_ring.ring_type = R_SPOILED; 1302 Player.p_ring.ring_duration = (short) ROLL(10.0, 25.0); 1303 break; 1304 1305 case R_NAZREG: /* ring disappears */ 1306 Player.p_ring.ring_type = R_NONE; 1307 break; 1308 1309 case R_SPOILED: /* ring kills player */ 1310 death("A cursed ring"); 1311 break; 1312 1313 case R_DLREG: /* this ring doesn't expire */ 1314 Player.p_ring.ring_duration = 0; 1315 break; 1316 } 1317 } 1318 1319 if (Player.p_age / N_AGE > Player.p_degenerated) 1320 /* age player slightly */ 1321 { 1322 ++Player.p_degenerated; 1323 if (Player.p_quickness > 23.0) 1324 Player.p_quickness *= 0.99; 1325 Player.p_strength *= 0.97; 1326 Player.p_brains *= 0.95; 1327 Player.p_magiclvl *= 0.97; 1328 Player.p_maxenergy *= 0.95; 1329 Player.p_quksilver *= 0.95; 1330 Player.p_sword *= 0.93; 1331 Player.p_shield *= 0.93; 1332 } 1333 } 1334 /**/ 1335 /************************************************************************ 1336 / 1337 / FUNCTION NAME: initplayer() 1338 / 1339 / FUNCTION: initialize a character 1340 / 1341 / AUTHOR: E. A. Estes, 12/4/85 1342 / 1343 / ARGUMENTS: 1344 / struct player *playerp - pointer to structure to init 1345 / 1346 / RETURN VALUE: none 1347 / 1348 / MODULES CALLED: floor(), drandom() 1349 / 1350 / GLOBAL INPUTS: none 1351 / 1352 / GLOBAL OUTPUTS: none 1353 / 1354 / DESCRIPTION: 1355 / Put a bunch of default values in the given structure. 1356 / 1357 *************************************************************************/ 1358 1359 void 1360 initplayer(struct player *playerp) 1361 { 1362 playerp->p_experience = 1363 playerp->p_level = 1364 playerp->p_strength = 1365 playerp->p_sword = 1366 playerp->p_might = 1367 playerp->p_energy = 1368 playerp->p_maxenergy = 1369 playerp->p_shield = 1370 playerp->p_quickness = 1371 playerp->p_quksilver = 1372 playerp->p_speed = 1373 playerp->p_magiclvl = 1374 playerp->p_mana = 1375 playerp->p_brains = 1376 playerp->p_poison = 1377 playerp->p_gems = 1378 playerp->p_sin = 1379 playerp->p_1scratch = 1380 playerp->p_2scratch = 0.0; 1381 1382 playerp->p_gold = ROLL(50.0, 75.0) + 0.1; /* give some gold */ 1383 1384 playerp->p_x = ROLL(-125.0, 251.0); 1385 playerp->p_y = ROLL(-125.0, 251.0); /* give random x, y */ 1386 1387 /* clear ring */ 1388 playerp->p_ring.ring_type = R_NONE; 1389 playerp->p_ring.ring_duration = 0; 1390 playerp->p_ring.ring_inuse = FALSE; 1391 1392 playerp->p_age = 0L; 1393 1394 playerp->p_degenerated = 1; /* don't degenerate initially */ 1395 1396 playerp->p_type = C_FIGHTER; /* default */ 1397 playerp->p_specialtype = SC_NONE; 1398 playerp->p_lives = 1399 playerp->p_crowns = 1400 playerp->p_charms = 1401 playerp->p_amulets = 1402 playerp->p_holywater = 1403 playerp->p_lastused = 0; 1404 playerp->p_status = S_NOTUSED; 1405 playerp->p_tampered = T_OFF; 1406 playerp->p_istat = I_OFF; 1407 1408 playerp->p_palantir = 1409 playerp->p_blessing = 1410 playerp->p_virgin = 1411 playerp->p_blindness = FALSE; 1412 1413 playerp->p_name[0] = 1414 playerp->p_password[0] = 1415 playerp->p_login[0] = '\0'; 1416 } 1417 /**/ 1418 /************************************************************************ 1419 / 1420 / FUNCTION NAME: readmessage() 1421 / 1422 / FUNCTION: read message from other players 1423 / 1424 / AUTHOR: E. A. Estes, 12/4/85 1425 / 1426 / ARGUMENTS: none 1427 / 1428 / RETURN VALUE: none 1429 / 1430 / MODULES CALLED: fseek(), fgets(), wmove(), waddstr(), wclrtoeol() 1431 / 1432 / GLOBAL INPUTS: *stdscr, Databuf[], *Messagefp 1433 / 1434 / GLOBAL OUTPUTS: none 1435 / 1436 / DESCRIPTION: 1437 / If there is a message from other players, print it. 1438 / 1439 *************************************************************************/ 1440 1441 void 1442 readmessage(void) 1443 { 1444 move(3, 0); 1445 clrtoeol(); 1446 fseek(Messagefp, 0L, 0); 1447 if (fgets(Databuf, SZ_DATABUF, Messagefp) != NULL) 1448 addstr(Databuf); 1449 } 1450 /**/ 1451 /************************************************************************ 1452 / 1453 / FUNCTION NAME: error() 1454 / 1455 / FUNCTION: process evironment error 1456 / 1457 / AUTHOR: E. A. Estes, 12/4/85 1458 / 1459 / ARGUMENTS: 1460 / char *whichfile - pointer to name of file which caused error 1461 / 1462 / RETURN VALUE: none 1463 / 1464 / MODULES CALLED: wclear(), cleanup() 1465 / 1466 / GLOBAL INPUTS: errno, *stdscr, printw(), printf(), Windows 1467 / 1468 / GLOBAL OUTPUTS: none 1469 / 1470 / DESCRIPTION: 1471 / Print message about offending file, and exit. 1472 / 1473 *************************************************************************/ 1474 1475 void 1476 error(const char *whichfile) 1477 { 1478 int (*funcp) (const char *, ...); 1479 1480 if (Windows) 1481 { 1482 funcp = (void *)printw; 1483 clear(); 1484 } 1485 else 1486 funcp = printf; 1487 1488 (*funcp)("An unrecoverable error has occurred reading %s. (errno = %d)\n", whichfile, errno); 1489 (*funcp)("Please run 'setup' to determine the problem.\n"); 1490 cleanup(TRUE); 1491 /*NOTREACHED*/ 1492 } 1493 /**/ 1494 /************************************************************************ 1495 / 1496 / FUNCTION NAME: distance() 1497 / 1498 / FUNCTION: calculate distance between two points 1499 / 1500 / AUTHOR: E. A. Estes, 12/4/85 1501 / 1502 / ARGUMENTS: 1503 / double x1, y1 - x, y coordinates of first point 1504 / double x2, y2 - x, y coordinates of second point 1505 / 1506 / RETURN VALUE: distance between the two points 1507 / 1508 / MODULES CALLED: sqrt() 1509 / 1510 / GLOBAL INPUTS: none 1511 / 1512 / GLOBAL OUTPUTS: none 1513 / 1514 / DESCRIPTION: 1515 / This function is provided because someone's hypot() library function 1516 / fails if x1 == x2 && y1 == y2. 1517 / 1518 *************************************************************************/ 1519 1520 double 1521 distance(double x_1, double x_2, double y_1, double y_2) 1522 { 1523 double deltax, deltay; 1524 1525 deltax = x_1 - x_2; 1526 deltay = y_1 - y_2; 1527 return(sqrt(deltax * deltax + deltay * deltay)); 1528 } 1529 1530 /**/ 1531 /************************************************************************ 1532 / 1533 / FUNCTION NAME: ill_sig() 1534 / 1535 / FUNCTION: exit upon trapping an illegal signal 1536 / 1537 / AUTHOR: E. A. Estes, 12/4/85 1538 / 1539 / ARGUMENTS: 1540 / int whichsig - signal which occured to cause jump to here 1541 / 1542 / RETURN VALUE: none 1543 / 1544 / MODULES CALLED: wclear(), printw(), cleanup() 1545 / 1546 / GLOBAL INPUTS: *stdscr 1547 / 1548 / GLOBAL OUTPUTS: none 1549 / 1550 / DESCRIPTION: 1551 / When an illegal signal is caught, print a message, and cleanup. 1552 / 1553 *************************************************************************/ 1554 1555 void 1556 ill_sig(int whichsig) 1557 { 1558 clear(); 1559 if (!(whichsig == SIGINT || whichsig == SIGQUIT)) 1560 printw("Error: caught signal # %d.\n", whichsig); 1561 cleanup(TRUE); 1562 /*NOTREACHED*/ 1563 } 1564 /**/ 1565 /************************************************************************ 1566 / 1567 / FUNCTION NAME: descrstatus() 1568 / 1569 / FUNCTION: return a string describing the player status 1570 / 1571 / AUTHOR: E. A. Estes, 3/3/86 1572 / 1573 / ARGUMENTS: 1574 / struct player playerp - pointer to player structure to describe 1575 / 1576 / RETURN VALUE: string describing player's status 1577 / 1578 / MODULES CALLED: none 1579 / 1580 / GLOBAL INPUTS: none 1581 / 1582 / GLOBAL OUTPUTS: none 1583 / 1584 / DESCRIPTION: 1585 / Return verbal description of player status. 1586 / If player status is S_PLAYING, check for low energy and blindness. 1587 / 1588 *************************************************************************/ 1589 1590 const char * 1591 descrstatus(struct player *playerp) 1592 { 1593 switch (playerp->p_status) 1594 { 1595 case S_PLAYING: 1596 if (playerp->p_energy < 0.2 * (playerp->p_maxenergy + playerp->p_shield)) 1597 return("Low Energy"); 1598 else if (playerp->p_blindness) 1599 return("Blind"); 1600 else 1601 return("In game"); 1602 1603 case S_CLOAKED: 1604 return("Cloaked"); 1605 1606 case S_INBATTLE: 1607 return("In Battle"); 1608 1609 case S_MONSTER: 1610 return("Encounter"); 1611 1612 case S_TRADING: 1613 return("Trading"); 1614 1615 case S_OFF: 1616 return("Off"); 1617 1618 case S_HUNGUP: 1619 return("Hung up"); 1620 1621 default: 1622 return(""); 1623 } 1624 } 1625 /**/ 1626 /************************************************************************ 1627 / 1628 / FUNCTION NAME: collecttaxes() 1629 / 1630 / FUNCTION: collect taxes from current player 1631 / 1632 / AUTHOR: E. A. Estes, 2/7/86 1633 / 1634 / ARGUMENTS: 1635 / double gold - amount of gold to tax 1636 / double gems - amount of gems to tax 1637 / 1638 / RETURN VALUE: none 1639 / 1640 / MODULES CALLED: fread(), fseek(), fopen(), floor(), fwrite(), fclose() 1641 / 1642 / GLOBAL INPUTS: Player 1643 / 1644 / GLOBAL OUTPUTS: Player 1645 / 1646 / DESCRIPTION: 1647 / Pay taxes on gold and gems. If the player does not have enough 1648 / gold to pay taxes on the added gems, convert some gems to gold. 1649 / Add taxes to tax data base; add remaining gold and gems to 1650 / player's cache. 1651 / 1652 *************************************************************************/ 1653 1654 void 1655 collecttaxes(double gold, double gems) 1656 { 1657 FILE *fp; /* to update Goldfile */ 1658 double dtemp; /* for temporary calculations */ 1659 double taxes; /* tax liability */ 1660 1661 /* add to cache */ 1662 Player.p_gold += gold; 1663 Player.p_gems += gems; 1664 1665 /* calculate tax liability */ 1666 taxes = N_TAXAMOUNT / 100.0 * (N_GEMVALUE * gems + gold); 1667 1668 if (Player.p_gold < taxes) 1669 /* not enough gold to pay taxes, must convert some gems to gold */ 1670 { 1671 dtemp = floor(taxes / N_GEMVALUE + 1.0); /* number of gems to convert */ 1672 1673 if (Player.p_gems >= dtemp) 1674 /* player has enough to convert */ 1675 { 1676 Player.p_gems -= dtemp; 1677 Player.p_gold += dtemp * N_GEMVALUE; 1678 } 1679 else 1680 /* take everything; this should never happen */ 1681 { 1682 Player.p_gold += Player.p_gems * N_GEMVALUE; 1683 Player.p_gems = 0.0; 1684 taxes = Player.p_gold; 1685 } 1686 } 1687 1688 Player.p_gold -= taxes; 1689 1690 if ((fp = fopen(_PATH_GOLD, "r+")) != NULL) 1691 /* update taxes */ 1692 { 1693 dtemp = 0.0; 1694 fread((char *) &dtemp, sizeof(double), 1, fp); 1695 dtemp += floor(taxes); 1696 fseek(fp, 0L, 0); 1697 fwrite((char *) &dtemp, sizeof(double), 1, fp); 1698 fclose(fp); 1699 } 1700 } 1701