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