예제 #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!")
예제 #2
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")
예제 #3
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))
예제 #4
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")
예제 #5
0
def run(data, allfile=False):
    infolder = data + "extract/"
    outfolder = data + "repack/"
    infile = data + "bin_input.txt"
    infilename = data + "name_input.txt"
    chartot = transtot = 0
    table, invtable, ccodes, glyphs = game.getFontData(data)

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

    nasm.run(common.bundledFile("bin_patch.asm"))