main.c revision 1.10
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
60int	main __P((int, char **));
61
62int
63main(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
269void
270initialstate()
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
308long
309rollnewplayer()
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
398void
399procmain()
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
608void
609titlelist()
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
712long
713recallplayer()
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
771void
772neatstuff()
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
873void
874genchar(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
910void
911playinit()
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
990void
991cleanup(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