def read_node(self, name: str, data: Dict) -> Node: try: location = None if data["coordinates"] is not None: location = location_from_json(data["coordinates"]) generic_args = { "identifier": NodeIdentifier.create(self.current_world_name, self.current_area_name, name), "heal": data["heal"], "location": location, "description": data["description"], "layers": tuple(data["layers"]), "extra": frozen_lib.wrap(data["extra"]), } node_type: int = data["node_type"] if node_type == "generic": return GenericNode(**generic_args) elif node_type == "dock": return DockNode( **generic_args, dock_type=self.dock_weakness_database.find_type( data["dock_type"]), default_connection=NodeIdentifier.from_json( data["default_connection"]), default_dock_weakness=self.dock_weakness_database. get_by_weakness( data["dock_type"], data["default_dock_weakness"], ), override_default_open_requirement=read_optional_requirement( data["override_default_open_requirement"], self.resource_database), override_default_lock_requirement=read_optional_requirement( data["override_default_lock_requirement"], self.resource_database), ) elif node_type == "pickup": return PickupNode( **generic_args, pickup_index=PickupIndex(data["pickup_index"]), major_location=data["major_location"], ) elif node_type == "teleporter": return TeleporterNode( **generic_args, default_connection=AreaIdentifier.from_json( data["destination"]), keep_name_when_vanilla=data["keep_name_when_vanilla"], editable=data["editable"], ) elif node_type == "event": return EventNode( **generic_args, event=self.resource_database.get_by_type_and_index( ResourceType.EVENT, data["event_name"])) elif node_type == "configurable_node": return ConfigurableNode(**generic_args, ) elif node_type == "logbook": lore_type = LoreType(data["lore_type"]) if lore_type == LoreType.REQUIRES_ITEM: required_translator = self.resource_database.get_item( data["extra"]["translator"]) else: required_translator = None if lore_type in { LoreType.SPECIFIC_PICKUP, LoreType.SKY_TEMPLE_KEY_HINT }: hint_index = data["extra"]["hint_index"] else: hint_index = None return LogbookNode( **generic_args, string_asset_id=data["string_asset_id"], scan_visor=self._get_scan_visor(), lore_type=lore_type, required_translator=required_translator, hint_index=hint_index, ) elif node_type == "player_ship": return PlayerShipNode( **generic_args, is_unlocked=read_requirement(data["is_unlocked"], self.resource_database), item_to_summon=self._get_command_visor(), ) else: raise Exception(f"Unknown type: {node_type}") except Exception as e: raise Exception(f"In node {name}, got error: {e}")
def apply_previous_state(self, previous_state: Optional[dict]) -> bool: if previous_state is None: return False starting_location = None needs_starting_location = len( self.game_configuration.starting_location.locations) > 1 configurable_nodes = {} try: pickup_name_to_pickup = { pickup.name: pickup for pickup in self._collected_pickups.keys() } quantity_to_change = { pickup_name_to_pickup[pickup_name]: quantity for pickup_name, quantity in previous_state["collected_pickups"].items() } previous_actions = [ self.game_description.world_list.node_by_identifier( NodeIdentifier.from_string(identifier)) for identifier in previous_state["actions"] ] if needs_starting_location: starting_location = AreaIdentifier.from_json( previous_state["starting_location"]) teleporters: Dict[NodeIdentifier, Optional[AreaIdentifier]] = { NodeIdentifier.from_json(item["teleporter"]): (AreaIdentifier.from_json(item["data"]) if item["data"] is not None else None) for item in previous_state["elevators"] } if self.game_configuration.game == RandovaniaGame.METROID_PRIME_ECHOES: configurable_nodes = { NodeIdentifier.from_string(identifier): (LayoutTranslatorRequirement(item) if item is not None else None) for identifier, item in previous_state["configurable_nodes"].items() } except (KeyError, AttributeError): return False self.setup_starting_location(starting_location) for teleporter, area_location in teleporters.items(): combo = self._elevator_id_to_combo[teleporter] if area_location is None: combo.setCurrentIndex(0) continue for i in range(combo.count()): if area_location == combo.itemData(i): combo.setCurrentIndex(i) break for identifier, requirement in configurable_nodes.items(): combo = self._translator_gate_to_combo[identifier] for i in range(combo.count()): if requirement == combo.itemData(i): combo.setCurrentIndex(i) break self.bulk_change_quantity(quantity_to_change) self._add_new_actions(previous_actions) world_list = self.game_description.world_list state = self.state_for_current_configuration() self.focus_on_world(world_list.nodes_to_world(state.node)) self.focus_on_area(world_list.nodes_to_area(state.node)) return True