def write_background_data_to_rom(self, rom): # Write the background tileset data block_size = self.bg_tileset.block_size(bpp=BG_TILESET_BPP) with EbCompressibleBlock(block_size) as block: self.bg_tileset.to_block(block=block, offset=0, bpp=BG_TILESET_BPP) self._write_compressed_block(rom, block, BG_TILESET_POINTER) # Write the background tile arrangement data block_size = self.bg_arrangement.block_size() with EbCompressibleBlock(block_size) as block: self.bg_arrangement.to_block(block=block, offset=0) self._write_compressed_block(rom, block, BG_ARRANGEMENT_POINTER) # Write the background palette data # There is an additional pointer to this location, so change that one # too block_size = self.bg_palette.block_size() with EbCompressibleBlock(block_size) as block: self.bg_palette.to_block(block=block, offset=0) new_offset = self._write_compressed_block(rom, block, BG_PALETTE_POINTER) write_asm_pointer(block=rom, offset=BG_PALETTE_POINTER_SECONDARY, pointer=to_snes_address(new_offset)) # Write the background animated palette data block_size = self.bg_anim_palette.block_size() with EbCompressibleBlock(block_size) as block: self.bg_anim_palette.to_block(block=block, offset=0) self._write_compressed_block(rom, block, BG_ANIM_PALETTE_POINTER)
def to_block(self, block): with EbCompressibleBlock( self.graphics.block_size(bpp=self.bpp)) as compressed_block: self.graphics.to_block(block=compressed_block, offset=0, bpp=self.bpp) compressed_block.compress() graphics_offset = block.allocate(data=compressed_block) if self.arrangement: with EbCompressibleBlock( self.arrangement.block_size()) as compressed_block: self.arrangement.to_block(block=compressed_block, offset=0) compressed_block.compress() arrangement_offset = block.allocate(data=compressed_block) else: arrangement_offset = None palette_offsets = [] for i, palette in enumerate(self.palettes): with EbCompressibleBlock(palette.block_size()) as compressed_block: palette.to_block(block=compressed_block, offset=0) if self.compressed_palettes: compressed_block.compress() palette_offset = block.allocate(data=compressed_block) palette_offsets.append(palette_offset) return graphics_offset, arrangement_offset, palette_offsets
def write_to_rom(self, rom): graphics_1_block_size = self.graphics_1.block_size(bpp=2) with EbCompressibleBlock(graphics_1_block_size) as compressed_block: self.graphics_1.to_block(block=compressed_block, offset=0, bpp=2) compressed_block.compress() graphics_1_offset = rom.allocate(data=compressed_block) write_asm_pointer(block=rom, offset=GRAPHICS_1_ASM_POINTER_OFFSET, pointer=to_snes_address(graphics_1_offset)) graphics_2_block_size = self.graphics_2.block_size(bpp=2) with EbCompressibleBlock(graphics_2_block_size) as compressed_block: self.graphics_2.to_block(block=compressed_block, offset=0, bpp=2) compressed_block.compress() graphics_2_offset = rom.allocate(data=compressed_block) write_asm_pointer(block=rom, offset=GRAPHICS_2_ASM_POINTER_OFFSET, pointer=to_snes_address(graphics_2_offset)) # Write palettes offset = FLAVOR_PALETTES_OFFSET for palette in self.flavor_palettes: palette.to_block(block=rom, offset=offset) offset += 64 # Write names for asm_pointer_offset in FLAVOR_NAME_ASM_POINTER_OFFSETS: name = self.flavor_names[asm_pointer_offset] offset = rom.allocate(size=FLAVOR_NAME_ENTRY.size) FLAVOR_NAME_ENTRY.to_block(block=rom, offset=offset, value=name) write_asm_pointer(block=rom, offset=asm_pointer_offset, pointer=to_snes_address(offset))
def read_background_data_from_rom(self, rom): with EbCompressibleBlock() as block: # Read the background tileset data self._decompress_block(rom, block, BG_TILESET_POINTER) self.bg_tileset.from_block( block=block, offset=0, bpp=BG_TILESET_BPP ) # Read the background tile arrangement data self._decompress_block(rom, block, BG_ARRANGEMENT_POINTER) self.bg_arrangement.from_block(block=block, offset=0) # Read the background palette data # The decompressed data is smaller than the expected value, # so it is extended with black entries. self._decompress_block(rom, block, BG_PALETTE_POINTER) block.from_array( block.to_array() + [0]*(BG_SUBPALETTE_LENGTH*2 - len(block)) ) self.bg_palette.from_block(block=block, offset=0) # Read the background animated palette data # Each subpalette corresponds to an animation frame. self._decompress_block(rom, block, BG_ANIM_PALETTE_POINTER) self.bg_anim_palette.from_block(block=block, offset=0)
def read_from_rom(self, rom): with EbCompressibleBlock() as block: # Read the tileset data block.from_compressed_block( block=rom, offset=from_snes_address( read_asm_pointer(rom, TILESET_POINTER) ) ) self.tileset.from_block(block=block, offset=0, bpp=TILESET_BPP) # Read the arrangement data block.from_compressed_block( block=rom, offset=from_snes_address( read_asm_pointer(rom, ARRANGEMENT_POINTER) ) ) self.arrangement.from_block(block=block, offset=0) # Read the palette data block.from_compressed_block( block=rom, offset=from_snes_address( read_asm_pointer(rom, PALETTE_POINTER) ) ) self.palette.from_block(block=block, offset=0)
def write_to_rom(self, rom): self.enemy_config_table.to_block( block=rom, offset=from_snes_address(ENEMY_CONFIGURATION_TABLE_DEFAULT_OFFSET)) self.enemy_group_bg_table.to_block( block=rom, offset=from_snes_address( ENEMY_GROUP_BACKGROUND_TABLE_DEFAULT_OFFSET)) # Write the sprites self.graphics_pointer_table.recreate(num_rows=len(self.battle_sprites)) for i, battle_sprite in enumerate(self.battle_sprites): self.graphics_pointer_table[i] = [None, battle_sprite.size()] with EbCompressibleBlock( size=battle_sprite.block_size()) as compressed_block: battle_sprite.to_block(block=compressed_block, offset=0) compressed_block.compress() graphics_offset = rom.allocate(data=compressed_block) self.graphics_pointer_table[i][0] = to_snes_address( graphics_offset) graphics_pointer_table_offset = rom.allocate( size=self.graphics_pointer_table.size) self.graphics_pointer_table.to_block( block=rom, offset=graphics_pointer_table_offset) write_asm_pointer( block=rom, offset=GRAPHICS_POINTER_TABLE_ASM_POINTER_OFFSET, pointer=to_snes_address(graphics_pointer_table_offset)) for pointer_offset in GRAPHICS_POINTER_TABLE_POINTER_OFFSETS: rom.write_multi( pointer_offset, item=to_snes_address(graphics_pointer_table_offset), size=3) # Write the palettes if self.palettes: palettes_offset = rom.allocate(size=self.palettes[0].block_size() * len(self.palettes)) write_asm_pointer(block=rom, offset=PALETTES_ASM_POINTER_OFFSET, pointer=to_snes_address(palettes_offset)) for palette in self.palettes: palette.to_block(block=rom, offset=palettes_offset) palettes_offset += palette.block_size() # Write the groups for i, group in enumerate(self.enemy_groups): offset = rom.allocate( size=(len(group) * EnemyGroupTableEntry.size + 1)) self.enemy_group_table[i][0] = to_snes_address(offset) for group_entry in group: EnemyGroupTableEntry.to_block(block=rom, offset=offset, value=group_entry) offset += EnemyGroupTableEntry.size rom[offset] = 0xff self.enemy_group_table.to_block( block=rom, offset=from_snes_address(ENEMY_GROUP_TABLE_DEFAULT_OFFSET))
def to_block(self, block, tileset_asm_pointer_offset, palette_offset): tileset_block_size = self.tileset.block_size(bpp=2) with EbCompressibleBlock(tileset_block_size) as compressed_block: self.tileset.to_block(block=compressed_block, offset=0, bpp=2) compressed_block.compress() tileset_offset = block.allocate(data=compressed_block) write_asm_pointer(block=block, offset=tileset_asm_pointer_offset, pointer=to_snes_address(tileset_offset)) self.palette.to_block(block=block, offset=palette_offset)
def from_block(self, block, offset): with EbCompressibleBlock() as compressed_block: compressed_block.from_compressed_block(block=block, offset=offset) self.palettes[0].from_block(block=compressed_block, offset=0) self.arrangement.from_block(block=compressed_block, offset=self.palettes[0].block_size()) self.graphics.from_block(block=compressed_block, offset=self.palettes[0].block_size() + 2048, bpp=self.bpp)
def from_block(self, block, graphics_offset, arrangement_offset, palette_offsets): with EbCompressibleBlock() as compressed_block: compressed_block.from_compressed_block(block=block, offset=graphics_offset) self.graphics.from_block(block=compressed_block, offset=0, bpp=self.bpp) if self.arrangement: with EbCompressibleBlock() as compressed_block: compressed_block.from_compressed_block(block=block, offset=arrangement_offset) self.arrangement.from_block(block=compressed_block, offset=0) for i, palette_offset in enumerate(palette_offsets): if self.compressed_palettes: with EbCompressibleBlock() as compressed_block: compressed_block.from_compressed_block(block=block, offset=palette_offset) self.palettes[i].from_block(block=compressed_block, offset=0) else: self.palettes[i].from_block(block=block, offset=palette_offset)
def read_from_rom(self, rom): graphics_offset = from_snes_address( read_asm_pointer(block=rom, offset=GRAPHICS_ASM_POINTER_OFFSET)) with EbCompressibleBlock() as compressed_block: compressed_block.from_compressed_block(block=rom, offset=graphics_offset) self.tileset.from_block(block=compressed_block, bpp=4) self.palette.from_block(block=rom, offset=PALETTE_OFFSET)
def from_block(self, block, tileset_asm_pointer_offset, palette_offset): with EbCompressibleBlock() as compressed_block: compressed_block.from_compressed_block( block=block, offset=from_snes_address( read_asm_pointer(block=block, offset=tileset_asm_pointer_offset))) self.tileset.from_block(block=compressed_block, bpp=2) self.palette.from_block(block=block, offset=palette_offset)
def write_to_rom(self, rom): # Write the tileset data block_size = self.tileset.block_size(bpp=TILESET_BPP) with EbCompressibleBlock(block_size) as block: self.tileset.to_block(block=block, offset=0, bpp=TILESET_BPP) self._write_compressed_block(rom, block, TILESET_POINTER) # Write the tile arrangement data block_size = self.arrangement.block_size() with EbCompressibleBlock(block_size) as block: self.arrangement.to_block(block=block, offset=0) self._write_compressed_block(rom, block, ARRANGEMENT_POINTER) # Write the palette data block_size = self.palette.block_size() with EbCompressibleBlock(block_size) as block: self.palette.to_block(block=block, offset=0) self._write_compressed_block(rom, block, PALETTE_POINTER)
def arrangements_to_block(self, block): with EbCompressibleBlock(1024 * 16 * 2) as compressed_block: i = 0 for arrangement in self.arrangements: for y in range(4): for x in range(4): compressed_block.write_multi(key=i, item=arrangement[y][x], size=2) i += 2 compressed_block.compress() return block.allocate(data=compressed_block)
def write_to_rom(self, rom): tileset_block_size = self.tileset.block_size(bpp=4) with EbCompressibleBlock(tileset_block_size) as compressed_block: self.tileset.to_block(block=compressed_block, offset=0, bpp=4) compressed_block.compress() tileset_offset = rom.allocate(data=compressed_block) write_asm_pointer(block=rom, offset=GRAPHICS_ASM_POINTER_OFFSET, pointer=to_snes_address(tileset_offset)) self.palette.to_block(block=rom, offset=PALETTE_OFFSET)
def to_block(self, rom): # Arrangement space is 2048 bytes long since it's 32x32x2 in VRAM with EbCompressibleBlock(size=self.palettes[0].block_size() + 2048 + self.graphics.block_size(bpp=self.bpp)) \ as compressed_block: self.palettes[0].to_block(block=compressed_block, offset=0) self.arrangement.to_block(block=compressed_block, offset=self.palettes[0].block_size()) self.graphics.to_block(block=compressed_block, offset=self.palettes[0].block_size() + 2048, bpp=self.bpp) compressed_block.compress() return rom.allocate(data=compressed_block)
def write_chars_data_to_rom(self, rom): # Write the characters tileset data block_size = self.chars_tileset.block_size(bpp=CHARS_TILESET_BPP) with EbCompressibleBlock(block_size) as block: self.chars_tileset.to_block(block=block, offset=0, bpp=CHARS_TILESET_BPP) self._write_compressed_block(rom, block, CHARS_TILESET_POINTER) # Write the characters palette data block_size = self.chars_palette.block_size() with EbCompressibleBlock(block_size) as block: self.chars_palette.to_block(block=block, offset=0) self._write_compressed_block(rom, block, CHARS_PALETTE_POINTER) # Write the characters animation palette data block_size = self.chars_anim_palette.block_size() with EbCompressibleBlock(block_size) as block: self.chars_anim_palette.to_block(block=block, offset=0) self._write_compressed_block(rom, block, CHARS_ANIM_PALETTE_POINTER)
def arrangements_from_block(self, block, offset): with EbCompressibleBlock() as compressed_block: compressed_block.from_compressed_block(block=block, offset=offset) num_arrangements = len(compressed_block) // 32 j = 0 for i in range(num_arrangements): arrangement = [[0 for x in range(4)] for y in range(4)] for y in range(4): for x in range(4): arrangement[y][x] = compressed_block.read_multi(key=j, size=2) j += 2 self.arrangements[i] = arrangement
def from_block(self, block, offset): with EbCompressibleBlock() as compressed_block: compressed_block.from_compressed_block(block=block, offset=offset) self.graphics.from_block(block=compressed_block, offset=0, bpp=TILE_BPP) next_offset = self.graphics_data_size self.palette.from_block(block=compressed_block, offset=next_offset) next_offset += self.palette.block_size() for arrangement in self.arrangements: arrangement.from_block(block=compressed_block, offset=next_offset) next_offset += arrangement.block_size()
def read_from_rom(self, rom): with EbCompressibleBlock() as compressed_block: compressed_block.from_compressed_block( block=rom, offset=from_snes_address(read_asm_pointer(rom, GRAPHICS_1_ASM_POINTER_OFFSET))) self.graphics_1.from_block(block=compressed_block, bpp=2) with EbCompressibleBlock() as compressed_block: compressed_block.from_compressed_block( block=rom, offset=from_snes_address(read_asm_pointer(rom, GRAPHICS_2_ASM_POINTER_OFFSET))) self.graphics_2.from_block(block=compressed_block, bpp=2) # Read palettes offset = FLAVOR_PALETTES_OFFSET for palette in self.flavor_palettes: palette.from_block(block=rom, offset=offset) offset += 64 # Read names for asm_pointer_offset in FLAVOR_NAME_ASM_POINTER_OFFSETS: self.flavor_names[asm_pointer_offset] = FLAVOR_NAME_ENTRY.from_block( block=rom, offset=from_snes_address(read_asm_pointer(block=rom, offset=asm_pointer_offset)))
def read_chars_data_from_rom(self, rom): with EbCompressibleBlock() as block: # Read the characters tileset data self._decompress_block(rom, block, CHARS_TILESET_POINTER) self.chars_tileset.from_block(block=block, offset=0, bpp=CHARS_TILESET_BPP) # Read the characters palette data self._decompress_block(rom, block, CHARS_PALETTE_POINTER) self.chars_palette.from_block(block=block, offset=0) # Read the characters animated palette data # Each subpalette corresponds to an animation frame. self._decompress_block(rom, block, CHARS_ANIM_PALETTE_POINTER) self.chars_anim_palette.from_block(block=block, offset=0)
def read_from_rom(self, rom): self.enemy_config_table.from_block(block=rom, offset=from_snes_address(ENEMY_CONFIGURATION_TABLE_DEFAULT_OFFSET)) self.enemy_group_bg_table.from_block(block=rom, offset=from_snes_address(ENEMY_GROUP_BACKGROUND_TABLE_DEFAULT_OFFSET)) # Read the sprites log.debug("Reading battle sprites") self.graphics_pointer_table.from_block( rom, from_snes_address(read_asm_pointer(block=rom, offset=GRAPHICS_POINTER_TABLE_ASM_POINTER_OFFSET))) self.battle_sprites = [] for i in range(self.graphics_pointer_table.num_rows): with EbCompressibleBlock() as compressed_block: compressed_block.from_compressed_block( block=rom, offset=from_snes_address(self.graphics_pointer_table[i][0])) sprite = EbBattleSprite() sprite.from_block(block=compressed_block, offset=0, size=self.graphics_pointer_table[i][1]) self.battle_sprites.append(sprite) # Determine how many palettes there are num_palettes = 0 for i in range(self.enemy_config_table.num_rows): num_palettes = max(num_palettes, self.enemy_config_table[i][14]) num_palettes += 1 # Read the palettes log.debug("Reading palettes") palettes_offset = from_snes_address(read_asm_pointer(block=rom, offset=PALETTES_ASM_POINTER_OFFSET)) self.palettes = [] for i in range(num_palettes): palette = EbPalette(num_subpalettes=1, subpalette_length=16) palette.from_block(block=rom, offset=palettes_offset) self.palettes.append(palette) palettes_offset += palette.block_size() # Read the groups log.debug("Reading enemy groups") self.enemy_group_table.from_block(rom, from_snes_address(ENEMY_GROUP_TABLE_DEFAULT_OFFSET)) self.enemy_groups = [] for i in range(self.enemy_group_table.num_rows): group = [] group_offset = from_snes_address(self.enemy_group_table[i][0]) while rom[group_offset] != 0xff: group.append(EnemyGroupTableEntry.from_block(block=rom, offset=group_offset)) group_offset += EnemyGroupTableEntry.size self.enemy_groups.append(group)
def to_block(self, block): self.graphics_data_size = self.graphics.block_size(bpp=TILE_BPP, trimmed=True) total_block_size = (self.graphics_data_size + self.palette.block_size() + sum(arrangement.block_size() for arrangement in self.arrangements)) with EbCompressibleBlock(total_block_size) as compressed_block: self.graphics.to_block(block=compressed_block, offset=0, bpp=TILE_BPP) next_offset = self.graphics_data_size self.palette.to_block(block=compressed_block, offset=next_offset) next_offset += self.palette.block_size() for arrangement in self.arrangements: arrangement.to_block(block=compressed_block, offset=next_offset) next_offset += arrangement.block_size() compressed_block.compress() return block.allocate(data=compressed_block)
def minitiles_to_block(self, block): with EbCompressibleBlock( self.minitiles.block_size(bpp=4)) as compressed_block: self.minitiles.to_block(block=compressed_block, offset=0, bpp=4) compressed_block.compress() return block.allocate(data=compressed_block)
def minitiles_from_block(self, block, offset): with EbCompressibleBlock() as compressed_block: compressed_block.from_compressed_block(block=block, offset=offset) self.minitiles.from_block(block=compressed_block, bpp=4)
def write_to_rom(self, rom): # Write the data table self.bg_table.to_block( block=rom, offset=from_snes_address(BACKGROUND_TABLE_OFFSET)) self.scroll_table.to_block( block=rom, offset=from_snes_address(SCROLL_TABLE_OFFSET)) self.distortion_table.to_block( block=rom, offset=from_snes_address(DISTORTION_TABLE_OFFSET)) # Write graphics and arrangements self.graphics_pointer_table.recreate(num_rows=len(self.backgrounds)) self.arrangement_pointer_table.recreate(num_rows=len(self.backgrounds)) for i, (tileset, color_depth, arrangement) in enumerate(self.backgrounds): with EbCompressibleBlock(size=tileset.block_size( bpp=color_depth)) as compressed_block: tileset.to_block(block=compressed_block, offset=0, bpp=color_depth) compressed_block.compress() tileset_offset = rom.allocate(data=compressed_block) self.graphics_pointer_table[i] = [ to_snes_address(tileset_offset) ] with EbCompressibleBlock( size=arrangement.block_size()) as compressed_block: arrangement.to_block(block=compressed_block, offset=0) compressed_block.compress() arrangement_offset = rom.allocate(data=compressed_block) self.arrangement_pointer_table[i] = [ to_snes_address(arrangement_offset) ] graphics_pointer_table_offset = rom.allocate( size=self.graphics_pointer_table.size) self.graphics_pointer_table.to_block( block=rom, offset=graphics_pointer_table_offset) for asm_pointer_offset in GRAPHICS_POINTER_TABLE_ASM_POINTER_OFFSETS: write_asm_pointer( block=rom, offset=asm_pointer_offset, pointer=to_snes_address(graphics_pointer_table_offset)) arrangement_pointer_table_offset = rom.allocate( size=self.arrangement_pointer_table.size) self.arrangement_pointer_table.to_block( block=rom, offset=arrangement_pointer_table_offset) for asm_pointer_offset in ARRANGEMENT_POINTER_TABLE_ASM_POINTER_OFFSETS: write_asm_pointer( block=rom, offset=asm_pointer_offset, pointer=to_snes_address(arrangement_pointer_table_offset)) # Write pals self.palette_pointer_table.recreate(num_rows=len(self.palettes)) for i, palette in enumerate(self.palettes): with Block(32) as block: palette.to_block(block=block, offset=0) palette_offset = rom.allocate(data=block) self.palette_pointer_table[i] = [ to_snes_address(palette_offset) ] palette_pointer_table_offset = rom.allocate( size=self.palette_pointer_table.size) self.palette_pointer_table.to_block( block=rom, offset=palette_pointer_table_offset) for asm_pointer_offset in PALETTE_POINTER_TABLE_ASM_POINTER_OFFSETS: write_asm_pointer( block=rom, offset=asm_pointer_offset, pointer=to_snes_address(palette_pointer_table_offset))
def read_from_rom(self, rom): self.bg_table.from_block( block=rom, offset=from_snes_address(BACKGROUND_TABLE_OFFSET)) self.scroll_table.from_block( block=rom, offset=from_snes_address(SCROLL_TABLE_OFFSET)) self.distortion_table.from_block( block=rom, offset=from_snes_address(DISTORTION_TABLE_OFFSET)) self.graphics_pointer_table.from_block( block=rom, offset=from_snes_address( read_asm_pointer( block=rom, offset=GRAPHICS_POINTER_TABLE_ASM_POINTER_OFFSETS[0]))) self.arrangement_pointer_table.from_block( block=rom, offset=from_snes_address( read_asm_pointer( block=rom, offset=ARRANGEMENT_POINTER_TABLE_ASM_POINTER_OFFSETS[0]))) self.palette_pointer_table.from_block( block=rom, offset=from_snes_address( read_asm_pointer( block=rom, offset=PALETTE_POINTER_TABLE_ASM_POINTER_OFFSETS[0]))) self.backgrounds = [ None for i in range(self.graphics_pointer_table.num_rows) ] self.palettes = [ None for i in range(self.palette_pointer_table.num_rows) ] for i in range(self.bg_table.num_rows): graphics_id = self.bg_table[i][0] color_depth = self.bg_table[i][2] if self.backgrounds[graphics_id] is None: # Max tiles used in rom: 421 (2bpp) 442 (4bpp) tileset = EbGraphicTileset(num_tiles=512, tile_width=8, tile_height=8) with EbCompressibleBlock() as compressed_block: compressed_block.from_compressed_block( block=rom, offset=from_snes_address( self.graphics_pointer_table[graphics_id][0])) tileset.from_block(compressed_block, offset=0, bpp=color_depth) arrangement = EbTileArrangement(width=32, height=32) with EbCompressibleBlock() as compressed_block: compressed_block.from_compressed_block( block=rom, offset=from_snes_address( self.arrangement_pointer_table[graphics_id][0])) arrangement.from_block(block=compressed_block, offset=0) self.backgrounds[graphics_id] = (tileset, color_depth, arrangement) palette_id = self.bg_table[i][1] if self.palettes[palette_id] is None: palette = EbPalette(num_subpalettes=1, subpalette_length=16) palette.from_block( block=rom, offset=from_snes_address( self.palette_pointer_table[palette_id][0])) self.palettes[palette_id] = palette