示例#1
0
    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 []
示例#2
0
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,
    )