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)
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
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)
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)}" )
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 _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])
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)
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)
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))
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 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 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])
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)
async def load(self): """Load the ROM into memory and initialize all modules""" self._rom = NintendoDSRom.fromFile(self.filename) await AsyncTaskDelegator.buffer() self._loaded_modules = {} self._rom_module = Modules.get_rom_module()(self) self._rom_module.load_rom_data() for name, module in Modules.all().items(): logger.debug(f"Loading module {name} for ROM...") if name == 'rom': continue else: self._loaded_modules[name] = module(self) await AsyncTaskDelegator.buffer() self._sprite_renderer = SpriteProvider(self) await AsyncTaskDelegator.buffer() self._string_provider = StringProvider(self) await AsyncTaskDelegator.buffer() self._icon_banner = IconBanner(self._rom)
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))
def main(): base_dir = os.path.join(os.path.dirname(__file__), '..', '..', '..', '..', '..') rom = NintendoDSRom.fromFile(os.path.join(base_dir, 'skyworkcopy.nds')) for file_name in get_files_from_rom_with_extension(rom, 'ssb'): print(file_name) bin_before = rom.getFileByName(file_name) ssb_before = SsbHandler.deserialize(bin_before) bin_after = SsbHandler.serialize(ssb_before) after_header = SsbHeaderEu(bin_after) print("Header before:") print(str(ssb_before._header)) print("Header after:") print(str(after_header)) ssb_after = SsbHandler.deserialize(bin_after) assert (ssb_before._header.number_of_strings == ssb_after._header.number_of_strings) assert (ssb_before._header.const_table_length == ssb_after._header.const_table_length) assert (ssb_before._header.constant_strings_start == ssb_after._header.constant_strings_start) assert ( ssb_before._header.data_offset == ssb_after._header.data_offset) assert (ssb_before._header.number_of_constants == ssb_after._header.number_of_constants) assert (ssb_before._header.string_table_lengths == ssb_after._header.string_table_lengths) assert (ssb_before.routine_info == ssb_after.routine_info) assert (ssb_before.routine_ops == ssb_after.routine_ops) assert (ssb_before.constants == ssb_after.constants) assert (ssb_before.strings == ssb_after.strings) assert (len(bin_before) == len(bin_after)) assert (bin_before == bin_after)
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, 'sky_jp.nds')) with open(os.path.join(output_dir, "enter23.ssb"), 'wb') as f: f.write(rom.getFileByName('SCRIPT/D42P21A/enter23.ssb')) for file_name in get_files_from_rom_with_extension(rom, 'ssb'): 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, Pmd2XmlReader.load_default('EoS_JP')) with open(out_file_name, 'w') as f: f.write(export_ssb_as_txt(ssb))
from ndspy.rom import NintendoDSRom from xml.etree.ElementTree import Element, ElementTree from skytemple_files.common.xml_util import prettify from skytemple_files.common.types.file_types import FileType from skytemple_files.common.util import get_files_from_rom_with_extension, get_ppmdu_config_for_rom from skytemple_files.graphics.fonts.banner_font.handler import BannerFontHandler from PIL import Image #base_dir = os.path.join(os.path.dirname(__file__), '..', '..', '..', '..', '..') out_dir = os.path.join(os.path.dirname(__file__), 'dbg_output') os.makedirs(out_dir, exist_ok=True) #rom = NintendoDSRom.fromFile(os.path.join(base_dir, 'skyworkcopy_us.nds')) rom = NintendoDSRom.fromFile("/media/disk/Documents/Common/Games/Nintendo DS/Hack/Pokemon Mystery Dungeon - Explorers of Sky (4273) (US).nds") for fn in ["FONT/banner.bin", "FONT/banner_c.bin", "FONT/banner_s.bin"]: font_ref = rom.getFileByName(fn) font = BannerFontHandler.deserialize(font_ref) tree = ElementTree() xml = tree.parse(os.path.join(out_dir, fn.replace('/', '_') + f'.xml')) tables = dict() for i in range(256): path = os.path.join(out_dir, fn.replace('/', '_') + f'.{i}.png') if os.path.exists(path): tables[i] = Image.open(path, 'r') font.import_from_xml(xml, tables) assert BannerFontHandler.deserialize(BannerFontHandler.serialize(font))==BannerFontHandler.deserialize(font_ref)
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # 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.util import get_ppmdu_config_for_rom from skytemple_files.dungeon_data.fixed_bin.handler import FixedBinHandler output_dir = os.path.join(os.path.dirname(__file__), 'dbg_output') os.makedirs(output_dir, exist_ok=True) rom = NintendoDSRom.fromFile( '/home/marco/dev/skytemple/skytemple/skyworkcopy.nds') static_data = get_ppmdu_config_for_rom(rom) fixed_bin = rom.getFileByName('BALANCE/fixed.bin') fixed = FixedBinHandler.deserialize(fixed_bin, static_data=static_data) fixed_bin_after = FixedBinHandler.serialize(fixed) with open(os.path.join(output_dir, 'before.bin'), 'wb') as f: f.write(fixed_bin) with open(os.path.join(output_dir, 'after.bin'), 'wb') as f: f.write(fixed_bin_after) assert fixed_bin == fixed_bin_after print("ok!")
# but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # 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_files_from_rom_with_extension, get_ppmdu_config_for_rom from skytemple_files.graphics.chr.handler import ChrHandler from skytemple_files.graphics.pal.handler import PalHandler base_dir = os.path.join(os.path.dirname(__file__), '..', '..', '..', '..', '..') out_dir = os.path.join(os.path.dirname(__file__), 'dbg_output') os.makedirs(out_dir, exist_ok=True) rom = NintendoDSRom.fromFile(os.path.join(base_dir, 'skyworkcopy_us.nds')) config = get_ppmdu_config_for_rom(rom) for fn in get_files_from_rom_with_extension(rom, 'chr'): font = ChrHandler.deserialize(rom.getFileByName(fn)) pal = PalHandler.deserialize(rom.getFileByName(fn[:-4] + ".pal")) font.set_palette(pal) font.to_pil().save(os.path.join(out_dir, fn.replace('/', '_') + f'.png')) assert rom.getFileByName(fn) == ChrHandler.serialize(font)
# but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # 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
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.fixed_bin.model import TileRule, FloorType, TileRuleType from skytemple_files.graphics.dma.dma_drawer import DmaDrawer from skytemple_files.graphics.dma.model import Dma, DmaType from skytemple_files.graphics.dpc.model import Dpc from skytemple_files.graphics.dpci.model import Dpci from skytemple_files.graphics.dpl.model import Dpl from skytemple_files.graphics.dpla.model import Dpla from skytemple_files.hardcoded.fixed_floor import HardcodedFixedFloorTables 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(output_dir, 'test_fixed_floor.nds')) static_data = get_ppmdu_config_for_rom(rom) ov29 = get_binary_from_rom_ppmdu(rom, static_data.binaries['overlay/overlay_0029.bin']) fixed = FileType.FIXED_BIN.deserialize(rom.getFileByName('BALANCE/fixed.bin'), static_data) dungeon_bin = FileType.DUNGEON_BIN.deserialize(rom.getFileByName('DUNGEON/dungeon.bin'), static_data) mappa = FileType.MAPPA_BIN.deserialize(rom.getFileByName('BALANCE/mappa_s.bin')) monster_bin = FileType.BIN_PACK.deserialize(rom.getFileByName('MONSTER/monster.bin')) monster_md = FileType.MD.deserialize(rom.getFileByName('BALANCE/monster.md')) entity_table = HardcodedFixedFloorTables.get_entity_spawn_table(ov29, static_data) item_table = HardcodedFixedFloorTables.get_item_spawn_list(ov29, static_data) monster_table = HardcodedFixedFloorTables.get_monster_spawn_list(ov29, static_data) def draw_monster_sprite(img: Image.Image, x: int, y: int, monster_id: int, direction: Pmd2ScriptDirection):
# # 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.util import get_ppmdu_config_for_rom, create_file_in_rom, set_binary_in_rom_ppmdu from skytemple_files.patch.patches import Patcher if __name__ == '__main__': out_dir = os.path.join(os.path.dirname(__file__), 'dbg_output') base_dir = os.path.join(os.path.dirname(__file__), '..', '..', '..', '..') os.makedirs(out_dir, exist_ok=True) in_rom = NintendoDSRom.fromFile( os.path.join(base_dir, 'skyworkcopy_us.nds')) patcher = Patcher(in_rom, get_ppmdu_config_for_rom(in_rom)) assert not patcher.is_applied('ActorAndLevelLoader') patcher.apply('ActorAndLevelLoader') with open(os.path.join(out_dir, 'actor_list.bin'), 'wb') as f: f.write(in_rom.getFileByName('BALANCE/actor_list.bin')) with open(os.path.join(out_dir, 'level_list.bin'), 'wb') as f: f.write(in_rom.getFileByName('BALANCE/level_list.bin')) assert patcher.is_applied('ActorAndLevelLoader') in_rom.saveToFile(os.path.join(out_dir, 'patched.nds')) # Check if really patched out_rom = NintendoDSRom.fromFile(os.path.join(out_dir, 'patched.nds')) assert Patcher(
# GNU General Public License for more details. # # 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 PIL import Image from ndspy.rom import NintendoDSRom from skytemple_files.graphics.w16.handler import W16Handler from skytemple_files.graphics.w16.model import W16Image base_dir = os.path.join(os.path.dirname(__file__), '..', '..', '..', '..', '..') rom = NintendoDSRom.fromFile(os.path.join(base_dir, 'allister/allister.nds')) bfn = 'FONT/clrmark1.w16' bin = rom.getFileByName(bfn) w16 = W16Handler.deserialize(bin) for i, img in enumerate(w16): fn = os.path.join(base_dir, f'allister/clrmarks/converted/clrmark1_{i:03}.png') if os.path.exists(fn): with open(fn, 'rb') as f: im = img.set(Image.open(f)) rom.setFileByName(bfn, W16Handler.serialize(w16)) # test & verify bin = rom.getFileByName(bfn)
def main(): os.makedirs(os.path.join(os.path.dirname(__file__), 'dbg_output'), exist_ok=True) base_dir = os.path.join(os.path.dirname(__file__), '..', '..', '..', '..', '..') rom = NintendoDSRom.fromFile(os.path.join(base_dir, 'skyworkcopy_edit.nds')) prf('opening rom') bin = rom.getFileByName('MAP_BG/bg_list.dat') prf('loading level list') bg_list = BgListDatHandler.deserialize(bin) prf('deserializing level list') for l in bg_list.level: filename = l.bpc_name prf(f'loading {filename}') #if filename != 'D15P21A' and filename != 'D17P34A' and #if filename != 'D01P41A': # beach cave boss area # continue # debug map: T00P01 # crossroads: P01P01A if filename != 'P01P01A': continue try: filename_h = os.path.join(os.path.dirname(__file__), 'dbg_output', filename.replace('/', '_')) bma = l.get_bma(rom) prf(f'loading {filename} BMA') bpc = l.get_bpc(rom, bma.tiling_width, bma.tiling_height) prf(f'loading {filename} BPC') bpl = l.get_bpl(rom) prf(f'loading {filename} BPL') # Print debug information print(f"{l}") print(f"{filename} ({bpc.number_of_layers}): " f"UP: {bpc._upper_layer_pointer} - " f"LW: {bpc._lower_layer_pointer} - " f"LayerSpec: {bpc.layers}") # Palettes! palettes = bpl.palettes prf(f'setting up for {filename} image export, including BPA load') bpas = l.get_bpas(rom) non_none_bpas = [b for b in bpas if b is not None] for n in range(0, bpc.number_of_layers): # Save tiles! bpc.tiles_to_pil(n, palettes).save(filename_h + '.' + str(n) + '.tiles.png') prf(f'saving tiles for {filename}') # Save chunks! bpc.chunks_to_pil(n, palettes).save(filename_h + '.' + str(n) + '.png') prf(f'saving chunks for {filename}') # Saving animated chunks! # Default for only one frame, doesn't really matter duration = 1000 if len(non_none_bpas) > 0: # Assuming the game runs 60 FPS. duration = round( 1000 / 60 * non_none_bpas[0].frame_info[0].duration_per_frame) frames = bpc.chunks_animated_to_pil(n, palettes, bpas) frames[0].save(filename_h + '.' + str(n) + '.gif', save_all=True, append_images=frames[1:], duration=duration, loop=0, optimize=False) prf(f'saving animated chunks for {filename}') except (ValueError, AssertionError, NotImplementedError, SystemError) as ex: prf(f'error for {filename}') print(f"error for {filename}:") print(''.join( traceback.format_exception(etype=type(ex), value=ex, tb=ex.__traceback__)))
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # 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 PIL import Image from ndspy.rom import NintendoDSRom from skytemple_files.graphics.kao.handler import KaoHandler dir = os.path.join(os.path.dirname(__file__), '..', '..', '..', '..', '..') rom = NintendoDSRom.fromFile(os.path.join(dir, 'skyworkcopy.nds')) kao_data = rom.getFileByName('FONT/kaomado.kao') kao = KaoHandler.deserialize(kao_data) #kao.get(427, 0).get().show() with open(os.path.join(dir, 'kaomado.kao'), 'wb') as f: f.write(kao_data) with open(os.path.join(dir, 'dh', 'new427.png'), 'rb') as f: i = Image.open(f) kao.get(427, 0).set(i) kao.get(427, 2).set(i) with open(os.path.join(dir, 'dh', 'new051.png'), 'rb') as f: i = Image.open(f) kao.get(51, 0).set(i)
def open_rom(self, filename: str): self._rom = NintendoDSRom.fromFile(filename) self._rom_filename = filename self._project_fm = ProjectFileManager(filename) self._static_data = get_ppmdu_config_for_rom(self._rom) self._open_files = {}
# (at your option) any later version. # # SkyTemple is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # 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 base_dir = os.path.join(os.path.dirname(__file__), '..', '..', '..', '..', '..') rom_vanilla = NintendoDSRom.fromFile(os.path.join(base_dir, 'skyworkcopy.nds')) rom_modified = NintendoDSRom.fromFile( os.path.join(base_dir, 'skyworkcopy_edit.nds')) bin_vanilla = rom_vanilla.getFileByName('MAP_BG/s05p01a.bma') with open('/tmp/before.bin', 'wb') as f: f.write(bin_vanilla) bin_modified = rom_modified.getFileByName('MAP_BG/s05p01a.bma') with open('/tmp/after.bin', 'wb') as f: f.write(bin_modified)