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