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