xref: /csrg-svn/games/phantasia/io.c (revision 56571)
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 
getstring(cp,mx)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 
more(where)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
infloat()15134599Sbostic infloat()
15234599Sbostic {
15334599Sbostic double	result;		/* return value */
15434599Sbostic 
15534599Sbostic     getstring(Databuf, SZ_DATABUF);
15634613Sbostic     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 
inputoption()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 /
22934599Sbostic /************************************************************************/
23034599Sbostic 
interrupt()23134599Sbostic interrupt()
23234599Sbostic {
23334599Sbostic char	line[81];		/* a place to store data already on screen */
23434599Sbostic register int	loop;		/* counter */
23534599Sbostic int	x, y;			/* coordinates on screen */
23634599Sbostic int	ch;			/* input */
23734599Sbostic unsigned	savealarm;	/* to save alarm value */
23834599Sbostic 
23934599Sbostic #ifdef SYS3
24034599Sbostic     signal(SIGINT, SIG_IGN);
24134599Sbostic #endif
24234599Sbostic #ifdef SYS5
24334599Sbostic     signal(SIGINT, SIG_IGN);
24434599Sbostic #endif
24534599Sbostic 
24634599Sbostic     savealarm = alarm(0);		/* turn off any alarms */
24734599Sbostic 
24834599Sbostic     getyx(stdscr, y, x);		/* save cursor location */
24934599Sbostic 
25034599Sbostic     for (loop = 0; loop < 80; ++loop)	/* save line on screen */
25134599Sbostic 	{
25234599Sbostic 	move(4, loop);
25334599Sbostic 	line[loop] = inch();
25434599Sbostic 	}
25534599Sbostic     line[80] = '\0';			/* nul terminate */
25634599Sbostic 
25734599Sbostic     if (Player.p_status == S_INBATTLE || Player.p_status == S_MONSTER)
25834599Sbostic 	/* in midst of fighting */
25934599Sbostic 	{
26034599Sbostic 	mvaddstr(4, 0, "Quitting now will automatically kill your character.  Still want to ? ");
26134599Sbostic 	ch = getanswer("NY", FALSE);
26234599Sbostic 	if (ch == 'Y')
26334599Sbostic 	    death("Bailing out");
26434599Sbostic 	    /*NOTREACHED*/
26534599Sbostic 	}
26634599Sbostic     else
26734599Sbostic 	{
26834599Sbostic 	mvaddstr(4, 0, "Do you really want to quit ? ");
26934599Sbostic 	ch = getanswer("NY", FALSE);
27034599Sbostic 	if (ch == 'Y')
27134599Sbostic 	    leavegame();
27234599Sbostic 	    /*NOTREACHED*/
27334599Sbostic 	}
27434599Sbostic 
27534599Sbostic     mvaddstr(4, 0, line); 		/* restore data on screen */
27634599Sbostic     move(y, x);				/* restore cursor */
27734599Sbostic     refresh();
27834599Sbostic 
27934599Sbostic #ifdef SYS3
28034599Sbostic     signal(SIGINT, interrupt);
28134599Sbostic #endif
28234599Sbostic #ifdef SYS5
28334599Sbostic     signal(SIGINT, interrupt);
28434599Sbostic #endif
28534599Sbostic 
28634599Sbostic     alarm(savealarm);			/* restore alarm */
28734599Sbostic }
28834599Sbostic /**/
28934599Sbostic /************************************************************************
29034599Sbostic /
29134599Sbostic / FUNCTION NAME: getanswer()
29234599Sbostic /
29334599Sbostic / FUNCTION: get an answer from operator
29434599Sbostic /
29534599Sbostic / AUTHOR: E. A. Estes, 12/4/85
29634599Sbostic /
29734599Sbostic / ARGUMENTS:
29834599Sbostic /	char *choices - string of (upper case) valid choices
29934599Sbostic /	bool def - set if default answer
30034599Sbostic /
30134599Sbostic / RETURN VALUE: none
30234599Sbostic /
30334599Sbostic / MODULES CALLED: alarm(), wmove(), waddch(), signal(), setjmp(), strchr(),
30434599Sbostic /	_filbuf(), clearok(), toupper(), wrefresh(), mvprintw(), wclrtoeol()
30534599Sbostic /
30634599Sbostic / GLOBAL INPUTS: catchalarm(), Echo, _iob[], _ctype[], *stdscr, Timeout,
30734599Sbostic /	Timeoenv[]
30834599Sbostic /
30934599Sbostic / GLOBAL OUTPUTS: _iob[]
31034599Sbostic /
31134599Sbostic / DESCRIPTION:
31234599Sbostic /	Get a single character answer from operator.
31334599Sbostic /	Timeout waiting for response.  If we timeout, or the
31434599Sbostic /	answer in not in the list of valid choices, print choices,
31534599Sbostic /	and wait again, otherwise return the first character in ths
31634599Sbostic /	list of choices.
31734599Sbostic /	Give up after 3 tries.
31834599Sbostic /
31934599Sbostic /************************************************************************/
32034599Sbostic 
getanswer(choices,def)32134599Sbostic getanswer(choices, def)
32234599Sbostic char	*choices;
32334599Sbostic bool	def;
32434599Sbostic {
32534599Sbostic int	ch;			/* input */
32634599Sbostic int	loop;			/* counter */
32734599Sbostic int	oldx, oldy;		/* original coordinates on screen */
32834599Sbostic 
32934599Sbostic     getyx(stdscr, oldy, oldx);
33034599Sbostic     alarm(0);				/* make sure alarm is off */
33134599Sbostic 
33234599Sbostic     for (loop = 3; loop; --loop)
33334599Sbostic 	/* try for 3 times */
33434599Sbostic 	{
33534599Sbostic 	if (setjmp(Timeoenv) != 0)
33634599Sbostic 	    /* timed out waiting for response */
33734599Sbostic 	    {
33834599Sbostic 	    if (def || loop <= 1)
33934599Sbostic 		/* return default answer */
34034599Sbostic 		break;
34134599Sbostic 	    else
34234599Sbostic 		/* prompt, and try again */
34334599Sbostic 		goto YELL;
34434599Sbostic 	    }
34534599Sbostic 	else
34634599Sbostic 	    /* wait for response */
34734599Sbostic 	    {
34834599Sbostic 	    clrtoeol();
34934599Sbostic 	    refresh();
35034599Sbostic #ifdef BSD41
35134599Sbostic 	    sigset(SIGALRM, catchalarm);
35234599Sbostic #else
35334599Sbostic 	    signal(SIGALRM, catchalarm);
35434599Sbostic #endif
35534599Sbostic 	    /* set timeout */
35634599Sbostic 	    if (Timeout)
35734599Sbostic 		alarm(7);		/* short */
35834599Sbostic 	    else
35934599Sbostic 		alarm(600);		/* long */
36034599Sbostic 
36134599Sbostic 	    ch = getchar();
36234599Sbostic 
36334599Sbostic 	    alarm(0);			/* turn off timeout */
36434599Sbostic 
36534599Sbostic 	    if (ch < 0)
36634599Sbostic 		/* caught some signal */
36734599Sbostic 		{
36834599Sbostic 		++loop;
36934599Sbostic 		continue;
37034599Sbostic 		}
37134599Sbostic 	    else if (ch == CH_REDRAW)
37234599Sbostic 		/* redraw screen */
37334599Sbostic 		{
37434599Sbostic 		clearok(stdscr, TRUE);	/* force clear screen */
37534599Sbostic 		++loop;			/* don't count this input */
37634599Sbostic 		continue;
37734599Sbostic 		}
37834599Sbostic 	    else if (Echo)
37934599Sbostic 		{
38034599Sbostic 		addch(ch);		/* echo character */
38134599Sbostic 		refresh();
38234599Sbostic 		}
38334599Sbostic 
38434599Sbostic 	    if (islower(ch))
38534599Sbostic 		/* convert to upper case */
38634599Sbostic 		ch = toupper(ch);
38734599Sbostic 
38834599Sbostic 	    if (def || strchr(choices, ch) != NULL)
38934599Sbostic 		/* valid choice */
39034599Sbostic 		return(ch);
39134599Sbostic 	    else if (!def && loop > 1)
39234599Sbostic 		/* bad choice; prompt, and try again */
39334599Sbostic 		{
39434599Sbostic YELL:		mvprintw(oldy + 1, 0, "Please choose one of : [%s]\n", choices);
39534599Sbostic 		move(oldy, oldx);
39634599Sbostic 		clrtoeol();
39734599Sbostic 		continue;
39834599Sbostic 		}
39934599Sbostic 	    else
40034599Sbostic 		/* return default answer */
40134599Sbostic 		break;
40234599Sbostic 	    }
40334599Sbostic 	}
40434599Sbostic 
40534599Sbostic     return(*choices);
40634599Sbostic }
40734599Sbostic /**/
40834599Sbostic /************************************************************************
40934599Sbostic /
41034599Sbostic / FUNCTION NAME: catchalarm()
41134599Sbostic /
41234599Sbostic / FUNCTION: catch timer when waiting for input
41334599Sbostic /
41434599Sbostic / AUTHOR: E. A. Estes, 12/4/85
41534599Sbostic /
41634599Sbostic / ARGUMENTS: none
41734599Sbostic /
41834599Sbostic / RETURN VALUE: none
41934599Sbostic /
42034599Sbostic / MODULES CALLED: longjmp()
42134599Sbostic /
42234599Sbostic / GLOBAL INPUTS: Timeoenv[]
42334599Sbostic /
42434599Sbostic / GLOBAL OUTPUTS: none
42534599Sbostic /
42634599Sbostic / DESCRIPTION:
42734599Sbostic /	Come here when the alarm expires while waiting for input.
42834599Sbostic /	Simply longjmp() into getanswer().
42934599Sbostic /
43034599Sbostic /************************************************************************/
43134599Sbostic 
432*56571Sbostic void
catchalarm()43334599Sbostic catchalarm()
43434599Sbostic {
43534599Sbostic     longjmp(Timeoenv, 1);
43634599Sbostic }
437