}/* 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 */
}/* 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 */
}/* 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 */
}/* 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 */
}/* 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 */
}/* 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 */
}/* 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 */
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 */
/* * 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 */
}/* 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 z_loadb() { zword addr = (zword)(Process.zargs[0] + Process.zargs[1]); zbyte value; FastMem.LOW_BYTE(addr, out value); Process.store(value); }/* z_loadb */
}/* z_get_prop */ /* * z_get_prop_addr, store the address of an object property. * * Process.zargs[0] = object * Process.zargs[1] = number of property to be examined * */ internal static void z_get_prop_addr() { zword prop_addr; zbyte value; zbyte mask; if (Process.zargs[0] == 0) { Err.runtime_error(ErrorCodes.ERR_GET_PROP_ADDR_0); Process.store(0); return; } if (main.story_id == Story.BEYOND_ZORK) { if (Process.zargs[0] > MAX_OBJECT) { 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 = first_property(Process.zargs[0]); /* Scan down the property list */ for (; ;) { FastMem.LOW_BYTE(prop_addr, out value); if ((value & mask) <= Process.zargs[1]) { break; } prop_addr = next_property(prop_addr); } /* Calculate the property address or return zero */ if ((value & mask) == Process.zargs[1]) { if (main.h_version >= ZMachine.V4 && (value & 0x80) > 0) { prop_addr++; } Process.store((zword)(prop_addr + 1)); } else { Process.store(0); } }/* z_get_prop_addr */
}/* z_insert_obj */ /* * z_put_prop, set the value of an object property. * * Process.zargs[0] = object * Process.zargs[1] = number of property to set * Process.zargs[2] = value to set property to * */ internal static void z_put_prop() { zword prop_addr; zbyte value; zbyte mask; if (Process.zargs[0] == 0) { Err.runtime_error(ErrorCodes.ERR_PUT_PROP_0); return; } /* Property id is in bottom five or six bits */ mask = (zbyte)((main.h_version <= ZMachine.V3) ? 0x1f : 0x3f); /* Load address of first property */ prop_addr = first_property(Process.zargs[0]); /* Scan down the property list */ for (; ;) { FastMem.LOW_BYTE(prop_addr, out value); if ((value & mask) <= Process.zargs[1]) { break; } prop_addr = next_property(prop_addr); } /* Exit if the property does not exist */ if ((value & mask) != Process.zargs[1]) { Err.runtime_error(ErrorCodes.ERR_NO_PROP); } /* Store the new property value (byte or word sized) */ prop_addr++; if ((main.h_version <= ZMachine.V3 && !((value & 0xe0) > 0)) || (main.h_version >= ZMachine.V4 && !((value & 0xc0) > 0))) { zbyte v = (zbyte)Process.zargs[2]; FastMem.SET_BYTE(prop_addr, v); } else { zword v = Process.zargs[2]; FastMem.SET_WORD(prop_addr, v); } }/* z_put_prop */
}/* z_jin */ /* * z_get_child, store the child of an object. * * Process.zargs[0] = object * */ internal static void z_get_child() { zword obj_addr; /* If we are monitoring object locating display a short note */ if (main.option_object_locating == true) { Stream.stream_mssg_on(); Text.print_string("@get_child "); Text.print_object(Process.zargs[0]); Stream.stream_mssg_off(); } if (Process.zargs[0] == 0) { Err.runtime_error(ErrorCodes.ERR_GET_CHILD_0); Process.store(0); Process.branch(false); return; } obj_addr = object_address(Process.zargs[0]); if (main.h_version <= ZMachine.V3) { zbyte child; /* Get child id from object */ obj_addr += O1_CHILD; FastMem.LOW_BYTE(obj_addr, out child); /* Store child id and branch */ Process.store(child); Process.branch(child > 0); } else { zword child; /* Get child id from object */ obj_addr += O4_CHILD; FastMem.LOW_WORD(obj_addr, out child); /* Store child id and branch */ Process.store(child); Process.branch(child > 0); } }/* z_get_child */
}/* z_remove_obj */ /* * z_set_attr, set an object attribute. * * Process.zargs[0] = object * Process.zargs[1] = number of attribute to set * */ internal static void z_set_attr() { zword obj_addr; zbyte value; if (main.story_id == Story.SHERLOCK) { if (Process.zargs[1] == 48) { return; } } if (Process.zargs[1] > ((main.h_version <= ZMachine.V3) ? 31 : 47)) { Err.runtime_error(ErrorCodes.ERR_ILL_ATTR); } /* If we are monitoring attribute assignment display a short note */ if (main.option_attribute_assignment == true) { Stream.stream_mssg_on(); Text.print_string("@set_attr "); Text.print_object(Process.zargs[0]); Text.print_string(" "); Text.print_num(Process.zargs[1]); Stream.stream_mssg_off(); } if (Process.zargs[0] == 0) { Err.runtime_error(ErrorCodes.ERR_SET_ATTR_0); return; } /* Get attribute address */ obj_addr = (zword)(object_address(Process.zargs[0]) + Process.zargs[1] / 8); /* Load attribute byte */ FastMem.LOW_BYTE(obj_addr, out value); /* Set attribute bit */ value |= (zbyte)(0x80 >> (Process.zargs[1] & 7)); /* Store attribute byte */ FastMem.SET_BYTE(obj_addr, value); }/* z_set_attr */
}/* z_clear_attr */ /* * z_jin, branch if the first object is inside the second. * * Process.zargs[0] = first object * Process.zargs[1] = second object * */ internal static void z_jin() { zword obj_addr; /* If we are monitoring object locating display a short note */ if (main.option_object_locating == true) { Stream.stream_mssg_on(); Text.print_string("@jin "); Text.print_object(Process.zargs[0]); Text.print_string(" "); Text.print_object(Process.zargs[1]); Stream.stream_mssg_off(); } if (Process.zargs[0] == 0) { Err.runtime_error(ErrorCodes.ERR_JIN_0); Process.branch(0 == Process.zargs[1]); return; } obj_addr = object_address(Process.zargs[0]); if (main.h_version <= ZMachine.V3) { zbyte parent; /* Get parent id from object */ obj_addr += O1_PARENT; FastMem.LOW_BYTE(obj_addr, out parent); /* Branch if the parent is obj2 */ Process.branch(parent == Process.zargs[1]); } else { zword parent; /* Get parent id from object */ obj_addr += O4_PARENT; FastMem.LOW_WORD(obj_addr, out parent); /* Branch if the parent is obj2 */ Process.branch(parent == Process.zargs[1]); } }/* z_jin */
}/* z_loadw */ /* * z_scan_table, 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. * */ internal static void z_scan_table() { zword addr = Process.zargs[1]; int i; /* Supply default arguments */ if (Process.zargc < 4) { Process.zargs[3] = 0x82; } /* Scan byte or word array */ for (i = 0; i < Process.zargs[2]; i++) { if ((Process.zargs[3] & 0x80) > 0) /* scan word array */ { zword wvalue; FastMem.LOW_WORD(addr, out wvalue); if (wvalue == Process.zargs[0]) { goto finished; } } else /* scan byte array */ { zbyte bvalue; FastMem.LOW_BYTE(addr, out bvalue); if (bvalue == Process.zargs[0]) { goto finished; } } addr += (zword)(Process.zargs[3] & 0x7f); } addr = 0; finished: Process.store(addr); Process.branch(addr > 0); }/* z_scan_table */
}/* object_name */ /* * first_property * * Calculate the start address of the property list associated with * an object. * */ static zword first_property(zword obj) { zword prop_addr; zbyte size; /* Fetch address of object name */ prop_addr = object_name(obj); /* Get length of object name */ FastMem.LOW_BYTE(prop_addr, out size); /* Add name length to pointer */ return((zword)(prop_addr + 1 + 2 * size)); }/* first_property */
}/* translate_from_zscii */ /* * unicode_to_zscii * * Convert a Unicode character to ZSCII, returning 0 on failure. * */ internal static zbyte unicode_to_zscii(zword c) { int i; if (c >= CharCodes.ZC_LATIN1_MIN) { if (main.hx_unicode_table != 0) /* game has its own Unicode table */ { zbyte N; FastMem.LOW_BYTE(main.hx_unicode_table, out N); for (i = 0x9b; i < 0x9b + N; i++) { zword addr = (zword)(main.hx_unicode_table + 1 + 2 * (i - 0x9b)); zword unicode; FastMem.LOW_WORD(addr, out unicode); if (c == unicode) { return((zbyte)i); } } return(0); } else /* game uses standard set */ { for (i = 0x9b; i <= 0xdf; i++) { if (c == zscii_to_latin1[i - 0x9b]) { return((zbyte)i); } } return(0); } } return((zbyte)c); }/* unicode_to_zscii */
}/* z_get_child */ /* * z_get_next_prop, store the number of the first or next property. * * Process.zargs[0] = object * Process.zargs[1] = address of current property (0 gets the first property) * */ internal static void z_get_next_prop() { zword prop_addr; zbyte value; zbyte mask; if (Process.zargs[0] == 0) { Err.runtime_error(ErrorCodes.ERR_GET_NEXT_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 = first_property(Process.zargs[0]); if (Process.zargs[1] != 0) { /* Scan down the property list */ do { FastMem.LOW_BYTE(prop_addr, out value); prop_addr = next_property(prop_addr); } while ((value & mask) > Process.zargs[1]); /* Exit if the property does not exist */ if ((value & mask) != Process.zargs[1]) { Err.runtime_error(ErrorCodes.ERR_NO_PROP); } } /* Return the property id */ FastMem.LOW_BYTE(prop_addr, out value); Process.store((zword)(value & mask)); }/* z_get_next_prop */
}/* z_get_prop_len */ /* * z_get_sibling, store the sibling of an object. * * Process.zargs[0] = object * */ internal static void z_get_sibling() { zword obj_addr; if (Process.zargs[0] == 0) { Err.runtime_error(ErrorCodes.ERR_GET_SIBLING_0); Process.store(0); Process.branch(false); return; } obj_addr = object_address(Process.zargs[0]); if (main.h_version <= ZMachine.V3) { zbyte sibling; /* Get sibling id from object */ obj_addr += O1_SIBLING; FastMem.LOW_BYTE(obj_addr, out sibling); /* Store sibling and branch */ Process.store(sibling); Process.branch(sibling > 0); // TODO I'm not sure about this logic Process.branch (sibling); // I think it means if the sibling isn't zero, jump.. } else { zword sibling; /* Get sibling id from object */ obj_addr += O4_SIBLING; FastMem.LOW_WORD(obj_addr, out sibling); /* Store sibling and branch */ Process.store(sibling); Process.branch(sibling > 0); } }/* z_get_sibling */
}/* z_restart */ /* * get_default_name * * Read a default file name from the memory of the Z-machine and * copy it to a string. * */ internal static string get_default_name(zword addr) { if (addr != 0) { var sb = new System.Text.StringBuilder(); zbyte len; int i; FastMem.LOW_BYTE(addr, out len); addr++; for (i = 0; i < len; i++) { zbyte c; FastMem.LOW_BYTE(addr, out c); addr++; if (c >= 'A' && c <= 'Z') { c += 'a' - 'A'; } // default_name[i] = c; sb.Append((char)c); } // default_name[i] = 0; if (sb.ToString().IndexOf(".") == -1) { sb.Append(".AUX"); return(sb.ToString()); } else { return(auxilary_name); } } return(null); }/* get_default_name */
}/* alphabet */ /* * find_resolution * * Find the number of bytes used for dictionary resolution. * */ internal static void find_resolution() { zword dct = main.h_dictionary; zbyte sep_count; zbyte entry_len; FastMem.LOW_BYTE(dct, out sep_count); dct += (zword)(1 + sep_count); /* skip word separators */ FastMem.LOW_BYTE(dct, out entry_len); resolution = (main.h_version <= ZMachine.V3) ? 2 : 3; if (2 * resolution > entry_len) { Err.runtime_error(ErrorCodes.ERR_DICT_LEN); } decoded = new zword[3 * resolution + 1]; encoded = new zword[resolution]; }/* find_resolution */
}/* z_set_attr */ /* * z_test_attr, branch if an object attribute is set. * * Process.zargs[0] = object * Process.zargs[1] = number of attribute to test * */ internal static void z_test_attr() { zword obj_addr; zbyte value; if (Process.zargs[1] > ((main.h_version <= ZMachine.V3) ? 31 : 47)) { Err.runtime_error(ErrorCodes.ERR_ILL_ATTR); } /* If we are monitoring attribute testing display a short note */ if (main.option_attribute_testing == true) { Stream.stream_mssg_on(); Text.print_string("@test_attr "); Text.print_object(Process.zargs[0]); Text.print_string(" "); Text.print_num(Process.zargs[1]); Stream.stream_mssg_off(); } if (Process.zargs[0] == 0) { Err.runtime_error(ErrorCodes.ERR_TEST_ATTR_0); Process.branch(false); return; } /* Get attribute address */ obj_addr = (zword)(object_address(Process.zargs[0]) + Process.zargs[1] / 8); /* Load attribute byte */ FastMem.LOW_BYTE(obj_addr, out value); /* Test attribute */ Process.branch((value & (0x80 >> (Process.zargs[1] & 7))) > 0); }/* z_test_attr */
/* * 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 z_copy_table() { 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.LOW_BYTE(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.LOW_BYTE(addr, out value); FastMem.storeb((zword)(Process.zargs[1] + i), value); } } }/* z_copy_table */
//zword unicode_tolower (zword); /* * is_terminator * * Check if the given key is an input terminator. * */ internal static bool is_terminator(zword key) { if (key == CharCodes.ZC_TIME_OUT) { return(true); } if (key == CharCodes.ZC_RETURN) { return(true); } if (key >= CharCodes.ZC_HKEY_MIN && key <= CharCodes.ZC_HKEY_MAX) { return(true); } if (main.h_terminating_keys != 0) { if (key >= CharCodes.ZC_ARROW_MIN && key <= CharCodes.ZC_MENU_CLICK) { zword addr = main.h_terminating_keys; zbyte c; do { FastMem.LOW_BYTE(addr, out c); if (c == 255 || key == Text.translate_from_zscii(c)) { return(true); } addr++; } while (c != 0); } } return(false); }/* is_terminator */
}/* next_property */ /* * unlink_object * * Unlink an object from its parent and siblings. * */ static void unlink_object(zword object_var) { zword obj_addr; zword parent_addr; zword sibling_addr; if (object_var == 0) { Err.runtime_error(ErrorCodes.ERR_REMOVE_OBJECT_0); return; } obj_addr = object_address(object_var); if (main.h_version <= ZMachine.V3) { zbyte parent; zbyte younger_sibling; zbyte older_sibling; zbyte zero = 0; /* Get parent of object, and return if no parent */ obj_addr += O1_PARENT; FastMem.LOW_BYTE(obj_addr, out parent); if (parent == 0) { return; } /* Get (older) sibling of object and set both parent and sibling * pointers to 0 */ FastMem.SET_BYTE(obj_addr, zero); obj_addr += (zword)(O1_SIBLING - O1_PARENT); FastMem.LOW_BYTE(obj_addr, out older_sibling); FastMem.SET_BYTE(obj_addr, zero); /* Get first child of parent (the youngest sibling of the object) */ parent_addr = (zword)(object_address(parent) + O1_CHILD); FastMem.LOW_BYTE(parent_addr, out younger_sibling); /* Remove object from the list of siblings */ if (younger_sibling == object_var) { FastMem.SET_BYTE(parent_addr, older_sibling); } else { do { sibling_addr = (zword)(object_address(younger_sibling) + O1_SIBLING); FastMem.LOW_BYTE(sibling_addr, out younger_sibling); } while (younger_sibling != object_var); FastMem.SET_BYTE(sibling_addr, older_sibling); } } else { zword parent; zword younger_sibling; zword older_sibling; zword zero = 0; /* Get parent of object, and return if no parent */ obj_addr += O4_PARENT; FastMem.LOW_WORD(obj_addr, out parent); if (parent == 0) { return; } /* Get (older) sibling of object and set both parent and sibling * pointers to 0 */ FastMem.SET_WORD(obj_addr, zero); obj_addr += (zword)(O4_SIBLING - O4_PARENT); FastMem.LOW_WORD(obj_addr, out older_sibling); FastMem.SET_WORD(obj_addr, zero); /* Get first child of parent (the youngest sibling of the object) */ parent_addr = (zword)(object_address(parent) + O4_CHILD); FastMem.LOW_WORD(parent_addr, out younger_sibling); /* Remove object from the list of siblings */ if (younger_sibling == object_var) { FastMem.SET_WORD(parent_addr, older_sibling); } else { do { sibling_addr = (zword)(object_address(younger_sibling) + O4_SIBLING); FastMem.LOW_WORD(sibling_addr, out younger_sibling); } while (younger_sibling != object_var); FastMem.SET_WORD(sibling_addr, older_sibling); } } }/* unlink_object */
}/* read_number */ /* * z_read, 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 * */ internal static void z_read() { zword[] buffer = new zword[General.INPUT_BUFFER_SIZE]; zword addr; zword key; zbyte max, size; zbyte c; int i; /* Supply default arguments */ if (Process.zargc < 3) { Process.zargs[2] = 0; } /* Get maximum input size */ addr = Process.zargs[0]; FastMem.LOW_BYTE(addr, out max); if (main.h_version <= ZMachine.V4) { max--; } if (max >= General.INPUT_BUFFER_SIZE) { max = (zbyte)(General.INPUT_BUFFER_SIZE - 1); } /* Get initial input size */ if (main.h_version >= ZMachine.V5) { addr++; FastMem.LOW_BYTE(addr, out size); } else { size = 0; } /* Copy initial input to local buffer */ for (i = 0; i < size; i++) { addr++; FastMem.LOW_BYTE(addr, out c); buffer[i] = Text.translate_from_zscii(c); } buffer[i] = 0; /* Draw status line for V1 to V3 games */ if (main.h_version <= ZMachine.V3) { Screen.z_show_status(); } /* Read input from current input stream */ key = Stream.stream_read_input( max, buffer, /* buffer and size */ Process.zargs[2], /* timeout value */ Process.zargs[3], /* timeout routine */ true, /* enable hot keys */ main.h_version == ZMachine.V6); /* no script in V6 */ if (key == CharCodes.ZC_BAD) { return; } /* Perform save_undo for V1 to V4 games */ if (main.h_version <= ZMachine.V4) { FastMem.save_undo(); } /* Copy local buffer back to dynamic memory */ for (i = 0; buffer[i] != 0; i++) { if (key == CharCodes.ZC_RETURN) { buffer[i] = Text.unicode_tolower(buffer[i]); } FastMem.storeb((zword)(Process.zargs[0] + ((main.h_version <= ZMachine.V4) ? 1 : 2) + i), Text.translate_to_zscii(buffer[i])); } /* Add null character (V1-V4) or write input length into 2nd byte */ if (main.h_version <= ZMachine.V4) { FastMem.storeb((zword)(Process.zargs[0] + 1 + i), 0); } else { FastMem.storeb((zword)(Process.zargs[0] + 1), (byte)i); } /* Tokenise line if a token buffer is present */ if (key == CharCodes.ZC_RETURN && Process.zargs[1] != 0) { Text.tokenise_line(Process.zargs[0], Process.zargs[1], 0, false); } /* Store key */ if (main.h_version >= ZMachine.V5) { Process.store(Text.translate_to_zscii(key)); } }/* z_read */
}/* z_print_unicode */ /* * lookup_text * * 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. * */ internal static zword lookup_text(int padding, zword dct) { zword entry_addr; zword entry_count; zword entry; zword addr; zbyte entry_len; zbyte sep_count; int entry_number; int lower, upper; int i; bool sorted; if (resolution == 0) { find_resolution(); } Text.encode_text(padding); FastMem.LOW_BYTE(dct, out sep_count); /* skip word separators */ dct += (zword)(1 + sep_count); FastMem.LOW_BYTE(dct, out entry_len); /* get length of entries */ dct += 1; FastMem.LOW_WORD(dct, out entry_count); /* get number of entries */ dct += 2; if ((short)entry_count < 0) /* bad luck, entries aren't sorted */ { entry_count = (zword)(-(short)entry_count); sorted = false; } else { sorted = true; /* entries are sorted */ } lower = 0; upper = entry_count - 1; while (lower <= upper) { if (sorted) /* binary search */ { entry_number = (lower + upper) / 2; } else /* linear search */ { entry_number = lower; } entry_addr = (zword)(dct + entry_number * entry_len); /* Compare word to dictionary entry */ addr = entry_addr; for (i = 0; i < resolution; i++) { FastMem.LOW_WORD(addr, out entry); if (encoded[i] != entry) { goto continuing; } addr += 2; } return(entry_addr); /* exact match found, return now */ continuing: if (sorted) /* binary search */ { if (encoded[i] > entry) { lower = entry_number + 1; } else { upper = entry_number - 1; } } else { lower++; /* linear search */ } } /* No exact match has been found */ if (padding == 0x05) { return(0); } entry_number = (padding == 0x00) ? lower : upper; if (entry_number == -1 || entry_number == entry_count) { return(0); } return((zword)(dct + entry_number * entry_len)); }/* lookup_text */
}/* 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 z_insert_obj() { 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.stream_mssg_on(); Text.print_string("@move_obj "); Text.print_object(obj1); Text.print_string(" "); Text.print_object(obj2); Stream.stream_mssg_off(); } if (obj1 == 0) { Err.runtime_error(ErrorCodes.ERR_MOVE_OBJECT_0); return; } if (obj2 == 0) { Err.runtime_error(ErrorCodes.ERR_MOVE_OBJECT_TO_0); return; } /* Get addresses of both objects */ obj1_addr = object_address(obj1); obj2_addr = object_address(obj2); /* Remove object 1 from current parent */ unlink_object(obj1); /* Make object 1 first child of object 2 */ if (main.h_version <= ZMachine.V3) { zbyte child; obj1_addr += O1_PARENT; FastMem.SET_BYTE(obj1_addr, (zbyte)obj2); obj2_addr += O1_CHILD; FastMem.LOW_BYTE(obj2_addr, out child); FastMem.SET_BYTE(obj2_addr, (zbyte)obj1); obj1_addr += (zword)(O1_SIBLING - O1_PARENT); FastMem.SET_BYTE(obj1_addr, child); } else { zword child; obj1_addr += O4_PARENT; FastMem.SET_WORD(obj1_addr, obj2); obj2_addr += O4_CHILD; FastMem.LOW_WORD(obj2_addr, out child); FastMem.SET_WORD(obj2_addr, obj1); obj1_addr += (zword)(O4_SIBLING - O4_PARENT); FastMem.SET_WORD(obj1_addr, child); } }/* z_insert_obj */
}/* 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 z_get_prop() { zword prop_addr; zword wprop_val; zbyte bprop_val; zbyte value; zbyte mask; if (Process.zargs[0] == 0) { Err.runtime_error(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 = first_property(Process.zargs[0]); /* Scan down the property list */ for (; ;) { FastMem.LOW_BYTE(prop_addr, out value); if ((value & mask) <= Process.zargs[1]) { break; } prop_addr = next_property(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.LOW_BYTE(prop_addr, out bprop_val); wprop_val = bprop_val; } else { FastMem.LOW_WORD(prop_addr, out wprop_val); } } else /* property not found */ /* Load default value */ { prop_addr = (zword)(main.h_objects + 2 * (Process.zargs[1] - 1)); FastMem.LOW_WORD(prop_addr, out wprop_val); } /* Store the property value */ Process.store(wprop_val); }/* z_get_prop */