Initial zone/fieldmap drawing
This commit is contained in:
parent
7fe8fb7351
commit
5d701a02fc
119
ff5reader.py
119
ff5reader.py
|
@ -152,30 +152,32 @@ class FF5Reader(QMainWindow):
|
|||
(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),
|
||||
('Name', 1, [z[2] for z in zone_names]),
|
||||
('ShadowFlags', 1, None),
|
||||
(hex(4, 2), 1, None),
|
||||
(hex(5, 2), 1, None),
|
||||
('Flags '+hex(6,2),1, None),
|
||||
(hex(7, 2), 1, None),
|
||||
('Tilesets', 3, split_tilesets),
|
||||
(hex(11, 2), 1, None),
|
||||
('Collision Layer',1, None),
|
||||
(hex(13, 2), 1, None),
|
||||
(hex(14, 2), 1, None),
|
||||
(hex(15, 2), 1, None),
|
||||
(hex(16, 2), 1, None),
|
||||
(hex(17, 2), 1, None),
|
||||
(hex(18, 2), 1, None),
|
||||
(hex(19, 2), 1, None),
|
||||
(hex(20, 2), 1, None),
|
||||
(hex(21, 2), 1, None),
|
||||
('Palette', 1, None),
|
||||
(hex(23, 2), 1, None),
|
||||
(hex(24, 2), 1, None),
|
||||
('Music', 1, const.BGM_Tracks)]
|
||||
zone_structure = [('NPC Layer', 2, None), # 00 01
|
||||
('Name', 1, [z[2] for z in zone_names]), # 02
|
||||
('ShadowFlags', 1, None), # 03
|
||||
('Graphic maths', 1, None), # 04
|
||||
('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]
|
||||
zone_data = [parse_struct(ROM_en, 0x0E9C00 + (i*0x1A), zone_structure) for i in range(const.zone_count)]
|
||||
|
||||
|
@ -223,20 +225,21 @@ class FF5Reader(QMainWindow):
|
|||
perfcount()
|
||||
print('Generating map tiles')
|
||||
worldmap_palettes = [generate_palette(ROM_jp, 0x0FFCC0+(i*0x100), length=0x160, transparent=True) for i in range(3)]
|
||||
world_tiles = [make_worldmap_tiles(ROM_jp, 0x0FF0C0+(i*0x300), 0x1B8000+(i*0x2000), 0x0FF9C0+(i*0x100)) for i in range(3)]
|
||||
world_tiles = [make_worldmap_blocks(ROM_jp, 0x0FF0C0+(i*0x300), 0x1B8000+(i*0x2000), 0x0FF9C0+(i*0x100)) for i in range(3)]
|
||||
worldpixmaps = [make_worldmap_pixmap(ROM_jp, i, 0x0FFCC0+(t*0x100), world_tiles[t]) for i, t in enumerate([0, 1, 0, 2, 2])]
|
||||
world_tiles_pixmaps = []
|
||||
world_blocks_pixmaps = []
|
||||
for i, tiles in enumerate(world_tiles):
|
||||
a = []
|
||||
for t in tiles:
|
||||
t.setColorTable(worldmap_palettes[i])
|
||||
a.append(QPixmap.fromImage(t))
|
||||
world_tiles_pixmaps.append(a)
|
||||
world_blocks_pixmaps.append(a)
|
||||
perfcount()
|
||||
worldmap_subtiles = make_worldmap_subtiles_pixmap(ROM_jp, 0x1B8000, 0x0FF9C0, 0x0FFCC0)
|
||||
worldmap_subtiles += make_worldmap_subtiles_pixmap(ROM_jp, 0x1BA000, 0x0FFAC0, 0x0FFDC0)
|
||||
worldmap_subtiles += make_worldmap_subtiles_pixmap(ROM_jp, 0x1BC000, 0x0FFBC0, 0x0FFEC0, length=128)
|
||||
worldmap_tiles = make_worldmap_tiles_pixmap(ROM_jp, 0x1B8000, 0x0FF9C0, 0x0FFCC0)
|
||||
worldmap_tiles += make_worldmap_tiles_pixmap(ROM_jp, 0x1BA000, 0x0FFAC0, 0x0FFDC0)
|
||||
worldmap_tiles += make_worldmap_tiles_pixmap(ROM_jp, 0x1BC000, 0x0FFBC0, 0x0FFEC0, length=128)
|
||||
perfcount()
|
||||
|
||||
field_tiles = make_all_field_tiles(ROM_jp)
|
||||
field_minitiles = make_all_field_minitiles(ROM_jp)
|
||||
perfcount()
|
||||
|
@ -245,6 +248,19 @@ class FF5Reader(QMainWindow):
|
|||
perfcount()
|
||||
fieldmap_tiles = [make_field_map_tile_pixmap(ROM_jp, i, st_field_tiles, st_field_minitiles) for i in range(const.zone_count)]
|
||||
perfcount()
|
||||
print('Generating field map blocks')
|
||||
zones = [parse_zone(ROM_jp, i) for i in range(const.zone_count)]
|
||||
field_blocksets = [get_field_map_block_layouts(ROM_jp, i) for i in range(28)]
|
||||
perfcount()
|
||||
blockmaps = get_blockmaps(ROM_jp)
|
||||
field_blocks = []
|
||||
zone_pxs = []
|
||||
for z in zones:
|
||||
blocks = make_field_map_blocks_px(ROM_jp, z.blockset, field_tiles, field_minitiles, field_blocksets)
|
||||
field_blocks.append(stitch_tileset_px(blocks))
|
||||
zone_pxs += make_zone_pxs(blocks, [blockmaps[b] for b in z.blockmaps if b!=-1])
|
||||
perfcount()
|
||||
|
||||
print('Generating Battle backgrounds')
|
||||
battle_bgs = make_battle_backgrounds(ROM_jp)
|
||||
perfcount()
|
||||
|
@ -275,31 +291,36 @@ class FF5Reader(QMainWindow):
|
|||
strings_tab = QTabWidget()
|
||||
structs_tab = QTabWidget()
|
||||
sprites_tab = QTabWidget()
|
||||
backgrounds_tab = QTabWidget()
|
||||
self.ff5widget.addTab(strings_tab, 'Strings')
|
||||
self.ff5widget.addTab(structs_tab, 'Structs')
|
||||
self.ff5widget.addTab(sprites_tab, 'Images')
|
||||
self.ff5widget.addTab(backgrounds_tab, 'Backgrounds')
|
||||
|
||||
sprites_tab.addTab(make_pixmap_table(self.glyph_sprites['glyphs_en_s'], scale=4), 'Glyphs (EN)')
|
||||
sprites_tab.addTab(make_pixmap_table(self.glyph_sprites['glyphs_en_l'], scale=2), 'Glyphs (Dialogue EN)')
|
||||
sprites_tab.addTab(make_pixmap_table(self.glyph_sprites['glyphs_jp_s'], scale=4), 'Glyphs (JP)')
|
||||
sprites_tab.addTab(make_pixmap_table(self.glyph_sprites['glyphs_jp_l'], scale=2), 'Glyphs (Large JP)')
|
||||
sprites_tab.addTab(make_pixmap_table(self.glyph_sprites['glyphs_kanji'], scale=2),'Glyphs (Kanji)')
|
||||
sprites_tab.addTab(make_pixmap_table(worldmap_subtiles, cols=16, scale=4), 'Worldmap Subtiles')
|
||||
sprites_tab.addTab(make_pixmap_table(world_tiles_pixmaps[0], cols=16, scale=4), 'World 1 Tiles')
|
||||
sprites_tab.addTab(make_pixmap_table(world_tiles_pixmaps[1], cols=16, scale=4), 'World 2 Tiles')
|
||||
sprites_tab.addTab(make_pixmap_table(world_tiles_pixmaps[2], cols=16, scale=4), 'Underwater Tiles')
|
||||
sprites_tab.addTab(make_pixmap_table(worldpixmaps, cols=1, scale=1, large=True), 'Worldmaps')
|
||||
sprites_tab.addTab(make_pixmap_table(fieldmap_tiles, cols=8, scale=2), 'Fieldmap Tiles')
|
||||
sprites_tab.addTab(make_pixmap_table(battle_bgs, cols=8, scale=1), 'Battle BGs')
|
||||
sprites_tab.addTab(make_pixmap_table(self.battle_strips, cols=22, scale=2), 'Character Battle Sprites')
|
||||
sprites_tab.addTab(make_pixmap_table(status_strips, cols=22, scale=2), 'Status Sprites')
|
||||
sprites_tab.addTab(make_pixmap_table(enemy_sprites_named, cols=32, scale=1), 'Enemy Sprites')
|
||||
sprites_tab.addTab(make_px_table(self.glyph_sprites['glyphs_en_s'], scale=4), 'Glyphs (EN)')
|
||||
sprites_tab.addTab(make_px_table(self.glyph_sprites['glyphs_en_l'], scale=2), 'Glyphs (Dialogue EN)')
|
||||
sprites_tab.addTab(make_px_table(self.glyph_sprites['glyphs_jp_s'], scale=4), 'Glyphs (JP)')
|
||||
sprites_tab.addTab(make_px_table(self.glyph_sprites['glyphs_jp_l'], scale=2), 'Glyphs (Large JP)')
|
||||
sprites_tab.addTab(make_px_table(self.glyph_sprites['glyphs_kanji'], scale=2),'Glyphs (Kanji)')
|
||||
sprites_tab.addTab(make_px_table(self.battle_strips, cols=22, scale=2), 'Character Battle Sprites')
|
||||
sprites_tab.addTab(make_px_table(status_strips, cols=22, scale=2), 'Status Sprites')
|
||||
sprites_tab.addTab(make_px_table(enemy_sprites_named, cols=32, scale=1), 'Enemy Sprites')
|
||||
|
||||
self.ff4widget.addTab(make_pixmap_table(self.battle_strips_ff4, cols=16, scale=2), 'Character Battle Sprites')
|
||||
self.ff4widget.addTab(make_pixmap_table(self.portraits_ff4, cols=14, scale=2), 'Character Portraits')
|
||||
self.ff4widget.addTab(make_pixmap_table(self.field_strips_ff4, cols=17, scale=2), 'Character Field Sprites')
|
||||
self.ff6widget.addTab(make_pixmap_table(self.battle_strips_ff6, cols=32, scale=2), 'Character Sprites')
|
||||
self.ff6widget.addTab(make_pixmap_table(self.portraits_ff6, cols=19, scale=2), 'Character Portraits')
|
||||
backgrounds_tab.addTab(make_px_table(worldmap_tiles, cols=16, scale=4), 'Worldmap Tiles')
|
||||
backgrounds_tab.addTab(make_px_table(world_blocks_pixmaps[0], cols=16, scale=4), 'World 1 Blocks')
|
||||
backgrounds_tab.addTab(make_px_table(world_blocks_pixmaps[1], cols=16, scale=4), 'World 2 Blocks')
|
||||
backgrounds_tab.addTab(make_px_table(world_blocks_pixmaps[2], cols=16, scale=4), 'Underwater Blocks')
|
||||
backgrounds_tab.addTab(make_px_table(worldpixmaps, cols=1, scale=1, large=True), 'Worldmaps')
|
||||
backgrounds_tab.addTab(make_px_table(fieldmap_tiles, cols=8, scale=1), 'Fieldmap Tiles')
|
||||
backgrounds_tab.addTab(make_px_table(field_blocks, cols=16, scale=1), 'Field Blocks')
|
||||
backgrounds_tab.addTab(make_px_table(zone_pxs, cols=4, scale=1, large=1), 'Zone')
|
||||
backgrounds_tab.addTab(make_px_table(battle_bgs, cols=8, scale=1), 'Battle BGs')
|
||||
|
||||
self.ff4widget.addTab(make_px_table(self.battle_strips_ff4, cols=16, scale=2), 'Character Battle Sprites')
|
||||
self.ff4widget.addTab(make_px_table(self.portraits_ff4, cols=14, scale=2), 'Character Portraits')
|
||||
self.ff4widget.addTab(make_px_table(self.field_strips_ff4, cols=17, scale=2), 'Character Field Sprites')
|
||||
self.ff6widget.addTab(make_px_table(self.battle_strips_ff6, cols=32, scale=2), 'Character Sprites')
|
||||
self.ff6widget.addTab(make_px_table(self.portraits_ff6, cols=19, scale=2), 'Character Portraits')
|
||||
|
||||
|
||||
structs_tab.addTab(make_table(zone_headers, zone_data, True), 'Zones')
|
||||
|
|
|
@ -29,7 +29,7 @@ def hex_length(i):
|
|||
'''
|
||||
return divceil(i.bit_length(), 4)
|
||||
|
||||
def hex(num, digits):
|
||||
def hex(num, digits=2):
|
||||
'''
|
||||
Consolidate hex formatting for consistency
|
||||
'''
|
||||
|
@ -60,12 +60,16 @@ def parse_struct(rom, offset, structure):
|
|||
return out
|
||||
|
||||
|
||||
def decompress_lzss(rom, start, header=False):
|
||||
def decompress_lzss(rom, start, header=False, length=None):
|
||||
'''
|
||||
Algorithm from http://slickproductions.org/slickwiki/index.php/Noisecross:Final_Fantasy_V_Compression
|
||||
'''
|
||||
uncompressed_length = indirect(rom, start)
|
||||
ptr = start+2
|
||||
ptr = start
|
||||
if length:
|
||||
uncompressed_length = length
|
||||
else:
|
||||
uncompressed_length = indirect(rom, start)
|
||||
ptr += 2
|
||||
output = []
|
||||
buffer = [0 for i in range(0x800)]
|
||||
buffer_p = 0x07DE
|
||||
|
|
|
@ -156,7 +156,7 @@ def make_table(headers, items, sortable=False, row_labels=True, scale=2):
|
|||
return table
|
||||
|
||||
|
||||
def make_pixmap_table(items, cols=16, scale=4, large=False):
|
||||
def make_px_table(items, cols=16, scale=4, large=False):
|
||||
rows = divceil(len(items), cols)
|
||||
rd = hex_length(rows-1)+1
|
||||
cd = hex_length(cols-1)
|
||||
|
|
151
includes/snes.py
151
includes/snes.py
|
@ -20,6 +20,29 @@ Functions common to SNES FFs
|
|||
|
||||
from includes.helpers import *
|
||||
from includes.snestile import *
|
||||
from collections import namedtuple
|
||||
|
||||
zone = namedtuple('zone', 'npcs name shadowflags blockset tilesets blockmaps palette music')
|
||||
|
||||
def parse_zone(rom, id, start_address=0x0E9C00):
|
||||
ptr = start_address+(id*0x1A)
|
||||
npcs = indirect(rom, ptr)
|
||||
name = rom[ptr+2]
|
||||
shadowflags = rom[ptr+3]
|
||||
blockset = rom[ptr+8]
|
||||
tilesets_b = indirect(rom, ptr+9, length=3)
|
||||
tilesets = [(tilesets_b & 0x00003F),
|
||||
(tilesets_b & 0x000FC0) >> 6,
|
||||
(tilesets_b & 0x03F000) >> 12,
|
||||
(tilesets_b & 0xFC0000) >> 18]
|
||||
pal_address = 0x03BB00 + (indirect(rom, ptr+0x16)<<8)
|
||||
blockmaps_b = indirect(rom, ptr+0xC, length=4)
|
||||
blockmaps = [(blockmaps_b & 0x000003FF) - 1,
|
||||
((blockmaps_b & 0x000FFC00) >> 10) - 1,
|
||||
((blockmaps_b & 0x3FF00000) >> 20) - 1]
|
||||
palettes = [generate_palette(rom, pal_address+i*32, transparent=True) for i in range(8)]
|
||||
music = rom[ptr+0x19]
|
||||
return zone(npcs, name, shadowflags, blockset, tilesets, blockmaps, palettes, music)
|
||||
|
||||
|
||||
def make_battle_strip(rom, palette_address, tile_address, num_tiles, bpp=4):
|
||||
|
@ -96,27 +119,27 @@ def make_character_status_sprites(rom):
|
|||
return pixmaps
|
||||
|
||||
|
||||
def make_worldmap_subtiles(rom, tiles_address, lut_address, length=0x100):
|
||||
def make_worldmap_tiles(rom, tiles_address, lut_address, length=0x100):
|
||||
subtiles = []
|
||||
for i in range(length):
|
||||
pal_index = rom[lut_address+i]//16
|
||||
subtiles.append(create_tile_mode7_compressed_indexed(rom[tiles_address+i*32:tiles_address+i*32+32], pal_index))
|
||||
return subtiles
|
||||
|
||||
def stitch_worldmap_tiles(rom, subtiles, offset=0x0FF0C0):
|
||||
tiles = []
|
||||
def stitch_worldmap_tiles(rom, tiles, offset=0x0FF0C0):
|
||||
blocks = []
|
||||
for i in range(0xC0):
|
||||
canvas = Canvas_Indexed(2, 2)
|
||||
for j in range(4):
|
||||
k = indirect(rom, offset+(j*0xC0)+i, length=1)
|
||||
canvas.draw_tile(j%2, j//2, subtiles[k])
|
||||
tiles.append(canvas.image)
|
||||
return tiles
|
||||
canvas.draw_tile(j%2, j//2, tiles[k])
|
||||
blocks.append(canvas.image)
|
||||
return blocks
|
||||
|
||||
def make_worldmap_tiles(rom, tiles_address, subtiles_address, lut_address, length=0x100):
|
||||
return stitch_worldmap_tiles(rom, make_worldmap_subtiles(rom, subtiles_address, lut_address, length=length), tiles_address)
|
||||
def make_worldmap_blocks(rom, blocks_address, tiles_address, lut_address, length=0x100):
|
||||
return stitch_worldmap_tiles(rom, make_worldmap_tiles(rom, tiles_address, lut_address, length=length), blocks_address)
|
||||
|
||||
def make_worldmap_subtiles_pixmap(rom, tiles_address, lut_address, palette_address, length=0x100):
|
||||
def make_worldmap_tiles_pixmap(rom, tiles_address, lut_address, palette_address, length=0x100):
|
||||
tiles = []
|
||||
palettes = [generate_palette(rom, palette_address+i*32, transparent=True) for i in range(16)]
|
||||
for i in range(length):
|
||||
|
@ -182,6 +205,12 @@ def stitch_tileset(tiles):
|
|||
canvas.draw_tile(i%16, i//16, tile)
|
||||
return canvas
|
||||
|
||||
def stitch_tileset_px(tiles_px):
|
||||
canvas = Canvas(16, len(tiles_px)//16)
|
||||
for i, tile in enumerate(tiles_px):
|
||||
canvas.draw_pixmap(i%16, i//16, tile)
|
||||
return canvas.pixmap()
|
||||
|
||||
def get_field_map_tiles(rom, id):
|
||||
'''
|
||||
This is a bit of a mess of pointer chains for now, so generalising it will have to wait.
|
||||
|
@ -214,6 +243,46 @@ def make_field_map_tile_pixmap(rom, id, st_tiles, st_minitiles):
|
|||
canvas.draw_pixmap(0, 48, st_minitiles[minitile].pixmap(p))
|
||||
return canvas.pixmap()
|
||||
|
||||
def get_field_map_block_layouts(rom, id, start_address=0x0F0000):
|
||||
ptr = indirect(rom, start_address+(id*2)) + start_address
|
||||
data = decompress_lzss(rom, ptr)
|
||||
output = []
|
||||
for i in range(0, 0x200, 2):
|
||||
output.append([data[j+i+k] for j in range(0, 0x800, 0x200) for k in range(2)])
|
||||
#for i in range(0, 0x800, 8):
|
||||
#output.append([data[i+k] for k in range(8)])
|
||||
return output
|
||||
|
||||
def make_field_map_blocks_px(rom, id, tilesets, minitilesets, blockmaps):
|
||||
*i_tiles, i_minitiles, palettes = get_field_map_tiles(rom, id)
|
||||
tiles = tilesets[i_tiles[0]] + tilesets[i_tiles[1]] + tilesets[i_tiles[2]]
|
||||
tiles += minitilesets[i_minitiles]
|
||||
i_blockmap = rom[0x0E9C08 + (id * 0x1A)]
|
||||
blockmap = blockmaps[i_blockmap]
|
||||
|
||||
blocks = [make_tilemap_canvas(tm, tiles, cols=2, rows=2, pal_adjust=0, tile_modulo=0x1000) for tm in blockmap]
|
||||
return [b.pixmap(palettes) for b in blocks]
|
||||
|
||||
def get_blockmaps(rom, start_address=0x0B0000, num=0x148):
|
||||
bank = 0x0B0000
|
||||
ptrs = [indirect(rom, start_address)+bank]
|
||||
for i in range(1, num):
|
||||
ptr = indirect(rom, start_address+(i*2))
|
||||
if (ptr+bank) < ptrs[-1]:
|
||||
bank += 0x010000
|
||||
ptrs.append(ptr+bank)
|
||||
blockmaps = [decompress_lzss(rom, ptr) for ptr in ptrs]
|
||||
return blockmaps
|
||||
|
||||
def make_zone_pxs(blocks, blockmaps):
|
||||
output = []
|
||||
for bm in blockmaps:
|
||||
canvas = Canvas(64, 64, tilesize=16)
|
||||
for i, b in enumerate(bm):
|
||||
canvas.draw_pixmap(i%64, i//64, blocks[b])
|
||||
output.append(canvas.pixmap())
|
||||
return output
|
||||
|
||||
def decompress_battle_tilemap(rom, address):
|
||||
'''
|
||||
Decompresses the tilemap for a battle background.
|
||||
|
@ -248,14 +317,13 @@ def decompress_battle_tilemap(rom, address):
|
|||
output[1::2] = [i&0xDF for i in o2[:length//2]]
|
||||
return bytes(output)
|
||||
|
||||
def apply_battle_tilemap_flips(rom, id, battle_terrain):
|
||||
def apply_battle_tilemap_flips(rom, id, tilemap):
|
||||
if id==0xFF:
|
||||
return battle_terrain
|
||||
return tilemap
|
||||
ptr = indirect(rom, 0x14C736+(id*2))+0x140000
|
||||
length = len(battle_terrain)//2
|
||||
output = list(battle_terrain)
|
||||
length = len(tilemap)//2
|
||||
output = list(tilemap)
|
||||
buffer = []
|
||||
|
||||
while len(buffer) < length:
|
||||
a = rom[ptr]
|
||||
ptr += 1
|
||||
|
@ -267,49 +335,54 @@ def apply_battle_tilemap_flips(rom, id, battle_terrain):
|
|||
for b in reversed(range(0, 8, 1)):
|
||||
buffer.append((a>>b)&0x01)
|
||||
|
||||
for i in range(len(battle_terrain)//2):
|
||||
for i in range(len(tilemap)//2):
|
||||
output[i*2+1] |= (buffer[i] << 6)
|
||||
return bytes(output)
|
||||
|
||||
def make_tilemap_canvas(tilemap, tiles, tile_adjust=0, pal_adjust=-1):
|
||||
def parse_tileset_word(data):
|
||||
a, b = data[:2]
|
||||
tile_index = a|((b & 0x03) << 8)
|
||||
palette = (b & 0x1C) >> 2
|
||||
priority = (b & 0x20) >> 5
|
||||
h_flip = (b & 0x40) >> 6
|
||||
v_flip = (b & 0x80) >> 7
|
||||
return tile_index, palette, h_flip, v_flip, priority
|
||||
|
||||
def make_tilemap_canvas(tilemap, tiles, cols=64, rows=64, tile_adjust=0, pal_adjust=-1, tile_modulo=0x80):
|
||||
'''
|
||||
Battle bg is 64x64 map size, 8x8 tile size
|
||||
4bpp tiles
|
||||
'''
|
||||
canvas = Canvas_Indexed(64, 64)
|
||||
canvas = Canvas_Indexed(cols, rows)
|
||||
for i in range(len(tilemap)//2):
|
||||
a, b = tilemap[i*2:(i+1)*2]
|
||||
tile_index = a|((b & 0x02) << 8)
|
||||
p = (b & 0x1C) >> 2
|
||||
priority = (b & 0x20) >> 5
|
||||
h_flip = (b & 0x40) >> 6
|
||||
v_flip = (b & 0x80) >> 7
|
||||
|
||||
x = (i % 32) + 32*((i//1024) % 2)
|
||||
y = (i //32) - 32*((i//1024) % 2)
|
||||
tile_index, p, h_flip, v_flip, priority = parse_tileset_word(tilemap[i*2:(i+1)*2])
|
||||
if cols > 32:
|
||||
x = (i % 32) + 32*((i//1024) % 2)
|
||||
y = (i //32) - 32*((i//1024) % 2)
|
||||
else:
|
||||
x = i % cols
|
||||
y = i //cols
|
||||
try:
|
||||
tile = tiles[(tile_index+tile_adjust)%0x80]
|
||||
tile = tiles[(tile_index+tile_adjust)%tile_modulo]
|
||||
canvas.draw_tile(x, y, tile, h_flip, v_flip, p+pal_adjust)
|
||||
except BaseException as e:
|
||||
print(e, p, hex(tile_index,2), hex(tile_adjust,2), hex(tile_index+tile_adjust,2))
|
||||
return canvas
|
||||
|
||||
def make_tilemap_pixmap(tilemap, tiles, palettes, tile_adjust=0, pal_adjust=-1):
|
||||
def make_tilemap_pixmap(tilemap, tiles, palettes, cols=64, rows=64, tile_adjust=0, pal_adjust=-1):
|
||||
'''
|
||||
Battle bg is 64x64 map size, 8x8 tile size
|
||||
4bpp tiles
|
||||
'''
|
||||
canvas = Canvas(64, 64)
|
||||
canvas = Canvas(cols, rows)
|
||||
for i in range(len(tilemap)//2):
|
||||
a, b = tilemap[i*2:(i+1)*2]
|
||||
tile_index = a|((b & 0x02) << 8)
|
||||
p = (b & 0x1C) >> 2
|
||||
priority = (b & 0x20) >> 5
|
||||
h_flip = (b & 0x40) >> 6
|
||||
v_flip = (b & 0x80) >> 7
|
||||
|
||||
x = (i % 32) + 32*((i//1024) % 2)
|
||||
y = (i //32) - 32*((i//1024) % 2)
|
||||
tile_index, p, h_flip, v_flip, priority = parse_tileset_word(tilemap[i*2:(i+1)*2])
|
||||
if cols > 32:
|
||||
x = (i % 32) + 32*((i//1024) % 2)
|
||||
y = (i //32) - 32*((i//1024) % 2)
|
||||
else:
|
||||
x = i % cols
|
||||
y = i //cols
|
||||
try:
|
||||
palette = palettes[p+pal_adjust]
|
||||
tile = tiles[(tile_index+tile_adjust)%0x80]
|
||||
|
@ -366,7 +439,7 @@ def make_battle_backgrounds(rom):
|
|||
a.append(b)
|
||||
a = [(i, j) for i, j in zip(a[0::2], a[1::2])]
|
||||
animations.append(a)
|
||||
animation_time = 15 # Frames before changing
|
||||
animation_time = 8 # Frames before changing
|
||||
|
||||
pal_cycle_ptr_start = 0x14C6CD
|
||||
pal_cycle_ptrs = [indirect(rom, pal_cycle_ptr_start+(i*2))+0x140000 for i in range(3)]
|
||||
|
|
|
@ -213,12 +213,13 @@ def generate_palette(rom, offset, length=32, transparent=False):
|
|||
|
||||
|
||||
class Canvas:
|
||||
def __init__(self, cols, rows, color=bg_trans):
|
||||
self.image = QImage(8*cols, 8*rows, QImage.Format_ARGB32_Premultiplied)
|
||||
def __init__(self, cols, rows, color=bg_trans, tilesize=8):
|
||||
self.image = QImage(tilesize*cols, tilesize*rows, QImage.Format_ARGB32_Premultiplied)
|
||||
self.tilesize = tilesize
|
||||
self.image.fill(color)
|
||||
self.painter = QtGui.QPainter(self.image)
|
||||
self.max_x = 1
|
||||
self.max_y = 1
|
||||
self.max_col = 1
|
||||
self.max_row = 1
|
||||
|
||||
def __del__(self):
|
||||
del self.painter
|
||||
|
@ -226,19 +227,19 @@ class Canvas:
|
|||
def draw_pixmap(self, col, row, pixmap, h_flip=False, v_flip=False):
|
||||
h_s = -1 if h_flip else 1
|
||||
v_s = -1 if v_flip else 1
|
||||
x = (col+h_flip)*8*h_s
|
||||
y = (row+v_flip)*8*v_s
|
||||
x = (col+h_flip)*self.tilesize*h_s
|
||||
y = (row+v_flip)*self.tilesize*v_s
|
||||
self.painter.scale(h_s, v_s)
|
||||
self.painter.drawPixmap(x, y, pixmap)
|
||||
self.painter.scale(h_s, v_s) # Invert it again to restore it to normal
|
||||
if col > self.max_x:
|
||||
self.max_x = col
|
||||
if row > self.max_y:
|
||||
self.max_y = row
|
||||
if col > self.max_col:
|
||||
self.max_col = col
|
||||
if row > self.max_row:
|
||||
self.max_row = row
|
||||
|
||||
def pixmap(self, trim=False):
|
||||
if trim:
|
||||
return QPixmap.fromImage(self.image.copy(0, 0, self.max_x*8+8, self.max_y*8+8))
|
||||
return QPixmap.fromImage(self.image.copy(0, 0, (self.max_col+1)*self.tilesize, (self.max_row+1)*self.tilesize))
|
||||
return QPixmap.fromImage(self.image)
|
||||
|
||||
|
||||
|
@ -270,6 +271,8 @@ class Canvas_Indexed:
|
|||
self.max_row = max(row, self.max_row)
|
||||
|
||||
def pixmap(self, palette, trim=False):
|
||||
if isinstance(palette[0], list):
|
||||
palette = [i for p in palette for i in p] # Flatten
|
||||
if trim:
|
||||
img = self.image.copy(0, 0, (self.max_col+1)*self.tilesize, (self.max_row+1)*self.tilesize)
|
||||
img.setColorTable(palette)
|
||||
|
|
Loading…
Reference in New Issue