From b7bfc07c0bf649a4773b115b7fbfa02dd43f2bf1 Mon Sep 17 00:00:00 2001 From: Luke Hubmayer-Werner Date: Wed, 15 Mar 2017 19:43:29 +1030 Subject: [PATCH] JP Dialogue pasing improvements --- const.py | 94 ++++++++++++++++++++++++++++++++++++++++---- ff5reader.py | 108 +++++++++++++++++---------------------------------- 2 files changed, 122 insertions(+), 80 deletions(-) diff --git a/const.py b/const.py index f0440eb..03dd242 100644 --- a/const.py +++ b/const.py @@ -16,7 +16,7 @@ Glyphs = ( '/','!','?','.', 'ti','fi','Bl','a', 'pe','l','\'','"', 'if','lt','tl','ir', # 0xA0 'tt','や','ユ','ゆ', 'ヨ', 'よ', 'ワ', 'わ', 'ン', 'ん', 'ヲ','を', '[key]', '[shoe]', '◆', '[hammer]', # 0xB0 '⛺', '[ribbon]', '[potion]', '[shirt]', '♪', '-', '[shuriken]', '‥', '[scroll]', '!', '[claw]', '?', '[glove]', '%', '/', ':', # 0xC0 - '「', '」', '0', 'A', 'B', 'X', 'Y', 'L', 'R', 'E', 'H', 'M', 'P', 'S', 'C', 'T', # 0xD0 + '「', '」', '.', 'A', 'B', 'X', 'Y', 'L', 'R', 'E', 'H', 'M', 'P', 'S', 'C', 'T', # 0xD0 '↑', '→', '+', '[sword]', '[wh.mag]', '[blk.mag]', '🕒', '[knife]', '[spear]', '[axe]', '[katana]', '[rod]', '[staff]', '[bow]', '[harp]', '[whip]', # 0xE0 '[bell]', '[shield]', '[helmet]', '[armor]', '[ring]', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ') # F0 Glyphs_JP = list(Glyphs) # Transcription of the japanese glyph tiles @@ -28,6 +28,7 @@ Glyphs_JP[0x60:0xCD] = [ 'ム','む','メ','め', 'モ','も','ラ','ら', 'リ','り','ル','る', 'レ','れ','ロ','ろ', # 0xA0 'ヤ','や','ユ','ゆ', 'ヨ','よ','ワ','わ', 'ン','ん','ヲ','を', 'ッ','っ','ャ','ゃ', # 0xB0 'ュ','ゅ','ョ','ょ', 'ァ','ー','ィ', '‥', 'ぅ','!','ェ','?', 'ォ'] # 0xC0 +Glyphs_JP[0xD2] = '。' Glyphs_JP[0xE3] = '[洋剣]' Glyphs_JP[0xE7:0xF0] = ['[刂]', '[槍]', '[鉞]', '[刀]', '[棒]', '[杖]', '[弓]', '♪', '[鞭]'] Glyphs_JP2 = list(Glyphs_JP) # Japanese glyphs using the dakuten encoding @@ -37,25 +38,27 @@ Glyphs_JP2[0x20:0x52] = [ 'ヂ','ぢ','ヅ','づ', 'デ','で','ド','ど', # 0x40-0x48 'パ','ぱ','ピ','ぴ', 'プ','ぷ','ペ','ぺ', 'ポ','ぽ'] # 0x48-0x52 Glyphs_JP_large = list(Glyphs_JP2) # Large glyphs are subtly different again +Glyphs_JP_large[0xC7] = '⋯' Glyphs_JP_large[0xE0:0xEB] = ['←','→','+','、', '◯', '『', 'F', '°C', '・', '(', ')'] +Glyphs_JP_large[0xFF] = ' ' -Glyphs_Kanji = ( # TODO: finish this - '王','行','力','様', ' ',' ',' ',' ', '入','城',' ','士', ' ',' ',' ','父', # 0x000 - '人','見',' ',' ', '大',' ',' ','何', ' ',' ',' ',' ', ' ',' ',' ',' ', # 0x010 +Glyphs_Kanji1 = ( # TODO: finish this + '王','行','力','様', ' ','世','界',' ', '入','城',' ','士', ' ',' ','海','父', # 0x000 + '人','見',' ',' ', '大',' ',' ','何', ' ',' ',' ',' ', '言',' ',' ',' ', # 0x010 ' ','心','間',' ', '風',' ',' ',' ', ' ',' ',' ',' ', '火',' ',' ',' ', # 0x020 - ' ',' ',' ',' ', ' ',' ',' ',' ', '地',' ',' ',' ', ' ',' ',' ',' ', # 0x030 + ' ',' ',' ',' ', ' ','女',' ',' ', '地',' ',' ',' ', ' ',' ',' ',' ', # 0x030 ' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', ' ','一',' ',' ', # 0x040 - ' ',' ','神',' ', ' ',' ','殿',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', # 0x050 + ' ',' ','神',' ', ' ',' ','殿',' ', ' ',' ',' ',' ', ' ','子',' ',' ', # 0x050 ' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', # 0x060 ' ',' ','階',' ', ' ',' ',' ',' ', ' ',' ','土',' ', ' ',' ',' ',' ', # 0x070 ' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', # 0x080 ' ',' ',' ',' ', ' ','下',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', # 0x090 ' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', # 0x0A0 - ' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', # 0x0B0 + ' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', ' ','運','河',' ', # 0x0B0 ' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', ' ','少',' ',' ', # 0x0C0 ' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', # 0x0D0 - ' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', # 0x0E0 + ' ',' ',' ',' ', ' ','博',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', # 0x0E0 ' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', # 0x0F0 ' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', # 0x100 @@ -70,6 +73,81 @@ Glyphs_Kanji = ( # TODO: finish this ' ',' ',' ',' ', ' ',' ',' ',' ', ' ','刀',' ',' ', ' ',' ',' ',' ', # 0x180 ' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', # 0x190 ' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ') # 0x1A0 +Glyphs_Kanji = [g if g!=' ' else '${:03X}'.format(i) for (i,g) in enumerate(Glyphs_Kanji1)] + +Dialogue_Macros = { + # Is 0x00 a wait for input marker? + # 0x01 is linebreak + 0x02: [0x20, 0xBC, 0x82], # 0x02 expands to Bartz's name バッツ. Used for his dialogue in EN, only used for other chars in JP. + 0x03: [0x6E, 0xA8, 0x78, 0x7E, 0xAA], # 0x03 is クリスタル + 0x04: [0x7E, 0x8C, 0x6E, 0xC5, 0xB8], # expands to タイクーン + 0x06: [0x37, 0xBF], # expands to じゃ + 0x07: [0x8D, 0xAB], # expands to いる + 0x08: [0xFF, 0xFF, 0xFF, 0xFF], # 4 spaces + 0x09: [0xFF, 0xFF, 0xFF], # 3 spaces + 0x0A: [0xFF, 0xFF], # 2 spaces + # 0x0B - monster? fiend? + # 0x0C appears to be a pause in delivery + 0x0D: [0x1E24, 0x9B, 0x1E52, 0x1E57], # expands to 風の神殿 + # 0x0E - hiryuu? + # 0x0F + # 0x10 is a gil substitution + # 0x11 and 0x12 appear to be item (obtained) substitutions + + 0x14: [0x76, 0x46, 0xD0], # Cid speaking - シド「 + 0x15: [0x9E, 0x46, 0xD0], # Mid speaking - ミド「 + 0x16: [0x1E05, 0x1E06], # expands to 世界 + # 0x17 uses the next byte for something + + 0x19: [0xAC, 0x92, 0xD0], # Lenna speaking - レナ「 + 0x1A: [0x2A, 0xA6, 0x64, 0xD0], # Galuf speaking - ガラフ「 + 0x1B: [0x64, 0xC4, 0xA8, 0x78, 0xD0], # Faris speaking - ファリス「 + 0x1C: [0x6E, 0xAA, 0xAA, 0xD0], # Krile/Kara speaking - クルル「 + + # 0x1E-0x1F form kanji with the next byte + # 0x20-0xCC are standard character set + 0xCD: [0xC9, 0xC9], # % (0xCD) to !! + 0xCF: [0xBD, 0x85], # : (0xCF) appears to expand to って + # 0xD0-0xD4 are 「」。AB + # 0xD5 is X - or perhaps a 2byte + + 0xD9: [0x93, 0x8D], # expands to ない + 0xDD: [0xC7, 0xC7], # S (0xDD) to …… + 0xDE: [0x3F, 0x8D, 0x37, 0xC3, 0x89, 0x25], # C (0xDE) to だいじょうぶ + 0xDF: [0x61, 0xE3], # T (0xDF) to は、 + 0xE0: [0xB9, 0x3F], # expands to んだ + 0xE1: [0x85, 0x8D], # expands to てい + 0xE2: [0x77, 0x7F], # expands to した + # 0xE3 is 、 + 0xE4: [0x77, 0x85], # ◯ (0xE4) appears to expand to して + # 0xE5 is used for Bartz speaking in JP. This only appears as 『 + 0xE6: [0x91, 0x1E0F, 0x1E03], # F (0xE6) appears to expand to otousan (お父様) + 0xE7: [0xC9, 0xCB], # °C (0xE7) to !? - yes this is the wrong order interrobang + 0xE8: [0x45, 0x79], # ・ (0xE8) appears to expand to です + # 0xE9, 0xEA are () + 0xEB: [0x73, 0x9B], # expands to この + # 0xEC - used in "power of crystal" context, need to confim wording ingame + 0xEF: [0x1E1C, 0xBD, 0x85], # expands to 言って + # 0xF0 - soldier speaking + 0xF1: [0x6B, 0xA7], # expands to から + # 0xF2 queen? doctor? hakase? + 0xF3: [0x1E0E, 0x3D, 0x6F], # expands to 海ぞく + + 0xF5: [0x2B, 0xE3], # expands to が、 + # 0xF6 see dialogue 0x0A3, 0x0A4, 0x0B6 - almost certainly たち + 0xF7: [0x7F, 0x9B], # expands to たの + 0xF8: [0x9D, 0x79], # expands to ます + 0xF9: [0x6F, 0x3F, 0x75, 0x8D], # expands to ください + 0xFA: [0x6B, 0xBD, 0x7F], # expands to かった + # 0xFB - used in received item context, lenna being poisoned - maybe a sound trigger? + 0xFC: [0x95, 0xE3], # expands to に、 + + # 0xFF is space + } + +Dialogue_Exceptions = [0xDA, 0xDB, 0xDC, 0xE3, 0xE5, 0xE9, 0xEA, 0xFF] + +DoubleChars = [0x17, 0x1E, 0x1F] # 0x1E and 0x1F are kanji, 0x17 is unknown as of yet (invisible) BGM_Tracks = ( "Ahead on our way", "The Fierce Battle", "A Presentiment", "Go Go Boko!", diff --git a/ff5reader.py b/ff5reader.py index cb4f4eb..c9359c4 100644 --- a/ff5reader.py +++ b/ff5reader.py @@ -251,100 +251,64 @@ def make_string_img(bytestring, jp=False): del painter return string, QPixmap.fromImage(img) +def dialogue_preprocessor(bytestring, expand=True): + out = [[]] + bytes = iter(bytestring) + for b in bytes: + if b in const.DoubleChars: + b2 = next(bytes) + out[-1].append((b<<8) + b2) + elif expand: + if b in const.Dialogue_Macros: + out[-1].extend(const.Dialogue_Macros[b]) + else: + out[-1].append(b) + return out + + def make_string_img_large(bytestring): if len(bytestring) < 1: raise ValueError('Empty bytestring was passed') + line = dialogue_preprocessor(bytestring)[0] string = "" - rows = 20 # This is just for testing - img = QImage(len(bytestring)*16, 14*rows, QImage.Format_RGB16) + cols = 16 # This is the maximum dialogue glyphs per row in JP + rows = 32 # This is just for testing + img = QImage(cols*16, rows*16, QImage.Format_RGB16) img.fill(bg_color) painter = QtGui.QPainter(img) - it = iter(range(len(bytestring))) x = 0 - xmax = x + xmax = 0 y = 0 - tabstop = 0 try: - for i in it: - j = bytestring[i] - ''' - There's a lot of dialogue substitutions, this is going to be annoying and/or messy. - TODO: The best way of going about this would be preprocessing the string, I think. - Is 0x00 a wait for input marker? - 0x03 is クリスタル - 0x0A is a speaker tab, perhaps linebreak as well? - 0x0D appears to expand to 風の神殿 - : (0xCF) appears to expand to って - S (0xDD) to …… - C (0xDE) to だいじょうぶ - T (0xDF) to は、 - ◯ (0xE4) appears to expand to して - F (0xE6) appears to expand to otousan (お父様) - ・ (0xE8) appears to expand to です - % (0xCD) to !! - °C (0xE7) to !? - ''' + for j in line: + # Is 0x00 a wait for input marker? + if x >= 16: + string += '[wr]\n' + xmax = 16 + x = 0 + y += 1 if j == 0x01: - string = string + '\n[0x01]' + string += '[br]\n' y += 1 xmax = x if x > xmax else xmax x = 0 continue - elif j == 0x09: - string = string + '\t[0x09]' - x = tabstop + elif 0x1E00 <= j < 0x2000: + string += const.Glyphs_Kanji[j-0x1E00] + painter.drawPixmap(x*16, (y*16)+2, glyph_sprites_kanji[j-0x1E00]) + elif (j < 0x1E) or ((j > 0xD5) and (j not in const.Dialogue_Exceptions)): + string += '[0x{:02X}]'.format(j) continue - elif j == 0x0A: - if x != 0: - y += 1 - xmax = x if x > xmax else xmax - string = string + '\n' - string = string + '\t[0x0A]' - x = tabstop - continue - elif j == 0x19: - # Lenna is speaking - string = string + "[レナ「]" - painter.drawPixmap(0*16, (y*14)+1, glyph_sprites_large[0xAC]) - painter.drawPixmap(1*16, (y*14)+1, glyph_sprites_large[0x92]) - painter.drawPixmap(2*16, (y*14)+1, glyph_sprites_large[0xD0]) - x += 3 - tabstop = x - continue - elif j == 0x1B: - # Faris is speaking - string = string + "[ファリス「]" - painter.drawPixmap(0*16, (y*14)+1, glyph_sprites_large[0x64]) - painter.drawPixmap(1*16, (y*14)+1, glyph_sprites_large[0xC4]) - painter.drawPixmap(2*16, (y*14)+1, glyph_sprites_large[0xA8]) - painter.drawPixmap(3*16, (y*14)+1, glyph_sprites_large[0x78]) - painter.drawPixmap(4*16, (y*14)+1, glyph_sprites_large[0xD0]) - x += 5 - tabstop = x - continue - elif j < 0x1E: - string = string + '[0x{:02X}]'.format(j) - continue - elif j == 0x1E: - string = string + const.Glyphs_Kanji[bytestring[i+1]] - painter.drawPixmap(x*16, (y*14)+1, glyph_sprites_kanji[bytestring[i+1]]) - next(it) - elif j == 0x1F: - string = string + const.Glyphs_Kanji[0x100 + bytestring[i+1]] - painter.drawPixmap(x*16, (y*14)+1, glyph_sprites_kanji[0x100 + bytestring[i+1]]) - next(it) else: - string = string + const.Glyphs_JP_large[j] - painter.drawPixmap(x*16, (y*14)+1, glyph_sprites_large[j]) + string += const.Glyphs_JP_large[j] + painter.drawPixmap(x*16, (y*16)+2, glyph_sprites_large[j]) x += 1 - if (j == 0xD0) or (j == 0xE5): - tabstop = x except (StopIteration, IndexError): pass del painter xmax = x if x > xmax else xmax - return string, QPixmap.fromImage(img.copy(0, 0, xmax*16, (y+1)*14)) + return string, QPixmap.fromImage(img.copy(0, 0, xmax*16, (y+1)*16)) def make_string_img_list(start, length, num, start_jp=None, len_jp=None, start_str=None, start_jp_str=None, indirect=False, large=False): start_jp = start if start_jp is None else start_jp