#!/usr/bin/env python # -*- coding: UTF-8 -*- # # Created by Praetorian (ShadowNate) for Classic Adventures in Greek # classic.adventures.in.greek@gmail.com # # DONE Add code and switch option: to get the blade runner installation directory as input, then find the TLK files and export them with proper naming # DONE fix proper names for sheets as per latest code changes # import os, sys shutilLibFound = False xlwtLibFound = False csvLibFound = False try: import shutil except ImportError: print "[Error] Shutil python library is required to be installed!" else: shutilLibFound = True try: import xlwt except ImportError: print "[Error] xlwt python library is required to be installed!" else: xlwtLibFound = True try: import csv except ImportError: print "[Error] csv python library is required to be installed!" else: csvLibFound = True if (not shutilLibFound) or (not xlwtLibFound) or (not csvLibFound): sys.stdout.write("[Error] Errors were found when trying to import required python libraries\n") sys.exit(1) from os import walk, errno, path from xlwt import * from audFileLib import * from treFileLib import * from pogoTextResource import * from devCommentaryText import * # encoding=utf8 #reload(sys) #sys.setdefaultencoding('utf8') COMPANY_EMAIL = "classic.adventures.in.greek@gmail.com" APP_VERSION = "0.80" APP_NAME = "sortBladeRunnerWavs" APP_WRAPPER_NAME = "quotesSpreadsheetCreator.py" APP_NAME_SPACED = "Blade Runner Transcript Excel Creator (bare bones)" APP_SHORT_DESC = "* Create an Excel (.XLS) for transcribing Blade Runner.\n* (Optional) Extract TRx (x is the language code) files as additional sheets in the Excel\n* (Optional) Export speech files from the game's TLK resources to WAV format." OUTPUT_XLS_FILENAME = 'out' OUTPUT_XLS_FILENAME_EXT = '.xls' OUTPUT_XLS_QUOTES_SHEET = 'INGQUO_' # needs suffix x.TRx where x is the language code SUPPORTED_TLK_INPUT_FILES = [('1.TLK', 'TLK01'), ('2.TLK', 'TLK02'), ('3.TLK', 'TLK03'), ('A.TLK', 'TLK0A'), ('SPCHSFX.TLK', 'TLKSPCHSFX')] SUPPORTED_MIX_INPUT_FILES = ['STARTUP.MIX'] # 15 TRx files SUPPORTED_EXPORTED_TRx_FILES = ['CLUES.TR','ACTORS.TR','CRIMES.TR','CLUETYPE.TR','KIA.TR','SPINDEST.TR','VK.TR','OPTIONS.TR','DLGMENU.TR','ENDCRED.TR','HELP.TR','SCORERS.TR','KIACRED.TR','ERRORMSG.TR','AUTOSAVE.TR'] SUPPORTED_PLACEHOLDER_VQA_ENGLISH_FILES = [ ('WSTLGO_', 'Westwood Studios Partnership Intro'), ('BRLOGO_', 'Blade Runner Logo')] SUPPORTED_PLACEHOLDER_VQA_LOCALIZED_FILES = [ ('INTRO_', 'Intro cutscene - Prologue'), ('MW_A_', 'Eisenduller murder scene'), ('MW_B01_', 'Act 3 intro part - Start part'), ('MW_B02_', 'Act 3 intro part - Lucy is Replicant'), ('MW_B03_', 'Act 3 intro part - Dektora is Replicant'), ('MW_B04_', 'Act 3 intro part - Lucy and Dektora are human'), ('MW_B05_', 'Act 3 intro part - End part '), ('INTRGT_', 'Interrogation scene - Baker, Holloway, McCoy'), ('MW_C01_', 'Clovis and Sadik pay a visit to the Twins - Start Part'), ('MW_C02_', 'Clovis and Sadik pay a visit to the Twins - Clovis has an INCEPT PHOTO'), ('MW_C03_', 'Clovis and Sadik pay a visit to the Twins - Clovis DOES NOT have an INCEPT PHOTO'), ('MW_D_', 'Tyrell, Kolvig and Clovis meet-up at Tyrell Corp'), ('END01A_', 'Underground getaway - Lucy Human'), ('END01B_', 'Underground getaway - Lucy with DNA'), ('END01C_', 'Underground getaway - Lucy not enough DNA'), ('END01D_', 'Underground getaway - Dektora Human'), ('END01E_', 'Underground getaway - Dektora with DNA'), ('END01F_', 'Underground getaway - Dektora, not enough DNA'), ('END03_', 'Underground getaway - McCoy alone'), ('END04A_', 'Finale - McCoy on Moonbus'), ('END04B_', 'Finale - McCoy with Lucy on Moonbus'), ('END04C_', 'Finale - McCoy with Dektora on Moonbus'), ('END06_', 'Underground getaway - Steele Ending') ] SUPPORTED_SPECIAL_POGO_FILE = 'POGO.TR' SUPPORTED_LANGUAGES_DESCRIPTION_CODE_TLIST = [('EN_ANY', 'E', 'English'), ('DE_DEU', 'G', 'German'), ('FR_FRA', 'F', 'French'), ('IT_ITA', 'I', 'Italian'), ('ES_ESP', 'S', 'Spanish'), ('RU_RUS', 'R', 'Russian')] DEFAULT_LANG_DESC_CODE = SUPPORTED_LANGUAGES_DESCRIPTION_CODE_TLIST[0] gTraceModeEnabled = False gActiveLanguageDescriptionCodeTuple = '' gStringReplacementForRootFolderWithExportedFiles = "" gNumReplaceStartingCharacters = 0 gWavFiles = [] gWavFilesNoDups = [] gActorPropertyEntries = [] #[0]:id, [1]:ShortHand Name [2]:Full Name gActorPropertyEntriesWasInit = False # strFileName should be the full file name (including extension) def calculateFoldHash(strFileName): i = 0 hash = 0 strParam = strFileName.upper() lenFileName = len(strParam); while i < lenFileName and i < 12: groupSum = 0 # work in groups of 4 bytes for j in range(0, 4): # LSB first, so the four letters in the string are re-arranged (first letter goes to lower place) groupSum >>= 8; if (i < lenFileName): groupSum |= (ord(strParam[i]) << 24) i += 1 else: # if i >= lenFileName but still haven't completed the four byte loop add 0s groupSum |= 0 hash = ((hash << 1) | ((hash >> 31) & 1)) + groupSum hash &= 0xFFFFFFFF # mask here! #print (strParam +': ' +''.join('{:08X}'.format(hash))) return hash # Fill the gActorPropertyEntries table def initActorPropertyEntries(thePathToActorNamesTxt): global gActorPropertyEntriesWasInit global gActorPropertyEntries firstLine = True gActorPropertyEntriesWasInit = False # print "[Debug] opening actornames" if thePathToActorNamesTxt is None or not thePathToActorNamesTxt: actorNamesTextFile = u'actornames.txt' relPath = u'.' thePathToActorNamesTxt = os.path.join(relPath, actorNamesTextFile) print "[Warning] Actor names text file %s not found in arguments. Attempting to open local file if it exists" % (thePathToActorNamesTxt) if os.access(thePathToActorNamesTxt, os.F_OK): print "[Info] Actor names text file found: {0}.".format(thePathToActorNamesTxt) with open(thePathToActorNamesTxt) as tsv: if gTraceModeEnabled: print "[Debug] Parsing Override Encoding file info..." for line in csv.reader(tsv, dialect="excel-tab"): #skip first line header if firstLine == True: #if gTraceModeEnabled: # print "[Debug] Skipping Header line in Excel sheet" firstLine = False else: gActorPropertyEntries.append(line) gActorPropertyEntriesWasInit = True tsv.close() else: ## error print "[Error] Actor names text file not found: {0}.".format(thePathToActorNamesTxt) sys.exit(1) # terminate if finding actor names file failed (Blade Runner) def getActorShortNameById(lookupActorId): if not gActorPropertyEntriesWasInit: return '' else: for actorEntryTmp in gActorPropertyEntries: if int(actorEntryTmp[0]) == int(lookupActorId): return actorEntryTmp[1] return '' def getActorFullNameById(lookupActorId): if not gActorPropertyEntriesWasInit: return '' else: for actorEntryTmp in gActorPropertyEntries: if int(actorEntryTmp[0]) == int(lookupActorId): return actorEntryTmp[2] return '' def getActorIdByShortName(lookupActorShortName): if not gActorPropertyEntriesWasInit: return '' else: for actorEntryTmp in gActorPropertyEntries: if actorEntryTmp[1] == lookupActorShortName: return actorEntryTmp[0].zfill(2) return '' def getActorShortNameAndLocalQuoteIdByAUDHashID(audHashId): actorId = 0 actorShortName = '' actorLocalQuoteId = 0 if not gActorPropertyEntriesWasInit: print "[Error] actor properties were not initialized!" return (actorId, actorShortName, actorLocalQuoteId) for actorEntryTmp in gActorPropertyEntries: if( (audHashId - (int(actorEntryTmp[0]) * 10000) ) >= 0) and ((audHashId - (int(actorEntryTmp[0]) * 10000)) < 10000): actorId = int(actorEntryTmp[0]) actorShortName = actorEntryTmp[1] actorLocalQuoteId = audHashId - (actorId * 10000) return (actorId, actorShortName, actorLocalQuoteId) return (actorId, actorShortName, actorLocalQuoteId) # Aux. Ensure existence of output directory def ensure_dir(directory): try: os.makedirs(directory) except OSError as e: if e.errno != errno.EEXIST: raise # # Reading in the INPUT TLK files and checking all the AUD file properties # def inputTLKsExport(inputTLKpath, outputWAVpath): # try to open all TLK file entries from SUPPORTED_TLK_INPUT_FILES # then per TLK file # create an output folder in the OUTPUT PATH named TLK## for the 1, 2, 3 TLK and TLKSPCHSFX for the SPCHSFX.TLK # printout: # total entries # total data size # and per entry the # fileID # segment offset # file size print "[Info] Checking in %s for TLK files to export to %s" % (inputTLKpath, outputWAVpath) inputTLKFilesFound = [] # breaking after first for loop yields only the top directory files, which is what we want for (dirpath, dirnames, filenames) in walk(inputTLKpath): for filename in filenames: for tlkTuple in SUPPORTED_TLK_INPUT_FILES: if filename.upper() == tlkTuple[0]: inputTLKFilesFound.append(tlkTuple) break if len(inputTLKFilesFound) == 0: print "[Error] No valid speech audio files (TLK) were found in the specified input path (-ip switch)" sys.exit(1) for tmpTLKfileTuple in inputTLKFilesFound: if gTraceModeEnabled: print "[Info] Found TLK: %s" % ('"' + inputTLKpath + tmpTLKfileTuple[0] + '"') errorFound = False inTLKFile = None # # Create output folder if not exists at output path if gTraceModeEnabled: print "Ensuring output directory %s" % (os.path.join(outputWAVpath, tmpTLKfileTuple[1] )) ensure_dir(os.path.join(outputWAVpath, tmpTLKfileTuple[1] ) ) try: inTLKFile = open(os.path.join(inputTLKpath,tmpTLKfileTuple[0]), 'rb') except: errorFound = True print "[Error] Unexpected event:", sys.exc_info()[0] raise if not errorFound: tmpBuff = inTLKFile.read(2) # H: unsigned short (2 bytes) followed by I: unsigned int (4 bytes) tlkFileEntriesNumTuple = struct.unpack('H', tmpBuff) numOfTREEntriesToExtract = tlkFileEntriesNumTuple[0] tmpBuff = inTLKFile.read(4) tlkFileDataSegmentSizeTuple = struct.unpack('I', tmpBuff) allTlkFileSize = tlkFileDataSegmentSizeTuple[0] inTLKFile.seek(0, 2) # go to file end allActualBytesInMixFile = inTLKFile.tell() inTLKFile.seek(6, 0) # go to start of table of TLK file entries (right after the 6 bytes header) # 2 + 4 = 6 bytes short MIX header # 12 bytes per TLK entry in entries table # quick size validation if gTraceModeEnabled: print "[Debug] Entries: %d, Data segment size: %d bytes" % (numOfTREEntriesToExtract, allTlkFileSize) if allActualBytesInMixFile != 2 + 4 + 12 * numOfTREEntriesToExtract + allTlkFileSize: print "[Error] TLK file size mismatch with reported size in header for %s!" % (tmpTLKfileTuple[0]) else: # # 12 bytes per entry # 4 bytes: ID # 4 bytes: Offset in data segment # 4 bytes: Size of data # for i in range(0, numOfTREEntriesToExtract): inTLKFile.seek(2 + 4 + 12*i) tmpBuff = inTLKFile.read(4) tmpRdTuple = struct.unpack('I', tmpBuff) idOfAUDEntry = tmpRdTuple[0] tmpBuff = inTLKFile.read(4) tmpRdTuple = struct.unpack('I', tmpBuff) offsetOfAUDEntry = tmpRdTuple[0] tmpBuff = inTLKFile.read(4) tmpRdTuple = struct.unpack('I', tmpBuff) sizeOfAUDEntry = tmpRdTuple[0] if gTraceModeEnabled: print "[Debug] Entry: %s, offset: %s, Data segment size: %s bytes" % (''.join('{:08X}'.format(idOfAUDEntry)), ''.join('{:08X}'.format(offsetOfAUDEntry)),''.join('{:08X}'.format(sizeOfAUDEntry))) # # put file in AUD object # do we need AUD decode? # create WAV from AUD # write WAV to appropriate output folder # Figure out proper naming for file # then: # AudFile aud; # aud.loadAudFile(fs); (fs is file stream) # aud.export_as_wav(fs, offset, offset + int(sizeof(AudHeader)) + aud.header().size_in, target); # # inTLKFile.seek(2 + 4 + 12*numOfTREEntriesToExtract + offsetOfAUDEntry) if(offsetOfAUDEntry + sizeOfAUDEntry > allTlkFileSize): print "[Error] audio file (AUD) file size mismatch with reported size in entry header!" else: targetSimpleAudFileName = ''.join('{:08X}'.format(idOfAUDEntry)).upper()+'.AUD' audFileBuffer = inTLKFile.read(sizeOfAUDEntry) if (len(audFileBuffer) == sizeOfAUDEntry): # load audio file (AUD) file thisAudFile = audFile(gTraceModeEnabled) if (thisAudFile.loadAudFile(audFileBuffer, allTlkFileSize, targetSimpleAudFileName)): if gTraceModeEnabled: print "[Debug] Audio file (AUD) file %s was loaded successfully!" % (targetSimpleAudFileName) # find # print "[Debug] Emulating Wav write to appropriate folder..." (actorID, actorSName, localQuoteId) = getActorShortNameAndLocalQuoteIdByAUDHashID(idOfAUDEntry) targetSimpleWavFileName = actorSName + '_' + str(localQuoteId).zfill(4) + '_' + ''.join('{:08X}'.format(idOfAUDEntry)).upper()+'.WAV' #print os.path.join(outputWAVpath, tmpTLKfileTuple[1], targetSimpleWavFileName) if not os.path.isfile(os.path.join(outputWAVpath, tmpTLKfileTuple[1], targetSimpleWavFileName) ): thisAudFile.export_as_wav(audFileBuffer, os.path.join(outputWAVpath, tmpTLKfileTuple[1], targetSimpleWavFileName) ) else: if gTraceModeEnabled: print "[Info] Output file %s already exists. Skipping..." % (os.path.join(outputWAVpath, tmpTLKfileTuple[1], targetSimpleWavFileName)) else: print "[Error] while loading audio file (AUD) %s!" % (targetSimpleAudFileName) else: print "[Error] while reading audio file (AUD) file %s into mem buffer" % (targetSimpleAudFileName) #print "[Error] while reading audio file (AUD) file %s into mem buffer" % (''.join('{:08X}'.format(idOfMIXEntry))) inTLKFile.close() # SYS EXIT IS HERE ONLY FOR DEBUG PURPOSES OF PARSING TLK FILES - SHOULD BE COMMENTED OUT NORMALLY # sys.exit(0) return def appendVQAPlaceHolderSheets(excelOutBook = None): if excelOutBook != None: print "[Info] Appending placeholder sheets for supported video cutscenes (VQA)..." currVQAFileNameLclzd = None for currVQAFileNameDesc in SUPPORTED_PLACEHOLDER_VQA_ENGLISH_FILES + SUPPORTED_PLACEHOLDER_VQA_LOCALIZED_FILES: if currVQAFileNameDesc in SUPPORTED_PLACEHOLDER_VQA_ENGLISH_FILES: currVQAFileNameLclzd = currVQAFileNameDesc[0] + 'E.VQA' elif currVQAFileNameDesc in SUPPORTED_PLACEHOLDER_VQA_LOCALIZED_FILES: currVQAFileNameLclzd = currVQAFileNameDesc[0] + ('%s' % (gActiveLanguageDescriptionCodeTuple[1])) + '.VQA' if currVQAFileNameLclzd is not None: if gTraceModeEnabled: print "[Debug] Creating placeholder sheet %s: %s!" % (currVQAFileNameLclzd, currVQAFileNameDesc[1]) sh = excelOutBook.add_sheet(currVQAFileNameLclzd) # First Row n = 0 # keeps track of rows col_names = ['VQA File: %s' % (currVQAFileNameLclzd), '22050 audio sampling rate', currVQAFileNameDesc[1] ] colIdx = 0 for colNameIt in col_names: sh.write(n, colIdx, colNameIt) colIdx+=1 # Second Row n = 1 col_names = ['Start (YT)', 'End (YT)', 'Subtitle', 'By Actor', 'StartTime', 'Time Diff-SF', 'TimeDiff-SF(ms)', 'TimeDiff-EF', 'TimeDiff-EF(ms)', 'Frame Start', 'Frame End', 'Notes'] colIdx = 0 for colNameIt in col_names: sh.write(n, colIdx, colNameIt) colIdx+=1 #n+=1 return def appendPOGOTextSheet(excelOutBook = None): if excelOutBook != None: print "[Info] Appending POGO sheet..." currTreFileName = '%s%s' % (SUPPORTED_SPECIAL_POGO_FILE, gActiveLanguageDescriptionCodeTuple[1]) # POGO if gTraceModeEnabled: print "[Debug] TR%s file %s was loaded successfully!" % (gActiveLanguageDescriptionCodeTuple[1], currTreFileName) # POGO sh = excelOutBook.add_sheet(currTreFileName) n = 0 # keeps track of rows col1_name = 'Text Resource File: %s' % (currTreFileName) sh.write(n, 0, col1_name) # Second Row n = 1 col1_name = 'TextId' col2_name = 'Text' sh.write(n, 0, col1_name) sh.write(n, 1, col2_name) n+=1 pogoTRInstance = pogoTextResource(gTraceModeEnabled) for m, e1 in enumerate(pogoTRInstance.getPogoEntriesList(), n): sh.write(m, 0, e1[0]) objStr = e1[1] try: # We assume utf-8 charset for POGO (since we get the text from a python script) objUTF8Unicode = unicode(objStr, 'utf-8') except Exception as e: print '[Error] Failed to create unicode string: ' + str(e) objUTF8Unicode = unicode("???", 'utf-8') sh.write(m, 1, objUTF8Unicode) def appendDevCommentarySheet(excelOutBook = None): if excelOutBook != None: print "[Info] Appending Developer Commentary sheet..." if excelOutBook != None: sh = excelOutBook.add_sheet("DEV COMMENTARY") devCommentaryTextInstance = devCommentaryText(gTraceModeEnabled) # First Segment n = 0 # keeps track of rows col_names = ['AUDIO COMMENTARY'] colIdx = 0 for colNameIt in col_names: sh.write(n, colIdx, colNameIt) colIdx+=1 n+= 1 for idStr, textStr in devCommentaryTextInstance.getAudioCommentaryTextEntriesList(): sh.write(n, 0, idStr) # We assume utf-8 charset for Audio Commentary and extra text entries (since we get the text from a python script) try: objUTF8Unicode = unicode(textStr, 'utf-8') except Exception as e: print '[Error] Failed to create unicode string: ' + str(e) objUTF8Unicode = unicode("???", 'utf-8') sh.write(n, 1, objUTF8Unicode) n+=1 # Second Segment col_names = ['I_SEZ QUOTES'] colIdx = 0 for colNameIt in col_names: sh.write(n, colIdx, colNameIt) colIdx+=1 n+= 1 for idStr, textStr in devCommentaryTextInstance.getISEZTextEntriesList(): sh.write(n, 0, idStr) # We assume utf-8 charset for I_SEZ Commentary (since we get the text from a python script) try: objUTF8Unicode = unicode(textStr, 'utf-8') except Exception as e: print '[Error] Failed to create unicode string: ' + str(e) objUTF8Unicode = unicode("???", 'utf-8') sh.write(n, 1, objUTF8Unicode) n+=1 return def inputMIXExtractTREs(inputMIXpath, excelOutBook = None): print "[Info] Checking in %s for MIX files to extract Text Resources (TR%ss) from..." % (inputMIXpath, gActiveLanguageDescriptionCodeTuple[1]) inputMIXFilesFound = [] # breaking after first for loop yields only the top directory files, which is what we want for (dirpath, dirnames, filenames) in walk(inputMIXpath): for filename in filenames: for mixFileName in SUPPORTED_MIX_INPUT_FILES: if filename.upper() == mixFileName: inputMIXFilesFound.append(mixFileName) break if len(inputMIXFilesFound) == 0: print "[Error] No supported game archive resource files (MIX) were found in the specified input path (-ip switch)" sys.exit(1) for tmpMIXfileName in inputMIXFilesFound: if gTraceModeEnabled: print "[Info] Found MIX file: %s" % ('"' + tmpMIXfileName + '"') errorFound = False inMIXFile = None # try: inMIXFile = open(os.path.join(inputMIXpath,tmpMIXfileName), 'rb') except: errorFound = True print "[Error] Unexpected event:", sys.exc_info()[0] raise if not errorFound: totalTREs = 0 tmpBuff = inMIXFile.read(2) # H: unsigned short (2 bytes) followed by I: unsigned int (4 bytes) mixFileEntriesNumTuple = struct.unpack('H', tmpBuff) numOfTREEntriesToExtract = mixFileEntriesNumTuple[0] tmpBuff = inMIXFile.read(4) mixFileDataSegmentSizeTuple = struct.unpack('I', tmpBuff) allMixFileSize = mixFileDataSegmentSizeTuple[0] inMIXFile.seek(0, 2) # go to file end allActualBytesInMixFile = inMIXFile.tell() inMIXFile.seek(6, 0) # go to start of table of MIX file entries (right after the 6 bytes header) # 2 + 4 = 6 bytes short MIX header # 12 bytes per MIX entry in entries table # quick size validation if gTraceModeEnabled: print "[Debug] Entries: %d, Data segment size: %d bytes" % (numOfTREEntriesToExtract, allMixFileSize) if allActualBytesInMixFile != 2 + 4 + 12 * numOfTREEntriesToExtract + allMixFileSize: print "[Error] MIX file size mismatch with reported size in header for %s!" % (tmpMIXfileName) else: # # 12 bytes per entry # 4 bytes: ID # 4 bytes: Offset in data segment # 4 bytes: Size of data # for i in range(0, numOfTREEntriesToExtract): foundTREFile = False currTreFileName = 'UNKNOWN.TR%s' % (gActiveLanguageDescriptionCodeTuple[1]) inMIXFile.seek(2 + 4 + 12*i) tmpBuff = inMIXFile.read(4) tmpRdTuple = struct.unpack('I', tmpBuff) idOfMIXEntry = tmpRdTuple[0] tmpBuff = inMIXFile.read(4) tmpRdTuple = struct.unpack('I', tmpBuff) offsetOfMIXEntry = tmpRdTuple[0] tmpBuff = inMIXFile.read(4) tmpRdTuple = struct.unpack('I', tmpBuff) sizeOfMIXEntry = tmpRdTuple[0] for suppTREFileName in SUPPORTED_EXPORTED_TRx_FILES: suppTREFileName = suppTREFileName + gActiveLanguageDescriptionCodeTuple[1] if(idOfMIXEntry == calculateFoldHash(suppTREFileName)): foundTREFile = True currTreFileName = suppTREFileName break if (foundTREFile == True): if gTraceModeEnabled: print "[Debug] Entry Name: %s, Entry ID: %s, offset: %s, Data segment size: %s bytes" % (currTreFileName, ''.join('{:08X}'.format(idOfMIXEntry)), ''.join('{:08X}'.format(offsetOfMIXEntry)),''.join('{:08X}'.format(sizeOfMIXEntry))) # # IF TRE FILE: # put file in TRE object # # inMIXFile.seek(2 + 4 + 12*numOfTREEntriesToExtract + offsetOfMIXEntry) if(offsetOfMIXEntry + sizeOfMIXEntry > allMixFileSize): print "[Error] TR%s file size mismatch with reported size in entry header!" % (gActiveLanguageDescriptionCodeTuple[1]) else: treFileBuffer = inMIXFile.read(sizeOfMIXEntry) if (len(treFileBuffer) == sizeOfMIXEntry): # load TRE file thisTreFile = treFile(gTraceModeEnabled) if (thisTreFile.loadTreFile(treFileBuffer, allMixFileSize, currTreFileName)): if gTraceModeEnabled: print "[Debug] TR%s file %s was loaded successfully!" % (gActiveLanguageDescriptionCodeTuple[1], currTreFileName) if excelOutBook != None: sh = excelOutBook.add_sheet(currTreFileName) n = 0 # keeps track of rows col1_name = 'Text Resource File: %s' % (currTreFileName) sh.write(n, 0, col1_name) # Second Row n = 1 col1_name = 'TextId' col2_name = 'Text' sh.write(n, 0, col1_name) sh.write(n, 1, col2_name) n+=1 for m, e1 in enumerate(thisTreFile.stringEntriesLst, n): sh.write(m, 0, e1[0]) objStr = e1[1] if ( currTreFileName[:-1] == 'ERRORMSG.TR'): # ERRORMSG.TRx uses different font than the others # and there are conflicts (with the other in-game fonts) # Supposedly these messages would be printed by an OS font # They seem to mostly use the Latin-1 codepage, although there are a few # characters that don't encode right (but they do with a IBM437 like the rest of the TRx # Probably, these are forgotten (buggy) characters from a previous plan (print error messages with in-game font?) # So we treat them as bugs and fix them. # Further proof that they are buggy, there are language versions that have two codes for the same character # in ERRORMSG TRx. # Eg. in Spanish version they use \xa2 (correct with IBM437) and \xf3 (correct with Latin-1) for the 'ó' character # or in French version 'è' uses both \x8a and \xe8 objEncodeSafeStr = "" for i in range(0, len(objStr)): # ENG version has no buggy character exceptions # GER version has no buggy character exceptions # FRA version if (objStr[i] == '\x82'): # FRA - ERRORMSG.TRF objEncodeSafeStr += '\xe9' # fixing buggy character 'é' elif (objStr[i] == '\x85'): # FRA - ERRORMSG.TRF (also used in ITA ERRORMSG.TRI - same glyph) objEncodeSafeStr += '\xe0' # fixing buggy character 'à' elif (objStr[i] == '\x8a'): # FRA - ERRORMSG.TRF (also used in ITA ERRORMSG.TRI - same glyph) objEncodeSafeStr += '\xe8' # fixing buggy character 'è' # ITA version #elif (objStr[i] == '\x85'): # ITA - ERRORMSG.TRI [commented out: already covered in FRA check above] # objEncodeSafeStr += '\xe0' # buggy - fixed above #elif (objStr[i] == '\x8a'): # ITA - ERRORMSG.TRI [commented out: already covered in FRA check above] # objEncodeSafeStr += '\xe8' # buggy - fixed above elif (objStr[i] == '\x97'): # ITA - ERRORMSG.TRI objEncodeSafeStr += '\xf9' # fixing buggy character 'ù' # ESP version elif (objStr[i] == '\xa2'): # ESP - ERRORMSG.TRS objEncodeSafeStr += '\xf3' # fixing buggy character 'ó' else: objEncodeSafeStr += objStr[i] # try: objUTF8Unicode = unicode(objEncodeSafeStr, 'latin-1') except Exception as e: print '[Error] Failed to create unicode string: ' + str(e) objUTF8Unicode = unicode("???", 'latin-1') else: # all the other official game TRx use the KIA6PT.FON # There could be variances of the KIA6PT.FON per Blade Runner version # TODO: For now, we assume that there aren't significant variances that warrant a more elaborate approach # TODO: Tested for EN, DEU, FRA, ITA, ESP. Pending testing for Russian version. try: objUTF8Unicode = unicode(objStr, 'cp437') except Exception as e: print '[Error] Failed to create unicode string: ' + str(e) objUTF8Unicode = unicode("???", 'cp437') sh.write(m, 1, objUTF8Unicode) #for tupleIdString in thisTreFile.stringEntriesLst: # #print "[Debug] Id: %d\t Text: %s" % (tupleIdString[0], tupleIdString[1]) # pass totalTREs = totalTREs + 1 else: print "[Error] while loading TR%s %s file!" % (gActiveLanguageDescriptionCodeTuple[1], currTreFileName) else: print "[Error] while reading TR%s file %s into mem buffer" % (gActiveLanguageDescriptionCodeTuple[1], currTreFileName) #print "[Error] while reading TR%s file %s into mem buffer" % (gActiveLanguageDescriptionCodeTuple[1], ''.join('{:08X}'.format(idOfMIXEntry))) inMIXFile.close() print "[Info] Total TR%ss processed: %d " % (gActiveLanguageDescriptionCodeTuple[1], totalTREs) return # # Creating the OUTPUT XLS file with one sheet named as the @param sheet with entries based on the list1 (wav files, without duplicates) # def outputXLS(filename, sheet, list1, parseTREResourcesAlso = False, addDevCommAndExtraSFXSheetEnabled = False, addPOGOTextSheetEnabled = False, mixInputFolderPath = ''): global gStringReplacementForRootFolderWithExportedFiles global gNumReplaceStartingCharacters book = xlwt.Workbook() sh = book.add_sheet(sheet) # First Row n = 0 # keeps track of rows # variables = [x, y, z] # x_desc = 'Display' # y_desc = 'Dominance' # z_desc = 'Test' # desc = [x_desc, y_desc, z_desc] # # # #You may need to group the variables together # #for n, (v_desc, v) in enumerate(zip(desc, variables)): # for n, (v_desc, v) in enumerate(zip(desc, variables)): # sh.write(n, 0, v_desc) # sh.write(n, 1, v) col1_name = 'BladeRunnerTLK In-Game dialogue / voiceover quotes' sh.write(n, 0, col1_name) # Second Row n = 1 col1_name = 'Filename' col2_name = 'Quote' col3_name = 'By Actor' col4_name = 'Notes' col5_name = 'To Actor' col6_name = 'Resource' col7_name = 'ShortHandFileName' sh.write(n, 0, col1_name) sh.write(n, 1, col2_name) sh.write(n, 2, col3_name) sh.write(n, 3, col4_name) sh.write(n, 4, col5_name) sh.write(n, 5, col6_name) sh.write(n, 6, col7_name) n+=1 for m, e1 in enumerate(list1, n): twoTokensOfRelDirnameAndFilenameXLS = e1.split('&', 2) if len(twoTokensOfRelDirnameAndFilenameXLS) == 3: fourTokensOfFilename = twoTokensOfRelDirnameAndFilenameXLS[0].split('#', 3) if len(fourTokensOfFilename) == 4: # fix rogue _ chars in 3rd token of filename (split at '_') tmpAUDFileName = fourTokensOfFilename[0] + '-' + fourTokensOfFilename[1] + '.AUD' #ActorId-QuoteId.AUD sh.write(m, 0, tmpAUDFileName) twoTokensOfQuote = fourTokensOfFilename[2].split('-', 1) if len(twoTokensOfQuote) == 2: #Quote sh.write(m, 1, twoTokensOfQuote[1]) else: #Quote sh.write(m, 1, fourTokensOfFilename[2]) #Notes sh.write(m, 3, 'TODO') #byActor sh.write(m, 2, fourTokensOfFilename[3]) #ResourceFolder sh.write(m, 5, twoTokensOfRelDirnameAndFilenameXLS[1]) #ShortHandFileName tmpActorShortHand = getActorShortNameById(fourTokensOfFilename[0]) shortHandFileName = tmpActorShortHand + '_' + fourTokensOfFilename[1] + '_' + fourTokensOfFilename[2] + '.WAV' # real path of filename realPathOfFileNameToLink = twoTokensOfRelDirnameAndFilenameXLS[2] # checks if not empty if gStringReplacementForRootFolderWithExportedFiles and gNumReplaceStartingCharacters > 0: realPathOfFileNameToLink = realPathOfFileNameToLink.replace(realPathOfFileNameToLink[:gNumReplaceStartingCharacters], gStringReplacementForRootFolderWithExportedFiles) #works in Linux + Libreoffice # also works in Windows + LibreOffice (run from msys) -- tried something like: # python sortBladeRunnerWavs.py -op /g/WORKSPACE/BladeRunnerWorkspace/br-mixer-master/data/WAV -m "G:/WORKSPACE/BladeRunnerWorkspace/br-mixer-master/data/WAV" # put real full path for each file as FILE URL, and real (or approximate shorthand file name as alias) hyperlinkAudioFormula = 'HYPERLINK("file://%s","%s")' % (realPathOfFileNameToLink, shortHandFileName) sh.write(m, 6, Formula(hyperlinkAudioFormula)) else: sh.write(m, 0, e1) #Notes sh.write(m, 3, 'error') else: sh.write(m, 0, e1) #Notes sh.write(m, 3, 'error') # works for filenames where some rogue greek characters exist #sh.write(m, 0, str.decode("%s" % e1, 'utf-8')) # for m, e2 in enumerate(list2, n+1): # sh.write(m, 1, e2) appendVQAPlaceHolderSheets(book) if parseTREResourcesAlso == True and mixInputFolderPath != '': inputMIXExtractTREs(mixInputFolderPath, book) if addPOGOTextSheetEnabled == True: appendPOGOTextSheet(book) if addDevCommAndExtraSFXSheetEnabled == True: appendDevCommentarySheet(book) try: book.save(filename) print "[Info] Done." except Exception as e: print "[Error] Could not save the output Excel file:: " + str(e) # # Aux function to validate input language description # def getLanguageDescCodeTuple(candidateLangDescriptionStr): if (candidateLangDescriptionStr is None or not candidateLangDescriptionStr ): resultTuple = DEFAULT_LANG_DESC_CODE else: tmpMatchTuplesList = [ (x,y,z) for (x,y,z) in SUPPORTED_LANGUAGES_DESCRIPTION_CODE_TLIST if x == candidateLangDescriptionStr] if tmpMatchTuplesList is not None and len(tmpMatchTuplesList) > 0: resultTuple = tmpMatchTuplesList[0] else: resultTuple = None return resultTuple def printInfoMessageForLanguageSelectionSyntax(): tmpCSVSupportedLangDescValues = ", ".join( zip(*SUPPORTED_LANGUAGES_DESCRIPTION_CODE_TLIST)[0] ) print "Valid values for language selection are: %s" % (tmpCSVSupportedLangDescValues) print "Default value is: %s (%s)" % (DEFAULT_LANG_DESC_CODE[0], DEFAULT_LANG_DESC_CODE[2]) return # # # # ######################## # main def main(argsCL): # TODO parse arguments using argparse? https://docs.python.org/3/library/argparse.html#module-argparse global gTraceModeEnabled global gStringReplacementForRootFolderWithExportedFiles global gNumReplaceStartingCharacters global gActiveLanguageDescriptionCodeTuple global gWavFiles global gWavFilesNoDups gTraceModeEnabled = False gActiveLanguageDescriptionCodeTuple = DEFAULT_LANG_DESC_CODE pathToActorNamesTxt = "" candidateLangDescriptionTxt = "" TMProotFolderWithExportedFiles = "" TMProotFolderWithInputTLKFiles = "" exportWavFilesMode = False extractTreFilesMode = False extractDevCommAndExtraSFXMode = False extractPOGOTextMode = False invalidSyntax = False print "Running %s (%s)..." % (APP_NAME_SPACED, APP_VERSION) # print "Len of sysargv = %s" % (len(argsCL)) if len(argsCL) == 2: if(argsCL[1] == '--help'or argsCL[1] == '-h'): print "%s %s supports Westwood's Blade Runner PC Game (1997)." % (APP_NAME_SPACED, APP_VERSION) print APP_SHORT_DESC print "Created by Praetorian of the classic adventures in Greek team." print "Always keep backups!" print "--------------------" print "%s takes has one mandatory argument, ie. the folder of the exported WAV files:" % (APP_WRAPPER_NAME) print "Valid syntax: %s -op folderpath_for_exported_wav_Files [-ip folderpath_for_TLK_Files] [-ian path_to_actornames_txt] [-m stringPathToReplaceFolderpathInExcelLinks] [-ld gameInputLanguageDescription] [-xwav] [-xtre] [-xdevs] [-xpogo] [--trace]" % (APP_WRAPPER_NAME) print "The -op switch has an argument that is the path for exported WAV files folder. The -op switch is REQUIRED always." print "The -ip switch has an argument that is the path for the input (TLK or MIX) files folder (can be the same as the Blade Runner installation folder)." print "The -ian switch is followed by the path to actornames.txt, if it's not in the current working directory." print "The -m switch has an argument that is a replacement string for the path to the folder of exported WAV files which will be used as a prefix for the links in the output XLS file." print "The -ld switch has an argument that is the language description of the original game files that you use as input." printInfoMessageForLanguageSelectionSyntax() print "The -xwav switch enables the WAV audio export mode from the TLK files. It requires an INPUT path to be set with the -ip switch." print "The -xtre switch enables the TRx parsing mode from the original MIX files. It requires an INPUT path to be set with the -ip switch." print "The -xdevs switch will add a sheet for Developer Commentary text and some additional voice-overs from SFX.MIX." print "The -xpogo switch will add a sheet for the POGO text." print "The --trace switch enables more debug messages being printed during execution." print "--------------------" print "If the app finishes successfully, a file named %s-(language)%s will be created in the current working folder." % (OUTPUT_XLS_FILENAME, OUTPUT_XLS_FILENAME_EXT) print "--------------------" print "Thank you for using this app." print "Please provide any feedback to: %s " % (COMPANY_EMAIL) sys.exit() elif(argsCL[1] == '--version' or argsCL[1] == '-v'): print "%s %s supports Westwood's Blade Runner PC Game (1997)." % (APP_NAME_SPACED, APP_VERSION) print "Please provide any feedback to: %s " % (COMPANY_EMAIL) sys.exit() else: invalidSyntax = True elif len(argsCL) > 2: for i in range(1, len(argsCL)): if( i < (len(argsCL) - 1) and argsCL[i][:1] == '-' and argsCL[i+1][:1] != '-'): if (argsCL[i] == '-op'): TMProotFolderWithExportedFiles = argsCL[i+1] gNumReplaceStartingCharacters = len(TMProotFolderWithExportedFiles) elif (argsCL[i] == '-ip'): TMProotFolderWithInputTLKFiles = argsCL[i+1] elif (argsCL[i] == '-m'): gStringReplacementForRootFolderWithExportedFiles = argsCL[i+1] elif (argsCL[i] == '-ian'): pathToActorNamesTxt = argsCL[i+1] elif (argsCL[i] == '-ld'): candidateLangDescriptionTxt = argsCL[i+1] elif (argsCL[i] == '-xwav'): print "[Info] Export WAVs from TLK files mode enabled (only missing files will be exported)." exportWavFilesMode = True elif (argsCL[i] == '-xtre'): print "[Info] Extract Text Resources (TRx) mode enabled." extractTreFilesMode = True elif (argsCL[i] == '-xdevs'): print "[Info] Additional Sheet for developer commentary and extra SFX mode enabled." extractDevCommAndExtraSFXMode = True elif (argsCL[i] == '-xpogo'): print "[Info] Additional Sheet for POGO text mode enabled." extractPOGOTextMode = True elif argsCL[i] == '--trace': print "[Info] Trace mode enabled (more debug messages)." gTraceModeEnabled = True elif argsCL[i][:1] == '-': invalidSyntax = True break if (not exportWavFilesMode): print "[Info] Export WAVs from TLK files mode disabled." if (not extractTreFilesMode): print "[Info] Extract Text Resources (TRx) mode disabled." if (not extractDevCommAndExtraSFXMode): print "[Info] Additional Sheet for developer commentary and extra SFX mode disabled." if (not extractPOGOTextMode): print "[Info] Additional Sheet for POGO text mode disabled." if not TMProotFolderWithExportedFiles: # this argument is mandatory print "[Error] The output path for exported files (-op switch) argument is mandatory!" invalidSyntax = True if (not invalidSyntax) and (exportWavFilesMode == True or extractTreFilesMode == True) and (TMProotFolderWithInputTLKFiles == ''): print "[Error] No game input path (-ip switch) specified, while the export audio to WAV mode or the extract Text Resources mode is enabled." invalidSyntax = True if (not invalidSyntax) and (exportWavFilesMode == False and extractTreFilesMode == False) and (TMProotFolderWithInputTLKFiles != ''): print "[Warning] Specified game input path (-ip switch) will be ignored, since the export audio to WAV mode and the extract Text Resources mode are disabled." # not invalid syntax though gActiveLanguageDescriptionCodeTuple = getLanguageDescCodeTuple(candidateLangDescriptionTxt) if (not invalidSyntax) and gActiveLanguageDescriptionCodeTuple is None: print "[Error] Invalid language code was specified" printInfoMessageForLanguageSelectionSyntax() invalidSyntax = True if not invalidSyntax: print "[Info] Game Language Selected: %s (%s)" % (gActiveLanguageDescriptionCodeTuple[0], gActiveLanguageDescriptionCodeTuple[2]) # parse Actors files: initActorPropertyEntries(pathToActorNamesTxt) # for actorEntryTmp in gActorPropertyEntries: # print "[Debug] Found actor: %s %s %s" % (actorEntryTmp[0], actorEntryTmp[1], actorEntryTmp[2]) # # Early checks for invalid cases # 1. if TMProotFolderWithInputTLKFiles is not valid and -xtre or -xwav -> error! # use os.path.isdir? # # 2. if not -wav and -op path is invalid then empty INGQUOT sheet -> error # 3 [We check for this further bellow, before call for outputXLS]. if not -wav and -op path is empty (has no WAVs) then empty INGQUOT sheet -> Treat as an error case! if ((exportWavFilesMode == True or extractTreFilesMode == True) and (not os.path.isdir(TMProotFolderWithInputTLKFiles))): print "[Error] Invalid game input path (-ip switch) was specified, while the export audio to WAV mode or the extract Text Resources mode is enabled." sys.exit(1) if ((exportWavFilesMode == False) and (not os.path.isdir(TMProotFolderWithExportedFiles))): print "[Error] Invalid output path for exported files (-op switch) was specified, while the export audio to WAV mode is disabled (if enabled, it would create the path)." sys.exit(1) # # Checking for the optional case of parsing the input TLK files to export to WAV # if TMProotFolderWithInputTLKFiles != '': if (exportWavFilesMode == True): inputTLKsExport(TMProotFolderWithInputTLKFiles, TMProotFolderWithExportedFiles) #if (extractTreFilesMode == True): # inputMIXExtractTREs(TMProotFolderWithInputTLKFiles) # # Parsing the exported WAV files # print "[Info] Parsing the exported WAV audio files. Please wait (this could take a while)..." for (dirpath, dirnames, filenames) in walk(TMProotFolderWithExportedFiles): for nameIdx, nameTmp in enumerate(filenames): relDirName = '' # os.path.split would Split the pathname path into a pair, (head, tail) where tail is the last pathname component and head is everything leading up to that. The tail part will never contain a slash pathTokens = dirpath.split(os.path.sep) for pTokenTmp in pathTokens: if pTokenTmp.find("TLK") != -1: relDirName = pTokenTmp # print os.path.dirname(dirpath) # print os.path.abspath(os.path.join(os.path.join(dirpath, nameTmp), os.pardir)) filenames[nameIdx] = filenames[nameIdx] +'&' + relDirName + '&' + os.path.join(dirpath, nameTmp) gWavFiles.extend(filenames) # break for fileIdx, filenameTmp in enumerate(gWavFiles): twoTokensOfFilenameAndRelDirname = filenameTmp.split('&', 1) if len(twoTokensOfFilenameAndRelDirname) != 2: print "[Error] While attempting filename and relative dirname split: %s" % (filenameTmp) sys.exit(0) twoTokensOfFilenameForExt = twoTokensOfFilenameAndRelDirname[0].split('.', 1) if len(twoTokensOfFilenameForExt) == 2: if twoTokensOfFilenameForExt[1] != 'WAV' and twoTokensOfFilenameForExt[1] != 'wav': print "[Error] Found non supported file extension (not WAV): %s" % (twoTokensOfFilenameAndRelDirname[0]) sys.exit(0) else: print "[Error] While attempting extension split: %s" % (twoTokensOfFilenameAndRelDirname[0]) sys.exit(0) #remove WAV extension here # filenameTmp = twoTokensOfFilenameAndRelDirname[0] + '&' + twoTokensOfFilenameForExt[0] # print "[Debug] Found %s" % (filenameTmp) threeTokensOfFilename = twoTokensOfFilenameForExt[0].split('_', 2) if len(threeTokensOfFilename) == 3: # fix rogue _ chars in 3rd token of filename (split at '_') threeTokensOfFilename[2] = threeTokensOfFilename[2].replace("_", "-") # Replace first token # replace actor name shorthand with ActorID in first part tmpActorId = getActorIdByShortName(threeTokensOfFilename[0]) tmpActorFullName = '' if(tmpActorId != '' and tmpActorId is not None): tmpActorFullName = getActorFullNameById(tmpActorId) if(tmpActorFullName != '' and tmpActorFullName is not None): threeTokensOfFilename[0] = tmpActorId.zfill(2) threeTokensOfFilename.append(tmpActorFullName) else: #fatal error if something cannot convert to spot it immediately print "[Error] in actorIdMatch match: %s %s" % (tmpActorId, twoTokensOfFilenameForExt[0]) sys.exit(0) else: #fatal error if something cannot convert to spot it immediately print "[Error] in shorthand match: %s %s" % (threeTokensOfFilename[0], twoTokensOfFilenameForExt[0]) sys.exit(0) # # # foundMatchForActorShortHand = False # for actorEntryTmp in gActorPropertyEntries: # if actorEntryTmp[1] == threeTokensOfFilename[0]: # threeTokensOfFilename[0] = actorEntryTmp[0].zfill(2) # threeTokensOfFilename.append(actorEntryTmp[2]) # foundMatchForActorShortHand = True # break # end of replace actor name shorthand twoTokensOfFilenameForExt[0] = '#'.join(threeTokensOfFilename) filenameTmp = twoTokensOfFilenameForExt[0] + '&' + twoTokensOfFilenameAndRelDirname[1] gWavFiles[fileIdx] = filenameTmp else: print "[Error] in splitting tokens on _: %s" % (filenameTmp) sys.exit(0) #sort in-place # # gWavFiles.sort() # # # # # # Code for renaming non conforming filenames - just to be consistent in file naming # # TO BE RUN ONCE FOR CONFORMANCE. No NEED TO Re-RUN # # If its run though, comment this section and re-run the tool to get proper links in Excel file # # # for filenameSrcTmp in gWavFiles: # # get real full path from last token when split at & # # create target full path from the parentdir of last token and the current state of first 3 tokens when splitting at '#' # # report mismatch # # print (BUT DON'T PROCEED AT THIS POINT) what you would rename to what. # threeTokensOfFilenameAndRelDirname = filenameSrcTmp.split('&', 2) # currentSrcFullPath = threeTokensOfFilenameAndRelDirname[2] # fourTokensOfTargetFileName = threeTokensOfFilenameAndRelDirname[0].split('#', 3) # tmpActorShortHand = getActorShortNameById(fourTokensOfTargetFileName[0]) # targetFileName = tmpActorShortHand + '_' + fourTokensOfTargetFileName[1] + '_' + fourTokensOfTargetFileName[2] + '.WAV' # # os.path.split would Split the pathname path into a pair, (head, tail) where tail is the last pathname component and head is everything leading up to that. The tail part will never contain a slash # (srcParentDir, srcTail) = os.path.split(currentSrcFullPath) # targetFullPath = os.path.join(srcParentDir, targetFileName) # # os.rename(src, dst) # if(currentSrcFullPath != targetFullPath): # print currentSrcFullPath # print targetFullPath # os.rename(currentSrcFullPath, targetFullPath) # # END OF: Code for renaming non conforming filenames - just to be consistent in file naming # # for filenameSrcTmp in gWavFiles: duplicateFound = False # print "[Debug]Converted %s" % (filenameSrcTmp) # Weed out duplicates by copying to another table (quick and dirty) twoTokensOfRelDirnameAndFilenameSrc = filenameSrcTmp.split('&', 2) tmpRelDirNameSrc = twoTokensOfRelDirnameAndFilenameSrc[1] threeTokensOfQuoteFilenameSrc = twoTokensOfRelDirnameAndFilenameSrc[0].split('#', 2) #concatenate actorID and quoteID for search key keyForDuplicateSearchSrc = threeTokensOfQuoteFilenameSrc[0] + threeTokensOfQuoteFilenameSrc[1] for fileTargIdx, filenameTargTmp in enumerate(gWavFilesNoDups): twoTokensOfRelDirnameAndFilenameTarg = filenameTargTmp.split('&', 2) tmpRelDirNameTarg = twoTokensOfRelDirnameAndFilenameTarg[1] threeTokensOfQuoteFilenameTarg = twoTokensOfRelDirnameAndFilenameTarg[0].split('#', 2) #concatenate actorID and quoteID for search key keyForDuplicateSearchTarg = threeTokensOfQuoteFilenameTarg[0] + threeTokensOfQuoteFilenameTarg[1] if(keyForDuplicateSearchSrc == keyForDuplicateSearchTarg): #print "[Debug] Found duplicate %s" % (filenameSrcTmp) duplicateFound = True gWavFilesNoDups[fileTargIdx] = twoTokensOfRelDirnameAndFilenameTarg[0] + '&' + tmpRelDirNameSrc + ',' + tmpRelDirNameTarg + '&' + twoTokensOfRelDirnameAndFilenameTarg[2] break if(duplicateFound == False): gWavFilesNoDups.append(filenameSrcTmp) # for filenameSrcTmp in gWavFilesNoDups: # print "[Debug] Unique %s" % (filenameSrcTmp) if len(gWavFilesNoDups) == 0: print "[Error] No supported audio files (WAV) were found in the output folder path (-op switch)." sys.exit(1) constructedOutputFilename = "%s-%s%s" % (OUTPUT_XLS_FILENAME, gActiveLanguageDescriptionCodeTuple[2], OUTPUT_XLS_FILENAME_EXT) print "[Info] Creating output excel %s file..." % (constructedOutputFilename) outputXLS(constructedOutputFilename, OUTPUT_XLS_QUOTES_SHEET + gActiveLanguageDescriptionCodeTuple[1] + '.TR' + gActiveLanguageDescriptionCodeTuple[1], gWavFilesNoDups, extractTreFilesMode, extractDevCommAndExtraSFXMode, extractPOGOTextMode, TMProotFolderWithInputTLKFiles) else: invalidSyntax = True if invalidSyntax == True: print "[Error] Invalid syntax!\n Try: \n %s --help for more info \n %s --version for version info " % (APP_WRAPPER_NAME, APP_WRAPPER_NAME) print "Valid syntax: %s -op folderpath_for_exported_wav_Files [-ip folderpath_for_TLK_Files] [-ian path_to_actornames_txt] [-m stringPathToReplaceFolderpathInExcelLinks] [-ld gameInputLanguageDescription] [-xwav] [-xtre] [-xdevs] [-xpogo] [--trace]" % (APP_WRAPPER_NAME) print "\nDetected arguments:" tmpi = 0 for tmpArg in argsCL: if tmpi==0: #skip first argument tmpi+=1 continue print "Argument: %s" % (tmpArg) tmpi+=1 # 00_0000 -- DealsInInsects dupl TLK01, TLK0A # 00_0510 -- ThinkingOfChangingJobs-Leon dupl TLK02, TLK03 # 00-8520 -- WhatDoYouKnow dupl TLK01, TLK0A # Total unique quotes seems to be 5495! # TODO rename files in folders to conform to the underscore '_' and '-' format (a few don't -- let's have them all conforming!) # # ######################### # if __name__ == '__main__': main(sys.argv[0:]) else: ## debug #print '[Debug] %s was imported from another module' % (APP_WRAPPER_NAME) pass