def setup_starting_area_elements(self):
        game_description = default_prime2_game_description()
        world_to_group = {}
        self._starting_location_for_area = {}

        for row, world in enumerate(game_description.world_list.worlds):
            for column, is_dark_world in enumerate([False, True]):
                group_box = QGroupBox(self.starting_locations_contents)
                group_box.setTitle(world.correct_name(is_dark_world))
                vertical_layout = QVBoxLayout(group_box)
                vertical_layout.setContentsMargins(8, 4, 8, 4)
                vertical_layout.setSpacing(2)
                vertical_layout.setAlignment(QtCore.Qt.AlignTop)
                group_box.vertical_layout = vertical_layout

                world_to_group[world.correct_name(is_dark_world)] = group_box
                self.starting_locations_layout.addWidget(group_box, row, column)

        for world in game_description.world_list.worlds:
            for area in sorted(world.areas, key=lambda a: a.name):
                group_box = world_to_group[world.correct_name(area.in_dark_aether)]
                check = QtWidgets.QCheckBox(group_box)
                check.setText(area.name)
                check.area_location = AreaLocation(world.world_asset_id, area.area_asset_id)
                check.stateChanged.connect(functools.partial(self._on_check_starting_area, check))
                group_box.vertical_layout.addWidget(check)
                self._starting_location_for_area[area.area_asset_id] = check

        self.starting_area_quick_fill_ship.clicked.connect(self._starting_location_on_select_ship)
        self.starting_area_quick_fill_save_station.clicked.connect(self._starting_location_on_select_save_station)
    def __init__(self, main_window: MainWindow, background_processor: BackgroundTaskMixin, options: Options):
        super().__init__()
        self.setupUi(self)
        self._options = options
        self._main_window = main_window

        self.game_description = default_database.default_prime2_game_description()
        self.world_list = self.game_description.world_list
        self.resource_database = self.game_description.resource_database

        # Update with Options
        self.setup_trick_level_elements()
        self.setup_elevator_elements()
        self.setup_sky_temple_elements()
        self.setup_starting_area_elements()
        self.setup_translators_elements()
        self.setup_hint_elements()

        # Alignment
        self.trick_level_layout.setAlignment(QtCore.Qt.AlignTop)
        self.elevator_layout.setAlignment(QtCore.Qt.AlignTop)
        self.goal_layout.setAlignment(QtCore.Qt.AlignTop)
        self.starting_area_layout.setAlignment(QtCore.Qt.AlignTop)
        self.translators_layout.setAlignment(QtCore.Qt.AlignTop)
        self.hint_layout.setAlignment(QtCore.Qt.AlignTop)
Beispiel #3
0
    def _setup_difficulties_menu(self):
        game = default_database.default_prime2_game_description()
        for i, trick_level in enumerate(LayoutTrickLevel):
            if trick_level not in {
                    LayoutTrickLevel.NO_TRICKS,
                    LayoutTrickLevel.MINIMAL_RESTRICTIONS
            }:
                difficulty_action = QAction(self)
                difficulty_action.setText(trick_level.long_name)
                self.menu_difficulties.addAction(difficulty_action)
                difficulty_action.triggered.connect(
                    functools.partial(self._open_difficulty_details_popup,
                                      trick_level))

        configurable_tricks = TrickLevelConfiguration.all_possible_tricks()
        tricks_in_use = used_tricks(game.world_list)

        for trick in sorted(game.resource_database.trick,
                            key=lambda _trick: _trick.long_name):
            if trick.index not in configurable_tricks or trick not in tricks_in_use:
                continue

            trick_menu = QMenu(self)
            trick_menu.setTitle(trick.long_name)
            self.menu_trick_details.addAction(trick_menu.menuAction())

            used_difficulties = difficulties_for_trick(game.world_list, trick)
            for i, trick_level in enumerate(LayoutTrickLevel):
                if trick_level in used_difficulties:
                    difficulty_action = QAction(self)
                    difficulty_action.setText(trick_level.long_name)
                    trick_menu.addAction(difficulty_action)
                    difficulty_action.triggered.connect(
                        functools.partial(self._open_trick_details_popup,
                                          trick, trick_level))
    def setup_location_pool_elements(self):
        self.randomization_mode_combo.setItemData(0, RandomizationMode.FULL)
        self.randomization_mode_combo.setItemData(
            1, RandomizationMode.MAJOR_MINOR_SPLIT)
        self.randomization_mode_combo.currentIndexChanged.connect(
            self._on_update_randomization_mode)

        game_description = default_prime2_game_description()
        world_to_group = {}
        self._location_pool_for_node = {}

        for world in game_description.world_list.worlds:
            for is_dark_world in [False, True]:
                group_box = QGroupBox(self.excluded_locations_area_contents)
                group_box.setTitle(world.correct_name(is_dark_world))
                vertical_layout = QVBoxLayout(group_box)
                vertical_layout.setContentsMargins(8, 4, 8, 4)
                vertical_layout.setSpacing(2)
                group_box.vertical_layout = vertical_layout

                world_to_group[world.correct_name(is_dark_world)] = group_box
                self.excluded_locations_area_layout.addWidget(group_box)

        for world, area, node in game_description.world_list.all_worlds_areas_nodes:
            if not isinstance(node, PickupNode):
                continue

            group_box = world_to_group[world.correct_name(area.in_dark_aether)]
            check = QtWidgets.QCheckBox(group_box)
            check.setText(game_description.world_list.node_name(node))
            check.node = node
            check.stateChanged.connect(
                functools.partial(self._on_check_location, check))
            group_box.vertical_layout.addWidget(check)
            self._location_pool_for_node[node] = check
def add_elevator_connections_to_patches(
        layout_configuration: LayoutConfiguration, rng: Random,
        patches: GamePatches) -> GamePatches:
    """
    :param layout_configuration:
    :param rng:
    :param patches:
    :return:
    """
    if layout_configuration.elevators == LayoutElevators.RANDOMIZED:
        if rng is None:
            raise MissingRng("Elevator")

        world_list = default_database.default_prime2_game_description(
        ).world_list
        areas_to_not_change = {
            2278776548,  # Sky Temple Gateway
            2068511343,  # Sky Temple Energy Controller
            3136899603,  # Aerie Transport Station
            1564082177,  # Aerie
        }

        elevator_connection = copy.copy(patches.elevator_connection)
        elevator_connection.update(
            elevator_distributor.elevator_connections_for_seed_number(
                rng=rng,
                elevator_database=elevator_distributor.
                create_elevator_database(world_list, areas_to_not_change)))
        return dataclasses.replace(patches,
                                   elevator_connection=elevator_connection)
    else:
        return patches
 def as_json(self) -> list:
     world_list = default_database.default_prime2_game_description().world_list
     return list(sorted(
         world_list.area_name(world_list.area_by_area_location(location), separator="/",
                              distinguish_dark_aether=False)
         for location in self.locations
     ))
    async def _setup_locations_combo(self):
        network_client = common_qt_lib.get_network_client()
        game_session = network_client.current_game_session
        user = network_client.current_user

        game = default_database.default_prime2_game_description()
        index_to_name = {
            node.pickup_index.index: game.world_list.area_name(area)
            for world, area, node in game.world_list.all_worlds_areas_nodes
            if isinstance(node, PickupNode)
        }

        if game_session is None:
            names = index_to_name
        else:
            patcher_data = await network_client.session_admin_player(
                user.id, SessionAdminUserAction.CREATE_PATCHER_FILE,
                CosmeticPatches().as_json)
            names = {
                pickup["pickup_index"]:
                "{}: {}".format(index_to_name[pickup["pickup_index"]],
                                pickup["hud_text"][0])
                for pickup in patcher_data["pickups"]
            }

        self.collect_location_combo.clear()
        for index, name in sorted(names.items()):
            self.collect_location_combo.addItem(name, index)

        self.collect_location_button.setEnabled(True)
        self.collect_location_combo.setVisible(True)
        self.setup_collect_location_combo_button.deleteLater()
def _areas_list():
    world_list = default_database.default_prime2_game_description().world_list
    areas = [
        AreaLocation(world.world_asset_id, area.area_asset_id)
        for world in world_list.worlds
        for area in world.areas
    ]
    return list(sorted(areas))
Beispiel #9
0
 def _open_difficulty_details_popup(self, difficulty: LayoutTrickLevel):
     self._exec_trick_details(
         TrickDetailsPopup(
             self,
             self,
             default_database.default_prime2_game_description(),
             None,
             difficulty,
         ))
Beispiel #10
0
 def _open_trick_details_popup(self, trick: TrickResourceInfo,
                               level: LayoutTrickLevel):
     self._exec_trick_details(
         TrickDetailsPopup(
             self,
             self,
             default_database.default_prime2_game_description(),
             trick,
             level,
         ))
Beispiel #11
0
    def __init__(self):
        super().__init__()
        self.logger = logging.getLogger(__name__)
        self.logger.setLevel(logging.DEBUG)

        self.dolphin = dolphin_memory_engine
        self.game = default_prime2_game_description()

        self.message_queue = []
        self._pickups_to_give = []
        self._permanent_pickups = []
Beispiel #12
0
    def _create_pickup_spoilers(self):
        self.pickup_spoiler_show_all_button.clicked.connect(
            self._toggle_show_all_pickup_spoiler)
        self.pickup_spoiler_show_all_button.currently_show_all = True

        self._create_pickup_spoiler_combobox()

        game_description = default_prime2_game_description()
        world_to_group = {}

        for world in game_description.world_list.worlds:
            for is_dark_world in [False, True]:
                group_box = QGroupBox(self.pickup_spoiler_scroll_contents)
                group_box.setTitle(world.correct_name(is_dark_world))
                vertical_layout = QVBoxLayout(group_box)
                vertical_layout.setContentsMargins(8, 4, 8, 4)
                vertical_layout.setSpacing(2)
                group_box.vertical_layout = vertical_layout

                vertical_layout.horizontal_layouts = []
                world_to_group[world.correct_name(is_dark_world)] = group_box
                self.pickup_spoiler_scroll_content_layout.addWidget(group_box)

        for world, area, node in game_description.world_list.all_worlds_areas_nodes:
            if not isinstance(node, PickupNode):
                continue

            group_box = world_to_group[world.correct_name(area.in_dark_aether)]
            horizontal_layout = QHBoxLayout()
            horizontal_layout.setSpacing(2)

            label = QLabel(group_box)
            label.setText(game_description.world_list.node_name(node))
            horizontal_layout.addWidget(label)
            horizontal_layout.label = label

            push_button = QPushButton(group_box)
            push_button.setFlat(True)
            push_button.setText("Hidden")
            push_button.item_is_hidden = True
            push_button.pickup_index = node.pickup_index
            push_button.clicked.connect(
                partial(self._toggle_pickup_spoiler, push_button))
            push_button.item_name = "Nothing was Set, ohno"
            push_button.row = horizontal_layout
            horizontal_layout.addWidget(push_button)
            horizontal_layout.button = push_button
            self.pickup_spoiler_buttons.append(push_button)

            group_box.vertical_layout.addLayout(horizontal_layout)
            group_box.vertical_layout.horizontal_layouts.append(
                horizontal_layout)
def add_elevator_connections_to_patches(
        layout_configuration: LayoutConfiguration, rng: Random,
        patches: GamePatches) -> GamePatches:
    """
    :param layout_configuration:
    :param rng:
    :param patches:
    :return:
    """
    elevator_connection = copy.copy(patches.elevator_connection)

    if layout_configuration.elevators != LayoutElevators.VANILLA:
        if rng is None:
            raise MissingRng("Elevator")

        world_list = default_database.default_prime2_game_description(
        ).world_list
        areas_to_not_change = {
            2278776548,  # Sky Temple Gateway
            2068511343,  # Sky Temple Energy Controller
            3136899603,  # Aerie Transport Station
            1564082177,  # Aerie
        }

        elevator_db = elevator_distributor.create_elevator_database(
            world_list, areas_to_not_change)

        if layout_configuration.elevators in {
                LayoutElevators.TWO_WAY_RANDOMIZED,
                LayoutElevators.TWO_WAY_UNCHECKED
        }:
            connections = elevator_distributor.two_way_elevator_connections(
                rng=rng,
                elevator_database=elevator_db,
                between_areas=layout_configuration.elevators ==
                LayoutElevators.TWO_WAY_RANDOMIZED)
        else:
            connections = elevator_distributor.one_way_elevator_connections(
                rng=rng,
                elevator_database=elevator_db,
                world_list=world_list,
                elevator_target=layout_configuration.elevators ==
                LayoutElevators.ONE_WAY_ELEVATOR)

        elevator_connection.update(connections)

    if layout_configuration.skip_final_bosses:
        elevator_connection[136970379] = AreaLocation(1006255871, 1393588666)

    return dataclasses.replace(patches,
                               elevator_connection=elevator_connection)
Beispiel #14
0
def test_create_patches(
    mock_random: MagicMock,
    mock_calculate_item_pool: MagicMock,
    mock_create_base_patches: MagicMock,
    mock_retcon_playthrough_filler: MagicMock,
    mock_indices_for_unassigned_pickups: MagicMock,
):
    # Setup
    seed_number: int = 91319
    game = default_prime2_game_description()
    status_update: Union[MagicMock, Callable[[str], None]] = MagicMock()
    configuration = LayoutConfiguration.from_params(
        trick_level=LayoutTrickLevel.NO_TRICKS,
        sky_temple_keys=LayoutSkyTempleKeyMode.FULLY_RANDOM,
        elevators=LayoutRandomizedFlag.VANILLA,
        pickup_quantities={},
        starting_location=StartingLocation.default(),
        starting_resources=StartingResources.from_item_loss(False),
    )
    permalink = Permalink(
        seed_number=seed_number,
        spoiler=True,
        patcher_configuration=PatcherConfiguration.default(),
        layout_configuration=configuration,
    )
    mock_calculate_item_pool.return_value = list(
        sorted(game.pickup_database.original_pickup_mapping.values()))
    mock_create_base_patches.return_value.starting_location = game.starting_location
    mock_create_base_patches.return_value.custom_initial_items = None

    filler_patches = mock_retcon_playthrough_filler.return_value

    # Run
    result = generator._create_patches(permalink, game, status_update)

    # Assert
    mock_random.assert_called_once_with(permalink.as_str)
    mock_calculate_item_pool.assert_called_once_with(permalink, game)

    mock_create_base_patches.assert_called_once_with(mock_random.return_value,
                                                     game, permalink, ANY)

    mock_retcon_playthrough_filler.assert_called_once_with(
        ANY, ANY, ANY, mock_random.return_value, status_update)

    mock_indices_for_unassigned_pickups.assert_called_once_with(
        mock_random.return_value, game, filler_patches.pickup_assignment, ANY)
    filler_patches.assign_new_pickups.assert_called_once_with(
        mock_indices_for_unassigned_pickups.return_value)

    assert result == filler_patches.assign_new_pickups.return_value
    def from_json(cls, value: list) -> "StartingLocation":
        if not isinstance(value, list):
            raise ValueError("StartingLocation from_json must receive a list, got {}".format(type(value)))

        world_list = default_database.default_prime2_game_description().world_list

        elements = []
        for location in value:
            world_name, area_name = location.split("/")
            world = world_list.world_with_name(world_name)
            area = world.area_by_name(area_name)
            elements.append(AreaLocation(world.world_asset_id, area.area_asset_id))

        return cls.with_elements(elements)
Beispiel #16
0
def test_create_patches(
    mock_random: MagicMock,
    mock_calculate_item_pool: MagicMock,
    mock_create_base_patches: MagicMock,
    mock_validate_item_pool_size: MagicMock,
    mock_run_filler: MagicMock,
    mock_assign_remaining_items: MagicMock,
):
    # Setup
    game = default_prime2_game_description()
    status_update: Union[MagicMock, Callable[[str], None]] = MagicMock()

    permalink = MagicMock()
    pool_patches = MagicMock()
    item_pool = MagicMock()
    filler_patches = MagicMock()
    remaining_items = MagicMock()

    mock_calculate_item_pool.return_value = pool_patches, item_pool
    mock_run_filler.return_value = filler_patches, remaining_items

    # Run
    result = generator._create_randomized_patches(permalink, game,
                                                  status_update)

    # Assert
    mock_random.assert_called_once_with(permalink.as_str)
    mock_create_base_patches.assert_called_once_with(
        permalink.layout_configuration, mock_random.return_value, game)

    # pool
    mock_calculate_item_pool.assert_called_once_with(
        permalink.layout_configuration, game.resource_database,
        mock_create_base_patches.return_value)

    mock_validate_item_pool_size.assert_called_once_with(item_pool, game)
    mock_run_filler.assert_called_once_with(permalink.layout_configuration,
                                            game, item_pool, pool_patches,
                                            mock_random.return_value,
                                            status_update)
    mock_assign_remaining_items.assert_called_once_with(
        mock_random.return_value, game.world_list,
        filler_patches.pickup_assignment, remaining_items,
        permalink.layout_configuration.randomization_mode)
    filler_patches.assign_pickup_assignment.assert_called_once_with(
        mock_assign_remaining_items.return_value)

    assert result == filler_patches.assign_pickup_assignment.return_value
Beispiel #17
0
    def _update_hints_text(self):
        game_description = default_database.default_prime2_game_description()

        number_for_hint_type = {
            hint_type: i + 1
            for i, hint_type in enumerate(LoreType)
        }
        used_hint_types = set()

        self.hint_tree_widget.setSortingEnabled(False)

        # TODO: This ignores the Dark World names. But there's currently no logbook nodes in Dark World.
        for world in game_description.world_list.worlds:

            world_item = QtWidgets.QTreeWidgetItem(self.hint_tree_widget)
            world_item.setText(0, world.name)
            world_item.setExpanded(True)

            for area in world.areas:
                hint_types = {}

                for node in area.nodes:
                    if isinstance(node, LogbookNode):
                        if node.required_translator is not None:
                            hint_types[
                                node.
                                lore_type] = node.required_translator.short_name
                        else:
                            hint_types[node.lore_type] = "✓"

                if hint_types:
                    area_item = QtWidgets.QTreeWidgetItem(world_item)
                    area_item.setText(0, area.name)

                    for hint_type, text in hint_types.items():
                        area_item.setText(number_for_hint_type[hint_type],
                                          text)
                        used_hint_types.add(hint_type)

        self.hint_tree_widget.resizeColumnToContents(0)
        self.hint_tree_widget.setSortingEnabled(True)
        self.hint_tree_widget.sortByColumn(0, QtCore.Qt.AscendingOrder)

        for hint_type in used_hint_types:
            self.hint_tree_widget.headerItem().setText(
                number_for_hint_type[hint_type], hint_type.long_name)
    async def _setup_locations_combo(self):
        game = default_database.default_prime2_game_description()
        index_to_name = {
            node.pickup_index.index:
            game.world_list.area_name(area,
                                      distinguish_dark_aether=True,
                                      separator=" - ")
            for world, area, node in game.world_list.all_worlds_areas_nodes
            if isinstance(node, PickupNode)
        }

        self.collect_location_combo.clear()
        for index, name in sorted(index_to_name.items()):
            self.collect_location_combo.addItem(name, index)

        self.collect_location_button.setEnabled(True)
        self.collect_location_combo.setVisible(True)
        self.setup_collect_location_combo_button.deleteLater()
    def __init__(self, window_manager: Optional[WindowManager],
                 editor: PresetEditor):
        super().__init__()
        self.setupUi(self)
        common_qt_lib.set_default_window_icon(self)

        self._editor = editor
        self._window_manager = window_manager
        self._main_rules = MainRulesWindow(editor)
        self._game_patches = GamePatchesWindow(editor)

        self.game_description = default_database.default_prime2_game_description(
        )
        self.world_list = self.game_description.world_list
        self.resource_database = self.game_description.resource_database

        # Update with Options
        self.logic_tab_widget.addTab(self._main_rules.centralWidget,
                                     "Item Pool")
        self.patches_tab_widget.addTab(self._game_patches.centralWidget,
                                       "Other")

        self.name_edit.textEdited.connect(self._edit_name)
        self.setup_trick_level_elements()
        self.setup_damage_elements()
        self.setup_elevator_elements()
        self.setup_sky_temple_elements()
        self.setup_starting_area_elements()
        self.setup_location_pool_elements()
        self.setup_translators_elements()
        self.setup_hint_elements()
        self.setup_beam_configuration_elements()

        # Alignment
        self.trick_level_layout.setAlignment(QtCore.Qt.AlignTop)
        self.elevator_layout.setAlignment(QtCore.Qt.AlignTop)
        self.goal_layout.setAlignment(QtCore.Qt.AlignTop)
        self.starting_area_layout.setAlignment(QtCore.Qt.AlignTop)
        self.translators_layout.setAlignment(QtCore.Qt.AlignTop)
        self.hint_layout.setAlignment(QtCore.Qt.AlignTop)

        self.button_box.accepted.connect(self.accept)
        self.button_box.rejected.connect(self.reject)
Beispiel #20
0
    def _setup_difficulties_menu(self):
        game = default_database.default_prime2_game_description()
        tricks_in_use = used_tricks(game)

        for trick in sorted(game.resource_database.trick,
                            key=lambda _trick: _trick.long_name):
            if trick not in tricks_in_use:
                continue

            trick_menu = QMenu(self)
            trick_menu.setTitle(trick.long_name)
            self.menu_trick_details.addAction(trick_menu.menuAction())

            used_difficulties = difficulties_for_trick(game, trick)
            for i, trick_level in enumerate(iterate_enum(LayoutTrickLevel)):
                if trick_level in used_difficulties:
                    difficulty_action = QAction(self)
                    difficulty_action.setText(trick_level.long_name)
                    trick_menu.addAction(difficulty_action)
                    difficulty_action.triggered.connect(
                        functools.partial(self._open_trick_details_popup,
                                          trick, trick_level))
Beispiel #21
0
def _all_trick_indices():
    resource_db = default_database.default_prime2_game_description().resource_database
    return {trick.index for trick in resource_db.trick}
Beispiel #22
0
    def _update_hints_text(self):
        game_description = default_database.default_prime2_game_description()
        item_database = default_database.default_prime2_item_database()

        rows = []

        for item in item_database.major_items.values():
            rows.append((
                item.name,
                item.item_category.hint_details[1],
                item.item_category.general_details[1],
                item.broad_category.hint_details[1],
            ))

        from randovania.games.prime.echoes_items import DARK_TEMPLE_KEY_NAMES
        for dark_temple_key in DARK_TEMPLE_KEY_NAMES:
            rows.append((
                dark_temple_key.format("").strip(),
                ItemCategory.TEMPLE_KEY.hint_details[1],
                ItemCategory.TEMPLE_KEY.general_details[1],
                ItemCategory.KEY.hint_details[1],
            ))

        rows.append((
            "Sky Temple Key",
            ItemCategory.SKY_TEMPLE_KEY.hint_details[1],
            ItemCategory.SKY_TEMPLE_KEY.general_details[1],
            ItemCategory.KEY.hint_details[1],
        ))

        for item in item_database.ammo.values():
            rows.append((
                item.name,
                ItemCategory.EXPANSION.hint_details[1],
                ItemCategory.EXPANSION.general_details[1],
                item.broad_category.hint_details[1],
            ))

        self.hint_item_names_tree_widget.setRowCount(len(rows))
        for i, elements in enumerate(rows):
            for j, element in enumerate(elements):
                self.hint_item_names_tree_widget.setItem(
                    i, j, QtWidgets.QTableWidgetItem(element))

        for i in range(4):
            self.hint_item_names_tree_widget.resizeColumnToContents(i)

        number_for_hint_type = {
            hint_type: i + 1
            for i, hint_type in enumerate(LoreType)
        }
        used_hint_types = set()

        self.hint_tree_widget.setSortingEnabled(False)

        # TODO: This ignores the Dark World names. But there's currently no logbook nodes in Dark World.
        for world in game_description.world_list.worlds:

            world_item = QtWidgets.QTreeWidgetItem(self.hint_tree_widget)
            world_item.setText(0, world.name)
            world_item.setExpanded(True)

            for area in world.areas:
                hint_types = {}

                for node in area.nodes:
                    if isinstance(node, LogbookNode):
                        if node.required_translator is not None:
                            hint_types[
                                node.
                                lore_type] = node.required_translator.short_name
                        else:
                            hint_types[node.lore_type] = "✓"

                if hint_types:
                    area_item = QtWidgets.QTreeWidgetItem(world_item)
                    area_item.setText(0, area.name)

                    for hint_type, text in hint_types.items():
                        area_item.setText(number_for_hint_type[hint_type],
                                          text)
                        used_hint_types.add(hint_type)

        self.hint_tree_widget.resizeColumnToContents(0)
        self.hint_tree_widget.setSortingEnabled(True)
        self.hint_tree_widget.sortByColumn(0, QtCore.Qt.AscendingOrder)

        for hint_type in used_hint_types:
            self.hint_tree_widget.headerItem().setText(
                number_for_hint_type[hint_type], hint_type.long_name)
Beispiel #23
0
def _all_tricks():
    return default_database.default_prime2_game_description(
    ).resource_database.trick
 def as_json(self) -> list:
     world_list = default_database.default_prime2_game_description().world_list
     return list(sorted(
         world_list.area_name(world_list.area_by_area_location(location))
         for location in self.locations
     ))
Beispiel #25
0
def _areas_list():
    world_list = default_database.default_prime2_game_description(
        False).world_list
    return world_list, list(world_list.all_areas)
Beispiel #26
0
def test_copy_worlds():
    game_description = default_prime2_game_description()
    game_copy = copy.deepcopy(game_description)

    assert game_description.world_list.worlds == game_copy.world_list.worlds
    assert game_description.world_list.worlds is not game_copy.world_list.worlds
    def _update_current_player(self):
        description = self.layout_description
        current_player = self.current_player_index
        preset = description.permalink.get_preset(current_player)

        title_text = """
        <p>
            Permalink: <span style='font-weight:600;'>{description.permalink.as_str}</span><br/>
            Seed Hash: {description.shareable_word_hash} ({description.shareable_hash})<br/>
            Preset Name: {preset.name}
        </p>
        """.format(description=description, preset=preset)
        self.layout_title_label.setText(title_text)

        categories = list(preset_describer.describe(preset))
        self.layout_description_left_label.setText(preset_describer.merge_categories(categories[::2]))
        self.layout_description_right_label.setText(preset_describer.merge_categories(categories[1::2]))

        # Game Spoiler
        has_spoiler = description.permalink.spoiler
        self.pickup_tab.setEnabled(has_spoiler)
        patches = description.all_patches[current_player]

        if has_spoiler:
            pickup_names = {
                pickup.pickup.name
                for pickup in patches.pickup_assignment.values()
            }
            game_description = default_prime2_game_description()
            starting_area = game_description.world_list.area_by_area_location(patches.starting_location)

            extra_items = patcher_file.additional_starting_items(preset.layout_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, distinguish_dark_aether=True, separator=" - ")
            ))
            self.spoiler_starting_items_label.setText("Random Starting Items: {}".format(
                ", ".join(extra_items)
                if extra_items else "None"
            ))

        else:
            pickup_names = {}
            self.layout_info_tab.removeTab(self.layout_info_tab.indexOf(self.pickup_tab))
            self.spoiler_starting_location_label.setText("Starting Location")
            self.spoiler_starting_items_label.setText("Random Starting Items")

        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 has_spoiler else "????"
                if has_spoiler and description.permalink.player_count > 1:
                    pickup_button.target_player = pickup_target.player
                    pickup_button.player_names = self._player_names
            else:
                pickup_button.item_name = "Nothing"

            if not pickup_button.item_is_hidden:
                pickup_button.setText(pickup_button.item_name)
Beispiel #28
0
def create_report(seeds_dir: str, output_file: str, csv_dir: Optional[str]):
    def item_creator():
        return collections.defaultdict(int)

    items = collections.defaultdict(item_creator)
    locations = collections.defaultdict(item_creator)
    item_hints = collections.defaultdict(item_creator)
    location_hints = collections.defaultdict(item_creator)

    game_description = default_prime2_game_description()
    world_list = game_description.world_list
    index_to_location = {
        node.pickup_index.index:
        (world_list.world_name_from_node(node, distinguish_dark_aether=True),
         world_list.node_name(node))
        for node in game_description.world_list.all_nodes
        if isinstance(node, PickupNode)
    }

    logbook_to_name = {
        str(node.string_asset_id): game_description.world_list.node_name(node)
        for node in game_description.world_list.all_nodes
        if isinstance(node, LogbookNode)
    }

    seed_count = 0
    pickup_count = None
    for seed in Path(seeds_dir).glob("**/*.json"):
        for game_modifications in read_json(seed)["game_modifications"]:
            accumulate_results(game_modifications, items, locations,
                               item_hints, location_hints, index_to_location,
                               logbook_to_name)
        if seed_count == 0:
            pickup_count = calculate_pickup_count(items)
        seed_count += 1

    if pickup_count is None:
        raise Exception("No seeds found")

    stddev_by_location = {
        location: calculate_stddev(pickup_count, locations[location])
        for location in locations.keys()
    }

    final_results = {
        "seed_count": seed_count,
        "stddev_by_location": {
            location: stddev
            for location, stddev in sorted(
                stddev_by_location.items(), key=lambda t: t[1], reverse=True)
        },
        "items": sort_by_contents(items),
        "locations": sort_by_contents(locations),
        "item_hints": sort_by_contents(item_hints),
        "location_hints": sort_by_contents(location_hints),
    }

    if csv_dir is not None:
        os.makedirs(csv_dir, exist_ok=True)
        for field in "items", "locations", "item_hints", "location_hints":
            data = final_results[field]

            possible_columns = set()
            for potential_values in data.values():
                possible_columns |= set(potential_values.keys())

            possible_columns = list(sorted(possible_columns))
            possible_columns.insert(0, "row_name")

            with open(os.path.join(csv_dir, field + ".csv"), "w",
                      newline='') as csv_file:
                writer = csv.DictWriter(csv_file, fieldnames=possible_columns)
                writer.writeheader()

                for column, row_data in data.items():
                    row_data = copy.copy(row_data)
                    row_data["row_name"] = column
                    writer.writerow(row_data)

    with open(output_file, "w") as output:
        json.dump(final_results, output, indent=4, separators=(',', ': '))