def valid_targets(self) -> List[AreaIdentifier]: if self.mode == TeleporterShuffleMode.ONE_WAY_ANYTHING: return [ location for location in self.excluded_targets.areas_list(self.game) if location not in self.excluded_targets.locations ] elif self.mode in { TeleporterShuffleMode.ONE_WAY_ELEVATOR, TeleporterShuffleMode.ONE_WAY_ELEVATOR_REPLACEMENT }: world_list = default_database.game_description_for( self.game).world_list result = [] for identifier in self.editable_teleporters: node = world_list.node_by_identifier(identifier) if isinstance(node, TeleporterNode) and node.editable: # Valid destinations must be valid starting areas area = world_list.nodes_to_area(node) if area.valid_starting_location: result.append(identifier.area_identifier) # Hack for Metroid Prime 1, where the scripting for Metroid Prime Lair is dependent on the previous room elif area.name == "Metroid Prime Lair": result.append( AreaIdentifier.from_string( "Impact Crater/Subchamber Five")) return result else: return []
def decode_single(player_index: int, all_pools: Dict[int, PoolResults], game: GameDescription, game_modifications: dict, configuration: BaseConfiguration) -> GamePatches: """ Decodes a dict created by `serialize` back into a GamePatches. :param player_index: :param all_pools: :param game: :param game_modifications: :param configuration: :return: """ world_list = game.world_list weakness_db = game.dock_weakness_database if game_modifications["game"] != game.game.value: raise ValueError( f"Expected '{game.game.value}', got '{game_modifications['game']}'" ) initial_pickup_assignment = all_pools[player_index].assignment # Starting Location starting_location = AreaIdentifier.from_string( game_modifications["starting_location"]) # Initial items starting_items = { find_resource_info_with_long_name(game.resource_database.item, resource_name): quantity for resource_name, quantity in game_modifications["starting_items"].items() } # Elevators elevator_connection: ElevatorConnection = { NodeIdentifier.from_string(source_name): AreaIdentifier.from_string(target_name) for source_name, target_name in game_modifications["teleporters"].items() } # Dock Weakness dock_weakness: dict[NodeIdentifier, DockWeakness] = { NodeIdentifier.from_string(source_name): weakness_db.get_by_weakness( weakness_data["type"], weakness_data["name"], ) for source_name, weakness_data in game_modifications["dock_weakness"].items() } # Configurable Nodes configurable_nodes = { NodeIdentifier.from_string(identifier): data_reader.read_requirement(requirement, game.resource_database) for identifier, requirement in game_modifications["configurable_nodes"].items() } # Pickups target_name_re = re.compile(r"(.*) for Player (\d+)") pickup_assignment: PickupAssignment = {} for world_name, world_data in game_modifications["locations"].items(): for area_node_name, target_name in typing.cast(dict[str, str], world_data).items(): if target_name == _ETM_NAME: continue pickup_name_match = target_name_re.match(target_name) if pickup_name_match is not None: pickup_name = pickup_name_match.group(1) target_player = int(pickup_name_match.group(2)) - 1 else: pickup_name = target_name target_player = 0 node_identifier = NodeIdentifier.create( world_name, *area_node_name.split("/", 1)) node = world_list.node_by_identifier(node_identifier) assert isinstance(node, PickupNode) if node.pickup_index in initial_pickup_assignment: pickup = initial_pickup_assignment[node.pickup_index] if (pickup_name, target_player) != (pickup.name, player_index): raise ValueError( f"{area_node_name} should be vanilla based on configuration" ) elif pickup_name != _ETM_NAME: configuration_item_pool = all_pools[target_player].pickups pickup = _find_pickup_with_name(configuration_item_pool, pickup_name) configuration_item_pool.remove(pickup) else: pickup = None if pickup is not None: pickup_assignment[node.pickup_index] = PickupTarget( pickup, target_player) # Hints hints = {} for identifier_str, hint in game_modifications["hints"].items(): hints[NodeIdentifier.from_string(identifier_str)] = Hint.from_json( hint) return GamePatches( player_index=player_index, configuration=configuration, pickup_assignment=pickup_assignment, # PickupAssignment elevator_connection=elevator_connection, # ElevatorConnection dock_connection={}, # Dict[Tuple[int, int], DockConnection] dock_weakness=dock_weakness, configurable_nodes=configurable_nodes, starting_items=starting_items, # ResourceGainTuple starting_location=starting_location, # AreaIdentifier hints=hints, )