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
getstring(cp,mx)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 /**/
94 /************************************************************************
95 /
96 / FUNCTION NAME: more()
97 /
98 / FUNCTION: pause and prompt player
99 /
100 / AUTHOR: E. A. Estes, 12/4/85
101 /
102 / ARGUMENTS:
103 / int where - line on screen on which to pause
104 /
105 / RETURN VALUE: none
106 /
107 / MODULES CALLED: wmove(), waddstr(), getanswer()
108 /
109 / GLOBAL INPUTS: *stdscr
110 /
111 / GLOBAL OUTPUTS: none
112 /
113 / DESCRIPTION:
114 / Print a message, and wait for a space character.
115 /
116 /************************************************************************/
117
more(where)118 more(where)
119 int where;
120 {
121 mvaddstr(where, 0, "-- more --");
122 getanswer(" ", FALSE);
123 }
124 /**/
125 /************************************************************************
126 /
127 / FUNCTION NAME: infloat()
128 /
129 / FUNCTION: input a floating point number from operator
130 /
131 / AUTHOR: E. A. Estes, 12/4/85
132 /
133 / ARGUMENTS: none
134 /
135 / RETURN VALUE: floating point number from operator
136 /
137 / MODULES CALLED: sscanf(), getstring()
138 /
139 / GLOBAL INPUTS: Databuf[]
140 /
141 / GLOBAL OUTPUTS: none
142 /
143 / DESCRIPTION:
144 / Read a string from player, and scan for a floating point
145 / number.
146 / If no valid number is found, return 0.0.
147 /
148 /************************************************************************/
149
150 double
infloat()151 infloat()
152 {
153 double result; /* return value */
154
155 getstring(Databuf, SZ_DATABUF);
156 if (sscanf(Databuf, "%lf", &result) < 1)
157 /* no valid number entered */
158 result = 0.0;
159
160 return(result);
161 }
162 /**/
163 /************************************************************************
164 /
165 / FUNCTION NAME: inputoption()
166 /
167 / FUNCTION: input an option value from player
168 /
169 / AUTHOR: E. A. Estes, 12/4/85
170 /
171 / ARGUMENTS: none
172 /
173 / RETURN VALUE: none
174 /
175 / MODULES CALLED: floor(), drandom(), getanswer()
176 /
177 / GLOBAL INPUTS: Player
178 /
179 / GLOBAL OUTPUTS: Player
180 /
181 / DESCRIPTION:
182 / Age increases with every move.
183 / Refresh screen, and get a single character option from player.
184 / Return a random value if player's ring has gone bad.
185 /
186 /************************************************************************/
187
inputoption()188 inputoption()
189 {
190 ++Player.p_age; /* increase age */
191
192 if (Player.p_ring.ring_type != R_SPOILED)
193 /* ring ok */
194 return(getanswer("T ", TRUE));
195 else
196 /* bad ring */
197 {
198 getanswer(" ", TRUE);
199 return((int) ROLL(0.0, 5.0) + '0');
200 }
201 }
202 /**/
203 /************************************************************************
204 /
205 / FUNCTION NAME: interrupt()
206 /
207 / FUNCTION: handle interrupt from operator
208 /
209 / AUTHOR: E. A. Estes, 12/4/85
210 /
211 / ARGUMENTS: none
212 /
213 / RETURN VALUE: none
214 /
215 / MODULES CALLED: fork(), exit(), wait(), death(), alarm(), execl(), wmove(),
216 / getgid(), signal(), getenv(), wclear(), setuid(), getuid(), setgid(),
217 / crmode(), clearok(), waddstr(), cleanup(), wrefresh(), leavegame(),
218 / getanswer()
219 /
220 / GLOBAL INPUTS: Player, *stdscr
221 /
222 / GLOBAL OUTPUTS: none
223 /
224 / DESCRIPTION:
225 / Allow player to quit upon hitting the interrupt key.
226 / If the player wants to quit while in battle, he/she automatically
227 / dies.
228 /
229 /************************************************************************/
230
interrupt()231 interrupt()
232 {
233 char line[81]; /* a place to store data already on screen */
234 register int loop; /* counter */
235 int x, y; /* coordinates on screen */
236 int ch; /* input */
237 unsigned savealarm; /* to save alarm value */
238
239 #ifdef SYS3
240 signal(SIGINT, SIG_IGN);
241 #endif
242 #ifdef SYS5
243 signal(SIGINT, SIG_IGN);
244 #endif
245
246 savealarm = alarm(0); /* turn off any alarms */
247
248 getyx(stdscr, y, x); /* save cursor location */
249
250 for (loop = 0; loop < 80; ++loop) /* save line on screen */
251 {
252 move(4, loop);
253 line[loop] = inch();
254 }
255 line[80] = '\0'; /* nul terminate */
256
257 if (Player.p_status == S_INBATTLE || Player.p_status == S_MONSTER)
258 /* in midst of fighting */
259 {
260 mvaddstr(4, 0, "Quitting now will automatically kill your character. Still want to ? ");
261 ch = getanswer("NY", FALSE);
262 if (ch == 'Y')
263 death("Bailing out");
264 /*NOTREACHED*/
265 }
266 else
267 {
268 mvaddstr(4, 0, "Do you really want to quit ? ");
269 ch = getanswer("NY", FALSE);
270 if (ch == 'Y')
271 leavegame();
272 /*NOTREACHED*/
273 }
274
275 mvaddstr(4, 0, line); /* restore data on screen */
276 move(y, x); /* restore cursor */
277 refresh();
278
279 #ifdef SYS3
280 signal(SIGINT, interrupt);
281 #endif
282 #ifdef SYS5
283 signal(SIGINT, interrupt);
284 #endif
285
286 alarm(savealarm); /* restore alarm */
287 }
288 /**/
289 /************************************************************************
290 /
291 / FUNCTION NAME: getanswer()
292 /
293 / FUNCTION: get an answer from operator
294 /
295 / AUTHOR: E. A. Estes, 12/4/85
296 /
297 / ARGUMENTS:
298 / char *choices - string of (upper case) valid choices
299 / bool def - set if default answer
300 /
301 / RETURN VALUE: none
302 /
303 / MODULES CALLED: alarm(), wmove(), waddch(), signal(), setjmp(), strchr(),
304 / _filbuf(), clearok(), toupper(), wrefresh(), mvprintw(), wclrtoeol()
305 /
306 / GLOBAL INPUTS: catchalarm(), Echo, _iob[], _ctype[], *stdscr, Timeout,
307 / Timeoenv[]
308 /
309 / GLOBAL OUTPUTS: _iob[]
310 /
311 / DESCRIPTION:
312 / Get a single character answer from operator.
313 / Timeout waiting for response. If we timeout, or the
314 / answer in not in the list of valid choices, print choices,
315 / and wait again, otherwise return the first character in ths
316 / list of choices.
317 / Give up after 3 tries.
318 /
319 /************************************************************************/
320
getanswer(choices,def)321 getanswer(choices, def)
322 char *choices;
323 bool def;
324 {
325 int ch; /* input */
326 int loop; /* counter */
327 int oldx, oldy; /* original coordinates on screen */
328
329 getyx(stdscr, oldy, oldx);
330 alarm(0); /* make sure alarm is off */
331
332 for (loop = 3; loop; --loop)
333 /* try for 3 times */
334 {
335 if (setjmp(Timeoenv) != 0)
336 /* timed out waiting for response */
337 {
338 if (def || loop <= 1)
339 /* return default answer */
340 break;
341 else
342 /* prompt, and try again */
343 goto YELL;
344 }
345 else
346 /* wait for response */
347 {
348 clrtoeol();
349 refresh();
350 #ifdef BSD41
351 sigset(SIGALRM, catchalarm);
352 #else
353 signal(SIGALRM, catchalarm);
354 #endif
355 /* set timeout */
356 if (Timeout)
357 alarm(7); /* short */
358 else
359 alarm(600); /* long */
360
361 ch = getchar();
362
363 alarm(0); /* turn off timeout */
364
365 if (ch < 0)
366 /* caught some signal */
367 {
368 ++loop;
369 continue;
370 }
371 else if (ch == CH_REDRAW)
372 /* redraw screen */
373 {
374 clearok(stdscr, TRUE); /* force clear screen */
375 ++loop; /* don't count this input */
376 continue;
377 }
378 else if (Echo)
379 {
380 addch(ch); /* echo character */
381 refresh();
382 }
383
384 if (islower(ch))
385 /* convert to upper case */
386 ch = toupper(ch);
387
388 if (def || strchr(choices, ch) != NULL)
389 /* valid choice */
390 return(ch);
391 else if (!def && loop > 1)
392 /* bad choice; prompt, and try again */
393 {
394 YELL: mvprintw(oldy + 1, 0, "Please choose one of : [%s]\n", choices);
395 move(oldy, oldx);
396 clrtoeol();
397 continue;
398 }
399 else
400 /* return default answer */
401 break;
402 }
403 }
404
405 return(*choices);
406 }
407 /**/
408 /************************************************************************
409 /
410 / FUNCTION NAME: catchalarm()
411 /
412 / FUNCTION: catch timer when waiting for input
413 /
414 / AUTHOR: E. A. Estes, 12/4/85
415 /
416 / ARGUMENTS: none
417 /
418 / RETURN VALUE: none
419 /
420 / MODULES CALLED: longjmp()
421 /
422 / GLOBAL INPUTS: Timeoenv[]
423 /
424 / GLOBAL OUTPUTS: none
425 /
426 / DESCRIPTION:
427 / Come here when the alarm expires while waiting for input.
428 / Simply longjmp() into getanswer().
429 /
430 /************************************************************************/
431
432 void
catchalarm()433 catchalarm()
434 {
435 longjmp(Timeoenv, 1);
436 }
437