Initial import from FreeBSD RELENG_4:
[dragonfly.git] / games / phantasia / io.c
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  */
6
7 #include <string.h>
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 getstring(cp, mx)
46 char    *cp;
47 int     mx;
48 {
49 char    *inptr;         /* pointer into string for next string */
50 int     x, y;                   /* original x, y coordinates on screen */
51 int     ch;                     /* input */
52
53     getyx(stdscr, y, x);        /* get coordinates on screen */
54     inptr = cp;
55     *inptr = '\0';              /* clear string to start */
56     --mx;                       /* reserve room in string for nul terminator */
57
58     do
59         /* get characters and process */
60         {
61         if (Echo)
62             mvaddstr(y, x, cp); /* print string on screen */
63         clrtoeol();             /* clear any data after string */
64         refresh();              /* update screen */
65
66         ch = getchar();         /* get character */
67
68         switch (ch)
69             {
70             case CH_ERASE:      /* back up one character */
71                 if (inptr > cp)
72                     --inptr;
73                 break;
74
75             case CH_KILL:       /* back up to original location */
76                 inptr = cp;
77                 break;
78
79             case CH_NEWLINE:    /* terminate string */
80                 break;
81
82             case CH_REDRAW:     /* redraw screen */
83                 clearok(stdscr, TRUE);
84                 continue;
85
86             default:            /* put data in string */
87                 if (ch >= ' ' || Wizard)
88                     /* printing char; put in string */
89                     *inptr++ = ch;
90             }
91
92         *inptr = '\0';          /* terminate string */
93         }
94     while (ch != CH_NEWLINE && inptr < cp + mx);
95 }
96 /*\f*/
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 more(where)
122 int     where;
123 {
124     mvaddstr(where, 0, "-- more --");
125     getanswer(" ", FALSE);
126 }
127 /*\f*/
128 /************************************************************************
129 /
130 / FUNCTION NAME: infloat()
131 /
132 / FUNCTION: input a floating point number from operator
133 /
134 / AUTHOR: E. A. Estes, 12/4/85
135 /
136 / ARGUMENTS: none
137 /
138 / RETURN VALUE: floating point number from operator
139 /
140 / MODULES CALLED: sscanf(), getstring()
141 /
142 / GLOBAL INPUTS: Databuf[]
143 /
144 / GLOBAL OUTPUTS: none
145 /
146 / DESCRIPTION:
147 /       Read a string from player, and scan for a floating point
148 /       number.
149 /       If no valid number is found, return 0.0.
150 /
151 *************************************************************************/
152
153 double
154 infloat()
155 {
156 double  result;         /* return value */
157
158     getstring(Databuf, SZ_DATABUF);
159     if (sscanf(Databuf, "%lf", &result) < 1)
160         /* no valid number entered */
161         result = 0.0;
162
163     return(result);
164 }
165 /*\f*/
166 /************************************************************************
167 /
168 / FUNCTION NAME: inputoption()
169 /
170 / FUNCTION: input an option value from player
171 /
172 / AUTHOR: E. A. Estes, 12/4/85
173 /
174 / ARGUMENTS: none
175 /
176 / RETURN VALUE: none
177 /
178 / MODULES CALLED: floor(), drandom(), getanswer()
179 /
180 / GLOBAL INPUTS: Player
181 /
182 / GLOBAL OUTPUTS: Player
183 /
184 / DESCRIPTION:
185 /       Age increases with every move.
186 /       Refresh screen, and get a single character option from player.
187 /       Return a random value if player's ring has gone bad.
188 /
189 *************************************************************************/
190
191 inputoption()
192 {
193     ++Player.p_age;             /* increase age */
194
195     if (Player.p_ring.ring_type != R_SPOILED)
196         /* ring ok */
197         return(getanswer("T ", TRUE));
198     else
199         /* bad ring */
200         {
201         getanswer(" ", TRUE);
202         return((int) ROLL(0.0, 5.0) + '0');
203         }
204 }
205 /*\f*/
206 /************************************************************************
207 /
208 / FUNCTION NAME: interrupt()
209 /
210 / FUNCTION: handle interrupt from operator
211 /
212 / AUTHOR: E. A. Estes, 12/4/85
213 /
214 / ARGUMENTS: none
215 /
216 / RETURN VALUE: none
217 /
218 / MODULES CALLED: fork(), exit(), wait(), death(), alarm(), execl(), wmove(),
219 /       getgid(), signal(), getenv(), wclear(), setuid(), getuid(), setgid(),
220 /       crmode(), clearok(), waddstr(), cleanup(), wrefresh(), leavegame(),
221 /       getanswer()
222 /
223 / GLOBAL INPUTS: Player, *stdscr
224 /
225 / GLOBAL OUTPUTS: none
226 /
227 / DESCRIPTION:
228 /       Allow player to quit upon hitting the interrupt key.
229 /       If the player wants to quit while in battle, he/she automatically
230 /       dies.
231 /
232 *************************************************************************/
233
234 interrupt()
235 {
236 char    line[81];               /* a place to store data already on screen */
237 int     loop;           /* counter */
238 int     x, y;                   /* coordinates on screen */
239 int     ch;                     /* input */
240 unsigned        savealarm;      /* to save alarm value */
241
242 #ifdef SYS3
243     signal(SIGINT, SIG_IGN);
244 #endif
245 #ifdef SYS5
246     signal(SIGINT, SIG_IGN);
247 #endif
248
249     savealarm = alarm(0);               /* turn off any alarms */
250
251     getyx(stdscr, y, x);                /* save cursor location */
252
253     for (loop = 0; loop < 80; ++loop)   /* save line on screen */
254         {
255         move(4, loop);
256         line[loop] = inch();
257         }
258     line[80] = '\0';                    /* nul terminate */
259
260     if (Player.p_status == S_INBATTLE || Player.p_status == S_MONSTER)
261         /* in midst of fighting */
262         {
263         mvaddstr(4, 0, "Quitting now will automatically kill your character.  Still want to ? ");
264         ch = getanswer("NY", FALSE);
265         if (ch == 'Y')
266             death("Bailing out");
267             /*NOTREACHED*/
268         }
269     else
270         {
271         mvaddstr(4, 0, "Do you really want to quit ? ");
272         ch = getanswer("NY", FALSE);
273         if (ch == 'Y')
274             leavegame();
275             /*NOTREACHED*/
276         }
277
278     mvaddstr(4, 0, line);               /* restore data on screen */
279     move(y, x);                         /* restore cursor */
280     refresh();
281
282 #ifdef SYS3
283     signal(SIGINT, interrupt);
284 #endif
285 #ifdef SYS5
286     signal(SIGINT, interrupt);
287 #endif
288
289     alarm(savealarm);                   /* restore alarm */
290 }
291 /*\f*/
292 /************************************************************************
293 /
294 / FUNCTION NAME: getanswer()
295 /
296 / FUNCTION: get an answer from operator
297 /
298 / AUTHOR: E. A. Estes, 12/4/85
299 /
300 / ARGUMENTS:
301 /       char *choices - string of (upper case) valid choices
302 /       bool def - set if default answer
303 /
304 / RETURN VALUE: none
305 /
306 / MODULES CALLED: alarm(), wmove(), waddch(), signal(), setjmp(), strchr(),
307 /       _filbuf(), clearok(), toupper(), wrefresh(), mvprintw(), wclrtoeol()
308 /
309 / GLOBAL INPUTS: catchalarm(), Echo, _iob[], _ctype[], *stdscr, Timeout,
310 /       Timeoenv[]
311 /
312 / GLOBAL OUTPUTS: _iob[]
313 /
314 / DESCRIPTION:
315 /       Get a single character answer from operator.
316 /       Timeout waiting for response.  If we timeout, or the
317 /       answer in not in the list of valid choices, print choices,
318 /       and wait again, otherwise return the first character in ths
319 /       list of choices.
320 /       Give up after 3 tries.
321 /
322 *************************************************************************/
323
324 getanswer(choices, def)
325 char    *choices;
326 bool    def;
327 {
328 int     ch;                     /* input */
329 int     loop;                   /* counter */
330 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         /* try for 3 times */
337         {
338         if (setjmp(Timeoenv) != 0)
339             /* timed out waiting for response */
340             {
341             if (def || loop <= 1)
342                 /* return default answer */
343                 break;
344             else
345                 /* prompt, and try again */
346                 goto YELL;
347             }
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                 {
371                 ++loop;
372                 continue;
373                 }
374             else if (ch == CH_REDRAW)
375                 /* redraw screen */
376                 {
377                 clearok(stdscr, TRUE);  /* force clear screen */
378                 ++loop;                 /* don't count this input */
379                 continue;
380                 }
381             else if (Echo)
382                 {
383                 addch(ch);              /* echo character */
384                 refresh();
385                 }
386
387             if (islower(ch))
388                 /* convert to upper case */
389                 ch = toupper(ch);
390
391             if (def || strchr(choices, ch) != NULL)
392                 /* valid choice */
393                 return(ch);
394             else if (!def && loop > 1)
395                 /* bad choice; prompt, and try again */
396                 {
397 YELL:           mvprintw(oldy + 1, 0, "Please choose one of : [%s]\n", choices);
398                 move(oldy, oldx);
399                 clrtoeol();
400                 continue;
401                 }
402             else
403                 /* return default answer */
404                 break;
405             }
406         }
407
408     return(*choices);
409 }
410 /*\f*/
411 /************************************************************************
412 /
413 / FUNCTION NAME: catchalarm()
414 /
415 / FUNCTION: catch timer when waiting for input
416 /
417 / AUTHOR: E. A. Estes, 12/4/85
418 /
419 / ARGUMENTS: none
420 /
421 / RETURN VALUE: none
422 /
423 / MODULES CALLED: longjmp()
424 /
425 / GLOBAL INPUTS: Timeoenv[]
426 /
427 / GLOBAL OUTPUTS: none
428 /
429 / DESCRIPTION:
430 /       Come here when the alarm expires while waiting for input.
431 /       Simply longjmp() into getanswer().
432 /
433 *************************************************************************/
434
435 void
436 catchalarm()
437 {
438     longjmp(Timeoenv, 1);
439 }