Exemplo n.º 1
0
def patchdump():
    patchfile = "data/bad_to_good.xdelta"
    common.logMessage("Creating xdelta patch", patchfile, "...")
    xdelta = common.bundledFile("xdelta.exe")
    if not os.path.isfile(xdelta):
        common.logError("xdelta not found")
        return
    common.execute(
        xdelta + " -f -e -s {rom} {rompatch} {patch}".format(
            rom=romfile.replace(".nds", "_bad.nds"),
            rompatch=romfile,
            patch=patchfile), False)
    common.logMessage("Done!")
Exemplo n.º 2
0
def run(data):
    infolder = data + "extract/"
    outfolder = data + "out_IMG/"

    common.logMessage("Extracting images to", outfolder, "...")
    common.makeFolder(outfolder)

    files = common.getFiles(infolder)

    extracted = 0
    with codecs.open(common.bundledFile("images.txt"), "r", "utf-8") as imagef:
        for file in files:
            section = common.getSection(imagef, file)
            with common.Stream(infolder + file, "rb") as f:
                for imgname in section.keys():
                    imgdata = section[imgname][0].split(",")
                    mapstart = int(imgdata[1], 16)
                    imgnum = int(imgdata[2]) if len(imgdata) >= 3 else 1
                    readpal = len(imgdata) >= 4 and imgdata[3] == "1"
                    extracted += imgnum
                    if "-" in imgdata[0]:
                        tilestart = int(imgdata[0].split("-")[0], 16)
                        tileend = int(imgdata[0].split("-")[1], 16)
                        for i in common.showProgress(range(tilestart, tileend + 1, 1)):
                            ws.extractMappedImage(f, outfolder + imgname + "_" + hex(i) + ".png", i, mapstart, imgnum, readpal)
                    else:
                        tilestart = int(imgdata[0], 16)
                        ws.extractMappedImage(f, outfolder + imgname + ".png", tilestart, mapstart, imgnum, readpal)
                if file == "bank_09.bin":
                    map = game.getBerserkMap(outfolder)
                    ws.writeMappedImage(f, 0xf080, [map], ws.bwpalette)
                    extracted += 1
    # Extract ramen stand image
    with common.Stream(infolder + "bank_03.bin", "rb") as f:
        map = game.getRamenMap(outfolder)
        ws.writeMappedImage(f, 0x3748, [map], ws.bwpalette)
        map = game.getLanternMap(outfolder)
        ws.writeMappedImage(f, 0x3748, [map], ws.bwpalette)
    common.logMessage("Done! Extracted", extracted, "files")
Exemplo n.º 3
0
def run(data):
    workfolder = data + "work_IMG/"
    infolder = data + "extract/"
    outfolder = data + "repack/"

    common.logMessage("Repacking images from", workfolder, "...")

    files = common.getFiles(infolder)

    repacked = 0
    with codecs.open(common.bundledFile("images.txt"), "r", "utf-8") as imagef:
        for file in files:
            section = common.getSection(imagef, file)
            if len(section) > 0:
                with common.Stream(outfolder + file, "rb+") as f:
                    for imgname in section.keys():
                        imgdata = section[imgname][0].split(",")
                        mapstart = int(imgdata[1], 16)
                        imgnum = int(imgdata[2]) if len(imgdata) >= 3 else 1
                        readpal = len(imgdata) >= 4 and imgdata[3] == "1"
                        writepal = len(imgdata) >= 5 and imgdata[4] == "1"
                        tilestart = int(imgdata[0], 16)
                        ws.repackMappedImage(f, workfolder + imgname + ".png",
                                             tilestart, mapstart, imgnum,
                                             readpal, writepal)
                        repacked += imgnum
                    if file == "bank_09.bin":
                        map = game.getBerserkMap(workfolder)
                        ws.repackMappedTiles(f, 0xf080, map, ws.bwpalette)
                        repacked += 1
    # Repack ramen stand images
    with common.Stream(outfolder + "bank_03.bin", "rb+") as f:
        map = game.getRamenMap(workfolder)
        ws.repackMappedTiles(f, 0x3748, map, ws.bwpalette)
        map = game.getLanternMap(workfolder)
        ws.repackMappedTiles(f, 0x3748, map, ws.bwpalette)
        repacked += 2
    common.logMessage("Done! Repacked", repacked, "files")
Exemplo n.º 4
0
def run(firstgame):
    binin = "data/extract/arm9.bin"
    binout = "data/repack/arm9.bin"
    binfile = "data/bin_input.txt"
    patchfile = ""
    if not os.path.isfile(binfile):
        common.logError("Input file", binfile, "not found")
        return
    fixchars = game.getFixChars()

    patchfile = "bin_patch.asm"
    fontfile = "data/replace/data/font/lcfont12.NFTR"
    injectfile = "data/extract/data/font/digit8.NFTR"
    # Set the appropriate range depending on the game
    if firstgame:
        binrange = game.binrange[0]
        freeranges = game.freeranges[0]
        game.monthsection = game.monthsection[0]
        game.skipsection = game.skipsection[0]
    else:
        binrange = game.binrange[1]
        freeranges = game.freeranges[1]
        game.monthsection = game.monthsection[1]
        game.skipsection = game.skipsection[1]
        binin = binin.replace(".bin", "_dec.bin")
        binout = binout.replace(".bin", "_dec.bin")

    nds.repackBIN(binrange,
                  freeranges,
                  game.detectShiftJIS,
                  game.writeBINShiftJIS,
                  "cp932",
                  "#",
                  binin,
                  binout,
                  fixchars=fixchars)
    # Check that the redirects file is created, or create an empty one
    redfile = "data/redirects.asm"
    if not os.path.isfile(redfile):
        with codecs.open(redfile, "w", "utf-8") as f:
            f.write(".ascii \"NDSC\"\n\n")
            f.write("REDIRECT_START:\n\n")
    # Extract font data
    if not os.path.isfile(fontfile):
        fontfile = fontfile.replace("replace/", "extract/")
    common.copyFile(injectfile, injectfile.replace("extract/", "repack/"))
    nitro.extractFontData(fontfile, "data/font_data.bin")
    # Run armips
    common.armipsPatch(common.bundledFile(patchfile))
    if not firstgame:
        # Compress the binary
        compfile = binout.replace("_dec.bin", ".bin")
        common.logMessage("Compressing BIN ...")
        nds.compressBinary(binout, compfile)
        common.logMessage("Done!")
        # Apply AP patch
        apin = "data/extract/overlay/overlay_0000.bin"
        apout = "data/repack/overlay/overlay_0000.bin"
        common.copyFile(apin, apout)
        with common.Stream(apout, "rb+") as f:
            f.seek(0x432)
            f.writeByte(0x36)
            f.seek(0x58b)
            f.writeByte(0x7b)
Exemplo n.º 5
0
def run(data, allfile=False):
    infolder = data + "extract/"
    outfolder = data + "repack/"
    infile = data + "bin_input.txt"
    infilename = data + "name_input.txt"
    chartot = transtot = 0
    table, invtable, ccodes, glyphs = game.getFontData(data)

    with codecs.open(infile, "r", "utf-8") as bin:
        common.logMessage("Repacking bin from", infile, "...")
        for file in common.showProgress(game.fileranges):
            section = common.getSection(bin, file)
            if len(section) == 0:
                continue
            chartot, transtot = common.getSectionPercentage(
                section, chartot, transtot)
            # Repack the file
            common.logMessage("Processing", file, "...")
            common.copyFile(infolder + file, outfolder + file)
            with common.Stream(outfolder + file, "rb+") as f:
                if file != "bank_1d.bin":
                    for binrange in game.fileranges[file]:
                        f.seek(binrange[0])
                        while f.tell() < binrange[1]:
                            if (len(binrange) >= 3):
                                f.seek(binrange[2], 1)
                            strpos = f.tell()
                            readstr = game.readString(f, table, True)
                            if allfile and len(readstr) > 50:
                                f.seek(strpos + 2)
                                continue
                            if readstr.startswith("|"):
                                f.seek(strpos + 2)
                                continue
                            if readstr != "":
                                newstr = ""
                                if readstr in section:
                                    newstr = section[readstr].pop(0)
                                    if len(section[readstr]) == 0:
                                        del section[readstr]
                                strend = f.tell()
                                if newstr != "":
                                    if newstr == "!":
                                        newstr = ""
                                    common.logDebug("Repacking", newstr, "at",
                                                    common.toHex(strpos))
                                    f.seek(strpos)
                                    game.writeString(f, newstr, invtable,
                                                     ccodes,
                                                     strend - strpos - 2, True)
                                    while f.tell() < strend:
                                        f.writeByte(int(ccodes[" "][0], 16))
                                    f.seek(strend - 2)
                                    f.writeUShort(0xffff)
                else:
                    # String pointers are stored starting at 0xcd00
                    f.seek(0xcd00)
                    ptrs = []
                    for i in range(23):
                        ptrs.append(f.readUShort())
                        f.seek(14, 1)
                    strings = []
                    for ptr in ptrs:
                        f.seek(ptr)
                        strings.append(game.readString(f, table, True))
                    newptrs = []
                    f.seek(0xce70)
                    for i in range(len(strings)):
                        if strings[i] in section:
                            newstr = section[strings[i]].pop(0)
                        else:
                            newstr = strings[i]
                        newstr = common.wordwrap(newstr, glyphs,
                                                 game.wordwrap_angel,
                                                 game.detectTextCode)
                        common.logDebug("Repacking", newstr, "at",
                                        common.toHex(f.tell()))
                        newstr = newstr.split("|")
                        if len(newstr) > 8:
                            common.logError("Line too long",
                                            str(len(newstr)) + "/8", newstr[0])
                            newstr = newstr[:8]
                        while len(newstr) < 8:
                            newstr.append("")
                        for binstr in newstr:
                            if not binstr.startswith("▼"):
                                binstr = " " + binstr
                            newptrs.append(f.tell())
                            game.writeString(f, binstr, invtable, ccodes, -1,
                                             True)
                            f.writeUShort(0xffff)
                    f.seek(0xcd00)
                    for newptr in newptrs:
                        f.writeUShort(newptr)
    # Set the name input selection glyphs in bank 14
    newglyphs = {}
    with codecs.open(infilename, "r", "utf-8") as name:
        nameglyphs = name.read().replace("\r",
                                         "").replace("\n",
                                                     "").replace("#", "")
    with common.Stream(outfolder + "bank_14.bin", "rb+") as f:
        # Write the new name input values
        f.seek(0xc250)
        for nameglyph in nameglyphs:
            if nameglyph in invtable and invtable[nameglyph][:2] != 'ff':
                f.writeUShort(int(invtable[nameglyph], 16))
            else:
                glyphcode = int(ccodes[nameglyph][0], 16) - 0x20
                glyphcode <<= 6
                glyphcode += 0xa300
                newglyphs[nameglyph] = glyphcode
                f.writeUShort(glyphcode)
        # Write "Adam", but using the long glyphs
        f.seek(0x296c + 3)
        f.writeUShort(int(invtable["A"], 16))
        f.seek(3, 1)
        f.writeUShort(newglyphs["d"])
        f.seek(3, 1)
        f.writeUShort(newglyphs["a"])
        f.seek(3, 1)
        f.writeUShort(newglyphs["m"])
    common.logMessage("Done! Translation is at {0:.2f}%".format(
        (100 * transtot) / chartot))

    nasm.run(common.bundledFile("bin_patch.asm"))
Exemplo n.º 6
0
def run():
    xmlfile = "data/fontdump.xml"
    imgfile = "data/fontdump.png"
    fontfile = "font.png"
    fontconfigfile = "fontconfig.txt"
    outfile = "data/fontout.png"
    infont = "data/extract_NFP/ETC.NFP/GL_12FNT.NFT"
    tempfont = "data/GL_12FNT.NFTR"
    outfont = "data/work_NFP/ETC.NFP/GL_12FNT.NFT"
    binin = "data/bin_input.txt"
    spcin = "data/spc_input.txt"
    table = "data/table.txt"

    common.logMessage("Repacking font ...")
    fontexe = common.bundledFile("NerdFontTerminatoR.exe")
    if not os.path.isfile(fontexe):
        common.logError("NerdFontTerminatoR not found")
        return

    # List of characters
    with codecs.open(fontconfigfile, "r", "utf-8") as f:
        fontconfig = common.getSection(f, "")
        upperchars = fontconfig["upperchars"][0].split("|")
        lowerchars = fontconfig["lowerchars"][0].split("|")
        numbers = fontconfig["numbers"][0].split("|")
        punctuation = fontconfig["punctuation"][0].split("|")
        customs = fontconfig["customs"][0].split("|")
        all = upperchars + lowerchars + numbers + punctuation + customs

    # X Position in the font.png file
    positions = {}
    for i in range(len(upperchars)):
        positions[upperchars[i]] = i * 12
        positions[lowerchars[i]] = (i * 12) + 6
    for i in range(len(numbers)):
        positions[numbers[i]] = (len(upperchars) * 12) + (i * 6)
    for i in range(len(punctuation)):
        positions[punctuation[i]] = (len(upperchars) * 12) + (len(numbers) * 6) + (i * 6)
    for i in range(len(customs)):
        positions[customs[i]] = (len(upperchars) * 12) + (len(numbers) * 6) + (len(punctuation) * 6) + (i * 12)

    # Fix the font size before dumping it
    with common.Stream(infont, "rb") as font:
        with common.Stream(tempfont, "wb") as temp:
            font.seek(8)
            size = font.readUInt()
            font.seek(0)
            temp.write(font.read(size))
    # Dump the font
    common.execute(fontexe + " -e " + tempfont + " " + xmlfile + " " + imgfile, False)

    # Generate the code range
    coderanges = [(0x89, 0x9F), (0xE0, 0xEA)]
    skipcodes = [0x7F]
    charrange = (0x40, 0xFC)
    codes = []
    for coderange in coderanges:
        for i in range(coderange[0], coderange[1] + 1):
            first = charrange[0]
            if i == 0x88:
                first = 0x9F
            last = charrange[1]
            if i == 0xEA:
                last = 0xA4
            for j in range(first, last + 1):
                if j in skipcodes:
                    continue
                hexcode = i * 0x100 + j
                if hexcode > 0x9872 and hexcode < 0x989F:
                    continue
                codes.append(hexcode)

    # Generate a basic bigrams list
    items = ["  "]
    for char1 in upperchars:
        for char2 in lowerchars:
            items.append(char1 + char2)
    for char1 in upperchars:
        items.append(" " + char1)
        items.append(char1 + " ")
        for char2 in upperchars:
            if char1 + char2 not in items:
                items.append(char1 + char2)
    for char1 in lowerchars:
        items.append(" " + char1)
        items.append(char1 + " ")
        for char2 in lowerchars:
            if char1 + char2 not in items:
                items.append(char1 + char2)
    for custom in customs:
        items.append(custom)
    # And a complete one from all the bigrams
    with codecs.open(spcin, "r", "utf-8") as spc:
        inputs = common.getSection(spc, "", "#", game.fixchars)
    with codecs.open(binin, "r", "utf-8") as bin:
        inputs.update(common.getSection(bin, "", "#", game.fixchars))
    for k, input in inputs.items():
        for str in input:
            str = "<0A>".join(str.replace("|", "<0A>").split(">>"))
            if str.startswith("<<"):
                str = str[2:]
                pad = " " * ((20 - len(str)) // 2)
                str = pad + str + pad
            if str.startswith("[") and str[3] == "]":
                str = str[4:]
            i = 0
            while i < len(str):
                if i < len(str) - 1 and str[i+1] == "<":
                    str = str[:i+1] + " " + str[i+1:]
                elif i < len(str) - 4 and (str[i+1:i+5] == "UNK(" or str[i+1:i+5] == "CUS("):
                    str = str[:i+1] + " " + str[i+1:]
                char = str[i]
                if char == "<" and i < len(str) - 3 and str[i+3] == ">":
                    i += 4
                elif char == "U" and i < len(str) - 4 and str[i:i+4] == "UNK(":
                    i += 9
                elif char == "C" and i < len(str) - 4 and str[i:i+4] == "CUS(":
                    i += 9
                else:
                    if i + 1 == len(str):
                        bigram = char + " "
                    else:
                        bigram = char + str[i+1]
                    i += 2
                    if bigram not in items:
                        if bigram[0] not in all or bigram[1] not in all:
                            common.logError("Invalid bigram", bigram, "from phrase", str)
                        else:
                            items.append(bigram)

    # Open the images
    img = Image.open(imgfile)
    pixels = img.load()
    font = Image.open(fontfile)
    fontpixels = font.load()

    # Generate the image and table
    fontx = 106
    fonty = 5644
    x = len(codes) - 1
    tablestr = ""
    for item in items:
        if item in customs:
            for i2 in range(11):
                for j2 in range(11):
                    pixels[fontx + i2, fonty + j2] = fontpixels[positions[item] + i2, j2]
        else:
            for i2 in range(5):
                for j2 in range(11):
                    pixels[fontx + i2, fonty + j2] = fontpixels[positions[item[0]] + i2, j2]
            for j2 in range(11):
                pixels[fontx + 5, fonty + j2] = fontpixels[positions[" "], j2]
            for i2 in range(5):
                for j2 in range(11):
                    pixels[fontx + i2 + 6, fonty + j2] = fontpixels[positions[item[1]] + i2, j2]
        fontx -= 13
        if fontx < 0:
            fontx = 197
            fonty -= 13
        tablestr = (item + "=" + common.toHex(codes[x]) + "\n") + tablestr
        x -= 1
    with codecs.open(table, "w", "utf-8") as f:
        f.write(tablestr)
    img.save(outfile, "PNG")

    # Generate the new font
    common.execute(fontexe + " -i " + xmlfile + " " + outfile + " " + tempfont, False)
    common.copyFile(tempfont, outfont)
    # Clean up the temp files
    os.remove(xmlfile)
    os.remove(imgfile)
    os.remove(outfile)
    os.remove(tempfont)

    if x < len(items):
        common.logMessage("Done! Couldn't fit", len(items) - x, "bigrams")
    else:
        common.logMessage("Done! Room for", x - len(items), "more bigrams")