def _add_box_with_requirements(self, alternative: RequirementList): group_box = self._create_box_in_grid() group_box.rows = [] vertical_layout = QVBoxLayout(group_box) vertical_layout.setObjectName(f"Layout with index {self._current_last_index - 1}") vertical_layout.setAlignment(Qt.AlignTop) empty = True trick_level = LayoutTrickLevel.NO_TRICKS for item in sorted(alternative.items): if self.edit_mode: ItemRow(group_box, vertical_layout, self.resource_database, item, group_box.rows) else: if item.resource.resource_type == ResourceType.DIFFICULTY: trick_level = LayoutTrickLevel.from_number(item.amount) else: empty = False label = QLabel(group_box) if item.resource.resource_type == ResourceType.TRICK: label.setText(f"{item.resource} ({LayoutTrickLevel.from_number(item.amount).long_name})") else: label.setText(item.pretty_text) vertical_layout.addWidget(label) if self.edit_mode: tools_layout = QHBoxLayout(group_box) tools_layout.setObjectName(f"Tools layout with index {self._current_last_index - 1}") vertical_layout.addLayout(tools_layout) add_new_button = QPushButton(group_box) add_new_button.setText("New Requirement") tools_layout.addWidget(add_new_button) delete_button = QPushButton(group_box) delete_button.setText("Delete") delete_button.clicked.connect(partial(self._delete_alternative, group_box)) tools_layout.addWidget(delete_button) def _new_row(): empty_item = IndividualRequirement( self.resource_database.get_by_type(ResourceType.ITEM)[0], 1, False ) ItemRow(group_box, vertical_layout, self.resource_database, empty_item, group_box.rows) vertical_layout.removeItem(tools_layout) vertical_layout.addLayout(tools_layout) add_new_button.clicked.connect(_new_row) else: group_box.setTitle(f"Difficulty: {trick_level.long_name}") if empty: label = QLabel(group_box) label.setText("No requirements.") vertical_layout.addWidget(label) return group_box
def _on_slide_trick_slider(self, trick: TrickResourceInfo, value: int): if self._slider_for_trick[trick].isEnabled(): with self._editor as options: options.set_configuration_field( "trick_level", options.configuration.trick_level.set_level_for_trick( trick, LayoutTrickLevel.from_number(value)))
def pretty_print_resource_requirement(requirement: ResourceRequirement) -> str: if requirement.resource.resource_type == ResourceType.TRICK: return f"{requirement.resource} ({LayoutTrickLevel.from_number(requirement.amount).long_name})" elif requirement.resource.resource_type == ResourceType.DIFFICULTY: trick_level = LayoutTrickLevel.from_number(requirement.amount) return f"Difficulty: {trick_level.long_name}" else: return requirement.pretty_text
def _difficulties_for_trick(world_list: WorldList, trick: SimpleResourceInfo): result = set() for area in world_list.all_areas: for _, _, requirements in area.all_connections: for individual in requirements.all_individual: if individual.resource == trick: result.add(LayoutTrickLevel.from_number(individual.amount)) return result
def from_json(cls, value: dict, game: RandovaniaGame): minimal_logic = value["minimal_logic"] specific_levels = { trick_short_name: LayoutTrickLevel(level) for trick_short_name, level in value["specific_levels"].items() if level != LayoutTrickLevel.DISABLED.value } return cls( minimal_logic=minimal_logic, specific_levels={} if minimal_logic else specific_levels, game=game, )
def test_database_collectable(preset_manager, game_enum, preset_name, ignore_events, ignore_pickups): game, initial_state, permalink = run_bootstrap( preset_manager.included_preset_with(game_enum, 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.maximum().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 difficulties_for_trick(world_list: WorldList, trick: TrickResourceInfo): result = set() for area in world_list.all_areas: for _, _, requirement in area.all_connections: for resource_requirement in requirement.iterate_resource_requirements( ): if resource_requirement.resource == trick: result.add( LayoutTrickLevel.from_number( resource_requirement.amount)) return result
def get_layout_configuration_from_args(args) -> LayoutConfiguration: try: sky_temple_keys = int(args.sky_temple_keys) except ValueError: sky_temple_keys = args.sky_temple_keys # TODO: support for item loss return LayoutConfiguration.from_params( trick_level_configuration=TrickLevelConfiguration( LayoutTrickLevel(args.trick_level)), sky_temple_keys=LayoutSkyTempleKeyMode(sky_temple_keys), elevators=LayoutElevators.VANILLA, starting_location=StartingLocation.default(), )
def trick_resources_for_configuration( configuration: TrickLevelConfiguration, resource_database: ResourceDatabase, ) -> CurrentResources: """ :param configuration: :param resource_database: :return: """ static_resources = {} for trick in resource_database.trick: if configuration.minimal_logic: level = LayoutTrickLevel.maximum() else: level = configuration.level_for_trick(trick) static_resources[trick] = level.as_number return static_resources
def process(req: Requirement, result: Set[LayoutTrickLevel]): for resource_requirement in req.iterate_resource_requirements(): if resource_requirement.resource == trick: result.add( LayoutTrickLevel.from_number(resource_requirement.amount))
def test_reach_size_from_start_echoes(small_echoes_game_description, default_layout_configuration): # Setup game = small_echoes_game_description specific_levels = { trick.short_name: LayoutTrickLevel.maximum() for trick in game.resource_database.trick } def item(name: str): return find_resource_info_with_long_name(game.resource_database.item, name) def nodes(*names): result = [game.world_list.node_from_name(name) for name in names] result.sort(key=lambda it: it.index) return result layout_configuration = dataclasses.replace( default_layout_configuration, trick_level=TrickLevelConfiguration( minimal_logic=False, specific_levels=specific_levels, game=default_layout_configuration.game), starting_location=StartingLocationList.with_elements( [game.starting_location], game=RandovaniaGame.PRIME2, )) patches = base_patches_factory.create_base_patches(layout_configuration, Random(15000), game, False, player_index=0) state = bootstrap.calculate_starting_state(game, patches, 100) state.resources[item("Combat Visor")] = 1 state.resources[item("Amber Translator")] = 1 state.resources[item("Scan Visor")] = 1 state.resources[item("Morph Ball")] = 1 state.resources[item("Power Beam")] = 1 state.resources[item("Charge Beam")] = 1 state.resources[item("Grapple Beam")] = 1 state.resources[item("Dark Beam")] = 1 state.resources[item("Dark Ammo")] = 50 state.resources[item("Missile")] = 5 # Run reach = GeneratorReach.reach_from_state(game, state) # Assert assert list(reach.nodes) == nodes( "Temple Grounds/Path of Eyes/Front of Translator Gate", "Temple Grounds/Path of Eyes/Lore Scan", "Temple Grounds/Path of Eyes/Translator Gate", "Temple Grounds/Path of Eyes/Door to Torvus Transport Access", "Temple Grounds/Torvus Transport Access/Door to Path of Eyes", "Temple Grounds/Torvus Transport Access/Door to Transport to Torvus Bog", "Temple Grounds/Transport to Torvus Bog/Door to Torvus Transport Access", "Temple Grounds/Transport to Torvus Bog/Elevator to Torvus Bog - Transport to Temple Grounds", "Torvus Bog/Transport to Temple Grounds/Elevator to Temple Grounds - Transport to Torvus Bog", "Torvus Bog/Transport to Temple Grounds/Door to Temple Transport Access", "Torvus Bog/Temple Transport Access/Door to Transport to Temple Grounds", "Torvus Bog/Temple Transport Access/Door to Torvus Lagoon", "Torvus Bog/Torvus Lagoon/Door to Temple Transport Access", "Torvus Bog/Torvus Lagoon/Door to Path of Roots", "Torvus Bog/Torvus Lagoon/Keybearer Corpse (S-Dly)", "Torvus Bog/Path of Roots/Door to Torvus Lagoon", "Torvus Bog/Path of Roots/Door to Great Bridge", "Torvus Bog/Path of Roots/Pickup (Missile)", "Torvus Bog/Path of Roots/Next to Pickup", "Torvus Bog/Path of Roots/Under Lore Scan", "Torvus Bog/Path of Roots/Lore Scan", "Torvus Bog/Great Bridge/Door to Path of Roots", ) assert len(list(reach.safe_nodes)) == 20