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
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
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
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