-W is included in CFLAGS already.
[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.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 /*\f*/
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 /*\f*/
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 /*\f*/
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 /*\f*/
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 /*\f*/
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 /*\f*/
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 }