def generateAiScripts(self, baseFolder, targetFolder, dcx=True): """ Extract all unique .lua files from .laubnd files so they can be easily accessed. """ SN_RGX = r"[1-9][0-9][0-9][0-9][0-9][0-9]_(battle|logic).lua" inputFiles = [ "m10_00_00_00", "m10_01_00_00", "m10_02_00_00", "m11_00_00_00", "m12_00_00_00", "m12_01_00_00", "m13_00_00_00", "m13_01_00_00", "m13_02_00_00", "m14_00_00_00", "m14_01_00_00", "m15_00_00_00", "m15_01_00_00", "m16_00_00_00", "m17_00_00_00", "m18_00_00_00", "m18_01_00_00" ] tempList = [] for iFile in inputFiles: fullName = baseFolder + iFile + '.luabnd' if (dcx): fullName += '.dcx' with open(fullName, 'rb') as f: content = f.read() bndcontent = content if (dcx): dcxHandler = DCXHandler() bndcontent = dcxHandler.open_dcx(content) data = bnd_rebuilder.unpack_bnd(bndcontent) for item in data: strName = item[1].decode('shift_jis') match = re.search(SN_RGX, strName) if not (match == None): if not strName in tempList: tempList.append(strName) fileName = match.group(0) if not (os.path.isfile(targetFolder + fileName)): with open(targetFolder + fileName, 'wb') as wf: wf.write(item[2])
def Open(self, fname): #Unused print("ffx opened: " + fname) self.currentContent = [] self.lastFFX = 0 self.lastMDL = 0 self.lastTPF = 0 self.existingFiles = [] with open(fname, 'rb') as f: content = f.read() self.currentContent = bnd_rebuilder.unpack_bnd(content) for i, item in enumerate(self.currentContent): strName = item[1].decode('shift_jis') if not strName in self.existingFiles: self.existingFiles.append(strName) if (item[0] < 100000): if (item[0] > self.lastFFX): self.lastFFX = item[0] self.lastFFXIdx = i + 1 elif (item[0] < 200000): if (item[0] > self.lastTPF): self.lastTPF = item[0] self.lastTPFIdx = i + 1 else: if (item[0] > self.lastMDL): self.lastMDL = item[0] self.lastMDLIdx = i + 1 self.fileOpen = True
def ExtractEffects(self): #Unused self.CheckDirs() inputFiles = ['m10', 'm10_00', 'm10_01', 'm10_02', 'm11', 'm12', 'm12_00', 'm12_01', 'm13', 'm13_00', 'm13_01', 'm13_02', 'm14', 'm14_00', 'm14_01', 'm15', 'm15_00', 'm15_01', 'm16', 'm17', 'm18', 'm18_00', 'm18_01'] tempList = [] toExtract = [] for key in self.ffx_ref: toExtract += self.ffx_ref[key] #print(toExtract) for iFile in inputFiles: print(iFile) with open('sfx\\FRPG_SfxBnd_' + iFile + '.ffxbnd', 'rb') as f: content = f.read() data = bnd_rebuilder.unpack_bnd(content) for item in data: strName = item[1].decode('shift_jis') #print(strName) toRemove = -1 for i, ffxId in enumerate(toExtract): if (strName == self.ffxString.format(ffxId)): #print("ffx : " + ffxId) with open(self.ffxPath.format(ffxId), "wb") as ffxFile: ffxFile.write(item[2]) elif (strName == self.tpfString.format(ffxId)): #print("tex : " + ffxId) with open(self.tpfPath.format(ffxId), "wb") as tpfFile: tpfFile.write(item[2]) elif (strName == self.modelString.format(ffxId)): #print("modle : " + ffxId) with open(self.modelPath.format(ffxId), "wb") as flverFile: flverFile.write(item[2])
def open(self, filename, dcx=True): """ Opens .luabnd file with filename @filename. """ self.luabnd_content = [] self.luabnd_maxIndex = 0 self.useDCX = dcx fullname = filename if (self.useDCX): fullname += '.dcx' with open(fullname, 'rb') as f: content = f.read() bndcontent = content if (self.useDCX): self.dcxhandler = DCXHandler() bndcontent = self.dcxhandler.open_dcx(content) self.luabnd_content = bnd_rebuilder.unpack_bnd(bndcontent) luagnlBytes = b'' luainfoBytes = b'' self.luabnd_maxIndex = 0 for item in self.luabnd_content: if (item[0] == 1000000): luagnlBytes = item[2] elif (item[0] == 1000001): luainfoBytes = item[2] else: if (item[0] > self.luabnd_maxIndex): self.luabnd_maxIndex = item[0] return (luagnlBytes, luainfoBytes)
def export_to_gameparam(self): if self.game_version.get() == rngopts.RandOptGameVersion.PTDE: paths_to_search = PTDE_GAMEPARAM_PATH_LIST elif self.game_version.get() == rngopts.RandOptGameVersion.REMASTERED: paths_to_search = DS1R_GAMEPARAM_PATH_LIST else: paths_to_search = [] has_gameparam = False for filepath in paths_to_search: normed_path = os.path.normpath(os.path.join(os.getcwd(), filepath)) if os.path.isfile(normed_path): has_gameparam = True gameparam_filepath = normed_path gameparambak_filepath = normed_path + ".bak" is_remastered = ( self.game_version.get() == rngopts.RandOptGameVersion.REMASTERED) if not has_gameparam: self.msg_area.config(state="normal") self.msg_area.delete(1.0, "end") self.msg_area.insert("end", "\n\n") self.msg_area.insert("end", "ERROR", "error_red") self.msg_area.insert( "end", ": GameParam.parambnd[.dcx] is missing or cannot be opened." + " Check that this program is in the correct directory and GameParam.parambnd[.dcx] is present and retry.\n\n" + "Click \"Continue\" to continue in seed-information-only mode, or" + " click \"Quit\" to exit.") self.msg_area.tag_config("error_red", foreground="red") self.msg_area.config(state="disabled") self.export_button.config(state="disabled") self.lift_msg_area() else: if is_remastered: gp_filename = "GameParam.parambnd.dcx" else: gp_filename = "GameParam.parambnd" with open(gameparam_filepath, "rb") as f: content = f.read() try: if is_remastered: if not dcx_handler.appears_dcx(content): raise ValueError( ".dcx file does not appear to be DCX-compressed.") content = dcx_handler.uncompress_dcx_content(content) content_list = bnd_rebuilder.unpack_bnd(content) except: self.msg_area.config(state="normal") self.msg_area.delete(1.0, "end") self.msg_area.insert("end", "\n\n") self.msg_area.insert("end", "ERROR", "error_red") self.msg_area.insert( "end", ": " + gp_filename + " is malformed or corrupted and cannot be" + " parsed to export randomized items. If possible, restore " + gp_filename + " from a backup copy.\n\n" + "Click \"Continue\" to continue in seed-information-only mode, or" + " click \"Quit\" to exit.") self.msg_area.tag_config("error_red", foreground="red") self.msg_area.config(state="disabled") self.export_button.config(state="disabled") self.lift_msg_area() return # Back up GameParam.parambnd if needed. if not os.path.isfile(gameparambak_filepath): shutil.copy2(gameparam_filepath, gameparambak_filepath) if self.is_seed_empty(): self.get_new_seed() for index, (file_id, filepath, filedata) in enumerate(content_list): if (filepath == "N:\FRPG\data\INTERROOT_win32\param\GameParam\CharaInitParam.param" or filepath == "N:\FRPG\data\INTERROOT_x64\param\GameParam\CharaInitParam.param" ): chr_init_data = filedata # TODO: Implement this system correctly by passing chr_init_data # instead of None to preserve externally modified characters (e.g. another mod). # However, we need some way to determine external modifications # compared to data left over from a previous run that changed # ChrInit data. (options, randomized_data, rng) = self.randomize_data(None) (item_table, randomized_chr_data) = randomized_data syncnum = self.get_syncnum_string(rng) result_ilp = item_table.build_itemlotparam() ilp_binary_export = result_ilp.export_as_binary() result_slp = item_table.build_shoplineup() slp_binary_export = result_slp.export_as_binary() cip_binary_export = randomized_chr_data.export_as_binary() for index, (file_id, filepath, filedata) in enumerate(content_list): if (filepath == "N:\FRPG\data\INTERROOT_win32\param\GameParam\ItemLotParam.param" or filepath == "N:\FRPG\data\INTERROOT_x64\param\GameParam\ItemLotParam.param" ): content_list[index] = (file_id, filepath, ilp_binary_export) if (filepath == "N:\FRPG\data\INTERROOT_win32\param\GameParam\ShopLineupParam.param" or filepath == "N:\FRPG\data\INTERROOT_x64\param\GameParam\ShopLineupParam.param" ): content_list[index] = (file_id, filepath, slp_binary_export) if (filepath == "N:\FRPG\data\INTERROOT_win32\param\GameParam\CharaInitParam.param" or filepath == "N:\FRPG\data\INTERROOT_x64\param\GameParam\CharaInitParam.param" ): content_list[index] = (file_id, filepath, cip_binary_export) new_content = bnd_rebuilder.repack_bnd(content_list) if is_remastered: new_content = dcx_handler.compress_dcx_content(new_content) with open(gameparam_filepath, "wb") as f: f.write(new_content) seed_folder = self.export_seed_info( (options, randomized_data, rng)) self.msg_continue_button.lower() self.msg_area.config(state="normal") self.msg_area.delete(1.0, "end") self.msg_area.insert("end", "\n\n") self.msg_area.insert("end", "SUCCESS", "yay") self.msg_area.insert( "end", "! " + gp_filename + " has been modified successfully.\n\n" + "The information for this seed has been exported in the directory\n\n " + seed_folder + "\n\n") self.msg_area.insert( "end", "SyncNum: " + syncnum + "\n (When racing, all SyncNums should be equal or settings do not match.)\n\n" ) self.msg_area.insert( "end", "Click \"Back\" to begin again, or click \"Quit\" to exit.") self.msg_area.tag_config("yay", foreground="green") self.msg_area.config(state="disabled") self.msg_area.lift() self.back_button.lift() self.msg_quit_button.lift()
def AddEverythingToCommon(self, useDCX): """ Collects all effects from individual map effect files and adds them to CommonEffects """ inputFiles = ['m10', 'm10_00', 'm10_01', 'm10_02', 'm11', 'm12', 'm12_00', 'm12_01', 'm13', 'm13_00', 'm13_01', 'm13_02', 'm14', 'm14_00', 'm14_01', 'm15', 'm15_00', 'm15_01', 'm16', 'm17', 'm18', 'm18_00', 'm18_01'] MODEL_PATTERN = r'.*s1([0-9][0-9][0-9])[0-9].*' TPF_PATTERN = r'.*s1([0-9][0-9][0-9])[0-9].*' ENEMY_EFFECT_ID_PATTERN = r'.*00([1-9][0-9][0-9][0-9][0-9]).ffx' ENEMY_MODEL_ID_PATTERN = r'.*s([1-9][0-9][0-9][0-9][0-9]).flver' ENEMY_TPF_ID_PATTERN = r'.*s([1-9][0-9][0-9][0-9][0-9]).tpf' tempList = [] self.ffx_files.clear() for iFile in inputFiles: openFileName = 'sfx\\FRPG_SfxBnd_' + iFile + '.ffxbnd' if (useDCX): openFileName += '.dcx' with open(openFileName, 'rb') as f: upcontent = f.read() content = upcontent if (useDCX): dcxh = DCXHandler() content = dcxh.open_dcx(upcontent) data = bnd_rebuilder.unpack_bnd(content) for item in data: strName = item[1].decode('shift_jis') if not strName in tempList: if (useDCX): enFXMatch = re.match(ENEMY_EFFECT_ID_PATTERN, strName) if (enFXMatch != None): fid = int(enFXMatch.group(1)) if (fid < 20001): # prev = 60001 below as well in 2 locations tempList.append(strName) self.ffx_files.append(item) else: enMDLMatch = re.match(ENEMY_MODEL_ID_PATTERN, strName) if (enMDLMatch != None): fid = int(enMDLMatch.group(1)) if (fid < 20001): tempList.append(strName) self.ffx_files.append(item) else: enTPFMatch = re.match(ENEMY_TPF_ID_PATTERN, strName) if (enTPFMatch != None): fid = int(enTPFMatch.group(1)) if (fid < 20001): tempList.append(strName) self.ffx_files.append(item) else: tempList.append(strName) self.ffx_files.append(item) existingEffects = [] lastIndex = 0 lastIndexTpf = 0 lastIndexMdl = 0 ffxEntries = [] tpfEntries = [] mdlEntries = [] openFileName = 'sfx\\FRPG_SfxBnd_CommonEffects.ffxbnd' if (useDCX): openFileName += '.dcx' oldCheckSum = sha256_checksum(openFileName) writeSuccessful = True with open(openFileName, 'rb') as f: upcontent = f.read() content = upcontent if (useDCX): dcxh = DCXHandler() content = dcxh.open_dcx(upcontent) data = bnd_rebuilder.unpack_bnd(content) for item in data: strName = item[1].decode('shift_jis') if not strName in existingEffects: existingEffects.append(strName) if (item[0] < 100000): ffxEntries.append(item) if (item[0] > lastIndex): lastIndex = item[0] elif (item[0] < 200000): tpfEntries.append(item) if (item[0] > lastIndexTpf): lastIndexTpf = item[0] else: mdlEntries.append(item) if (item[0] > lastIndexMdl): lastIndexMdl = item[0] if (not os.path.isfile(openFileName + '.bak')): with open(openFileName + '.bak', 'wb') as f2: f2.write(upcontent) oldLen = len(ffxEntries) + len(tpfEntries) + len(mdlEntries) lastIndex += 1 lastIndexTpf += 1 lastIndexMdl += 1 for i, ffx in enumerate(self.ffx_files): strName = ffx[1].decode('shift_jis') if not strName in existingEffects: if (ffx[0] < 100000): newEntry = (lastIndex, ffx[1], ffx[2]) lastIndex += 1 ffxEntries.append(newEntry) elif (ffx[0] < 200000): newEntry = (lastIndexTpf, ffx[1], ffx[2]) lastIndexTpf += 1 tpfEntries.append(newEntry) else: newEntry = (lastIndexMdl, ffx[1], ffx[2]) lastIndexMdl += 1 mdlEntries.append(newEntry) newContent = [] newContent += ffxEntries newContent += tpfEntries newContent += mdlEntries print("[FFX] Effect data gathered: " + str(len(newContent))) if not len(newContent) == oldLen: if (useDCX): print("[FFX] Saving and recompressing sfx\\FRPG_SfxBnd_CommonEffects.ffxbnd.dcx. This takes quite a while with the Remaster.") dcxh = DCXHandler() temp = dcxh.open_file('sfx\\FRPG_SfxBnd_CommonEffects.ffxbnd.dcx') dcxh.save_dcx('sfx\\FRPG_SfxBnd_CommonEffects.ffxbnd.dcx', bnd_rebuilder.repack_bnd(newContent)) else: print("[FFX] Saving sfx\\FRPG_SfxBnd_CommonEffects.ffxbnd.") with open('sfx\\FRPG_SfxBnd_CommonEffects.ffxbnd', 'wb') as f: f.write(bnd_rebuilder.repack_bnd(newContent)) newCheckSum = sha256_checksum(openFileName) if (oldCheckSum == newCheckSum): writeSuccessful = False print('[FFX] sfx\\FRPG_SfxBnd_CommonEffects.ffxbnd saved') if not useDCX: for iFile in inputFiles: data = [] with open('sfx\\FRPG_SfxBnd_' + iFile + '.ffxbnd', 'rb') as f: content = f.read() data = bnd_rebuilder.unpack_bnd(content) if not (os.path.isfile('sfx\\FRPG_SfxBnd_' + iFile + '.ffxbnd.bak')): with open('sfx\\FRPG_SfxBnd_' + iFile + '.ffxbnd.bak', 'wb') as bakf: bakf.write(content) with open('sfx\\FRPG_SfxBnd_' + iFile + '.ffxbnd', 'wb') as sf: sf.write(bnd_rebuilder.repack_bnd(data[:1])) print('[FFX] Clean-up complete') else: print('[FFX] Ignored cleanup (REMASTERED Version being used)') print("[FFX] Done") return writeSuccessful