/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef GLK_FROTZ_PROCESSOR #define GLK_FROTZ_PROCESSOR #include "glk/frotz/mem.h" #include "glk/frotz/glk_interface.h" #include "glk/frotz/frotz_types.h" #include "common/stack.h" namespace Glk { namespace Frotz { #define TEXT_BUFFER_SIZE 200 #define CODE_BYTE(v) v = codeByte() #define CODE_WORD(v) v = codeWord() #define CODE_IDX_WORD(v,i) v = codeWordIdx(i) #define GET_PC(v) v = getPC() #define SET_PC(v) setPC(v) enum string_type { LOW_STRING, ABBREVIATION, HIGH_STRING, EMBEDDED_STRING, VOCABULARY }; class Processor; class Quetzal; typedef void (Processor::*Opcode)(); /** * Zcode processor */ class Processor : public GlkInterface, public virtual Mem { friend class Quetzal; private: static const char *const ERR_MESSAGES[ERR_NUM_ERRORS]; static Opcode var_opcodes[64]; static Opcode ext_opcodes[64]; Common::Array<Opcode> op0_opcodes; Common::Array<Opcode> op1_opcodes; int _finished; zword zargs[8]; int zargc; uint _randomInterval; uint _randomCtr; bool first_restart; bool script_valid; // Stack data zword _stack[STACK_SIZE]; zword *_sp; zword *_fp; zword _frameCount; // Text related fields static zchar ZSCII_TO_LATIN1[]; zchar *_decoded, *_encoded; int _resolution; int _errorCount[ERR_NUM_ERRORS]; // Buffer related fields bool _locked; zchar _prevC; zchar _buffer[TEXT_BUFFER_SIZE]; size_t _bufPos; // Stream related fields int script_width; strid_t sfp, rfp, pfp; bool ostream_screen; bool ostream_script; bool ostream_memory; bool ostream_record; bool istream_replay; bool message; Common::FixedStack<Redirect, MAX_NESTING> _redirect; protected: /** * \defgroup General support methods * @{ */ /** * Load an operand, either a variable or a constant. */ void load_operand(zbyte type); /** * Given the operand specifier byte, load all (up to four) operands * for a VAR or EXT opcode. */ void load_all_operands(zbyte specifier); /** * Call a subroutine. Save PC and FP then load new PC and initialise * new stack frame. Note that the caller may legally provide less or * more arguments than the function actually has. The call type "ct" * can be 0 (z_call_s), 1 (z_call_n) or 2 (direct call). */ void call(zword routine, int argc, zword *args, int ct); /** * Return from the current subroutine and restore the previous _stack * frame. The result may be stored (0), thrown away (1) or pushed on * the stack (2). In the latter case a direct call has been finished * and we must exit the interpreter loop. */ void ret(zword value); /** * Take a jump after an instruction based on the flag, either true or * false. The branch can be short or long; it is encoded in one or two * bytes respectively. When bit 7 of the first byte is set, the jump * takes place if the flag is true; otherwise it is taken if the flag * is false. When bit 6 of the first byte is set, the branch is short; * otherwise it is long. The offset occupies the bottom 6 bits of the * first byte plus all the bits in the second byte for long branches. * Uniquely, an offset of 0 means return false, and an offset of 1 is * return true. */ void branch(bool flag); /** * Store an operand, either as a variable or pushed on the stack. */ void store(zword value); /* * Call the interpreter loop directly. This is necessary when * * - a sound effect has been finished * - a read instruction has timed out * - a newline countdown has hit zero * * The interpreter returns the result value on the stack. */ int direct_call(zword addr); /** * Set the seed value for the random number generator. */ void seed_random(int value); /**@}*/ /** * \defgroup Input support methods * @{ */ /** * High level output function. */ void print_char(zchar c); /** * Print a string of ASCII characters. */ void print_string(const char *s); /** * Print an unsigned 32bit number in decimal or hex. */ void print_long(uint value, int base); /** * High level newline function. */ void new_line(); /** * Copy the contents of the text buffer to the output streams. */ void flush_buffer(); /** * Returns true if the buffer is empty */ bool bufferEmpty() const { return !_bufPos; } /** * An error has occurred. Ignore it, pass it to os_fatal or report * it according to err_report_mode. * @param errNum Numeric code for error (1 to ERR_NUM_ERRORS) */ void runtimeError(ErrorCode errNum); /**@}*/ /** * \defgroup Input support methods * @{ */ /** * Check if the given key is an input terminator. */ bool is_terminator(zchar key); /** * Ask the user a question; return true if the answer is yes. */ bool read_yes_or_no(const char *s); /** * Read a string from the current input stream. */ void read_string(int max, zchar *buffer); /** * Ask the user to type in a number and return it. */ int read_number(); /**@}*/ /** * \defgroup Memory support methods * @{ */ /** * Called when the H_FLAGS field of the header has changed */ virtual void flagsChanged(zbyte value) override; /** * This function does the dirty work for z_save_undo. */ int save_undo(); /** * This function does the dirty work for z_restore_undo. */ int restore_undo(); /** * Begin output redirection to the memory of the Z-machine. */ void memory_open(zword table, zword xsize, bool buffering); /** * End of output redirection. */ void memory_close(); /** * Redirect a newline to the memory of the Z-machine. */ void memory_new_line(); /** * Redirect a string of characters to the memory of the Z-machine. */ void memory_word(const zchar *s); /**@}*/ /** * \defgroup Object support methods * @{ */ /** * Calculate the address of an object. */ zword object_address(zword obj); /** * Return the address of the given object's name. */ zword object_name(zword object); /** * Calculate the start address of the property list associated with an object. */ zword first_property(zword obj); /** * Calculate the address of the next property in a property list. */ zword next_property(zword prop_addr); /** * Unlink an object from its parent and siblings. */ void unlink_object(zword object); /**@}*/ /** * \defgroup Screen support methods * @{ */ /** * Start printing a so-called debugging message. The contents of the * message are passed to the message stream, a Frotz specific output * stream with maximum priority. */ void screen_mssg_on(); /** * Stop printing a "debugging" message */ void screen_mssg_off(); /** * Map a runic character to its Unicode equivalent, if there is one */ uint32 zchar_to_unicode_rune(zchar c); /** * Display a single character on the screen. */ void screen_char(zchar c); /** * Print a newline to the screen. */ void screen_new_line(); /** * Print a newline to the screen. */ void screen_word(const zchar *s); /** * Erase the entire screen to background colour. */ void erase_screen(zword win); /** * Erase a window to background colour. */ void erase_window(zword win); /**@}*/ /** * \defgroup Stream support methods * @{ */ /** * Waits for the user to type an input line */ zchar console_read_input(int max, zchar *buf, zword timeout, bool continued); /** * Waits for a keypress */ zchar console_read_key(zword timeout); /** * Write a single character to the scrollback buffer. * */ void scrollback_char(zchar c); /** * Write a string to the scrollback buffer. */ void scrollback_word(const zchar *s); /** * Send an input line to the scrollback buffer. */ void scrollback_write_input(const zchar *buf, zchar key); /** * Remove an input line from the scrollback buffer. */ void scrollback_erase_input(const zchar *buf); /** * Start printing a "debugging" message. */ void stream_mssg_on(); /** * Stop printing a "debugging" message. */ void stream_mssg_off(); /** * Send a single character to the output stream. */ void stream_char(zchar c); /** * Send a string of characters to the output streams. */ void stream_word(const zchar *s); /** * Send a newline to the output streams. */ void stream_new_line(); /** * Read a single keystroke from the current input stream. */ zchar stream_read_key(zword timeout, zword routine, bool hot_keys); /** * Read a line of input from the current input stream. */ zchar stream_read_input(int max, zchar *buf, zword timeout, zword routine, bool hot_keys, bool no_scripting); /* * script_open * * Open the transscript file. 'AMFV' makes this more complicated as it * turns transscription on/off several times to exclude some text from * the transscription file. This wasn't a problem for the original V4 * interpreters which always sent transscription to the printer, but it * means a problem to modern interpreters that offer to open a new file * every time transscription is turned on. Our solution is to append to * the old transscription file in V1 to V4, and to ask for a new file * name in V5+. * */ void script_open(); /* * Stop transscription. */ void script_close(); /** * Write a newline to the transscript file. */ void script_new_line(); /** * Write a single character to the transscript file. */ void script_char(zchar c); /** * Write a string to the transscript file. */ void script_word(const zchar *s); /** * Send an input line to the transscript file. */ void script_write_input(const zchar *buf, zchar key); /** * Remove an input line from the transscript file. */ void script_erase_input(const zchar *buf); /** * Start sending a "debugging" message to the transscript file. */ void script_mssg_on(); /** * Stop writing a "debugging" message. */ void script_mssg_off(); /** * Open a file to record the player's input. */ void record_open(); /** * Stop recording the player's input. */ void record_close(); /** * Helper function for record_char. */ void record_code(int c, bool force_encoding); /** * Write a character to the command file. */ void record_char(zchar c); /** * Copy a keystroke to the command file. */ void record_write_key(zchar key); /** * Copy a line of input to a command file. */ void record_write_input(const zchar *buf, zchar key); /** * Open a file of commands for playback. */ void replay_open(); /** * Stop playback of commands. */ void replay_close(); /* * Helper function for replay_key and replay_line. */ int replay_code(); /** * Read a character from the command file. */ zchar replay_char(); /** * Read a keystroke from a command file. */ zchar replay_read_key(); /* * Read a line of input from a command file. */ zchar replay_read_input(zchar *buf); /**@}*/ /** * \defgroup Text support methods * @{ */ /** * Map a ZSCII character into Unicode. */ zchar translate_from_zscii(zbyte c); /** * Convert a Unicode character to ZSCII, returning 0 on failure. */ zbyte unicode_to_zscii(zchar c); /** * Map a Unicode character onto the ZSCII alphabet. */ zbyte translate_to_zscii(zchar c); /** * Return a character from one of the three character sets. */ zchar alphabet(int set, int index); /** * Find the number of bytes used for dictionary resolution. */ void find_resolution(); /** * Copy a ZSCII string from the memory to the global "decoded" string. */ void load_string(zword addr, zword length); /** * Encode the Unicode text in the global "decoded" string then write * the result to the global "encoded" array. (This is used to look up * words in the dictionary.) Up to V3 the vocabulary resolution is * two, from V4 it is three, and from V9 it is any number of words. * Because each word contains three Z-characters, that makes six or * nine Z-characters respectively. Longer words are chopped to the * proper size, shorter words are are padded out with 5's. For word * completion we pad with 0s and 31s, the minimum and maximum * Z-characters. */ void encode_text(int padding); /** * Convert _encoded text to Unicode. The _encoded text consists of 16bit * words. Every word holds 3 Z-characters (5 bits each) plus a spare * bit to mark the last word. The Z-characters translate to ZSCII by * looking at the current current character set. Some select another * character set, others refer to abbreviations. * * There are several different string types: * * LOW_STRING - from the lower 64KB (byte address) * ABBREVIATION - from the abbreviations table (word address) * HIGH_STRING - from the end of the memory map (packed address) * EMBEDDED_STRING - from the instruction stream (at PC) * VOCABULARY - from the dictionary (byte address) * * The last type is only used for word completion. */ void decode_text(string_type st, zword addr); /** * Print a signed 16bit number. */ void print_num(zword value); /** * print_object * * Print an object description. * */ void print_object(zword object); /** * Scan a dictionary searching for the given word. The first argument * can be * * 0x00 - find the first word which is >= the given one * 0x05 - find the word which exactly matches the given one * 0x1f - find the last word which is <= the given one * * The return value is 0 if the search fails. */ zword lookup_text(int padding, zword dct); /** * Handles converting abbreviations that weren't handled by early Infocom games * into their expanded versions */ void handleAbbreviations(); /** * Translate a single word to a token and append it to the token * buffer. Every token consists of the address of the dictionary * entry, the length of the word and the offset of the word from * the start of the text buffer. Unknown words cause empty slots * if the flag is set (such that the text can be scanned several * times with different dictionaries); otherwise they are zero. * */ void tokenise_text(zword text, zword length, zword from, zword parse, zword dct, bool flag); /** * Split an input line into words and translate the words to tokens. */ void tokenise_line(zword text, zword token, zword dct, bool flag); /** * Scan the vocabulary to complete the last word on the input line * (similar to "tcsh" under Unix). The return value is * * 2 ==> completion is impossible * 1 ==> completion is ambiguous * 0 ==> completion is successful * * The function also returns a string in its second argument. In case * of 2, the string is empty; in case of 1, the string is the longest * extension of the last word on the input line that is common to all * possible completions (for instance, if the last word on the input * is "fo" and its only possible completions are "follow" and "folly" * then the string is "ll"); in case of 0, the string is an extension * to the last word that results in the only possible completion. */ int completion(const zchar *buffer, zchar *result); /** * Convert a Unicode character to lowercase. * Taken from Zip2000 by Kevin Bracey. */ zchar unicode_tolower(zchar c); /**@}*/ /** * \defgroup Window/V6 Opcode methods * @{ */ /** * Return the window number in zargs[0]. In V6 only, -3 refers to the * current window. */ zword winarg0(); /** * Return the (optional) window number in zargs[2]. -3 refers to the * current window. This optional window number was only used by some * V6 opcodes: set_cursor, set_margins, set_colour. */ zword winarg2(); /**@}*/ protected: /** * \defgroup General Opcode methods * @{ */ /* * Load and execute an extended opcode. */ void __extended__(); /* * Exit game because an unknown opcode has been hit. */ void __illegal__(); /* * Store the current _stack frame for later use with z_throw. * * no zargs used */ void z_catch(); /** * Go back to the given _stack frame and return the given value. * * zargs[0] = value to return * zargs[1] = _stack frame */ void z_throw(); /* * Call a subroutine and discard its result. * * zargs[0] = packed address of subroutine * zargs[1] = first argument (optional) * ... * zargs[7] = seventh argument (optional) */ void z_call_n(); /** * Call a subroutine and store its result. * * zargs[0] = packed address of subroutine * zargs[1] = first argument (optional) * ... * zargs[7] = seventh argument (optional) */ void z_call_s(); /** * Branch if subroutine was called with >= n arg's. * * zargs[0] = number of arguments */ void z_check_arg_count(); /** * Jump unconditionally to the given address. * * zargs[0] = PC relative address */ void z_jump(); /* * No operation. * * no zargs used */ void z_nop(); /* * Stop game and exit interpreter. * * no zargs used */ void z_quit(); /* * Return from a subroutine with the given value. * * zargs[0] = value to return */ void z_ret(); /* * Return from a subroutine with a value popped off the stack. * * no zargs used */ void z_ret_popped(); /* * Return from a subroutine with false (0). * * no zargs used */ void z_rfalse(); /* * Return from a subroutine with true (1). * * no zargs used */ void z_rtrue(); /** * Store a random number or set the random number seed. * * zargs[0] = range (positive) or seed value (negative) */ void z_random(); /** * Load / play / stop / discard a sound effect. * * zargs[0] = number of bleep (1 or 2) or sample * zargs[1] = operation to perform (samples only) * zargs[2] = repeats and volume (play sample only) * zargs[3] = end-of-sound routine (play sample only, optional) * * Note: Volumes range from 1 to 8, volume 255 is the default volume. * Repeats are stored in the high byte, 255 is infinite loop. * */ void z_sound_effect(); /** * Branch if the story file is a legal copy */ void z_piracy(); /** * Save the current Z-machine state for a future undo. * * no zargs used */ void z_save_undo(); /** * Restore a Z-machine state from memory. * * no zargs used */ void z_restore_undo(); /**@}*/ /** * \defgroup Input Opcode methods * @{ */ /** * Add or remove a menu and branch if successful. * * zargs[0] = number of menu * zargs[1] = table of menu entries or 0 to remove menu */ void z_make_menu(); /** * Read a line of input and (in V5+) store the terminating key. * * zargs[0] = address of text buffer * zargs[1] = address of token buffer * zargs[2] = timeout in tenths of a second (optional) * zargs[3] = packed address of routine to be called on timeout */ void z_read(); /** * Read and store a key. * * zargs[0] = input device (must be 1) * zargs[1] = timeout in tenths of a second (optional) * zargs[2] = packed address of routine to be called on timeout */ void z_read_char(); /** * z_read_mouse, write the current mouse status into a table. * * zargs[0] = address of table */ void z_read_mouse(); /**@}*/ /** * \defgroup Math Opcode methods * @{ */ /** * 16 bit addition. * * zargs[0] = first value * zargs[1] = second value */ void z_add(); /** * Bitwise AND operation. * * zargs[0] = first value * zargs[1] = second value */ void z_and(); /** * Arithmetic SHIFT operation. * * zargs[0] = value * zargs[1] = #positions to shift left (positive) or right */ void z_art_shift(); /** * Signed 16bit division. * * zargs[0] = first value * zargs[1] = second value */ void z_div(); /** * B ranch if the first value equals any of the following. * * zargs[0] = first value * zargs[1] = second value (optional) * ... * zargs[3] = fourth value (optional) */ void z_je(); /** * Branch if the first value is greater than the second. * * zargs[0] = first value * zargs[1] = second value */ void z_jg(); /** * Branch if the first value is less than the second. * * zargs[0] = first value * zargs[1] = second value */ void z_jl(); /** * Branch if value is zero. * * zargs[0] = value */ void z_jz(); /** * Logical SHIFT operation. * * zargs[0] = value * zargs[1] = #positions to shift left (positive) or right (negative) */ void z_log_shift(); /* * Remainder after signed 16bit division. * * zargs[0] = first value * zargs[1] = second value */ void z_mod(); /** * 16 bit multiplication. * * zargs[0] = first value * zargs[1] = second value */ void z_mul(); /** * Bitwise NOT operation. * * zargs[0] = value */ void z_not(); /** * Bitwise OR operation. * * zargs[0] = first value * zargs[1] = second value */ void z_or(); /** * 16 bit substraction. * * zargs[0] = first value * zargs[1] = second value */ void z_sub(); /** * Branch if all the flags of a bit mask are set in a value. * * zargs[0] = value to be examined * zargs[1] = bit mask */ void z_test(); /**@}*/ /** * \defgroup Object Opcode methods * @{ */ /** * Branch if the first object is inside the second. * * zargs[0] = first object * zargs[1] = second object */ void z_jin(); /** * Store the child of an object. * * zargs[0] = object */ void z_get_child(); /** * Store the number of the first or next property. * * zargs[0] = object * zargs[1] = address of current property (0 gets the first property) */ void z_get_next_prop(); /** * Store the parent of an object. * * zargs[0] = object */ void z_get_parent(); /** * Store the value of an object property. * * zargs[0] = object * zargs[1] = number of property to be examined */ void z_get_prop(); /** * Store the address of an object property. * * zargs[0] = object * zargs[1] = number of property to be examined */ void z_get_prop_addr(); /** * Store the length of an object property. * * zargs[0] = address of property to be examined */ void z_get_prop_len(); /** * Store the sibling of an object. * * zargs[0] = object */ void z_get_sibling(); /** * Make an object the first child of another object. * * zargs[0] = object to be moved * zargs[1] = destination object */ void z_insert_obj(); /** * Set the value of an object property. * * zargs[0] = object * zargs[1] = number of property to set * zargs[2] = value to set property to */ void z_put_prop(); /** * Unlink an object from its parent and siblings. * * zargs[0] = object */ void z_remove_obj(); /** * Set an object attribute. * * zargs[0] = object * zargs[1] = number of attribute to set */ void z_set_attr(); /** * Branch if an object attribute is set. * * zargs[0] = object * zargs[1] = number of attribute to test */ void z_test_attr(); /** * Clear an object attribute. * * zargs[0] = object * zargs[1] = number of attribute to be cleared */ void z_clear_attr(); /**@}*/ /** * \defgroup Screen Opcode methods * @{ */ /** * Turn text buffering on/off. * * zargs[0] = new text buffering flag (0 or 1) */ void z_buffer_mode(); /** * Set the screen buffering mode. * * zargs[0] = mode */ void z_buffer_screen(); /** * Erase the line starting at the cursor position. * * zargs[0] = 1 + #units to erase (1 clears to the end of the line) */ void z_erase_line(); /** * Erase a window or the screen to background colour. * * zargs[0] = window (-3 current, -2 screen, -1 screen & unsplit) */ void z_erase_window(); /** * Write the cursor coordinates into a table. * * zargs[0] = address to write information to */ void z_get_cursor(); /** * Print ASCII text in a rectangular area. * * zargs[0] = address of text to be printed * zargs[1] = width of rectangular area * zargs[2] = height of rectangular area (optional) * zargs[3] = number of char's to skip between lines (optional) */ void z_print_table(); /** * Set the foreground and background colours * to specific RGB colour values. * * zargs[0] = foreground colour * zargs[1] = background colour * zargs[2] = window (-3 is the current one, optional) */ void z_set_true_colour(); /** * Set the foreground and background colours. * * zargs[0] = foreground colour * zargs[1] = background colour * zargs[2] = window (-3 is the current one, optional) */ void z_set_colour(); /** * Set the font for text output and store the previous font. * * zargs[0] = number of font or 0 to keep current font */ void z_set_font(); /** * Set the cursor position or turn the cursor on/off. * * zargs[0] = y-coordinate or -2/-1 for cursor on/off * zargs[1] = x-coordinate * zargs[2] = window (-3 is the current one, optional) */ void z_set_cursor(); /** * z_set_text_style, set the style for text output. * * zargs[0] = style flags to set or 0 to reset text style */ void z_set_text_style(); /** * Select the current window. * * zargs[0] = window to be selected (-3 is the current one) */ void z_set_window(); /** * Display the status line for V1 to V3 games. * * no zargs used */ void pad_status_line(int column); /** * Display the status line for V1 to V3 games. * * no zargs used */ void z_show_status(); /** * Split the screen into an upper (1) and lower (0) window. * * zargs[0] = height of upper window in screen units (V6) or #lines */ void z_split_window(); /**@}*/ /** * \defgroup Stream Opcode methods * @{ */ /** * Select an input stream. * * zargs[0] = input stream to be selected */ void z_input_stream(); /** * Open or close an output stream. * * zargs[0] = stream to open (positive) or close (negative) * zargs[1] = address to redirect output to (stream 3 only) * zargs[2] = width of redirected output (stream 3 only, optional) */ void z_output_stream(); /** * Re-load dynamic area, clear the stack and set the PC. * * no zargs used */ void z_restart(); /** * Save [a part of] the Z-machine state to disk. * * zargs[0] = address of memory area to save (optional) * zargs[1] = number of bytes to save * zargs[2] = address of suggested file name */ void z_save(); /** * Restore [a part of] a Z-machine state from disk * * zargs[0] = address of area to restore (optional) * zargs[1] = number of bytes to restore * zargs[2] = address of suggested file name */ void z_restore(); /** * Check the story file integrity. * * no zargs used */ void z_verify(); /**@}*/ /** * \defgroup Table Opcode methods * @{ */ /** * Copy a table or fill it with zeroes. * * zargs[0] = address of table * zargs[1] = destination address or 0 for fill * zargs[2] = size of table * * Note: Copying is safe even when source and destination overlap; but * if zargs[1] is negative the table _must_ be copied forwards. */ void z_copy_table(); /** * Store a value from a table of bytes. * * zargs[0] = address of table * zargs[1] = index of table entry to store */ void z_loadb(); /** * Store a value from a table of words. * * zargs[0] = address of table * zargs[1] = index of table entry to store */ void z_loadw(); /** * Find and store the address of a target within a table. * * zargs[0] = target value to be searched for * zargs[1] = address of table * zargs[2] = number of table entries to check value against * zargs[3] = type of table (optional, defaults to 0x82) * * Note: The table is a word array if bit 7 of zargs[3] is set; otherwise * it's a byte array. The lower bits hold the address step. */ void z_scan_table(); /** * Write a byte into a table of bytes. * * zargs[0] = address of table * zargs[1] = index of table entry * zargs[2] = value to be written */ void z_storeb(); /** * Write a word into a table of words. * * zargs[0] = address of table * zargs[1] = index of table entry * zargs[2] = value to be written */ void z_storew(); /**@}*/ /** * \defgroup Text Opcode methods * @{ */ /** * Test if a unicode character can be printed (bit 0) and read (bit 1). * * zargs[0] = Unicode */ void z_check_unicode(); /** * Encode a ZSCII string for use in a dictionary. * * zargs[0] = address of text buffer * zargs[1] = length of ASCII string * zargs[2] = offset of ASCII string within the text buffer * zargs[3] = address to store encoded text in * * This is a V5+ opcode and therefore the dictionary resolution must be * three 16bit words. */ void z_encode_text(); /** * Print a new line. * * no zargs used * */ void z_new_line(); /** * Print a string embedded in the instruction stream. * * no zargs used */ void z_print(); /** * Print a string from the lower 64KB. * * zargs[0] = address of string to print */ void z_print_addr(); /** * Print a single ZSCII character. * * zargs[0] = ZSCII character to be printed */ void z_print_char(); /** * Print a formatted table. * * zargs[0] = address of formatted table to be printed */ void z_print_form(); /** * Print a signed number. * * zargs[0] = number to print */ void z_print_num(); /** * Print an object description. * * zargs[0] = number of object to be printed */ void z_print_obj(); /** * Print the string at the given packed address. * * zargs[0] = packed address of string to be printed */ void z_print_paddr(); /* * Print the string at PC, print newline then return true. * * no zargs used */ void z_print_ret(); /** * Print unicode character * * zargs[0] = Unicode */ void z_print_unicode(); /** * Make a lexical analysis of a ZSCII string. * * zargs[0] = address of string to analyze * zargs[1] = address of token buffer * zargs[2] = address of dictionary (optional) * zargs[3] = set when unknown words cause empty slots (optional) */ void z_tokenise(); /**@}*/ /** * \defgroup Variable Opcode methods * @{ */ /** * Decrement a variable. * * zargs[0] = variable to decrement */ void z_dec(); /** * Decrement a variable and branch if now less than value. * * zargs[0] = variable to decrement * zargs[1] = value to check variable against */ void z_dec_chk(); /** * Increment a variable. * * zargs[0] = variable to increment */ void z_inc(); /** * Increment a variable and branch if now greater than value. * * zargs[0] = variable to increment * zargs[1] = value to check variable against */ void z_inc_chk(); /** * Store the value of a variable. * * zargs[0] = variable to store */ void z_load(); /** * Pop a value off the game stack and discard it. * * no zargs used */ void z_pop(); /** * Pop n values off the game or user stack and discard them. * * zargs[0] = number of values to discard * zargs[1] = address of user stack (optional) */ void z_pop_stack(); /** * Pop a value off... * * a) ...the game or a user stack and store it (V6) * * zargs[0] = address of user stack (optional) * * b) ...the game stack and write it to a variable (other than V6) * * zargs[0] = variable to write value to */ void z_pull(); /** * Push a value onto the game stack. * * zargs[0] = value to push onto the stack */ void z_push(); /** * Push a value onto a user stack then branch if successful. * * zargs[0] = value to push onto the stack * zargs[1] = address of user stack */ void z_push_stack(); /** * Write a value to a variable. * * zargs[0] = variable to be written to * zargs[1] = value to write */ void z_store(); /**@}*/ /** * \defgroup Window/V6 Opcode methods * @{ */ /** * z_draw_picture, draw a picture. * * zargs[0] = number of picture to draw * zargs[1] = y-coordinate of top left corner * zargs[2] = x-coordinate of top left corner */ void z_draw_picture(); /** * Get information on a picture or the graphics file. * * zargs[0] = number of picture or 0 for the graphics file * zargs[1] = address to write information to */ void z_picture_data(); /** * Erase a picture with background colour. * * zargs[0] = number of picture to erase * zargs[1] = y-coordinate of top left corner (optional) * zargs[2] = x-coordinate of top left corner (optional) */ void z_erase_picture(); /** * Set the left and right margins of a window. * * zargs[0] = left margin in pixels * zargs[1] = right margin in pixels * zargs[2] = window (-3 is the current one, optional) */ void z_set_margins(); /** * Place a window on the screen. * * zargs[0] = window (-3 is the current one) * zargs[1] = y-coordinate * zargs[2] = x-coordinate * */ void z_move_window(); /** * Change the width and height of a window. * * zargs[0] = window (-3 is the current one) * zargs[1] = new height in screen units * zargs[2] = new width in screen units */ void z_window_size(); /** * Set / clear / toggle window attributes. * * zargs[0] = window (-3 is the current one) * zargs[1] = window attribute flags * zargs[2] = operation to perform (optional, defaults to 0) */ void z_window_style(); /** * Store the value of a window property. * * zargs[0] = window (-3 is the current one) * zargs[1] = number of window property to be stored */ void z_get_wind_prop(); /** * Set the value of a window property. * * zargs[0] = window (-3 is the current one) * zargs[1] = number of window property to set * zargs[2] = value to set window property to */ void z_put_wind_prop(); /** * Scroll a window up or down. * * zargs[0] = window (-3 is the current one) * zargs[1] = #screen units to scroll up (positive) or down (negative) */ void z_scroll_window(); /** * Select a window as mouse window. * * zargs[0] = window number (-3 is the current) or -1 for the screen */ void z_mouse_window(); /** * Prepare a group of pictures for faster display. * * zargs[0] = address of table holding the picture numbers */ void z_picture_table(); /**@}*/ public: /** * Constructor */ Processor(OSystem *syst, const GlkGameDescription &gameDesc); virtual ~Processor() {} /** * Initialization */ void initialize(); /** * Z-code interpreter main loop */ void interpret(); /** * \defgroup Memory access methods * @{ */ /** * Square brackets operator */ zbyte &operator[](uint addr) { return zmp[addr]; } /** * Read a code byte */ zbyte codeByte() { return *pcp++; } /** * Read a code word */ zword codeWord() { zword v = READ_BE_UINT16(pcp); pcp += 2; return v; } /** * Return a code word at a given address */ zword codeWordIdx(uint addr) const { return READ_BE_UINT16(pcp + addr); } /** * Return the current program execution offset */ uint getPC() const { assert(pcp); return pcp - zmp; } /** * Set the program execution offset */ void setPC(uint addr) { pcp = zmp + addr; } /**@}*/ }; } // End of namespace Frotz } // End of namespace Glk #endif