1 /* 2 * interplayer.c - player to player routines for Phantasia 3 * 4 * $FreeBSD: src/games/phantasia/interplayer.c,v 1.6 1999/11/16 02:57:33 billf Exp $ 5 * $DragonFly: src/games/phantasia/interplayer.c,v 1.3 2005/05/31 00:06:26 swildner Exp $ 6 */ 7 8 #include <string.h> 9 #include "include.h" 10 11 /* functions which we need to know about */ 12 /* fight.c */ 13 extern void encounter(int); 14 /* io.c */ 15 extern int getanswer(const char *, bool); 16 extern void getstring(char *, int); 17 extern double infloat(void); 18 extern int inputoption(void); 19 extern void more(int); 20 /* misc.c */ 21 extern void altercoordinates(double, double, int); 22 extern void collecttaxes(double, double); 23 extern void death(const char *); 24 extern const char *descrlocation(struct player *, bool); 25 extern const char *descrstatus(struct player *); 26 extern const char *descrtype(struct player *, bool); 27 extern void displaystats(void); 28 extern double distance(double, double, double, double); 29 extern long findname(char *, struct player *); 30 extern void readmessage(void); 31 extern void readrecord(struct player *, long); 32 extern void truncstring(char *); 33 extern void writerecord(struct player *, long); 34 /* phantglobs.c */ 35 extern double drandom(void); 36 37 size_t allocvoid(void); 38 void battleplayer(long); 39 void checkbattle(void); 40 void checktampered(void); 41 void dotampered(void); 42 void myturn(void); 43 void tampered(int, double, double); 44 void throneroom(void); 45 void userlist(bool); 46 void writevoid(struct energyvoid *, long); 47 48 /* 49 * FUNCTION: check to see if current player should battle another 50 * 51 * GLOBAL INPUTS: Other, Users, Player, Fileloc, *Playersfp 52 * 53 * GLOBAL OUTPUTS: Users 54 * 55 * DESCRIPTION: 56 * Seach player file for a foe at the same coordinates as the 57 * current player. 58 * Also update user count. 59 */ 60 61 void 62 checkbattle(void) 63 { 64 long foeloc = 0L; /* location in file of person to fight */ 65 66 Users = 0; 67 fseek(Playersfp, 0L, SEEK_SET); 68 69 while (fread((char *)&Other, SZ_PLAYERSTRUCT, 1, Playersfp) == 1) { 70 if (Other.p_status != S_OFF 71 && Other.p_status != S_NOTUSED 72 && Other.p_status != S_HUNGUP 73 && (Other.p_status != S_CLOAKED || Other.p_specialtype != SC_VALAR)) { 74 /* player is on and not a cloaked valar */ 75 ++Users; 76 77 if (Player.p_x == Other.p_x 78 && Player.p_y == Other.p_y 79 /* same coordinates */ 80 && foeloc != Fileloc 81 /* not self */ 82 && Player.p_status == S_PLAYING 83 && (Other.p_status == S_PLAYING || Other.p_status == S_INBATTLE) 84 /* both are playing */ 85 && Other.p_specialtype != SC_VALAR 86 && Player.p_specialtype != SC_VALAR) { 87 /* neither is valar */ 88 battleplayer(foeloc); 89 return; 90 } 91 } 92 foeloc += SZ_PLAYERSTRUCT; 93 } 94 } 95 96 /* 97 * FUNCTION: inter-terminal battle with another player 98 * 99 * ARGUMENTS: 100 * long foeplace - location in player file of person to battle 101 * 102 * GLOBAL INPUTS: Foestrikes, LINES, Lines, Other, Shield, Player, *stdscr, 103 * Fileloc, *Enemyname 104 * 105 * GLOBAL OUTPUTS: Foestrikes, Lines, Shield, Player, Luckout, *Enemyname 106 * 107 * DESCRIPTION: 108 * Inter-terminal battle is a very fragile and slightly klugy thing. 109 * At any time, one player is master and the other is slave. 110 * We pick who is master first by speed and level. After that, 111 * the slave waits for the master to relinquish its turn, and 112 * the slave becomes master, and so on. 113 * 114 * The items in the player structure which control the handshake are: 115 * p_tampered: 116 * master increments this to relinquish control 117 * p_istat: 118 * master sets this to specify particular action 119 * p_1scratch: 120 * set to total damage inflicted so far; changes to indicate action 121 */ 122 123 void 124 battleplayer(long foeplace) 125 { 126 double dtemp; /* for temporary calculations */ 127 double oldhits = 0.0; /* previous damage inflicted by foe */ 128 int loop; /* for timing out */ 129 int ch; /* input */ 130 short oldtampered; /* old value of foe's p_tampered */ 131 132 Lines = 8; 133 Luckout = FALSE; 134 mvaddstr(4, 0, "Preparing for battle!\n"); 135 refresh(); 136 137 #ifdef SYS5 138 flushinp(); 139 #endif 140 141 /* set up variables, file, etc. */ 142 Player.p_status = S_INBATTLE; 143 Shield = Player.p_energy; 144 145 /* if p_tampered is not 0, someone else may try to change it (king, etc.) */ 146 Player.p_tampered = oldtampered = 1; 147 Player.p_1scratch = 0.0; 148 Player.p_istat = I_OFF; 149 150 readrecord(&Other, foeplace); 151 if (fabs(Player.p_level - Other.p_level) > 20.0) { 152 /* see if players are greatly mismatched */ 153 dtemp = (Player.p_level - Other.p_level) / MAX(Player.p_level, Other.p_level); 154 if (dtemp < -0.5) 155 /* foe outweighs this one */ 156 Player.p_speed *= 2.0; 157 } 158 writerecord(&Player, Fileloc); /* write out all our info */ 159 160 if (Player.p_blindness) 161 Enemyname = "someone"; 162 else 163 Enemyname = Other.p_name; 164 165 mvprintw(6, 0, "You have encountered %s Level: %.0f\n", Enemyname, Other.p_level); 166 refresh(); 167 168 for (loop = 0; Other.p_status != S_INBATTLE && loop < 30; ++loop) { 169 /* wait for foe to respond */ 170 readrecord(&Other, foeplace); 171 sleep(1); 172 } 173 174 if (Other.p_status != S_INBATTLE) { 175 /* foe did not respond */ 176 mvprintw(5, 0, "%s is not responding.\n", Enemyname); 177 goto LEAVE; 178 } 179 /* else, we are ready to battle */ 180 181 move(4, 0); 182 clrtoeol(); 183 184 /* 185 * determine who is first master 186 * if neither player is faster, check level 187 * if neither level is greater, battle is not allowed 188 * (this should never happen, but we have to handle it) 189 */ 190 if (Player.p_speed > Other.p_speed) 191 Foestrikes = FALSE; 192 else if (Other.p_speed > Player.p_speed) 193 Foestrikes = TRUE; 194 else if (Player.p_level > Other.p_level) 195 Foestrikes = FALSE; 196 else if (Other.p_level > Player.p_level) 197 Foestrikes = TRUE; 198 else { 199 /* no one is faster */ 200 printw("You can't fight %s yet.", Enemyname); 201 goto LEAVE; 202 } 203 204 for (;;) { 205 displaystats(); 206 readmessage(); 207 mvprintw(1, 26, "%20.0f", Shield); /* overprint energy */ 208 209 if (!Foestrikes) 210 /* take action against foe */ 211 myturn(); 212 else { 213 /* wait for foe to take action */ 214 mvaddstr(4, 0, "Waiting...\n"); 215 clrtoeol(); 216 refresh(); 217 218 for (loop = 0; loop < 20; ++loop) { 219 /* wait for foe to act */ 220 readrecord(&Other, foeplace); 221 if (Other.p_1scratch != oldhits) 222 /* p_1scratch changes to indicate action */ 223 break; 224 else { 225 /* wait and try again */ 226 sleep(1); 227 addch('.'); 228 refresh(); 229 } 230 } 231 232 if (Other.p_1scratch == oldhits) { 233 /* timeout */ 234 mvaddstr(22, 0, "Timeout: waiting for response. Do you want to wait ? "); 235 ch = getanswer("NY", FALSE); 236 move(22, 0); 237 clrtobot(); 238 if (ch == 'Y') 239 continue; 240 else 241 break; 242 } else { 243 /* foe took action */ 244 switch (Other.p_istat) { 245 case I_RAN: /* foe ran away */ 246 mvprintw(Lines++, 0, "%s ran away!", Enemyname); 247 break; 248 249 case I_STUCK: /* foe tried to run, but couldn't */ 250 mvprintw(Lines++, 0, "%s tried to run away.", Enemyname); 251 break; 252 253 case I_BLEWIT: /* foe tried to luckout, but didn't */ 254 mvprintw(Lines++, 0, "%s tried to luckout!", Enemyname); 255 break; 256 257 default: 258 dtemp = Other.p_1scratch - oldhits; 259 mvprintw(Lines++, 0, "%s hit you %.0f times!", Enemyname, dtemp); 260 Shield -= dtemp; 261 break; 262 } 263 264 oldhits = Other.p_1scratch; /* keep track of old hits */ 265 266 if (Other.p_tampered != oldtampered) { 267 /* p_tampered changes to relinquish turn */ 268 oldtampered = Other.p_tampered; 269 Foestrikes = FALSE; 270 } 271 } 272 } 273 274 /* decide what happens next */ 275 refresh(); 276 if (Lines > LINES - 2) { 277 more(Lines); 278 move(Lines = 8, 0); 279 clrtobot(); 280 } 281 282 if (Other.p_istat == I_KILLED || Shield < 0.0) { 283 /* we died */ 284 Shield = -2.0; /* insure this value is negative */ 285 break; 286 } 287 288 if (Player.p_istat == I_KILLED) { 289 /* we killed foe; award treasre */ 290 mvprintw(Lines++, 0, "You killed %s!", Enemyname); 291 Player.p_experience += Other.p_experience; 292 Player.p_crowns += (Player.p_level < 1000.0) ? Other.p_crowns : 0; 293 Player.p_amulets += Other.p_amulets; 294 Player.p_charms += Other.p_charms; 295 collecttaxes(Other.p_gold, Other.p_gems); 296 Player.p_sword = MAX(Player.p_sword, Other.p_sword); 297 Player.p_shield = MAX(Player.p_shield, Other.p_shield); 298 Player.p_quksilver = MAX(Player.p_quksilver, Other.p_quksilver); 299 if (Other.p_virgin && !Player.p_virgin) { 300 mvaddstr(Lines++, 0, "You have rescued a virgin. Will you be honorable ? "); 301 if ((ch = getanswer("YN", FALSE)) == 'Y') 302 Player.p_virgin = TRUE; 303 else { 304 ++Player.p_sin; 305 Player.p_experience += 8000.0; 306 } 307 } 308 sleep(3); /* give other person time to die */ 309 break; 310 } else if (Player.p_istat == I_RAN || Other.p_istat == I_RAN) 311 /* either player ran away */ 312 break; 313 } 314 315 LEAVE: 316 /* clean up things and leave */ 317 writerecord(&Player, Fileloc); /* update a final time */ 318 altercoordinates(0.0, 0.0, A_NEAR); /* move away from battle site */ 319 Player.p_energy = Shield; /* set energy to actual value */ 320 Player.p_tampered = T_OFF; /* clear p_tampered */ 321 322 more(Lines); /* pause */ 323 324 move(4, 0); 325 clrtobot(); /* clear bottom area of screen */ 326 327 if (Player.p_energy < 0.0) 328 /* we are dead */ 329 death("Interterminal battle"); 330 } 331 332 /* 333 * FUNCTION: process players action against foe in battle 334 * 335 * GLOBAL INPUTS: Lines, Other, Player, *stdscr, Fileloc, Luckout, 336 * *Enemyname 337 * 338 * GLOBAL OUTPUTS: Foestrikes, Lines, Player, Luckout 339 * 340 * DESCRIPTION: 341 * Take action action against foe, and decide who is master 342 * for next iteration. 343 */ 344 345 void 346 myturn(void) 347 { 348 double dtemp; /* for temporary calculations */ 349 int ch; /* input */ 350 351 mvaddstr(7, 0, "1:Fight 2:Run Away! 3:Power Blast "); 352 if (Luckout) 353 clrtoeol(); 354 else 355 addstr("4:Luckout "); 356 357 ch = inputoption(); 358 move(Lines = 8, 0); 359 clrtobot(); 360 361 switch (ch) { 362 default: /* fight */ 363 dtemp = ROLL(2.0, Player.p_might); 364 HIT: 365 mvprintw(Lines++, 0, "You hit %s %.0f times!", Enemyname, dtemp); 366 Player.p_sin += 0.5; 367 Player.p_1scratch += dtemp; 368 Player.p_istat = I_OFF; 369 break; 370 371 case '2': /* run away */ 372 /* change this to indicate action */ 373 Player.p_1scratch -= 1.0; 374 if (drandom() > 0.25) { 375 mvaddstr(Lines++, 0, "You got away!"); 376 Player.p_istat = I_RAN; 377 } else { 378 mvprintw(Lines++, 0, "%s is still after you!", Enemyname); 379 Player.p_istat = I_STUCK; 380 } 381 break; 382 383 case '3': /* power blast */ 384 dtemp = MIN(Player.p_mana, Player.p_level * 5.0); 385 Player.p_mana -= dtemp; 386 dtemp *= (drandom() + 0.5) * Player.p_magiclvl * 0.2 + 2.0; 387 mvprintw(Lines++, 0, "You blasted %s !", Enemyname); 388 goto HIT; 389 390 case '4': /* luckout */ 391 if (Luckout || drandom() > 0.1) { 392 if (Luckout) 393 mvaddstr(Lines++, 0, "You already tried that!"); 394 else { 395 mvaddstr(Lines++, 0, "Not this time . . ."); 396 Luckout = TRUE; 397 } 398 399 Player.p_1scratch -= 1.0; 400 Player.p_istat = I_BLEWIT; 401 } else { 402 mvaddstr(Lines++, 0, "You just lucked out!"); 403 Player.p_1scratch = Other.p_energy * 1.1; 404 } 405 break; 406 } 407 408 refresh(); 409 Player.p_1scratch = floor(Player.p_1scratch); /* clean up any mess */ 410 411 if (Player.p_1scratch > Other.p_energy) 412 Player.p_istat = I_KILLED; 413 else if (drandom() * Player.p_speed < drandom() * Other.p_speed) { 414 /* relinquish control */ 415 ++Player.p_tampered; 416 Foestrikes = TRUE; 417 } 418 419 writerecord(&Player, Fileloc); /* let foe know what we did */ 420 } 421 422 /* 423 * FUNCTION: check if current player has been tampered with 424 * 425 * GLOBAL INPUTS: *Energyvoidfp, Other, Player, Fileloc, Enrgyvoid 426 * 427 * GLOBAL OUTPUTS: Enrgyvoid 428 * 429 * DESCRIPTION: 430 * Check for energy voids, holy grail, and tampering by other 431 * players. 432 */ 433 434 void 435 checktampered(void) 436 { 437 long loc = 0L; /* location in energy void file */ 438 439 /* first check for energy voids */ 440 fseek(Energyvoidfp, 0L, SEEK_SET); 441 while (fread((char *)&Enrgyvoid, SZ_VOIDSTRUCT, 1, Energyvoidfp) == 1) 442 if (Enrgyvoid.ev_active 443 && Enrgyvoid.ev_x == Player.p_x 444 && Enrgyvoid.ev_y == Player.p_y) { 445 /* sitting on one */ 446 if (loc > 0L) { 447 /* not the holy grail; inactivate energy void */ 448 Enrgyvoid.ev_active = FALSE; 449 writevoid(&Enrgyvoid, loc); 450 tampered(T_NRGVOID, 0.0, 0.0); 451 } else if (Player.p_status != S_CLOAKED) 452 /* holy grail */ 453 tampered(T_GRAIL, 0.0, 0.0); 454 break; 455 } else 456 loc += SZ_VOIDSTRUCT; 457 458 /* now check for other things */ 459 readrecord(&Other, Fileloc); 460 if (Other.p_tampered != T_OFF) 461 tampered(Other.p_tampered, Other.p_1scratch, Other.p_2scratch); 462 } 463 464 /* 465 * FUNCTION: take care of tampering by other players 466 * 467 * ARGUMENTS: 468 * int what - what type of tampering 469 * double arg1, arg2 - rest of tampering info 470 * 471 * GLOBAL INPUTS: Other, Player, *stdscr, Enrgyvoid, *Playersfp 472 * 473 * GLOBAL OUTPUTS: Other, Player, Changed, Enrgyvoid 474 * 475 * DESCRIPTION: 476 * Take care of energy voids, holy grail, decree and intervention 477 * action on current player. 478 */ 479 480 void 481 tampered(int what, double arg1, double arg2) 482 { 483 long loc; /* location in file of other players */ 484 485 Changed = TRUE; 486 move(4, 0); 487 488 Player.p_tampered = T_OFF; /* no longer tampered with */ 489 490 switch (what) { 491 case T_NRGVOID: 492 addstr("You've hit an energy void !\n"); 493 Player.p_mana /= 3.0; 494 Player.p_energy /= 2.0; 495 Player.p_gold = floor(Player.p_gold / 1.25) + 0.1; 496 altercoordinates(0.0, 0.0, A_NEAR); 497 break; 498 499 case T_TRANSPORT: 500 addstr("The king transported you ! "); 501 if (Player.p_charms > 0) { 502 addstr("But your charm saved you. . .\n"); 503 --Player.p_charms; 504 } else { 505 altercoordinates(0.0, 0.0, A_FAR); 506 addch('\n'); 507 } 508 break; 509 510 case T_BESTOW: 511 printw("The king has bestowed %.0f gold pieces on you !\n", arg1); 512 Player.p_gold += arg1; 513 break; 514 515 case T_CURSED: 516 addstr("You've been cursed ! "); 517 if (Player.p_blessing) { 518 addstr("But your blessing saved you. . .\n"); 519 Player.p_blessing = FALSE; 520 } else { 521 addch('\n'); 522 Player.p_poison += 2.0; 523 Player.p_energy = 10.0; 524 Player.p_maxenergy *= 0.95; 525 Player.p_status = S_PLAYING; /* no longer cloaked */ 526 } 527 break; 528 529 case T_VAPORIZED: 530 addstr("You have been vaporized!\n"); 531 more(7); 532 death("Vaporization"); 533 break; 534 535 case T_MONSTER: 536 addstr("The Valar zapped you with a monster!\n"); 537 more(7); 538 encounter((int)arg1); 539 return; 540 541 case T_BLESSED: 542 addstr("The Valar has blessed you!\n"); 543 Player.p_energy = (Player.p_maxenergy *= 1.05) + Player.p_shield; 544 Player.p_mana += 500.0; 545 Player.p_strength += 0.5; 546 Player.p_brains += 0.5; 547 Player.p_magiclvl += 0.5; 548 Player.p_poison = MIN(0.5, Player.p_poison); 549 break; 550 551 case T_RELOCATE: 552 addstr("You've been relocated. . .\n"); 553 altercoordinates(arg1, arg2, A_FORCED); 554 break; 555 556 case T_HEAL: 557 addstr("You've been healed!\n"); 558 Player.p_poison -= 0.25; 559 Player.p_energy = Player.p_maxenergy + Player.p_shield; 560 break; 561 562 case T_EXVALAR: 563 addstr("You are no longer Valar!\n"); 564 Player.p_specialtype = SC_COUNCIL; 565 break; 566 567 case T_GRAIL: 568 addstr("You have found The Holy Grail!!\n"); 569 if (Player.p_specialtype < SC_COUNCIL) { 570 /* must be council of wise to behold grail */ 571 addstr("However, you are not experienced enough to behold it.\n"); 572 Player.p_sin *= Player.p_sin; 573 Player.p_mana += 1000; 574 } else if (Player.p_specialtype == SC_VALAR || 575 Player.p_specialtype == SC_EXVALAR) { 576 addstr("You have made it to the position of Valar once already.\n"); 577 addstr("The Grail is of no more use to you now.\n"); 578 } else { 579 addstr("It is now time to see if you are worthy to behold it. . .\n"); 580 refresh(); 581 sleep(4); 582 583 if (drandom() / 2.0 < Player.p_sin) { 584 addstr("You have failed!\n"); 585 Player.p_strength = 586 Player.p_mana = 587 Player.p_energy = 588 Player.p_maxenergy = 589 Player.p_magiclvl = 590 Player.p_brains = 591 Player.p_experience = 592 Player.p_quickness = 1.0; 593 594 altercoordinates(1.0, 1.0, A_FORCED); 595 Player.p_level = 0.0; 596 } else { 597 addstr("You made to position of Valar!\n"); 598 Player.p_specialtype = SC_VALAR; 599 Player.p_lives = 5; 600 fseek(Playersfp, 0L, SEEK_SET); 601 loc = 0L; 602 while (fread((char *)&Other, SZ_PLAYERSTRUCT, 1, Playersfp) == 1) 603 /* search for existing valar */ 604 if (Other.p_specialtype == SC_VALAR && 605 Other.p_status != S_NOTUSED) { 606 /* found old valar */ 607 Other.p_tampered = T_EXVALAR; 608 writerecord(&Other, loc); 609 break; 610 } else 611 loc += SZ_PLAYERSTRUCT; 612 } 613 } 614 615 /* move grail to new location */ 616 Enrgyvoid.ev_active = TRUE; 617 Enrgyvoid.ev_x = ROLL(-1.0e6, 2.0e6); 618 Enrgyvoid.ev_y = ROLL(-1.0e6, 2.0e6); 619 writevoid(&Enrgyvoid, 0L); 620 break; 621 } 622 refresh(); 623 sleep(2); 624 } 625 626 /* 627 * FUNCTION: print list of players and locations 628 * 629 * ARGUMENTS: 630 * bool ingameflag - set if called while playing 631 * 632 * GLOBAL INPUTS: LINES, Other, Circle, Wizard, Player, *stdscr, *Playersfp 633 * 634 * DESCRIPTION: 635 * We can only see the coordinate of those closer to the origin 636 * from us. 637 * Kings and council of the wise can see and can be seen by everyone. 638 * Palantirs are good for seeing everyone; and the valar can use 639 * one to see through a 'cloak' spell. 640 * The valar has no coordinates, and is completely invisible if 641 * cloaked. 642 */ 643 644 void 645 userlist(bool ingameflag) 646 { 647 int numusers = 0; /* number of users on file */ 648 649 if (ingameflag && Player.p_blindness) { 650 mvaddstr(8, 0, "You cannot see anyone.\n"); 651 return; 652 } 653 654 fseek(Playersfp, 0L, SEEK_SET); 655 mvaddstr(8, 0, 656 "Name X Y Lvl Type Login Status\n"); 657 658 while (fread((char *)&Other, SZ_PLAYERSTRUCT, 1, Playersfp) == 1) { 659 if (Other.p_status == S_NOTUSED 660 /* record is unused */ 661 || (Other.p_specialtype == SC_VALAR && Other.p_status == S_CLOAKED)) { 662 /* cloaked valar */ 663 if (!Wizard) 664 /* wizard can see everything on file */ 665 continue; 666 } 667 668 ++numusers; 669 670 if (ingameflag && 671 /* must be playing for the rest of these conditions */ 672 (Player.p_specialtype >= SC_KING 673 /* kings and higher can see others */ 674 || Other.p_specialtype >= SC_KING 675 /* kings and higher can be seen by others */ 676 || Circle >= CIRCLE(Other.p_x, Other.p_y) 677 /* those nearer the origin can be seen */ 678 || Player.p_palantir) 679 /* palantir enables one to see others */ 680 && (Other.p_status != S_CLOAKED 681 || (Player.p_specialtype == SC_VALAR && Player.p_palantir)) 682 /* not cloaked; valar can see through cloak with a palantir */ 683 && Other.p_specialtype != SC_VALAR) 684 /* not a valar */ 685 /* coordinates should be printed */ 686 printw("%-20s %8.0f %8.0f ", 687 Other.p_name, Other.p_x, Other.p_y); 688 else 689 /* cannot see player's coordinates */ 690 printw("%-20s %19.19s ", 691 Other.p_name, descrlocation(&Other, TRUE)); 692 693 printw("%6.0f %s %-9.9s%s\n", Other.p_level, descrtype(&Other, TRUE), 694 Other.p_login, descrstatus(&Other)); 695 696 if ((numusers % (LINES - 10)) == 0) { 697 more(LINES - 1); 698 move(9, 0); 699 clrtobot(); 700 } 701 } 702 703 printw("Total players on file = %d\n", numusers); 704 refresh(); 705 } 706 707 /* 708 * FUNCTION: king stuff upon entering throne 709 * 710 * GLOBAL INPUTS: *Energyvoidfp, Other, Player, *stdscr, 711 * Enrgyvoid, *Playersfp 712 * 713 * GLOBAL OUTPUTS: Other, Player, Changed 714 * 715 * DESCRIPTION: 716 * If player is not already king, make him/her so if the old king 717 * is not playing. 718 * Clear energy voids with new king. 719 * Print 'decree' prompt. 720 */ 721 722 void 723 throneroom(void) 724 { 725 FILE *fp; /* to clear energy voids */ 726 long loc = 0L; /* location of old king in player file */ 727 728 if (Player.p_specialtype < SC_KING) { 729 /* not already king -- assumes crown */ 730 fseek(Playersfp, 0L, SEEK_SET); 731 while (fread((char *)&Other, SZ_PLAYERSTRUCT, 1, Playersfp) == 1) 732 if (Other.p_specialtype == SC_KING && Other.p_status != S_NOTUSED) { 733 /* found old king */ 734 if (Other.p_status != S_OFF) { 735 /* old king is playing */ 736 mvaddstr(4, 0, "The king is playing, so you cannot steal his throne\n"); 737 altercoordinates(0.0, 0.0, A_NEAR); 738 move(6, 0); 739 return; 740 } else { 741 /* old king is not playing - remove him/her */ 742 Other.p_specialtype = SC_NONE; 743 if (Other.p_crowns) 744 --Other.p_crowns; 745 writerecord(&Other, loc); 746 break; 747 } 748 } else 749 loc += SZ_PLAYERSTRUCT; 750 751 /* make player new king */ 752 Changed = TRUE; 753 Player.p_specialtype = SC_KING; 754 mvaddstr(4, 0, "You have become king!\n"); 755 756 /* let everyone else know */ 757 fp = fopen(_PATH_MESS, "w"); 758 fprintf(fp, "All hail the new king!"); 759 fclose(fp); 760 761 /* clear all energy voids; retain location of holy grail */ 762 fseek(Energyvoidfp, 0L, SEEK_SET); 763 fread((char *)&Enrgyvoid, SZ_VOIDSTRUCT, 1, Energyvoidfp); 764 fp = fopen(_PATH_VOID, "w"); 765 fwrite((char *)&Enrgyvoid, SZ_VOIDSTRUCT, 1, fp); 766 fclose(fp); 767 } 768 769 mvaddstr(6, 0, "0:Decree "); 770 } 771 772 /* 773 * FUNCTION: king and valar special options 774 * 775 * GLOBAL INPUTS: *Energyvoidfp, Other, Illcmd[], Wizard, Player, *stdscr, 776 * Databuf[], Enrgyvoid 777 * 778 * GLOBAL OUTPUTS: Other, Player, Enrgyvoid 779 * 780 * DESCRIPTION: 781 * Tamper with other players. Handle king/valar specific options. 782 */ 783 784 void 785 dotampered(void) 786 { 787 short tamper; /* value for tampering with other players */ 788 const char *option; /* pointer to option description */ 789 double temp1 = 0.0, temp2 = 0.0; /* other tampering values */ 790 int ch; /* input */ 791 long loc; /* location in energy void file */ 792 FILE *fp; /* for opening gold file */ 793 794 move(6, 0); 795 clrtoeol(); 796 if (Player.p_specialtype < SC_COUNCIL && !Wizard) { 797 /* king options */ 798 addstr("1:Transport 2:Curse 3:Energy Void 4:Bestow 5:Collect Taxes "); 799 800 ch = getanswer(" ", TRUE); 801 move(6, 0); 802 clrtoeol(); 803 move(4, 0); 804 switch (ch) { 805 case '1': /* transport someone */ 806 tamper = T_TRANSPORT; 807 option = "transport"; 808 break; 809 810 case '2': /* curse another */ 811 tamper = T_CURSED; 812 option = "curse"; 813 break; 814 815 case '3': /* create energy void */ 816 if ((loc = allocvoid()) > 20L * (long)SZ_VOIDSTRUCT) 817 /* can only have 20 void active at once */ 818 mvaddstr(5, 0, "Sorry, void creation limit reached.\n"); 819 else { 820 addstr("Enter the X Y coordinates of void ? "); 821 getstring(Databuf, SZ_DATABUF); 822 sscanf(Databuf, "%lf %lf", &temp1, &temp2); 823 Enrgyvoid.ev_x = floor(temp1); 824 Enrgyvoid.ev_y = floor(temp2); 825 Enrgyvoid.ev_active = TRUE; 826 writevoid(&Enrgyvoid, loc); 827 mvaddstr(5, 0, "It is done.\n"); 828 } 829 return; 830 831 case '4': /* bestow gold to subject */ 832 tamper = T_BESTOW; 833 addstr("How much gold to bestow ? "); 834 temp1 = infloat(); 835 if (temp1 > Player.p_gold || temp1 < 0) { 836 mvaddstr(5, 0, "You don't have that !\n"); 837 return; 838 } 839 840 /* adjust gold after we are sure it will be given to someone */ 841 option = "give gold to"; 842 break; 843 844 case '5': /* collect accumulated taxes */ 845 if ((fp = fopen(_PATH_GOLD, "r+")) != NULL) { 846 /* collect taxes */ 847 fread((char *)&temp1, sizeof(double), 1, fp); 848 fseek(fp, 0L, SEEK_SET); 849 /* clear out value */ 850 temp2 = 0.0; 851 fwrite((char *)&temp2, sizeof(double), 1, fp); 852 fclose(fp); 853 } 854 855 mvprintw(4, 0, "You have collected %.0f in gold.\n", temp1); 856 Player.p_gold += floor(temp1); 857 return; 858 859 default: 860 return; 861 } 862 /* end of king options */ 863 } else { 864 /* council of wise, valar, wizard options */ 865 addstr("1:Heal "); 866 if (Player.p_palantir || Wizard) 867 addstr("2:Seek Grail "); 868 if (Player.p_specialtype == SC_VALAR || Wizard) 869 addstr("3:Throw Monster 4:Relocate 5:Bless "); 870 if (Wizard) 871 addstr("6:Vaporize "); 872 873 ch = getanswer(" ", TRUE); 874 if (!Wizard) { 875 if (ch > '2' && Player.p_specialtype != SC_VALAR) { 876 ILLCMD(); 877 return; 878 } 879 880 if (Player.p_mana < MM_INTERVENE) { 881 mvaddstr(5, 0, "No mana left.\n"); 882 return; 883 } else 884 Player.p_mana -= MM_INTERVENE; 885 } 886 887 switch (ch) { 888 case '1': /* heal another */ 889 tamper = T_HEAL; 890 option = "heal"; 891 break; 892 893 case '2': /* seek grail */ 894 if (Player.p_palantir) { 895 /* need a palantir to seek */ 896 fseek(Energyvoidfp, 0L, SEEK_SET); 897 fread((char *)&Enrgyvoid, SZ_VOIDSTRUCT, 1, Energyvoidfp); 898 temp1 = distance(Player.p_x, Enrgyvoid.ev_x, Player.p_y, Enrgyvoid.ev_y); 899 temp1 += ROLL(-temp1 / 10.0, temp1 / 5.0); /* add some error */ 900 mvprintw(5, 0, "The palantir says the Grail is about %.0f away.\n", temp1); 901 } else 902 /* no palantir */ 903 mvaddstr(5, 0, "You need a palantir to seek the Grail.\n"); 904 return; 905 906 case '3': /* lob monster at someone */ 907 mvaddstr(4, 0, "Which monster [0-99] ? "); 908 temp1 = infloat(); 909 temp1 = MAX(0.0, MIN(99.0, temp1)); 910 tamper = T_MONSTER; 911 option = "throw a monster at"; 912 break; 913 914 case '4': /* move another player */ 915 mvaddstr(4, 0, "New X Y coordinates ? "); 916 getstring(Databuf, SZ_DATABUF); 917 sscanf(Databuf, "%lf %lf", &temp1, &temp2); 918 tamper = T_RELOCATE; 919 option = "relocate"; 920 break; 921 922 case '5': /* bless a player */ 923 tamper = T_BLESSED; 924 option = "bless"; 925 break; 926 927 case '6': /* kill off a player */ 928 if (Wizard) { 929 tamper = T_VAPORIZED; 930 option = "vaporize"; 931 break; 932 } else 933 return; 934 935 default: 936 return; 937 } 938 939 /* adjust age after we are sure intervention will be done */ 940 /* end of valar, etc. options */ 941 } 942 943 for (;;) { 944 /* prompt for player to affect */ 945 mvprintw(4, 0, "Who do you want to %s ? ", option); 946 getstring(Databuf, SZ_DATABUF); 947 truncstring(Databuf); 948 949 if (Databuf[0] == '\0') 950 userlist(TRUE); 951 else 952 break; 953 } 954 955 if (strcmp(Player.p_name, Databuf) != 0) { 956 /* name other than self */ 957 if ((loc = findname(Databuf, &Other)) >= 0L) { 958 if (Other.p_tampered != T_OFF) { 959 mvaddstr(5, 0, "That person has something pending already.\n"); 960 return; 961 } else { 962 if (tamper == T_RELOCATE 963 && CIRCLE(temp1, temp2) < CIRCLE(Other.p_x, Other.p_y) 964 && !Wizard) 965 mvaddstr(5, 0, "Cannot move someone closer to the Lord's Chamber.\n"); 966 else { 967 if (tamper == T_BESTOW) 968 Player.p_gold -= floor(temp1); 969 if (!Wizard && (tamper == T_HEAL || tamper == T_MONSTER || 970 tamper == T_RELOCATE || tamper == T_BLESSED)) 971 Player.p_age += N_AGE; /* age penalty */ 972 Other.p_tampered = tamper; 973 Other.p_1scratch = floor(temp1); 974 Other.p_2scratch = floor(temp2); 975 writerecord(&Other, loc); 976 mvaddstr(5, 0, "It is done.\n"); 977 } 978 return; 979 } 980 } else 981 /* player not found */ 982 mvaddstr(5, 0, "There is no one by that name.\n"); 983 } else 984 /* self */ 985 mvaddstr(5, 0, "You may not do it to yourself!\n"); 986 } 987 988 /* 989 * FUNCTION: update energy void entry in energy void file 990 * 991 * ARGUMENTS: 992 * struct energyvoid *vp - pointer to structure to write to file 993 * long loc - location in file to update 994 * 995 * GLOBAL INPUTS: *Energyvoidfp 996 * 997 * DESCRIPTION: 998 * Write out energy void structure at specified location. 999 */ 1000 1001 void 1002 writevoid(struct energyvoid *vp, long loc) 1003 { 1004 fseek(Energyvoidfp, loc, SEEK_SET); 1005 fwrite((char *)vp, SZ_VOIDSTRUCT, 1, Energyvoidfp); 1006 fflush(Energyvoidfp); 1007 fseek(Energyvoidfp, 0L, SEEK_SET); 1008 } 1009 1010 /* 1011 * FUNCTION: allocate space for a new energy void 1012 * 1013 * RETURN VALUE: location of new energy void space 1014 * 1015 * GLOBAL INPUTS: *Energyvoidfp, Enrgyvoid 1016 * 1017 * DESCRIPTION: 1018 * Search energy void file for an inactive entry and return its 1019 * location. 1020 * If no inactive ones are found, return one more than last location. 1021 */ 1022 1023 size_t 1024 allocvoid(void) 1025 { 1026 size_t loc = 0; /* location of new energy void */ 1027 1028 fseek(Energyvoidfp, 0L, SEEK_SET); 1029 while (fread((char *)&Enrgyvoid, SZ_VOIDSTRUCT, 1, Energyvoidfp) == 1) 1030 if (Enrgyvoid.ev_active) 1031 loc += SZ_VOIDSTRUCT; 1032 else 1033 break; 1034 1035 return (loc); 1036 } 1037