def update_content(self, configuration: BaseConfiguration, all_patches: dict[int, GamePatches], players: PlayersConfiguration): self.tree_widget.clear() self.tree_widget.setColumnCount(2) self.tree_widget.setHeaderLabels(["Source", "Destination"]) world_list = filtered_database.game_description_for_layout(configuration).world_list patches = all_patches[players.player_index] per_world: dict[str, dict[str, str]] = collections.defaultdict(dict) for source, destination_loc in patches.all_elevator_connections(): source_world = world_list.world_by_area_location(source.identifier.area_identifier) source_name = elevators.get_elevator_or_area_name(self.game_enum, world_list, source.identifier.area_identifier, True) per_world[source_world.name][source_name] = elevators.get_elevator_or_area_name(self.game_enum, world_list, destination_loc, True) for world_name, world_contents in iterate_key_sorted(per_world): world_item = QtWidgets.QTreeWidgetItem(self.tree_widget) world_item.setText(0, world_name) world_item.setExpanded(True) for source_name, destination in iterate_key_sorted(world_contents): area_item = QtWidgets.QTreeWidgetItem(world_item) area_item.setText(0, source_name) area_item.setText(1, destination) self.tree_widget.resizeColumnToContents(0) self.tree_widget.resizeColumnToContents(1)
def _create_check_for_source_elevator(self, location: NodeIdentifier): name = elevators.get_elevator_or_area_name( self.game_enum, self.game_description.world_list, location.area_location, True) check = QtWidgets.QCheckBox(self.elevators_source_group) check.setText(name) check.area_location = location signal_handling.on_checked( check, functools.partial(self._on_elevator_source_check_changed, location)) return check
def _create_elevator_scan_port_patches( game: RandovaniaGame, world_list: WorldList, get_elevator_connection_for: Callable[[TeleporterNode], AreaIdentifier], ) -> Iterator[dict]: for node in _get_nodes_by_teleporter_id(world_list): if node.extra.get("scan_asset_id") is None: continue target_area_name = elevators.get_elevator_or_area_name( game, world_list, get_elevator_connection_for(node), True) yield { "asset_id": node.extra["scan_asset_id"], "strings": [ f"Access to &push;&main-color=#FF3333;{target_area_name}&pop; granted.", "" ], }
def _pretty_name_for_elevator( game: RandovaniaGame, world_list: WorldList, original_teleporter_node: TeleporterNode, connection: AreaIdentifier, ) -> str: """ Calculates the name the room that contains this elevator should have :param world_list: :param original_teleporter_node: :param connection: :return: """ if original_teleporter_node.keep_name_when_vanilla: if original_teleporter_node.default_connection == connection: return world_list.nodes_to_area(original_teleporter_node).name return "Transport to {}".format( elevators.get_elevator_or_area_name(game, world_list, connection, False))
def _create_elevator_scan_port_patches( game: RandovaniaGame, world_list: WorldList, elevator_connection: ElevatorConnection, ) -> Iterator[dict]: nodes_by_teleporter_id = _get_nodes_by_teleporter_id(world_list) for teleporter, node in nodes_by_teleporter_id.items(): if node.extra.get("scan_asset_id") is None: continue target_area_name = elevators.get_elevator_or_area_name( game, world_list, elevator_connection[teleporter], True) yield { "asset_id": node.extra["scan_asset_id"], "strings": [ f"Access to &push;&main-color=#FF3333;{target_area_name}&pop; granted.", "" ], }
def current_state_report(self) -> str: state = UncollectedState.from_reach(self.reach) pickups_by_name_and_quantity = collections.defaultdict(int) _KEY_MATCH = re.compile(r"Key (\d+)") for pickup in self.pickups_left: pickups_by_name_and_quantity[_KEY_MATCH.sub("Key", pickup.name)] += 1 to_progress = { _KEY_MATCH.sub("Key", resource.long_name) for resource in interesting_resources_for_reach(self.reach) if resource.resource_type == ResourceType.ITEM } wl = self.reach.game.world_list s = self.reach.state paths_to_be_opened = set() for node, requirement in self.reach.unreachable_nodes_with_requirements( ).items(): for alternative in requirement.alternatives: if any(r.negate or ( r.resource.resource_type != ResourceType.ITEM and not r.satisfied(s.resources, s.energy, self.game.resource_database)) for r in alternative.values()): continue paths_to_be_opened.add("* {}: {}".format( wl.node_name(node, with_world=True), " and ".join( sorted( r.pretty_text for r in alternative.values() if not r.satisfied(s.resources, s.energy, self.game.resource_database))))) teleporters = [] for node in wl.iterate_nodes(): if isinstance( node, TeleporterNode) and self.reach.is_reachable_node(node): other = wl.resolve_teleporter_node(node, s.patches) teleporters.append("* {} to {}".format( elevators.get_elevator_or_area_name( self.game.game, wl, wl.identifier_for_node(node).area_location, True), elevators.get_elevator_or_area_name( self.game.game, wl, wl.identifier_for_node(other).area_location, True) if other is not None else "<Not connected>", )) accessible_nodes = [ wl.node_name(n, with_world=True) for n in self.reach.iterate_nodes if self.reach.is_reachable_node(n) ] return ( "At {0} after {1} actions and {2} pickups, with {3} collected locations, {7} safe nodes.\n\n" "Pickups still available: {4}\n\n" "Resources to progress: {5}\n\n" "Paths to be opened:\n{8}\n\n" "Accessible teleporters:\n{9}\n\n" "Reachable nodes:\n{6}").format( self.game.world_list.node_name(self.reach.state.node, with_world=True, distinguish_dark_aether=True), self.num_actions, self.num_assigned_pickups, len(state.indices), ", ".join(name if quantity == 1 else f"{name} x{quantity}" for name, quantity in sorted( pickups_by_name_and_quantity.items())), ", ".join(sorted(to_progress)), "\n".join(accessible_nodes) if len(accessible_nodes) < 15 else f"{len(accessible_nodes)} nodes total", sum(1 for n in self.reach.iterate_nodes if self.reach.is_safe_node(n)), "\n".join(sorted(paths_to_be_opened)) or "None", "\n".join(teleporters) or "None", )