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