def write_data(self, rom: LocalRom): # move file to remap address self.file.relocate(rom) headcur = self.file.start code = rom.read_byte(headcur) loop = 0x20 while loop != 0 and code != 0x14: #terminator loop -= 1 if code == 0x01: # actors offset = self.file.end - self.file.start write_actor_data(rom, self.file.end, self.actors) self.file.end += len(self.actors) * 0x10 rom.write_byte(headcur + 1, len(self.actors)) rom.write_int32(headcur + 4, get_segment_address(3, offset)) elif code == 0x0B: # objects offset = self.append_object_data(rom, self.objects) rom.write_byte(headcur + 1, len(self.objects)) rom.write_int32(headcur + 4, get_segment_address(3, offset)) headcur += 8 code = rom.read_byte(headcur) # update file reference self.file.end = align16(self.file.end) update_dmadata(rom, self.file)
def patch_spirit_temple_mq_room_6(rom: LocalRom, room_addr): cur = room_addr actor_list_addr = 0 cmd_actors_offset = 0 # scan for actor list and header end code = rom.read_byte(cur) while code != 0x14: #terminator if code == 0x01: # actors actor_list_addr = rom.read_int32(cur + 4) cmd_actors_offset = cur - room_addr cur += 8 code = rom.read_byte(cur) cur += 8 # original header size header_size = cur - room_addr # set alternate header data location alt_data_off = header_size + 8 # set new alternate header offset alt_header_off = align16(alt_data_off + (4 * 3)) # alt header record size * num records # write alternate header data # the first 3 words are mandatory. the last 3 are just to make the binary # cleaner to read rom.write_int32s(room_addr + alt_data_off, [0, get_segment_address(3, alt_header_off), 0, 0, 0, 0]) # clone header a_start = room_addr a_end = a_start + header_size b_start = room_addr + alt_header_off b_end = b_start + header_size rom.buffer[b_start:b_end] = rom.buffer[a_start:a_end] # make the child header skip the first actor, # which avoids the spawning of the block while in the hole cmd_addr = room_addr + cmd_actors_offset actor_list_addr += 0x10 actors = rom.read_byte(cmd_addr + 1) rom.write_byte(cmd_addr + 1, actors - 1) rom.write_int32(cmd_addr + 4, actor_list_addr) # move header rom.buffer[a_start + 8:a_end + 8] = rom.buffer[a_start:a_end] # write alternate header command seg = get_segment_address(3, alt_data_off) rom.write_int32s(room_addr, [0x18000000, seg])
def write_data(self, rom: LocalRom): # write floormap and minimap data self.write_map_data(rom) # move file to remap address self.file.relocate(rom) start = self.file.start headcur = self.file.start room_list_offset = 0 code = rom.read_byte(headcur) loop = 0x20 while loop > 0 and code != 0x14: #terminator loop -= 1 if code == 0x03: #collision col_mesh_offset = rom.read_int24(headcur + 5) col_mesh = CollisionMesh(rom, start, col_mesh_offset) self.patch_mesh(rom, col_mesh) elif code == 0x04: #rooms room_list_offset = rom.read_int24(headcur + 5) elif code == 0x0D: #paths path_offset = self.append_path_data(rom) rom.write_int32(headcur + 4, path_offset) elif code == 0x0E: #transition actors t_offset = rom.read_int24(headcur + 5) addr = self.file.start + t_offset write_actor_data(rom, addr, self.transition_actors) headcur += 8 code = rom.read_byte(headcur) # update file references self.file.end = align16(self.file.end) update_dmadata(rom, self.file) update_scene_table(rom, self.id, self.file.start, self.file.end) # write room file data for room in self.rooms: room.write_data(rom) if self.id == 6 and room.id == 6: patch_spirit_temple_mq_room_6(rom, room.file.start) cur = self.file.start + room_list_offset for room in self.rooms: rom.write_int32s(cur, [room.file.start, room.file.end]) cur += 0x08
def adjust(args): start = time.perf_counter() logger = logging.getLogger('Adjuster') logger.info('Patching ROM.') vanillaRom = args.baserom if os.path.splitext(args.rom)[-1].lower() == '.bmbp': import Patch meta, args.rom = Patch.create_rom_file(args.rom) if os.stat(args.rom).st_size in (0x200000, 0x400000) and os.path.splitext( args.rom)[-1].lower() == '.sfc': rom = LocalRom(args.rom, patch=False, vanillaRom=vanillaRom) else: raise RuntimeError( 'Provided Rom is not a valid Link to the Past Randomizer Rom. Please provide one for adjusting.' ) palettes_options = {} palettes_options['dungeon'] = args.uw_palettes palettes_options['overworld'] = args.ow_palettes palettes_options['hud'] = args.hud_palettes palettes_options['sword'] = args.sword_palettes palettes_options['shield'] = args.shield_palettes # palettes_options['link']=args.link_palettesvera racerom = rom.read_byte(0x180213) > 0 apply_rom_settings( rom, args.heartbeep, args.heartcolor, args.quickswap, args.fastmenu, args.disablemusic, args.sprite, palettes_options, cutscenespeed=args.cutscenespeed if not racerom else "normal", reduceflashing=args.reduceflashing) path = output_path(f'{os.path.basename(args.rom)[:-4]}_adjusted.sfc') rom.write_to_file(path) logger.info('Done. Enjoy.') logger.debug('Total Time: %s', time.perf_counter() - start) return args, path
def patch_mesh(self, rom: LocalRom, mesh: CollisionMesh): start = self.file.start final_cams = [] # build final camera data for cam in self.coldelta.cams: data = cam['Data'] pos = cam['PositionIndex'] if pos < 0: final_cams.append((data, 0)) else: addr = start + (mesh.camera_data_addr & 0xFFFFFF) seg_off = rom.read_int32(addr + (pos * 8) + 4) final_cams.append((data, seg_off)) types_move_addr = 0 # if data can't fit within the old mesh space, append camera data if self.coldelta.is_larger: types_move_addr = mesh.camera_data_addr # append to end of file self.write_cam_data(rom, self.file.end, final_cams) mesh.camera_data_addr = get_segment_address( 2, self.file.end - self.file.start) self.file.end += len(final_cams) * 8 else: types_move_addr = mesh.camera_data_addr + (len(final_cams) * 8) # append in place addr = self.file.start + (mesh.camera_data_addr & 0xFFFFFF) self.write_cam_data(rom, addr, final_cams) # if polytypes needs to be moved, do so if (types_move_addr != mesh.polytypes_addr): a_start = self.file.start + (mesh.polytypes_addr & 0xFFFFFF) b_start = self.file.start + (types_move_addr & 0xFFFFFF) size = mesh.polytypes * 8 rom.buffer[b_start:b_start + size] = rom.buffer[a_start:a_start + size] mesh.polytypes_addr = types_move_addr # patch polytypes for item in self.coldelta.polytypes: id = item['Id'] high = item['High'] low = item['Low'] addr = self.file.start + (mesh.polytypes_addr & 0xFFFFFF) + (id * 8) rom.write_int32s(addr, [high, low]) # patch poly data for item in self.coldelta.polys: id = item['Id'] t = item['Type'] flags = item['Flags'] addr = self.file.start + (mesh.poly_addr & 0xFFFFFF) + (id * 0x10) vert_bit = rom.read_byte(addr + 0x02) & 0x1F # VertexA id data rom.write_int16(addr, t) rom.write_byte(addr + 0x02, (flags << 5) + vert_bit) # Write Mesh to Scene mesh.write_to_scene(rom, self.file.start)