}/* memory_word */ /* * memory_close * * End of output redirection. * */ internal static void MemoryClose() { if (depth >= 0) { if (redirect[depth].XSize != 0xffff) { MemoryNewline(); } if (Main.h_version == ZMachine.V6) { Main.h_line_width = (redirect[depth].XSize != 0xffff) ? redirect[depth].Total : redirect[depth].Width; FastMem.SetWord(ZMachine.H_LINE_WIDTH, Main.h_line_width); } if (depth == 0) { Main.ostream_memory = false; } depth--; } }/* memory_close */
/* * memory_open * * Begin output redirection to the memory of the Z-machine. * */ internal static void MemoryOpen(zword table, zword xsize, bool buffering) { if (++depth < MAX_NESTING) { if (!buffering) { xsize = 0xffff; } if (buffering && (short)xsize <= 0) { xsize = Screen.GetMaxWidth((zword)(-(short)xsize)); } FastMem.StoreW(table, 0); redirect[depth].Table = table; redirect[depth].Width = 0; redirect[depth].Total = 0; redirect[depth].XSize = xsize; Main.ostream_memory = true; } else { Err.RuntimeError(ErrorCodes.ERR_STR3_NESTING); } }/* memory_open */
} /* z_copy_table */ /* * z_loadb, store a value from a table of bytes. * * zargs[0] = address of table * zargs[1] = index of table entry to store * */ internal static void ZLoadB() { zword addr = (zword)(Process.zargs[0] + Process.zargs[1]); FastMem.LowByte(addr, out byte value); Process.Store(value); } /* z_loadb */
} /* z_loadb */ /* * z_loadw, store a value from a table of words. * * zargs[0] = address of table * zargs[1] = index of table entry to store * */ internal static void ZLoadW() { zword addr = (zword)(Process.zargs[0] + 2 * Process.zargs[1]); FastMem.LowWord(addr, out ushort value); Process.Store(value); } /* z_loadw */
}/* z_piracy */ /* * main * * Prepare and run the game. * */ public static int MainFunc(string[] args) { if (os_.process_arguments(args)) { Buffer.init_buffer(); Err.init_err(); FastMem.init_memory(); Process.init_process(); Sound.init_sound(); Text.init_text(); os_.init_screen(); FastMem.init_undo(); FastMem.z_restart(); os_.game_started(); // New function; Called to allow the screen to know info about the game Process.interpret(); FastMem.reset_memory(); os_.reset_screen(); } return(0); }/* main */
/* * z_copy_table, 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. * */ internal static void ZCopyTable() { zword addr; zword size = Process.zargs[2]; zbyte value; int i; if (Process.zargs[1] == 0) /* zero table */ { for (i = 0; i < size; i++) { FastMem.StoreB((zword)(Process.zargs[0] + i), 0); } } else if ((short)size < 0 || Process.zargs[0] > Process.zargs[1]) /* copy forwards */ { for (i = 0; i < (((short)size < 0) ? -(short)size : size); i++) { addr = (zword)(Process.zargs[0] + i); FastMem.LowByte(addr, out value); FastMem.StoreB((zword)(Process.zargs[1] + i), value); } } else /* copy backwards */ { for (i = size - 1; i >= 0; i--) { addr = (zword)(Process.zargs[0] + i); FastMem.LowByte(addr, out value); FastMem.StoreB((zword)(Process.zargs[1] + i), value); } } } /* z_copy_table */
}/* memory_open */ /* * memory_new_line * * Redirect a newline to the memory of the Z-machine. * */ internal static void memory_new_line() { zword size; zword addr; redirect[depth].total += redirect[depth].width; redirect[depth].width = 0; addr = redirect[depth].table; FastMem.LOW_WORD(addr, out size); addr += 2; if (redirect[depth].xsize != 0xffff) { redirect[depth].table = (zword)(addr + size); size = 0; } else { FastMem.storeb((zword)(addr + (size++)), 13); } FastMem.storew(redirect[depth].table, size); }/* memory_new_line */
/* * memory_open * * Begin output redirection to the memory of the Z-machine. * */ internal static void memory_open(zword table, zword xsize, bool buffering) { if (++depth < MAX_NESTING) { if (!buffering) { xsize = 0xffff; } if (buffering && (short)xsize <= 0) { xsize = Screen.get_max_width((zword)(-(short)xsize)); } FastMem.storew(table, 0); redirect[depth].table = table; redirect[depth].width = 0; redirect[depth].total = 0; redirect[depth].xsize = xsize; main.ostream_memory = true; } else { Err.runtime_error(ErrorCodes.ERR_STR3_NESTING); } }/* memory_open */
}/* memory_word */ /* * memory_close * * End of output redirection. * */ internal static void memory_close() { if (depth >= 0) { if (redirect[depth].xsize != 0xffff) { memory_new_line(); } if (main.h_version == ZMachine.V6) { main.h_line_width = (redirect[depth].xsize != 0xffff) ? redirect[depth].total : redirect[depth].width; FastMem.SET_WORD(ZMachine.H_LINE_WIDTH, main.h_line_width); } if (depth == 0) { main.ostream_memory = false; } depth--; } }/* memory_close */
}/* hot_key_seed */ /* * hot_key_undo * * ...allows user to undo the previous turn. * */ internal static bool hot_key_undo() { Text.print_string("Undo one turn\n"); if (FastMem.restore_undo() > 0) { if (main.h_version >= ZMachine.V5) /* for V5+ games we must */ { Process.store(2); /* store 2 (for success) */ return(true); /* and abort the input */ } if (main.h_version <= ZMachine.V3) /* for V3- games we must */ { Screen.z_show_status(); /* draw the status line */ return(false); /* and continue input */ } } else { Text.print_string("No more undo information available.\n"); } return(false); }/* hot_key_undo */
public static void Undo() { if (Main.cwin == 0) { if (FastMem.RestoreUndo() > 0) { OS.ResetScreen(); //OS.DisplayString("One Move Undone...\n>"); if (Main.h_version >= ZMachine.V5) { /* for V5+ games we must */ Process.Store(2); /* store 2 (for success) */ return; } if (Main.h_version <= ZMachine.V3) { /* for V3- games we must */ Screen.ZShowStatus(); /* draw the status line */ return; } OS.DisplayString("\nOne move undone...\n>"); } } }
}/* translate_to_zscii */ /* * alphabet * * Return a character from one of the three character sets. * */ private static zword Alphabet(int set, int index) { if (Main.h_version > ZMachine.V1 && set == 2 && index == 1) { return(0x0D); /* always newline */ } if (Main.h_alphabet != 0) { /* game uses its own alphabet */ zword addr = (zword)(Main.h_alphabet + 26 * set + index); FastMem.LowByte(addr, out zbyte c); return(TranslateFromZscii(c)); } else /* game uses default alphabet */ if (set == 0) { return((zword)('a' + index)); } else if (set == 1) { return((zword)('A' + index)); } else if (Main.h_version == ZMachine.V1) { return(_alphabet[index]); } else { return(_alphabet[index]); } }/* alphabet */
}/* first_property */ /* * next_property * * Calculate the address of the next property in a property list. * */ static zword next_property(zword prop_addr) { zbyte value; /* Load the current property id */ FastMem.LOW_BYTE(prop_addr, out value); prop_addr++; /* Calculate the length of this property */ if (main.h_version <= ZMachine.V3) { value >>= 5; } else if (!((value & 0x80) > 0)) { value >>= 6; } else { FastMem.LOW_BYTE(prop_addr, out value); value &= 0x3f; if (value == 0) { value = 64; /* demanded by Spec 1.0 */ } } /* Add property length to current property pointer */ return((zword)(prop_addr + value + 1)); }/* next_property */
}/* z_get_prop_addr */ /* * z_get_prop_len, store the length of an object property. * * Process.zargs[0] = address of property to be examined * */ internal static void z_get_prop_len() { zword addr; zbyte value; /* Back up the property pointer to the property id */ addr = (zword)(Process.zargs[0] - 1); FastMem.LOW_BYTE(addr, out value); /* Calculate length of property */ if (main.h_version <= ZMachine.V3) { value = (zbyte)((value >> 5) + 1); } else if (!((value & 0x80) > 0)) { value = (zbyte)((value >> 6) + 1); } else { value &= 0x3f; if (value == 0) { value = 64; /* demanded by Spec 1.0 */ } } /* Store length of property */ Process.store(value); }/* z_get_prop_len */
}/* z_get_sibling */ /* * z_insert_obj, make an object the first child of another object. * * Process.zargs[0] = object to be moved * Process.zargs[1] = destination object * */ internal static void ZInsertObj() { zword obj1 = Process.zargs[0]; zword obj2 = Process.zargs[1]; zword obj1_addr; zword obj2_addr; /* If we are monitoring object movements display a short note */ if (Main.option_object_movement == true) { Stream.StreamMssgOn(); Text.PrintString("@move_obj "); Text.PrintObject(obj1); Text.PrintString(" "); Text.PrintObject(obj2); Stream.StreamMssgOff(); } if (obj1 == 0) { Err.RuntimeError(ErrorCodes.ERR_MOVE_OBJECT_0); return; } if (obj2 == 0) { Err.RuntimeError(ErrorCodes.ERR_MOVE_OBJECT_TO_0); return; } /* Get addresses of both objects */ obj1_addr = ObjectAddress(obj1); obj2_addr = ObjectAddress(obj2); /* Remove object 1 from current parent */ UnlinkObject(obj1); /* Make object 1 first child of object 2 */ if (Main.h_version <= ZMachine.V3) { obj1_addr += O1_PARENT; FastMem.SetByte(obj1_addr, (zbyte)obj2); obj2_addr += O1_CHILD; FastMem.LowByte(obj2_addr, out byte child); FastMem.SetByte(obj2_addr, (zbyte)obj1); obj1_addr += (zword)(O1_SIBLING - O1_PARENT); FastMem.SetByte(obj1_addr, child); } else { obj1_addr += O4_PARENT; FastMem.SetWord(obj1_addr, obj2); obj2_addr += O4_CHILD; FastMem.LowWord(obj2_addr, out ushort child); FastMem.SetWord(obj2_addr, obj1); obj1_addr += (zword)(O4_SIBLING - O4_PARENT); FastMem.SetWord(obj1_addr, child); } }/* z_insert_obj */
}/* z_piracy */ /* * main * * Prepare and run the game. * */ public static int MainFunc(ReadOnlySpan <string> args) { if (OS.ProcessArguments(args)) { Buffer.InitBuffer(); Err.InitErr(); FastMem.InitMemory(); Process.InitProcess(); Sound.InitSound(); Text.InitText(); OS.InitScreen(); FastMem.InitUndo(); FastMem.ZRestart(); OS.GameStarted(); // New function; Called to allow the screen to know info about the game Process.Interpret(); FastMem.ResetMemory(); //OS.ResetScreen(); } return(0); }/* main */
}/* load_all_operands */ /* * interpret * * Z-code interpreter main loop * */ internal static void interpret() { do { zbyte opcode; FastMem.CODE_BYTE(out opcode); DebugState.Output("CODE: {0} -> {1:X}", FastMem.pcp - 1, opcode); if (main.abort_game_loop == true) { main.abort_game_loop = false; return; } zargc = 0; if (opcode < 0x80) { /* 2OP opcodes */ load_operand((zbyte)((opcode & 0x40) > 0 ? 2 : 1)); load_operand((zbyte)((opcode & 0x20) > 0 ? 2 : 1)); private_invoke(var_opcodes[opcode & 0x1f], "2OP", (opcode & 0x1f), opcode); } else if (opcode < 0xb0) { /* 1OP opcodes */ load_operand((zbyte)(opcode >> 4)); private_invoke(op1_opcodes[opcode & 0x0f], "1OP", (opcode & 0x0f), opcode); } else if (opcode < 0xc0) { /* 0OP opcodes */ private_invoke(op0_opcodes[opcode - 0xb0], "0OP", (opcode - 0xb0), opcode); } else { /* VAR opcodes */ zbyte specifier1; zbyte specifier2; if (opcode == 0xec || opcode == 0xfa) { /* opcodes 0xec */ FastMem.CODE_BYTE(out specifier1); /* and 0xfa are */ FastMem.CODE_BYTE(out specifier2); /* call opcodes */ load_all_operands(specifier1); /* with up to 8 */ load_all_operands(specifier2); /* arguments */ } else { FastMem.CODE_BYTE(out specifier1); load_all_operands(specifier1); } private_invoke(var_opcodes[opcode - 0xc0], "VAR", (opcode - 0xc0), opcode); } os_.tick(); } while (finished == 0); finished--; }/* interpret */
}/* z_print_char */ /* * z_print_form, print a formatted table. * * zargs[0] = address of formatted table to be printed * */ internal static void z_print_form() { zword count; zword addr = Process.zargs[0]; bool first = true; for (;;) { FastMem.LOW_WORD(addr, out count); addr += 2; if (count == 0) { break; } if (!first) { Buffer.new_line(); } while (count-- > 0) { zbyte c; FastMem.LOW_BYTE(addr, out c); addr++; Buffer.print_char(translate_from_zscii(c)); } first = false; } }/* z_print_form */
}/* translate_to_zscii */ /* * alphabet * * Return a character from one of the three character sets. * */ static zword alphabet(int set, int index) { if (main.h_version > ZMachine.V1 && set == 2 && index == 1) { return(0x0D); /* always newline */ } if (main.h_alphabet != 0) /* game uses its own alphabet */ { zbyte c; zword addr = (zword)(main.h_alphabet + 26 * set + index); FastMem.LOW_BYTE(addr, out c); return(translate_from_zscii(c)); } else /* game uses default alphabet */ if (set == 0) { return((zword)('a' + index)); } else if (set == 1) { return((zword)('A' + index)); } else if (main.h_version == ZMachine.V1) { return(" 0123456789.,!?_#'\"/\\<-:()"[index]); } else { return(" ^0123456789.,!?_#'\"/\\-:()"[index]); } }/* alphabet */
}/* find_resolution */ /* * load_string * * Copy a ZSCII string from the memory to the global "decoded" string. * */ internal static void load_string(zword addr, zword length) { int i = 0; if (resolution == 0) { find_resolution(); } while (i < 3 * resolution) { if (i < length) { zbyte c; FastMem.LOW_BYTE(addr, out c); addr++; decoded[i++] = Text.translate_from_zscii(c); } else { decoded[i++] = 0; } } }/* load_string */
}/* lookup_text */ /* * tokenise_text * * 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. * */ static void tokenise_text(zword text, zword length, zword from, zword parse, zword dct, bool flag) { zword addr; zbyte token_max, token_count; FastMem.LOW_BYTE(parse, out token_max); parse++; FastMem.LOW_BYTE(parse, out token_count); if (token_count < token_max) /* sufficient space left for token? */ { FastMem.storeb(parse++, (zbyte)(token_count + 1)); load_string((zword)(text + from), length); addr = lookup_text(0x05, dct); if (addr != 0 || !flag) { parse += (zword)(4 * token_count); // Will parse get updated properly? FastMem.storew((zword)(parse + 0), addr); FastMem.storeb((zword)(parse + 2), (zbyte)length); FastMem.storeb((zword)(parse + 3), (zbyte)from); } } }/* tokenise_text */
}/* find_resolution */ /* * load_string * * Copy a ZSCII string from the memory to the global "decoded" string. * */ internal static void LoadString(zword addr, zword length) { if (Decoded is null) { ThrowHelper.ThrowInvalidOperationException("Decoded not initialized"); } int i = 0; if (Resolution == 0) { FindResolution(); } while (i < 3 * Resolution) { if (i < length) { FastMem.LowByte(addr, out zbyte c); addr++; Decoded[i++] = Text.TranslateFromZscii(c); } else { Decoded[i++] = 0; } } }/* load_string */
}/* hot_key_seed */ /* * hot_key_undo * * ...allows user to undo the previous turn. * */ public static bool HotkeyUndo() { Text.PrintString("Undo one turn\n"); if (FastMem.RestoreUndo() > 0) { if (Main.h_version >= ZMachine.V5) { /* for V5+ games we must */ Process.Store(2); /* store 2 (for success) */ return(true); /* and abort the input */ } if (Main.h_version <= ZMachine.V3) { /* for V3- games we must */ Screen.ZShowStatus(); /* draw the status line */ return(false); /* and continue input */ } } else { Text.PrintString("No more undo information available.\n"); } return(false); }/* hot_key_undo */
internal static void ScriptOpen() { unchecked { Main.h_flags &= (zword) ~ZMachine.SCRIPTING_FLAG; } if (Main.h_version >= ZMachine.V5 || !ScriptValid) { if (!OS.ReadFileName(out string?new_name, General.DEFAULT_SCRIPT_NAME, FileTypes.FILE_SCRIPT)) { goto done; } ScriptName = new_name; } if ((Sfp = new System.IO.StreamWriter(ScriptName, true)) != null) { Main.h_flags |= ZMachine.SCRIPTING_FLAG; ScriptValid = true; Main.ostream_script = true; ScriptWidth = 0; Sfp.AutoFlush = true; } else { Text.PrintString("Cannot open file\n"); } done: FastMem.SetWord(ZMachine.H_FLAGS, Main.h_flags); }/* script_open */
}/* z_print_num */ /* * print_object * * Print an object description. * */ internal static void print_object(zword object_var) { zword addr = CObject.object_name(object_var); zword code = 0x94a5; zbyte length; FastMem.LOW_BYTE(addr, out length); addr++; if (length != 0) { FastMem.LOW_WORD(addr, out code); } if (code == 0x94a5) /* encoded text 0x94a5 == empty string */ { print_string("object#"); /* supply a generic name */ print_num(object_var); /* for anonymous objects */ } else { decode_text(string_type.LOW_STRING, addr); } }/* print_object */
}/* script_open */ /* * script_close * * Stop transscription. * */ internal static void script_close() { main.h_flags &= (ushort)~ZMachine.SCRIPTING_FLAG; FastMem.SET_WORD(ZMachine.H_FLAGS, main.h_flags); sfp.Close(); main.ostream_script = false; }/* script_close */
}/* script_open */ /* * script_close * * Stop transscription. * */ internal static void ScriptClose() { unchecked { Main.h_flags &= (ushort)~ZMachine.SCRIPTING_FLAG; } FastMem.SetWord(ZMachine.H_FLAGS, Main.h_flags); Sfp?.Close(); Main.ostream_script = false; }/* script_close */
internal static void z_make_menu() { /* This opcode was only used for the Macintosh version of Journey. * It controls menus with numbers greater than 2 (menus 0, 1 and 2 * are system menus). */ if (Process.zargs[0] < 3) { Process.branch(false); return; } if (Process.zargs[1] != 0) { zword items; int i; FastMem.LOW_WORD(Process.zargs[1], out items); for (i = 0; i < items; i++) { zword item; zbyte length; zbyte c; int j; FastMem.LOW_WORD(Process.zargs[1] + 2 + (2 * i), out item); FastMem.LOW_BYTE(item, out length); if (length > 31) { length = 31; } menu[length] = 0; for (j = 0; j < length; j++) { FastMem.LOW_BYTE(item + j + 1, out c); menu[j] = Text.translate_from_zscii(c); } if (i == 0) { os_.menu(ZMachine.MENU_NEW, Process.zargs[0], menu); } else { os_.menu(ZMachine.MENU_ADD, Process.zargs[0], menu); } } } else { os_.menu(ZMachine.MENU_REMOVE, Process.zargs[0], new zword[0]); } Process.branch(true); }/* z_make_menu */
}/* z_get_parent */ /* * z_get_prop, store the value of an object property. * * Process.zargs[0] = object * Process.zargs[1] = number of property to be examined * */ internal static void ZGetProp() { zword prop_addr; zword wprop_val; zbyte value; zbyte mask; if (Process.zargs[0] == 0) { Err.RuntimeError(ErrorCodes.ERR_GET_PROP_0); Process.Store(0); return; } /* Property id is in bottom five (six) bits */ mask = (zbyte)((Main.h_version <= ZMachine.V3) ? 0x1f : 0x3f); /* Load address of first property */ prop_addr = FirstProperty(Process.zargs[0]); /* Scan down the property list */ for (; ;) { FastMem.LowByte(prop_addr, out value); if ((value & mask) <= Process.zargs[1]) { break; } prop_addr = NextProperty(prop_addr); } if ((value & mask) == Process.zargs[1]) { /* property found */ /* Load property (byte or word sized) */ prop_addr++; if ((Main.h_version <= ZMachine.V3 && !((value & 0xe0) > 0)) || (Main.h_version >= ZMachine.V4 && !((value & 0xc0) > 0))) { FastMem.LowByte(prop_addr, out zbyte bprop_val); wprop_val = bprop_val; } else { FastMem.LowWord(prop_addr, out wprop_val); } } else { /* property not found */ /* Load default value */ prop_addr = (zword)(Main.h_objects + 2 * (Process.zargs[1] - 1)); FastMem.LowWord(prop_addr, out wprop_val); } /* Store the property value */ Process.Store(wprop_val); }/* z_get_prop */
/* * translate_from_zscii * * Map a ZSCII character into Unicode. * */ internal static zword translate_from_zscii(zbyte c) { if (c == 0xfc) { return(CharCodes.ZC_MENU_CLICK); } if (c == 0xfd) { return(CharCodes.ZC_DOUBLE_CLICK); } if (c == 0xfe) { return(CharCodes.ZC_SINGLE_CLICK); } if (c >= 0x9b && main.story_id != Story.BEYOND_ZORK) { if (main.hx_unicode_table != 0) /* game has its own Unicode table */ { zbyte N; FastMem.LOW_BYTE(main.hx_unicode_table, out N); if (c - 0x9b < N) { zword addr = (zword)(main.hx_unicode_table + 1 + 2 * (c - 0x9b)); zword unicode; FastMem.LOW_WORD(addr, out unicode); if (unicode < 0x20) { return('?'); } return(unicode); } else { return('?'); } } else /* game uses standard set */ if (c <= 0xdf) { return(zscii_to_latin1[c - 0x9b]); } else { return('?'); } } return((zword)c); }/* translate_from_zscii */