1 /* 2 * Phantasia 3.3.2 -- Interterminal fantasy game 3 * 4 * Edward A. Estes 5 * AT&T, March 12, 1986 6 */ 7 8 /* DISCLAIMER: 9 * 10 * This game is distributed for free as is. It is not guaranteed to work 11 * in every conceivable environment. It is not even guaranteed to work 12 * in ANY environment. 13 * 14 * This game is distributed without notice of copyright, therefore it 15 * may be used in any manner the recipient sees fit. However, the 16 * author assumes no responsibility for maintaining or revising this 17 * game, in its original form, or any derivitives thereof. 18 * 19 * The author shall not be responsible for any loss, cost, or damage, 20 * including consequential damage, caused by reliance on this material. 21 * 22 * The author makes no warranties, express or implied, including warranties 23 * of merchantability or fitness for a particular purpose or use. 24 * 25 * AT&T is in no way connected with this game. 26 */ 27 28 #include <sys/types.h> 29 #include <pwd.h> 30 31 /* 32 * The program allocates as much file space as it needs to store characters, 33 * so the possibility exists for the character file to grow without bound. 34 * The file is purged upon normal entry to try to avoid that problem. 35 * A similar problem exists for energy voids. To alleviate the problem here, 36 * the void file is cleared with every new king, and a limit is placed 37 * on the size of the energy void file. 38 */ 39 40 /* 41 * Put one line of text into the file 'motd' for announcements, etc. 42 */ 43 44 /* 45 * The scoreboard file is updated when someone dies, and keeps track 46 * of the highest character to date for that login. 47 * Being purged from the character file does not cause the scoreboard 48 * to be updated. 49 */ 50 51 /* 52 * All source files are set up for 'vi' with shiftwidth=4, tabstop=8. 53 */ 54 55 /**/ 56 57 /* 58 * main.c Main routines for Phantasia 59 */ 60 61 #include "include.h" 62 63 /*************************************************************************** 64 / FUNCTION NAME: main() 65 / 66 / FUNCTION: initialize state, and call main process 67 / 68 / AUTHOR: E. A. Estes, 12/4/85 69 / 70 / ARGUMENTS: 71 / int argc - argument count 72 / char **argv - argument vector 73 / 74 / RETURN VALUE: none 75 / 76 / MODULES CALLED: monstlist(), checkenemy(), activelist(), 77 / throneroom(), checkbattle(), readmessage(), changestats(), writerecord(), 78 / tradingpost(), adjuststats(), recallplayer(), displaystats(), checktampered(), 79 / fabs(), rollnewplayer(), time(), exit(), sqrt(), floor(), wmove(), 80 / signal(), strcat(), purgeoldplayers(), getuid(), isatty(), wclear(), 81 / strcpy(), system(), altercoordinates(), cleanup(), waddstr(), procmain(), 82 / playinit(), leavegame(), localtime(), getanswer(), neatstuff(), initialstate(), 83 / scorelist(), titlelist() 84 / 85 / GLOBAL INPUTS: *Login, Throne, Wizard, Player, *stdscr, Changed, Databuf[], 86 / Fileloc, Stattable[] 87 / 88 / GLOBAL OUTPUTS: Wizard, Player, Changed, Fileloc, Timeout, *Statptr 89 / 90 / DESCRIPTION: 91 / Process arguments, initialize program, and loop forever processing 92 / player input. 93 / 94 /***************************************************************************/ 95 96 main(argc, argv) 97 int argc; 98 char **argv; 99 { 100 bool noheader = FALSE; /* set if don't want header */ 101 bool headeronly = FALSE; /* set if only want header */ 102 bool examine = FALSE; /* set if examine a character */ 103 long seconds; /* for time of day */ 104 double dtemp; /* for temporary calculations */ 105 106 initialstate(); /* init globals */ 107 108 /* process arguments */ 109 while (--argc && (*++argv)[0] == '-') 110 switch ((*argv)[1]) 111 { 112 case 's': /* short */ 113 noheader = TRUE; 114 break; 115 116 case 'H': /* Header */ 117 headeronly = TRUE; 118 break; 119 120 case 'a': /* all users */ 121 activelist(); 122 cleanup(TRUE); 123 /*NOTREACHED*/ 124 125 case 'p': /* purge old players */ 126 purgeoldplayers(); 127 cleanup(TRUE); 128 /*NOTREACHED*/ 129 130 case 'S': /* set 'Wizard' */ 131 Wizard = !getuid(); 132 break; 133 134 case 'x': /* examine */ 135 examine = TRUE; 136 break; 137 138 case 'm': /* monsters */ 139 monstlist(); 140 cleanup(TRUE); 141 /*NOTREACHED*/ 142 143 case 'b': /* scoreboard */ 144 scorelist(); 145 cleanup(TRUE); 146 /*NOTREACHED*/ 147 } 148 149 if (!isatty(0)) /* don't let non-tty's play */ 150 cleanup(TRUE); 151 /*NOTREACHED*/ 152 153 playinit(); /* set up to catch signals, init curses */ 154 155 if (examine) 156 { 157 changestats(FALSE); 158 cleanup(TRUE); 159 /*NOTREACHED*/ 160 } 161 162 if (!noheader) 163 { 164 titlelist(); 165 purgeoldplayers(); /* clean up old characters */ 166 } 167 168 if (headeronly) 169 cleanup(TRUE); 170 /*NOTREACHED*/ 171 172 do 173 /* get the player structure filled */ 174 { 175 Fileloc = -1L; 176 177 mvaddstr(22, 17, "Do you have a character to run [Q = Quit] ? "); 178 179 switch (getanswer("NYQ", FALSE)) 180 { 181 case 'Y': 182 Fileloc = recallplayer(); 183 break; 184 185 case 'Q': 186 cleanup(TRUE); 187 /*NOTREACHED*/ 188 189 default: 190 Fileloc = rollnewplayer(); 191 break; 192 } 193 clear(); 194 } 195 while (Fileloc < 0L); 196 197 if (Player.p_level > 5.0) 198 /* low level players have long timeout */ 199 Timeout = TRUE; 200 201 /* update some important player statistics */ 202 strcpy(Player.p_login, Login); 203 time(&seconds); 204 Player.p_lastused = localtime(&seconds)->tm_yday; 205 Player.p_status = S_PLAYING; 206 writerecord(&Player, Fileloc); 207 208 Statptr = &Stattable[Player.p_type]; /* initialize pointer */ 209 210 /* catch interrupts */ 211 #ifdef BSD41 212 sigset(SIGINT, interrupt); 213 #endif 214 #ifdef BSD42 215 signal(SIGINT, interrupt); 216 #endif 217 #ifdef SYS3 218 signal(SIGINT, interrupt); 219 #endif 220 #ifdef SYS5 221 signal(SIGINT, interrupt); 222 #endif 223 224 altercoordinates(Player.p_x, Player.p_y, A_FORCED); /* set some flags */ 225 226 clear(); 227 228 for (;;) 229 /* loop forever, processing input */ 230 { 231 232 adjuststats(); /* cleanup stats */ 233 234 if (Throne && Player.p_crowns == 0 && Player.p_specialtype != SC_KING) 235 /* not allowed on throne -- move */ 236 { 237 mvaddstr(5,0,"You're not allowed in the Lord's Chamber without a crown.\n"); 238 altercoordinates(0.0, 0.0, A_NEAR); 239 } 240 241 checktampered(); /* check for energy voids, etc. */ 242 243 if (Player.p_status != S_CLOAKED 244 /* not cloaked */ 245 && (dtemp = fabs(Player.p_x)) == fabs(Player.p_y) 246 /* |x| = |y| */ 247 && !Throne) 248 /* not on throne */ 249 { 250 dtemp = sqrt(dtemp / 100.0); 251 if (floor(dtemp) == dtemp) 252 /* |x| / 100 == n*n; at a trading post */ 253 { 254 tradingpost(); 255 clear(); 256 } 257 } 258 259 checkbattle(); /* check for player to player battle */ 260 neatstuff(); /* gurus, medics, etc. */ 261 262 if (Player.p_status == S_CLOAKED) 263 /* costs 3 mana per turn to be cloaked */ 264 if (Player.p_mana > 3.0) 265 Player.p_mana -= 3.0; 266 else 267 /* ran out of mana, uncloak */ 268 { 269 Player.p_status = S_PLAYING; 270 Changed = TRUE; 271 } 272 273 if (Player.p_status != S_PLAYING && Player.p_status != S_CLOAKED) 274 /* change status back to S_PLAYING */ 275 { 276 Player.p_status = S_PLAYING; 277 Changed = TRUE; 278 } 279 280 if (Changed) 281 /* update file only if important stuff has changed */ 282 { 283 writerecord(&Player, Fileloc); 284 Changed = FALSE; 285 continue; 286 } 287 288 readmessage(); /* read message, if any */ 289 290 displaystats(); /* print statistics */ 291 292 move(6, 0); 293 294 if (Throne) 295 /* maybe make king, print prompt, etc. */ 296 throneroom(); 297 298 /* print status line */ 299 addstr("1:Move 2:Players 3:Talk 4:Stats 5:Quit "); 300 if (Player.p_level >= MEL_CLOAK && Player.p_magiclvl >= ML_CLOAK) 301 addstr("6:Cloak "); 302 if (Player.p_level >= MEL_TELEPORT && Player.p_magiclvl >= ML_TELEPORT) 303 addstr("7:Teleport "); 304 if (Player.p_specialtype >= SC_COUNCIL || Wizard) 305 addstr("8:Intervene "); 306 307 procmain(); /* process input */ 308 } 309 } 310 /**/ 311 /************************************************************************ 312 / 313 / FUNCTION NAME: initialstate() 314 / 315 / FUNCTION: initialize some important global variable 316 / 317 / AUTHOR: E. A. Estes, 12/4/85 318 / 319 / ARGUMENTS: none 320 / 321 / RETURN VALUE: none 322 / 323 / MODULES CALLED: time(), fopen(), srandom(), error(), getuid(), getlogin(), 324 / getpwuid() 325 / 326 / GLOBAL INPUTS: 327 / 328 / GLOBAL OUTPUTS: *Energyvoidfp, Echo, Marsh, *Login, Users, Beyond, 329 / Throne, Wizard, Changed, Okcount, Timeout, Windows, *Monstfp, *Messagefp, 330 / *Playersfp 331 / 332 / DESCRIPTION: 333 / Set global flags, and open files which remain open. 334 / 335 /************************************************************************/ 336 337 initialstate() 338 { 339 Beyond = FALSE; 340 Marsh = FALSE; 341 Throne = FALSE; 342 Changed = FALSE; 343 Wizard = FALSE; 344 Timeout = FALSE; 345 Users = 0; 346 Windows = FALSE; 347 Echo = TRUE; 348 349 /* setup login name */ 350 if ((Login = getlogin()) == NULL) 351 Login = getpwuid(getuid())->pw_name; 352 353 /* open some files */ 354 if ((Playersfp = fopen(_PATH_PEOPLE, "r+")) == NULL) 355 error(_PATH_PEOPLE); 356 /*NOTREACHED*/ 357 358 if ((Monstfp = fopen(_PATH_MONST, "r+")) == NULL) 359 error(_PATH_MONST); 360 /*NOTREACHED*/ 361 362 if ((Messagefp = fopen(_PATH_MESS, "r")) == NULL) 363 error(_PATH_MESS); 364 /*NOTREACHED*/ 365 366 if ((Energyvoidfp = fopen(_PATH_VOID, "r+")) == NULL) 367 error(_PATH_VOID); 368 /*NOTREACHED*/ 369 370 srandom((unsigned) time((long *) NULL)); /* prime random numbers */ 371 } 372 /**/ 373 /************************************************************************ 374 / 375 / FUNCTION NAME: rollnewplayer() 376 / 377 / FUNCTION: roll up a new character 378 / 379 / AUTHOR: E. A. Estes, 12/4/85 380 / 381 / ARGUMENTS: none 382 / 383 / RETURN VALUE: none 384 / 385 / MODULES CALLED: initplayer(), allocrecord(), truncstring(), fabs(), wmove(), 386 / wclear(), sscanf(), strcmp(), genchar(), waddstr(), findname(), mvprintw(), 387 / getanswer(), getstring() 388 / 389 / GLOBAL INPUTS: Other, Wizard, Player, *stdscr, Databuf[] 390 / 391 / GLOBAL OUTPUTS: Echo 392 / 393 / DESCRIPTION: 394 / Prompt player, and roll up new character. 395 / 396 /************************************************************************/ 397 398 long 399 rollnewplayer() 400 { 401 int chartype; /* character type */ 402 int ch; /* input */ 403 404 initplayer(&Player); /* initialize player structure */ 405 406 clear(); 407 mvaddstr(4, 21, "Which type of character do you want:"); 408 mvaddstr(8, 4, "1:Magic User 2:Fighter 3:Elf 4:Dwarf 5:Halfling 6:Experimento "); 409 if (Wizard) { 410 addstr("7:Super ? "); 411 chartype = getanswer("1234567", FALSE); 412 } 413 else { 414 addstr("? "); 415 chartype = getanswer("123456", FALSE); 416 } 417 418 do 419 { 420 genchar(chartype); /* roll up a character */ 421 422 /* print out results */ 423 mvprintw(12, 14, 424 "Strength : %2.0f Quickness: %2.0f Mana : %2.0f\n", 425 Player.p_strength, Player.p_quickness, Player.p_mana); 426 mvprintw(13, 14, 427 "Energy Level: %2.0f Brains : %2.0f Magic Level: %2.0f\n", 428 Player.p_energy, Player.p_brains, Player.p_magiclvl); 429 430 if (Player.p_type == C_EXPER || Player.p_type == C_SUPER) 431 break; 432 433 mvaddstr(14, 14, "Type '1' to keep >"); 434 ch = getanswer(" ", TRUE); 435 } 436 while (ch != '1'); 437 438 if (Player.p_type == C_EXPER || Player.p_type == C_SUPER) 439 /* get coordinates for experimento */ 440 for (;;) 441 { 442 mvaddstr(16, 0, "Enter the X Y coordinates of your experimento ? "); 443 getstring(Databuf, SZ_DATABUF); 444 sscanf(Databuf, "%lf %lf", &Player.p_x, &Player.p_y); 445 446 if (fabs(Player.p_x) > D_EXPER || fabs(Player.p_y) > D_EXPER) 447 mvaddstr(17, 0, "Invalid coordinates. Try again.\n"); 448 else 449 break; 450 } 451 452 for (;;) 453 /* name the new character */ 454 { 455 mvprintw(18, 0, 456 "Give your character a name [up to %d characters] ? ", SZ_NAME - 1); 457 getstring(Player.p_name, SZ_NAME); 458 truncstring(Player.p_name); /* remove trailing blanks */ 459 460 if (Player.p_name[0] == '\0') 461 /* no null names */ 462 mvaddstr(19, 0, "Invalid name."); 463 else if (findname(Player.p_name, &Other) >= 0L) 464 /* cannot have duplicate names */ 465 mvaddstr(19, 0, "Name already in use."); 466 else 467 /* name is acceptable */ 468 break; 469 470 addstr(" Pick another.\n"); 471 } 472 473 /* get a password for character */ 474 Echo = FALSE; 475 476 do 477 { 478 mvaddstr(20, 0, "Give your character a password [up to 8 characters] ? "); 479 getstring(Player.p_password, SZ_PASSWORD); 480 mvaddstr(21, 0, "One more time to verify ? "); 481 getstring(Databuf, SZ_PASSWORD); 482 } 483 while (strcmp(Player.p_password, Databuf) != 0); 484 485 Echo = TRUE; 486 487 return(allocrecord()); 488 } 489 /**/ 490 /************************************************************************ 491 / 492 / FUNCTION NAME: procmain() 493 / 494 / FUNCTION: process input from player 495 / 496 / AUTHOR: E. A. Estes, 12/4/85 497 / 498 / ARGUMENTS: none 499 / 500 / RETURN VALUE: none 501 / 502 / MODULES CALLED: dotampered(), changestats(), inputoption(), allstatslist(), 503 / fopen(), wmove(), drandom(), sscanf(), fclose(), altercoordinates(), 504 / waddstr(), fprintf(), distance(), userlist(), leavegame(), encounter(), 505 / getstring(), wclrtobot() 506 / 507 / GLOBAL INPUTS: Circle, Illcmd[], Throne, Wizard, Player, *stdscr, 508 / Databuf[], Illmove[] 509 / 510 / GLOBAL OUTPUTS: Player, Changed 511 / 512 / DESCRIPTION: 513 / Process main menu options. 514 / 515 /************************************************************************/ 516 517 procmain() 518 { 519 int ch; /* input */ 520 double x; /* desired new x coordinate */ 521 double y; /* desired new y coordinate */ 522 double temp; /* for temporary calculations */ 523 FILE *fp; /* for opening files */ 524 register int loop; /* a loop counter */ 525 bool hasmoved = FALSE; /* set if player has moved */ 526 527 ch = inputoption(); 528 mvaddstr(4, 0, "\n\n"); /* clear status area */ 529 530 move(7, 0); 531 clrtobot(); /* clear data on bottom area of screen */ 532 533 if (Player.p_specialtype == SC_VALAR && (ch == '1' || ch == '7')) 534 /* valar cannot move */ 535 ch = ' '; 536 537 switch (ch) 538 { 539 case 'K': /* move up/north */ 540 case 'N': 541 x = Player.p_x; 542 y = Player.p_y + MAXMOVE(); 543 hasmoved = TRUE; 544 break; 545 546 case 'J': /* move down/south */ 547 case 'S': 548 x = Player.p_x; 549 y = Player.p_y - MAXMOVE(); 550 hasmoved = TRUE; 551 break; 552 553 case 'L': /* move right/east */ 554 case 'E': 555 x = Player.p_x + MAXMOVE(); 556 y = Player.p_y; 557 hasmoved = TRUE; 558 break; 559 560 case 'H': /* move left/west */ 561 case 'W': 562 x = Player.p_x - MAXMOVE(); 563 y = Player.p_y; 564 hasmoved = TRUE; 565 break; 566 567 default: /* rest */ 568 Player.p_energy += (Player.p_maxenergy + Player.p_shield) / 15.0 569 + Player.p_level / 3.0 + 2.0; 570 Player.p_energy = 571 MIN(Player.p_energy, Player.p_maxenergy + Player.p_shield); 572 573 if (Player.p_status != S_CLOAKED) 574 /* cannot find mana if cloaked */ 575 { 576 Player.p_mana += (Circle + Player.p_level) / 4.0; 577 578 if (drandom() < 0.2 && Player.p_status == S_PLAYING && !Throne) 579 /* wandering monster */ 580 encounter(-1); 581 } 582 break; 583 584 case 'X': /* change/examine a character */ 585 changestats(TRUE); 586 break; 587 588 case '1': /* move */ 589 for (loop = 3; loop; --loop) 590 { 591 mvaddstr(4, 0, "X Y Coordinates ? "); 592 getstring(Databuf, SZ_DATABUF); 593 594 if (sscanf(Databuf, "%lf %lf", &x, &y) != 2) 595 mvaddstr(5, 0, "Try again\n"); 596 else if (distance(Player.p_x, x, Player.p_y, y) > MAXMOVE()) 597 ILLMOVE(); 598 else 599 { 600 hasmoved = TRUE; 601 break; 602 } 603 } 604 break; 605 606 case '2': /* players */ 607 userlist(TRUE); 608 break; 609 610 case '3': /* message */ 611 mvaddstr(4, 0, "Message ? "); 612 getstring(Databuf, SZ_DATABUF); 613 /* we open the file for writing to erase any data which is already there */ 614 fp = fopen(_PATH_MESS, "w"); 615 if (Databuf[0] != '\0') 616 fprintf(fp, "%s: %s", Player.p_name, Databuf); 617 fclose(fp); 618 break; 619 620 case '4': /* stats */ 621 allstatslist(); 622 break; 623 624 case '5': /* good-bye */ 625 leavegame(); 626 /*NOTREACHED*/ 627 628 case '6': /* cloak */ 629 if (Player.p_level < MEL_CLOAK || Player.p_magiclvl < ML_CLOAK) 630 ILLCMD(); 631 else if (Player.p_status == S_CLOAKED) 632 Player.p_status = S_PLAYING; 633 else if (Player.p_mana < MM_CLOAK) 634 mvaddstr(5, 0, "No mana left.\n"); 635 else 636 { 637 Changed = TRUE; 638 Player.p_mana -= MM_CLOAK; 639 Player.p_status = S_CLOAKED; 640 } 641 break; 642 643 case '7': /* teleport */ 644 /* 645 * conditions for teleport 646 * - 20 per (level plus magic level) 647 * - OR council of the wise or valar or ex-valar 648 * - OR transport from throne 649 * transports from throne cost no mana 650 */ 651 if (Player.p_level < MEL_TELEPORT || Player.p_magiclvl < ML_TELEPORT) 652 ILLCMD(); 653 else 654 for (loop = 3; loop; --loop) 655 { 656 mvaddstr(4, 0, "X Y Coordinates ? "); 657 getstring(Databuf, SZ_DATABUF); 658 659 if (sscanf(Databuf, "%lf %lf", &x, &y) == 2) 660 { 661 temp = distance(Player.p_x, x, Player.p_y, y); 662 if (!Throne 663 /* can transport anywhere from throne */ 664 && Player.p_specialtype <= SC_COUNCIL 665 /* council, valar can transport anywhere */ 666 && temp > (Player.p_level + Player.p_magiclvl) * 20.0) 667 /* can only move 20 per exp. level + mag. level */ 668 ILLMOVE(); 669 else 670 { 671 temp = (temp / 75.0 + 1.0) * 20.0; /* mana used */ 672 673 if (!Throne && temp > Player.p_mana) 674 mvaddstr(5, 0, "Not enough power for that distance.\n"); 675 else 676 { 677 if (!Throne) 678 Player.p_mana -= temp; 679 hasmoved = TRUE; 680 break; 681 } 682 } 683 } 684 } 685 break; 686 687 case 'C': 688 case '9': /* monster */ 689 if (Throne) 690 /* no monsters while on throne */ 691 mvaddstr(5, 0, "No monsters in the chamber!\n"); 692 else if (Player.p_specialtype != SC_VALAR) 693 /* the valar cannot call monsters */ 694 { 695 Player.p_sin += 1e-6; 696 encounter(-1); 697 } 698 break; 699 700 case '0': /* decree */ 701 if (Wizard || Player.p_specialtype == SC_KING && Throne) 702 /* kings must be on throne to decree */ 703 dotampered(); 704 else 705 ILLCMD(); 706 break; 707 708 case '8': /* intervention */ 709 if (Wizard || Player.p_specialtype >= SC_COUNCIL) 710 dotampered(); 711 else 712 ILLCMD(); 713 break; 714 } 715 716 if (hasmoved) 717 /* player has moved -- alter coordinates, and do random monster */ 718 { 719 altercoordinates(x, y, A_SPECIFIC); 720 721 if (drandom() < 0.2 && Player.p_status == S_PLAYING && !Throne) 722 encounter(-1); 723 } 724 } 725 /**/ 726 /************************************************************************ 727 / 728 / FUNCTION NAME: titlelist() 729 / 730 / FUNCTION: print title page 731 / 732 / AUTHOR: E. A. Estes, 12/4/85 733 / 734 / ARGUMENTS: none 735 / 736 / RETURN VALUE: none 737 / 738 / MODULES CALLED: fread(), fseek(), fopen(), fgets(), wmove(), strcpy(), 739 / fclose(), strlen(), waddstr(), sprintf(), wrefresh() 740 / 741 / GLOBAL INPUTS: Lines, Other, *stdscr, Databuf[], *Playersfp 742 / 743 / GLOBAL OUTPUTS: Lines 744 / 745 / DESCRIPTION: 746 / Print important information about game, players, etc. 747 / 748 /************************************************************************/ 749 750 titlelist() 751 { 752 register FILE *fp; /* used for opening various files */ 753 bool councilfound = FALSE; /* set if we find a member of the council */ 754 bool kingfound = FALSE; /* set if we find a king */ 755 double hiexp, nxtexp; /* used for finding the two highest players */ 756 double hilvl, nxtlvl; /* used for finding the two highest players */ 757 char hiname[21], nxtname[21];/* used for finding the two highest players */ 758 759 mvaddstr(0, 14, "W e l c o m e t o P h a n t a s i a (vers. 3.3.2)!"); 760 761 /* print message of the day */ 762 if ((fp = fopen(_PATH_MOTD, "r")) != NULL 763 && fgets(Databuf, SZ_DATABUF, fp) != NULL) 764 { 765 mvaddstr(2, 40 - strlen(Databuf) / 2, Databuf); 766 fclose(fp); 767 } 768 769 /* search for king */ 770 fseek(Playersfp, 0L, 0); 771 while (fread((char *) &Other, SZ_PLAYERSTRUCT, 1, Playersfp) == 1) 772 if (Other.p_specialtype == SC_KING && Other.p_status != S_NOTUSED) 773 /* found the king */ 774 { 775 sprintf(Databuf, "The present ruler is %s Level:%.0f", 776 Other.p_name, Other.p_level); 777 mvaddstr(4, 40 - strlen(Databuf) / 2, Databuf); 778 kingfound = TRUE; 779 break; 780 } 781 782 if (!kingfound) 783 mvaddstr(4, 24, "There is no ruler at this time."); 784 785 /* search for valar */ 786 fseek(Playersfp, 0L, 0); 787 while (fread((char *) &Other, SZ_PLAYERSTRUCT, 1, Playersfp) == 1) 788 if (Other.p_specialtype == SC_VALAR && Other.p_status != S_NOTUSED) 789 /* found the valar */ 790 { 791 sprintf(Databuf, "The Valar is %s Login: %s", Other.p_name, Other.p_login); 792 mvaddstr(6, 40 - strlen(Databuf) / 2 , Databuf); 793 break; 794 } 795 796 /* search for council of the wise */ 797 fseek(Playersfp, 0L, 0); 798 Lines = 10; 799 while (fread((char *) &Other, SZ_PLAYERSTRUCT, 1, Playersfp) == 1) 800 if (Other.p_specialtype == SC_COUNCIL && Other.p_status != S_NOTUSED) 801 /* found a member of the council */ 802 { 803 if (!councilfound) 804 { 805 mvaddstr(8, 30, "Council of the Wise:"); 806 councilfound = TRUE; 807 } 808 809 /* This assumes a finite (<=5) number of C.O.W.: */ 810 sprintf(Databuf, "%s Login: %s", Other.p_name, Other.p_login); 811 mvaddstr(Lines++, 40 - strlen(Databuf) / 2, Databuf); 812 } 813 814 /* search for the two highest players */ 815 nxtname[0] = hiname[0] = '\0'; 816 hiexp = 0.0; 817 nxtlvl = hilvl = 0; 818 819 fseek(Playersfp, 0L, 0); 820 while (fread((char *) &Other, SZ_PLAYERSTRUCT, 1, Playersfp) == 1) 821 if (Other.p_experience > hiexp && Other.p_specialtype <= SC_KING && Other.p_status != S_NOTUSED) 822 /* highest found so far */ 823 { 824 nxtexp = hiexp; 825 hiexp = Other.p_experience; 826 nxtlvl = hilvl; 827 hilvl = Other.p_level; 828 strcpy(nxtname, hiname); 829 strcpy(hiname, Other.p_name); 830 } 831 else if (Other.p_experience > nxtexp 832 && Other.p_specialtype <= SC_KING 833 && Other.p_status != S_NOTUSED) 834 /* next highest found so far */ 835 { 836 nxtexp = Other.p_experience; 837 nxtlvl = Other.p_level; 838 strcpy(nxtname, Other.p_name); 839 } 840 841 mvaddstr(15, 28, "Highest characters are:"); 842 sprintf(Databuf, "%s Level:%.0f and %s Level:%.0f", 843 hiname, hilvl, nxtname, nxtlvl); 844 mvaddstr(17, 40 - strlen(Databuf) / 2, Databuf); 845 846 /* print last to die */ 847 if ((fp = fopen(_PATH_LASTDEAD,"r")) != NULL 848 && fgets(Databuf, SZ_DATABUF, fp) != NULL) 849 { 850 mvaddstr(19, 25, "The last character to die was:"); 851 mvaddstr(20, 40 - strlen(Databuf) / 2,Databuf); 852 fclose(fp); 853 } 854 855 refresh(); 856 } 857 /**/ 858 /************************************************************************ 859 / 860 / FUNCTION NAME: recallplayer() 861 / 862 / FUNCTION: find a character on file 863 / 864 / AUTHOR: E. A. Estes, 12/4/85 865 / 866 / ARGUMENTS: none 867 / 868 / RETURN VALUE: none 869 / 870 / MODULES CALLED: writerecord(), truncstring(), more(), death(), wmove(), 871 / wclear(), strcmp(), printw(), cleanup(), waddstr(), findname(), mvprintw(), 872 / getanswer(), getstring() 873 / 874 / GLOBAL INPUTS: Player, *stdscr, Databuf[] 875 / 876 / GLOBAL OUTPUTS: Echo, Player 877 / 878 / DESCRIPTION: 879 / Search for a character of a certain name, and check password. 880 / 881 /************************************************************************/ 882 883 long 884 recallplayer() 885 { 886 long loc = 0L; /* location in player file */ 887 register int loop; /* loop counter */ 888 int ch; /* input */ 889 890 clear(); 891 mvprintw(10, 0, "What was your character's name ? "); 892 getstring(Databuf, SZ_NAME); 893 truncstring(Databuf); 894 895 if ((loc = findname(Databuf, &Player)) >= 0L) 896 /* found character */ 897 { 898 Echo = FALSE; 899 900 for (loop = 0; loop < 2; ++loop) 901 { 902 /* prompt for password */ 903 mvaddstr(11, 0, "Password ? "); 904 getstring(Databuf, SZ_PASSWORD); 905 if (strcmp(Databuf, Player.p_password) == 0) 906 /* password good */ 907 { 908 Echo = TRUE; 909 910 if (Player.p_status != S_OFF) 911 /* player did not exit normally last time */ 912 { 913 clear(); 914 addstr("Your character did not exit normally last time.\n"); 915 addstr("If you think you have good cause to have your character saved,\n"); 916 printw("you may quit and mail your reason to 'root'.\n"); 917 addstr("Otherwise, continuing spells certain death.\n"); 918 addstr("Do you want to quit ? "); 919 ch = getanswer("YN", FALSE); 920 if (ch == 'Y') 921 { 922 Player.p_status = S_HUNGUP; 923 writerecord(&Player, loc); 924 cleanup(TRUE); 925 /*NOTREACHED*/ 926 } 927 death("Stupidity"); 928 /*NOTREACHED*/ 929 } 930 return(loc); 931 } 932 else 933 mvaddstr(12, 0, "No good.\n"); 934 } 935 936 Echo = TRUE; 937 } 938 else 939 mvaddstr(11, 0, "Not found.\n"); 940 941 more(13); 942 return(-1L); 943 } 944 /**/ 945 /************************************************************************ 946 / 947 / FUNCTION NAME: neatstuff() 948 / 949 / FUNCTION: do random stuff 950 / 951 / AUTHOR: E. A. Estes, 3/3/86 952 / 953 / ARGUMENTS: none 954 / 955 / RETURN VALUE: none 956 / 957 / MODULES CALLED: collecttaxes(), floor(), wmove(), drandom(), infloat(), 958 / waddstr(), mvprintw(), getanswer() 959 / 960 / GLOBAL INPUTS: Player, *stdscr, *Statptr 961 / 962 / GLOBAL OUTPUTS: Player 963 / 964 / DESCRIPTION: 965 / Handle gurus, medics, etc. 966 / 967 /************************************************************************/ 968 969 neatstuff() 970 { 971 double temp; /* for temporary calculations */ 972 int ch; /* input */ 973 974 switch ((int) ROLL(0.0, 100.0)) 975 { 976 case 1: 977 case 2: 978 if (Player.p_poison > 0.0) 979 { 980 mvaddstr(4, 0, "You've found a medic! How much will you offer to be cured ? "); 981 temp = floor(infloat()); 982 if (temp < 0.0 || temp > Player.p_gold) 983 /* negative gold, or more than available */ 984 { 985 mvaddstr(6, 0, "He was not amused, and made you worse.\n"); 986 Player.p_poison += 1.0; 987 } 988 else if (drandom() / 2.0 > (temp + 1.0) / MAX(Player.p_gold, 1)) 989 /* medic wants 1/2 of available gold */ 990 mvaddstr(5, 0, "Sorry, he wasn't interested.\n"); 991 else 992 { 993 mvaddstr(5, 0, "He accepted."); 994 Player.p_poison = MAX(0.0, Player.p_poison - 1.0); 995 Player.p_gold -= temp; 996 } 997 } 998 break; 999 1000 case 3: 1001 mvaddstr(4, 0, "You've been caught raping and pillaging!\n"); 1002 Player.p_experience += 4000.0; 1003 Player.p_sin += 0.5; 1004 break; 1005 1006 case 4: 1007 temp = ROLL(10.0, 75.0); 1008 mvprintw(4, 0, "You've found %.0f gold pieces, want them ? ", temp); 1009 ch = getanswer("NY", FALSE); 1010 1011 if (ch == 'Y') 1012 collecttaxes(temp, 0.0); 1013 break; 1014 1015 case 5: 1016 if (Player.p_sin > 1.0) 1017 { 1018 mvaddstr(4, 0, "You've found a Holy Orb!\n"); 1019 Player.p_sin -= 0.25; 1020 } 1021 break; 1022 1023 case 6: 1024 if (Player.p_poison < 1.0) 1025 { 1026 mvaddstr(4, 0, "You've been hit with a plague!\n"); 1027 Player.p_poison += 1.0; 1028 } 1029 break; 1030 1031 case 7: 1032 mvaddstr(4, 0, "You've found some holy water.\n"); 1033 ++Player.p_holywater; 1034 break; 1035 1036 case 8: 1037 mvaddstr(4, 0, "You've met a Guru. . ."); 1038 if (drandom() * Player.p_sin > 1.0) 1039 addstr("You disgusted him with your sins!\n"); 1040 else if (Player.p_poison > 0.0) 1041 { 1042 addstr("He looked kindly upon you, and cured you.\n"); 1043 Player.p_poison = 0.0; 1044 } 1045 else 1046 { 1047 addstr("He rewarded you for your virtue.\n"); 1048 Player.p_mana += 50.0; 1049 Player.p_shield += 2.0; 1050 } 1051 break; 1052 1053 case 9: 1054 mvaddstr(4, 0, "You've found an amulet.\n"); 1055 ++Player.p_amulets; 1056 break; 1057 1058 case 10: 1059 if (Player.p_blindness) 1060 { 1061 mvaddstr(4, 0, "You've regained your sight!\n"); 1062 Player.p_blindness = FALSE; 1063 } 1064 break; 1065 1066 default: /* deal with poison */ 1067 if (Player.p_poison > 0.0) 1068 { 1069 temp = Player.p_poison * Statptr->c_weakness 1070 * Player.p_maxenergy / 600.0; 1071 if (Player.p_energy > Player.p_maxenergy / 10.0 1072 && temp + 5.0 < Player.p_energy) 1073 Player.p_energy -= temp; 1074 } 1075 break; 1076 } 1077 } 1078 /**/ 1079 /************************************************************************ 1080 / 1081 / FUNCTION NAME: genchar() 1082 / 1083 / FUNCTION: generate a random character 1084 / 1085 / AUTHOR: E. A. Estes, 12/4/85 1086 / 1087 / ARGUMENTS: 1088 / int type - ASCII value of character type to generate 1089 / 1090 / RETURN VALUE: none 1091 / 1092 / MODULES CALLED: floor(), drandom() 1093 / 1094 / GLOBAL INPUTS: Wizard, Player, Stattable[] 1095 / 1096 / GLOBAL OUTPUTS: Player 1097 / 1098 / DESCRIPTION: 1099 / Use the lookup table for rolling stats. 1100 / 1101 /************************************************************************/ 1102 1103 genchar(type) 1104 int type; 1105 { 1106 register int subscript; /* used for subscripting into Stattable */ 1107 register struct charstats *statptr;/* for pointing into Stattable */ 1108 1109 subscript = type - '1'; 1110 1111 if (subscript < C_MAGIC || subscript > C_EXPER) 1112 if (subscript != C_SUPER || !Wizard) 1113 /* fighter is default */ 1114 subscript = C_FIGHTER; 1115 1116 statptr = &Stattable[subscript]; 1117 1118 Player.p_quickness = 1119 ROLL(statptr->c_quickness.base, statptr->c_quickness.interval); 1120 Player.p_strength = 1121 ROLL(statptr->c_strength.base, statptr->c_strength.interval); 1122 Player.p_mana = 1123 ROLL(statptr->c_mana.base, statptr->c_mana.interval); 1124 Player.p_maxenergy = 1125 Player.p_energy = 1126 ROLL(statptr->c_energy.base, statptr->c_energy.interval); 1127 Player.p_brains = 1128 ROLL(statptr->c_brains.base, statptr->c_brains.interval); 1129 Player.p_magiclvl = 1130 ROLL(statptr->c_magiclvl.base, statptr->c_magiclvl.interval); 1131 1132 Player.p_type = subscript; 1133 1134 if (Player.p_type == C_HALFLING) 1135 /* give halfling some experience */ 1136 Player.p_experience = ROLL(600.0, 200.0); 1137 } 1138 /**/ 1139 /************************************************************************ 1140 / 1141 / FUNCTION NAME: playinit() 1142 / 1143 / FUNCTION: initialize for playing game 1144 / 1145 / AUTHOR: E. A. Estes, 12/4/85 1146 / 1147 / ARGUMENTS: none 1148 / 1149 / RETURN VALUE: none 1150 / 1151 / MODULES CALLED: signal(), wclear(), noecho(), crmode(), initscr(), 1152 / wrefresh() 1153 / 1154 / GLOBAL INPUTS: *stdscr, ill_sig() 1155 / 1156 / GLOBAL OUTPUTS: Windows 1157 / 1158 / DESCRIPTION: 1159 / Catch a bunch of signals, and turn on curses stuff. 1160 / 1161 /************************************************************************/ 1162 1163 playinit() 1164 { 1165 /* catch/ingnore signals */ 1166 1167 #ifdef BSD41 1168 sigignore(SIGQUIT); 1169 sigignore(SIGALRM); 1170 sigignore(SIGTERM); 1171 sigignore(SIGTSTP); 1172 sigignore(SIGTTIN); 1173 sigignore(SIGTTOU); 1174 sighold(SIGINT); 1175 sigset(SIGHUP, ill_sig); 1176 sigset(SIGTRAP, ill_sig); 1177 sigset(SIGIOT, ill_sig); 1178 sigset(SIGEMT, ill_sig); 1179 sigset(SIGFPE, ill_sig); 1180 sigset(SIGBUS, ill_sig); 1181 sigset(SIGSEGV, ill_sig); 1182 sigset(SIGSYS, ill_sig); 1183 sigset(SIGPIPE, ill_sig); 1184 #endif 1185 #ifdef BSD42 1186 signal(SIGQUIT, ill_sig); 1187 signal(SIGALRM, SIG_IGN); 1188 signal(SIGTERM, SIG_IGN); 1189 signal(SIGTSTP, SIG_IGN); 1190 signal(SIGTTIN, SIG_IGN); 1191 signal(SIGTTOU, SIG_IGN); 1192 signal(SIGINT, ill_sig); 1193 signal(SIGHUP, SIG_DFL); 1194 signal(SIGTRAP, ill_sig); 1195 signal(SIGIOT, ill_sig); 1196 signal(SIGEMT, ill_sig); 1197 signal(SIGFPE, ill_sig); 1198 signal(SIGBUS, ill_sig); 1199 signal(SIGSEGV, ill_sig); 1200 signal(SIGSYS, ill_sig); 1201 signal(SIGPIPE, ill_sig); 1202 #endif 1203 #ifdef SYS3 1204 signal(SIGINT, SIG_IGN); 1205 signal(SIGQUIT, SIG_IGN); 1206 signal(SIGTERM, SIG_IGN); 1207 signal(SIGALRM, SIG_IGN); 1208 signal(SIGHUP, ill_sig); 1209 signal(SIGTRAP, ill_sig); 1210 signal(SIGIOT, ill_sig); 1211 signal(SIGEMT, ill_sig); 1212 signal(SIGFPE, ill_sig); 1213 signal(SIGBUS, ill_sig); 1214 signal(SIGSEGV, ill_sig); 1215 signal(SIGSYS, ill_sig); 1216 signal(SIGPIPE, ill_sig); 1217 #endif 1218 #ifdef SYS5 1219 signal(SIGINT, SIG_IGN); 1220 signal(SIGQUIT, SIG_IGN); 1221 signal(SIGTERM, SIG_IGN); 1222 signal(SIGALRM, SIG_IGN); 1223 signal(SIGHUP, ill_sig); 1224 signal(SIGTRAP, ill_sig); 1225 signal(SIGIOT, ill_sig); 1226 signal(SIGEMT, ill_sig); 1227 signal(SIGFPE, ill_sig); 1228 signal(SIGBUS, ill_sig); 1229 signal(SIGSEGV, ill_sig); 1230 signal(SIGSYS, ill_sig); 1231 signal(SIGPIPE, ill_sig); 1232 #endif 1233 1234 initscr(); /* turn on curses */ 1235 noecho(); /* do not echo input */ 1236 crmode(); /* do not process erase, kill */ 1237 clear(); 1238 refresh(); 1239 Windows = TRUE; /* mark the state */ 1240 } 1241 1242 /**/ 1243 /************************************************************************ 1244 / 1245 / FUNCTION NAME: cleanup() 1246 / 1247 / FUNCTION: close some files, and maybe exit 1248 / 1249 / AUTHOR: E. A. Estes, 12/4/85 1250 / 1251 / ARGUMENTS: 1252 / bool doexit - exit flag 1253 / 1254 / RETURN VALUE: none 1255 / 1256 / MODULES CALLED: exit(), wmove(), fclose(), endwin(), nocrmode(), wrefresh() 1257 / 1258 / GLOBAL INPUTS: *Energyvoidfp, LINES, *stdscr, Windows, *Monstfp, 1259 / *Messagefp, *Playersfp 1260 / 1261 / GLOBAL OUTPUTS: none 1262 / 1263 / DESCRIPTION: 1264 / Close all open files. If we are "in curses" terminate curses. 1265 / If 'doexit' is set, exit, otherwise return. 1266 / 1267 /************************************************************************/ 1268 1269 cleanup(doexit) 1270 bool doexit; 1271 { 1272 if (Windows) 1273 { 1274 move(LINES - 2, 0); 1275 refresh(); 1276 nocrmode(); 1277 endwin(); 1278 } 1279 1280 fclose(Playersfp); 1281 fclose(Monstfp); 1282 fclose(Messagefp); 1283 fclose(Energyvoidfp); 1284 1285 if (doexit) 1286 exit(0); 1287 /*NOTREACHED*/ 1288 } 1289