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