xref: /dragonfly/games/phantasia/io.c (revision 1de703da)
1 /*
2  * io.c - input/output routines for Phantasia
3  *
4  * $FreeBSD: src/games/phantasia/io.c,v 1.6 1999/11/16 02:57:33 billf Exp $
5  * $DragonFly: src/games/phantasia/io.c,v 1.2 2003/06/17 04:25:24 dillon Exp $
6  */
7 
8 #include <string.h>
9 #include "include.h"
10 
11 /************************************************************************
12 /
13 / FUNCTION NAME: getstring()
14 /
15 / FUNCTION: read a string from operator
16 /
17 / AUTHOR: E. A. Estes, 12/4/85
18 /
19 / ARGUMENTS:
20 /	char *cp - pointer to buffer area to fill
21 /	int mx - maximum number of characters to put in buffer
22 /
23 / RETURN VALUE: none
24 /
25 / MODULES CALLED: wmove(), _filbuf(), clearok(), waddstr(), wrefresh(),
26 /	wclrtoeol()
27 /
28 / GLOBAL INPUTS: Echo, _iob[], Wizard, *stdscr
29 /
30 / GLOBAL OUTPUTS: _iob[]
31 /
32 / DESCRIPTION:
33 /	Read a string from the keyboard.
34 /	This routine is specially designed to:
35 /
36 /	    - strip non-printing characters (unless Wizard)
37 /	    - echo, if desired
38 /	    - redraw the screen if CH_REDRAW is entered
39 /	    - read in only 'mx - 1' characters or less characters
40 /	    - nul-terminate string, and throw away newline
41 /
42 /	'mx' is assumed to be at least 2.
43 /
44 *************************************************************************/
45 
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 	    {
71 	    case CH_ERASE:	/* back up one character */
72 		if (inptr > cp)
73 		    --inptr;
74 		break;
75 
76 	    case CH_KILL:	/* back up to original location */
77 		inptr = cp;
78 		break;
79 
80 	    case CH_NEWLINE:	/* terminate string */
81 		break;
82 
83 	    case CH_REDRAW:	/* redraw screen */
84 		clearok(stdscr, TRUE);
85 		continue;
86 
87 	    default:		/* put data in string */
88 		if (ch >= ' ' || Wizard)
89 		    /* printing char; put in string */
90 		    *inptr++ = ch;
91 	    }
92 
93 	*inptr = '\0';		/* terminate string */
94 	}
95     while (ch != CH_NEWLINE && inptr < cp + mx);
96 }
97 /**/
98 /************************************************************************
99 /
100 / FUNCTION NAME: more()
101 /
102 / FUNCTION: pause and prompt player
103 /
104 / AUTHOR: E. A. Estes, 12/4/85
105 /
106 / ARGUMENTS:
107 /	int where - line on screen on which to pause
108 /
109 / RETURN VALUE: none
110 /
111 / MODULES CALLED: wmove(), waddstr(), getanswer()
112 /
113 / GLOBAL INPUTS: *stdscr
114 /
115 / GLOBAL OUTPUTS: none
116 /
117 / DESCRIPTION:
118 /	Print a message, and wait for a space character.
119 /
120 *************************************************************************/
121 
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 inputoption()
193 {
194     ++Player.p_age;		/* increase age */
195 
196     if (Player.p_ring.ring_type != R_SPOILED)
197 	/* ring ok */
198 	return(getanswer("T ", TRUE));
199     else
200 	/* bad ring */
201 	{
202 	getanswer(" ", TRUE);
203 	return((int) ROLL(0.0, 5.0) + '0');
204 	}
205 }
206 /**/
207 /************************************************************************
208 /
209 / FUNCTION NAME: interrupt()
210 /
211 / FUNCTION: handle interrupt from operator
212 /
213 / AUTHOR: E. A. Estes, 12/4/85
214 /
215 / ARGUMENTS: none
216 /
217 / RETURN VALUE: none
218 /
219 / MODULES CALLED: fork(), exit(), wait(), death(), alarm(), execl(), wmove(),
220 /	getgid(), signal(), getenv(), wclear(), setuid(), getuid(), setgid(),
221 /	crmode(), clearok(), waddstr(), cleanup(), wrefresh(), leavegame(),
222 /	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 interrupt()
236 {
237 char	line[81];		/* a place to store data already on screen */
238 int	loop;		/* counter */
239 int	x, y;			/* coordinates on screen */
240 int	ch;			/* input */
241 unsigned	savealarm;	/* to save alarm value */
242 
243 #ifdef SYS3
244     signal(SIGINT, SIG_IGN);
245 #endif
246 #ifdef SYS5
247     signal(SIGINT, SIG_IGN);
248 #endif
249 
250     savealarm = alarm(0);		/* turn off any alarms */
251 
252     getyx(stdscr, y, x);		/* save cursor location */
253 
254     for (loop = 0; loop < 80; ++loop)	/* save line on screen */
255 	{
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 	}
270     else
271 	{
272 	mvaddstr(4, 0, "Do you really want to quit ? ");
273 	ch = getanswer("NY", FALSE);
274 	if (ch == 'Y')
275 	    leavegame();
276 	    /*NOTREACHED*/
277 	}
278 
279     mvaddstr(4, 0, line); 		/* restore data on screen */
280     move(y, x);				/* restore cursor */
281     refresh();
282 
283 #ifdef SYS3
284     signal(SIGINT, interrupt);
285 #endif
286 #ifdef SYS5
287     signal(SIGINT, interrupt);
288 #endif
289 
290     alarm(savealarm);			/* restore alarm */
291 }
292 /**/
293 /************************************************************************
294 /
295 / FUNCTION NAME: getanswer()
296 /
297 / FUNCTION: get an answer from operator
298 /
299 / AUTHOR: E. A. Estes, 12/4/85
300 /
301 / ARGUMENTS:
302 /	char *choices - string of (upper case) valid choices
303 /	bool def - set if default answer
304 /
305 / RETURN VALUE: none
306 /
307 / MODULES CALLED: alarm(), wmove(), waddch(), signal(), setjmp(), strchr(),
308 /	_filbuf(), clearok(), toupper(), wrefresh(), mvprintw(), wclrtoeol()
309 /
310 / GLOBAL INPUTS: catchalarm(), Echo, _iob[], _ctype[], *stdscr, Timeout,
311 /	Timeoenv[]
312 /
313 / GLOBAL OUTPUTS: _iob[]
314 /
315 / DESCRIPTION:
316 /	Get a single character answer from operator.
317 /	Timeout waiting for response.  If we timeout, or the
318 /	answer in not in the list of valid choices, print choices,
319 /	and wait again, otherwise return the first character in ths
320 /	list of choices.
321 /	Give up after 3 tries.
322 /
323 *************************************************************************/
324 
325 getanswer(choices, def)
326 char	*choices;
327 bool	def;
328 {
329 int	ch;			/* input */
330 int	loop;			/* counter */
331 int	oldx, oldy;		/* original coordinates on screen */
332 
333     getyx(stdscr, oldy, oldx);
334     alarm(0);				/* make sure alarm is off */
335 
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 	    }
349 	else
350 	    /* wait for response */
351 	    {
352 	    clrtoeol();
353 	    refresh();
354 #ifdef BSD41
355 	    sigset(SIGALRM, catchalarm);
356 #else
357 	    signal(SIGALRM, catchalarm);
358 #endif
359 	    /* set timeout */
360 	    if (Timeout)
361 		alarm(7);		/* short */
362 	    else
363 		alarm(600);		/* long */
364 
365 	    ch = getchar();
366 
367 	    alarm(0);			/* turn off timeout */
368 
369 	    if (ch < 0)
370 		/* caught some signal */
371 		{
372 		++loop;
373 		continue;
374 		}
375 	    else if (ch == CH_REDRAW)
376 		/* redraw screen */
377 		{
378 		clearok(stdscr, TRUE);	/* force clear screen */
379 		++loop;			/* don't count this input */
380 		continue;
381 		}
382 	    else if (Echo)
383 		{
384 		addch(ch);		/* echo character */
385 		refresh();
386 		}
387 
388 	    if (islower(ch))
389 		/* convert to upper case */
390 		ch = toupper(ch);
391 
392 	    if (def || strchr(choices, ch) != NULL)
393 		/* valid choice */
394 		return(ch);
395 	    else if (!def && loop > 1)
396 		/* bad choice; prompt, and try again */
397 		{
398 YELL:		mvprintw(oldy + 1, 0, "Please choose one of : [%s]\n", choices);
399 		move(oldy, oldx);
400 		clrtoeol();
401 		continue;
402 		}
403 	    else
404 		/* return default answer */
405 		break;
406 	    }
407 	}
408 
409     return(*choices);
410 }
411 /**/
412 /************************************************************************
413 /
414 / FUNCTION NAME: catchalarm()
415 /
416 / FUNCTION: catch timer when waiting for input
417 /
418 / AUTHOR: E. A. Estes, 12/4/85
419 /
420 / ARGUMENTS: none
421 /
422 / RETURN VALUE: none
423 /
424 / MODULES CALLED: longjmp()
425 /
426 / GLOBAL INPUTS: Timeoenv[]
427 /
428 / GLOBAL OUTPUTS: none
429 /
430 / DESCRIPTION:
431 /	Come here when the alarm expires while waiting for input.
432 /	Simply longjmp() into getanswer().
433 /
434 *************************************************************************/
435 
436 void
437 catchalarm()
438 {
439     longjmp(Timeoenv, 1);
440 }
441