def __init__(self, prop: str, world: "World") -> None: name = f"Has property '{prop}' ?" image = np.array(load_or_create_image(world, prop)) super().__init__(name=name, image=image) self.world = world self.prop = prop
def __init__(self, zone: "Zone", world: "World") -> None: name = f"Is in {zone}?" image = np.array(load_or_create_image(world, zone)) super().__init__(name=name, image=image) self.world = world self.zone = zone self.slot = self.world.zone_id_to_slot[zone.zone_id]
def _add_property_needed(self, graph: OptionGraph, prop: str) -> HasProperty: has_prop = HasProperty(prop, world=self.world) graph.add_node(has_prop) image = np.array(load_or_create_image(self.world, prop)) get_prop = Option(f"Get {prop}", image=image) graph.add_node(get_prop) graph.add_edge(has_prop, get_prop, index=int(False)) return has_prop
def _add_zone_option(self, graph: OptionGraph, zone_id: int) -> IsInZone: zone = self.world.zone_from_id[zone_id] is_in_zone = IsInZone(zone, self.world) graph.add_node(is_in_zone) image = np.array(load_or_create_image(self.world, zone)) reach_zone = Option(f"Reach {zone}", image=image) graph.add_node(reach_zone) graph.add_edge(is_in_zone, reach_zone, index=int(False)) return is_in_zone
def _add_crafting_option( self, graph: OptionGraph, item_id: int, quantity: int ) -> HasItem: item = self.world.item_from_id[item_id] has_item = HasItem(item=item, world=self.world, quantity=quantity) graph.add_node(has_item) image = np.array(load_or_create_image(self.world, item)) get_item = Option(f"Get {item}", image=image) graph.add_node(get_item) graph.add_edge(has_item, get_item, index=int(False)) return has_item
def __init__(self, recipe: "Recipe", world: "World") -> None: name = f"Craft {recipe}" if recipe.outputs is not None: obj = recipe.outputs[0] else: obj = list(recipe.added_properties.keys())[0] image = np.array(load_or_create_image(world, obj)) action = world.action("craft", recipe.recipe_id) super().__init__(action, name=name, image=image) self.recipe = recipe
def __init__(self, item: "Item", world: "World", quantity: int = 1) -> None: name = f"Has {quantity} {item}?" conditon_text = f"{quantity}" if quantity > 1 else "" image = load_or_create_image(world, item, text=conditon_text) super().__init__(name=name, image=np.array(image)) self.world = world self.item = item self.quantity = quantity self.slot = self.world.item_id_to_slot[item.item_id]
def __init__(self, zone: "Zone", world: "World") -> None: name = f"Move to {zone}" image = np.array(load_or_create_image(world, zone)) action = world.action("move", zone.zone_id) super().__init__(action, name=name, image=image) self.zone = zone
def __init__(self, item: "Item", world: "World") -> None: name = f"Search {item}" image = np.array(load_or_create_image(world, item)) action = world.action("get", item.item_id) super().__init__(action, name=name, image=image) self.item = item
def get_requirements_graph(self) -> nx.DiGraph: """Build the world requirements graph. Returns: The world requirements graph as a networkx DiGraph. """ graph = nx.DiGraph() # Add items nodes for i, item in enumerate(self.items): color = "blue" if item in self.foundable_items: color = "green" elif isinstance(item, Tool): color = "cyan" graph.add_node( item.item_id, type="item", color=color, image=np.array(load_or_create_image(self, item)), item_id=item.item_id, label=item.name.capitalize(), ) # Add properties nodes for i, prop in enumerate(self.zone_properties): graph.add_node( prop, type="zone_property", color="orange", prop_id=i, image=np.array(load_or_create_image(self, prop)), label=prop.capitalize(), ) # Add recipes edges def _add_crafts(in_nodes, out_node): for index, node in enumerate(in_nodes): graph.add_edge( node, out_node, type="craft", color=[1, 0, 0, 1], index=index + 1, ) for recipe in self.recipes: in_items_ids = [] if recipe.inputs is not None: in_items_ids = [stack.item_id for stack in recipe.inputs] out_items_ids = [] if recipe.outputs is not None: out_items_ids = [stack.item_id for stack in recipe.outputs] in_props = (list(recipe.needed_properties.keys()) if recipe.needed_properties is not None else []) out_props = (list(recipe.added_properties.keys()) if recipe.needed_properties is not None else []) for out_item in out_items_ids: _add_crafts(in_items_ids + in_props, out_item) for out_prop in out_props: _add_crafts(in_items_ids + in_props, out_prop) # Add required_tools and drops edges for foundable_item in self.foundable_items: need_tool = (foundable_item.required_tools is not None and None not in foundable_item.required_tools) if need_tool: for tool in foundable_item.required_tools: graph.add_edge( tool.item_id, foundable_item.item_id, type="tool_requirement", color=[0, 1, 1, 1], index=0, ) if hasattr(foundable_item, "items_dropped"): for dropped_item in foundable_item.items_dropped: if dropped_item != foundable_item: graph.add_edge( foundable_item.item_id, dropped_item.item_id, type="drop", color=[0, 1, 0, 1], index=0, ) return graph
def make_menus(world: "World", window_shape: tuple): """Build menus for user interface. Args: world: The current world. window_shape: Shape of the window containing menus. """ def add_button( menu: Menu, id_to_action: Dict[str, Any], image: Image, scaling: float, text_width: int, action_type, identificator, padding, ): buffered = BytesIO() image.save(buffered, format="PNG") buffered.seek(0) image = BaseImage(buffered).scale(scaling, scaling) button = menu.add.button( " " * text_width, lambda *args: args, action_type, identificator, padding=padding, ) decorator = button.get_decorator() decorator.add_baseimage(0, 0, image, centered=True) id_to_action[button.get_id()] = (action_type, identificator) id_to_action = {} # Item Menu items_menu_height = int(0.75 * window_shape[1]) items_menu_width = int(0.15 * window_shape[0]) items_menu = Menu( title="Search", height=items_menu_height, width=items_menu_width, keyboard_enabled=False, joystick_enabled=False, position=(0, 0), overflow=(False, True), theme=THEME_BLUE, ) for item in world.searchable_items: add_button( items_menu, id_to_action, image=load_or_create_image(world, item), scaling=0.5, text_width=8, action_type="get", identificator=item.item_id, padding=(12, 0, 12, 0), ) # Recipes Menu recipes_menu_height = window_shape[1] - items_menu_height recipes_menu_width = window_shape[0] recipes_menu = Menu( title="Craft", height=recipes_menu_height, width=recipes_menu_width, keyboard_enabled=False, joystick_enabled=False, rows=1, columns=world.n_recipes, position=(0, 100), overflow=(True, False), column_max_width=int(0.08 * window_shape[0]), theme=THEME_ORANGE, ) for recipe in world.recipes: add_button( recipes_menu, id_to_action, image=load_or_create_image(world, recipe), scaling=0.5, text_width=8, action_type="craft", identificator=recipe.recipe_id, padding=(16, 0, 16, 0), ) # Zones Menu zones_menu_height = items_menu_height zones_menu_width = int(0.20 * window_shape[0]) zones_menu = Menu( title="Move", height=zones_menu_height, width=zones_menu_width, keyboard_enabled=False, joystick_enabled=False, position=(100, 0), overflow=(False, True), theme=THEME_GREEN, ) for zone in world.zones: add_button( zones_menu, id_to_action, image=load_or_create_image(world, zone), scaling=0.2, text_width=19, action_type="move", identificator=zone.zone_id, padding=(26, 0, 26, 0), ) return (items_menu, recipes_menu, zones_menu), id_to_action
def _load_image(self, item_id) -> "Surface": image = load_or_create_image(self.world, self.world.item_from_id[item_id]) image = pilImageToSurface(image) return scale(image, self.shape, 0.09)
def _load_property_image(self, prop: str): image = load_or_create_image(self.world, prop) image = pilImageToSurface(image) return scale(image, self.shape, 0.2)
def _load_zone_image(self, zone_id, window_shape): image = load_or_create_image(self.world, self.world.zone_from_id[zone_id]) image = pilImageToSurface(image) return scale(image, window_shape, 0.25)