Migrate worldmap and battle strip generation to struct system

This commit is contained in:
Luke Hubmayer-Werner 2023-08-07 21:20:35 +09:30
parent 3a35eb73f0
commit 11059735ee
7 changed files with 123 additions and 35 deletions

View File

@ -1,9 +1,11 @@
Label SNES PSX_file PSX_offset format Comment Label SNES PSX_file PSX_offset format Comment
locations_bg_palettes 0x03BB00 /nar/ff5_binx.bin 0x03BF80 43 of Palette128Of555 locations_bg_palettes 0x03BB00 /nar/ff5_binx.bin 0x03BF80 43 of Palette128Of555
worldmap_blocks 0x0FF0C0 /nar/ff5_binx.bin 0x040300 3 of 192 of 4 of u8 worldmap_blocks 0x0FF0C0 /nar/ff5_binx.bin 0x040300 3 of 4 of 192 of u8 # Top-left corners, top-right corners, bottom-left corners, bottom-right corners
worldmap_tiles.bias 0x0FF9C0 /nar/ff5_bin3.bin 0x03FB00 3 of 256 of u8 Add to each pixel of the mode7c tiles worldmap_tiles.bias 0x0FF9C0 /nar/ff5_bin3.bin 0x03FB00 3 of 256 of u8 Add to each pixel of the mode7c tiles
worldmap_palettes 0x0FFCC0 /nar/ff5_binx.bin 0x040000 3 of Palette128Of555 worldmap_palettes 0x0FFCC0 /nar/ff5_binx.bin 0x040000 3 of Palette128Of555
worldmap_tiles 0x1B8000 /nar/ff5_bin3.bin 0x039B00 3 of 256 of TileSNESMode7c Add the biases worldmap_tiles.0 0x1B8000 /nar/ff5_bin3.bin 0x039B00 256 of TileSNESMode7c Add the biases
worldmap_tiles.1 0x1BA000 /nar/ff5_bin3.bin 0x039B00 256 of TileSNESMode7c Add the biases
worldmap_tiles.2 0x1BC000 /nar/ff5_bin3.bin 0x039B00 128 of TileSNESMode7c Add the biases
character_battle_sprite_tiles 0x120000 /mnu/men_bin.eng 0x010200 5 of 22 of 48 of TileSNES4bpp character_battle_sprite_tiles 0x120000 /mnu/men_bin.eng 0x010200 5 of 22 of 48 of TileSNES4bpp
character_battle_sprite_palettes 0x14A3C0 /btl/ff5_btl.bin 0x0273C0 5 of 22 of Palette16Of555 Also /mnu/men_bin.eng:0x03A5C0 character_battle_sprite_palettes 0x14A3C0 /btl/ff5_btl.bin 0x0273C0 5 of 22 of Palette16Of555 Also /mnu/men_bin.eng:0x03A5C0
character_battle_sprite_layouts 0x14B997 /btl/ff5_btl.bin 0x028997 11 of 6 of u8 character_battle_sprite_layouts 0x14B997 /btl/ff5_btl.bin 0x028997 11 of 6 of u8

1 Label SNES PSX_file PSX_offset format Comment
2 locations_bg_palettes 0x03BB00 /nar/ff5_binx.bin 0x03BF80 43 of Palette128Of555
3 worldmap_blocks 0x0FF0C0 /nar/ff5_binx.bin 0x040300 3 of 192 of 4 of u8 3 of 4 of 192 of u8 # Top-left corners, top-right corners, bottom-left corners, bottom-right corners
4 worldmap_tiles.bias 0x0FF9C0 /nar/ff5_bin3.bin 0x03FB00 3 of 256 of u8 Add to each pixel of the mode7c tiles
5 worldmap_palettes 0x0FFCC0 /nar/ff5_binx.bin 0x040000 3 of Palette128Of555
6 worldmap_tiles worldmap_tiles.0 0x1B8000 /nar/ff5_bin3.bin 0x039B00 3 of 256 of TileSNESMode7c 256 of TileSNESMode7c Add the biases
7 worldmap_tiles.1 0x1BA000 /nar/ff5_bin3.bin 0x039B00 256 of TileSNESMode7c Add the biases
8 worldmap_tiles.2 0x1BC000 /nar/ff5_bin3.bin 0x039B00 128 of TileSNESMode7c Add the biases
9 character_battle_sprite_tiles 0x120000 /mnu/men_bin.eng 0x010200 5 of 22 of 48 of TileSNES4bpp
10 character_battle_sprite_palettes 0x14A3C0 /btl/ff5_btl.bin 0x0273C0 5 of 22 of Palette16Of555 Also /mnu/men_bin.eng:0x03A5C0
11 character_battle_sprite_layouts 0x14B997 /btl/ff5_btl.bin 0x028997 11 of 6 of u8

View File

@ -27,8 +27,8 @@ func load_snes_rom(filename: String):
var bytes := rom_snes.get_buffer(rom_snes.get_len()) var bytes := rom_snes.get_buffer(rom_snes.get_len())
var buffer = StreamPeerBuffer.new() var buffer = StreamPeerBuffer.new()
buffer.data_array = bytes buffer.data_array = bytes
SpriteLoader.load_snes_rom(rom_snes) # SpriteLoader.load_snes_rom(rom_snes)
MapLoader.load_snes_rom(rom_snes) # MapLoader.load_snes_rom(rom_snes)
StringLoader.load_snes_rom(rom_snes, true) StringLoader.load_snes_rom(rom_snes, true)
# Don't do this concurrently, avoid file pointer conflicts # Don't do this concurrently, avoid file pointer conflicts
#var _thread_error = thread.start(SoundLoader, 'parse_rom', rom_snes) #var _thread_error = thread.start(SoundLoader, 'parse_rom', rom_snes)
@ -45,7 +45,20 @@ func load_snes_rom(filename: String):
if not s: if not s:
assert(false, 'Invalid StructType: "%s"' % d.format) assert(false, 'Invalid StructType: "%s"' % d.format)
buffer.seek(d.SNES) buffer.seek(d.SNES)
snes_data[key] = s.get_value(buffer, [0, 0]) if '.' in key:
var keysplit: PoolStringArray = key.split('.', 1)
var k0 := keysplit[0]
var k1 = keysplit[1]
if k1.is_valid_integer():
k1 = int(k1)
if not (k0 in snes_data):
snes_data[k0] = {k1: s.get_value(buffer, [0, 0])}
else:
snes_data[k0][k1] = s.get_value(buffer, [0, 0])
else:
snes_data[key] = s.get_value(buffer, [0, 0])
SpriteLoader.load_from_structs(snes_data)
MapLoader.load_snes_rom(rom_snes)
func load_psx_folder(_dirname: String): func load_psx_folder(_dirname: String):
pass pass
@ -73,24 +86,6 @@ func _ready():
var _error := psx_productcode_regex.compile('(S[A-Z]{3}_\\d{3}\\.\\d{2});(\\d)') var _error := psx_productcode_regex.compile('(S[A-Z]{3}_\\d{3}\\.\\d{2});(\\d)')
load_snes_rom(ROM_filename) load_snes_rom(ROM_filename)
# Debugging breakpoint # Debugging breakpoint
for i in 128:
var weapon = snes_data.tbl_weapons[i]
if weapon.byte_2_leftover:
print('Weapon %d ($%02X) has byte_2_leftover set' % [i, i])
if weapon.byte_8_leftover:
print('Weapon %d ($%02X) has byte_8_leftover set' % [i, i])
if weapon['is_5.4']:
print('Weapon %d ($%02X) has 5.4 set' % [i, i])
for i in 96:
var armor = snes_data.tbl_armors[i]
if armor.byte_0_leftover:
print('Armor %d ($%02X) "%s" has byte_0_leftover set' % [i, i, StringLoader.tables.items[i+0x80]])
if armor.byte_4_leftovers:
print('Armor %d ($%02X) "%s" has byte_4_leftovers set' % [i, i, StringLoader.tables.items[i+0x80]])
if armor.byte_2_leftovers:
print('Armor %d ($%02X) "%s" has byte_2_leftovers set to %d ($%02X)' % [i, i, StringLoader.tables.items[i+0x80], armor.byte_2_leftovers, armor.byte_2_leftovers])
if armor.gear_special:
print('Armor %d ($%02X) "%s" has gear_special set to %d ($%02X)' % [i, i, StringLoader.tables.items[i+0x80], armor.gear_special, armor.gear_special])
pass pass
func _exit_tree() -> void: func _exit_tree() -> void:

View File

@ -121,6 +121,19 @@ static func generate_palette(rom: File, offset: int, length: int = 16) -> Image:
length = 16 length = 16
return generate_palette_rgb8(rom, offset, length) return generate_palette_rgb8(rom, offset, length)
static func generate_palette_from_colorarray(colors: PoolColorArray, format:=Image.FORMAT_RGBF) -> Image:
var img := Image.new()
var rows := len(colors)/16
img.create(16, rows, false, format)
img.lock()
var i := 0
for y in rows:
for x in 16:
img.set_pixel(x, y, colors[i])
i += 1
img.unlock()
return img
static func make_tile_atlas(tile_images) -> Image: static func make_tile_atlas(tile_images) -> Image:
var r := Rect2(0, 0, 8, 8) var r := Rect2(0, 0, 8, 8)
var image = Image.new() var image = Image.new()
@ -260,12 +273,90 @@ func snes_load_map_sprites(rom: File):
print_debug('Invalid bpp "%s" in sprite blocks json' % bpp) print_debug('Invalid bpp "%s" in sprite blocks json' % bpp)
sprite_blocks[k] = tiles sprite_blocks[k] = tiles
static func bias_tile(unbiased: PoolByteArray, bias: int) -> Image:
var image := Image.new()
var biased = ByteArray(64)
for i in 64:
biased[i] = unbiased[i] + bias
image.create_from_data(8, 8, false, INDEX_FORMAT, biased)
return image
func load_snes_rom(rom: File): func load_snes_rom(rom: File):
snes_load_battle_sprites(rom) snes_load_battle_sprites(rom)
snes_load_worldmap(rom) snes_load_worldmap(rom)
# snes_load_map_sprites(rom) # snes_load_map_sprites(rom)
func load_from_structs(data: Dictionary):
# Load Battle sprites
for character_tiles in data.character_battle_sprite_tiles:
for job_tiles in character_tiles:
var strip_image = Image.new()
# Should probably refactor later
strip_image.create(16, 24 * num_Character_Battle_Sprite_Layouts, false, INDEX_FORMAT)
for sprite in num_Character_Battle_Sprite_Layouts:
var sprite_tiles: PoolByteArray = data.character_battle_sprite_layouts[sprite]
for i in 6:
strip_image.blit_rect(job_tiles[sprite_tiles[i]], Rect2(0, 0, 8, 8), Vector2((i%2) * 8, ((i/2) * 8) + (sprite * 24)))
strip_images.append(strip_image)
strip_textures.append(texture_from_image(strip_image))
# Character Battle Sprite Palettes
for character_palettes in data.character_battle_sprite_palettes:
for job_palette in character_palettes:
character_battle_sprite_palette_textures.append(texture_from_image(generate_palette_from_colorarray(job_palette)))
character_battle_sprite_palette_disabled_texture = texture_from_image(generate_palette_from_colorarray(data.character_battle_sprite_disabled_palette))
character_battle_sprite_palette_stone_texture = texture_from_image(generate_palette_from_colorarray(data.character_battle_sprite_stone_palette))
weapon_textures['Fist'] = texture_from_image(data.tiles_fist)
# Load World Map
# Load Worldmap Graphics
var worldmap_tile_counts = [256, 256, 128] # Only 128 underwater tiles
for world_ts in 3: # Bartz/Combined World, Galuf World, Underwater (world tilesets, not to be confused with the 5 world maps)
var tile_count: int = worldmap_tile_counts[world_ts]
var image := generate_palette_from_colorarray(data.worldmap_palettes[world_ts])
worldmap_palette_imgs.append(image)
worldmap_palette_textures.append(texture_from_image(image))
var tile_biases: PoolByteArray = data.worldmap_tiles.bias[world_ts]
var tile_images_unbiased = data.worldmap_tiles[world_ts]
var tile_images := []
for i in tile_count:
tile_images.append(bias_tile(tile_images_unbiased[i].get_data(), tile_biases[i]))
if world_ts == 0: # Waterfall hack: lay it out vertically, pushing out dummy tiles
tile_images[0x97] = tile_images[0x88]
tile_images[0x98] = tile_images[0x87]
worldmap_tile_individual_imgs.append(tile_images)
worldmap_tile_atlas_textures.append(texture_from_image(make_tile_atlas(tile_images)))
# Block definitions
var block_images = []
var block_textures = []
var block_tile_ids := PoolByteArray()
for block in 0xC0: # 192 blocks per world tileset
image = Image.new()
image.create(16, 16, false, INDEX_FORMAT)
for i in 4:
var src_idx: int = data.worldmap_blocks[world_ts][i][block]
block_tile_ids.append(src_idx)
if src_idx < tile_count:
image.blit_rect(tile_images[src_idx], Rect2(0, 0, 8, 8), Vector2((i%2)*8, (i/2)*8))
block_images.append(image)
block_textures.append(texture_from_image(image))
worldmap_block_individual_imgs.append(block_images)
worldmap_block_individual_textures.append(block_textures)
worldmap_block_tile_ids.append(block_tile_ids)
# Make block atlas
# image = Image.new()
# image.create(16*16, 16*12, false, INDEX_FORMAT)
# for block in 0xC0:
# image.blit_rect(block_images[block], Rect2(0, 0, 16, 16), Vector2((block%16)*16, (block/16)*16))
# worldmap_block_atlas_imgs.append(image)
# worldmap_block_atlas_textures.append(texture_from_image(image))
# # DEBUG: Make tile atlas
# image = Image.new()
# image.create(16*8, (tile_count/16)*8, false, INDEX_FORMAT)
# for tile in tile_count:
# image.blit_rect(tile_images[tile], Rect2(0, 0, 8, 8), Vector2((tile%16)*8, (tile/16)*8))
# worldmap_tile_atlas_textures.append(texture_from_image(image))
MapLoader.update_worldmap_block_tile_ids(worldmap_block_tile_ids)
const gba_marker := 'FINAL FANTASY V ADVANCE SYGMAB' const gba_marker := 'FINAL FANTASY V ADVANCE SYGMAB'
const gba_marker_pos_US := 0x12FE10 const gba_marker_pos_US := 0x12FE10

View File

@ -1,6 +1,7 @@
shader_type canvas_item; shader_type canvas_item;
uniform sampler2D tile_atlas : hint_normal; uniform sampler2D tile_atlas : hint_normal;
uniform sampler2D palette : hint_normal; uniform sampler2D palette : hint_normal;
uniform float palette_rows = 8.0; // 128 colours
// uniform float tile_width = 8.0; // uniform float tile_width = 8.0;
uniform float tilemap_width = 512.0; // Require square tilemap for now uniform float tilemap_width = 512.0; // Require square tilemap for now
uniform bool enable_sea_scroll = true; // Disable on underwater maps (tileset 3) uniform bool enable_sea_scroll = true; // Disable on underwater maps (tileset 3)
@ -73,7 +74,7 @@ void fragment() {
vec2 lut_uv = get_tile_atlas_uv(s, UV); vec2 lut_uv = get_tile_atlas_uv(s, UV);
float color_id = texture(tile_atlas, lut_uv).r; float color_id = texture(tile_atlas, lut_uv).r;
float color_idx16 = color_id * index_scale; float color_idx16 = color_id * index_scale;
float pal_row = trunc(color_idx16) / 16.0; float pal_row = trunc(color_idx16) / palette_rows;
float pal_col = fract(color_idx16); float pal_col = fract(color_idx16);
vec2 palette_uv = vec2(pal_col, pal_row); vec2 palette_uv = vec2(pal_col, pal_row);
COLOR = texture(palette, palette_uv); COLOR = texture(palette, palette_uv);

View File

@ -25,11 +25,11 @@ func _ready():
$PartyMenu.update_labels(data) $PartyMenu.update_labels(data)
ThemeManager.set_menu_color_555(data.config.menu_color_r, data.config.menu_color_g, data.config.menu_color_b) ThemeManager.set_menu_color_555(data.config.menu_color_r, data.config.menu_color_g, data.config.menu_color_b)
var lbl = Label.new() # var lbl = Label.new()
for i in 22: # for i in 22:
lbl.text = lbl.text + '%s - %s\n' % [StringLoader.get_job_name(i), StringLoader.get_job_desc(i)] # lbl.text = lbl.text + '%s - %s\n' % [StringLoader.get_job_name(i), StringLoader.get_job_desc(i)]
for i in 78: # for i in 78:
lbl.text = lbl.text + '\n%s - %s' % [StringLoader.get_ability_name(i), StringLoader.get_ability_desc(i)] # lbl.text = lbl.text + '\n%s - %s' % [StringLoader.get_ability_name(i), StringLoader.get_ability_desc(i)]
for i in range(128, 161): # for i in range(128, 161):
lbl.text = lbl.text + '\n%s - %s' % [StringLoader.get_ability_name(i), StringLoader.get_ability_desc(i)] # lbl.text = lbl.text + '\n%s - %s' % [StringLoader.get_ability_name(i), StringLoader.get_ability_desc(i)]
add_child(lbl) # add_child(lbl)

View File

@ -14,14 +14,12 @@ theme = ExtResource( 6 )
script = ExtResource( 3 ) script = ExtResource( 3 )
[node name="audio_system" parent="." instance=ExtResource( 5 )] [node name="audio_system" parent="." instance=ExtResource( 5 )]
visible = false
position = Vector2( 0, 160 ) position = Vector2( 0, 160 )
[node name="worldmap_system" parent="." instance=ExtResource( 2 )] [node name="worldmap_system" parent="." instance=ExtResource( 2 )]
visible = false
[node name="battle_sprites" parent="." instance=ExtResource( 4 )] [node name="battle_sprites" parent="." instance=ExtResource( 4 )]
visible = false
[node name="PartyMenu" parent="." instance=ExtResource( 1 )] [node name="PartyMenu" parent="." instance=ExtResource( 1 )]
visible = false
margin_right = 320.0 margin_right = 320.0

View File

@ -4,6 +4,7 @@
[resource] [resource]
shader = ExtResource( 1 ) shader = ExtResource( 1 )
shader_param/palette_rows = 8.0
shader_param/tilemap_width = 512.0 shader_param/tilemap_width = 512.0
shader_param/enable_sea_scroll = true shader_param/enable_sea_scroll = true
shader_param/enable_waterfall_scroll = true shader_param/enable_waterfall_scroll = true