コード例 #1
0
 def is_applied(self, rom: NintendoDSRom, config: Pmd2Data) -> bool:
     if config.game_version == GAME_VERSION_EOS:
         if config.game_region == GAME_REGION_US:
             return read_u32(
                 rom.loadArm9Overlays([29])[29].data,
                 OFFSET_US) != ORIGINAL_INSTRUCTION
         if config.game_region == GAME_REGION_EU:
             return read_u32(
                 rom.loadArm9Overlays([29])[29].data,
                 OFFSET_EU) != ORIGINAL_INSTRUCTION
     raise NotImplementedError()
コード例 #2
0
 def is_applied(self, rom: NintendoDSRom, config: Pmd2Data) -> bool:
     if config.game_version == GAME_VERSION_EOS:
         if config.game_region == GAME_REGION_US:
             return read_u32(
                 rom.loadArm9Overlays([11])[11].data, PATCH_CHECK_ADDR_APPLIED_US
             ) != PATCH_CHECK_INSTR_APPLIED
         if config.game_region == GAME_REGION_EU:
             return read_u32(
                 rom.loadArm9Overlays([11])[11].data, PATCH_CHECK_ADDR_APPLIED_EU
             ) != PATCH_CHECK_INSTR_APPLIED
     raise NotImplementedError()
コード例 #3
0
    def apply(self, apply: Callable[[], None], rom: NintendoDSRom,
              config: Pmd2Data) -> None:
        if not self.is_applied(rom, config):
            if config.game_version == GAME_VERSION_EOS:
                if config.game_region == GAME_REGION_US:
                    bar_list = BAR_LIST_US
                if config.game_region == GAME_REGION_EU:
                    bar_list = BAR_LIST_EU
                if config.game_region == GAME_REGION_JP:
                    bar_list = BAR_LIST_JP

            data = rom.loadArm9Overlays([19])[19].data

            header = bytearray([0xFF] * (4 + 2 * NB_ITEMS))
            write_u32(header, u32(4 + 2 * NB_ITEMS), 0)
            list_data: List[bytes] = []
            for x in range(bar_list, bar_list + BAR_LIST_SIZE,
                           BAR_LIST_ENTRY_SIZE):
                item_id = read_u16(data, x)
                cdata = bytes(data[x + 2:x + BAR_LIST_ENTRY_SIZE])
                if cdata in list_data:
                    index = list_data.index(cdata)
                else:
                    index = len(list_data)
                    list_data.append(cdata)
                write_u16(header, u16_checked(index), 4 + 2 * item_id)
            file_data = header + b''.join(list_data)
            if ITEM_LIST_PATH not in rom.filenames:
                create_file_in_rom(rom, ITEM_LIST_PATH, file_data)
            else:
                rom.setFileByName(ITEM_LIST_PATH, file_data)
        try:
            apply()
        except RuntimeError as ex:
            raise ex
コード例 #4
0
    def apply(self, apply: Callable[[], None], rom: NintendoDSRom, config: Pmd2Data) -> None:
        if not self.is_applied(rom, config):
            if OBJECT_TABLE_PATH not in rom.filenames:
                if config.game_version == GAME_VERSION_EOS:
                    if config.game_region == GAME_REGION_US:
                        start_ov11 = START_OV11_US
                        start_table = START_TABLE_US
                        table_entries = TABLE_ENTRIES_US
                    if config.game_region == GAME_REGION_EU:
                        start_ov11 = START_OV11_EU
                        start_table = START_TABLE_EU
                        table_entries = TABLE_ENTRIES_EU
                    if config.game_region == GAME_REGION_JP:
                        start_ov11 = START_OV11_JP
                        start_table = START_TABLE_JP
                        table_entries = TABLE_ENTRIES_JP

                data = rom.loadArm9Overlays([11])[11].data

                table = []

                for i in range(table_entries):
                    offset = start_table - start_ov11 + i * 0xC
                    array = bytearray(0x10)
                    attr = read_u32(data, offset)
                    write_u32(array, attr, 0)
                    attr2 = read_u8(data, offset + 8)
                    write_u8(array, attr2, 4)
                    addr: int = read_u32(data, offset + 4)
                    if addr != 0:
                        addr -= start_ov11
                        count = 0
                        while data[addr + count] != 0:
                            if count >= 10:
                                raise ValueError("Invalid string length (more than 10 characters)")
                            array[5 + count] = data[addr + count]
                            count += 1
                    if sum(array) == 0:
                        print("Found blank entry, stopping at", i)
                        break
                    table.append(array)
                file_data = b''.join(table)
                create_file_in_rom(rom, OBJECT_TABLE_PATH, file_data)
        try:
            apply()
        except RuntimeError as ex:
            raise ex
コード例 #5
0
ファイル: util.py プロジェクト: chazcoffdude/skytemple-files
def get_binary_from_rom_ppmdu(rom: NintendoDSRom, binary: 'Pmd2Binary'):
    """Returns the correct binary from the rom, using the binary block specifications."""
    parts = binary.filepath.split('/')
    if parts[0] == 'arm9.bin':
        return rom.arm9 + rom.arm9PostData
    if parts[0] == 'arm7.bin':
        return rom.arm7
    if parts[0] == 'overlay':
        if len(parts) > 1:
            r = re.compile(r'overlay_(\d+).bin', re.IGNORECASE)
            match = r.match(parts[1])
            if match is not None:
                ov_id = int(match.group(1))
                overlays = rom.loadArm9Overlays([ov_id])
                if len(overlays) > 0:
                    return overlays[ov_id].data
    raise ValueError(f"Binary {binary.filepath} not found.")
コード例 #6
0
ファイル: util.py プロジェクト: chazcoffdude/skytemple-files
def set_binary_in_rom_ppmdu(rom: NintendoDSRom, binary: 'Pmd2Binary',
                            data: bytes):
    """Sets the correct binary in the rom, using the binary block specifications."""
    parts = binary.filepath.split('/')
    if parts[0] == 'arm9.bin':
        rom.arm9 = bytes(data)
        return
    if parts[0] == 'arm7.bin':
        rom.arm7 = bytes(data)
        return
    if parts[0] == 'overlay':
        if len(parts) > 1:
            r = re.compile(r'overlay_(\d+).bin', re.IGNORECASE)
            match = r.match(parts[1])
            if match is not None:
                ov_id = int(match.group(1))
                overlays = rom.loadArm9Overlays([ov_id])
                if len(overlays) > 0:
                    rom.files[overlays[ov_id].fileID] = data
                    return
    raise ValueError(f"Binary {binary.filepath} not found.")
コード例 #7
0
    def apply(self, apply: Callable[[], None], rom: NintendoDSRom,
              config: Pmd2Data) -> None:
        if not self.is_applied(rom, config):
            if config.game_version == GAME_VERSION_EOS:
                if config.game_region == GAME_REGION_US:
                    start_table = START_TABLE_US
                if config.game_region == GAME_REGION_EU:
                    start_table = START_TABLE_EU
        if ANIM_PATH not in rom.filenames:
            data = rom.loadArm9Overlays([10])[10].data

            header = bytearray(5 * 4)
            write_u32(header, u32(5 * 4), 0)
            write_u32(header, u32(5 * 4 + 52), 4)
            write_u32(header, u32(5 * 4 + 52 + 5600), 8)
            write_u32(header, u32(5 * 4 + 52 + 5600 + 13512), 12)
            write_u32(header, u32(5 * 4 + 52 + 5600 + 13512 + 19600), 16)
            file_data = bytes(header) + bytes(
                data[start_table:start_table + 0x14560])
            create_file_in_rom(rom, ANIM_PATH, file_data)
        try:
            apply()
        except RuntimeError as ex:
            raise ex
コード例 #8
0
 def is_applied(self, rom: NintendoDSRom, config: Pmd2Data) -> bool:
     return 36 in rom.loadArm9Overlays([36])
コード例 #9
0
    def apply(self, apply: Callable[[], None], rom: NintendoDSRom,
              config: Pmd2Data) -> None:
        if not self.is_applied(rom, config):
            if config.game_version == GAME_VERSION_EOS:
                if config.game_region == GAME_REGION_US:
                    start_ov29 = START_OV29_US
                    start_table = START_TABLE_US
                    start_m_functions = START_M_FUNC_US
                    end_m_functions = END_M_FUNC_US
                    data_seg = DATA_SEG_US
                if config.game_region == GAME_REGION_EU:
                    start_ov29 = START_OV29_EU
                    start_table = START_TABLE_EU
                    start_m_functions = START_M_FUNC_EU
                    end_m_functions = END_M_FUNC_EU
                    data_seg = DATA_SEG_EU

            main_func = dict()

            data = rom.loadArm9Overlays([29])[29].data

            switch = AsmFunction(
                data[start_table - start_ov29:start_m_functions - start_ov29],
                start_table)
            ext_data = switch.process()[1]
            lst_data = {}
            data_processed = set()
            for offset in ext_data:
                code = 0
                for x in range(4):
                    code += data[offset - start_ov29 + x] * (256**x)
                lst_data[offset] = code
                data_processed.add(offset)
            switch.provide_data(lst_data)
            main_calls = switch.process_switch(0, (0, 1400), {})

            unique_main_calls = set(main_calls)
            unique_main_calls.add(data_seg)
            unique_main_calls = list(sorted(unique_main_calls))
            unique_main_calls.append(end_m_functions)

            for i in range(len(unique_main_calls) - 1):
                if unique_main_calls[i] != data_seg:
                    start = unique_main_calls[i]
                    end = unique_main_calls[i + 1]
                    func_data = data[start - start_ov29:end - start_ov29]
                    main_func[start] = AsmFunction(func_data, start)
                    ext_data = main_func[start].process()[1]
                    if i >= len(unique_main_calls) - 3:
                        new_baddr = (end_m_functions - len(func_data) -
                                     start_m_functions - 0x8) // 0x4
                        if new_baddr < 0:
                            new_baddr += 2 * 0x800000
                        main_func[start].add_instructions(
                            bytes([
                                new_baddr % 256, (new_baddr // 256) % 256,
                                (new_baddr // 65536) % 256, 0xEA
                            ]))
                    lst_data = {}
                    for offset in ext_data:
                        code = 0
                        for x in range(4):
                            code += data[offset - start_ov29 + x] * (256**x)
                        lst_data[offset] = code
                        data_processed.add(offset)
                    main_func[start].provide_data(lst_data)

            nb_items = len(main_calls)
            header = bytearray(4 + 2 * nb_items + len(main_func) * 8)
            write_u32(header, u32_checked(4 + 2 * nb_items), 0)
            code_data = bytearray(0)
            current_ptr = len(header)
            id_codes = dict()
            for i, t in enumerate(main_func.items()):
                k = t[0]
                x = t[1]
                id_codes[k] = i
                fdata = bytearray(x.compile(start_m_functions))
                write_u32(header, u32_checked(current_ptr),
                          4 + 2 * nb_items + i * 8)
                write_u32(header, u32_checked(len(fdata)),
                          4 + 2 * nb_items + i * 8 + 4)
                code_data += fdata

                current_ptr += len(fdata)
            for i, x in enumerate(main_calls):
                write_u16(header, u16(id_codes[x]), 4 + 2 * i)
            file_data = header + code_data
            if ITEM_CODE_PATH not in rom.filenames:
                create_file_in_rom(rom, ITEM_CODE_PATH, file_data)
            else:
                rom.setFileByName(ITEM_CODE_PATH, file_data)
        try:
            apply()
        except RuntimeError as ex:
            raise ex
コード例 #10
0
    def apply(self, apply: Callable[[], None], rom: NintendoDSRom, config: Pmd2Data) -> None:
        if not self.is_applied(rom, config):
            if config.game_version == GAME_VERSION_EOS:
                if config.game_region == GAME_REGION_US:
                    start_ov11 = START_OV11_US
                    start_table = START_TABLE_US
                    start_m_functions = START_M_FUNC_US
                    end_m_functions = END_M_FUNC_US
                if config.game_region == GAME_REGION_EU:
                    start_ov11 = START_OV11_EU
                    start_table = START_TABLE_EU
                    start_m_functions = START_M_FUNC_EU
                    end_m_functions = END_M_FUNC_EU
        if SP_CODE_PATH not in rom.filenames:
            main_func = dict()

            data = rom.loadArm9Overlays([11])[11].data

            switch = AsmFunction(data[start_table - start_ov11:start_m_functions - start_ov11], start_table)
            switch.process()
            main_calls = switch.process_switch(5, (0, 64), {})

            unique_main_calls = list(sorted(set(main_calls)))
            unique_main_calls.append(end_m_functions)

            last_call = None
            for i in range(len(unique_main_calls) - 1):
                start = unique_main_calls[i]
                end = unique_main_calls[i + 1]
                func_data = data[start - start_ov11:end - start_ov11]
                main_func[start] = AsmFunction(func_data, start)
                main_func[start].process()
                last_call = start

            nb_proc = len(main_calls)
            header = bytearray(4 + 2 * nb_proc + len(main_func) * 8)
            write_u32(header, u32_checked(4 + 2 * nb_proc), 0)
            code_data = bytearray(0)
            current_ptr = u32_checked(len(header))
            id_codes = dict()
            print(nb_proc)
            for i, t in enumerate(main_func.items()):
                k = t[0]
                x = t[1]
                id_codes[k] = i
                fdata = bytearray(x.compile(start_m_functions))
                if k == last_call:
                    # Add a branch to the end for the last case since it doesn't have one
                    fdata += bytearray([0x1C, 0x2, 0x00, 0xEA])
                write_u32(header, current_ptr, 4 + 2 * nb_proc + i * 8)
                write_u32(header, u32_checked(len(fdata)), 4 + 2 * nb_proc + i * 8 + 4)
                code_data += fdata

                current_ptr += len(fdata)  # type: ignore
            for i, x in enumerate(main_calls):
                write_u16(header, id_codes[x], 4 + 2 * i)
            file_data = header + code_data
            create_file_in_rom(rom, SP_CODE_PATH, file_data)
        try:
            apply()
        except RuntimeError as ex:
            raise ex
コード例 #11
0
    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
コード例 #12
0
    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:
                start_ov29 = START_OV29_US
                start_table = START_TABLE_US
                start_m_functions = START_M_FUNC_US
                end_m_functions = END_M_FUNC_US
                start_metronome_data = START_METRONOME_DATA_US
            if config.game_region == GAME_REGION_EU:
                start_ov29 = START_OV29_EU
                start_table = START_TABLE_EU
                start_m_functions = START_M_FUNC_EU
                end_m_functions = END_M_FUNC_EU
                start_metronome_data = START_METRONOME_DATA_EU

        if MOVE_CODE_PATH not in rom.filenames:
            main_func = dict()

            data = rom.loadArm9Overlays([29])[29].data

            switch = AsmFunction(
                data[start_table - start_ov29:start_m_functions - start_ov29],
                start_table)
            switch.process()
            main_calls = switch.process_switch(6, (0, 559), {0: 542})

            unique_main_calls = list(sorted(set(main_calls)))
            unique_main_calls.append(end_m_functions)

            last_call = None
            for i in range(len(unique_main_calls) - 1):
                start = unique_main_calls[i]
                end = unique_main_calls[i + 1]
                func_data = data[start - start_ov29:end - start_ov29]
                main_func[start] = AsmFunction(func_data, start)
                main_func[start].process()
                last_call = start

            nb_moves = len(main_calls)
            header = bytearray(4 + 2 * nb_moves + len(main_func) * 8)
            write_u32(header, u32_checked(4 + 2 * nb_moves), 0)
            code_data = bytearray(0)
            current_ptr = len(header)
            id_codes = dict()
            for i, t in enumerate(main_func.items()):
                k = t[0]
                x = t[1]
                id_codes[k] = i
                fdata = bytearray(x.compile(start_m_functions))
                if k == last_call:
                    # Add a branch to the end for the last case since it doesn't have one
                    fdata += bytearray([0x63, 0x09, 0x00, 0xEA])
                write_u32(header, u32_checked(current_ptr),
                          4 + 2 * nb_moves + i * 8)
                write_u32(header, u32_checked(len(fdata)),
                          4 + 2 * nb_moves + i * 8 + 4)
                code_data += fdata

                current_ptr += len(fdata)
            for i, x in enumerate(main_calls):
                write_u16(header, id_codes[x], 4 + 2 * i)
            file_data = header + code_data
            create_file_in_rom(rom, MOVE_CODE_PATH, file_data)

        if METRONOME_DATA_PATH not in rom.filenames:
            # Metronome
            data = rom.loadArm9Overlays([10])[10].data
            file_data = bytearray(METRONOME_DATA_LENGTH // 2)
            for x in range(start_metronome_data,
                           start_metronome_data + METRONOME_DATA_LENGTH, 8):
                write_u32(file_data, read_u32(data, x),
                          (x - start_metronome_data) // 2)
            create_file_in_rom(rom, METRONOME_DATA_PATH, file_data)
        try:
            apply()
        except RuntimeError as ex:
            raise ex