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