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