Esempio n. 1
0
def run(data, allfile=False):
    infolder = data + "extract/"
    outfile = data + "bin_output.txt"
    with codecs.open(data + "table_input.txt", "r", "utf-8") as tablef:
        table = common.getSection(tablef, "")
    if allfile:
        game.fileranges = {"bank_1d.bin": [(0x0, 0xfff0)]}

    with codecs.open(outfile, "w", "utf-8") as out:
        common.logMessage("Extracting bin to", outfile, "...")
        for file in common.showProgress(game.fileranges):
            out.write("!FILE:" + file + "\n")
            with common.Stream(infolder + file, "rb") as f:
                for range in game.fileranges[file]:
                    f.seek(range[0])
                    while f.tell() < range[1]:
                        if (len(range) >= 3):
                            f.seek(range[2], 1)
                        pos = f.tell()
                        binstr = game.readString(f, table, True)
                        if allfile and len(binstr) > 50:
                            f.seek(pos + 2)
                            continue
                        if binstr.startswith("|"):
                            f.seek(pos + 2)
                            continue
                        if binstr != "":
                            common.logDebug("Found string at", common.toHex(pos), binstr)
                            out.write(binstr + "=\n")
        common.logMessage("Done!")
Esempio n. 2
0
def extractARC(infolder, outfolder):
    common.makeFolder(outfolder)
    common.logMessage("Extracting ARC to", outfolder, "...")
    files = common.getFiles(infolder, ".arc")
    for file in common.showProgress(files):
        common.logDebug("Processing", file, "...")
        common.execute(
            "wszst EXTRACT " + infolder + file + " -D " + outfolder + file,
            False)
    common.logMessage("Done! Extracted", len(files), "files")
Esempio n. 3
0
def extractTPL(infolder, outfolder, splitName=True):
    common.makeFolder(outfolder)
    common.logMessage("Extracting TPL to", outfolder, "...")
    files = common.getFiles(infolder, ".tpl")
    for file in common.showProgress(files):
        common.logDebug("Processing", file, "...")
        filename = file.split("/")[0] if splitName else file
        common.execute(
            "wimgt DECODE " + infolder + file + " -D " + outfolder + filename +
            "/" + os.path.basename(file).replace(".tpl", ".png"), False)
    common.logMessage("Done! Extracted", len(files), "files")
Esempio n. 4
0
def repackIso(isofile, isopatch, workfolder, patchfile=""):
    common.logMessage("Repacking ISO", isopatch, "...")
    common.copyFile(isofile, isopatch)
    iso = pycdlib.PyCdlib()
    iso.open(isopatch, "r+b")
    files = common.getFiles(workfolder)
    for file in common.showProgress(files):
        filelen = os.path.getsize(workfolder + file)
        with open(workfolder + file, "rb") as f:
            iso.modify_file_in_place(f, filelen, "/" + file)
    iso.close()
    common.logMessage("Done!")
    # Create xdelta patch
    if patchfile != "":
        common.xdeltaPatch(patchfile, isofile, isopatch)
Esempio n. 5
0
def extractBREFT(infolder, tempfolder, outfolder):
    common.makeFolder(tempfolder)
    common.makeFolder(outfolder)
    common.logMessage("Extracting BREFT to", outfolder, "...")
    files = common.getFiles(infolder, ".breft")
    for file in common.showProgress(files):
        common.logDebug("Processing", file, "...")
        outfile = file.split("/")
        outfile = "/" + outfile[1] + "/" + outfile[3]
        common.execute(
            "wszst EXTRACT " + infolder + file + " -D " + tempfolder + outfile,
            False)
        for imgfile in os.listdir(tempfolder + outfile + "/files"):
            common.execute(
                "wimgt DECODE " + tempfolder + outfile + "/files/" + imgfile +
                " -D " + outfolder + outfile + "/" + imgfile + ".png", False)
    common.logMessage("Done! Extracted", len(files), "files")
Esempio n. 6
0
def repackUMD(isofile, isopatch, workfolder, patchfile=""):
    common.logMessage("Repacking ISO", isopatch, "...")
    common.copyFile(isofile, isopatch)
    umdreplace = common.bundledExecutable("UMD-replace.exe")
    if not os.path.isfile(umdreplace):
        common.logError("UMD-replace not found")
        return
    files = common.getFiles(workfolder)
    for file in common.showProgress(files):
        common.execute(
            umdreplace +
            " \"{imagename}\" \"/{filename}\" \"{newfile}\"".format(
                imagename=isopatch, filename=file, newfile=workfolder + file),
            False)
    common.logMessage("Done!")
    # Create xdelta patch
    if patchfile != "":
        common.xdeltaPatch(patchfile, isofile, isopatch)
Esempio n. 7
0
def run():
    infolder = "data/extract/data/graphics/"
    outfolder = "data/out_IMG/"

    common.logMessage("Extracting KBG to", outfolder, "...")
    files = common.getFiles(infolder, ".kbg")
    for file in common.showProgress(files):
        common.logDebug("Processing", file, "...")
        with common.Stream(infolder + file, "rb") as f:
            palettes, ncgr = game.readKBG(f)
            tiledata = f.read(ncgr.tilelen)
            nitro.readNCGRTiles(ncgr, tiledata)
            # Export img
            common.makeFolders(outfolder + os.path.dirname(file))
            outfile = outfolder + file.replace(".kbg", ".png")
            nitro.drawNCGR(outfile, None, ncgr, palettes, ncgr.width,
                           ncgr.height)
    common.logMessage("Done! Extracted", len(files), "files")
Esempio n. 8
0
def run():
    infolder = "data/extract_NFP/NFP2D.NFP/"
    outfolder = "data/out_VSC/"
    common.makeFolder(outfolder)

    common.logMessage("Extracting VSC to", outfolder, "...")
    files = common.getFiles(infolder, ".VSC")
    for file in common.showProgress(files):
        common.logDebug("Processing", file, "...")
        with common.Stream(infolder + file, "rb") as f:
            # Read header
            f.seek(4)
            unk1 = f.readUShort()
            unk2 = f.readUShort()
            size = f.readUInt()
            unk3 = f.readUInt()
            bpp = 4 if f.readUInt() == 1 else 8
            width = f.readUInt()
            height = f.readUInt()
            unk4 = f.readUInt()
            mapsize = f.readUInt()
            unk5 = f.readUInt()
            tilesize = f.readUInt()
            common.logDebug("size:", size, "width:", width, "height:", height, "mapsize:", mapsize, "tilesize:", tilesize, "bpp:", bpp)
            common.logDebug("unk1:", unk1, "unk2:", unk2, "unk3:", unk3, "unk4:", unk4, "unk5:", unk5)
            # Read data
            common.logDebug("mapoffset:", f.tell())
            mapdata = f.read(mapsize)
            common.logDebug("tileoffset:", f.tell())
            tiledata = f.read(tilesize)
            common.logDebug("paloffset:", f.tell())
            cpal = f.readString(4)
            if cpal != "CPAL":
                common.logError("Palette header", cpal)
                continue
            f.seek(20, 1)
            palnum = f.readUShort()
            f.seek(4, 1)
            paldata = f.read(palnum * 32)
            # Draw the image
            img = game.drawMappedImage(width, height, mapdata, tiledata, paldata, 8, bpp)
            img.save(outfolder + file.replace(".VSC", ".png"), "PNG")
    common.logMessage("Done! Extracted", len(files), "files")
Esempio n. 9
0
def run():
    infolder = "data/extract/data/graphics/"
    outfolder = "data/repack/data/graphics/"
    workfolder = "data/work_IMG/"

    common.logMessage("Repacking KBG from", workfolder, "...")
    files = common.getFiles(infolder, ".kbg")
    for file in common.showProgress(files):
        pngfile = workfolder + file.replace(".kbg", ".png")
        if not os.path.isfile(pngfile):
            continue
        common.logDebug("Processing", file, "...")
        with common.Stream(infolder + file, "rb") as fin:
            with common.Stream(outfolder + file, "wb") as f:
                palettes, ncgr = game.readKBG(fin)
                fin.seek(0)
                f.write(fin.read(ncgr.tileoffset))
        nitro.writeNCGR(outfolder + file, ncgr, pngfile, palettes)
    common.logMessage("Done!")
Esempio n. 10
0
def extractTIM(infolder, outfolder, extensions=".tim", readfunc=None):
    common.makeFolder(outfolder)
    common.logMessage("Extracting TIM to", outfolder, "...")
    files = common.getFiles(infolder, extensions)
    for file in common.showProgress(files):
        common.logDebug("Processing", file, "...")
        extension = os.path.splitext(file)[1]
        if readfunc is not None:
            tim, transp, forcepal = readfunc(infolder + file)
        else:
            transp = False
            forcepal = -1
            with common.Stream(infolder + file, "rb") as f:
                tim = readTIM(f)
        if tim is None:
            continue
        # Export img
        common.makeFolders(outfolder + os.path.dirname(file))
        outfile = outfolder + file.replace(extension, ".png")
        drawTIM(outfile, tim, transp, forcepal)
    common.logMessage("Done! Extracted", len(files), "files")
Esempio n. 11
0
def run():
    infolder = "data/extract_NFP/SPC.NFP/"
    outfile = "data/spc_output.txt"

    common.logMessage("Extracting SPC to", outfile, "...")
    with codecs.open(outfile, "w", "utf-8") as out:
        files = common.getFiles(infolder, ".SPC")
        for file in common.showProgress(files):
            common.logDebug("Processing", file, "...")
            first = True
            with common.Stream(infolder + file, "rb") as f:
                f.seek(12)  # "SCRP" + filesize + "CODE"
                codesize = f.readUInt()
                if codesize > 10:
                    f.seek(6, 1)
                    while f.tell() < 16 + codesize - 2:
                        pos = f.tell()
                        byte = f.readByte()
                        if byte == 0x10:
                            try:
                                sjis = game.readShiftJIS(f)
                                if sjis != "":
                                    common.logDebug("Found string at", pos, "with length", len(sjis))
                                    if first:
                                        first = False
                                        out.write("!FILE:" + file + "\n")
                                    out.write(sjis + "=\n")
                                f.seek(9, 1)
                            except UnicodeDecodeError:
                                common.logError("UnicodeDecodeError")
                        elif byte == 0x15:
                            f.seek(1, 1)
                            bytelen = f.readByte()
                            f.seek(8 * bytelen, 1)
                        elif byte in game.spccodes:
                            f.seek(game.spccodes[byte], 1)
                        else:
                            common.logDebug("Unknown byte", common.toHex(byte), "at", pos)
    common.logMessage("Done! Extracted", len(files), "files")
Esempio n. 12
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")
Esempio n. 13
0
def run():
    infolder = "data/extract/data/Rom/event/script/"
    outfile = "data/cnut_output.txt"

    common.logMessage("Extracting CNUT to", outfile, "...")
    with codecs.open(outfile, "w", "utf-8") as out:
        files = common.getFiles(infolder, ".cnut")
        for file in common.showProgress(files):
            common.logDebug("Processing", file, "...")
            first = True
            size = os.path.getsize(infolder + file)
            with common.Stream(infolder + file, "rb") as f:
                while f.tell() < size - 4:
                    pos = f.tell()
                    b1 = f.readByte()
                    b2 = f.readByte()
                    b3 = f.readByte()
                    b4 = f.readByte()
                    if b1 == 0x10 and b2 == 0x00 and b3 == 0x00 and b4 == 0x08:
                        # Found a string
                        check = game.readShiftJIS(f)
                        # Remove some codes that are found in almost every string start/end
                        if check.startswith("#CLR()"):
                            check = check[6:]
                        if check.startswith("#ARW("):
                            check = check[7:]
                        if check.endswith("#INP()"):
                            check = check[:-6]
                        if not common.isAscii(check):
                            if first:
                                out.write("!FILE:" + file + "\n")
                                first = False
                            out.write(check + "=\n")
                    else:
                        f.seek(pos + 1)
    common.logMessage("Done! Extracted", len(files), "files")
Esempio n. 14
0
def run(firstgame):
    infolder = "data/extract/data/data/"
    outfile = "data/dat_output.txt"
    ignorefiles = ["route.dat", "debttable.dat", "errandgossip.dat", "market.dat", "traderexptable.dat"]
    if not firstgame:
        ignorefiles.append("love_event.dat")
    encoding = "shift_jis" if firstgame else "shift_jisx0213"
    game.monthsection = game.skipsection = None

    common.logMessage("Extracting DAT to", outfile, "...")
    with codecs.open(outfile, "w", "utf-8") as out:
        files = common.getFiles(infolder, ".dat")
        for file in common.showProgress(files):
            if file in ignorefiles:
                continue
            common.logDebug("Processing", file, "...")
            first = True
            foundstrings = []
            size = os.path.getsize(infolder + file)
            # The file contains several strings, padded with 0s
            with common.Stream(infolder + file, "rb") as f:
                while f.tell() < size - 2:
                    pos = f.tell()
                    check = game.detectShiftJIS(f, encoding)
                    if check != "" and check != "%":
                        # Check for repeated strings, only within a single file
                        if check not in foundstrings:
                            common.logDebug("Found string at", pos)
                            if first:
                                out.write("!FILE:" + file + "\n")
                                first = False
                            out.write(check + "=\n")
                            foundstrings.append(check)
                        pos = f.tell() - 1
                    f.seek(pos + 1)
    common.logMessage("Done! Extracted", len(files), "files")
Esempio n. 15
0
def run(firstgame):
    infolder = "data/extract/data/script/"
    outfolder = "data/repack/data/script/"
    infile = "data/wsb_input.txt"
    fontfile = "data/replace/data/font/lcfont12.NFTR"
    if not os.path.isfile(infile):
        common.logError("Input file", infile, "not found")
        return

    encoding = "shift_jis" if firstgame else "shift_jisx0213"
    common.logMessage("Repacking WSB from", infile, "...")
    # Read the glyph size from the font
    if not os.path.isfile(fontfile):
        fontfile = fontfile.replace("replace/", "extract/")
    glyphs = nitro.readNFTR(fontfile).glyphs
    wordwrap = game.wordwrap[0] if firstgame else game.wordwrap[1]
    fixchars = game.getFixChars()
    with codecs.open(infile, "r", "utf-8") as wsb:
        commonsection = common.getSection(wsb, "COMMON", fixchars=fixchars)
        chartot, transtot = common.getSectionPercentage(commonsection)
        files = common.getFiles(infolder, ".wsb")
        for file in common.showProgress(files):
            section = common.getSection(wsb, file, fixchars=fixchars)
            chartot, transtot = common.getSectionPercentage(
                section, chartot, transtot)
            # Repack the file
            pointerdiff = {}
            pointers = {}
            common.logDebug(" Processing", file, "...")
            insize = os.path.getsize(infolder + file)
            with common.Stream(infolder + file, "rb") as fin:
                with common.Stream(outfolder + file, "wb") as f:
                    # Copy header
                    fin.seek(4)  # 0x10
                    codeoffset = fin.readUInt()
                    if codeoffset == 0 and not firstgame:
                        fin.seek(0)
                        f.write(fin.read())
                        continue
                    fin.seek(8, 1)  # all 0xFF
                    unk = fin.readUInt()
                    textoffset = fin.readUInt()
                    codeoffset2 = fin.readUInt()
                    fin.seek(0)
                    f.write(fin.read(32))
                    # Write new strings
                    while fin.tell() < codeoffset:
                        pos = fin.tell()
                        fpos = f.tell()
                        b1 = fin.readByte()
                        b2 = fin.readByte()
                        f.writeByte(b1)
                        f.writeByte(b2)
                        if (b1 == 0x55 and b2 == 0x08) or (b1 == 0x95
                                                           and b2 == 0x10):
                            sjis, oldlen = game.readShiftJIS(
                                fin, b1 == 0x95, False, encoding)
                            # Fix a bugged line with wrong speaker code
                            if file == "event/ev_mou/mou_10.wsb" and sjis == "そうじゃな。|わっちの直感が申すには……>>":
                                f.seek(fpos - 12)
                                f.writeByte(0x53)
                                f.seek(fpos + 2)
                            strreplaced = False
                            if sjis != "" and sjis != ">>":
                                sjissplit = sjis.split(">>")
                                for i in range(len(sjissplit)):
                                    newsjis = sjisline = sjissplit[i]
                                    if sjisline in commonsection:
                                        newsjis = commonsection[sjisline][0]
                                    elif sjisline in section:
                                        newsjis = section[sjisline].pop(0)
                                        if len(section[sjisline]) == 0:
                                            del section[sjisline]
                                    if newsjis != "":
                                        # Disable wordwrap for strings that contain replace codes
                                        if newsjis.count("@<") > 0:
                                            sjissplit[i] = newsjis
                                        # Check for automatic centering
                                        elif newsjis.count("<<") > 0:
                                            sjissplit[i] = common.centerLines(
                                                newsjis,
                                                glyphs,
                                                wordwrap,
                                                centercode="<<")
                                        else:
                                            sjissplit[i] = common.wordwrap(
                                                newsjis, glyphs, wordwrap)
                                            if sjissplit[i].count("|") > 2:
                                                common.logError(
                                                    "Sub-line too long:",
                                                    sjissplit[i])
                                                cutsplit = sjissplit[i].split(
                                                    "|")
                                                sjissplit[i] = cutsplit[
                                                    0] + "|" + cutsplit[
                                                        1] + "|" + cutsplit[2]
                                newsjis = ">>".join(sjissplit)
                                if newsjis != sjis and newsjis != "" and newsjis != ">>":
                                    common.logDebug("Repacking", newsjis, "at",
                                                    common.toHex(pos))
                                    strreplaced = True
                                    if newsjis == "!":
                                        newsjis = ""
                                    newlen = game.writeShiftJIS(
                                        f, newsjis, b1 == 0x95, False, 0,
                                        encoding, firstgame)
                                    lendiff = newlen - oldlen
                                    if newlen > (0x80 if firstgame else
                                                 0x70) and b1 == 0x55:
                                        common.logDebug(
                                            "String is too long", newlen,
                                            "changing to 0x95")
                                        f.seek(fpos)
                                        f.writeByte(0x95)
                                        f.writeByte(0x10)
                                        game.writeShiftJIS(
                                            f, newsjis, True, False, 0,
                                            encoding, firstgame)
                                        lendiff += 2
                                    if lendiff != 0:
                                        common.logDebug(
                                            "Adding", lendiff, "at", pos)
                                        pointerdiff[pos - 16] = lendiff
                            if not strreplaced:
                                fin.seek(pos + 2)
                                f.write(
                                    fin.read(oldlen +
                                             (4 if b1 == 0x95 else 2)))
                        elif (b1, b2) in game.wsbcodes:
                            if (b1, b2) in game.wsbpointers:
                                if b1 == 0x81 and b2 == 0xB9:
                                    f.write(fin.read(2))
                                pointer = fin.readUInt()
                                pointers[f.tell()] = pointer
                                f.writeUInt(pointer)
                            else:
                                f.write(fin.read(game.wsbcodes[(b1, b2)]))
                    # Write code section
                    if codeoffset > 0:
                        newcodeoffset = f.tell()
                        codediff = 0
                        codenum = fin.readUInt()
                        f.writeUInt(codenum)
                        for i in range(codenum):
                            fin.seek(codeoffset + 4 + 4 * i)
                            f.seek(newcodeoffset + 4 + 4 * i)
                            codepointer = fin.readUInt()
                            f.writeUInt(codepointer + codediff)
                            fin.seek(codeoffset + codepointer)
                            f.seek(newcodeoffset + codepointer + codediff)
                            sjis, codelen = game.readShiftJIS(
                                fin, False, True, encoding)
                            strreplaced = False
                            if sjis in section or sjis in commonsection:
                                if sjis in commonsection:
                                    newsjis = commonsection[sjis][0]
                                else:
                                    newsjis = section[sjis].pop(0)
                                    if len(section[sjis]) == 0:
                                        del section[sjis]
                                if newsjis != "":
                                    strreplaced = True
                                    newcodelen = game.writeShiftJIS(
                                        f, newsjis, False, True, 0, encoding,
                                        firstgame)
                                    if codelen != newcodelen:
                                        codediff += newcodelen - codelen
                            if not strreplaced:
                                fin.seek(codeoffset + codepointer)
                                f.write(fin.read(codelen))
                    f.writeZero(insize - fin.tell())
                    # Write new header offsets
                    f.seek(4)
                    f.writeUInt(common.shiftPointer(codeoffset, pointerdiff))
                    f.seek(8, 1)
                    f.writeUInt(common.shiftPointer(unk, pointerdiff))
                    f.writeUInt(common.shiftPointer(textoffset, pointerdiff))
                    f.writeUInt(common.shiftPointer(codeoffset2, pointerdiff))
                    # Shift pointers
                    for k, v in pointers.items():
                        f.seek(k)
                        f.writeUInt(common.shiftPointer(v, pointerdiff))
    common.logMessage("Done! Translation is at {0:.2f}%".format(
        (100 * transtot) / chartot))
Esempio n. 16
0
def run():
    infolder = "data/extract_NFP/SPC.NFP/"
    outfolder = "data/work_NFP/SPC.NFP/"
    infile = "data/spc_input.txt"
    infixfile = "data/sprite_fix.txt"
    tablefile = "data/table.txt"
    chartot = transtot = 0

    if not os.path.isfile(infile):
        common.logError("Input file", infile, "not found.")
        return
    common.makeFolder(outfolder)

    common.logMessage("Repacking SPC from", infile, "...")
    common.loadTable(tablefile)
    spritefixf = codecs.open(infixfile, "r", "utf-8")
    with codecs.open(infile, "r", "utf-8") as spc:
        files = common.getFiles(infolder, [".SPC", ".SET"])
        for file in common.showProgress(files):
            section = common.getSection(spc, file, "#", game.fixchars)
            spritefix = common.getSection(spritefixf, file, "#")
            if len(section) == 0 and len(spritefix) == 0:
                common.copyFile(infolder + file, outfolder + file)
                continue
            chartot, transtot = common.getSectionPercentage(
                section, chartot, transtot)
            common.logDebug("Repacking", file, "...")
            codepointers = []
            pointerdiff = {}
            funcpointers = {"MswMess": [], "MswHit": []}
            nextstr = None
            addstr = ""
            last29 = []
            oldstrpos = 0
            f = open(outfolder + file, "wb")
            f.close()
            with common.Stream(outfolder + file, "r+b") as f:
                with common.Stream(infolder + file, "rb") as fin:
                    # Write the header
                    f.writeString("SCRP")
                    fin.seek(4)
                    f.writeUInt(fin.readUInt())
                    f.writeString("CODE")
                    fin.seek(4, 1)
                    codesize = fin.readUInt()
                    f.writeUInt(codesize)
                    f.write(fin.read(6))
                    # Loop the file and shift pointers
                    while fin.tell() < 16 + codesize - 2:
                        pos = fin.tell()
                        byte = fin.readByte()
                        f.writeByte(byte)
                        if byte == 0x10:
                            oldlen = fin.readUShort()
                            fin.seek(-2, 1)
                            strpos = fin.tell()
                            strposf = f.tell()
                            sjis = game.readShiftJIS(fin)
                            if (sjis != "" and sjis
                                    in section) or nextstr is not None:
                                common.logDebug("Found SJIS string at",
                                                strpos + 16)
                                # Check if we have a nextstr to inject instead of using the section
                                if nextstr is None:
                                    newsjis = section[sjis].pop(0)
                                    if len(section[sjis]) == 0:
                                        del section[sjis]
                                    if newsjis == "!":
                                        newsjis = ""
                                        # Center the line
                                        savestrpos = f.tell()
                                        f.seek(oldstrpos - 28)
                                        checkbyte = f.readByte()
                                        if checkbyte == 0x02:
                                            f.seek(-1, 1)
                                            f.writeByte(1)
                                        f.seek(savestrpos)
                                    elif newsjis == "":
                                        newsjis = sjis
                                else:
                                    newsjis = nextstr
                                    nextstr = None
                                # If the string starts with <<, pad it with spaces
                                if newsjis.startswith("<<"):
                                    newsjis = newsjis[2:]
                                    pad = " " * ((20 - len(newsjis)) // 2)
                                    newsjis = pad + newsjis + pad
                                # If the string starts with "[xx]", add mouth flapping
                                if newsjis.startswith(
                                        "[") and newsjis[3] == "]":
                                    flapbyte = newsjis[1:3]
                                    newsjis = newsjis[4:]
                                    flappos = f.tell()
                                    f.seek(strposf - 5)
                                    f.writeByte(int(flapbyte, 16))
                                    f.seek(flappos)
                                # If the string contains a >>, split it and save it for later
                                if newsjis.find(">>") > 0:
                                    splitstr = newsjis.split(">>", 1)
                                    newsjis = splitstr[0]
                                    addstr = splitstr[1]
                                # Check if we have a string after
                                savepos = fin.tell()
                                fin.seek(9, 1)
                                b1 = fin.readByte()
                                b2 = fin.readByte()
                                fin.seek(savepos)
                                if b1 == 0x10 and b2 == 0x01:
                                    nextstr = ""
                                # If the string contains a |, try to turn the string into a 2-lines message
                                if newsjis.find("|") > 0:
                                    splitstr = newsjis.split("|", 1)
                                    newsjis = splitstr[0]
                                    nextstr = splitstr[1]
                                    newsjis = newsjis.replace("|", "<0A>")
                                    # Change the byte 0x1C bytes before the string to 2 if it's 1
                                    checkpos = 28
                                    if newsjis.startswith("FIX("):
                                        splitstr = newsjis.split(")", 1)
                                        newsjis = splitstr[1]
                                        checkpos = int(splitstr[0].replace(
                                            "FIX(", ""))
                                    f.seek(-checkpos, 1)
                                    checkbyte = f.readByte()
                                    if checkbyte == 0x01:
                                        f.seek(-1, 1)
                                        f.writeByte(2)
                                    f.seek(checkpos - 1, 1)
                                # Write the SJIS string
                                newlen = game.writeShiftJIS(f, newsjis)
                                lendiff = newlen - oldlen
                                if lendiff != 0:
                                    common.logDebug("Adding", lendiff, "at",
                                                    strpos)
                                    pointerdiff[strpos - 16] = lendiff
                                fin.seek(1, 1)
                            else:
                                common.logDebug(
                                    "Found ASCII or unaltered string at",
                                    strpos + 16)
                                fixPos = pos - 16
                                # Patch RITT_02 to add Dayakka's missing text
                                if file == "RITT_02.SPC" and fixPos == 1775:
                                    fin.seek(strpos + oldlen + 2)
                                    f.writeUShort(0x09)
                                    f.writeString("APP_DAYA")
                                    f.writeByte(0x00)
                                    pointerdiff[strpos - 16] = 8
                                elif file == "RITT_02.SPC" and fixPos == 1810:
                                    fin.seek(strpos + oldlen + 2)
                                    f.writeUShort(0x09)
                                    f.writeString("DAYA_004")
                                    f.writeByte(0x00)
                                    pointerdiff[strpos - 16] = 8
                                elif file == "RITT_02.SPC" and fixPos == 1845:
                                    fin.seek(strpos + oldlen + 2)
                                    f.writeUShort(0x05)
                                    f.writeString("AWAY")
                                    f.writeByte(0x00)
                                    pointerdiff[strpos - 16] = 4
                                elif file == "SYS_054.SPC" and fixPos == 4233:
                                    fin.seek(strpos + oldlen + 2)
                                    f.writeUShort(0x09)
                                    f.writeString("MSW_C083")
                                    f.writeByte(0x00)
                                else:
                                    fin.seek(strpos + 2)
                                    asciistr = fin.readNullString()
                                    if asciistr in spritefix:
                                        fin.seek(strpos + oldlen + 2)
                                        f.writeUShort(0x08)
                                        f.writeString(spritefix[asciistr][0])
                                        f.writeByte(0x00)
                                    else:
                                        fin.seek(strpos)
                                        f.write(fin.read(oldlen + 2))
                            f.write(fin.read(2))
                            pointer = fin.readUInt()
                            f.writeUInt(
                                common.shiftPointer(pointer, pointerdiff))
                            # Check if we have an addstr
                            if addstr != "" and nextstr is None:
                                addstrsplit = addstr.split(">>")
                                for addstr in addstrsplit:
                                    strsplit = addstr.split("|")
                                    startpointer = f.tell()
                                    startpointeri = fin.tell()
                                    f.writeByte(0x28)
                                    f.writeByte(0x00)
                                    funcpointers["MswMess"].append(f.tell() -
                                                                   16)
                                    f.writeByte(0x29)
                                    f.writeUInt(0x03)
                                    f.writeByte(0x80)
                                    f.writeUInt(0x00)
                                    f.writeByte(0x2A)
                                    f.writeByte(0x00)
                                    f.writeByte(0x31)
                                    f.writeByte(0x0F)
                                    f.writeUInt(0x0C)
                                    f.writeByte(0x29)
                                    f.writeUInt(0x00)
                                    funcpointers["MswHit"].append(f.tell() -
                                                                  16)
                                    f.writeByte(0x29)
                                    f.writeUInt(0x01)
                                    f.writeByte(0x80)
                                    f.writeUInt(0x00)
                                    f.writeByte(0x2A)
                                    f.writeByte(0x00)
                                    f.writeByte(0x31)
                                    f.writeByte(0x0F)
                                    f.writeUInt(0x04)
                                    f.writeByte(0x29)
                                    f.writeUInt(last29[len(last29) - 1])
                                    f.writeByte(0x10)
                                    strpointer = f.tell()
                                    game.writeShiftJIS(f, strsplit[0])
                                    f.writeByte(0x22)
                                    f.writeByte(0x00)
                                    f.writeUInt(strpointer - 16 - 4)
                                    f.writeByte(0x28)
                                    f.writeByte(0x00)
                                    f.writeByte(0x10)
                                    strpointer2 = f.tell()
                                    game.writeShiftJIS(
                                        f, strsplit[1]
                                        if len(strsplit) == 2 else "")
                                    f.writeByte(0x22)
                                    f.writeByte(0x00)
                                    f.writeUInt(strpointer2 - 16 - 4)
                                    endpointer = f.tell()
                                    common.logDebug("Adding new str",
                                                    endpointer - startpointer,
                                                    "at", startpointeri)
                                    if startpointeri - 16 not in pointerdiff:
                                        pointerdiff[startpointeri - 16] = 0
                                    pointerdiff[
                                        startpointeri -
                                        16] += endpointer - startpointer
                                addstr = ""
                            oldstrpos = strposf
                        elif byte == 0x15:
                            f.write(fin.read(1))
                            bytelen = fin.readByte()
                            f.writeByte(bytelen)
                            for i in range(bytelen):
                                f.write(fin.read(4))
                                codepointers.append(f.tell())
                                f.write(fin.read(4))
                        elif byte in game.spccodes:
                            if byte == 0x11:
                                codepointers.append(f.tell())
                            elif byte == 0x12:
                                codepointers.append(f.tell() + 1)
                            elif byte == 0x29:
                                last29.append(fin.readUInt())
                                fin.seek(-4, 1)
                            # Patch SYS_046/7 and fix the disappearing cut-in sprites
                            fixPos = pos - 16
                            if (file == "SYS_046.SPC" and byte == 0x29
                                    and fixPos
                                    in [9660, 11356, 11915, 13108, 13646]) or (
                                        file == "SYS_047.SPC" and byte == 0x29
                                        and fixPos == 1607):
                                f.writeUInt(0x0A)
                                fin.seek(4, 1)
                            else:
                                f.write(fin.read(game.spccodes[byte]))
                        common.logDebug("Unknown byte", common.toHex(byte),
                                        "at", pos)
                    f.writeByte(0x8F)
                    f.writeByte(0x00)
                    f.writeByte(0x00)
                    endpos = f.tell()
                    # Shift the other code pointers
                    for codepointer in codepointers:
                        f.seek(codepointer)
                        pointer = f.readUInt()
                        f.seek(-4, 1)
                        f.writeUInt(common.shiftPointer(pointer, pointerdiff))
                    # Write the code section size in the header
                    f.seek(12)
                    f.writeUInt(endpos - 16)
                    f.seek(endpos)
                    # Function section
                    fin.seek(codesize + 16)
                    f.writeString("FUNC")
                    fin.seek(4, 1)
                    funcsize = fin.readUInt()
                    f.writeUInt(funcsize)
                    # Copy the function section while shifting pointers
                    common.logDebug(str(funcpointers))
                    while True:
                        # Read the function name
                        function = fin.readNullString()
                        if function == "":
                            break
                        f.writeString(function)
                        f.writeZero(1)
                        common.logDebug("Found function:", function)
                        # Read the pointers until we find 0
                        while True:
                            pointer = fin.readUInt()
                            if pointer == 0:
                                f.writeUInt(0)
                                break
                            else:
                                pointer = common.shiftPointer(
                                    pointer, pointerdiff)
                                if function in funcpointers and len(
                                        funcpointers[function]) > 0:
                                    for newpointer in funcpointers[function]:
                                        common.logDebug(
                                            function, "new:", newpointer,
                                            "poi:", pointer)
                                        if pointer > newpointer:
                                            f.writeUInt(newpointer)
                                            funcpointers[function].remove(
                                                newpointer)
                                f.writeUInt(pointer)
                    f.writeZero(1)
                    # Write the file size in the header
                    pos = f.tell()
                    f.seek(4)
                    f.writeUInt(pos - 4)
                    f.seek(pos)
                    # Write TERM and pad with 0s
                    f.writeString("TERM")
                    f.writeZero(16 - (f.tell() % 16))
    common.logMessage("Done! Translation is at {0:.2f}%".format(
        (100 * transtot) / chartot))
Esempio n. 17
0
def extract(rom, bin, tdg, kpc, spc, vsc, yce):
    all = not rom and not bin and not tdg and not kpc and not spc and not vsc and not yce
    if all or rom:
        nds.extractRom(romfile, infolder, outfolder)
        # Extract NFP archives
        nfpin = "data/extract/data/"
        nfpout = "data/extract_NFP/"
        nfpwork = "data/work_NFP/"
        common.logMessage("Extracting NFP ...")
        common.makeFolder(nfpout)
        files = common.getFiles(nfpin, ".NFP")
        for file in common.showProgress(files):
            common.logDebug("Processing", file, "...")
            common.makeFolder(nfpout + file)
            with common.Stream(nfpin + file, "rb") as f:
                f.seek(52)  # Header: NFP2.0 (c)NOBORI 1997-2006
                filenum = f.readInt()
                f.seek(4, 1)  # Always 0x50
                datastart = f.readInt()
                f.seek(16, 1)  # All 0
                common.logDebug("Found", filenum, "files, data starting at",
                                datastart)
                for i in range(filenum):
                    # Filenames are always 16 bytes long, padded with 0s
                    subname = f.readString(16)
                    # Read starting position and size (multiplied by 4)
                    startpos = f.readInt()
                    size = f.readInt() // 4
                    # Extract the file
                    common.logDebug("Extracting", subname, "starting at",
                                    startpos, "with size", size)
                    savepos = f.tell()
                    f.seek(startpos)
                    with common.Stream(nfpout + file + "/" + subname,
                                       "wb") as newf:
                        newf.write(f.read(size))
                    f.seek(savepos)
        # Copy everything to the work folder
        common.copyFolder(nfpout, nfpwork)
        common.logMessage("Done! Extracted", len(files), "archives")
    if all or bin:
        import extract_bin
        extract_bin.run()
    if all or tdg:
        nitro.extractNSBMD("data/extract_NFP/NFP3D.NFP/", "data/out_3DG/",
                           ".3DG")
    if all or kpc:
        import extract_kpc
        extract_kpc.run()
    if all or spc:
        import extract_spc
        extract_spc.run()
    if all or vsc:
        import extract_vsc
        extract_vsc.run()
    if all or yce:
        for i in range(1, 8):
            common.copyFile(
                "data/extract_NFP/NFP2D.NFP/AV01_0" + str(i) + ".YCE",
                "data/extract_NFP/NFP2D.NFP/AV00_0" + str(i) + ".YCE")
        import extract_yce
        extract_yce.run()
Esempio n. 18
0
def run():
    infolder = "data/extract_NFP/NFP2D.NFP/"
    workfolder = "data/work_KPC/"
    outfolder = "data/work_NFP/NFP2D.NFP/"
    common.copyFolder(infolder, outfolder)

    common.logMessage("Repacking KPC from", workfolder, "...")
    files = common.getFiles(infolder, ".KPC")
    for file in common.showProgress(files):
        pngname = file.replace(".KPC", ".png")
        if not os.path.isfile(workfolder + pngname):
            common.copyFile(infolder + file, outfolder + file)
            continue
        common.logDebug("Processing", file, "...")
        with common.Stream(infolder + file, "rb") as fin:
            with common.Stream(outfolder + file, "wb") as f:
                # Find palette offset
                fin.seek(9)
                palcompressed = fin.readByte() == 1
                fin.seek(2, 1)
                width = fin.readUShort() * 8
                height = fin.readUShort() * 8
                fin.seek(128)
                palsize = fin.readUInt()
                paloffset = fin.readUInt()
                # Read palette
                fin.seek(paloffset)
                if palcompressed:
                    paldata = common.decompress(fin, palsize)
                else:
                    paldata = fin.read(palsize)
                # Fix transparency for EQ_M0* files since their palette colors 0 and 1 are the same.
                tiles, maps = game.readMappedImage(workfolder + pngname, width,
                                                   height, paldata,
                                                   file.startswith("EQ_M0"))
                # Copy the header
                fin.seek(0)
                f.write(fin.read(192))
                # Write map data
                mapstart = f.tell()
                for map in maps:
                    mapdata = (map[0] << 12) + (map[1] << 11) + (
                        map[2] << 10) + map[3]
                    f.writeUShort(mapdata)
                mapend = f.tell()
                f.writeByte(0)
                # Write tile data
                tilestart = f.tell()
                for tile in tiles:
                    for i in range(32):
                        index2 = tile[i * 2]
                        index1 = tile[i * 2 + 1]
                        f.writeByte(((index1) << 4) | index2)
                tileend = f.tell()
                f.writeByte(0)
                # Write palette
                palstart = f.tell()
                f.write(paldata)
                palend = f.tell()
                f.writeByte(0)
                # Write header data
                f.seek(9)
                f.writeByte(0)
                f.writeByte(0)
                f.writeByte(0)
                f.seek(16)
                f.writeUInt(mapend - mapstart)
                f.writeUInt(mapstart)
                f.seek(92)
                f.writeUInt(tileend - tilestart)
                f.writeUInt(tilestart)
                f.seek(128)
                f.writeUInt(palend - palstart)
                f.writeUInt(palstart)
    common.logMessage("Done!")
Esempio n. 19
0
def run():
    infolder = "data/extract/data/Rom/event/script/"
    outfolder = "data/repack/data/Rom/event/script/"
    infile = "data/cnut_input.txt"
    fontfile = "data/repack/data/Rom/font/font0.NFTR"
    replacefontfile = "data/replace/data/Rom/font/font0.NFTR"
    chartot = transtot = 0

    if not os.path.isfile(infile):
        common.logError("Input file", infile, "not found")
        return

    common.logMessage("Repacking CNUT from", infile, "...")
    if os.path.isfile(replacefontfile):
        glyphs = nitro.readNFTR(replacefontfile).glyphs
    else:
        glyphs = nitro.readNFTR(fontfile).glyphs
    with codecs.open(infile, "r", "utf-8") as cnut:
        files = common.getFiles(infolder, ".cnut")
        for file in common.showProgress(files):
            section = common.getSection(cnut, file, "//")
            if len(section) == 0:
                common.makeFolders(outfolder + file)
                common.copyFile(infolder + file, outfolder + file)
                continue
            chartot, transtot = common.getSectionPercentage(
                section, chartot, transtot)
            # Repack the file
            common.logDebug("Processing", file, "...")
            size = os.path.getsize(infolder + file)
            lastpos = 0
            with common.Stream(infolder + file, "rb") as fin:
                common.makeFolders(infolder + file)
                with common.Stream(outfolder + file, "wb") as f:
                    while fin.tell() < size - 4:
                        pos = fin.tell()
                        b1 = fin.readByte()
                        b2 = fin.readByte()
                        b3 = fin.readByte()
                        b4 = fin.readByte()
                        if b1 == 0x10 and b2 == 0x00 and b3 == 0x00 and b4 == 0x08:
                            # Found a string
                            check = game.readShiftJIS(fin)
                            pre = post = ""
                            # Add back some codes that are removed from extracted lines
                            if check.startswith("#CLR()"):
                                pre = "#CLR()"
                                check = check[6:]
                            if check.startswith("#ARW("):
                                pre += check[:7]
                                check = check[7:]
                            if check.endswith("#INP()"):
                                post = "#INP()"
                                check = check[:-6]
                            # Check if the line is translated and replace it
                            if check in section:
                                newsjis = section[check].pop(0)
                                if len(section[check]) == 0:
                                    del section[check]
                                if newsjis != "":
                                    newsjis = pre + newsjis + post
                                    if newsjis != check:
                                        newsjis = common.wordwrap(
                                            newsjis, glyphs, 205,
                                            game.detectTextCode)
                                        newsjis = newsjis.replace(
                                            ">>", "#INP()" + pre).replace(
                                                "|", "<0A>")
                                        # Copy data up to here
                                        endpos = fin.tell()
                                        fin.seek(lastpos)
                                        f.write(fin.read(pos + 4 - lastpos))
                                        lastpos = endpos
                                        common.logDebug("  Repacking at", pos)
                                        game.writeShiftJIS(f, newsjis)
                        else:
                            fin.seek(pos + 1)
                    fin.seek(lastpos)
                    f.write(fin.read(size - lastpos))
    common.logMessage("Done! Translation is at {0:.2f}%".format(
        (100 * transtot) / chartot))
Esempio n. 20
0
def run(firstgame, analyzefile):
    infolder = "data/extract/data/script/"
    outfile = "data/wsb_output.txt"
    commonfile = "data/common.txt"
    analyzeout = "data/wsb_analysis.txt"

    commonstr = {}
    # Read common strings from another file
    if os.path.isfile(commonfile):
        with codecs.open(commonfile, "r", "utf-8") as commonf:
            commonstr = common.getSection(commonf, "COMMON")
    encoding = "shift_jis" if firstgame else "shift_jisx0213"
    common.logMessage("Extracting WSB to", outfile, "...")
    with codecs.open(analyzeout, "w", "utf-8") as a:
        with codecs.open(outfile, "w", "utf-8") as out:
            if len(commonstr) > 0:
                out.write("!FILE:COMMON\n")
                for s in commonstr:
                    out.write(s + "=\n")
            files = common.getFiles(infolder, ".wsb")
            for file in common.showProgress(files):
                analyze = analyzefile != "" and file.endswith(analyzefile)
                if analyzefile != "" and not analyze:
                    continue
                first = True
                common.logDebug("Processing", file, "...")
                with common.Stream(infolder + file, "rb") as f:
                    f.seek(4)  # 0x10
                    codeoffset = f.readUInt()
                    f.seek(8, 1)  # all 0xFF
                    unk = f.readUInt()
                    textoffset = f.readUInt()
                    codeoffset2 = f.readUInt()
                    common.logDebug("codeoffset:", codeoffset, "unk:", unk,
                                    "textoffset:", textoffset, "codeoffset2:",
                                    codeoffset2)
                    f.seek(4, 1)
                    # Parse the various code blocks while looking for strings
                    while f.tell() < codeoffset:
                        pos = f.tell()
                        b1 = f.readByte()
                        b2 = f.readByte()
                        if (b1 == 0x55 and b2 == 0x08) or (b1 == 0x95
                                                           and b2 == 0x10):
                            # Found a string pointer
                            if analyze:
                                lenline = f.readBytes(4 if b1 == 0x95 else 2)
                                f.seek(-(4 if b1 == 0x95 else 2), 1)
                            sjis, strlen = game.readShiftJIS(
                                f, b1 == 0x95, False, encoding)
                            if sjis != "" and sjis != ">>" and sjis != " ":
                                sjissplit = sjis.split(">>")
                                for sjisline in sjissplit:
                                    if sjisline != "" and sjisline != " " and sjisline not in commonstr:
                                        if first:
                                            out.write("!FILE:" + file + "\n")
                                            first = False
                                        out.write(sjisline + "=\n")
                            if analyze:
                                # Try to calculate the length to check if the calculation is correct
                                addlen = ""
                                with common.Stream() as test:
                                    game.writeShiftJIS(test, sjis, b1 == 0x95,
                                                       False, 0, encoding,
                                                       firstgame)
                                    testlen = test.tell()
                                    test.seek(0)
                                    addlen = test.readBytes(4 if b1 ==
                                                            0x95 else 2)
                                    if lenline != addlen:
                                        test.seek(0)
                                        addlen += "\nDIFF\n" + test.readBytes(
                                            testlen) + "\n"
                                        fpos = f.tell()
                                        f.seek(pos + 2)
                                        addlen += f.readBytes(fpos - f.tell())
                                writeLine(a, pos, b1, b2,
                                          lenline + sjis + " " + addlen)
                        elif (b1, b2) in game.wsbcodes:
                            if analyze:
                                ptrstr = ""
                                if (b1, b2) in game.wsbpointers:
                                    ptrstr += "ptr"
                                writeLine(
                                    a, pos, b1, b2,
                                    f.readBytes(game.wsbcodes[(b1, b2)]) +
                                    ptrstr)
                            else:
                                f.seek(game.wsbcodes[(b1, b2)], 1)
                        else:
                            if analyze:
                                writeLine(a, pos, b1, b2, "Unknown!")
                    if codeoffset > 0:
                        codenum = f.readUInt()
                        for i in range(codenum):
                            f.seek(codeoffset + 4 + 4 * i)
                            codepointer = f.readUInt()
                            f.seek(codeoffset + codepointer)
                            sjis, codelen = game.readShiftJIS(
                                f, False, True, encoding)
                            # Ignore ASCII strings and a particular debug line found in every file
                            if not common.isAscii(sjis) and sjis.find(
                                    "%d, %d") < 0 and sjis not in commonstr:
                                if first:
                                    out.write("!FILE:" + file + "\n")
                                    first = False
                                out.write(sjis + "=\n")
                            if analyze:
                                writeLine(a, i, 0, 0,
                                          str(codepointer) + " " + sjis)
    common.logMessage("Done! Extracted", len(files), "files")
Esempio n. 21
0
def run(firstgame, no_redirect):
    infolder = "data/extract/data/data/"
    outfolder = "data/repack/data/data/"
    infile = "data/dat_input.txt"
    redfile = "data/redirects.asm"
    fontfile = "data/replace/data/font/lcfont12.NFTR"
    if not os.path.isfile(infile):
        common.logError("Input file", infile, "not found")
        return
    common.makeFolder(outfolder)
    chartot = transtot = 0
    monthsection, skipsection = game.monthsection, game.skipsection
    game.monthsection = game.skipsection = None

    encoding = "shift_jis" if firstgame else "shift_jisx0213"
    common.logMessage("Repacking DAT from", infile, "...")
    # Read the glyph size from the font
    if not os.path.isfile(fontfile):
        fontfile = fontfile.replace("replace/", "extract/")
    glyphs = nitro.readNFTR(fontfile).glyphs
    fixchars = game.getFixChars()
    # Copy this txt file
    if not firstgame and os.path.isfile(infolder + "facilityhelp.txt"):
        common.copyFile(infolder + "facilityhelp.txt",
                        outfolder + "facilityhelp.txt")
    redirects = []
    with codecs.open(infile, "r", "utf-8") as dat:
        files = common.getFiles(infolder, ".dat")
        for file in common.showProgress(files):
            section = common.getSection(dat, file, fixchars=fixchars)
            # If there are no lines, just copy the file
            if len(section) == 0:
                common.copyFile(infolder + file, outfolder + file)
                # Part of the AP patch
                if not firstgame and file == "route.dat":
                    with common.Stream(outfolder + file, "rb+") as f:
                        f.seek(0x5ee8)
                        f.writeByte(0x0)
                continue
            i = 0
            chartot, transtot = common.getSectionPercentage(
                section, chartot, transtot)
            common.logDebug("Processing", file, "...")
            size = os.path.getsize(infolder + file)
            with common.Stream(infolder + file, "rb") as fin:
                with common.Stream(outfolder + file, "wb") as f:
                    f.write(fin.read())
                    fin.seek(0)
                    # Loop the file and replace strings as needed
                    while fin.tell() < size - 2:
                        pos = fin.tell()
                        check = game.detectShiftJIS(fin, encoding)
                        if check != "":
                            if file == "entrance_icon.dat":
                                # For entrance_icon, just write the string and update the pointer
                                if check in section:
                                    # For the first one, seek to the correct position in the output file
                                    if i == 0:
                                        f.seek(pos)
                                    # Write the string
                                    newsjis = check
                                    if check in section and section[check][
                                            0] != "":
                                        common.logDebug(
                                            "Replacing string at", pos)
                                        newsjis = section[check][0]
                                    startpos = f.tell()
                                    game.writeShiftJIS(f, newsjis, False, True,
                                                       0, encoding)
                                    endpos = f.tell()
                                    # Update the pointer
                                    f.seek(0x1c98 + 4 * i)
                                    f.writeUInt(startpos - 0x1c98)
                                    f.seek(endpos)
                                    i += 1
                            else:
                                # Found a SJIS string, check if we have to replace it
                                if check in section and section[check][0] != "":
                                    common.logDebug("Replacing string at", pos)
                                    f.seek(pos)
                                    newsjis = section[check][0]
                                    maxlen = 0
                                    if file == "goods.dat":
                                        newsjis = common.wordwrap(
                                            newsjis, glyphs, 170)
                                        maxlen = 60
                                    elif file == "gossip.dat":
                                        newsjis = common.wordwrap(
                                            newsjis, glyphs, 190)
                                        if newsjis.count("<<") > 0:
                                            newsjis = common.centerLines(
                                                newsjis,
                                                glyphs,
                                                190,
                                                centercode="<<")
                                        if fin.tell() - pos < 35:
                                            maxlen = 35
                                        else:
                                            maxlen = 160
                                    elif file == "scenarioguide.dat":
                                        newsjis = common.wordwrap(
                                            newsjis, glyphs, 165)
                                        maxlen = 60
                                        if newsjis.count("|") > 1:
                                            common.logError(
                                                "scenarioguide line", newsjis,
                                                "too long")
                                    newlen = game.writeShiftJIS(
                                        f, newsjis, False, True, maxlen,
                                        encoding)
                                    if newlen < 0:
                                        if file != "gossip.dat" or no_redirect or maxlen != 160:
                                            common.logError(
                                                "String {} is too long ({}/{})."
                                                .format(
                                                    newsjis, len(newsjis),
                                                    maxlen))
                                        else:
                                            common.logWarning(
                                                "String {} is too long ({}/{})."
                                                .format(
                                                    newsjis, len(newsjis),
                                                    maxlen))
                                            # Doesn't fit, write it shorter
                                            f.seek(pos)
                                            cutat = 155 if firstgame else 150
                                            while ord(newsjis[cutat]) > 127:
                                                cutat -= 1
                                            stringfit = newsjis[:cutat]
                                            stringrest = newsjis[cutat:]
                                            game.writeShiftJIS(
                                                f, stringfit, False, True,
                                                maxlen, encoding)
                                            f.seek(-1, 1)
                                            f.writeByte(0x1f)
                                            f.writeByte(len(redirects))
                                            redirects.append(stringrest)
                                    # Pad with 0s if the line is shorter
                                    while f.tell() < fin.tell():
                                        f.writeByte(0x00)
                            pos = fin.tell() - 1
                        fin.seek(pos + 1)
    with codecs.open(redfile, "w", "utf-8") as f:
        f.write(".ascii \"NDSC\"\n\n")
        f.write("REDIRECT_START:\n\n")
        for i in range(len(redirects)):
            f.write(".dh REDIRECT_{} - REDIRECT_START\n".format(i))
        for i in range(len(redirects)):
            f.write("\nREDIRECT_{}:\n".format(i))
            redirect = redirects[i].replace("\"", "\\\"")
            redirect = redirect.replace("|", "\" :: .db 0xa :: .ascii \"")
            redirectascii = ""
            for c in redirect:
                if ord(c) > 127:
                    sjisc = common.toHex(
                        int.from_bytes(c.encode(encoding), "big"))
                    redirectascii += "\" :: .db 0x" + sjisc[:2] + " :: .db 0x" + sjisc[
                        2:] + " :: .ascii \""
                else:
                    redirectascii += c
            f.write(".ascii \"{}\" :: .db 0\n".format(redirectascii))
    game.monthsection, game.skipsection = monthsection, skipsection
    common.logMessage("Done! Translation is at {0:.2f}%".format(
        (100 * transtot) / chartot))
Esempio n. 22
0
def run():
    infolder = "data/extract_NFP/NFP2D.NFP/"
    outfolder = "data/out_KPC/"
    common.makeFolder(outfolder)

    common.logMessage("Extracting KPC to", outfolder, "...")
    files = common.getFiles(infolder, ".KPC")
    for file in common.showProgress(files):
        common.logDebug("Processing", file, "...")
        with common.Stream(infolder + file, "rb") as f:
            # Read header
            f.seek(4)
            bits = []
            for i in range(5):
                bits.append(f.readByte())
            palcompressed = f.readByte() == 1
            mapcompressed = f.readByte() == 1
            tilecompressed = f.readByte() == 1
            width = f.readUShort() * 8
            height = f.readUShort() * 8
            mapsize = f.readUInt()
            mapoffset = f.readUInt()
            f.seek(5, 1)
            bpp = 8 if f.readUShort() == 1 else 4
            f.seek(92)
            tilesize = f.readUInt()
            tileoffset = f.readUInt()
            f.seek(124)
            unk = f.readUInt()
            palsize = f.readUInt()
            paloffset = f.readUInt()
            common.logDebug("width:", width, "height:", height, "bpp:", bpp)
            common.logDebug("mapsize:", mapsize, "mapoffset:", mapoffset)
            common.logDebug("tilesize:", tilesize, "tileoffset:", tileoffset)
            common.logDebug("palsize:", palsize, "paloffset:", paloffset)
            common.logDebug("palcompressed:", palcompressed, "mapcompressed:",
                            mapcompressed, "tilecompressed:", tilecompressed)
            common.logDebug("bits:", bits, "unk:", unk)
            # Read palette
            f.seek(paloffset)
            if palcompressed:
                paldata = nds.decompress(f, palsize)
            else:
                paldata = f.read(palsize)
            # Read map data
            f.seek(mapoffset)
            if mapcompressed:
                mapdata = nds.decompress(f, mapsize)
            else:
                mapdata = f.read(mapsize)
            # Read tile data
            f.seek(tileoffset)
            if tilecompressed:
                tiledata = nds.decompress(f, tilesize)
            else:
                tiledata = f.read(tilesize)
            # Draw the image
            img = game.drawMappedImage(width, height, mapdata, tiledata,
                                       paldata, 8, bpp)
            img.save(outfolder + file.replace(".KPC", ".png"), "PNG")
    common.logMessage("Done! Extracted", len(files), "files")
Esempio n. 23
0
def run(data, processed):
    infolder = data + ("extract/" if not processed else "repack/")
    files = ["bank_11.bin", "bank_12.bin"]
    outfile = data + "analyze_output.txt"
    with codecs.open(data + "table_input.txt", "r", "utf-8") as tablef:
        table = common.getSection(tablef, "")
    invtable = {}
    with codecs.open(data + "table.txt", "r", "utf-8") as tablef:
        convtable = common.getSection(tablef, "")
        for char in convtable:
            invtable[int(convtable[char][0], 16)] = char

    with codecs.open(outfile, "w", "utf-8") as out:
        for file in common.showProgress(files):
            common.logMessage("Processing", file, "...")
            out.write("!FILE:" + file + "\n")
            size = os.path.getsize(infolder + file)
            with common.Stream(infolder + file, "rb") as f:
                while f.tell() < size - 1:
                    pos = f.tell()
                    opcode = f.readByte()
                    if opcode in game.opcodes and game.opcodes[opcode] != -1:
                        addline = ""
                        if opcode in game.ptropcodes:
                            addline = " Pointer: " + repr(
                                game.ptropcodes[opcode])
                        if opcode == 0x0a:
                            if processed:
                                common.logDebug("Failing at",
                                                common.toHex(pos))
                                writeLine(
                                    out, pos, opcode,
                                    game.readString(f,
                                                    table,
                                                    processed=invtable))
                            else:
                                writeLine(out, pos, opcode,
                                          game.readString(f, table))
                        elif opcode in game.repopcodes:
                            readbytes = ""
                            replen = 0
                            while True:
                                byte = f.readBytes(1)
                                readbytes += byte
                                replen += 1
                                if byte == "FF " and (opcode
                                                      not in game.ptropcodes
                                                      or replen > 2):
                                    break
                            writeLine(out, pos, opcode, readbytes + addline)
                        else:
                            writeLine(
                                out, pos, opcode,
                                f.readBytes(game.opcodes[opcode]) + addline)
                            if opcode == 0xff:
                                out.write("\n")
                                check = f.readUInt()
                                check2 = f.readUInt()
                                f.seek(-8, 1)
                                if check == 0xffffffff and check2 == 0xffffffff:
                                    break
                    else:
                        common.logError("Uknown opcode", common.toHex(opcode),
                                        "at", common.toHex(pos))
                        writeLine(out, pos, opcode, "Unknown")
            out.write("\n\n")
        common.logMessage("Done! Extracted", len(files), "files")
Esempio n. 24
0
def run():
    infolder = "data/extract_NFP/NFP2D.NFP/"
    workfolder = "data/work_VSC/"
    outfolder = "data/work_NFP/NFP2D.NFP/"

    common.logMessage("Repacking VSC from", workfolder, "...")
    files = common.getFiles(infolder, ".VSC")
    for file in common.showProgress(files):
        pngname = file.replace(".VSC", ".png")
        if not os.path.isfile(workfolder + pngname):
            common.copyFile(infolder + file, outfolder + file)
            continue
        common.logDebug("Processing", file, "...")
        with common.Stream(infolder + file, "rb") as fin:
            with common.Stream(outfolder + file, "wb") as f:
                # Read header
                fin.seek(16)
                bpp = 4 if fin.readUInt() == 1 else 8
                width = fin.readUInt()
                height = fin.readUInt()
                fin.seek(4, 1)
                mapsize = fin.readUInt()
                fin.seek(4, 1)
                tilesize = fin.readUInt()
                mapdata = fin.read(mapsize)
                fin.seek(tilesize, 1)
                fin.seek(24, 1)
                palnum = fin.readUShort()
                fin.seek(4, 1)
                paloffset = fin.tell()
                paldata = fin.read(palnum * 32)
                tiles, maps = game.readMappedImage(workfolder + pngname, width,
                                                   height, paldata)
                # Copy the header
                fin.seek(0)
                f.write(fin.read(44))
                # Write map data
                mapstart = f.tell()
                for map in maps:
                    mapdata = (map[0] << 12) + (map[1] << 11) + (
                        map[2] << 10) + map[3]
                    f.writeUShort(mapdata)
                mapend = f.tell()
                # Write tile data
                tilestart = f.tell()
                for tile in tiles:
                    for i in range(32 if bpp == 4 else 64):
                        if bpp == 8:
                            f.writeByte(tile[i])
                        else:
                            index2 = tile[i * 2]
                            index1 = tile[i * 2 + 1]
                            f.writeByte(((index1) << 4) | index2)
                tileend = f.tell()
                # Copy the palette
                fin.seek(paloffset - 30)
                f.write(fin.read(30 + palnum * 32))
                palend = f.tell()
                f.writeZero(16 - palend % 16)
                # Write the new header data
                f.seek(8)
                f.writeUInt(palend)
                f.seek(36)
                f.writeUInt(mapend - mapstart)
                f.writeUInt(tileend - tilestart)
    common.logMessage("Done!")
Esempio n. 25
0
def run(data):
    infolder = data + "extract/"
    outfolder = data + "repack/"
    files = ["bank_11.bin", "bank_12.bin"]
    binfile = outfolder + "bank_14.bin"
    debugfile = outfolder + "bank_1e.bin"
    infile = data + "script_input.txt"
    chartot = transtot = 0
    table, invtable, ccodes, glyphs = game.getFontData(data)

    if not os.path.isfile(infile):
        common.logError("Input file", infile, "not found")
        return

    pointers = {}
    pointerdiff = {}
    common.logMessage("Repacking script from", infile, "...")
    with codecs.open(infile, "r", "utf-8") as script:
        for file in common.showProgress(files):
            section = common.getSection(script, file)
            pointers[file] = []
            pointerdiff[file] = {}
            if len(section) == 0:
                continue
            chartot, transtot = common.getSectionPercentage(
                section, chartot, transtot)
            # Repack the file
            common.logMessage("Processing", file, "...")
            size = os.path.getsize(infolder + file)
            with common.Stream(infolder + file, "rb") as fin:
                with common.Stream(outfolder + file, "wb") as f:
                    while fin.tell() < size:
                        opcode = fin.readByte()
                        if opcode == 0x0a:
                            f.writeByte(opcode)
                            strpos2 = f.tell()
                            strpos = fin.tell()
                            readstr = game.readString(fin, table)
                            newstr = ""
                            if readstr != "":
                                addend = ""
                                if readstr[-2:] == ">>":
                                    addend = ">>"
                                    readstr = readstr[:-2]
                                if readstr in section:
                                    newstr = section[readstr].pop(0)
                                    if len(section[readstr]) == 0:
                                        del section[readstr]
                            strend = fin.tell()
                            if newstr != "":
                                newstr = common.wordwrap(
                                    newstr, glyphs, game.wordwrap,
                                    game.detectTextCode)
                                if newstr == "!":
                                    newstr = ""
                                newstr += addend
                                common.logDebug("Writing string at",
                                                common.toHex(strpos),
                                                common.toHex(strpos2), newstr)
                                game.writeString(f, newstr, invtable, ccodes)
                                f.writeUShort(0xffff)
                                strend2 = f.tell()
                                lendiff = (strend2 - strpos2) - (strend -
                                                                 strpos)
                                if lendiff != 0:
                                    common.logDebug("Adding", lendiff, "at",
                                                    common.toHex(strpos))
                                    pointerdiff[file][strpos + 1] = lendiff
                            else:
                                fin.seek(strpos)
                                f.write(fin.read(strend - strpos))
                        elif opcode in game.repopcodes:
                            if opcode in game.ptropcodes:
                                pointers[file].append(f.tell())
                            f.writeByte(opcode)
                            replen = 0
                            while True:
                                loopbyte = fin.readByte()
                                f.writeByte(loopbyte)
                                replen += 1
                                if loopbyte == 0xff and (opcode
                                                         not in game.ptropcodes
                                                         or replen > 2):
                                    break
                        else:
                            if opcode in game.ptropcodes:
                                pointers[file].append(f.tell())
                            f.writeByte(opcode)
                            f.write(fin.read(game.opcodes[opcode]))
                            if opcode == 0xff:
                                check = fin.readUInt()
                                check2 = fin.readUInt()
                                fin.seek(-8, 1)
                                if check == 0xffffffff and check2 == 0xffffffff:
                                    break
                    # Pad with 0xffff
                    f.writeBytes(0xff, 0xffff - f.tell() + 1)
    common.logMessage("Shifting script pointers ...")
    for file in common.showProgress(files):
        with common.Stream(outfolder + file, "rb+") as f:
            for pointerpos in pointers[file]:
                f.seek(pointerpos)
                opcode = f.readByte()
                for pointeroff in game.ptropcodes[opcode]:
                    pointerfile = file
                    if type(pointeroff) == tuple:
                        f.seek(pointerpos + 1 + pointeroff[1])
                        bankid = f.readUShort()
                        pointerfile = files[0] if bankid == 0x00f1 else files[1]
                        pointeroff = pointeroff[0]
                    f.seek(pointerpos + 1 + pointeroff)
                    pointer = f.readUShort()
                    if pointer != 0xffff:
                        newpointer = common.shiftPointer(
                            pointer, pointerdiff[pointerfile])
                    else:
                        newpointer = pointer
                    f.seek(-2, 1)
                    f.writeUShort(newpointer)
    common.logMessage("Shifting bin pointers ...")
    # Read pointer tables in the bin file
    with common.Stream(binfile.replace("/repack/", "/extract/"), "rb+") as f:
        f.seek(0x23b0)
        while f.tell() < 0x2740:
            pos1 = f.tell()
            ptr1 = f.readUShort()
            bank1 = f.readUShort()
            pos2 = f.tell()
            ptr2 = f.readUShort()
            bank2 = f.readUShort()
            game.binptrs.append((pos1, ptr1, bank1))
            game.binptrs.append((pos2, ptr2, bank2))
            f.seek(8, 1)
        for binrange in [(0x2ff7, 0x3027), (0x3063, 0x309b), (0x480f, 0x481f),
                         (0x496b, 0x499b), (0x4a01, 0x4a39)]:
            f.seek(binrange[0])
            while f.tell() < binrange[1]:
                pos = f.tell()
                ptr = f.readUShort()
                bank = f.readUShort()
                game.binptrs.append((pos, ptr, bank))
        f.seek(0x902e)
        while f.tell() < 0x9106:
            pos = f.tell()
            ptr = f.readUShort()
            game.binptrs.append((pos, ptr, 0xf2))
    game.binptrs.append((0x26b8, 0x3d7b, 0xf2))
    shiftPointers(binfile, game.binptrs, pointerdiff)
    # Shift debug pointers
    debugptrs = []
    with common.Stream(debugfile.replace("/repack/", "/extract/"), "rb+") as f:
        f.seek(0xcd92)
        while f.tell() < 0xd420:
            pos1 = f.tell()
            ptr1 = f.readUShort()
            bank1 = f.readUShort()
            debugptrs.append((pos1, ptr1, bank1))
            f.seek(12, 1)
    shiftPointers(debugfile, debugptrs, pointerdiff)
    common.logMessage("Done! Translation is at {0:.2f}%".format(
        (100 * transtot) / chartot))
Esempio n. 26
0
def repack(no_rom, bin, tdg, kpc, spc, vsc, yce, deb, force, analyze):
    all = not bin and not tdg and not kpc and not spc and not vsc and not yce
    if all or bin or spc:
        import repack_font
        repack_font.run()
    if all or bin:
        import repack_bin
        repack_bin.run()
        common.armipsPatch("bin_patch.asm")
    if all or tdg:
        common.copyFile("data/extract_NFP/NFP3D.NFP/MSW_C053.3DG",
                        "data/extract_NFP/NFP3D.NFP/MSW_C083.3DG")
        nitro.repackNSBMD("data/work_3DG/", "data/extract_NFP/NFP3D.NFP/",
                          "data/work_NFP/NFP3D.NFP/", ".3DG", game.write3DG)
        import patch_jnt
        patch_jnt.run()
    if all or kpc:
        import repack_kpc
        repack_kpc.run()
    if all or spc:
        import repack_spc
        repack_spc.run()
    if all or vsc:
        import repack_vsc
        repack_vsc.run()
    if all or yce:
        import repack_yce
        repack_yce.run()

    if not no_rom:
        debfolder = "data/extract_NFP/"
        nfpin = "data/extract/data/"
        nfpwork = "data/work_NFP/"
        nfpout = "data/repack/data/"
        # Debug map
        if deb:
            common.copyFile(debfolder + "SPC.NFP/S_DEBUG.SPC",
                            nfpwork + "SPC.NFP/S_MAIN.SPC")
        else:
            common.copyFile(debfolder + "SPC.NFP/S_MAIN.SPC",
                            nfpwork + "SPC.NFP/S_MAIN.SPC")
        if force != "":
            common.copyFile(nfpwork + "SPC.NFP/" + force + ".SPC",
                            nfpwork + "SPC.NFP/SYS_000.SPC")
        # Repack NFP archives
        if os.path.isdir(replacefolder):
            common.mergeFolder(replacefolder, nfpwork)
        common.logMessage("Repacking NFP ...")
        files = common.getFiles(nfpin, ".NFP")
        for file in common.showProgress(files):
            subfiles = os.listdir(nfpwork + file)
            filenum = len(subfiles)
            # Data starts at header (80 bytes) + entries (24 bytes each)
            datapos = 80 + (24 * filenum)
            # The file list is padded with 0s if it doesn't start at a multiple of 16
            datapos += datapos % 16
            common.logDebug("Repacking", file, "with", filenum, "files ...")
            with common.Stream(nfpout + file, "wb") as f:
                f.writeString("NFP2.0 (c)NOBORI 1997-2006")
                f.writeZero(26)
                f.writeInt(filenum)
                f.writeInt(0x50)
                f.writeInt(datapos)
                for i in range(filenum):
                    subfile = subfiles[i]
                    subfilepath = nfpwork + file + "/" + subfile
                    filesize = os.path.getsize(subfilepath)
                    f.seek(80 + (24 * i))
                    f.writeString(subfile)
                    if len(subfile) < 16:
                        f.writeZero(16 - len(subfile))
                    f.writeInt(datapos)
                    f.writeInt(filesize * 4)
                    f.seek(datapos)
                    with open(subfilepath, "rb") as newf:
                        f.write(newf.read(filesize))
                    datapos += filesize
        # Edit banner and repack ROM
        nds.editBannerTitle(
            bannerfile,
            "Tengen Toppa\nGurren Lagann\nKonami Digital Entertainment")
        nds.repackRom(romfile, rompatch, outfolder, patchfile)
Esempio n. 27
0
def repack(file, outfile, infolder, outfolder):
    common.logDebug("Processing", file, "...")
    cpk = readCPK(file)
    if cpk is None:
        common.logError("Error reading CPK")
        return
    if len(cpk.filetable) == 0:
        common.logError("No files in CPK filetable")
        return
    # Get all the file with the custom extensions
    idtoext = {}
    for subfile in common.getFiles(infolder):
        nameext = os.path.splitext(subfile)
        idtoext[nameext[0]] = nameext[1]
    with common.Stream(outfile, "wb") as fout:
        with common.Stream(file, "rb") as fin:
            idnewdata = {}
            # Copy the file up to the ContentOffset
            contentoffsetentry = cpk.getFileEntry("CONTENT_OFFSET")
            contentoffset = contentoffsetentry.fileoffset
            fout.write(fin.read(contentoffset))
            # Sort the list by original offset, to keep the file order the same
            sortedfiletable = sorted(cpk.filetable, key=lambda e: e.fileoffset)
            for i in common.showProgress(range(len(sortedfiletable))):
                entry = sortedfiletable[i]
                if entry.filetype != "FILE":
                    continue
                folder, filename = entry.getFolderFile(infolder)
                folder2, _ = entry.getFolderFile(outfolder)
                if not os.path.isfile(folder + filename):
                    filename += idtoext[filename]
                if not os.path.isfile(folder + filename):
                    common.logError("Input file", folder + filename, "not found")
                    continue
                if not os.path.isfile(folder2 + filename):
                    # Read this directly from the CPK so we avoid compressing it again
                    fin.seek(entry.fileoffset)
                    filedata = fin.read(entry.filesize)
                    uncdatalen = entry.extractsize
                    cdatalen = entry.filesize
                else:
                    with common.Stream(folder2 + filename, "rb") as subf:
                        filedata = subf.read()
                    # TODO: compress the file again if it was compressed originally?
                    uncdatalen = cdatalen = len(filedata)
                # Write the file data and align
                fileoffset = fout.tell() - entry.offset
                fout.write(filedata)
                # If this is the last file, we don't align
                if i + 1 < len(sortedfiletable) and cdatalen % cpk.align > 0:
                    fout.writeZero(cpk.align - (cdatalen % cpk.align))
                idnewdata[entry.id] = (fileoffset, uncdatalen, cdatalen)
            # Update TOC
            tocentry = cpk.getFileEntry("TOC_HDR")
            itocentry = cpk.getFileEntry("ITOC_HDR")
            updatetoc = False
            updateitoc = False
            for id in idnewdata:
                newoffset, newuncdatalen, newcdatalen = idnewdata[id]
                if tocentry is not None:
                    idtocentry = cpk.getIDEntry(id, tocname="TOC")
                    if idtocentry is None:
                        common.logError("TOC entry not found for id", id)
                    else:
                        tocentry.utf.updateColumnDataType(newoffset, idtocentry.fileoffsetpos, idtocentry.fileoffsettype)
                        tocentry.utf.updateColumnDataType(newuncdatalen, idtocentry.extractsizepos, idtocentry.extractsizetype)
                        tocentry.utf.updateColumnDataType(newcdatalen, idtocentry.filesizepos, idtocentry.filesizetype)
                        updatetoc = True
                if itocentry is not None:
                    iditocentry = cpk.getIDEntry(id, tocname="ITOC")
                    if iditocentry is not None:
                        # TODO: Not sure if only updating the datah here is correct in all cases, also might need to check the offset
                        itocentry.utf.utfdatah.updateColumnDataType(newuncdatalen, iditocentry.extractsizepos, iditocentry.extractsizetype)
                        itocentry.utf.utfdatah.updateColumnDataType(newcdatalen, iditocentry.filesizepos, iditocentry.filesizetype)
                        updateitoc = True
            # Write the new packets
            if updatetoc:
                fout.seek(tocentry.fileoffset + 0x10)
                tocentry.utf.rawpacket.seek(0)
                utfpacket = tocentry.utf.rawpacket.read()
                if tocentry.encrypted:
                    utfpacket = decryptUTF(utfpacket)
                fout.write(utfpacket)
            if updateitoc:
                # TODO: check if this works whern the ITOC is encrypted
                itocentry.utf.utfdatah.rawpacket.seek(0)
                utfpacket = itocentry.utf.utfdatah.rawpacket.read()
                itocentry.utf.rawpacket.seek(itocentry.utf.datahpos)
                datapos = itocentry.utf.rawpacket.readInt() + itocentry.utf.dataoffset
                fout.seek(itocentry.fileoffset + 0x10 + datapos)
                fout.write(utfpacket)
Esempio n. 28
0
def run():
    infolder = "data/extract_NFP/NFP2D.NFP/"
    altinfolder = "data/work_YCE/"
    outfolder = "data/out_YCE/"
    outfile = "data/yce_data.txt"
    common.makeFolder(outfolder)

    common.logMessage("Extracting YCE to", outfolder, "...")
    with open(outfile, "w") as yce:
        files = common.getFiles(infolder, ".YCE")
        for file in common.showProgress(files):
            common.logDebug("Processing", file, "...")
            filepath = infolder + file
            if os.path.isfile(altinfolder + file):
                filepath = altinfolder + file
            with common.Stream(filepath, "rb") as f:
                # Read header
                f.seek(8)
                size = f.readUInt()  # size - header (7)
                f.seek(4, 1)  # Always 0
                f.seek(4, 1)  # Always 24
                f.readUInt()  # Animation data offset
                f.readUInt()  # ?
                num = f.readUInt()  # Number of images
                images = []
                for i in range(num):
                    img = game.YCETexture()
                    img.offset = f.readUInt() + 24  # Image data offset
                    images.append(img)
                for img in images:
                    common.logDebug("Reading image at offset", img.offset,
                                    "...")
                    f.seek(img.offset)
                    img.size = f.readUInt()  # Image data size
                    constant = f.readUInt()  # 0x1C
                    if constant != 0x1C:
                        common.logDebug("Constant is not 0x1C!",
                                        common.toHex(constant))
                    img.oamnum = f.readUInt()  # Number of OAMs
                    img.oamsize = f.readUInt()  # OAM data size
                    img.tilesize = f.readUInt()  # Tile data size
                    img.paloffset = f.readUInt(
                    ) + img.offset  # Palette data offset (relative to offset)
                    constant = f.readUInt()  # 0x01
                    if constant != 0x01:
                        common.logDebug("Constant 2 is not 0x01!",
                                        common.toHex(constant))
                    common.logDebug("size:", img.size, "oamnum:", img.oamnum,
                                    "oamsize:", img.oamsize)
                    common.logDebug("tilesize:", img.tilesize, "paloffset:",
                                    img.paloffset)
                    img.oams = []
                    for j in range(img.oamnum):
                        oam = game.OAM()
                        oam.x = f.readShort(
                        )  # X position of the cell (-128 to 127)
                        oam.y = f.readShort(
                        )  # Y position of the cell (-256 to 255)
                        for x in range(8):
                            unkbyte = f.readByte()
                            if unkbyte != 0x00:
                                common.logDebug("unkbyte", x, "is not 0x00!",
                                                common.toHex(unkbyte))
                        shape = f.readByte()  # NCER OBJ Shape
                        size = f.readByte()  # NCER OBJ Size
                        for x in range(2):
                            unkbyte = f.readByte()
                            if unkbyte != 0x00:
                                common.logDebug("unkbyte2", x, "is not 0x00!",
                                                common.toHex(unkbyte))
                        oam.offset = f.readUInt()
                        # Table from http://www.romhacking.net/documents/%5B469%5Dnds_formats.htm#NCER
                        if shape == 0:
                            if size == 0:
                                tilesize = (8, 8)
                            elif size == 1:
                                tilesize = (16, 16)
                            elif size == 2:
                                tilesize = (32, 32)
                            elif size == 3:
                                tilesize = (64, 64)
                        elif shape == 1:
                            if size == 0:
                                tilesize = (16, 8)
                            elif size == 1:
                                tilesize = (32, 8)
                            elif size == 2:
                                tilesize = (32, 16)
                            elif size == 3:
                                tilesize = (64, 32)
                        elif shape == 2:
                            if size == 0:
                                tilesize = (8, 16)
                            elif size == 1:
                                tilesize = (8, 32)
                            elif size == 2:
                                tilesize = (16, 32)
                            elif size == 3:
                                tilesize = (32, 64)
                        oam.width = tilesize[0]
                        oam.height = tilesize[1]
                        img.oams.append(oam)
                    # Calculate width and height
                    minx = miny = 512
                    maxx = maxy = -512
                    for oam in img.oams:
                        minx = min(minx, oam.x)
                        miny = min(miny, oam.y)
                        maxx = max(maxx, oam.x + oam.width)
                        maxy = max(maxy, oam.y + oam.height)
                    img.width = maxx - minx
                    img.height = maxy - miny
                    for oam in img.oams:
                        oam.x -= minx
                        oam.y -= miny
                    common.logDebug("width:", img.width, "height:", img.height)
                    common.logDebug("oams:", img.oams)
                # Create image
                width = height = 0
                for img in images:
                    width = max(width, img.width + 40)
                    height += max(img.height, 10)
                outimg = Image.new("RGBA", (width, height), (0, 0, 0, 0))
                pixels = outimg.load()
                # Read images
                currheight = 0
                for img in images:
                    # Load palette
                    palette = []
                    f.seek(img.paloffset)
                    paldata = f.read(32)
                    for i in range(0, 32, 2):
                        p = struct.unpack("<H", paldata[i:i + 2])[0]
                        palette.append(common.readPalette(p))
                    # Read tile data
                    f.seek(img.offset + img.oamsize)
                    tiledata = f.read(img.tilesize)
                    for oam in img.oams:
                        x = oam.offset * 64
                        for i in range(oam.height // 8):
                            for j in range(oam.width // 8):
                                for i2 in range(8):
                                    for j2 in range(8):
                                        index = (tiledata[x // 2] >>
                                                 ((x % 2) << 2)) & 0x0f
                                        pixels[oam.x + j * 8 + j2,
                                               currheight + oam.y + i * 8 +
                                               i2] = palette[index]
                                        x += 1
                    # Draw palette
                    pixels = common.drawPalette(pixels, palette, width - 40,
                                                currheight)
                    currheight += max(img.height, 10)
                outimg.save(outfolder + file.replace(".YCE", ".png"), "PNG")
            yce.write(
                file + "=" +
                base64.standard_b64encode(pickle.dumps(images)).decode() +
                "\n")
    common.logMessage("Done! Extracted", len(files), "files")
Esempio n. 29
0
def run(data, speaker=True, scene=False, merge=False):
    infolder = data + "extract/"
    files = ["bank_11.bin", "bank_12.bin"]
    outfile = data + "script_output.txt"
    with codecs.open(data + "table_input.txt", "r", "utf-8") as tablef:
        table = common.getSection(tablef, "")
    if merge:
        mergescript = codecs.open(data + "script_input.txt", "r", "utf-8")

    # Get the scenes list from the debug menu
    if scene:
        scenenames = {"bank_11.bin": [], "bank_12.bin": []}
        with common.Stream(infolder + "bank_1e.bin", "rb") as f:
            f.seek(0xcd90)
            while True:
                unk = f.readUShort()
                if unk == 0xffff:
                    break
                scenepos = f.readUShort()
                scenebank = "bank_11.bin" if f.readUShort(
                ) == 0x00f1 else "bank_12.bin"
                scenename = f.readNullString()
                scenenames[scenebank].append({
                    'pos': scenepos,
                    'name': scenename
                })
                f.seek(1, 1)  # Always 0x90
        for bankname in scenenames:
            scenenames[bankname] = sorted(scenenames[bankname],
                                          key=lambda i: i['pos'])

    # Extract the scripts
    with codecs.open(outfile, "w", "utf-8") as out:
        common.logMessage("Extracting script to", outfile, "...")
        for file in common.showProgress(files):
            common.logMessage("Processing", file, "...")
            out.write("!FILE:" + file + "\n")
            size = os.path.getsize(infolder + file)
            lastspeaker = -1
            if scene:
                nextscene = scenenames[file].pop(0)
            if merge:
                mergesection = common.getSection(mergescript, file)
            with common.Stream(infolder + file, "rb") as f:
                while f.tell() < size - 1:
                    opcode = f.readByte()
                    if opcode == 0x0a:
                        strpos = f.tell()
                        # Print the scene name
                        if scene:
                            if (nextscene is not None
                                    and strpos >= nextscene['pos']):
                                out.write("\n\n##SCENE:" + nextscene['name'] +
                                          "\n")
                                nextscene = scenenames[file].pop(0) if len(
                                    scenenames[file]) > 0 else None
                        # Add the speaker name
                        if speaker:
                            # Usually 7 bytes before there's a 0x10 byte, followed by the speaker expression and then the speaker sprite
                            speakercode = -1
                            f.seek(-7, 1)
                            checkspeaker = f.readByte()
                            if checkspeaker == 0x10:
                                f.seek(1, 1)
                                speakercode = f.readByte()
                            else:
                                # Sometimes, it's 6 bytes before instead so check that one too
                                checkspeaker = f.readByte()
                                if checkspeaker == 0x10:
                                    f.seek(1, 1)
                                    speakercode = f.readByte()
                            if speakercode != -1:
                                if speakercode not in game.speakercodes:
                                    common.logDebug("Unknown speaker code",
                                                    speakercode)
                                else:
                                    if speakercode != lastspeaker:
                                        out.write(
                                            "#" +
                                            game.speakercodes[speakercode] +
                                            "\n")
                                    lastspeaker = speakercode
                        # Read the string
                        f.seek(strpos)
                        readstr = game.readString(f, table)
                        if readstr != "":
                            if readstr[-2:] == ">>":
                                readstr = readstr[:-2]
                            out.write(readstr)
                            out.write("=")
                            if merge and readstr in mergesection:
                                out.write(mergesection[readstr].pop(0))
                                if len(mergesection[readstr]) == 0:
                                    del mergesection[readstr]
                            out.write("\n")
                            common.logDebug("Read string:", readstr)
                    elif opcode in game.repopcodes:
                        while f.readByte() != 0xff:
                            pass
                    else:
                        f.seek(game.opcodes[opcode], 1)
            out.write("\n\n")
        common.logMessage("Done! Extracted", len(files), "files")
Esempio n. 30
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"))