diff options
16 files changed, 366 insertions, 858 deletions
diff --git a/devtools/create_bladerunner/subtitles/common/actornames.txt b/devtools/create_bladerunner/subtitles/common/actornames.txt new file mode 100644 index 0000000000..2836d18de8 --- /dev/null +++ b/devtools/create_bladerunner/subtitles/common/actornames.txt @@ -0,0 +1,75 @@ +Id Short ActorDesc #skip first row +0 MCCOY McCoy +1 STEEL Steele +2 GORDO Gordo +3 DEKTO Dektora +4 GUZZA Guzza +5 CLOVI Clovis +6 LLUCY Lucy +7 IIIZO Izo +8 SADIK Sadik +9 CRAZY Crazylegs +10 LUTHE Luther +11 GRIGO Grigorian +12 TRANS Transient +13 LANCE Lance +14 BBBOB Bullet Bob +15 RUNCI Runciter +16 INSEC Insect Dealer +17 TGUAR Tyrell Guard +18 EARLQ Early Q +19 ZUBEN Zuben +20 HASAN Hasan +21 MARCU Marcus +22 MMMIA Mia +23 OLEAR Officer Leary +24 OGRAY Officer Grayford +25 HANOI Hanoi +26 BAKER Baker +27 DCLER Desk Clerk +28 HOWIE Howie Lee +29 FISHD Fish Dealer +30 KLEIN Klein +31 MURRA Murray +32 HBARK Hawker's Barkeep +33 HOLLO Holloway +34 SWALL Sergeant Walls +35 MORAJ Moraji +36 TBARD The Bard +37 PHOTG Photographer +38 DISPA Dispatcher +39 ANSWM Answering Machine +40 RAJIF Rajif +41 GKOLV Governor Kolvig +42 ERLQB Early Q Bartender +43 HPARR Hawker's Parrot +44 TAFPA Taffy Patron +45 LOCGU Lockup Guard +46 TEENA Teenager +47 HPATA Hysteria Patron A +48 HPATB Hysteria Patron B +49 HPATC Hysteria Patron C +50 SHOES Shoeshine Man +51 TYREL Tyrell +52 CCHEW Chew +53 GGAFF Gaff +54 BRYAN Bryant +55 TAFFY Taffy +56 SEBAS Sebastian +57 RACHA Rachael +58 GDOLL General Doll +59 ISABE Isabella +60 BLIMP Blimp Guy +61 NEWSC Newscaster +62 LLEON Leon +63 MALAN Male Announcer +64 FREEA Free Slot A +65 FREEB Free Slot B +66 MAGGI Maggie +67 ACTGA Actor Genwalker A +68 ACTGB Actor Genwalker B +69 ACTGC Actor Genwalker C +70 MUTAA Mutant A +71 MUTAB Mutant B +72 MUTAC Mutant C +99 MAINF Mainframe diff --git a/devtools/create_bladerunner/subtitles/fontCreator/fonFileLib.py b/devtools/create_bladerunner/subtitles/fontCreator/fonFileLib.py index c523162950..9c27062bc2 100644 --- a/devtools/create_bladerunner/subtitles/fontCreator/fonFileLib.py +++ b/devtools/create_bladerunner/subtitles/fontCreator/fonFileLib.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python2.7 # -*- coding: UTF-8 -*- # import os, sys, shutil diff --git a/devtools/create_bladerunner/subtitles/fontCreator/fontCreator.py b/devtools/create_bladerunner/subtitles/fontCreator/fontCreator.py new file mode 100644 index 0000000000..582282ed88 --- /dev/null +++ b/devtools/create_bladerunner/subtitles/fontCreator/fontCreator.py @@ -0,0 +1,10 @@ +#!/usr/bin/env python2.7 +# -*- coding: UTF-8 -*- +import sys +if not (sys.version_info[0] == 2 and sys.version_info[1] == 7): + sys.stdout.write("Error:: Blade Runner Font Creator script requires Python 2.7\n") + sys.exit(1) + +import grabberFromPNG17BR +if __name__ == "__main__": + grabberFromPNG17BR.main(sys.argv[0:])
\ No newline at end of file diff --git a/devtools/create_bladerunner/subtitles/fontCreator/grabberFromPNG17BR.py b/devtools/create_bladerunner/subtitles/fontCreator/grabberFromPNG17BR.py index a02cd5b7c9..629f0e25c5 100644 --- a/devtools/create_bladerunner/subtitles/fontCreator/grabberFromPNG17BR.py +++ b/devtools/create_bladerunner/subtitles/fontCreator/grabberFromPNG17BR.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python2.7 # -*- coding: UTF-8 -*- #------------------------------------------------------------------------------- # Name: grabberFromPNG15BR @@ -6,7 +6,7 @@ # FON file for the Westwood Blade Runner PC game. # # Author: antoniou -# +#w # Created: 16-05-2018 # Copyright: (c) antoniou 2018 # Licence: @@ -76,10 +76,12 @@ import os.path from fonFileLib import * company_email = "classic.adventures.in.greek@gmail.com" -app_version = "0.50" +app_version = "0.70" app_name = "grabberFromPNGHHBR" -app_name_spaced = "Extract or create Font Files (.FON) for Blade Runner" +app_name_spaced = "Blade Runner Font Creator/Extractor" +app_short_desc = "Extract or create Font Files (.FON) for Blade Runner" +traceModeEnabled = False supportedMIXInputFiles = ['STARTUP.MIX'] ## 4 font files @@ -173,10 +175,11 @@ class grabberFromPNG: targetLangOrderAndListOfForeignLettersStrUnicode = None targetLangOrderAndListOfForeignLettersStr = None # Read from an override file if it exists. Filename should be overrideEncoding.txt (overrideEncodingTextFile) - if(not self.overrideEncodingPath): + if not self.overrideEncodingPath : overrideEncodingTextFile = u'overrideEncoding.txt' relPath = u'.' self.overrideEncodingPath = os.path.join(relPath,overrideEncodingTextFile) + print "Warning:: Font Creation Override Encoding file not found in arguments. Attempting to open local file %s if it exists" % (configureFontsTranslationTextFile) if os.access(self.overrideEncodingPath, os.F_OK): ## debug @@ -234,14 +237,15 @@ class grabberFromPNG: except: overrideFailed = True raise - if not (self.targetEncoding is None or self.targetEncoding == '' or targetLangOrderAndListOfForeignLettersStrUnicode is None or len(targetLangOrderAndListOfForeignLettersStrUnicode) == 0 or self.originalFontName is None or self.originalFontName == ''): + if not (self.targetEncoding is None or not self.targetEncoding or targetLangOrderAndListOfForeignLettersStrUnicode is None or len(targetLangOrderAndListOfForeignLettersStrUnicode) == 0 or self.originalFontName is None or not self.originalFontName): overrideFailed = False - print "Target Encoding: " , self.targetEncoding + print "Info:: Target Encoding: " , self.targetEncoding #print "Lang Order: " , targetLangOrderAndListOfForeignLettersStrUnicode - print "Explicit Kern List: " , self.listOfExplicitKerning - print "Explicit Width Increment List: " , self.listOfWidthIncrements - print "Original Font Name: " , self.originalFontName + if traceModeEnabled: + print "Explicit Kern List: " , self.listOfExplicitKerning + print "Explicit Width Increment List: " , self.listOfWidthIncrements + print "Info:: Original Font Name: " , self.originalFontName if(len(self.listOfOutOfOrderGlyphs) == 0 and self.specialGlyphMode == True): # Just keep those that are needed @@ -253,7 +257,8 @@ class grabberFromPNG: elif self.originalFontName == 'TAHOMA': # treat TAHOMA18 and TAHOMA24 similarily here self.listOfOutOfOrderGlyphs.append((u'\xe9', u'\u0192')) # french e punctuated self.listOfOutOfOrderGlyphs.append((u'\xfc', u'\u2013')) # u umlaut - print "Explicit Out Of Order Glyphs List: " , self.listOfOutOfOrderGlyphs + if traceModeEnabled: + print "Info:: Explicit Out Of Order Glyphs List: " , self.listOfOutOfOrderGlyphs else: ## debug print "Error: Override encoding file not found: {0}.".format(self.overrideEncodingPath) @@ -284,9 +289,11 @@ class grabberFromPNG: sys.exit() # terminate if override Failed (Blade Runner) targetLangOrderAndListOfForeignLetters = list(targetLangOrderAndListOfForeignLettersStr) - print targetLangOrderAndListOfForeignLetters, len(targetLangOrderAndListOfForeignLetters) # new + if traceModeEnabled: + print targetLangOrderAndListOfForeignLetters, len(targetLangOrderAndListOfForeignLetters) # new self.targetLangOrderAndListOfForeignLettersAsciiValues = [ord(i) for i in targetLangOrderAndListOfForeignLetters] - print self.targetLangOrderAndListOfForeignLettersAsciiValues, len(self.targetLangOrderAndListOfForeignLettersAsciiValues) + if traceModeEnabled: + print self.targetLangOrderAndListOfForeignLettersAsciiValues, len(self.targetLangOrderAndListOfForeignLettersAsciiValues) self.maxAsciiValueInEncoding = max(self.targetLangOrderAndListOfForeignLettersAsciiValues) # for charAsciiValue in targetLangOrderAndListOfForeignLetters: @@ -502,7 +509,8 @@ class grabberFromPNG: if self.tabSpaceWidth == 0: #print "start startPre", startCol, self.startColOfPrevFontLetter self.tabSpaceWidth = startCol - self.startColOfPrevFontLetter - print "Tab Space Width detected: %d " % (self.tabSpaceWidth) + if traceModeEnabled: + print "Tab Space Width detected: %d " % (self.tabSpaceWidth) # new if -- don't use else here, to include the case of when we first detected the tab space width if self.tabSpaceWidth > 0: self.listOfXOffsets.append(startCol - (self.startOfAllLettersIncludingTheExtraDoubleAndWithKern + (self.lettersFound + 1) * self.tabSpaceWidth) ) # + self.deductKerningPixels ) @@ -589,6 +597,7 @@ class grabberFromPNG: # TODO the special settings for handling italic native letters should be in the settings(?) filepathSplitTbl = os.path.split(self.imageRowFilePNG) sFilenameOnlyImageRowFilePNG = filepathSplitTbl[1] + print "Info:: Parsing input Font glyphs image %s. Please wait..." % (sFilenameOnlyImageRowFilePNG) if sFilenameOnlyImageRowFilePNG.startswith("itcrp_") or sFilenameOnlyImageRowFilePNG.startswith("it_"): italicsMode = True @@ -596,7 +605,8 @@ class grabberFromPNG: if sFilenameOnlyImageRowFilePNG.startswith("itcrp_"): trimTopPixels = 1 trimBottomPixels = 1 - print "Will trim upper line by %d pixels and bottom line by %d pixels" % (trimTopPixels, trimBottomPixels) + if traceModeEnabled: + print "Will trim upper line by %d pixels and bottom line by %d pixels" % (trimTopPixels, trimBottomPixels) pix = im.load() # pix argument is mutable (will be changed in the parseImage body) if self.parseImage(pix, w1, h1, trimTopPixels, trimBottomPixels, True) == 0: #first run, just get the start column, ignore the letter - don't store it . We need this for the tab space width calculation and eventually the kerning calc of the letters @@ -605,7 +615,8 @@ class grabberFromPNG: self.lettersFound = self.lettersFound + 1 # == 0 means one character font was detected so +1 to the counter # print self.listOfBaselines #debug - print "Font Letters Detected (not including the first double): %d" % (self.lettersFound) + if traceModeEnabled: + print "Debug:: Font Glyphs Detected (not including the first double): %d" % (self.lettersFound) if (self.lettersFound ) > 0 : #print "widths: ", self.listOfWidths[0:] #print "Plain x offsets:" @@ -637,7 +648,8 @@ class grabberFromPNG: tmpOrd = self.targetLangOrderAndListOfForeignLettersAsciiValues[kIncIndx] keysOfWidthIncrements, valuesOfWidthIncrements = (zip(*self.listOfWidthIncrements)) if tmpOrd in keysOfWidthIncrements: - print "Explicit width increment for %d: %d" % (tmpOrd, valuesOfWidthIncrements[keysOfWidthIncrements.index(tmpOrd)]) + if traceModeEnabled: + print "Explicit width increment for %d: %d" % (tmpOrd, valuesOfWidthIncrements[keysOfWidthIncrements.index(tmpOrd)]) explicitWidthIncrementVal = valuesOfWidthIncrements[keysOfWidthIncrements.index(tmpOrd)] listOfCalcWidths.append(tmpWidth + explicitWidthIncrementVal ) if explicitWidthIncrementVal == 0: @@ -646,7 +658,8 @@ class grabberFromPNG: #maxFontWidth = max(self.listOfWidths) maxFontWidth = max(listOfCalcWidths) maxFontHeight = max(self.listOfHeights) - print "Max Width, Max Height (not necessarily for the same character font): %d, %d" % (maxFontWidth, maxFontHeight) + if traceModeEnabled: + print "Debug:: Max Width, Max Height (not necessarily for the same character glyph): %d, %d" % (maxFontWidth, maxFontHeight) #print "Index\tAsciiOrd\tX Offs\tY Offs\tWidth\tHeight" #print zip(range(1, len(self.listOfXOffsets)), self.targetLangOrderAndListOfForeignLettersAsciiValues[1:], self.listOfXOffsets, self.listOfYOffsets, listOfCalcWidths, self.listOfHeights) targetFontFile = None @@ -675,7 +688,8 @@ class grabberFromPNG: # this size should be updated at the end (after filling the file with all font image data) # # pack 'I' unsigned int - print "NumberOfEntriesInFontTabl", (self.maxAsciiValueInEncoding + 1 + 1) + if traceModeEnabled: + print "Number Of Entries In Font Table", (self.maxAsciiValueInEncoding + 1 + 1) numberOfEntriesInFontTable = self.maxAsciiValueInEncoding + 1 + 1 # 0x0100 # This is actually the max ascii value + plus one (1) to get the font index value + plus another one (1) to get the count (since we have zero based indices) # TODO ??? could be more than this if we need to keep other characters (not in our codeset) and expand the ascii table and offset the new characters numberOfEntriesInFontTableInFile = pack('I', numberOfEntriesInFontTable ) @@ -759,7 +773,8 @@ class grabberFromPNG: keysOfExplicitKerning, valuesOfExplicitKerning = (zip(*self.listOfExplicitKerning)) if (i - 1) in keysOfExplicitKerning: # found explicit kerning for this - print "Explicit kerning for %d " % (i-1) + if traceModeEnabled: + print "Explicit kerning for %d " % (i-1) self.listOfXOffsets[kIncIndx] = valuesOfExplicitKerning[keysOfExplicitKerning.index(i-1)] # explicit X offset tmpXOffsetToWrite = pack('i', self.listOfXOffsets[kIncIndx]) # x offset - from left # TODO check if ok. Changed to signed int since it can be negative sometimes! @@ -770,7 +785,8 @@ class grabberFromPNG: if len(self.listOfWidthIncrements ) > 0: keysOfWidthIncrements, valuesOfWidthIncrements = (zip(*self.listOfWidthIncrements)) if (i - 1) in keysOfWidthIncrements: - print "Explicit width increment for %d " % (i-1) + if traceModeEnabled: + print "Explicit width increment for %d " % (i-1) foundExplicitWidthIncrement = True self.listOfWidths[kIncIndx] = self.listOfWidths[kIncIndx] + valuesOfWidthIncrements[keysOfWidthIncrements.index(i-1)] @@ -802,10 +818,11 @@ class grabberFromPNG: targetFontFile.write(tmpDataOffsetToWrite) # end of for loop over all possible ascii values contained in the fon file # print the corrected properties per glyph font: - print "***** FINAL (Explicit Kern, width accounted) *****\nIndex\tAsciiOrd\tX Offs\tY Offs\tWidth\tHeight" - tmpListOfTuplesToPrintDbg = zip(range(1, len(self.listOfXOffsets)), self.targetLangOrderAndListOfForeignLettersAsciiValues[1:], self.listOfXOffsets, self.listOfYOffsets, listOfCalcWidths, self.listOfHeights) - for itemDbg in tmpListOfTuplesToPrintDbg: - print "%4d\t%8d\t%6d\t%6d\t%6d\t%6d" % (itemDbg[0], itemDbg[1], itemDbg[2], itemDbg[3], itemDbg[4], itemDbg[5]) + if traceModeEnabled: + print "***** FINAL (Explicit Kern, width accounted) *****\nIndex\tAsciiOrd\tX Offs\tY Offs\tWidth\tHeight" + tmpListOfTuplesToPrintDbg = zip(range(1, len(self.listOfXOffsets)), self.targetLangOrderAndListOfForeignLettersAsciiValues[1:], self.listOfXOffsets, self.listOfYOffsets, listOfCalcWidths, self.listOfHeights) + for itemDbg in tmpListOfTuplesToPrintDbg: + print "%4d\t%8d\t%6d\t%6d\t%6d\t%6d" % (itemDbg[0], itemDbg[1], itemDbg[2], itemDbg[3], itemDbg[4], itemDbg[5]) # # @@ -901,6 +918,10 @@ class grabberFromPNG: errMsg = "No letters were found in input png!" print errMsg retVal = -2 + if retVal == 0: + print "Done." + else: + print "Errors were found." return (retVal, errMsg, origGameFontSizeEqBaseLine, totalFontLetters, importedNumOfLetters) def extractFonFilesFromMix(self): @@ -1003,11 +1024,10 @@ class grabberFromPNG: # # ######################## # main -# -# ######################### -# -if __name__ == '__main__': -# main() +def main(argsCL): + # TODO parse arguments using argparse? https://docs.python.org/3/library/argparse.html#module-argparse + global traceModeEnabled + traceModeEnabled = False invalidSyntax = False extractFonMode = False @@ -1025,11 +1045,12 @@ if __name__ == '__main__': TMPSpaceWidthInPixels = 10 # TMPdeductKerningPixels = 0 TMPcustomBaseLineOffset = 0 - -# print "Len of sysargv = %s" % (len(sys.argv)) - if len(sys.argv) == 2: - if(sys.argv[1] == '--help'or sys.argv[1] == '-h'): + 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 Blade Runner (English version, CD edition)." % (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 "--------------------" @@ -1037,9 +1058,9 @@ if __name__ == '__main__': print "1. Put overrideEncoding.txt file in the same folder with this tool. (Recommended, but not obligatory step)" print "--------------------" print "Valid syntax A - export game fonts:" - print "%s -ip [folderpath_for_MIX_Files]\n" % (app_name) + print "%s -ip folderpath_for_MIX_Files [--trace]\n" % (app_name) print "Valid syntax B - create subtitle font:" - print "%s -im [image_Row_PNG_Filename] -om [output_FON_filename] -pxLL [minSpaceBetweenLettersInRowLeftToLeft] -pxTT [minSpaceBetweenLettersInColumnTopToTop] -pxKn [kerningForFirstDummyFontLetter] -pxWS [whiteSpaceWidthInPixels]\n" % (app_name) # deductKerningPixels" + print "%s -im image_Row_PNG_Filename -om output_FON_filename -pxLL minSpaceBetweenLettersInRowLeftToLeft -pxTT minSpaceBetweenLettersInColumnTopToTop -pxKn kerningForFirstDummyFontLetter -pxWS whiteSpaceWidthInPixels [--noSpecialGlyphs] [--noAutoTabCalculation] [--trace]\n" % (app_name) # deductKerningPixels" print "The -ip switch has an argument that is the path for the input (MIX) files folder (can be the same as the Blade Runner installation folder)." print "The -oe switch has an argument that is the input overrideEncoding file to use for the particular font creation." print "The -im switch has an argument that is the input PNG image with a row of the font glyphs spaced apart." @@ -1051,50 +1072,54 @@ if __name__ == '__main__': print "The -pxWS switch has an integer argument that sets the white space width in pixels for this particular font." print "The --noSpecialGlyphs switch removes consideration for special glyphs that exist out of their proper ascii order." print "The --noAutoTabCalculation switch removes the detection of tab spacing between letters (use this switch if you didn't create the PNG row file using a tab spaced list of glyphs)." + print "The --trace switch enables more debug messages being printed during execution." print "--------------------" print "Thank you for using this app." print "Please provide any feedback to: %s " % (company_email) sys.exit() - elif(sys.argv[1] == '--version' or sys.argv[1] == '-v'): + elif(argsCL[1] == '--version' or argsCL[1] == '-v'): print "%s %s supports Blade Runner (English version, CD edition)." % (app_name_spaced, app_version) print "Please provide any feedback to: %s " % (company_email) sys.exit() else: invalidSyntax = True - elif len(sys.argv) > 2: - for i in range(1, len(sys.argv)): - if( i < (len(sys.argv) - 1) and sys.argv[i][:1] == '-' and sys.argv[i+1][:1] != '-'): - if (sys.argv[i] == '-ip'): - TMPinputPathForMixFiles = sys.argv[i+1] + 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] == '-ip'): + TMPinputPathForMixFiles = argsCL[i+1] extractFonMode = True print "Original FON file extraction mode enabled." - elif (sys.argv[i] == '-oe'): - TMPOverrideEncodingFilePath = sys.argv[i+1] - elif (sys.argv[i] == '-im'): - TMPimageRowFilePNG = sys.argv[i+1] - elif (sys.argv[i] == '-om'): - TMPTargetFONfilename = sys.argv[i+1] - elif (sys.argv[i] == '-pxLL'): - TMPminSpaceBetweenLettersInRowLeftToLeft = int(sys.argv[i+1]) - elif (sys.argv[i] == '-pxTT'): - TMPminSpaceBetweenLettersInColumnTopToTop = int(sys.argv[i+1]) - elif (sys.argv[i] == '-pxKn'): - TMPkerningForFirstDummyFontLetter = int(sys.argv[i+1]) - elif (sys.argv[i] == '-pxYo'): - TMPYOffsToApplyToAllGlyphsExceptFirstSpecialGamma = int(sys.argv[i+1]) - elif (sys.argv[i] == '-pxWS'): - TMPSpaceWidthInPixels = int(sys.argv[i+1]) - elif sys.argv[i] == '--noSpecialGlyphs': - print "No special out-of-order glyphs mode enabled." + elif (argsCL[i] == '-oe'): + TMPOverrideEncodingFilePath = argsCL[i+1] + elif (argsCL[i] == '-im'): + TMPimageRowFilePNG = argsCL[i+1] + elif (argsCL[i] == '-om'): + TMPTargetFONfilename = argsCL[i+1] + elif (argsCL[i] == '-pxLL'): + TMPminSpaceBetweenLettersInRowLeftToLeft = int(argsCL[i+1]) + elif (argsCL[i] == '-pxTT'): + TMPminSpaceBetweenLettersInColumnTopToTop = int(argsCL[i+1]) + elif (argsCL[i] == '-pxKn'): + TMPkerningForFirstDummyFontLetter = int(argsCL[i+1]) + elif (argsCL[i] == '-pxYo'): + TMPYOffsToApplyToAllGlyphsExceptFirstSpecialGamma = int(argsCL[i+1]) + elif (argsCL[i] == '-pxWS'): + TMPSpaceWidthInPixels = int(argsCL[i+1]) + elif argsCL[i] == '--noSpecialGlyphs': + print "Info:: No special out-of-order glyphs mode enabled." TMPSpecialGlyphMode = False - elif sys.argv[i] == '--noAutoTabCalculation': - print "No automatic tab calculation between glyphs." + elif argsCL[i] == '--noAutoTabCalculation': + print "Info:: No automatic tab calculation between glyphs." TMPAutoTabCalculation = False + elif sys.argv[i] == '--trace': + print "Info:: Trace mode enabled (more debug messages)." + traceModeEnabled = True if (extractFonMode == False) and (not TMPTargetFONfilename or not TMPimageRowFilePNG or TMPminSpaceBetweenLettersInRowLeftToLeft <= 0 or TMPminSpaceBetweenLettersInColumnTopToTop <= 0 or TMPkerningForFirstDummyFontLetter <= 0 or TMPSpaceWidthInPixels <= 0) : # this argument is mandatory invalidSyntax = True - if (extractFonMode == True) and ( (TMPinputPathForMixFiles == '') or not TMPOverrideEncodingFilePath ): + if (extractFonMode == True) and ( (not TMPinputPathForMixFiles) or not TMPOverrideEncodingFilePath ): invalidSyntax = True else: invalidSyntax = True @@ -1124,15 +1149,26 @@ if __name__ == '__main__': invalidSyntax = True if invalidSyntax == True: - print "Invalid syntax\n Try: \n %s -op [folderpath_for_extracted_wav_Files] \n %s --help for more info \n %s --version for version info " % (app_name, app_name, app_name) + print "Invalid syntax\n Try: \n %s --help for more info \n %s --version for version info " % (app_name, app_name) + print "Valid syntax A - export game fonts:" + print "%s -ip folderpath_for_MIX_Files [--trace]\n" % (app_name) + print "Valid syntax B - create subtitle font:" + print "%s -im image_Row_PNG_Filename -om output_FON_filename -pxLL minSpaceBetweenLettersInRowLeftToLeft -pxTT minSpaceBetweenLettersInColumnTopToTop -pxKn kerningForFirstDummyFontLetter -pxWS whiteSpaceWidthInPixels [--noSpecialGlyphs] [--noAutoTabCalculation] [--trace]\n" % (app_name) # deductKerningPixels" tmpi = 0 - for tmpArg in sys.argv: + for tmpArg in argsCL: if tmpi==0: #skip first argument tmpi+=1 continue print "\nArgument: %s" % (tmpArg) tmpi+=1 + + +# +# ######################### +# +if __name__ == '__main__': + main(sys.argv[0:]) else: - #debug - #print 'font grabber imported from another module' + ## debug + #print 'Debug:: %s was imported from another module' % (app_name) pass diff --git a/devtools/create_bladerunner/subtitles/mixResourceCreator/mixResourceCreator.py b/devtools/create_bladerunner/subtitles/mixResourceCreator/mixResourceCreator.py new file mode 100644 index 0000000000..ad786fafa6 --- /dev/null +++ b/devtools/create_bladerunner/subtitles/mixResourceCreator/mixResourceCreator.py @@ -0,0 +1,10 @@ +#!/usr/bin/env python2.7 +# -*- coding: UTF-8 -*- +import sys +if not (sys.version_info[0] == 2 and sys.version_info[1] == 7): + sys.stdout.write("Error:: Blade Runner MIX Resource Creator script requires Python 2.7\n") + sys.exit(1) + +import packBladeRunnerMIXFromPCTLKXLS04 +if __name__ == "__main__": + packBladeRunnerMIXFromPCTLKXLS04.main(sys.argv[0:])
\ No newline at end of file diff --git a/devtools/create_bladerunner/subtitles/mixResourceCreator/packBladeRunnerMIXFromPCTLKXLS-04.py b/devtools/create_bladerunner/subtitles/mixResourceCreator/packBladeRunnerMIXFromPCTLKXLS-04.py deleted file mode 100644 index 2ebb5e9fe3..0000000000 --- a/devtools/create_bladerunner/subtitles/mixResourceCreator/packBladeRunnerMIXFromPCTLKXLS-04.py +++ /dev/null @@ -1,725 +0,0 @@ -#!/usr/bin/python -# -*- coding: UTF-8 -*- -# -# Created by Praetorian (ShadowNate) for Classic Adventures in Greek -# classic.adventures.in.greek@gmail.com -# Works with Excel version outSpeech-15-06-2018-1856-TranslatingComms-080.xls and above -# -# TODO Support at least one translation too (ie Greek) -# Print a warning if packing a TRE without the corresponding font(s) -- only a warning though -# -import os, sys, shutil -import ctypes -import csv -import os.path -import xlrd -from xlrd import * -# for pack -from struct import * -import re - -company_email = "classic.adventures.in.greek@gmail.com" -app_version = "0.60" -app_name = "packBladeRunnerMIXFromPCTLKXLS" -app_name_spaced = "Get a TRE file from spoken in-game quotes" -numOfSpokenQuotes = 0 - -defaultSubtitlesFontName = 'SUBTLS_E.FON' - -origEncoding = 'windows-1252' -defaultTargetEncoding = 'windows-1252' -defaultTargetEncodingUnicode = unicode(defaultTargetEncoding, 'utf-8') -targetEncoding = '' -targetEncodingUnicode = '' - -configureFontsTranslationTextFile = u'configureFontsTranslation.txt' -relPath = u'.' -configureFontsTranslationTextFileRelPath = os.path.join(relPath, configureFontsTranslationTextFile) - - -# DONE ADD ALL SHEETS NEEDED FROM THE XLS -# all dialogue sheets get the SUBTLS_E.FON for translation to TRE -# - TODO maybe merge this with TAHOMA18.FON eventually -supportedDialogueSheets = ['INGQUO_E.TRE', 'WSTLGO_E.VQA', 'BRLOGO_E.VQA', 'INTRO_E.VQA', 'MW_A_E.VQA', 'MW_B01_E.VQA', 'MW_B02_E.VQA', 'MW_B03_E.VQA', 'MW_B04_E.VQA', 'MW_B05_E.VQA', 'INTRGT_E.VQA', 'MW_D_E.VQA', 'MW_C01_E.VQA', 'MW_C02_E.VQA', 'MW_C03_E.VQA', 'END04A_E.VQA', 'END04B_E.VQA', 'END04C_E.VQA', 'END06_E.VQA', 'END01A_E.VQA', 'END01B_E.VQA', 'END01C_E.VQA', 'END01D_E.VQA', 'END01E_E.VQA', 'END01F_E.VQA', 'END03_E.VQA'] -# -# Each TRE sheet gets a specific font to handle their translation to TRE -# TAHOMA means both TAHOMA (their translation should be identical (although in the original they have minor differences but they don't affect anything) -# We use a single naming for TAHOMA here because both TAHOMA18 and TAHOMA24 are used for ENDCRED.TRE -# The TRE files that are identically named to the originals are supposed to override them (needs ScummVM compatible functionality for that) - -supportedTranslationSheets = [('OPTIONS.TRE', 'KIA6PT'), ('DLGMENU.TRE', 'KIA6PT'), ('SCORERS.TRE', 'TAHOMA'), ('VK.TRE', 'KIA6PT'), ('CLUES.TRE', 'KIA6PT'), ('CRIMES.TRE', 'KIA6PT'), ('ACTORS.TRE', 'KIA6PT'), ('HELP.TRE', 'KIA6PT'), ('AUTOSAVE.TRE', 'KIA6PT'), ('ERRORMSG.TRE', 'KIA6PT'), ('SPINDEST.TRE', 'KIA6PT'), ('KIA.TRE', 'KIA6PT'), ('KIACRED.TRE', 'KIA6PT'), ('CLUETYPE.TRE', 'KIA6PT'), ('ENDCRED.TRE', 'TAHOMA'), ('POGO.TRE', 'KIA6PT')] -# The FON files that are identically named to the originals are supposed to override them (needs ScummVM compatible functionality for that) -supportedOtherFilesForMix = [defaultSubtitlesFontName, 'KIA6PT.FON', 'TAHOMA18.FON', 'TAHOMA24.FON'] # , '10PT.FON'] # we don't deal with 10PT.FON since it's not used -- TODO verify this. - - -tableOfStringIds = [] -tableOfStringOffsets = [] -tableOfStringEntries = [] - -# this list is used in order to replace the actual indices of characters with delegate font indices (ASCII indexes of the target code-page) which have been used during the font creation (or exist in in the internal TAHOMA font) -# contains tuples of two values. First value is actual Utf char, the second is a replacement ASCII char -listOfFontNamesToOutOfOrderGlyphs = [] -arrangedListOfFontNamesToOutOfOrderGlyphs = [] - -actorPropertyEntries = [] -actorPropertyEntriesWasInit = False - -def initOverrideEncoding(): - global targetEncoding - - configureTranslationFailed = True - try: - if os.access(configureFontsTranslationTextFileRelPath, os.F_OK): - conFontsTranslationFile = open(configureFontsTranslationTextFileRelPath, 'r') - linesLst = conFontsTranslationFile.readlines() - conFontsTranslationFile.close() - if linesLst is None or len(linesLst) == 0: - configureTranslationFailed = True - else: - print "Font Translation Configuration Info: " - involvedTokensLst =[] - for readEncodLine in linesLst: - tmplineTokens = re.findall("[^\t\n]+",readEncodLine ) - for x in tmplineTokens: - involvedTokensLst.append(x) - - for tokenNameKeyPair in involvedTokensLst: - nameKeyTupl = tokenNameKeyPair.split('=', 1) - try: - if len(nameKeyTupl) == 2 and nameKeyTupl[0] == 'targetEncoding' and nameKeyTupl[1] is not None and nameKeyTupl[1] != '-' and nameKeyTupl[1] != '': - targetEncodingUnicode = unicode(nameKeyTupl[1], 'utf-8') - targetEncoding = unicode.encode("%s" % targetEncodingUnicode, origEncoding) - elif len(nameKeyTupl) == 2 and nameKeyTupl[0] == 'fontNameAndOutOfOrderGlyphs' and nameKeyTupl[1] is not None and nameKeyTupl[1] != '': - # split at hash tag first - tmpListOfOutOfOrderGlyphs = [] - del(tmpListOfOutOfOrderGlyphs[:]) - fontNameAndOOOGlyphsTuple = nameKeyTupl[1].split('#', 1) - if (len (fontNameAndOOOGlyphsTuple) == 2 and fontNameAndOOOGlyphsTuple[0] != '' and fontNameAndOOOGlyphsTuple[1] is not None and fontNameAndOOOGlyphsTuple[1] != ''): - tmpFontName = fontNameAndOOOGlyphsTuple[0] - # split at comma, then split at ':' and store tuples of character - explicitOutOfOrderGlyphsTokenUnicode = unicode(fontNameAndOOOGlyphsTuple[1], 'utf-8') # unicode(fontNameAndOOOGlyphsTuple[1], 'utf-8') - #explicitOutOfOrderGlyphsTokenStr = unicode.encode("%s" % explicitOutOfOrderGlyphsTokenUnicode, targetEncoding) - #explicitOutOfOrderGlyphsTokenStr = explicitOutOfOrderGlyphsTokenUnicode.decode(targetEncoding) # unicode.encode("%s" % explicitOutOfOrderGlyphsTokenUnicode, 'utf-8') - tokensOfOutOfOrderGlyphsStrList = explicitOutOfOrderGlyphsTokenUnicode.split(',') - for tokenX in tokensOfOutOfOrderGlyphsStrList: - tokensOfTupleList = tokenX.split(':') - tmpListOfOutOfOrderGlyphs.append( (unichr(ord(tokensOfTupleList[0])), unichr(ord(tokensOfTupleList[1]))) ) - - if tmpFontName not in [x[0] for x in listOfFontNamesToOutOfOrderGlyphs]: - listOfFontNamesToOutOfOrderGlyphs.append( ( tmpFontName, tmpListOfOutOfOrderGlyphs) ) - - else: - configureTranslationFailed = True - break - except: - configureTranslationFailed = True - raise - - if not (targetEncoding is None or targetEncoding == ''): - configureTranslationFailed = False - - except: - print "Error while trying to access file for encoding info: %s" % (configureFontsTranslationTextFileRelPath) - raise - configureTranslationFailed = True - - if configureTranslationFailed == True: -# targetEncoding = defaultTargetEncoding - print "Error! Could not find proper override encoding info in: %s" % (configureFontsTranslationTextFileRelPath) - sys.exit() # terminate if override Failed (Blade Runner) - # - # TODO ASDF fix this!!! - # - if(len(listOfFontNamesToOutOfOrderGlyphs) == 0): - tmpFontType = defaultSubtitlesFontName[:-4] # remove the .FON extensionFromTheName - print "Empty list for out of order glyphs. Assuming default out of order glyphs and only for the %s font" % (tmpFontType) - tmplistOfOutOfOrderGlyphs = [] - tmplistOfOutOfOrderGlyphs.append((u'\xed', u'\u0386')) # spanish i (si) - tmplistOfOutOfOrderGlyphs.append((u'\xf1', u'\xa5')) # spanish n (senor) - tmplistOfOutOfOrderGlyphs.append((u'\xe2', u'\xa6')) # a for (liver) pate - tmplistOfOutOfOrderGlyphs.append((u'\xe9', u'\xa7')) # e for (liver) pate - listOfFontNamesToOutOfOrderGlyphs.append( (tmpFontType, tmplistOfOutOfOrderGlyphs)) - print "Explicit Out Of Order Glyphs List: " , listOfFontNamesToOutOfOrderGlyphs - # arrange list properly: - # check if the list contains same item as key and value (in different pairs) - # if such case then the pair with the key should preceed the pair with the value matched, - # to avoid replacing instances of a special character (key) with a delegate (value) that will be later replaced again due to the second pair - # - for (itFontName, itOOOGlyphList) in listOfFontNamesToOutOfOrderGlyphs: - while (True): - foundMatchingPairs = False - for glyphDelegItA in itOOOGlyphList: - for glyphDelegItB in itOOOGlyphList: - if (glyphDelegItA[1] == glyphDelegItB[0] and itOOOGlyphList.index(glyphDelegItA) < itOOOGlyphList.index(glyphDelegItB)): - # swap - itamA, itamB = itOOOGlyphList.index(glyphDelegItA), itOOOGlyphList.index(glyphDelegItB) - itOOOGlyphList[itamB], itOOOGlyphList[itamA] = itOOOGlyphList[itamA], itOOOGlyphList[itamB] - foundMatchingPairs = True - break - if (foundMatchingPairs == True): - break - if(foundMatchingPairs == False): - break # the whole while loop - arrangedListOfFontNamesToOutOfOrderGlyphs.append( ( itFontName, itOOOGlyphList)) - print "Arranged Glyphs Delegates List: " , arrangedListOfFontNamesToOutOfOrderGlyphs - return - -# -# Fill the actorPropertyEntries table -def initActorPropertyEntries(): - global actorPropertyEntriesWasInit - global actorPropertyEntries - firstLine = True -# print "opening actornames" - with open("./actornames.txt") as tsv: - for line in csv.reader(tsv, dialect="excel-tab"): - #skip first line header - if firstLine == True: -# print "skippingHeader" - firstLine = False - else: - actorPropertyEntries.append(line) - actorPropertyEntriesWasInit = True - tsv.close() - -def getActorShortNameById(lookupActorId): - global actorPropertyEntriesWasInit - global actorPropertyEntries - if not actorPropertyEntriesWasInit: - return '' - else: - for actorEntryTmp in actorPropertyEntries: - if int(actorEntryTmp[0]) == int(lookupActorId): - return actorEntryTmp[1] - return '' - - -def getActorFullNameById(lookupActorId): - global actorPropertyEntriesWasInit - global actorPropertyEntries - if not actorPropertyEntriesWasInit: - return '' - else: - for actorEntryTmp in actorPropertyEntries: - if int(actorEntryTmp[0]) == int(lookupActorId): - return actorEntryTmp[2] - return '' - -def getActorIdByShortName(lookupActorShortName): - global actorPropertyEntriesWasInit - global actorPropertyEntries - if not actorPropertyEntriesWasInit: - return '' - else: - for actorEntryTmp in actorPropertyEntries: - if actorEntryTmp[1] == lookupActorShortName: - return actorEntryTmp[0].zfill(2) - return '' - -# -# -# FOR MIX FILE -# - -# 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 - -# -# aux - sort by first object in list of tuples -def getSortMixFilesKey(item): - keyTmp = item[0] & 0xFFFFFFFF - - signedKeyTmp = ctypes.c_long(keyTmp).value - return signedKeyTmp -# -def outputMIX(): - # output file should be SUBTITLES.MIX - # checking with known hashes to verify calculateFoldHash - #calculateFoldHash('AR01-MIN.SET') - #calculateFoldHash('AR02-MIN.SET') - #calculateFoldHash('CLOVDIES.AUD') - #calculateFoldHash('INTRO.VQA') - - errorFound = False - outMIXFile = None - try: - outMIXFile = open("./SUBTITLES.MIX", 'wb') - except: - errorFound = True - if not errorFound: - # Write header - # 2 bytes: number of entries (NumFiles) - # TODO 4 bytes: size of data segment - # 12 * NumFiles bytes: Entry descriptors table - # 4 bytes: ID (hash) - # 4 bytes: Byte offset in Data Segment - # 4 bytes: Byte length of entry data - # TODO *Data Segment* - contains the file data. Offset from Entry Descriptors does not include header segment byte length. - # Note that the offsets are relative to the start of the body so to find the - # actual offset in the MIX you have to add the size of the header which is - # (6 + (12 * NumFiles)) - - # - # ID column should in ascending order in MIX FILES (the engine uses binary sort to search for files) - # so order the files based on ID hash - # Create a list of 3-item tuples, first item is id, second item is filename - # Then sort the list - # Then write to entry table - # - # Also filenames should be 8 characters at most and 4 more for extension to conform with specs - # ^^ this is done manually by making sure the filenames in the sheets of the excel as compliant - # Based on observations from STARTUP.MIX: - # 1) the hash ids can overflow and so lower numbers seem to appear down in the index table entries list - # -- So we sort hash but we first tranlste the unsigned key to signed with ctypes - # 2) the offsets are not necessarily sorted, meaning that the first entry in the index table won't necessarily have the 0x00000000 offset - i = 0 - mixFileEntries = [] - totalFilesDataSize = 0 - currOffsetForDataSegment = 0 # we start after header and table of index entries, from 0, (but this means that when reading the offset we need to add 6 + numOfFiles * 12). This does not concern us though. - for sheetDialogueName in supportedDialogueSheets: - sheetDialogueNameTRE = sheetDialogueName[:-4] + '.TRE' - if os.path.isfile('./' + sheetDialogueNameTRE): - entryID = calculateFoldHash(sheetDialogueNameTRE) - mixEntryfileSizeBytes = os.path.getsize('./' + sheetDialogueNameTRE) - mixFileEntries.append((entryID, sheetDialogueNameTRE, mixEntryfileSizeBytes)) - totalFilesDataSize += mixEntryfileSizeBytes - - for translatedTREFileName in [ x[0] for x in supportedTranslationSheets] : - if os.path.isfile('./' + translatedTREFileName): - entryID = calculateFoldHash(translatedTREFileName) - mixEntryfileSizeBytes = os.path.getsize('./' + translatedTREFileName) - mixFileEntries.append((entryID, translatedTREFileName, mixEntryfileSizeBytes)) - totalFilesDataSize += mixEntryfileSizeBytes - - for otherFileName in supportedOtherFilesForMix: - if os.path.isfile('./' + otherFileName): - entryID = calculateFoldHash(otherFileName) - mixEntryfileSizeBytes = os.path.getsize('./' + otherFileName) - mixFileEntries.append((entryID, otherFileName, mixEntryfileSizeBytes)) - totalFilesDataSize += mixEntryfileSizeBytes - mixFileEntries.sort(key=getSortMixFilesKey) - # - # We write num of files here. After we verified they exist - # - numOfFiles = len(mixFileEntries) - numOfFilesToWrite = pack('h',numOfFiles) # short 2 bytes - outMIXFile.write(numOfFilesToWrite) - - # This is just the data segment (after the entries index table). Adds up all the file sizes here - totalFilesDataSizeToWrite = pack('I',totalFilesDataSize) # unsigned integer 4 bytes - outMIXFile.write(totalFilesDataSizeToWrite) - - print ("Sorted Entries based on EntryId") - for mixFileEntry in mixFileEntries: - print (''.join('{:08X}'.format(mixFileEntry[0])) + ': ' + mixFileEntry[1] + ' : ' + ''.join('{:08X}'.format(mixFileEntry[2]))) - entryID = mixFileEntry[0] & 0xFFFFFFFF - entryIDToWrite = pack('I',entryID) # unsigned integer 4 bytes - outMIXFile.write(entryIDToWrite) - entryOffset = currOffsetForDataSegment # offsets have base after header and table of index entries - entryOffsetToWrite = pack('I',entryOffset) # unsigned integer 4 bytes - outMIXFile.write(entryOffsetToWrite) - entryByteLength = mixFileEntry[2] # File size - entryByteLengthToWrite = pack('I',entryByteLength) # unsigned integer 4 bytes - outMIXFile.write(entryByteLengthToWrite) - currOffsetForDataSegment += entryByteLength - # Add data segments here - errorReadingFound = False - for mixFileEntry in mixFileEntries: - try: - inEntryMIXFile = open("./"+ mixFileEntry[1], 'rb') - except: - errorReadingFound = True - if not errorReadingFound: - outMIXFile.write(inEntryMIXFile.read()) - inEntryMIXFile.close() - else: - print ("Error while reading in ENTRY file") - break - - outMIXFile.close() - print "TOTAL RESOURCES IN MIX: %d" % (numOfFiles) - return -# -# END FOR MIX FILE -# -# - -#def inputXLS(filename) - #TODO extra pass once the quotes have been updated for weird unicode characters - #TODO some ' quotes appear as \u2019 and others appear normally as '. what's that about? - #DONE manually I've replaced all weird \u2019 single quotes with ''' - #the spanish n is \xf1 -> we put it at ascii value: \xA5 -- font index 0xA6 ? - #the spanish i is \xed -> we put it at ascii value: \xA2 -- font index 0xA3 ? - #pâté - # a actual ascii value is 0xE2 in codepage 1252 -- put it in ascii value 0xA6 (165) -- font index 0xA7 - # e actual ascii value is 0xE9 in codepage 1252 -- put it in ascii value 0xA7 (166) -- font index 0xA8 - #TODO what are other characters are special? - #TODO transition to ASCII chars to store in TRE file? - #DONE manually I've replaced all one-char '...' with three dots - # TODO actors TRE has 0x49 entries, (73 names), but table of ids has 73 entries BUT the offset table (first offset is calced + 0x04, so from end of the first 4 count bytes) has 74 entries. The last entry indexes the end of file (!) - # TODO all strings are NULL terminated in the TRE file! - -def translateQuoteToAsciiProper(cellObj, pSheetName): - newQuoteReplaceSpecials = cellObj.value.encode("utf-8") - #print ('Encoded to unicode: %s ' % (newQuoteReplaceSpecials)) - newQuoteReplaceSpecials = newQuoteReplaceSpecials.decode("utf-8") - - pertinentListOfOutOfOrderGlyphs = [] - #print pSheetName - #print supportedDialogueSheets - #print defaultSubtitlesFontName[:-4] - #print [x[0] for x in listOfFontNamesToOutOfOrderGlyphs] - if pSheetName in supportedDialogueSheets and defaultSubtitlesFontName[:-4] in [x[0] for x in listOfFontNamesToOutOfOrderGlyphs]: - for (tmpFontName, tmpOOOList) in listOfFontNamesToOutOfOrderGlyphs: - if tmpFontName == defaultSubtitlesFontName[:-4]: - pertinentListOfOutOfOrderGlyphs = tmpOOOList - break - elif pSheetName in [x[0] for x in supportedTranslationSheets]: - pertinentFontType = '' - #[treAndFontTypeTuple for treAndFontTypeTuple in supportedTranslationSheets if treAndFontTypeTuple[0] == pSheetName] - for (tmpSheetName, tmpFontType) in supportedTranslationSheets: - if tmpSheetName == pSheetName: - pertinentFontType = tmpFontType - break - for (tmpFontName, tmpOOOList) in listOfFontNamesToOutOfOrderGlyphs: - if tmpFontName == pertinentFontType: - pertinentListOfOutOfOrderGlyphs = tmpOOOList - break - - #newQuoteReplaceSpecials = newQuoteReplaceSpecials.replace(u"\u0386", u"\u00A3") - for repTuple in pertinentListOfOutOfOrderGlyphs: - newQuoteReplaceSpecials = newQuoteReplaceSpecials.replace(repTuple[0], repTuple[1]) - # WORKAROUND, we re-replace the spanish i delegate again here! -# newQuoteReplaceSpecials = newQuoteReplaceSpecials.replace(u'\xa2', u'\u0386') # this is needed for spanish i because in utf-8 it's actually the u'\u0386' that's assigned to A tonomeno which is the delegate. -# newQuoteReplaceSpecials = newQuoteReplaceSpecials.replace(u"\u0386", u"\u00A3") -# #newQuoteReplaceSpecials = newQuoteReplaceSpecials.replace(u"\u0386", u"\u00A3") # greek alpha tonomeno -- TODO which character is this in the excel (utf value) ??? -# newQuoteReplaceSpecials = newQuoteReplaceSpecials.replace(u"\u00ed", u"\u00A2") # spanish i -# newQuoteReplaceSpecials = newQuoteReplaceSpecials.replace(u"\u00f1", u"\u00A5") # spanish n -# #newQuoteReplaceSpecials = newQuoteReplaceSpecials.replace(u"\u00A4", u"\u00A5") # spanish n -# newQuoteReplaceSpecials = newQuoteReplaceSpecials.replace(u"\u00e2", u"\u00A6") # a from pate -- todo this is not confirmed in-game font (but it is in our external font as of yet) -# newQuoteReplaceSpecials = newQuoteReplaceSpecials.replace(u"\u00e9", u"\u00A7") # e from pate -- todo this is not confirmed in-game font (but it is in our external font as of yet) - # other replacements. - newQuoteReplaceSpecials = newQuoteReplaceSpecials.replace(u"\u2019", u"\u0027") # right single quote - newQuoteReplaceSpecials = newQuoteReplaceSpecials.replace(u"\u2018", u"\u0027") # left single quote - newQuoteReplaceSpecials = newQuoteReplaceSpecials.replace(u"\u2026", u"\u002e\u002e\u002e") # three dots together (changes length) - newQuoteReplaceSpecials = newQuoteReplaceSpecials.replace(u"\u201D", u"\u0022") # right double quote - newQuoteReplaceSpecials = newQuoteReplaceSpecials.replace(u"\u201C", u"\u0022") # left double quote - # TODO? replace new line ??? with another char (maybe |)? - - #newQuoteReplaceSpecialsUnicode = unicode(newQuoteReplaceSpecials, 'utf-8') - #newQuoteReplaceSpecialsStr = unicode.encode("%s" % newQuoteReplaceSpecials, targetEncoding) - - #print type(newQuoteReplaceSpecials) # type is unicode - #print type(newQuoteReplaceSpecials.encode('utf-8')) # type is str -# print targetEncoding -# print newQuoteReplaceSpecials -# newQuoteReplaceSpecialsDec = newQuoteReplaceSpecials.decode(targetEncoding) - newQuoteReplaceSpecialsRetStr = '' - newQuoteReplaceSpecialsRetStr = newQuoteReplaceSpecials.encode(targetEncoding) -# try: -# newQuoteReplaceSpecialsRetStr = newQuoteReplaceSpecials.encode(targetEncoding) -# except: -# print "===============================================================================" -# print "===============================================================================" -# print "ERROR:" -# print newQuoteReplaceSpecials -# print newQuoteReplaceSpecials.encode(targetEncoding, errors='xmlcharrefreplace') -# print "===============================================================================" -# print "===============================================================================" -# newQuoteReplaceSpecialsRetStr = newQuoteReplaceSpecials.encode(targetEncoding, errors='xmlcharrefreplace') - return newQuoteReplaceSpecialsRetStr -# return newQuoteReplaceSpecialsEnStr - - -def inputXLS(filename): - global numOfSpokenQuotes - global tableOfStringIds - global tableOfStringOffsets - global tableOfStringEntries - # Open the workbook - xl_workbook = xlrd.open_workbook(filename, encoding_override="utf-8") - - - # List sheet names, and pull a sheet by name - # - # sheet_names = xl_workbook.sheet_names() - #print('Sheet Names', sheet_names) - # - #xl_sheet = xl_workbook.sheet_by_name(sheet_names[0]) - - # Or grab the first sheet by index - # (sheets are zero-indexed) - # First sheet is the in-game quotes - # - # xl_sheet = xl_workbook.sheet_by_index(0) - # - # - mergedListOfSubtitleSheetsAndTranslatedTREs = supportedDialogueSheets + [ x[0] for x in supportedTranslationSheets ] - - for sheetDialogueName in mergedListOfSubtitleSheetsAndTranslatedTREs: - xl_sheet = xl_workbook.sheet_by_name(sheetDialogueName) - if(xl_sheet is not None): - print ('Sheet name: %s' % xl_sheet.name) - numOfSpokenQuotes = xl_sheet.nrows - 2 # all rows minus the first TWO rows with headers - print ('num of spoken quotes: %d' % numOfSpokenQuotes) - # stats for debug - extremeQuotesList = [] - longestLength = 0 - predefinedLengthThreshold = 145 - quoteNumAboveThreshold = 0 - # end of stats for debug - - - absStartOfIndexTable = 4 - absStartOfOffsetTable = absStartOfIndexTable + (numOfSpokenQuotes * 4) # = 4 + 0x1577 * 4 = 4 + 0x55DC = 0x55E0 - absStartOfStringTable = absStartOfOffsetTable + ((numOfSpokenQuotes+1) * 4) # = 0x55E0 + (0x1578 * 4) = 0xABC0 - curStrStartOffset = absStartOfStringTable - 4 - newQuoteReplaceSpecialsAscii = '' - tmpQuoteID = 0 - #switchFlagShowQuote = False # for debugging - tmpStartFrame = 0 # for VQA sheets - tmpEndFrame = 0 # for VQA sheets - mode = 0 # init to unknown - if xl_sheet.name == supportedDialogueSheets[0]: - print 'IN GAME QUOTES' - mode = 1 #in-game quote - elif xl_sheet.name in supportedDialogueSheets: - print 'VQA SCENE DIALOGUE' - mode = 2 #VQA - elif xl_sheet.name in [ x[0] for x in supportedTranslationSheets ]: - print 'TRANSLATED TRE' - mode = 3 # Translated TRE - # - del tableOfStringIds[:] - del tableOfStringEntries[:] - del tableOfStringOffsets[:] - for row_idx in range(2, xl_sheet.nrows): - #print "Line %d" % (row_idx) - for col_idx in range(0, xl_sheet.ncols): - cell_obj = xl_sheet.cell(row_idx, col_idx) - # - # FOR IN-GAME QUOTES -- Iterate through columns starting from col 0. We need cols: 0, 2 - # - if mode == 1: - #print ('Column: [%s] cell_obj: [%s]' % (col_idx, cell_obj)) - if(col_idx == 0): - #switchFlagShowQuote = False - twoTokensfirstColSplitAtDotXLS = cell_obj.value.split('.', 1) - if len(twoTokensfirstColSplitAtDotXLS) == 2: - twoTokensfirstColSplitAtDashXLS = twoTokensfirstColSplitAtDotXLS[0].split('-', 1) - if len(twoTokensfirstColSplitAtDashXLS) == 2: - tmpQuoteID = int( twoTokensfirstColSplitAtDashXLS[0]) * 10000 + int(twoTokensfirstColSplitAtDashXLS[1]) - #print ('row_idx %d. tag %s = quoteId [%d]' % (row_idx, twoTokensfirstColSplitAtDotXLS[0], tmpQuoteID)) - tableOfStringIds.append(tmpQuoteID) - #if(tmpQuoteID == 160110 or tmpQuoteID == 160010): - # switchFlagShowQuote = True - - elif(col_idx == 1) : - #if switchFlagShowQuote == True: - # print ('length: %d: %s' % (len(cell_obj.value), cell_obj.value)) - # print ('object: %s' % (cell_obj)) - # #newQuoteReplaceSpecials = cell_obj.value.decode("utf-8") # unicode(cell_obj.value, 'windows-1252') - # #print ('decoded to unicode: %s ' % (newQuoteReplaceSpecials)) # error with char xf1 - newQuoteReplaceSpecialsAscii = translateQuoteToAsciiProper(cell_obj, xl_sheet.name) - #if switchFlagShowQuote == True: - # print ('length: %d: %s' % (len(newQuoteReplaceSpecialsAscii), newQuoteReplaceSpecialsAscii)) - #print ':'.join(x.encode('hex') for x in newQuoteReplaceSpecialsAscii) # seems to work. new chars are non-printable but exist in string - - tableOfStringEntries.append(newQuoteReplaceSpecialsAscii) - tableOfStringOffsets.append(curStrStartOffset) - curStrStartOffset += (len(newQuoteReplaceSpecialsAscii) + 1) - if ( longestLength < len(newQuoteReplaceSpecialsAscii)): - longestLength = len(newQuoteReplaceSpecialsAscii) - if ( predefinedLengthThreshold < len(newQuoteReplaceSpecialsAscii)): - extremeQuotesList.append((tmpQuoteID, newQuoteReplaceSpecialsAscii)) - quoteNumAboveThreshold += 1 - #print ('row_idx %d. tag %s = quoteId [%d], length: %d: %s' % (row_idx, twoTokensfirstColSplitAtDotXLS[0], tmpQuoteID, len(newQuoteReplaceSpecialsAscii), newQuoteReplaceSpecialsAscii)) - # - # FOR VQAs -- Iterate through columns starting from col 2. We need cols: 2, 9, 10 - # - elif mode == 2: - if(col_idx == 2): # subtitle text - newQuoteReplaceSpecialsAscii = translateQuoteToAsciiProper(cell_obj, xl_sheet.name) - #print ('length: %d: %s' % (len(newQuoteReplaceSpecialsAscii), newQuoteReplaceSpecialsAscii)) - #print ':'.join(x.encode('hex') for x in newQuoteReplaceSpecialsAscii) # seems to work. new chars are non-printable but exist in string - # don't append to tableOfStringEntries yet - elif(col_idx == 9): # startFrame - #print "cell: %s" % (cell_obj.value) - tmpStartFrame = int(cell_obj.value) - elif(col_idx == 10): # endFrame - tmpEndFrame = int(cell_obj.value) - tmpQuoteID = tmpStartFrame | (tmpEndFrame << 16) # top 16 bits are end frame (up to 65536 frames which is enough) and low 16 bits are startFrame - - tableOfStringIds.append(tmpQuoteID) - tableOfStringEntries.append(newQuoteReplaceSpecialsAscii) - tableOfStringOffsets.append(curStrStartOffset) - curStrStartOffset += (len(newQuoteReplaceSpecialsAscii) + 1) - if ( longestLength < len(newQuoteReplaceSpecialsAscii)): - longestLength = len(newQuoteReplaceSpecialsAscii) - if ( predefinedLengthThreshold < len(newQuoteReplaceSpecialsAscii)): - extremeQuotesList.append((tmpQuoteID, newQuoteReplaceSpecialsAscii)) - quoteNumAboveThreshold += 1 - # - # For translated TRE sheets the id is already in first column, the text is in the next one - # - elif mode == 3: - #print ('Column: [%s] cell_obj: [%s]' % (col_idx, cell_obj)) - if(col_idx == 0): - tmpQuoteID = int(cell_obj.value) - tableOfStringIds.append(tmpQuoteID) - elif(col_idx == 1) : - #if switchFlagShowQuote == True: - # print ('length: %d: %s' % (len(cell_obj.value), cell_obj.value)) - # print ('object: %s' % (cell_obj)) - # #newQuoteReplaceSpecials = cell_obj.value.decode("utf-8") # unicode(cell_obj.value, 'windows-1252') - # #print ('decoded to unicode: %s ' % (newQuoteReplaceSpecials)) # error with char xf1 - newQuoteReplaceSpecialsAscii = translateQuoteToAsciiProper(cell_obj, xl_sheet.name) - #if switchFlagShowQuote == True: - # print ('length: %d: %s' % (len(newQuoteReplaceSpecialsAscii), newQuoteReplaceSpecialsAscii)) - #print ':'.join(x.encode('hex') for x in newQuoteReplaceSpecialsAscii) # seems to work. new chars are non-printable but exist in string - - tableOfStringEntries.append(newQuoteReplaceSpecialsAscii) - tableOfStringOffsets.append(curStrStartOffset) - curStrStartOffset += (len(newQuoteReplaceSpecialsAscii) + 1) - if ( longestLength < len(newQuoteReplaceSpecialsAscii)): - longestLength = len(newQuoteReplaceSpecialsAscii) - if ( predefinedLengthThreshold < len(newQuoteReplaceSpecialsAscii)): - extremeQuotesList.append((tmpQuoteID, newQuoteReplaceSpecialsAscii)) - quoteNumAboveThreshold += 1 - #print ('row_idx %d. tag %s = quoteId [%d], length: %d: %s' % (row_idx, twoTokensfirstColSplitAtDotXLS[0], tmpQuoteID, len(newQuoteReplaceSpecialsAscii), newQuoteReplaceSpecialsAscii)) - - tableOfStringOffsets.append(curStrStartOffset) # the final extra offset entry - print 'Longest Length = %d, quotes above threshold (%d): %d' % (longestLength, predefinedLengthThreshold, quoteNumAboveThreshold) - for extremQuotTuple in extremeQuotesList: - print "Id: %d, Q: %s" % (extremQuotTuple[0], extremQuotTuple[1]) - # - # WRITE TO TRE FILE - # - errorFound = False - outTREFile = None - outTREFileName = sheetDialogueName[:-4] - try: - outTREFile = open("./" + outTREFileName + ".TRE", 'wb') - except: - errorFound = True - if not errorFound: - numOfSpokenQuotesToWrite = pack('I',numOfSpokenQuotes) # unsigned integer 4 bytes - outTREFile.write(numOfSpokenQuotesToWrite) - # write string IDs table - for idxe in range(0,len(tableOfStringIds)): - idOfStringToWrite = pack('I',tableOfStringIds[idxe]) # unsigned integer 4 bytes - outTREFile.write(idOfStringToWrite) - # write string offsets table - for idxe in range(0,len(tableOfStringOffsets)): - offsetOfStringToWrite = pack('I',tableOfStringOffsets[idxe]) # unsigned integer 4 bytes - outTREFile.write(offsetOfStringToWrite) - #write strings with null terminator - for idxe in range(0,len(tableOfStringEntries)): - outTREFile.write(tableOfStringEntries[idxe]) - outTREFile.write('\0') - outTREFile.close() - return -# -# -# -# ######################## -# main -# 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__": - pathToQuoteExcelFile = "" - invalidSyntax = False - -# print "Len of sysargv = %s" % (len(sys.argv)) - if len(sys.argv) == 2: - if(sys.argv[1] == '--help'or sys.argv[1] == '-h'): - print "%s %s supports Blade Runner (English version, CD edition)." % (app_name_spaced, app_version) - print "Created by Praetorian of the classic adventures in Greek team." - print "Always keep backups!" - print "--------------------" - print "Preparatory steps:" - print "0. Keep actornames.txt in the same folder as this app." - print "1. Copy the BladeRunnerPCTLK.xlsx file (latest version, downloaded from Google Sheets) in some folder on your PC." - print "--------------------" - print "%s takes 1 mandatory argument:" % (app_name_spaced) - print "Valid syntax (in-game and VQA quotes): %s -x [folderpath_to_ BladeRunnerPCTLK_xlsx_file]" % (app_name) - print "1st argument is the path to the excel file with the subtitle quotes." - print "If the app finishes successfully a " + supportedDialogueSheets[0] + " and a few other .TRE files for the VQAs " - print "in the Excel file as well as a SUBTITLES.MIX file containing all of them will be created in the same folder with the app." - print "--------------------" - print "Thank you for using this app." - print "Please provide any feedback to: %s " % (company_email) - sys.exit() - elif(sys.argv[1] == '--version' or sys.argv[1] == '-v'): - print "%s %s supports Blade Runner (English version, CD edition)." % (app_name_spaced, app_version) - print "Please provide any feedback to: %s " % (company_email) - sys.exit() - else: - invalidSyntax = True - elif len(sys.argv) == 3: - if(sys.argv[1] == '-x'): - pathToQuoteExcelFile = sys.argv[2] - else: - invalidSyntax = True - - if not pathToQuoteExcelFile: - invalidSyntax = True - - if not invalidSyntax: - # parse any overrideEncoding file if exists: - initOverrideEncoding() - - - # parse the EXCEL File - # parse Actors files: - initActorPropertyEntries() -# for actorEntryTmp in actorPropertyEntries: -# print "Found actor: %s %s %s" % (actorEntryTmp[0], actorEntryTmp[1], actorEntryTmp[2]) - inputXLS(pathToQuoteExcelFile) - outputMIX() - - else: - invalidSyntax = True - - if invalidSyntax == True: - print "Invalid syntax\n Try: \n %s --help for more info \n %s --version for version info " % (app_name, app_name) - print "Valid syntax (in-game and VQA quotes): %s -x [folderpath_to_ BladeRunnerPCTLK_xlsx_file]" % (app_name) - print "1st argument is the path to the excel file with the subtitle quotes." - print "If the app finishes successfully a " + supportedDialogueSheets[0] + " and a few other .TRE files for the VQAs " - print "in the Excel file as well as a SUBTITLES.MIX file containing all of them will be created in the same folder with the app." - tmpi = 0 - for tmpArg in sys.argv: - if tmpi==0: #skip first argument - tmpi+=1 - continue - print "\nArgument: %s" % (tmpArg) - tmpi+=1 -else: - ## debug - #print '%s was imported from another module' % (app_name_spaced,) - pass diff --git a/devtools/create_bladerunner/subtitles/module.mk b/devtools/create_bladerunner/subtitles/module.mk index 1bfdd397f8..66ebab78c3 100644 --- a/devtools/create_bladerunner/subtitles/module.mk +++ b/devtools/create_bladerunner/subtitles/module.mk @@ -1,2 +1,49 @@ MODULE := devtools/create_bladerunner/subtitles + +# Set the name of the final output +TOOL_OUTPUT := SUBTITLES.MIX +FONT_OUTPUT := SUBTLS_E.FON + +BLADERUNNER_SUBTITLES_SCRIPTS_ROOT_FOLDER := $(srcdir)/devtools/create_bladerunner/subtitles +BLADERUNNER_SUBTITLES_SAMPLE_INPUT_FOLDER := $(srcdir)/devtools/create_bladerunner/subtitles/sampleInput +INTERMEDIATE_RESOURCE_FILES_UI := "OPTIONS.TRE" "DLGMENU.TRE" "SCORERS.TRE" "VK.TRE" "CLUES.TRE" "CRIMES.TRE" "ACTORS.TRE" "HELP.TRE" "AUTOSAVE.TRE" "ERRORMSG.TRE" "SPINDEST.TRE" "KIA.TRE" "KIACRED.TRE" "CLUETYPE.TRE" "ENDCRED.TRE" "POGO.TRE" +INTERMEDIATE_RESOURCE_FILES_SUBS := "INGQUO_E.TRE" "WSTLGO_E.TRE" "BRLOGO_E.TRE" "INTRO_E.TRE" "MW_A_E.TRE" "MW_B01_E.TRE" "MW_B02_E.TRE" "MW_B03_E.TRE" "MW_B04_E.TRE" "MW_B05_E.TRE" "INTRGT_E.TRE" "MW_D_E.TRE" "MW_C01_E.TRE" "MW_C02_E.TRE" "MW_C03_E.TRE" "END04A_E.TRE" "END04B_E.TRE" "END04C_E.TRE" "END06_E.TRE" "END01A_E.TRE" "END01B_E.TRE" "END01C_E.TRE" "END01D_E.TRE" "END01E_E.TRE" "END01F_E.TRE" "END03_E.TRE" +INPUT_TRANSCRIPT_FILENAME := englishTranscript.xls +INPUT_TRANSCRIPT_AUX_CONF_FILENAME := configureFontsTranslation.txt +INPUT_FONT_GLYPHS_PNG_FILENAME := subtitlesFont.png +INPUT_FONT_GLYPHS_PNG_AUX_CONF_FILENAME := overrideEncodingSUBLTS.txt + +$(MODULE): $(TOOL_OUTPUT) +# +# Font file creation from an input PNG image named $(INPUT_FONT_GLYPHS_PNG_FILENAME) +# The $(INPUT_FONT_GLYPHS_PNG_AUX_CONF_FILENAME) is used to configure the font creation +# also the command line switches pxLL, pxTT, pxKn, pxWS configure additional aspects for the font creation +$(FONT_OUTPUT): $(BLADERUNNER_SUBTITLES_SAMPLE_INPUT_FOLDER)/$(INPUT_FONT_GLYPHS_PNG_FILENAME) $(BLADERUNNER_SUBTITLES_SAMPLE_INPUT_FOLDER)/$(INPUT_FONT_GLYPHS_PNG_AUX_CONF_FILENAME) + $(info ---------) + $(info Creating Blade Runner subtitles font $(FONT_OUTPUT)...) + $(info This process assumes that the folder: ) + $(info $(BLADERUNNER_SUBTITLES_SAMPLE_INPUT_FOLDER)) + $(info contains: ) + $(info *. $(INPUT_FONT_GLYPHS_PNG_FILENAME) - a PNG (image) input file with the Font glyphs) + $(info *. $(INPUT_FONT_GLYPHS_PNG_AUX_CONF_FILENAME) - a TXT (text) input file with configuration settings for the glyph image processing) + $(info If successful a $(FONT_OUTPUT) file will be created in your working directory) + $(BLADERUNNER_SUBTITLES_SCRIPTS_ROOT_FOLDER)/fontCreator/fontCreator.py -im $(BLADERUNNER_SUBTITLES_SAMPLE_INPUT_FOLDER)/$(INPUT_FONT_GLYPHS_PNG_FILENAME) -oe $(BLADERUNNER_SUBTITLES_SAMPLE_INPUT_FOLDER)/$(INPUT_FONT_GLYPHS_PNG_AUX_CONF_FILENAME) -om $(FONT_OUTPUT) -pxLL 42 -pxTT 30 -pxKn 1 -pxWS 7 + +# Creation of final output mix file SUBTILES.MIX +# The MIX file will pack the fonts file $(FONT_OUTPUT) as well as resources created from the transcript (EXCEL) file $(INPUT_TRANSCRIPT_FILENAME) +# The $(INPUT_TRANSCRIPT_AUX_CONF_FILENAME) file is used to configure the creation of the mix file +# This command sequence will erase any intermediate resource files (.TRE) at the end. +# The $(FONT_OUTPUT) file will not be erased. +$(TOOL_OUTPUT): $(FONT_OUTPUT) $(BLADERUNNER_SUBTITLES_SCRIPTS_ROOT_FOLDER)/common/actornames.txt $(BLADERUNNER_SUBTITLES_SAMPLE_INPUT_FOLDER)/$(INPUT_TRANSCRIPT_AUX_CONF_FILENAME) $(BLADERUNNER_SUBTITLES_SAMPLE_INPUT_FOLDER)/$(INPUT_TRANSCRIPT_FILENAME) $(BLADERUNNER_SUBTITLES_SAMPLE_INPUT_FOLDER)/$(INPUT_TRANSCRIPT_AUX_CONF_FILENAME) + $(info ---------) + $(info Creating Blade Runner subtitles MIX file: $(TOOL_OUTPUT)...) + $(info This process assumes that the folder: ) + $(info $(BLADERUNNER_SUBTITLES_SAMPLE_INPUT_FOLDER)) + $(info contains: ) + $(info *. $(INPUT_TRANSCRIPT_FILENAME) - an XLS (Excel) input file with the transcript) + $(info *. $(INPUT_TRANSCRIPT_AUX_CONF_FILENAME) - a TXT (text) input file with configuration settings for the transcript processing) + $(info If successful a $(TOOL_OUTPUT) file will be created in your working directory) + $(info Copy the $(TOOL_OUTPUT) into your Blade Runner game directory) + $(BLADERUNNER_SUBTITLES_SCRIPTS_ROOT_FOLDER)/mixResourceCreator/mixResourceCreator.py -x $(BLADERUNNER_SUBTITLES_SAMPLE_INPUT_FOLDER)/$(INPUT_TRANSCRIPT_FILENAME) -ian $(BLADERUNNER_SUBTITLES_SCRIPTS_ROOT_FOLDER)/common/actornames.txt -cft $(BLADERUNNER_SUBTITLES_SAMPLE_INPUT_FOLDER)/$(INPUT_TRANSCRIPT_AUX_CONF_FILENAME) + -$(RM) $(INTERMEDIATE_RESOURCE_FILES_UI) $(INTERMEDIATE_RESOURCE_FILES_SUBS) diff --git a/devtools/create_bladerunner/subtitles/quotesSpreadsheetCreator/audFileDecode.py b/devtools/create_bladerunner/subtitles/quotesSpreadsheetCreator/audFileDecode.py index a46b3d8798..2c87108479 100644 --- a/devtools/create_bladerunner/subtitles/quotesSpreadsheetCreator/audFileDecode.py +++ b/devtools/create_bladerunner/subtitles/quotesSpreadsheetCreator/audFileDecode.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python2.7 # -*- coding: UTF-8 -*- # import ctypes diff --git a/devtools/create_bladerunner/subtitles/quotesSpreadsheetCreator/audFileLib.py b/devtools/create_bladerunner/subtitles/quotesSpreadsheetCreator/audFileLib.py index 1adf4bc969..682a31e16c 100644 --- a/devtools/create_bladerunner/subtitles/quotesSpreadsheetCreator/audFileLib.py +++ b/devtools/create_bladerunner/subtitles/quotesSpreadsheetCreator/audFileLib.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python2.7 # -*- coding: UTF-8 -*- # import os, sys, shutil diff --git a/devtools/create_bladerunner/subtitles/quotesSpreadsheetCreator/quoteSpreadsheetCreator.py b/devtools/create_bladerunner/subtitles/quotesSpreadsheetCreator/quoteSpreadsheetCreator.py new file mode 100644 index 0000000000..c1bdc84413 --- /dev/null +++ b/devtools/create_bladerunner/subtitles/quotesSpreadsheetCreator/quoteSpreadsheetCreator.py @@ -0,0 +1,10 @@ +#!/usr/bin/env python2.7 +# -*- coding: UTF-8 -*- +import sys +if not (sys.version_info[0] == 2 and sys.version_info[1] == 7): + sys.stdout.write("Error:: Blade Runner Quotes Spreadsheet Creator script requires Python 2.7\n") + sys.exit(1) + +import sortBladeRunnerWavs02 +if __name__ == "__main__": + sortBladeRunnerWavs02.main(sys.argv[0:])
\ No newline at end of file diff --git a/devtools/create_bladerunner/subtitles/quotesSpreadsheetCreator/sortBladeRunnerWavs02.py b/devtools/create_bladerunner/subtitles/quotesSpreadsheetCreator/sortBladeRunnerWavs02.py index 4bc5bb7e23..b3f368ed40 100644 --- a/devtools/create_bladerunner/subtitles/quotesSpreadsheetCreator/sortBladeRunnerWavs02.py +++ b/devtools/create_bladerunner/subtitles/quotesSpreadsheetCreator/sortBladeRunnerWavs02.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python2.7 # -*- coding: UTF-8 -*- # # Created by Praetorian (ShadowNate) for Classic Adventures in Greek @@ -24,9 +24,12 @@ from treFileLib import * #sys.setdefaultencoding('utf8') company_email = "classic.adventures.in.greek@gmail.com" -app_version = "0.50" +app_version = "0.70" app_name = "sortBladeRunnerWavs" -app_name_spaced = "Sort Blade Runner Audio Speech Files" +app_name_spaced = "Blade Runner Transcript Excel Creator (bare bones)" +app_short_desc = "Create an Excel (.XLS) for transcribing Blade Runner. It can also extract TRE files and export WAV files for game's resources. " +traceModeEnabled = False + stringReplacementForRootFolderWithExtractedFiles = "" numReplaceStartingCharacters = 0 @@ -67,12 +70,18 @@ def calculateFoldHash(strFileName): return hash # Fill the actorPropertyEntries table -def initActorPropertyEntries(): +def initActorPropertyEntries(thePathToActorNamesTxt): global actorPropertyEntriesWasInit global actorPropertyEntries firstLine = True # print "opening actornames" - with open("./actornames.txt") as tsv: + 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) + with open(thePathToActorNamesTxt) as tsv: for line in csv.reader(tsv, dialect="excel-tab"): #skip first line header if firstLine == True: @@ -122,7 +131,7 @@ def getActorShortNameAndLocalQuoteIdByAUDHashID(audHashId): actorShortName = '' actorLocalQuoteId = 0 if not actorPropertyEntriesWasInit: - print "Error actor properties were not initialized!" + print "Error:: actor properties were not initialized!" return (actorId, actorShortName, actorLocalQuoteId) for actorEntryTmp in actorPropertyEntries: @@ -155,7 +164,7 @@ def inputTLKsExtract(inputTLKpath, outputWAVpath): # fileID # segment offset # file size - print "Checking in %s for TLK files to extract to %s" % (inputTLKpath, outputWAVpath) + print "Info:: Checking in %s for TLK files to extract 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): @@ -165,18 +174,20 @@ def inputTLKsExtract(inputTLKpath, outputWAVpath): inputTLKFilesFound.append(tlkTuple) break for tmpTLKfileTuple in inputTLKFilesFound: - print "Found TLK: %s" % ('"' + inputTLKpath + tmpTLKfileTuple[0] + '"') + if traceModeEnabled: + print "Info:: Found TLK: %s" % ('"' + inputTLKpath + tmpTLKfileTuple[0] + '"') errorFound = False inTLKFile = None # # Create output folder if not exists at output path - print "Ensuring output directory %s" % (os.path.join(outputWAVpath, tmpTLKfileTuple[1] )) + if traceModeEnabled: + 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 "Unexpected error:", sys.exc_info()[0] + print "Error:: Unexpected error:", sys.exc_info()[0] raise if not errorFound: tmpBuff = inTLKFile.read(2) @@ -192,9 +203,10 @@ def inputTLKsExtract(inputTLKpath, outputWAVpath): # 2 + 4 = 6 bytes short MIX header # 12 bytes per TLK entry in entries table # quick size validation - print "Entries: %d, data segment %d bytes" % (numOfEntriesToExtract, allTlkFileSize) + if traceModeEnabled: + print "Entries: %d, data segment %d bytes" % (numOfEntriesToExtract, allTlkFileSize) if allActualBytesInMixFile != 2 + 4 + 12 * numOfEntriesToExtract + allTlkFileSize: - print "Error: TLK file size mismatch with reported size in header for %s!" % (tmpTLKfileTuple[0]) + print "Error:: TLK file size mismatch with reported size in header for %s!" % (tmpTLKfileTuple[0]) else: # # 12 bytes per entry @@ -213,7 +225,8 @@ def inputTLKsExtract(inputTLKpath, outputWAVpath): tmpBuff = inTLKFile.read(4) tmpRdTuple = struct.unpack('I', tmpBuff) sizeOfAUDEntry = tmpRdTuple[0] - print "Entry: %s, offset %s, data segment %s bytes" % (''.join('{:08X}'.format(idOfAUDEntry)), ''.join('{:08X}'.format(offsetOfAUDEntry)),''.join('{:08X}'.format(sizeOfAUDEntry))) + if traceModeEnabled: + print "Entry: %s, offset %s, data segment %s bytes" % (''.join('{:08X}'.format(idOfAUDEntry)), ''.join('{:08X}'.format(offsetOfAUDEntry)),''.join('{:08X}'.format(sizeOfAUDEntry))) # # put file in AUD object # do we need AUD decode? @@ -228,7 +241,7 @@ def inputTLKsExtract(inputTLKpath, outputWAVpath): # inTLKFile.seek(2 + 4 + 12*numOfEntriesToExtract + offsetOfAUDEntry) if(offsetOfAUDEntry + sizeOfAUDEntry > allTlkFileSize): - print "Error: AUD file size mismatch with reported size in entry header!" + print "Error:: AUD file size mismatch with reported size in entry header!" else: audFileBuffer = inTLKFile.read(sizeOfAUDEntry) if (len(audFileBuffer) == sizeOfAUDEntry): @@ -244,11 +257,12 @@ def inputTLKsExtract(inputTLKpath, outputWAVpath): if not os.path.isfile(os.path.join(outputWAVpath, tmpTLKfileTuple[1], targetSimpleFileName) ): thisAudFile.extract_as_wav(audFileBuffer, os.path.join(outputWAVpath, tmpTLKfileTuple[1], targetSimpleFileName) ) else: - print "Output file %s already exists. Skipping..." % (os.path.join(outputWAVpath, tmpTLKfileTuple[1], targetSimpleFileName)) + if traceModeEnabled: + print "Info:: Output file %s already exists. Skipping..." % (os.path.join(outputWAVpath, tmpTLKfileTuple[1], targetSimpleFileName)) else: - print "Error while LOADING aud file!" + print "Error:: while LOADING aud file!" else: - print "Error while reading AUD file %s into mem buffer" % (''.join('{:08X}'.format(idOfAUDEntry))) + print "Error:: while reading AUD file %s into mem buffer" % (''.join('{:08X}'.format(idOfAUDEntry))) inTLKFile.close() @@ -257,7 +271,7 @@ def inputTLKsExtract(inputTLKpath, outputWAVpath): return def inputMIXExtractTREs(inputMIXpath, excelOutBook = None): - print "Checking in %s for MIX files to extract TRE's from" % (inputMIXpath) + print "Info:: Checking in %s for MIX files to extract TRE's from" % (inputMIXpath) inputMIXFilesFound = [] # breaking after first for loop yields only the top directory files, which is what we want for (dirpath, dirnames, filenames) in walk(inputMIXpath): @@ -267,7 +281,8 @@ def inputMIXExtractTREs(inputMIXpath, excelOutBook = None): inputMIXFilesFound.append(mixFileName) break for tmpMIXfileName in inputMIXFilesFound: - print "Found MIX: %s" % ('"' + inputMIXpath + tmpMIXfileName + '"') + if traceModeEnabled: + print "Found MIX: %s" % ('"' + inputMIXpath + tmpMIXfileName + '"') errorFound = False inMIXFile = None # @@ -275,7 +290,7 @@ def inputMIXExtractTREs(inputMIXpath, excelOutBook = None): inMIXFile = open(os.path.join(inputMIXpath,tmpMIXfileName), 'rb') except: errorFound = True - print "Unexpected error:", sys.exc_info()[0] + print "Error:: Unexpected error:", sys.exc_info()[0] raise if not errorFound: totalTREs = 0 @@ -292,9 +307,10 @@ def inputMIXExtractTREs(inputMIXpath, excelOutBook = None): # 2 + 4 = 6 bytes short MIX header # 12 bytes per MIX entry in entries table # quick size validation - print "Entries: %d, data segment %d bytes" % (numOfEntriesToExtract, allMixFileSize) + if traceModeEnabled: + print "Entries: %d, data segment %d bytes" % (numOfEntriesToExtract, allMixFileSize) if allActualBytesInMixFile != 2 + 4 + 12 * numOfEntriesToExtract + allMixFileSize: - print "Error: MIX file size mismatch with reported size in header for %s!" % (tmpMIXfileName) + print "Error:: MIX file size mismatch with reported size in header for %s!" % (tmpMIXfileName) else: # # 12 bytes per entry @@ -323,7 +339,8 @@ def inputMIXExtractTREs(inputMIXpath, excelOutBook = None): break if (foundTREFile == True): - print "Entry Name: %s, Entry ID: %s, offset %s, data segment %s bytes" % (currTreFileName, ''.join('{:08X}'.format(idOfMIXEntry)), ''.join('{:08X}'.format(offsetOfMIXEntry)),''.join('{:08X}'.format(sizeOfMIXEntry))) + if traceModeEnabled: + print "Entry Name: %s, Entry ID: %s, offset %s, data segment %s bytes" % (currTreFileName, ''.join('{:08X}'.format(idOfMIXEntry)), ''.join('{:08X}'.format(offsetOfMIXEntry)),''.join('{:08X}'.format(sizeOfMIXEntry))) # # IF TRE FILE: # put file in TRE object @@ -331,14 +348,15 @@ def inputMIXExtractTREs(inputMIXpath, excelOutBook = None): # inMIXFile.seek(2 + 4 + 12*numOfEntriesToExtract + offsetOfMIXEntry) if(offsetOfMIXEntry + sizeOfMIXEntry > allMixFileSize): - print "Error: TRE file size mismatch with reported size in entry header!" + print "Error:: TRE file size mismatch with reported size in entry header!" else: treFileBuffer = inMIXFile.read(sizeOfMIXEntry) if (len(treFileBuffer) == sizeOfMIXEntry): # load TRE file thisTreFile = treFile() if (thisTreFile.loadTreFile(treFileBuffer, allMixFileSize)): - print "TRE file loaded" + if traceModeEnabled: + print "Info:: TRE file loaded" if excelOutBook != None: sh = excelOutBook.add_sheet(currTreFileName) n = 0 # keeps track of rows @@ -377,11 +395,11 @@ def inputMIXExtractTREs(inputMIXpath, excelOutBook = None): # pass totalTREs = totalTREs + 1 else: - print "Error while LOADING TRE file!" + print "Error:: while LOADING TRE file!" else: - print "Error while reading TRE file %s into mem buffer" % (''.join('{:08X}'.format(idOfMIXEntry))) + print "Error:: while reading TRE file %s into mem buffer" % (''.join('{:08X}'.format(idOfMIXEntry))) inMIXFile.close() - print "Total TREs: %d " % (totalTREs) + print "Info:: Total TREs: %d " % (totalTREs) return @@ -494,15 +512,13 @@ def outputXLS(filename, sheet, list1, parseTREResourcesAlso = False, mixInputFol # # ######################## # main -# 00_0000 -- DealsInInsects dupl TLK01, TLK0A -# 00_0510 -- ThinkingOfChangingJobs-Leon dupl TLK02, TLK03 -# 00-8520 -- WhatDoYouKnow dupl TLK01, TLK0A +def main(argsCL): + # TODO parse arguments using argparse? https://docs.python.org/3/library/argparse.html#module-argparse + global traceModeEnabled + traceModeEnabled = False + + pathToActorNamesTxt = "" -# 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__": TMProotFolderWithExtractedFiles = "" TMProotFolderWithInputTLKFiles = "" @@ -510,50 +526,55 @@ if __name__ == "__main__": extractTreFilesMode = False invalidSyntax = False -# print "Len of sysargv = %s" % (len(sys.argv)) - if len(sys.argv) == 2: - if(sys.argv[1] == '--help'or sys.argv[1] == '-h'): + 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 Blade Runner (English version, CD edition)." % (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 "Preparatory steps:" - print "1. Put actornames.txt file in the same folder with this tool." - print "--------------------" - print "%s takes has one mandatory argument, the folder of the extracted WAV files:" % (app_name_spaced) - print "Valid syntax: %s -ip [folderpath_for_TLK_Files] -op [folderpath_for_extracted_wav_Files] -m [stringPathToReplaceFolderpathInExcelLinks]" % (app_name) + print "%s takes has one mandatory argument, the folder of the extracted WAV files:" % (app_name) + print "Valid syntax: %s -op folderpath_for_extracted_wav_Files [-ip folderpath_for_TLK_Files] [-ian path_to_actornames_txt] [-m stringPathToReplaceFolderpathInExcelLinks] [-xwav] [-xtre] [--trace]" % (app_name) print "The -op switch has an argument that is the path for extracted 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 -m switch has an argument that is a replacement string for the path to the folder of extracted WAV files which will be used as a prefix for the links in the output XLS file." print "The -xwav switch enables the WAV audio extract mode from the TLK files. It requires an INPUT path to be set with the -ip switch." print "The -xtre switch enables the TRE parsing mode from the original MIX files. It requires an INPUT path to be set with the -ip switch." + print "The --trace switch enables more debug messages being printed during execution." print "If the app finishes successfully a sortedWavs.xls file will be created in the same folder with the app." print "--------------------" print "Thank you for using this app." print "Please provide any feedback to: %s " % (company_email) sys.exit() - elif(sys.argv[1] == '--version' or sys.argv[1] == '-v'): + elif(argsCL[1] == '--version' or argsCL[1] == '-v'): print "%s %s supports Blade Runner (English version, CD edition)." % (app_name_spaced, app_version) print "Please provide any feedback to: %s " % (company_email) sys.exit() else: invalidSyntax = True - elif len(sys.argv) > 2: - for i in range(1, len(sys.argv)): - if( i < (len(sys.argv) - 1) and sys.argv[i][:1] == '-' and sys.argv[i+1][:1] != '-'): - if (sys.argv[i] == '-op'): - TMProotFolderWithExtractedFiles = sys.argv[i+1] + 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'): + TMProotFolderWithExtractedFiles = argsCL[i+1] numReplaceStartingCharacters = len(TMProotFolderWithExtractedFiles) - elif (sys.argv[i] == '-ip'): - TMProotFolderWithInputTLKFiles = sys.argv[i+1] - elif (sys.argv[i] == '-m'): - stringReplacementForRootFolderWithExtractedFiles = sys.argv[i+1] - elif (sys.argv[i] == '-xwav'): + elif (argsCL[i] == '-ip'): + TMProotFolderWithInputTLKFiles = argsCL[i+1] + elif (argsCL[i] == '-m'): + stringReplacementForRootFolderWithExtractedFiles = argsCL[i+1] + elif (argsCL[i] == '-ian'): + pathToActorNamesTxt = argsCL[i+1] + elif (argsCL[i] == '-xwav'): print "Extract WAVs from TLK files mode enabled." extractWavFilesMode = True - elif (sys.argv[i] == '-xtre'): + elif (argsCL[i] == '-xtre'): print "Extract TRE mode enabled." extractTreFilesMode = True + elif argsCL[i] == '--trace': + print "Info:: Trace mode enabled (more debug messages)." + traceModeEnabled = True if not TMProotFolderWithExtractedFiles: # this argument is mandatory invalidSyntax = True @@ -563,7 +584,7 @@ if __name__ == "__main__": if not invalidSyntax: # parse Actors files: - initActorPropertyEntries() + initActorPropertyEntries(pathToActorNamesTxt) # for actorEntryTmp in actorPropertyEntries: # print "Found actor: %s %s %s" % (actorEntryTmp[0], actorEntryTmp[1], actorEntryTmp[2]) # @@ -708,15 +729,28 @@ if __name__ == "__main__": invalidSyntax = True if invalidSyntax == True: - print "Invalid syntax\n Try: \n %s -op [folderpath_for_extracted_wav_Files] \n %s --help for more info \n %s --version for version info " % (app_name, app_name, app_name) + print "Invalid syntax\n Try: \n %s --help for more info \n %s --version for version info " % (app_name, app_name) + print "Valid syntax: %s -op folderpath_for_extracted_wav_Files [-ip folderpath_for_TLK_Files] [-ian path_to_actornames_txt] [-m stringPathToReplaceFolderpathInExcelLinks] [-xwav] [-xtre] [--trace]" % (app_name) tmpi = 0 - for tmpArg in sys.argv: + for tmpArg in argsCL: if tmpi==0: #skip first argument tmpi+=1 continue print "\nArgument: %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 '%s was imported from another module' % (app_name_spaced,) + #print 'Debug:: %s was imported from another module' % (app_name) pass diff --git a/devtools/create_bladerunner/subtitles/quotesSpreadsheetCreator/treFileLib.py b/devtools/create_bladerunner/subtitles/quotesSpreadsheetCreator/treFileLib.py index b9d147248d..29eac6a8e5 100644 --- a/devtools/create_bladerunner/subtitles/quotesSpreadsheetCreator/treFileLib.py +++ b/devtools/create_bladerunner/subtitles/quotesSpreadsheetCreator/treFileLib.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python2.7 # -*- coding: UTF-8 -*- # import os, sys, shutil diff --git a/devtools/create_bladerunner/subtitles/sampleInput/configureFontsTranslation.txt b/devtools/create_bladerunner/subtitles/sampleInput/configureFontsTranslation.txt new file mode 100644 index 0000000000..8b4a355ecb --- /dev/null +++ b/devtools/create_bladerunner/subtitles/sampleInput/configureFontsTranslation.txt @@ -0,0 +1,4 @@ +targetEncoding=windows-1253 +fontNameAndOutOfOrderGlyphs=SUBTLS_E#í:Ά,ñ:¥,â:¦,é:§,Ά:£ +fontNameAndOutOfOrderGlyphs=KIA6PT#é:ƒ,ü:– +fontNameAndOutOfOrderGlyphs=TAHOMA#é:ƒ,ü:–
\ No newline at end of file diff --git a/devtools/create_bladerunner/subtitles/sampleInput/overrideEncodingSUBLTS.txt b/devtools/create_bladerunner/subtitles/sampleInput/overrideEncodingSUBLTS.txt new file mode 100644 index 0000000000..a4d403f874 --- /dev/null +++ b/devtools/create_bladerunner/subtitles/sampleInput/overrideEncodingSUBLTS.txt @@ -0,0 +1,7 @@ +targetEncoding=windows-1253 +asciiCharList=!!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~…Ά£¥¦§ΈΉΊΌΎΏΐΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩΪΫάέήίΰαβγδεζηθικλμνξοπρςστυφχψωϊϋόύώ +explicitKerningList=i:-1 +explicitWidthIncrement=i:0,j:1,l:1 +originalFontName=SUBLTS +specialOutOfOrderGlyphsUTF8ToAsciiTargetEncoding=í:Ά,ñ:¥,â:¦,é:§,Ά:£ + diff --git a/devtools/create_bladerunner/subtitles/sampleInput/subtitlesFont.png b/devtools/create_bladerunner/subtitles/sampleInput/subtitlesFont.png Binary files differnew file mode 100644 index 0000000000..bed9020750 --- /dev/null +++ b/devtools/create_bladerunner/subtitles/sampleInput/subtitlesFont.png diff --git a/devtools/module.mk b/devtools/module.mk index 0f2d19176a..62f07580d4 100644 --- a/devtools/module.mk +++ b/devtools/module.mk @@ -14,9 +14,9 @@ DEVTOOLS := \ devtools/md5table$(EXEEXT) \ devtools/make-scumm-fontdata$(EXEEXT) -include $(srcdir)/devtools/*/module.mk +include $(srcdir)/devtools/*/module.mk $(srcdir)/devtools/*/*/module.mk -.PHONY: $(srcdir)/devtools/*/module.mk +.PHONY: $(srcdir)/devtools/*/module.mk $(srcdir)/devtools/*/*/module.mk # Make sure the 'all' / 'clean' targets build/clean the devtools, too #all: |