2 * io.c - input/output routines for Phantasia
4 * $FreeBSD: src/games/phantasia/io.c,v 1.6 1999/11/16 02:57:33 billf Exp $
10 /* functions which we need to know about */
12 extern void death(const char *);
13 extern void leavegame(void);
15 extern double drandom(void);
18 int getanswer(const char *, bool);
19 void getstring(char *, int);
21 int inputoption(void);
26 * FUNCTION: read a string from operator
29 * char *cp - pointer to buffer area to fill
30 * int mx - maximum number of characters to put in buffer
32 * GLOBAL INPUTS: Echo, _iob[], Wizard, *stdscr
34 * GLOBAL OUTPUTS: _iob[]
37 * Read a string from the keyboard.
38 * This routine is specially designed to:
40 * - strip non-printing characters (unless Wizard)
42 * - redraw the screen if CH_REDRAW is entered
43 * - read in only 'mx - 1' characters or less characters
44 * - nul-terminate string, and throw away newline
46 * 'mx' is assumed to be at least 2.
50 getstring(char *cp
, int mx
)
52 char *inptr
; /* pointer into string for next string */
53 int x
, y
; /* original x, y coordinates on screen */
56 getyx(stdscr
, y
, x
); /* get coordinates on screen */
58 *inptr
= '\0'; /* clear string to start */
59 --mx
; /* reserve room in string for nul terminator */
62 /* get characters and process */
64 mvaddstr(y
, x
, cp
); /* print string on screen */
65 clrtoeol(); /* clear any data after string */
66 refresh(); /* update screen */
68 ch
= getchar(); /* get character */
71 case CH_ERASE
: /* back up one character */
76 case CH_KILL
: /* back up to original location */
80 case CH_NEWLINE
: /* terminate string */
83 case CH_REDRAW
: /* redraw screen */
84 clearok(stdscr
, TRUE
);
87 default: /* put data in string */
88 if (ch
>= ' ' || Wizard
)
89 /* printing char; put in string */
93 *inptr
= '\0'; /* terminate string */
94 } while (ch
!= CH_NEWLINE
&& inptr
< cp
+ mx
);
98 * FUNCTION: pause and prompt player
101 * int where - line on screen on which to pause
103 * GLOBAL INPUTS: *stdscr
106 * Print a message, and wait for a space character.
112 mvaddstr(where
, 0, "-- more --");
113 getanswer(" ", FALSE
);
117 * FUNCTION: input a floating point number from operator
119 * RETURN VALUE: floating point number from operator
121 * GLOBAL INPUTS: Databuf[]
124 * Read a string from player, and scan for a floating point
126 * If no valid number is found, return 0.0.
132 double result
; /* return value */
134 getstring(Databuf
, SZ_DATABUF
);
135 if (sscanf(Databuf
, "%lf", &result
) < 1)
136 /* no valid number entered */
143 * FUNCTION: input an option value from player
145 * GLOBAL INPUTS: Player
147 * GLOBAL OUTPUTS: Player
150 * Age increases with every move.
151 * Refresh screen, and get a single character option from player.
152 * Return a random value if player's ring has gone bad.
158 ++Player
.p_age
; /* increase age */
160 if (Player
.p_ring
.ring_type
!= R_SPOILED
)
162 return (getanswer("T ", TRUE
));
165 getanswer(" ", TRUE
);
166 return ((int)ROLL(0.0, 5.0) + '0');
171 * FUNCTION: handle interrupt from operator
173 * GLOBAL INPUTS: Player, *stdscr
176 * Allow player to quit upon hitting the interrupt key.
177 * If the player wants to quit while in battle, he/she automatically
184 char line
[81]; /* a place to store data already on screen */
185 int loop
; /* counter */
186 int x
, y
; /* coordinates on screen */
188 unsigned savealarm
; /* to save alarm value */
191 signal(SIGINT
, SIG_IGN
);
194 signal(SIGINT
, SIG_IGN
);
197 savealarm
= alarm(0); /* turn off any alarms */
199 getyx(stdscr
, y
, x
); /* save cursor location */
201 for (loop
= 0; loop
< 80; ++loop
) { /* save line on screen */
205 line
[80] = '\0'; /* nul terminate */
207 if (Player
.p_status
== S_INBATTLE
|| Player
.p_status
== S_MONSTER
) {
208 /* in midst of fighting */
209 mvaddstr(4, 0, "Quitting now will automatically kill your character. Still want to ? ");
210 ch
= getanswer("NY", FALSE
);
212 death("Bailing out");
215 mvaddstr(4, 0, "Do you really want to quit ? ");
216 ch
= getanswer("NY", FALSE
);
222 mvaddstr(4, 0, line
); /* restore data on screen */
223 move(y
, x
); /* restore cursor */
227 signal(SIGINT
, interrupt
);
230 signal(SIGINT
, interrupt
);
233 alarm(savealarm
); /* restore alarm */
237 * FUNCTION: get an answer from operator
240 * char *choices - string of (upper case) valid choices
241 * bool def - set if default answer
243 * GLOBAL INPUTS: catchalarm(), Echo, _iob[], _ctype[], *stdscr, Timeout,
246 * GLOBAL OUTPUTS: _iob[]
249 * Get a single character answer from operator.
250 * Timeout waiting for response. If we timeout, or the
251 * answer in not in the list of valid choices, print choices,
252 * and wait again, otherwise return the first character in ths
254 * Give up after 3 tries.
258 getanswer(const char *choices
, bool def
)
261 volatile int loop
; /* counter */
262 volatile int oldx
, oldy
; /* original coordinates on screen */
264 getyx(stdscr
, oldy
, oldx
);
265 alarm(0); /* make sure alarm is off */
267 for (loop
= 3; loop
; --loop
) {
268 /* try for 3 times */
269 if (setjmp(Timeoenv
) != 0) {
270 /* timed out waiting for response */
271 if (def
|| loop
<= 1)
272 /* return default answer */
275 /* prompt, and try again */
278 /* wait for response */
282 sigset(SIGALRM
, catchalarm
);
284 signal(SIGALRM
, catchalarm
);
288 alarm(7); /* short */
290 alarm(600); /* long */
294 alarm(0); /* turn off timeout */
297 /* caught some signal */
300 } else if (ch
== CH_REDRAW
) {
302 clearok(stdscr
, TRUE
); /* force clear screen */
303 ++loop
; /* don't count this input */
306 addch(ch
); /* echo character */
311 /* convert to upper case */
314 if (def
|| strchr(choices
, ch
) != NULL
)
317 else if (!def
&& loop
> 1) {
318 /* bad choice; prompt, and try again */
319 YELL
: mvprintw(oldy
+ 1, 0,
320 "Please choose one of : [%s]\n", choices
);
325 /* return default answer */
334 * FUNCTION: catch timer when waiting for input
336 * GLOBAL INPUTS: Timeoenv[]
339 * Come here when the alarm expires while waiting for input.
340 * Simply longjmp() into getanswer().
344 catchalarm(__unused
int sig
)
346 longjmp(Timeoenv
, 1);