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