io.c revision 1.1.1.1 1 /*
2 * io.c - input/output routines for Phantasia
3 */
4
5 #include "include.h"
6
7 /************************************************************************
8 /
9 / FUNCTION NAME: getstring()
10 /
11 / FUNCTION: read a string from operator
12 /
13 / AUTHOR: E. A. Estes, 12/4/85
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 / RETURN VALUE: none
20 /
21 / MODULES CALLED: wmove(), _filbuf(), clearok(), waddstr(), wrefresh(),
22 / wclrtoeol()
23 /
24 / GLOBAL INPUTS: Echo, _iob[], Wizard, *stdscr
25 /
26 / GLOBAL OUTPUTS: _iob[]
27 /
28 / DESCRIPTION:
29 / Read a string from the keyboard.
30 / This routine is specially designed to:
31 /
32 / - strip non-printing characters (unless Wizard)
33 / - echo, if desired
34 / - redraw the screen if CH_REDRAW is entered
35 / - read in only 'mx - 1' characters or less characters
36 / - nul-terminate string, and throw away newline
37 /
38 / 'mx' is assumed to be at least 2.
39 /
40 /************************************************************************/
41
42 getstring(cp, mx)
43 register char *cp;
44 register int mx;
45 {
46 register char *inptr; /* pointer into string for next string */
47 int x, y; /* original x, y coordinates on screen */
48 int ch; /* input */
49
50 getyx(stdscr, y, x); /* get coordinates on screen */
51 inptr = cp;
52 *inptr = '\0'; /* clear string to start */
53 --mx; /* reserve room in string for nul terminator */
54
55 do
56 /* get characters and process */
57 {
58 if (Echo)
59 mvaddstr(y, x, cp); /* print string on screen */
60 clrtoeol(); /* clear any data after string */
61 refresh(); /* update screen */
62
63 ch = getchar(); /* get character */
64
65 switch (ch)
66 {
67 case CH_ERASE: /* back up one character */
68 if (inptr > cp)
69 --inptr;
70 break;
71
72 case CH_KILL: /* back up to original location */
73 inptr = cp;
74 break;
75
76 case CH_NEWLINE: /* terminate string */
77 break;
78
79 case CH_REDRAW: /* redraw screen */
80 clearok(stdscr, TRUE);
81 continue;
82
83 default: /* put data in string */
84 if (ch >= ' ' || Wizard)
85 /* printing char; put in string */
86 *inptr++ = ch;
87 }
88
89 *inptr = '\0'; /* terminate string */
90 }
91 while (ch != CH_NEWLINE && inptr < cp + mx);
92 }
93 /**/
95 /************************************************************************
96 /
97 / FUNCTION NAME: more()
98 /
99 / FUNCTION: pause and prompt player
100 /
101 / AUTHOR: E. A. Estes, 12/4/85
102 /
103 / ARGUMENTS:
104 / int where - line on screen on which to pause
105 /
106 / RETURN VALUE: none
107 /
108 / MODULES CALLED: wmove(), waddstr(), getanswer()
109 /
110 / GLOBAL INPUTS: *stdscr
111 /
112 / GLOBAL OUTPUTS: none
113 /
114 / DESCRIPTION:
115 / Print a message, and wait for a space character.
116 /
117 /************************************************************************/
118
119 more(where)
120 int where;
121 {
122 mvaddstr(where, 0, "-- more --");
123 getanswer(" ", FALSE);
124 }
125 /**/
127 /************************************************************************
128 /
129 / FUNCTION NAME: infloat()
130 /
131 / FUNCTION: input a floating point number from operator
132 /
133 / AUTHOR: E. A. Estes, 12/4/85
134 /
135 / ARGUMENTS: none
136 /
137 / RETURN VALUE: floating point number from operator
138 /
139 / MODULES CALLED: sscanf(), getstring()
140 /
141 / GLOBAL INPUTS: Databuf[]
142 /
143 / GLOBAL OUTPUTS: none
144 /
145 / DESCRIPTION:
146 / Read a string from player, and scan for a floating point
147 / number.
148 / If no valid number is found, return 0.0.
149 /
150 /************************************************************************/
151
152 double
153 infloat()
154 {
155 double result; /* return value */
156
157 getstring(Databuf, SZ_DATABUF);
158 if (sscanf(Databuf, "%lf", &result) < 1)
159 /* no valid number entered */
160 result = 0.0;
161
162 return(result);
163 }
164 /**/
166 /************************************************************************
167 /
168 / FUNCTION NAME: inputoption()
169 /
170 / FUNCTION: input an option value from player
171 /
172 / AUTHOR: E. A. Estes, 12/4/85
173 /
174 / ARGUMENTS: none
175 /
176 / RETURN VALUE: none
177 /
178 / MODULES CALLED: floor(), drandom(), getanswer()
179 /
180 / GLOBAL INPUTS: Player
181 /
182 / GLOBAL OUTPUTS: Player
183 /
184 / DESCRIPTION:
185 / Age increases with every move.
186 / Refresh screen, and get a single character option from player.
187 / Return a random value if player's ring has gone bad.
188 /
189 /************************************************************************/
190
191 inputoption()
192 {
193 ++Player.p_age; /* increase age */
194
195 if (Player.p_ring.ring_type != R_SPOILED)
196 /* ring ok */
197 return(getanswer("T ", TRUE));
198 else
199 /* bad ring */
200 {
201 getanswer(" ", TRUE);
202 return((int) ROLL(0.0, 5.0) + '0');
203 }
204 }
205 /**/
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 register 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 /**/
294 /************************************************************************
295 /
296 / FUNCTION NAME: getanswer()
297 /
298 / FUNCTION: get an answer from operator
299 /
300 / AUTHOR: E. A. Estes, 12/4/85
301 /
302 / ARGUMENTS:
303 / char *choices - string of (upper case) valid choices
304 / bool def - set if default answer
305 /
306 / RETURN VALUE: none
307 /
308 / MODULES CALLED: alarm(), wmove(), waddch(), signal(), setjmp(), strchr(),
309 / _filbuf(), clearok(), toupper(), wrefresh(), mvprintw(), wclrtoeol()
310 /
311 / GLOBAL INPUTS: catchalarm(), Echo, _iob[], _ctype[], *stdscr, Timeout,
312 / Timeoenv[]
313 /
314 / GLOBAL OUTPUTS: _iob[]
315 /
316 / DESCRIPTION:
317 / Get a single character answer from operator.
318 / Timeout waiting for response. If we timeout, or the
319 / answer in not in the list of valid choices, print choices,
320 / and wait again, otherwise return the first character in ths
321 / list of choices.
322 / Give up after 3 tries.
323 /
324 /************************************************************************/
325
326 getanswer(choices, def)
327 char *choices;
328 bool def;
329 {
330 int ch; /* input */
331 int loop; /* counter */
332 int oldx, oldy; /* original coordinates on screen */
333
334 getyx(stdscr, oldy, oldx);
335 alarm(0); /* make sure alarm is off */
336
337 for (loop = 3; loop; --loop)
338 /* try for 3 times */
339 {
340 if (setjmp(Timeoenv) != 0)
341 /* timed out waiting for response */
342 {
343 if (def || loop <= 1)
344 /* return default answer */
345 break;
346 else
347 /* prompt, and try again */
348 goto YELL;
349 }
350 else
351 /* wait for response */
352 {
353 clrtoeol();
354 refresh();
355 #ifdef BSD41
356 sigset(SIGALRM, catchalarm);
357 #else
358 signal(SIGALRM, catchalarm);
359 #endif
360 /* set timeout */
361 if (Timeout)
362 alarm(7); /* short */
363 else
364 alarm(600); /* long */
365
366 ch = getchar();
367
368 alarm(0); /* turn off timeout */
369
370 if (ch < 0)
371 /* caught some signal */
372 {
373 ++loop;
374 continue;
375 }
376 else if (ch == CH_REDRAW)
377 /* redraw screen */
378 {
379 clearok(stdscr, TRUE); /* force clear screen */
380 ++loop; /* don't count this input */
381 continue;
382 }
383 else if (Echo)
384 {
385 addch(ch); /* echo character */
386 refresh();
387 }
388
389 if (islower(ch))
390 /* convert to upper case */
391 ch = toupper(ch);
392
393 if (def || strchr(choices, ch) != NULL)
394 /* valid choice */
395 return(ch);
396 else if (!def && loop > 1)
397 /* bad choice; prompt, and try again */
398 {
399 YELL: mvprintw(oldy + 1, 0, "Please choose one of : [%s]\n", choices);
400 move(oldy, oldx);
401 clrtoeol();
402 continue;
403 }
404 else
405 /* return default answer */
406 break;
407 }
408 }
409
410 return(*choices);
411 }
412 /**/
414 /************************************************************************
415 /
416 / FUNCTION NAME: catchalarm()
417 /
418 / FUNCTION: catch timer when waiting for input
419 /
420 / AUTHOR: E. A. Estes, 12/4/85
421 /
422 / ARGUMENTS: none
423 /
424 / RETURN VALUE: none
425 /
426 / MODULES CALLED: longjmp()
427 /
428 / GLOBAL INPUTS: Timeoenv[]
429 /
430 / GLOBAL OUTPUTS: none
431 /
432 / DESCRIPTION:
433 / Come here when the alarm expires while waiting for input.
434 / Simply longjmp() into getanswer().
435 /
436 /************************************************************************/
437
438 void
439 catchalarm()
440 {
441 longjmp(Timeoenv, 1);
442 }
443