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