1*8a56d9bbSmillert /* $OpenBSD: io.c,v 1.10 2021/04/29 01:57:00 millert Exp $ */
2df930be7Sderaadt /* $NetBSD: io.c,v 1.2 1995/03/24 03:58:50 cgd Exp $ */
3df930be7Sderaadt
4df930be7Sderaadt /*
5df930be7Sderaadt * io.c - input/output routines for Phantasia
6df930be7Sderaadt */
7df930be7Sderaadt
8010ae45bSmestre #include <ctype.h>
9010ae45bSmestre #include <curses.h>
10010ae45bSmestre #include <math.h>
11010ae45bSmestre #include <setjmp.h>
12010ae45bSmestre #include <signal.h>
13010ae45bSmestre #include <string.h>
14010ae45bSmestre #include <unistd.h>
15010ae45bSmestre
16010ae45bSmestre #include "macros.h"
17010ae45bSmestre #include "phantdefs.h"
18010ae45bSmestre #include "phantglobs.h"
19010ae45bSmestre
20010ae45bSmestre static jmp_buf Timeoenv; /* used for timing out waiting for input */
21df930be7Sderaadt
22df930be7Sderaadt /************************************************************************
23df930be7Sderaadt /
24df930be7Sderaadt / FUNCTION NAME: getstring()
25df930be7Sderaadt /
26df930be7Sderaadt / FUNCTION: read a string from operator
27df930be7Sderaadt /
28df930be7Sderaadt / AUTHOR: E. A. Estes, 12/4/85
29df930be7Sderaadt /
30df930be7Sderaadt / ARGUMENTS:
31df930be7Sderaadt / char *cp - pointer to buffer area to fill
32df930be7Sderaadt / int mx - maximum number of characters to put in buffer
33df930be7Sderaadt /
34df930be7Sderaadt / RETURN VALUE: none
35df930be7Sderaadt /
36df930be7Sderaadt / MODULES CALLED: wmove(), _filbuf(), clearok(), waddstr(), wrefresh(),
37df930be7Sderaadt / wclrtoeol()
38df930be7Sderaadt /
39df930be7Sderaadt / GLOBAL INPUTS: Echo, _iob[], Wizard, *stdscr
40df930be7Sderaadt /
41df930be7Sderaadt / GLOBAL OUTPUTS: _iob[]
42df930be7Sderaadt /
43df930be7Sderaadt / DESCRIPTION:
44df930be7Sderaadt / Read a string from the keyboard.
45df930be7Sderaadt / This routine is specially designed to:
46df930be7Sderaadt /
47df930be7Sderaadt / - strip non-printing characters (unless Wizard)
48df930be7Sderaadt / - echo, if desired
49df930be7Sderaadt / - redraw the screen if CH_REDRAW is entered
50df930be7Sderaadt / - read in only 'mx - 1' characters or less characters
51df930be7Sderaadt / - nul-terminate string, and throw away newline
52df930be7Sderaadt /
53df930be7Sderaadt / 'mx' is assumed to be at least 2.
54df930be7Sderaadt /
55db690800Sfn *************************************************************************/
56df930be7Sderaadt
57c4b20be9Spjanzen void
getstring(char * cp,int mx)58f0d3161eStb getstring(char *cp, int mx)
59df930be7Sderaadt {
60c4b20be9Spjanzen char *inptr; /* pointer into string for next string */
61df930be7Sderaadt int x, y; /* original x, y coordinates on screen */
62df930be7Sderaadt int ch; /* input */
63df930be7Sderaadt
64df930be7Sderaadt getyx(stdscr, y, x); /* get coordinates on screen */
65df930be7Sderaadt inptr = cp;
66df930be7Sderaadt *inptr = '\0'; /* clear string to start */
67df930be7Sderaadt --mx; /* reserve room in string for nul terminator */
68df930be7Sderaadt
69df930be7Sderaadt do
70df930be7Sderaadt /* get characters and process */
71df930be7Sderaadt {
72df930be7Sderaadt if (Echo)
73df930be7Sderaadt mvaddstr(y, x, cp); /* print string on screen */
74df930be7Sderaadt clrtoeol(); /* clear any data after string */
75df930be7Sderaadt refresh(); /* update screen */
76df930be7Sderaadt
77df930be7Sderaadt ch = getchar(); /* get character */
78df930be7Sderaadt
79c4b20be9Spjanzen switch (ch) {
80df930be7Sderaadt case CH_NEWLINE: /* terminate string */
81f8908df1Sdownsj case CH_RETURN:
82df930be7Sderaadt break;
83df930be7Sderaadt
84df930be7Sderaadt case CH_REDRAW: /* redraw screen */
85df930be7Sderaadt clearok(stdscr, TRUE);
86df930be7Sderaadt continue;
87df930be7Sderaadt
88df930be7Sderaadt default: /* put data in string */
89f8908df1Sdownsj if (ch == Ch_Erase) { /* back up one character */
90f8908df1Sdownsj if (inptr > cp)
91f8908df1Sdownsj --inptr;
92f8908df1Sdownsj break;
93f8908df1Sdownsj } else if (ch == Ch_Kill) { /* back up to original location */
94f8908df1Sdownsj inptr = cp;
95f8908df1Sdownsj break;
96f8908df1Sdownsj } else if (isprint(ch) || Wizard) {
97df930be7Sderaadt /* printing char; put in string */
98df930be7Sderaadt *inptr++ = ch;
99df930be7Sderaadt }
100f8908df1Sdownsj }
101df930be7Sderaadt
102df930be7Sderaadt *inptr = '\0'; /* terminate string */
103df930be7Sderaadt }
104f8908df1Sdownsj while (ch != CH_NEWLINE && ch != CH_RETURN && inptr < cp + mx);
105df930be7Sderaadt }
106df930be7Sderaadt /**/
107df930be7Sderaadt /************************************************************************
108df930be7Sderaadt /
109df930be7Sderaadt / FUNCTION NAME: more()
110df930be7Sderaadt /
111df930be7Sderaadt / FUNCTION: pause and prompt player
112df930be7Sderaadt /
113df930be7Sderaadt / AUTHOR: E. A. Estes, 12/4/85
114df930be7Sderaadt /
115df930be7Sderaadt / ARGUMENTS:
116df930be7Sderaadt / int where - line on screen on which to pause
117df930be7Sderaadt /
118df930be7Sderaadt / RETURN VALUE: none
119df930be7Sderaadt /
120df930be7Sderaadt / MODULES CALLED: wmove(), waddstr(), getanswer()
121df930be7Sderaadt /
122df930be7Sderaadt / GLOBAL INPUTS: *stdscr
123df930be7Sderaadt /
124df930be7Sderaadt / GLOBAL OUTPUTS: none
125df930be7Sderaadt /
126df930be7Sderaadt / DESCRIPTION:
127df930be7Sderaadt / Print a message, and wait for a space character.
128df930be7Sderaadt /
129db690800Sfn *************************************************************************/
130df930be7Sderaadt
131c4b20be9Spjanzen void
more(int where)132f0d3161eStb more(int where)
133df930be7Sderaadt {
134df930be7Sderaadt mvaddstr(where, 0, "-- more --");
135df930be7Sderaadt getanswer(" ", FALSE);
136df930be7Sderaadt }
137df930be7Sderaadt /**/
138df930be7Sderaadt /************************************************************************
139df930be7Sderaadt /
140df930be7Sderaadt / FUNCTION NAME: infloat()
141df930be7Sderaadt /
142df930be7Sderaadt / FUNCTION: input a floating point number from operator
143df930be7Sderaadt /
144df930be7Sderaadt / AUTHOR: E. A. Estes, 12/4/85
145df930be7Sderaadt /
146df930be7Sderaadt / ARGUMENTS: none
147df930be7Sderaadt /
148df930be7Sderaadt / RETURN VALUE: floating point number from operator
149df930be7Sderaadt /
150df930be7Sderaadt / MODULES CALLED: sscanf(), getstring()
151df930be7Sderaadt /
152df930be7Sderaadt / GLOBAL INPUTS: Databuf[]
153df930be7Sderaadt /
154df930be7Sderaadt / GLOBAL OUTPUTS: none
155df930be7Sderaadt /
156df930be7Sderaadt / DESCRIPTION:
157df930be7Sderaadt / Read a string from player, and scan for a floating point
158df930be7Sderaadt / number.
159df930be7Sderaadt / If no valid number is found, return 0.0.
160df930be7Sderaadt /
161db690800Sfn *************************************************************************/
162df930be7Sderaadt
163df930be7Sderaadt double
infloat(void)164f0d3161eStb infloat(void)
165df930be7Sderaadt {
166df930be7Sderaadt double result; /* return value */
167df930be7Sderaadt
168df930be7Sderaadt getstring(Databuf, SZ_DATABUF);
169df930be7Sderaadt if (sscanf(Databuf, "%lf", &result) < 1)
170df930be7Sderaadt /* no valid number entered */
171df930be7Sderaadt result = 0.0;
172df930be7Sderaadt
173df930be7Sderaadt return (result);
174df930be7Sderaadt }
175df930be7Sderaadt /**/
176df930be7Sderaadt /************************************************************************
177df930be7Sderaadt /
178df930be7Sderaadt / FUNCTION NAME: inputoption()
179df930be7Sderaadt /
180df930be7Sderaadt / FUNCTION: input an option value from player
181df930be7Sderaadt /
182df930be7Sderaadt / AUTHOR: E. A. Estes, 12/4/85
183df930be7Sderaadt /
184df930be7Sderaadt / ARGUMENTS: none
185df930be7Sderaadt /
186df930be7Sderaadt / RETURN VALUE: none
187df930be7Sderaadt /
188df930be7Sderaadt / MODULES CALLED: floor(), drandom(), getanswer()
189df930be7Sderaadt /
190df930be7Sderaadt / GLOBAL INPUTS: Player
191df930be7Sderaadt /
192df930be7Sderaadt / GLOBAL OUTPUTS: Player
193df930be7Sderaadt /
194df930be7Sderaadt / DESCRIPTION:
195df930be7Sderaadt / Age increases with every move.
196df930be7Sderaadt / Refresh screen, and get a single character option from player.
197df930be7Sderaadt / Return a random value if player's ring has gone bad.
198df930be7Sderaadt /
199db690800Sfn *************************************************************************/
200df930be7Sderaadt
201c4b20be9Spjanzen int
inputoption(void)202f0d3161eStb inputoption(void)
203df930be7Sderaadt {
204df930be7Sderaadt ++Player.p_age; /* increase age */
205df930be7Sderaadt
206df930be7Sderaadt if (Player.p_ring.ring_type != R_SPOILED)
207df930be7Sderaadt /* ring ok */
208df930be7Sderaadt return (getanswer("T ", TRUE));
209df930be7Sderaadt else
210df930be7Sderaadt /* bad ring */
211df930be7Sderaadt {
212df930be7Sderaadt getanswer(" ", TRUE);
213df930be7Sderaadt return ((int) ROLL(0.0, 5.0) + '0');
214df930be7Sderaadt }
215df930be7Sderaadt }
216df930be7Sderaadt /**/
217df930be7Sderaadt /************************************************************************
218df930be7Sderaadt /
219df930be7Sderaadt / FUNCTION NAME: interrupt()
220df930be7Sderaadt /
221df930be7Sderaadt / FUNCTION: handle interrupt from operator
222df930be7Sderaadt /
223df930be7Sderaadt / AUTHOR: E. A. Estes, 12/4/85
224df930be7Sderaadt /
225df930be7Sderaadt / ARGUMENTS: none
226df930be7Sderaadt /
227df930be7Sderaadt / RETURN VALUE: none
228df930be7Sderaadt /
229df930be7Sderaadt / MODULES CALLED: fork(), exit(), wait(), death(), alarm(), execl(), wmove(),
230c4b20be9Spjanzen / signal(), getenv(), wclear(), crmode(), clearok(), waddstr(),
231c4b20be9Spjanzen / cleanup(), wrefresh(), leavegame(), getanswer()
232df930be7Sderaadt /
233df930be7Sderaadt / GLOBAL INPUTS: Player, *stdscr
234df930be7Sderaadt /
235df930be7Sderaadt / GLOBAL OUTPUTS: none
236df930be7Sderaadt /
237df930be7Sderaadt / DESCRIPTION:
238df930be7Sderaadt / Allow player to quit upon hitting the interrupt key.
239df930be7Sderaadt / If the player wants to quit while in battle, he/she automatically
240df930be7Sderaadt / dies.
241df930be7Sderaadt /
242db690800Sfn *************************************************************************/
243df930be7Sderaadt
244c4b20be9Spjanzen void
interrupt(void)245f0d3161eStb interrupt(void)
246df930be7Sderaadt {
247df930be7Sderaadt char line[81]; /* a place to store data already on screen */
248c4b20be9Spjanzen int loop; /* counter */
249df930be7Sderaadt int x, y; /* coordinates on screen */
250df930be7Sderaadt int ch; /* input */
251df930be7Sderaadt unsigned savealarm; /* to save alarm value */
252df930be7Sderaadt
253df930be7Sderaadt savealarm = alarm(0); /* turn off any alarms */
254df930be7Sderaadt
255df930be7Sderaadt getyx(stdscr, y, x); /* save cursor location */
256df930be7Sderaadt
257c4b20be9Spjanzen for (loop = 0; loop < 80; ++loop) { /* save line on screen */
258df930be7Sderaadt move(4, loop);
259df930be7Sderaadt line[loop] = inch();
260df930be7Sderaadt }
261df930be7Sderaadt line[80] = '\0'; /* nul terminate */
262df930be7Sderaadt
263df930be7Sderaadt if (Player.p_status == S_INBATTLE || Player.p_status == S_MONSTER)
264df930be7Sderaadt /* in midst of fighting */
265df930be7Sderaadt {
266df930be7Sderaadt mvaddstr(4, 0, "Quitting now will automatically kill your character. Still want to ? ");
267df930be7Sderaadt ch = getanswer("NY", FALSE);
268df930be7Sderaadt if (ch == 'Y')
269df930be7Sderaadt death("Bailing out");
270c4b20be9Spjanzen } else {
271df930be7Sderaadt mvaddstr(4, 0, "Do you really want to quit ? ");
272df930be7Sderaadt ch = getanswer("NY", FALSE);
273df930be7Sderaadt if (ch == 'Y')
274df930be7Sderaadt leavegame();
275df930be7Sderaadt }
276df930be7Sderaadt
277df930be7Sderaadt mvaddstr(4, 0, line); /* restore data on screen */
278df930be7Sderaadt move(y, x); /* restore cursor */
279df930be7Sderaadt refresh();
280df930be7Sderaadt
281df930be7Sderaadt alarm(savealarm); /* restore alarm */
282df930be7Sderaadt }
283df930be7Sderaadt /**/
284df930be7Sderaadt /************************************************************************
285df930be7Sderaadt /
286df930be7Sderaadt / FUNCTION NAME: getanswer()
287df930be7Sderaadt /
288df930be7Sderaadt / FUNCTION: get an answer from operator
289df930be7Sderaadt /
290df930be7Sderaadt / AUTHOR: E. A. Estes, 12/4/85
291df930be7Sderaadt /
292df930be7Sderaadt / ARGUMENTS:
293df930be7Sderaadt / char *choices - string of (upper case) valid choices
294df930be7Sderaadt / bool def - set if default answer
295df930be7Sderaadt /
296df930be7Sderaadt / RETURN VALUE: none
297df930be7Sderaadt /
298df930be7Sderaadt / MODULES CALLED: alarm(), wmove(), waddch(), signal(), setjmp(), strchr(),
299df930be7Sderaadt / _filbuf(), clearok(), toupper(), wrefresh(), mvprintw(), wclrtoeol()
300df930be7Sderaadt /
301df930be7Sderaadt / GLOBAL INPUTS: catchalarm(), Echo, _iob[], _ctype[], *stdscr, Timeout,
302df930be7Sderaadt / Timeoenv[]
303df930be7Sderaadt /
304df930be7Sderaadt / GLOBAL OUTPUTS: _iob[]
305df930be7Sderaadt /
306df930be7Sderaadt / DESCRIPTION:
307df930be7Sderaadt / Get a single character answer from operator.
308df930be7Sderaadt / Timeout waiting for response. If we timeout, or the
309df930be7Sderaadt / answer in not in the list of valid choices, print choices,
310df930be7Sderaadt / and wait again, otherwise return the first character in ths
311df930be7Sderaadt / list of choices.
312df930be7Sderaadt / Give up after 3 tries.
313df930be7Sderaadt /
314db690800Sfn *************************************************************************/
315df930be7Sderaadt
316c4b20be9Spjanzen int
getanswer(char * choices,bool def)317f0d3161eStb getanswer(char *choices, bool def)
318df930be7Sderaadt {
319df930be7Sderaadt int ch; /* input */
320fc804817Smillert volatile int loop; /* counter */
321fc804817Smillert volatile int oldx, oldy; /* original coordinates on screen */
322df930be7Sderaadt
323df930be7Sderaadt getyx(stdscr, oldy, oldx);
324df930be7Sderaadt alarm(0); /* make sure alarm is off */
325df930be7Sderaadt
326c4b20be9Spjanzen for (loop = 3; loop; --loop)
327df930be7Sderaadt /* try for 3 times */
328df930be7Sderaadt {
329df930be7Sderaadt if (setjmp(Timeoenv) != 0)
330df930be7Sderaadt /* timed out waiting for response */
331df930be7Sderaadt {
332df930be7Sderaadt if (def || loop <= 1)
333df930be7Sderaadt /* return default answer */
334df930be7Sderaadt break;
335df930be7Sderaadt else
336df930be7Sderaadt /* prompt, and try again */
337df930be7Sderaadt goto YELL;
338c4b20be9Spjanzen } else
339df930be7Sderaadt /* wait for response */
340df930be7Sderaadt {
341df930be7Sderaadt clrtoeol();
342df930be7Sderaadt refresh();
343df930be7Sderaadt signal(SIGALRM, catchalarm);
344df930be7Sderaadt /* set timeout */
345df930be7Sderaadt if (Timeout)
346df930be7Sderaadt alarm(7); /* short */
347df930be7Sderaadt else
348df930be7Sderaadt alarm(600); /* long */
349df930be7Sderaadt
350df930be7Sderaadt ch = getchar();
351df930be7Sderaadt
352df930be7Sderaadt alarm(0); /* turn off timeout */
353df930be7Sderaadt
354c4b20be9Spjanzen if (ch < 0) {
355df930be7Sderaadt /* caught some signal */
356df930be7Sderaadt ++loop;
357df930be7Sderaadt continue;
358c4b20be9Spjanzen } else if (ch == CH_REDRAW) {
359df930be7Sderaadt /* redraw screen */
360df930be7Sderaadt clearok(stdscr, TRUE); /* force clear screen */
361df930be7Sderaadt ++loop; /* don't count this input */
362df930be7Sderaadt continue;
363c4b20be9Spjanzen } else if (Echo) {
364df930be7Sderaadt addch(ch); /* echo character */
365df930be7Sderaadt refresh();
366df930be7Sderaadt }
367df930be7Sderaadt if (islower(ch))
368df930be7Sderaadt /* convert to upper case */
369df930be7Sderaadt ch = toupper(ch);
370df930be7Sderaadt
371df930be7Sderaadt if (def || strchr(choices, ch) != NULL)
372df930be7Sderaadt /* valid choice */
373df930be7Sderaadt return (ch);
374c4b20be9Spjanzen else if (!def && loop > 1) {
375df930be7Sderaadt /* bad choice; prompt, and try again */
376df930be7Sderaadt YELL: mvprintw(oldy + 1, 0, "Please choose one of : [%s]\n", choices);
377df930be7Sderaadt move(oldy, oldx);
378df930be7Sderaadt clrtoeol();
379df930be7Sderaadt continue;
380c4b20be9Spjanzen } else
381df930be7Sderaadt /* return default answer */
382df930be7Sderaadt break;
383df930be7Sderaadt }
384df930be7Sderaadt }
385df930be7Sderaadt
386df930be7Sderaadt return (*choices);
387df930be7Sderaadt }
388df930be7Sderaadt /**/
389df930be7Sderaadt /************************************************************************
390df930be7Sderaadt /
391df930be7Sderaadt / FUNCTION NAME: catchalarm()
392df930be7Sderaadt /
393df930be7Sderaadt / FUNCTION: catch timer when waiting for input
394df930be7Sderaadt /
395df930be7Sderaadt / AUTHOR: E. A. Estes, 12/4/85
396df930be7Sderaadt /
397df930be7Sderaadt / ARGUMENTS: none
398df930be7Sderaadt /
399df930be7Sderaadt / RETURN VALUE: none
400df930be7Sderaadt /
401df930be7Sderaadt / MODULES CALLED: longjmp()
402df930be7Sderaadt /
403df930be7Sderaadt / GLOBAL INPUTS: Timeoenv[]
404df930be7Sderaadt /
405df930be7Sderaadt / GLOBAL OUTPUTS: none
406df930be7Sderaadt /
407df930be7Sderaadt / DESCRIPTION:
408df930be7Sderaadt / Come here when the alarm expires while waiting for input.
409df930be7Sderaadt / Simply longjmp() into getanswer().
410df930be7Sderaadt /
411db690800Sfn *************************************************************************/
412df930be7Sderaadt
413df930be7Sderaadt void
catchalarm(int dummy)414f0d3161eStb catchalarm(int dummy)
415df930be7Sderaadt {
416df930be7Sderaadt longjmp(Timeoenv, 1);
417df930be7Sderaadt }
418