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