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