def extract(file, outfolder, guessextension=None): common.logDebug("Processing", file, "...") common.makeFolder(outfolder) 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 with common.Stream(file, "rb") as f: for entry in cpk.filetable: if entry.filetype != "FILE": continue folder, filename = entry.getFolderFile(outfolder) f.seek(entry.fileoffset) data = f.read(entry.filesize) f.seek(entry.fileoffset) checkcomp = f.readString(8) if checkcomp == "CRILAYLA": extractsize = entry.extractsize if entry.extractsize != 0 else entry.filesize if extractsize != 0: data = compression.decompressCRILAYLA(f, entry.fileoffset) if guessextension is not None: filename = guessextension(data, entry, filename) if not os.path.isdir(folder): common.makeFolders(folder) with common.Stream(folder + filename, "wb") as fout: fout.write(data)
def extractIso(isofile, extractfolder, workfolder=""): common.logMessage("Extracting ISO", isofile, "...") common.makeFolder(extractfolder) common.execute( "wit EXTRACT -o {iso} {folder}".format(iso=isofile, folder=extractfolder), False) if workfolder != "": common.copyFolder(extractfolder, workfolder) common.logMessage("Done!")
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")
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")
def extractRom(romfile, extractfolder, workfolder=""): common.logMessage("Extracting ROM", romfile, "...") ndstool = common.bundledExecutable("ndstool.exe") if not os.path.isfile(ndstool): common.logError("ndstool not found") return common.makeFolder(extractfolder) common.execute(ndstool + " -x {rom} -9 {folder}arm9.bin -7 {folder}arm7.bin -y9 {folder}y9.bin -y7 {folder}y7.bin -t {folder}banner.bin -h {folder}header.bin -d {folder}data -y {folder}overlay". format(rom=romfile, folder=extractfolder), False) if workfolder != "": common.copyFolder(extractfolder, workfolder) common.logMessage("Done!")
def extractIso(isofile, extractfolder, workfolder=""): common.logMessage("Extracting ISO", isofile, "...") common.makeFolder(extractfolder) iso = pycdlib.PyCdlib() iso.open(isofile) for dirname, dirlist, filelist in iso.walk(iso_path="/"): common.makeFolders(extractfolder + dirname[1:]) for file in filelist: with open(extractfolder + dirname[1:] + "/" + file, "wb") as f: iso.get_file_from_iso_fp(f, iso_path=dirname + "/" + file) iso.close() if workfolder != "": common.copyFolder(extractfolder, workfolder) common.logMessage("Done!")
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")
def extractRom(romfile, extractfolder, workfolder="", banksize=0x4000): common.logMessage("Extracting ROM", romfile, "...") common.makeFolder(extractfolder) filesize = os.path.getsize(romfile) banknum = filesize // banksize common.logMessage("Extracting", banknum, "banks ...") with common.Stream(romfile, "rb") as f: for i in range(banknum): bankname = "bank_" if i < 0x10: bankname += "0" bankname += format(i, 'x') with common.Stream(extractfolder + bankname + ".bin", "wb") as fout: fout.write(f.read(banksize)) if workfolder != "": common.copyFolder(extractfolder, workfolder) common.logMessage("Done!")
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")
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")
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")
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")
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))
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")
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))
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()