Beispiel #1
0
    def write_to_rom(self, rom):
        # Write animations to rom
        animation_offsets = []
        for animation in self.animations:
            offset = animation.to_block(rom)
            animation_offsets.append(offset)

        # Build up animation table
        new_num_rows = len(
            self.animations
        ) + 1  # Add 1 because the table is prefixed with an empty entry
        if self.table.num_rows != new_num_rows:
            self.table.recreate(new_num_rows)

        self.table[0] = [0, 0, 0, 0]  # The first entry should be empty
        for i, animation in enumerate(self.animations):
            self.table[i + 1] = [
                to_snes_address(animation_offsets[i]),
                animation.graphics_data_size, animation.frames,
                animation.unknown
            ]

        # Relocate animation table so we can store more than six animations
        new_table_offset = rom.allocate(size=self.table.size)
        write_animation_table_address(rom, to_snes_address(new_table_offset))
        self.table.to_block(rom, offset=new_table_offset)
Beispiel #2
0
    def write_to_rom(self, rom):
        apply_relocation_patch(rom)

        # Write frames and populate swirl table
        frame_hashes = {}
        animation_pointers = []
        animation_pointers_index = 0
        for i, swirl in enumerate(self.swirls):
            num_frames = len(swirl.frames)

            self.swirl_table[i] = [swirl.speed, animation_pointers_index, num_frames]

            frame_offsets = write_swirl_frames(rom, swirl, frame_hashes)
            animation_pointers += frame_offsets
            animation_pointers_index += num_frames

        # Allocate animation pointer table
        animation_pointer_table_offset = rom.allocate(size=4 * len(animation_pointers))
        for offset, pointer_delta in RELOCATED_SWIRL_ANIMATION_POINTER_TABLE_POINTERS:
            rom.write_multi(offset, to_snes_address(animation_pointer_table_offset + pointer_delta), 3)

        # Write animation pointer table
        for animation_pointer in animation_pointers:
            rom.write_multi(animation_pointer_table_offset, to_snes_address(animation_pointer), 4)
            animation_pointer_table_offset += 4

        # Write swirls table
        self.swirl_table.to_block(
            rom, offset=from_snes_address(SWIRL_TABLE_DEFAULT_OFFSET))
Beispiel #3
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))
Beispiel #4
0
    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 write_town_map_icons_to_rom(self, rom):
     log.debug("Writing town map icons")
     graphics_offset, arrangement_offset, palette_offsets = self.town_map_icons.to_block(rom)
     write_asm_pointer(block=rom,
                       offset=TOWN_MAP_ICON_GRAPHICS_ASM_POINTER_OFFSET,
                       pointer=to_snes_address(graphics_offset))
     write_asm_pointer(block=rom,
                       offset=TOWN_MAP_ICON_PALETTE_ASM_POINTER_OFFSET,
                       pointer=to_snes_address(palette_offsets[0]))
 def write_town_map_icons_to_rom(self, rom):
     log.debug("Writing town map icons")
     graphics_offset, arrangement_offset, palette_offsets = self.town_map_icons.to_block(rom)
     write_asm_pointer(block=rom,
                       offset=TOWN_MAP_ICON_GRAPHICS_ASM_POINTER_OFFSET,
                       pointer=to_snes_address(graphics_offset))
     write_asm_pointer(block=rom,
                       offset=TOWN_MAP_ICON_PALETTE_ASM_POINTER_OFFSET,
                       pointer=to_snes_address(palette_offsets[0]))
    def write_logos_to_rom(self, rom, logos, infos):
        for info, logo in zip(infos, logos):
            graphics_offset, arrangement_offset, palette_offsets = logo.to_block(rom)

            for asm_pointer_offset in info.graphics_asm_pointer_offsets:
                write_asm_pointer(block=rom, offset=asm_pointer_offset, pointer=to_snes_address(graphics_offset))
            for asm_pointer_offset in info.arrangement_asm_pointer_offsets:
                write_asm_pointer(block=rom, offset=asm_pointer_offset, pointer=to_snes_address(arrangement_offset))
            for offset, asm_pointer_offset in zip(palette_offsets, info.palette_asm_pointer_offsets):
                write_asm_pointer(block=rom, offset=asm_pointer_offset, pointer=to_snes_address(offset))
    def write_logos_to_rom(self, rom, logos, infos):
        for info, logo in zip(infos, logos):
            graphics_offset, arrangement_offset, palette_offsets = logo.to_block(rom)

            for asm_pointer_offset in info.graphics_asm_pointer_offsets:
                write_asm_pointer(block=rom, offset=asm_pointer_offset, pointer=to_snes_address(graphics_offset))
            for asm_pointer_offset in info.arrangement_asm_pointer_offsets:
                write_asm_pointer(block=rom, offset=asm_pointer_offset, pointer=to_snes_address(arrangement_offset))
            for offset, asm_pointer_offset in zip(palette_offsets, info.palette_asm_pointer_offsets):
                write_asm_pointer(block=rom, offset=asm_pointer_offset, pointer=to_snes_address(offset))
Beispiel #9
0
    def write_to_rom(self, rom):
        self.font_pointer_table.from_block(block=rom,
                                           offset=from_snes_address(FONT_POINTER_TABLE_OFFSET))
        for i, font in enumerate(self.fonts):
            log.debug("Writing font #{} to the ROM".format(FONT_FILENAMES[i]))

            graphics_offset, widths_offset = font.to_block(block=rom)
            self.font_pointer_table[i][0] = to_snes_address(widths_offset)
            self.font_pointer_table[i][1] = to_snes_address(graphics_offset)
        self.font_pointer_table.to_block(block=rom,
                                         offset=from_snes_address(FONT_POINTER_TABLE_OFFSET))

        self.write_credits_font_to_rom(rom)
Beispiel #10
0
    def write_to_rom(self, rom):
        self.font_pointer_table.from_block(block=rom,
                                           offset=from_snes_address(FONT_POINTER_TABLE_OFFSET))
        for i, font in enumerate(self.fonts):
            log.debug("Writing font #{} to the ROM".format(FONT_FILENAMES[i]))

            graphics_offset, widths_offset = font.to_block(block=rom)
            self.font_pointer_table[i][0] = to_snes_address(widths_offset)
            self.font_pointer_table[i][1] = to_snes_address(graphics_offset)
        self.font_pointer_table.to_block(block=rom,
                                         offset=from_snes_address(FONT_POINTER_TABLE_OFFSET))

        self.write_credits_font_to_rom(rom)
    def write_to_rom(self, rom):
        rom.deallocate((0xf61e7, 0xf8984))

        pointer_table_offset = rom.allocate(size=self.table.size,
                                            can_write_to=partial(not_in_bank, 0x0f))
        self.table.to_block(rom, pointer_table_offset)
        rom.write_multi(self.POINTER_TABLE_POINTER_OFFSET, to_snes_address(pointer_table_offset), 3)
Beispiel #12
0
 def write_to_rom(self, rom):
     # Deallocate the range of the ROM in which we will write the door destinations.
     # We deallocate it here instead of specifying it in FREE_RANGES because we want to be sure that this module
     # get first dibs at writing to this range. This is because door destinations needs to be written to the 0x0F
     # bank of the EB ROM, and this is one of the few ranges available in that bank.
     rom.deallocate((0x0F0000, 0x0F58EE))
     destination_offsets = dict()
     empty_area_offset = from_snes_address(
         rom.allocate(data=[0, 0], can_write_to=not_in_destination_bank))
     i = 0
     for door_area in self.door_areas:
         if (door_area is None) or (not door_area):
             self.pointer_table[i] = [empty_area_offset]
         else:
             num_doors = len(door_area)
             area_offset = rom.allocate(
                 size=(2 + num_doors * 5),
                 can_write_to=not_in_destination_bank)
             self.pointer_table[i] = [to_snes_address(area_offset)]
             rom.write_multi(area_offset, num_doors, 2)
             area_offset += 2
             for door in door_area:
                 door.write_to_block(rom, area_offset, destination_offsets)
                 area_offset += 5
         i += 1
     self.pointer_table.to_block(rom, from_snes_address(0xD00000))
Beispiel #13
0
    def write_sprites_to_free(self, rom):
        if self.num_sprites == 0:
            self.sprite_pointers = []
            return

        unique_sprites, unique_sprite_usages = self.calculate_unique_sprites()

        # Find a free area
        offset = rom.allocate(size=sum(
            [x.block_size() for x in unique_sprites.values()]),
                              can_write_to=(lambda y: (y & 0xf) == 0))
        self.bank = to_snes_address(offset) >> 16
        offset_start = offset & 0xffff

        # Write each sprite
        sprite_offsets = dict()
        for i, (sprite_hash,
                sprite) in enumerate(sorted(unique_sprites.items())):
            sprite.to_block(rom, offset)
            sprite_offsets[sprite_hash] = offset
            offset += sprite.block_size()

        # Get the pointers for each sprite in the group
        self.sprite_pointers = [None] * self.num_sprites
        for i, (sprite_hash, is_mirrored) in enumerate(unique_sprite_usages):
            self.sprite_pointers[i] = (sprite_offsets[sprite_hash]
                                       & 0xffff) | is_mirrored | (
                                           self.sprites[i][1] << 1)
 def _write_compressed_block(rom, compressed_block, pointer):
     compressed_block.compress()
     new_offset = rom.allocate(data=compressed_block)
     write_asm_pointer(
         block=rom, offset=pointer, pointer=to_snes_address(new_offset)
     )
     return new_offset
Beispiel #15
0
 def write_to_rom(self, rom):
     for offset, table in self.tables.iteritems():
         new_table_offset = rom.allocate(size=table.size)
         table.to_block(rom, new_table_offset)
         log.info("Writing table @ " + hex(new_table_offset))
         for pointer in self.TABLE_OFFSETS[offset]:
             pointer.write(rom, to_snes_address(new_table_offset))
    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 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 _write_compressed_block(rom, compressed_block, pointer):
     compressed_block.compress()
     new_offset = rom.allocate(data=compressed_block)
     write_asm_pointer(block=rom,
                       offset=pointer,
                       pointer=to_snes_address(new_offset))
     return new_offset
Beispiel #19
0
    def write_to_rom(self, rom):
        rom.deallocate((0xf61e7, 0xf8984))

        pointer_table_offset = rom.allocate(size=self.table.size,
                                            can_write_to=partial(not_in_bank, 0x0f))
        self.table.to_block(rom, pointer_table_offset)
        rom.write_multi(self.POINTER_TABLE_POINTER_OFFSET, to_snes_address(pointer_table_offset), 3)
Beispiel #20
0
 def write_gfx_to_rom(self, rom, offset, gfx):
     graphics_offset, arrangement_offset, palette_offsets = gfx.to_block(
         block=rom)
     write_asm_pointer(block=rom,
                       offset=offset,
                       pointer=to_snes_address(graphics_offset))
     gfx.palettes[0].to_block(block=rom,
                              offset=CAST_GRAPHICS_PALETTE_OFFSET)
 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)
Beispiel #22
0
    def write_to_rom(self, rom):
        offset = rom.allocate(size=len(self.data))
        self.write_pointer_to_rom(rom, to_snes_address(offset))
        log.debug('Writing staff text')
        rom[offset:offset + len(self.data)] = self.data

        for length_offset in LENGTH_OFFSETS:
            rom.write_multi(length_offset, self.height, 2)
Beispiel #23
0
 def to_block(cls, block, offset, value):
     data_size = cls.data_table_entry.to_block_size(value)
     data_offset = block.allocate(size=data_size,
                                  can_write_to=partial(
                                      is_in_bank, cls.bank))
     cls.pointer_table_entry.to_block(block, offset,
                                      to_snes_address(data_offset))
     cls.data_table_entry.to_block(block, data_offset, value)
Beispiel #24
0
    def write_to_rom(self, rom):
        rom.deallocate((0xf58ef, 0xf61e5))

        pointer_table_offset = rom.allocate(size=self.pointer_table.size,
                                            can_write_to=partial(
                                                not_in_bank, 0x0f))
        self.pointer_table.to_block(rom, pointer_table_offset)
        rom.write_multi(MAP_MUSIC_ASM_POINTER_OFFSET,
                        to_snes_address(pointer_table_offset), 3)
Beispiel #25
0
    def to_block(self, block, value):
        if self.pointer:
            loc = block.allocate(size=self.table_entry.size)
            self.pointer.write(block, to_snes_address(loc))
        else:
            loc = self.default_offset

        value = self.table_entry.from_yml_rep(value)
        self.table_entry.to_block(block, loc, value)
Beispiel #26
0
    def to_block(self, block, value):
        if self.pointer:
            loc = block.allocate(size=self.table_entry.size)
            self.pointer.write(block, to_snes_address(loc))
        else:
            loc = self.default_offset

        value = self.table_entry.from_yml_rep(value)
        self.table_entry.to_block(block, loc, value)
Beispiel #27
0
def test_to_snes_address():
    assert_equal(to_snes_address(0), 0xc00000)
    assert_equal(to_snes_address(0xf1234), 0xcf1234)
    assert_equal(to_snes_address(0x2abc4f), 0xeabc4f)
    assert_equal(to_snes_address(0x3fffff), 0xffffff)
    assert_equal(to_snes_address(0x400000), 0x400000)
    assert_equal(to_snes_address(0x4daa34), 0x4daa34)
    assert_equal(to_snes_address(0x5fffff), 0x5fffff)
Beispiel #28
0
def test_to_snes_address():
    assert_equal(to_snes_address(0), 0xc00000)
    assert_equal(to_snes_address(0xf1234), 0xcf1234)
    assert_equal(to_snes_address(0x2abc4f), 0xeabc4f)
    assert_equal(to_snes_address(0x3fffff), 0xffffff)
    assert_equal(to_snes_address(0x400000), 0x400000)
    assert_equal(to_snes_address(0x4daa34), 0x4daa34)
    assert_equal(to_snes_address(0x5fffff), 0x5fffff)
Beispiel #29
0
 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)
Beispiel #30
0
 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)
Beispiel #31
0
    def write_to_rom(self, rom):
        pointer_table_offset = rom.allocate(size=self.pointer_table.size)

        bank = rom.get_largest_unallocated_range()[0] >> 16
        log.debug("Writing data to {:#x} bank".format(bank))
        self.pointer_table_entry_class.bank = bank
        rom[POINTER_TABLE_BANK_OFFSET] = bank + 0xc0

        log.debug("Writing pointer table to {:#x}".format(pointer_table_offset))
        rom.write_multi(POINTER_TABLE_POINTER_OFFSET, to_snes_address(pointer_table_offset), 3)
        self.pointer_table.to_block(rom, pointer_table_offset)
Beispiel #32
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] = [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 write_to_rom(self, rom):
        pointer_table_offset = rom.allocate(size=self.pointer_table.size)

        bank = rom.get_largest_unallocated_range()[0] >> 16
        log.debug("Writing data to {:#x} bank".format(bank))
        self.pointer_table_entry_class.bank = bank
        rom[POINTER_TABLE_BANK_OFFSET] = bank + 0xc0

        log.debug(
            "Writing pointer table to {:#x}".format(pointer_table_offset))
        rom.write_multi(POINTER_TABLE_POINTER_OFFSET,
                        to_snes_address(pointer_table_offset), 3)
        self.pointer_table.to_block(rom, pointer_table_offset)
Beispiel #34
0
    def to_block(cls, block, offset, value):
        if not value:
            super(TownMapIconPlacementPointerTableEntry,
                  cls).to_block(block, offset, 0)
        else:
            pointer = block.allocate(
                size=sum([cls.table_entry_class.size for x in value]) + 1)
            super(TownMapIconPlacementPointerTableEntry,
                  cls).to_block(block, offset, to_snes_address(pointer))

            for icon_placement in value:
                cls.table_entry_class.to_block(block, pointer, icon_placement)
                pointer += cls.table_entry_class.size
            block[pointer] = 0xff
Beispiel #35
0
    def write_to_rom(self, rom):
        if not test_swirl_relocated(rom):
            apply_relocation_patch(rom)

        # Write frames and populate swirl table
        frame_hashes = {}
        animation_pointers = []
        animation_pointers_index = 0
        for i, swirl in enumerate(self.swirls):
            num_frames = len(swirl.frames)

            self.swirl_table[i] = [
                swirl.speed, animation_pointers_index, num_frames
            ]

            frame_offsets = write_swirl_frames(rom, swirl, frame_hashes)
            animation_pointers += frame_offsets
            animation_pointers_index += num_frames

        # Allocate animation pointer table
        animation_pointer_table_offset = rom.allocate(size=4 *
                                                      len(animation_pointers))
        for offset, pointer_delta in RELOCATED_SWIRL_ANIMATION_POINTER_TABLE_POINTERS:
            rom.write_multi(
                offset,
                to_snes_address(animation_pointer_table_offset +
                                pointer_delta), 3)

        # Write animation pointer table
        for animation_pointer in animation_pointers:
            rom.write_multi(animation_pointer_table_offset,
                            to_snes_address(animation_pointer), 4)
            animation_pointer_table_offset += 4

        # Write swirls table
        self.swirl_table.to_block(
            rom, offset=from_snes_address(SWIRL_TABLE_DEFAULT_OFFSET))
    def write_to_rom(self, rom):
        with Block(size=sum(x.block_size() for x in self.groups)) as block:
            offset = 0
            # Write all the groups to the block, and sprites to rom
            for i, group in enumerate(self.groups):
                group.write_sprites_to_free(rom)
                group.to_block(block, offset)
                self.group_pointer_table[i] = [offset]
                offset += group.block_size()
            # Write the block to rom and correct the group pointers
            address = to_snes_address(rom.allocate(data=block))
            for i in range(self.group_pointer_table.num_rows):
                self.group_pointer_table[i][0] += address

        self.group_pointer_table.to_block(block=rom, offset=from_snes_address(GROUP_POINTER_TABLE_OFFSET))
        self.palette_table.to_block(block=rom, offset=from_snes_address(PALETTE_TABLE_OFFSET))
Beispiel #37
0
    def write_to_rom(self, rom):
        if self.mode != 'prefix':
            self.get_patch(self.mode, rom.type).apply(rom)

        loc = rom.allocate(size=self.table_entry.to_block_size(self.text))
        addr = to_snes_address(loc)
        write_asm_pointer(block=rom,
                          offset=self.asm_pointer_offset,
                          pointer=addr)
        self.table_entry.to_block(rom, loc, self.text)

        if self.mode == 'prefix':
            self.get_patch(self.mode, rom.type).apply(rom)
            rom.write_multi(self.custom_asm_offset + 9, addr & 0xFFFF, 2)
            rom.write_multi(self.custom_asm_offset + 14, (addr >> 16) & 0xFF,
                            2)
            rom.write_multi(self.custom_asm_offset + 26, len(self.text), 2)
    def write_chars_layouts_to_rom(self, rom):
        block_size = sum(
            TitleScreenLayoutEntry.block_size()*len(c)
            for c in self.chars_layouts
        )

        # Ensure the new data is located in only one bank
        # Spreading it across two banks might make part of it inaccessible.
        def can_write_to(begin):
            return begin >> 16 == (begin + block_size) >> 16

        with Block(block_size) as block:
            # Write the character animation data to the ROM
            offset = 0
            for layout in self.chars_layouts:
                for entry in layout:
                    entry.to_block(block=block, offset=offset)
                    offset += entry.block_size()
            new_offset = to_snes_address(rom.allocate(
                data=block,
                size=block_size,
                can_write_to=can_write_to
            ))

            # Write the offsets to the layouts to the ROM
            new_bank = new_offset >> 16
            new_data_start = new_offset & 0xFFFF
            data_offset = new_data_start
            for c, layout in enumerate(self.chars_layouts):
                rom[CHARS_LAYOUT_TABLE + c*2:CHARS_LAYOUT_TABLE + c*2 + 2] = [
                    data_offset & 0xFF, data_offset >> 8
                ]
                data_offset += len(layout)*TitleScreenLayoutEntry.block_size()

            # Change the offset for the character layouts
            # The way this normally works is that EarthBound stores the address
            # of the bank holding the data (0xE1 by default, hence the 0x210000
            # offset); the offsets in the table are then prefixed with that
            # address. However, reallocating the data may have changed its
            # bank, so we need to manually set it to the new bank address.

            # In order to change the offset, we are replacing a LDA instruction 
            # which addresses a direct page (0xA5) with a LDA instruction
            # that treats its operand as the constant to load (0xA9)
            # See https://wiki.superfamicom.org/snes/show/65816+Reference#instructions.
            rom[CHARS_LAYOUT_BANK:CHARS_LAYOUT_BANK + 2] = [0xA9, new_bank]
Beispiel #39
0
    def write_to_rom(self, rom):
        with Block(size=sum(x.block_size() for x in self.groups)) as block:
            offset = 0
            # Write all the groups to the block, and sprites to rom
            for i, group in enumerate(self.groups):
                group.write_sprites_to_free(rom)
                group.to_block(block, offset)
                self.group_pointer_table[i] = [offset]
                offset += group.block_size()
            # Write the block to rom and correct the group pointers
            address = to_snes_address(rom.allocate(data=block))
            for i in range(self.group_pointer_table.num_rows):
                self.group_pointer_table[i][0] += address

        self.group_pointer_table.to_block(
            block=rom, offset=from_snes_address(GROUP_POINTER_TABLE_OFFSET))
        self.palette_table.to_block(
            block=rom, offset=from_snes_address(PALETTE_TABLE_OFFSET))
Beispiel #40
0
    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 write_to_rom(self, rom):
        if self.data["Enable Skip"]:
            rom[0x1faae] = 0x5c
            offset = rom.allocate(size=(10 + 4 * 5 * 5 + 3 * 6 * 5))
            rom.write_multi(0x1faaf, to_snes_address(offset), 3)
            rom[offset:offset+4] = [0x48, 0x08, 0xe2, 0x20]
            offset += 4

            offset = self.write_loader_asm(rom, offset, self.data["Name1"], 5, 0xce, 0x99)
            offset = self.write_loader_asm(rom, offset, self.data["Name2"], 5, 0x2d, 0x9a)
            offset = self.write_loader_asm(rom, offset, self.data["Name3"], 5, 0x8c, 0x9a)
            offset = self.write_loader_asm(rom, offset, self.data["Name4"], 5, 0xeb, 0x9a)
            offset = self.write_loader_asm(rom, offset, self.data["Pet"],   6, 0x19, 0x98)
            offset = self.write_loader_asm(rom, offset, self.data["Food"],  6, 0x1f, 0x98)
            offset = self.write_loader_asm(rom, offset, self.data["Thing"], 6, 0x29, 0x98)

            if self.data["Enable Summary"]:
                rom[offset:offset+6] = [0x28, 0x68, 0x5c, 0xc0, 0xfa, 0xc1]
            else:
                rom[offset:offset+6] = [0x28, 0x68, 0x5c, 0x05, 0xfd, 0xc1]
Beispiel #42
0
 def write_to_rom(self, rom):
     # Deallocate the range of the ROM in which we will write the door destinations.
     # We deallocate it here instead of specifying it in FREE_RANGES because we want to be sure that this module
     # get first dibs at writing to this range. This is because door destinations needs to be written to the 0x0F
     # bank of the EB ROM, and this is one of the few ranges available in that bank.
     rom.deallocate((0x0F0000, 0x0F58EE))
     destination_offsets = dict()
     empty_area_offset = from_snes_address(rom.allocate(data=[0, 0], can_write_to=not_in_destination_bank))
     i = 0
     for door_area in self.door_areas:
         if (door_area is None) or (not door_area):
             self.pointer_table[i] = [empty_area_offset]
         else:
             num_doors = len(door_area)
             area_offset = rom.allocate(size=(2 + num_doors * 5), can_write_to=not_in_destination_bank)
             self.pointer_table[i] = [to_snes_address(area_offset)]
             rom.write_multi(area_offset, num_doors, 2)
             area_offset += 2
             for door in door_area:
                 door.write_to_block(rom, area_offset, destination_offsets)
                 area_offset += 5
         i += 1
     self.pointer_table.to_block(rom, from_snes_address(0xD00000))
Beispiel #43
0
    def write_sprites_to_free(self, rom):
        if self.num_sprites == 0:
            self.sprite_pointers = []
            return

        unique_sprites, unique_sprite_usages = self.calculate_unique_sprites()

        # Find a free area
        offset = rom.allocate(size=sum([x.block_size() for x in unique_sprites.itervalues()]),
                              can_write_to=(lambda y: (y & 0xf) == 0))
        self.bank = to_snes_address(offset) >> 16
        offset_start = offset & 0xffff

        # Write each sprite
        sprite_offsets = dict()
        for i, (sprite_hash, sprite) in enumerate(unique_sprites.iteritems()):
            sprite.to_block(rom, offset)
            sprite_offsets[sprite_hash] = offset
            offset += sprite.block_size()

        # Get the pointers for each sprite in the group
        self.sprite_pointers = [None] * self.num_sprites
        for i, (sprite_hash, is_mirrored) in enumerate(unique_sprite_usages):
            self.sprite_pointers[i] = (sprite_offsets[sprite_hash] & 0xffff) | is_mirrored | (self.sprites[i][1] << 1)
 def write_to_rom(self, rom):
     pointer_table_offset = rom.allocate(size=self.table.size)
     self.table.to_block(rom, pointer_table_offset)
     write_asm_pointer(rom, self.POINTER_TABLE_ASM_POINTER_OFFSET, to_snes_address(pointer_table_offset))
    def write_to_rom(self, rom):
        rom.deallocate((0xf58ef, 0xf61e5))

        pointer_table_offset = rom.allocate(size=self.pointer_table.size, can_write_to=partial(not_in_bank, 0x0f))
        self.pointer_table.to_block(rom, pointer_table_offset)
        rom.write_multi(MAP_MUSIC_ASM_POINTER_OFFSET, to_snes_address(pointer_table_offset), 3)
Beispiel #46
0
 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)
Beispiel #47
0
 def write_to_rom(self, rom):
     pointer_table_offset = rom.allocate(size=self.table.size)
     self.table.to_block(rom, pointer_table_offset)
     write_asm_pointer(rom, self.POINTER_TABLE_ASM_POINTER_OFFSET,
                       to_snes_address(pointer_table_offset))
Beispiel #48
0
 def to_block(cls, block, offset, value):
     data_size = cls.data_table_entry.to_block_size(value)
     data_offset = block.allocate(size=data_size, can_write_to=partial(is_in_bank, cls.bank))
     cls.pointer_table_entry.to_block(block, offset, to_snes_address(data_offset))
     cls.data_table_entry.to_block(block, data_offset, value)
Beispiel #49
0
 def to_block(cls, block, offset, value):
     data_size = cls.data_table_entry.to_block_size(value)
     data_offset = block.allocate(size=data_size)
     cls.pointer_table_entry.to_block(block, offset, to_snes_address(data_offset))
     cls.data_table_entry.to_block(block, data_offset, value)
Beispiel #50
0
 def write_town_maps_to_rom(self, rom):
     log.debug("Writing town maps")
     for pointer_offset, town_map in zip(TOWN_MAP_POINTER_OFFSETS,
                                         self.town_maps):
         offset = town_map.to_block(rom)
         rom.write_multi(pointer_offset, to_snes_address(offset), size=4)
Beispiel #51
0
    def to_block(cls, block, offset, value):
        if not value:
            super(TownMapIconPlacementPointerTableEntry, cls).to_block(block, offset, 0)
        else:
            pointer = block.allocate(size=sum([cls.table_entry_class.size for x in value]) + 1)
            super(TownMapIconPlacementPointerTableEntry, cls).to_block(block, offset, to_snes_address(pointer))

            for icon_placement in value:
                cls.table_entry_class.to_block(block, pointer, icon_placement)
                pointer += cls.table_entry_class.size
            block[pointer] = 0xff
 def write_town_maps_to_rom(self, rom):
     log.debug("Writing town maps")
     for pointer_offset, town_map in zip(TOWN_MAP_POINTER_OFFSETS, self.town_maps):
         offset = town_map.to_block(rom)
         rom.write_multi(pointer_offset, to_snes_address(offset), size=4)
Beispiel #53
0
    def write_to_rom(self, rom):
        # Collisions need to be in the 0xD8 bank
        rom.deallocate((0x180000, 0x18f05d))
        collision_offsets = dict()
        collision_array = array('B', [0] * 16)
        log.debug("Writing collisions")
        for tileset_id, tileset in enumerate(self.tilesets):
            with Block(len(tileset.collisions) * 2) as collision_table:
                j = 0
                for collision in tileset.collisions:
                    for i, collision_item in enumerate(collision):
                        collision_array[i] = collision_item
                    collision_hash = crc32(collision_array)

                    try:
                        collision_offset = collision_offsets[collision_hash]
                    except KeyError:
                        collision_offset = rom.allocate(data=collision,
                                                        can_write_to=partial(is_in_bank, 0x18)) & 0xffff
                        collision_offsets[collision_hash] = collision_offset

                    collision_table.write_multi(key=j, item=collision_offset, size=2)
                    j += 2
                collision_table_offset = rom.allocate(data=collision_table, can_write_to=partial(not_in_bank, 0x18))
                self.collisions_pointer_table[tileset_id] = [to_snes_address(collision_table_offset)]

        self.collisions_pointer_table.to_block(block=rom, offset=from_snes_address(COLLISIONS_POINTER_TABLE_OFFSET))

        # Palettes need to be in the 0xDA bank
        rom.deallocate((0x1a0000, 0x1afaa6))  # Not sure if this can go farther
        # Write maps/drawing tilesets associations and map tset pals
        log.debug("Writing palettes")
        for map_tileset_id in range(32):  # For each map tileset
            # Find the drawing tileset number for this map tileset
            for i, tileset in enumerate(self.tilesets):
                if tileset.has_map_tileset(map_tileset_id):
                    tileset_id = i
                    break
            else:
                # TODO Error, this drawing tileset isn't associated
                tileset_id = 0
            self.map_tileset_table[map_tileset_id] = [tileset_id]

            palettes = tileset.get_palettes_by_map_tileset(map_tileset_id)
            palettes.sort()

            # Write the event palettes
            for map_palette_id, palette in palettes:
                palette.flag_palette_to_block(rom)

            # Write the standard palettes
            palette_offset = rom.allocate(size=0xc0 * len(palettes), can_write_to=partial(is_in_bank, 0x1a))
            self.palette_pointer_table[map_tileset_id] = [to_snes_address(palette_offset)]
            for map_palette_id, palette in palettes:
                palette.to_block(block=rom, offset=palette_offset)
                palette_offset += palette.block_size()

        self.map_tileset_table.to_block(block=rom, offset=from_snes_address(MAP_TILESET_TABLE_OFFSET))
        self.palette_pointer_table.to_block(block=rom, offset=from_snes_address(PALETTE_POINTER_TABLE_OFFSET))

        for tileset_id, tileset in enumerate(self.tilesets):
            log.debug("Writing tileset #{}".format(tileset_id))
            self.graphics_pointer_table[tileset_id] = [to_snes_address(tileset.minitiles_to_block(rom))]
            self.arrangements_pointer_table[tileset_id] = [to_snes_address(tileset.arrangements_to_block(rom))]

        self.graphics_pointer_table.to_block(block=rom, offset=from_snes_address(GRAPHICS_POINTER_TABLE_OFFSET))
        self.arrangements_pointer_table.to_block(block=rom, offset=from_snes_address(ARRANGEMENTS_POINTER_TABLE_OFFSET))