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