1 /* $NetBSD: misc.c,v 1.7 2000/04/27 00:30:53 jdc Exp $ */ 2 3 /* 4 * misc.c Phantasia miscellaneous support routines 5 */ 6 7 #include "include.h" 8 9 10 void 11 movelevel() 12 { 13 const struct charstats *statptr; /* for pointing into Stattable */ 14 double new; /* new level */ 15 double inc; /* increment between new and old levels */ 16 17 Changed = TRUE; 18 19 if (Player.p_type == C_EXPER) 20 /* roll a type to use for increment */ 21 statptr = &Stattable[(int) ROLL(C_MAGIC, C_HALFLING - C_MAGIC + 1)]; 22 else 23 statptr = Statptr; 24 25 new = explevel(Player.p_experience); 26 inc = new - Player.p_level; 27 Player.p_level = new; 28 29 /* add increments to statistics */ 30 Player.p_strength += statptr->c_strength.increase * inc; 31 Player.p_mana += statptr->c_mana.increase * inc; 32 Player.p_brains += statptr->c_brains.increase * inc; 33 Player.p_magiclvl += statptr->c_magiclvl.increase * inc; 34 Player.p_maxenergy += statptr->c_energy.increase * inc; 35 36 /* rest to maximum upon reaching new level */ 37 Player.p_energy = Player.p_maxenergy + Player.p_shield; 38 39 if (Player.p_crowns > 0 && Player.p_level >= 1000.0) 40 /* no longer able to be king -- turn crowns into cash */ 41 { 42 Player.p_gold += ((double) Player.p_crowns) * 5000.0; 43 Player.p_crowns = 0; 44 } 45 if (Player.p_level >= 3000.0 && Player.p_specialtype < SC_COUNCIL) 46 /* make a member of the council */ 47 { 48 mvaddstr(6, 0, "You have made it to the Council of the Wise.\n"); 49 addstr("Good Luck on your search for the Holy Grail.\n"); 50 51 Player.p_specialtype = SC_COUNCIL; 52 53 /* no rings for council and above */ 54 Player.p_ring.ring_type = R_NONE; 55 Player.p_ring.ring_duration = 0; 56 57 Player.p_lives = 3; /* three extra lives */ 58 } 59 if (Player.p_level > 9999.0 && Player.p_specialtype != SC_VALAR) 60 death("Old age"); 61 } 62 63 const char * 64 descrlocation(playerp, shortflag) 65 struct player *playerp; 66 bool shortflag; 67 { 68 double circle; /* corresponding circle for coordinates */ 69 int quadrant; /* quandrant of grid */ 70 const char *label; /* pointer to place name */ 71 static const char *const nametable[4][4] = /* names of places */ 72 { 73 {"Anorien", "Ithilien", "Rohan", "Lorien"}, 74 {"Gondor", "Mordor", "Dunland", "Rovanion"}, 75 {"South Gondor", "Khand", "Eriador", "The Iron Hills"}, 76 {"Far Harad", "Near Harad", "The Northern Waste", "Rhun"} 77 }; 78 79 if (playerp->p_specialtype == SC_VALAR) 80 return (" is in Valhala"); 81 else 82 if ((circle = CIRCLE(playerp->p_x, playerp->p_y)) >= 1000.0) { 83 if (MAX(fabs(playerp->p_x), fabs(playerp->p_y)) > D_BEYOND) 84 label = "The Point of No Return"; 85 else 86 label = "The Ashen Mountains"; 87 } else 88 if (circle >= 55) 89 label = "Morannon"; 90 else 91 if (circle >= 35) 92 label = "Kennaquahair"; 93 else 94 if (circle >= 20) 95 label = "The Dead Marshes"; 96 else 97 if (circle >= 9) 98 label = "The Outer Waste"; 99 else 100 if (circle >= 5) 101 label = "The Moors Adventurous"; 102 else { 103 if (playerp->p_x == 0.0 && playerp->p_y == 0.0) 104 label = "The Lord's Chamber"; 105 else { 106 /* this 107 * 108 * expr 109 * essi 110 * on 111 * is 112 * spli 113 * t 114 * to 115 * prev 116 * ent 117 * comp 118 * iler 119 * 120 * loop 121 * 122 * with 123 * 124 * some 125 * 126 * comp 127 * iler 128 * s */ 129 quadrant = ((playerp->p_x > 0.0) ? 1 : 0); 130 quadrant += ((playerp->p_y >= 0.0) ? 2 : 0); 131 label = nametable[((int) circle) - 1][quadrant]; 132 } 133 } 134 135 if (shortflag) 136 sprintf(Databuf, "%.29s", label); 137 else 138 sprintf(Databuf, " is in %s (%.0f,%.0f)", label, playerp->p_x, playerp->p_y); 139 140 return (Databuf); 141 } 142 143 void 144 tradingpost() 145 { 146 double numitems; /* number of items to purchase */ 147 double cost; /* cost of purchase */ 148 double blessingcost; /* cost of blessing */ 149 int ch; /* input */ 150 int size; /* size of the trading post */ 151 int loop; /* loop counter */ 152 int cheat = 0; /* number of times player has tried to cheat */ 153 bool dishonest = FALSE; /* set when merchant is dishonest */ 154 155 Player.p_status = S_TRADING; 156 writerecord(&Player, Fileloc); 157 158 clear(); 159 addstr("You are at a trading post. All purchases must be made with gold."); 160 161 size = sqrt(fabs(Player.p_x / 100)) + 1; 162 size = MIN(7, size); 163 164 /* set up cost of blessing */ 165 blessingcost = 1000.0 * (Player.p_level + 5.0); 166 167 /* print Menu */ 168 move(7, 0); 169 for (loop = 0; loop < size; ++loop) 170 /* print Menu */ 171 { 172 if (loop == 6) 173 cost = blessingcost; 174 else 175 cost = Menu[loop].cost; 176 printw("(%d) %-12s: %6.0f\n", loop + 1, Menu[loop].item, cost); 177 } 178 179 mvprintw(5, 0, "L:Leave P:Purchase S:Sell Gems ? "); 180 181 for (;;) { 182 adjuststats(); /* truncate any bad values */ 183 184 /* print some important statistics */ 185 mvprintw(1, 0, "Gold: %9.0f Gems: %9.0f Level: %6.0f Charms: %6d\n", 186 Player.p_gold, Player.p_gems, Player.p_level, Player.p_charms); 187 printw("Shield: %9.0f Sword: %9.0f Quicksilver:%3.0f Blessed: %s\n", 188 Player.p_shield, Player.p_sword, Player.p_quksilver, 189 (Player.p_blessing ? " True" : "False")); 190 printw("Brains: %9.0f Mana: %9.0f", Player.p_brains, Player.p_mana); 191 192 move(5, 36); 193 ch = getanswer("LPS", FALSE); 194 move(15, 0); 195 clrtobot(); 196 switch (ch) { 197 case 'L': /* leave */ 198 case '\n': 199 altercoordinates(0.0, 0.0, A_NEAR); 200 return; 201 202 case 'P': /* make purchase */ 203 mvaddstr(15, 0, "What what would you like to buy ? "); 204 ch = getanswer(" 1234567", FALSE); 205 move(15, 0); 206 clrtoeol(); 207 208 if (ch - '0' > size) 209 addstr("Sorry, this merchant doesn't have that."); 210 else 211 switch (ch) { 212 case '1': 213 printw("Mana is one per %.0f gold piece. How many do you want (%.0f max) ? ", 214 Menu[0].cost, floor(Player.p_gold / Menu[0].cost)); 215 cost = (numitems = floor(infloat())) * Menu[0].cost; 216 217 if (cost > Player.p_gold || numitems < 0) 218 ++cheat; 219 else { 220 cheat = 0; 221 Player.p_gold -= cost; 222 if (drandom() < 0.02) 223 dishonest = TRUE; 224 else 225 Player.p_mana += numitems; 226 } 227 break; 228 229 case '2': 230 printw("Shields are %.0f per +1. How many do you want (%.0f max) ? ", 231 Menu[1].cost, floor(Player.p_gold / Menu[1].cost)); 232 cost = (numitems = floor(infloat())) * Menu[1].cost; 233 234 if (numitems == 0.0) 235 break; 236 else 237 if (cost > Player.p_gold || numitems < 0) 238 ++cheat; 239 else 240 if (numitems < Player.p_shield) 241 NOBETTER(); 242 else { 243 cheat = 0; 244 Player.p_gold -= cost; 245 if (drandom() < 0.02) 246 dishonest = TRUE; 247 else 248 Player.p_shield = numitems; 249 } 250 break; 251 252 case '3': 253 printw("A book costs %.0f gp. How many do you want (%.0f max) ? ", 254 Menu[2].cost, floor(Player.p_gold / Menu[2].cost)); 255 cost = (numitems = floor(infloat())) * Menu[2].cost; 256 257 if (cost > Player.p_gold || numitems < 0) 258 ++cheat; 259 else { 260 cheat = 0; 261 Player.p_gold -= cost; 262 if (drandom() < 0.02) 263 dishonest = TRUE; 264 else 265 if (drandom() * numitems > Player.p_level / 10.0 266 && numitems != 1) { 267 printw("\nYou blew your mind!\n"); 268 Player.p_brains /= 5; 269 } else { 270 Player.p_brains += floor(numitems) * ROLL(20, 8); 271 } 272 } 273 break; 274 275 case '4': 276 printw("Swords are %.0f gp per +1. How many + do you want (%.0f max) ? ", 277 Menu[3].cost, floor(Player.p_gold / Menu[3].cost)); 278 cost = (numitems = floor(infloat())) * Menu[3].cost; 279 280 if (numitems == 0.0) 281 break; 282 else 283 if (cost > Player.p_gold || numitems < 0) 284 ++cheat; 285 else 286 if (numitems < Player.p_sword) 287 NOBETTER(); 288 else { 289 cheat = 0; 290 Player.p_gold -= cost; 291 if (drandom() < 0.02) 292 dishonest = TRUE; 293 else 294 Player.p_sword = numitems; 295 } 296 break; 297 298 case '5': 299 printw("A charm costs %.0f gp. How many do you want (%.0f max) ? ", 300 Menu[4].cost, floor(Player.p_gold / Menu[4].cost)); 301 cost = (numitems = floor(infloat())) * Menu[4].cost; 302 303 if (cost > Player.p_gold || numitems < 0) 304 ++cheat; 305 else { 306 cheat = 0; 307 Player.p_gold -= cost; 308 if (drandom() < 0.02) 309 dishonest = TRUE; 310 else 311 Player.p_charms += numitems; 312 } 313 break; 314 315 case '6': 316 printw("Quicksilver is %.0f gp per +1. How many + do you want (%.0f max) ? ", 317 Menu[5].cost, floor(Player.p_gold / Menu[5].cost)); 318 cost = (numitems = floor(infloat())) * Menu[5].cost; 319 320 if (numitems == 0.0) 321 break; 322 else 323 if (cost > Player.p_gold || numitems < 0) 324 ++cheat; 325 else 326 if (numitems < Player.p_quksilver) 327 NOBETTER(); 328 else { 329 cheat = 0; 330 Player.p_gold -= cost; 331 if (drandom() < 0.02) 332 dishonest = TRUE; 333 else 334 Player.p_quksilver = numitems; 335 } 336 break; 337 338 case '7': 339 if (Player.p_blessing) { 340 addstr("You already have a blessing."); 341 break; 342 } 343 printw("A blessing requires a %.0f gp donation. Still want one ? ", blessingcost); 344 ch = getanswer("NY", FALSE); 345 346 if (ch == 'Y') { 347 if (Player.p_gold < blessingcost) 348 ++cheat; 349 else { 350 cheat = 0; 351 Player.p_gold -= blessingcost; 352 if (drandom() < 0.02) 353 dishonest = TRUE; 354 else 355 Player.p_blessing = TRUE; 356 } 357 } 358 break; 359 } 360 break; 361 362 case 'S': /* sell gems */ 363 mvprintw(15, 0, "A gem is worth %.0f gp. How many do you want to sell (%.0f max) ? ", 364 (double) N_GEMVALUE, Player.p_gems); 365 numitems = floor(infloat()); 366 367 if (numitems > Player.p_gems || numitems < 0) 368 ++cheat; 369 else { 370 cheat = 0; 371 Player.p_gems -= numitems; 372 Player.p_gold += numitems * N_GEMVALUE; 373 } 374 } 375 376 if (cheat == 1) 377 mvaddstr(17, 0, "Come on, merchants aren't stupid. Stop cheating.\n"); 378 else 379 if (cheat == 2) { 380 mvaddstr(17, 0, "You had your chance. This merchant happens to be\n"); 381 printw("a %.0f level magic user, and you made %s mad!\n", 382 ROLL(Circle * 20.0, 40.0), (drandom() < 0.5) ? "him" : "her"); 383 altercoordinates(0.0, 0.0, A_FAR); 384 Player.p_energy /= 2.0; 385 ++Player.p_sin; 386 more(23); 387 return; 388 } else 389 if (dishonest) { 390 mvaddstr(17, 0, "The merchant stole your money!"); 391 refresh(); 392 altercoordinates(Player.p_x - Player.p_x / 10.0, 393 Player.p_y - Player.p_y / 10.0, A_SPECIFIC); 394 sleep(2); 395 return; 396 } 397 } 398 } 399 400 void 401 displaystats() 402 { 403 mvprintw(0, 0, "%s%s\n", Player.p_name, descrlocation(&Player, FALSE)); 404 mvprintw(1, 0, "Level :%7.0f Energy :%9.0f(%9.0f) Mana :%9.0f Users:%3d\n", 405 Player.p_level, Player.p_energy, Player.p_maxenergy + Player.p_shield, 406 Player.p_mana, Users); 407 mvprintw(2, 0, "Quick :%3.0f(%3.0f) Strength:%9.0f(%9.0f) Gold :%9.0f %s\n", 408 Player.p_speed, Player.p_quickness + Player.p_quksilver, Player.p_might, 409 Player.p_strength + Player.p_sword, Player.p_gold, descrstatus(&Player)); 410 } 411 412 void 413 allstatslist() 414 { 415 static const char *const flags[] = /* to print value of some bools */ 416 { 417 "False", 418 " True" 419 }; 420 421 mvprintw(8, 0, "Type: %s\n", descrtype(&Player, FALSE)); 422 423 mvprintw(10, 0, "Experience: %9.0f", Player.p_experience); 424 mvprintw(11, 0, "Brains : %9.0f", Player.p_brains); 425 mvprintw(12, 0, "Magic Lvl : %9.0f", Player.p_magiclvl); 426 mvprintw(13, 0, "Sin : %9.5f", Player.p_sin); 427 mvprintw(14, 0, "Poison : %9.5f", Player.p_poison); 428 mvprintw(15, 0, "Gems : %9.0f", Player.p_gems); 429 mvprintw(16, 0, "Age : %9ld", Player.p_age); 430 mvprintw(10, 40, "Holy Water: %9d", Player.p_holywater); 431 mvprintw(11, 40, "Amulets : %9d", Player.p_amulets); 432 mvprintw(12, 40, "Charms : %9d", Player.p_charms); 433 mvprintw(13, 40, "Crowns : %9d", Player.p_crowns); 434 mvprintw(14, 40, "Shield : %9.0f", Player.p_shield); 435 mvprintw(15, 40, "Sword : %9.0f", Player.p_sword); 436 mvprintw(16, 40, "Quickslver: %9.0f", Player.p_quksilver); 437 438 mvprintw(18, 0, "Blessing: %s Ring: %s Virgin: %s Palantir: %s", 439 flags[(int)Player.p_blessing], 440 flags[Player.p_ring.ring_type != R_NONE], 441 flags[(int)Player.p_virgin], 442 flags[(int)Player.p_palantir]); 443 } 444 445 const char * 446 descrtype(playerp, shortflag) 447 struct player *playerp; 448 bool shortflag; 449 { 450 int type; /* for caluculating result subscript */ 451 static const char *const results[] =/* description table */ 452 { 453 " Magic User", " MU", 454 " Fighter", " F ", 455 " Elf", " E ", 456 " Dwarf", " D ", 457 " Halfling", " H ", 458 " Experimento", " EX", 459 " Super", " S ", 460 " King", " K ", 461 " Council of Wise", " CW", 462 " Ex-Valar", " EV", 463 " Valar", " V ", 464 " ? ", " ? " 465 }; 466 467 type = playerp->p_type; 468 469 switch (playerp->p_specialtype) { 470 case SC_NONE: 471 type = playerp->p_type; 472 break; 473 474 case SC_KING: 475 type = 7; 476 break; 477 478 case SC_COUNCIL: 479 type = 8; 480 break; 481 482 case SC_EXVALAR: 483 type = 9; 484 break; 485 486 case SC_VALAR: 487 type = 10; 488 break; 489 } 490 491 type *= 2; /* calculate offset */ 492 493 if (type > 20) 494 /* error */ 495 type = 22; 496 497 if (shortflag) 498 /* use short descriptions */ 499 ++type; 500 501 if (playerp->p_crowns > 0) { 502 strcpy(Databuf, results[type]); 503 Databuf[0] = '*'; 504 return (Databuf); 505 } else 506 return (results[type]); 507 } 508 509 long 510 findname(name, playerp) 511 const char *name; 512 struct player *playerp; 513 { 514 long loc = 0; /* location in the file */ 515 516 fseek(Playersfp, 0L, SEEK_SET); 517 while (fread((char *) playerp, SZ_PLAYERSTRUCT, 1, Playersfp) == 1) { 518 if (strcmp(playerp->p_name, name) == 0) { 519 if (playerp->p_status != S_NOTUSED || Wizard) 520 /* found it */ 521 return (loc); 522 } 523 loc += SZ_PLAYERSTRUCT; 524 } 525 526 return (-1); 527 } 528 529 long 530 allocrecord() 531 { 532 long loc = 0L; /* location in file */ 533 534 fseek(Playersfp, 0L, SEEK_SET); 535 while (fread((char *) &Other, SZ_PLAYERSTRUCT, 1, Playersfp) == 1) { 536 if (Other.p_status == S_NOTUSED) 537 /* found an empty record */ 538 return (loc); 539 else 540 loc += SZ_PLAYERSTRUCT; 541 } 542 543 /* make a new record */ 544 initplayer(&Other); 545 Player.p_status = S_OFF; 546 writerecord(&Other, loc); 547 548 return (loc); 549 } 550 551 void 552 freerecord(playerp, loc) 553 struct player *playerp; 554 long loc; 555 { 556 playerp->p_name[0] = CH_MARKDELETE; 557 playerp->p_status = S_NOTUSED; 558 writerecord(playerp, loc); 559 } 560 561 void 562 leavegame() 563 { 564 565 if (Player.p_level < 1.0) 566 /* delete character */ 567 freerecord(&Player, Fileloc); 568 else { 569 Player.p_status = S_OFF; 570 writerecord(&Player, Fileloc); 571 } 572 573 cleanup(TRUE); 574 /* NOTREACHED */ 575 } 576 577 void 578 death(how) 579 const char *how; 580 { 581 FILE *fp; /* for updating various files */ 582 int ch; /* input */ 583 static const char *const deathmesg[] = 584 /* add more messages here, if desired */ 585 { 586 "You have been wounded beyond repair. ", 587 "You have been disemboweled. ", 588 "You've been mashed, mauled, and spit upon. (You're dead.)\n", 589 "You died! ", 590 "You're a complete failure -- you've died!!\n", 591 "You have been dealt a fatal blow! " 592 }; 593 594 clear(); 595 596 if (strcmp(how, "Stupidity") != 0) { 597 if (Player.p_level > 9999.0) 598 /* old age */ 599 addstr("Characters must be retired upon reaching level 10000. Sorry."); 600 else 601 if (Player.p_lives > 0) 602 /* extra lives */ 603 { 604 addstr("You should be more cautious. You've been killed.\n"); 605 printw("You only have %d more chance(s).\n", --Player.p_lives); 606 more(3); 607 Player.p_energy = Player.p_maxenergy; 608 return; 609 } else 610 if (Player.p_specialtype == SC_VALAR) { 611 addstr("You had your chances, but Valar aren't totally\n"); 612 addstr("immortal. You are now left to wither and die . . .\n"); 613 more(3); 614 Player.p_brains = Player.p_level / 25.0; 615 Player.p_energy = Player.p_maxenergy /= 5.0; 616 Player.p_quksilver = Player.p_sword = 0.0; 617 Player.p_specialtype = SC_COUNCIL; 618 return; 619 } else 620 if (Player.p_ring.ring_inuse && 621 (Player.p_ring.ring_type == R_DLREG || Player.p_ring.ring_type == R_NAZREG)) 622 /* good ring in use - saved 623 * from death */ 624 { 625 mvaddstr(4, 0, "Your ring saved you from death!\n"); 626 refresh(); 627 Player.p_ring.ring_type = R_NONE; 628 Player.p_energy = Player.p_maxenergy / 12.0 + 1.0; 629 if (Player.p_crowns > 0) 630 --Player.p_crowns; 631 return; 632 } else 633 if (Player.p_ring.ring_type == R_BAD 634 || Player.p_ring.ring_type == R_SPOILED) 635 /* bad ring in 636 * possession; name 637 * idiot after player */ 638 { 639 mvaddstr(4, 0, 640 "Your ring has taken control of you and turned you into a monster!\n"); 641 fseek(Monstfp, 13L * SZ_MONSTERSTRUCT, SEEK_SET); 642 fread((char *) &Curmonster, SZ_MONSTERSTRUCT, 1, Monstfp); 643 strcpy(Curmonster.m_name, Player.p_name); 644 fseek(Monstfp, 13L * SZ_MONSTERSTRUCT, SEEK_SET); 645 fwrite((char *) &Curmonster, SZ_MONSTERSTRUCT, 1, Monstfp); 646 fflush(Monstfp); 647 } 648 } 649 enterscore(); /* update score board */ 650 651 /* put info in last dead file */ 652 fp = fopen(_PATH_LASTDEAD, "w"); 653 fprintf(fp, "%s (%s, run by %s, level %.0f, killed by %s)", 654 Player.p_name, descrtype(&Player, TRUE), 655 Player.p_login, Player.p_level, how); 656 fclose(fp); 657 658 /* let other players know */ 659 fp = fopen(_PATH_MESS, "w"); 660 fprintf(fp, "%s was killed by %s.", Player.p_name, how); 661 fclose(fp); 662 663 freerecord(&Player, Fileloc); 664 665 clear(); 666 move(10, 0); 667 addstr(deathmesg[(int) ROLL(0.0, (double) sizeof(deathmesg) / sizeof(char *))]); 668 addstr("Care to give it another try ? "); 669 ch = getanswer("NY", FALSE); 670 671 if (ch == 'Y') { 672 cleanup(FALSE); 673 execl(_PATH_GAMEPROG, "phantasia", "-s", 674 (Wizard ? "-S" : (char *) NULL), 0); 675 exit(0); 676 /* NOTREACHED */ 677 } 678 cleanup(TRUE); 679 /* NOTREACHED */ 680 } 681 682 void 683 writerecord(playerp, place) 684 struct player *playerp; 685 long place; 686 { 687 fseek(Playersfp, place, SEEK_SET); 688 fwrite((char *) playerp, SZ_PLAYERSTRUCT, 1, Playersfp); 689 fflush(Playersfp); 690 } 691 692 double 693 explevel(experience) 694 double experience; 695 { 696 if (experience < 1.1e7) 697 return (floor(pow((experience / 1000.0), 0.4875))); 698 else 699 return (floor(pow((experience / 1250.0), 0.4865))); 700 } 701 702 void 703 truncstring(string) 704 char *string; 705 { 706 int length; /* length of string */ 707 708 length = strlen(string); 709 while (string[--length] == ' ') 710 string[length] = '\0'; 711 } 712 713 void 714 altercoordinates(xnew, ynew, operation) 715 double xnew; 716 double ynew; 717 int operation; 718 { 719 switch (operation) { 720 case A_FORCED: /* move with no checks */ 721 break; 722 723 case A_NEAR: /* pick random coordinates near */ 724 xnew = Player.p_x + ROLL(1.0, 5.0); 725 ynew = Player.p_y - ROLL(1.0, 5.0); 726 /* fall through for check */ 727 728 case A_SPECIFIC: /* just move player */ 729 if (Beyond && fabs(xnew) < D_BEYOND && fabs(ynew) < D_BEYOND) 730 /* 731 * cannot move back from point of no return 732 * pick the largest coordinate to remain unchanged 733 */ 734 { 735 if (fabs(xnew) > fabs(ynew)) 736 xnew = SGN(Player.p_x) * MAX(fabs(Player.p_x), D_BEYOND); 737 else 738 ynew = SGN(Player.p_y) * MAX(fabs(Player.p_y), D_BEYOND); 739 } 740 break; 741 742 case A_FAR: /* pick random coordinates far */ 743 xnew = Player.p_x + SGN(Player.p_x) * ROLL(50 * Circle, 250 * Circle); 744 ynew = Player.p_y + SGN(Player.p_y) * ROLL(50 * Circle, 250 * Circle); 745 break; 746 } 747 748 /* now set location flags and adjust coordinates */ 749 Circle = CIRCLE(Player.p_x = floor(xnew), Player.p_y = floor(ynew)); 750 751 /* set up flags based upon location */ 752 Throne = Marsh = Beyond = FALSE; 753 754 if (Player.p_x == 0.0 && Player.p_y == 0.0) 755 Throne = TRUE; 756 else 757 if (Circle < 35 && Circle >= 20) 758 Marsh = TRUE; 759 else 760 if (MAX(fabs(Player.p_x), fabs(Player.p_y)) >= D_BEYOND) 761 Beyond = TRUE; 762 763 Changed = TRUE; 764 } 765 766 void 767 readrecord(playerp, loc) 768 struct player *playerp; 769 long loc; 770 { 771 fseek(Playersfp, loc, SEEK_SET); 772 fread((char *) playerp, SZ_PLAYERSTRUCT, 1, Playersfp); 773 } 774 775 void 776 adjuststats() 777 { 778 double dtemp; /* for temporary calculations */ 779 780 if (explevel(Player.p_experience) > Player.p_level) 781 /* move one or more levels */ 782 { 783 movelevel(); 784 if (Player.p_level > 5.0) 785 Timeout = TRUE; 786 } 787 if (Player.p_specialtype == SC_VALAR) 788 /* valar */ 789 Circle = Player.p_level / 5.0; 790 791 /* calculate effective quickness */ 792 dtemp = ((Player.p_gold + Player.p_gems / 2.0) - 1000.0) / Statptr->c_goldtote 793 - Player.p_level;; 794 dtemp = MAX(0.0, dtemp);/* gold slows player down */ 795 Player.p_speed = Player.p_quickness + Player.p_quksilver - dtemp; 796 797 /* calculate effective strength */ 798 if (Player.p_poison > 0.0) 799 /* poison makes player weaker */ 800 { 801 dtemp = 1.0 - Player.p_poison * Statptr->c_weakness / 800.0; 802 dtemp = MAX(0.1, dtemp); 803 } else 804 dtemp = 1.0; 805 Player.p_might = dtemp * Player.p_strength + Player.p_sword; 806 807 /* insure that important things are within limits */ 808 Player.p_quksilver = MIN(99.0, Player.p_quksilver); 809 Player.p_mana = MIN(Player.p_mana, 810 Player.p_level * Statptr->c_maxmana + 1000.0); 811 Player.p_brains = MIN(Player.p_brains, 812 Player.p_level * Statptr->c_maxbrains + 200.0); 813 Player.p_charms = MIN(Player.p_charms, Player.p_level + 10.0); 814 815 /* 816 * some implementations have problems with floating point compare 817 * we work around it with this stuff 818 */ 819 Player.p_gold = floor(Player.p_gold) + 0.1; 820 Player.p_gems = floor(Player.p_gems) + 0.1; 821 Player.p_mana = floor(Player.p_mana) + 0.1; 822 823 if (Player.p_ring.ring_type != R_NONE) 824 /* do ring things */ 825 { 826 /* rest to max */ 827 Player.p_energy = Player.p_maxenergy + Player.p_shield; 828 829 if (Player.p_ring.ring_duration <= 0) 830 /* clean up expired rings */ 831 switch (Player.p_ring.ring_type) { 832 case R_BAD: /* ring drives player crazy */ 833 Player.p_ring.ring_type = R_SPOILED; 834 Player.p_ring.ring_duration = (short) ROLL(10.0, 25.0); 835 break; 836 837 case R_NAZREG: /* ring disappears */ 838 Player.p_ring.ring_type = R_NONE; 839 break; 840 841 case R_SPOILED: /* ring kills player */ 842 death("A cursed ring"); 843 break; 844 845 case R_DLREG: /* this ring doesn't expire */ 846 Player.p_ring.ring_duration = 0; 847 break; 848 } 849 } 850 if (Player.p_age / N_AGE > Player.p_degenerated) 851 /* age player slightly */ 852 { 853 ++Player.p_degenerated; 854 if (Player.p_quickness > 23.0) 855 Player.p_quickness *= 0.99; 856 Player.p_strength *= 0.97; 857 Player.p_brains *= 0.95; 858 Player.p_magiclvl *= 0.97; 859 Player.p_maxenergy *= 0.95; 860 Player.p_quksilver *= 0.95; 861 Player.p_sword *= 0.93; 862 Player.p_shield *= 0.93; 863 } 864 } 865 866 void 867 initplayer(playerp) 868 struct player *playerp; 869 { 870 playerp->p_experience = 871 playerp->p_level = 872 playerp->p_strength = 873 playerp->p_sword = 874 playerp->p_might = 875 playerp->p_energy = 876 playerp->p_maxenergy = 877 playerp->p_shield = 878 playerp->p_quickness = 879 playerp->p_quksilver = 880 playerp->p_speed = 881 playerp->p_magiclvl = 882 playerp->p_mana = 883 playerp->p_brains = 884 playerp->p_poison = 885 playerp->p_gems = 886 playerp->p_sin = 887 playerp->p_1scratch = 888 playerp->p_2scratch = 0.0; 889 890 playerp->p_gold = ROLL(50.0, 75.0) + 0.1; /* give some gold */ 891 892 playerp->p_x = ROLL(-125.0, 251.0); 893 playerp->p_y = ROLL(-125.0, 251.0); /* give random x, y */ 894 895 /* clear ring */ 896 playerp->p_ring.ring_type = R_NONE; 897 playerp->p_ring.ring_duration = 0; 898 playerp->p_ring.ring_inuse = FALSE; 899 900 playerp->p_age = 0L; 901 902 playerp->p_degenerated = 1; /* don't degenerate initially */ 903 904 playerp->p_type = C_FIGHTER; /* default */ 905 playerp->p_specialtype = SC_NONE; 906 playerp->p_lives = 907 playerp->p_crowns = 908 playerp->p_charms = 909 playerp->p_amulets = 910 playerp->p_holywater = 911 playerp->p_lastused = 0; 912 playerp->p_status = S_NOTUSED; 913 playerp->p_tampered = T_OFF; 914 playerp->p_istat = I_OFF; 915 916 playerp->p_palantir = 917 playerp->p_blessing = 918 playerp->p_virgin = 919 playerp->p_blindness = FALSE; 920 921 playerp->p_name[0] = 922 playerp->p_password[0] = 923 playerp->p_login[0] = '\0'; 924 } 925 926 void 927 readmessage() 928 { 929 move(3, 0); 930 clrtoeol(); 931 fseek(Messagefp, 0L, SEEK_SET); 932 if (fgets(Databuf, SZ_DATABUF, Messagefp) != NULL) 933 addstr(Databuf); 934 } 935 936 void 937 error(whichfile) 938 const char *whichfile; 939 { 940 int (*funcp) __P((const char *,...)); 941 942 if (Windows) { 943 funcp = printw; 944 clear(); 945 } else 946 funcp = printf; 947 948 (*funcp) ("An unrecoverable error has occurred reading %s. (errno = %d)\n", whichfile, errno); 949 (*funcp) ("Please run 'setup' to determine the problem.\n"); 950 cleanup(TRUE); 951 /* NOTREACHED */ 952 } 953 954 double 955 distance(x1, x2, y1, y2) 956 double x1, x2, y1, y2; 957 { 958 double deltax, deltay; 959 960 deltax = x1 - x2; 961 deltay = y1 - y2; 962 return (sqrt(deltax * deltax + deltay * deltay)); 963 } 964 965 void 966 ill_sig(whichsig) 967 int whichsig; 968 { 969 clear(); 970 if (!(whichsig == SIGINT || whichsig == SIGQUIT)) 971 printw("Error: caught signal # %d.\n", whichsig); 972 cleanup(TRUE); 973 /* NOTREACHED */ 974 } 975 976 const char * 977 descrstatus(playerp) 978 struct player *playerp; 979 { 980 switch (playerp->p_status) { 981 case S_PLAYING: 982 if (playerp->p_energy < 0.2 * (playerp->p_maxenergy + playerp->p_shield)) 983 return ("Low Energy"); 984 else 985 if (playerp->p_blindness) 986 return ("Blind"); 987 else 988 return ("In game"); 989 990 case S_CLOAKED: 991 return ("Cloaked"); 992 993 case S_INBATTLE: 994 return ("In Battle"); 995 996 case S_MONSTER: 997 return ("Encounter"); 998 999 case S_TRADING: 1000 return ("Trading"); 1001 1002 case S_OFF: 1003 return ("Off"); 1004 1005 case S_HUNGUP: 1006 return ("Hung up"); 1007 1008 default: 1009 return (""); 1010 } 1011 } 1012 1013 double 1014 drandom() 1015 { 1016 if (sizeof(int) != 2) 1017 /* use only low bits */ 1018 return ((double) (random() & 0x7fff) / 32768.0); 1019 else 1020 return ((double) random() / 32768.0); 1021 } 1022 1023 void 1024 collecttaxes(gold, gems) 1025 double gold; 1026 double gems; 1027 { 1028 FILE *fp; /* to update Goldfile */ 1029 double dtemp; /* for temporary calculations */ 1030 double taxes; /* tax liability */ 1031 1032 /* add to cache */ 1033 Player.p_gold += gold; 1034 Player.p_gems += gems; 1035 1036 /* calculate tax liability */ 1037 taxes = N_TAXAMOUNT / 100.0 * (N_GEMVALUE * gems + gold); 1038 1039 if (Player.p_gold < taxes) 1040 /* not enough gold to pay taxes, must convert some gems to 1041 * gold */ 1042 { 1043 dtemp = floor(taxes / N_GEMVALUE + 1.0); /* number of gems to 1044 * convert */ 1045 1046 if (Player.p_gems >= dtemp) 1047 /* player has enough to convert */ 1048 { 1049 Player.p_gems -= dtemp; 1050 Player.p_gold += dtemp * N_GEMVALUE; 1051 } else 1052 /* take everything; this should never happen */ 1053 { 1054 Player.p_gold += Player.p_gems * N_GEMVALUE; 1055 Player.p_gems = 0.0; 1056 taxes = Player.p_gold; 1057 } 1058 } 1059 Player.p_gold -= taxes; 1060 1061 if ((fp = fopen(_PATH_GOLD, "r+")) != NULL) 1062 /* update taxes */ 1063 { 1064 dtemp = 0.0; 1065 fread((char *) &dtemp, sizeof(double), 1, fp); 1066 dtemp += floor(taxes); 1067 fseek(fp, 0L, SEEK_SET); 1068 fwrite((char *) &dtemp, sizeof(double), 1, fp); 1069 fclose(fp); 1070 } 1071 } 1072