Exemple #1
0
 def requirement_to_leave(
         self, patches: GamePatches,
         current_resources: CurrentResources) -> Requirement:
     return RequirementAnd([
         ResourceRequirement(patches.translator_gates[self.gate], 1, False),
         ResourceRequirement(self.scan_visor, 1, False),
     ])
Exemple #2
0
    def configurable_node_assignment(self, configuration: DreadConfiguration, game: GameDescription,
                                     rng: Random) -> NodeConfigurationAssignment:
        result = {}

        rsb = game.resource_database

        requirement_for_type = {
            "POWERBEAM": rsb.requirement_template["Shoot Beam"],
            "BOMB": rsb.requirement_template["Lay Bomb"],
            "MISSILE": rsb.requirement_template["Shoot Missile"],
            "SUPERMISSILE": rsb.requirement_template["Shoot Super Missile"],
            "POWERBOMB": rsb.requirement_template["Lay Power Bomb"],
            "SCREWATTACK": ResourceRequirement(rsb.get_item("Screw"), 1, False),
            "WEIGHT": Requirement.impossible(),
            "SPEEDBOOST": ResourceRequirement(rsb.get_item("Speed"), 1, False),
        }

        for node in game.world_list.all_nodes:
            if not isinstance(node, ConfigurableNode):
                continue

            result[game.world_list.identifier_for_node(node)] = RequirementAnd([
                requirement_for_type[block_type]
                for block_type in node.extra["tile_types"]
            ]).simplify()

        return result
Exemple #3
0
def test_gate_assignment_for_configuration_all_emerald(echoes_game_description, default_echoes_configuration):
    # Setup
    patches_factory = echoes_game_description.game.generator.base_patches_factory
    scan_visor = find_resource_info_with_long_name(echoes_game_description.resource_database.item, "Scan Visor")
    emerald = find_resource_info_with_long_name(echoes_game_description.resource_database.item, "Emerald Translator")

    translator_configuration = default_echoes_configuration.translator_configuration
    configuration = dataclasses.replace(
        default_echoes_configuration,
        translator_configuration=dataclasses.replace(
            translator_configuration,
            translator_requirement={
                key: LayoutTranslatorRequirement.EMERALD
                for key in translator_configuration.translator_requirement.keys()
            }
        )
    )

    rng = MagicMock()

    # Run
    results = patches_factory.configurable_node_assignment(
        configuration, echoes_game_description, rng)

    # Assert
    assert list(results.values()) == [
        RequirementAnd([
            ResourceRequirement(scan_visor, 1, False),
            ResourceRequirement(emerald, 1, False),
        ])
    ] * len(translator_configuration.translator_requirement)
Exemple #4
0
def test_gate_assignment_for_configuration_all_random(echoes_game_description, default_echoes_configuration):
    # Setup
    patches_factory = echoes_game_description.game.generator.base_patches_factory
    scan_visor = find_resource_info_with_long_name(echoes_game_description.resource_database.item, "Scan Visor")
    violet = find_resource_info_with_long_name(echoes_game_description.resource_database.item, "Violet Translator")
    emerald = find_resource_info_with_long_name(echoes_game_description.resource_database.item, "Emerald Translator")

    translator_configuration = default_echoes_configuration.translator_configuration
    configuration = dataclasses.replace(
        default_echoes_configuration,
        translator_configuration=translator_configuration.with_full_random(),
    )

    requirements = [
        RequirementAnd([
            ResourceRequirement(scan_visor, 1, False),
            ResourceRequirement(emerald, 1, False),
        ]),
        RequirementAnd([
            ResourceRequirement(scan_visor, 1, False),
            ResourceRequirement(violet, 1, False),
        ])
    ]
    requirements = requirements * len(translator_configuration.translator_requirement)

    choices = [LayoutTranslatorRequirement.EMERALD, LayoutTranslatorRequirement.VIOLET]
    rng = MagicMock()
    rng.choice.side_effect = choices * len(translator_configuration.translator_requirement)

    # Run
    results = patches_factory.configurable_node_assignment(
        configuration, echoes_game_description, rng)

    # Assert
    assert list(results.values()) == requirements[:len(translator_configuration.translator_requirement)]
Exemple #5
0
    def requirement_to_leave(
            self, patches: GamePatches,
            current_resources: CurrentResources) -> Requirement:
        items = [ResourceRequirement(self.scan_visor, 1, False)]
        if self.required_translator is not None:
            items.append(
                ResourceRequirement(self.required_translator, 1, False))

        return RequirementAnd(items)
Exemple #6
0
 def make_req(item_id: int):
     return RequirementAnd([
         ResourceRequirement(
             ItemResourceInfo("Scan Visor", "Scan", 1, frozendict({"item_id": 9})), 1, False,
         ),
         ResourceRequirement(
             ItemResourceInfo("Other", "Other", 1, frozendict({"item_id": item_id})), 1, False,
         ),
     ])
Exemple #7
0
    def requirement_to_leave(self, context: NodeContext) -> Requirement:
        items = []
        if self.scan_visor is not None:
            items.append(ResourceRequirement(self.scan_visor, 1, False))
        if self.required_translator is not None:
            items.append(
                ResourceRequirement(self.required_translator, 1, False))

        return RequirementAnd(items)
Exemple #8
0
def test_simple_echoes_damage(echoes_resource_database):
    db = echoes_resource_database
    req = ResourceRequirement(
        db.get_by_type_and_index(ResourceType.DAMAGE, "DarkWorld1"),
        50,
        False,
    )
    d_suit = db.get_item_by_name("Dark Suit")
    l_suit = db.get_item_by_name("Light Suit")

    assert req.damage({}, db) == 50
    assert req.damage({d_suit: 1}, db) == 11
    assert req.damage({l_suit: 1}, db) == 0
Exemple #9
0
def test_connections_from_dock_blast_shield(empty_patches):
    # Setup
    trivial = Requirement.trivial()
    req_1 = ResourceRequirement(
        SimpleResourceInfo("Ev1", "Ev1", ResourceType.EVENT), 1, False)
    req_2 = ResourceRequirement(
        SimpleResourceInfo("Ev2", "Ev2", ResourceType.EVENT), 1, False)
    dock_type = DockType("Type", "Type", frozendict())
    weak_1 = DockWeakness("Weak 1", frozendict(), req_1, None)
    weak_2 = DockWeakness("Weak 2", frozendict(), trivial,
                          DockLock(DockLockType.FRONT_BLAST_BACK_BLAST, req_2))

    node_1_identifier = NodeIdentifier.create("W", "Area 1", "Node 1")
    node_2_identifier = NodeIdentifier.create("W", "Area 2", "Node 2")

    node_1 = DockNode(node_1_identifier, False, None, "", ("default", ), {},
                      dock_type, node_2_identifier, weak_1, None, None)
    node_1_lock = DockLockNode.create_from_dock(node_1)
    node_2 = DockNode(node_2_identifier, False, None, "", ("default", ), {},
                      dock_type, node_1_identifier, weak_2, None, None)
    node_2_lock = DockLockNode.create_from_dock(node_2)

    area_1 = Area("Area 1", None, True, [node_1, node_1_lock], {}, {})
    area_2 = Area("Area 2", None, True, [node_2, node_2_lock], {}, {})

    world = World("W", [area_1, area_2], {})
    world_list = WorldList([world])

    context = NodeContext(
        patches=empty_patches,
        current_resources={},
        database=None,
        node_provider=world_list,
    )

    # Run
    result_1 = list(node_1.connections_from(context))
    result_2 = list(node_2.connections_from(context))

    # Assert
    assert result_1 == [
        (node_2,
         RequirementAnd([req_1,
                         ResourceRequirement.simple(node_2_identifier)])),
        (node_1_lock, RequirementAnd([trivial, req_2])),
    ]
    assert result_2 == [
        (node_1, ResourceRequirement.simple(node_2_identifier)),
        (node_2_lock, req_2),
    ]
Exemple #10
0
def test_set_as_str_things(echoes_resource_database):
    item = echoes_resource_database.get_item_by_name

    req_set = RequirementSet([
        RequirementList([
            ResourceRequirement(item("Screw Attack"), 1, False),
            ResourceRequirement(item("Space Jump Boots"), 1, False),
        ]),
        RequirementList([
            ResourceRequirement(item("Power Bomb"), 1, False),
        ]),
    ])

    assert req_set.as_str == "(Power Bomb ≥ 1) or (Screw Attack ≥ 1, Space Jump Boots ≥ 1)"
Exemple #11
0
    def configurable_node_assignment(
            self, configuration: EchoesConfiguration, game: GameDescription,
            rng: Random) -> NodeConfigurationAssignment:
        """
        :param configuration:
        :param game:
        :param rng:
        :return:
        """

        all_choices = list(LayoutTranslatorRequirement)
        all_choices.remove(LayoutTranslatorRequirement.RANDOM)
        all_choices.remove(LayoutTranslatorRequirement.RANDOM_WITH_REMOVED)
        without_removed = copy.copy(all_choices)
        without_removed.remove(LayoutTranslatorRequirement.REMOVED)
        random_requirements = {
            LayoutTranslatorRequirement.RANDOM,
            LayoutTranslatorRequirement.RANDOM_WITH_REMOVED
        }

        result = {}

        scan_visor = search.find_resource_info_with_long_name(
            game.resource_database.item, "Scan Visor")
        scan_visor_req = ResourceRequirement(scan_visor, 1, False)

        for node in game.world_list.all_nodes:
            if not isinstance(node, ConfigurableNode):
                continue

            identifier = game.world_list.identifier_for_node(node)
            requirement = configuration.translator_configuration.translator_requirement[
                identifier]
            if requirement in random_requirements:
                if rng is None:
                    raise MissingRng("Translator")
                requirement = rng.choice(
                    all_choices if requirement == LayoutTranslatorRequirement.
                    RANDOM_WITH_REMOVED else without_removed)

            translator = game.resource_database.get_by_type_and_index(
                ResourceType.ITEM, requirement.item_name)
            result[identifier] = RequirementAnd([
                scan_visor_req,
                ResourceRequirement(translator, 1, False),
            ])

        return result
Exemple #12
0
 def requirement_to_leave(
         self, patches: GamePatches,
         current_resources: CurrentResources) -> Requirement:
     if current_resources.get("add_self_as_requirement_to_resources") == 1:
         return ResourceRequirement(self.event, 1, False)
     else:
         return Requirement.trivial()
Exemple #13
0
    def patch_resource_database(
            self, db: ResourceDatabase,
            configuration: BaseConfiguration) -> ResourceDatabase:
        base_damage_reduction = db.base_damage_reduction
        damage_reductions = copy.copy(db.damage_reductions)
        requirement_template = copy.copy(db.requirement_template)

        suits = [db.get_item_by_name("Varia Suit")]
        if configuration.heat_protection_only_varia:
            requirement_template["Heat-Resisting Suit"] = ResourceRequirement(
                db.get_item_by_name("Varia Suit"), 1, False)
        else:
            suits.extend([
                db.get_item_by_name("Gravity Suit"),
                db.get_item_by_name("Phazon Suit")
            ])

        reductions = [DamageReduction(None, configuration.heat_damage / 10.0)]
        reductions.extend([DamageReduction(suit, 0) for suit in suits])
        damage_reductions[db.get_by_type_and_index(ResourceType.DAMAGE,
                                                   "HeatDamage1")] = reductions

        if configuration.progressive_damage_reduction:
            base_damage_reduction = self.prime1_progressive_damage_reduction
        else:
            base_damage_reduction = self.prime1_absolute_damage_reduction

        return dataclasses.replace(db,
                                   damage_reductions=damage_reductions,
                                   base_damage_reduction=base_damage_reduction,
                                   requirement_template=requirement_template)
Exemple #14
0
def read_resource_requirement(data: Dict, resource_database: ResourceDatabase
                              ) -> ResourceRequirement:
    data = data["data"]
    return ResourceRequirement.with_data(
        resource_database,
        ResourceType(data["type"]), data["index"],
        data["amount"], data["negate"])
Exemple #15
0
 def requirement_to_leave(self, context: NodeContext) -> Requirement:
     # FIXME: using non-resource as key in CurrentResources
     if context.current_resources.get(
             "add_self_as_requirement_to_resources") == 1:
         return ResourceRequirement(self.pickup_index, 1, False)
     else:
         return Requirement.trivial()
Exemple #16
0
def test_node_identifier_as_requirement():
    nic = NodeIdentifier.create
    req = ResourceRequirement.simple(nic("W", "A", "N"))
    db = typing.cast(ResourceDatabase, None)

    assert not req.satisfied({}, 0, db)
    assert req.satisfied({nic("W", "A", "N"): 1}, 0, db)
Exemple #17
0
def test_requirement_list_constructor(echoes_resource_database):
    def item(name):
        return search.find_resource_info_with_long_name(
            echoes_resource_database.item, name)

    req_list = RequirementList([
        ResourceRequirement(item("Dark Visor"), 1, False),
        ResourceRequirement(item("Missile"), 5, False),
        ResourceRequirement(item("Seeker Launcher"), 1, False),
    ])
    extract = [(req.resource.long_name, req.amount) for req in req_list.items]

    assert sorted(extract) == [
        ("Dark Visor", 1),
        ("Missile", 5),
        ("Seeker Launcher", 1),
    ]
Exemple #18
0
 def requirement_to_leave(
         self, patches: GamePatches,
         current_resources: CurrentResources) -> Requirement:
     # FIXME: using non-resource as key in CurrentResources
     if current_resources.get("add_self_as_requirement_to_resources") == 1:
         return ResourceRequirement(self.pickup_index, 1, False)
     else:
         return Requirement.trivial()
Exemple #19
0
def _requirement_from_back(
        context: NodeContext,
        identifier: NodeIdentifier) -> typing.Optional[ResourceRequirement]:
    target_node = context.node_provider.node_by_identifier(identifier)
    if isinstance(target_node, DockNode):
        weak = context.patches.dock_weakness.get(
            identifier, target_node.default_dock_weakness)
        if weak.lock is not None:
            return ResourceRequirement.simple(identifier)

    return None
Exemple #20
0
def _extra_requirement_for_node(game: GameDescription, node: Node) -> Optional[Requirement]:
    extra_requirement = None

    if node.is_resource_node:
        resource_node: ResourceNode = node

        node_resource = resource_node.resource()
        if node_resource in game.dangerous_resources:
            extra_requirement = ResourceRequirement(node_resource, 1, False)

    return extra_requirement
Exemple #21
0
def _extra_requirement_for_node(game: GameDescription, context: NodeContext,
                                node: Node) -> Optional[Requirement]:
    extra_requirement = None

    if node.is_resource_node:
        assert isinstance(node, ResourceNode)
        node_resource = node.resource(context)
        if node_resource in game.dangerous_resources:
            extra_requirement = ResourceRequirement(node_resource, 1, False)

    return extra_requirement
Exemple #22
0
def test_basic_search_with_translator_gate(has_translator: bool, echoes_resource_database, echoes_game_patches):
    # Setup
    scan_visor = echoes_resource_database.get_item("DarkVisor")
    nc = functools.partial(NodeIdentifier.create, "Test World", "Test Area A")

    node_a = GenericNode(nc("Node A"), True, None, "", ("default",), {})
    node_b = GenericNode(nc("Node B"), True, None, "", ("default",), {})
    node_c = GenericNode(nc("Node C"), True, None, "", ("default",), {})
    translator_node = ConfigurableNode(translator_identif := nc("Translator Gate"),
                                       True, None, "", ("default",), {})

    world_list = WorldList([
        World("Test World", [
            Area("Test Area A", None, True, [node_a, node_b, node_c, translator_node],
                 {
                     node_a: {
                         node_b: Requirement.trivial(),
                         translator_node: Requirement.trivial(),
                     },
                     node_b: {
                         node_a: Requirement.trivial(),
                     },
                     node_c: {
                         translator_node: Requirement.trivial(),
                     },
                     translator_node: {
                         node_a: Requirement.trivial(),
                         node_c: Requirement.trivial(),
                     },
                 },
                 {}
                 )
        ], {})
    ])
    game = GameDescription(RandovaniaGame.METROID_PRIME_ECHOES, DockWeaknessDatabase([], {}, (None, None)),
                           echoes_resource_database, ("default",), Requirement.impossible(),
                           None, {}, None, world_list)

    patches = echoes_game_patches.assign_node_configuration({
        translator_identif: ResourceRequirement(scan_visor, 1, False)
    })
    initial_state = State({scan_visor: 1 if has_translator else 0}, (), 99,
                          node_a, patches, None, StateGameData(echoes_resource_database, game.world_list, 100, 99))

    # Run
    reach = reach_lib.reach_with_all_safe_resources(game, initial_state)

    # Assert
    if has_translator:
        assert set(reach.safe_nodes) == {node_a, node_b, translator_node, node_c}
    else:
        assert set(reach.safe_nodes) == {node_a, node_b}
Exemple #23
0
def test_list_dangerous_resources(input_data, output_data):
    # setup
    req_list = RequirementList(
        (ResourceRequirement(_make_resource(str(item[0])), 1, item[1])
         for item in input_data))

    expected_result = {_make_resource(str(item)) for item in output_data}

    # run
    result = set(req_list.dangerous_resources)

    # assert
    assert result == expected_result
Exemple #24
0
def test_set_hash(echoes_resource_database):
    req_set_a = RequirementSet([
        RequirementList([
            ResourceRequirement(
                echoes_resource_database.get_item_by_name("Power Bomb"), 1,
                False),
        ]),
    ])
    req_set_b = RequirementSet([
        RequirementList([
            ResourceRequirement(
                echoes_resource_database.get_item_by_name("Power Bomb"), 1,
                False),
        ]),
    ])

    assert req_set_a == req_set_b
    assert req_set_a is not req_set_b

    hash_a = hash(req_set_a)
    hash_b = hash(req_set_b)
    assert hash_a == hash_b

    assert hash_a == req_set_a._cached_hash
Exemple #25
0
    def state_for_current_configuration(self) -> Optional[State]:
        state = self._initial_state.copy()
        if self._actions:
            state.node = self._actions[-1]

        for teleporter, combo in self._elevator_id_to_combo.items():
            state.patches.elevator_connection[teleporter] = combo.currentData()

        for gate, item in self._translator_gate_to_combo.items():
            scan_visor = self.game_description.resource_database.get_item(
                "Scan")

            requirement: Optional[
                LayoutTranslatorRequirement] = item.currentData()
            if requirement is None:
                translator_req = Requirement.impossible()
            else:
                translator = self.game_description.resource_database.get_item(
                    requirement.item_name)
                translator_req = ResourceRequirement(translator, 1, False)

            state.patches.configurable_nodes[gate] = RequirementAnd([
                ResourceRequirement(scan_visor, 1, False),
                translator_req,
            ])

        for pickup, quantity in self._collected_pickups.items():
            for _ in range(quantity):
                add_pickup_to_state(state, pickup)

        for node in self._collected_nodes:
            add_resource_gain_to_current_resources(
                node.resource_gain_on_collect(state.node_context()),
                state.resources)

        return state
Exemple #26
0
def test_list_dangerous_resources(input_data, output_data):
    # setup
    req_list = RequirementList(
        (ResourceRequirement(SimpleResourceInfo(item[0], str(item[0]), str(item[0]), ""), 1, item[1])
         for item in input_data))
    expected_result = {
        SimpleResourceInfo(item, str(item), str(item), "")
        for item in output_data
    }

    # run
    result = set(req_list.dangerous_resources)

    # assert
    assert result == expected_result
Exemple #27
0
def test_pretty_print_requirement_array_combinable(
        mock_print_requirement: MagicMock, echoes_resource_database):
    mock_print_requirement.return_value = ["a", "b"]

    array = RequirementAnd([
        ResourceRequirement(echoes_resource_database.item[0], 1, False),
        RequirementTemplate("Shoot Sunburst"),
    ])

    # Run
    result = list(pretty_print.pretty_print_requirement_array(array, 3))

    # Assert
    assert result == [(3, "Power Beam and Shoot Sunburst")]
    mock_print_requirement.assert_not_called()
Exemple #28
0
def test_sort_resource_requirement():
    resources = [
        NodeIdentifier.create("World", "Area", "Node"),
        PickupIndex(10),
        _make_resource("Resource"),
        TrickResourceInfo("Trick", "Trick", "Long Description"),
        ItemResourceInfo("Item", "Item", 1),
    ]

    # Assert resources has an entry for every type of ResourceInfo
    assert {type(it) for it in resources} == set(ResourceInfo.__args__)
    assert len(resources) == len(ResourceInfo.__args__)

    requirements = [ResourceRequirement.simple(it) for it in resources]

    result = sorted(requirements)
    assert result == list(reversed(requirements))
Exemple #29
0
def test_get_pickups_that_solves_unreachable(echoes_game_description, mocker):
    def item(name):
        return search.find_resource_info_with_long_name(
            echoes_game_description.resource_database.item, name)

    mock_req_lists: MagicMock = mocker.patch(
        "randovania.generator.filler.pickup_list._requirement_lists_without_satisfied_resources"
    )

    pickups_left = []
    reach = MagicMock()
    reach.state.resources = {}
    reach.state.energy = 100
    possible_set = MagicMock()
    reach.unreachable_nodes_with_requirements.return_value = {
        "foo": possible_set
    }
    uncollected_resource_nodes = [MagicMock()]

    mock_req_lists.return_value = {
        RequirementList([
            ResourceRequirement(item("Dark Visor"), 1, False),
            ResourceRequirement(item("Missile"), 5, False),
        ]),
        RequirementList([
            ResourceRequirement(item("Screw Attack"), 1, False),
        ]),
        RequirementList([
            ResourceRequirement(item("Power Bomb"), 1, False),
            ResourceRequirement(item("Boost Ball"), 1, False),
        ]),
        RequirementList([
            ResourceRequirement(item("Spider Ball"), 1, False),
            ResourceRequirement(item("Boost Ball"), 1, False),
        ]),
    }

    # Run
    result = pickup_list.get_pickups_that_solves_unreachable(
        pickups_left, reach, uncollected_resource_nodes)

    # Assert
    mock_req_lists.assert_called_once_with(
        reach.state, [possible_set],
        [uncollected_resource_nodes[0].resource.return_value])
    assert result == tuple()
Exemple #30
0
def _unsatisfied_item_requirements_in_list(
        alternative: RequirementList, state: State,
        uncollected_resources: List[ResourceInfo]):
    possible = True
    items = []
    damage = []

    for individual in alternative.items:
        if individual.negate:
            possible = False
            break

        if individual.resource.resource_type == ResourceType.DAMAGE:
            damage.append(individual)
            continue

        if individual.satisfied(state.resources, state.energy,
                                state.resource_database):
            continue

        if individual.resource.resource_type != ResourceType.ITEM:
            if individual.resource not in uncollected_resources:
                possible = False
                break

        items.append(individual)

    if not possible:
        return

    sum_damage = sum(
        req.damage(state.resources, state.resource_database) for req in damage)
    if state.energy < sum_damage:
        tank_count = (sum_damage -
                      state.energy) // state.game_data.energy_per_tank
        yield items + [
            ResourceRequirement(state.resource_database.energy_tank,
                                tank_count + 1, False)
        ]
        # FIXME: get the required items for reductions (aka suits)
    else:
        yield items