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