FF6 portraits. Character sprites need LUT for palettes.
This commit is contained in:
parent
d32ca0608e
commit
b246973513
71
ff5reader.py
71
ff5reader.py
|
@ -17,6 +17,7 @@ skip_pyqt5 = 'PYQT4' in os.environ
|
|||
filename_en = 'Final Fantasy V (Japan) [En by RPGe v1.1].sfc'
|
||||
filename_jp = 'Final Fantasy V (Japan).sfc'
|
||||
filename_jp_ff4 = 'Final Fantasy IV (Japan) (Rev A).sfc'
|
||||
filename_jp_ff6 = 'Final Fantasy VI (Japan).sfc'
|
||||
|
||||
if not skip_pyqt5:
|
||||
try:
|
||||
|
@ -97,7 +98,10 @@ with open(filename_jp, 'rb') as file:
|
|||
print(len(ROM_jp), filename_jp)
|
||||
with open(filename_jp_ff4, 'rb') as file:
|
||||
ROM_FF4jp = file.read()
|
||||
print(len(ROM_jp), filename_jp)
|
||||
print(len(ROM_FF4jp), filename_jp_ff4)
|
||||
with open(filename_jp_ff6, 'rb') as file:
|
||||
ROM_FF6jp = file.read()
|
||||
print(len(ROM_FF6jp), filename_jp_ff6)
|
||||
|
||||
stringlist_headers = ['Address', 'ID', 'Name']
|
||||
imglist_headers = stringlist_headers + ['Img', 'Name JP', 'Img JP']
|
||||
|
@ -207,6 +211,8 @@ class FF5Reader(QMainWindow):
|
|||
status_strips = make_character_status_sprites(ROM_en)
|
||||
enemy_sprites = make_enemy_sprites(ROM_en)
|
||||
self.battle_strips_ff4 = make_character_battle_sprites_ff4(ROM_FF4jp)
|
||||
self.battle_strips_ff6 = make_character_battle_sprites_ff6(ROM_FF6jp)
|
||||
self.portraits_ff6 = make_character_portrait_sprites_ff6(ROM_FF6jp)
|
||||
|
||||
enemy_sprites_named = [stack_labels(s, d[-2]) for s, d in zip(enemy_sprites, enemy_sprite_data)]
|
||||
|
||||
|
@ -228,6 +234,8 @@ class FF5Reader(QMainWindow):
|
|||
#sprites_tab.addTab(make_pixmap_table(enemy_sprites, scale=1), 'Enemy Sprites')
|
||||
sprites_tab.addTab(make_pixmap_table(enemy_sprites_named, cols=32, scale=1), 'Enemy Sprites')
|
||||
sprites_tab.addTab(make_pixmap_table(self.battle_strips_ff4, cols=16, scale=2), 'FF4 Character Battle Sprites')
|
||||
sprites_tab.addTab(make_pixmap_table(self.battle_strips_ff6, cols=32, scale=2), 'FF6 Character Battle Sprites')
|
||||
sprites_tab.addTab(make_pixmap_table(self.portraits_ff6, cols=19, scale=2), 'FF6 Character Portraits')
|
||||
|
||||
|
||||
structs_tab.addTab(make_table(zone_headers, zone_data, True), 'Zones')
|
||||
|
@ -286,12 +294,12 @@ class Canvas:
|
|||
def __del__(self):
|
||||
del self.painter
|
||||
|
||||
def draw_pixmap(self, row, column, pixmap):
|
||||
self.painter.drawPixmap(row*8, column*8, pixmap)
|
||||
if row > self.max_x:
|
||||
self.max_x = row
|
||||
if column > self.max_y:
|
||||
self.max_y = column
|
||||
def draw_pixmap(self, col, row, pixmap):
|
||||
self.painter.drawPixmap(col*8, row*8, pixmap)
|
||||
if col > self.max_x:
|
||||
self.max_x = col
|
||||
if row > self.max_y:
|
||||
self.max_y = row
|
||||
|
||||
def pixmap(self, trim=False):
|
||||
if trim:
|
||||
|
@ -320,8 +328,7 @@ def make_enemy_sprites(rom):
|
|||
tile_offset = ((((rom[0x14B180+e_id]&0x7F)<<8)| rom[0x14B181+e_id]) << 3) + 0x150000 # For whatever reason this is big endian
|
||||
pal_offset = ((((rom[0x14B182+e_id]&0x03)<<8)| rom[0x14B183+e_id]) << 4) + 0x0ED000 # For whatever reason this is big endian
|
||||
pal_size = 16 if triplane else 32
|
||||
palette = generate_palette(rom, pal_offset, pal_size)
|
||||
palette[0] = 0
|
||||
palette = generate_palette(rom, pal_offset, pal_size, transparent=True)
|
||||
layout_id = rom[0x14B184+e_id]
|
||||
boss_layout = bool(rom[0x14B182+e_id]&0x80)
|
||||
if boss_layout:
|
||||
|
@ -345,9 +352,8 @@ def make_enemy_sprites(rom):
|
|||
|
||||
|
||||
def make_battle_strip(rom, palette_address, tile_address, num_tiles):
|
||||
palette = generate_palette(rom, palette_address)
|
||||
palette = generate_palette(rom, palette_address, transparent=True)
|
||||
# We don't want the background drawn, so we'll make that colour transparent
|
||||
palette[0] = 0
|
||||
battle_strip = Canvas(2, divceil(num_tiles, 2)) # KO sprites are here which means more tiles than FFV
|
||||
for j in range(num_tiles):
|
||||
offset = tile_address+(j*32)
|
||||
|
@ -373,6 +379,49 @@ def make_character_battle_sprites_ff4(rom):
|
|||
return battle_strips
|
||||
|
||||
|
||||
def make_character_battle_sprites_ff6(rom):
|
||||
# Palettes are non-trivial for this, will need a LUT
|
||||
tile_address = 0x150000
|
||||
palette_address = 0x268000
|
||||
battle_strips = []
|
||||
for i in range(0, 16*32, 32): # quite a few characters
|
||||
battle_strips.append(make_battle_strip(rom, palette_address+0x80, tile_address+(i*181), 181))
|
||||
tile_address += 16*181*32
|
||||
for i in range(0, 6*32, 32): # bonus memes
|
||||
battle_strips.append(make_battle_strip(rom, palette_address+0x80, tile_address+(i*171), 171))
|
||||
tile_address += 6*171*32
|
||||
for i in range(0, 4*32, 32): # bonus memes
|
||||
battle_strips.append(make_battle_strip(rom, palette_address+0x80, tile_address+(i*55), 55))
|
||||
tile_address += 4*55*32
|
||||
for i in range(0, 40*32, 32): # bonus memes
|
||||
battle_strips.append(make_battle_strip(rom, palette_address+0x80, tile_address+(i*56), 56))
|
||||
return battle_strips
|
||||
|
||||
def make_character_portrait_sprites_ff6(rom):
|
||||
# 5x5 tiles per character, annoying arrangement but palettes are good
|
||||
tile_address = 0x2D1D00
|
||||
palette_address = 0x2D5860
|
||||
palettes = [generate_palette(rom, palette_address+i*32, transparent=True) for i in range(19)]
|
||||
# Coordinates for each tile
|
||||
LUT = [(0,0), (1,0), (2,0), (3,0), (0,2), (1,2), (2,2), (3,2), (4,0), (4,1), (4,2), (4,3), (4,4), (0,4), (1,4), (2,4), (0,1), (1,1), (2,1), (3,1), (0,3), (1,3), (2,3), (3,3), (3,4)]
|
||||
portraits = []
|
||||
for palette, t_start in zip(palettes, [tile_address+i*25*32 for i in range(19)]):
|
||||
canvas = Canvas(5, 5)
|
||||
for t in range(25):
|
||||
offset = t_start+(t*32)
|
||||
canvas.draw_pixmap(*LUT[t], create_tile(rom[offset:offset+32], palette))
|
||||
portraits.append(canvas.pixmap())
|
||||
# Palette-swap time!
|
||||
for palette in palettes:
|
||||
for t_start in [tile_address+i*25*32 for i in range(19)]:
|
||||
canvas = Canvas(5, 5)
|
||||
for t in range(25):
|
||||
offset = t_start+(t*32)
|
||||
canvas.draw_pixmap(*LUT[t], create_tile(rom[offset:offset+32], palette))
|
||||
portraits.append(canvas.pixmap())
|
||||
return portraits
|
||||
|
||||
|
||||
def make_character_battle_sprites(rom):
|
||||
tile_address = 0x120000
|
||||
palette_address = 0x14A3C0
|
||||
|
|
|
@ -139,7 +139,7 @@ def generate_glyphs_large(rom, offset, num=0x100):
|
|||
spritelist.append(create_tritile(rom[j:j+24]))
|
||||
return spritelist
|
||||
|
||||
def generate_palette(rom, offset, length=32):
|
||||
def generate_palette(rom, offset, length=32, transparent=False):
|
||||
'''
|
||||
Length is in bytes not colors (2 bytes per color)
|
||||
We need to convert BGR555 to ARGB32 for each 2 bytes
|
||||
|
@ -155,4 +155,6 @@ def generate_palette(rom, offset, length=32):
|
|||
else:
|
||||
color = 0 # Transparent
|
||||
palette.append(color)
|
||||
if transparent:
|
||||
palette[0] = 0
|
||||
return palette
|
||||
|
|
Loading…
Reference in New Issue