Home | History | Annotate | Line # | Download | only in phantasia
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 
     63 int	main(int, char **);
     64 
     65 int
     66 main(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 
    272 void
    273 initialstate()
    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 
    323 long
    324 rollnewplayer()
    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 
    413 void
    414 procmain()
    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 
    623 void
    624 titlelist()
    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 
    727 long
    728 recallplayer()
    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 
    786 void
    787 neatstuff()
    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 
    888 void
    889 genchar(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 
    925 void
    926 playinit()
    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 
   1005 void
   1006 cleanup(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