def main(): parser = argparse.ArgumentParser() parser.add_argument('levels', type=int, metavar=('PC1_Level', 'PC2_Level', 'PC3_Level', 'PC4_Level'), nargs=4, help='Party levels') parser.add_argument('projDir', metavar='ProjectDirectory', nargs=1, help='CoilSnake project directory') parser.add_argument('--enemy', action='store', nargs=1, metavar='Enemy_ID', type=int, dest="enemyInfo", help="Enemy number") args = parser.parse_args() proj = Project.Project() proj.load(args.projDir[0] + os.sep + Project.PROJECT_FILENAME) partyStats = [None, None, None, None] with proj.get_resource("eb", "stats_growth_vars", "yml", "r") as f: growthVars = yml_load(f) for i in range(4): partyStats[i] = calcStats(growthVars[i], args.levels[i]) print "*** Party Stats ***" print '\t'.join(map(str, ['', 'HP', 'PP', 'Off', 'Def', 'Speed', 'Guts', 'Vit', 'IQ', "Luck"])) for i in range(4): print i, '\t', '\t'.join(map(str, partyStats[i])) if args.enemyInfo is not None: with proj.get_resource("eb", "enemy_configuration_table", "yml", "r") as f: enemyData = (yml_load(f))[args.enemyInfo[0]] print "\n*** Enemy Stats:", enemyData["Name"], "***" print '\t'.join(map(str, ['', 'HP', 'PP', 'Off', 'Def', 'Speed', 'Guts', "Luck"])) print '\t%d\t%d\t%d\t%d\t%d\t%d\t%d' % (enemyData["HP"], enemyData["PP"], enemyData["Offense"], enemyData["Defense"], enemyData["Speed"], enemyData["Guts"], enemyData["Luck"]) print "\n*** Damage Dealt by Enemy to Party ***" print "Level\tTarget\tMinDmg\tMaxDmg\tSMASH\tSmash%" for i in range(1, 5): for j in range(0, 4): damage = i * enemyData["Offense"] - partyStats[j][3] smashDamage = 4 * enemyData["Offense"] - partyStats[j][3] smashOdds = enemyData["Guts"] / 5.0 print "%d\t%d\t%d\t%d\t%d\t%.2f%%" % (i, j, damage*0.75, damage*1.25, smashDamage, smashOdds) print print "*** Damage Dealt by Party to Enemy ***" print "PC\tMinDmg\tMaxDmg\tSMASH\tSmash%" for i in range(0, 4): damage = 2 * partyStats[i][2] - enemyData["Defense"] smashDamage = 4 * partyStats[i][2] - enemyData["Defense"] smashOdds = max(partyStats[i][5] / 5.0, 5.0) print "%d\t%d\t%d\t%d\t%d" % (i, damage * 0.75, damage * 1.25, smashDamage, smashOdds)
def upgrade_project(self, old_version, new_version, rom, resource_open_r, resource_open_w, resource_delete): if old_version == 1: self.read_from_rom(rom) self.write_to_project(resource_open_w) elif old_version < new_version: self.read_from_project(resource_open_r) # Remove all patches that should not exist if rom.type in REMOVED_PATCHES: for patch_name in REMOVED_PATCHES[rom.type]: if patch_name in self.patches: del self.patches[patch_name] # Add in all the new patches for ip_desc_filename in [ s for s in os.listdir(get_ips_directory(rom.type)) if s.lower().endswith(".yml") ]: with open( os.path.join(get_ips_directory(rom.type), ip_desc_filename)) as ips_desc_file: ips_desc = yml_load(ips_desc_file) ips_desc_title = ips_desc["Title"] ips_is_hidden = ("Hidden" in ips_desc) and ips_desc["Hidden"] if (not ips_is_hidden) and (ips_desc_title not in self.patches): self.patches[ips_desc_title] = "disabled" self.write_to_project(resource_open_w)
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: with resource_open_r("map_changes", "yml") as f: data = yml_load(f) for i in data: if data[i] is None: data[i] = [] else: for entry in data[i]: entry["Tile Changes"] = entry["Changes"] del entry["Changes"] for j, change in enumerate(entry["Tile Changes"]): entry["Tile Changes"][j] = MapEventSubTableEntry.to_yml_rep(change) with resource_open_w("map_changes", "yml") as f: yml_dump(data, f) convert_values_to_hex_repr_in_yml_file("map_changes", resource_open_r, resource_open_w, ["Event Flag"], default_flow_style=None) self.upgrade_project(5, 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)
def load(self, f, romtype=None): if isinstance(f, str): self._dir_name = os.path.dirname(f) else: self._dir_name = os.path.dirname(f.name) try: if isinstance(f, str): f = open(f, 'r') data = yml_load(f) if (romtype is None) or (romtype == data["romtype"]): self.romtype = data["romtype"] self._resources = data["resources"] if "version" in data: self.version = data["version"] else: self.version = 1 if self._resources is None: self._resources = {} else: # Loading a project of the wrong romtype self.romtype = romtype self._resources = {} except IOError: # Project file doesn't exist if not os.path.exists(self._dir_name): os.makedirs(self._dir_name) if romtype is None: self.romtype = "Unknown" else: self.romtype = romtype self._resources = {}
def read_from_project(self, resource_open): for table in self.tables.itervalues(): with resource_open(table.name.lower(), "yml") as f: yml_rep = yml_load(f) num_rows = len(yml_rep) table.recreate(num_rows=num_rows) table.from_yml_rep(yml_rep)
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")
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 <= 2: replace_field_in_yml(resource_name="map_sectors", resource_open_r=resource_open_r, resource_open_w=resource_open_w, key="Town Map", value_map={"scummers": "summers"}) self.read_from_rom(rom) with resource_open_r("map_sectors", 'yml') as f: data = yml_load(f) for i in data: data[i]["Town Map Image"] = TOWNMAP_IMAGE_ENTRY.to_yml_rep(self.sector_town_map_table[i][0] & 0xf) data[i]["Town Map Arrow"] = TOWNMAP_ARROW_ENTRY.to_yml_rep(self.sector_town_map_table[i][0] >> 4) data[i]["Town Map X"] = TOWNMAP_X.to_yml_rep(self.sector_town_map_table[i][1]) data[i]["Town Map Y"] = TOWNMAP_Y.to_yml_rep(self.sector_town_map_table[i][2]) with resource_open_w("map_sectors", 'yml') as f: yaml.dump(data, f, Dumper=yaml.CSafeDumper, default_flow_style=False) 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)
def write_to_rom(self, rom): for ips_desc_filename in [s for s in os.listdir(get_ips_directory(rom.type)) if s.lower().endswith(".yml")]: patch_name = ips_desc_filename[:-4] with open(os.path.join(get_ips_directory(rom.type), ips_desc_filename)) as ips_desc_file: ips_desc = yml_load(ips_desc_file) if "Hidden" in ips_desc and ips_desc["Hidden"]: continue elif (ips_desc["Title"] in self.patches) and (self.patches[ips_desc["Title"]].lower() == "enabled"): # First, check that we can apply this ranges = map(lambda y: tuple(map(lambda z: int(z, 0), y[1:-1].split(','))), ips_desc["Ranges"]) for range in ranges: if not rom.is_unallocated(range): raise CoilSnakeError( "Can't apply patch \"{}\" because range ({:#x},{:#x}) is not unallocated".format( ips_desc["Title"], range[0], range[1])) # Now apply the patch ips = IpsPatch() offset = 0 if "Header" in ips_desc: offset = ips_desc["Header"] ips.load(get_ips_filename(rom.type, patch_name), offset) ips.apply(rom) # Mark the used ranges as used for range in ranges: rom.mark_allocated(range)
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: with resource_open_r("map_changes", "yml", True) as f: data = yml_load(f) for i in data: if data[i] is None: data[i] = [] else: for entry in data[i]: entry["Tile Changes"] = entry["Changes"] del entry["Changes"] for j, change in enumerate(entry["Tile Changes"]): entry["Tile Changes"][ j] = MapEventSubTableEntry.to_yml_rep(change) with resource_open_w("map_changes", "yml", True) as f: yml_dump(data, f) convert_values_to_hex_repr_in_yml_file("map_changes", resource_open_r, resource_open_w, ["Event Flag"], default_flow_style=None) self.upgrade_project(5, 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)
def write_to_rom(self, rom): for ips_desc_filename in [s for s in os.listdir(get_ips_directory(rom.type)) if s.lower().endswith(".yml")]: patch_name = ips_desc_filename[:-4] with open(os.path.join(get_ips_directory(rom.type), ips_desc_filename)) as ips_desc_file: ips_desc = yml_load(ips_desc_file) if (ips_desc["Title"] in self.patches) and (self.patches[ips_desc["Title"]].lower() == "enabled"): # First, check that we can apply this ranges = map(lambda y: tuple(map(lambda z: int(z, 0), y[1:-1].split(','))), ips_desc["Ranges"]) for range in ranges: if not rom.is_unallocated(range): raise CoilSnakeError( "Can't apply patch \"{}\" because range ({:#x},{:#x}) is not unallocated".format( ips_desc["Title"], range[0], range[1])) # Now apply the patch ips = IpsPatch() offset = 0 if "Header" in ips_desc: offset = ips_desc["Header"] ips.load(get_ips_filename(rom.type, patch_name), offset) ips.apply(rom) # Mark the used ranges as used for range in ranges: rom.mark_allocated(range)
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 == 4: with resource_open_r("TownMaps/icon_positions", "yml", True) as f: data = yml_load(f) for i in range(6): old_key = TownMapEnum.tostring(i).lower() data[i] = data[old_key] del data[old_key] with resource_open_w("TownMaps/icon_positions", "yml", True) as f: yml_dump(data, f, default_flow_style=False) convert_values_to_hex_repr_in_yml_file("TownMaps/icon_positions", resource_open_r, resource_open_w, ["Event Flag"]) self.upgrade_project(5, new_version, rom, resource_open_r, resource_open_w, resource_delete) elif old_version <= 2: self.read_from_rom(rom) self.write_to_project(resource_open_w) self.upgrade_project(new_version, 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)
def read_from_project(self, resource_open): with resource_open("sprite_group_palettes", "yml", True) as f: self.palette_table.from_yml_file(f) with resource_open("sprite_groups", "yml", True) 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() == self.palette_table[j][0].list(): group.palette = j break else: raise CoilSnakeError("Sprite Group #" + str(i).zfill(3) + " uses an invalid palette")
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 == 4: with resource_open_r("sprite_groups", "yml", True) as f: data = yml_load(f) for i in data: entry = data[i] collision_settings = entry["Collision Settings"] entry["North/South Collision Width"] = collision_settings[0] entry["North/South Collision Height"] = collision_settings[1] entry["East/West Collision Width"] = collision_settings[2] entry["East/West Collision Height"] = collision_settings[3] del entry["Collision Settings"] with resource_open_w("sprite_groups", "yml", True) as f: yml_dump(data, f) self.upgrade_project(old_version + 1, new_version, rom, resource_open_r, resource_open_w, resource_delete) elif old_version == 2: replace_field_in_yml(resource_name="sprite_groups", resource_open_r=resource_open_r, resource_open_w=resource_open_w, key="Unknown A", new_key="Size", value_map=dict(enumerate(SPRITE_SIZES))) replace_field_in_yml(resource_name="sprite_groups", resource_open_r=resource_open_r, resource_open_w=resource_open_w, key="Unknown B", new_key="Collision Settings") self.upgrade_project(old_version + 1, 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)
def from_files(self, image_file, widths_file, image_format="png", widths_format="yml"): image = open_indexed_image(image_file) self.tileset.from_image(image, _FONT_IMAGE_ARRANGEMENT, _FONT_IMAGE_PALETTE) del image if widths_format == "yml": widths_dict = yml_load(widths_file) self.character_widths = map(lambda i: widths_dict[i], range(self.tileset.num_tiles_maximum))
def read_from_project(self, resource_open): with resource_open(DEATH_SCREEN_PATH, "png") as f: image = open_indexed_image(f) self.arrangement.from_image(image, self.tileset, 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
def read_from_project(self, resource_open): with resource_open(DEATH_SCREEN_PATH, "png") as f: image = open_indexed_image(f) self.arrangement.from_image(image, self.tileset, self.palette) with resource_open(DEATH_SCREEN_SUBPALETTES_PATH, "yml") as f: subpalettes = yml_load(f) for subpalette, tiles in subpalettes.items(): for x, y in tiles: self.arrangement[x, y].subpalette = subpalette
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)]
def read_from_rom(self, rom): self.patches = dict() # Loop through all the patches for this romtype for ip_desc_filename in [s for s in os.listdir(get_ips_directory(rom.type)) if s.lower().endswith(".yml")]: with open(os.path.join(get_ips_directory(rom.type), ip_desc_filename)) as ips_desc_file: ips_desc = yml_load(ips_desc_file) ips_desc_title = ips_desc["Title"] if ips_desc["Auto-Apply"]: self.patches[ips_desc_title] = "enabled" else: self.patches[ips_desc_title] = "disabled"
def read_from_rom(self, rom): self.patches = dict() # Loop through all the patches for this romtype for ip_desc_filename in [s for s in os.listdir(get_ips_directory(rom.type)) if s.lower().endswith(".yml")]: with open(os.path.join(get_ips_directory(rom.type), ip_desc_filename)) as ips_desc_file: ips_desc = yml_load(ips_desc_file) ips_desc_title = ips_desc["Title"] if "Hidden" in ips_desc and ips_desc["Hidden"]: continue elif ips_desc["Auto-Apply"]: self.patches[ips_desc_title] = "enabled" else: self.patches[ips_desc_title] = "disabled"
def read_from_project(self, resource_open): with resource_open("Fonts/character_substitutions", "yml") as f: data = yml_load(f) if data is not None: for key, value in data.iteritems(): if not isinstance(key, basestring): raise InvalidUserDataError("String to be replaced is not actually a string: " + key) if len(key) != 1: raise InvalidUserDataError("String to be replaced must be a 1 character long: " + key) if not isinstance(value, basestring): raise InvalidUserDataError("String to replace with is not actually a string: " + value) CharacterSubstitutions.character_substitutions = data
def read_from_project(self, resource_open): """ Reads a user-written list of ranges that shouldn't be touched. """ with resource_open(self.FILE, 'yml') as f: ranges = yml_load(f) if not ranges: self.ranges = [] elif type(ranges) != list: raise InvalidYmlRepresentationError("used_range files is invalid. Must be a list of ranges.") else: self.ranges = [] for entry in ranges: self.ranges.append(range_from_string(entry))
def read_from_project(self, resourceOpener): self.door_areas = [] with resourceOpener("map_doors", "yml", True) as f: input = yml_load(f) for y in input: row = input[y] for x in row: if row[x] is None: self.door_areas.append(None) else: entry = [] for door in row[x]: d = door_from_yml_rep(door) entry.append(d) self.door_areas.append(entry)
def read_from_project(self, resourceOpener): self.door_areas = [] with resourceOpener("map_doors", "yml", True) as f: input = sort_yml_doors(yml_load(f)) for y in input: row = input[y] for x in row: if row[x] is None: self.door_areas.append(None) else: entry = [] for door in row[x]: d = door_from_yml_rep(door) entry.append(d) self.door_areas.append(entry)
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 range(new_image_h): for x in range(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", True) as widths_file: widths_dict = yml_load(widths_file) for character_id in range(96, 128): if character_id not in widths_dict: widths_dict[character_id] = 0 with resource_open_w(widths_resource_name, "yml", True) 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)
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)
def read_from_project(self, resource_open): formatting_data = {} with resource_open(CAST_FORMATTING_FILE_NAME, 'yml', True) as f: formatting_data = yml_load(f) for fmt_entry in formatting_data: entry = EbCastEntry() entry.set_values(formatting_data[fmt_entry]['begin'], formatting_data[fmt_entry]['size'], formatting_data[fmt_entry]['misc']) self.entries.append(entry) if entry.size == 0: raise InvalidArgumentError( 'Cast graphics entry number {} has size 0 - would crash the cast screen.' .format(fmt_entry))
def upgrade_project(self, old_version, new_version, rom, resource_open_r, resource_open_w, resource_delete): if old_version == 1: self.read_from_rom(rom) self.write_to_project(resource_open_w) elif old_version < new_version: self.read_from_project(resource_open_r) # Add in all the new patches for ip_desc_filename in [s for s in os.listdir(get_ips_directory(rom.type)) if s.lower().endswith(".yml")]: with open(os.path.join(get_ips_directory(rom.type), ip_desc_filename)) as ips_desc_file: ips_desc = yml_load(ips_desc_file) ips_desc_title = ips_desc["Title"] if ips_desc_title not in self.patches: self.patches[ips_desc_title] = "disabled" self.write_to_project(resource_open_w)
def read_from_project(self, resource_open): log.debug('Reading dynamic cast names') yml_data = {} with resource_open(CAST_DYNAMIC_NAMES_FILE_NAME, 'yml', True) as f: yml_data = yml_load(f) for n in self.dynamic_names: n.read_from_yml_data(yml_data) log.debug('Reading cast formatting data') self.formatting.read_from_project(resource_open) log.debug('Reading cast name graphics') self.read_gfx_from_project(self.name_gfx, resource_open) log.debug('Reading miscellaneous cast graphics') self.read_gfx_from_project(self.misc_gfx, resource_open)
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)
def read_from_project(self, resource_open): with resource_open("Fonts/character_substitutions", "yml") as f: data = yml_load(f) if data is not None: for key, value in data.iteritems(): if not isinstance(key, basestring): raise InvalidUserDataError( "String to be replaced is not actually a string: " + key) if len(key) != 1: raise InvalidUserDataError( "String to be replaced must be a 1 character long: " + key) if not isinstance(value, basestring): raise InvalidUserDataError( "String to replace with is not actually a string: " + value) CharacterSubstitutions.character_substitutions = data
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 == 4: with resource_open_r("sprite_groups", "yml") as f: data = yml_load(f) for i in data: entry = data[i] collision_settings = entry["Collision Settings"] entry["North/South Collision Width"] = collision_settings[ 0] entry["North/South Collision Height"] = collision_settings[ 1] entry["East/West Collision Width"] = collision_settings[2] entry["East/West Collision Height"] = collision_settings[3] del entry["Collision Settings"] with resource_open_w("sprite_groups", "yml") as f: yml_dump(data, f) self.upgrade_project(old_version + 1, new_version, rom, resource_open_r, resource_open_w, resource_delete) elif old_version == 2: replace_field_in_yml(resource_name="sprite_groups", resource_open_r=resource_open_r, resource_open_w=resource_open_w, key="Unknown A", new_key="Size", value_map=dict(enumerate(SPRITE_SIZES))) replace_field_in_yml(resource_name="sprite_groups", resource_open_r=resource_open_r, resource_open_w=resource_open_w, key="Unknown B", new_key="Collision Settings") self.upgrade_project(old_version + 1, 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)
def read_from_project(self, resource_open): for i, tileset in enumerate(self.tilesets): log.debug("Reading tileset #{}".format(i)) with resource_open("Tilesets/" + str(i).zfill(2), "fts") as f: tileset.from_file(f) log.debug("Reading palette settings") with resource_open("map_palette_settings", "yml") as f: yml_rep = yml_load(f) for map_tileset in yml_rep: # Get the draw (normal) tileset tileset = None for ts in self.tilesets: if ts.has_map_tileset(map_tileset): tileset = ts break # For each map palette palettes = tileset.get_palettes_by_map_tileset(map_tileset) for palette_id, palette in palettes: entry = yml_rep[map_tileset][palette_id] palette.settings_from_yml_rep(entry)
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)
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 <= 6: with resource_open_r("map_palette_settings", "yml") as f: yml_rep = yml_load(f) for map_tileset in yml_rep.itervalues(): for map_palette in map_tileset.itervalues(): if "Event Palette" in map_palette: map_palette["Event Palette"] = { "Colors": map_palette["Event Palette"], "Event Flag": 0, "Flash Effect": 0, "Sprite Palette": map_palette["Sprite Palette"] } self.write_map_palette_settings(yml_rep, resource_open_w) self.upgrade_project( 7, 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)
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)
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 == 4: with resource_open_r("TownMaps/icon_positions", "yml") as f: data = yml_load(f) for i in range(6): old_key = TownMapEnum.tostring(i).lower() data[i] = data[old_key] del data[old_key] with resource_open_w("TownMaps/icon_positions", "yml") as f: yml_dump(data, f, default_flow_style=False) convert_values_to_hex_repr_in_yml_file("TownMaps/icon_positions", resource_open_r, resource_open_w, ["Event Flag"]) self.upgrade_project(5, new_version, rom, resource_open_r, resource_open_w, resource_delete) elif old_version <= 2: self.read_from_rom(rom) self.write_to_project(resource_open_w) self.upgrade_project(new_version, 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)
def upgrade_project(self, old_version, new_version, rom, resource_open_r, resource_open_w, resource_delete): if old_version == 1: self.read_from_rom(rom) self.write_to_project(resource_open_w) elif old_version < new_version: self.read_from_project(resource_open_r) # Remove all patches that should not exist if rom.type in REMOVED_PATCHES: for patch_name in REMOVED_PATCHES[rom.type]: if patch_name in self.patches: del self.patches[patch_name] # Add in all the new patches for ip_desc_filename in [s for s in os.listdir(get_ips_directory(rom.type)) if s.lower().endswith(".yml")]: with open(os.path.join(get_ips_directory(rom.type), ip_desc_filename)) as ips_desc_file: ips_desc = yml_load(ips_desc_file) ips_desc_title = ips_desc["Title"] ips_is_hidden = ("Hidden" in ips_desc) and ips_desc["Hidden"] if (not ips_is_hidden) and (ips_desc_title not in self.patches): self.patches[ips_desc_title] = "disabled" self.write_to_project(resource_open_w)
def read_from_project(self, resource_open): with resource_open("patches", "yml") as f: self.patches = yml_load(f)
def read_from_project(self, resource_open): with resource_open("text_misc", "yml") as f: self.data = yml_load(f)
def from_yml_file(self, f): yml_rep = yml_load(f) self.from_yml_rep(yml_rep)
def read_staff_chars_from_assets(self): with open_asset('structures', 'eb_staff_chars.yml') as f: yml_data = yml_load(f) self.read_staff_chars(yml_data)
def read_from_project(self, resource_open): with resource_open("text_misc", "yml", True) as f: self.data = yml_load(f)
def read_chars_data_from_project(self, resource_open): # Read the characters positions with resource_open(CHARS_POSITIONS_PATH, "yml", True) 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 range(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 range(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 range(TILE_HEIGHT)] for _ in range(TILE_WIDTH)] for _ in range(CHARS_NUM_TILES) ] unused_tiles = set(range(CHARS_NUM_TILES)) # Set the new character layouts self.chars_layouts = [[] for _ in range(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 range(0, width, 2) for j in range(0, height, 2) ] if width % 2 == 1: l.extend([(width-1, j) for j in range(1, height, 2)]) if height % 2 == 1: l.extend([(i, height-1) for i in range(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)
def read_from_project(self, resource_open): with resource_open("naming_skip", "yml", True) as f: self.data = yml_load(f)
def read_staff_chars_from_project(self, resource_open): with resource_open(STAFF_CHARS_FILE_NAME, 'yml', True) as f: yml_data = yml_load(f) self.read_staff_chars(yml_data)
def load(self): try: with open(self.PREFERENCES_FILENAME, 'r') as f: self.preferences = yml_load(f) except IOError: self.preferences = {}
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)
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 == 3: replace_field_in_yml(resource_name="item_configuration_table", resource_open_r=resource_open_r, resource_open_w=resource_open_w, key="Effect", new_key="Action") replace_field_in_yml(resource_name="psi_ability_table", resource_open_r=resource_open_r, resource_open_w=resource_open_w, key="Effect", new_key="Action") replace_field_in_yml(resource_name="psi_ability_table", resource_open_r=resource_open_r, resource_open_w=resource_open_w, key="PSI Name", value_map={0: None, 1: 0, 2: 1, 3: 2, 4: 3, 5: 4, 6: 5, 7: 6, 8: 7, 9: 8, 10: 9, 11: 10, 12: 11, 13: 12, 14: 13, 15: 14, 16: 15, 17: 16}) resource_delete("cmd_window_text") resource_delete("psi_anim_palettes") resource_delete("sound_stone_palette") self.upgrade_project(old_version=old_version + 1, new_version=new_version, rom=rom, resource_open_r=resource_open_r, resource_open_w=resource_open_w, resource_delete=resource_delete) elif old_version == 2: replace_field_in_yml(resource_name="timed_delivery_table", resource_open_r=resource_open_r, resource_open_w=resource_open_w, key="Suitable Area Text Pointer", new_key="Delivery Success Text Pointer") replace_field_in_yml(resource_name="timed_delivery_table", resource_open_r=resource_open_r, resource_open_w=resource_open_w, key="Unsuitable Area Text Pointer", new_key="Delivery Failure Text Pointer") with resource_open_r("timed_delivery_table", "yml") as f: out = yml_load(f) yml_str_rep = yml_dump(out, default_flow_style=False) yml_str_rep = convert_values_to_hex_repr(yml_str_rep, "Event Flag") with resource_open_w("timed_delivery_table", "yml") as f: f.write(yml_str_rep) self.upgrade_project(old_version=old_version + 1, new_version=new_version, rom=rom, resource_open_r=resource_open_r, resource_open_w=resource_open_w, resource_delete=resource_delete) elif old_version == 1: replace_field_in_yml(resource_name="psi_ability_table", resource_open_r=resource_open_r, resource_open_w=resource_open_w, key="Target", new_key="Usability Outside of Battle", value_map={"Nobody": "Other", "Enemies": "Unusable", "Allies": "Usable"}) replace_field_in_yml(resource_name="battle_action_table", resource_open_r=resource_open_r, resource_open_w=resource_open_w, key="Direction", value_map={"Party": "Enemy", "Enemy": "Party"}) self.upgrade_project(old_version=old_version + 1, new_version=new_version, rom=rom, resource_open_r=resource_open_r, resource_open_w=resource_open_w, resource_delete=resource_delete) else: self.upgrade_project(old_version + 1, new_version, rom, resource_open_r, resource_open_w, resource_delete)
return allocated_range[0] def get_largest_unallocated_range(self): largest_begin, largest_end = 1, 0 for begin, end in self.unallocated_ranges: if end - begin > largest_end - largest_begin: largest_begin = begin largest_end = end if largest_end - largest_begin <= 0: raise NotEnoughUnallocatedSpaceError("Not enough free space left") return largest_begin, largest_end with open_asset("romtypes.yml") as f: ROM_TYPE_MAP = yml_load(f) ROM_TYPE_NAME_UNKNOWN = "Unknown" class Rom(AllocatableBlock): def reset(self, size=0): super(Rom, self).reset(size) self.type = ROM_TYPE_NAME_UNKNOWN def from_file(self, filename): super(Rom, self).from_file(filename) self._setup_rom_post_load() def _setup_rom_post_load(self): self.type = self._detect_type()
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)