Commit | Line | Data |
---|---|---|
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 | 10 | static 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 |
36 | void |
37 | getstring(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 |
96 | void |
97 | more(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 | |
116 | double | |
313fa7d1 | 117 | infloat(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 |
142 | int |
143 | inputoption(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 |
168 | void |
169 | interrupt(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 |
244 | int |
245 | getanswer(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 */ | |
306 | YELL: 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 | 330 | static void |
a8718c14 | 331 | catchalarm(__unused int sig) |
984263bc | 332 | { |
6693db17 | 333 | longjmp(Timeoenv, 1); |
984263bc | 334 | } |