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