mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2025-01-19 06:45:39 +00:00
Merge pull request #1724 from stenzek/cheevos-hardcore-mode
Cheevos: Implement hardcore mode
This commit is contained in:
commit
a8a1a9efd5
|
@ -66,7 +66,7 @@
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="label_3">
|
<widget class="QLabel" name="label_3">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Please enter user name and password for retroachievements.org below. Your password will not be saved in DuckStation, instead an access token will be generated and used instead.</string>
|
<string>Please enter user name and password for retroachievements.org below. Your password will not be saved in DuckStation, an access token will be generated and used instead.</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="wordWrap">
|
<property name="wordWrap">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include "common/string_util.h"
|
#include "common/string_util.h"
|
||||||
#include "core/system.h"
|
#include "core/system.h"
|
||||||
#include "frontend-common/cheevos.h"
|
#include "frontend-common/cheevos.h"
|
||||||
|
#include "mainwindow.h"
|
||||||
#include "qtutils.h"
|
#include "qtutils.h"
|
||||||
#include "settingsdialog.h"
|
#include "settingsdialog.h"
|
||||||
#include "settingwidgetbinder.h"
|
#include "settingwidgetbinder.h"
|
||||||
|
@ -15,11 +16,12 @@ AchievementSettingsWidget::AchievementSettingsWidget(QtHostInterface* host_inter
|
||||||
{
|
{
|
||||||
m_ui.setupUi(this);
|
m_ui.setupUi(this);
|
||||||
|
|
||||||
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.enable, "Cheevos", "Enabled", false);
|
|
||||||
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.richPresence, "Cheevos", "RichPresence", true);
|
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.richPresence, "Cheevos", "RichPresence", true);
|
||||||
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.testMode, "Cheevos", "TestMode", false);
|
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.testMode, "Cheevos", "TestMode", false);
|
||||||
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.useFirstDiscFromPlaylist, "Cheevos",
|
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.useFirstDiscFromPlaylist, "Cheevos",
|
||||||
"UseFirstDiscFromPlaylist", true);
|
"UseFirstDiscFromPlaylist", true);
|
||||||
|
m_ui.enable->setChecked(m_host_interface->GetBoolSettingValue("Cheevos", "Enabled", false));
|
||||||
|
m_ui.challengeMode->setChecked(m_host_interface->GetBoolSettingValue("Cheevos", "ChallengeMode", false));
|
||||||
|
|
||||||
dialog->registerWidgetHelp(m_ui.enable, tr("Enable Achievements"), tr("Unchecked"),
|
dialog->registerWidgetHelp(m_ui.enable, tr("Enable Achievements"), tr("Unchecked"),
|
||||||
tr("When enabled and logged in, DuckStation will scan for achievements on startup."));
|
tr("When enabled and logged in, DuckStation will scan for achievements on startup."));
|
||||||
|
@ -33,10 +35,14 @@ AchievementSettingsWidget::AchievementSettingsWidget(QtHostInterface* host_inter
|
||||||
m_ui.useFirstDiscFromPlaylist, tr("Use First Disc From Playlist"), tr("Unchecked"),
|
m_ui.useFirstDiscFromPlaylist, tr("Use First Disc From Playlist"), tr("Unchecked"),
|
||||||
tr(
|
tr(
|
||||||
"When enabled, the first disc in a playlist will be used for achievements, regardless of which disc is active."));
|
"When enabled, the first disc in a playlist will be used for achievements, regardless of which disc is active."));
|
||||||
|
dialog->registerWidgetHelp(m_ui.challengeMode, tr("Enable Hardcore Mode"), tr("Unchecked"),
|
||||||
|
tr("\"Challenge\" mode for achievements. Disables save state, cheats, and slowdown "
|
||||||
|
"functions, but you receive double the achievement points."));
|
||||||
|
|
||||||
connect(m_ui.enable, &QCheckBox::stateChanged, this, &AchievementSettingsWidget::updateEnableState);
|
connect(m_ui.enable, &QCheckBox::toggled, this, &AchievementSettingsWidget::onEnableToggled);
|
||||||
connect(m_ui.loginButton, &QPushButton::clicked, this, &AchievementSettingsWidget::onLoginLogoutPressed);
|
connect(m_ui.loginButton, &QPushButton::clicked, this, &AchievementSettingsWidget::onLoginLogoutPressed);
|
||||||
connect(m_ui.viewProfile, &QPushButton::clicked, this, &AchievementSettingsWidget::onViewProfilePressed);
|
connect(m_ui.viewProfile, &QPushButton::clicked, this, &AchievementSettingsWidget::onViewProfilePressed);
|
||||||
|
connect(m_ui.challengeMode, &QCheckBox::toggled, this, &AchievementSettingsWidget::onChallengeModeToggled);
|
||||||
connect(host_interface, &QtHostInterface::achievementsLoaded, this, &AchievementSettingsWidget::onAchievementsLoaded);
|
connect(host_interface, &QtHostInterface::achievementsLoaded, this, &AchievementSettingsWidget::onAchievementsLoaded);
|
||||||
|
|
||||||
updateEnableState();
|
updateEnableState();
|
||||||
|
@ -51,9 +57,11 @@ AchievementSettingsWidget::~AchievementSettingsWidget() = default;
|
||||||
void AchievementSettingsWidget::updateEnableState()
|
void AchievementSettingsWidget::updateEnableState()
|
||||||
{
|
{
|
||||||
const bool enabled = m_host_interface->GetBoolSettingValue("Cheevos", "Enabled", false);
|
const bool enabled = m_host_interface->GetBoolSettingValue("Cheevos", "Enabled", false);
|
||||||
|
const bool challenge_mode = m_host_interface->GetBoolSettingValue("Cheevos", "ChallengeMode", false);
|
||||||
m_ui.testMode->setEnabled(enabled);
|
m_ui.testMode->setEnabled(enabled);
|
||||||
m_ui.useFirstDiscFromPlaylist->setEnabled(enabled);
|
m_ui.useFirstDiscFromPlaylist->setEnabled(enabled);
|
||||||
m_ui.richPresence->setEnabled(enabled);
|
m_ui.richPresence->setEnabled(enabled);
|
||||||
|
m_ui.challengeMode->setEnabled(enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AchievementSettingsWidget::updateLoginState()
|
void AchievementSettingsWidget::updateLoginState()
|
||||||
|
@ -98,17 +106,73 @@ void AchievementSettingsWidget::onLoginLogoutPressed()
|
||||||
|
|
||||||
void AchievementSettingsWidget::onViewProfilePressed()
|
void AchievementSettingsWidget::onViewProfilePressed()
|
||||||
{
|
{
|
||||||
if (!Cheevos::IsLoggedIn())
|
const std::string username(m_host_interface->GetStringSettingValue("Cheevos", "Username"));
|
||||||
|
if (username.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const QByteArray encoded_username(QUrl::toPercentEncoding(QString::fromStdString(Cheevos::GetUsername())));
|
const QByteArray encoded_username(QUrl::toPercentEncoding(QString::fromStdString(username)));
|
||||||
QtUtils::OpenURL(
|
QtUtils::OpenURL(
|
||||||
QtUtils::GetRootWidget(this),
|
QtUtils::GetRootWidget(this),
|
||||||
QUrl(QStringLiteral("https://retroachievements.org/user/%1").arg(QString::fromUtf8(encoded_username))));
|
QUrl(QStringLiteral("https://retroachievements.org/user/%1").arg(QString::fromUtf8(encoded_username))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AchievementSettingsWidget::onEnableToggled(bool checked)
|
||||||
|
{
|
||||||
|
const bool challenge_mode = m_host_interface->GetBoolSettingValue("Cheevos", "ChallengeMode", false);
|
||||||
|
const bool challenge_mode_active = checked && challenge_mode;
|
||||||
|
if (challenge_mode_active && !confirmChallengeModeEnable())
|
||||||
|
{
|
||||||
|
QSignalBlocker sb(m_ui.challengeMode);
|
||||||
|
m_ui.challengeMode->setChecked(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_host_interface->SetBoolSettingValue("Cheevos", "Enabled", checked);
|
||||||
|
m_host_interface->applySettings(false);
|
||||||
|
|
||||||
|
if (challenge_mode)
|
||||||
|
m_host_interface->getMainWindow()->onAchievementsChallengeModeToggled(challenge_mode_active);
|
||||||
|
|
||||||
|
updateEnableState();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AchievementSettingsWidget::onChallengeModeToggled(bool checked)
|
||||||
|
{
|
||||||
|
if (checked && !confirmChallengeModeEnable())
|
||||||
|
{
|
||||||
|
QSignalBlocker sb(m_ui.challengeMode);
|
||||||
|
m_ui.challengeMode->setChecked(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_host_interface->SetBoolSettingValue("Cheevos", "ChallengeMode", checked);
|
||||||
|
m_host_interface->applySettings(false);
|
||||||
|
m_host_interface->getMainWindow()->onAchievementsChallengeModeToggled(checked);
|
||||||
|
}
|
||||||
|
|
||||||
void AchievementSettingsWidget::onAchievementsLoaded(quint32 id, const QString& game_info_string, quint32 total,
|
void AchievementSettingsWidget::onAchievementsLoaded(quint32 id, const QString& game_info_string, quint32 total,
|
||||||
quint32 points)
|
quint32 points)
|
||||||
{
|
{
|
||||||
m_ui.gameInfo->setText(game_info_string);
|
m_ui.gameInfo->setText(game_info_string);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AchievementSettingsWidget::confirmChallengeModeEnable()
|
||||||
|
{
|
||||||
|
if (!System::IsValid())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
QString message = tr("Enabling hardcore mode will shut down your current game.\n\n");
|
||||||
|
|
||||||
|
if (m_host_interface->ShouldSaveResumeState())
|
||||||
|
{
|
||||||
|
message +=
|
||||||
|
tr("The current state will be saved, but you will be unable to load it until you disable hardcore mode.\n\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
message += tr("Do you want to continue?");
|
||||||
|
if (QMessageBox::question(QtUtils::GetRootWidget(this), tr("Enable Hardcore Mode"), message) != QMessageBox::Yes)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
m_host_interface->synchronousPowerOffSystem();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
|
@ -14,13 +14,17 @@ public:
|
||||||
~AchievementSettingsWidget();
|
~AchievementSettingsWidget();
|
||||||
|
|
||||||
private Q_SLOTS:
|
private Q_SLOTS:
|
||||||
void updateEnableState();
|
void onEnableToggled(bool checked);
|
||||||
void updateLoginState();
|
void onChallengeModeToggled(bool checked);
|
||||||
void onLoginLogoutPressed();
|
void onLoginLogoutPressed();
|
||||||
void onViewProfilePressed();
|
void onViewProfilePressed();
|
||||||
void onAchievementsLoaded(quint32 id, const QString& game_info_string, quint32 total, quint32 points);
|
void onAchievementsLoaded(quint32 id, const QString& game_info_string, quint32 total, quint32 points);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool confirmChallengeModeEnable();
|
||||||
|
void updateEnableState();
|
||||||
|
void updateLoginState();
|
||||||
|
|
||||||
Ui::AchievementSettingsWidget m_ui;
|
Ui::AchievementSettingsWidget m_ui;
|
||||||
|
|
||||||
QtHostInterface* m_host_interface;
|
QtHostInterface* m_host_interface;
|
||||||
|
|
|
@ -60,6 +60,13 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QCheckBox" name="challengeMode">
|
||||||
|
<property name="text">
|
||||||
|
<string>Enable Hardcore Mode</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
@ -97,32 +104,6 @@
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
|
||||||
<widget class="QGroupBox" name="groupBox_3">
|
|
||||||
<property name="title">
|
|
||||||
<string>Account Settings</string>
|
|
||||||
</property>
|
|
||||||
<layout class="QGridLayout" name="gridLayout_2">
|
|
||||||
<item row="0" column="0">
|
|
||||||
<widget class="QCheckBox" name="hardcoreMode">
|
|
||||||
<property name="enabled">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Enable Hardcore Mode</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="0">
|
|
||||||
<widget class="QLabel" name="label_2">
|
|
||||||
<property name="text">
|
|
||||||
<string>Enabling hardcore mode will disable cheats, save sates, and debugging features.</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
<item>
|
||||||
<widget class="QGroupBox" name="groupBox_4">
|
<widget class="QGroupBox" name="groupBox_4">
|
||||||
<property name="minimumSize">
|
<property name="minimumSize">
|
||||||
|
|
|
@ -354,7 +354,7 @@ void MainWindow::updateMouseMode(bool paused)
|
||||||
void MainWindow::onEmulationStarting()
|
void MainWindow::onEmulationStarting()
|
||||||
{
|
{
|
||||||
m_emulation_running = true;
|
m_emulation_running = true;
|
||||||
updateEmulationActions(true, false);
|
updateEmulationActions(true, false, m_host_interface->IsCheevosChallengeModeActive());
|
||||||
|
|
||||||
// ensure it gets updated, since the boot can take a while
|
// ensure it gets updated, since the boot can take a while
|
||||||
QGuiApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
|
QGuiApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
|
||||||
|
@ -362,13 +362,13 @@ void MainWindow::onEmulationStarting()
|
||||||
|
|
||||||
void MainWindow::onEmulationStarted()
|
void MainWindow::onEmulationStarted()
|
||||||
{
|
{
|
||||||
updateEmulationActions(false, true);
|
updateEmulationActions(false, true, m_host_interface->IsCheevosChallengeModeActive());
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::onEmulationStopped()
|
void MainWindow::onEmulationStopped()
|
||||||
{
|
{
|
||||||
m_emulation_running = false;
|
m_emulation_running = false;
|
||||||
updateEmulationActions(false, false);
|
updateEmulationActions(false, false, m_host_interface->IsCheevosChallengeModeActive());
|
||||||
switchToGameListView();
|
switchToGameListView();
|
||||||
|
|
||||||
if (m_cheat_manager_dialog)
|
if (m_cheat_manager_dialog)
|
||||||
|
@ -610,7 +610,8 @@ void MainWindow::onGameListEntryDoubleClicked(const GameListEntry* entry)
|
||||||
QString path = QString::fromStdString(entry->path);
|
QString path = QString::fromStdString(entry->path);
|
||||||
if (!m_emulation_running)
|
if (!m_emulation_running)
|
||||||
{
|
{
|
||||||
if (!entry->code.empty() && m_host_interface->GetBoolSettingValue("Main", "SaveStateOnExit", true))
|
if (!entry->code.empty() && m_host_interface->GetBoolSettingValue("Main", "SaveStateOnExit", true) &&
|
||||||
|
!m_host_interface->IsCheevosChallengeModeActive())
|
||||||
{
|
{
|
||||||
m_host_interface->resumeSystemFromState(path, true);
|
m_host_interface->resumeSystemFromState(path, true);
|
||||||
}
|
}
|
||||||
|
@ -670,7 +671,7 @@ void MainWindow::onGameListContextMenuRequested(const QPoint& point, const GameL
|
||||||
m_host_interface->bootSystem(std::move(boot_params));
|
m_host_interface->bootSystem(std::move(boot_params));
|
||||||
});
|
});
|
||||||
|
|
||||||
if (m_ui.menuDebug->menuAction()->isVisible())
|
if (m_ui.menuDebug->menuAction()->isVisible() && !m_host_interface->IsCheevosChallengeModeActive())
|
||||||
{
|
{
|
||||||
connect(menu.addAction(tr("Boot and Debug")), &QAction::triggered, [this, entry]() {
|
connect(menu.addAction(tr("Boot and Debug")), &QAction::triggered, [this, entry]() {
|
||||||
m_open_debugger_on_start = true;
|
m_open_debugger_on_start = true;
|
||||||
|
@ -841,27 +842,27 @@ void MainWindow::setupAdditionalUi()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::updateEmulationActions(bool starting, bool running)
|
void MainWindow::updateEmulationActions(bool starting, bool running, bool cheevos_challenge_mode)
|
||||||
{
|
{
|
||||||
m_ui.actionStartDisc->setDisabled(starting || running);
|
m_ui.actionStartDisc->setDisabled(starting || running);
|
||||||
m_ui.actionStartBios->setDisabled(starting || running);
|
m_ui.actionStartBios->setDisabled(starting || running);
|
||||||
m_ui.actionResumeLastState->setDisabled(starting || running);
|
m_ui.actionResumeLastState->setDisabled(starting || running || cheevos_challenge_mode);
|
||||||
|
|
||||||
m_ui.actionPowerOff->setDisabled(starting || !running);
|
m_ui.actionPowerOff->setDisabled(starting || !running);
|
||||||
m_ui.actionPowerOffWithoutSaving->setDisabled(starting || !running);
|
m_ui.actionPowerOffWithoutSaving->setDisabled(starting || !running);
|
||||||
m_ui.actionReset->setDisabled(starting || !running);
|
m_ui.actionReset->setDisabled(starting || !running);
|
||||||
m_ui.actionPause->setDisabled(starting || !running);
|
m_ui.actionPause->setDisabled(starting || !running);
|
||||||
m_ui.actionChangeDisc->setDisabled(starting || !running);
|
m_ui.actionChangeDisc->setDisabled(starting || !running);
|
||||||
m_ui.actionCheats->setDisabled(starting || !running);
|
m_ui.actionCheats->setDisabled(starting || !running || cheevos_challenge_mode);
|
||||||
m_ui.actionScreenshot->setDisabled(starting || !running);
|
m_ui.actionScreenshot->setDisabled(starting || !running);
|
||||||
m_ui.actionViewSystemDisplay->setEnabled(starting || running);
|
m_ui.actionViewSystemDisplay->setEnabled(starting || running);
|
||||||
m_ui.menuChangeDisc->setDisabled(starting || !running);
|
m_ui.menuChangeDisc->setDisabled(starting || !running);
|
||||||
m_ui.menuCheats->setDisabled(starting || !running);
|
m_ui.menuCheats->setDisabled(starting || !running || cheevos_challenge_mode);
|
||||||
m_ui.actionCheatManager->setDisabled(starting || !running);
|
m_ui.actionCheatManager->setDisabled(starting || !running || cheevos_challenge_mode);
|
||||||
m_ui.actionCPUDebugger->setDisabled(starting || !running);
|
m_ui.actionCPUDebugger->setDisabled(starting || !running || cheevos_challenge_mode);
|
||||||
m_ui.actionDumpRAM->setDisabled(starting || !running);
|
m_ui.actionDumpRAM->setDisabled(starting || !running || cheevos_challenge_mode);
|
||||||
m_ui.actionDumpVRAM->setDisabled(starting || !running);
|
m_ui.actionDumpVRAM->setDisabled(starting || !running || cheevos_challenge_mode);
|
||||||
m_ui.actionDumpSPURAM->setDisabled(starting || !running);
|
m_ui.actionDumpSPURAM->setDisabled(starting || !running || cheevos_challenge_mode);
|
||||||
|
|
||||||
m_ui.actionSaveState->setDisabled(starting || !running);
|
m_ui.actionSaveState->setDisabled(starting || !running);
|
||||||
m_ui.menuSaveState->setDisabled(starting || !running);
|
m_ui.menuSaveState->setDisabled(starting || !running);
|
||||||
|
@ -869,6 +870,9 @@ void MainWindow::updateEmulationActions(bool starting, bool running)
|
||||||
|
|
||||||
m_ui.actionFullscreen->setDisabled(starting || !running);
|
m_ui.actionFullscreen->setDisabled(starting || !running);
|
||||||
|
|
||||||
|
m_ui.actionLoadState->setDisabled(cheevos_challenge_mode);
|
||||||
|
m_ui.menuLoadState->setDisabled(cheevos_challenge_mode);
|
||||||
|
|
||||||
if (running && m_status_speed_widget->isHidden())
|
if (running && m_status_speed_widget->isHidden())
|
||||||
{
|
{
|
||||||
m_status_speed_widget->show();
|
m_status_speed_widget->show();
|
||||||
|
@ -945,7 +949,7 @@ void MainWindow::switchToEmulationView()
|
||||||
|
|
||||||
void MainWindow::connectSignals()
|
void MainWindow::connectSignals()
|
||||||
{
|
{
|
||||||
updateEmulationActions(false, false);
|
updateEmulationActions(false, false, m_host_interface->IsCheevosChallengeModeActive());
|
||||||
onEmulationPaused(false);
|
onEmulationPaused(false);
|
||||||
|
|
||||||
connect(qApp, &QGuiApplication::applicationStateChanged, this, &MainWindow::onApplicationStateChanged);
|
connect(qApp, &QGuiApplication::applicationStateChanged, this, &MainWindow::onApplicationStateChanged);
|
||||||
|
@ -1458,6 +1462,28 @@ void MainWindow::openMemoryCardEditor(const QString& card_a_path, const QString&
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::onAchievementsChallengeModeToggled(bool enabled)
|
||||||
|
{
|
||||||
|
if (enabled)
|
||||||
|
{
|
||||||
|
if (m_cheat_manager_dialog)
|
||||||
|
{
|
||||||
|
m_cheat_manager_dialog->close();
|
||||||
|
delete m_cheat_manager_dialog;
|
||||||
|
m_cheat_manager_dialog = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_debugger_window)
|
||||||
|
{
|
||||||
|
m_debugger_window->close();
|
||||||
|
delete m_debugger_window;
|
||||||
|
m_debugger_window = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateEmulationActions(false, System::IsValid(), enabled);
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::onToolsMemoryCardEditorTriggered()
|
void MainWindow::onToolsMemoryCardEditorTriggered()
|
||||||
{
|
{
|
||||||
openMemoryCardEditor(QString(), QString());
|
openMemoryCardEditor(QString(), QString());
|
||||||
|
|
|
@ -40,6 +40,9 @@ public:
|
||||||
/// Opens memory card editor with the specified paths.
|
/// Opens memory card editor with the specified paths.
|
||||||
void openMemoryCardEditor(const QString& card_a_path, const QString& card_b_path);
|
void openMemoryCardEditor(const QString& card_a_path, const QString& card_b_path);
|
||||||
|
|
||||||
|
/// Updates the state of the controls which should be disabled by achievements challenge mode.
|
||||||
|
void onAchievementsChallengeModeToggled(bool enabled);
|
||||||
|
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
/// Updates debug menu visibility (hides if disabled).
|
/// Updates debug menu visibility (hides if disabled).
|
||||||
void updateDebugMenuVisibility();
|
void updateDebugMenuVisibility();
|
||||||
|
@ -113,7 +116,7 @@ private:
|
||||||
void setupAdditionalUi();
|
void setupAdditionalUi();
|
||||||
void connectSignals();
|
void connectSignals();
|
||||||
void addThemeToMenu(const QString& name, const QString& key);
|
void addThemeToMenu(const QString& name, const QString& key);
|
||||||
void updateEmulationActions(bool starting, bool running);
|
void updateEmulationActions(bool starting, bool running, bool cheevos_challenge_mode);
|
||||||
bool isShowingGameList() const;
|
bool isShowingGameList() const;
|
||||||
void switchToGameListView();
|
void switchToGameListView();
|
||||||
void switchToEmulationView();
|
void switchToEmulationView();
|
||||||
|
|
|
@ -957,6 +957,7 @@ void QtHostInterface::populateGameListContextMenu(const GameListEntry* entry, QW
|
||||||
{
|
{
|
||||||
const std::vector<SaveStateInfo> available_states(GetAvailableSaveStates(entry->code.c_str()));
|
const std::vector<SaveStateInfo> available_states(GetAvailableSaveStates(entry->code.c_str()));
|
||||||
const QString timestamp_format = QLocale::system().dateTimeFormat(QLocale::ShortFormat);
|
const QString timestamp_format = QLocale::system().dateTimeFormat(QLocale::ShortFormat);
|
||||||
|
const bool challenge_mode = IsCheevosChallengeModeActive();
|
||||||
for (const SaveStateInfo& ssi : available_states)
|
for (const SaveStateInfo& ssi : available_states)
|
||||||
{
|
{
|
||||||
if (ssi.global)
|
if (ssi.global)
|
||||||
|
@ -971,7 +972,7 @@ void QtHostInterface::populateGameListContextMenu(const GameListEntry* entry, QW
|
||||||
if (slot < 0)
|
if (slot < 0)
|
||||||
{
|
{
|
||||||
resume_action->setText(tr("Resume (%1)").arg(timestamp_str));
|
resume_action->setText(tr("Resume (%1)").arg(timestamp_str));
|
||||||
resume_action->setEnabled(true);
|
resume_action->setEnabled(!challenge_mode);
|
||||||
action = resume_action;
|
action = resume_action;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -980,6 +981,7 @@ void QtHostInterface::populateGameListContextMenu(const GameListEntry* entry, QW
|
||||||
action = load_state_menu->addAction(tr("Game Save %1 (%2)").arg(slot).arg(timestamp_str));
|
action = load_state_menu->addAction(tr("Game Save %1 (%2)").arg(slot).arg(timestamp_str));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
action->setDisabled(challenge_mode);
|
||||||
connect(action, &QAction::triggered, [this, path]() { loadState(path); });
|
connect(action, &QAction::triggered, [this, path]() { loadState(path); });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,12 +49,12 @@ static void SendPlaying();
|
||||||
static void GameChanged();
|
static void GameChanged();
|
||||||
|
|
||||||
bool g_active = false;
|
bool g_active = false;
|
||||||
|
bool g_challenge_mode = false;
|
||||||
u32 g_game_id = 0;
|
u32 g_game_id = 0;
|
||||||
|
|
||||||
static bool s_logged_in = false;
|
static bool s_logged_in = false;
|
||||||
static bool s_test_mode = false;
|
static bool s_test_mode = false;
|
||||||
static bool s_use_first_disc_from_playlist = true;
|
static bool s_use_first_disc_from_playlist = true;
|
||||||
static bool s_hardcode_mode = false;
|
|
||||||
static bool s_rich_presence_enabled = false;
|
static bool s_rich_presence_enabled = false;
|
||||||
|
|
||||||
static rc_runtime_t s_rcheevos_runtime;
|
static rc_runtime_t s_rcheevos_runtime;
|
||||||
|
@ -210,7 +210,7 @@ static std::string GetUserAgent()
|
||||||
return StringUtil::StdStringFromFormat("DuckStation %s", g_scm_tag_str);
|
return StringUtil::StdStringFromFormat("DuckStation %s", g_scm_tag_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Initialize(bool test_mode, bool use_first_disc_from_playlist, bool enable_rich_presence)
|
bool Initialize(bool test_mode, bool use_first_disc_from_playlist, bool enable_rich_presence, bool challenge_mode)
|
||||||
{
|
{
|
||||||
s_http_downloader = FrontendCommon::HTTPDownloader::Create();
|
s_http_downloader = FrontendCommon::HTTPDownloader::Create();
|
||||||
if (!s_http_downloader)
|
if (!s_http_downloader)
|
||||||
|
@ -221,6 +221,7 @@ bool Initialize(bool test_mode, bool use_first_disc_from_playlist, bool enable_r
|
||||||
|
|
||||||
s_http_downloader->SetUserAgent(GetUserAgent());
|
s_http_downloader->SetUserAgent(GetUserAgent());
|
||||||
g_active = true;
|
g_active = true;
|
||||||
|
g_challenge_mode = challenge_mode;
|
||||||
s_test_mode = test_mode;
|
s_test_mode = test_mode;
|
||||||
s_use_first_disc_from_playlist = use_first_disc_from_playlist;
|
s_use_first_disc_from_playlist = use_first_disc_from_playlist;
|
||||||
s_rich_presence_enabled = enable_rich_presence;
|
s_rich_presence_enabled = enable_rich_presence;
|
||||||
|
@ -318,6 +319,9 @@ const std::string& GetRichPresenceString()
|
||||||
|
|
||||||
static void LoginASyncCallback(s32 status_code, const FrontendCommon::HTTPDownloader::Request::Data& data)
|
static void LoginASyncCallback(s32 status_code, const FrontendCommon::HTTPDownloader::Request::Data& data)
|
||||||
{
|
{
|
||||||
|
if (GetHostInterface()->IsFullscreenUIEnabled())
|
||||||
|
ImGuiFullscreen::CloseBackgroundProgressDialog("cheevos_async_login");
|
||||||
|
|
||||||
rapidjson::Document doc;
|
rapidjson::Document doc;
|
||||||
if (!ParseResponseJSON("Login", status_code, data, doc))
|
if (!ParseResponseJSON("Login", status_code, data, doc))
|
||||||
return;
|
return;
|
||||||
|
@ -341,7 +345,12 @@ static void LoginASyncCallback(s32 status_code, const FrontendCommon::HTTPDownlo
|
||||||
GetHostInterface()->GetSettingsInterface()->Save();
|
GetHostInterface()->GetSettingsInterface()->Save();
|
||||||
}
|
}
|
||||||
|
|
||||||
GetHostInterface()->ReportFormattedMessage("Logged into RetroAchievements using username '%s'.", username.c_str());
|
if (GetHostInterface()->IsFullscreenUIEnabled())
|
||||||
|
{
|
||||||
|
GetHostInterface()->ReportFormattedMessage(
|
||||||
|
GetHostInterface()->TranslateString("Cheevos", "Logged into RetroAchievements using username '%s'."),
|
||||||
|
username.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
if (g_active)
|
if (g_active)
|
||||||
{
|
{
|
||||||
|
@ -371,6 +380,13 @@ bool LoginAsync(const char* username, const char* password)
|
||||||
if (s_logged_in || std::strlen(username) == 0 || std::strlen(password) == 0)
|
if (s_logged_in || std::strlen(username) == 0 || std::strlen(password) == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (GetHostInterface()->IsFullscreenUIEnabled())
|
||||||
|
{
|
||||||
|
ImGuiFullscreen::OpenBackgroundProgressDialog(
|
||||||
|
"cheevos_async_login", GetHostInterface()->TranslateStdString("Cheevos", "Logging in to RetroAchivements..."), 0,
|
||||||
|
1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
SendLogin(username, password, s_http_downloader.get());
|
SendLogin(username, password, s_http_downloader.get());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -444,7 +460,7 @@ static void UpdateImageDownloadProgress()
|
||||||
if (!GetHostInterface()->IsFullscreenUIEnabled())
|
if (!GetHostInterface()->IsFullscreenUIEnabled())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
std::string message("Downloading achievement resources...");
|
std::string message(g_host_interface->TranslateStdString("Cheevos", "Downloading achievement resources..."));
|
||||||
if (!s_image_download_progress_active)
|
if (!s_image_download_progress_active)
|
||||||
{
|
{
|
||||||
ImGuiFullscreen::OpenBackgroundProgressDialog(str_id, std::move(message), 0,
|
ImGuiFullscreen::OpenBackgroundProgressDialog(str_id, std::move(message), 0,
|
||||||
|
@ -497,8 +513,8 @@ static std::string GetBadgeImageFilename(const char* badge_name, bool locked, bo
|
||||||
SmallString clean_name(badge_name);
|
SmallString clean_name(badge_name);
|
||||||
FileSystem::SanitizeFileName(clean_name);
|
FileSystem::SanitizeFileName(clean_name);
|
||||||
return GetHostInterface()->GetUserDirectoryRelativePath("cache" FS_OSPATH_SEPARATOR_STR
|
return GetHostInterface()->GetUserDirectoryRelativePath("cache" FS_OSPATH_SEPARATOR_STR
|
||||||
"achievement_badge" FS_OSPATH_SEPARATOR_STR "%s%s.png",
|
"achievement_badge" FS_OSPATH_SEPARATOR_STR "%s%s.png",
|
||||||
clean_name.GetCharArray(), locked ? "_lock" : "");
|
clean_name.GetCharArray(), locked ? "_lock" : "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -520,19 +536,20 @@ static std::string ResolveBadgePath(const char* badge_name, bool locked)
|
||||||
|
|
||||||
static void DisplayAchievementSummary()
|
static void DisplayAchievementSummary()
|
||||||
{
|
{
|
||||||
std::string title(
|
std::string title = s_game_title;
|
||||||
StringUtil::StdStringFromFormat("%s%s", s_game_title.c_str(), s_hardcode_mode ? " (Hardcore Mode)" : ""));
|
if (g_challenge_mode)
|
||||||
std::string summary;
|
title += GetHostInterface()->TranslateString("Cheevos", " (Hardcore Mode)");
|
||||||
|
|
||||||
|
std::string summary;
|
||||||
if (GetAchievementCount() > 0)
|
if (GetAchievementCount() > 0)
|
||||||
{
|
{
|
||||||
summary = StringUtil::StdStringFromFormat("You have earned %u of %u achievements, and %u of %u points.",
|
summary = StringUtil::StdStringFromFormat(
|
||||||
GetUnlockedAchiementCount(), GetAchievementCount(),
|
GetHostInterface()->TranslateString("Cheevos", "You have earned %u of %u achievements, and %u of %u points."),
|
||||||
GetCurrentPointsForGame(), GetMaximumPointsForGame());
|
GetUnlockedAchiementCount(), GetAchievementCount(), GetCurrentPointsForGame(), GetMaximumPointsForGame());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
summary = "This game has no achievements.";
|
summary = GetHostInterface()->TranslateString("Cheevos", "This game has no achievements.");
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGuiFullscreen::AddNotification(10.0f, std::move(title), std::move(summary), s_game_icon);
|
ImGuiFullscreen::AddNotification(10.0f, std::move(title), std::move(summary), s_game_icon);
|
||||||
|
@ -588,7 +605,7 @@ static void GetUserUnlocks()
|
||||||
{
|
{
|
||||||
char url[256];
|
char url[256];
|
||||||
int res = rc_url_get_unlock_list(url, sizeof(url), s_username.c_str(), s_login_token.c_str(), g_game_id,
|
int res = rc_url_get_unlock_list(url, sizeof(url), s_username.c_str(), s_login_token.c_str(), g_game_id,
|
||||||
static_cast<int>(s_hardcode_mode));
|
static_cast<int>(g_challenge_mode));
|
||||||
Assert(res == 0);
|
Assert(res == 0);
|
||||||
|
|
||||||
s_http_downloader->CreateRequest(url, GetUserUnlocksCallback);
|
s_http_downloader->CreateRequest(url, GetUserUnlocksCallback);
|
||||||
|
@ -642,19 +659,29 @@ static void GetPatchesCallback(s32 status_code, const FrontendCommon::HTTPDownlo
|
||||||
const auto achievements(patch_data["Achievements"].GetArray());
|
const auto achievements(patch_data["Achievements"].GetArray());
|
||||||
for (const auto& achievement : achievements)
|
for (const auto& achievement : achievements)
|
||||||
{
|
{
|
||||||
if (!achievement.HasMember("ID") || !achievement["ID"].IsNumber() || !achievement.HasMember("MemAddr") ||
|
if (!achievement.HasMember("ID") || !achievement["ID"].IsNumber() || !achievement.HasMember("Flags") ||
|
||||||
!achievement["MemAddr"].IsString() || !achievement.HasMember("Title") || !achievement["Title"].IsString())
|
!achievement["Flags"].IsNumber() || !achievement.HasMember("MemAddr") || !achievement["MemAddr"].IsString() ||
|
||||||
|
!achievement.HasMember("Title") || !achievement["Title"].IsString())
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const u32 id = achievement["ID"].GetUint();
|
const u32 id = achievement["ID"].GetUint();
|
||||||
|
const u32 category = achievement["Flags"].GetUint();
|
||||||
const char* memaddr = achievement["MemAddr"].GetString();
|
const char* memaddr = achievement["MemAddr"].GetString();
|
||||||
std::string title = achievement["Title"].GetString();
|
std::string title = achievement["Title"].GetString();
|
||||||
std::string description = GetOptionalString(achievement, "Description");
|
std::string description = GetOptionalString(achievement, "Description");
|
||||||
std::string badge_name = GetOptionalString(achievement, "BadgeName");
|
std::string badge_name = GetOptionalString(achievement, "BadgeName");
|
||||||
const u32 points = GetOptionalUInt(achievement, "Points");
|
const u32 points = GetOptionalUInt(achievement, "Points");
|
||||||
|
|
||||||
|
// Skip local and unofficial achievements for now.
|
||||||
|
if (static_cast<AchievementCategory>(category) == AchievementCategory::Local ||
|
||||||
|
static_cast<AchievementCategory>(category) == AchievementCategory::Unofficial)
|
||||||
|
{
|
||||||
|
Log_WarningPrintf("Skipping unofficial achievement %u (%s)", id, title.c_str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (GetAchievementByID(id))
|
if (GetAchievementByID(id))
|
||||||
{
|
{
|
||||||
Log_ErrorPrintf("Achievement %u already exists", id);
|
Log_ErrorPrintf("Achievement %u already exists", id);
|
||||||
|
@ -681,7 +708,8 @@ static void GetPatchesCallback(s32 status_code, const FrontendCommon::HTTPDownlo
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse rich presence
|
// parse rich presence
|
||||||
if (s_rich_presence_enabled && patch_data.HasMember("RichPresencePatch") && patch_data["RichPresencePatch"].IsString())
|
if (s_rich_presence_enabled && patch_data.HasMember("RichPresencePatch") &&
|
||||||
|
patch_data["RichPresencePatch"].IsString())
|
||||||
{
|
{
|
||||||
const char* patch = patch_data["RichPresencePatch"].GetString();
|
const char* patch = patch_data["RichPresencePatch"].GetString();
|
||||||
int res = rc_runtime_activate_richpresence(&s_rcheevos_runtime, patch, nullptr, 0);
|
int res = rc_runtime_activate_richpresence(&s_rcheevos_runtime, patch, nullptr, 0);
|
||||||
|
@ -719,19 +747,11 @@ static void GetPatchesCallback(s32 status_code, const FrontendCommon::HTTPDownlo
|
||||||
|
|
||||||
static void GetPatches(u32 game_id)
|
static void GetPatches(u32 game_id)
|
||||||
{
|
{
|
||||||
#if 1
|
|
||||||
char url[256] = {};
|
char url[256] = {};
|
||||||
int res = rc_url_get_patch(url, sizeof(url), s_username.c_str(), s_login_token.c_str(), game_id);
|
int res = rc_url_get_patch(url, sizeof(url), s_username.c_str(), s_login_token.c_str(), game_id);
|
||||||
Assert(res == 0);
|
Assert(res == 0);
|
||||||
|
|
||||||
s_http_downloader->CreateRequest(url, GetPatchesCallback);
|
s_http_downloader->CreateRequest(url, GetPatchesCallback);
|
||||||
#else
|
|
||||||
std::optional<std::vector<u8>> f = FileSystem::ReadBinaryFile("D:\\10434.txt");
|
|
||||||
if (!f)
|
|
||||||
return;
|
|
||||||
|
|
||||||
GetPatchesCallback(200, *f);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string GetGameHash(CDImage* cdi)
|
static std::string GetGameHash(CDImage* cdi)
|
||||||
|
@ -855,9 +875,9 @@ void GameChanged(const std::string& path, CDImage* image)
|
||||||
|
|
||||||
if (s_game_hash.empty())
|
if (s_game_hash.empty())
|
||||||
{
|
{
|
||||||
GetHostInterface()->AddOSDMessage(
|
GetHostInterface()->AddOSDMessage(GetHostInterface()->TranslateStdString(
|
||||||
GetHostInterface()->TranslateStdString("OSDMessage", "Failed to read executable from disc. Achievements disabled."),
|
"OSDMessage", "Failed to read executable from disc. Achievements disabled."),
|
||||||
10.0f);
|
10.0f);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1086,7 +1106,7 @@ void UnlockAchievement(u32 achievement_id, bool add_notification /* = true*/)
|
||||||
|
|
||||||
char url[256];
|
char url[256];
|
||||||
rc_url_award_cheevo(url, sizeof(url), s_username.c_str(), s_login_token.c_str(), achievement_id,
|
rc_url_award_cheevo(url, sizeof(url), s_username.c_str(), s_login_token.c_str(), achievement_id,
|
||||||
static_cast<int>(s_hardcode_mode), s_game_hash.c_str());
|
static_cast<int>(g_challenge_mode), s_game_hash.c_str());
|
||||||
s_http_downloader->CreateRequest(url, UnlockAchievementCallback);
|
s_http_downloader->CreateRequest(url, UnlockAchievementCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,13 @@ class CDImage;
|
||||||
|
|
||||||
namespace Cheevos {
|
namespace Cheevos {
|
||||||
|
|
||||||
|
enum class AchievementCategory : u32
|
||||||
|
{
|
||||||
|
Local = 0,
|
||||||
|
Core = 3,
|
||||||
|
Unofficial = 5
|
||||||
|
};
|
||||||
|
|
||||||
struct Achievement
|
struct Achievement
|
||||||
{
|
{
|
||||||
u32 id;
|
u32 id;
|
||||||
|
@ -21,6 +28,7 @@ struct Achievement
|
||||||
};
|
};
|
||||||
|
|
||||||
extern bool g_active;
|
extern bool g_active;
|
||||||
|
extern bool g_challenge_mode;
|
||||||
extern u32 g_game_id;
|
extern u32 g_game_id;
|
||||||
|
|
||||||
ALWAYS_INLINE bool IsActive()
|
ALWAYS_INLINE bool IsActive()
|
||||||
|
@ -28,6 +36,16 @@ ALWAYS_INLINE bool IsActive()
|
||||||
return g_active;
|
return g_active;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE bool IsChallengeModeEnabled()
|
||||||
|
{
|
||||||
|
return g_challenge_mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE bool IsChallengeModeActive()
|
||||||
|
{
|
||||||
|
return g_active && g_challenge_mode;
|
||||||
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE bool HasActiveGame()
|
ALWAYS_INLINE bool HasActiveGame()
|
||||||
{
|
{
|
||||||
return g_game_id != 0;
|
return g_game_id != 0;
|
||||||
|
@ -38,7 +56,7 @@ ALWAYS_INLINE u32 GetGameID()
|
||||||
return g_game_id;
|
return g_game_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Initialize(bool test_mode, bool use_first_disc_from_playlist, bool enable_rich_presence);
|
bool Initialize(bool test_mode, bool use_first_disc_from_playlist, bool enable_rich_presence, bool challenge_mode);
|
||||||
void Reset();
|
void Reset();
|
||||||
void Shutdown();
|
void Shutdown();
|
||||||
void Update();
|
void Update();
|
||||||
|
|
|
@ -985,7 +985,10 @@ void CommonHostInterface::OnRunningGameChanged(const std::string& path, CDImage*
|
||||||
{
|
{
|
||||||
System::SetCheatList(nullptr);
|
System::SetCheatList(nullptr);
|
||||||
if (g_settings.auto_load_cheats)
|
if (g_settings.auto_load_cheats)
|
||||||
|
{
|
||||||
|
DebugAssert(!IsCheevosChallengeModeActive());
|
||||||
LoadCheatListFromGameTitle();
|
LoadCheatListFromGameTitle();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WITH_DISCORD_PRESENCE
|
#ifdef WITH_DISCORD_PRESENCE
|
||||||
|
@ -1018,7 +1021,8 @@ void CommonHostInterface::DrawImGuiWindows()
|
||||||
|
|
||||||
if (System::IsValid())
|
if (System::IsValid())
|
||||||
{
|
{
|
||||||
DrawDebugWindows();
|
if (!IsCheevosChallengeModeActive())
|
||||||
|
DrawDebugWindows();
|
||||||
DrawFPSWindow();
|
DrawFPSWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1236,6 +1240,15 @@ void CommonHostInterface::DrawDebugWindows()
|
||||||
g_dma.DrawDebugStateWindow();
|
g_dma.DrawDebugStateWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CommonHostInterface::IsCheevosChallengeModeActive() const
|
||||||
|
{
|
||||||
|
#ifdef WITH_CHEEVOS
|
||||||
|
return Cheevos::IsChallengeModeActive();
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void CommonHostInterface::DoFrameStep()
|
void CommonHostInterface::DoFrameStep()
|
||||||
{
|
{
|
||||||
if (System::IsShutdown())
|
if (System::IsShutdown())
|
||||||
|
@ -1766,6 +1779,12 @@ void CommonHostInterface::RegisterHotkeys()
|
||||||
RegisterAudioHotkeys();
|
RegisterAudioHotkeys();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void DisplayHotkeyBlockedByChallengeModeMessage()
|
||||||
|
{
|
||||||
|
g_host_interface->AddOSDMessage(g_host_interface->TranslateStdString(
|
||||||
|
"OSDMessage", "Hotkey unavailable because achievements hardcore mode is active."));
|
||||||
|
}
|
||||||
|
|
||||||
void CommonHostInterface::RegisterGeneralHotkeys()
|
void CommonHostInterface::RegisterGeneralHotkeys()
|
||||||
{
|
{
|
||||||
RegisterHotkey(StaticString(TRANSLATABLE("Hotkeys", "General")), StaticString("OpenQuickMenu"),
|
RegisterHotkey(StaticString(TRANSLATABLE("Hotkeys", "General")), StaticString("OpenQuickMenu"),
|
||||||
|
@ -1807,7 +1826,12 @@ void CommonHostInterface::RegisterGeneralHotkeys()
|
||||||
RegisterHotkey(StaticString(TRANSLATABLE("Hotkeys", "General")), StaticString("ToggleCheats"),
|
RegisterHotkey(StaticString(TRANSLATABLE("Hotkeys", "General")), StaticString("ToggleCheats"),
|
||||||
StaticString(TRANSLATABLE("Hotkeys", "Toggle Cheats")), [this](bool pressed) {
|
StaticString(TRANSLATABLE("Hotkeys", "Toggle Cheats")), [this](bool pressed) {
|
||||||
if (pressed && System::IsValid())
|
if (pressed && System::IsValid())
|
||||||
DoToggleCheats();
|
{
|
||||||
|
if (!IsCheevosChallengeModeActive())
|
||||||
|
DoToggleCheats();
|
||||||
|
else
|
||||||
|
DisplayHotkeyBlockedByChallengeModeMessage();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
RegisterHotkey(StaticString(TRANSLATABLE("Hotkeys", "General")), StaticString("PowerOff"),
|
RegisterHotkey(StaticString(TRANSLATABLE("Hotkeys", "General")), StaticString("PowerOff"),
|
||||||
|
@ -1838,7 +1862,7 @@ void CommonHostInterface::RegisterGeneralHotkeys()
|
||||||
#else
|
#else
|
||||||
RegisterHotkey(StaticString(TRANSLATABLE("Hotkeys", "General")), StaticString("TogglePatchCodes"),
|
RegisterHotkey(StaticString(TRANSLATABLE("Hotkeys", "General")), StaticString("TogglePatchCodes"),
|
||||||
StaticString(TRANSLATABLE("Hotkeys", "Toggle Patch Codes")), [this](bool pressed) {
|
StaticString(TRANSLATABLE("Hotkeys", "Toggle Patch Codes")), [this](bool pressed) {
|
||||||
if (pressed && System::IsValid())
|
if (pressed && System::IsValid() && !IsCheevosChallengeModeActive())
|
||||||
DoToggleCheats();
|
DoToggleCheats();
|
||||||
});
|
});
|
||||||
#endif
|
#endif
|
||||||
|
@ -1858,7 +1882,12 @@ void CommonHostInterface::RegisterGeneralHotkeys()
|
||||||
RegisterHotkey(StaticString(TRANSLATABLE("Hotkeys", "General")), StaticString("FrameStep"),
|
RegisterHotkey(StaticString(TRANSLATABLE("Hotkeys", "General")), StaticString("FrameStep"),
|
||||||
StaticString(TRANSLATABLE("Hotkeys", "Frame Step")), [this](bool pressed) {
|
StaticString(TRANSLATABLE("Hotkeys", "Frame Step")), [this](bool pressed) {
|
||||||
if (pressed && System::IsValid())
|
if (pressed && System::IsValid())
|
||||||
DoFrameStep();
|
{
|
||||||
|
if (!IsCheevosChallengeModeActive())
|
||||||
|
DoFrameStep();
|
||||||
|
else
|
||||||
|
DisplayHotkeyBlockedByChallengeModeMessage();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
#ifndef __ANDROID__
|
#ifndef __ANDROID__
|
||||||
|
@ -1866,10 +1895,17 @@ void CommonHostInterface::RegisterGeneralHotkeys()
|
||||||
StaticString(TRANSLATABLE("Hotkeys", "Rewind")), [this](bool pressed) {
|
StaticString(TRANSLATABLE("Hotkeys", "Rewind")), [this](bool pressed) {
|
||||||
if (System::IsValid())
|
if (System::IsValid())
|
||||||
{
|
{
|
||||||
AddOSDMessage(pressed ? TranslateStdString("OSDMessage", "Rewinding...") :
|
if (!IsCheevosChallengeModeActive())
|
||||||
TranslateStdString("OSDMessage", "Stopped rewinding."),
|
{
|
||||||
5.0f);
|
AddOSDMessage(pressed ? TranslateStdString("OSDMessage", "Rewinding...") :
|
||||||
System::SetRewinding(pressed);
|
TranslateStdString("OSDMessage", "Stopped rewinding."),
|
||||||
|
5.0f);
|
||||||
|
System::SetRewinding(pressed);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DisplayHotkeyBlockedByChallengeModeMessage();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
#endif
|
#endif
|
||||||
|
@ -1966,7 +2002,12 @@ void CommonHostInterface::RegisterSaveStateHotkeys()
|
||||||
RegisterHotkey(StaticString(TRANSLATABLE("Hotkeys", "Save States")), StaticString("LoadSelectedSaveState"),
|
RegisterHotkey(StaticString(TRANSLATABLE("Hotkeys", "Save States")), StaticString("LoadSelectedSaveState"),
|
||||||
StaticString(TRANSLATABLE("Hotkeys", "Load From Selected Slot")), [this](bool pressed) {
|
StaticString(TRANSLATABLE("Hotkeys", "Load From Selected Slot")), [this](bool pressed) {
|
||||||
if (pressed)
|
if (pressed)
|
||||||
m_save_state_selector_ui->LoadCurrentSlot();
|
{
|
||||||
|
if (!IsCheevosChallengeModeActive())
|
||||||
|
m_save_state_selector_ui->LoadCurrentSlot();
|
||||||
|
else
|
||||||
|
DisplayHotkeyBlockedByChallengeModeMessage();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
RegisterHotkey(StaticString(TRANSLATABLE("Hotkeys", "Save States")), StaticString("SaveSelectedSaveState"),
|
RegisterHotkey(StaticString(TRANSLATABLE("Hotkeys", "Save States")), StaticString("SaveSelectedSaveState"),
|
||||||
StaticString(TRANSLATABLE("Hotkeys", "Save To Selected Slot")), [this](bool pressed) {
|
StaticString(TRANSLATABLE("Hotkeys", "Save To Selected Slot")), [this](bool pressed) {
|
||||||
|
@ -1990,7 +2031,12 @@ void CommonHostInterface::RegisterSaveStateHotkeys()
|
||||||
TinyString::FromFormat("LoadGameState%u", slot), TinyString::FromFormat("Load Game State %u", slot),
|
TinyString::FromFormat("LoadGameState%u", slot), TinyString::FromFormat("Load Game State %u", slot),
|
||||||
[this, slot](bool pressed) {
|
[this, slot](bool pressed) {
|
||||||
if (pressed)
|
if (pressed)
|
||||||
LoadState(false, slot);
|
{
|
||||||
|
if (!IsCheevosChallengeModeActive())
|
||||||
|
LoadState(false, slot);
|
||||||
|
else
|
||||||
|
DisplayHotkeyBlockedByChallengeModeMessage();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
RegisterHotkey(StaticString(TRANSLATABLE("Hotkeys", "Save States")),
|
RegisterHotkey(StaticString(TRANSLATABLE("Hotkeys", "Save States")),
|
||||||
TinyString::FromFormat("SaveGameState%u", slot), TinyString::FromFormat("Save Game State %u", slot),
|
TinyString::FromFormat("SaveGameState%u", slot), TinyString::FromFormat("Save Game State %u", slot),
|
||||||
|
@ -2006,7 +2052,12 @@ void CommonHostInterface::RegisterSaveStateHotkeys()
|
||||||
TinyString::FromFormat("LoadGlobalState%u", slot),
|
TinyString::FromFormat("LoadGlobalState%u", slot),
|
||||||
TinyString::FromFormat("Load Global State %u", slot), [this, slot](bool pressed) {
|
TinyString::FromFormat("Load Global State %u", slot), [this, slot](bool pressed) {
|
||||||
if (pressed)
|
if (pressed)
|
||||||
LoadState(true, slot);
|
{
|
||||||
|
if (!IsCheevosChallengeModeActive())
|
||||||
|
LoadState(true, slot);
|
||||||
|
else
|
||||||
|
DisplayHotkeyBlockedByChallengeModeMessage();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
RegisterHotkey(StaticString(TRANSLATABLE("Hotkeys", "Save States")),
|
RegisterHotkey(StaticString(TRANSLATABLE("Hotkeys", "Save States")),
|
||||||
TinyString::FromFormat("SaveGlobalState%u", slot),
|
TinyString::FromFormat("SaveGlobalState%u", slot),
|
||||||
|
@ -2606,6 +2657,31 @@ void CommonHostInterface::SaveSettings(SettingsInterface& si)
|
||||||
HostInterface::SaveSettings(si);
|
HostInterface::SaveSettings(si);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CommonHostInterface::FixIncompatibleSettings(bool display_osd_messages)
|
||||||
|
{
|
||||||
|
// if challenge mode is enabled, disable things like rewind since they use save states
|
||||||
|
if (IsCheevosChallengeModeActive())
|
||||||
|
{
|
||||||
|
g_settings.emulation_speed = std::max(g_settings.emulation_speed, 1.0f);
|
||||||
|
g_settings.fast_forward_speed = std::max(g_settings.fast_forward_speed, 1.0f);
|
||||||
|
g_settings.turbo_speed = std::max(g_settings.turbo_speed, 1.0f);
|
||||||
|
g_settings.rewind_enable = false;
|
||||||
|
g_settings.auto_load_cheats = false;
|
||||||
|
g_settings.debugging.enable_gdb_server = false;
|
||||||
|
g_settings.debugging.show_vram = false;
|
||||||
|
g_settings.debugging.show_gpu_state = false;
|
||||||
|
g_settings.debugging.show_cdrom_state = false;
|
||||||
|
g_settings.debugging.show_spu_state = false;
|
||||||
|
g_settings.debugging.show_timers_state = false;
|
||||||
|
g_settings.debugging.show_mdec_state = false;
|
||||||
|
g_settings.debugging.show_dma_state = false;
|
||||||
|
g_settings.debugging.dump_cpu_to_vram_copies = false;
|
||||||
|
g_settings.debugging.dump_vram_to_cpu_copies = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
HostInterface::FixIncompatibleSettings(display_osd_messages);
|
||||||
|
}
|
||||||
|
|
||||||
void CommonHostInterface::ApplySettings(bool display_osd_messages)
|
void CommonHostInterface::ApplySettings(bool display_osd_messages)
|
||||||
{
|
{
|
||||||
Settings old_settings(std::move(g_settings));
|
Settings old_settings(std::move(g_settings));
|
||||||
|
@ -2967,6 +3043,9 @@ bool CommonHostInterface::LoadCheatList(const char* filename)
|
||||||
|
|
||||||
bool CommonHostInterface::LoadCheatListFromGameTitle()
|
bool CommonHostInterface::LoadCheatListFromGameTitle()
|
||||||
{
|
{
|
||||||
|
if (IsCheevosChallengeModeActive())
|
||||||
|
return false;
|
||||||
|
|
||||||
const std::string filename(GetCheatFileName());
|
const std::string filename(GetCheatFileName());
|
||||||
if (filename.empty() || !FileSystem::FileExists(filename.c_str()))
|
if (filename.empty() || !FileSystem::FileExists(filename.c_str()))
|
||||||
return false;
|
return false;
|
||||||
|
@ -2976,7 +3055,7 @@ bool CommonHostInterface::LoadCheatListFromGameTitle()
|
||||||
|
|
||||||
bool CommonHostInterface::LoadCheatListFromDatabase()
|
bool CommonHostInterface::LoadCheatListFromDatabase()
|
||||||
{
|
{
|
||||||
if (System::GetRunningCode().empty())
|
if (System::GetRunningCode().empty() || IsCheevosChallengeModeActive())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
std::unique_ptr<CheatList> cl = std::make_unique<CheatList>();
|
std::unique_ptr<CheatList> cl = std::make_unique<CheatList>();
|
||||||
|
@ -3308,15 +3387,18 @@ void CommonHostInterface::UpdateCheevosActive()
|
||||||
const bool cheevos_test_mode = GetBoolSettingValue("Cheevos", "TestMode", false);
|
const bool cheevos_test_mode = GetBoolSettingValue("Cheevos", "TestMode", false);
|
||||||
const bool cheevos_use_first_disc_from_playlist = GetBoolSettingValue("Cheevos", "UseFirstDiscFromPlaylist", true);
|
const bool cheevos_use_first_disc_from_playlist = GetBoolSettingValue("Cheevos", "UseFirstDiscFromPlaylist", true);
|
||||||
const bool cheevos_rich_presence = GetBoolSettingValue("Cheevos", "RichPresence", true);
|
const bool cheevos_rich_presence = GetBoolSettingValue("Cheevos", "RichPresence", true);
|
||||||
|
const bool cheevos_hardcore = GetBoolSettingValue("Cheevos", "ChallengeMode", false);
|
||||||
|
|
||||||
if (cheevos_enabled != Cheevos::IsActive() || cheevos_test_mode != Cheevos::IsTestModeActive() ||
|
if (cheevos_enabled != Cheevos::IsActive() || cheevos_test_mode != Cheevos::IsTestModeActive() ||
|
||||||
cheevos_use_first_disc_from_playlist != Cheevos::IsUsingFirstDiscFromPlaylist() ||
|
cheevos_use_first_disc_from_playlist != Cheevos::IsUsingFirstDiscFromPlaylist() ||
|
||||||
cheevos_rich_presence != Cheevos::IsRichPresenceEnabled())
|
cheevos_rich_presence != Cheevos::IsRichPresenceEnabled() ||
|
||||||
|
cheevos_hardcore != Cheevos::IsChallengeModeEnabled())
|
||||||
{
|
{
|
||||||
Cheevos::Shutdown();
|
Cheevos::Shutdown();
|
||||||
if (cheevos_enabled)
|
if (cheevos_enabled)
|
||||||
{
|
{
|
||||||
if (!Cheevos::Initialize(cheevos_test_mode, cheevos_use_first_disc_from_playlist, cheevos_rich_presence))
|
if (!Cheevos::Initialize(cheevos_test_mode, cheevos_use_first_disc_from_playlist, cheevos_rich_presence,
|
||||||
|
cheevos_hardcore))
|
||||||
ReportError("Failed to initialize cheevos after settings change.");
|
ReportError("Failed to initialize cheevos after settings change.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -308,6 +308,9 @@ public:
|
||||||
void DrawOSDMessages();
|
void DrawOSDMessages();
|
||||||
void DrawDebugWindows();
|
void DrawDebugWindows();
|
||||||
|
|
||||||
|
/// Returns true if features such as save states should be disabled.
|
||||||
|
bool IsCheevosChallengeModeActive() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
enum : u32
|
enum : u32
|
||||||
{
|
{
|
||||||
|
@ -391,6 +394,9 @@ protected:
|
||||||
/// Saves current settings variables to ini.
|
/// Saves current settings variables to ini.
|
||||||
virtual void SaveSettings(SettingsInterface& si) override;
|
virtual void SaveSettings(SettingsInterface& si) override;
|
||||||
|
|
||||||
|
/// Checks and fixes up any incompatible settings.
|
||||||
|
virtual void FixIncompatibleSettings(bool display_osd_messages);
|
||||||
|
|
||||||
/// Checks for settings changes, std::move() the old settings away for comparing beforehand.
|
/// Checks for settings changes, std::move() the old settings away for comparing beforehand.
|
||||||
virtual void CheckForSettingsChanges(const Settings& old_settings) override;
|
virtual void CheckForSettingsChanges(const Settings& old_settings) override;
|
||||||
|
|
||||||
|
|
|
@ -93,6 +93,15 @@ static void OpenAboutWindow();
|
||||||
static void SetDebugMenuEnabled(bool enabled);
|
static void SetDebugMenuEnabled(bool enabled);
|
||||||
static void UpdateDebugMenuVisibility();
|
static void UpdateDebugMenuVisibility();
|
||||||
|
|
||||||
|
static ALWAYS_INLINE bool IsCheevosHardcoreModeActive()
|
||||||
|
{
|
||||||
|
#ifdef WITH_CHEEVOS
|
||||||
|
return Cheevos::IsChallengeModeActive();
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
static CommonHostInterface* s_host_interface;
|
static CommonHostInterface* s_host_interface;
|
||||||
static MainWindowType s_current_main_window = MainWindowType::Landing;
|
static MainWindowType s_current_main_window = MainWindowType::Landing;
|
||||||
static std::bitset<static_cast<u32>(FrontendCommon::ControllerNavigationButton::Count)> s_nav_input_values{};
|
static std::bitset<static_cast<u32>(FrontendCommon::ControllerNavigationButton::Count)> s_nav_input_values{};
|
||||||
|
@ -285,14 +294,14 @@ void Shutdown()
|
||||||
void Render()
|
void Render()
|
||||||
{
|
{
|
||||||
if (s_debug_menu_enabled)
|
if (s_debug_menu_enabled)
|
||||||
{
|
|
||||||
DrawDebugMenu();
|
DrawDebugMenu();
|
||||||
if (System::IsValid())
|
|
||||||
s_host_interface->DrawDebugWindows();
|
if (System::IsValid())
|
||||||
}
|
|
||||||
else if (System::IsValid())
|
|
||||||
{
|
{
|
||||||
DrawStatsOverlay();
|
DrawStatsOverlay();
|
||||||
|
|
||||||
|
if (!IsCheevosHardcoreModeActive())
|
||||||
|
s_host_interface->DrawDebugWindows();
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGuiFullscreen::BeginLayout();
|
ImGuiFullscreen::BeginLayout();
|
||||||
|
@ -707,7 +716,7 @@ void DrawLandingWindow()
|
||||||
BeginMenuButtons(7, 0.5f);
|
BeginMenuButtons(7, 0.5f);
|
||||||
|
|
||||||
if (MenuButton(" " ICON_FA_PLAY_CIRCLE " Resume",
|
if (MenuButton(" " ICON_FA_PLAY_CIRCLE " Resume",
|
||||||
"Starts the console from where it was before it was last closed."))
|
"Starts the console from where it was before it was last closed.", !IsCheevosHardcoreModeActive()))
|
||||||
{
|
{
|
||||||
s_host_interface->RunLater([]() { s_host_interface->ResumeSystemFromMostRecentState(); });
|
s_host_interface->RunLater([]() { s_host_interface->ResumeSystemFromMostRecentState(); });
|
||||||
ClearImGuiFocus();
|
ClearImGuiFocus();
|
||||||
|
@ -725,7 +734,7 @@ void DrawLandingWindow()
|
||||||
if (MenuButton(" " ICON_FA_TOOLBOX " Start BIOS", "Start the console without any disc inserted."))
|
if (MenuButton(" " ICON_FA_TOOLBOX " Start BIOS", "Start the console without any disc inserted."))
|
||||||
s_host_interface->RunLater(DoStartBIOS);
|
s_host_interface->RunLater(DoStartBIOS);
|
||||||
|
|
||||||
if (MenuButton(" " ICON_FA_UNDO " Load State", "Loads a global save state."))
|
if (MenuButton(" " ICON_FA_UNDO " Load State", "Loads a global save state.", !IsCheevosHardcoreModeActive()))
|
||||||
{
|
{
|
||||||
OpenSaveStateSelector(true);
|
OpenSaveStateSelector(true);
|
||||||
}
|
}
|
||||||
|
@ -1066,6 +1075,91 @@ static bool ToggleButtonForNonSetting(const char* title, const char* summary, co
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void DrawAchievementsLoginWindow()
|
||||||
|
{
|
||||||
|
ImGui::SetNextWindowSize(LayoutScale(700.0f, 0.0f));
|
||||||
|
ImGui::SetNextWindowPos(ImGui::GetIO().DisplaySize * 0.5f, ImGuiCond_Always, ImVec2(0.5f, 0.5f));
|
||||||
|
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, LayoutScale(10.0f));
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, LayoutScale(10.0f, 10.0f));
|
||||||
|
ImGui::PushFont(g_large_font);
|
||||||
|
|
||||||
|
bool is_open = true;
|
||||||
|
if (ImGui::BeginPopupModal("Achievements Login", &is_open, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize))
|
||||||
|
{
|
||||||
|
|
||||||
|
ImGui::TextWrapped("Please enter user name and password for retroachievements.org.");
|
||||||
|
ImGui::NewLine();
|
||||||
|
ImGui::TextWrapped(
|
||||||
|
"Your password will not be saved in DuckStation, an access token will be generated and used instead.");
|
||||||
|
|
||||||
|
ImGui::NewLine();
|
||||||
|
|
||||||
|
static char username[256] = {};
|
||||||
|
static char password[256] = {};
|
||||||
|
|
||||||
|
ImGui::Text("User Name: ");
|
||||||
|
ImGui::SameLine(LayoutScale(200.0f));
|
||||||
|
ImGui::InputText("##username", username, sizeof(username));
|
||||||
|
|
||||||
|
ImGui::Text("Password: ");
|
||||||
|
ImGui::SameLine(LayoutScale(200.0f));
|
||||||
|
ImGui::InputText("##password", password, sizeof(password), ImGuiInputTextFlags_Password);
|
||||||
|
|
||||||
|
ImGui::NewLine();
|
||||||
|
|
||||||
|
BeginMenuButtons();
|
||||||
|
|
||||||
|
const bool login_enabled = (std::strlen(username) > 0 && std::strlen(password) > 0);
|
||||||
|
|
||||||
|
if (ActiveButton(ICON_FA_KEY " Login", false, login_enabled))
|
||||||
|
{
|
||||||
|
Cheevos::LoginAsync(username, password);
|
||||||
|
std::memset(username, 0, sizeof(username));
|
||||||
|
std::memset(password, 0, sizeof(password));
|
||||||
|
ImGui::CloseCurrentPopup();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ActiveButton(ICON_FA_TIMES " Cancel", false))
|
||||||
|
ImGui::CloseCurrentPopup();
|
||||||
|
|
||||||
|
EndMenuButtons();
|
||||||
|
|
||||||
|
ImGui::EndPopup();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::PopFont();
|
||||||
|
ImGui::PopStyleVar(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ConfirmChallengeModeEnable()
|
||||||
|
{
|
||||||
|
if (!System::IsValid())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
const bool cheevos_enabled = s_host_interface->GetBoolSettingValue("Cheevos", "Enabled", false);
|
||||||
|
const bool cheevos_hardcore = s_host_interface->GetBoolSettingValue("Cheevos", "ChallengeMode", false);
|
||||||
|
if (!cheevos_enabled || !cheevos_hardcore)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
SmallString message;
|
||||||
|
message.AppendString("Enabling hardcore mode will shut down your current game.\n\n");
|
||||||
|
|
||||||
|
if (s_host_interface->ShouldSaveResumeState())
|
||||||
|
{
|
||||||
|
message.AppendString(
|
||||||
|
"The current state will be saved, but you will be unable to load it until you disable hardcore mode.\n\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
message.AppendString("Do you want to continue?");
|
||||||
|
|
||||||
|
if (!s_host_interface->ConfirmMessage(message))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
s_host_interface->PowerOffSystem(s_host_interface->ShouldSaveResumeState());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void DrawSettingsWindow()
|
void DrawSettingsWindow()
|
||||||
{
|
{
|
||||||
BeginFullscreenColumns();
|
BeginFullscreenColumns();
|
||||||
|
@ -1954,23 +2048,45 @@ void DrawSettingsWindow()
|
||||||
BeginMenuButtons();
|
BeginMenuButtons();
|
||||||
|
|
||||||
MenuHeading("Settings");
|
MenuHeading("Settings");
|
||||||
|
if (ToggleButtonForNonSetting(ICON_FA_TROPHY " Enable RetroAchievements",
|
||||||
|
"When enabled and logged in, DuckStation will scan for achievements on startup.",
|
||||||
|
"Cheevos", "Enabled", false))
|
||||||
|
{
|
||||||
|
s_host_interface->RunLater([]() {
|
||||||
|
if (!ConfirmChallengeModeEnable())
|
||||||
|
s_host_interface->GetSettingsInterface()->SetBoolValue("Cheevos", "Enabled", false);
|
||||||
|
else
|
||||||
|
SaveAndApplySettings();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
settings_changed |= ToggleButtonForNonSetting(
|
settings_changed |= ToggleButtonForNonSetting(
|
||||||
"Enable RetroAchievements", "When enabled and logged in, DuckStation will scan for achievements on startup.",
|
ICON_FA_USER_FRIENDS " Rich Presence",
|
||||||
"Cheevos", "Enabled", false);
|
|
||||||
settings_changed |= ToggleButtonForNonSetting(
|
|
||||||
"Rich Presence",
|
|
||||||
"When enabled, rich presence information will be collected and sent to the server where supported.",
|
"When enabled, rich presence information will be collected and sent to the server where supported.",
|
||||||
"Cheevos", "RichPresence", true);
|
"Cheevos", "RichPresence", true);
|
||||||
settings_changed |=
|
settings_changed |=
|
||||||
ToggleButtonForNonSetting("Test Mode",
|
ToggleButtonForNonSetting(ICON_FA_STETHOSCOPE " Test Mode",
|
||||||
"When enabled, DuckStation will assume all achievements are locked and not "
|
"When enabled, DuckStation will assume all achievements are locked and not "
|
||||||
"send any unlock notifications to the server.",
|
"send any unlock notifications to the server.",
|
||||||
"Cheevos", "TestMode", false);
|
"Cheevos", "TestMode", false);
|
||||||
settings_changed |= ToggleButtonForNonSetting("Use First Disc From Playlist",
|
settings_changed |= ToggleButtonForNonSetting(ICON_FA_COMPACT_DISC " Use First Disc From Playlist",
|
||||||
"When enabled, the first disc in a playlist will be used for "
|
"When enabled, the first disc in a playlist will be used for "
|
||||||
"achievements, regardless of which disc is active.",
|
"achievements, regardless of which disc is active.",
|
||||||
"Cheevos", "UseFirstDiscFromPlaylist", true);
|
"Cheevos", "UseFirstDiscFromPlaylist", true);
|
||||||
|
|
||||||
|
if (ToggleButtonForNonSetting(ICON_FA_HARD_HAT " Hardcore Mode",
|
||||||
|
"\"Challenge\" mode for achievements. Disables save state, cheats, and slowdown "
|
||||||
|
"functions, but you receive double the achievement points.",
|
||||||
|
"Cheevos", "ChallengeMode", false))
|
||||||
|
{
|
||||||
|
s_host_interface->RunLater([]() {
|
||||||
|
if (!ConfirmChallengeModeEnable())
|
||||||
|
s_host_interface->GetSettingsInterface()->SetBoolValue("Cheevos", "ChallengeMode", false);
|
||||||
|
else
|
||||||
|
SaveAndApplySettings();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
MenuHeading("Account");
|
MenuHeading("Account");
|
||||||
if (Cheevos::IsLoggedIn())
|
if (Cheevos::IsLoggedIn())
|
||||||
{
|
{
|
||||||
|
@ -1991,13 +2107,20 @@ void DrawSettingsWindow()
|
||||||
if (MenuButton(ICON_FA_KEY " Logout", "Logs out of RetroAchievements."))
|
if (MenuButton(ICON_FA_KEY " Logout", "Logs out of RetroAchievements."))
|
||||||
Cheevos::Logout();
|
Cheevos::Logout();
|
||||||
}
|
}
|
||||||
else
|
else if (Cheevos::IsActive())
|
||||||
{
|
{
|
||||||
ActiveButton(SmallString::FromFormat(ICON_FA_USER " Not Logged In", Cheevos::GetUsername().c_str()), false,
|
ActiveButton(ICON_FA_USER " Not Logged In", false, false,
|
||||||
false, ImGuiFullscreen::LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY);
|
ImGuiFullscreen::LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY);
|
||||||
|
|
||||||
if (MenuButton(ICON_FA_KEY " Login", "Logs in to RetroAchievements."))
|
if (MenuButton(ICON_FA_KEY " Login", "Logs in to RetroAchievements."))
|
||||||
Cheevos::LoginAsync("", "");
|
ImGui::OpenPopup("Achievements Login");
|
||||||
|
|
||||||
|
DrawAchievementsLoginWindow();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ActiveButton(ICON_FA_USER " Achievements are disabled.", false, false,
|
||||||
|
ImGuiFullscreen::LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY);
|
||||||
}
|
}
|
||||||
|
|
||||||
MenuHeading("Current Game");
|
MenuHeading("Current Game");
|
||||||
|
@ -2220,7 +2343,7 @@ void DrawQuickMenu(MainWindowType type)
|
||||||
s_host_interface->RunLater([]() { s_host_interface->SaveScreenshot(); });
|
s_host_interface->RunLater([]() { s_host_interface->SaveScreenshot(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ActiveButton(ICON_FA_UNDO " Load State", false))
|
if (ActiveButton(ICON_FA_UNDO " Load State", false, !IsCheevosHardcoreModeActive()))
|
||||||
{
|
{
|
||||||
s_current_main_window = MainWindowType::None;
|
s_current_main_window = MainWindowType::None;
|
||||||
OpenSaveStateSelector(true);
|
OpenSaveStateSelector(true);
|
||||||
|
@ -2232,7 +2355,7 @@ void DrawQuickMenu(MainWindowType type)
|
||||||
OpenSaveStateSelector(false);
|
OpenSaveStateSelector(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ActiveButton(ICON_FA_FROWN_OPEN " Cheat List", false))
|
if (ActiveButton(ICON_FA_FROWN_OPEN " Cheat List", false, !IsCheevosHardcoreModeActive()))
|
||||||
{
|
{
|
||||||
s_current_main_window = MainWindowType::None;
|
s_current_main_window = MainWindowType::None;
|
||||||
DoCheatsMenu();
|
DoCheatsMenu();
|
||||||
|
@ -3248,9 +3371,7 @@ void DrawDebugSystemMenu()
|
||||||
|
|
||||||
if (ImGui::MenuItem("Change Disc", nullptr, false, system_enabled))
|
if (ImGui::MenuItem("Change Disc", nullptr, false, system_enabled))
|
||||||
{
|
{
|
||||||
#if 0
|
|
||||||
DoChangeDisc();
|
DoChangeDisc();
|
||||||
#endif
|
|
||||||
ClearImGuiFocus();
|
ClearImGuiFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3260,17 +3381,9 @@ void DrawDebugSystemMenu()
|
||||||
ClearImGuiFocus();
|
ClearImGuiFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ImGui::MenuItem("Frame Step", nullptr, false, system_enabled))
|
|
||||||
{
|
|
||||||
#if 0
|
|
||||||
s_host_interface->RunLater([]() { DoFrameStep(); });
|
|
||||||
#endif
|
|
||||||
ClearImGuiFocus();
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
|
|
||||||
if (ImGui::BeginMenu("Load State"))
|
if (ImGui::BeginMenu("Load State", !IsCheevosHardcoreModeActive()))
|
||||||
{
|
{
|
||||||
for (u32 i = 1; i <= CommonHostInterface::GLOBAL_SAVE_STATE_SLOTS; i++)
|
for (u32 i = 1; i <= CommonHostInterface::GLOBAL_SAVE_STATE_SLOTS; i++)
|
||||||
{
|
{
|
||||||
|
@ -3302,7 +3415,7 @@ void DrawDebugSystemMenu()
|
||||||
|
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
|
|
||||||
if (ImGui::BeginMenu("Cheats", system_enabled))
|
if (ImGui::BeginMenu("Cheats", system_enabled && !IsCheevosHardcoreModeActive()))
|
||||||
{
|
{
|
||||||
const bool has_cheat_file = System::HasCheatList();
|
const bool has_cheat_file = System::HasCheatList();
|
||||||
if (ImGui::BeginMenu("Enabled Cheats", has_cheat_file))
|
if (ImGui::BeginMenu("Enabled Cheats", has_cheat_file))
|
||||||
|
@ -3812,9 +3925,8 @@ void DrawAchievementWindow()
|
||||||
const ImRect title_bb(ImVec2(left, top), ImVec2(right, top + g_large_font->FontSize));
|
const ImRect title_bb(ImVec2(left, top), ImVec2(right, top + g_large_font->FontSize));
|
||||||
text.Assign(Cheevos::GetGameTitle());
|
text.Assign(Cheevos::GetGameTitle());
|
||||||
|
|
||||||
const std::string& developer = Cheevos::GetGameDeveloper();
|
if (Cheevos::IsChallengeModeActive())
|
||||||
if (!developer.empty())
|
text.AppendString(" (Hardcore Mode)");
|
||||||
text.AppendFormattedString(" (%s)", developer.c_str());
|
|
||||||
|
|
||||||
top += g_large_font->FontSize + spacing;
|
top += g_large_font->FontSize + spacing;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue