Esempio n. 1
0
    def add_elevator_connections_to_patches(self, configuration: EchoesConfiguration, rng: Random,
                                            patches: GamePatches) -> GamePatches:
        elevator_connection = copy.copy(patches.elevator_connection)
        elevators = configuration.elevators

        if not elevators.is_vanilla:
            if rng is None:
                raise MissingRng("Elevator")

            world_list = filtered_database.game_description_for_layout(configuration).world_list
            elevator_db = elevator_distributor.create_elevator_database(
                world_list, elevators.editable_teleporters)

            if elevators.mode in {TeleporterShuffleMode.TWO_WAY_RANDOMIZED, TeleporterShuffleMode.TWO_WAY_UNCHECKED}:
                connections = elevator_distributor.two_way_elevator_connections(
                    rng=rng,
                    elevator_database=elevator_db,
                    between_areas=elevators.mode == TeleporterShuffleMode.TWO_WAY_RANDOMIZED
                )
            else:
                connections = elevator_distributor.one_way_elevator_connections(
                    rng=rng,
                    elevator_database=elevator_db,
                    target_locations=elevators.valid_targets,
                    replacement=elevators.mode != TeleporterShuffleMode.ONE_WAY_ELEVATOR,
                )

            elevator_connection.update(connections)

        for teleporter, destination in elevators.static_teleporters.items():
            elevator_connection[teleporter] = destination

        return dataclasses.replace(patches, elevator_connection=elevator_connection)
    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)
Esempio n. 3
0
    def __init__(
        self,
        parent: QWidget,
        window_manager: WindowManager,
        preset: Preset,
    ):

        super().__init__(parent)
        self.setupUi(self)
        set_default_window_icon(self)

        self._window_manager = window_manager
        self._game_description = filtered_database.game_description_for_layout(
            preset.configuration)
        database = self._game_description.resource_database

        trick_level = preset.configuration.trick_level
        if trick_level.minimal_logic:
            trick_usage_description = "Minimal Logic"
        else:
            trick_usage_description = ", ".join(
                sorted(
                    f"{trick.long_name} ({trick_level.level_for_trick(trick).long_name})"
                    for trick in database.trick
                    if trick_level.has_specific_level_for_trick(trick)))

        # setup
        self.area_list_label.linkActivated.connect(
            self._on_click_link_to_data_editor)
        self.setWindowTitle("{} for preset {}".format(self.windowTitle(),
                                                      preset.name))
        self.title_label.setText(self.title_label.text().format(
            trick_levels=trick_usage_description))

        # connect
        self.button_box.accepted.connect(self.button_box_close)
        self.button_box.rejected.connect(self.button_box_close)

        if trick_level.minimal_logic:
            return

        # Update
        trick_resources = self._game_description.game.generator.bootstrap.trick_resources_for_configuration(
            trick_level, database)

        lines = []

        for world in sorted(self._game_description.world_list.worlds,
                            key=lambda it: it.name):
            for area in sorted(world.areas, key=lambda it: it.name):
                used_tricks = _check_used_tricks(area, trick_resources,
                                                 database)
                if used_tricks:
                    lines.append(
                        f'<p><a href="data-editor://{world.correct_name(area.in_dark_aether)}/{area.name}">'
                        f'{world.correct_name(area.in_dark_aether)} - {area.name}</a>'
                        f'<br />{"<br />".join(used_tricks)}</p>')

        self.area_list_label.setText("".join(lines))
Esempio n. 4
0
def test_node_index_multiple_games(default_prime_preset):
    default_config = default_prime_preset.configuration
    assert isinstance(default_config, PrimeConfiguration)
    alt_config = dataclasses.replace(default_config, items_every_room=True)

    alt_game = filtered_database.game_description_for_layout(alt_config)
    default_game = filtered_database.game_description_for_layout(
        default_config)

    all_nodes_default = default_game.world_list.all_nodes
    all_nodes_alt = alt_game.world_list.all_nodes

    for node in alt_game.world_list.iterate_nodes():
        assert all_nodes_alt[node.node_index] is node

    for node in default_game.world_list.iterate_nodes():
        assert all_nodes_default[node.node_index] is node
def serialize_single(player_index: int, num_players: int,
                     patches: GamePatches) -> dict:
    """
    Encodes a given GamePatches into a JSON-serializable dict.
    :param player_index:
    :param num_players:
    :param patches:
    :return:
    """
    game = filtered_database.game_description_for_layout(patches.configuration)
    world_list = game.world_list

    dock_weakness_to_type = {}
    for dock_type, weaknesses in game.dock_weakness_database.weaknesses.items(
    ):
        for weakness in weaknesses.values():
            dock_weakness_to_type[weakness] = dock_type

    result = {
        # This field helps schema migrations, if nothing else
        "game": patches.configuration.game.value,
        "starting_location": patches.starting_location.as_string,
        "starting_items": {
            resource_info.long_name: quantity
            for resource_info, quantity in
            patches.starting_items.as_resource_gain()
        },
        "teleporters": {
            source.identifier.as_string: connection.as_string
            for source, connection in patches.all_elevator_connections()
        },
        "dock_weakness": {
            dock.identifier.as_string: {
                "type": dock_weakness_to_type[weakness].short_name,
                "name": weakness.name,
            }
            for dock, weakness in patches.all_dock_weaknesses()
        },
        "configurable_nodes": {
            identifier.as_string: data_writer.write_requirement(requirement)
            for identifier, requirement in patches.configurable_nodes.items()
        },
        "locations": {
            key: value
            for key, value in _pickup_assignment_to_item_locations(
                world_list, patches.pickup_assignment, num_players).items()
        },
        "hints": {
            identifier.as_string: hint.as_json
            for identifier, hint in patches.hints.items()
        }
    }
    return result
Esempio n. 6
0
    def update_content(self, configuration: BaseConfiguration,
                       all_patches: dict[int, GamePatches],
                       players: PlayersConfiguration):
        self.tree_widget.clear()
        self.tree_widget.setColumnCount(3)
        self.tree_widget.setHeaderLabels(["Hint", "Pickup", "In-Game Text"])

        game = filtered_database.game_description_for_layout(configuration)
        world_list = game.world_list
        patches = all_patches[players.player_index]

        per_world: dict[str, dict[str,
                                  tuple[str,
                                        str]]] = collections.defaultdict(dict)
        namer = DreadHintNamer(all_patches, players)
        exporter = HintExporter(namer, random.Random(0), ["A joke hint."])

        for identifier, hint in patches.hints.items():
            node = game.world_list.node_by_identifier(identifier)
            source_world = world_list.nodes_to_world(node)
            source_name = world_list.node_name(node)

            hint_text = exporter.create_message_for_hint(
                hint, all_patches, players, False)

            # FIXME: tell the room name instead of the pickup name
            if hint.target is None:
                hinted_pickup = ""
            else:
                target = patches.pickup_assignment.get(hint.target)
                if target is None:
                    hinted_pickup = "Nothing"
                else:
                    hinted_pickup = target.pickup.name
                    if players.is_multiworld:
                        hinted_pickup = f"{players.player_names[target.player]}'s {hinted_pickup}"

            per_world[source_world.name][source_name] = (hint_text,
                                                         hinted_pickup)

        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, content in iterate_key_sorted(world_contents):
                area_item = QtWidgets.QTreeWidgetItem(world_item)
                area_item.setText(0, source_name)
                area_item.setText(1, content[1])
                area_item.setText(2, content[0])

        self.tree_widget.resizeColumnToContents(0)
        self.tree_widget.resizeColumnToContents(1)
        self.tree_widget.resizeColumnToContents(3)
Esempio n. 7
0
async def create_player_pool(rng: Random,
                             configuration: BaseConfiguration,
                             player_index: int,
                             num_players: int,
                             rng_required: bool = True) -> PlayerPool:
    game = filtered_database.game_description_for_layout(
        configuration).get_mutable()

    game_generator = game.game.generator
    game.resource_database = game_generator.bootstrap.patch_resource_database(
        game.resource_database, configuration)

    base_patches = game_generator.base_patches_factory.create_base_patches(
        configuration,
        rng,
        game,
        num_players > 1,
        player_index=player_index,
        rng_required=rng_required)

    base_patches = dock_weakness_distributor.distribute_pre_fill_weaknesses(
        base_patches)

    base_patches = await game_generator.hint_distributor.assign_pre_filler_hints(
        base_patches,
        PreFillParams(
            rng,
            configuration,
            game,
            num_players > 1,
        ),
        rng_required=rng_required)

    pool_results = pool_creator.calculate_pool_results(
        configuration,
        game.resource_database,
        base_patches,
        rng,
        rng_required=rng_required)
    target_assignment = [(index, PickupTarget(pickup, player_index))
                         for index, pickup in pool_results.assignment.items()]
    patches = base_patches.assign_new_pickups(
        target_assignment).assign_extra_initial_items(
            pool_results.initial_resources.as_resource_gain())

    return PlayerPool(
        game=game,
        game_generator=game_generator,
        configuration=configuration,
        patches=patches,
        pickups=pool_results.pickups,
    )
    def update_content(self, configuration: BaseConfiguration,
                       all_patches: dict[int, GamePatches],
                       players: PlayersConfiguration):
        patches = all_patches[players.player_index]
        pickup_names = {
            pickup.pickup.name
            for pickup in patches.pickup_assignment.values()
        }
        game_description = filtered_database.game_description_for_layout(
            configuration)
        self._create_pickup_spoilers(game_description)
        starting_area = game_description.world_list.area_by_area_location(
            patches.starting_location)

        extra_items = item_names.additional_starting_items(
            configuration, game_description.resource_database,
            patches.starting_items)

        self.spoiler_starting_location_label.setText(
            "Starting Location: {}".format(
                game_description.world_list.area_name(starting_area)))
        self.spoiler_starting_items_label.setText(
            "Random Starting Items: {}".format(
                ", ".join(extra_items) if extra_items else "None"))
        self._update_show_all_button_state()

        self.pickup_spoiler_pickup_combobox.clear()
        self.pickup_spoiler_pickup_combobox.addItem("None")
        for pickup_name in sorted(pickup_names):
            self.pickup_spoiler_pickup_combobox.addItem(pickup_name)

        for pickup_button in self.pickup_spoiler_buttons:
            pickup_target = patches.pickup_assignment.get(
                pickup_button.pickup_index)

            pickup_button.target_player = None
            if pickup_target is not None:
                pickup_button.item_name = pickup_target.pickup.name
                if players.is_multiworld:
                    pickup_button.target_player = pickup_target.player
                    pickup_button.player_names = players.player_names
            else:
                pickup_button.item_name = "Nothing"

            if not pickup_button.item_is_hidden:
                pickup_button.setText(pickup_button.item_name)
Esempio n. 9
0
def setup_resolver(configuration: BaseConfiguration,
                   patches: GamePatches) -> Tuple[State, Logic]:
    set_attempts(0)

    game = filtered_database.game_description_for_layout(
        configuration).get_mutable()
    bootstrap = game.game.generator.bootstrap

    game.resource_database = bootstrap.patch_resource_database(
        game.resource_database, configuration)

    new_game, starting_state = bootstrap.logic_bootstrap(
        configuration, game, patches)
    logic = Logic(new_game, configuration)
    starting_state.resources.add_self_as_requirement_to_resources = True

    return starting_state, logic
Esempio n. 10
0
    def __init__(self, description: LayoutDescription,
                 players_config: PlayersConfiguration,
                 cosmetic_patches: BaseCosmeticPatches):
        self.description = description
        self.players_config = players_config
        self.cosmetic_patches = cosmetic_patches

        self.item_db = default_database.item_database_for_game(
            self.game_enum())

        self.patches = description.all_patches[players_config.player_index]
        self.configuration = description.get_preset(
            players_config.player_index).configuration
        self.rng = Random(
            description.get_seed_for_player(players_config.player_index))
        self.game = filtered_database.game_description_for_layout(
            self.configuration)
Esempio n. 11
0
def run_bootstrap(preset: Preset):
    game = filtered_database.game_description_for_layout(preset.configuration).get_mutable()
    generator = game.game.generator

    derived_nodes.create_derived_nodes(game)
    game.resource_database = generator.bootstrap.patch_resource_database(game.resource_database,
                                                                         preset.configuration)
    permalink = GeneratorParameters(
        seed_number=15000,
        spoiler=True,
        presets=[preset],
    )
    patches = generator.base_patches_factory.create_base_patches(preset.configuration, Random(15000),
                                                                 game, False, player_index=0)
    _, state = generator.bootstrap.logic_bootstrap(preset.configuration, game, patches)

    return game, state, permalink
Esempio n. 12
0
def calculate_pool_item_count(layout: BaseConfiguration) -> Tuple[int, int]:
    """
    Calculate how many pickups are needed for given layout, with how many spots are there.
    :param layout:
    :return:
    """
    game_description = filtered_database.game_description_for_layout(layout)

    num_pickup_nodes = game_description.world_list.num_pickup_nodes
    pool_pickups, pool_assignment, _ = calculate_pool_results(layout, game_description.resource_database,
                                                              rng_required=False)
    min_starting_items = layout.major_items_configuration.minimum_random_starting_items

    pool_count = len(pool_pickups) + len(pool_assignment)
    maximum_size = num_pickup_nodes + min_starting_items

    return pool_count, maximum_size
def decode(
    game_modifications: List[dict],
    layout_configurations: Dict[int, BaseConfiguration],
) -> Dict[int, GamePatches]:
    all_games = {
        index: filtered_database.game_description_for_layout(configuration)
        for index, configuration in layout_configurations.items()
    }
    all_pools = {
        index:
        pool_creator.calculate_pool_results(configuration,
                                            all_games[index].resource_database)
        for index, configuration in layout_configurations.items()
    }
    return {
        index: decode_single(index, all_pools, all_games[index], modifications,
                             layout_configurations[index])
        for index, modifications in enumerate(game_modifications)
    }
Esempio n. 14
0
async def create_player_pool(rng: Random, configuration: BaseConfiguration,
                             player_index: int, num_players: int, rng_required: bool = True) -> PlayerPool:
    game = filtered_database.game_description_for_layout(configuration).get_mutable()
    derived_nodes.create_derived_nodes(game)

    game_generator = game.game.generator
    game.resource_database = game_generator.bootstrap.patch_resource_database(game.resource_database, configuration)

    base_patches = game_generator.base_patches_factory.create_base_patches(configuration, rng, game,
                                                                           num_players > 1,
                                                                           player_index=player_index,
                                                                           rng_required=rng_required)

    base_patches = await game_generator.hint_distributor.assign_pre_filler_hints(
        base_patches,
        PreFillParams(
            rng,
            configuration,
            game,
            num_players > 1,
        ),
        rng_required=rng_required
    )

    item_pool, pickup_assignment, initial_items = pool_creator.calculate_pool_results(configuration,
                                                                                      game.resource_database,
                                                                                      base_patches,
                                                                                      rng,
                                                                                      rng_required=rng_required)
    target_assignment = {
        index: PickupTarget(pickup, player_index)
        for index, pickup in pickup_assignment.items()
    }
    patches = base_patches.assign_pickup_assignment(target_assignment).assign_extra_initial_items(initial_items)

    return PlayerPool(
        game=game,
        game_generator=game_generator,
        configuration=configuration,
        patches=patches,
        pickups=item_pool,
    )
Esempio n. 15
0
    def create_message_for_hint(
        self,
        hint: Hint,
        all_patches: dict[int, GamePatches],
        players_config: PlayersConfiguration,
        with_color: bool,
    ) -> str:
        patches = all_patches[players_config.player_index]

        if hint.hint_type == HintType.JOKE:
            return self.namer.format_joke(self.create_joke_hint(), with_color)

        elif hint.hint_type == HintType.RED_TEMPLE_KEY_SET:
            return create_temple_key_hint(all_patches,
                                          players_config.player_index,
                                          hint.dark_temple, self.namer,
                                          with_color)

        else:
            assert hint.hint_type == HintType.LOCATION

            configuration = all_patches[
                players_config.player_index].configuration

            pickup_target = patches.pickup_assignment.get(hint.target)
            phint = pickup_hint.create_pickup_hint(
                patches.pickup_assignment,
                filtered_database.game_description_for_layout(
                    configuration).world_list,
                hint.precision.item,
                pickup_target,
                players_config,
                hint.precision.include_owner,
            )
            return self.namer.format_location_hint(
                configuration.game,
                phint,
                hint,
                with_color,
            )
    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(["Gate", "Requirement"])

        game = filtered_database.game_description_for_layout(configuration)
        world_list = game.world_list
        patches = all_patches[players.player_index]

        gate_index_to_name, identifier_to_gate = gate_data()

        resource_db = game.resource_database
        items_by_id = {
            item.extra["item_id"]: item.long_name
            for item in resource_db.item
            if "item_id" in item.extra
        }

        per_world: dict[str, dict[str, str]] = collections.defaultdict(dict)

        for source_loc, requirement in patches.configurable_nodes.items():
            source_world = world_list.world_by_area_location(source_loc.area_identifier)
            source_name = gate_index_to_name[identifier_to_gate[source_loc]]

            index = patch_data_factory.translator_index_for_requirement(requirement)
            per_world[source_world.name][source_name] = items_by_id[index]

        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)
Esempio n. 17
0
async def resolve(
        configuration: BaseConfiguration,
        patches: GamePatches,
        status_update: Optional[Callable[[str],
                                         None]] = None) -> Optional[State]:
    if status_update is None:
        status_update = _quiet_print

    game = filtered_database.game_description_for_layout(
        configuration).get_mutable()
    derived_nodes.create_derived_nodes(game)
    bootstrap = game.game.generator.bootstrap

    game.resource_database = bootstrap.patch_resource_database(
        game.resource_database, configuration)
    event_pickup.replace_with_event_pickups(game)

    new_game, starting_state = bootstrap.logic_bootstrap(
        configuration, game, patches)
    logic = Logic(new_game, configuration)
    starting_state.resources["add_self_as_requirement_to_resources"] = 1
    debug.log_resolve_start()

    return await advance_depth(starting_state, logic, status_update)
Esempio n. 18
0
 def __init__(self, patches: GamePatches, distance_painter: Callable[[str, bool], str]):
     self.world_list = filtered_database.game_description_for_layout(patches.configuration).world_list
     self.patches = patches
     self.distance_painter = distance_painter