Refactoring, split into files
This commit is contained in:
parent
8f33b58648
commit
7c3d2e6ce9
|
@ -0,0 +1,92 @@
|
|||
'''
|
||||
No license for now
|
||||
'''
|
||||
|
||||
Glyphs = (
|
||||
' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', # 0x00
|
||||
' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', # 0x10
|
||||
'A','B','C','D', 'E','F','G','H', 'I','J','K','L', 'M','N','O','P', # 0x20
|
||||
'Q','R','S','T','U','V','W','X','Y','Z','[stone]','[toad]','[mini]','[float]','[poison]','[KO]', # 0x30
|
||||
'[blind]',' ',' ',' ',' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', # 0x40
|
||||
' ',' ',' ','0', '1','2','3','4', '5','6','7','8', '9','_m','_H','_P', # 0x50
|
||||
'A','B','C','D', 'E','F','G','H', 'I','J','K','L', 'M','N','O','P', # 0x60
|
||||
'Q','R','S','T', 'U','V','W','X', 'Y','Z','a','b', 'c','d','e','f', # 0x70
|
||||
'g','h','i','j', 'k','l','m','n', 'o','p','q','r', 's','t','u','v', # 0x80
|
||||
'w','x','y','z', 'il','it',' ','li', 'll','\'','"',':', ';',',','(',')', # 0x90
|
||||
'/','!','?','.', '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
|
||||
'↑', '→', '+', '[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
|
||||
Glyphs_JP[0x60:0xCD] = [
|
||||
'ハ','は','ヒ','ひ', 'フ','ふ','ヘ','へ', 'ホ','ほ','カ','か', 'キ','き','ク','く', # 0x60
|
||||
'ケ','け','コ','こ', 'サ','さ','シ','し', 'ス','す','セ','せ', 'ソ','そ','タ','た', # 0x70
|
||||
'チ','ち','ツ','つ', 'テ','て','ト','と', 'ウ','う','ア','あ', 'イ','い','エ','え', # 0x80
|
||||
'オ','お','ナ','な', 'ニ','に','ヌ','ぬ', 'ネ','ね','ノ','の', 'マ','ま','ミ','み', # 0x90
|
||||
'ム','む','メ','め', 'モ','も','ラ','ら', 'リ','り','ル','る', 'レ','れ','ロ','ろ', # 0xA0
|
||||
'ヤ','や','ユ','ゆ', 'ヨ','よ','ワ','わ', 'ン','ん','ヲ','を', 'ッ','っ','ャ','ゃ', # 0xB0
|
||||
'ュ','ゅ','ョ','ょ', 'ァ','ー','ィ', '‥', 'ぅ','!','ェ','?', 'ォ'] # 0xC0
|
||||
Glyphs_JP[0xE3] = '[洋剣]'
|
||||
Glyphs_JP[0xE7:0xF0] = ['[刂]', '[槍]', '[鉞]', '[刀]', '[棒]', '[杖]', '[弓]', '♪', '[鞭]']
|
||||
Glyphs_JP2 = list(Glyphs_JP) # Japanese glyphs using the dakuten encoding
|
||||
Glyphs_JP2[0x20:0x52] = [
|
||||
'バ','ば','ビ','び', 'ブ','ぶ','ベ','べ', 'ボ','ぼ','ガ','が', 'ギ','ぎ','グ','ぐ', # 0x20
|
||||
'ゲ','げ','ゴ','ご', 'ザ','ざ','ジ','じ', 'ズ','ず','ゼ','ぜ', 'ゾ','ぞ','ダ','だ', # 0x30
|
||||
'ヂ','ぢ','ヅ','づ', 'デ','で','ド','ど', # 0x40-0x48
|
||||
'パ','ぱ','ピ','ぴ', 'プ','ぷ','ペ','ぺ', 'ポ','ぽ'] # 0x48-0x52
|
||||
Glyphs_JP_large = list(Glyphs_JP2) # Large glyphs are subtly different again
|
||||
Glyphs_JP_large[0xE0:0xEB] = ['←','→','+','、', '◯', '『', 'F', '°C', '・', '(', ')']
|
||||
|
||||
Glyphs_Kanji = ( # TODO: finish this
|
||||
'王','行','力','様', ' ',' ',' ',' ', '入','城',' ','士', ' ',' ',' ','父', # 0x000
|
||||
'人','見',' ',' ', '大',' ',' ','何', ' ',' ',' ',' ', ' ',' ',' ',' ', # 0x010
|
||||
' ','心','間',' ', '風',' ',' ',' ', ' ',' ',' ',' ', '火',' ',' ',' ', # 0x020
|
||||
' ',' ',' ',' ', ' ',' ',' ',' ', '地',' ',' ',' ', ' ',' ',' ',' ', # 0x030
|
||||
' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', ' ','一',' ',' ', # 0x040
|
||||
' ',' ','神',' ', ' ',' ','殿',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', # 0x050
|
||||
' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', # 0x060
|
||||
' ',' ','階',' ', ' ',' ',' ',' ', ' ',' ','土',' ', ' ',' ',' ',' ', # 0x070
|
||||
|
||||
' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', # 0x080
|
||||
' ',' ',' ',' ', ' ','下',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', # 0x090
|
||||
' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', # 0x0A0
|
||||
' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', # 0x0B0
|
||||
' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', ' ','少',' ',' ', # 0x0C0
|
||||
' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', # 0x0D0
|
||||
' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', # 0x0E0
|
||||
' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', # 0x0F0
|
||||
|
||||
' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', # 0x100
|
||||
' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', # 0x110
|
||||
' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', # 0x120
|
||||
' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', # 0x130
|
||||
' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', # 0x140
|
||||
'炎',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', # 0x150
|
||||
' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', # 0x160
|
||||
' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', # 0x170
|
||||
|
||||
' ',' ',' ',' ', ' ',' ',' ',' ', ' ','刀',' ',' ', ' ',' ',' ',' ', # 0x180
|
||||
' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', # 0x190
|
||||
' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ') # 0x1A0
|
||||
|
||||
BGM_Tracks = (
|
||||
"Ahead on our way", "The Fierce Battle", "A Presentiment", "Go Go Boko!",
|
||||
"Pirates Ahoy", "Tenderness in the Air", "Fate in Haze", "Moogle theme",
|
||||
"Prelude/Crystal Room", "The Last Battle", "Requiem", "Nostalgia",
|
||||
"Cursed Earths", "Lenna's Theme", "Victory's Fanfare", "Deception",
|
||||
"The Day Will Come", "Nothing?", "ExDeath's Castle", "My Home, Sweet Home",
|
||||
"Waltz Suomi", "Sealed Away", "The Four Warriors of Dawn", "Danger",
|
||||
"The Fire Powered Ship", "As I Feel, You Feel", "Mambo de Chocobo!", "Music Box",
|
||||
"Intension of the Earth", "The Dragon Spreads its Wings", "Beyond the Deep Blue Sea", "The Prelude of Empty Skies",
|
||||
"Searching the Light", "Harvest", "Battle with Gilgamesh", "Four Valiant Hearts",
|
||||
"The Book of Sealings", "What?", "Hurry! Hurry!", "Unknown Lands",
|
||||
"The Airship", "Fanfare 1", "Fanfare 2", "The Battle",
|
||||
"Walking the Snowy Mountains", "The Evil Lord Exdeath", "The Castle of Dawn", "I'm a Dancer",
|
||||
"Reminiscence", "Run!", "The Ancient Library", "Royal Palace",
|
||||
"Good Night!", "Piano Lesson 1", "Piano Lesson 2", "Piano Lesson 3",
|
||||
"Piano Lesson 4", "Piano Lesson 5", "Piano Lesson 6", "Piano Lesson 7",
|
||||
"Piano Lesson 8", "Musica Machina", "Meteor falling?", "The Land Unknown",
|
||||
"The Decisive Battle", "The Silent Beyond", "Dear Friends", "Final Fantasy",
|
||||
"A New Origin", "Chirping sound")
|
248
ff5reader.py
248
ff5reader.py
|
@ -7,10 +7,12 @@ import sys
|
|||
import os
|
||||
import struct
|
||||
from array import array
|
||||
#from heximg import HexImg
|
||||
from snestile import create_tile, create_tritile
|
||||
import const
|
||||
import time
|
||||
|
||||
pyqt_version = 0
|
||||
skip_pyqt5 = True # "PYQT4" in os.environ
|
||||
skip_pyqt5 = "PYQT4" in os.environ
|
||||
|
||||
if not skip_pyqt5:
|
||||
try:
|
||||
|
@ -35,7 +37,7 @@ if not skip_pyqt5:
|
|||
except ImportError:
|
||||
print("Couldn't import Qt5 dependencies. "
|
||||
"Make sure you installed the PyQt5 package.")
|
||||
if pyqt_version is 0:
|
||||
if pyqt_version == 0:
|
||||
try:
|
||||
import sip
|
||||
sip.setapi('QVariant', 2)
|
||||
|
@ -70,11 +72,6 @@ if not monofont.fixedPitch():
|
|||
monofont.setStyleHint(QFont.TypeWriter)
|
||||
if not monofont.fixedPitch():
|
||||
monofont.setFamily("Monospace")
|
||||
#"Ubuntu Mono",
|
||||
#"DejaVu Sans Mono",
|
||||
#"Liberation Mono",
|
||||
#"courier"])
|
||||
#monofont.setPixelSize(8)
|
||||
|
||||
def divceil(numerator, denominator):
|
||||
# Reverse floor division for ceil
|
||||
|
@ -86,186 +83,24 @@ def hex_length(i):
|
|||
filename = "Final Fantasy V (Japan) [En by RPGe v1.1].sfc"
|
||||
with open(filename, 'rb') as file1:
|
||||
ROM = file1.read()
|
||||
print(len(ROM))
|
||||
print(len(ROM), filename)
|
||||
filename2 = "Final Fantasy V (Japan).sfc"
|
||||
with open(filename2, 'rb') as file2:
|
||||
ROM2 = file2.read()
|
||||
print(len(ROM2))
|
||||
print(len(ROM2), filename2)
|
||||
|
||||
col_palette = [QColor( 0, 0, 0),
|
||||
QColor( 0, 0,128,0),
|
||||
QColor(128,128,128),
|
||||
QColor(255,255,255)]
|
||||
col_palette = [QColor(0, 0, 0), QColor(0, 0, 128, 0),
|
||||
QColor(128, 128, 128), QColor(255, 255, 255)]
|
||||
bg_color = QColor(0, 0, 128)
|
||||
#for i in range(4, 256):
|
||||
#col_palette.append(QColor(i, i, i))
|
||||
|
||||
def create_tile(bytes):
|
||||
'''
|
||||
Creates a QPixmap of a SNES tile. DO NOT USE OUTSIDE OF QApplication CONTEXT
|
||||
'''
|
||||
planes = len(bytes)//8
|
||||
tile = array('B', range(64))
|
||||
img = QImage(8, 8, QImage.Format_Indexed8)
|
||||
imgbits = img.bits()
|
||||
imgbits.setsize(img.byteCount())
|
||||
if planes == 0:
|
||||
raise ValueError("Empty bytes passed")
|
||||
if planes == 1:
|
||||
img.setColorTable([0x00000080, 0xFFFFFFFF])
|
||||
t_ptr = 0
|
||||
for j, x in [(j,x) for j in range(8) for x in reversed(range(8))]:
|
||||
tile[t_ptr] = (bytes[j] >> x & 1)
|
||||
t_ptr += 1
|
||||
else:
|
||||
img.setColorTable([c.rgba() for c in col_palette])
|
||||
t_ptr = 0
|
||||
for j, x in [(j,x) for j in range(0, 16, 2) for x in reversed(range(8))]:
|
||||
tile[t_ptr] = (bytes[j] >> x & 1) | ((bytes[j+1] >> x & 1) << 1)
|
||||
t_ptr += 1
|
||||
t_ptr = 0
|
||||
if planes == 3:
|
||||
for j, x in [(j,x) for j in range(16, 24, 1) for x in reversed(range(8))]:
|
||||
tile[t_ptr] |= ((bytes[j] >> x & 1) << 2)
|
||||
t_ptr += 1
|
||||
elif planes >= 4:
|
||||
for j, x in [(j,x) for j in range(16, 32, 2) for x in reversed(range(8))]:
|
||||
tile[t_ptr] |= ((bytes[j] >> x & 1) << 2) | ((bytes[j+1] >> x & 1) << 3)
|
||||
t_ptr += 1
|
||||
if planes == 8:
|
||||
t_ptr = 0
|
||||
for j, x in [(j,x) for j in range(32, 48, 2) for x in reversed(range(8))]:
|
||||
tile[t_ptr] |= ((bytes[j] >> x & 1) << 4) | ((bytes[j+1] >> x & 1) << 5) \
|
||||
| ((bytes[j+16] >> x & 1) << 6) | ((bytes[j+17] >> x & 1) << 7)
|
||||
t_ptr += 1
|
||||
imgbits[:64] = tile
|
||||
return QPixmap.fromImage(img)
|
||||
|
||||
def create_tritile(bytes):
|
||||
img = QImage(16, 12, QImage.Format_Indexed8)
|
||||
imgbits = img.bits()
|
||||
imgbits.setsize(img.byteCount())
|
||||
img.setColorTable([0xFF000080, 0xFFFFFFFF])
|
||||
tile = array('B', range(192))
|
||||
for p, row, b in [(p,j,b) for p in range(2) for j in range(12) for b in reversed(range(8))]:
|
||||
tile[(7-b) + (row*16) + (p*8)] = (bytes[row + (p*12)] >> b & 1)
|
||||
imgbits[:192] = tile
|
||||
return QPixmap.fromImage(img)
|
||||
|
||||
def create_quadtile(bytes, ltr=False):
|
||||
img = QImage(16, 16, QImage.Format_ARGB32_Premultiplied)
|
||||
img.fill(QColor(0,0,0,0))
|
||||
painter = QtGui.QPainter(img)
|
||||
painter.drawPixmap(0, 0, create_tile(bytes[0:8]))
|
||||
painter.drawPixmap(8, 8, create_tile(bytes[24:32]))
|
||||
if ltr:
|
||||
painter.drawPixmap(8, 0, create_tile(bytes[8:16]))
|
||||
painter.drawPixmap(0, 8, create_tile(bytes[16:24]))
|
||||
else:
|
||||
painter.drawPixmap(0, 8, create_tile(bytes[8:16]))
|
||||
painter.drawPixmap(8, 0, create_tile(bytes[16:24]))
|
||||
del painter
|
||||
return QPixmap.fromImage(img)
|
||||
|
||||
glyph_sprites = []
|
||||
glyph_sprites2 = []
|
||||
glyph_sprites_jp = []
|
||||
glyph_sprites_large = []
|
||||
glyph_sprites_kanji = []
|
||||
|
||||
Glyphs = (
|
||||
' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', # 0x00
|
||||
' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', # 0x10
|
||||
'A','B','C','D', 'E','F','G','H', 'I','J','K','L', 'M','N','O','P', # 0x20
|
||||
'Q','R','S','T','U','V','W','X','Y','Z','[stone]','[toad]','[mini]','[float]','[poison]','[KO]', # 0x30
|
||||
'[blind]',' ',' ',' ',' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', # 0x40
|
||||
' ',' ',' ','0', '1','2','3','4', '5','6','7','8', '9','_m','_H','_P', # 0x50
|
||||
'A','B','C','D', 'E','F','G','H', 'I','J','K','L', 'M','N','O','P', # 0x60
|
||||
'Q','R','S','T', 'U','V','W','X', 'Y','Z','a','b', 'c','d','e','f', # 0x70
|
||||
'g','h','i','j', 'k','l','m','n', 'o','p','q','r', 's','t','u','v', # 0x80
|
||||
'w','x','y','z', 'il','it',' ','li', 'll','\'','"',':', ';',',','(',')', # 0x90
|
||||
'/','!','?','.', '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
|
||||
'↑', '→', '+', '[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
|
||||
Glyphs_JP[0x60:0xCD] = [
|
||||
'ハ','は','ヒ','ひ', 'フ','ふ','ヘ','へ', 'ホ','ほ','カ','か', 'キ','き','ク','く', # 0x60
|
||||
'ケ','け','コ','こ', 'サ','さ','シ','し', 'ス','す','セ','せ', 'ソ','そ','タ','た', # 0x70
|
||||
'チ','ち','ツ','つ', 'テ','て','ト','と', 'ウ','う','ア','あ', 'イ','い','エ','え', # 0x80
|
||||
'オ','お','ナ','な', 'ニ','に','ヌ','ぬ', 'ネ','ね','ノ','の', 'マ','ま','ミ','み', # 0x90
|
||||
'ム','む','メ','め', 'モ','も','ラ','ら', 'リ','り','ル','る', 'レ','れ','ロ','ろ', # 0xA0
|
||||
'ヤ','や','ユ','ゆ', 'ヨ','よ','ワ','わ', 'ン','ん','ヲ','を', 'ッ','っ','ャ','ゃ', # 0xB0
|
||||
'ュ','ゅ','ョ','ょ', 'ァ','ー','ィ', '‥', 'ぅ','!','ェ','?', 'ォ'] # 0xC0
|
||||
Glyphs_JP[0xE3] = '[洋剣]'
|
||||
Glyphs_JP[0xE7:0xF0] = ['[刂]', '[槍]', '[鉞]', '[刀]', '[棒]', '[杖]', '[弓]', '♪', '[鞭]']
|
||||
Glyphs_JP2 = list(Glyphs_JP) # Japanese glyphs using the dakuten encoding
|
||||
Glyphs_JP2[0x20:0x52] = [
|
||||
'バ','ば','ビ','び', 'ブ','ぶ','ベ','べ', 'ボ','ぼ','ガ','が', 'ギ','ぎ','グ','ぐ', # 0x20
|
||||
'ゲ','げ','ゴ','ご', 'ザ','ざ','ジ','じ', 'ズ','ず','ゼ','ぜ', 'ゾ','ぞ','ダ','だ', # 0x30
|
||||
'ヂ','ぢ','ヅ','づ', 'デ','で','ド','ど', # 0x40-0x48
|
||||
'パ','ぱ','ピ','ぴ', 'プ','ぷ','ペ','ぺ', 'ポ','ぽ'] # 0x48-0x52
|
||||
Glyphs_JP_large = list(Glyphs_JP2) # Large glyphs are subtly different again
|
||||
Glyphs_JP_large[0xE0:0xEB] = ['←','→','+','、', '◯', '『', 'F', '°C', '・', '(', ')']
|
||||
|
||||
Glyphs_Kanji = (
|
||||
'王','行','力','様', ' ',' ',' ',' ', '入','城',' ','士', ' ',' ',' ','父', # 0x000
|
||||
'人','見',' ',' ', '大',' ',' ','何', ' ',' ',' ',' ', ' ',' ',' ',' ', # 0x010
|
||||
' ','心','間',' ', '風',' ',' ',' ', ' ',' ',' ',' ', '火',' ',' ',' ', # 0x020
|
||||
' ',' ',' ',' ', ' ',' ',' ',' ', '地',' ',' ',' ', ' ',' ',' ',' ', # 0x030
|
||||
' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', ' ','一',' ',' ', # 0x040
|
||||
' ',' ','神',' ', ' ',' ','殿',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', # 0x050
|
||||
' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', # 0x060
|
||||
' ',' ','階',' ', ' ',' ',' ',' ', ' ',' ','土',' ', ' ',' ',' ',' ', # 0x070
|
||||
|
||||
' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', # 0x080
|
||||
' ',' ',' ',' ', ' ','下',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', # 0x090
|
||||
' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', # 0x0A0
|
||||
' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', # 0x0B0
|
||||
' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', ' ','少',' ',' ', # 0x0C0
|
||||
' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', # 0x0D0
|
||||
' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', # 0x0E0
|
||||
' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', # 0x0F0
|
||||
|
||||
' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', # 0x100
|
||||
' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', # 0x110
|
||||
' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', # 0x120
|
||||
' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', # 0x130
|
||||
' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', # 0x140
|
||||
'炎',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', # 0x150
|
||||
' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', # 0x160
|
||||
' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', # 0x170
|
||||
|
||||
' ',' ',' ',' ', ' ',' ',' ',' ', ' ','刀',' ',' ', ' ',' ',' ',' ', # 0x180
|
||||
' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ',' ',' ', # 0x190
|
||||
' ',' ',' ',' ', ' ',' ',' ',' ', ' ',' ') # 0x1A0
|
||||
|
||||
BGM_Tracks = (
|
||||
"Ahead on our way", "The Fierce Battle", "A Presentiment", "Go Go Boko!",
|
||||
"Pirates Ahoy", "Tenderness in the Air", "Fate in Haze", "Moogle theme",
|
||||
"Prelude/Crystal Room", "The Last Battle", "Requiem", "Nostalgia",
|
||||
"Cursed Earths", "Lenna's Theme", "Victory's Fanfare", "Deception",
|
||||
"The Day Will Come", "Nothing?", "ExDeath's Castle", "My Home, Sweet Home",
|
||||
"Waltz Suomi", "Sealed Away", "The Four Warriors of Dawn", "Danger",
|
||||
"The Fire Powered Ship", "As I Feel, You Feel", "Mambo de Chocobo!", "Music Box",
|
||||
"Intension of the Earth", "The Dragon Spreads its Wings", "Beyond the Deep Blue Sea", "The Prelude of Empty Skies",
|
||||
"Searching the Light", "Harvest", "Battle with Gilgamesh", "Four Valiant Hearts",
|
||||
"The Book of Sealings", "What?", "Hurry! Hurry!", "Unknown Lands",
|
||||
"The Airship", "Fanfare 1", "Fanfare 2", "The Battle",
|
||||
"Walking the Snowy Mountains", "The Evil Lord Exdeath", "The Castle of Dawn", "I'm a Dancer",
|
||||
"Reminiscence", "Run!", "The Ancient Library", "Royal Palace",
|
||||
"Good Night!", "Piano Lesson 1", "Piano Lesson 2", "Piano Lesson 3",
|
||||
"Piano Lesson 4", "Piano Lesson 5", "Piano Lesson 6", "Piano Lesson 7",
|
||||
"Piano Lesson 8", "Musica Machina", "Meteor falling?", "The Land Unknown",
|
||||
"The Decisive Battle", "The Silent Beyond", "Dear Friends", "Final Fantasy",
|
||||
"A New Origin", "Chirping sound")
|
||||
|
||||
stringlist_headers = ["Address", "ID", "Name"]
|
||||
imglist_headers = stringlist_headers + ["Img", "Name JP", "Img JP"]
|
||||
|
||||
|
||||
|
||||
npc_layer_count = 0x200
|
||||
npc_layer_structure = [("Dialogue/trigger ID", 1, None),
|
||||
("0x01", 1, None),
|
||||
|
@ -277,7 +112,6 @@ npc_layer_structure = [("Dialogue/trigger ID", 1, None),
|
|||
npc_layer_headers = ["Address", "Layer"] + [x[0] for x in npc_layer_structure]
|
||||
|
||||
|
||||
|
||||
class FF5Reader(QMainWindow):
|
||||
"""
|
||||
Main GUI class
|
||||
|
@ -285,7 +119,7 @@ class FF5Reader(QMainWindow):
|
|||
def __init__(self):
|
||||
QMainWindow.__init__(self, None)
|
||||
generate_glyphs(ROM, glyph_sprites, 0x11F000)
|
||||
generate_glyphs(ROM2, glyph_sprites2, 0x11F000)
|
||||
generate_glyphs(ROM2, glyph_sprites_jp, 0x11F000)
|
||||
generate_glyphs_large(ROM2, glyph_sprites_large, 0x03E800)
|
||||
generate_glyphs_large(ROM2, glyph_sprites_kanji, 0x1BD000, 0x1AA)
|
||||
global zone_names
|
||||
|
@ -319,7 +153,7 @@ class FF5Reader(QMainWindow):
|
|||
("Palette", 1, None),
|
||||
("0x17", 1, None),
|
||||
("0x18", 1, None),
|
||||
("Music", 1, BGM_Tracks)]
|
||||
("Music", 1, const.BGM_Tracks)]
|
||||
zone_headers = ["Address"] + [z[0] for z in zone_structure]
|
||||
|
||||
zone_data = []
|
||||
|
@ -333,7 +167,7 @@ class FF5Reader(QMainWindow):
|
|||
if z[2] and val < len(z[2]):
|
||||
zone_data[-1].append(z[2][val][2])
|
||||
else:
|
||||
zone_data[-1].append("0x{0:0{1}X}".format(val, z[1]*2))
|
||||
zone_data[-1].append("0x{:0{}X}".format(val, z[1]*2))
|
||||
j += z[1]
|
||||
|
||||
npc_layers = []
|
||||
|
@ -352,7 +186,7 @@ class FF5Reader(QMainWindow):
|
|||
if z[2] and val < len(z[2]):
|
||||
npc_layers[-1].append(z[2][val])
|
||||
else:
|
||||
npc_layers[-1].append("0x{0:0{1}X}".format(val, z[1]*2))
|
||||
npc_layers[-1].append("0x{:0{}X}".format(val, z[1]*2))
|
||||
j += z[1]
|
||||
|
||||
dialogue = make_string_img_list(0x2013F0, 3, 0x500, start_jp=0x082220, len_jp=2, start_str=0x0, start_jp_str=0x0A0000, indirect=True, large=True) # start_str=0x210000
|
||||
|
@ -360,7 +194,7 @@ class FF5Reader(QMainWindow):
|
|||
self.tabwidget = QTabWidget()
|
||||
self.enemy_sprites = QFrame()
|
||||
self.tabwidget.addTab(make_pixmap_table(glyph_sprites, 4), "Glyphs (EN)")
|
||||
self.tabwidget.addTab(make_pixmap_table(glyph_sprites2, 4), "Glyphs (JP)")
|
||||
self.tabwidget.addTab(make_pixmap_table(glyph_sprites_jp, 4), "Glyphs (JP)")
|
||||
self.tabwidget.addTab(make_pixmap_table(glyph_sprites_large, 2), "Glyphs (Large)")
|
||||
self.tabwidget.addTab(make_pixmap_table(glyph_sprites_kanji, 2), "Glyphs (Kanji)")
|
||||
self.tabwidget.addTab(self.enemy_sprites, "Enemy Sprites")
|
||||
|
@ -384,7 +218,7 @@ class FF5Reader(QMainWindow):
|
|||
def generate_glyphs(rom, spritelist, offset, num=0x100):
|
||||
for i in range(num):
|
||||
j = offset + (i*16)
|
||||
spritelist.append(create_tile(rom[j:j+16]))
|
||||
spritelist.append(create_tile(rom[j:j+16], col_palette))
|
||||
|
||||
def generate_glyphs_large(rom, spritelist, offset, num=0x100):
|
||||
for i in range(num):
|
||||
|
@ -400,19 +234,19 @@ def make_string_img(bytestring, jp=False):
|
|||
painter = QtGui.QPainter(img)
|
||||
if jp:
|
||||
for x, j in enumerate(bytestring):
|
||||
string = string + Glyphs_JP2[j]
|
||||
string = string + const.Glyphs_JP2[j]
|
||||
if 0x20 <= j < 0x52:
|
||||
if j > 0x48:
|
||||
painter.drawPixmap(x*8, 2, glyph_sprites2[j+0x17])
|
||||
painter.drawPixmap(x*8+1,-5, glyph_sprites2[0x52])
|
||||
painter.drawPixmap(x*8, 2, glyph_sprites_jp[j+0x17])
|
||||
painter.drawPixmap(x*8+1,-5, glyph_sprites_jp[0x52])
|
||||
else:
|
||||
painter.drawPixmap(x*8, 2, glyph_sprites2[j+0x40])
|
||||
painter.drawPixmap(x*8+1,-6, glyph_sprites2[0x51])
|
||||
painter.drawPixmap(x*8, 2, glyph_sprites_jp[j+0x40])
|
||||
painter.drawPixmap(x*8+1,-6, glyph_sprites_jp[0x51])
|
||||
else:
|
||||
painter.drawPixmap(x*8, 2, glyph_sprites2[j])
|
||||
painter.drawPixmap(x*8, 2, glyph_sprites_jp[j])
|
||||
else:
|
||||
for x, j in enumerate(bytestring):
|
||||
string = string + Glyphs[j]
|
||||
string = string + const.Glyphs[j]
|
||||
painter.drawPixmap(x*8, 1, glyph_sprites[j])
|
||||
del painter
|
||||
return string, QPixmap.fromImage(img)
|
||||
|
@ -436,6 +270,7 @@ def make_string_img_large(bytestring):
|
|||
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?
|
||||
|
@ -492,15 +327,15 @@ def make_string_img_large(bytestring):
|
|||
string = string + '[0x{:02X}]'.format(j)
|
||||
continue
|
||||
elif j == 0x1E:
|
||||
string = string + Glyphs_Kanji[bytestring[i+1]]
|
||||
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 + Glyphs_Kanji[0x100 + bytestring[i+1]]
|
||||
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 + Glyphs_JP_large[j]
|
||||
string = string + const.Glyphs_JP_large[j]
|
||||
painter.drawPixmap(x*16, (y*14)+1, glyph_sprites_large[j])
|
||||
x += 1
|
||||
if (j == 0xD0) or (j == 0xE5):
|
||||
|
@ -549,7 +384,7 @@ def make_string_img_list(start, length, num, start_jp=None, len_jp=None, start_s
|
|||
except ValueError:
|
||||
print("ID: {} \tRef.0x{:06X} 0x{:06X} \tRange EN: 0x{:06X}-0x{:06X} \tRange JP: 0x{:06X}-0x{:06X}".format(id, en, jp, en_start, en_end, jp_start, jp_end))
|
||||
raise
|
||||
stringlist.append(["0x{:06X}".format(en), "0x{0:0{1}X}".format(id, id_digits), string, img, string_JP, img_JP, "0x{:06X}".format(jp_start)])
|
||||
stringlist.append(["0x{:06X}".format(en), "0x{:0{}X}".format(id, id_digits), string, img, string_JP, img_JP, "0x{:06X}".format(jp_start)])
|
||||
else:
|
||||
for id in range(num):
|
||||
j1 = start + (id*length)
|
||||
|
@ -559,29 +394,26 @@ def make_string_img_list(start, length, num, start_jp=None, len_jp=None, start_s
|
|||
string_JP, img_JP = make_string_img_large(ROM2[j2:j2+len_jp])
|
||||
else:
|
||||
string_JP, img_JP = make_string_img(ROM2[j2:j2+len_jp], jp=True)
|
||||
stringlist.append(["0x{:06X}".format(j1), "0x{0:0{1}X}".format(id, id_digits), string, img, string_JP, img_JP])
|
||||
stringlist.append(["0x{:06X}".format(j1), "0x{:0{}X}".format(id, id_digits), string, img, string_JP, img_JP])
|
||||
return stringlist
|
||||
|
||||
def make_table(headers, items, sortable=False, row_labels=True):
|
||||
"""
|
||||
Helper function to tabulate 2d lists
|
||||
"""
|
||||
table = QTableWidget()
|
||||
cols = len(headers)
|
||||
rows = len(items)
|
||||
rd = hex_length(rows-1)
|
||||
cols = len(headers)
|
||||
table.setRowCount(rows)
|
||||
table = QTableWidget(rows, cols)
|
||||
if row_labels:
|
||||
table.setVerticalHeaderLabels(['0x{0:0{1}X}'.format(v, rd) for v in range(rows)])
|
||||
table.setVerticalHeaderLabels(['0x{:0{}X}'.format(v, rd) for v in range(rows)])
|
||||
else:
|
||||
table.verticalHeader().setVisible(False)
|
||||
table.setColumnCount(cols)
|
||||
table.setHorizontalHeaderLabels(headers)
|
||||
for row, col, item in [(x,y,items[x][y]) for x in range(rows) for y in range(cols)]:
|
||||
if type(item) == type(QPixmap()):
|
||||
pixmap_scaled = item.scaled(item.size() * 2)
|
||||
lab = QLabel()
|
||||
lab.setPixmap(pixmap_scaled)
|
||||
lab.setPixmap(item.scaled(item.size() * 2))
|
||||
table.setCellWidget(row, col, lab)
|
||||
elif item is not None:
|
||||
q_item = QTableWidgetItem(item)
|
||||
|
@ -604,19 +436,16 @@ def make_table(headers, items, sortable=False, row_labels=True):
|
|||
return table
|
||||
|
||||
def make_pixmap_table(items, scale=4):
|
||||
table = QTableWidget()
|
||||
rows = divceil(len(items), 16)
|
||||
rd = hex_length(rows-1)+1
|
||||
cols = 16
|
||||
table.setRowCount(rows)
|
||||
table.setVerticalHeaderLabels(['0x{0:0{1}X}'.format(v*16, rd) for v in range(rows)])
|
||||
table.setColumnCount(cols)
|
||||
rows = divceil(len(items), cols)
|
||||
rd = hex_length(rows-1)+1
|
||||
table = QTableWidget(rows, cols)
|
||||
table.setVerticalHeaderLabels(['0x{:0{}X}'.format(v*cols, rd) for v in range(rows)])
|
||||
table.setHorizontalHeaderLabels(['0x{:X}'.format(v) for v in range(cols)])
|
||||
for i in range(len(items)):
|
||||
item = items[i]
|
||||
pixmap_scaled = item.scaled(item.size() * scale)
|
||||
lab = QLabel()
|
||||
lab.setPixmap(pixmap_scaled)
|
||||
lab.setPixmap(item.scaled(item.size() * scale))
|
||||
table.setCellWidget(i // cols, i % cols, lab)
|
||||
table.resizeColumnsToContents()
|
||||
return table
|
||||
|
@ -624,7 +453,6 @@ def make_pixmap_table(items, scale=4):
|
|||
|
||||
def main():
|
||||
app = QApplication(sys.argv)
|
||||
|
||||
mainwindow = FF5Reader()
|
||||
sys.exit(app.exec_())
|
||||
|
||||
|
|
|
@ -0,0 +1,124 @@
|
|||
'''
|
||||
No license for now
|
||||
'''
|
||||
import os
|
||||
from array import array
|
||||
|
||||
pyqt_version = 0
|
||||
skip_pyqt5 = "PYQT4" in os.environ
|
||||
|
||||
if not skip_pyqt5:
|
||||
try:
|
||||
from PyQt5 import QtGui
|
||||
from PyQt5.QtGui import QImage, QPixmap, QColor, QPainter
|
||||
pyqt_version = 5
|
||||
except ImportError:
|
||||
print("Missing PyQt5, trying PyQt4...")
|
||||
if pyqt_version == 0:
|
||||
try:
|
||||
from PyQt4 import QtGui
|
||||
from PyQt4.QtGui import QImage, QPixmap, QColor, QPainter
|
||||
pyqt_version = 4
|
||||
except ImportError:
|
||||
print("Missing PyQt4 dependencies")
|
||||
raise
|
||||
|
||||
|
||||
def create_tile(bytes, palette):
|
||||
'''
|
||||
Creates a QPixmap of a SNES tile. DO NOT USE OUTSIDE OF QApplication CONTEXT
|
||||
'''
|
||||
planes = len(bytes)//8
|
||||
tile = array('B', range(64))
|
||||
img = QImage(8, 8, QImage.Format_Indexed8)
|
||||
imgbits = img.bits()
|
||||
imgbits.setsize(img.byteCount())
|
||||
if planes == 0:
|
||||
raise ValueError("Empty bytes passed")
|
||||
if planes == 1:
|
||||
img.setColorTable([0x00000080, 0xFFFFFFFF])
|
||||
for i, (j, x) in enumerate([(j,x) for j in range(8) for x in reversed(range(8))]):
|
||||
tile[i] = (bytes[j] >> x & 1)
|
||||
else:
|
||||
img.setColorTable([c.rgba() for c in palette])
|
||||
for i, (j, x) in enumerate([(j,x) for j in range(0, 16, 2) for x in reversed(range(8))]):
|
||||
tile[i] = (bytes[j] >> x & 1) | ((bytes[j+1] >> x & 1) << 1)
|
||||
if planes == 3:
|
||||
for i, (j, x) in enumerate([(j,x) for j in range(16, 24, 1) for x in reversed(range(8))]):
|
||||
tile[i] |= ((bytes[j] >> x & 1) << 2)
|
||||
elif planes >= 4:
|
||||
for i, (j, x) in enumerate([(j,x) for j in range(16, 32, 2) for x in reversed(range(8))]):
|
||||
tile[i] |= ((bytes[j] >> x & 1) << 2) | ((bytes[j+1] >> x & 1) << 3)
|
||||
if planes == 8:
|
||||
for i, (j, x) in enumerate([(j,x) for j in range(32, 48, 2) for x in reversed(range(8))]):
|
||||
tile[i] |= ((bytes[j] >> x & 1) << 4) | ((bytes[j+1] >> x & 1) << 5) \
|
||||
| ((bytes[j+16] >> x & 1) << 6) | ((bytes[j+17] >> x & 1) << 7)
|
||||
imgbits[:64] = tile
|
||||
return QPixmap.fromImage(img)
|
||||
|
||||
def create_tile_old(bytes, palette):
|
||||
'''
|
||||
Creates a QPixmap of a SNES tile. DO NOT USE OUTSIDE OF QApplication CONTEXT
|
||||
'''
|
||||
planes = len(bytes)//8
|
||||
tile = array('B', range(64))
|
||||
img = QImage(8, 8, QImage.Format_Indexed8)
|
||||
imgbits = img.bits()
|
||||
imgbits.setsize(img.byteCount())
|
||||
if planes == 0:
|
||||
raise ValueError("Empty bytes passed")
|
||||
if planes == 1:
|
||||
img.setColorTable([0x00000080, 0xFFFFFFFF])
|
||||
t_ptr = 0
|
||||
for j, x in [(j,x) for j in range(8) for x in reversed(range(8))]:
|
||||
tile[t_ptr] = (bytes[j] >> x & 1)
|
||||
t_ptr += 1
|
||||
else:
|
||||
img.setColorTable([c.rgba() for c in palette])
|
||||
t_ptr = 0
|
||||
for j, x in [(j,x) for j in range(0, 16, 2) for x in reversed(range(8))]:
|
||||
tile[t_ptr] = (bytes[j] >> x & 1) | ((bytes[j+1] >> x & 1) << 1)
|
||||
t_ptr += 1
|
||||
t_ptr = 0
|
||||
if planes == 3:
|
||||
for j, x in [(j,x) for j in range(16, 24, 1) for x in reversed(range(8))]:
|
||||
tile[t_ptr] |= ((bytes[j] >> x & 1) << 2)
|
||||
t_ptr += 1
|
||||
elif planes >= 4:
|
||||
for j, x in [(j,x) for j in range(16, 32, 2) for x in reversed(range(8))]:
|
||||
tile[t_ptr] |= ((bytes[j] >> x & 1) << 2) | ((bytes[j+1] >> x & 1) << 3)
|
||||
t_ptr += 1
|
||||
if planes == 8:
|
||||
t_ptr = 0
|
||||
for j, x in [(j,x) for j in range(32, 48, 2) for x in reversed(range(8))]:
|
||||
tile[t_ptr] |= ((bytes[j] >> x & 1) << 4) | ((bytes[j+1] >> x & 1) << 5) \
|
||||
| ((bytes[j+16] >> x & 1) << 6) | ((bytes[j+17] >> x & 1) << 7)
|
||||
t_ptr += 1
|
||||
imgbits[:64] = tile
|
||||
return QPixmap.fromImage(img)
|
||||
|
||||
def create_tritile(bytes):
|
||||
img = QImage(16, 12, QImage.Format_Indexed8)
|
||||
imgbits = img.bits()
|
||||
imgbits.setsize(img.byteCount())
|
||||
img.setColorTable([0xFF000080, 0xFFFFFFFF])
|
||||
tile = array('B', range(192))
|
||||
for p, row, b in [(p,j,b) for p in range(2) for j in range(12) for b in reversed(range(8))]:
|
||||
tile[(7-b) + (row*16) + (p*8)] = (bytes[row + (p*12)] >> b & 1)
|
||||
imgbits[:192] = tile
|
||||
return QPixmap.fromImage(img)
|
||||
|
||||
def create_quadtile(bytes, ltr=False):
|
||||
img = QImage(16, 16, QImage.Format_ARGB32_Premultiplied)
|
||||
img.fill(QColor(0,0,0,0))
|
||||
painter = QtGui.QPainter(img)
|
||||
painter.drawPixmap(0, 0, create_tile(bytes[0:8]))
|
||||
painter.drawPixmap(8, 8, create_tile(bytes[24:32]))
|
||||
if ltr:
|
||||
painter.drawPixmap(8, 0, create_tile(bytes[8:16]))
|
||||
painter.drawPixmap(0, 8, create_tile(bytes[16:24]))
|
||||
else:
|
||||
painter.drawPixmap(0, 8, create_tile(bytes[8:16]))
|
||||
painter.drawPixmap(8, 0, create_tile(bytes[16:24]))
|
||||
del painter
|
||||
return QPixmap.fromImage(img)
|
Loading…
Reference in New Issue