xref: /csrg-svn/games/phantasia/io.c (revision 34613)
134599Sbostic /*
234599Sbostic  * io.c - input/output routines for Phantasia
334599Sbostic  */
434599Sbostic 
534599Sbostic #include "include.h"
634599Sbostic 
734599Sbostic /************************************************************************
834599Sbostic /
934599Sbostic / FUNCTION NAME: getstring()
1034599Sbostic /
1134599Sbostic / FUNCTION: read a string from operator
1234599Sbostic /
1334599Sbostic / AUTHOR: E. A. Estes, 12/4/85
1434599Sbostic /
1534599Sbostic / ARGUMENTS:
1634599Sbostic /	char *cp - pointer to buffer area to fill
1734599Sbostic /	int mx - maximum number of characters to put in buffer
1834599Sbostic /
1934599Sbostic / RETURN VALUE: none
2034599Sbostic /
2134599Sbostic / MODULES CALLED: wmove(), _filbuf(), clearok(), waddstr(), wrefresh(),
2234599Sbostic /	wclrtoeol()
2334599Sbostic /
2434599Sbostic / GLOBAL INPUTS: Echo, _iob[], Wizard, *stdscr
2534599Sbostic /
2634599Sbostic / GLOBAL OUTPUTS: _iob[]
2734599Sbostic /
2834599Sbostic / DESCRIPTION:
2934599Sbostic /	Read a string from the keyboard.
3034599Sbostic /	This routine is specially designed to:
3134599Sbostic /
3234599Sbostic /	    - strip non-printing characters (unless Wizard)
3334599Sbostic /	    - echo, if desired
3434599Sbostic /	    - redraw the screen if CH_REDRAW is entered
3534599Sbostic /	    - read in only 'mx - 1' characters or less characters
3634599Sbostic /	    - nul-terminate string, and throw away newline
3734599Sbostic /
3834599Sbostic /	'mx' is assumed to be at least 2.
3934599Sbostic /
4034599Sbostic /************************************************************************/
4134599Sbostic 
4234599Sbostic getstring(cp, mx)
4334599Sbostic register char	*cp;
4434599Sbostic register int	mx;
4534599Sbostic {
4634599Sbostic register char	*inptr;		/* pointer into string for next string */
4734599Sbostic int	x, y;			/* original x, y coordinates on screen */
4834599Sbostic int	ch;			/* input */
4934599Sbostic 
5034599Sbostic     getyx(stdscr, y, x);	/* get coordinates on screen */
5134599Sbostic     inptr = cp;
5234599Sbostic     *inptr = '\0';		/* clear string to start */
5334599Sbostic     --mx;			/* reserve room in string for nul terminator */
5434599Sbostic 
5534599Sbostic     do
5634599Sbostic 	/* get characters and process */
5734599Sbostic 	{
5834599Sbostic 	if (Echo)
5934599Sbostic 	    mvaddstr(y, x, cp);	/* print string on screen */
6034599Sbostic 	clrtoeol();		/* clear any data after string */
6134599Sbostic 	refresh();		/* update screen */
6234599Sbostic 
6334599Sbostic 	ch = getchar();		/* get character */
6434599Sbostic 
6534599Sbostic 	switch (ch)
6634599Sbostic 	    {
6734599Sbostic 	    case CH_ERASE:	/* back up one character */
6834599Sbostic 		if (inptr > cp)
6934599Sbostic 		    --inptr;
7034599Sbostic 		break;
7134599Sbostic 
7234599Sbostic 	    case CH_KILL:	/* back up to original location */
7334599Sbostic 		inptr = cp;
7434599Sbostic 		break;
7534599Sbostic 
7634599Sbostic 	    case CH_NEWLINE:	/* terminate string */
7734599Sbostic 		break;
7834599Sbostic 
7934599Sbostic 	    case CH_REDRAW:	/* redraw screen */
8034599Sbostic 		clearok(stdscr, TRUE);
8134599Sbostic 		continue;
8234599Sbostic 
8334599Sbostic 	    default:		/* put data in string */
8434599Sbostic 		if (ch >= ' ' || Wizard)
8534599Sbostic 		    /* printing char; put in string */
8634599Sbostic 		    *inptr++ = ch;
8734599Sbostic 	    }
8834599Sbostic 
8934599Sbostic 	*inptr = '\0';		/* terminate string */
9034599Sbostic 	}
9134599Sbostic     while (ch != CH_NEWLINE && inptr < cp + mx);
9234599Sbostic }
9334599Sbostic /**/
9434599Sbostic /************************************************************************
9534599Sbostic /
9634599Sbostic / FUNCTION NAME: more()
9734599Sbostic /
9834599Sbostic / FUNCTION: pause and prompt player
9934599Sbostic /
10034599Sbostic / AUTHOR: E. A. Estes, 12/4/85
10134599Sbostic /
10234599Sbostic / ARGUMENTS:
10334599Sbostic /	int where - line on screen on which to pause
10434599Sbostic /
10534599Sbostic / RETURN VALUE: none
10634599Sbostic /
10734599Sbostic / MODULES CALLED: wmove(), waddstr(), getanswer()
10834599Sbostic /
10934599Sbostic / GLOBAL INPUTS: *stdscr
11034599Sbostic /
11134599Sbostic / GLOBAL OUTPUTS: none
11234599Sbostic /
11334599Sbostic / DESCRIPTION:
11434599Sbostic /	Print a message, and wait for a space character.
11534599Sbostic /
11634599Sbostic /************************************************************************/
11734599Sbostic 
11834599Sbostic more(where)
11934599Sbostic int	where;
12034599Sbostic {
12134599Sbostic     mvaddstr(where, 0, "-- more --");
12234599Sbostic     getanswer(" ", FALSE);
12334599Sbostic }
12434599Sbostic /**/
12534599Sbostic /************************************************************************
12634599Sbostic /
12734599Sbostic / FUNCTION NAME: infloat()
12834599Sbostic /
12934599Sbostic / FUNCTION: input a floating point number from operator
13034599Sbostic /
13134599Sbostic / AUTHOR: E. A. Estes, 12/4/85
13234599Sbostic /
13334599Sbostic / ARGUMENTS: none
13434599Sbostic /
13534599Sbostic / RETURN VALUE: floating point number from operator
13634599Sbostic /
13734599Sbostic / MODULES CALLED: sscanf(), getstring()
13834599Sbostic /
13934599Sbostic / GLOBAL INPUTS: Databuf[]
14034599Sbostic /
14134599Sbostic / GLOBAL OUTPUTS: none
14234599Sbostic /
14334599Sbostic / DESCRIPTION:
14434599Sbostic /	Read a string from player, and scan for a floating point
14534599Sbostic /	number.
14634599Sbostic /	If no valid number is found, return 0.0.
14734599Sbostic /
14834599Sbostic /************************************************************************/
14934599Sbostic 
15034599Sbostic double
15134599Sbostic infloat()
15234599Sbostic {
15334599Sbostic double	result;		/* return value */
15434599Sbostic 
15534599Sbostic     getstring(Databuf, SZ_DATABUF);
156*34613Sbostic     if (sscanf(Databuf, "%lf", &result) < 1)
15734599Sbostic 	/* no valid number entered */
15834599Sbostic 	result = 0.0;
15934599Sbostic 
16034599Sbostic     return(result);
16134599Sbostic }
16234599Sbostic /**/
16334599Sbostic /************************************************************************
16434599Sbostic /
16534599Sbostic / FUNCTION NAME: inputoption()
16634599Sbostic /
16734599Sbostic / FUNCTION: input an option value from player
16834599Sbostic /
16934599Sbostic / AUTHOR: E. A. Estes, 12/4/85
17034599Sbostic /
17134599Sbostic / ARGUMENTS: none
17234599Sbostic /
17334599Sbostic / RETURN VALUE: none
17434599Sbostic /
17534599Sbostic / MODULES CALLED: floor(), drandom(), getanswer()
17634599Sbostic /
17734599Sbostic / GLOBAL INPUTS: Player
17834599Sbostic /
17934599Sbostic / GLOBAL OUTPUTS: Player
18034599Sbostic /
18134599Sbostic / DESCRIPTION:
18234599Sbostic /	Age increases with every move.
18334599Sbostic /	Refresh screen, and get a single character option from player.
18434599Sbostic /	Return a random value if player's ring has gone bad.
18534599Sbostic /
18634599Sbostic /************************************************************************/
18734599Sbostic 
18834599Sbostic inputoption()
18934599Sbostic {
19034599Sbostic     ++Player.p_age;		/* increase age */
19134599Sbostic 
19234599Sbostic     if (Player.p_ring.ring_type != R_SPOILED)
19334599Sbostic 	/* ring ok */
19434599Sbostic 	return(getanswer("T ", TRUE));
19534599Sbostic     else
19634599Sbostic 	/* bad ring */
19734599Sbostic 	{
19834599Sbostic 	getanswer(" ", TRUE);
19934599Sbostic 	return((int) ROLL(0.0, 5.0) + '0');
20034599Sbostic 	}
20134599Sbostic }
20234599Sbostic /**/
20334599Sbostic /************************************************************************
20434599Sbostic /
20534599Sbostic / FUNCTION NAME: interrupt()
20634599Sbostic /
20734599Sbostic / FUNCTION: handle interrupt from operator
20834599Sbostic /
20934599Sbostic / AUTHOR: E. A. Estes, 12/4/85
21034599Sbostic /
21134599Sbostic / ARGUMENTS: none
21234599Sbostic /
21334599Sbostic / RETURN VALUE: none
21434599Sbostic /
21534599Sbostic / MODULES CALLED: fork(), exit(), wait(), death(), alarm(), execl(), wmove(),
21634599Sbostic /	getgid(), signal(), getenv(), wclear(), setuid(), getuid(), setgid(),
21734599Sbostic /	crmode(), clearok(), waddstr(), cleanup(), wrefresh(), leavegame(),
21834599Sbostic /	getanswer()
21934599Sbostic /
22034599Sbostic / GLOBAL INPUTS: Player, *stdscr
22134599Sbostic /
22234599Sbostic / GLOBAL OUTPUTS: none
22334599Sbostic /
22434599Sbostic / DESCRIPTION:
22534599Sbostic /	Allow player to quit upon hitting the interrupt key.
22634599Sbostic /	If the player wants to quit while in battle, he/she automatically
22734599Sbostic /	dies.
22834599Sbostic /	If SHELL is defined, spawn a shell if the if the question is
22934599Sbostic /	answered with a '!'.
23034599Sbostic /	We are careful to save the state of the screen, and return it
23134599Sbostic /	to its original condition.
23234599Sbostic /
23334599Sbostic /************************************************************************/
23434599Sbostic 
23534599Sbostic interrupt()
23634599Sbostic {
23734599Sbostic char	line[81];		/* a place to store data already on screen */
23834599Sbostic register int	loop;		/* counter */
23934599Sbostic int	x, y;			/* coordinates on screen */
24034599Sbostic int	ch;			/* input */
24134599Sbostic unsigned	savealarm;	/* to save alarm value */
24234599Sbostic #ifdef SHELL
24334599Sbostic register char	*shell;		/* pointer to shell to spawn */
24434599Sbostic int	childpid;		/* pid of spawned process */
24534599Sbostic #endif
24634599Sbostic 
24734599Sbostic #ifdef SYS3
24834599Sbostic     signal(SIGINT, SIG_IGN);
24934599Sbostic #endif
25034599Sbostic #ifdef SYS5
25134599Sbostic     signal(SIGINT, SIG_IGN);
25234599Sbostic #endif
25334599Sbostic 
25434599Sbostic     savealarm = alarm(0);		/* turn off any alarms */
25534599Sbostic 
25634599Sbostic     getyx(stdscr, y, x);		/* save cursor location */
25734599Sbostic 
25834599Sbostic     for (loop = 0; loop < 80; ++loop)	/* save line on screen */
25934599Sbostic 	{
26034599Sbostic 	move(4, loop);
26134599Sbostic 	line[loop] = inch();
26234599Sbostic 	}
26334599Sbostic     line[80] = '\0';			/* nul terminate */
26434599Sbostic 
26534599Sbostic     if (Player.p_status == S_INBATTLE || Player.p_status == S_MONSTER)
26634599Sbostic 	/* in midst of fighting */
26734599Sbostic 	{
26834599Sbostic 	mvaddstr(4, 0, "Quitting now will automatically kill your character.  Still want to ? ");
26934599Sbostic #ifdef SHELL
27034599Sbostic 	ch = getanswer("NY!", FALSE);
27134599Sbostic #else
27234599Sbostic 	ch = getanswer("NY", FALSE);
27334599Sbostic #endif
27434599Sbostic 	if (ch == 'Y')
27534599Sbostic 	    death("Bailing out");
27634599Sbostic 	    /*NOTREACHED*/
27734599Sbostic 	}
27834599Sbostic     else
27934599Sbostic 	{
28034599Sbostic #ifdef SHELL
28134599Sbostic 	mvaddstr(4, 0, "Do you really want to quit [! = Shell] ? ");
28234599Sbostic 	ch = getanswer("NY!", FALSE);
28334599Sbostic #else
28434599Sbostic 	mvaddstr(4, 0, "Do you really want to quit ? ");
28534599Sbostic 	ch = getanswer("NY", FALSE);
28634599Sbostic #endif
28734599Sbostic 	if (ch == 'Y')
28834599Sbostic 	    leavegame();
28934599Sbostic 	    /*NOTREACHED*/
29034599Sbostic 	}
29134599Sbostic 
29234599Sbostic #ifdef SHELL
29334599Sbostic     if (ch == '!')
29434599Sbostic 	/* shell escape */
29534599Sbostic 	{
29634599Sbostic 	if ((shell = getenv("SHELL")) == NULL)
29734599Sbostic 	    /* use default */
29834599Sbostic 	    shell = SHELL;
29934599Sbostic 
30034599Sbostic 	if ((childpid = fork()) == 0)
30134599Sbostic 	    /* in child */
30234599Sbostic 	    {
30334599Sbostic 	    clear();
30434599Sbostic 	    refresh();
30534599Sbostic 	    cleanup(FALSE);		/* out of curses, close files */
30634599Sbostic 
30734599Sbostic 	    setuid(getuid());		/* make sure we are running with real uid */
30834599Sbostic 	    setgid(getgid());		/* make sure we are running with real gid */
30934599Sbostic 	    execl(shell, shell, "-i", 0);
31034599Sbostic 	    execl(SHELL, SHELL, "-i", 0);	/* last resort */
31134599Sbostic 
31234599Sbostic 	    exit(0);
31334599Sbostic 	    /*NOTREACHED*/
31434599Sbostic 	    }
31534599Sbostic 	else
31634599Sbostic 	    /* in parent */
31734599Sbostic 	    {
31834599Sbostic 	    while (wait((int *) NULL) != childpid);	/* wait until done */
31934599Sbostic 	    crmode();			/* restore keyboard */
32034599Sbostic 	    clearok(stdscr, TRUE);	/* force redraw of screen */
32134599Sbostic 	    }
32234599Sbostic 	}
32334599Sbostic #endif
32434599Sbostic 
32534599Sbostic     mvaddstr(4, 0, line); 		/* restore data on screen */
32634599Sbostic     move(y, x);				/* restore cursor */
32734599Sbostic     refresh();
32834599Sbostic 
32934599Sbostic #ifdef SYS3
33034599Sbostic     signal(SIGINT, interrupt);
33134599Sbostic #endif
33234599Sbostic #ifdef SYS5
33334599Sbostic     signal(SIGINT, interrupt);
33434599Sbostic #endif
33534599Sbostic 
33634599Sbostic     alarm(savealarm);			/* restore alarm */
33734599Sbostic }
33834599Sbostic /**/
33934599Sbostic /************************************************************************
34034599Sbostic /
34134599Sbostic / FUNCTION NAME: getanswer()
34234599Sbostic /
34334599Sbostic / FUNCTION: get an answer from operator
34434599Sbostic /
34534599Sbostic / AUTHOR: E. A. Estes, 12/4/85
34634599Sbostic /
34734599Sbostic / ARGUMENTS:
34834599Sbostic /	char *choices - string of (upper case) valid choices
34934599Sbostic /	bool def - set if default answer
35034599Sbostic /
35134599Sbostic / RETURN VALUE: none
35234599Sbostic /
35334599Sbostic / MODULES CALLED: alarm(), wmove(), waddch(), signal(), setjmp(), strchr(),
35434599Sbostic /	_filbuf(), clearok(), toupper(), wrefresh(), mvprintw(), wclrtoeol()
35534599Sbostic /
35634599Sbostic / GLOBAL INPUTS: catchalarm(), Echo, _iob[], _ctype[], *stdscr, Timeout,
35734599Sbostic /	Timeoenv[]
35834599Sbostic /
35934599Sbostic / GLOBAL OUTPUTS: _iob[]
36034599Sbostic /
36134599Sbostic / DESCRIPTION:
36234599Sbostic /	Get a single character answer from operator.
36334599Sbostic /	Timeout waiting for response.  If we timeout, or the
36434599Sbostic /	answer in not in the list of valid choices, print choices,
36534599Sbostic /	and wait again, otherwise return the first character in ths
36634599Sbostic /	list of choices.
36734599Sbostic /	Give up after 3 tries.
36834599Sbostic /
36934599Sbostic /************************************************************************/
37034599Sbostic 
37134599Sbostic getanswer(choices, def)
37234599Sbostic char	*choices;
37334599Sbostic bool	def;
37434599Sbostic {
37534599Sbostic int	ch;			/* input */
37634599Sbostic int	loop;			/* counter */
37734599Sbostic int	oldx, oldy;		/* original coordinates on screen */
37834599Sbostic 
37934599Sbostic     getyx(stdscr, oldy, oldx);
38034599Sbostic     alarm(0);				/* make sure alarm is off */
38134599Sbostic 
38234599Sbostic     for (loop = 3; loop; --loop)
38334599Sbostic 	/* try for 3 times */
38434599Sbostic 	{
38534599Sbostic 	if (setjmp(Timeoenv) != 0)
38634599Sbostic 	    /* timed out waiting for response */
38734599Sbostic 	    {
38834599Sbostic 	    if (def || loop <= 1)
38934599Sbostic 		/* return default answer */
39034599Sbostic 		break;
39134599Sbostic 	    else
39234599Sbostic 		/* prompt, and try again */
39334599Sbostic 		goto YELL;
39434599Sbostic 	    }
39534599Sbostic 	else
39634599Sbostic 	    /* wait for response */
39734599Sbostic 	    {
39834599Sbostic 	    clrtoeol();
39934599Sbostic 	    refresh();
40034599Sbostic #ifdef BSD41
40134599Sbostic 	    sigset(SIGALRM, catchalarm);
40234599Sbostic #else
40334599Sbostic 	    signal(SIGALRM, catchalarm);
40434599Sbostic #endif
40534599Sbostic 	    /* set timeout */
40634599Sbostic 	    if (Timeout)
40734599Sbostic 		alarm(7);		/* short */
40834599Sbostic 	    else
40934599Sbostic 		alarm(600);		/* long */
41034599Sbostic 
41134599Sbostic 	    ch = getchar();
41234599Sbostic 
41334599Sbostic 	    alarm(0);			/* turn off timeout */
41434599Sbostic 
41534599Sbostic 	    if (ch < 0)
41634599Sbostic 		/* caught some signal */
41734599Sbostic 		{
41834599Sbostic 		++loop;
41934599Sbostic 		continue;
42034599Sbostic 		}
42134599Sbostic 	    else if (ch == CH_REDRAW)
42234599Sbostic 		/* redraw screen */
42334599Sbostic 		{
42434599Sbostic 		clearok(stdscr, TRUE);	/* force clear screen */
42534599Sbostic 		++loop;			/* don't count this input */
42634599Sbostic 		continue;
42734599Sbostic 		}
42834599Sbostic 	    else if (Echo)
42934599Sbostic 		{
43034599Sbostic 		addch(ch);		/* echo character */
43134599Sbostic 		refresh();
43234599Sbostic 		}
43334599Sbostic 
43434599Sbostic 	    if (islower(ch))
43534599Sbostic 		/* convert to upper case */
43634599Sbostic 		ch = toupper(ch);
43734599Sbostic 
43834599Sbostic 	    if (def || strchr(choices, ch) != NULL)
43934599Sbostic 		/* valid choice */
44034599Sbostic 		return(ch);
44134599Sbostic 	    else if (!def && loop > 1)
44234599Sbostic 		/* bad choice; prompt, and try again */
44334599Sbostic 		{
44434599Sbostic YELL:		mvprintw(oldy + 1, 0, "Please choose one of : [%s]\n", choices);
44534599Sbostic 		move(oldy, oldx);
44634599Sbostic 		clrtoeol();
44734599Sbostic 		continue;
44834599Sbostic 		}
44934599Sbostic 	    else
45034599Sbostic 		/* return default answer */
45134599Sbostic 		break;
45234599Sbostic 	    }
45334599Sbostic 	}
45434599Sbostic 
45534599Sbostic     return(*choices);
45634599Sbostic }
45734599Sbostic /**/
45834599Sbostic /************************************************************************
45934599Sbostic /
46034599Sbostic / FUNCTION NAME: catchalarm()
46134599Sbostic /
46234599Sbostic / FUNCTION: catch timer when waiting for input
46334599Sbostic /
46434599Sbostic / AUTHOR: E. A. Estes, 12/4/85
46534599Sbostic /
46634599Sbostic / ARGUMENTS: none
46734599Sbostic /
46834599Sbostic / RETURN VALUE: none
46934599Sbostic /
47034599Sbostic / MODULES CALLED: longjmp()
47134599Sbostic /
47234599Sbostic / GLOBAL INPUTS: Timeoenv[]
47334599Sbostic /
47434599Sbostic / GLOBAL OUTPUTS: none
47534599Sbostic /
47634599Sbostic / DESCRIPTION:
47734599Sbostic /	Come here when the alarm expires while waiting for input.
47834599Sbostic /	Simply longjmp() into getanswer().
47934599Sbostic /
48034599Sbostic /************************************************************************/
48134599Sbostic 
48234599Sbostic catchalarm()
48334599Sbostic {
48434599Sbostic     longjmp(Timeoenv, 1);
48534599Sbostic }
486