Load enemy sprites

This commit is contained in:
Luke Hubmayer-Werner 2023-08-08 00:22:11 +09:30
parent d1bb23b0f3
commit 19717c6b01
6 changed files with 133 additions and 13 deletions

View File

@ -49,7 +49,8 @@ I have mostly solved parsing of SNES menus in a sister project, however there ar
- [x] Character sprites
- [ ] Weapon sprites (solved problem, soon™)
- [ ] Weapon animations (will hardcode these)
- [ ] Enemy sprites (solved problem, soon™)
- [x] Enemy sprites
- [ ] Enemy sprite separate shadows
- [ ] Backgrounds (solved problem, soon™)
- [ ] Enemy AI (needs research)
- [ ] Abilities (will hardcode these, with fixes and extensions where appropriate)

View File

@ -1,14 +1,19 @@
Label SNES PSX_file PSX_offset format Comment
locations_bg_palettes 0x03BB00 /nar/ff5_binx.bin 0x03BF80 43 of Palette128Of555
enemy_battle_sprite_palettes 0x0ED000 See enemy_battle_sprite_data for pointers. Some are 8 colours instead of 16.
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_palettes 0x0FFCC0 /nar/ff5_binx.bin 0x040000 3 of Palette128Of555
enemy_battle_sprite_layouts_small 0x10D004 102 of 8 of u8 length 0x330
enemy_battle_sprite_layouts_large 0x10D334 72 of 16 of u16 length 0x900
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_palettes 0x14A3C0 /btl/ff5_btl.bin 0x0273C0 5 of 22 of Palette16Of555 Also /mnu/men_bin.eng:0x03A5C0
enemy_battle_sprite_data 0x14B180 384 of EnemySpriteData length 0x780
character_battle_sprite_layouts 0x14B997 /btl/ff5_btl.bin 0x028997 11 of 6 of u8
enemy_battle_sprite_tiles 0x150000 See enemy_battle_sprite_data for pointers
character_battle_sprite_disabled_palette 0x00F867 /mnu/memsave.bin 0x000034 Palette16Of555
character_battle_sprite_stone_palette 0x00F807 N/A N/A Palette16Of555 Also 0x199835
tiles_fist 0x11D710 /btl/ff5_btl.bin 0x021D10 TileSNES3bpp Also /mnu/men_bin.eng:0x00D910

1 Label SNES PSX_file PSX_offset format Comment
2 locations_bg_palettes 0x03BB00 /nar/ff5_binx.bin 0x03BF80 43 of Palette128Of555
3 enemy_battle_sprite_palettes 0x0ED000 See enemy_battle_sprite_data for pointers. Some are 8 colours instead of 16.
4 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
5 worldmap_tiles.bias 0x0FF9C0 /nar/ff5_bin3.bin 0x03FB00 3 of 256 of u8 Add to each pixel of the mode7c tiles
6 worldmap_palettes 0x0FFCC0 /nar/ff5_binx.bin 0x040000 3 of Palette128Of555
7 enemy_battle_sprite_layouts_small 0x10D004 102 of 8 of u8 length 0x330
8 enemy_battle_sprite_layouts_large 0x10D334 72 of 16 of u16 length 0x900
9 worldmap_tiles.0 0x1B8000 /nar/ff5_bin3.bin 0x039B00 256 of TileSNESMode7c Add the biases
10 worldmap_tiles.1 0x1BA000 /nar/ff5_bin3.bin 0x039B00 256 of TileSNESMode7c Add the biases
11 worldmap_tiles.2 0x1BC000 /nar/ff5_bin3.bin 0x039B00 128 of TileSNESMode7c Add the biases
12 character_battle_sprite_tiles 0x120000 /mnu/men_bin.eng 0x010200 5 of 22 of 48 of TileSNES4bpp
13 character_battle_sprite_palettes 0x14A3C0 /btl/ff5_btl.bin 0x0273C0 5 of 22 of Palette16Of555 Also /mnu/men_bin.eng:0x03A5C0
14 enemy_battle_sprite_data 0x14B180 384 of EnemySpriteData length 0x780
15 character_battle_sprite_layouts 0x14B997 /btl/ff5_btl.bin 0x028997 11 of 6 of u8
16 enemy_battle_sprite_tiles 0x150000 See enemy_battle_sprite_data for pointers
17 character_battle_sprite_disabled_palette 0x00F867 /mnu/memsave.bin 0x000034 Palette16Of555
18 character_battle_sprite_stone_palette 0x00F807 N/A N/A Palette16Of555 Also 0x199835
19 tiles_fist 0x11D710 /btl/ff5_btl.bin 0x021D10 TileSNES3bpp Also /mnu/men_bin.eng:0x00D910

View File

@ -115,3 +115,15 @@ u8 weak
struct StatusEffect
4 of u8 initial
3 of u8 immune
struct EnemySpriteData
u7 tileset_offset_hi # combined with lo, << 3, + 0x150000
u1 is_3bpp
u8 tileset_offset_lo
u2 palette_offset_hi # combined with lo, << 4, + 0x0ED000
u4 unk
u1 is_separate_shadow
u1 is_large_layout
u8 palette_offset_lo
u8 layout_id # Small? <<3, + 0x10D004, take 8 bytes. Large? <<5, + 0x10D334, take 32 bytes.

Can't render this file because it has a wrong number of fields in line 43.

View File

@ -70,6 +70,7 @@ func load_snes_rom(filename: String):
snes_data.job_levels.append(ability_list)
print(snes_data.job_levels)
SpriteLoader.load_from_structs(snes_data)
SpriteLoader.load_enemy_battle_sprites(snes_data, buffer)
MapLoader.load_snes_rom(rom_snes)
func load_psx_folder(_dirname: String):

View File

@ -5,6 +5,7 @@ const INDEX_FORMAT := globals.INDEX_FORMAT
const snes_graphics := preload('res://scripts/loaders/snes/graphics.gd')
const gba_graphics := preload('res://scripts/loaders/gba/graphics.gd')
var shader_material = load('res://palette_mat.tres')
const TILE_RECT := Rect2(0, 0, 8, 8)
# Offsets
@ -135,13 +136,12 @@ static func generate_palette_from_colorarray(colors: PoolColorArray, format:=Ima
return img
static func make_tile_atlas(tile_images) -> Image:
var r := Rect2(0, 0, 8, 8)
var image = Image.new()
image.create(128, 128, false, INDEX_FORMAT)
var tile = 0
for y in tile_images.size()/16:
for x in 16:
image.blit_rect(tile_images[tile], r, Vector2(x*8, y*8))
image.blit_rect(tile_images[tile], TILE_RECT, Vector2(x*8, y*8))
tile += 1
return image
@ -273,6 +273,102 @@ static func make_tile_atlas(tile_images) -> Image:
# print_debug('Invalid bpp "%s" in sprite blocks json' % bpp)
# sprite_blocks[k] = tiles
# func load_snes_rom(rom: File):
# snes_load_battle_sprites(rom)
# snes_load_worldmap(rom)
# # snes_load_map_sprites(rom)
# Cache these as they are shared between monsters
var monster_battle_sprite_palettes := {} # offset -> 16 colour palette image
var monster_battle_sprite_palette_textures := {} # offset -> 16 colour palette texture
var monster_battle_sprite_images := {} # "tiles_offset:layout_id:large:bpp" -> tiles laid out in image
var monster_battle_sprite_textures := {} # "tiles_offset:layout_id:large:bpp" -> tiles laid out in texture
func load_enemy_battle_sprites(data: Dictionary, buffer: StreamPeerBuffer):
var PAL: int = Common.SNES_PSX_addresses.enemy_battle_sprite_palettes.SNES
var TILES: int = Common.SNES_PSX_addresses.enemy_battle_sprite_tiles.SNES
var Palette16Of555 = RomLoader.structdefs.Palette16Of555
data.monster_battle_sprites = []
for monster in data.enemy_battle_sprite_data:
var entry = {}
# Fetch or generate+cache palette
var palette_offset = (monster.palette_offset_hi << 12) + (monster.palette_offset_lo << 4)
if not (palette_offset in monster_battle_sprite_palettes):
buffer.seek(palette_offset + PAL)
var colors = PoolColorArray()
for i in 16:
colors.append(snes_graphics.bgr555_to_color(buffer.get_u16()))
var image := generate_palette_from_colorarray(colors)
monster_battle_sprite_palettes[palette_offset] = image
monster_battle_sprite_palette_textures[palette_offset] = texture_from_image(image)
entry['palette'] = monster_battle_sprite_palette_textures[palette_offset]
# Fetch or generate+cache tiles and layout
var bpp := 3 if monster.is_3bpp else 4
var tiles_offset = (monster.tileset_offset_hi << 11) + (monster.tileset_offset_lo << 3)
var key: String
if monster.is_large_layout:
var layout = data.enemy_battle_sprite_layouts_large[monster.layout_id]
key = '%04X:%02X:1:%d' % [tiles_offset, monster.layout_id, bpp]
if not (key in monster_battle_sprite_images):
buffer.seek(tiles_offset + TILES)
var image := Image.new()
image.create(128, 128, false, INDEX_FORMAT)
var max_col := 0
var max_row := 0
if bpp == 3:
for y in 16:
for x in 16:
if (layout[y] & (0x8000 >> x)):
image.blit_rect(snes_graphics._3plane_to_tile(buffer.get_data(24)[1]), TILE_RECT, Vector2(x, y)*8)
if max_row < y:
max_row = y
if max_col < x:
max_col = x
else:
for y in 16:
for x in 16:
if (layout[y] & (0x8000 >> x)):
image.blit_rect(snes_graphics._4plane_to_tile(buffer.get_data(32)[1]), TILE_RECT, Vector2(x, y)*8)
if max_row < y:
max_row = y
if max_col < x:
max_col = x
image.crop(8*(max_col+1), 8*(max_row+1))
monster_battle_sprite_images[key] = image
monster_battle_sprite_textures[key] = texture_from_image(image)
else:
var layout = data.enemy_battle_sprite_layouts_small[monster.layout_id]
key = '%04X:%02X:0:%d' % [tiles_offset, monster.layout_id, bpp]
if not (key in monster_battle_sprite_images):
buffer.seek(tiles_offset + TILES)
var image := Image.new()
image.create(64, 64, false, INDEX_FORMAT)
var max_col := 0
var max_row := 0
if bpp == 3:
for y in 8:
for x in 8:
if (layout[y] & (0x80 >> x)):
image.blit_rect(snes_graphics._3plane_to_tile(buffer.get_data(24)[1]), TILE_RECT, Vector2(x, y)*8)
if max_row < y:
max_row = y
if max_col < x:
max_col = x
else:
for y in 8:
for x in 8:
if (layout[y] & (0x80 >> x)):
image.blit_rect(snes_graphics._4plane_to_tile(buffer.get_data(32)[1]), TILE_RECT, Vector2(x, y)*8)
if max_row < y:
max_row = y
if max_col < x:
max_col = x
image.crop(8*(max_col+1), 8*(max_row+1))
monster_battle_sprite_images[key] = image
monster_battle_sprite_textures[key] = texture_from_image(image)
entry['sprite'] = monster_battle_sprite_textures[key]
# Save monster
data.monster_battle_sprites.append(entry)
static func bias_tile(unbiased: PoolByteArray, bias: int) -> Image:
var image := Image.new()
var biased = ByteArray(64)
@ -281,11 +377,6 @@ static func bias_tile(unbiased: PoolByteArray, bias: int) -> Image:
image.create_from_data(8, 8, false, INDEX_FORMAT, biased)
return image
# func load_snes_rom(rom: File):
# snes_load_battle_sprites(rom)
# snes_load_worldmap(rom)
# # snes_load_map_sprites(rom)
func load_from_structs(data: Dictionary):
# Load Battle sprites
for character_tiles in data.character_battle_sprite_tiles:
@ -296,7 +387,7 @@ func load_from_structs(data: Dictionary):
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_image.blit_rect(job_tiles[sprite_tiles[i]], TILE_RECT, 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
@ -335,7 +426,7 @@ func load_from_structs(data: Dictionary):
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))
image.blit_rect(tile_images[src_idx], TILE_RECT, 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)
@ -353,7 +444,7 @@ func load_from_structs(data: Dictionary):
# 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))
# image.blit_rect(tile_images[tile], TILE_RECT, 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)
@ -397,7 +488,7 @@ func load_gba_rom(filename: String):
var strip_image = Image.new()
strip_image.create(16, 24 * num_Character_Battle_Sprite_Layouts, false, INDEX_FORMAT)
for i in range(6 * num_Character_Battle_Sprite_Layouts):
strip_image.blit_rect(tiles[battle_strip_layouts[i]], Rect2(0, 0, 8, 8), Vector2((i%2) * 8, (i/2) * 8))
strip_image.blit_rect(tiles[battle_strip_layouts[i]], TILE_RECT, Vector2((i%2) * 8, (i/2) * 8))
strip_images.append(strip_image)
strip_textures.append(texture_from_image(strip_image))

View File

@ -1,5 +1,5 @@
extends Control
const palette_mat := preload('res://palette_mat.tres')
var save_slots = []
var save_slot_dicts = []
@ -25,6 +25,16 @@ func _ready():
$PartyMenu.update_labels(data)
ThemeManager.set_menu_color_555(data.config.menu_color_r, data.config.menu_color_g, data.config.menu_color_b)
var monster_box := GridContainer.new()
monster_box.columns = 8
add_child(monster_box)
for mon in RomLoader.snes_data.monster_battle_sprites:
var t := TextureRect.new()
t.material = palette_mat.duplicate()
t.texture = mon.sprite
t.material.set_shader_param('palette', mon.palette)
monster_box.add_child(t)
# var lbl = Label.new()
# for i in 22:
# lbl.text = lbl.text + '%s - %s\n' % [StringLoader.get_job_name(i), StringLoader.get_job_desc(i)]