def make_sprite_by_number(self, sprite_number, sprite_filename): #go into the manifest and get the actual name of the sprite with open(common.get_resource([self.console_name,self.internal_name,"manifests"],"manifest.json")) as file: manifest = json.load(file) if str(sprite_number) in manifest: folder_name = manifest[str(sprite_number)]["folder name"] #dynamic imports to follow source_subpath = f"source.{self.console_name}.{self.internal_name}.{folder_name}" sprite_module = importlib.import_module(f"{source_subpath}.sprite") resource_subpath = os.path.join(self.console_name,self.internal_name,folder_name) sprite = sprite_module.Sprite(sprite_filename,manifest[str(sprite_number)],resource_subpath) try: animationlib = importlib.import_module(f"{source_subpath}.animation") animation_assist = animationlib.AnimationEngine(resource_subpath, self, sprite) except ImportError: #there was no sprite-specific animation library, so import the parent animationlib = importlib.import_module(f"source.meta.gui.animationlib") animation_assist = animationlib.AnimationEngineParent(resource_subpath, self, sprite) return sprite, animation_assist else: # FIXME: English raise AssertionError(f"make_sprite_by_number() called for non-implemented sprite_number {sprite_number}")
def __init__(self, my_subpath, game, sprite): self.game = game self.sprite = sprite self.resource_subpath = my_subpath #the path to this sprite's subfolder in resources self.spiffy_dict = { } #the variables created by the spiffy buttons will go here self.overhead = True #by default, this will create NESW direction buttons. If false, only left/right buttons self.overview_scale_factor = sprite.overview_scale_factor #when the overview is made, it is scaled up by this amount self.step_number_label = tk.Label() self.step_total_label = tk.Label() self.tiles_list_label = tk.Label() self.plugins = [] self.prev_palette_info = [] with open( common.get_resource([self.resource_subpath, "manifests"], "animations.json")) as file: self.animations = json.load(file) if "$schema" in self.animations: del self.animations["$schema"] #using a default value until the animation_panel attachment overrides this self.current_animation = next(iter(self.animations.keys()))
def set_background(self, image_title): if self.current_background_title == image_title: if self.last_known_zoom == self.zoom_getter(): return #there is nothing to do here, because nothing has changed else: #image name is different, so need to load a new image image_filename = self.current_background_title if image_title in self.background_datas["title"]: image_filename = self.background_datas["title"][image_title] elif image_title in self.background_datas["filename"]: image_filename = image_title self.raw_background = Image.open( common.get_resource( [self.console_name, self.internal_name, "backgrounds"], image_filename)) #this doesn't work yet; not sure how to hook it if "origin" in self.background_datas: if image_title in self.background_datas["origin"]: # print("Setting Coordinates because of background (%s): %s" % (image_title, self.background_datas["origin"][image_title])) if hasattr(self, "coord_setter"): self.coord_setter( self.background_datas["origin"][image_title]) #now re-zoom the image new_size = tuple( int(dim * self.zoom_getter()) for dim in self.raw_background.size) self.background_image = gui_common.get_tk_image( self.raw_background.resize(new_size, resample=Image.NEAREST)) if self.current_background_title is None: self.background_ID = self.canvas.create_image( 0, 0, image=self.background_image, anchor=tk.NW) #so that we can manipulate the object later else: self.canvas.itemconfig(self.background_ID, image=self.background_image) self.last_known_zoom = self.zoom_getter() self.current_background_title = image_title
def get_spiffy_buttons(self, parent, fish): spiffy_buttons = widgetlib.SpiffyButtons(parent, self.resource_subpath, self) spiffy_manifest = common.get_resource([self.resource_subpath,"manifests"],"spiffy-buttons.json") if spiffy_manifest: with open(spiffy_manifest) as f: spiffy_list = json.load(f) for group in spiffy_list["button-groups"]: group_key = group["group-fish-key"] button_group = spiffy_buttons.make_new_group(group_key,fish) button_list = [] for button in group["buttons"]: if "meta" in button and button["meta"] == "newline": button_list.append((None,None,None,None)) elif "meta" in button and button["meta"] == "blank": #a blank space, baby button_list.append((None,"",None,None)) else: default = button["default"] if "default" in button else False disabled = group["disabled"] if "disabled" in group else False button_list.append((button["fish-subkey"],button["img"],default,disabled)) button_group.adds(button_list,fish) return spiffy_buttons
def get_stamp(self): dims = { "bg": { "width": 332, "height": 142 }, "cb": { "width": 0, "height": 0, "x": 148, "y": 110 }, "name": { "width": 8, "height": 12, "x": 0, "y": 0 }, "author": { "width": 7, "height": 7, "x": 0, "y": 0 } } stamp = Image.open( common.get_resource([self.resource_subpath, "sheets", "stamp"], "stamp.png")).convert("RGBA") rowIMG = { "name": Image.open( common.get_resource([self.resource_subpath, "sheets", "stamp"], "uppercase.png")), "author": Image.open( common.get_resource([self.resource_subpath, "sheets", "stamp"], "lowercase.png")), } charmap = { "name": [ascii_uppercase, ".,?!_#%()+-/;:<=>[] "], "author": [ascii_uppercase, digits + " "] } spritedata = { "name": self.metadata["sprite.name"] if "sprite.name" in self.metadata and self.metadata["sprite.name"] != "" else "Unknown Samus Sprite", "author": self.metadata["author.name"] if "author.name" in self.metadata and self.metadata["author.name"] != "" else "Unknown Author" } dims["fullName"] = { "width": len(spritedata["name"]) * (dims["name"]["width"]) } dims["fullAuthor"] = { "width": len(spritedata["author"]) * (dims["author"]["width"] + 1) } ltrsIMG = Image.new( "RGBA", (max(dims["fullName"]["width"], dims["fullAuthor"]["width"]), 38), (255, 255, 255, 0)) if spritedata["name"] != "" and spritedata["author"] != "": createdby = Image.open( common.get_resource([self.resource_subpath, "sheets", "stamp"], "createdby.png")) x = dims["cb"]["x"] y = dims["cb"]["y"] stamp.paste(createdby, (x, y), createdby) createdby.close() coords = { "dest": { "x": (int(ltrsIMG.size[0] / 2) - int(dims["fullName"]["width"] / 2)), "y": dims["name"]["y"] }, "src": { "x": 0, "y": 0 } } for row in ["name", "author"]: for i, ltr in enumerate(spritedata[row][:(26 + 15)]): found = False ltr = ltr.upper() for ltrs in [row, "name", "author"]: for j, line in enumerate(charmap[ltrs]): if not found and ltr in line: found = True # print(ltr,line.find(ltr),j) coords["src"]["x"] = (line.find(ltr) * (dims[ltrs]["width"] + 1)) coords["src"]["y"] = j * dims[ltrs]["height"] ltrIMG = rowIMG[ltrs].crop( (coords["src"]["x"], coords["src"]["y"], coords["src"]["x"] + dims[ltrs]["width"], coords["src"]["y"] + dims[ltrs]["height"] + 1)) (x, y) = (coords["dest"]["x"], coords["dest"]["y"]) if row == "name" and ltrs == "author": y += 4 ltrIMG = Image.alpha_composite( Image.new("RGBA", ltrIMG.size, (255, 255, 255, 0)), ltrIMG.convert("RGBA")) ltrsIMG.paste(ltrIMG, (x, y)) ltrIMG.close() coords["dest"]["x"] += dims[ltrs]["width"] if ltrs == "author": coords["dest"]["x"] += 1 coords["dest"]["x"] = (int(ltrsIMG.size[0] / 2) - int(dims["fullAuthor"]["width"] / 2)) coords["dest"]["y"] += dims[row]["height"] + 17 find = [0, 0, 0] replace = (255, 255, 255) data = common.np.array(ltrsIMG) r, g, b, a = data.T black_areas = (r == find[0]) & (g == find[1]) & (b == find[2]) data[..., :-1][black_areas.T] = replace ltrsIMG = Image.fromarray(data) # ltrsIMG.save(os.path.join(".","ltrs.png")) stamp.paste(ltrsIMG, (int(stamp.size[0] / 2) - int(ltrsIMG.size[0] / 2), 91), ltrsIMG) rowIMG = {} return stamp
def add(self, internal_value_name, image_filename, fish, default=False, disabled=False): if image_filename is None: image_filename = "blank.png" #disable sprite object in widgetlib icon_path = common.get_resource( [self.sprite_resource_subpath, "icons"], image_filename ) #common.get_resource([self.parent.animation_engine.resource_subpath,"icons"],image_filename) if icon_path is None: icon_path = common.get_resource(["meta", "icons"], image_filename) if icon_path is None: # FIXME: English raise AssertionError( f"No image resource found with name {image_filename}") img = ImageTk.PhotoImage(Image.open(icon_path)) #disable sprite object in widgetlib fish_key = self.sprite_resource_subpath.replace(os.sep, '.') display_text = fish.translate( fish_key, self.label, internal_value_name ) #fish.translate(self.parent.animation_engine.resource_subpath, self.label, internal_value_name) button = tk.Radiobutton( self.parent.spiffy_buttons_section, image=img, name="_".join([self.label.lower(), internal_value_name, "button"]), text=display_text, variable=self.var, value=internal_value_name, activebackground=self.parent.DIMENSIONS["button"]["color.active"], selectcolor=self.parent.DIMENSIONS["button"]["color.selected"], width=self.parent.DIMENSIONS["button"]["width"], height=self.parent.DIMENSIONS["button"]["height"], indicatoron=False, command=self.press_spiffy_button) if disabled: button.configure(state="disabled") bindings = None keypresses = None bindings_filename = common.get_resource(["meta", "manifests"], "bindings.json") with open(bindings_filename, encoding="utf-8") as f: bindings = json.load(f) keypresses_switcher = bindings[ self.label.lower()] if self.label.lower() in bindings else {} keypresses = keypresses_switcher.get(internal_value_name.lower(), None) if keypresses: for keypress in keypresses: button.bind_all(keypress, partial(self.invoke_spiffy_button, button)) ToolTip(button, display_text) button.image = img button.grid(row=self.row, column=self.col) if not self.default_exists or default: button.select() self.press_spiffy_button() self.default_exists = True self.col += 1
def show_trawler(frames_by_animation,animations_by_frame,overhead): cyan = "#00CAFF" green = "#00FF7A" yellow = "#FFFF00" default = "" def on_enter(e): if e.widget["background"] == default: e.widget["background"] = yellow def on_leave(e): if e.widget["background"] == yellow: e.widget["background"] = default def show_cell_data(itemID="A0", lookup="byFrame"): title = "" msg = "" process_cells = len(cell_buttons) > 0 if lookup == "byFrame": title = itemID if process_cells and itemID in cell_buttons: for _,button in cell_buttons.items(): bg = button.cget("bg") if bg != green: button.configure(bg=default) button.update() cell_buttons[itemID].configure(bg=cyan) cell_buttons[itemID].update() for animation,directions in animations_by_frame[itemID].items(): for direction,frames in directions.items(): msg += "> " + animation + " " msg += "(" + direction + ")\n" msg += ">> Poses: " for frameID, frame in frames.items(): for cell in frame: msg += str(frameID + 1) if "flip" in cell and cell["flip"] != "": msg += " " + cell["flip"] + "-flipped" if "crop" in cell and cell["crop"] != "": crop = "[" + ",".join(map(str,cell["crop"])) + "]" switcher = { "[0,0,16,8]": "Top", "[0,0,8,8]": "Top Left", "[8,0,16,8]": "Top Right", "[0,0,8,16]": "Left", "[8,0,16,16]": "Right", "[0,8,16,16]": "Bottom", "[0,8,8,16]": "Bottom Left", "[8,8,16,16]": "Bottom Right" } crop = switcher.get(crop,crop) msg += " " + crop msg += "; " msg += "\n" msg += "\n" elif lookup == "byAnim": animation = itemID.split(":")[0] direction = itemID.split(":")[1] directions = frames_by_animation[animation] if overhead: if "_" in direction: aim = direction.split("_")[0] direction = direction.split("_")[1] direction = direction + "_aim_diag_" + aim if direction + "_aim_shoot" in directions: direction = direction + "_aim_shoot" if direction not in directions: if direction == "neutral" and "right" in directions: direction = "right" elif direction == "up" and "right_aim_up" in directions: direction = "right_aim_up" elif direction == "down" and "right_aim_down" in directions: direction = "right_aim_down" elif "right" in directions: direction = "right" else: direction = list(directions.keys())[0] title = animation + " (" + direction + ")" frames = directions[direction] if process_cells: for cellID,button in cell_buttons.items(): bg = button.cget("bg") if bg != cyan: button.configure(bg=default) button.update() for frameID, frame in frames.items(): msg += "> Pose: " + str(frameID + 1) + "\n" msg += ">> Cells: " for cell in frame: msg += cell["id"] if process_cells and cell["id"] in cell_buttons: cell_buttons[cell["id"]].configure(bg=green) cell_buttons[cell["id"]].update() if "flip" in cell and cell["flip"] != "": msg += " " + cell["flip"] + "-flipped" msg += "; " msg += "\n\n" widgets.make_messagebox("info",title,msg,parent=trawler) def show_ani_data(direction): animation = self.widgets["animation_display"].storageVar.get() show_cell_data(itemID=animation + ":" + direction, lookup="byAnim") dims = { "text": { "width": 4, "height": 1 }, "image": { "width": 20, "height": 20 } } trawler = Toplevel() trawler.title("Sheet Trawler") trawler.geometry("1024x768") default = trawler.cget("bg") self = widgets.make_frame(trawler) self.widgets = {} self.frames = {} cell_buttons = {} if "A0" in animations_by_frame: letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" disabled = [ "D5","D6", "E0","E1", "G5","G6", "K5", "P0", # right half "Q2","Q3","Q4", "R3","R4","R5", "U3", "V7", "W0","W1","W2","W3","W4","W5","W6","W7", "X0", "Z1","Z6" # Z6: lower right quarter "AB5","AB6","AB7" ] # Cell Grid, click a cell for animations that use that cell cell_grid = Frame(trawler) for letter in letters: for i in range(0,7+1): cell_name = letter + str(i) cell_button = widgets.make_button( cell_grid, cell_name, partial(show_cell_data,cell_name), { "width": dims["text"]["width"], "height": dims["text"]["height"], "state": "disabled" if cell_name in disabled else "active" } ) cell_button.bind("<Enter>", on_enter) cell_button.bind("<Leave>", on_leave) cell_button.grid(row=letters.index(letter),column=i) cell_buttons[cell_name] = cell_button letters = [ "AA", "AB" ] for letter in letters: lstr = "" for i in range(0,7+1): cell_name = letter + str(i) cell_button = widgets.make_button( cell_grid, cell_name, partial(show_cell_data,cell_name), { "width": dims["text"]["width"], "height": dims["text"]["height"], "state": "disabled" if cell_name in disabled else "active" } ) cell_button.bind("<Enter>", on_enter) cell_button.bind("<Leave>", on_leave) cell_button.grid(row=letters.index(letter)+26,column=i) cell_buttons[cell_name] = cell_button cell_grid.pack(side=LEFT, anchor=N) # Display info about selected cell self.frames["cell_display"] = widgets.make_frame(trawler) thiswidget = { "cell_display": { "type": "selectbox", "default": "index", "options": { # "Vanilla Link": "vanilla", "Index labels": "index", # "Currently loaded sprite": "loaded" } } } dict_widgets = widgets.make_widgets_from_dict({}, thiswidget, self.frames["cell_display"]) for key in dict_widgets: self.widgets[key] = dict_widgets[key] self.widgets[key].pack() self.frames["cell_display"].pack(side=LEFT, anchor=N) # Display info about selected animation self.frames["animation_display"] = widgets.make_frame(trawler) thiswidget = { "animation_display": { "type": "selectbox", "options": {} } } directions = ["down","left","up","right"] if overhead: directions = ["down","down_left","left","up_left","up","up_right","right","down_right","neutral"] for direction in directions: text = direction img = "arrow-" + direction.replace("_","") + ".png" if direction == "neutral": img = "no-thing.png" thiswidget[direction] = { "type": "button", "label": { "text": text }, "options": { "image": common.get_resource( ["meta","icons"], img ), "width": dims["image"]["width"], "height": dims["image"]["height"], "compound": "none" } } for ani in frames_by_animation.keys(): thiswidget["animation_display"]["options"][ani] = ani dict_widgets = widgets.make_widgets_from_dict(self, thiswidget, self.frames["animation_display"]) for key in dict_widgets: self.widgets[key] = dict_widgets[key] if self.widgets[key].type == "button": self.widgets[key].config(command=partial(show_ani_data,key)) self.widgets[key].pack(side=LEFT) self.frames["animation_display"].pack(side=LEFT, anchor=N)
def equipment_test(save=False): #get equipment image with(Image.open(common.get_resource(["snes","metroid3","samus","sheets"],"equipment.png"))) as equipment_image: equipment = {} #collect icon names & coordinates icon_specs = {} #lemons, missiles, supers projectiles = { "lemon_right": [( 0, 0),(16,16)], #left: h-flip "lemon_upright": [( 16, 0),(16,16)], #downright: v-flip; upleft: h-flip; downleft: both "lemon_up": [( 32, 0),(16,16)], #down: v-flip "missile_right": [( 48, 0),(16,16)], #left: h-flip "missile_upright": [( 64, 0),(16,16)], #downright: v-flip, upleft: h-flip; downleft: both "missile_up": [( 80, 0),(16,16)], #down: v-flip "super_right": [( 96, 0),(16,16)], #left: h-flip "super_upright": [(112, 0),(16,16)], #downright: v-flip; upleft: h-flip; downleft: both "super_up": [(128, 0),(16,16)] #down: v-flip } for k,v in projectiles.items(): icon_specs[k] = coord_calc(v[0],v[1]) #morph ball bombs for i in range(3): icon_specs["mbb" + str(i)] = coord_calc((144+(8*i),0),(8,8)) #powerbombs for i in range(3): icon_specs["pb" + str(i)] = coord_calc((144+(8*i),8),(8,8)) #poof cloud for i in range(3): icon_specs["poof" + str(i)] = coord_calc((144+(8*i),16),(8,8)) #morph ball bombs blast for i in range(3): for j in range(2): w = 32 h = 32 x1 = 176 + (w * j) x2 = 0 + (h * i) id = (i*2)+(j*1) if(id < 5): icon_specs["mbb_blast" + str(id)] = coord_calc((x1,x2),(w,h)) #charg[ing|ed] lemon for i in range(6): w = 16 h = 16 x1 = 0 + (w * i) x2 = 16 icon_specs["charge" + str(i)] = coord_calc((x1,x2),(w,h)) #iced lemon for i in range(3): w = 16 h = 16 x1 = 64 + (w * i) x2 = 48 icon_specs["ice" + str(i)] = coord_calc((x1,x2),(w,h)) #iced particles for i in range(4): w = 16 h = 16 x1 = 80 + (w * i) x2 = 32 icon_specs["ice_particle" + str(i)] = coord_calc((x1,x2),(w,h)) #charged ice for i in range(2): w = 16 h = 16 x1 = 112 + (w * i) x2 = 48 icon_specs["charge_ice" + str(i)] = coord_calc((x1,x2),(w,h)) #spazer icon_specs["spazer0"] = coord_calc((112,16),( 9,2)) #from blaster icon_specs["spazer1"] = coord_calc((112,19),(18,2)) #repeated; # FIXME: Get number of repeats #plasma icon_specs["plasma0"] = coord_calc((128,16),(5,3)) #from blaster icon_specs["plasma1"] = coord_calc((134,16),(4,3)) #repeated; # FIXME: Get number of repeats #charged spazer icon_specs["charge_spazer0"] = coord_calc((112,22),(5,2)) #from blaster #charged plasma #charged spazer/plasma (none/ice/wave) icon_specs["charge_special0"] = coord_calc((128,22),(8,7)) #repeated; # FIXME: Get number of repeats #wave lemon for i in range(5): w = 16 h = 16 x1 = 0 + (w * i) x2 = 32 icon_specs["wave" + str(i)] = coord_calc((x1,x2),(w,h)) #cycle through collected icons and write to disk for icon in icon_specs: icon_coords = icon_specs.get(icon) cropped_image = equipment_image.crop(icon_coords) equipment[icon] = cropped_image if save: cropped_image.save(os.path.join(".","resources","user","snes","metroid","samus","sheets") + icon + ".png") ship_dir = os.path.join(".","resources","app","snes","metroid3","samus","sheets","ship") for file in os.listdir(ship_dir): icon = "optional_ship_" + file[:file.rfind('.')] with(Image.open(os.path.join(ship_dir,file))) as img: equipment[icon] = img return equipment
def load_layout(self): self.layout = layoutlib.Layout( common.get_resource([self.resource_subpath, "manifests"], "layout.json"))
def get_representative_images(self, style="default"): if "sprite.name" in self.metadata and self.metadata["sprite.name"]: sprite_save_name = self.metadata["sprite.name"].lower() else: # FIXME: English sprite_save_name = "unknown" manifest_file = common.get_resource( [self.resource_subpath, "manifests"], "representative-images.json") if manifest_file: with open(manifest_file) as manifest: manifest_images = json.load(manifest) else: manifest_images = {} if "default" not in manifest_images: # try to have sane defaults animationkeys = list(self.animations.keys()) if "$schema" in animationkeys: animationkeys.remove("$schema") animation = animationkeys[0] # default to first image here direction = list( self.animations[animation].keys())[0] # first direction pose = 0 # first pose # by default, will use default palettes, without having any info # supplied probably won't matter, but just in case, use the # first frame of palette frame = 0 if style in manifest_images: images = manifest_images[style] elif style == "default": images = [[]] # use defaults else: # FIXME: English raise AssertionError( f"received call to get_representative_image()" + ' ' + "with unknown style {style}") return_images = [] for image in images: animationkeys = list(self.animations.keys()) if "$schema" in animationkeys: animationkeys.remove("$schema") animation = animationkeys[0] # default to first image here if 0 in image: animation = image[0] direction = list(self.animations[animation].keys())[ 0] # default: first direction if 1 in image: direction = image[1] pose = image[2] if len(image) > 2 else 0 # default: #first pose # defaults to the defaults determined by get_image palette = image[3] if len(image) > 3 else [] # default to the first frame of timed palette frame = image[4] if len(image) > 4 else 0 # default to the sprite name and style filename = image[5] if len(image) > 5 else \ common.filename_scrub( "-".join([sprite_save_name, style]) + ".png") return_images.append((filename, self.get_image(animation, direction, pose, palette, frame)[0])) # should return a list of tuples of the form (filename, PIL Image) return return_images
def load_animations(self): with open( common.get_resource([self.resource_subpath, "manifests"], "animations.json")) as file: self.animations = json.load(file)
import os from source.meta.common import common APP_VERSION = "" app_version_filename = common.get_resource( ["meta", "manifests"], "app_version.txt" ) if app_version_filename and os.path.isfile(app_version_filename): with open(app_version_filename) as f: APP_VERSION = f.readlines()[0].strip() # maximum number of frames an animation will display before it stops MAX_FRAMES = 1E9 # adds some extra checks that are useful for development purposes # (to unset this, just comment out this line, don't set to false) DEBUG_MODE = True def main(): print(f"Called main() on utility library {__file__}") if __name__ == "__main__": main()
def equipment_test(save=False): #get equipment image equipment_image = Image.open( common.get_resource(["snes", "zelda3", "link", "sheets"], "equipment.png")) equipment = {} #collect icon names & coordinates icon_specs = {} #the swords are at the same x-coordinate but have differing y-values, set up these y-values swords = [("fighter", 0), ("master", 32), ("tempered", 64), ("gold", 96)] #tuples for fun stuff; first is top-left origin, second is width,height coords = [((0, 0), (8, 16)), ((8, 0), (8, 16)), ((16, 0), (16, 16)), ((32, 0), (16, 16)), ((48, 0), (19, 8)), ((48, 8), (16, 8)), ((64, 8), (16, 8)), ((80, 0), (16, 16)), ((96, 0), (16, 16)), ((112, 6), (16, 18)), ((128, 3), (8, 21)), ((136, 0), (8, 16)), ((144, 0), (16, 16)), ((160, 0), (16, 8))] #cycle through coordinate info for i in range(len(coords)): #cycle through swords and y-offsets for j in range(len(swords)): origin, dims = coords[i] x, y = origin level, y_offset = swords[j] icon_specs[level + "_sword" + str(i)] = coord_calc( (x, y + y_offset), dims) #next row is some inventory stuff inventory = { "main_shadow": ((0, 112), (16, 16)), "small_shadow": ((16, 112), (16, 16)), "book": ((32, 112), (16, 16)), "bush": ((48, 112), (16, 16)), "pendant": ((64, 112), (16, 16)), "crystal": ((80, 112), (16, 16)) } #add some inventory stuff for key in inventory: origin, dims = inventory[key] icon_specs[key] = coord_calc(origin, dims) #shields shields = [("fighter", 0), ("fire", 16), ("mirror", 32)] #cycle through x-coordinates for i in range(4): #cycle through shields and y-offsets for j in range(len(shields)): level, y_offset = shields[j] origin = (i * 16, 128 + y_offset) icon_specs[level + "_shield" + str(i)] = coord_calc( origin, (16, 16)) inventory = { "cane0": ((0, 176), (8, 16)), #vertical "cane1": ((8, 176), (8, 16)), #vertical "cane2": ((16, 176), (16, 8)), #horizontal "cane3": ((32, 176), (16, 16)), #diagonal ltr "cane4": ((48, 176), (8, 16)), #vertical "somaria_block": ((64, 176), (16, 16)), "rod0": ((0, 192), (8, 16)), #vertical "rod1": ((8, 192), (8, 16)), #vertical "rod2": ((16, 192), (16, 8)), #horizontal "rod3": ((16, 200), (8, 8)), #fourth-wall NtS "rod4": ((32, 192), (16, 16)), #diagonal ltr "rod5": ((48, 192), (8, 16)), #vertical "hammer0": ((0, 208), (8, 16)), #vertical ltr "hammer1": ((8, 208), (8, 16)), #vertical "hammer2": ((16, 208), (8, 16)), #vertical "hammer3": ((24, 208), (8, 16)), #vertical "hammer4": ((32, 208), (16, 8)), #horizontal "hammer5": ((32, 216), (8, 8)), #vertical "hammer6": ((48, 208), (16, 16)), #diagonal ltr "hook0": ((0, 224), (8, 8)), #horizontal "hook1": ((8, 224), (8, 8)), #vertical "hook2": ((0, 232), (16, 8)), #vertical "hook3": ((16, 232), (8, 8)), #chainlink "hook4": ((24, 224), (8, 16)), #horizontal "boomerang": ((32, 224), (16, 16)), #NE "bow0": ((0, 256), (8, 16)), "bow1": ((16, 256), (16, 8)), "bow2": ((32, 256), (16, 16)), "shovel0": ((0, 272), (8, 8)), #down "shovel1": ((16, 272), (8, 8)), #up "swagduck0": ((32, 272), (16, 16)), "swagduck1": ((48, 272), (16, 16)), #flap "bed0": ((0, 288), (32, 32)), "bed1": ((32, 288), (32, 32)), "tall_grass0": ((0, 320), (16, 8)), "tall_grass1": ((0, 328), (16, 8)), "tall_grass2": ((16, 320), (16, 8)) } #add more inventory stuff for key in inventory: origin, dims = inventory[key] icon_specs[key] = coord_calc(origin, dims) #add bugnet for i in range(7): icon_specs["bugnet" + str(i)] = coord_calc((i * 16, 240), (16, 16)) #cycle through collected icons and write to disk for icon in icon_specs: icon_coords = icon_specs.get(icon) cropped_image = equipment_image.crop(icon_coords) equipment[icon] = cropped_image if save: cropped_image.save( os.path.join(".", "resources", "user", "snes", "zelda3", "link", "sheets") + icon + ".png") return equipment