main.c revision 1.16
1/* $NetBSD: main.c,v 1.16 2006/05/13 22:29:53 christos 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 } 723 if (fp) 724 fclose(fp); 725 refresh(); 726} 727 728long 729recallplayer() 730{ 731 long loc = 0L; /* location in player file */ 732 int loop; /* loop counter */ 733 int ch; /* input */ 734 735 clear(); 736 mvprintw(10, 0, "What was your character's name ? "); 737 getstring(Databuf, SZ_NAME); 738 truncstring(Databuf); 739 740 if ((loc = findname(Databuf, &Player)) >= 0L) 741 /* found character */ 742 { 743 Echo = FALSE; 744 745 for (loop = 0; loop < 2; ++loop) { 746 /* prompt for password */ 747 mvaddstr(11, 0, "Password ? "); 748 getstring(Databuf, SZ_PASSWORD); 749 if (strcmp(Databuf, Player.p_password) == 0) 750 /* password good */ 751 { 752 Echo = TRUE; 753 754 if (Player.p_status != S_OFF) 755 /* player did not exit normally last 756 * time */ 757 { 758 clear(); 759 addstr("Your character did not exit normally last time.\n"); 760 addstr("If you think you have good cause to have your character saved,\n"); 761 printw("you may quit and mail your reason to 'root'.\n"); 762 addstr("Otherwise, continuing spells certain death.\n"); 763 addstr("Do you want to quit ? "); 764 ch = getanswer("YN", FALSE); 765 if (ch == 'Y') { 766 Player.p_status = S_HUNGUP; 767 writerecord(&Player, loc); 768 cleanup(TRUE); 769 /* NOTREACHED */ 770 } 771 death("Stupidity"); 772 /* NOTREACHED */ 773 } 774 return (loc); 775 } else 776 mvaddstr(12, 0, "No good.\n"); 777 } 778 779 Echo = TRUE; 780 } else 781 mvaddstr(11, 0, "Not found.\n"); 782 783 more(13); 784 return (-1L); 785} 786 787void 788neatstuff() 789{ 790 double temp; /* for temporary calculations */ 791 int ch; /* input */ 792 793 switch ((int) ROLL(0.0, 100.0)) { 794 case 1: 795 case 2: 796 if (Player.p_poison > 0.0) { 797 mvaddstr(4, 0, "You've found a medic! How much will you offer to be cured ? "); 798 temp = floor(infloat()); 799 if (temp < 0.0 || temp > Player.p_gold) 800 /* negative gold, or more than available */ 801 { 802 mvaddstr(6, 0, "He was not amused, and made you worse.\n"); 803 Player.p_poison += 1.0; 804 } else 805 if (drandom() / 2.0 > (temp + 1.0) / MAX(Player.p_gold, 1)) 806 /* medic wants 1/2 of available gold */ 807 mvaddstr(5, 0, "Sorry, he wasn't interested.\n"); 808 else { 809 mvaddstr(5, 0, "He accepted."); 810 Player.p_poison = MAX(0.0, Player.p_poison - 1.0); 811 Player.p_gold -= temp; 812 } 813 } 814 break; 815 816 case 3: 817 mvaddstr(4, 0, "You've been caught raping and pillaging!\n"); 818 Player.p_experience += 4000.0; 819 Player.p_sin += 0.5; 820 break; 821 822 case 4: 823 temp = ROLL(10.0, 75.0); 824 mvprintw(4, 0, "You've found %.0f gold pieces, want them ? ", temp); 825 ch = getanswer("NY", FALSE); 826 827 if (ch == 'Y') 828 collecttaxes(temp, 0.0); 829 break; 830 831 case 5: 832 if (Player.p_sin > 1.0) { 833 mvaddstr(4, 0, "You've found a Holy Orb!\n"); 834 Player.p_sin -= 0.25; 835 } 836 break; 837 838 case 6: 839 if (Player.p_poison < 1.0) { 840 mvaddstr(4, 0, "You've been hit with a plague!\n"); 841 Player.p_poison += 1.0; 842 } 843 break; 844 845 case 7: 846 mvaddstr(4, 0, "You've found some holy water.\n"); 847 ++Player.p_holywater; 848 break; 849 850 case 8: 851 mvaddstr(4, 0, "You've met a Guru. . ."); 852 if (drandom() * Player.p_sin > 1.0) 853 addstr("You disgusted him with your sins!\n"); 854 else 855 if (Player.p_poison > 0.0) { 856 addstr("He looked kindly upon you, and cured you.\n"); 857 Player.p_poison = 0.0; 858 } else { 859 addstr("He rewarded you for your virtue.\n"); 860 Player.p_mana += 50.0; 861 Player.p_shield += 2.0; 862 } 863 break; 864 865 case 9: 866 mvaddstr(4, 0, "You've found an amulet.\n"); 867 ++Player.p_amulets; 868 break; 869 870 case 10: 871 if (Player.p_blindness) { 872 mvaddstr(4, 0, "You've regained your sight!\n"); 873 Player.p_blindness = FALSE; 874 } 875 break; 876 877 default: /* deal with poison */ 878 if (Player.p_poison > 0.0) { 879 temp = Player.p_poison * Statptr->c_weakness 880 * Player.p_maxenergy / 600.0; 881 if (Player.p_energy > Player.p_maxenergy / 10.0 882 && temp + 5.0 < Player.p_energy) 883 Player.p_energy -= temp; 884 } 885 break; 886 } 887} 888 889void 890genchar(type) 891 int type; 892{ 893 int subscript; /* used for subscripting into Stattable */ 894 const struct charstats *statptr; /* for pointing into Stattable */ 895 896 subscript = type - '1'; 897 898 if (subscript < C_MAGIC || subscript > C_EXPER) 899 if (subscript != C_SUPER || !Wizard) 900 /* fighter is default */ 901 subscript = C_FIGHTER; 902 903 statptr = &Stattable[subscript]; 904 905 Player.p_quickness = 906 ROLL(statptr->c_quickness.base, statptr->c_quickness.interval); 907 Player.p_strength = 908 ROLL(statptr->c_strength.base, statptr->c_strength.interval); 909 Player.p_mana = 910 ROLL(statptr->c_mana.base, statptr->c_mana.interval); 911 Player.p_maxenergy = 912 Player.p_energy = 913 ROLL(statptr->c_energy.base, statptr->c_energy.interval); 914 Player.p_brains = 915 ROLL(statptr->c_brains.base, statptr->c_brains.interval); 916 Player.p_magiclvl = 917 ROLL(statptr->c_magiclvl.base, statptr->c_magiclvl.interval); 918 919 Player.p_type = subscript; 920 921 if (Player.p_type == C_HALFLING) 922 /* give halfling some experience */ 923 Player.p_experience = ROLL(600.0, 200.0); 924} 925 926void 927playinit() 928{ 929 /* catch/ingnore signals */ 930 931#ifdef BSD41 932 sigignore(SIGQUIT); 933 sigignore(SIGALRM); 934 sigignore(SIGTERM); 935 sigignore(SIGTSTP); 936 sigignore(SIGTTIN); 937 sigignore(SIGTTOU); 938 sighold(SIGINT); 939 sigset(SIGHUP, ill_sig); 940 sigset(SIGTRAP, ill_sig); 941 sigset(SIGIOT, ill_sig); 942 sigset(SIGEMT, ill_sig); 943 sigset(SIGFPE, ill_sig); 944 sigset(SIGBUS, ill_sig); 945 sigset(SIGSEGV, ill_sig); 946 sigset(SIGSYS, ill_sig); 947 sigset(SIGPIPE, ill_sig); 948#endif 949#ifdef BSD42 950 signal(SIGQUIT, ill_sig); 951 signal(SIGALRM, SIG_IGN); 952 signal(SIGTERM, SIG_IGN); 953 signal(SIGTSTP, SIG_IGN); 954 signal(SIGTTIN, SIG_IGN); 955 signal(SIGTTOU, SIG_IGN); 956 signal(SIGINT, ill_sig); 957 signal(SIGHUP, SIG_DFL); 958 signal(SIGTRAP, ill_sig); 959 signal(SIGIOT, ill_sig); 960 signal(SIGEMT, ill_sig); 961 signal(SIGFPE, ill_sig); 962 signal(SIGBUS, ill_sig); 963 signal(SIGSEGV, ill_sig); 964 signal(SIGSYS, ill_sig); 965 signal(SIGPIPE, ill_sig); 966#endif 967#ifdef SYS3 968 signal(SIGINT, SIG_IGN); 969 signal(SIGQUIT, SIG_IGN); 970 signal(SIGTERM, SIG_IGN); 971 signal(SIGALRM, SIG_IGN); 972 signal(SIGHUP, ill_sig); 973 signal(SIGTRAP, ill_sig); 974 signal(SIGIOT, ill_sig); 975 signal(SIGEMT, ill_sig); 976 signal(SIGFPE, ill_sig); 977 signal(SIGBUS, ill_sig); 978 signal(SIGSEGV, ill_sig); 979 signal(SIGSYS, ill_sig); 980 signal(SIGPIPE, ill_sig); 981#endif 982#ifdef SYS5 983 signal(SIGINT, SIG_IGN); 984 signal(SIGQUIT, SIG_IGN); 985 signal(SIGTERM, SIG_IGN); 986 signal(SIGALRM, SIG_IGN); 987 signal(SIGHUP, ill_sig); 988 signal(SIGTRAP, ill_sig); 989 signal(SIGIOT, ill_sig); 990 signal(SIGEMT, ill_sig); 991 signal(SIGFPE, ill_sig); 992 signal(SIGBUS, ill_sig); 993 signal(SIGSEGV, ill_sig); 994 signal(SIGSYS, ill_sig); 995 signal(SIGPIPE, ill_sig); 996#endif 997 998 initscr(); /* turn on curses */ 999 noecho(); /* do not echo input */ 1000 cbreak(); /* do not process erase, kill */ 1001 clear(); 1002 refresh(); 1003 Windows = TRUE; /* mark the state */ 1004} 1005 1006void 1007cleanup(doexit) 1008 int doexit; 1009{ 1010 if (Windows) { 1011 move(LINES - 2, 0); 1012 refresh(); 1013 nocbreak(); 1014 endwin(); 1015 } 1016 if (Playersfp) 1017 fclose(Playersfp); 1018 if (Monstfp) 1019 fclose(Monstfp); 1020 if (Messagefp) 1021 fclose(Messagefp); 1022 if (Energyvoidfp) 1023 fclose(Energyvoidfp); 1024 1025 if (doexit) 1026 exit(0); 1027 /* NOTREACHED */ 1028} 1029