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