def _init_td_label_stores(self): self._labels_td_level = {} self._labels_td_dungeon = {} store: Gtk.ListStore = self.builder.get_object('td_level_store') self._labels_td_level[-1] = _('None') store.append([-1, _('None')]) if self._list: for level in self._list.list: lbl = f'{level.name} (#{level.id:03})' self._labels_td_level[level.id] = lbl store.append([level.id, lbl]) else: for i in range(0, 400): lbl = f'? (#{i:03})' self._labels_td_level[i] = lbl store.append([i, lbl]) static = self.module.project.get_rom_module().get_static_data() dungeons = HardcodedDungeons.get_dungeon_list( self.module.project.get_binary(BinaryName.ARM9), static) store: Gtk.ListStore = self.builder.get_object('td_dungeon_store') for i, dungeon in enumerate(dungeons): lbl = f'{self.module.project.get_string_provider().get_value(StringType.DUNGEON_NAMES_SELECTION, i)} (#{i:03})' self._labels_td_dungeon[i] = lbl store.append([i, lbl])
def save_dungeon_restrictions(self, restrictions: List[DungeonRestriction]): self.project.modify_binary( BinaryName.ARM9, lambda binary: HardcodedDungeons.set_dungeon_restrictions( restrictions, binary, self.project.get_rom_module().get_static_data()))
def __init__(self, config: RandomizerConfig, rom: NintendoDSRom, static_data: Pmd2Data, seed: str): super().__init__(config, rom, static_data, seed) self.dungeons = HardcodedDungeons.get_dungeon_list( get_binary_from_rom_ppmdu(self.rom, self.static_data.binaries['arm9.bin']), self.static_data)
def set_tileset_properties(self, lst: List[TilesetProperties]): self.project.modify_binary( BinaryName.OVERLAY_10, lambda binary: HardcodedDungeons.set_tileset_properties( lst, binary, self.project.get_rom_module().get_static_data())) row = self._tree_model[self._root_node] recursive_up_item_store_mark_as_modified(row)
def _init_secondary_terrain(self): w: Gtk.ComboBox = self.builder.get_object('secondary_terrain_type') s: Gtk.ListStore = w.get_model() for v in SecondaryTerrainTableEntry: s.append([v.value, v.name.capitalize()]) secondary_terrain = HardcodedDungeons.get_secondary_terrains( self.module.project.get_binary(BinaryName.ARM9), self.module.project.get_rom_module().get_static_data() )[self.item_id] w.set_active(secondary_terrain.value)
def on_secondary_terrain_type_changed(self, w: Gtk.ComboBox): idx = w.get_active() static = self.module.project.get_rom_module().get_static_data() secondary_terrains = HardcodedDungeons.get_secondary_terrains( self.module.project.get_binary(BinaryName.ARM9), static ) secondary_terrains[self.item_id] = SecondaryTerrainTableEntry(idx) def update(arm9): HardcodedDungeons.set_secondary_terrains(secondary_terrains, arm9, static) self.module.project.modify_binary(BinaryName.ARM9, update) self.mark_as_modified()
def get_mapping_dungeon_assets( self ) -> Tuple[List[GroundTilesetMapping], MappaBin, FixedBin, ModelContext[DungeonBinPack], List[DungeonDefinition]]: static_data = self.project.get_rom_module().get_static_data() config = self.project.get_rom_module().get_static_data() ov11 = self.project.get_binary(BinaryName.OVERLAY_11) mappings = HardcodedGroundDungeonTilesets.get_ground_dungeon_tilesets(ov11, config) mappa = self.project.open_file_in_rom('BALANCE/mappa_s.bin', FileType.MAPPA_BIN) fixed = self.project.open_file_in_rom( 'BALANCE/fixed.bin', FileType.FIXED_BIN, static_data=static_data ) dungeon_bin_context: ModelContext[DungeonBinPack] = self.project.open_file_in_rom( 'DUNGEON/dungeon.bin', FileType.DUNGEON_BIN, static_data=static_data, threadsafe=True ) dungeon_list = HardcodedDungeons.get_dungeon_list( self.project.get_binary(BinaryName.ARM9), static_data ) return mappings, mappa, fixed, dungeon_bin_context, dungeon_list
def update(arm9bin): static_data = self.project.get_rom_module().get_static_data() HardcodedDungeons.set_marker_placements(markers, arm9bin, static_data)
def get_world_map_markers(self) -> List[MapMarkerPlacement]: """Returns the world map markers""" arm9bin = self.project.get_binary(BinaryName.ARM9) static_data = self.project.get_rom_module().get_static_data() markers = HardcodedDungeons.get_marker_placements(arm9bin, static_data) return markers
def get_tileset_properties(self) -> List[TilesetProperties]: return HardcodedDungeons.get_tileset_properties( self.project.get_binary(BinaryName.OVERLAY_10), self.project.get_rom_module().get_static_data())
from skytemple_files.hardcoded.dungeons import HardcodedDungeons base_dir = os.path.join(os.path.dirname(__file__), '..', '..', '..', '..') rom_us = NintendoDSRom.fromFile( os.path.join(base_dir, 'skyworkcopy_us_unpatched.nds')) ppmdu_us = get_ppmdu_config_for_rom(rom_us) arm9_us = get_binary_from_rom_ppmdu(rom_us, ppmdu_us.binaries['arm9.bin']) ov10_us = get_binary_from_rom_ppmdu( rom_us, ppmdu_us.binaries['overlay/overlay_0010.bin']) rom_eu = NintendoDSRom.fromFile(os.path.join(base_dir, 'skyworkcopy_edit.nds')) ppmdu_eu = get_ppmdu_config_for_rom(rom_eu) ov10_eu = get_binary_from_rom_ppmdu( rom_eu, ppmdu_eu.binaries['overlay/overlay_0010.bin']) # TilesetProperties lst = HardcodedDungeons.get_tileset_properties(ov10_us, ppmdu_us) for i, e in enumerate(lst): print(i, ': ', e) HardcodedDungeons.set_tileset_properties(lst, ov10_us, ppmdu_us) assert lst == HardcodedDungeons.get_tileset_properties(ov10_us, ppmdu_us) assert lst == HardcodedDungeons.get_tileset_properties(ov10_eu, ppmdu_eu) # IMPORT HELP USING THE PMD SPREADSHEET info = """Beach Cave,Rock Slide,Rock,Cringe Beach Cave Pit,Rock Slide,Rock,Cringe Drenched Bluff,Rock Slide,Rock,Cringe Mt. Bristle,Rock Slide,Rock,Cringe Mt. Bristle Peak,Rock Slide,Rock,Cringe Waterfall Cave,Rock Slide,Rock,Cringe Apple Woods,Seed Bomb,Grass,Sleep Craggy Coast,Rock Slide,Rock,Cringe
def get_dungeon_restrictions(self) -> List[DungeonRestriction]: # TODO: Cache? return HardcodedDungeons.get_dungeon_restrictions( self.project.get_binary(BinaryName.ARM9), self.project.get_rom_module().get_static_data())
def get_dungeon_list(self) -> List[DungeonDefinition]: if self._cached_dungeon_list == None: self._cached_dungeon_list = HardcodedDungeons.get_dungeon_list( self.project.get_binary(BinaryName.ARM9), self.project.get_rom_module().get_static_data()) return self._cached_dungeon_list
# You should have received a copy of the GNU General Public License # along with SkyTemple. If not, see <https://www.gnu.org/licenses/>. import os from ndspy.rom import NintendoDSRom from skytemple_files.common.types.file_types import FileType from skytemple_files.common.util import get_ppmdu_config_for_rom, get_binary_from_rom_ppmdu from skytemple_files.hardcoded.dungeons import HardcodedDungeons base_dir = os.path.join(os.path.dirname(__file__), '..', '..', '..', '..') rom_us = NintendoDSRom.fromFile('/tmp/rando.nds') ppmdu_us = get_ppmdu_config_for_rom(rom_us) arm9_us = get_binary_from_rom_ppmdu(rom_us, ppmdu_us.binaries['arm9.bin']) dungeon_list = HardcodedDungeons.get_dungeon_list(arm9_us, ppmdu_us) for i, d in enumerate(dungeon_list): print(i, d) # 0x35 (53) is used by dungeons >= 0xB4, which are NOT on the list (dojo dungeons). print(set(range(0, 100)) - set([x.mappa_index for x in dungeon_list])) # <<< {53} # End: # Function that returns the number of floors in a dungeon: # if ID >= 0xB4 && ID <= 0xBD { # return 5 # } else if ID == 0xBE { # return 1 # } else if ID >= 0xBF { # return 0x30
def draw_dungeon_map_bgs(rom, dungeon_map_bg_dir, config): os.makedirs(dungeon_map_bg_dir, exist_ok=True) dungeon_bin = FileType.DUNGEON_BIN.deserialize(rom.getFileByName('DUNGEON/dungeon.bin'), config) ground_dungeon_tilesets = HardcodedGroundDungeonTilesets.get_ground_dungeon_tilesets( get_binary_from_rom_ppmdu(rom, config.binaries['overlay/overlay_0011.bin']), config ) dungeons = HardcodedDungeons.get_dungeon_list( get_binary_from_rom_ppmdu(rom, config.binaries['arm9.bin']), config ) mappa = FileType.MAPPA_BIN.deserialize(rom.getFileByName('BALANCE/mappa_s.bin')) levels_by_id = config.script_data.level_list__by_id bg_list_bin = rom.getFileByName('MAP_BG/bg_list.dat') bg_list = FileType.BG_LIST_DAT.deserialize(bg_list_bin) for i, entry in enumerate(ground_dungeon_tilesets): if entry.ground_level >= 0xFFFF: continue level = levels_by_id[entry.ground_level] print(f"{i + 1}/{len(ground_dungeon_tilesets)-1} - {level.name}") print(entry) mappa_idx = dungeons[entry.dungeon_id].mappa_index start_offset = dungeons[entry.dungeon_id].start_after length = dungeons[entry.dungeon_id].number_floors if entry.dungeon_id == 71: print("DEEP CONCEALED RUINS SKIPPED") continue if entry.unk2 == 1: tileset_id = mappa.floor_lists[mappa_idx][start_offset].layout.tileset_id elif entry.unk2 == 100: tileset_id = mappa.floor_lists[mappa_idx][start_offset + length - 1].layout.tileset_id else: raise ValueError("Unknown unk2") if tileset_id == 170: tileset_id = 1 dma: Dma = dungeon_bin.get(f'dungeon{tileset_id}.dma') dpl: Dpl = dungeon_bin.get(f'dungeon{tileset_id}.dpl') dpla: Dpla = dungeon_bin.get(f'dungeon{tileset_id}.dpla') dpci: Dpci = dungeon_bin.get(f'dungeon{tileset_id}.dpci') dpc: Dpc = dungeon_bin.get(f'dungeon{tileset_id}.dpc') bma: Bma = bg_list.level[level.mapid].get_bma(rom) duration = round(1000 / 60 * max(16, min(dpla.durations_per_frame_for_colors))) drawer = DmaDrawer(dma) rules = drawer.rules_from_bma(bma) mappings = drawer.get_mappings_for_rules(rules, treat_outside_as_wall=True, variation_index=0) frames = drawer.draw(mappings, dpci, dpc, dpl, dpla) frames[0].save( os.path.join(dungeon_map_bg_dir, level.name + '.gif'), save_all=True, append_images=frames[1:], duration=duration, loop=0, optimize=False ) frames[0].save( os.path.join(dungeon_map_bg_dir, level.name + '.png') )
from ndspy.rom import NintendoDSRom from skytemple_files.common.types.file_types import FileType from skytemple_files.common.util import get_ppmdu_config_for_rom, get_binary_from_rom_ppmdu from skytemple_files.dungeon_data.mappa_bin.validator.exception import DungeonTotalFloorCountInvalidError from skytemple_files.dungeon_data.mappa_bin.validator.validator import DungeonValidator from skytemple_files.hardcoded.dungeons import HardcodedDungeons rom = NintendoDSRom.fromFile('../../../../../4261 - Pokemon Mystery Dungeon Explorers of Sky (U)(Xenophobia).nds') config = get_ppmdu_config_for_rom(rom) mappa_bin = rom.getFileByName('BALANCE/mappa_s.bin') mappa = FileType.MAPPA_BIN.deserialize(mappa_bin) dungeons = HardcodedDungeons.get_dungeon_list( get_binary_from_rom_ppmdu(rom, config.binaries['arm9.bin']), config ) for i, dungeon in enumerate(dungeons): print(i, dungeon) print("") validator = DungeonValidator(mappa.floor_lists) validator.validate(dungeons) for e in validator.errors: if not isinstance(e, DungeonTotalFloorCountInvalidError): print(repr(e)) print("") print(validator.invalid_dungeons)
def update(arm9): HardcodedDungeons.set_secondary_terrains(secondary_terrains, arm9, static)
def save_dungeon_list(self, dungeons: List[DungeonDefinition]): self.project.modify_binary( BinaryName.ARM9, lambda binary: HardcodedDungeons.set_dungeon_list( dungeons, binary, self.project.get_rom_module().get_static_data())) self._cached_dungeon_list = None
def apply(self, apply: Callable[[], None], rom: NintendoDSRom, config: Pmd2Data): if not self.is_applied(rom, config): if config.game_version == GAME_VERSION_EOS: if config.game_region == GAME_REGION_US: rank_table = FLOOR_RANKS_TABLE_US item_table = ITEM_AVAILABLE_TABLE_US forbid_table = FLOOR_FORBID_TABLE_US if config.game_region == GAME_REGION_EU: rank_table = FLOOR_RANKS_TABLE_EU item_table = ITEM_AVAILABLE_TABLE_EU forbid_table = FLOOR_FORBID_TABLE_EU header = bytearray(NB_ITEMS_TABLE * 4) rank_data = bytearray(0) forbid_data = bytearray(0) current_ptr = len(header) for i in range(NB_ITEMS_TABLE): start = read_uintle(rom.arm9, rank_table + i * 4, 4) - ARM9_START end = start + 1 + FLOORS_NB[i] if end % 4 != 0: end += 4 - (end % 4) rdata = rom.arm9[start:end] fdata = bytearray(len(rdata)) x = forbid_table while rom.arm9[x] != 0x64: if rom.arm9[x] == i: fdata[rom.arm9[x + 1]] = 1 x += 2 rom.arm9 = rom.arm9[:start] + bytes( [0xCC] * (end - start)) + rom.arm9[end:] write_uintle(header, current_ptr, i * 4, 4) rank_data += bytearray(rdata) forbid_data += bytearray(fdata) current_ptr += end - start file_data = header + rank_data if FLOOR_RANKS_PATH not in rom.filenames: create_file_in_rom(rom, FLOOR_RANKS_PATH, file_data) else: rom.setFileByName(FLOOR_RANKS_PATH, file_data) file_data = header + forbid_data if FLOOR_FORBID_PATH not in rom.filenames: create_file_in_rom(rom, FLOOR_FORBID_PATH, file_data) else: rom.setFileByName(FLOOR_FORBID_PATH, file_data) dungeon_list = HardcodedDungeons.get_dungeon_list(rom.arm9, config) groups = [d.mappa_index for d in dungeon_list] print(hex(len(groups))) list_available = [] for x in range(AVAILABLE_ITEMS_NB): list_available.append(bytearray(0x100 // 8)) for i, g in enumerate(groups): off = item_table + g * (AVAILABLE_ITEMS_NB // 8) + (x // 8) if rom.arm9[off] & (1 << (x % 8)): list_available[-1][i // 8] |= 1 << (i % 8) file_data = bytearray().join(list_available) if AVAILABLE_ITEMS_PATH not in rom.filenames: create_file_in_rom(rom, AVAILABLE_ITEMS_PATH, file_data) else: rom.setFileByName(AVAILABLE_ITEMS_PATH, file_data) try: apply() except RuntimeError as ex: raise ex
def apply(self, apply: Callable[[], None], rom: NintendoDSRom, config: Pmd2Data) -> None: if config.game_version == GAME_VERSION_EOS: if config.game_region == GAME_REGION_US: new_pkmn_str_region = US_NEW_PKMN_STR_REGION new_cat_str_region = US_NEW_CAT_STR_REGION file_assoc = US_FILE_ASSOC table_sf = US_TABLE_SF table_mf = US_TABLE_MF table_sp = US_TABLE_SP if config.game_region == GAME_REGION_EU: new_pkmn_str_region = EU_NEW_PKMN_STR_REGION new_cat_str_region = EU_NEW_CAT_STR_REGION file_assoc = EU_FILE_ASSOC table_sf = EU_TABLE_SF table_mf = EU_TABLE_MF table_sp = EU_TABLE_SP if not self.is_applied(rom, config): bincfg = config.binaries['arm9.bin'] binary = bytearray(get_binary_from_rom_ppmdu(rom, bincfg)) # Apply the patch for filename in get_files_from_rom_with_extension(rom, 'str'): bin_before = rom.getFileByName(filename) strings = StrHandler.deserialize(bin_before) block = config.string_index_data.string_blocks['Pokemon Names'] monsters = strings.strings[block.begin:block.end] strings.strings[block.begin:block.end] = [""] * (block.end - block.begin) block = config.string_index_data.string_blocks[ 'Pokemon Categories'] cats = strings.strings[block.begin:block.end] strings.strings[block.begin:block.end] = [""] * (block.end - block.begin) for x in range(NUM_NEW_ENTRIES): if x < NUM_PREVIOUS_ENTRIES * 2: str_pkmn = monsters[x % NUM_PREVIOUS_ENTRIES] else: str_pkmn = "DmyPk%04d" % x if len(strings.strings) <= new_pkmn_str_region + x - 1: strings.strings.append(str_pkmn) else: strings.strings[new_pkmn_str_region + x - 1] = str_pkmn for x in range(NUM_NEW_ENTRIES): if x < NUM_PREVIOUS_ENTRIES * 2: str_cat = cats[x % NUM_PREVIOUS_ENTRIES] else: str_cat = "DmyCa%04d" % x if len(strings.strings) <= new_cat_str_region + x - 1: strings.strings.append(str_cat) else: strings.strings[new_cat_str_region + x - 1] = str_cat bin_after = StrHandler.serialize(strings) rom.setFileByName(filename, bin_after) sorted_list = list( enumerate(strings.strings[new_pkmn_str_region - 1:new_pkmn_str_region - 1 + NUM_NEW_ENTRIES])) sorted_list.sort(key=lambda x: normalize_string(x[1])) sorted_list = [x[0] for x in sorted_list] inv_sorted_list = [ sorted_list.index(i) for i in range(NUM_NEW_ENTRIES) ] m2n_model = ValListHandler.deserialize( rom.getFileByName(file_assoc[filename][0])) m2n_model.set_list(inv_sorted_list) rom.setFileByName(file_assoc[filename][0], ValListHandler.serialize(m2n_model)) n2m_model = ValListHandler.deserialize( rom.getFileByName(file_assoc[filename][1])) n2m_model.set_list(sorted_list) rom.setFileByName(file_assoc[filename][1], ValListHandler.serialize(n2m_model)) # Expand kao file kao_bin = rom.getFileByName('FONT/kaomado.kao') kao_model = KaoHandler.deserialize(kao_bin) kao_model.expand(NUM_NEW_ENTRIES - 1) for i in range(NUM_PREVIOUS_ENTRIES - 1): for j in range(SUBENTRIES): a = kao_model.get(i, j) b = kao_model.get(i + NUM_PREVIOUS_ENTRIES, j) if b == None and a != None: kao_model.set(i + NUM_PREVIOUS_ENTRIES, j, a) rom.setFileByName('FONT/kaomado.kao', KaoHandler.serialize(kao_model)) # Expand tbl_talk tlk_bin = rom.getFileByName('MESSAGE/tbl_talk.tlk') tlk_model = TblTalkHandler.deserialize(tlk_bin) while tlk_model.get_nb_monsters() < NUM_NEW_ENTRIES: tlk_model.add_monster_personality(DUMMY_PERSONALITY) rom.setFileByName('MESSAGE/tbl_talk.tlk', TblTalkHandler.serialize(tlk_model)) # Add monsters md_bin = rom.getFileByName('BALANCE/monster.md') md_model = MdHandler.deserialize(md_bin) while len(md_model.entries) < NUM_NEW_ENTRIES: md_model.entries.append( MdEntry.new_empty(u16_checked(len(md_model.entries)))) for i in range(NUM_PREVIOUS_ENTRIES): md_model.entries[i].entid = i if md_model.entries[NUM_PREVIOUS_ENTRIES + i].gender == Gender.INVALID: md_model.entries[NUM_PREVIOUS_ENTRIES + i].entid = NUM_PREVIOUS_ENTRIES + i else: md_model.entries[NUM_PREVIOUS_ENTRIES + i].entid = i block = bincfg.symbols['MonsterSpriteData'] data = binary[block.begin:block.end] + binary[block.begin:block. end] data += b'\x00\x00' * (NUM_NEW_ENTRIES - (len(data) // 2)) for i in range(0, len(data), 2): md_model.entries[i // 2].unk17 = data[i] md_model.entries[i // 2].unk18 = data[i + 1] md_model.entries[i // 2].bitfield1_0 = False md_model.entries[i // 2].bitfield1_1 = False md_model.entries[i // 2].bitfield1_2 = False md_model.entries[i // 2].bitfield1_3 = False x = table_sf while read_u16(rom.arm9, x) != 0: pkmn_id = read_u16(rom.arm9, x) md_model.entries[pkmn_id].bitfield1_3 = True # pylint: disable=invalid-sequence-index if md_model.entries[NUM_PREVIOUS_ENTRIES + pkmn_id].gender != Gender.INVALID: md_model.entries[NUM_PREVIOUS_ENTRIES + pkmn_id].bitfield1_3 = True x += 2 x = table_mf while read_u16(rom.arm9, x) != 0: pkmn_id = read_u16(rom.arm9, x) md_model.entries[pkmn_id].bitfield1_2 = True # pylint: disable=invalid-sequence-index if md_model.entries[NUM_PREVIOUS_ENTRIES + pkmn_id].gender != Gender.INVALID: md_model.entries[NUM_PREVIOUS_ENTRIES + pkmn_id].bitfield1_2 = True x += 2 ov19 = rom.loadArm9Overlays([19])[19].data for x in range(table_sp, table_sp + TABLE_SP_SIZE, 2): pkmn_id = read_u16(ov19, x) md_model.entries[pkmn_id].bitfield1_1 = True # pylint: disable=invalid-sequence-index md_model.entries[pkmn_id].bitfield1_0 = True # pylint: disable=invalid-sequence-index if md_model.entries[NUM_PREVIOUS_ENTRIES + pkmn_id].gender != Gender.INVALID: md_model.entries[NUM_PREVIOUS_ENTRIES + pkmn_id].bitfield1_1 = True md_model.entries[NUM_PREVIOUS_ENTRIES + pkmn_id].bitfield1_0 = True rom.setFileByName('BALANCE/monster.md', MdHandler.serialize(md_model)) # Edit Mappa bin mappa_bin = rom.getFileByName('BALANCE/mappa_s.bin') mappa_model = MappaBinHandler.deserialize(mappa_bin) dl = HardcodedDungeons.get_dungeon_list(bytes(rom.arm9), config) # Handle Dojos start_floor = 0 for x in range(DOJO_DUNGEONS_FIRST, DOJO_DUNGEONS_LAST - 2): dl.append( DungeonDefinition(u8(5), DOJO_MAPPA_ENTRY, u8(start_floor), u8(0))) start_floor += 5 dl.append( DungeonDefinition(u8(1), DOJO_MAPPA_ENTRY, u8(start_floor), u8(0))) start_floor += 1 dl.append( DungeonDefinition(u8(0x30), DOJO_MAPPA_ENTRY, u8(start_floor), u8(0))) start_floor += 0x30 for dungeon in dl: for f in range(dungeon.start_after + 1, dungeon.start_after + dungeon.number_floors, 2): try: for entry in mappa_model.floor_lists[ dungeon.mappa_index][f].monsters: if entry.md_index != DUMMY_PKMN and entry.md_index < NUM_PREVIOUS_ENTRIES and \ entry.md_index + NUM_PREVIOUS_ENTRIES < len(md_model.entries) and \ md_model.entries[entry.md_index + NUM_PREVIOUS_ENTRIES].gender != Gender.INVALID: entry.md_index += NUM_PREVIOUS_ENTRIES except: print(f"{dungeon.mappa_index}, {f} is not valid.") rom.setFileByName('BALANCE/mappa_s.bin', MappaBinHandler.serialize(mappa_model)) # Add moves waza_p_bin = rom.getFileByName('BALANCE/waza_p.bin') waza_p_model = WazaPHandler.deserialize(waza_p_bin) while len(waza_p_model.learnsets) < NUM_PREVIOUS_ENTRIES: waza_p_model.learnsets.append( waza_p_model.learnsets[DUMMY_LS]) # Max Moveset waza_p_model.learnsets = waza_p_model.learnsets + waza_p_model.learnsets while len(waza_p_model.learnsets) < NUM_NEW_ENTRIES: waza_p_model.learnsets.append( waza_p_model.learnsets[DUMMY_LS]) # Max Moveset rom.setFileByName('BALANCE/waza_p.bin', WazaPHandler.serialize(waza_p_model)) # Add moves 2 waza_p_bin = rom.getFileByName('BALANCE/waza_p2.bin') waza_p_model = WazaPHandler.deserialize(waza_p_bin) while len(waza_p_model.learnsets) < NUM_PREVIOUS_ENTRIES: waza_p_model.learnsets.append( waza_p_model.learnsets[DUMMY_LS]) # Max Moveset waza_p_model.learnsets = waza_p_model.learnsets + waza_p_model.learnsets while len(waza_p_model.learnsets) < NUM_NEW_ENTRIES: waza_p_model.learnsets.append( waza_p_model.learnsets[DUMMY_LS]) # Max Moveset rom.setFileByName('BALANCE/waza_p2.bin', WazaPHandler.serialize(waza_p_model)) # Add levels level_bin = rom.getFileByName('BALANCE/m_level.bin') level_model = BinPackHandler.deserialize(level_bin) while len(level_model.get_files_bytes()) < NUM_PREVIOUS_ENTRIES: new_bytes_unpacked = bytes(LEVEL_BIN_ENTRY_LEVEL_LEN * 100) new_bytes_pkdpx = PkdpxHandler.serialize( PkdpxHandler.compress(new_bytes_unpacked)) new_bytes = Sir0Handler.serialize( Sir0Handler.wrap(new_bytes_pkdpx, [])) level_model.append(new_bytes) # Empty Levelup data for i in range(NUM_PREVIOUS_ENTRIES): level_model.append(level_model[i]) while len(level_model.get_files_bytes()) < NUM_NEW_ENTRIES: new_bytes_unpacked = bytes(LEVEL_BIN_ENTRY_LEVEL_LEN * 100) new_bytes_pkdpx = PkdpxHandler.serialize( PkdpxHandler.compress(new_bytes_unpacked)) new_bytes = Sir0Handler.serialize( Sir0Handler.wrap(new_bytes_pkdpx, [])) level_model.append(new_bytes) # Empty Levelup data rom.setFileByName('BALANCE/m_level.bin', BinPackHandler.serialize(level_model)) # Add evolutions evo_bin = rom.getFileByName('BALANCE/md_evo.bin') evo_model = MdEvoHandler.deserialize(evo_bin) while len(evo_model.evo_entries) < NUM_NEW_ENTRIES: evo_model.evo_entries.append( MdEvoEntry(bytearray(MEVO_ENTRY_LENGTH))) while len(evo_model.evo_stats) < NUM_NEW_ENTRIES: evo_model.evo_stats.append( MdEvoStats(bytearray(MEVO_STATS_LENGTH))) rom.setFileByName('BALANCE/md_evo.bin', MdEvoHandler.serialize(evo_model)) # Fixed floors ov29 = config.binaries['overlay/overlay_0029.bin'] ov29bin = bytearray(get_binary_from_rom_ppmdu(rom, ov29)) monster_list = HardcodedFixedFloorTables.get_monster_spawn_list( ov29bin, config) for m in monster_list: if m.md_idx >= NUM_PREVIOUS_MD_MAX: m.md_idx += NUM_NEW_ENTRIES - NUM_PREVIOUS_MD_MAX HardcodedFixedFloorTables.set_monster_spawn_list( ov29bin, monster_list, config) set_binary_in_rom_ppmdu(rom, ov29, bytes(ov29bin)) try: apply() except RuntimeError as ex: raise ex