2 * Copyright 2010-2012 Chris Spiegel.
4 * This file is part of Bocfel.
6 * Bocfel is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License, version
8 * 2 or 3, as published by the Free Software Foundation.
10 * Bocfel is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with Bocfel. If not, see <http://www.gnu.org/licenses/>.
26 #include <libchimara/garglk.h>
46 enum font { FONT_NONE = -1, FONT_PREVIOUS, FONT_NORMAL, FONT_PICTURE, FONT_CHARACTER, FONT_FIXED } font;
51 long x, y; /* Only meaningful for window 1 */
60 } windows[8], *mainwin = &windows[0], *curwin = &windows[0];
62 static struct window *upperwin = &windows[1];
63 static struct window statuswin;
64 static long upper_window_height = 0;
65 static long upper_window_width = 0;
66 static winid_t errorwin;
69 /* In all versions but 6, styles are global and stored in mainwin. For
70 * V6, styles are tracked per window and thus stored in each individual
71 * window. For convenience, this macro expands to the “style window”
74 #define style_window (zversion == 6 ? curwin : mainwin)
76 /* If the window needs to be temporarily switched (@show_status and
77 * @print_form print to specific windows, and window_change() might
78 * temporarily need to switch to the upper window), the code that
79 * requires a specific window can be wrapped in these macros.
82 #define SWITCH_WINDOW_START(win) { struct window *saved_ = curwin; curwin = (win); glk_set_window((win)->id);
83 #define SWITCH_WINDOW_END() curwin = saved_; glk_set_window(curwin->id); }
85 #define SWITCH_WINDOW_START(win) { struct window *saved_ = curwin; curwin = (win);
86 #define SWITCH_WINDOW_END() curwin = saved_; }
89 /* Output stream bits. */
90 #define STREAM_SCREEN (1U << 1)
91 #define STREAM_TRANS (1U << 2)
92 #define STREAM_MEMORY (1U << 3)
93 #define STREAM_SCRIPT (1U << 4)
95 static unsigned int streams = STREAM_SCREEN;
96 static zterp_io *transio, *scriptio;
103 static int stablei = -1;
105 static int istream = ISTREAM_KEYBOARD;
106 static zterp_io *istreamio;
110 enum { INPUT_CHAR, INPUT_LINE } type;
112 /* ZSCII value of key read for @read_char. */
115 /* Unicode line of chars read for @read. */
121 /* Character used to terminate input. If terminating keys are not
122 * supported by the Glk implementation being used (or if Glk is not
123 * used at all) this will be ZSCII_NEWLINE; or in the case of
129 /* This macro makes it so that code elsewhere needn’t check have_unicode before printing. */
130 #define GLK_PUT_CHAR(c) do { if(!have_unicode) glk_put_char(unicode_to_latin1[c]); else glk_put_char_uni(c); } while(0)
132 void show_message(const char *fmt, ...)
138 vsnprintf(message, sizeof message, fmt, ap);
142 static int error_lines = 0;
148 /* Allow multiple messages to stack, but force at least 5 lines to
149 * always be visible in the main window. This is less than perfect
150 * because it assumes that each message will be less than the width
151 * of the screen, but it’s not a huge deal, really; even if the
152 * lines are too long, at least Gargoyle and glktermw are graceful
155 glk_window_get_size(mainwin->id, &w, &h);
157 if(h > 5) glk_window_set_arrangement(glk_window_get_parent(errorwin), winmethod_Below | winmethod_Fixed, ++error_lines, errorwin);
158 glk_put_char_stream(glk_window_get_stream(errorwin), UNICODE_LINEFEED);
162 errorwin = glk_window_open(mainwin->id, winmethod_Below | winmethod_Fixed, error_lines = 2, wintype_TextBuffer, 0);
165 /* If windows are not supported (e.g. in cheapglk), messages will not
166 * get displayed. If this is the case, print to the main window.
170 glk_set_style_stream(glk_window_get_stream(errorwin), style_Alert);
171 glk_put_string_stream(glk_window_get_stream(errorwin), message);
175 SWITCH_WINDOW_START(mainwin);
176 glk_put_string("\12[");
177 glk_put_string(message);
178 glk_put_string("]\12");
182 /* In Glk messages go to a separate window, but they're interleaved in
183 * non-Glk. Put brackets around the message in an attempt to offset
184 * it from the game a bit.
186 fprintf(stderr, "\n[%s]\n", message);
191 * This returns true if the stream was successfully selected.
192 * Deselecting a stream is always successful.
194 int output_stream(int16_t number, uint16_t table)
198 streams |= 1U << number;
202 if(number != -3 || stablei == 0) streams &= ~(1U << -number);
207 STORE_WORD(0x10, WORD(0x10) | FLAGS2_TRANSCRIPT);
210 transio = zterp_io_open(options.transcript_name, ZTERP_IO_TRANS | (options.overwrite_transcript ? ZTERP_IO_WRONLY : ZTERP_IO_APPEND));
213 STORE_WORD(0x10, WORD(0x10) & ~FLAGS2_TRANSCRIPT);
214 streams &= ~STREAM_TRANS;
215 warning("unable to open the transcript");
219 else if(number == -2)
221 STORE_WORD(0x10, WORD(0x10) & ~FLAGS2_TRANSCRIPT);
227 ZASSERT(stablei < 16, "too many stream tables");
229 stables[stablei].table = table;
230 user_store_word(stables[stablei].table, 0);
231 stables[stablei].i = 2;
233 else if(number == -3 && stablei >= 0)
235 user_store_word(stables[stablei].table, stables[stablei].i - 2);
243 scriptio = zterp_io_open(options.record_name, ZTERP_IO_WRONLY | ZTERP_IO_INPUT);
246 streams &= ~STREAM_SCRIPT;
247 warning("unable to open the script");
251 /* XXX v6 has even more handling */
253 return number < 0 || (streams & (1U << number));
256 void zoutput_stream(void)
258 output_stream(zargs[0], zargs[1]);
262 * This returns true if the stream was successfully selected.
264 int input_stream(int which)
268 if(istream == ISTREAM_KEYBOARD)
270 if(istreamio != NULL)
272 zterp_io_close(istreamio);
276 else if(istream == ISTREAM_FILE)
278 if(istreamio == NULL)
280 istreamio = zterp_io_open(options.replay_name, ZTERP_IO_INPUT | ZTERP_IO_RDONLY);
281 if(istreamio == NULL)
283 warning("unable to open the command script");
284 istream = ISTREAM_KEYBOARD;
290 ZASSERT(0, "invalid input stream: %d", istream);
293 return istream == which;
296 void zinput_stream(void)
298 input_stream(zargs[0]);
301 /* This does not even pretend to understand V6 windows. */
302 static void set_current_window(struct window *window)
307 if(curwin == upperwin && upperwin->id != NULL)
309 upperwin->x = upperwin->y = 0;
310 glk_window_move_cursor(upperwin->id, 0, 0);
313 glk_set_window(curwin->id);
319 /* Find and validate a window. If window is -3 and the story is V6,
320 * return the current window.
322 static struct window *find_window(uint16_t window)
326 ZASSERT(zversion == 6 ? w == -3 || (w >= 0 && w < 8) : w == 0 || w == 1, "invalid window selected: %d", w);
328 if(w == -3) return curwin;
334 /* When resizing the upper window, the screen’s contents should not
335 * change (§8.6.1); however, the way windows are handled with Glk makes
336 * this slightly impossible. When an Inform game tries to display
337 * something with “box”, it expands the upper window, displays the quote
338 * box, and immediately shrinks the window down again. This is a
339 * problem under Glk because the window immediately disappears. Other
340 * games, such as Bureaucracy, expect the upper window to shrink as soon
341 * as it has been requested. Thus the following system is used:
343 * If a request is made to shrink the upper window, it is granted
344 * immediately if there has been user input since the last window resize
345 * request. If there has not been user input, the request is delayed
346 * until after the next user input is read.
348 static long delayed_window_shrink = -1;
349 static int saw_input;
351 static void update_delayed(void)
355 if(delayed_window_shrink == -1 || upperwin->id == NULL) return;
357 glk_window_set_arrangement(glk_window_get_parent(upperwin->id), winmethod_Above | winmethod_Fixed, delayed_window_shrink, upperwin->id);
358 upper_window_height = delayed_window_shrink;
360 /* Glk might resize the window to a smaller height than was requested,
361 * so track the actual height, not the requested height.
363 glk_window_get_size(upperwin->id, NULL, &height);
364 if(height != upper_window_height)
366 /* This message probably won’t be seen in a window since the upper
367 * window is likely covering everything, but try anyway.
369 show_message("Unable to fulfill window size request: wanted %ld, got %lu", delayed_window_shrink, (unsigned long)height);
370 upper_window_height = height;
373 delayed_window_shrink = -1;
376 /* Both the upper and lower windows have their own issues to deal with
377 * when there is line input. This function ensures that the cursor
378 * position is properly tracked in the upper window, and if possible,
379 * aids in the suppression of newline printing on input cancellation in
382 static void cleanup_screen(struct input *input)
384 if(input->type != INPUT_LINE) return;
386 /* If the current window is the upper window, the position of the
387 * cursor needs to be tracked, so after a line has successfully been
388 * read, advance the cursor to the initial position of the next line,
389 * or if a terminating key was used or input was canceled, to the end
392 if(curwin == upperwin)
394 if(input->term != ZSCII_NEWLINE) upperwin->x += input->len;
396 if(input->term == ZSCII_NEWLINE || upperwin->x >= upper_window_width)
399 if(upperwin->y < upper_window_height) upperwin->y++;
402 glk_window_move_cursor(upperwin->id, upperwin->x, upperwin->y);
405 /* If line input echoing is turned off, newlines will not be printed
406 * when input is canceled, but neither will the input line. Fix that.
410 glk_set_style(style_Input);
411 for(int i = 0; i < input->len; i++) GLK_PUT_CHAR(input->line[i]);
412 if(input->term == ZSCII_NEWLINE) glk_put_char(UNICODE_LINEFEED);
417 /* In an interrupt, if the story tries to read or write, the previous
418 * read event (which triggered the interrupt) needs to be canceled.
419 * This function does the cancellation.
421 static void cancel_read_events(struct window *window)
423 if(window->pending_read)
427 glk_cancel_char_event(window->id);
428 glk_cancel_line_event(window->id, &ev);
430 /* If the pending read was a line input, zero terminate the string
431 * so when it’s re-requested the length of the already-loaded
432 * portion can be discovered. Also deal with cursor positioning in
433 * the upper window, and line echoing in the lower window.
435 if(ev.type == evtype_LineInput && window->line != NULL)
437 uint32_t line[ev.val1];
438 struct input input = { .type = INPUT_LINE, .line = line, .term = 0, .len = ev.val1 };
440 if(have_unicode) window->line->unicode[ev.val1] = 0;
441 else window->line->latin1 [ev.val1] = 0;
443 for(int i = 0; i < input.len; i++)
445 if(have_unicode) line[i] = window->line->unicode[i];
446 else line[i] = window->line->latin1 [i];
449 cleanup_screen(&input);
452 window->pending_read = 0;
457 static void clear_window(struct window *window)
459 if(window->id == NULL) return;
461 /* glk_window_clear() cannot be used while there are pending read requests. */
462 cancel_read_events(window);
464 glk_window_clear(window->id);
466 window->x = window->y = 0;
470 /* If restoring from an interrupt (which is a bad idea to begin with),
471 * it’s entirely possible that there will be pending read events that
472 * need to be canceled, so allow that.
474 void cancel_all_events(void)
477 for(int i = 0; i < 8; i++) cancel_read_events(&windows[i]);
481 static void resize_upper_window(long nlines)
484 if(upperwin->id == NULL) return;
486 /* To avoid code duplication, put all window resizing code in
487 * update_delayed() and, if necessary, call it from here.
489 delayed_window_shrink = nlines;
490 if(upper_window_height <= nlines || saw_input) update_delayed();
495 if(zversion == 3) clear_window(upperwin);
497 /* As in a few other areas, changing the upper window causes reverse
498 * video to be deactivated, so reapply the current style.
504 void close_upper_window(void)
506 /* The upper window is never destroyed; rather, when it’s closed, it
507 * shrinks to zero height.
509 resize_upper_window(0);
512 delayed_window_shrink = -1;
516 set_current_window(mainwin);
519 void get_screen_size(unsigned int *width, unsigned int *height)
527 /* The main window can be proportional, and if so, its width is not
528 * generally useful because games tend to care about width with a
529 * fixed font. If a status window is available, or if an upper window
530 * is available, use that to calculate the width, because these
531 * windows will have a fixed-width font. The height is the combined
532 * height of all windows.
534 glk_window_get_size(mainwin->id, &w, &h);
536 if(statuswin.id != NULL)
538 glk_window_get_size(statuswin.id, &w, &h);
541 if(upperwin->id != NULL)
543 glk_window_get_size(upperwin->id, &w, &h);
548 zterp_os_get_screen_size(width, height);
551 /* XGlk does not report the size of textbuffer windows, so here’s a safety net. */
552 if(*width == 0) *width = 80;
553 if(*height == 0) *height = 24;
555 /* Terrible hack: Because V6 is not properly supported, the window to
556 * which Journey writes its story is completely covered up by window
557 * 1. For the same reason, only the bottom 6 lines of window 1 are
558 * actually useful, even though the game expands it to cover the whole
559 * screen. By pretending that the screen height is only 6, the main
560 * window, where text is actually sent, becomes visible.
562 if(is_story("83-890706") && *height > 6) *height = 6;
565 #ifdef GLK_MODULE_LINE_TERMINATORS
566 static uint32_t *term_keys, term_size, term_nkeys;
568 void term_keys_reset(void)
576 static void insert_key(uint32_t key)
578 if(term_nkeys == term_size)
582 term_keys = realloc(term_keys, term_size * sizeof *term_keys);
583 if(term_keys == NULL) die("unable to allocate memory for terminating keys");
586 term_keys[term_nkeys++] = key;
589 void term_keys_add(uint8_t key)
593 case 129: insert_key(keycode_Up); break;
594 case 130: insert_key(keycode_Down); break;
595 case 131: insert_key(keycode_Left); break;
596 case 132: insert_key(keycode_Right); break;
597 case 133: insert_key(keycode_Func1); break;
598 case 134: insert_key(keycode_Func2); break;
599 case 135: insert_key(keycode_Func3); break;
600 case 136: insert_key(keycode_Func4); break;
601 case 137: insert_key(keycode_Func5); break;
602 case 138: insert_key(keycode_Func6); break;
603 case 139: insert_key(keycode_Func7); break;
604 case 140: insert_key(keycode_Func8); break;
605 case 141: insert_key(keycode_Func9); break;
606 case 142: insert_key(keycode_Func10); break;
607 case 143: insert_key(keycode_Func11); break;
608 case 144: insert_key(keycode_Func12); break;
610 /* Keypad 0–9 should be here, but Glk doesn’t support that. */
611 case 145: case 146: case 147: case 148: case 149:
612 case 150: case 151: case 152: case 153: case 154:
615 /* Mouse clicks would go here if I supported them. */
616 case 252: case 253: case 254:
620 for(int i = 129; i <= 144; i++) term_keys_add(i);
624 ZASSERT(0, "invalid terminating key: %u", (unsigned)key);
630 /* Print out a character. The character is in “c” and is either Unicode
631 * or ZSCII; if the former, “unicode” is true.
633 static void put_char_base(uint16_t c, int unicode)
637 if(streams & STREAM_MEMORY)
639 ZASSERT(stablei != -1, "invalid stream table");
641 /* When writing to memory, ZSCII should always be used (§7.5.3). */
642 if(unicode) c = unicode_to_zscii_q[c];
644 user_store_byte(stables[stablei].table + stables[stablei].i++, c);
648 /* For screen and transcription, always prefer Unicode. */
649 if(!unicode) c = zscii_to_unicode[c];
655 /* §16 makes no mention of what a newline in font 3 should map to.
656 * Other interpreters that implement font 3 assume it stays a
657 * newline, and this makes the most sense, so don’t do any
658 * translation in that case.
660 if(curwin->font == FONT_CHARACTER && !options.disable_graphics_font && c != UNICODE_LINEFEED)
662 zscii = unicode_to_zscii[c];
664 /* These four characters have a “built-in” reverse video (see §16). */
665 if(zscii >= 123 && zscii <= 126)
667 style_window->style ^= STYLE_REVERSE;
671 c = zscii_to_font3[zscii];
674 if((streams & STREAM_SCREEN) && curwin->id != NULL)
676 cancel_read_events(curwin);
678 if(curwin == upperwin)
680 /* Interpreters seem to have differing ideas about what
681 * happens when the cursor reaches the end of a line in the
682 * upper window. Some wrap, some let it run off the edge (or,
683 * at least, stop the text at the edge). The standard, from
684 * what I can see, says nothing on this issue. Follow Windows
685 * Frotz and don’t wrap.
688 if(c == UNICODE_LINEFEED)
690 if(upperwin->y < upper_window_height)
692 /* Glk wraps, so printing a newline when the cursor has
693 * already reached the edge of the screen will produce two
696 if(upperwin->x < upper_window_width) GLK_PUT_CHAR(c);
698 /* Even if a newline isn’t explicitly printed here
699 * (because the cursor is at the edge), setting
700 * upperwin->x to 0 will cause the next character to be on
701 * the next line because the text will have wrapped.
707 else if(upperwin->x < upper_window_width && upperwin->y < upper_window_height)
719 if((streams & STREAM_SCREEN) && curwin == mainwin) zterp_io_putc(zterp_io_stdout(), c);
722 /* If the reverse video bit was flipped (for the character font), flip it back. */
723 if(zscii >= 123 && zscii <= 126)
725 style_window->style ^= STYLE_REVERSE;
729 if((streams & STREAM_TRANS) && curwin == mainwin) zterp_io_putc(transio, c);
734 void put_char_u(uint16_t c)
739 void put_char(uint8_t c)
744 static void put_string(const char *s)
748 if(*s == '\n') put_char(ZSCII_NEWLINE);
753 /* Decode and print a zcode string at address “addr”. This can be
754 * called recursively thanks to abbreviations; the initial call should
755 * have “in_abbr” set to 0.
756 * Each time a character is decoded, it is passed to the function
759 static int print_zcode(uint32_t addr, int in_abbr, void (*outc)(uint8_t))
761 int abbrev = 0, shift = 0, special = 0;
762 int c, lastc = 0; /* Initialize lastc to shut gcc up */
764 uint32_t counter = addr;
765 int current_alphabet = 0;
769 ZASSERT(counter < memory_size - 1, "string runs beyond the end of memory");
773 for(int i = 10; i >= 0; i -= 5)
779 if(special == 2) lastc = c;
780 else outc((lastc << 5) | c);
789 new_addr = user_word(header.abbr + 64 * (abbrev - 1) + 2 * c);
791 /* new_addr is a word address, so multiply by 2 */
792 print_zcode(new_addr * 2, 1, outc);
812 if(zversion >= 3 || (zversion == 2 && c == 1))
814 ZASSERT(!in_abbr, "abbreviation being used recursively");
826 current_alphabet = (current_alphabet + (c - 3)) % 3;
835 if(zversion <= 2) shift = (current_alphabet + shift) % 3;
845 if(zversion <= 2 && c != 6) shift = (current_alphabet + shift) % 3;
847 outc(atable[(26 * shift) + (c - 6)]);
854 } while((w & 0x8000) == 0);
856 return counter - addr;
859 /* Prints the string at addr “addr”.
861 * Returns the number of bytes the string took up. “outc” is passed as
862 * the character-print function to print_zcode(); if it is NULL,
865 int print_handler(uint32_t addr, void (*outc)(uint8_t))
867 return print_zcode(addr, 0, outc != NULL ? outc : put_char);
872 pc += print_handler(pc, NULL);
875 void zprint_ret(void)
878 put_char(ZSCII_NEWLINE);
884 put_char(ZSCII_NEWLINE);
887 void zerase_window(void)
890 switch((int16_t)zargs[0])
893 for(int i = 0; i < 8; i++) clear_window(&windows[i]);
896 close_upper_window();
899 /* 8.7.3.2.1 says V5+ should have the cursor set to 1, 1 of the
900 * erased window; V4 the lower window goes bottom left, the upper
901 * to 1, 1. Glk doesn’t give control over the cursor when
902 * clearing, and that doesn’t really seem to be an issue; so just
903 * call glk_window_clear().
905 clear_window(mainwin);
908 clear_window(upperwin);
911 show_message("@erase_window: unhandled window: %d", (int16_t)zargs[0]);
915 /* glk_window_clear() kills reverse video in Gargoyle. Reapply style. */
920 void zerase_line(void)
923 /* XXX V6 does pixel handling here. */
924 if(zargs[0] != 1 || curwin != upperwin || upperwin->id == NULL) return;
926 for(long i = upperwin->x; i < upper_window_width; i++) GLK_PUT_CHAR(UNICODE_SPACE);
928 glk_window_move_cursor(upperwin->id, upperwin->x, upperwin->y);
932 /* XXX This is more complex in V6 and needs to be updated when V6 windowing is implemented. */
933 static void set_cursor(uint16_t y, uint16_t x)
936 /* All the windows in V6 can have their cursor positioned; if V6 ever
937 * comes about this should be fixed.
939 if(curwin != upperwin) return;
941 /* -1 and -2 are V6 only, but at least Zracer passes -1 (or it’s
942 * trying to position the cursor to line 65535; unlikely!)
944 if((int16_t)y == -1 || (int16_t)y == -2) return;
946 /* §8.7.2.3 says 1,1 is the top-left, but at least one program (Paint
947 * and Corners) uses @set_cursor 0 0 to go to the top-left; so
953 /* This is actually illegal, but some games (e.g. Beyond Zork) expect it to work. */
954 if(y > upper_window_height) resize_upper_window(y);
956 if(upperwin->id != NULL)
961 glk_window_move_cursor(upperwin->id, x - 1, y - 1);
966 void zset_cursor(void)
968 set_cursor(zargs[0], zargs[1]);
971 void zget_cursor(void)
974 user_store_word(zargs[0] + 0, upperwin->y + 1);
975 user_store_word(zargs[0] + 2, upperwin->x + 1);
977 user_store_word(zargs[0] + 0, 1);
978 user_store_word(zargs[0] + 2, 1);
983 static int16_t fg_color = 1, bg_color = 1;
984 #elif defined(GARGLK)
985 static glui32 zcolor_map[] = {
988 0x000000, /* Black */
990 0x00d600, /* Green */
991 0xefef00, /* Yellow */
993 0xff00ff, /* Magenta */
995 0xffffff, /* White */
996 0xb5b5b5, /* Light grey */
997 0x8c8c8c, /* Medium grey */
998 0x5a5a5a, /* Dark grey */
1000 static glui32 fg_color = zcolor_Default, bg_color = zcolor_Default;
1002 void update_color(int which, unsigned long color)
1004 if(which < 2 || which > 12) return;
1006 zcolor_map[which - 1] = color;
1010 /* A window argument may be supplied in V6, and this needs to be implemented. */
1011 void zset_colour(void)
1013 /* Glk (apart from Gargoyle) has no color support. */
1014 #if !defined(ZTERP_GLK) || defined(GARGLK)
1015 int16_t fg = zargs[0], bg = zargs[1];
1017 /* In V6, each window has its own color settings. Since multiple
1018 * windows are not supported, simply ignore all color requests except
1019 * those in the main window.
1021 if(zversion == 6 && curwin != mainwin) return;
1023 if(options.disable_color) return;
1025 /* XXX -1 is a valid color in V6. */
1027 if(fg >= 1 && fg <= (zversion >= 5 ? 12 : 9)) fg_color = zcolor_map[fg - 1];
1028 if(bg >= 1 && bg <= (zversion >= 5 ? 12 : 9)) bg_color = zcolor_map[bg - 1];
1031 if(fg >= 1 && fg <= 9) fg_color = fg;
1032 if(bg >= 1 && bg <= 9) bg_color = bg;
1035 set_current_style();
1040 /* Convert a 15-bit color to a 24-bit color. */
1041 static glui32 convert_color(unsigned long color)
1043 /* Map 5-bit color values to 8-bit. */
1044 const uint8_t table[] = {
1045 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
1046 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
1047 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
1048 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff
1051 return table[(color & 0x001f) >> 0] << 16 |
1052 table[(color & 0x03e0) >> 5] << 8 |
1053 table[(color & 0x7c00) >> 10] << 0;
1057 void zset_true_colour(void)
1060 long fg = (int16_t)zargs[0], bg = (int16_t)zargs[1];
1062 if (fg >= 0) fg_color = convert_color(fg);
1063 else if(fg == -1) fg_color = zcolor_Default;
1065 if (bg >= 0) bg_color = convert_color(bg);
1066 else if(bg == -1) bg_color = zcolor_Default;
1068 set_current_style();
1072 int header_fixed_font;
1075 /* Idea from Nitfol. */
1076 static const int style_map[] =
1081 style_Subheader, /* Bold */
1082 style_Subheader, /* Bold */
1083 style_Emphasized, /* Italic */
1084 style_Emphasized, /* Italic */
1085 style_Alert, /* Bold Italic */
1086 style_Alert, /* Bold Italic */
1087 style_Preformatted, /* Fixed */
1088 style_Preformatted, /* Fixed */
1089 style_User1, /* Bold Fixed */
1090 style_User1, /* Bold Fixed */
1091 style_User2, /* Italic Fixed */
1092 style_User2, /* Italic Fixed */
1093 style_Note, /* Bold Italic Fixed */
1094 style_Note, /* Bold Italic Fixed */
1098 /* Yes, there are three ways to indicate that a fixed-width font should be used. */
1099 #define use_fixed_font() (header_fixed_font || curwin->font == FONT_FIXED || (style & STYLE_FIXED))
1101 void set_current_style(void)
1103 unsigned style = style_window->style;
1105 if(curwin->id == NULL) return;
1108 if(use_fixed_font()) style |= STYLE_FIXED;
1110 if(options.disable_fixed) style &= ~STYLE_FIXED;
1112 ZASSERT(style < 16, "invalid style selected: %x", (unsigned)style);
1114 glk_set_style(style_map[style]);
1116 garglk_set_reversevideo(style & STYLE_REVERSE);
1118 garglk_set_zcolors(fg_color, bg_color);
1120 /* Glk can’t mix other styles with fixed-width, but the upper window
1121 * is always fixed, so if it is selected, there is no need to
1122 * explicitly request it here. In addition, the user can disable
1123 * fixed-width fonts or tell Bocfel to assume that the output font is
1124 * already fixed (e.g. in an xterm); in either case, there is no need
1125 * to request a fixed font.
1126 * This means that another style can also be applied if applicable.
1128 if(use_fixed_font() &&
1129 !options.disable_fixed &&
1130 !options.assume_fixed &&
1133 glk_set_style(style_Preformatted);
1137 /* According to standard 1.1, if mixed styles aren't available, the
1138 * priority is Fixed, Italic, Bold, Reverse.
1140 if (style & STYLE_ITALIC) glk_set_style(style_Emphasized);
1141 else if(style & STYLE_BOLD) glk_set_style(style_Subheader);
1142 else if(style & STYLE_REVERSE) glk_set_style(style_Alert);
1143 else glk_set_style(style_Normal);
1146 zterp_os_set_style(style, fg_color, bg_color);
1150 #undef use_fixed_font
1152 /* V6 has per-window styles, but all others have a global style; in this
1153 * case, track styles via the main window.
1155 void zset_text_style(void)
1157 /* A style of 0 means all others go off. */
1158 if(zargs[0] == 0) style_window->style = STYLE_NONE;
1159 else style_window->style |= zargs[0];
1161 set_current_style();
1164 /* Interpreters seem to disagree on @set_font. Given the code
1171 * the following values are returned:
1172 * Frotz 2.43: 0, 1, 1, 1
1173 * Gargoyle r384: 1, 4, 4, 4
1174 * Fizmo 0.6.5: 1, 4, 1, 0
1175 * Nitfol 0.5: 1, 4, 0, 1
1176 * Filfre .987: 1, 4, 0, 1
1177 * Zoom 1.1.4: 1, 1, 0, 1
1178 * ZLR 0.07: 0, 1, 0, 1
1179 * Windows Frotz 1.15: 1, 4, 1, 1
1180 * XZip 1.8.2: 0, 4, 0, 0
1182 * The standard says that “ID 0 means ‘the previous font’.” (§8.1.2).
1183 * The Frotz 2.43 source code says that “zargs[0] = number of font or 0
1184 * to keep current font”.
1186 * How to implement @set_font turns on the meaning of “previous”. Does
1187 * it mean the previous font _after_ the @set_font call, meaning Frotz
1188 * is right? Or is it the previous font _before_ the @set_font call,
1189 * meaning the identity of two fonts needs to be tracked?
1191 * Currently I do the latter. That yields the following:
1193 * Almost comically, no interpreters agree with each other.
1195 void zset_font(void)
1197 struct window *win = curwin;
1199 if(zversion == 6 && znargs == 2 && (int16_t)zargs[1] != -3)
1201 ZASSERT(zargs[1] < 8, "invalid window selected: %d", (int16_t)zargs[1]);
1202 win = &windows[zargs[1]];
1205 /* If no previous font has been stored, consider that an error. */
1206 if(zargs[0] == FONT_PREVIOUS && win->prev_font != FONT_NONE)
1208 zargs[0] = win->prev_font;
1211 else if(zargs[0] == FONT_NORMAL ||
1212 (zargs[0] == FONT_CHARACTER && !options.disable_graphics_font) ||
1213 (zargs[0] == FONT_FIXED && !options.disable_fixed))
1216 win->prev_font = win->font;
1217 win->font = zargs[0];
1224 set_current_style();
1227 void zprint_table(void)
1229 uint16_t text = zargs[0], width = zargs[1], height = zargs[2], skip = zargs[3];
1233 uint16_t start = 0; /* initialize to appease gcc */
1235 if(curwin == upperwin) start = upperwin->x + 1;
1238 if(znargs < 3) height = 1;
1239 if(znargs < 4) skip = 0;
1241 for(uint16_t i = 0; i < height; i++)
1243 for(uint16_t j = 0; j < width; j++)
1245 put_char(user_byte(text + n++));
1252 if(curwin == upperwin)
1254 set_cursor(upperwin->y + 2, start);
1259 put_char(ZSCII_NEWLINE);
1265 void zprint_char(void)
1267 /* Check 32 (space) first: a cursory examination of story files
1268 * indicates that this is the most common value passed to @print_char.
1269 * This appears to be due to V4+ games blanking the upper window.
1271 #define valid_zscii_output(c) ((c) == 32 || (c) == 0 || (c) == 9 || (c) == 11 || (c) == 13 || ((c) > 32 && (c) <= 126) || ((c) >= 155 && (c) <= 251))
1272 ZASSERT(valid_zscii_output(zargs[0]), "@print_char called with invalid character: %u", (unsigned)zargs[0]);
1273 #undef valid_zscii_output
1278 void zprint_num(void)
1282 long v = (int16_t)zargs[0];
1288 buf[i++] = '0' + (v % 10);
1291 if((int16_t)zargs[0] < 0) buf[i++] = '-';
1293 while(i--) put_char(buf[i]);
1296 void zprint_addr(void)
1298 print_handler(zargs[0], NULL);
1301 void zprint_paddr(void)
1303 print_handler(unpack(zargs[0], 1), NULL);
1306 /* XXX This is more complex in V6 and needs to be updated when V6 windowing is implemented. */
1307 void zsplit_window(void)
1309 if(zargs[0] == 0) close_upper_window();
1310 else resize_upper_window(zargs[0]);
1313 void zset_window(void)
1315 set_current_window(find_window(zargs[0]));
1319 static void window_change(void)
1321 /* When a textgrid (the upper window) in Gargoyle is rearranged, it
1322 * forgets about reverse video settings, so reapply any styles to the
1323 * current window (it doesn’t hurt if the window is a textbuffer). If
1324 * the current window is not the upper window that’s OK, because
1325 * set_current_style() is called when a @set_window is requested.
1327 set_current_style();
1329 /* If the new window is smaller, the cursor of the upper window might
1330 * be out of bounds. Pull it back in if so.
1332 if(zversion >= 3 && upperwin->id != NULL && upper_window_height > 0)
1334 long x = upperwin->x, y = upperwin->y;
1337 glk_window_get_size(upperwin->id, &w, &h);
1339 upper_window_width = w;
1340 upper_window_height = h;
1345 SWITCH_WINDOW_START(upperwin);
1346 set_cursor(y + 1, x + 1);
1347 SWITCH_WINDOW_END();
1351 * Only 0x20 and 0x21 are mentioned; what of 0x22 and 0x24? Zoom and
1352 * Windows Frotz both update the V5 header entries, so do that here,
1355 * Also, no version restrictions are given, but assume V4+ per §11.1.
1359 unsigned width, height;
1361 get_screen_size(&width, &height);
1363 STORE_BYTE(0x20, height > 254 ? 254 : height);
1364 STORE_BYTE(0x21, width > 255 ? 255 : width);
1368 STORE_WORD(0x22, width > UINT16_MAX ? UINT16_MAX : width);
1369 STORE_WORD(0x24, height > UINT16_MAX ? UINT16_MAX : height);
1380 static int timer_running;
1382 static void start_timer(uint16_t n)
1384 if(!TIMER_AVAILABLE()) return;
1386 if(timer_running) die("nested timers unsupported");
1387 glk_request_timer_events(n * 100);
1391 static void stop_timer(void)
1393 if(!TIMER_AVAILABLE()) return;
1395 glk_request_timer_events(0);
1399 static void request_char(void)
1401 if(have_unicode) glk_request_char_event_uni(curwin->id);
1402 else glk_request_char_event(curwin->id);
1404 curwin->pending_read = 1;
1407 static void request_line(union line *line, glui32 maxlen, glui32 initlen)
1409 if(have_unicode) glk_request_line_event_uni(curwin->id, line->unicode, maxlen, initlen);
1410 else glk_request_line_event(curwin->id, line->latin1, maxlen, initlen);
1412 curwin->pending_read = 1;
1413 curwin->line = line;
1417 #define special_zscii(c) ((c) >= 129 && (c) <= 154)
1419 /* This is called when input stream 1 (read from file) is selected. If
1420 * it succefully reads a character/line from the file, it fills the
1421 * struct at “input” with the appropriate information and returns true.
1422 * If it fails to read (likely due to EOF) then it sets the input stream
1423 * back to the keyboard and returns false.
1425 static int istream_read_from_file(struct input *input)
1427 if(input->type == INPUT_CHAR)
1431 c = zterp_io_getc(istreamio);
1434 input_stream(ISTREAM_KEYBOARD);
1438 /* Don’t translate special ZSCII characters (cursor keys, function keys, keypad). */
1439 if(special_zscii(c)) input->key = c;
1440 else input->key = unicode_to_zscii_q[c];
1445 uint16_t line[1024];
1447 n = zterp_io_readline(istreamio, line, sizeof line / sizeof *line);
1450 input_stream(ISTREAM_KEYBOARD);
1454 if(n > input->maxlen) n = input->maxlen;
1459 if(curwin->id != NULL)
1461 glk_set_style(style_Input);
1462 for(long i = 0; i < n; i++) GLK_PUT_CHAR(line[i]);
1463 GLK_PUT_CHAR(UNICODE_LINEFEED);
1464 set_current_style();
1467 for(long i = 0; i < n; i++) zterp_io_putc(zterp_io_stdout(), line[i]);
1468 zterp_io_putc(zterp_io_stdout(), UNICODE_LINEFEED);
1471 for(long i = 0; i < n; i++) input->line[i] = line[i];
1477 /* It’s possible that output is buffered, meaning that until
1478 * glk_select() is called, output will not be displayed. When reading
1479 * from a command-script, flush on each command so that output is
1480 * visible while the script is being replayed.
1482 glk_select_poll(&ev);
1487 case evtype_Arrange:
1491 /* No other events should arrive. Timers are only started in
1492 * get_input() and are stopped before that function returns.
1493 * Input events will not happen with glk_select_poll(), and no
1494 * other event type is expected to be raised.
1505 #ifdef GLK_MODULE_LINE_TERMINATORS
1506 /* Glk returns terminating characters as keycode_*, but we need them as
1507 * ZSCII. This should only ever be called with values that are matched
1508 * in the switch, because those are the only ones that Glk was told are
1509 * terminating characters. In the event that another keycode comes
1510 * through, though, treat it as Enter.
1512 static uint8_t zscii_from_glk(glui32 key)
1516 case 13: return ZSCII_NEWLINE;
1517 case keycode_Up: return 129;
1518 case keycode_Down: return 130;
1519 case keycode_Left: return 131;
1520 case keycode_Right: return 131;
1521 case keycode_Func1: return 133;
1522 case keycode_Func2: return 134;
1523 case keycode_Func3: return 135;
1524 case keycode_Func4: return 136;
1525 case keycode_Func5: return 137;
1526 case keycode_Func6: return 138;
1527 case keycode_Func7: return 139;
1528 case keycode_Func8: return 140;
1529 case keycode_Func9: return 141;
1530 case keycode_Func10: return 142;
1531 case keycode_Func11: return 143;
1532 case keycode_Func12: return 144;
1535 return ZSCII_NEWLINE;
1540 /* This is like strlen() but in addition to C strings it can find the
1541 * length of a Unicode string (which is assumed to be zero terminated)
1542 * if Unicode is being used.
1544 static size_t line_len(const union line *line)
1548 if(!have_unicode) return strlen(line->latin1);
1550 for(i = 0; line->unicode[i] != 0; i++)
1558 /* Attempt to read input from the user. The input type can be either a
1559 * single character or a full line. If “timer” is not zero, a timer is
1560 * started that fires off every “timer” tenths of a second (if the value
1561 * is 1, it will timeout 10 times a second, etc.). Each time the timer
1562 * times out the routine at address “routine” is called. If the routine
1563 * returns true, the input is canceled.
1565 * The function returns 1 if input was stored, 0 if there was a
1566 * cancellation as described above.
1568 static int get_input(int16_t timer, int16_t routine, struct input *input)
1570 /* If either of these is zero, no timeout should happen. */
1571 if(timer == 0) routine = 0;
1572 if(routine == 0) timer = 0;
1574 /* Flush all streams when input is requested. */
1576 zterp_io_flush(zterp_io_stdout());
1578 zterp_io_flush(scriptio);
1579 zterp_io_flush(transio);
1581 /* Generally speaking, newline will be the reason the line input
1582 * stopped, so set it by default. It will be overridden where
1585 input->term = ZSCII_NEWLINE;
1587 if(istream == ISTREAM_FILE && istream_read_from_file(input)) return 1;
1591 struct window *saved = NULL;
1593 /* In V6, input might be requested on an unsupported window. If so,
1594 * switch to the main window temporarily.
1596 if(curwin->id == NULL)
1600 glk_set_window(curwin->id);
1603 if(input->type == INPUT_CHAR)
1609 for(int i = 0; i < input->preloaded; i++)
1611 if(have_unicode) line.unicode[i] = input->line[i];
1612 else line.latin1 [i] = input->line[i];
1615 request_line(&line, input->maxlen, input->preloaded);
1618 if(timer != 0) start_timer(timer);
1628 case evtype_Arrange:
1634 ZASSERT(timer != 0, "got unexpected evtype_Timer");
1636 struct window *saved2 = curwin;
1641 ret = direct_call(routine);
1643 /* It’s possible for an interrupt to switch windows; if it
1644 * does, simply switch back. This is the easiest way to deal
1645 * with an undefined bit of the Z-machine.
1647 if(curwin != saved2) set_current_window(saved2);
1655 /* If this got reset to 0, that means an interrupt had to
1656 * cancel the read event in order to either read or write.
1658 if(!curwin->pending_read)
1660 if(input->type == INPUT_CHAR) request_char();
1661 else request_line(&line, input->maxlen, line_len(&line));
1670 case evtype_CharInput:
1671 ZASSERT(input->type == INPUT_CHAR, "got unexpected evtype_CharInput");
1672 ZASSERT(ev.win == curwin->id, "got evtype_CharInput on unexpected window");
1678 case keycode_Delete: input->key = 8; break;
1679 case keycode_Return: input->key = 13; break;
1680 case keycode_Escape: input->key = 27; break;
1681 case keycode_Up: input->key = 129; break;
1682 case keycode_Down: input->key = 130; break;
1683 case keycode_Left: input->key = 131; break;
1684 case keycode_Right: input->key = 132; break;
1685 case keycode_Func1: input->key = 133; break;
1686 case keycode_Func2: input->key = 134; break;
1687 case keycode_Func3: input->key = 135; break;
1688 case keycode_Func4: input->key = 136; break;
1689 case keycode_Func5: input->key = 137; break;
1690 case keycode_Func6: input->key = 138; break;
1691 case keycode_Func7: input->key = 139; break;
1692 case keycode_Func8: input->key = 140; break;
1693 case keycode_Func9: input->key = 141; break;
1694 case keycode_Func10: input->key = 142; break;
1695 case keycode_Func11: input->key = 143; break;
1696 case keycode_Func12: input->key = 144; break;
1699 input->key = ZSCII_QUESTIONMARK;
1701 if(ev.val1 <= UINT16_MAX)
1703 uint8_t c = unicode_to_zscii[ev.val1];
1705 if(c != 0) input->key = c;
1713 case evtype_LineInput:
1714 ZASSERT(input->type == INPUT_LINE, "got unexpected evtype_LineInput");
1715 ZASSERT(ev.win == curwin->id, "got evtype_LineInput on unexpected window");
1716 input->len = ev.val1;
1717 #ifdef GLK_MODULE_LINE_TERMINATORS
1718 if(zversion >= 5) input->term = zscii_from_glk(ev.val2);
1727 if(input->type == INPUT_CHAR)
1729 glk_cancel_char_event(curwin->id);
1733 /* On cancellation, the buffer still needs to be filled, because
1734 * it’s possible that line input echoing has been turned off and the
1735 * contents will need to be written out.
1741 glk_cancel_line_event(curwin->id, &ev);
1742 input->len = ev.val1;
1746 for(glui32 i = 0; i < input->len; i++)
1748 if(have_unicode) input->line[i] = line.unicode[i] > UINT16_MAX ? UNICODE_QUESTIONMARK : line.unicode[i];
1749 else input->line[i] = (uint8_t)line.latin1[i];
1753 curwin->pending_read = 0;
1754 curwin->line = NULL;
1756 if(status == 1) saw_input = 1;
1758 if(errorwin != NULL)
1760 glk_window_close(errorwin, NULL);
1767 glk_set_window(curwin->id);
1772 if(input->type == INPUT_CHAR)
1777 n = zterp_io_readline(zterp_io_stdin(), line, sizeof line / sizeof *line);
1779 /* On error/eof, or if an invalid key was typed, pretend “Enter” was hit. */
1782 input->key = ZSCII_NEWLINE;
1786 input->key = unicode_to_zscii[line[0]];
1787 if(input->key == 0) input->key = ZSCII_NEWLINE;
1792 input->len = input->preloaded;
1794 if(input->maxlen > input->preloaded)
1797 uint16_t line[1024];
1799 n = zterp_io_readline(zterp_io_stdin(), line, sizeof line / sizeof *line);
1802 if(n > input->maxlen - input->preloaded) n = input->maxlen - input->preloaded;
1803 for(long i = 0; i < n; i++) input->line[i + input->preloaded] = line[i];
1813 void zread_char(void)
1816 uint16_t routine = zargs[2];
1817 struct input input = { .type = INPUT_CHAR };
1820 cancel_read_events(curwin);
1823 if(zversion >= 4 && znargs > 1) timer = zargs[1];
1825 if(!get_input(timer, routine, &input))
1835 if(streams & STREAM_SCRIPT)
1837 /* Values 127 to 159 are not valid Unicode, and these just happen to
1838 * match up to the values needed for special ZSCII keys, so store
1841 if(special_zscii(input.key)) zterp_io_putc(scriptio, input.key);
1842 else zterp_io_putc(scriptio, zscii_to_unicode[input.key]);
1849 static void status_putc(uint8_t c)
1851 glk_put_char(zscii_to_unicode[c]);
1855 void zshow_status(void)
1858 glui32 width, height;
1860 int first = variable(0x11), second = variable(0x12);
1862 if(statuswin.id == NULL) return;
1864 glk_window_clear(statuswin.id);
1866 SWITCH_WINDOW_START(&statuswin);
1868 glk_window_get_size(statuswin.id, &width, &height);
1871 garglk_set_reversevideo(1);
1873 glk_set_style(style_Alert);
1875 for(glui32 i = 0; i < width; i++) glk_put_char(ZSCII_SPACE);
1877 glk_window_move_cursor(statuswin.id, 1, 0);
1879 /* Variable 0x10 is global variable 1. */
1880 print_object(variable(0x10), status_putc);
1882 if(STATUS_IS_TIME())
1884 snprintf(rhs, sizeof rhs, "Time: %d:%02d%s ", (first + 11) % 12 + 1, second, first < 12 ? "am" : "pm");
1885 if(strlen(rhs) > width) snprintf(rhs, sizeof rhs, "%02d:%02d", first, second);
1889 snprintf(rhs, sizeof rhs, "Score: %d Moves: %d ", first, second);
1890 if(strlen(rhs) > width) snprintf(rhs, sizeof rhs, "%d/%d", first, second);
1893 if(strlen(rhs) <= width)
1895 glk_window_move_cursor(statuswin.id, width - strlen(rhs), 0);
1896 glk_put_string(rhs);
1899 SWITCH_WINDOW_END();
1903 /* This is strcmp() except that the first string is Unicode. */
1904 static int unicmp(const uint32_t *s1, const char *s2)
1906 while(*s1 != 0 && *s2 == *s1)
1917 /* Try to parse a meta command. Returns true if input should be
1918 * restarted, false to indicate no more input is required. In most
1919 * cases input will be required because the game has requested it, but
1920 * /undo and /restore jump to different locations, so the current @read
1923 static int handle_meta_command(const uint32_t *string)
1925 if(unicmp(string, "undo") == 0)
1927 uint16_t flags2 = WORD(0x10);
1928 int success = pop_save();
1933 STORE_WORD(0x10, flags2);
1935 if(zversion >= 5) store(success);
1936 else put_string("[undone]\n\n>");
1942 put_string("[no save found, unable to undo]");
1945 else if(unicmp(string, "scripton") == 0)
1947 if(output_stream(OSTREAM_SCRIPT, 0)) put_string("[transcripting on]");
1948 else put_string("[transcripting failed]");
1950 else if(unicmp(string, "scriptoff") == 0)
1952 output_stream(-OSTREAM_SCRIPT, 0);
1953 put_string("[transcripting off]");
1955 else if(unicmp(string, "recon") == 0)
1957 if(output_stream(OSTREAM_RECORD, 0)) put_string("[command recording on]");
1958 else put_string("[command recording failed]");
1960 else if(unicmp(string, "recoff") == 0)
1962 output_stream(-OSTREAM_RECORD, 0);
1963 put_string("[command recording off]");
1965 else if(unicmp(string, "replay") == 0)
1967 if(input_stream(ISTREAM_FILE)) put_string("[replaying commands]");
1968 else put_string("[replaying commands failed]");
1970 else if(unicmp(string, "save") == 0)
1972 if(interrupt_level() != 0)
1974 put_string("[cannot call /save while in an interrupt]");
1980 /* pc is currently set to the next instruction, but the restore
1981 * needs to come back to *this* instruction; so temporarily set
1982 * pc back before saving.
1985 if(do_save(1)) put_string("[saved]");
1986 else put_string("[save failed]");
1990 else if(unicmp(string, "restore") == 0)
1994 put_string("[restored]\n\n>");
1999 put_string("[restore failed]");
2002 else if(unicmp(string, "help") == 0)
2005 "/undo: undo a turn\n"
2006 "/scripton: start a transcript\n"
2007 "/scriptoff: stop a transcript\n"
2008 "/recon: start a command record\n"
2009 "/recoff: stop a command record\n"
2010 "/replay: replay a command record\n"
2011 "/save: save the game\n"
2012 "/restore: restore a game saved by /save"
2017 put_string("[unknown command]");
2025 uint16_t text = zargs[0], parse = zargs[1];
2026 uint8_t maxchars = zversion >= 5 ? user_byte(text) : user_byte(text) - 1;
2027 uint8_t zscii_string[maxchars];
2028 uint32_t string[maxchars + 1];
2029 struct input input = { .type = INPUT_LINE, .line = string, .maxlen = maxchars };
2031 uint16_t routine = zargs[3];
2034 cancel_read_events(curwin);
2037 if(zversion <= 3) zshow_status();
2039 if(zversion >= 4 && znargs > 2) timer = zargs[2];
2045 input.preloaded = user_byte(text + 1);
2046 ZASSERT(input.preloaded <= maxchars, "too many preloaded characters: %d when max is %d", input.preloaded, maxchars);
2048 for(i = 0; i < input.preloaded; i++) string[i] = zscii_to_unicode[user_byte(text + i + 2)];
2051 /* Under garglk, preloaded input works as it’s supposed to.
2052 * Under Glk, it can fail one of two ways:
2053 * 1. The preloaded text is printed out once, but is not editable.
2054 * 2. The preloaded text is printed out twice, the second being editable.
2055 * I have chosen option #2. For non-Glk, option #1 is done by necessity.
2058 if(curwin->id != NULL) garglk_unput_string_uni(string);
2062 if(!get_input(timer, routine, &input))
2065 cleanup_screen(&input);
2067 if(zversion >= 5) store(0);
2072 cleanup_screen(&input);
2079 if(options.enable_escape && (streams & STREAM_TRANS))
2081 zterp_io_putc(transio, 033);
2082 zterp_io_putc(transio, '[');
2083 for(int i = 0; options.escape_string[i] != 0; i++) zterp_io_putc(transio, options.escape_string[i]);
2086 for(int i = 0; i < input.len; i++)
2088 zscii_string[i] = unicode_to_zscii_q[unicode_tolower(string[i])];
2089 if(streams & STREAM_TRANS) zterp_io_putc(transio, string[i]);
2090 if(streams & STREAM_SCRIPT) zterp_io_putc(scriptio, string[i]);
2093 if(options.enable_escape && (streams & STREAM_TRANS))
2095 zterp_io_putc(transio, 033);
2096 zterp_io_putc(transio, '[');
2097 zterp_io_putc(transio, '0');
2098 zterp_io_putc(transio, 'm');
2101 if(streams & STREAM_TRANS) zterp_io_putc(transio, UNICODE_LINEFEED);
2102 if(streams & STREAM_SCRIPT) zterp_io_putc(scriptio, UNICODE_LINEFEED);
2104 if(!options.disable_meta_commands)
2106 string[input.len] = 0;
2108 if(string[0] == '/')
2110 if(handle_meta_command(string + 1))
2112 /* The game still wants input, so try again. */
2113 put_string("\n\n>");
2120 /* V1–4 do not have @save_undo, so simulate one each time @read is
2123 * pc is currently set to the next instruction, but the undo needs
2124 * to come back to *this* instruction; so temporarily set pc back
2125 * before pushing the save.
2129 uint32_t tmp_pc = pc;
2139 user_store_byte(text + 1, input.len); /* number of characters read */
2141 for(int i = 0; i < input.len; i++)
2143 user_store_byte(text + i + 2, zscii_string[i]);
2146 if(parse != 0) tokenize(text, parse, 0, 0);
2152 for(int i = 0; i < input.len; i++)
2154 user_store_byte(text + i + 1, zscii_string[i]);
2157 user_store_byte(text + input.len + 1, 0);
2159 tokenize(text, parse, 0, 0);
2163 void zprint_unicode(void)
2165 if(valid_unicode(zargs[0])) put_char_u(zargs[0]);
2166 else put_char_u(UNICODE_QUESTIONMARK);
2169 void zcheck_unicode(void)
2173 /* valid_unicode() will tell which Unicode characters can be printed;
2174 * and if the Unicode character is in the Unicode input table, it can
2175 * also be read. If Unicode is not available, then any character >255
2176 * is invalid for both reading and writing.
2178 if(have_unicode || zargs[0] < 256)
2180 if(valid_unicode(zargs[0])) res |= 0x01;
2181 if(unicode_to_zscii[zargs[0]] != 0) res |= 0x02;
2187 /* Should picture_data and get_wind_prop be moved to a V6 source file? */
2188 void zpicture_data(void)
2192 user_store_word(zargs[1] + 0, 0);
2193 user_store_word(zargs[1] + 2, 0);
2196 /* No pictures means no valid pictures, so never branch. */
2200 void zget_wind_prop(void)
2205 win = find_window(zargs[0]);
2207 /* These are mostly bald-faced lies. */
2210 case 0: /* y coordinate */
2213 case 1: /* x coordinate */
2216 case 2: /* y size */
2219 case 3: /* x size */
2222 case 4: /* y cursor */
2225 case 5: /* x cursor */
2228 case 6: /* left margin size */
2231 case 7: /* right margin size */
2234 case 8: /* newline interrupt routine */
2237 case 9: /* interrupt countdown */
2240 case 10: /* text style */
2243 case 11: /* colour data */
2246 case 12: /* font number */
2249 case 13: /* font size */
2250 val = (10 << 8) | 10;
2252 case 14: /* attributes */
2255 case 15: /* line count */
2258 case 16: /* true foreground colour */
2261 case 17: /* true background colour */
2265 die("unknown window property: %u", (unsigned)zargs[1]);
2271 /* This is not correct, because @output_stream does not work as it
2272 * should with a width argument; however, this does print out the
2273 * contents of a table that was sent to stream 3, so it’s at least
2276 * Output should be to the currently-selected window, but since V6 is
2277 * only marginally supported, other windows are not active. Send to the
2278 * main window for the time being.
2280 void zprint_form(void)
2282 SWITCH_WINDOW_START(mainwin);
2284 for(uint16_t i = 0; i < user_word(zargs[0]); i++)
2286 put_char(user_byte(zargs[0] + 2 + i));
2289 put_char(ZSCII_NEWLINE);
2291 SWITCH_WINDOW_END();
2294 void zmake_menu(void)
2299 void zbuffer_screen(void)
2305 /* Glk does not guarantee great control over how various styles are
2306 * going to look, but Gargoyle does. Abusing the Glk “style hints”
2307 * functions allows for quite fine-grained control over style
2308 * appearance. First, clear the (important) attributes for each style,
2309 * and then recreate each in whatever mold is necessary. Re-use some
2310 * that are expected to be correct (emphasized for italic, subheader for
2313 static void set_default_styles(void)
2315 int styles[] = { style_Subheader, style_Emphasized, style_Alert, style_Preformatted, style_User1, style_User2, style_Note };
2317 for(int i = 0; i < 7; i++)
2319 glk_stylehint_set(wintype_AllTypes, styles[i], stylehint_Size, 0);
2320 glk_stylehint_set(wintype_AllTypes, styles[i], stylehint_Weight, 0);
2321 glk_stylehint_set(wintype_AllTypes, styles[i], stylehint_Oblique, 0);
2323 /* This sets wintype_TextGrid to be proportional, which of course is
2324 * wrong; but text grids are required to be fixed, so Gargoyle
2325 * simply ignores this hint for those windows.
2327 glk_stylehint_set(wintype_AllTypes, styles[i], stylehint_Proportional, 1);
2332 int create_mainwin(void)
2337 set_default_styles();
2340 glk_stylehint_set(wintype_AllTypes, style_Subheader, stylehint_Weight, 1);
2343 glk_stylehint_set(wintype_AllTypes, style_Emphasized, stylehint_Oblique, 1);
2346 glk_stylehint_set(wintype_AllTypes, style_Alert, stylehint_Weight, 1);
2347 glk_stylehint_set(wintype_AllTypes, style_Alert, stylehint_Oblique, 1);
2350 glk_stylehint_set(wintype_AllTypes, style_Preformatted, stylehint_Proportional, 0);
2353 glk_stylehint_set(wintype_AllTypes, style_User1, stylehint_Weight, 1);
2354 glk_stylehint_set(wintype_AllTypes, style_User1, stylehint_Proportional, 0);
2357 glk_stylehint_set(wintype_AllTypes, style_User2, stylehint_Oblique, 1);
2358 glk_stylehint_set(wintype_AllTypes, style_User2, stylehint_Proportional, 0);
2360 /* Bold Italic Fixed */
2361 glk_stylehint_set(wintype_AllTypes, style_Note, stylehint_Weight, 1);
2362 glk_stylehint_set(wintype_AllTypes, style_Note, stylehint_Oblique, 1);
2363 glk_stylehint_set(wintype_AllTypes, style_Note, stylehint_Proportional, 0);
2366 mainwin->id = glk_window_open(0, 0, 0, wintype_TextBuffer, 1);
2367 if(mainwin->id == NULL) return 0;
2368 glk_set_window(mainwin->id);
2370 #ifdef GLK_MODULE_LINE_ECHO
2371 mainwin->has_echo = glk_gestalt(gestalt_LineInputEcho, 0);
2372 if(mainwin->has_echo) glk_set_echo_line_event(mainwin->id, 0);
2381 int create_statuswin(void)
2384 if(statuswin.id == NULL) statuswin.id = glk_window_open(mainwin->id, winmethod_Above | winmethod_Fixed, 1, wintype_TextGrid, 0);
2385 return statuswin.id != NULL;
2391 int create_upperwin(void)
2394 /* On a restart, this function will get called again. It would be
2395 * possible to try to resize the upper window to 0 if it already
2396 * exists, but it’s easier to just destroy and recreate it.
2398 if(upperwin->id != NULL) glk_window_close(upperwin->id, NULL);
2400 /* The upper window appeared in V3. */
2403 upperwin->id = glk_window_open(mainwin->id, winmethod_Above | winmethod_Fixed, 0, wintype_TextGrid, 0);
2404 upperwin->x = upperwin->y = 0;
2405 upper_window_height = 0;
2407 if(upperwin->id != NULL)
2411 glk_window_get_size(upperwin->id, &w, &h);
2412 upper_window_width = w;
2414 if(h != 0 || upper_window_width == 0)
2416 glk_window_close(upperwin->id, NULL);
2417 upperwin->id = NULL;
2422 return upperwin->id != NULL;
2428 void init_screen(void)
2430 for(int i = 0; i < 8; i++)
2432 windows[i].style = STYLE_NONE;
2433 windows[i].font = FONT_NORMAL;
2434 windows[i].prev_font = FONT_NONE;
2437 clear_window(&windows[i]);
2438 #ifdef GLK_MODULE_LINE_TERMINATORS
2439 if(windows[i].id != NULL && term_nkeys != 0 && glk_gestalt(gestalt_LineTerminators, 0)) glk_set_terminators_line_event(windows[i].id, term_keys, term_nkeys);
2444 close_upper_window();
2447 if(statuswin.id != NULL) glk_window_clear(statuswin.id);
2449 if(errorwin != NULL)
2451 glk_window_close(errorwin, NULL);
2458 fg_color = zcolor_Default;
2459 bg_color = zcolor_Default;
2467 if(scriptio != NULL) zterp_io_close(scriptio);
2470 input_stream(ISTREAM_KEYBOARD);
2472 streams = STREAM_SCREEN;
2474 set_current_window(mainwin);