示例#1
0
        }/* 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 */
示例#2
0
        } /* 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 */
示例#3
0
        }/* 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 */
示例#4
0
        /*
         * 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 */
示例#5
0
        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 */
示例#6
0
        }/* z_push */

        /*
         * z_push_stack, 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
         *
         */

        internal static void ZPushStack()
        {
            zword addr = Process.zargs[1];

            FastMem.LowWord(addr, out ushort size);

            if (size != 0)
            {
                FastMem.StoreW((zword)(addr + 2 * size), Process.zargs[0]);

                size--;
                FastMem.StoreW(addr, size);
            }

            Process.Branch(size > 0); // TODO I think that's what's expected here
        }/* z_push_stack */
示例#7
0
        internal static void ZPop() => Main.sp++; /* z_pop */

        /*
         * z_pop_stack, 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)
         *
         */

        internal static void ZPopStack()
        {
            if (Process.zargc == 2)
            {       /* it's a user stack */
                zword addr = Process.zargs[1];

                FastMem.LowWord(addr, out ushort size);

                size += Process.zargs[0];
                FastMem.StoreW(addr, size);
            }
            else
            {
                Main.sp += Process.zargs[0];    /* it's the game stack */
            }
        }/* z_pop_stack */
示例#8
0
        }/* 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 */
示例#9
0
        }/* 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 */
示例#10
0
        }/* 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 */
示例#11
0
        }/* z_pop_stack */

        /*
         * z_pull, 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
         *
         */

        internal static void ZPull()
        {
            zword value;

            if (Main.h_version != ZMachine.V6)
            {   /* not a V6 game, pop stack and write */
                value = Main.Stack[Main.sp++];

                if (Process.zargs[0] == 0)
                {
                    Main.Stack[Main.sp] = value;
                }
                else if (Process.zargs[0] < 16)
                {
                    // *(fp - Process.zargs[0]) = value;
                    Main.Stack[Main.fp - Process.zargs[0]] = value;
                }
                else
                {
                    zword addr = (zword)(Main.h_globals + 2 * (Process.zargs[0] - 16));
                    FastMem.SetWord(addr, value);
                }
            }
            else
            {     /* it's V6, but is there a user stack? */
                if (Process.zargc == 1)
                { /* it's a user stack */
                    zword addr = Process.zargs[0];

                    FastMem.LowWord(addr, out ushort size);

                    size++;
                    FastMem.StoreW(addr, size);

                    addr += (zword)(2 * size);
                    FastMem.LowWord(addr, out value);
                }
                else
                {
                    value = Main.Stack[Main.sp++];// value = *sp++;	/* it's the game stack */
                }

                Process.Store(value);
            }
        }/* z_pull */
示例#12
0
        }/* z_dec_chk */

        /*
         * z_inc, increment a variable.
         *
         *  zargs[0] = variable to increment
         *
         */

        internal static void ZInc()
        {
            if (Process.zargs[0] == 0)
            {
                Main.Stack[Main.sp]++; // (*sp)++;
            }
            else if (Process.zargs[0] < 16)
            {
                (Main.Stack[Main.fp - Process.zargs[0]])++;
            }
            else
            {
                zword addr = (zword)(Main.h_globals + 2 * (Process.zargs[0] - 16));
                FastMem.LowWord(addr, out ushort value);
                value++;
                FastMem.SetWord(addr, value);
            }
        }/* z_inc */
示例#13
0
        /*
         * z_dec, decrement a variable.
         *
         *  zargs[0] = variable to decrement
         *
         */

        internal static void ZDec()
        {
            if (Process.zargs[0] == 0)
            {
                Main.Stack[Main.sp]--;
            }
            else if (Process.zargs[0] < 16)
            {
                Main.Stack[Main.fp - Process.zargs[0]]--;
            }
            else
            {
                zword addr = (zword)(Main.h_globals + 2 * (Process.zargs[0] - 16));
                FastMem.LowWord(addr, out ushort value);
                value--;
                FastMem.SetWord(addr, value);
            }
        }/* z_dec */
示例#14
0
        } /* 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 */
示例#15
0
        }/* object_address */

        /*
         * object_name
         *
         * Return the address of the given object's name.
         *
         */
        internal static zword ObjectName(zword object_var)
        {
            zword obj_addr = ObjectAddress(object_var);

            /* The object name address is found at the start of the properties */

            if (Main.h_version <= ZMachine.V3)
            {
                obj_addr += O1_PROPERTY_OFFSET;
            }
            else
            {
                obj_addr += O4_PROPERTY_OFFSET;
            }

            FastMem.LowWord(obj_addr, out zword name_addr);

            return(name_addr);
        }/* object_name */
示例#16
0
        }/* z_inc_chk */

        /*
         * z_load, store the value of a variable.
         *
         *	zargs[0] = variable to store
         *
         */

        internal static void ZLoad()
        {
            zword value;

            if (Process.zargs[0] == 0)
            {
                value = Main.Stack[Main.sp];
            }
            else if (Process.zargs[0] < 16)
            {
                value = Main.Stack[Main.fp - Process.zargs[0]];
            }
            else
            {
                zword addr = (zword)(Main.h_globals + 2 * (Process.zargs[0] - 16));
                FastMem.LowWord(addr, out value);
            }

            Process.Store(value);
        }/* z_load */
示例#17
0
        }/* 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 */
示例#18
0
        }/* z_dec */

        /*
         * z_dec_chk, decrement a variable and branch if now less than value.
         *
         *  zargs[0] = variable to decrement
         *  zargs[1] = value to check variable against
         *
         */

        internal static void ZDecChk()
        {
            zword value;

            if (Process.zargs[0] == 0)
            {
                value = --Main.Stack[Main.sp];
            }
            else if (Process.zargs[0] < 16)
            {
                value = --Main.Stack[Main.fp - Process.zargs[0]];
            }
            else
            {
                zword addr = (zword)(Main.h_globals + 2 * (Process.zargs[0] - 16));
                FastMem.LowWord(addr, out value);
                value--;
                FastMem.SetWord(addr, value);
            }

            Process.Branch((short)value < (short)Process.zargs[1]);
        }/* z_dec_chk */
示例#19
0
        }/* memory_new_line */

        /*
         * memory_word
         *
         * Redirect a string of characters to the memory of the Z-machine.
         *
         */

        internal static void MemoryWord(ReadOnlySpan <zword> s)
        {
            zword addr;
            zword c;

            int pos = 0;

            if (Main.h_version == ZMachine.V6)
            {
                int width = OS.StringWidth(s);

                if (redirect[depth].XSize != 0xffff)
                {
                    if (redirect[depth].Width + width > redirect[depth].XSize)
                    {
                        if (s[pos] is ' ' or CharCodes.ZC_INDENT or CharCodes.ZC_GAP)
                        {
                            width = OS.StringWidth(s.Slice(++pos));
                        }

                        MemoryNewline();
                    }
                }

                redirect[depth].Width += (zword)width;
            }

            addr = redirect[depth].Table;

            FastMem.LowWord(addr, out zword size);
            addr += 2;

            while ((c = s[pos++]) != 0)
            {
                FastMem.StoreB((zword)(addr + (size++)), Text.TranslateToZscii(c));
            }

            FastMem.StoreW(redirect[depth].Table, size);
        }/* memory_word */
示例#20
0
        }/* 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 */
示例#21
0
        }/* memory_open */

        /*
         * memory_new_line
         *
         * Redirect a newline to the memory of the Z-machine.
         *
         */

        internal static void MemoryNewline()
        {
            zword addr;

            redirect[depth].Total += redirect[depth].Width;
            redirect[depth].Width  = 0;

            addr = redirect[depth].Table;

            FastMem.LowWord(addr, out zword 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 */
示例#22
0
        }/* 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 */