Пример #1
0
        }/* reset_memory */

        /*
         * storeb
         *
         * Write a byte value to the dynamic Z-machine memory.
         *
         */

        internal static void storeb(zword addr, zbyte value)
        {
            if (addr >= main.h_dynamic_size)
            {
                Err.runtime_error(ErrorCodes.ERR_STORE_RANGE);
            }

            if (addr == ZMachine.H_FLAGS + 1)
            {   /* flags register is modified */
                main.h_flags &= (zword)(~(ZMachine.SCRIPTING_FLAG | ZMachine.FIXED_FONT_FLAG));
                main.h_flags |= (zword)(value & (ZMachine.SCRIPTING_FLAG | ZMachine.FIXED_FONT_FLAG));

                if ((value & ZMachine.SCRIPTING_FLAG) > 0)
                {
                    if (!main.ostream_script)
                    {
                        Files.script_open();
                    }
                }
                else
                {
                    if (main.ostream_script)
                    {
                        Files.script_close();
                    }
                }

                Screen.refresh_text_style();
            }

            SET_BYTE(addr, value);

            DebugState.Output("storeb: {0} -> {1}", addr, value);
        }/* storeb */
Пример #2
0
        }/* z_catch */

        /*
         * z_throw, go back to the given stack frame and return the given value.
         *
         *	zargs[0] = value to return
         *	zargs[1] = stack frame
         *
         */

        internal static void z_throw()
        {
            // TODO This has never been tested
            if (main.option_save_quetzal == true)
            {
                if (zargs[1] > main.frame_count)
                {
                    Err.runtime_error(ErrorCodes.ERR_BAD_FRAME);
                }

                /* Unwind the stack a frame at a time. */
                for (; main.frame_count > zargs[1]; --main.frame_count)
                {
                    //fp = stack + 1 + fp[1];
                    main.fp = 1 + main.stack[main.fp + 1]; // TODO I think this is correct
                }
            }
            else
            {
                if (zargs[1] > General.STACK_SIZE)
                {
                    Err.runtime_error(ErrorCodes.ERR_BAD_FRAME);
                }

                main.fp = zargs[1]; // fp = stack + zargs[1];
            }

            ret(zargs[0]);
        }/* z_throw */
Пример #3
0
        /*
         * 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 */
Пример #4
0
        }/* z_art_shift */

        /*
         * z_div, signed 16bit division.
         *
         *	zargs[0] = first value
         *	zargs[1] = second value
         *
         */

        internal static void z_div()
        {
            if (Process.zargs[1] == 0)
            {
                Err.runtime_error(ErrorCodes.ERR_DIV_ZERO);
            }

            Process.store((zword)((short)Process.zargs[0] / (short)Process.zargs[1]));
        }/* z_div */
Пример #5
0
        }/* 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 */
Пример #6
0
        }/* 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 */
Пример #7
0
        internal static void print_char(zword c)
        {
            if (main.message || main.ostream_memory || main.enable_buffering)
            {
                if (!print_char_flag)
                {
                    /* Characters 0 and ZC_RETURN are special cases */

                    if (c == CharCodes.ZC_RETURN)
                    {
                        new_line(); return;
                    }
                    if (c == 0)
                    {
                        return;
                    }

                    /* Flush the buffer before a whitespace or after a hyphen */

                    if (c == ' ' || c == CharCodes.ZC_INDENT || c == CharCodes.ZC_GAP || (prev_c == '-' && c != '-'))
                    {
                        flush_buffer();
                    }

                    /* Set the flag if this is part one of a style or font change */

                    if (c == CharCodes.ZC_NEW_FONT || c == CharCodes.ZC_NEW_STYLE)
                    {
                        print_char_flag = true;
                    }

                    /* Remember the current character code */

                    prev_c = c;
                }
                else
                {
                    print_char_flag = false;
                }

                /* Insert the character into the buffer */

                buffer_var[bufpos++] = (char)c;

                if (bufpos == General.TEXT_BUFFER_SIZE)
                {
                    Err.runtime_error(ErrorCodes.ERR_TEXT_BUF_OVF);
                }
            }
            else
            {
                Stream.stream_char(c);
            }
        }/* print_char */
Пример #8
0
        }/* 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 */
Пример #9
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 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 */
Пример #10
0
        }/* 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 */
Пример #11
0
        }/* z_check_arg_count */

        /*
         * z_jump, jump unconditionally to the given address.
         *
         *	zargs[0] = PC relative address
         *
         */

        internal static void z_jump()
        {
            long pc;

            FastMem.GET_PC(out pc);

            pc += (short)zargs[0] - 2; // TODO This actually counts on an overflow to work

            if (pc >= main.story_size)
            {
                Err.runtime_error(ErrorCodes.ERR_ILL_JUMP_ADDR);
            }

            FastMem.SET_PC(pc);
        }/* z_jump */
Пример #12
0
        }/* 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 */
Пример #13
0
        }/* 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 */
Пример #14
0
        }/* 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 */
Пример #15
0
        }/* 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 */
Пример #16
0
        }/* call */

        /*
         * ret
         *
         * Return from the current subroutine and restore the previous stack
         * frame. The result may be stored (0), thrown away (1) or pushed on
         * the stack (2). In the latter case a direct call has been finished
         * and we must exit the interpreter loop.
         *
         */

        internal static void ret(zword value)
        {
            long pc;
            int  ct;

            if (main.sp > main.fp)
            {
                Err.runtime_error(ErrorCodes.ERR_STK_UNDF);
            }

            main.sp = main.fp;

            DebugState.Output("Removing Frame: {0}", main.frame_count);

            ct = main.stack[main.sp++] >> (main.option_save_quetzal == true ? 12 : 8);
            main.frame_count--;
            main.fp = 1 + main.stack[main.sp++];              // fp = stack + 1 + *sp++;
            pc      = main.stack[main.sp++];
            pc      = (main.stack[main.sp++] << 9) | (int)pc; // TODO Really don't trust casting PC to int

            FastMem.SET_PC(pc);

            /* Handle resulting value */

            if (ct == 0)
            {
                store(value);
            }
            if (ct == 2)
            {
                main.stack[--main.sp] = value;
            }

            /* Stop main loop for direct calls */

            if (ct == 2)
            {
                finished++;
            }
        }/* ret */
Пример #17
0
        /*
         * object_address
         *
         * Calculate the address of an object.
         *
         */

        internal static zword object_address(zword obj)
        {
            /* Check object number */

            if (obj > ((main.h_version <= ZMachine.V3) ? 255 : MAX_OBJECT))
            {
                Text.print_string("@Attempt to address illegal object ");
                Text.print_num(obj);
                Text.print_string(".  This is normally fatal.");
                Buffer.new_line();
                Err.runtime_error(ErrorCodes.ERR_ILL_OBJ);
            }

            /* Return object address */

            if (main.h_version <= ZMachine.V3)
            {
                return((zword)(main.h_objects + ((obj - 1) * O1_SIZE + 62)));
            }
            else
            {
                return((zword)(main.h_objects + ((obj - 1) * O4_SIZE + 126)));
            }
        }/* object_address */
Пример #18
0
        /*
         * Save a game using Quetzal format. Return 1 if OK, 0 if failed.
         */

        internal static zword save_quetzal(FileStream svf, MemoryStream stf)
        {
            zlong ifzslen = 0, cmemlen = 0, stkslen = 0;
            long  pc;
            zword i, j, n;
            int   nvars, nargs, nstk, p;
            zbyte var;
            long  cmempos, stkspos;
            int   c;

            /* Write `IFZS' header. */
            if (!write_chnk(svf, ID_FORM, 0))
            {
                return(0);
            }
            if (!write_long(svf, ID_IFZS))
            {
                return(0);
            }

            /* Write `IFhd' chunk. */
            FastMem.GET_PC(out pc);
            if (!write_chnk(svf, ID_IFhd, 13))
            {
                return(0);
            }
            if (!write_word(svf, main.h_release))
            {
                return(0);
            }
            for (i = ZMachine.H_SERIAL; i < ZMachine.H_SERIAL + 6; ++i)
            {
                if (!write_byte(svf, FastMem.ZMData[FastMem.zmp + i]))
                {
                    return(0);
                }
            }
            if (!write_word(svf, main.h_checksum))
            {
                return(0);
            }
            if (!write_long(svf, pc << 8)) /* Includes pad. */ return {
                (0);
            }

            /* Write `CMem' chunk. */
            if ((cmempos = svf.Position) < 0)
            {
                return(0);
            }
            if (!write_chnk(svf, ID_CMem, 0))
            {
                return(0);
            }
            // (void) fseek (stf, 0, SEEK_SET);
            stf.Position = 0;
            /* j holds current run length. */
            for (i = 0, j = 0, cmemlen = 0; i < main.h_dynamic_size; ++i)
            {
                if ((c = stf.ReadByte()) == -1)
                {
                    return(0);
                }
                c ^= (int)FastMem.ZMData[i];
                if (c == 0)
                {
                    ++j;        /* It's a run of equal bytes. */
                }
                else
                {
                    /* Write out any run there may be. */
                    if (j > 0)
                    {
                        for (; j > 0x100; j -= 0x100)
                        {
                            if (!write_run(svf, 0xFF))
                            {
                                return(0);
                            }
                            cmemlen += 2;
                        }
                        if (!write_run(svf, (byte)(j - 1)))
                        {
                            return(0);
                        }
                        cmemlen += 2;
                        j        = 0;
                    }
                    /* Any runs are now written. Write this (nonzero) byte. */
                    if (!write_byte(svf, (zbyte)c))
                    {
                        return(0);
                    }
                    ++cmemlen;
                }
            }

            /*
             * Reached end of dynamic memory. We ignore any unwritten run there may be
             * at this point.
             */
            if ((cmemlen & 1) > 0)      /* Chunk length must be even. */
            {
                if (!write_byte(svf, 0))
                {
                    return(0);
                }
            }

            /* Write `Stks' chunk. You are not expected to understand this. ;) */
            if ((stkspos = svf.Position) < 0)
            {
                return(0);
            }
            if (!write_chnk(svf, ID_Stks, 0))
            {
                return(0);
            }

            /*
             * We construct a list of frame indices, most recent first, in `frames'.
             * These indices are the offsets into the `stack' array of the word before
             * the first word pushed in each frame.
             */
            frames[0] = (zword)main.sp; /* The frame we'd get by doing a call now. */
            for (i = (zword)(main.fp + 4), n = 0; i < General.STACK_SIZE + 4; i = (zword)(main.stack[i - 3] + 5))
            {
                frames[++n] = i;
            }

            /*
             * All versions other than V6 can use evaluation stack outside a function
             * context. We write a faked stack frame (most fields zero) to cater for
             * this.
             */
            if (main.h_version != ZMachine.V6)
            {
                for (i = 0; i < 6; ++i)
                {
                    if (!write_byte(svf, 0))
                    {
                        return(0);
                    }
                }
                nstk = General.STACK_SIZE - frames[n];
                if (!write_word(svf, nstk))
                {
                    return(0);
                }
                for (j = (zword)(General.STACK_SIZE - 1); j >= frames[n]; --j)
                {
                    if (!write_word(svf, main.stack[j]))
                    {
                        return(0);
                    }
                }
                stkslen = (zword)(8 + 2 * nstk);
            }

            /* Write out the rest of the stack frames. */
            for (i = n; i > 0; --i)
            {
                p     = frames[i] - 4; // p = stack + frames[i] - 4;	/* Points to call frame. */
                nvars = (main.stack[p] & 0x0F00) >> 8;
                nargs = main.stack[p] & 0x00FF;
                nstk  = (zword)(frames[i] - frames[i - 1] - nvars - 4);
                pc    = ((zlong)main.stack[p + 3] << 9) | main.stack[p + 2];

                switch (main.stack[p] & 0xF000) /* Check type of call. */
                {
                case 0x0000:                    /* Function. */
                    var = FastMem.ZMData[FastMem.zmp + pc];
                    pc  = ((pc + 1) << 8) | (zlong)nvars;
                    break;

                case 0x1000:                               /* Procedure. */
                    var = 0;
                    pc  = (pc << 8) | 0x10 | (zlong)nvars; /* Set procedure flag. */
                    break;

                /* case 0x2000: */
                default:
                    Err.runtime_error(ErrorCodes.ERR_SAVE_IN_INTER);
                    return(0);
                }
                if (nargs != 0)
                {
                    nargs = (zword)((1 << nargs) - 1);  /* Make args into bitmap. */
                }
                /* Write the main part of the frame... */
                if (!write_long(svf, pc) ||
                    !write_byte(svf, var) ||
                    !write_byte(svf, nargs) ||
                    !write_word(svf, nstk))
                {
                    return(0);
                }

                /* Write the variables and eval stack. */
                for (j = 0, --p; j < nvars + nstk; ++j, --p)
                {
                    if (!write_word(svf, main.stack[p]))
                    {
                        return(0);
                    }
                }

                /* Calculate length written thus far. */
                stkslen += (zword)(8 + 2 * (nvars + nstk));
            }

            /* Fill in variable chunk lengths. */
            ifzslen = 3 * 8 + 4 + 14 + cmemlen + stkslen;
            if ((cmemlen & 1) > 0)
            {
                ++ifzslen;
            }
            svf.Position = 4;
            if (!write_long(svf, ifzslen))
            {
                return(0);
            }
            svf.Position = cmempos + 4;
            if (!write_long(svf, cmemlen))
            {
                return(0);
            }
            svf.Position = stkspos + 4;
            if (!write_long(svf, stkslen))
            {
                return(0);
            }

            /* After all that, still nothing went wrong! */
            return(1);
        }
Пример #19
0
        }/* __extended__ */

        /*
         * __illegal__
         *
         * Exit game because an unknown opcode has been hit.
         *
         */

        static void __illegal__()
        {
            Err.runtime_error(ErrorCodes.ERR_ILL_OPCODE);
        }/* __illegal__ */
Пример #20
0
        }/* interpret */

        /*
         * call
         *
         * Call a subroutine. Save PC and FP then load new PC and initialise
         * new stack frame. Note that the caller may legally provide less or
         * more arguments than the function actually has. The call type "ct"
         * can be 0 (z_call_s), 1 (z_call_n) or 2 (direct call).
         *
         */

        internal static void call(zword routine, int argc, int args_offset, int ct)
        {
            long  pc;
            zword value;
            zbyte count;
            int   i;

            if (main.sp < 4)//if (sp - stack < 4)
            {
                Err.runtime_error(ErrorCodes.ERR_STK_OVF);
            }

            FastMem.GET_PC(out pc);

            main.stack[--main.sp] = (zword)(pc >> 9);
            main.stack[--main.sp] = (zword)(pc & 0x1ff);
            main.stack[--main.sp] = (zword)(main.fp - 1); // *--sp = (zword) (fp - stack - 1);
            main.stack[--main.sp] = (zword)(argc | (ct << (main.option_save_quetzal == true ? 12 : 8)));

            main.fp = main.sp;
            main.frame_count++;

            DebugState.Output("Added Frame: {0} -> {1}:{2}:{3}:{4}",
                              main.frame_count,
                              main.stack[main.sp + 0],
                              main.stack[main.sp + 1],
                              main.stack[main.sp + 2],
                              main.stack[main.sp + 3]);

            /* Calculate byte address of routine */

            if (main.h_version <= ZMachine.V3)
            {
                pc = (long)routine << 1;
            }
            else if (main.h_version <= ZMachine.V5)
            {
                pc = (long)routine << 2;
            }
            else if (main.h_version <= ZMachine.V7)
            {
                pc = ((long)routine << 2) + ((long)main.h_functions_offset << 3);
            }
            else /* (h_version <= V8) */
            {
                pc = (long)routine << 3;
            }

            if (pc >= main.story_size)
            {
                Err.runtime_error(ErrorCodes.ERR_ILL_CALL_ADDR);
            }

            FastMem.SET_PC(pc);

            /* Initialise local variables */

            FastMem.CODE_BYTE(out count);

            if (count > 15)
            {
                Err.runtime_error(ErrorCodes.ERR_CALL_NON_RTN);
            }
            if (main.sp < count)
            {
                Err.runtime_error(ErrorCodes.ERR_STK_OVF);
            }

            if (main.option_save_quetzal == true)
            {
                main.stack[main.fp] |= (zword)(count << 8);     /* Save local var count for Quetzal. */
            }
            value = 0;

            for (i = 0; i < count; i++)
            {
                if (main.h_version <= ZMachine.V4)              /* V1 to V4 games provide default */
                {
                    FastMem.CODE_WORD(out value);               /* values for all local variables */
                }
                main.stack[--main.sp] = (zword)((argc-- > 0) ? zargs[args_offset + i] : value);
                //*--sp = (zword) ((argc-- > 0) ? args[i] : value);
            }

            /* Start main loop for direct calls */

            if (ct == 2)
            {
                interpret();
            }
        }/* call */
Пример #21
0
        static void decode_text(string_type st, zword addr)
        {
            // zword* ptr;
            long  byte_addr;
            zword c2;
            zword code;
            zbyte c, prev_c = 0;
            int   shift_state = 0;
            int   shift_lock  = 0;
            int   status      = 0;

            // ptr = NULL;		/* makes compilers shut up */
            byte_addr = 0;

            if (resolution == 0)
            {
                find_resolution();
            }

            /* Calculate the byte address if necessary */

            if (st == string_type.ABBREVIATION)
            {
                byte_addr = (long)addr << 1;
            }

            else if (st == string_type.HIGH_STRING)
            {
                if (main.h_version <= ZMachine.V3)
                {
                    byte_addr = (long)addr << 1;
                }
                else if (main.h_version <= ZMachine.V5)
                {
                    byte_addr = (long)addr << 2;
                }
                else if (main.h_version <= ZMachine.V7)
                {
                    byte_addr = ((long)addr << 2) + ((long)main.h_strings_offset << 3);
                }
                else /* (h_version <= V8) */
                {
                    byte_addr = (long)addr << 3;
                }

                if (byte_addr >= main.story_size)
                {
                    Err.runtime_error(ErrorCodes.ERR_ILL_PRINT_ADDR);
                }
            }

            /* Loop until a 16bit word has the highest bit set */
            if (st == string_type.VOCABULARY)
            {
                ptrDt = 0;
            }

            do
            {
                int i;

                /* Fetch the next 16bit word */

                if (st == string_type.LOW_STRING || st == string_type.VOCABULARY)
                {
                    FastMem.LOW_WORD(addr, out code);
                    addr += 2;
                }
                else if (st == string_type.HIGH_STRING || st == string_type.ABBREVIATION)
                {
                    FastMem.HIGH_WORD(byte_addr, out code);
                    byte_addr += 2;
                }
                else
                {
                    FastMem.CODE_WORD(out code);
                }

                /* Read its three Z-characters */

                for (i = 10; i >= 0; i -= 5)
                {
                    zword abbr_addr;
                    zword ptr_addr;
                    zword zc;

                    c = (zbyte)((code >> i) & 0x1f);

                    switch (status)
                    {
                    case 0:     /* normal operation */

                        if (shift_state == 2 && c == 6)
                        {
                            status = 2;
                        }

                        else if (main.h_version == ZMachine.V1 && c == 1)
                        {
                            Buffer.new_line();
                        }

                        else if (main.h_version >= ZMachine.V2 && shift_state == 2 && c == 7)
                        {
                            Buffer.new_line();
                        }

                        else if (c >= 6)
                        {
                            outchar(st, alphabet(shift_state, c - 6));
                        }

                        else if (c == 0)
                        {
                            outchar(st, ' ');
                        }

                        else if (main.h_version >= ZMachine.V2 && c == 1)
                        {
                            status = 1;
                        }

                        else if (main.h_version >= ZMachine.V3 && c <= 3)
                        {
                            status = 1;
                        }

                        else
                        {
                            shift_state = (shift_lock + (c & 1) + 1) % 3;

                            if (main.h_version <= ZMachine.V2 && c >= 4)
                            {
                                shift_lock = shift_state;
                            }

                            break;
                        }

                        shift_state = shift_lock;

                        break;

                    case 1:     /* abbreviation */

                        ptr_addr = (zword)(main.h_abbreviations + 64 * (prev_c - 1) + 2 * c);

                        FastMem.LOW_WORD(ptr_addr, out abbr_addr);
                        decode_text(string_type.ABBREVIATION, abbr_addr);

                        status = 0;
                        break;

                    case 2:     /* ZSCII character - first part */

                        status = 3;
                        break;

                    case 3:     /* ZSCII character - second part */

                        zc = (zword)((prev_c << 5) | c);

                        c2 = translate_from_zscii((zbyte)zc);     // TODO This doesn't seem right
                        outchar(st, c2);

                        status = 0;
                        break;
                    }

                    prev_c = c;
                }
            } while (!((code & 0x8000) > 0));

            if (st == string_type.VOCABULARY)
            {
                ptrDt = 0;
            }
        }/* decode_text */
Пример #22
0
        }/* 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 */
Пример #23
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 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 */
Пример #24
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 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 */