Update Andrew Plotkin's unit tests
[projects/chimara/chimara.git] / interpreters / frotz / input.c
1 /* input.c - High level input functions
2  *      Copyright (c) 1995-1997 Stefan Jokisch
3  *
4  * This file is part of Frotz.
5  *
6  * Frotz is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * Frotz is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "frotz.h"
22
23 extern int save_undo (void);
24
25 extern zchar stream_read_key (zword, zword, bool);
26 extern zchar stream_read_input (int, zchar *, zword, zword, bool, bool);
27
28 extern void tokenise_line (zword, zword, zword, bool);
29 zchar unicode_tolower (zchar);
30
31 /*
32  * is_terminator
33  *
34  * Check if the given key is an input terminator.
35  *
36  */
37
38 bool is_terminator (zchar key)
39 {
40
41     if (key == ZC_TIME_OUT)
42         return TRUE;
43     if (key == ZC_RETURN)
44         return TRUE;
45     if (key >= ZC_HKEY_MIN && key <= ZC_HKEY_MAX)
46         return TRUE;
47
48     if (h_terminating_keys != 0)
49
50         if (key >= ZC_ARROW_MIN && key <= ZC_MENU_CLICK) {
51
52             zword addr = h_terminating_keys;
53             zbyte c;
54
55             do {
56                 LOW_BYTE (addr, c)
57                 if (c == 255 || key == translate_from_zscii (c))
58                     return TRUE;
59                 addr++;
60             } while (c != 0);
61
62         }
63
64     return FALSE;
65
66 }/* is_terminator */
67
68 /*
69  * z_make_menu, add or remove a menu and branch if successful.
70  *
71  *      zargs[0] = number of menu
72  *      zargs[1] = table of menu entries or 0 to remove menu
73  *
74  */
75
76 void z_make_menu (void)
77 {
78
79     /* This opcode was only used for the Macintosh version of Journey.
80        It controls menus with numbers greater than 2 (menus 0, 1 and 2
81        are system menus). */
82
83     branch (FALSE);
84
85 }/* z_make_menu */
86
87 /*
88  * read_yes_or_no
89  *
90  * Ask the user a question; return true if the answer is yes.
91  *
92  */
93
94 bool read_yes_or_no (const char *s)
95 {
96     zchar key;
97
98     print_string (s);
99     print_string ("? (y/n) >");
100
101     key = stream_read_key (0, 0, FALSE);
102
103     if (key == 'y' || key == 'Y') {
104         print_string ("y\n");
105         return TRUE;
106     } else {
107         print_string ("n\n");
108         return FALSE;
109     }
110
111 }/* read_yes_or_no */
112
113 /*
114  * read_string
115  *
116  * Read a string from the current input stream.
117  *
118  */
119
120 void read_string (int max, zchar *buffer)
121 {
122     zchar key;
123
124     buffer[0] = 0;
125
126     do {
127
128         key = stream_read_input (max, buffer, 0, 0, FALSE, FALSE);
129
130     } while (key != ZC_RETURN);
131
132 }/* read_string */
133
134 /*
135  * read_number
136  *
137  * Ask the user to type in a number and return it.
138  *
139  */
140
141 int read_number (void)
142 {
143     zchar buffer[6];
144     int value = 0;
145     int i;
146
147     read_string (5, buffer);
148
149     for (i = 0; buffer[i] != 0; i++)
150         if (buffer[i] >= '0' && buffer[i] <= '9')
151             value = 10 * value + buffer[i] - '0';
152
153     return value;
154
155 }/* read_number */
156
157 /*
158  * z_read, read a line of input and (in V5+) store the terminating key.
159  *
160  *      zargs[0] = address of text buffer
161  *      zargs[1] = address of token buffer
162  *      zargs[2] = timeout in tenths of a second (optional)
163  *      zargs[3] = packed address of routine to be called on timeout
164  *
165  */
166
167 void z_read (void)
168 {
169     zchar buffer[INPUT_BUFFER_SIZE];
170     zword addr;
171     zchar key;
172     zbyte max, size;
173     zbyte c;
174     int i;
175
176     /* Supply default arguments */
177
178     if (zargc < 3)
179         zargs[2] = 0;
180
181     /* Get maximum input size */
182
183     addr = zargs[0];
184
185     LOW_BYTE (addr, max)
186
187     if (h_version <= V4)
188         max--;
189
190     if (max >= INPUT_BUFFER_SIZE)
191         max = INPUT_BUFFER_SIZE - 1;
192
193     /* Get initial input size */
194
195     if (h_version >= V5) {
196         addr++;
197         LOW_BYTE (addr, size)
198     } else size = 0;
199
200     /* Copy initial input to local buffer */
201
202     for (i = 0; i < size; i++) {
203         addr++;
204         LOW_BYTE (addr, c)
205         buffer[i] = translate_from_zscii (c);
206     }
207
208     buffer[i] = 0;
209
210     /* Draw status line for V1 to V3 games */
211
212     if (h_version <= V3)
213         z_show_status ();
214
215     /* Read input from current input stream */
216
217     key = stream_read_input (
218         max, buffer,            /* buffer and size */
219         zargs[2],               /* timeout value   */
220         zargs[3],               /* timeout routine */
221         FALSE,                  /* enable hot keys */
222         h_version == V6);       /* no script in V6 */
223
224     if (key == ZC_BAD)
225         return;
226
227     /* Perform save_undo for V1 to V4 games */
228
229     if (h_version <= V4)
230         save_undo ();
231
232     /* Copy local buffer back to dynamic memory */
233
234     for (i = 0; buffer[i] != 0; i++) {
235
236         if (key == ZC_RETURN) {
237
238                 buffer[i] = unicode_tolower (buffer[i]);
239
240         }
241
242         storeb ((zword) (zargs[0] + ((h_version <= V4) ? 1 : 2) + i), translate_to_zscii (buffer[i]));
243
244     }
245
246     /* Add null character (V1-V4) or write input length into 2nd byte */
247
248     if (h_version <= V4)
249         storeb ((zword) (zargs[0] + 1 + i), 0);
250     else
251         storeb ((zword) (zargs[0] + 1), i);
252
253     /* Tokenise line if a token buffer is present */
254
255     if (key == ZC_RETURN && zargs[1] != 0)
256         tokenise_line (zargs[0], zargs[1], 0, FALSE);
257
258     /* Store key */
259
260     if (h_version >= V5)
261         store (translate_to_zscii (key));
262
263 }/* z_read */
264
265 /*
266  * z_read_char, read and store a key.
267  *
268  *      zargs[0] = input device (must be 1)
269  *      zargs[1] = timeout in tenths of a second (optional)
270  *      zargs[2] = packed address of routine to be called on timeout
271  *
272  */
273
274 void z_read_char (void)
275 {
276     zchar key;
277
278     /* Supply default arguments */
279
280     if (zargc < 2)
281         zargs[1] = 0;
282
283     /* Read input from the current input stream */
284
285     key = stream_read_key (
286         zargs[1],       /* timeout value   */
287         zargs[2],       /* timeout routine */
288         FALSE);         /* enable hot keys */
289
290     if (key == ZC_BAD)
291         return;
292
293     /* Store key */
294
295     store (translate_to_zscii (key));
296
297 }/* z_read_char */
298
299 /*
300  * z_read_mouse, write the current mouse status into a table.
301  *
302  *      zargs[0] = address of table
303  *
304  */
305
306 void z_read_mouse (void)
307 {
308     zword btn;
309
310     /* Read the mouse position, the last menu click
311        and which buttons are down */
312
313     btn = os_read_mouse ();
314     hx_mouse_y = mouse_y;
315     hx_mouse_x = mouse_x;
316
317     storew ((zword) (zargs[0] + 0), hx_mouse_y);
318     storew ((zword) (zargs[0] + 2), hx_mouse_x);
319     storew ((zword) (zargs[0] + 4), btn);               /* mouse button bits */
320     storew ((zword) (zargs[0] + 6), menu_selected);     /* menu selection */
321
322 }/* z_read_mouse */