diff --git a/src/core/settings.cpp b/src/core/settings.cpp index 3dc251234..0ec10d21c 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp @@ -344,6 +344,7 @@ void Settings::Load(SettingsInterface& si) achievements_use_first_disc_from_playlist = si.GetBoolValue("Cheevos", "UseFirstDiscFromPlaylist", true); achievements_rich_presence = si.GetBoolValue("Cheevos", "RichPresence", true); achievements_challenge_mode = si.GetBoolValue("Cheevos", "ChallengeMode", false); + achievements_leaderboards = si.GetBoolValue("Cheevos", "Leaderboards", true); achievements_sound_effects = si.GetBoolValue("Cheevos", "SoundEffects", true); log_level = ParseLogLevelName(si.GetStringValue("Logging", "LogLevel", GetLogLevelName(DEFAULT_LOG_LEVEL)).c_str()) @@ -529,6 +530,7 @@ void Settings::Save(SettingsInterface& si) const si.SetBoolValue("Cheevos", "UseFirstDiscFromPlaylist", achievements_use_first_disc_from_playlist); si.SetBoolValue("Cheevos", "RichPresence", achievements_rich_presence); si.SetBoolValue("Cheevos", "ChallengeMode", achievements_challenge_mode); + si.SetBoolValue("Cheevos", "Leaderboards", achievements_leaderboards); si.SetBoolValue("Cheevos", "SoundEffects", achievements_sound_effects); si.SetStringValue("Logging", "LogLevel", GetLogLevelName(log_level)); diff --git a/src/core/settings.h b/src/core/settings.h index 5d91fa9c3..7f4a42166 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -173,6 +173,7 @@ struct Settings bool achievements_use_first_disc_from_playlist : 1; bool achievements_rich_presence : 1; bool achievements_challenge_mode : 1; + bool achievements_leaderboards : 1; bool achievements_sound_effects : 1; #endif diff --git a/src/duckstation-qt/achievementsettingswidget.cpp b/src/duckstation-qt/achievementsettingswidget.cpp index 816fb8d6e..1a5f11079 100644 --- a/src/duckstation-qt/achievementsettingswidget.cpp +++ b/src/duckstation-qt/achievementsettingswidget.cpp @@ -24,6 +24,7 @@ AchievementSettingsWidget::AchievementSettingsWidget(SettingsDialog* dialog, QWi SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.unofficialTestMode, "Cheevos", "UnofficialTestMode", false); SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.useFirstDiscFromPlaylist, "Cheevos", "UseFirstDiscFromPlaylist", true); + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.leaderboards, "Cheevos", "Leaderboards", true); SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.soundEffects, "Cheevos", "SoundEffects", true); dialog->registerWidgetHelp(m_ui.enable, tr("Enable Achievements"), tr("Unchecked"), @@ -46,10 +47,16 @@ AchievementSettingsWidget::AchievementSettingsWidget(SettingsDialog* dialog, QWi tr("\"Challenge\" mode for achievements. Disables save state, cheats, and slowdown " "functions, but you receive double the achievement points.")); dialog->registerWidgetHelp( - m_ui.challengeMode, tr("Enable Sound Effects"), tr("Checked"), + m_ui.soundEffects, tr("Enable Sound Effects"), tr("Checked"), tr("Plays sound effects for events such as achievement unlocks and leaderboard submissions.")); + dialog->registerWidgetHelp( + m_ui.leaderboards, tr("Enable Leaderboards"), tr("Checked"), + tr("Enables tracking and submission of leaderboards in supported games. If leaderboards " + "are disabled, you will still be able to view the leaderboard and scores, but no scores will be uploaded.")); connect(m_ui.enable, &QCheckBox::stateChanged, this, &AchievementSettingsWidget::updateEnableState); + connect(m_ui.challengeMode, &QCheckBox::stateChanged, this, &AchievementSettingsWidget::updateEnableState); + connect(m_ui.challengeMode, &QCheckBox::stateChanged, this, &AchievementSettingsWidget::onChallengeModeStateChanged); if (!m_dialog->isPerGameSettings()) { @@ -80,10 +87,40 @@ AchievementSettingsWidget::~AchievementSettingsWidget() = default; void AchievementSettingsWidget::updateEnableState() { const bool enabled = m_dialog->getEffectiveBoolValue("Cheevos", "Enabled", false); + const bool challenge = m_dialog->getEffectiveBoolValue("Cheevos", "ChallengeMode", false); m_ui.testMode->setEnabled(enabled); m_ui.useFirstDiscFromPlaylist->setEnabled(enabled); m_ui.richPresence->setEnabled(enabled); m_ui.challengeMode->setEnabled(enabled); + m_ui.leaderboards->setEnabled(enabled && challenge); + m_ui.unofficialTestMode->setEnabled(enabled); + m_ui.soundEffects->setEnabled(enabled); +} + +void AchievementSettingsWidget::onChallengeModeStateChanged() +{ + if (!QtHost::IsSystemValid()) + return; + + const bool enabled = m_dialog->getEffectiveBoolValue("Cheevos", "Enabled", false); + const bool challenge = m_dialog->getEffectiveBoolValue("Cheevos", "ChallengeMode", false); + if (!enabled || !challenge) + return; + + // don't bother prompting if the game doesn't have achievements + auto lock = Achievements::GetLock(); + if (!Achievements::HasActiveGame()) + return; + + if (QMessageBox::question( + QtUtils::GetRootWidget(this), tr("Reset System"), + tr("Hardcore mode will not be enabled until the system is reset. Do you want to reset the system now?")) != + QMessageBox::Yes) + { + return; + } + + g_emu_thread->resetSystem(); } void AchievementSettingsWidget::updateLoginState() diff --git a/src/duckstation-qt/achievementsettingswidget.h b/src/duckstation-qt/achievementsettingswidget.h index 1747cb93e..669996135 100644 --- a/src/duckstation-qt/achievementsettingswidget.h +++ b/src/duckstation-qt/achievementsettingswidget.h @@ -14,6 +14,7 @@ public: private Q_SLOTS: void updateEnableState(); + void onChallengeModeStateChanged(); void onLoginLogoutPressed(); void onViewProfilePressed(); void onAchievementsRefreshed(quint32 id, const QString& game_info_string, quint32 total, quint32 points); diff --git a/src/duckstation-qt/achievementsettingswidget.ui b/src/duckstation-qt/achievementsettingswidget.ui index b61a4c3af..972d67f2a 100644 --- a/src/duckstation-qt/achievementsettingswidget.ui +++ b/src/duckstation-qt/achievementsettingswidget.ui @@ -39,27 +39,6 @@ - - - - Enable Hardcore Mode - - - - - - - Use First Disc From Playlist - - - - - - - Enable Test Mode - - - @@ -74,13 +53,41 @@ - + + + + Enable Test Mode + + + + + + + Enable Hardcore Mode + + + + Enable Sound Effects + + + + Use First Disc From Playlist + + + + + + + Enable Leaderboards + + + diff --git a/src/frontend-common/achievements.cpp b/src/frontend-common/achievements.cpp index 42faf69b2..f4571ec4b 100644 --- a/src/frontend-common/achievements.cpp +++ b/src/frontend-common/achievements.cpp @@ -404,6 +404,11 @@ bool Achievements::ChallengeModeActive() return s_challenge_mode; } +bool Achievements::LeaderboardsActive() +{ + return ChallengeModeActive() && g_settings.achievements_leaderboards; +} + bool Achievements::IsTestModeActive() { return g_settings.achievements_test_mode; @@ -485,11 +490,11 @@ void Achievements::UpdateSettings(const Settings& old_config) if (g_settings.achievements_challenge_mode != old_config.achievements_challenge_mode) { // Hardcore mode can only be enabled through reset (ResetChallengeMode()). - if (s_challenge_mode && !old_config.achievements_challenge_mode) + if (s_challenge_mode && !g_settings.achievements_challenge_mode) { ResetChallengeMode(); } - else if (g_settings.achievements_challenge_mode) + else if (!s_challenge_mode && g_settings.achievements_challenge_mode) { Host::AddKeyedOSDMessage( "challenge_mode_reset", @@ -1013,14 +1018,8 @@ void Achievements::DisplayAchievementSummary() if (GetLeaderboardCount() > 0) { summary.push_back('\n'); - if (ChallengeModeActive()) - { - summary.append(Host::TranslateString("Achievements", "Leaderboards are enabled.")); - } - else - { - summary.append(Host::TranslateString("Achievements", "Leaderboards are disabled because hardcore mode is off.")); - } + if (LeaderboardsActive()) + summary.append("Leaderboard submission is enabled."); } Host::RunOnCPUThread([title = std::move(title), summary = std::move(summary), icon = s_game_icon]() { @@ -1822,6 +1821,13 @@ void Achievements::SubmitLeaderboard(u32 leaderboard_id, int value) return; } + if (!LeaderboardsActive()) + { + Log_WarningPrintf("Skipping sending leaderboard %u result to server because leaderboards are disabled.", + leaderboard_id); + return; + } + std::unique_lock lock(s_achievements_mutex); s_submitting_lboard_id = leaderboard_id; diff --git a/src/frontend-common/achievements.h b/src/frontend-common/achievements.h index 91c77cc2b..622e2e688 100644 --- a/src/frontend-common/achievements.h +++ b/src/frontend-common/achievements.h @@ -72,6 +72,7 @@ static ALWAYS_INLINE bool IsUsingRAIntegration() bool IsActive(); bool IsLoggedIn(); bool ChallengeModeActive(); +bool LeaderboardsActive(); bool IsTestModeActive(); bool IsUnofficialTestModeActive(); bool IsRichPresenceEnabled(); diff --git a/src/frontend-common/fullscreen_ui.cpp b/src/frontend-common/fullscreen_ui.cpp index 833d78a23..1d871b904 100644 --- a/src/frontend-common/fullscreen_ui.cpp +++ b/src/frontend-common/fullscreen_ui.cpp @@ -3572,6 +3572,9 @@ void FullscreenUI::DrawAchievementsSettingsPage() DrawToggleSetting(bsi, ICON_FA_LIST_OL " Leaderboards", "Enables tracking and submission of leaderboards in supported games.", "Cheevos", "Leaderboards", true, enabled && challenge); + DrawToggleSetting(bsi, ICON_FA_HEADPHONES " Sound Effects", + "Plays sound effects for events such as achievement unlocks and leaderboard submissions.", + "Cheevos", "SoundEffects", true, enabled); DrawToggleSetting(bsi, ICON_FA_MEDAL " Test Unofficial Achievements", "When enabled, DuckStation will list achievements from unofficial sets. These achievements are not " "tracked by RetroAchievements.",