예제 #1
0
    async def _show_failed_generation_exception(self,
                                                exception: GenerationFailure):
        box = QtWidgets.QMessageBox(
            QtWidgets.QMessageBox.Critical,
            "An error occurred while generating game for {0.permalink.as_base64_str}"
            .format(exception), str(exception), QtWidgets.QMessageBox.Ok,
            self.parent)
        common_qt_lib.set_default_window_icon(box)

        if isinstance(exception.source, UnableToGenerate):
            box.setText(
                box.text() +
                "\n\nClick 'Show Details' to see a report of where the failure occurred.\n"
                "Double check if your settings aren't impossible, or try again."
            )
            box.setDetailedText(str(exception.source))

        elif isinstance(exception.source, ImpossibleForSolver):
            box.setText(
                box.text() +
                "\n\nRandovania sometimes generates games with insufficient Energy Tanks. "
                "Please try generating again.")

        elif isinstance(exception.source, multiprocessing.TimeoutError):
            box.setText(
                box.text() +
                "\n\nRandovania sometimes gets stuck infinitely when trying to verify a game, "
                "so there's a timeout. Please try generating again.")

        await async_dialog.execute_dialog(box)
예제 #2
0
    def __init__(self):
        super().__init__()
        self.setupUi(self)
        common_qt_lib.set_default_window_icon(self)

        self.refresh_button = QPushButton("Refresh")
        self.button_box.addButton(self.refresh_button, QDialogButtonBox.ResetRole)
        self.button_box.button(QDialogButtonBox.Ok).setEnabled(False)
        self.button_box.button(QDialogButtonBox.Ok).setText("Import")

        self.button_box.accepted.connect(self.attempt_join)
        self.button_box.rejected.connect(self.reject)
        self.refresh_button.clicked.connect(self.refresh)

        self._status_checks = (
            (self.status_open_check, "open"),
            (self.status_invitational_check, "invitational"),
            (self.status_pending_check, "pending"),
            (self.status_inprogress_check, "in_progress"),
            (self.status_finished_check, "finished"),
            (self.status_cancelled_check, "cancelled"),
        )
        for check, _ in self._status_checks:
            check.stateChanged.connect(self.update_list)
        self.filter_name_edit.textEdited.connect(self.update_list)

        self.table_widget.itemSelectionChanged.connect(self.on_selection_changed)
        self.table_widget.itemDoubleClicked.connect(self.on_double_click)
예제 #3
0
def display_exception(val: Exception):
    if not isinstance(val, KeyboardInterrupt):
        logging.exception("unhandled exception", exc_info=val)
        box = QtWidgets.QMessageBox(
            QtWidgets.QMessageBox.Critical,
            "An exception was raised",
            ("An unhandled Exception occurred:\n{}\n\n"
             "When reporting, make sure to paste the entire contents of the following box."
             "\nIt has already be copied to your clipboard."
             ).format(val),
            QtWidgets.QMessageBox.Ok,
        )
        from randovania.gui.lib import common_qt_lib
        common_qt_lib.set_default_window_icon(box)
        detailed_exception = "".join(traceback.format_exception(val))
        box.setDetailedText(detailed_exception)

        common_qt_lib.set_clipboard(detailed_exception)

        # Expand the detailed text
        for button in box.buttons():
            if box.buttonRole(button) == QtWidgets.QMessageBox.ActionRole:
                button.click()
                break

        box_layout: QtWidgets.QGridLayout = box.layout()
        box_layout.addItem(
            QtWidgets.QSpacerItem(600, 0, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding),
            box_layout.rowCount(), 0, 1, box_layout.columnCount(),
        )
        box.exec_()
예제 #4
0
    def __init__(self, options: Options, default_iso_name: str, spoiler: bool):
        super().__init__()
        self.setupUi(self)
        common_qt_lib.set_default_window_icon(self)

        self._options = options
        self.default_iso_name = default_iso_name
        self.check_extracted_game()

        # Input
        self.input_file_edit.textChanged.connect(self._validate_input_file)
        self.input_file_button.clicked.connect(self._on_input_file_button)

        # Output
        self.output_file_edit.textChanged.connect(self._validate_output_file)
        self.output_file_button.clicked.connect(self._on_output_file_button)

        # Spoiler
        self.auto_save_spoiler_check.setEnabled(spoiler)
        self.auto_save_spoiler_check.setChecked(options.auto_save_spoiler)

        # Accept/Reject
        self.accept_button.clicked.connect(self.accept)
        self.cancel_button.clicked.connect(self.reject)

        self.input_file_edit.has_error = False
        self.output_file_edit.has_error = False

        if options.output_directory is not None:
            self.output_file_edit.setText(str(options.output_directory.joinpath(self.default_iso_name)))

        self._validate_input_file()
        self._validate_output_file()
예제 #5
0
    def __init__(
        self,
        parent: QWidget,
        window_manager: WindowManager,
        game_description: GameDescription,
        areas_to_show: List[Tuple[World, Area]],
    ):
        super().__init__(parent)
        self.setupUi(self)
        set_default_window_icon(self)

        self._window_manager = window_manager
        self._game_description = game_description

        # setup
        self.area_list_label.linkActivated.connect(
            self._on_click_link_to_data_editor)

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

        # Update
        if areas_to_show:
            lines = [(
                f'<a href="data-editor://{world.correct_name(area.in_dark_aether)}/{area.name}">'
                f'{world.correct_name(area.in_dark_aether)} - {area.name}</a>')
                     for (world, area) in areas_to_show]
            self.area_list_label.setText("<br />".join(sorted(lines)))
        else:
            self.area_list_label.setText(
                "This trick is not used in this level.")
    def __init__(self):
        super().__init__()
        self.logger.setLevel(logging.DEBUG)
        self.window = QMainWindow()
        self.setupUi(self.window)
        common_qt_lib.set_default_window_icon(self.window)

        for status in enum_lib.iterate_enum(GameConnectionStatus):
            self.current_status_combo.addItem(status.pretty_text, status)

        self.permanent_pickups = []
        self.pickups = []

        self.collect_location_combo.setVisible(False)
        self.setup_collect_location_combo_button = QtWidgets.QPushButton(
            self.window)
        self.setup_collect_location_combo_button.setText(
            "Load list of locations")
        self.setup_collect_location_combo_button.clicked.connect(
            self._setup_locations_combo)
        self.gridLayout.addWidget(self.setup_collect_location_combo_button, 1,
                                  0, 1, 1)

        self.collect_location_button.clicked.connect(self._emit_collection)
        self.collect_location_button.setEnabled(False)

        self._expected_patches = dol_patcher.ALL_VERSIONS_PATCHES[0]
        # FIXME: use PAL again
        self.patches = self._expected_patches

        self._game_memory = bytearray(24 * (2**20))
        self._game_memory_initialized = False
        self.patches = None
예제 #7
0
    def __init__(self, network_client: QtNetworkClient):
        super().__init__()
        self.setupUi(self)
        common_qt_lib.set_default_window_icon(self)
        self.network_client = network_client

        self.refresh_button = QPushButton("Refresh")
        self.button_box.addButton(self.refresh_button,
                                  QDialogButtonBox.ResetRole)
        self.button_box.button(QDialogButtonBox.Ok).setEnabled(False)
        self.button_box.button(QDialogButtonBox.Ok).setText("Join")

        self.button_box.accepted.connect(self.attempt_join)
        self.button_box.rejected.connect(self.reject)
        self.refresh_button.clicked.connect(self.refresh)

        checks = (
            self.has_password_yes_check,
            self.has_password_no_check,
            self.state_setup_check,
            self.state_inprogress_check,
            self.state_finished_check,
        )
        for check in checks:
            check.stateChanged.connect(self.update_list)
        self.filter_name_edit.textEdited.connect(self.update_list)

        self.table_widget.itemSelectionChanged.connect(
            self.on_selection_changed)
        self.table_widget.itemDoubleClicked.connect(self.on_double_click)

        self.network_client.ConnectionStateUpdated.connect(
            self.on_server_connection_state_updated)
        self.on_server_connection_state_updated(
            self.network_client.connection_state)
예제 #8
0
    def __init__(self):
        super().__init__()
        self.window = QMainWindow()
        self.setupUi(self.window)
        common_qt_lib.set_default_window_icon(self.window)

        for status in enum_lib.iterate_enum(GameConnectionStatus):
            self.current_status_combo.addItem(status.pretty_text, status)

        self.permanent_pickups = []
        self.pickups = []

        self.collect_location_combo.setVisible(False)
        self.setup_collect_location_combo_button = QtWidgets.QPushButton(
            self.window)
        self.setup_collect_location_combo_button.setText(
            "Load list of locations")
        self.setup_collect_location_combo_button.clicked.connect(
            self._setup_locations_combo)
        self.gridLayout.addWidget(self.setup_collect_location_combo_button, 1,
                                  0, 1, 1)

        self.collect_location_button.clicked.connect(self._emit_collection)
        self.collect_location_button.setEnabled(False)

        self._expected_patches = dol_patcher.ALL_VERSIONS_PATCHES[1]
        self._game_memory = bytearray(24 * (2**20))
        self._write_memory(self._expected_patches.build_string_address,
                           self._expected_patches.build_string)

        # CPlayerState
        self._write_memory(
            self._expected_patches.string_display.cstate_manager_global +
            0x150c, 0xA00000.to_bytes(4, "big"))
예제 #9
0
    def __init__(self, options: Options, default_iso_name: str):
        super().__init__()
        self.setupUi(self)
        common_qt_lib.set_default_window_icon(self)

        self._options = options
        self.default_iso_name = default_iso_name
        self.check_extracted_game()

        # Input
        self.input_file_edit.textChanged.connect(self._validate_input_file)
        self.input_file_button.clicked.connect(self._on_input_file_button)

        # Output
        self.output_file_edit.textChanged.connect(self._validate_output_file)
        self.output_file_button.clicked.connect(self._on_output_file_button)

        # Accept/Reject
        self.accept_button.clicked.connect(self.accept)
        self.cancel_button.clicked.connect(self.reject)

        self.input_file_edit.has_error = False
        self.output_file_edit.has_error = False
        self._validate_input_file()
        self._validate_output_file()
예제 #10
0
    def __init__(self):
        super().__init__()
        self.window = QMainWindow()
        self.setupUi(self.window)
        common_qt_lib.set_default_window_icon(self.window)

        for status in iterate_enum(ConnectionStatus):
            self.current_status_combo.addItem(status.value, status)

        self.permanent_pickups = []
        self.pickups = []
        self._inventory = {}

        self.collect_location_combo.setVisible(False)
        self.setup_collect_location_combo_button = QtWidgets.QPushButton(
            self.window)
        self.setup_collect_location_combo_button.setText(
            "Load list of locations")
        self.setup_collect_location_combo_button.clicked.connect(
            self._setup_locations_combo)
        self.gridLayout.addWidget(self.setup_collect_location_combo_button, 1,
                                  0, 1, 1)

        self.collect_location_button.clicked.connect(self._emit_collection)
        self.collect_location_button.setEnabled(False)
예제 #11
0
    def __init__(self, data: dict, edit_mode: bool):
        super().__init__()
        self.setupUi(self)
        set_default_window_icon(self)

        self.edit_mode = edit_mode
        self.radio_button_to_node = {}

        self.world_selector_box.currentIndexChanged.connect(self.on_select_world)
        self.area_selector_box.currentIndexChanged.connect(self.on_select_area)
        self.node_details_label.linkActivated.connect(self._on_click_link_to_other_node)
        self.other_node_connection_edit_button.clicked.connect(self._open_edit_connection)

        self.save_database_button.clicked.connect(self._prompt_save_database)
        self.new_node_button.clicked.connect(self._create_new_node)
        self.delete_node_button.clicked.connect(self._remove_node)
        self.verticalLayout.setAlignment(Qt.AlignTop)
        self.alternatives_grid_layout = QGridLayout(self.other_node_alternatives_contents)

        world_reader, self.game_description = data_reader.decode_data_with_world_reader(data)
        self.generic_index = world_reader.generic_index

        self.resource_database = self.game_description.resource_database
        self.world_list = self.game_description.world_list

        for world in sorted(self.world_list.worlds, key=lambda x: x.name):
            self.world_selector_box.addItem("{0.name} ({0.dark_name})".format(world), userData=world)

        self.update_edit_mode()
예제 #12
0
    def __init__(self, network_client: QtNetworkClient):
        super().__init__()
        self.setupUi(self)
        common_qt_lib.set_default_window_icon(self)
        self.network_client = network_client

        login_methods = network_client.available_login_methods
        self.guest_button.setVisible("guest" in login_methods)
        self.discord_button.setEnabled("discord" in login_methods)
        self.discord_button.setToolTip("" if self.discord_button.isEnabled(
        ) else "This Randovania build is not configured to login with Discord."
                                       )
        self.privacy_policy_label.setText(
            self.privacy_policy_label.text().replace("color:#0000ff;", ""))

        self.button_box.button(
            QtWidgets.QDialogButtonBox.Reset).setText("Logout")

        # Signals
        self.network_client.ConnectionStateUpdated.connect(
            self.on_server_connection_state_updated)
        self.network_client.UserChanged.connect(self.on_user_changed)

        self.guest_button.clicked.connect(self.on_login_as_guest_button)
        self.discord_button.clicked.connect(self.on_login_with_discord_button)
        self.button_box.button(QtWidgets.QDialogButtonBox.Ok).clicked.connect(
            self.on_ok_button)
        self.button_box.button(
            QtWidgets.QDialogButtonBox.Reset).clicked.connect(
                self.on_logout_button)

        # Initial update
        self.on_user_changed(network_client.current_user)
예제 #13
0
    def __init__(self, game_connection: GameConnection, options: Options):
        super().__init__()
        self.setupUi(self)
        self.game_connection = game_connection
        self.options = options
        common_qt_lib.set_default_window_icon(self)

        self._action_to_theme = {
            self.action_theme_2d_style: TrackerTheme.CLASSIC,
            self.action_theme_game_icons: TrackerTheme.GAME,
        }

        theme_group = QActionGroup(self)
        for action, theme in self._action_to_theme.items():
            theme_group.addAction(action)
            action.setChecked(theme == options.tracker_theme)
            action.triggered.connect(self._on_action_theme)

        self._tracker_elements: List[Element] = []
        self.create_tracker(RandovaniaGame.PRIME2)

        self.game_connection_setup = GameConnectionSetup(
            self, self.game_connection_tool, self.connection_status_label,
            self.game_connection, options)
        self.force_update_button.clicked.connect(self.on_force_update_button)

        self._update_timer = QTimer(self)
        self._update_timer.setInterval(100)
        self._update_timer.timeout.connect(self._on_timer_update)
        self._update_timer.setSingleShot(True)
예제 #14
0
    def __init__(self):
        super().__init__()
        self.logger.setLevel(logging.DEBUG)
        self.window = QMainWindow()
        self.setupUi(self.window)
        common_qt_lib.set_default_window_icon(self.window)

        self.pickups = []

        self.collect_location_combo.setVisible(False)
        self.setup_collect_location_combo_button = QtWidgets.QPushButton(
            self.window)
        self.setup_collect_location_combo_button.setText(
            "Load list of locations")
        self.setup_collect_location_combo_button.clicked.connect(
            self._setup_locations_combo)
        self.gridLayout.addWidget(self.setup_collect_location_combo_button, 0,
                                  0, 1, 2)

        self.collect_location_button.clicked.connect(self._emit_collection)
        self.collect_location_button.setEnabled(False)
        self.collect_randomly_check.stateChanged.connect(
            self._on_collect_randomly_toggle)
        self._timer = QtCore.QTimer(self.window)
        self._timer.timeout.connect(self._collect_randomly)
        self._timer.setInterval(10000)

        self._used_version = echoes_dol_versions.ALL_VERSIONS[0]
        self._connector = EchoesRemoteConnector(self._used_version)
        self.game = default_database.game_description_for(
            RandovaniaGame.METROID_PRIME_ECHOES)

        self._game_memory = bytearray(24 * (2**20))
        self._game_memory_initialized = False
예제 #15
0
    def __init__(self, parent: QtWidgets.QWidget, db: ResourceDatabase):
        super().__init__(parent)
        self.setupUi(self)
        set_default_window_icon(self)

        self.db = db
        self.tab_item.setModel(ResourceDatabaseItemModel(db))
        self.tab_event.setModel(
            ResourceDatabaseGenericModel(db, ResourceType.EVENT))
        self.tab_trick.setModel(ResourceDatabaseTrickModel(db))
        self.tab_damage.setModel(
            ResourceDatabaseGenericModel(db, ResourceType.DAMAGE))
        self.tab_version.setModel(
            ResourceDatabaseGenericModel(db, ResourceType.VERSION))
        self.tab_misc.setModel(
            ResourceDatabaseGenericModel(db, ResourceType.MISC))

        for tab in self._all_tabs:
            tab.model().dataChanged.connect(
                functools.partial(self._on_data_changed, tab.model()))

        self.editor_for_template = {}
        for name in db.requirement_template.keys():
            self.create_template_editor(name)

        self.create_new_template_button = QtWidgets.QPushButton()
        self.create_new_template_button.setText("Create new")
        self.create_new_template_button.clicked.connect(
            self.create_new_template)
        self.tab_template_layout.addWidget(self.create_new_template_button)
예제 #16
0
    def __init__(self, game_connection: GameConnection, options: Options):
        super().__init__()
        self.setupUi(self)
        self.game_connection = game_connection
        common_qt_lib.set_default_window_icon(self)

        self.game_data = data_reader.decode_data(
            default_data.decode_default_prime2())
        self._energy_tank_item = find_resource_info_with_long_name(
            self.game_data.resource_database.item, "Energy Tank")

        self._item_to_label: Dict[ItemResourceInfo, ClickableLabel] = {}
        self._labels_for_keys = []
        self.create_tracker()

        self.game_connection_setup = GameConnectionSetup(
            self, self.game_connection_tool, self.connection_status_label,
            self.game_connection, options)
        self.force_update_button.setEnabled(not options.tracking_inventory)
        self.force_update_button.clicked.connect(self.on_force_update_button)

        self._update_timer = QTimer(self)
        self._update_timer.setInterval(100)
        self._update_timer.timeout.connect(self._on_timer_update)
        self._update_timer.setSingleShot(True)
예제 #17
0
    async def _show_dialog_for_prime3_layout(self):
        from randovania.games.patchers import gollop_corruption_patcher

        patches = self.layout_description.all_patches[
            self.current_player_index]
        game = default_database.game_description_for(RandovaniaGame.PRIME3)

        item_names = []
        for index in range(game.world_list.num_pickup_nodes):
            p_index = PickupIndex(index)
            if p_index in patches.pickup_assignment:
                name = patches.pickup_assignment[p_index].pickup.name
            else:
                name = "Missile Expansion"
            item_names.append(name)

        layout_string = gollop_corruption_patcher.layout_string_for_items(
            item_names)
        starting_location = patches.starting_location

        commands = "\n".join([
            f'set seed="{layout_string}"',
            f'set "starting_items={gollop_corruption_patcher.starting_items_for(patches.starting_items)}"',
            f'set "starting_location={gollop_corruption_patcher.starting_location_for(starting_location)}"',
        ])
        message_box = QtWidgets.QMessageBox(QtWidgets.QMessageBox.Information,
                                            "Commands for patcher", commands)
        common_qt_lib.set_default_window_icon(message_box)
        message_box.setTextInteractionFlags(Qt.TextSelectableByMouse)
        QApplication.clipboard().setText(commands)
        await async_dialog.execute_dialog(message_box)
예제 #18
0
    def __init__(
        self,
        parent: QWidget,
        window_manager: WindowManager,
        preset: Preset,
    ):

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

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

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

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

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

        if trick_level.minimal_logic:
            return

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

        lines = []

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

        self.area_list_label.setText("".join(lines))
예제 #19
0
    def __init__(self, text: str, title: str, parent: QtWidgets.QWidget):
        super().__init__(parent)
        self.setupUi(self)
        common_qt_lib.set_default_window_icon(self)
        self.setWindowTitle(title)
        self.label.setText(text)

        self.button_box.accepted.connect(self.accept)
    def __init__(self):
        super().__init__()
        self.setupUi(self)
        common_qt_lib.set_default_window_icon(self)

        self.background_tasks_button_lock_signal.connect(self.update_button_label)
        self.progress_update_signal.connect(self.update_progress)
        self.update_button.clicked.connect(self.on_button_press)
예제 #21
0
    def __init__(self, parent: QWidget, item: MajorItem, starting_state: MajorItemState,
                 resources_database: ResourceDatabase):
        super().__init__(parent)
        self.setupUi(self)
        set_default_window_icon(self)
        self._item = item

        self.setWindowTitle(f"Item: {item.name}")
        self.item_name_label.setText(item.name)

        # connect
        self.excluded_radio.toggled.connect(self._on_select_excluded)
        self.vanilla_radio.toggled.connect(self._on_select_vanilla)
        self.starting_radio.toggled.connect(self._on_select_starting)
        self.shuffled_radio.toggled.connect(self._on_select_shuffled)
        self.shuffled_spinbox.valueChanged.connect(self._on_shuffled_value)
        self.provided_ammo_spinbox.valueChanged.connect(self._on_shuffled_value)

        # Update
        self.vanilla_radio.setEnabled(item.original_index is not None)
        self.shuffled_radio.setEnabled(item.model_index is not None)

        if not self.vanilla_radio.isEnabled():
            self.vanilla_radio.setToolTip(
                "This item does not exist in the original game, so there's no vanilla location.")

        if not self.shuffled_radio.isEnabled():
            self.shuffled_radio.setToolTip(
                "There's currently no available model and/or logic for this item to be shuffled.")

        # At least one radio should be selected
        for radio in (self.shuffled_radio, self.starting_radio, self.vanilla_radio):
            if radio.isEnabled():
                radio.setChecked(True)
                break

        if item.ammo_index:
            self.provided_ammo_label.setText(
                "<html><head/><body><p>Provided Ammo ({})</p></body></html>".format(
                    " and ".join(
                        resources_database.get_item(ammo_index).long_name
                        for ammo_index in item.ammo_index
                    )
                )
            )
        else:
            self.provided_ammo_label.hide()
            self.provided_ammo_spinbox.hide()

        if self._item.required:
            self.item_name_label.setToolTip(
                "This item is necessary for the game to function properly and can't be removed.")
            self.setEnabled(False)
            self.state = self._create_state(num_included_in_starting_items=1)
        else:
            if self._item.warning is not None:
                self.item_name_label.setToolTip(self._item.warning)
            self.state = starting_state
예제 #22
0
    def __init__(self, persistence_path: Path, layout_configuration: LayoutConfiguration):
        super().__init__()
        self.setupUi(self)
        set_default_window_icon(self)

        self._collected_pickups = {}
        self._widget_for_pickup = {}
        self._actions = []
        self._asset_id_to_item = {}
        self._node_to_item = {}
        self.layout_configuration = layout_configuration
        self.persistence_path = persistence_path

        player_index = 0  # FIXME
        try:
            player_pool = generator.create_player_pool(None, self.layout_configuration, player_index)
        except base_patches_factory.MissingRng as e:
            raise InvalidLayoutForTracker("Layout is configured to have random {}, "
                                          "but that isn't supported by the tracker.".format(e))

        pool_patches = player_pool.patches
        self.game_description, self._initial_state = logic_bootstrap(layout_configuration,
                                                                     player_pool.game,
                                                                     pool_patches)
        self.logic = Logic(self.game_description, layout_configuration)

        self._initial_state.resources["add_self_as_requirement_to_resources"] = 1

        self.menu_reset_action.triggered.connect(self._confirm_reset)
        self.resource_filter_check.stateChanged.connect(self.update_locations_tree_for_reachable_nodes)
        self.hide_collected_resources_check.stateChanged.connect(self.update_locations_tree_for_reachable_nodes)
        self.undo_last_action_button.clicked.connect(self._undo_last_action)

        self.configuration_label.setText("Trick Level: {}; Elevators: Vanilla; Starts with:\n{}".format(
            layout_configuration.trick_level_configuration.global_level.value,
            ", ".join(
                resource.short_name
                for resource in pool_patches.starting_items.keys()
            )
        ))

        self.setup_pickups_box(player_pool.pickups)
        self.setup_possible_locations_tree()

        self._starting_nodes = {
            node
            for node in self.game_description.world_list.all_nodes
            if node.is_resource_node and node.resource() in self._initial_state.resources
        }

        persistence_path.mkdir(parents=True, exist_ok=True)
        previous_state = _load_previous_state(persistence_path, layout_configuration)

        if not self.apply_previous_state(previous_state):
            with persistence_path.joinpath("layout_configuration.json").open("w") as layout_file:
                json.dump(layout_configuration.as_json, layout_file)
            self._add_new_action(self._initial_state.node)
예제 #23
0
    def __init__(self, options: Options, preset_manager: PresetManager, preview: bool):
        super().__init__()
        self.setupUi(self)
        self.setWindowTitle("Randovania {}".format(VERSION))
        self.is_preview_mode = preview
        self.setAcceptDrops(True)
        common_qt_lib.set_default_window_icon(self)

        self.intro_label.setText(self.intro_label.text().format(version=VERSION))

        self._preset_manager = preset_manager

        if preview:
            debug.set_level(2)

        # Signals
        self.newer_version_signal.connect(self.display_new_version)
        self.background_tasks_button_lock_signal.connect(self.enable_buttons_with_background_tasks)
        self.progress_update_signal.connect(self.update_progress)
        self.stop_background_process_button.clicked.connect(self.stop_background_process)
        self.options_changed_signal.connect(self.on_options_changed)

        self.intro_play_now_button.clicked.connect(lambda: self.welcome_tab_widget.setCurrentWidget(self.tab_play))
        self.open_faq_button.clicked.connect(self._open_faq)
        self.open_database_viewer_button.clicked.connect(self._open_data_visualizer)

        self.import_permalink_button.clicked.connect(self._import_permalink)
        self.create_new_seed_button.clicked.connect(
            lambda: self.welcome_tab_widget.setCurrentWidget(self.tab_create_seed))

        # Menu Bar
        self.menu_action_data_visualizer.triggered.connect(self._open_data_visualizer)
        self.menu_action_item_tracker.triggered.connect(self._open_item_tracker)
        self.menu_action_edit_new_database.triggered.connect(self._open_data_editor_default)
        self.menu_action_edit_existing_database.triggered.connect(self._open_data_editor_prompt)
        self.menu_action_validate_seed_after.triggered.connect(self._on_validate_seed_change)
        self.menu_action_timeout_generation_after_a_time_limit.triggered.connect(self._on_generate_time_limit_change)

        self.generate_seed_tab = GenerateSeedTab(self, self, self, options)
        self.generate_seed_tab.setup_ui()
        self._details_window = SeedDetailsWindow(self, self, options)
        self._details_window.added_to_tab = False

        # Needs the GenerateSeedTab
        self._create_open_map_tracker_actions()

        # Setting this event only now, so all options changed trigger only once
        options.on_options_changed = self.options_changed_signal.emit
        self._options = options
        with options:
            self.on_options_changed()

        self.main_tab_widget.setCurrentIndex(0)

        # Update hints text
        self._update_hints_text()
예제 #24
0
async def message_box(parent: Optional[QtWidgets.QWidget],
                      icon: QtWidgets.QMessageBox.Icon,
                      title: str, text: str,
                      buttons: QtWidgets.QMessageBox.StandardButtons = QtWidgets.QMessageBox.Ok,
                      default_button: QtWidgets.QMessageBox.StandardButton = QtWidgets.QMessageBox.NoButton,
                      ) -> QtWidgets.QMessageBox.StandardButton:
    box = QtWidgets.QMessageBox(icon, title, text, buttons, parent)
    box.setDefaultButton(default_button)
    common_qt_lib.set_default_window_icon(box)
    return await execute_dialog(box)
예제 #25
0
    def __init__(self, persistence_path: Path,
                 layout_configuration: LayoutConfiguration):
        super().__init__()
        self.setupUi(self)
        set_default_window_icon(self)

        self._collected_pickups = {}
        self._widget_for_pickup = {}
        self._actions = []
        self._asset_id_to_item = {}
        self._node_to_item = {}
        self.layout_configuration = layout_configuration
        self.persistence_path = persistence_path

        player_pool = generator.create_player_pool(Random(0),
                                                   self.layout_configuration,
                                                   0)
        pool_patches = player_pool.patches
        self.game_description, self._initial_state = logic_bootstrap(
            layout_configuration, player_pool.game, pool_patches)
        self.logic = Logic(self.game_description, layout_configuration)

        self._initial_state.resources[
            "add_self_as_requirement_to_resources"] = 1

        self.menu_reset_action.triggered.connect(self._confirm_reset)
        self.resource_filter_check.stateChanged.connect(
            self.update_locations_tree_for_reachable_nodes)
        self.hide_collected_resources_check.stateChanged.connect(
            self.update_locations_tree_for_reachable_nodes)
        self.undo_last_action_button.clicked.connect(self._undo_last_action)

        self.configuration_label.setText(
            "Trick Level: {}; Starts with:\n{}".format(
                layout_configuration.trick_level_configuration.
                pretty_description,
                ", ".join(resource.short_name
                          for resource in pool_patches.starting_items.keys())))

        self.setup_pickups_box(player_pool.pickups)
        self.setup_possible_locations_tree()
        self.setup_elevators()
        self.setup_translator_gates()

        persistence_path.mkdir(parents=True, exist_ok=True)
        previous_state = _load_previous_state(persistence_path,
                                              layout_configuration)

        if not self.apply_previous_state(previous_state):
            self.setup_starting_location(None)

            with persistence_path.joinpath("layout_configuration.json").open(
                    "w") as layout_file:
                json.dump(layout_configuration.as_json, layout_file)
            self._add_new_action(self._initial_state.node)
예제 #26
0
    def __init__(self, user_data_dir: Path):
        super().__init__()
        NetworkClient.__init__(self, user_data_dir.joinpath("network_client"), randovania.get_configuration())
        from randovania.gui.lib import common_qt_lib
        common_qt_lib.set_default_window_icon(self)

        if self.configuration.get("discord_client_id") is not None:
            self.discord = pypresence.AioClient(self.configuration["discord_client_id"])
            self.discord._events_on = False  # workaround for broken AioClient
        else:
            self.discord = None
예제 #27
0
    def __init__(self, options: Options, patch_data: dict, word_hash: str, spoiler: bool, games: list[RandovaniaGame]):
        super().__init__()
        common_qt_lib.set_default_window_icon(self)
        self._options = options
        self._patch_data = patch_data
        self._word_hash = word_hash
        self._has_spoiler = spoiler
        self._games = games

        if (func := _try_get_field(self, "setupUi", None)) is not None:
            func(self)
예제 #28
0
def display_exception(val: Exception):
    if not isinstance(val, KeyboardInterrupt):
        box = QtWidgets.QMessageBox(QtWidgets.QMessageBox.Critical,
                                    "An exception was raised",
                                    "An unhandled Exception occurred:\n{}".format(val),
                                    QtWidgets.QMessageBox.Ok)
        from randovania.gui.lib import common_qt_lib
        common_qt_lib.set_default_window_icon(box)
        if val.__traceback__ is not None:
            box.setDetailedText("".join(traceback.format_tb(val.__traceback__)))
        box.exec_()
예제 #29
0
    def __init__(self, window_manager: Optional[WindowManager],
                 options: Options):
        super().__init__()
        self.setupUi(self)
        set_default_window_icon(self)

        self._options = options
        self._window_manager = window_manager
        self._game_details_tabs = []

        # Ui
        self._tool_button_menu = QtWidgets.QMenu(self.tool_button)
        self.tool_button.setMenu(self._tool_button_menu)

        self._action_open_tracker = QtGui.QAction(self)
        self._action_open_tracker.setText("Open map tracker")
        self._action_open_tracker.setEnabled(self._window_manager is not None)
        self._tool_button_menu.addAction(self._action_open_tracker)

        self._action_copy_permalink = QtGui.QAction(self)
        self._action_copy_permalink.setText("Copy Permalink")
        self._tool_button_menu.addAction(self._action_copy_permalink)

        self._action_export_preset = QtGui.QAction(self)
        self._action_export_preset.setText("Export current player's preset")
        self._tool_button_menu.addAction(self._action_export_preset)

        self._action_view_trick_usages = QtGui.QAction(self)
        self._action_view_trick_usages.setText(
            "View current player's expected trick usage")
        self._tool_button_menu.addAction(self._action_view_trick_usages)

        # Signals
        self.export_log_button.clicked.connect(self._export_log)
        self.export_iso_button.clicked.connect(self._export_iso)
        self._action_open_tracker.triggered.connect(self._open_map_tracker)
        self._action_copy_permalink.triggered.connect(self._copy_permalink)
        self._action_export_preset.triggered.connect(self._export_preset)
        self._action_view_trick_usages.triggered.connect(
            self._view_trick_usages)
        self.player_index_combo.activated.connect(self._update_current_player)
        self.CloseEvent.connect(self.stop_background_process)

        # Progress
        self.background_tasks_button_lock_signal.connect(
            self.enable_buttons_with_background_tasks)
        self.progress_update_signal.connect(self.update_progress)
        self.stop_background_process_button.clicked.connect(
            self.stop_background_process)

        # Cosmetic
        self.customize_user_preferences_button.clicked.connect(
            self._open_user_preferences_dialog)
예제 #30
0
    def __init__(self, window_manager: Optional[WindowManager],
                 options: Options):
        super().__init__()
        self.setupUi(self)
        set_default_window_icon(self)

        self._history_items = []
        self.pickup_spoiler_buttons = []
        self._pickup_spoiler_world_to_group = {}
        self._options = options
        self._window_manager = window_manager

        # Ui
        self._tool_button_menu = QMenu(self.tool_button)
        self.tool_button.setMenu(self._tool_button_menu)

        self._action_open_tracker = QAction(self)
        self._action_open_tracker.setText("Open map tracker")
        self._action_open_tracker.setEnabled(self._window_manager is not None)
        self._tool_button_menu.addAction(self._action_open_tracker)

        self._action_copy_permalink = QAction(self)
        self._action_copy_permalink.setText("Copy Permalink")
        self._tool_button_menu.addAction(self._action_copy_permalink)

        self._action_open_dolphin = QAction(self)
        self._action_open_dolphin.setText("Open Dolphin Hook")
        self._tool_button_menu.addAction(self._action_open_dolphin)
        self._action_open_dolphin.setVisible(False)

        # Signals
        self.export_log_button.clicked.connect(self._export_log)
        self.export_iso_button.clicked.connect(self._export_iso)
        self._action_open_tracker.triggered.connect(self._open_map_tracker)
        self._action_copy_permalink.triggered.connect(self._copy_permalink)
        self.pickup_spoiler_pickup_combobox.currentTextChanged.connect(
            self._on_change_pickup_filter)
        self.pickup_spoiler_show_all_button.clicked.connect(
            self._toggle_show_all_pickup_spoiler)
        self.player_index_combo.activated.connect(self._update_current_player)
        self.CloseEvent.connect(self.stop_background_process)

        # Progress
        self.background_tasks_button_lock_signal.connect(
            self.enable_buttons_with_background_tasks)
        self.progress_update_signal.connect(self.update_progress)
        self.stop_background_process_button.clicked.connect(
            self.stop_background_process)

        # Cosmetic
        self.customize_user_preferences_button.clicked.connect(
            self._open_user_preferences_dialog)