예제 #1
0
    def read_from_project(self, resource_open):
        # Read graphics. Just use the first of each image.
        with resource_open("WindowGraphics/Windows1_0", "png") as image_file:
            image = open_indexed_image(image_file)
            self.graphics_1.from_image(image=image,
                                       arrangement=ARRANGEMENT_1,
                                       palette=self.flavor_palettes[0])

        with resource_open("WindowGraphics/Windows2_0", "png") as image_file:
            image = open_indexed_image(image_file)
            self.graphics_2.from_image(image=image,
                                       arrangement=ARRANGEMENT_2,
                                       palette=self.flavor_palettes[0].get_subpalette(7))

        # Read pals from Windows1 of each flavor.
        # Read subpal 7 from Windows2 of each flavor.
        for i, palette in enumerate(self.flavor_palettes):
            # Read all the palette data from Windows1
            with resource_open("WindowGraphics/Windows1_" + str(i), "png") as image_file:
                image = open_indexed_image(image_file)
                palette.from_image(image=image)

            with resource_open("WindowGraphics/Windows2_" + str(i), "png") as image_file:
                image = open_indexed_image(image_file)
                palette_data = image.getpalette()
                m = 0
                for k in range(4):
                    palette[7, k].from_tuple((palette_data[m], palette_data[m + 1], palette_data[m + 2]))
                    m += 3

        # Read names
        with resource_open("WindowGraphics/flavor_names", "txt", True) as f:
            for asm_pointer_offset in FLAVOR_NAME_ASM_POINTER_OFFSETS:
                name = f.readline()[:-1]
                self.flavor_names[asm_pointer_offset] = FLAVOR_NAME_ENTRY.from_yml_rep(name)
예제 #2
0
    def read_background_data_from_project(self, resource_open):
        # Load the background reference image
        # The image's arrangement, tileset and palette will be used for the
        # animation frames
        with resource_open(BG_REFERENCE_PATH, "png") as f:
            image = open_indexed_image(f)
            self.bg_arrangement.from_image(
                image, self.bg_tileset, self.bg_palette
            )

        # Read the background animated frames
        for frame in range(NUM_ANIM_FRAMES):
            # Create temporary structures used to check consistency between
            # frames
            tileset = EbGraphicTileset(BG_NUM_TILES, TILE_WIDTH, TILE_HEIGHT)
            arrangement = EbTileArrangement(
                BG_ARRANGEMENT_WIDTH, BG_ARRANGEMENT_HEIGHT
            )
            palette = EbPalette(NUM_SUBPALETTES, BG_SUBPALETTE_LENGTH)

            # Read one frame's image data
            with resource_open(BG_FRAMES_PATH.format(frame), "png") as f:
                image = open_indexed_image(f)
                arrangement.from_image(image, tileset, palette)

            # Make sure each frame's tileset and arrangement is identical
            # The background palette is checked only if it isn't the fake
            # palette used for the first few frames
            if frame >= CHARS_NUM_ANIM_SUBPALETTES:
                # Get the background animated subpalette from the background
                # palette
                colors = palette[0, BG_ANIM_SLICE]
                self.bg_anim_palette.subpalettes[
                    frame - CHARS_NUM_ANIM_SUBPALETTES
                ] = colors
                palette[0, BG_ANIM_SLICE] = self.bg_palette[
                    0, BG_ANIM_SLICE
                ]
                if self.bg_palette != palette:
                    log.warn(
                        "Palette from background frame {} does not match "
                        "reference.".format(frame)
                    )
            if self.bg_tileset != tileset:
                log.warn(
                    "Tileset from background frame {} does not match "
                    "reference.".format(frame)
                )
            if self.bg_arrangement != arrangement:
                log.warn(
                    "Arrangement from background frame {} does not match "
                    "reference.".format(frame)
                )
예제 #3
0
 def read_from_project(self, resource_open):
     with resource_open(NESS_DEATH_SCREEN_PATH, "png") as f:
         image = open_indexed_image(f)
         self.arrangement.from_image(image, self.ness_tileset, self.palette,
                                     True, False)
     with resource_open(JEFF_DEATH_SCREEN_PATH, "png") as f:
         image = open_indexed_image(f)
         self.jeff_tileset.from_image(image, self.arrangement, self.palette)
     with resource_open(DEATH_SCREEN_SUBPALETTES_PATH, "yml", True) as f:
         subpalettes = yml_load(f)
         for subpalette, tiles in subpalettes.items():
             for x, y in tiles:
                 self.arrangement[x, y].subpalette = subpalette
예제 #4
0
 def read_gfx_from_project(self, obj, resource_open):
     with resource_open(obj.path(), 'png') as image_file:
         image = open_indexed_image(image_file)
         palette = EbPalette(num_subpalettes=1, subpalette_length=4)
         palette.from_image(image)
         obj.palettes[0] = palette
         obj.from_image(image, obj.cast_arrangement())
예제 #5
0
    def read_from_project(self, resource_open):
        with resource_open("sprite_group_palettes", "yml") as f:
            self.palette_table.from_yml_file(f)

        with resource_open("sprite_groups", "yml") as f:
            input = yml_load(f)
            num_groups = len(input)
            self.groups = []
            for i in range(num_groups):
                group = SpriteGroup(16)
                group.from_yml_rep(input[i])

                palette = EbPalette(1, 16)

                with resource_open("SpriteGroups/" + str(i).zfill(3),
                                   "png") as f2:
                    image = open_indexed_image(f2)
                    group.from_image(image)
                    palette.from_image(image)
                    del image

                self.groups.append(group)

                # Assign the palette number to the sprite
                for j in range(8):
                    if palette.list()[3:] == self.palette_table[j][0].list(
                    )[3:]:
                        group.palette = j
                        break
                else:
                    raise CoilSnakeError("Sprite Group #" + str(i).zfill(3) +
                                         " uses an invalid palette")
예제 #6
0
 def read_town_maps_from_project(self, resource_open):
     for resource_name, town_map in zip(TOWN_MAP_RESOURCE_NAMES,
                                        self.town_maps):
         log.info("- Reading {}".format(resource_name))
         with resource_open(resource_name, "png") as image_file:
             image = open_indexed_image(image_file)
             town_map.from_image(image)
예제 #7
0
    def from_files(self, image_file, widths_file, image_format="png", widths_format="yml"):
        image = open_indexed_image(image_file)

        if self.num_characters == 96:
            self.tileset.from_image(image, _FONT_IMAGE_ARRANGEMENT_96, FONT_IMAGE_PALETTE)
        elif self.num_characters == 128:
            self.tileset.from_image(image, _FONT_IMAGE_ARRANGEMENT_128, FONT_IMAGE_PALETTE)
        del image

        if widths_format == "yml":
            widths_dict = yml_load(widths_file)
            self.character_widths = [widths_dict[i] for i in range(self.tileset.num_tiles_maximum)]
예제 #8
0
    def upgrade_project(self, old_version, new_version, rom, resource_open_r,
                        resource_open_w, resource_delete):

        if old_version == new_version:
            return

        self.read_from_rom(rom)
        self.write_to_project(resource_open_w)

        if old_version == 9:
            with resource_open_r(OLD_DEATH_SCREEN_PATH, "png") as old:
                with resource_open_w(NESS_DEATH_SCREEN_PATH, "png") as new:
                    image = open_indexed_image(old)
                    image.save(new)

            resource_delete(OLD_DEATH_SCREEN_PATH)
예제 #9
0
    def upgrade_project(self, old_version, new_version, rom, resource_open_r, resource_open_w, resource_delete):
        if old_version == new_version:
            return
        elif old_version == 5:
            # Expand all the fonts from 96 characters to 128 characters
            for i, font in enumerate(self.fonts):
                log.debug("Expanding font #{}".format(FONT_FILENAMES[i]))
                image_resource_name = "Fonts/" + FONT_FILENAMES[i]
                widths_resource_name = "Fonts/" + FONT_FILENAMES[i] + "_widths"
                new_image_w, new_image_h = font.image_size()

                # Expand the image

                with resource_open_r(image_resource_name, 'png') as image_file:
                    image = open_indexed_image(image_file)

                    expanded_image = Image.new("P", (new_image_w, new_image_h), None)
                    for y in xrange(new_image_h):
                        for x in xrange(new_image_w):
                            expanded_image.putpixel((x, y), 1)
                    FONT_IMAGE_PALETTE.to_image(expanded_image)
                    expanded_image.paste(image, (0, 0))

                    with resource_open_w(image_resource_name, 'png') as image_file2:
                        expanded_image.save(image_file2, "png")

                # Expand the widths

                with resource_open_r(widths_resource_name, "yml") as widths_file:
                    widths_dict = yml_load(widths_file)

                for character_id in xrange(96, 128):
                    if character_id not in widths_dict:
                        widths_dict[character_id] = 0

                with resource_open_w(widths_resource_name, "yml") as widths_file:
                    yml_dump(widths_dict, widths_file, default_flow_style=False)

            self.upgrade_project(6, new_version, rom, resource_open_r, resource_open_w, resource_delete)
        elif old_version <= 2:
            # The credits font was a new feature in version 3

            self.read_credits_font_from_rom(rom)
            self.write_credits_font_to_project(resource_open_w)
            self.upgrade_project(3, new_version, rom, resource_open_r, resource_open_w, resource_delete)
        else:
            self.upgrade_project(old_version + 1, new_version, rom, resource_open_r, resource_open_w, resource_delete)
예제 #10
0
    def read_from_project(self, resource_open):
        with resource_open("bg_data_table", "yml", True) as f:
            self.bg_table.from_yml_file(f)
        with resource_open("bg_scrolling_table", "yml", True) as f:
            self.scroll_table.from_yml_file(f)
        with resource_open("bg_distortion_table", "yml", True) as f:
            self.distortion_table.from_yml_file(f)

        self.backgrounds = []
        self.palettes = []
        for i in range(self.bg_table.num_rows):
            new_color_depth = self.bg_table[i][2]
            with resource_open("BattleBGs/" + str(i).zfill(3), "png") as f:
                image = open_indexed_image(f)

                new_palette = EbPalette(num_subpalettes=1,
                                        subpalette_length=16)
                new_tileset = EbGraphicTileset(num_tiles=512,
                                               tile_width=8,
                                               tile_height=8)
                new_arrangement = EbTileArrangement(width=32, height=32)

                new_arrangement.from_image(image, new_tileset, new_palette)

                for j, (tileset, color_depth,
                        arrangement) in enumerate(self.backgrounds):
                    if (color_depth == new_color_depth) \
                            and (tileset == new_tileset) \
                            and (arrangement == new_arrangement):
                        self.bg_table[i][0] = j
                        break
                else:
                    self.bg_table[i][0] = len(self.backgrounds)
                    self.backgrounds.append(
                        (new_tileset, new_color_depth, new_arrangement))

                for j, palette in enumerate(self.palettes):
                    if palette == new_palette:
                        self.bg_table[i][1] = j
                        break
                else:
                    self.bg_table[i][1] = len(self.palettes)
                    self.palettes.append(new_palette)
예제 #11
0
    def read_from_project(self, resource_open):
        with resource_open('Animations/animations', 'yml', True) as f:
            animation_data = yml_load(f)

        for animation_id in animation_data:
            frames = animation_data[animation_id]['frames']
            unknown = animation_data[animation_id]['unknown']
            animation = Animation(frames=frames, unknown=unknown)
            self.animations.append(animation)

            for frame_id in range(frames):
                with resource_open(
                        'Animations/{}/{}'.format(animation_id,
                                                  str(frame_id).zfill(3)),
                        'png') as f:
                    image = open_indexed_image(f)
                    try:
                        animation.add_frame_from_image(image, frame_id)
                    except Exception as e:
                        message = 'Encountered error while reading frame #{} of Animation #{}'.format(
                            frame_id, animation_id)
                        raise CoilSnakeTraceableError(message, e)
예제 #12
0
    def read_from_project(self, resource_open):
        with resource_open("Swirls/swirls", "yml") as f:
            swirl_data = yml_load(f)

        self.swirls = [Swirl() for i in xrange(self.swirl_table.num_rows)]
        for swirl_id, swirl in enumerate(self.swirls):
            log.debug("Reading Swirl #{}".format(swirl_id))
            speed = swirl_data[swirl_id]["speed"]
            num_frames = swirl_data[swirl_id]["frames"]

            swirl.speed = speed
            for frame_id in range(num_frames):
                with resource_open(
                        "Swirls/{}/{}".format(swirl_id,
                                              str(frame_id).zfill(3)),
                        "png") as f:
                    image = open_indexed_image(f)
                    try:
                        swirl.add_frame_from_image(image)
                    except Exception as e:
                        message = "Encountered error while reading frame #{} of swirl #{}".format(
                            frame_id, swirl_id)
                        raise CoilSnakeTraceableError(message, e)
예제 #13
0
    def read_chars_data_from_project(self, resource_open):
        # Read the characters positions
        with resource_open(CHARS_POSITIONS_PATH, "yml") as f:
            chars_positions = yml_load(f)

        # Read the characters animated frames
        self.chars_tileset = None
        self.chars_anim_palette = EbPalette(CHARS_NUM_ANIM_SUBPALETTES,
                                            ANIM_SUBPALETTE_LENGTH)
        original_tileset = None
        for p in xrange(CHARS_NUM_ANIM_SUBPALETTES):
            # Read one of the animation frames
            with resource_open(CHARS_FRAMES_PATH.format(p), "png") as f:
                # Create temporary structures to hold the data
                image = open_indexed_image(f)
                arrangement = EbTileArrangement(image.width / TILE_WIDTH,
                                                image.height / TILE_HEIGHT)
                tileset = EbGraphicTileset(CHARS_NUM_TILES, TILE_WIDTH,
                                           TILE_HEIGHT)
                anim_subpalette = EbPalette(NUM_SUBPALETTES,
                                            ANIM_SUBPALETTE_LENGTH)
                arrangement.from_image(image, tileset, anim_subpalette, True)

            # Add the characters animation subpalette
            for i in xrange(ANIM_SUBPALETTE_LENGTH):
                self.chars_anim_palette[p, i] = anim_subpalette[0, i]

            # Add the characters tileset if not already set, otherwise
            # ensure that it the current tileset is identical
            if not self.chars_tileset:
                original_tileset = tileset
                self.chars_tileset = EbGraphicTileset(CHARS_NUM_TILES,
                                                      TILE_WIDTH, TILE_HEIGHT)
                self.chars_tileset.tiles = [[[0 for _ in xrange(TILE_HEIGHT)]
                                             for _ in xrange(TILE_WIDTH)]
                                            for _ in xrange(CHARS_NUM_TILES)]
                unused_tiles = set(xrange(CHARS_NUM_TILES))

                # Set the new character layouts
                self.chars_layouts = [[] for _ in xrange(NUM_CHARS)]
                for c, data in chars_positions.items():
                    # Get the data from the YAML file
                    x = int(data['x'] / TILE_WIDTH)
                    y = int(data['y'] / TILE_HEIGHT)
                    width = int(data['width'] / TILE_WIDTH)
                    height = int(data['height'] / TILE_HEIGHT)
                    x_offset = data['top_left_offset']['x']
                    y_offset = data['top_left_offset']['y']
                    unknown = data['unknown']

                    # Generate a list of all tiles must be visited
                    # Where possible, we try to generate a multi tile (4 tiles
                    # stored as one); otherwise, bordering tiles that are
                    # visited will all be single tiles.
                    l = [(i, j) for i in xrange(0, width, 2)
                         for j in xrange(0, height, 2)]
                    if width % 2 == 1:
                        l.extend([(width - 1, j)
                                  for j in xrange(1, height, 2)])
                    if height % 2 == 1:
                        l.extend([(i, height - 1)
                                  for i in xrange(1, width, 2)])

                    # Generate the new reduced tileset
                    for i, j in l:
                        # Put the tile in the new tileset
                        o_tile = arrangement[x + i, y + j].tile
                        n_tile = unused_tiles.pop()
                        self.chars_tileset.tiles[n_tile] = tileset[o_tile]

                        entry = TitleScreenLayoutEntry(i * 8 + x_offset,
                                                       j * 8 + y_offset,
                                                       n_tile, 0, unknown)

                        # Create a multi entry if possible to save space
                        if i < width - 1 and j < height - 1:
                            entry.set_single(True)
                            o_tile_r = arrangement[x + i + 1, y + j].tile
                            o_tile_d = arrangement[x + i, y + j + 1].tile
                            o_tile_dr = arrangement[x + i + 1, y + j + 1].tile
                            n_tile_r = n_tile + 1
                            n_tile_d = n_tile + 16
                            n_tile_dr = n_tile + 17
                            unused_tiles.difference_update(
                                (n_tile_r, n_tile_d, n_tile_dr))
                            self.chars_tileset.tiles[n_tile_r] = \
                                tileset[o_tile_r]
                            self.chars_tileset.tiles[n_tile_d] = \
                                tileset[o_tile_d]
                            self.chars_tileset.tiles[n_tile_dr] = \
                                tileset[o_tile_dr]

                        self.chars_layouts[c].append(entry)
                    self.chars_layouts[c][-1].set_final(True)

            elif original_tileset != tileset:
                log.warn("Tileset from characters frame {} does not match "
                         "tileset from characters frame 0.".format(p))

        # Read the initial characters palette
        with resource_open(CHARS_INITIAL_PATH, "png") as f:
            image = open_indexed_image(f)
            arrangement = EbTileArrangement(image.width / TILE_WIDTH,
                                            image.height / TILE_HEIGHT)
            tileset = EbGraphicTileset(CHARS_NUM_TILES, TILE_WIDTH,
                                       TILE_HEIGHT)
            self.chars_palette = EbPalette(NUM_SUBPALETTES,
                                           ANIM_SUBPALETTE_LENGTH)
            arrangement.from_image(image, tileset, self.chars_palette)
예제 #14
0
 def from_files(self, image_file, image_format="png"):
     image = open_indexed_image(image_file)
     self.palette.from_image(image)
     self.tileset.from_image(image, _CREDITS_PREVIEW_ARRANGEMENT, self.palette)
     del image
예제 #15
0
 def read_logos_from_project(self, resource_open, logos, infos):
     for info, logo in zip(infos, logos):
         log.info("- Reading " + info.name)
         with resource_open(info.name, "png") as image_file:
             image = open_indexed_image(image_file)
             logo.from_image(image)
예제 #16
0
 def read_town_map_icons_from_project(self, resource_open):
     log.info("- Reading town map icons")
     with resource_open("TownMaps/icons", "png") as image_file:
         image = open_indexed_image(image_file)
         self.town_map_icons.from_image(
             image=image, arrangement=TOWN_MAP_ICON_PREVIEW_ARRANGEMENT)
예제 #17
0
 def read_from_project(self, resource_open):
     with resource_open("Logos/SoundStone", "png") as image_file:
         image = open_indexed_image(image_file)
         self.palette.from_image(image)
         self.tileset.from_image(image, SOUND_STONE_ARRANGEMENT,
                                 self.palette)
예제 #18
0
    def read_from_project(self, resource_open):
        with resource_open("enemy_configuration_table", "yml") as f:
            self.enemy_config_table.from_yml_file(f)

        # Read the sprites and palettes
        self.battle_sprites = []
        self.palettes = []

        sprite_hashes = dict()
        num_sprites = 0
        palette_hashes = dict()
        num_palettes = 0
        for i in range(self.enemy_config_table.num_rows):
            battle_sprite = EbBattleSprite()
            palette = EbPalette(num_subpalettes=1, subpalette_length=16)

            try:
                with resource_open("BattleSprites/" + str(i).zfill(3), "png") as f:
                    image = open_indexed_image(f)
                    battle_sprite.from_image(image)
                    palette.from_image(image)
                    del image
            except IOError:
                # No battle sprite
                self.enemy_config_table[i][4] = 0
                self.enemy_config_table[i][14] = 0
                continue

            sprite_hash = battle_sprite.hash()
            try:
                self.enemy_config_table[i][4] = sprite_hashes[sprite_hash] + 1
            except KeyError:
                self.enemy_config_table[i][4] = num_sprites + 1
                sprite_hashes[sprite_hash] = num_sprites
                self.battle_sprites.append(battle_sprite)
                num_sprites += 1

            palette_hash = palette.hash()
            try:
                self.enemy_config_table[i][14] = palette_hashes[palette_hash]
            except KeyError:
                self.enemy_config_table[i][14] = num_palettes
                palette_hashes[palette_hash] = num_palettes
                self.palettes.append(palette)
                num_palettes += 1

        # Read the groups
        with resource_open("enemy_groups", "yml") as f:
            self.enemy_group_table.from_yml_file(f)

        with resource_open("enemy_groups", "yml") as f:
            self.enemy_group_bg_table.from_yml_file(f)

        with resource_open("enemy_groups", "yml") as f:
            self.enemy_groups = []
            enemy_groups_yml_rep = yml_load(f)
            for entry in enemy_groups_yml_rep.itervalues():
                enemy_group = entry["Enemies"]
                if type(enemy_group) == dict:
                    enemy_group = [enemy_group[x] for x in sorted(enemy_group.keys())]
                group = [EnemyGroupTableEntry.from_yml_rep(x) for x in enemy_group]
                self.enemy_groups.append(group)