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