def test_database_collectable(preset_manager, game_enum: RandovaniaGame,
                              ignore_events: set[str],
                              ignore_pickups: set[int]):
    game, initial_state, permalink = run_bootstrap(
        preset_manager.default_preset_for_game(game_enum).get_preset())
    all_pickups = set(
        reach_lib.filter_pickup_nodes(game.world_list.iterate_nodes()))
    pool_results = pool_creator.calculate_pool_results(
        permalink.get_preset(0).configuration, game.resource_database)

    initial_state.resources.add_resource_gain(
        pool_results.initial_resources.as_resource_gain())
    for pickup in pool_results.pickups:
        add_pickup_to_state(initial_state, pickup)
    for pickup in pool_results.assignment.values():
        add_pickup_to_state(initial_state, pickup)
    for trick in game.resource_database.trick:
        initial_state.resources.set_resource(
            trick,
            LayoutTrickLevel.maximum().as_number)

    expected_events = sorted([
        event for event in game.resource_database.event
        if event.short_name not in ignore_events
    ],
                             key=lambda it: it.short_name)
    expected_pickups = sorted(it.pickup_index for it in all_pickups
                              if it.pickup_index.index not in ignore_pickups)

    reach = _create_reach_with_unsafe(game, initial_state.heal())
    while list(reach_lib.collectable_resource_nodes(reach.nodes, reach)):
        reach.act_on(
            next(iter(reach_lib.collectable_resource_nodes(reach.nodes,
                                                           reach))))
        reach = advance_reach_with_possible_unsafe_resources(reach)

    # print("\nCurrent reach:")
    # print(game.world_list.node_name(reach.state.node, with_world=True))
    # for world in game.world_list.worlds:
    #     print(f"\n>> {world.name}")
    #     for node in world.all_nodes:
    #         print("[{!s:>5}, {!s:>5}, {!s:>5}] {}".format(
    #             reach.is_reachable_node(node), reach.is_safe_node(node),
    #             reach.state.resources.get(node.resource(), 0) > 0
    #             if isinstance(node, ResourceNode) else "",
    #             game.world_list.node_name(node, with_world=True)))

    collected_indices = set(reach.state.collected_pickup_indices)
    collected_events = {
        resource
        for resource, quantity in reach.state.resources.as_resource_gain()
        if quantity > 0 and resource.resource_type == ResourceType.EVENT
    }
    assert list(reach_lib.collectable_resource_nodes(reach.nodes, reach)) == []
    assert sorted(collected_indices) == expected_pickups
    assert sorted(collected_events,
                  key=lambda it: it.short_name) == expected_events
示例#2
0
def additional_starting_items(layout_configuration: LayoutConfiguration,
                              resource_database: ResourceDatabase,
                              starting_items: CurrentResources) -> List[str]:
    initial_items = pool_creator.calculate_pool_results(layout_configuration, resource_database)[2]

    return [
        "{}{}".format("{} ".format(quantity) if quantity > 1 else "", _resource_user_friendly_name(item))
        for item, quantity in starting_items.items()
        if 0 < quantity != initial_items.get(item, 0)
    ]
def test_decode(patches_with_data, default_layout_configuration):
    encoded, expected = patches_with_data

    game = data_reader.decode_data(default_layout_configuration.game_data)
    pool = pool_creator.calculate_pool_results(default_layout_configuration, game.resource_database)

    # Run
    decoded = game_patches_serializer.decode_single(0, {0: pool}, game, encoded, default_layout_configuration)

    # Assert
    assert decoded == expected
示例#4
0
def test_cs_item_pool_creator(default_cs_configuration: CSConfiguration,
                              puppies, starting_area):
    game_description = default_database.game_description_for(
        default_cs_configuration.game)
    default_cs_configuration = dataclasses.replace(default_cs_configuration,
                                                   puppies_anywhere=puppies)
    tricks = default_cs_configuration.trick_level.set_level_for_trick(
        game_description.resource_database.get_by_type_and_index(
            ResourceType.TRICK, "SNBubbler"), LayoutTrickLevel.HYPERMODE)
    tricks = tricks.set_level_for_trick(
        game_description.resource_database.get_by_type_and_index(
            ResourceType.TRICK, "SNMissiles"), LayoutTrickLevel.HYPERMODE)
    default_cs_configuration = dataclasses.replace(default_cs_configuration,
                                                   trick_level=tricks)

    base_patches = GamePatches(0, default_cs_configuration, {}, {}, {}, {}, {},
                               {}, starting_area, {})
    rng = Random()

    result = pool_creator.calculate_pool_results(
        default_cs_configuration, game_description.resource_database,
        base_patches, rng)

    # Puppies
    expected_puppies = {"Hajime", "Nene", "Mick", "Shinobu", "Kakeru"}
    names = {pickup.name for pickup in result.assignment.values()}

    assert puppies != names.issuperset(expected_puppies)

    # First Cave Weapon
    first_cave_assignment = [
        pickup for index, pickup in result.assignment.items()
        if index in FIRST_CAVE_INDICES
    ]
    expected_first_cave_len = 1 if starting_area.area_name == "Start Point" else 0

    assert len(first_cave_assignment) == expected_first_cave_len
    assert starting_area.area_name != "Start Point" or first_cave_assignment[
        0].broad_category.name in {"weapon", "missile_related"}

    # Camp weapon/life capsule
    camp_assignment = [
        pickup for index, pickup in result.assignment.items()
        if index in CAMP_INDICES
    ]

    if starting_area.area_name != "Camp":
        assert len(camp_assignment) == 0
    else:
        expected_names = set(STRONG_WEAPONS)
        expected_names.add("5HP Life Capsule")
        for pickup in camp_assignment:
            assert pickup.name in expected_names
def decode(game_modifications: List[dict],
           layout_configurations: Dict[int, EchoesConfiguration],
           ) -> Dict[int, GamePatches]:

    all_games = {index: data_reader.decode_data(configuration.game_data)
                 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)
    }
示例#6
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,
    )
示例#7
0
def additional_starting_items(layout_configuration: BaseConfiguration,
                              resource_database: ResourceDatabase,
                              starting_items: CurrentResources) -> List[str]:
    initial_items = calculate_pool_results(layout_configuration,
                                           resource_database)[2]

    return [
        add_quantity_to_resource(resource_user_friendly_name(item), quantity)
        for item, quantity in sorted(
            starting_items.items(),
            key=lambda a: resource_user_friendly_name(a[0]))
        if 0 < quantity != initial_items.get(item, 0)
    ]
示例#8
0
def additional_starting_items(layout_configuration: BaseConfiguration,
                              resource_database: ResourceDatabase,
                              starting_items: ResourceCollection) -> List[str]:
    initial_items = calculate_pool_results(layout_configuration,
                                           resource_database).initial_resources

    return [
        add_quantity_to_resource(resource_user_friendly_name(item), quantity)
        for item, quantity in sorted(
            starting_items.as_resource_gain(),
            key=lambda a: resource_user_friendly_name(a[0]))
        if 0 < quantity != initial_items[item]
    ]
示例#9
0
def test_database_collectable(preset_manager, preset_name, ignore_events,
                              ignore_pickups):
    game, initial_state, permalink = run_bootstrap(
        preset_manager.preset_for_name(preset_name).get_preset())
    all_pickups = set(filter_pickup_nodes(game.world_list.all_nodes))
    pool_results = pool_creator.calculate_pool_results(
        permalink.get_preset(0).configuration, game.resource_database)
    add_resources_into_another(initial_state.resources,
                               pool_results.initial_resources)
    for pickup in pool_results.pickups:
        add_pickup_to_state(initial_state, pickup)
    for pickup in pool_results.assignment.values():
        add_pickup_to_state(initial_state, pickup)
    for trick in game.resource_database.trick:
        initial_state.resources[trick] = LayoutTrickLevel.HYPERMODE.as_number

    expected_events = [
        event for event in game.resource_database.event
        if event.index not in ignore_events
    ]
    expected_pickups = sorted(it.pickup_index for it in all_pickups
                              if it.pickup_index.index not in ignore_pickups)

    reach = _create_reach_with_unsafe(game, initial_state.heal())
    while list(collectable_resource_nodes(reach.nodes, reach)):
        reach.act_on(next(iter(collectable_resource_nodes(reach.nodes,
                                                          reach))))
        reach = advance_reach_with_possible_unsafe_resources(reach)

    # print("\nCurrent reach:")
    # for world in game.world_list.worlds:
    #     print(f"\n>> {world.name}")
    #     for node in world.all_nodes:
    #         print("[{!s:>5}, {!s:>5}, {!s:>5}] {}".format(
    #             reach.is_reachable_node(node), reach.is_safe_node(node),
    #             reach.state.resources.get(node.resource(), 0) > 0 if isinstance(node, ResourceNode) else "",
    #             game.world_list.node_name(node)))

    collected_indices = {
        resource
        for resource, quantity in reach.state.resources.items()
        if quantity > 0 and isinstance(resource, PickupIndex)
    }
    collected_events = {
        resource
        for resource, quantity in reach.state.resources.items()
        if quantity > 0 and resource.resource_type == ResourceType.EVENT
    }
    assert list(collectable_resource_nodes(reach.nodes, reach)) == []
    assert sorted(collected_indices) == expected_pickups
    assert sorted(collected_events, key=lambda it: it.index) == expected_events
def test_create_pickup_all_from_pool(echoes_resource_database,
                                     default_layout_configuration,
                                     disable_hud_popup: bool):
    item_pool = pool_creator.calculate_pool_results(
        default_layout_configuration, echoes_resource_database)
    index = PickupIndex(0)
    if disable_hud_popup:
        memo_data = patcher_file._SimplifiedMemo()
    else:
        memo_data = default_prime2_memo_data()
    creator = patcher_file.PickupCreatorSolo(MagicMock(), memo_data)

    for item in item_pool.pickups:
        creator.create_pickup(index, PickupTarget(item, 0), item,
                              PickupModelStyle.ALL_VISIBLE)
示例#11
0
def test_decode(patches_with_data, default_echoes_configuration):
    encoded, expected = patches_with_data

    game = expected.game
    pool = pool_creator.calculate_pool_results(default_echoes_configuration,
                                               game.resource_database)

    # Run
    decoded = game_patches_serializer.decode_single(
        0, {0: pool}, game, encoded, default_echoes_configuration)

    # Assert
    assert set(decoded.all_elevator_connections()) == set(
        expected.all_elevator_connections())
    assert decoded == expected
示例#12
0
def test_create_pickup_all_from_pool(echoes_resource_database,
                                     disable_hud_popup: bool
                                     ):
    layout_configuration = LayoutConfiguration.from_params()
    item_pool = pool_creator.calculate_pool_results(layout_configuration, echoes_resource_database)[0]
    index = PickupIndex(0)
    if disable_hud_popup:
        memo_data = None
    else:
        memo_data = default_prime2_memo_data()

    for item in item_pool:
        try:
            patcher_file._create_pickup(index, item, item, PickupModelStyle.ALL_VISIBLE, memo_data)
        except Exception as e:
            assert str(e) == item.name
示例#13
0
def test_create_pickup_all_from_pool(echoes_resource_database,
                                     default_layout_configuration,
                                     disable_hud_popup: bool):
    item_pool = pool_creator.calculate_pool_results(
        default_layout_configuration, echoes_resource_database)
    index = PickupIndex(0)
    if disable_hud_popup:
        memo_data = claris_patcher_file._simplified_memo_data()
    else:
        memo_data = default_prime2_memo_data()
    creator = pickup_exporter.PickupExporterSolo(memo_data)

    for item in item_pool.pickups:
        data = creator.export(index, PickupTarget(item, 0), item,
                              PickupModelStyle.ALL_VISIBLE)
        for hud_text in data.hud_text:
            assert not hud_text.startswith("Locked")
示例#14
0
def test_decode(patches_with_data, default_echoes_configuration):
    encoded, expected = patches_with_data

    data = default_data.read_json_then_binary(
        default_echoes_configuration.game)[1]

    game = data_reader.decode_data(data)
    pool = pool_creator.calculate_pool_results(default_echoes_configuration,
                                               game.resource_database)

    # Run
    decoded = game_patches_serializer.decode_single(
        0, {0: pool}, game, encoded, default_echoes_configuration)

    # Assert
    assert decoded.elevator_connection == expected.elevator_connection
    assert decoded == expected
示例#15
0
def _create_starting_popup(layout_configuration: LayoutConfiguration,
                           resource_database: ResourceDatabase,
                           starting_items: CurrentResources) -> list:

    initial_items = pool_creator.calculate_pool_results(
        layout_configuration, resource_database)[2]

    extra_items = [
        "{}{}".format("{} ".format(quantity) if quantity > 1 else "",
                      _resource_user_friendly_name(item))
        for item, quantity in starting_items.items()
        if 0 < quantity != initial_items.get(item, 0)
    ]

    if extra_items:
        return ["Extra starting items:", ", ".join(extra_items)]
    else:
        return []
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)
    }
示例#17
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,
    )
示例#18
0
def create_player_pool(rng: Random, configuration: EchoesConfiguration,
                       player_index: int, num_players: int) -> PlayerPool:
    game = default_database.game_description_for(configuration.game)
    base_patches = base_patches_factory.create_base_patches(configuration, rng, game, num_players > 1,
                                                            player_index=player_index)

    item_pool, pickup_assignment, initial_items = pool_creator.calculate_pool_results(configuration,
                                                                                      game.resource_database)
    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,
        configuration=configuration,
        patches=patches,
        pickups=item_pool,
    )
示例#19
0
def create_player_pool(rng: Random, configuration: LayoutConfiguration, player_index: int) -> PlayerPool:
    game = data_reader.decode_data(configuration.game_data)

    base_patches = dataclasses.replace(base_patches_factory.create_base_patches(configuration, rng, game),
                                       player_index=player_index)

    item_pool, pickup_assignment, initial_items = pool_creator.calculate_pool_results(configuration,
                                                                                      game.resource_database)
    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,
        configuration=configuration,
        patches=patches,
        pickups=item_pool,
    )
示例#20
0
def test_calculate_reach_with_all_pickups(test_data):
    game, state, permalink = test_data

    pool_results = pool_creator.calculate_pool_results(
        permalink.get_preset(0).layout_configuration, game.resource_database)
    add_resources_into_another(state.resources, pool_results.initial_resources)
    for pickup in pool_results.pickups:
        add_pickup_to_state(state, pickup)
    for pickup in pool_results.assignment.values():
        add_pickup_to_state(state, pickup)

    first_reach, second_reach = _create_reaches_and_compare(game, state)
    first_actions, second_actions = _compare_actions(first_reach, second_reach)

    found_pickups = set(
        filter_pickup_nodes(filter_reachable(second_reach.nodes, first_reach)))
    all_pickups = set(filter_pickup_nodes(game.world_list.all_nodes))

    # assert (len(list(first_reach.nodes)), len(first_actions)) == (898, 9)
    # assert (len(list(second_reach.nodes)), len(second_actions)) == (898, 9)
    pprint.pprint(first_actions)
    assert all_pickups == found_pickups
示例#21
0
    def on_preset_changed(self, preset: Preset):
        # Item alternatives
        layout = preset.configuration
        major_configuration = layout.major_items_configuration

        for progressive_widget in self._progressive_widgets:
            progressive_widget.on_preset_changed(
                preset,
                self._boxes_for_category[
                    progressive_widget.progressive_item.item_category][2],
            )

        for split_ammo in self._split_ammo_widgets:
            split_ammo.on_preset_changed(preset, self._ammo_pickup_widgets)

        # Random Starting Items
        self.minimum_starting_spinbox.setValue(
            major_configuration.minimum_random_starting_items)
        self.maximum_starting_spinbox.setValue(
            major_configuration.maximum_random_starting_items)

        # Default Items
        for category, default_item in major_configuration.default_items.items(
        ):
            combo = self._default_items[category]
            combo.setCurrentIndex(combo.findData(default_item))

            for item, widget in self._boxes_for_category[category][2].items():
                widget.setEnabled(default_item != item)

        # Major Items
        for _, _, elements in self._boxes_for_category.values():
            for major_item, widget in elements.items():
                widget.state = major_configuration.items_state[major_item]

        # Energy Tank
        energy_tank_state = major_configuration.items_state[
            self._energy_tank_item]
        self.energy_tank_starting_spinbox.setValue(
            energy_tank_state.num_included_in_starting_items)
        self.energy_tank_shuffled_spinbox.setValue(
            energy_tank_state.num_shuffled_pickups)

        # Ammo
        ammo_provided = major_configuration.calculate_provided_ammo()
        ammo_configuration = layout.ammo_configuration

        for ammo_item, maximum in ammo_configuration.maximum_ammo.items():
            for spinbox in self._ammo_maximum_spinboxes[ammo_item]:
                spinbox.setValue(maximum)

        previous_pickup_for_item = {}
        resource_database = self.game_description.resource_database

        item_for_index: Dict[int, ItemResourceInfo] = {
            ammo_index: resource_database.get_item(ammo_index)
            for ammo_index in ammo_provided.keys()
        }

        for ammo, state in ammo_configuration.items_state.items():
            widgets = self._ammo_pickup_widgets[ammo]
            widgets.pickup_spinbox.setValue(state.pickup_count)

            if widgets.require_major_item_check is not None:
                widgets.require_major_item_check.setChecked(
                    state.requires_major_item)

            try:
                if state.pickup_count == 0:
                    widgets.expected_count.setText(
                        "No expansions will be created.")
                    continue

                ammo_per_pickup = items_for_ammo(
                    ammo, state, ammo_provided, previous_pickup_for_item,
                    ammo_configuration.maximum_ammo)

                totals = functools.reduce(
                    lambda a, b: [x + y for x, y in zip(a, b)],
                    ammo_per_pickup, [0 for _ in ammo.items])

                if {total % state.pickup_count for total in totals} == {0}:
                    count_text_template = _EXPECTED_COUNT_TEXT_TEMPLATE_EXACT
                else:
                    count_text_template = _EXPECTED_COUNT_TEXT_TEMPLATE

                widgets.expected_count.setText(
                    count_text_template.format(
                        per_expansion=" and ".join(
                            "{:.3g} {}".format(
                                total / state.pickup_count,
                                item_for_index[ammo_index].long_name)
                            for ammo_index, total in zip(ammo.items, totals)),
                        total=" and ".join(
                            "{} {}".format(
                                total, item_for_index[ammo_index].long_name)
                            for ammo_index, total in zip(ammo.items, totals)),
                        from_items=" and ".join("{} {}".format(
                            ammo_provided[ammo_index],
                            item_for_index[ammo_index].long_name)
                                                for ammo_index in ammo.items),
                    ))

            except InvalidConfiguration as invalid_config:
                widgets.expected_count.setText(str(invalid_config))

        # Item pool count
        try:
            pool_pickup = pool_creator.calculate_pool_results(
                layout, resource_database).pickups
            min_starting_items = layout.major_items_configuration.minimum_random_starting_items
            maximum_size = self.game_description.world_list.num_pickup_nodes + min_starting_items
            self.item_pool_count_label.setText("Items in pool: {}/{}".format(
                len(pool_pickup), maximum_size))
            common_qt_lib.set_error_border_stylesheet(
                self.item_pool_count_label,
                len(pool_pickup) > maximum_size)

        except InvalidConfiguration as invalid_config:
            self.item_pool_count_label.setText(
                "Invalid Configuration: {}".format(invalid_config))
            common_qt_lib.set_error_border_stylesheet(
                self.item_pool_count_label, True)