main.c revision 1.8
1/*	$NetBSD: main.c,v 1.8 1999/09/08 21:57:19 jsm 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
291	if ((Monstfp = fopen(_PATH_MONST, "r+")) == NULL)
292		error(_PATH_MONST);
293	/* NOTREACHED */
294
295	if ((Messagefp = fopen(_PATH_MESS, "r")) == NULL)
296		error(_PATH_MESS);
297	/* NOTREACHED */
298
299	if ((Energyvoidfp = fopen(_PATH_VOID, "r+")) == NULL)
300		error(_PATH_VOID);
301	/* NOTREACHED */
302
303	srandom((unsigned) time(NULL));	/* prime random numbers */
304}
305
306long
307rollnewplayer()
308{
309	int     chartype;	/* character type */
310	int     ch;		/* input */
311
312	initplayer(&Player);	/* initialize player structure */
313
314	clear();
315	mvaddstr(4, 21, "Which type of character do you want:");
316	mvaddstr(8, 4,
317"1:Magic User  2:Fighter  3:Elf  4:Dwarf  5:Halfling  6:Experimento  ");
318	if (Wizard) {
319		addstr("7:Super  ? ");
320		chartype = getanswer("1234567", FALSE);
321	} else {
322		addstr("?  ");
323		chartype = getanswer("123456", FALSE);
324	}
325
326	do {
327		genchar(chartype);	/* roll up a character */
328
329		/* print out results */
330		mvprintw(12, 14,
331		    "Strength    :  %2.0f  Quickness:  %2.0f  Mana       :  %2.0f\n",
332		    Player.p_strength, Player.p_quickness, Player.p_mana);
333		mvprintw(13, 14,
334		    "Energy Level:  %2.0f  Brains   :  %2.0f  Magic Level:  %2.0f\n",
335		    Player.p_energy, Player.p_brains, Player.p_magiclvl);
336
337		if (Player.p_type == C_EXPER || Player.p_type == C_SUPER)
338			break;
339
340		mvaddstr(14, 14, "Type '1' to keep >");
341		ch = getanswer(" ", TRUE);
342	}
343	while (ch != '1');
344
345	if (Player.p_type == C_EXPER || Player.p_type == C_SUPER)
346		/* get coordinates for experimento */
347		for (;;) {
348			mvaddstr(16, 0, "Enter the X Y coordinates of your experimento ? ");
349			getstring(Databuf, SZ_DATABUF);
350			sscanf(Databuf, "%lf %lf", &Player.p_x, &Player.p_y);
351
352			if (fabs(Player.p_x) > D_EXPER || fabs(Player.p_y) > D_EXPER)
353				mvaddstr(17, 0, "Invalid coordinates.  Try again.\n");
354			else
355				break;
356		}
357
358	for (;;)
359		/* name the new character */
360	{
361		mvprintw(18, 0,
362		    "Give your character a name [up to %d characters] ?  ", SZ_NAME - 1);
363		getstring(Player.p_name, SZ_NAME);
364		truncstring(Player.p_name);	/* remove trailing blanks */
365
366		if (Player.p_name[0] == '\0')
367			/* no null names */
368			mvaddstr(19, 0, "Invalid name.");
369		else
370			if (findname(Player.p_name, &Other) >= 0L)
371				/* cannot have duplicate names */
372				mvaddstr(19, 0, "Name already in use.");
373			else
374				/* name is acceptable */
375				break;
376
377		addstr("  Pick another.\n");
378	}
379
380	/* get a password for character */
381	Echo = FALSE;
382
383	do {
384		mvaddstr(20, 0, "Give your character a password [up to 8 characters] ? ");
385		getstring(Player.p_password, SZ_PASSWORD);
386		mvaddstr(21, 0, "Enter again to verify: ");
387		getstring(Databuf, SZ_PASSWORD);
388	}
389	while (strcmp(Player.p_password, Databuf) != 0);
390
391	Echo = TRUE;
392
393	return (allocrecord());
394}
395
396void
397procmain()
398{
399	int     ch;		/* input */
400	double  x;		/* desired new x coordinate */
401	double  y;		/* desired new y coordinate */
402	double  temp;		/* for temporary calculations */
403	FILE   *fp;		/* for opening files */
404	int     loop;		/* a loop counter */
405	bool    hasmoved = FALSE;	/* set if player has moved */
406
407	ch = inputoption();
408	mvaddstr(4, 0, "\n\n");	/* clear status area */
409
410	move(7, 0);
411	clrtobot();		/* clear data on bottom area of screen */
412
413	if (Player.p_specialtype == SC_VALAR && (ch == '1' || ch == '7'))
414		/* valar cannot move */
415		ch = ' ';
416
417	switch (ch) {
418	case 'K':		/* move up/north */
419	case 'N':
420		x = Player.p_x;
421		y = Player.p_y + MAXMOVE();
422		hasmoved = TRUE;
423		break;
424
425	case 'J':		/* move down/south */
426	case 'S':
427		x = Player.p_x;
428		y = Player.p_y - MAXMOVE();
429		hasmoved = TRUE;
430		break;
431
432	case 'L':		/* move right/east */
433	case 'E':
434		x = Player.p_x + MAXMOVE();
435		y = Player.p_y;
436		hasmoved = TRUE;
437		break;
438
439	case 'H':		/* move left/west */
440	case 'W':
441		x = Player.p_x - MAXMOVE();
442		y = Player.p_y;
443		hasmoved = TRUE;
444		break;
445
446	default:		/* rest */
447		Player.p_energy += (Player.p_maxenergy + Player.p_shield) / 15.0
448		    + Player.p_level / 3.0 + 2.0;
449		Player.p_energy =
450		    MIN(Player.p_energy, Player.p_maxenergy + Player.p_shield);
451
452		if (Player.p_status != S_CLOAKED)
453			/* cannot find mana if cloaked */
454		{
455			Player.p_mana += (Circle + Player.p_level) / 4.0;
456
457			if (drandom() < 0.2 && Player.p_status == S_PLAYING && !Throne)
458				/* wandering monster */
459				encounter(-1);
460		}
461		break;
462
463	case 'X':		/* change/examine a character */
464		changestats(TRUE);
465		break;
466
467	case '1':		/* move */
468		for (loop = 3; loop; --loop) {
469			mvaddstr(4, 0, "X Y Coordinates ? ");
470			getstring(Databuf, SZ_DATABUF);
471
472			if (sscanf(Databuf, "%lf %lf", &x, &y) != 2)
473				mvaddstr(5, 0, "Try again\n");
474			else
475				if (distance(Player.p_x, x, Player.p_y, y) > MAXMOVE())
476					ILLMOVE();
477				else {
478					hasmoved = TRUE;
479					break;
480				}
481		}
482		break;
483
484	case '2':		/* players */
485		userlist(TRUE);
486		break;
487
488	case '3':		/* message */
489		mvaddstr(4, 0, "Message ? ");
490		getstring(Databuf, SZ_DATABUF);
491		/* we open the file for writing to erase any data which is
492		 * already there */
493		fp = fopen(_PATH_MESS, "w");
494		if (Databuf[0] != '\0')
495			fprintf(fp, "%s: %s", Player.p_name, Databuf);
496		fclose(fp);
497		break;
498
499	case '4':		/* stats */
500		allstatslist();
501		break;
502
503	case '5':		/* good-bye */
504		leavegame();
505		/* NOTREACHED */
506
507	case '6':		/* cloak */
508		if (Player.p_level < MEL_CLOAK || Player.p_magiclvl < ML_CLOAK)
509			ILLCMD();
510		else
511			if (Player.p_status == S_CLOAKED)
512				Player.p_status = S_PLAYING;
513			else
514				if (Player.p_mana < MM_CLOAK)
515					mvaddstr(5, 0, "No mana left.\n");
516				else {
517					Changed = TRUE;
518					Player.p_mana -= MM_CLOAK;
519					Player.p_status = S_CLOAKED;
520				}
521		break;
522
523	case '7':		/* teleport */
524		/*
525	         * conditions for teleport
526	         *	- 20 per (level plus magic level)
527	         *	- OR council of the wise or valar or ex-valar
528	         *	- OR transport from throne
529	         * transports from throne cost no mana
530	         */
531		if (Player.p_level < MEL_TELEPORT || Player.p_magiclvl < ML_TELEPORT)
532			ILLCMD();
533		else
534			for (loop = 3; loop; --loop) {
535				mvaddstr(4, 0, "X Y Coordinates ? ");
536				getstring(Databuf, SZ_DATABUF);
537
538				if (sscanf(Databuf, "%lf %lf", &x, &y) == 2) {
539					temp = distance(Player.p_x, x, Player.p_y, y);
540					if (!Throne
541					/* can transport anywhere from throne */
542					    && Player.p_specialtype <= SC_COUNCIL
543					/* council, valar can transport
544					 * anywhere */
545					    && temp > (Player.p_level + Player.p_magiclvl) * 20.0)
546						/* can only move 20 per exp.
547						 * level + mag. level */
548						ILLMOVE();
549					else {
550						temp = (temp / 75.0 + 1.0) * 20.0;	/* mana used */
551
552						if (!Throne && temp > Player.p_mana)
553							mvaddstr(5, 0, "Not enough power for that distance.\n");
554						else {
555							if (!Throne)
556								Player.p_mana -= temp;
557							hasmoved = TRUE;
558							break;
559						}
560					}
561				}
562			}
563		break;
564
565	case 'C':
566	case '9':		/* monster */
567		if (Throne)
568			/* no monsters while on throne */
569			mvaddstr(5, 0, "No monsters in the chamber!\n");
570		else
571			if (Player.p_specialtype != SC_VALAR)
572				/* the valar cannot call monsters */
573			{
574				Player.p_sin += 1e-6;
575				encounter(-1);
576			}
577		break;
578
579	case '0':		/* decree */
580		if (Wizard || (Player.p_specialtype == SC_KING && Throne))
581			/* kings must be on throne to decree */
582			dotampered();
583		else
584			ILLCMD();
585		break;
586
587	case '8':		/* intervention */
588		if (Wizard || Player.p_specialtype >= SC_COUNCIL)
589			dotampered();
590		else
591			ILLCMD();
592		break;
593	}
594
595	if (hasmoved)
596		/* player has moved -- alter coordinates, and do random
597		 * monster */
598	{
599		altercoordinates(x, y, A_SPECIFIC);
600
601		if (drandom() < 0.2 && Player.p_status == S_PLAYING && !Throne)
602			encounter(-1);
603	}
604}
605
606void
607titlelist()
608{
609	FILE   *fp;		/* used for opening various files */
610	bool    councilfound = FALSE;	/* set if we find a member of the
611					 * council */
612	bool    kingfound = FALSE;	/* set if we find a king */
613	double  hiexp, nxtexp;	/* used for finding the two highest players */
614	double  hilvl, nxtlvl;	/* used for finding the two highest players */
615	char    hiname[21], nxtname[21];	/* used for finding the two
616						 * highest players */
617
618	nxtexp = 0;
619	mvaddstr(0, 14,
620	    "W e l c o m e   t o   P h a n t a s i a (vers. 3.3.2)!");
621
622	/* print message of the day */
623	if ((fp = fopen(_PATH_MOTD, "r")) != NULL
624	    && fgets(Databuf, SZ_DATABUF, fp) != NULL) {
625		mvaddstr(2, 40 - strlen(Databuf) / 2, Databuf);
626		fclose(fp);
627	}
628	/* search for king */
629	fseek(Playersfp, 0L, SEEK_SET);
630	while (fread((char *) &Other, SZ_PLAYERSTRUCT, 1, Playersfp) == 1)
631		if (Other.p_specialtype == SC_KING &&
632		    Other.p_status != S_NOTUSED)
633			/* found the king */
634		{
635			sprintf(Databuf, "The present ruler is %s  Level:%.0f",
636			    Other.p_name, Other.p_level);
637			mvaddstr(4, 40 - strlen(Databuf) / 2, Databuf);
638			kingfound = TRUE;
639			break;
640		}
641	if (!kingfound)
642		mvaddstr(4, 24, "There is no ruler at this time.");
643
644	/* search for valar */
645	fseek(Playersfp, 0L, SEEK_SET);
646	while (fread((char *) &Other, SZ_PLAYERSTRUCT, 1, Playersfp) == 1)
647		if (Other.p_specialtype == SC_VALAR && Other.p_status != S_NOTUSED)
648			/* found the valar */
649		{
650			sprintf(Databuf, "The Valar is %s   Login:  %s", Other.p_name, Other.p_login);
651			mvaddstr(6, 40 - strlen(Databuf) / 2, Databuf);
652			break;
653		}
654	/* search for council of the wise */
655	fseek(Playersfp, 0L, SEEK_SET);
656	Lines = 10;
657	while (fread((char *) &Other, SZ_PLAYERSTRUCT, 1, Playersfp) == 1)
658		if (Other.p_specialtype == SC_COUNCIL && Other.p_status != S_NOTUSED)
659			/* found a member of the council */
660		{
661			if (!councilfound) {
662				mvaddstr(8, 30, "Council of the Wise:");
663				councilfound = TRUE;
664			}
665			/* This assumes a finite (<=5) number of C.O.W.: */
666			sprintf(Databuf, "%s   Login:  %s", Other.p_name, Other.p_login);
667			mvaddstr(Lines++, 40 - strlen(Databuf) / 2, Databuf);
668		}
669	/* search for the two highest players */
670	nxtname[0] = hiname[0] = '\0';
671	hiexp = 0.0;
672	nxtlvl = hilvl = 0;
673
674	fseek(Playersfp, 0L, SEEK_SET);
675	while (fread((char *) &Other, SZ_PLAYERSTRUCT, 1, Playersfp) == 1)
676		if (Other.p_experience > hiexp && Other.p_specialtype <= SC_KING && Other.p_status != S_NOTUSED)
677			/* highest found so far */
678		{
679			nxtexp = hiexp;
680			hiexp = Other.p_experience;
681			nxtlvl = hilvl;
682			hilvl = Other.p_level;
683			strcpy(nxtname, hiname);
684			strcpy(hiname, Other.p_name);
685		} else
686			if (Other.p_experience > nxtexp
687			    && Other.p_specialtype <= SC_KING
688			    && Other.p_status != S_NOTUSED)
689				/* next highest found so far */
690			{
691				nxtexp = Other.p_experience;
692				nxtlvl = Other.p_level;
693				strcpy(nxtname, Other.p_name);
694			}
695	mvaddstr(15, 28, "Highest characters are:");
696	sprintf(Databuf, "%s  Level:%.0f   and   %s  Level:%.0f",
697	    hiname, hilvl, nxtname, nxtlvl);
698	mvaddstr(17, 40 - strlen(Databuf) / 2, Databuf);
699
700	/* print last to die */
701	if ((fp = fopen(_PATH_LASTDEAD, "r")) != NULL
702	    && fgets(Databuf, SZ_DATABUF, fp) != NULL) {
703		mvaddstr(19, 25, "The last character to die was:");
704		mvaddstr(20, 40 - strlen(Databuf) / 2, Databuf);
705		fclose(fp);
706	}
707	refresh();
708}
709
710long
711recallplayer()
712{
713	long    loc = 0L;	/* location in player file */
714	int     loop;		/* loop counter */
715	int     ch;		/* input */
716
717	clear();
718	mvprintw(10, 0, "What was your character's name ? ");
719	getstring(Databuf, SZ_NAME);
720	truncstring(Databuf);
721
722	if ((loc = findname(Databuf, &Player)) >= 0L)
723		/* found character */
724	{
725		Echo = FALSE;
726
727		for (loop = 0; loop < 2; ++loop) {
728			/* prompt for password */
729			mvaddstr(11, 0, "Password ? ");
730			getstring(Databuf, SZ_PASSWORD);
731			if (strcmp(Databuf, Player.p_password) == 0)
732				/* password good */
733			{
734				Echo = TRUE;
735
736				if (Player.p_status != S_OFF)
737					/* player did not exit normally last
738					 * time */
739				{
740					clear();
741					addstr("Your character did not exit normally last time.\n");
742					addstr("If you think you have good cause to have your character saved,\n");
743					printw("you may quit and mail your reason to 'root'.\n");
744					addstr("Otherwise, continuing spells certain death.\n");
745					addstr("Do you want to quit ? ");
746					ch = getanswer("YN", FALSE);
747					if (ch == 'Y') {
748						Player.p_status = S_HUNGUP;
749						writerecord(&Player, loc);
750						cleanup(TRUE);
751						/* NOTREACHED */
752					}
753					death("Stupidity");
754					/* NOTREACHED */
755				}
756				return (loc);
757			} else
758				mvaddstr(12, 0, "No good.\n");
759		}
760
761		Echo = TRUE;
762	} else
763		mvaddstr(11, 0, "Not found.\n");
764
765	more(13);
766	return (-1L);
767}
768
769void
770neatstuff()
771{
772	double  temp;		/* for temporary calculations */
773	int     ch;		/* input */
774
775	switch ((int) ROLL(0.0, 100.0)) {
776	case 1:
777	case 2:
778		if (Player.p_poison > 0.0) {
779			mvaddstr(4, 0, "You've found a medic!  How much will you offer to be cured ? ");
780			temp = floor(infloat());
781			if (temp < 0.0 || temp > Player.p_gold)
782				/* negative gold, or more than available */
783			{
784				mvaddstr(6, 0, "He was not amused, and made you worse.\n");
785				Player.p_poison += 1.0;
786			} else
787				if (drandom() / 2.0 > (temp + 1.0) / MAX(Player.p_gold, 1))
788					/* medic wants 1/2 of available gold */
789					mvaddstr(5, 0, "Sorry, he wasn't interested.\n");
790				else {
791					mvaddstr(5, 0, "He accepted.");
792					Player.p_poison = MAX(0.0, Player.p_poison - 1.0);
793					Player.p_gold -= temp;
794				}
795		}
796		break;
797
798	case 3:
799		mvaddstr(4, 0, "You've been caught raping and pillaging!\n");
800		Player.p_experience += 4000.0;
801		Player.p_sin += 0.5;
802		break;
803
804	case 4:
805		temp = ROLL(10.0, 75.0);
806		mvprintw(4, 0, "You've found %.0f gold pieces, want them ? ", temp);
807		ch = getanswer("NY", FALSE);
808
809		if (ch == 'Y')
810			collecttaxes(temp, 0.0);
811		break;
812
813	case 5:
814		if (Player.p_sin > 1.0) {
815			mvaddstr(4, 0, "You've found a Holy Orb!\n");
816			Player.p_sin -= 0.25;
817		}
818		break;
819
820	case 6:
821		if (Player.p_poison < 1.0) {
822			mvaddstr(4, 0, "You've been hit with a plague!\n");
823			Player.p_poison += 1.0;
824		}
825		break;
826
827	case 7:
828		mvaddstr(4, 0, "You've found some holy water.\n");
829		++Player.p_holywater;
830		break;
831
832	case 8:
833		mvaddstr(4, 0, "You've met a Guru. . .");
834		if (drandom() * Player.p_sin > 1.0)
835			addstr("You disgusted him with your sins!\n");
836		else
837			if (Player.p_poison > 0.0) {
838				addstr("He looked kindly upon you, and cured you.\n");
839				Player.p_poison = 0.0;
840			} else {
841				addstr("He rewarded you for your virtue.\n");
842				Player.p_mana += 50.0;
843				Player.p_shield += 2.0;
844			}
845		break;
846
847	case 9:
848		mvaddstr(4, 0, "You've found an amulet.\n");
849		++Player.p_amulets;
850		break;
851
852	case 10:
853		if (Player.p_blindness) {
854			mvaddstr(4, 0, "You've regained your sight!\n");
855			Player.p_blindness = FALSE;
856		}
857		break;
858
859	default:		/* deal with poison */
860		if (Player.p_poison > 0.0) {
861			temp = Player.p_poison * Statptr->c_weakness
862			    * Player.p_maxenergy / 600.0;
863			if (Player.p_energy > Player.p_maxenergy / 10.0
864			    && temp + 5.0 < Player.p_energy)
865				Player.p_energy -= temp;
866		}
867		break;
868	}
869}
870
871void
872genchar(type)
873	int     type;
874{
875	int     subscript;	/* used for subscripting into Stattable */
876	const struct charstats *statptr; /* for pointing into Stattable */
877
878	subscript = type - '1';
879
880	if (subscript < C_MAGIC || subscript > C_EXPER)
881		if (subscript != C_SUPER || !Wizard)
882			/* fighter is default */
883			subscript = C_FIGHTER;
884
885	statptr = &Stattable[subscript];
886
887	Player.p_quickness =
888	    ROLL(statptr->c_quickness.base, statptr->c_quickness.interval);
889	Player.p_strength =
890	    ROLL(statptr->c_strength.base, statptr->c_strength.interval);
891	Player.p_mana =
892	    ROLL(statptr->c_mana.base, statptr->c_mana.interval);
893	Player.p_maxenergy =
894	    Player.p_energy =
895	    ROLL(statptr->c_energy.base, statptr->c_energy.interval);
896	Player.p_brains =
897	    ROLL(statptr->c_brains.base, statptr->c_brains.interval);
898	Player.p_magiclvl =
899	    ROLL(statptr->c_magiclvl.base, statptr->c_magiclvl.interval);
900
901	Player.p_type = subscript;
902
903	if (Player.p_type == C_HALFLING)
904		/* give halfling some experience */
905		Player.p_experience = ROLL(600.0, 200.0);
906}
907
908void
909playinit()
910{
911	/* catch/ingnore signals */
912
913#ifdef	BSD41
914	sigignore(SIGQUIT);
915	sigignore(SIGALRM);
916	sigignore(SIGTERM);
917	sigignore(SIGTSTP);
918	sigignore(SIGTTIN);
919	sigignore(SIGTTOU);
920	sighold(SIGINT);
921	sigset(SIGHUP, ill_sig);
922	sigset(SIGTRAP, ill_sig);
923	sigset(SIGIOT, ill_sig);
924	sigset(SIGEMT, ill_sig);
925	sigset(SIGFPE, ill_sig);
926	sigset(SIGBUS, ill_sig);
927	sigset(SIGSEGV, ill_sig);
928	sigset(SIGSYS, ill_sig);
929	sigset(SIGPIPE, ill_sig);
930#endif
931#ifdef	BSD42
932	signal(SIGQUIT, ill_sig);
933	signal(SIGALRM, SIG_IGN);
934	signal(SIGTERM, SIG_IGN);
935	signal(SIGTSTP, SIG_IGN);
936	signal(SIGTTIN, SIG_IGN);
937	signal(SIGTTOU, SIG_IGN);
938	signal(SIGINT, ill_sig);
939	signal(SIGHUP, SIG_DFL);
940	signal(SIGTRAP, ill_sig);
941	signal(SIGIOT, ill_sig);
942	signal(SIGEMT, ill_sig);
943	signal(SIGFPE, ill_sig);
944	signal(SIGBUS, ill_sig);
945	signal(SIGSEGV, ill_sig);
946	signal(SIGSYS, ill_sig);
947	signal(SIGPIPE, ill_sig);
948#endif
949#ifdef	SYS3
950	signal(SIGINT, SIG_IGN);
951	signal(SIGQUIT, SIG_IGN);
952	signal(SIGTERM, SIG_IGN);
953	signal(SIGALRM, SIG_IGN);
954	signal(SIGHUP, ill_sig);
955	signal(SIGTRAP, ill_sig);
956	signal(SIGIOT, ill_sig);
957	signal(SIGEMT, ill_sig);
958	signal(SIGFPE, ill_sig);
959	signal(SIGBUS, ill_sig);
960	signal(SIGSEGV, ill_sig);
961	signal(SIGSYS, ill_sig);
962	signal(SIGPIPE, ill_sig);
963#endif
964#ifdef	SYS5
965	signal(SIGINT, SIG_IGN);
966	signal(SIGQUIT, SIG_IGN);
967	signal(SIGTERM, SIG_IGN);
968	signal(SIGALRM, SIG_IGN);
969	signal(SIGHUP, ill_sig);
970	signal(SIGTRAP, ill_sig);
971	signal(SIGIOT, ill_sig);
972	signal(SIGEMT, ill_sig);
973	signal(SIGFPE, ill_sig);
974	signal(SIGBUS, ill_sig);
975	signal(SIGSEGV, ill_sig);
976	signal(SIGSYS, ill_sig);
977	signal(SIGPIPE, ill_sig);
978#endif
979
980	initscr();		/* turn on curses */
981	noecho();		/* do not echo input */
982	crmode();		/* do not process erase, kill */
983	clear();
984	refresh();
985	Windows = TRUE;		/* mark the state */
986}
987
988void
989cleanup(doexit)
990	int    doexit;
991{
992	if (Windows) {
993		move(LINES - 2, 0);
994		refresh();
995		nocrmode();
996		endwin();
997	}
998	fclose(Playersfp);
999	fclose(Monstfp);
1000	fclose(Messagefp);
1001	fclose(Energyvoidfp);
1002
1003	if (doexit)
1004		exit(0);
1005	/* NOTREACHED */
1006}
1007