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:
                string_id = STRING_ID_US
                overlay_size = OVERLAY13_INITAL_SIZE_US
            if config.game_region == GAME_REGION_EU:
                string_id = STRING_ID_EU
                overlay_size = OVERLAY13_INITAL_SIZE_EU
            if config.game_region == GAME_REGION_JP:
                string_id = STRING_ID_JP
                overlay_size = OVERLAY13_INITAL_SIZE_JP

        # Change dialogue
        for lang in config.string_index_data.languages:
            filename = 'MESSAGE/' + lang.filename
            bin_before = rom.getFileByName(filename)
            strings = StrHandler.deserialize(bin_before)
            strings.strings[string_id - 1] = get_locales().translate(
                MESSAGE, lang.locale.replace('-', '_'))
            bin_after = StrHandler.serialize(strings)
            rom.setFileByName(filename, bin_after)

        table = loadOverlayTable(rom.arm9OverlayTable, lambda x, y: bytes())
        ov = table[13]
        ov.ramSize = overlay_size + OVERLAY13_ADD_SIZE
        rom.arm9OverlayTable = saveOverlayTable(table)
        ov13 = rom.files[ov.fileID]
        rom.files[ov.fileID] = ov13[:overlay_size]
        try:
            apply()
        except RuntimeError as ex:
            raise ex
    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
    def apply(self, apply: Callable[[], None], rom: NintendoDSRom, config: Pmd2Data):
        if not self.is_applied(rom, config):
            path_len = len(LIST_PATH%0)+1
            if path_len%4!=0:
                path_len += 4-(path_len%4)
            if config.game_version == GAME_VERSION_EOS:
                if config.game_region == GAME_REGION_US:
                    table = ITEM_LISTS_TABLE_US
                if config.game_region == GAME_REGION_EU:
                    table = ITEM_LISTS_TABLE_EU

            ranges = []
            for i in range(ITEM_LISTS_NB):
                start = read_uintle(rom.arm9, table+i*4, 4)-ARM9_START
                end = start
                size = 0
                while size<ITEM_LISTS_SIZE:
                    val = read_uintle(rom.arm9, end, 2)
                    if val>=30000:
                        size += (val-30000)*2
                    else:
                        size += 2
                    end += 2
                data = rom.arm9[start:end]
                if end%4!=0:
                    end += 4-(end%4)
                path = LIST_PATH%i
                if path not in rom.filenames:
                    create_file_in_rom(rom, path, data)
                else:
                    rom.setFileByName(path, data)
                rom.arm9 = rom.arm9[:start]+bytes([0xCC]*(end-start))+rom.arm9[end:]
                ranges.append([start, end])
            ranges.sort()
            i = 0
            while i<len(ranges)-1:
                if ranges[i][1]==ranges[i+1][0]:
                    ranges[i][1] = ranges[i+1][1]
                    del ranges[i+1]
                    i-=1
                i+=1
            buffer = bytearray(4*ITEM_LISTS_NB)
            for i in range(ITEM_LISTS_NB):
                path = LIST_PATH%i
                while ranges[0][1]-ranges[0][0]<path_len:
                    del ranges[0]
                    if len(ranges)==0:
                        raise RuntimeError("Don't have enough space to put filenames! ")
                
                rom.arm9 = rom.arm9[:ranges[0][0]]+path.encode(encoding="ascii")+bytes(path_len-len(path))+rom.arm9[ranges[0][0]+path_len:]
                write_uintle(buffer, ARM9_START+ranges[0][0], i*4, 4)
                ranges[0][0] += path_len
            rom.arm9 = rom.arm9[:table]+buffer+rom.arm9[table+len(buffer):]
        try:
            apply()
        except RuntimeError as ex:
            raise ex
 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()
Beispiel #5
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()
Beispiel #6
0
def draw_object(img: Image.Image, draw, obj: SsaObject, rom: NintendoDSRom):
    """Draws the sprite for an object"""
    if obj.object.name == 'NULL':
        if draw_invisible_actors_objects:
            # Draw invisible object hitboxes
            w = obj.hitbox_w * BPC_TILE_DIM
            h = obj.hitbox_h * BPC_TILE_DIM
            tlx = obj.pos.x_absolute - int(w / 2)
            tly = obj.pos.y_absolute - int(h / 2)
            draw.rectangle((
                tlx, tly, tlx + w, tly + h,
            ), COLOR_OBJECTS, (0, 0, 0))
        return

    try:
        sprite = FileType.WAN.deserialize(
            rom.getFileByName(f'GROUND/{obj.object.name}.wan')
        )
        ani_group = sprite.get_animations_for_group(sprite.anim_groups[0])
    except (ValueError, TypeError) as e:
        warnings.warn(f"Failed to render a sprite, replaced with placeholder ({obj}): {e}")
        if not draw_invisible_actors_objects:
            return
        return triangle(draw, obj.pos.x_absolute, obj.pos.y_absolute, COLOR_OBJECTS, obj.pos.direction.id)

    frame_id = obj.pos.direction.id - 1 if obj.pos.direction.id > 0 else 0
    if frame_id > len(ani_group) - 1:
        frame_id = 0
    mfg_id = ani_group[frame_id].frames[0].frame_id

    sprite_img, (cx, cy) = sprite.render_frame_group(sprite.frame_groups[mfg_id])
    render_x = obj.pos.x_absolute - cx
    render_y = obj.pos.y_absolute - cy
    img.paste(sprite_img, (render_x, render_y), sprite_img)
Beispiel #7
0
def draw_maps_main():
    global monster_bin_pack_file, monster_md
    os.makedirs(output_dir, exist_ok=True)

    rom = NintendoDSRom.fromFile(os.path.join(base_dir,
                                              'skyworkcopy_edit.nds'))
    monster_bin_pack_file = FileType.BIN_PACK.deserialize(
        rom.getFileByName('MONSTER/monster.bin'))
    monster_md = FileType.MD.deserialize(
        rom.getFileByName('BALANCE/monster.md'))

    script_info = load_script_files(get_rom_folder(rom, SCRIPT_DIR))

    map_bg_entry_level_list = FileType.BG_LIST_DAT.deserialize(
        rom.getFileByName('MAP_BG/bg_list.dat')).level

    for script_map in script_info['maps'].values():
        # Map BGs are NOT *actually* mapped 1:1 to scripts. They are loaded via Opcode. However it turns out, using the BPL name
        # is an easy way to map them.
        map_bg_entry = next(x for x in map_bg_entry_level_list
                            if x.bpl_name == script_map['name'])
        if script_map['enter_sse'] is not None:
            process(
                rom, map_bg_entry, script_map['name'], SCRIPT_DIR + '/' +
                script_map['name'] + '/' + script_map['enter_sse'])
        for ssa, _ in script_map['ssas']:
            process(rom, map_bg_entry, script_map['name'],
                    SCRIPT_DIR + '/' + script_map['name'] + '/' + ssa)
        for sss in script_map['subscripts'].keys():
            process(rom, map_bg_entry, script_map['name'],
                    SCRIPT_DIR + '/' + script_map['name'] + '/' + sss)
Beispiel #8
0
def draw_object(img: Image.Image, draw, obj: SsaObject, rom: NintendoDSRom):
    """Draws the sprite for an object"""

    if obj.object.name == 'NULL':
        return triangle(draw, obj.pos.x_absolute, obj.pos.y_absolute,
                        COLOR_ACTOR, obj.pos.direction.id)

    try:
        sprite = FileType.WAN.deserialize(
            rom.getFileByName(f'GROUND/{obj.object.name}.wan'))
    except ValueError as e:
        warnings.warn(
            f"Failed to render a sprite, replaced with placeholder ({obj}): {e}"
        )
        return triangle(draw, obj.pos.x_absolute, obj.pos.y_absolute,
                        COLOR_ACTOR, obj.pos.direction.id)

    ani_group = sprite.get_animations_for_group(sprite.anim_groups[0])
    frame_id = obj.pos.direction.id - 1 if obj.pos.direction.id > 0 else 0
    if frame_id > len(ani_group) - 1:
        frame_id = 0
    mfg_id = ani_group[frame_id].frames[0].frame_id

    sprite_img, (cx,
                 cy) = sprite.render_frame_group(sprite.frame_groups[mfg_id])
    render_x = obj.pos.x_absolute - cx
    render_y = obj.pos.y_absolute - cy
    img.paste(sprite_img, (render_x, render_y), sprite_img)
def main():
    output_dir = os.path.join(os.path.dirname(__file__), 'dbg_output')
    base_dir = os.path.join(os.path.dirname(__file__), '..', '..', '..', '..',
                            '..')
    os.makedirs(output_dir, exist_ok=True)

    rom = NintendoDSRom.fromFile(os.path.join(base_dir, 'skyworkcopy.nds'))

    file_name = 'SCRIPT/COMMON/unionall.ssb'

    # Files that don't work right now:
    print(file_name)

    bin_before = rom.getFileByName(file_name)
    ssb = SsbHandler.deserialize(bin_before)

    target_point = 0x11BF

    for i, ops in enumerate(ssb.routine_ops):
        print(f">>> Routine {i}:")
        for op in ops:
            offset = target_point - op.offset
            offset_two = target_point - int.from_bytes(op.offset.to_bytes(
                2, byteorder='little', signed=False),
                                                       byteorder='little',
                                                       signed=True)
            for param in op.params:
                if param == offset or param == offset_two:
                    print(
                        f"{op.offset:10x}: ({op.op_code.id:3}) {op.op_code.name:45} - {', '.join(hex(x) for x in op.params)}"
                    )
Beispiel #10
0
    def main_test():
        import os
        from skytemple_files.common.types.file_types import FileType
        from ndspy.rom import NintendoDSRom
        from skytemple_files.common.util import get_ppmdu_config_for_rom
        # Testing.
        base_dir = os.path.join(os.path.dirname(__file__), '..', '..', '..', '..')
        rom = NintendoDSRom.fromFile(os.path.join(base_dir, 'skyworkcopy_us.nds'))
        config = get_ppmdu_config_for_rom(rom)
        out_dir = '/tmp/monster_graphs'
        os.makedirs(out_dir, exist_ok=True)
        monster_md = FileType.MD.deserialize(rom.getFileByName('BALANCE/monster.md'))
        level_bin = FileType.BIN_PACK.deserialize(rom.getFileByName('BALANCE/m_level.bin'))
        waza_p = FileType.WAZA_P.deserialize(rom.getFileByName('BALANCE/waza_p.bin'))
        move_string_block = config.string_index_data.string_blocks['Move Names']
        monster_name_block = config.string_index_data.string_blocks['Pokemon Names']
        strings = FileType.STR.deserialize(rom.getFileByName('MESSAGE/text_e.str'))
        move_strings = strings.strings[move_string_block.begin:move_string_block.end]
        monster_strings = strings.strings[monster_name_block.begin:monster_name_block.end]

        level_bin = level_bin

        # The level_bin has no entry for monster 0.
        for monster, lbinentry_bin, waza_entry in zip(monster_md.entries[1:], level_bin, waza_p.learnsets[1:]):
            level_bin_entry = FileType.LEVEL_BIN_ENTRY.deserialize(
                FileType.COMMON_AT.deserialize(FileType.SIR0.deserialize(lbinentry_bin).content).decompress()
            )
            graph_provider = LevelUpGraphProvider(monster, level_bin_entry, waza_entry, move_strings)
            g = graph_provider.provide(
                f'{monster_strings[monster.md_index]}',
                dark=True
            )
            g.render_to_file(os.path.join(out_dir, f'{monster.md_index}.svg'))
            g.render_to_png(os.path.join(out_dir, f'{monster.md_index}.png'), dpi=92)
def main():
    rom_path = sys.argv[1]
    rom = NintendoDSRom.fromFile(rom_path)
    config = get_ppmdu_config_for_rom(rom)
    arm9 = rom.arm9
    original_arm9 = arm9[0:len(arm9)]

    extra_dungeon_data = ExtraDungeonDataList.read(arm9, config)
    guest_pokemon_data = GuestPokemonList.read(arm9, config)

    ExtraDungeonDataList.write(extra_dungeon_data, arm9, config)
    GuestPokemonList.write(guest_pokemon_data, arm9, config)

    extra_dungeon_data2 = ExtraDungeonDataList.read(arm9, config)
    guest_pokemon_data2 = GuestPokemonList.read(arm9, config)

    assert extra_dungeon_data == extra_dungeon_data2
    assert guest_pokemon_data == guest_pokemon_data2

    guest_pokemon_data.append(
        GuestPokemon(0, 64, 0, [1, 2, 3, 4], 901, 50, 255, 100, 102, 77, 88, 0,
                     0))
    GuestPokemonList.write(guest_pokemon_data, arm9, config)
    guest_pokemon_data2 = GuestPokemonList.read(arm9, config)
    assert guest_pokemon_data == guest_pokemon_data2

    guest_pokemon_data2.pop(-1)
    GuestPokemonList.write(guest_pokemon_data2, arm9, config)
    assert original_arm9 == arm9
Beispiel #12
0
def run_main(rom_path, export_dir, actor_mapping_path=None, opt_draw_invisible_actors_objects=True):
    global monster_bin_pack_file, monster_md, draw_invisible_actors_objects, ground_dungeon_tilesets
    draw_invisible_actors_objects = opt_draw_invisible_actors_objects

    print("Loading ROM and core files...")
    os.makedirs(export_dir, exist_ok=True)
    rom = NintendoDSRom.fromFile(rom_path)
    config = get_ppmdu_config_for_rom(rom)

    scriptdata = config.script_data
    if actor_mapping_path:
        with open(actor_mapping_path, 'r') as f:
            actor_mapping = json.load(f)
            for name, entid in actor_mapping.items():
                scriptdata.level_entities__by_name[name].entid = entid

    monster_bin_pack_file = FileType.BIN_PACK.deserialize(rom.getFileByName('MONSTER/monster.bin'))
    monster_md = FileType.MD.deserialize(rom.getFileByName('BALANCE/monster.md'))

    map_bg_dir = os.path.join(export_dir, 'MAP_BG')
    dungeon_map_bg_dir = os.path.join(export_dir, 'MAP_BG_DUNGEON_TILESET')
    print("-- DRAWING BACKGROUNDS --")
    draw_map_bgs(rom, map_bg_dir)
    print("-- DRAWING REST ROOM AND BOSS ROOM BACKGROUNDS --")
    draw_dungeon_map_bgs(rom, dungeon_map_bg_dir, config)
    print("-- DRAWING MAP ENTITIES --")
    draw_maps(rom, os.path.join(export_dir, 'MAP'), scriptdata)
Beispiel #13
0
    def _outer_wrapper(wrapped_function):
        import inspect
        import pytest
        from ndspy.rom import NintendoDSRom
        from unittest import SkipTest
        from parameterized import parameterized
        rom = None
        if 'SKYTEMPLE_TEST_ROM' in os.environ and os.environ[
                'SKYTEMPLE_TEST_ROM'] != '':
            rom = NintendoDSRom.fromFile(os.environ['SKYTEMPLE_TEST_ROM'])

        if rom:

            def dataset_name_func(testcase_func, _, param):
                return f'{testcase_func.__name__}/{param.args[0]}'

            files = [(x, rom.getFileByName(x))
                     for x in get_files_from_rom_with_extension(rom, file_ext)
                     if x.startswith(path)]

            if len(files) < 1:

                def no_files(*args, **kwargs):
                    raise SkipTest("No matching files were found in the ROM.")

                return pytest.mark.romtest(no_files)
            else:
                spec = inspect.getfullargspec(wrapped_function)
                if "pmd2_data" in spec.args or "pmd2_data" in spec.kwonlyargs:
                    pmd2_data = get_ppmdu_config_for_rom(rom)

                    def pmd2datawrapper(*args, **kwargs):
                        return wrapped_function(*args,
                                                **kwargs,
                                                pmd2_data=pmd2_data)

                    pmd2datawrapper.__name__ = wrapped_function.__name__

                    parameterized.expand(files, name_func=dataset_name_func)(
                        pytest.mark.romtest(pmd2datawrapper))
                else:
                    parameterized.expand(files, name_func=dataset_name_func)(
                        pytest.mark.romtest(wrapped_function))
                # since expands now adds the tests to our locals, we need to pass them back...
                # this isn't hacky at all wdym??????ßßß
                frame_locals = inspect.currentframe(
                ).f_back.f_locals  # type: ignore
                for local_name, local in inspect.currentframe().f_locals.items(
                ):  # type: ignore
                    if local_name.startswith('test_'):
                        frame_locals[local_name] = local

        else:

            def no_tests(*args, **kwargs):
                raise SkipTest("No ROM file provided or ROM not found.")

            return pytest.mark.romtest(no_tests)
async def main(executor):
    output_dir = os.path.join(os.path.dirname(__file__), 'dbg_output')
    base_dir = os.path.join(os.path.dirname(__file__), '..', '..', '..', '..',
                            '..')
    os.makedirs(output_dir, exist_ok=True)

    rom = NintendoDSRom.fromFile(
        os.path.join(base_dir, 'skyworkcopy_us_unpatched.nds'))

    script_info = load_script_files(get_rom_folder(rom, SCRIPT_DIR))

    # total, opening. decompiling, parsing, compiling, serializing
    times: List[Tuple[float, float, float, float, float, float]] = []

    static_data = Pmd2XmlReader.load_default(for_version='EoS_NA')
    awaitables = []
    for i, file_name in enumerate(get_files_from_rom_with_extension(
            rom, 'ssb')):
        # TODO: Those scripts fail for JP.
        if file_name in [
                'SCRIPT/D42P21A/enter23.ssb', 'SCRIPT/D73P11A/us0303.ssb',
                'SCRIPT/D73P11A/us0305.ssb', 'SCRIPT/D73P11A/us2003.ssb',
                'SCRIPT/D73P11A/us2005.ssb', 'SCRIPT/D73P11A/us2103.ssb',
                'SCRIPT/D73P11A/us2105.ssb', 'SCRIPT/D73P11A/us2203.ssb',
                'SCRIPT/D73P11A/us2205.ssb', 'SCRIPT/D73P11A/us2303.ssb',
                'SCRIPT/D73P11A/us2305.ssb'
        ]:
            continue
        # Run multiple in parallel with asyncio executors.
        awaitables.append(
            loop.run_in_executor(executor, process_single, file_name, times,
                                 static_data, output_dir, rom))

    pending = awaitables
    while len(pending) > 0:
        done, pending = await asyncio.wait(pending,
                                           return_when=asyncio.FIRST_COMPLETED)
        # to raise exceptions of tasks back to main loop:
        for fut in done:
            try:
                fut.result()
            except Exception:
                loop.stop()
                with poison_lock:
                    poison_container[0] = True
                raise

    times_structured = list(zip(*times))

    print_table_row("", "TOTAL", "OPENING", "DECOMPILING", "PARSING",
                    "COMPILING", "SERIALIZING")
    print_table_row(*(["==========="] * 7))
    print_table_row("TOTAL:", *[round(sum(t), 2) for t in times_structured])
    print_table_row("AVG:",
                    *[round(sum(t) / len(t), 2) for t in times_structured])
    print_table_row("MAX:", *[round(max(t), 2) for t in times_structured])
    print_table_row("MIN:", *[round(min(t), 2) for t in times_structured])
Beispiel #15
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:
                type_table = TYPE_TABLE_US
                gummi_iq_table = GUMMI_IQ_TABLE_US
                gummi_belly_table = GUMMI_BELLY_TABLE_US
            if config.game_region == GAME_REGION_EU:
                type_table = TYPE_TABLE_EU
                gummi_iq_table = GUMMI_IQ_TABLE_EU
                gummi_belly_table = GUMMI_BELLY_TABLE_EU
            if config.game_region == GAME_REGION_JP:
                type_table = TYPE_TABLE_JP
                gummi_iq_table = GUMMI_IQ_TABLE_JP
                gummi_belly_table = GUMMI_BELLY_TABLE_JP

        bincfg = config.binaries['overlay/overlay_0010.bin']
        data = bytearray(get_binary_from_rom_ppmdu(rom, bincfg))
        data[type_table:type_table + TABLE_LEN] = bytearray(NEW_TYPES)
        set_binary_in_rom_ppmdu(rom, bincfg, bytes(data))

        # Change Fairy's type name
        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['Type Names']
            strings.strings[block.begin + 18] = TYPE_LIST[filename]
            bin_after = StrHandler.serialize(strings)
            rom.setFileByName(filename, bin_after)

        bincfg = config.binaries['arm9.bin']
        data = bytearray(get_binary_from_rom_ppmdu(rom, bincfg))
        data[gummi_iq_table:gummi_iq_table +
             TABLE_LEN] = bytearray(NEW_IQ_GUMMI)
        data[gummi_belly_table:gummi_belly_table +
             TABLE_LEN] = bytearray(NEW_BELLY_GUMMI)
        set_binary_in_rom_ppmdu(rom, bincfg, bytes(data))

        try:
            apply()
        except RuntimeError as ex:
            raise ex
def main(rom_file, directory):
    rom = NintendoDSRom.fromFile(rom_file)

    for file_name in get_files_from_rom_with_extension(rom, 'ssb'):
        if os.path.exists(os.path.join(directory, file_name)):
            print(file_name)

            with open(os.path.join(directory, file_name), 'rb') as f:
                rom.setFileByName(file_name, f.read())

    rom.saveToFile(rom_file)
Beispiel #17
0
def draw_map_bgs(rom: NintendoDSRom, map_bg_dir):
    global map_bgs, map_bg_durations
    os.makedirs(map_bg_dir, exist_ok=True)

    bin = rom.getFileByName('MAP_BG/bg_list.dat')
    bg_list = FileType.BG_LIST_DAT.deserialize(bin)

    count = len(bg_list.level)
    for i, l in enumerate(bg_list.level):
        try:
            bma = l.get_bma(rom)
            print(f"{i + 1}/{count} - {l.bpl_name}")

            bpas = l.get_bpas(rom)
            non_none_bpas = [b for b in bpas if b is not None]
            bpc = l.get_bpc(rom)
            bpl = l.get_bpl(rom)

            # Saving animated map!
            bpa_duration = -1
            pal_ani_duration = -1
            if len(non_none_bpas) > 0:
                bpa_duration = round(
                    1000 / 60 *
                    non_none_bpas[0].frame_info[0].duration_per_frame)
            if bpl.has_palette_animation:
                pal_ani_duration = round(1000 / 60 *
                                         max(spec.duration_per_frame
                                             for spec in bpl.animation_specs))
            duration = max(bpa_duration, pal_ani_duration)
            if duration == -1:
                # Default for only one frame, doesn't really matter
                duration = 1000
            frames = bma.to_pil(bpc,
                                bpl,
                                bpas,
                                include_collision=False,
                                include_unknown_data_block=False)
            frames[0].save(os.path.join(map_bg_dir, l.bpl_name + '.gif'),
                           save_all=True,
                           append_images=frames[1:],
                           duration=duration,
                           loop=0,
                           optimize=False)
            frames[0].save(os.path.join(map_bg_dir, l.bpl_name + '.png'))
            map_bgs[l.bpl_name] = frames
            map_bg_durations[l.bpl_name] = duration
        except (NotImplementedError, SystemError) as ex:
            print(f"error for {l.bma_name}: {repr(ex)}", file=sys.stderr)
            print(''.join(
                traceback.format_exception(etype=type(ex),
                                           value=ex,
                                           tb=ex.__traceback__)),
                  file=sys.stderr)
Beispiel #18
0
    def load(self):
        """Load the ROM into memory and initialize all modules"""
        self._rom = NintendoDSRom.fromFile(self.filename)
        self._loaded_modules = {}
        for name, module in Modules.all().items():
            if name == 'rom':
                self._rom_module = module(self)
            else:
                self._loaded_modules[name] = module(self)

        self._sprite_renderer = SpriteProvider(self)
        self._string_provider = StringProvider(self)
Beispiel #19
0
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.")
Beispiel #20
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:
                string_id = STRING_ID_US
            if config.game_region == GAME_REGION_EU:
                string_id = STRING_ID_EU
            if config.game_region == GAME_REGION_JP:
                string_id = STRING_ID_JP

        # Change dialogue
        for lang in config.string_index_data.languages:
            filename = 'MESSAGE/' + lang.filename
            bin_before = rom.getFileByName(filename)
            strings = StrHandler.deserialize(bin_before)
            strings.strings[string_id - 1] = get_locales().translate(MESSAGE, lang.locale.replace('-', '_'))
            bin_after = StrHandler.serialize(strings)
            rom.setFileByName(filename, bin_after)
        try:
            apply()
        except RuntimeError as ex:
            raise ex
Beispiel #21
0
def main():
    output_dir = os.path.join(os.path.dirname(__file__), 'dbg_output',
                              'graphs')
    base_dir = os.path.join(os.path.dirname(__file__), '..', '..', '..', '..',
                            '..')

    rom = NintendoDSRom.fromFile(os.path.join(base_dir, 'skyworkcopy.nds'))

    total_count_labels_before = 0
    total_count_labels_after = 0

    for file_name in get_files_from_rom_with_extension(rom, 'ssb'):
        print(file_name)

        bin_before = rom.getFileByName(file_name)
        ssb = SsbHandler.deserialize(bin_before)

        routine_ops = ssb.get_filled_routine_ops()

        resolver = OpsLabelJumpToResolver(routine_ops)
        routine_ops = list(resolver)

        grapher = SsbGraphMinimizer(routine_ops)
        total_count_labels_before += grapher.count_labels()
        draw_graphs(grapher, file_name, output_dir, 'before_optimize')

        grapher.optimize_paths()
        draw_graphs(grapher, file_name, output_dir, 'after_optimize')

        #grapher._graphs = [ grapher._graphs[86] ]
        grapher.build_branches()
        draw_graphs(grapher, file_name, output_dir,
                    'after_branch_before_group')
        grapher.group_branches()
        grapher.invert_branches()
        draw_graphs(grapher, file_name, output_dir, 'after_branch')

        grapher.build_and_group_switch_cases()
        grapher.group_switch_cases()
        grapher.build_switch_fallthroughs()
        draw_graphs(grapher, file_name, output_dir, 'after_switch')

        grapher.build_loops()
        draw_graphs(grapher, file_name, output_dir, 'after_loops')

        grapher.remove_label_markers()
        draw_graphs(grapher, file_name, output_dir, 'done')

        total_count_labels_after += grapher.count_labels()

    print("Total number labels before: " + str(total_count_labels_before))
    print("Total number labels after:  " + str(total_count_labels_after))
Beispiel #22
0
    def load(self):
        """Load the ROM into memory and initialize all modules"""
        self._rom = NintendoDSRom.fromFile(self.filename)
        self._loaded_modules = {}
        for name, module in Modules.all().items():
            logger.debug(f"Loading module {name} for ROM...")
            if name == 'rom':
                self._rom_module = module(self)
            else:
                self._loaded_modules[name] = module(self)

        self._sprite_renderer = SpriteProvider(self)
        self._string_provider = StringProvider(self)
        self._icon_banner = IconBanner(self._rom)
def create_mapping():
    from ndspy.rom import NintendoDSRom
    rom = NintendoDSRom.fromFile(
        '/home/marco/dev/skytemple/skytemple/skyworkcopy_us_unpatched.nds')
    from skytemple_files.common.util import get_ppmdu_config_for_rom
    static_data = get_ppmdu_config_for_rom(rom)
    from skytemple_files.patch.patches import Patcher
    patcher = Patcher(rom, static_data)
    patcher.apply('ActorAndLevelLoader')

    from skytemple_files.common.types.file_types import FileType
    from skytemple_files.data.md.model import Md
    md: Md = FileType.MD.deserialize(rom.getFileByName('BALANCE/monster.md'))
    from skytemple_files.list.actor.model import ActorListBin
    actor_list: ActorListBin = FileType.SIR0.unwrap_obj(
        FileType.SIR0.deserialize(rom.getFileByName('BALANCE/actor_list.bin')),
        ActorListBin)
    from skytemple_files.hardcoded.fixed_floor import HardcodedFixedFloorTables
    from skytemple_files.common.util import get_binary_from_rom_ppmdu
    boss_list = HardcodedFixedFloorTables.get_monster_spawn_list(
        get_binary_from_rom_ppmdu(
            rom, static_data.binaries['overlay/overlay_0029.bin']),
        static_data)

    actor_list_pokedex_number_mapping = []
    for e in actor_list.list:
        monster = md.entries[e.entid]
        actor_list_pokedex_number_mapping.append(
            monster.national_pokedex_number)

    boss_list_pokedex_number_mapping = []
    for boss in boss_list:
        try:
            monster = md.entries[boss.md_idx]
            boss_list_pokedex_number_mapping.append(
                monster.national_pokedex_number)
        except IndexError:
            boss_list_pokedex_number_mapping.append(0)

    mapping = {}
    for idx, a in enumerate(actor_list_pokedex_number_mapping):
        if a == 0:
            continue
        indices = [
            i for i, x in enumerate(boss_list_pokedex_number_mapping) if x == a
        ]
        if len(indices) > 0:
            mapping[idx] = indices

    print(mapping)
def main():
    os.makedirs(output_dir, exist_ok=True)

    rom = NintendoDSRom.fromFile(os.path.join(base_dir, 'skyworkcopy.nds'))

    script_info = load_script_files(get_rom_folder(rom, SCRIPT_DIR))

    for script_map in script_info['maps'].values():
        if script_map['enter_sse'] is not None:
            process(rom, SCRIPT_DIR + '/' + script_map['name'] + '/', script_map['enter_sse'], script_map['enter_ssbs'])
        for ssa, ssb in script_map['ssas']:
            process(rom, SCRIPT_DIR + '/' + script_map['name'] + '/', ssa, [ssb])
        for sss, ssb in script_map['subscripts'].items():
            process(rom, SCRIPT_DIR + '/' + script_map['name'] + '/', sss, ssb)
def main():
    rom_path = sys.argv[1]
    rom = NintendoDSRom.fromFile(rom_path)
    config = get_ppmdu_config_for_rom(rom)
    block_compressed = config.binaries['arm9.bin'].symbols['CompressedIqGroupsSkills']
    arm9 = rom.arm9

    groups = IqGroupsSkills.read_uncompressed(arm9, config)
    IqGroupsSkills.write_compressed(arm9, groups, config)

    assert arm9[block_compressed.begin:block_compressed.end] == COMPRESSED_GROUPS

    groups2 = IqGroupsSkills.read_compressed(arm9, config)
    for i in range(len(groups)):
        assert sorted(groups[i]) == sorted(groups2[i])
Beispiel #26
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
Beispiel #27
0
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.")
Beispiel #28
0
    def apply(self, apply: Callable[[], None], rom: NintendoDSRom, config: Pmd2Data) -> None:
        START_ACCURACY = self.get_parameter("StartGraphicPos")
        START_POWER = START_ACCURACY + 12
        MAX_POWER = f"[M:B{START_POWER}]" + (f"[M:B{START_POWER + 10}]") * 9 + f"[M:B{START_POWER + 9}]"
        MAX_ACCU = f"[M:B{START_POWER}]" + (f"[M:B{START_ACCURACY + 11}]") * 10 + f"[M:B{START_POWER}]"
        DESC_CHANGES = {8: MAX_POWER,
                        60: MAX_POWER,
                        75: MAX_POWER,
                        100: MAX_POWER,
                        153: MAX_POWER,
                        156: MAX_POWER,
                        205: MAX_POWER,
                        206: MAX_POWER,
                        348: MAX_POWER,
                        477: MAX_POWER,
                        61: MAX_ACCU,
                        340: MAX_ACCU,
                        535: MAX_ACCU}
        bin_before = rom.getFileByName("FONT/markfont.dat")
        model = GraphicFontHandler.deserialize(bin_before)
        entries = []
        for x in range(model.get_nb_entries()):
            entries.append(model.get_entry(x))
        while len(entries) < max(START_ACCURACY + 12, START_POWER + 11):
            entries.append(None)

        for x in range(START_ACCURACY, START_ACCURACY + 12):
            img = Image.open(os.path.join(SRC_DIR, "accu_%02d.png" % (x - START_ACCURACY)), 'r')
            entries[x] = img
        for x in range(START_POWER, START_POWER + 11):
            img = Image.open(os.path.join(SRC_DIR, "pow_%02d.png" % (x - START_POWER)), 'r')
            entries[x] = img
        model.set_entries(entries)
        bin_after = GraphicFontHandler.serialize(model)
        rom.setFileByName("FONT/markfont.dat", bin_after)

        # Change some move descriptions
        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['Move Descriptions']
            for k, v in DESC_CHANGES.items():
                strings.strings[block.begin + k] = strings.strings[block.begin + k].replace(OLD_STAT, v)
            bin_after = StrHandler.serialize(strings)
            rom.setFileByName(filename, bin_after)

        try:
            apply()
        except RuntimeError as ex:
            raise ex
Beispiel #29
0
def main():
    os.makedirs(output_dir, exist_ok=True)

    rom = NintendoDSRom.fromFile(os.path.join(base_dir, 'skyworkcopy.nds'))

    script_info = load_script_files(get_rom_folder(rom, SCRIPT_DIR))

    for script_map in script_info['maps'].values():
        # Map BGs are NOT *actually* mapped 1:1 to scripts. They are loaded via Opcode. However it turns out, using the BPL name
        # is an easy way to map them.
        if script_map['enter_sse'] is not None:
            process(
                rom, script_map['name'], SCRIPT_DIR + '/' +
                script_map['name'] + '/' + script_map['enter_sse'])
        for ssa, _ in script_map['ssas']:
            process(rom, script_map['name'],
                    SCRIPT_DIR + '/' + script_map['name'] + '/' + ssa)
        for sss in script_map['subscripts'].keys():
            process(rom, script_map['name'],
                    SCRIPT_DIR + '/' + script_map['name'] + '/' + sss)
Beispiel #30
0
def main():
    output_dir = os.path.join(os.path.dirname(__file__), 'dbg_output')
    base_dir = os.path.join(os.path.dirname(__file__), '..', '..', '..', '..',
                            '..')
    os.makedirs(output_dir, exist_ok=True)

    rom = NintendoDSRom.fromFile(os.path.join(base_dir, 'skyworkcopy.nds'))

    for file_name in get_files_from_rom_with_extension(rom, 'ssb'):
        if 'm03a1310' not in file_name:
            continue
        print(file_name)

        out_file_name = os.path.join(output_dir,
                                     file_name.replace('/', '_') + '.txt')

        bin_before = rom.getFileByName(file_name)
        ssb = SsbHandler.deserialize(bin_before)

        with open(out_file_name, 'w') as f:
            f.write(export_ssb_as_txt(ssb))