xref: /openbsd-src/games/phantasia/io.c (revision 8a56d9bbcf8ba68b132f1e7971d09a63a2069c40)
1*8a56d9bbSmillert /*	$OpenBSD: io.c,v 1.10 2021/04/29 01:57:00 millert Exp $	*/
2df930be7Sderaadt /*	$NetBSD: io.c,v 1.2 1995/03/24 03:58:50 cgd Exp $	*/
3df930be7Sderaadt 
4df930be7Sderaadt /*
5df930be7Sderaadt  * io.c - input/output routines for Phantasia
6df930be7Sderaadt  */
7df930be7Sderaadt 
8010ae45bSmestre #include <ctype.h>
9010ae45bSmestre #include <curses.h>
10010ae45bSmestre #include <math.h>
11010ae45bSmestre #include <setjmp.h>
12010ae45bSmestre #include <signal.h>
13010ae45bSmestre #include <string.h>
14010ae45bSmestre #include <unistd.h>
15010ae45bSmestre 
16010ae45bSmestre #include "macros.h"
17010ae45bSmestre #include "phantdefs.h"
18010ae45bSmestre #include "phantglobs.h"
19010ae45bSmestre 
20010ae45bSmestre static jmp_buf Timeoenv;	/* used for timing out waiting for input */
21df930be7Sderaadt 
22df930be7Sderaadt /************************************************************************
23df930be7Sderaadt /
24df930be7Sderaadt / FUNCTION NAME: getstring()
25df930be7Sderaadt /
26df930be7Sderaadt / FUNCTION: read a string from operator
27df930be7Sderaadt /
28df930be7Sderaadt / AUTHOR: E. A. Estes, 12/4/85
29df930be7Sderaadt /
30df930be7Sderaadt / ARGUMENTS:
31df930be7Sderaadt /	char *cp - pointer to buffer area to fill
32df930be7Sderaadt /	int mx - maximum number of characters to put in buffer
33df930be7Sderaadt /
34df930be7Sderaadt / RETURN VALUE: none
35df930be7Sderaadt /
36df930be7Sderaadt / MODULES CALLED: wmove(), _filbuf(), clearok(), waddstr(), wrefresh(),
37df930be7Sderaadt /	wclrtoeol()
38df930be7Sderaadt /
39df930be7Sderaadt / GLOBAL INPUTS: Echo, _iob[], Wizard, *stdscr
40df930be7Sderaadt /
41df930be7Sderaadt / GLOBAL OUTPUTS: _iob[]
42df930be7Sderaadt /
43df930be7Sderaadt / DESCRIPTION:
44df930be7Sderaadt /	Read a string from the keyboard.
45df930be7Sderaadt /	This routine is specially designed to:
46df930be7Sderaadt /
47df930be7Sderaadt /	    - strip non-printing characters (unless Wizard)
48df930be7Sderaadt /	    - echo, if desired
49df930be7Sderaadt /	    - redraw the screen if CH_REDRAW is entered
50df930be7Sderaadt /	    - read in only 'mx - 1' characters or less characters
51df930be7Sderaadt /	    - nul-terminate string, and throw away newline
52df930be7Sderaadt /
53df930be7Sderaadt /	'mx' is assumed to be at least 2.
54df930be7Sderaadt /
55db690800Sfn *************************************************************************/
56df930be7Sderaadt 
57c4b20be9Spjanzen void
getstring(char * cp,int mx)58f0d3161eStb getstring(char *cp, int mx)
59df930be7Sderaadt {
60c4b20be9Spjanzen 	char   *inptr;		/* pointer into string for next string */
61df930be7Sderaadt 	int     x, y;		/* original x, y coordinates on screen */
62df930be7Sderaadt 	int     ch;		/* input */
63df930be7Sderaadt 
64df930be7Sderaadt 	getyx(stdscr, y, x);	/* get coordinates on screen */
65df930be7Sderaadt 	inptr = cp;
66df930be7Sderaadt 	*inptr = '\0';		/* clear string to start */
67df930be7Sderaadt 	--mx;			/* reserve room in string for nul terminator */
68df930be7Sderaadt 
69df930be7Sderaadt 	do
70df930be7Sderaadt 		/* get characters and process */
71df930be7Sderaadt 	{
72df930be7Sderaadt 		if (Echo)
73df930be7Sderaadt 			mvaddstr(y, x, cp);	/* print string on screen */
74df930be7Sderaadt 		clrtoeol();	/* clear any data after string */
75df930be7Sderaadt 		refresh();	/* update screen */
76df930be7Sderaadt 
77df930be7Sderaadt 		ch = getchar();	/* get character */
78df930be7Sderaadt 
79c4b20be9Spjanzen 		switch (ch) {
80df930be7Sderaadt 		case CH_NEWLINE:	/* terminate string */
81f8908df1Sdownsj 		case CH_RETURN:
82df930be7Sderaadt 			break;
83df930be7Sderaadt 
84df930be7Sderaadt 		case CH_REDRAW:	/* redraw screen */
85df930be7Sderaadt 			clearok(stdscr, TRUE);
86df930be7Sderaadt 			continue;
87df930be7Sderaadt 
88df930be7Sderaadt 		default:		/* put data in string */
89f8908df1Sdownsj 			if (ch == Ch_Erase) {	/* back up one character */
90f8908df1Sdownsj 				if (inptr > cp)
91f8908df1Sdownsj 					--inptr;
92f8908df1Sdownsj 				break;
93f8908df1Sdownsj 			} else if (ch == Ch_Kill) { /* back up to original location */
94f8908df1Sdownsj 				inptr = cp;
95f8908df1Sdownsj 				break;
96f8908df1Sdownsj 			} else if (isprint(ch) || Wizard) {
97df930be7Sderaadt 				/* printing char; put in string */
98df930be7Sderaadt 				*inptr++ = ch;
99df930be7Sderaadt 			}
100f8908df1Sdownsj 		}
101df930be7Sderaadt 
102df930be7Sderaadt 		*inptr = '\0';	/* terminate string */
103df930be7Sderaadt 	}
104f8908df1Sdownsj 	while (ch != CH_NEWLINE && ch != CH_RETURN && inptr < cp + mx);
105df930be7Sderaadt }
106df930be7Sderaadt /**/
107df930be7Sderaadt /************************************************************************
108df930be7Sderaadt /
109df930be7Sderaadt / FUNCTION NAME: more()
110df930be7Sderaadt /
111df930be7Sderaadt / FUNCTION: pause and prompt player
112df930be7Sderaadt /
113df930be7Sderaadt / AUTHOR: E. A. Estes, 12/4/85
114df930be7Sderaadt /
115df930be7Sderaadt / ARGUMENTS:
116df930be7Sderaadt /	int where - line on screen on which to pause
117df930be7Sderaadt /
118df930be7Sderaadt / RETURN VALUE: none
119df930be7Sderaadt /
120df930be7Sderaadt / MODULES CALLED: wmove(), waddstr(), getanswer()
121df930be7Sderaadt /
122df930be7Sderaadt / GLOBAL INPUTS: *stdscr
123df930be7Sderaadt /
124df930be7Sderaadt / GLOBAL OUTPUTS: none
125df930be7Sderaadt /
126df930be7Sderaadt / DESCRIPTION:
127df930be7Sderaadt /	Print a message, and wait for a space character.
128df930be7Sderaadt /
129db690800Sfn *************************************************************************/
130df930be7Sderaadt 
131c4b20be9Spjanzen void
more(int where)132f0d3161eStb more(int where)
133df930be7Sderaadt {
134df930be7Sderaadt 	mvaddstr(where, 0, "-- more --");
135df930be7Sderaadt 	getanswer(" ", FALSE);
136df930be7Sderaadt }
137df930be7Sderaadt /**/
138df930be7Sderaadt /************************************************************************
139df930be7Sderaadt /
140df930be7Sderaadt / FUNCTION NAME: infloat()
141df930be7Sderaadt /
142df930be7Sderaadt / FUNCTION: input a floating point number from operator
143df930be7Sderaadt /
144df930be7Sderaadt / AUTHOR: E. A. Estes, 12/4/85
145df930be7Sderaadt /
146df930be7Sderaadt / ARGUMENTS: none
147df930be7Sderaadt /
148df930be7Sderaadt / RETURN VALUE: floating point number from operator
149df930be7Sderaadt /
150df930be7Sderaadt / MODULES CALLED: sscanf(), getstring()
151df930be7Sderaadt /
152df930be7Sderaadt / GLOBAL INPUTS: Databuf[]
153df930be7Sderaadt /
154df930be7Sderaadt / GLOBAL OUTPUTS: none
155df930be7Sderaadt /
156df930be7Sderaadt / DESCRIPTION:
157df930be7Sderaadt /	Read a string from player, and scan for a floating point
158df930be7Sderaadt /	number.
159df930be7Sderaadt /	If no valid number is found, return 0.0.
160df930be7Sderaadt /
161db690800Sfn *************************************************************************/
162df930be7Sderaadt 
163df930be7Sderaadt double
infloat(void)164f0d3161eStb infloat(void)
165df930be7Sderaadt {
166df930be7Sderaadt 	double  result;		/* return value */
167df930be7Sderaadt 
168df930be7Sderaadt 	getstring(Databuf, SZ_DATABUF);
169df930be7Sderaadt 	if (sscanf(Databuf, "%lf", &result) < 1)
170df930be7Sderaadt 		/* no valid number entered */
171df930be7Sderaadt 		result = 0.0;
172df930be7Sderaadt 
173df930be7Sderaadt 	return (result);
174df930be7Sderaadt }
175df930be7Sderaadt /**/
176df930be7Sderaadt /************************************************************************
177df930be7Sderaadt /
178df930be7Sderaadt / FUNCTION NAME: inputoption()
179df930be7Sderaadt /
180df930be7Sderaadt / FUNCTION: input an option value from player
181df930be7Sderaadt /
182df930be7Sderaadt / AUTHOR: E. A. Estes, 12/4/85
183df930be7Sderaadt /
184df930be7Sderaadt / ARGUMENTS: none
185df930be7Sderaadt /
186df930be7Sderaadt / RETURN VALUE: none
187df930be7Sderaadt /
188df930be7Sderaadt / MODULES CALLED: floor(), drandom(), getanswer()
189df930be7Sderaadt /
190df930be7Sderaadt / GLOBAL INPUTS: Player
191df930be7Sderaadt /
192df930be7Sderaadt / GLOBAL OUTPUTS: Player
193df930be7Sderaadt /
194df930be7Sderaadt / DESCRIPTION:
195df930be7Sderaadt /	Age increases with every move.
196df930be7Sderaadt /	Refresh screen, and get a single character option from player.
197df930be7Sderaadt /	Return a random value if player's ring has gone bad.
198df930be7Sderaadt /
199db690800Sfn *************************************************************************/
200df930be7Sderaadt 
201c4b20be9Spjanzen int
inputoption(void)202f0d3161eStb inputoption(void)
203df930be7Sderaadt {
204df930be7Sderaadt 	++Player.p_age;		/* increase age */
205df930be7Sderaadt 
206df930be7Sderaadt 	if (Player.p_ring.ring_type != R_SPOILED)
207df930be7Sderaadt 		/* ring ok */
208df930be7Sderaadt 		return (getanswer("T ", TRUE));
209df930be7Sderaadt 	else
210df930be7Sderaadt 		/* bad ring */
211df930be7Sderaadt 	{
212df930be7Sderaadt 		getanswer(" ", TRUE);
213df930be7Sderaadt 		return ((int) ROLL(0.0, 5.0) + '0');
214df930be7Sderaadt 	}
215df930be7Sderaadt }
216df930be7Sderaadt /**/
217df930be7Sderaadt /************************************************************************
218df930be7Sderaadt /
219df930be7Sderaadt / FUNCTION NAME: interrupt()
220df930be7Sderaadt /
221df930be7Sderaadt / FUNCTION: handle interrupt from operator
222df930be7Sderaadt /
223df930be7Sderaadt / AUTHOR: E. A. Estes, 12/4/85
224df930be7Sderaadt /
225df930be7Sderaadt / ARGUMENTS: none
226df930be7Sderaadt /
227df930be7Sderaadt / RETURN VALUE: none
228df930be7Sderaadt /
229df930be7Sderaadt / MODULES CALLED: fork(), exit(), wait(), death(), alarm(), execl(), wmove(),
230c4b20be9Spjanzen /	signal(), getenv(), wclear(), crmode(), clearok(), waddstr(),
231c4b20be9Spjanzen /	cleanup(), wrefresh(), leavegame(), getanswer()
232df930be7Sderaadt /
233df930be7Sderaadt / GLOBAL INPUTS: Player, *stdscr
234df930be7Sderaadt /
235df930be7Sderaadt / GLOBAL OUTPUTS: none
236df930be7Sderaadt /
237df930be7Sderaadt / DESCRIPTION:
238df930be7Sderaadt /	Allow player to quit upon hitting the interrupt key.
239df930be7Sderaadt /	If the player wants to quit while in battle, he/she automatically
240df930be7Sderaadt /	dies.
241df930be7Sderaadt /
242db690800Sfn *************************************************************************/
243df930be7Sderaadt 
244c4b20be9Spjanzen void
interrupt(void)245f0d3161eStb interrupt(void)
246df930be7Sderaadt {
247df930be7Sderaadt 	char    line[81];	/* a place to store data already on screen */
248c4b20be9Spjanzen 	int     loop;		/* counter */
249df930be7Sderaadt 	int     x, y;		/* coordinates on screen */
250df930be7Sderaadt 	int     ch;		/* input */
251df930be7Sderaadt 	unsigned savealarm;	/* to save alarm value */
252df930be7Sderaadt 
253df930be7Sderaadt 	savealarm = alarm(0);	/* turn off any alarms */
254df930be7Sderaadt 
255df930be7Sderaadt 	getyx(stdscr, y, x);	/* save cursor location */
256df930be7Sderaadt 
257c4b20be9Spjanzen 	for (loop = 0; loop < 80; ++loop) {	/* save line on screen */
258df930be7Sderaadt 		move(4, loop);
259df930be7Sderaadt 		line[loop] = inch();
260df930be7Sderaadt 	}
261df930be7Sderaadt 	line[80] = '\0';	/* nul terminate */
262df930be7Sderaadt 
263df930be7Sderaadt 	if (Player.p_status == S_INBATTLE || Player.p_status == S_MONSTER)
264df930be7Sderaadt 		/* in midst of fighting */
265df930be7Sderaadt 	{
266df930be7Sderaadt 		mvaddstr(4, 0, "Quitting now will automatically kill your character.  Still want to ? ");
267df930be7Sderaadt 		ch = getanswer("NY", FALSE);
268df930be7Sderaadt 		if (ch == 'Y')
269df930be7Sderaadt 			death("Bailing out");
270c4b20be9Spjanzen 	} else {
271df930be7Sderaadt 		mvaddstr(4, 0, "Do you really want to quit ? ");
272df930be7Sderaadt 		ch = getanswer("NY", FALSE);
273df930be7Sderaadt 		if (ch == 'Y')
274df930be7Sderaadt 			leavegame();
275df930be7Sderaadt 	}
276df930be7Sderaadt 
277df930be7Sderaadt 	mvaddstr(4, 0, line);	/* restore data on screen */
278df930be7Sderaadt 	move(y, x);		/* restore cursor */
279df930be7Sderaadt 	refresh();
280df930be7Sderaadt 
281df930be7Sderaadt 	alarm(savealarm);	/* restore alarm */
282df930be7Sderaadt }
283df930be7Sderaadt /**/
284df930be7Sderaadt /************************************************************************
285df930be7Sderaadt /
286df930be7Sderaadt / FUNCTION NAME: getanswer()
287df930be7Sderaadt /
288df930be7Sderaadt / FUNCTION: get an answer from operator
289df930be7Sderaadt /
290df930be7Sderaadt / AUTHOR: E. A. Estes, 12/4/85
291df930be7Sderaadt /
292df930be7Sderaadt / ARGUMENTS:
293df930be7Sderaadt /	char *choices - string of (upper case) valid choices
294df930be7Sderaadt /	bool def - set if default answer
295df930be7Sderaadt /
296df930be7Sderaadt / RETURN VALUE: none
297df930be7Sderaadt /
298df930be7Sderaadt / MODULES CALLED: alarm(), wmove(), waddch(), signal(), setjmp(), strchr(),
299df930be7Sderaadt /	_filbuf(), clearok(), toupper(), wrefresh(), mvprintw(), wclrtoeol()
300df930be7Sderaadt /
301df930be7Sderaadt / GLOBAL INPUTS: catchalarm(), Echo, _iob[], _ctype[], *stdscr, Timeout,
302df930be7Sderaadt /	Timeoenv[]
303df930be7Sderaadt /
304df930be7Sderaadt / GLOBAL OUTPUTS: _iob[]
305df930be7Sderaadt /
306df930be7Sderaadt / DESCRIPTION:
307df930be7Sderaadt /	Get a single character answer from operator.
308df930be7Sderaadt /	Timeout waiting for response.  If we timeout, or the
309df930be7Sderaadt /	answer in not in the list of valid choices, print choices,
310df930be7Sderaadt /	and wait again, otherwise return the first character in ths
311df930be7Sderaadt /	list of choices.
312df930be7Sderaadt /	Give up after 3 tries.
313df930be7Sderaadt /
314db690800Sfn *************************************************************************/
315df930be7Sderaadt 
316c4b20be9Spjanzen int
getanswer(char * choices,bool def)317f0d3161eStb getanswer(char *choices, bool def)
318df930be7Sderaadt {
319df930be7Sderaadt 	         int ch;	 /* input */
320fc804817Smillert 	volatile int loop;	 /* counter */
321fc804817Smillert 	volatile int oldx, oldy; /* original coordinates on screen */
322df930be7Sderaadt 
323df930be7Sderaadt 	getyx(stdscr, oldy, oldx);
324df930be7Sderaadt 	alarm(0);		/* make sure alarm is off */
325df930be7Sderaadt 
326c4b20be9Spjanzen 	for (loop = 3; loop; --loop)
327df930be7Sderaadt 		/* try for 3 times */
328df930be7Sderaadt 	{
329df930be7Sderaadt 		if (setjmp(Timeoenv) != 0)
330df930be7Sderaadt 			/* timed out waiting for response */
331df930be7Sderaadt 		{
332df930be7Sderaadt 			if (def || loop <= 1)
333df930be7Sderaadt 				/* return default answer */
334df930be7Sderaadt 				break;
335df930be7Sderaadt 			else
336df930be7Sderaadt 				/* prompt, and try again */
337df930be7Sderaadt 				goto YELL;
338c4b20be9Spjanzen 		} else
339df930be7Sderaadt 			/* wait for response */
340df930be7Sderaadt 		{
341df930be7Sderaadt 			clrtoeol();
342df930be7Sderaadt 			refresh();
343df930be7Sderaadt 			signal(SIGALRM, catchalarm);
344df930be7Sderaadt 			/* set timeout */
345df930be7Sderaadt 			if (Timeout)
346df930be7Sderaadt 				alarm(7);	/* short */
347df930be7Sderaadt 			else
348df930be7Sderaadt 				alarm(600);	/* long */
349df930be7Sderaadt 
350df930be7Sderaadt 			ch = getchar();
351df930be7Sderaadt 
352df930be7Sderaadt 			alarm(0);	/* turn off timeout */
353df930be7Sderaadt 
354c4b20be9Spjanzen 			if (ch < 0) {
355df930be7Sderaadt 				/* caught some signal */
356df930be7Sderaadt 				++loop;
357df930be7Sderaadt 				continue;
358c4b20be9Spjanzen 			} else if (ch == CH_REDRAW) {
359df930be7Sderaadt 				/* redraw screen */
360df930be7Sderaadt 				clearok(stdscr, TRUE);	/* force clear screen */
361df930be7Sderaadt 				++loop;	/* don't count this input */
362df930be7Sderaadt 				continue;
363c4b20be9Spjanzen 			} else if (Echo) {
364df930be7Sderaadt 				addch(ch);	/* echo character */
365df930be7Sderaadt 				refresh();
366df930be7Sderaadt 			}
367df930be7Sderaadt 			if (islower(ch))
368df930be7Sderaadt 				/* convert to upper case */
369df930be7Sderaadt 				ch = toupper(ch);
370df930be7Sderaadt 
371df930be7Sderaadt 			if (def || strchr(choices, ch) != NULL)
372df930be7Sderaadt 				/* valid choice */
373df930be7Sderaadt 				return (ch);
374c4b20be9Spjanzen 			else if (!def && loop > 1) {
375df930be7Sderaadt 				/* bad choice; prompt, and try again */
376df930be7Sderaadt 			YELL:	mvprintw(oldy + 1, 0, "Please choose one of : [%s]\n", choices);
377df930be7Sderaadt 				move(oldy, oldx);
378df930be7Sderaadt 				clrtoeol();
379df930be7Sderaadt 				continue;
380c4b20be9Spjanzen 			} else
381df930be7Sderaadt 				/* return default answer */
382df930be7Sderaadt 				break;
383df930be7Sderaadt 		}
384df930be7Sderaadt 	}
385df930be7Sderaadt 
386df930be7Sderaadt 	return (*choices);
387df930be7Sderaadt }
388df930be7Sderaadt /**/
389df930be7Sderaadt /************************************************************************
390df930be7Sderaadt /
391df930be7Sderaadt / FUNCTION NAME: catchalarm()
392df930be7Sderaadt /
393df930be7Sderaadt / FUNCTION: catch timer when waiting for input
394df930be7Sderaadt /
395df930be7Sderaadt / AUTHOR: E. A. Estes, 12/4/85
396df930be7Sderaadt /
397df930be7Sderaadt / ARGUMENTS: none
398df930be7Sderaadt /
399df930be7Sderaadt / RETURN VALUE: none
400df930be7Sderaadt /
401df930be7Sderaadt / MODULES CALLED: longjmp()
402df930be7Sderaadt /
403df930be7Sderaadt / GLOBAL INPUTS: Timeoenv[]
404df930be7Sderaadt /
405df930be7Sderaadt / GLOBAL OUTPUTS: none
406df930be7Sderaadt /
407df930be7Sderaadt / DESCRIPTION:
408df930be7Sderaadt /	Come here when the alarm expires while waiting for input.
409df930be7Sderaadt /	Simply longjmp() into getanswer().
410df930be7Sderaadt /
411db690800Sfn *************************************************************************/
412df930be7Sderaadt 
413df930be7Sderaadt void
catchalarm(int dummy)414f0d3161eStb catchalarm(int dummy)
415df930be7Sderaadt {
416df930be7Sderaadt 	longjmp(Timeoenv, 1);
417df930be7Sderaadt }
418