Beispiel #1
0
    def open_rom(self, rom: Union[NintendoDSRom, BinaryIO, bytes, str,
                                  ndspy.rom.NintendoDSRom]):
        rom_last_filename = self.rom_last_filename
        if isinstance(rom, str):  # Filename
            rom_last_filename = rom
            rom = NintendoDSRom.fromFile(rom)
        elif isinstance(rom, BinaryIO):  # File
            rom = NintendoDSRom(rom.read())
        elif isinstance(rom, bytes):  # Raw bytes
            rom = NintendoDSRom(rom)
        elif isinstance(rom, ndspy.rom.NintendoDSRom):
            rom = NintendoDSRom(rom.save())
        elif isinstance(rom, NintendoDSRom):
            rom = rom

        # Load language from arm9
        if rom.name == b"LAYTON2":
            arm9 = rom.loadArm9()
            lang_address = 0x02000d3c - arm9.ramAddress
            lang_id = rom.arm9[lang_address]
            lang_table = ["jp", "en", "sp", "fr", "it", "ge", "du", "ko", "ch"]
            try:
                conf.LANG = lang_table[lang_id]
            except IndexError:  # US version?
                # TODO: Figure out how to read it properly
                conf.LANG = "en"
            print(f"Game language: {conf.LANG}")
            if conf.LANG == "jp":
                error_dialog = wx.MessageDialog(
                    self,
                    "Japanese is not currently supported",
                    style=wx.ICON_ERROR | wx.OK)
                error_dialog.ShowModal()
                return
        else:
            warning_game_dialog = wx.MessageDialog(
                self, "Warning: LaytonEditor is specifically made to edit "
                "Layton 2, and support with other games is not guaranteed.",
                style=wx.ICON_WARNING | wx.OK)
            warning_game_dialog.ShowModal()
            conf.LANG = "en"

        # After checking language
        self.rom = rom
        self.rom_last_filename = rom_last_filename

        RomSingleton(rom=self.rom)

        # Only open the main filesystem page.
        self.le_editor_pages.DeleteAllPages()
        menus_to_remove = []
        for menu in self.le_menu.Menus:
            if menu[1] != "File":
                menus_to_remove.append(menu[1])
        for menu_to_remove in menus_to_remove:
            self.remove_menu(menu_to_remove)
        self.open_filesystem_page("Rom FS")
Beispiel #2
0
def insertIntoRom(files, path, compress=False, username=None):
    """
    Insert a CodeFiles object into a rom.
    """

    with open(path, 'rb') as f:
        romData = f.read()

    rom = ndspy.rom.NintendoDSRom(romData)

    if compress:
        print('Compressing ARM9')
    rom.arm9 = files.arm9.save(compress)

    # ARM7 is never compressed.
    rom.arm7 = files.arm7.save()

    for id, ov in files.arm9Overlays.items():
        if compress:
            print(f'Compressing overlay {id} / {max(files.arm9Overlays)}')
        rom.files[ov.fileID] = ov.save(compress)

    rom.arm9OverlayTable = files.makeArm9Ovt()
    rom.arm7OverlayTable = files.makeArm7Ovt()

    # Try to overwrite an existing BUILDTIME file if possible.
    # Sadly, we can't insert a new BUILDTIME without potentially messing
    # up existing file IDs.
    buildtimeData = files.makeBuildtime(username=username)
    if 'BUILDTIME' in rom.filenames:
        rom.files[rom.filenames['BUILDTIME']] = buildtimeData

    newRomData = rom.save()

    with open(path, 'wb') as f:
        f.write(newRomData)
Beispiel #3
0
    def open_rom(self, rom: Union[NintendoDSRom, BinaryIO, bytes, str, ndspy.rom.NintendoDSRom]):
        if isinstance(rom, str):  # Filename
            self.rom_last_filename = rom
            self.rom = NintendoDSRom.fromFile(rom)
        elif isinstance(rom, BinaryIO):  # File
            self.rom = NintendoDSRom(rom.read())
        elif isinstance(rom, bytes):  # Raw bytes
            self.rom = NintendoDSRom(rom)
        elif isinstance(rom, ndspy.rom.NintendoDSRom):
            self.rom = NintendoDSRom(rom.save())
        elif isinstance(rom, NintendoDSRom):
            self.rom = rom

        RomSingleton(rom=self.rom)

        # Only open the main filesystem page.
        self.le_editor_pages.DeleteAllPages()
        menus_to_remove = []
        for menu in self.le_menu.Menus:
            if menu[1] != "File":
                menus_to_remove.append(menu[1])
        for menu_to_remove in menus_to_remove:
            self.remove_menu(menu_to_remove)
        self.open_filesystem_page("Rom FS")
def makeImages():
    imgFNs = [
        ('ts-0', '3089 BASE.enpg'),
        ('ts-1', '3090 WORLD1.enpg'),
        ('ts-2', '3091 WORLD2.enpg'),
        ('ts-3', '3092 WORLD3.enpg'),
        ('ts-4', '3093 WORLD4.enpg'),
        ('ts-5', '3094 WORLD5.enpg'),
        ('ts-6', '3095 WORLD6.enpg'),
        ('ts-7', '3096 WORLD7.enpg'),
        ('ts-8', '3097 WORLD8.enpg'),
    ]
    FIRST_FILE_ID = 3089

    imgs = []
    for fn, _ in imgFNs:
        imgs.append(QtGui.QImage(f'{fn}.png'))

    imgs[0] = addVersionNumber(imgs[0])

    converted = convertAllToEnpg(imgs)

    with open('Newer Super Mario Bros. DS.nds', 'rb') as f:
        rom = ndspy.rom.NintendoDSRom(f.read())

    for i, ((fn, gamefn), enpg) in enumerate(zip(imgFNs, converted)):
        compressed = ndspy.lz10.compress(enpg)
        with open(f'out-enpg/{gamefn}', 'wb') as f:
            f.write(enpg)
        with open(f'out-enpg-lz/{gamefn}', 'wb') as f:
            f.write(compressed)
        rom.files[FIRST_FILE_ID + i] = compressed
        enpgToImage(enpg).save(f'out-enpg-png/{gamefn}.png')

    with open('Newer Super Mario Bros. DS.nds', 'wb') as f:
        f.write(rom.save())
Beispiel #5
0
def makeImages():

    resources = loadResources()

    with open('config.json', 'r', encoding='utf-8') as f:
        config = json.load(f, object_pairs_hook=collections.OrderedDict)

    with open('Newer Super Mario Bros. DS Orig.nds', 'rb') as f:
        rom = ndspy.rom.NintendoDSRom(f.read())

    for i in range(2128, 2488):
        rom.filenames['zc_crsin'].files[i - rom.filenames['zc_crsin'].firstID] = f'{i} Dummy'
        rom.files[i] = b'DUMMY'

    fileIdMap = {}

    def fileIdGen():
        fid = 2128
        while True:
            yield fid
            fid += 2
    fileId = fileIdGen()

    # Make the top-screen images
    bottomImagesToMake = []
    topPairs = []
    for levelName, levelConfig in config['levels'].items():
        theme = config['themes'][levelConfig['theme']]
        main, aux = makeTopScreenIntroGraphics(
            resources = resources,
            title = levelConfig.get('title'),
            name = levelConfig.get('name'),
            background1 = hex2QColor(theme['background1']),
            background2 = hex2QColor(theme['background2']),
            banner1 = hex2QColor(theme['banner1']),
            banner2 = hex2QColor(theme['banner2']),
            preview = QtGui.QPixmap('previews/' + levelConfig['preview']),
            )

        topId = next(fileId)

        mainFn = '%d_%s_main' % (topId, levelName)
        auxFn = '%d_%s_aux' % (topId + 1, levelName)
        saveImagePair(main, aux, mainFn, auxFn, rom, topId)
        topPairs.append([mainFn, auxFn])

        bottomImageId = (levelConfig['theme'], levelConfig['bottom'])
        if bottomImageId not in bottomImagesToMake:
            bottomImagesToMake.append(bottomImageId)

        fileIdMap[(levelConfig['world'] - 1) * 24 + levelConfig['number']] = \
            (topId, bottomImagesToMake.index(bottomImageId))

    # Make the bottom-screen images
    bottomFileIds = []
    bottomPairs = []
    for i, (themeName, btm) in enumerate(bottomImagesToMake):
        print(f'Rendering bottom-screen graphics for {btm.split(".")[0]}'
            f' with the "{themeName}" theme ({i+1}/{len(bottomImagesToMake)})...')
        theme = config['themes'][themeName]
        main, aux = makeBottomScreenIntroGraphics(
            resources = resources,
            background1 = hex2QColor(theme['background1']),
            background2 = hex2QColor(theme['background2']),
            banner1 = hex2QColor(theme['banner1']),
            banner2 = hex2QColor(theme['banner2']),
            icon = QtGui.QPixmap('bottoms/' + btm),
            )

        btmId = next(fileId)
        bottomFileIds.append(btmId)

        mainFn = '_'.join([str(btmId),
                           'btm',
                           btm.split('.')[0],
                           themeName,
                           'main'])
        auxFn = '_'.join([str(btmId + 1),
                          'btm',
                          btm.split('.')[0],
                          themeName,
                          'aux'])
        saveImagePair(main, aux, mainFn, auxFn, rom, btmId)
        bottomPairs.append([mainFn, auxFn])

    print('Saving everything...')

    fileIdData = [0] * 2 * (max(fileIdMap) + 1)

    for idx, (topId, btmIdx) in fileIdMap.items():
        fileIdData[idx * 2] = topId
        fileIdData[idx * 2 + 1] = bottomFileIds[btmIdx]

    fileIdBytes = struct.pack('<%dH' % len(fileIdData), *fileIdData)
    fileIdBytesComp = ndspy.lz10.compress(fileIdBytes)
    with open('fileIDs.nerds', 'wb') as f:
        f.write(fileIdBytes)
    with open('fileIDs.nerds.lz', 'wb') as f:
        f.write(fileIdBytesComp)
    rom.files[2127] = fileIdBytesComp
    rom.filenames['zc_crsin'].files[0] = f'2127 fileIDs.nerds'

    with open('conversionInfo.json', 'w', encoding='utf-8') as f:
        json.dump({'top': topPairs, 'bottom': bottomPairs}, f)

    with open('Newer Super Mario Bros. DS.nds', 'wb') as f:
        f.write(rom.save())

    print('Done! :D')
Beispiel #6
0
def replace(rom_path,
            i_path,
            save_path,
            confirm=True,
            only_modified=False,
            debug_log=True):
    # Re-inserts files!
    rom = ndspy.rom.NintendoDSRom.fromFile(rom_path)
    if debug_log:
        print(rom)

    if confirm:
        inp = input("Insert ROM Contents from \"" + os.path.abspath(i_path) +
                    "\" into \"" + os.path.abspath(rom_path) +
                    "\" and save to file \"" + os.path.abspath(save_path) +
                    "\"? [y/n]")
        if inp != "y":
            print("Insertion cancelled!")
            return

    for i, file in enumerate(rom.files):
        try:
            rom_internal_file_name = rom.filenames[i]
            #print(rom_internal_file_name)

            path_wf = i_path + rom_internal_file_name

            #print(path_wf)

            if os.path.isfile(path_wf):
                with open(path_wf, 'rb') as f:
                    bin_file = f.read()

                    if only_modified:
                        h = hashlib.md5(bin_file).hexdigest()
                        h_romfile = hashlib.md5(file).hexdigest()

                        if not (h == h_romfile):
                            # Replace File!
                            rom.setFileByName(rom_internal_file_name, bin_file)
                            if debug_log:
                                print("[Inserted] " + rom_internal_file_name +
                                      " <- " + path_wf)
                        else:
                            pass
                            #print("File hasn't been modified!")
                    else:
                        rom.setFileByName(rom_internal_file_name, bin_file)
                        if debug_log:
                            print("[Inserted] " + rom_internal_file_name +
                                  " <- " + path_wf)
            else:
                pass
                #print("File skipped - File doesn't exist!")

        except KeyError:
            if debug_log:
                print("[Ignored] ID " + str(i) + " has no filename!")

    if debug_log:
        print("Saving rom...")
    with open(save_path, 'wb') as f:
        f.write(rom.save())
    if debug_log:
        print("Done!")
Beispiel #7
0
def main():
    """
    Main function for FNT Tool.
    """

    parser = argparse.ArgumentParser(
        description='FNT Tool: Extract or insert filename tables to or'
        ' from ROM or NARC files, either as binary or JSON'
        ' files.')

    parser.add_argument('infile', help='the file to be converted')
    parser.add_argument('outfile', help='the output filename')

    group = parser.add_mutually_exclusive_group(required=True)
    group.add_argument('-ib',
                       '--input_bin',
                       action='store_true',
                       help='the input file is a raw filename table file')
    group.add_argument('-ij',
                       '--input_json',
                       action='store_true',
                       help='the input file is a JSON file')
    group.add_argument('-ir',
                       '--input_rom',
                       action='store_true',
                       help='the input file is a ROM')
    group.add_argument('-in',
                       '--input_narc',
                       action='store_true',
                       help='the input file is a NARC file')

    group = parser.add_mutually_exclusive_group(required=True)
    group.add_argument('-ob',
                       '--output_bin',
                       action='store_true',
                       help='save the filename table to a raw filename'
                       ' table file')
    group.add_argument('-oj',
                       '--output_json',
                       action='store_true',
                       help='save the filename table to a JSON file')
    group.add_argument('-or',
                       '--output_rom',
                       action='store_true',
                       help='insert the filename table into a ROM'
                       ' (the ROM file must already exist)')
    group.add_argument('-on',
                       '--output_narc',
                       action='store_true',
                       help='insert the filename table into a NARC file'
                       ' (the NARC file must already exist)')

    args = parser.parse_args()

    # Make sure that outfile exists if we're going to insert
    if (args.output_rom
            or args.output_narc) and not os.path.exists(args.outfile):
        raise ValueError(
            'To use -or or -on, the output file must already exist!')

    # Open the input file
    with open(args.infile, 'rb') as f:
        ind = f.read()

    # Load the filename table from it
    print(f'Loading filenames from {args.infile}...')
    fnt = None
    if args.input_bin:
        fnt = ndspy.fnt.load(ind)
    elif args.input_json:
        fnt = _common.jsonToFnt(ind.decode('utf-8'))
    elif args.input_rom:
        fnt = ndspy.rom.NintendoDSRom(ind).filenames
    elif args.input_narc:
        fnt, _ = ndspy.narc.load(ind)

    assert fnt is not None

    # Open the output file, if it exists
    existing = None
    if os.path.isfile(args.outfile):
        with open(args.outfile, 'rb') as f:
            existing = f.read()

    # Create the output data in the requested format
    if args.output_rom or args.output_narc:
        print(f'Inserting filenames into {args.outfile}...')
    else:
        print(f'Saving filenames to {args.outfile}...')
    outd = None
    if args.output_bin:
        outd = ndspy.fnt.save(fnt)
    elif args.output_json:
        outd = _common.fntToJson(fnt).encode('utf-8')
    elif args.output_rom:
        rom = ndspy.rom.NintendoDSRom(existing)
        rom.filenames = fnt
        outd = rom.save()
    elif args.output_narc:
        _, files = ndspy.narc.load(existing)
        outd = ndspy.narc.save(fnt, files)

    assert outd is not None

    # Save it
    with open(args.outfile, 'wb') as f:
        f.write(outd)

    print('Done.')