Example #1
0
    def read(cls, file):
        anm_list = []
        start_offset = 0
        while True:
            file.seek(start_offset)
            nb_sprites, nb_scripts, zero1 = unpack('<III', file.read(12))
            width, height, fmt, unknown1 = unpack('<IIII', file.read(16))
            first_name_offset, unused, secondary_name_offset = unpack(
                '<III', file.read(12))
            version, unknown2, texture_offset, has_data, next_offset, unknown3 = unpack(
                '<IIIIII', file.read(24))

            if version == 0:
                assert zero1 == 0
                assert unknown3 == 0
                assert has_data == 0
            elif version == 2:
                assert zero1 == 0
                assert secondary_name_offset == 0
                assert has_data == 1  # Can be false but we don’t support that yet.
            else:
                raise WrongFormatError(version)

            instructions = cls._instructions[version]

            sprite_offsets = [
                unpack('<I', file.read(4))[0] for i in range(nb_sprites)
            ]
            script_offsets = [
                unpack('<II', file.read(8)) for i in range(nb_scripts)
            ]

            self = cls()

            self.size = (width, height)
            self.version = version

            # Names
            if first_name_offset:
                file.seek(start_offset + first_name_offset)
                self.first_name = read_string(file, 32,
                                              'ascii')  #TODO: 32, really?
            if secondary_name_offset:
                file.seek(start_offset + secondary_name_offset)
                self.secondary_name = read_string(file, 32,
                                                  'ascii')  #TODO: 32, really?

            # Sprites
            for offset in sprite_offsets:
                file.seek(start_offset + offset)
                idx, x, y, width, height = unpack('<Iffff', file.read(20))
                self.sprites[idx] = x, y, width, height

            # Scripts
            for i, offset in script_offsets:
                self.scripts[i] = Script()
                instruction_offsets = []
                file.seek(start_offset + offset)
                while True:
                    instruction_offsets.append(file.tell() -
                                               (start_offset + offset))
                    if version == 0:
                        time, opcode, size = unpack('<HBB', file.read(4))
                    elif version == 2:
                        opcode, size, time, mask = unpack(
                            '<HHHH', file.read(8))
                        if opcode == 0xffff:
                            break
                        size -= 8
                    data = file.read(size)
                    if opcode in instructions:
                        args = unpack('<%s' % instructions[opcode][0], data)
                    else:
                        args = (data, )
                        logger.warn('unknown opcode %d', opcode)

                    self.scripts[i].append((time, opcode, args))
                    if version == 0 and opcode == 0:
                        break

                # Translate offsets to instruction pointers and register interrupts
                for instr_offset, (j,
                                   instr) in zip(instruction_offsets,
                                                 enumerate(self.scripts[i])):
                    time, opcode, args = instr
                    if version == 0:
                        if opcode == 5:
                            args = (instruction_offsets.index(args[0]), )
                        elif opcode == 22:
                            interrupt = args[0]
                            self.scripts[i].interrupts[interrupt] = j + 1
                    elif version == 2:
                        if opcode == 4:
                            args = (instruction_offsets.index(args[0]),
                                    args[1])
                        elif opcode == 5:
                            args = (args[0],
                                    instruction_offsets.index(args[1]),
                                    args[2])
                        elif opcode == 21:
                            interrupt = args[0]
                            self.scripts[i].interrupts[interrupt] = j + 1
                        elif opcode == 69:
                            args = (args[0], args[1],
                                    instruction_offsets.index(args[2]),
                                    args[3])
                    self.scripts[i][j] = time, opcode, args

            # Texture
            if has_data:
                file.seek(start_offset + texture_offset)
                magic = file.read(4)
                assert magic == b'THTX'
                zero, fmt, width, height, size = unpack(
                    '<HHHHI', file.read(12))
                assert zero == 0
                data = file.read(size)
                self.texture = Texture(width, height, fmt, data)

            anm_list.append(self)

            if next_offset:
                start_offset += next_offset
            else:
                break

        return anm_list
Example #2
0
    def read(cls, file):
        anm_list = []
        start_offset = 0
        while True:
            file.seek(start_offset)
            nb_sprites, nb_scripts, zero1 = unpack("<III", file.read(12))
            width, height, fmt, unknown1 = unpack("<IIII", file.read(16))
            first_name_offset, unused, secondary_name_offset = unpack("<III", file.read(12))
            version, unknown2, texture_offset, has_data, next_offset, unknown3 = unpack("<IIIIII", file.read(24))

            if version == 0:
                assert zero1 == 0
                assert unknown3 == 0
                assert has_data == 0
            elif version == 2:
                assert zero1 == 0
                assert secondary_name_offset == 0
                assert has_data == 1  # Can be false but we don’t support that yet.
            else:
                raise WrongFormatError(version)

            instructions = cls._instructions[version]

            sprite_offsets = [unpack("<I", file.read(4))[0] for i in range(nb_sprites)]
            script_offsets = [unpack("<II", file.read(8)) for i in range(nb_scripts)]

            self = cls()

            self.size = (width, height)
            self.version = version

            # Names
            if first_name_offset:
                file.seek(start_offset + first_name_offset)
                self.first_name = read_string(file, 32, "ascii")  # TODO: 32, really?
            if secondary_name_offset:
                file.seek(start_offset + secondary_name_offset)
                self.secondary_name = read_string(file, 32, "ascii")  # TODO: 32, really?

            # Sprites
            for offset in sprite_offsets:
                file.seek(start_offset + offset)
                idx, x, y, width, height = unpack("<Iffff", file.read(20))
                self.sprites[idx] = x, y, width, height

            # Scripts
            for i, offset in script_offsets:
                self.scripts[i] = Script()
                instruction_offsets = []
                file.seek(start_offset + offset)
                while True:
                    instruction_offsets.append(file.tell() - (start_offset + offset))
                    if version == 0:
                        time, opcode, size = unpack("<HBB", file.read(4))
                    elif version == 2:
                        opcode, size, time, mask = unpack("<HHHH", file.read(8))
                        if opcode == 0xFFFF:
                            break
                        size -= 8
                    data = file.read(size)
                    if opcode in instructions:
                        args = unpack("<%s" % instructions[opcode][0], data)
                    else:
                        args = (data,)
                        logger.warn("unknown opcode %d", opcode)

                    self.scripts[i].append((time, opcode, args))
                    if version == 0 and opcode == 0:
                        break

                # Translate offsets to instruction pointers and register interrupts
                for instr_offset, (j, instr) in zip(instruction_offsets, enumerate(self.scripts[i])):
                    time, opcode, args = instr
                    if version == 0:
                        if opcode == 5:
                            args = (instruction_offsets.index(args[0]),)
                        elif opcode == 22:
                            interrupt = args[0]
                            self.scripts[i].interrupts[interrupt] = j + 1
                    elif version == 2:
                        if opcode == 4:
                            args = (instruction_offsets.index(args[0]), args[1])
                        elif opcode == 5:
                            args = (args[0], instruction_offsets.index(args[1]), args[2])
                        elif opcode == 21:
                            interrupt = args[0]
                            self.scripts[i].interrupts[interrupt] = j + 1
                        elif opcode == 69:
                            args = (args[0], args[1], instruction_offsets.index(args[2]), args[3])
                    self.scripts[i][j] = time, opcode, args

            # Texture
            if has_data:
                file.seek(start_offset + texture_offset)
                magic = file.read(4)
                assert magic == b"THTX"
                zero, fmt, width, height, size = unpack("<HHHHI", file.read(12))
                assert zero == 0
                data = file.read(size)
                self.texture = Texture(width, height, fmt, data)

            anm_list.append(self)

            if next_offset:
                start_offset += next_offset
            else:
                break

        return anm_list
Example #3
0
    def read(cls, file):
        """Read a Stage Definition file.

        Raise an exception if the file is invalid.
        Return a STD instance otherwise.
        """

        stage = Stage()

        nb_models, nb_faces = unpack("<HH", file.read(4))
        object_instances_offset, script_offset, zero = unpack("<III", file.read(12))
        assert zero == 0

        stage.name = read_string(file, 128, "shift_jis")

        bgm_a = read_string(file, 128, "shift_jis")
        bgm_b = read_string(file, 128, "shift_jis")
        bgm_c = read_string(file, 128, "shift_jis")
        bgm_d = read_string(file, 128, "shift_jis")

        bgm_a_path = read_string(file, 128, "ascii")
        bgm_b_path = read_string(file, 128, "ascii")
        bgm_c_path = read_string(file, 128, "ascii")
        bgm_d_path = read_string(file, 128, "ascii")

        stage.bgms = [
            None if bgm[0] == u" " else bgm
            for bgm in ((bgm_a, bgm_a_path), (bgm_b, bgm_b_path), (bgm_c, bgm_c_path), (bgm_d, bgm_d_path))
        ]

        # Read model definitions
        offsets = unpack("<%s" % ("I" * nb_models), file.read(4 * nb_models))
        for offset in offsets:
            model = Model()
            file.seek(offset)

            # Read model header
            id_, unknown, x, y, z, width, height, depth = unpack("<HHffffff", file.read(28))
            model.unknown = unknown
            model.bounding_box = x, y, z, width, height, depth  # TODO: check

            # Read model quads
            while True:
                unknown, size = unpack("<HH", file.read(4))
                if unknown == 0xFFFF:
                    break
                assert size == 0x1C
                script_index, x, y, z, width, height = unpack("<Hxxfffff", file.read(24))
                model.quads.append((script_index, x, y, z, width, height))
            stage.models.append(model)

        # Read object usages
        file.seek(object_instances_offset)
        while True:
            obj_id, unknown, x, y, z = unpack("<HHfff", file.read(16))
            if (obj_id, unknown) == (0xFFFF, 0xFFFF):
                break
            assert unknown == 256  # TODO: really?
            stage.object_instances.append((obj_id, x, y, z))

        # Read the script
        file.seek(script_offset)
        while True:
            frame, opcode, size = unpack("<IHH", file.read(8))
            if (frame, opcode, size) == (0xFFFFFFFF, 0xFFFF, 0xFFFF):
                break
            assert size == 0x0C
            data = file.read(size)
            if opcode in cls._instructions:
                args = unpack("<%s" % cls._instructions[opcode][0], data)
            else:
                args = (data,)
                logger.warn("unknown opcode %d", opcode)
            stage.script.append((frame, opcode, args))

        return stage
Example #4
0
    def read(cls, file):
        """Read a Stage Definition file.

        Raise an exception if the file is invalid.
        Return a STD instance otherwise.
        """

        stage = Stage()

        nb_models, nb_faces = unpack('<HH', file.read(4))
        object_instances_offset, script_offset, zero = unpack(
            '<III', file.read(12))
        assert zero == 0

        stage.name = read_string(file, 128, 'shift_jis')

        bgm_a = read_string(file, 128, 'shift_jis')
        bgm_b = read_string(file, 128, 'shift_jis')
        bgm_c = read_string(file, 128, 'shift_jis')
        bgm_d = read_string(file, 128, 'shift_jis')

        bgm_a_path = read_string(file, 128, 'ascii')
        bgm_b_path = read_string(file, 128, 'ascii')
        bgm_c_path = read_string(file, 128, 'ascii')
        bgm_d_path = read_string(file, 128, 'ascii')

        stage.bgms = [
            None if bgm[0] == u' ' else bgm
            for bgm in ((bgm_a, bgm_a_path), (bgm_b, bgm_b_path),
                        (bgm_c, bgm_c_path), (bgm_d, bgm_d_path))
        ]

        # Read model definitions
        offsets = unpack('<%s' % ('I' * nb_models), file.read(4 * nb_models))
        for offset in offsets:
            model = Model()
            file.seek(offset)

            # Read model header
            id_, unknown, x, y, z, width, height, depth = unpack(
                '<HHffffff', file.read(28))
            model.unknown = unknown
            model.bounding_box = x, y, z, width, height, depth  #TODO: check

            # Read model quads
            while True:
                unknown, size = unpack('<HH', file.read(4))
                if unknown == 0xffff:
                    break
                assert size == 0x1c
                script_index, x, y, z, width, height = unpack(
                    '<Hxxfffff', file.read(24))
                model.quads.append((script_index, x, y, z, width, height))
            stage.models.append(model)

        # Read object usages
        file.seek(object_instances_offset)
        while True:
            obj_id, unknown, x, y, z = unpack('<HHfff', file.read(16))
            if (obj_id, unknown) == (0xffff, 0xffff):
                break
            assert unknown == 256  #TODO: really?
            stage.object_instances.append((obj_id, x, y, z))

        # Read the script
        file.seek(script_offset)
        while True:
            frame, opcode, size = unpack('<IHH', file.read(8))
            if (frame, opcode, size) == (0xffffffff, 0xffff, 0xffff):
                break
            assert size == 0x0c
            data = file.read(size)
            if opcode in cls._instructions:
                args = unpack('<%s' % cls._instructions[opcode][0], data)
            else:
                args = (data, )
                logger.warn('unknown opcode %d', opcode)
            stage.script.append((frame, opcode, args))

        return stage