diff --git a/ff5reader.py b/ff5reader.py index d5a96f8..c0aa7cd 100755 --- a/ff5reader.py +++ b/ff5reader.py @@ -38,6 +38,7 @@ from includes.snes import * import includes.ff5.const as const from includes.ff5.strings import StringBlock, RPGe_Dialogue_Width from includes.ff5.strings import Strings as FFVStrings +import includes.ff5.structs as FFVStructs import includes.ff4 as ff4 import includes.ff5 as ff5 import includes.ff6 as ff6 @@ -87,16 +88,6 @@ class FF5Reader(QMainWindow): string_images[k0] += string_images.pop(k) perfcount() - battle_bg_structure = [('Tileset', 1, None), - ('Palette 1', 1, None), - ('Palette 2', 1, None), - ('Tilemap', 1, None), - ('TilemapFlip', 1, None), - (hex(5, 1), 1, None), - ('Animation', 1, None), - ('PaletteCycle',1, None),] - battle_bg_headers = ['Address'] + [z[0] for z in battle_bg_structure] - battle_bg_data = [parse_struct(ROM_jp, 0x14BA21 + (i*8), battle_bg_structure) for i in range(34)] tileset_headers = ("ID", "Offset", "Pointer", "Expected Length") tileset_data = [] @@ -117,16 +108,6 @@ class FF5Reader(QMainWindow): address = start + (npc*7) npc_layers.append([hex(i, 6), hex(layer, 3)] + parse_struct(ROM_en, address, const.npc_layer_structure)) - enemy_sprite_data = [] - enemy_sprite_structure = [ - ('Sprite data offset', 2, None), - ('Multiple things', 2, None), - ('Tile Layout ID', 1, None), - ] - enemy_sprite_headers = ['Address']+[i[0] for i in enemy_sprite_structure]+['EN Name','EN Name'] - address = 0x14B180 - for i in range(0x180): - enemy_sprite_data.append(parse_struct(ROM_en, address + (i*5), enemy_sprite_structure) + string_images['enemy_names'][i][3:5]) perfcount() print('Generating map tiles') @@ -187,6 +168,7 @@ class FF5Reader(QMainWindow): self.battle_strips = make_character_battle_sprites(ROM_en) status_strips = make_character_status_sprites(ROM_en) enemy_sprites = make_enemy_sprites(ROM_en) + enemy_sprite_data = FFVStructs.EnemySprite.get_data(ROM_en) enemy_sprites_named = [stack_labels(s, d[-2]) for s, d in zip(enemy_sprites, enemy_sprite_data)] perfcount() @@ -242,12 +224,13 @@ class FF5Reader(QMainWindow): self.ff6widget.addTab(make_px_table(self.portraits_ff6, cols=19, scale=2), 'Character Portraits') - structs_tab.addTab(make_table(ff5.ZoneData.zone_headers, ff5.ZoneData.get_data(), True), 'Zones') + structs_tab.addTab(make_table(FFVStructs.ZoneData.get_headers(), FFVStructs.ZoneData.get_data(ROM_en), True), 'Zones') + structs_tab.addTab(make_table(FFVStructs.BattleBackground.get_headers(), FFVStructs.BattleBackground.get_data(ROM_jp), True), 'BattleBGs') + structs_tab.addTab(make_table(FFVStructs.EnemySprite.get_headers(), enemy_sprite_data, True), 'Enemy Sprites') structs_tab.addTab(make_table(tileset_headers, tileset_data, True), 'Tilesets') - structs_tab.addTab(make_table(battle_bg_headers, battle_bg_data, True), 'BattleBGs') structs_tab.addTab(make_table(const.npc_layer_headers, npc_layers, True), 'NPC Layers') - structs_tab.addTab(make_table(enemy_sprite_headers, enemy_sprite_data, True), 'Enemy Sprites') + # Strings tabs for k, images in string_images.items(): scale = 1 if FFVStrings.config[k].get('dialog') else 2 caption = ' '.join(f'{w[0].upper()}{w[1:]}' for w in k.split('_')) diff --git a/includes/ff5/__init__.py b/includes/ff5/__init__.py index 59ae30d..8b13789 100644 --- a/includes/ff5/__init__.py +++ b/includes/ff5/__init__.py @@ -1,42 +1 @@ -from . import const, files, strings -from ..helpers import hex, parse_struct -class ZoneData: - def split_tilesets(data): - tilesets = [(data & 0x00003F), - (data & 0x000FC0) >> 6, - (data & 0x03F000) >> 12, - (data & 0xFC0000) >> 18] - return ' '.join([hex(i,2) for i in tilesets]) - - def split_blockmaps(data): - blockmaps = [(data & 0x000003FF) - 1, - ((data & 0x000FFC00) >> 10) - 1, - ((data & 0x3FF00000) >> 20) - 1] - return ' '.join([hex(i,3) for i in blockmaps]) - - zone_structure = [('NPC Layer', 2, None), # 00 01 - ('Name', 1, strings.Strings.blocks_RPGe['zone_names'].decoded), # 02 - ('ShadowFlags', 1, None), # 03 - ('Graphic maths', 1, None), # 04 - MSb animation-related, 6 LSbs are ID for table in 0x005BB8 which writes to $2131-$2133 (Color Math Designation, Subscreen BG color) - ('Tile properties',1, None), # 05 - ('Flags '+hex(6), 1, None), # 06 - (hex(7), 1, None), # 07 - ('Blockset', 1, None), # 08 - ('Tilesets', 3, split_tilesets), # 09 0A 0B - ('Blockmaps', 4, split_blockmaps), # 0C 0D 0E 0F - (hex(16), 1, None), # 10 - (hex(17), 1, None), # 11 - (hex(18), 1, None), # 12 - (hex(19), 1, None), # 13 - (hex(20), 1, None), # 14 - (hex(21), 1, None), # 15 - ('Palette', 1, None), # 16 - (hex(23), 1, None), # 17 - (hex(24), 1, None), # 18 - ('Music', 1, const.BGM_Tracks)] # 19 - zone_headers = ['Address'] + [z[0] for z in zone_structure] - - @classmethod - def get_data(cls): - return [parse_struct(files.ROM_RPGe, 0x0E9C00 + (i*0x1A), cls.zone_structure) for i in range(const.zone_count)] diff --git a/includes/ff5/structs.py b/includes/ff5/structs.py new file mode 100644 index 0000000..e61cd1a --- /dev/null +++ b/includes/ff5/structs.py @@ -0,0 +1,92 @@ +from . import const, strings +from ..helpers import hex, parse_struct + + +class StructBlock: + structure = None + block_start = 0 + block_length = 0 + block_count = 0 + + @classmethod + def get_data(cls, rom: bytes): + start = cls.block_start + step = cls.block_length + end = start + (step * cls.block_count) + return [parse_struct(rom, address, cls.structure) for address in range(start, end, step)] + + @classmethod + def get_headers(cls): + return ['Address'] + [z[0] for z in cls.structure] + +class BattleBackground(StructBlock): + structure = ( + ('Tileset', 1, None), + ('Palette 1', 1, None), + ('Palette 2', 1, None), + ('Tilemap', 1, None), + ('TilemapFlip', 1, None), + (hex(5, 1), 1, None), + ('Animation', 1, None), + ('PaletteCycle',1, None), + ) + block_start = 0x14BA21 + block_length = 8 + block_count = 34 + + +class EnemySprite(StructBlock): + structure = ( + ('Sprite data offset', 2, None), + ('Multiple things', 2, None), + ('Tile Layout ID', 1, None), + ) + headers = ['Address']+[i[0] for i in structure] + block_start = 0x14B180 + block_length = 5 + block_count = 0x180 + + +class ZoneData(StructBlock): + def split_tilesets(data): + tilesets = [ + (data & 0x00003F), # 0b00000000_00000000_00111111 + (data & 0x000FC0) >> 6, # 0b00000000_00001111_11000000 + (data & 0x03F000) >> 12, # 0b00000011_11110000_00000000 + (data & 0xFC0000) >> 18, # 0b11111100_00000000_00000000 + ] + return ' '.join([hex(i,2) for i in tilesets]) + + def split_blockmaps(data): + blockmaps = [ + ( data & 0x000003FF) - 1, # 0b00000000_00000000_00000011_11111111 + ((data & 0x000FFC00) >> 10) - 1, # 0b00000000_00001111_11111100_00000000 + ((data & 0x3FF00000) >> 20) - 1, # 0b00111111_11110000_00000000_00000000 + ] + return ' '.join([hex(i,3) for i in blockmaps]) + + structure = ( + ('NPC Layer', 2, None), # 00 01 + ('Name', 1, strings.Strings.blocks_RPGe['zone_names'].decoded), # 02 + ('ShadowFlags', 1, None), # 03 + ('Graphic maths', 1, None), # 04 - MSb animation-related, 6 LSbs are ID for table in 0x005BB8 which writes to $2131-$2133 (Color Math Designation, Subscreen BG color) + ('Tile properties',1, None), # 05 + ('Flags '+hex(6), 1, None), # 06 + (hex(7), 1, None), # 07 + ('Blockset', 1, None), # 08 + ('Tilesets', 3, split_tilesets), # 09 0A 0B + ('Blockmaps', 4, split_blockmaps), # 0C 0D 0E 0F + (hex(16), 1, None), # 10 + (hex(17), 1, None), # 11 + (hex(18), 1, None), # 12 + (hex(19), 1, None), # 13 + (hex(20), 1, None), # 14 + (hex(21), 1, None), # 15 + ('Palette', 1, None), # 16 + (hex(23), 1, None), # 17 + (hex(24), 1, None), # 18 + ('Music', 1, const.BGM_Tracks), # 19 + ) + block_start = 0x0E9C00 + block_length = 0x1A + block_count = const.zone_count