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