Merge branch 'vendor/LDNS'
[dragonfly.git] / games / phantasia / io.c
CommitLineData
984263bc
MD
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 $
313fa7d1 5 * $DragonFly: src/games/phantasia/io.c,v 1.3 2005/05/31 00:06:26 swildner Exp $
984263bc
MD
6 */
7
8#include <string.h>
9#include "include.h"
10
313fa7d1
SW
11/* functions which we need to know about */
12/* misc.c */
13extern void death(const char *);
14extern void leavegame(void);
15/* phantglobs.c */
16extern double drandom(void);
17
6693db17
SW
18void catchalarm(void);
19int getanswer(const char *, bool);
313fa7d1 20void getstring(char *, int);
313fa7d1
SW
21double infloat(void);
22int inputoption(void);
23void interrupt(void);
6693db17 24void more(int);
313fa7d1 25
6693db17
SW
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 */
984263bc 49
313fa7d1
SW
50void
51getstring(char *cp, int mx)
984263bc 52{
6693db17
SW
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);
984263bc 96}
6693db17
SW
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 */
984263bc 109
313fa7d1
SW
110void
111more(int where)
984263bc 112{
6693db17
SW
113 mvaddstr(where, 0, "-- more --");
114 getanswer(" ", FALSE);
984263bc 115}
6693db17
SW
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 */
984263bc
MD
129
130double
313fa7d1 131infloat(void)
984263bc 132{
6693db17 133 double result; /* return value */
984263bc 134
6693db17
SW
135 getstring(Databuf, SZ_DATABUF);
136 if (sscanf(Databuf, "%lf", &result) < 1)
137 /* no valid number entered */
138 result = 0.0;
984263bc 139
6693db17 140 return (result);
984263bc 141}
6693db17
SW
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 */
984263bc 155
313fa7d1
SW
156int
157inputoption(void)
984263bc 158{
6693db17
SW
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');
984263bc
MD
168 }
169}
6693db17
SW
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 */
984263bc 181
313fa7d1
SW
182void
183interrupt(void)
984263bc 184{
6693db17
SW
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 */
984263bc
MD
190
191#ifdef SYS3
6693db17 192 signal(SIGINT, SIG_IGN);
984263bc
MD
193#endif
194#ifdef SYS5
6693db17 195 signal(SIGINT, SIG_IGN);
984263bc
MD
196#endif
197
6693db17 198 savealarm = alarm(0); /* turn off any alarms */
984263bc 199
6693db17 200 getyx(stdscr, y, x); /* save cursor location */
984263bc 201
6693db17
SW
202 for (loop = 0; loop < 80; ++loop) { /* save line on screen */
203 move(4, loop);
204 line[loop] = inch();
984263bc 205 }
6693db17
SW
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 */
984263bc
MD
221 }
222
6693db17
SW
223 mvaddstr(4, 0, line); /* restore data on screen */
224 move(y, x); /* restore cursor */
225 refresh();
984263bc
MD
226
227#ifdef SYS3
6693db17 228 signal(SIGINT, interrupt);
984263bc
MD
229#endif
230#ifdef SYS5
6693db17 231 signal(SIGINT, interrupt);
984263bc
MD
232#endif
233
6693db17 234 alarm(savealarm); /* restore alarm */
984263bc 235}
6693db17
SW
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 */
984263bc 257
313fa7d1
SW
258int
259getanswer(const char *choices, bool def)
984263bc 260{
6693db17
SW
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();
984263bc 282#ifdef BSD41
6693db17 283 sigset(SIGALRM, catchalarm);
984263bc 284#else
6693db17 285 signal(SIGALRM, (sig_t)catchalarm);
984263bc 286#endif
6693db17
SW
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 */
320YELL: 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;
984263bc 328 }
984263bc
MD
329 }
330
6693db17 331 return (*choices);
984263bc 332}
6693db17
SW
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 */
984263bc
MD
343
344void
313fa7d1 345catchalarm(void)
984263bc 346{
6693db17 347 longjmp(Timeoenv, 1);
984263bc 348}