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