}/* first_property */ /* * next_property * * Calculate the address of the next property in a property list. * */ private static zword NextProperty(zword prop_addr) { /* Load the current property id */ FastMem.LowByte(prop_addr, out zbyte 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.LowByte(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_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_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 */
}/* 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 */
}/* 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 ZGetPropLen() { zword addr; /* Back up the property pointer to the property id */ addr = (zword)(Process.zargs[0] - 1); FastMem.LowByte(addr, out byte 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_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 */
}/* 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 */
}/* 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 */
}/* 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 ZGetPropAddr() { zword prop_addr; zbyte value; zbyte mask; if (Process.zargs[0] == 0) { Err.RuntimeError(ErrorCodes.ERR_GET_PROP_ADDR_0); Process.Store(0); return; } if (Main.StoryId == Story.BEYOND_ZORK && 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 = 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); } /* 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 */
/* * translate_from_zscii * * Map a ZSCII character into Unicode. * */ internal static zword TranslateFromZscii(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.StoryId != Story.BEYOND_ZORK) { if (Main.hx_unicode_table != 0) { /* game has its own Unicode table */ FastMem.LowByte(Main.hx_unicode_table, out zbyte N); if (c - 0x9b < N) { zword addr = (zword)(Main.hx_unicode_table + 1 + 2 * (c - 0x9b)); FastMem.LowWord(addr, out zword unicode); if (unicode < 0x20) { return('?'); } return(unicode); } else { return('?'); } } else if (c <= 0xdf) /* game uses standard set */ { return(zscii_to_latin1[c - 0x9b]); } else { return('?'); } } return(c); }/* translate_from_zscii */
}/* 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 ZPutProp() { zword prop_addr; zbyte value; zbyte mask; if (Process.zargs[0] == 0) { Err.RuntimeError(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 = 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); } /* Exit if the property does not exist */ if ((value & mask) != Process.zargs[1]) { Err.RuntimeError(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.SetByte(prop_addr, v); } else { zword v = Process.zargs[2]; FastMem.SetWord(prop_addr, v); } }/* z_put_prop */
}/* object_name */ /* * first_property * * Calculate the start address of the property list associated with * an object. * */ private static zword FirstProperty(zword obj) { /* Fetch address of object name */ zword prop_addr = ObjectName(obj); /* Get length of object name */ FastMem.LowByte(prop_addr, out zbyte size); /* Add name length to pointer */ return((zword)(prop_addr + 1 + 2 * size)); }/* first_property */
internal static void ZMakeMenu() { /* 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) { FastMem.LowWord(Process.zargs[1], out zword items); for (int i = 0; i < items; i++) { FastMem.LowWord(Process.zargs[1] + 2 + (2 * i), out zword item); FastMem.LowByte(item, out zbyte length); if (length > 31) { length = 31; } menu[length] = 0; for (int j = 0; j < length; j++) { FastMem.LowByte(item + j + 1, out zbyte c); menu[j] = Text.TranslateFromZscii(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], Array.Empty <zword>()); } Process.Branch(true); }/* z_make_menu */
}/* 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 ZJin() { zword obj_addr; /* If we are monitoring object locating display a short note */ if (Main.option_object_locating) { Stream.StreamMssgOn(); Text.PrintString("@jin "); Text.PrintObject(Process.zargs[0]); Text.PrintString(" "); Text.PrintObject(Process.zargs[1]); Stream.StreamMssgOff(); } if (Process.zargs[0] == 0) { Err.RuntimeError(ErrorCodes.ERR_JIN_0); Process.Branch(0 == Process.zargs[1]); return; } obj_addr = ObjectAddress(Process.zargs[0]); if (Main.h_version <= ZMachine.V3) { /* Get parent id from object */ obj_addr += O1_PARENT; FastMem.LowByte(obj_addr, out zbyte parent); /* Branch if the parent is obj2 */ Process.Branch(parent == Process.zargs[1]); } else { /* Get parent id from object */ obj_addr += O4_PARENT; FastMem.LowWord(obj_addr, out zword parent); /* Branch if the parent is obj2 */ Process.Branch(parent == Process.zargs[1]); } }/* z_jin */
}/* 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 ZSetAttr() { zword obj_addr; if (Main.StoryId == Story.SHERLOCK) { if (Process.zargs[1] == 48) { return; } } if (Process.zargs[1] > ((Main.h_version <= ZMachine.V3) ? 31 : 47)) { Err.RuntimeError(ErrorCodes.ERR_ILL_ATTR); } /* If we are monitoring attribute assignment display a short note */ if (Main.option_attribute_assignment == true) { Stream.StreamMssgOn(); Text.PrintString("@set_attr "); Text.PrintObject(Process.zargs[0]); Text.PrintString(" "); Text.PrintNum(Process.zargs[1]); Stream.StreamMssgOff(); } if (Process.zargs[0] == 0) { Err.RuntimeError(ErrorCodes.ERR_SET_ATTR_0); return; } /* Get attribute address */ obj_addr = (zword)(ObjectAddress(Process.zargs[0]) + Process.zargs[1] / 8); /* Load attribute byte */ FastMem.LowByte(obj_addr, out zbyte value); /* Set attribute bit */ value |= (zbyte)(0x80 >> (Process.zargs[1] & 7)); /* Store attribute byte */ FastMem.SetByte(obj_addr, value); }/* z_set_attr */
}/* z_get_next_prop */ /* * z_get_parent, store the parent of an object. * * Process.zargs[0] = object * */ internal static void ZGetParent() { zword obj_addr; /* If we are monitoring object locating display a short note */ if (Main.option_object_locating) { Stream.StreamMssgOn(); Text.PrintString("@get_parent "); Text.PrintObject(Process.zargs[0]); Stream.StreamMssgOff(); } if (Process.zargs[0] == 0) { Err.RuntimeError(ErrorCodes.ERR_GET_PARENT_0); Process.Store(0); return; } obj_addr = ObjectAddress(Process.zargs[0]); if (Main.h_version <= ZMachine.V3) { /* Get parent id from object */ obj_addr += O1_PARENT; FastMem.LowByte(obj_addr, out zbyte parent); /* Store parent */ Process.Store(parent); } else { /* Get parent id from object */ obj_addr += O4_PARENT; FastMem.LowWord(obj_addr, out zword parent); /* Store parent */ Process.Store(parent); } }/* z_get_parent */
}/* z_jin */ /* * z_get_child, store the child of an object. * * Process.zargs[0] = object * */ internal static void ZGetChild() { zword obj_addr; /* If we are monitoring object locating display a short note */ if (Main.option_object_locating) { Stream.StreamMssgOn(); Text.PrintString("@get_child "); Text.PrintObject(Process.zargs[0]); Stream.StreamMssgOff(); } if (Process.zargs[0] == 0) { Err.RuntimeError(ErrorCodes.ERR_GET_CHILD_0); Process.Store(0); Process.Branch(false); return; } obj_addr = ObjectAddress(Process.zargs[0]); if (Main.h_version <= ZMachine.V3) { /* Get child id from object */ obj_addr += O1_CHILD; FastMem.LowByte(obj_addr, out zbyte child); /* Store child id and branch */ Process.Store(child); Process.Branch(child > 0); } else { /* Get child id from object */ obj_addr += O4_CHILD; FastMem.LowWord(obj_addr, out zword child); /* Store child id and branch */ Process.Store(child); Process.Branch(child > 0); } }/* z_get_child */
}/* alphabet */ /* * find_resolution * * Find the number of bytes used for dictionary resolution. * */ internal static void FindResolution() { zword dct = Main.h_dictionary; FastMem.LowByte(dct, out zbyte sep_count); dct += (zword)(1 + sep_count); /* skip word separators */ FastMem.LowByte(dct, out zbyte entry_len); Resolution = (Main.h_version <= ZMachine.V3) ? 2 : 3; if (2 * Resolution > entry_len) { Err.RuntimeError(ErrorCodes.ERR_DICT_LEN); } Decoded = new zword[3 * Resolution + 1]; Encoded = new zword[Resolution]; }/* find_resolution */
} /* 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 ZScanTable() { 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 */ FastMem.LowWord(addr, out ushort wvalue); if (wvalue == Process.zargs[0]) { goto finished; } } else { /* scan byte array */ FastMem.LowByte(addr, out byte 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 */
}/* 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 ZGetNextProp() { zbyte value; if (Process.zargs[0] == 0) { Err.RuntimeError(ErrorCodes.ERR_GET_NEXT_PROP_0); Process.Store(0); return; } /* Property id is in bottom five (six) bits */ zbyte mask = (zbyte)((Main.h_version <= ZMachine.V3) ? 0x1f : 0x3f); /* Load address of first property */ zword prop_addr = FirstProperty(Process.zargs[0]); if (Process.zargs[1] != 0) { /* Scan down the property list */ do { FastMem.LowByte(prop_addr, out value); prop_addr = NextProperty(prop_addr); } while ((value & mask) > Process.zargs[1]); /* Exit if the property does not exist */ if ((value & mask) != Process.zargs[1]) { Err.RuntimeError(ErrorCodes.ERR_NO_PROP); } } /* Return the property id */ FastMem.LowByte(prop_addr, out value); Process.Store((zword)(value & mask)); }/* z_get_next_prop */
}/* translate_from_zscii */ /* * unicode_to_zscii * * Convert a Unicode character to ZSCII, returning 0 on failure. * */ internal static zbyte UnicodeToZscii(zword c) { int i; if (c >= CharCodes.ZC_LATIN1_MIN) { if (Main.hx_unicode_table != 0) { /* game has its own Unicode table */ FastMem.LowByte(Main.hx_unicode_table, out zbyte N); for (i = 0x9b; i < 0x9b + N; i++) { zword addr = (zword)(Main.hx_unicode_table + 1 + 2 * (i - 0x9b)); FastMem.LowWord(addr, out zword 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_prop_len */ /* * z_get_sibling, store the sibling of an object. * * Process.zargs[0] = object * */ internal static void ZGetSibling() { zword obj_addr; if (Process.zargs[0] == 0) { Err.RuntimeError(ErrorCodes.ERR_GET_SIBLING_0); Process.Store(0); Process.Branch(false); return; } obj_addr = ObjectAddress(Process.zargs[0]); if (Main.h_version <= ZMachine.V3) { /* Get sibling id from object */ obj_addr += O1_SIBLING; FastMem.LowByte(obj_addr, out byte 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 { /* Get sibling id from object */ obj_addr += O4_SIBLING; FastMem.LowWord(obj_addr, out ushort sibling); /* Store sibling and branch */ Process.Store(sibling); Process.Branch(sibling > 0); } }/* z_get_sibling */
}/* 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 ZTestAttr() { zword obj_addr; if (Process.zargs[1] > ((Main.h_version <= ZMachine.V3) ? 31 : 47)) { Err.RuntimeError(ErrorCodes.ERR_ILL_ATTR); } /* If we are monitoring attribute testing display a short note */ if (Main.option_attribute_testing == true) { Stream.StreamMssgOn(); Text.PrintString("@test_attr "); Text.PrintObject(Process.zargs[0]); Text.PrintString(" "); Text.PrintNum(Process.zargs[1]); Stream.StreamMssgOff(); } if (Process.zargs[0] == 0) { Err.RuntimeError(ErrorCodes.ERR_TEST_ATTR_0); Process.Branch(false); return; } /* Get attribute address */ obj_addr = (zword)(ObjectAddress(Process.zargs[0]) + Process.zargs[1] / 8); /* Load attribute byte */ FastMem.LowByte(obj_addr, out byte value); /* Test attribute */ Process.Branch((value & (0x80 >> (Process.zargs[1] & 7))) > 0); }/* z_test_attr */
//zword unicode_tolower (zword); /* * is_terminator * * Check if the given key is an input terminator. * */ internal static bool IsTerminator(zword key) { if (key == CharCodes.ZC_TIME_OUT) { return(true); } if (key == CharCodes.ZC_RETURN) { return(true); } if (key is >= CharCodes.ZC_HKEY_MIN and <= CharCodes.ZC_HKEY_MAX) { return(true); } if (Main.h_terminating_keys != 0) { if (key is >= CharCodes.ZC_ARROW_MIN and <= CharCodes.ZC_MENU_CLICK) { zword addr = Main.h_terminating_keys; zbyte c; do { FastMem.LowByte(addr, out c); if (c == 0xff || key == Text.TranslateFromZscii(c)) { return(true); } addr++; } while (c != 0); } } return(false); }/* is_terminator */
}/* next_property */ /* * unlink_object * * Unlink an object from its parent and siblings. * */ private static void UnlinkObject(zword object_var) { zword parent_addr; zword sibling_addr; if (object_var == 0) { Err.RuntimeError(ErrorCodes.ERR_REMOVE_OBJECT_0); return; } zword obj_addr = ObjectAddress(object_var); if (Main.h_version <= ZMachine.V3) { zbyte zero = 0; /* Get parent of object, and return if no parent */ obj_addr += O1_PARENT; FastMem.LowByte(obj_addr, out byte parent); if (parent == 0) { return; } /* Get (older) sibling of object and set both parent and sibling * pointers to 0 */ FastMem.SetByte(obj_addr, zero); obj_addr += (zword)(O1_SIBLING - O1_PARENT); FastMem.LowByte(obj_addr, out byte older_sibling); FastMem.SetByte(obj_addr, zero); /* Get first child of parent (the youngest sibling of the object) */ parent_addr = (zword)(ObjectAddress(parent) + O1_CHILD); FastMem.LowByte(parent_addr, out byte younger_sibling); /* Remove object from the list of siblings */ if (younger_sibling == object_var) { FastMem.SetByte(parent_addr, older_sibling); } else { do { sibling_addr = (zword)(ObjectAddress(younger_sibling) + O1_SIBLING); FastMem.LowByte(sibling_addr, out younger_sibling); } while (younger_sibling != object_var); FastMem.SetByte(sibling_addr, older_sibling); } } else { zword zero = 0; /* Get parent of object, and return if no parent */ obj_addr += O4_PARENT; FastMem.LowWord(obj_addr, out zword parent); if (parent == 0) { return; } /* Get (older) sibling of object and set both parent and sibling * pointers to 0 */ FastMem.SetWord(obj_addr, zero); obj_addr += (zword)(O4_SIBLING - O4_PARENT); FastMem.LowWord(obj_addr, out ushort older_sibling); FastMem.SetWord(obj_addr, zero); /* Get first child of parent (the youngest sibling of the object) */ parent_addr = (zword)(ObjectAddress(parent) + O4_CHILD); FastMem.LowWord(parent_addr, out ushort younger_sibling); /* Remove object from the list of siblings */ if (younger_sibling == object_var) { FastMem.SetWord(parent_addr, older_sibling); } else { do { sibling_addr = (zword)(ObjectAddress(younger_sibling) + O4_SIBLING); FastMem.LowWord(sibling_addr, out younger_sibling); } while (younger_sibling != object_var); FastMem.SetWord(sibling_addr, older_sibling); } } }/* unlink_object */