|
|
1.1 root 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: /**/
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:
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
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:
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: / If SHELL is defined, spawn a shell if the if the question is
229: / answered with a '!'.
230: / We are careful to save the state of the screen, and return it
231: / to its original condition.
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: #ifdef SHELL
243: register char *shell; /* pointer to shell to spawn */
244: int childpid; /* pid of spawned process */
245: #endif
246:
247: #ifdef SYS3
248: signal(SIGINT, SIG_IGN);
249: #endif
250: #ifdef SYS5
251: signal(SIGINT, SIG_IGN);
252: #endif
253:
254: savealarm = alarm(0); /* turn off any alarms */
255:
256: getyx(stdscr, y, x); /* save cursor location */
257:
258: for (loop = 0; loop < 80; ++loop) /* save line on screen */
259: {
260: move(4, loop);
261: line[loop] = inch();
262: }
263: line[80] = '\0'; /* nul terminate */
264:
265: if (Player.p_status == S_INBATTLE || Player.p_status == S_MONSTER)
266: /* in midst of fighting */
267: {
268: mvaddstr(4, 0, "Quitting now will automatically kill your character. Still want to ? ");
269: #ifdef SHELL
270: ch = getanswer("NY!", FALSE);
271: #else
272: ch = getanswer("NY", FALSE);
273: #endif
274: if (ch == 'Y')
275: death("Bailing out");
276: /*NOTREACHED*/
277: }
278: else
279: {
280: #ifdef SHELL
281: mvaddstr(4, 0, "Do you really want to quit [! = Shell] ? ");
282: ch = getanswer("NY!", FALSE);
283: #else
284: mvaddstr(4, 0, "Do you really want to quit ? ");
285: ch = getanswer("NY", FALSE);
286: #endif
287: if (ch == 'Y')
288: leavegame();
289: /*NOTREACHED*/
290: }
291:
292: #ifdef SHELL
293: if (ch == '!')
294: /* shell escape */
295: {
296: if ((shell = getenv("SHELL")) == NULL)
297: /* use default */
298: shell = SHELL;
299:
300: if ((childpid = fork()) == 0)
301: /* in child */
302: {
303: clear();
304: refresh();
305: cleanup(FALSE); /* out of curses, close files */
306:
307: setuid(getuid()); /* make sure we are running with real uid */
308: setgid(getgid()); /* make sure we are running with real gid */
309: execl(shell, shell, "-i", 0);
310: execl(SHELL, SHELL, "-i", 0); /* last resort */
311:
312: exit(0);
313: /*NOTREACHED*/
314: }
315: else
316: /* in parent */
317: {
318: while (wait((int *) NULL) != childpid); /* wait until done */
319: crmode(); /* restore keyboard */
320: clearok(stdscr, TRUE); /* force redraw of screen */
321: }
322: }
323: #endif
324:
325: mvaddstr(4, 0, line); /* restore data on screen */
326: move(y, x); /* restore cursor */
327: refresh();
328:
329: #ifdef SYS3
330: signal(SIGINT, interrupt);
331: #endif
332: #ifdef SYS5
333: signal(SIGINT, interrupt);
334: #endif
335:
336: alarm(savealarm); /* restore alarm */
337: }
338: /**/
339: /************************************************************************
340: /
341: / FUNCTION NAME: getanswer()
342: /
343: / FUNCTION: get an answer from operator
344: /
345: / AUTHOR: E. A. Estes, 12/4/85
346: /
347: / ARGUMENTS:
348: / char *choices - string of (upper case) valid choices
349: / bool def - set if default answer
350: /
351: / RETURN VALUE: none
352: /
353: / MODULES CALLED: alarm(), wmove(), waddch(), signal(), setjmp(), strchr(),
354: / _filbuf(), clearok(), toupper(), wrefresh(), mvprintw(), wclrtoeol()
355: /
356: / GLOBAL INPUTS: catchalarm(), Echo, _iob[], _ctype[], *stdscr, Timeout,
357: / Timeoenv[]
358: /
359: / GLOBAL OUTPUTS: _iob[]
360: /
361: / DESCRIPTION:
362: / Get a single character answer from operator.
363: / Timeout waiting for response. If we timeout, or the
364: / answer in not in the list of valid choices, print choices,
365: / and wait again, otherwise return the first character in ths
366: / list of choices.
367: / Give up after 3 tries.
368: /
369: /************************************************************************/
370:
371: getanswer(choices, def)
372: char *choices;
373: bool def;
374: {
375: int ch; /* input */
376: int loop; /* counter */
377: int oldx, oldy; /* original coordinates on screen */
378:
379: getyx(stdscr, oldy, oldx);
380: alarm(0); /* make sure alarm is off */
381:
382: for (loop = 3; loop; --loop)
383: /* try for 3 times */
384: {
385: if (setjmp(Timeoenv) != 0)
386: /* timed out waiting for response */
387: {
388: if (def || loop <= 1)
389: /* return default answer */
390: break;
391: else
392: /* prompt, and try again */
393: goto YELL;
394: }
395: else
396: /* wait for response */
397: {
398: clrtoeol();
399: refresh();
400: #ifdef BSD41
401: sigset(SIGALRM, catchalarm);
402: #else
403: signal(SIGALRM, catchalarm);
404: #endif
405: /* set timeout */
406: if (Timeout)
407: alarm(7); /* short */
408: else
409: alarm(600); /* long */
410:
411: ch = getchar();
412:
413: alarm(0); /* turn off timeout */
414:
415: if (ch < 0)
416: /* caught some signal */
417: {
418: ++loop;
419: continue;
420: }
421: else if (ch == CH_REDRAW)
422: /* redraw screen */
423: {
424: clearok(stdscr, TRUE); /* force clear screen */
425: ++loop; /* don't count this input */
426: continue;
427: }
428: else if (Echo)
429: {
430: addch(ch); /* echo character */
431: refresh();
432: }
433:
434: if (islower(ch))
435: /* convert to upper case */
436: ch = toupper(ch);
437:
438: if (def || strchr(choices, ch) != NULL)
439: /* valid choice */
440: return(ch);
441: else if (!def && loop > 1)
442: /* bad choice; prompt, and try again */
443: {
444: YELL: mvprintw(oldy + 1, 0, "Please choose one of : [%s]\n", choices);
445: move(oldy, oldx);
446: clrtoeol();
447: continue;
448: }
449: else
450: /* return default answer */
451: break;
452: }
453: }
454:
455: return(*choices);
456: }
457: /**/
458: /************************************************************************
459: /
460: / FUNCTION NAME: catchalarm()
461: /
462: / FUNCTION: catch timer when waiting for input
463: /
464: / AUTHOR: E. A. Estes, 12/4/85
465: /
466: / ARGUMENTS: none
467: /
468: / RETURN VALUE: none
469: /
470: / MODULES CALLED: longjmp()
471: /
472: / GLOBAL INPUTS: Timeoenv[]
473: /
474: / GLOBAL OUTPUTS: none
475: /
476: / DESCRIPTION:
477: / Come here when the alarm expires while waiting for input.
478: / Simply longjmp() into getanswer().
479: /
480: /************************************************************************/
481:
482: catchalarm()
483: {
484: longjmp(Timeoenv, 1);
485: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.