1 /* glkstuff.c -- non-screen related glk stuff */
9 int curr_status_ht = 0;
10 int mach_status_ht = 0;
12 winid_t gos_upper = NULL;
13 winid_t gos_lower = NULL;
14 winid_t gos_curwin = NULL;
16 int gos_linepending = 0;
17 char *gos_linebuf = NULL;
18 winid_t gos_linewin = NULL;
20 schanid_t gos_channel = NULL;
22 #define INFORMATION ""\
23 "An interpreter for Infocom and other Z-Machine games.\n"\
24 "Complies with standard 1.0 of Graham Nelson's specification.\n"\
25 "Plays Z-code versions 1-5 and 8.\n"\
27 "Syntax: frotz [options] story-file\n"\
28 " -a watch attribute setting\n"\
29 " -A watch attribute testing\n"\
30 " -i ignore fatal errors\n"\
31 " -I # interpreter number\n"\
32 " -o watch object movement\n"\
33 " -O watch object locating\n"\
34 " -P alter piracy opcode\n"\
35 " -Q use old-style save format\n"\
36 " -s # random number seed value\n"\
37 " -S # transscript width\n"\
38 " -t set Tandy bit\n"\
39 " -u # slots for multiple undo\n"\
40 " -x expand abbreviations g/x/z\n"
42 /* A unix-like getopt, but with the names changed to avoid any problems. */
43 static int zoptind = 1;
44 static int zoptopt = 0;
45 static char *zoptarg = NULL;
46 static int zgetopt (int argc, char *argv[], const char *options)
50 if (zoptind >= argc || argv[zoptind][0] != '-' || argv[zoptind][1] == 0)
52 zoptopt = argv[zoptind][pos++];
54 if (argv[zoptind][pos] == 0)
59 p = strchr (options, zoptopt);
60 if (zoptopt == ':' || p == NULL)
62 fputs ("illegal option -- ", stderr);
67 if (zoptind >= argc) {
68 fputs ("option requires an argument -- ", stderr);
71 zoptarg = argv[zoptind];
79 fputc (zoptopt, stderr);
84 static int user_random_seed = -1;
85 static int user_tandy_bit = 0;
86 static char *graphics_filename = NULL;
88 void os_process_arguments(int argc, char *argv[])
93 garglk_set_program_name("Frotz " VERSION);
94 garglk_set_program_info(
95 "Glk Frotz " VERSION "\n"
96 "Original Frotz by Stefan Jokisch\n"
97 "Unix port by Jim Dunleavy and David Griffith\n"
98 "Glk port by Tor Andersson\n");
101 /* Parse the options */
103 c = zgetopt(argc, argv, "aAiI:oOPQs:S:tu:xZ:");
106 case 'a': f_setup.attribute_assignment = 1; break;
107 case 'A': f_setup.attribute_testing = 1; break;
108 case 'i': f_setup.ignore_errors = 1; break;
109 case 'I': f_setup.interpreter_number = atoi(zoptarg); break;
110 case 'o': f_setup.object_movement = 1; break;
111 case 'O': f_setup.object_locating = 1; break;
112 case 'P': f_setup.piracy = 1; break;
113 case 'Q': f_setup.save_quetzal = 0; break;
114 case 's': user_random_seed = atoi(zoptarg); break;
115 case 'S': f_setup.script_cols = atoi(zoptarg); break;
116 case 't': user_tandy_bit = 1; break;
117 case 'u': f_setup.undo_slots = atoi(zoptarg); break;
118 case 'x': f_setup.expand_abbreviations = 1; break;
119 case 'Z': f_setup.err_report_mode = atoi(zoptarg);
120 if ((f_setup.err_report_mode < ERR_REPORT_NEVER) ||
121 (f_setup.err_report_mode > ERR_REPORT_FATAL))
122 f_setup.err_report_mode = ERR_DEFAULT_REPORT_MODE;
127 if (((argc - zoptind) != 1) && ((argc - zoptind) != 2))
131 win = glk_window_open(0, 0, 0, wintype_TextBuffer, 0);
133 glk_put_string("FROTZ V" VERSION " -- Glk 0.6.1 interface.\n");
134 glk_put_string(INFORMATION);
136 " -Z # error checking mode (default = %d)\n"
137 " %d = don't report errors. "
138 "%d = report first error.\n"
139 " %d = report all errors. "
140 "%d = exit after any error.\n",
141 ERR_DEFAULT_REPORT_MODE, ERR_REPORT_NEVER,
142 ERR_REPORT_ONCE, ERR_REPORT_ALWAYS, ERR_REPORT_FATAL);
150 story_name = argv[zoptind++];
152 graphics_filename = argv[zoptind++];
155 s = strrchr(story_name, '\\');
156 if (!s) s = strrchr(story_name, '/');
157 garglk_set_story_name(s ? s + 1 : story_name);
162 void os_init_screen(void)
164 glui32 width, height;
170 glk_stylehint_set(wintype_TextGrid, style_User1, stylehint_ReverseColor, 1);
173 gos_lower = glk_window_open(0, 0, 0, wintype_TextGrid, 0);
175 gos_lower = glk_window_open(0, 0, 0, wintype_TextBuffer, 0);
176 glk_window_get_size(gos_lower, &width, &height);
177 glk_window_close(gos_lower, NULL);
179 gos_lower = glk_window_open(0, 0, 0, wintype_TextBuffer, 0);
180 gos_upper = glk_window_open(gos_lower,
181 winmethod_Above | winmethod_Fixed,
183 wintype_TextGrid, 0);
187 glk_set_window(gos_lower);
188 gos_curwin = gos_lower;
191 * Icky magic bit setting
194 if (h_version == V3 && user_tandy_bit)
195 h_config |= CONFIG_TANDY;
197 if (h_version == V3 && gos_upper)
198 h_config |= CONFIG_SPLITSCREEN;
200 if (h_version == V3 && !gos_upper)
201 h_config |= CONFIG_NOSTATUSLINE;
204 h_config |= CONFIG_BOLDFACE | CONFIG_EMPHASIS |
205 CONFIG_FIXED | CONFIG_TIMEDINPUT;
208 h_flags &= ~(GRAPHICS_FLAG | MOUSE_FLAG | MENU_FLAG);
210 if ((h_version >= 5) && (h_flags & SOUND_FLAG))
211 h_flags |= SOUND_FLAG;
213 if ((h_version == 3) && (h_flags & OLD_SOUND_FLAG))
214 h_flags |= OLD_SOUND_FLAG;
216 if ((h_version == 6) && (f_setup.sound != 0))
217 h_config |= CONFIG_SOUND;
219 if (h_version >= V5 && (h_flags & UNDO_FLAG))
220 if (f_setup.undo_slots == 0)
221 h_flags &= ~UNDO_FLAG;
223 h_screen_cols = width;
224 h_screen_rows = height;
226 h_screen_height = h_screen_rows;
227 h_screen_width = h_screen_cols;
232 /* Must be after screen dimensions are computed. */
233 if (h_version == V6) {
234 h_flags &= ~GRAPHICS_FLAG;
237 /* Use the ms-dos interpreter number for v6, because that's the
238 * kind of graphics files we understand. Otherwise, use DEC. */
239 h_interpreter_number = h_version == 6 ? INTERP_MSDOS : INTERP_DEC_20;
240 if (f_setup.interpreter_number > 0)
241 h_interpreter_number = f_setup.interpreter_number;
242 h_interpreter_version = 'F';
244 /* Set these per spec 8.3.2. */
245 h_default_foreground = WHITE_COLOUR;
246 h_default_background = BLACK_COLOUR;
247 if (h_flags & COLOUR_FLAG) h_flags &= ~COLOUR_FLAG;
251 int os_random_seed (void)
253 if (user_random_seed == -1)
254 /* Use the epoch as seed value */
255 return (time(0) & 0x7fff);
256 return user_random_seed;
259 void os_restart_game (int stage) {}
261 void os_fatal (char *s)
264 gos_lower = glk_window_open(0, 0, 0, wintype_TextBuffer, 0);
266 glk_set_window(gos_lower);
267 glk_set_style(style_Normal);
268 glk_put_string("\n\nFatal error: ");
270 glk_put_string("\n");
274 void os_init_setup(void)
276 f_setup.attribute_assignment = 0;
277 f_setup.attribute_testing = 0;
278 f_setup.context_lines = 0;
279 f_setup.object_locating = 0;
280 f_setup.object_movement = 0;
281 f_setup.left_margin = 0;
282 f_setup.right_margin = 0;
283 f_setup.ignore_errors = 0;
284 f_setup.interpreter_number = 0;
286 f_setup.undo_slots = MAX_UNDO_SLOTS;
287 f_setup.expand_abbreviations = 0;
288 f_setup.script_cols = 80;
289 f_setup.save_quetzal = 1;
291 f_setup.err_report_mode = ERR_DEFAULT_REPORT_MODE;
294 void gos_cancel_pending_line(void)
297 glk_cancel_line_event(gos_linewin, &ev);
298 gos_linebuf[ev.val1] = '\0';
302 zchar os_read_key (int timeout, bool show_cursor)
305 winid_t win = gos_curwin ? gos_curwin : gos_lower;
308 gos_cancel_pending_line();
310 glk_request_char_event(win);
312 glk_request_timer_events(timeout * 100);
317 if (ev.type == evtype_Arrange) {
321 else if (ev.type == evtype_Timer)
323 glk_cancel_char_event(win);
324 glk_request_timer_events(0);
327 else if (ev.type == evtype_CharInput)
331 glk_request_timer_events(0);
333 if (gos_upper && mach_status_ht < curr_status_ht)
339 case keycode_Escape: return ZC_ESCAPE;
340 case keycode_PageUp: return ZC_ARROW_MIN;
341 case keycode_PageDown: return ZC_ARROW_MAX;
342 case keycode_Left: return ZC_ARROW_LEFT;
343 case keycode_Right: return ZC_ARROW_RIGHT;
344 case keycode_Up: return ZC_ARROW_UP;
345 case keycode_Down: return ZC_ARROW_DOWN;
346 case keycode_Return: return ZC_RETURN;
347 case keycode_Delete: return ZC_BACKSPACE;
348 case keycode_Tab: return ZC_INDENT;
354 zchar os_read_line (int max, zchar *buf, int timeout, int width, int continued)
357 winid_t win = gos_curwin ? gos_curwin : gos_lower;
359 if (!continued && gos_linepending)
360 gos_cancel_pending_line();
362 if (!continued || !gos_linepending)
364 glk_request_line_event(win, buf, max - 1, strlen(buf));
366 glk_request_timer_events(timeout * 100);
374 if (ev.type == evtype_Arrange) {
378 else if (ev.type == evtype_Timer)
385 else if (ev.type == evtype_LineInput)
389 glk_request_timer_events(0);
392 if (gos_upper && mach_status_ht < curr_status_ht)
399 zword os_read_mouse(void)
401 /* NOT IMPLEMENTED */
405 static glui32 flag2usage(int flag)
410 return fileusage_SavedGame | fileusage_BinaryMode;
412 return fileusage_SavedGame | fileusage_BinaryMode;
414 return fileusage_Transcript | fileusage_TextMode;
416 return fileusage_InputRecord | fileusage_TextMode;
418 return fileusage_InputRecord | fileusage_TextMode;
420 return fileusage_Data | fileusage_BinaryMode;
422 return fileusage_Data | fileusage_BinaryMode;
427 static glui32 flag2mode(int flag)
432 return filemode_Read;
434 return filemode_Write;
436 return filemode_ReadWrite; /* append really, but with erase option */
438 return filemode_Read;
440 return filemode_Write;
442 return filemode_Read;
444 return filemode_Write;
446 return filemode_ReadWrite;
449 strid_t frotzopenprompt(int flag)
453 glui32 gusage = flag2usage(flag);
454 glui32 gmode = flag2mode(flag);
456 fref = glk_fileref_create_by_prompt(gusage, gmode, 0);
460 stm = glk_stream_open_file(fref, gmode, 0);
462 glk_fileref_destroy(fref);
467 strid_t frotzopen(char *filename, int flag)
471 glui32 gusage = flag2usage(flag);
472 glui32 gmode = flag2mode(flag);
474 fref = glk_fileref_create_by_name(gusage, filename, 0);
478 stm = glk_stream_open_file(fref, gmode, 0);
480 glk_fileref_destroy(fref);