Cheevos: Implement hardcore mode

This commit is contained in:
Connor McLaughlin
2021-03-03 19:14:01 +10:00
parent 7a05b4f98e
commit 7dbc759619
12 changed files with 427 additions and 118 deletions

View File

@ -49,12 +49,12 @@ static void SendPlaying();
static void GameChanged();
bool g_active = false;
bool g_challenge_mode = false;
u32 g_game_id = 0;
static bool s_logged_in = false;
static bool s_test_mode = false;
static bool s_use_first_disc_from_playlist = true;
static bool s_hardcode_mode = false;
static bool s_rich_presence_enabled = false;
static rc_runtime_t s_rcheevos_runtime;
@ -210,7 +210,7 @@ static std::string GetUserAgent()
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();
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());
g_active = true;
g_challenge_mode = challenge_mode;
s_test_mode = test_mode;
s_use_first_disc_from_playlist = use_first_disc_from_playlist;
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)
{
if (GetHostInterface()->IsFullscreenUIEnabled())
ImGuiFullscreen::CloseBackgroundProgressDialog("cheevos_async_login");
rapidjson::Document doc;
if (!ParseResponseJSON("Login", status_code, data, doc))
return;
@ -341,7 +345,12 @@ static void LoginASyncCallback(s32 status_code, const FrontendCommon::HTTPDownlo
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)
{
@ -371,6 +380,13 @@ bool LoginAsync(const char* username, const char* password)
if (s_logged_in || std::strlen(username) == 0 || std::strlen(password) == 0)
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());
return true;
}
@ -444,7 +460,7 @@ static void UpdateImageDownloadProgress()
if (!GetHostInterface()->IsFullscreenUIEnabled())
return;
std::string message("Downloading achievement resources...");
std::string message(g_host_interface->TranslateStdString("Cheevos", "Downloading achievement resources..."));
if (!s_image_download_progress_active)
{
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);
FileSystem::SanitizeFileName(clean_name);
return GetHostInterface()->GetUserDirectoryRelativePath("cache" FS_OSPATH_SEPARATOR_STR
"achievement_badge" FS_OSPATH_SEPARATOR_STR "%s%s.png",
clean_name.GetCharArray(), locked ? "_lock" : "");
"achievement_badge" FS_OSPATH_SEPARATOR_STR "%s%s.png",
clean_name.GetCharArray(), locked ? "_lock" : "");
}
}
@ -520,19 +536,20 @@ static std::string ResolveBadgePath(const char* badge_name, bool locked)
static void DisplayAchievementSummary()
{
std::string title(
StringUtil::StdStringFromFormat("%s%s", s_game_title.c_str(), s_hardcode_mode ? " (Hardcore Mode)" : ""));
std::string summary;
std::string title = s_game_title;
if (g_challenge_mode)
title += GetHostInterface()->TranslateString("Cheevos", " (Hardcore Mode)");
std::string summary;
if (GetAchievementCount() > 0)
{
summary = StringUtil::StdStringFromFormat("You have earned %u of %u achievements, and %u of %u points.",
GetUnlockedAchiementCount(), GetAchievementCount(),
GetCurrentPointsForGame(), GetMaximumPointsForGame());
summary = StringUtil::StdStringFromFormat(
GetHostInterface()->TranslateString("Cheevos", "You have earned %u of %u achievements, and %u of %u points."),
GetUnlockedAchiementCount(), GetAchievementCount(), GetCurrentPointsForGame(), GetMaximumPointsForGame());
}
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);
@ -588,7 +605,7 @@ static void GetUserUnlocks()
{
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,
static_cast<int>(s_hardcode_mode));
static_cast<int>(g_challenge_mode));
Assert(res == 0);
s_http_downloader->CreateRequest(url, GetUserUnlocksCallback);
@ -681,7 +698,8 @@ static void GetPatchesCallback(s32 status_code, const FrontendCommon::HTTPDownlo
}
// 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();
int res = rc_runtime_activate_richpresence(&s_rcheevos_runtime, patch, nullptr, 0);
@ -855,9 +873,9 @@ void GameChanged(const std::string& path, CDImage* image)
if (s_game_hash.empty())
{
GetHostInterface()->AddOSDMessage(
GetHostInterface()->TranslateStdString("OSDMessage", "Failed to read executable from disc. Achievements disabled."),
10.0f);
GetHostInterface()->AddOSDMessage(GetHostInterface()->TranslateStdString(
"OSDMessage", "Failed to read executable from disc. Achievements disabled."),
10.0f);
return;
}
@ -1086,7 +1104,7 @@ void UnlockAchievement(u32 achievement_id, bool add_notification /* = true*/)
char url[256];
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);
}

View File

@ -21,6 +21,7 @@ struct Achievement
};
extern bool g_active;
extern bool g_challenge_mode;
extern u32 g_game_id;
ALWAYS_INLINE bool IsActive()
@ -28,6 +29,16 @@ ALWAYS_INLINE bool IsActive()
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()
{
return g_game_id != 0;
@ -38,7 +49,7 @@ ALWAYS_INLINE u32 GetGameID()
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 Shutdown();
void Update();

View File

@ -985,7 +985,10 @@ void CommonHostInterface::OnRunningGameChanged(const std::string& path, CDImage*
{
System::SetCheatList(nullptr);
if (g_settings.auto_load_cheats)
{
DebugAssert(!IsCheevosChallengeModeActive());
LoadCheatListFromGameTitle();
}
}
#ifdef WITH_DISCORD_PRESENCE
@ -1018,7 +1021,8 @@ void CommonHostInterface::DrawImGuiWindows()
if (System::IsValid())
{
DrawDebugWindows();
if (!IsCheevosChallengeModeActive())
DrawDebugWindows();
DrawFPSWindow();
}
@ -1236,6 +1240,15 @@ void CommonHostInterface::DrawDebugWindows()
g_dma.DrawDebugStateWindow();
}
bool CommonHostInterface::IsCheevosChallengeModeActive() const
{
#ifdef WITH_CHEEVOS
return Cheevos::IsChallengeModeActive();
#else
return false;
#endif
}
void CommonHostInterface::DoFrameStep()
{
if (System::IsShutdown())
@ -1766,6 +1779,12 @@ void CommonHostInterface::RegisterHotkeys()
RegisterAudioHotkeys();
}
static void DisplayHotkeyBlockedByChallengeModeMessage()
{
g_host_interface->AddOSDMessage(g_host_interface->TranslateStdString(
"OSDMessage", "Hotkey unavailable because achievements hardcore mode is active."));
}
void CommonHostInterface::RegisterGeneralHotkeys()
{
RegisterHotkey(StaticString(TRANSLATABLE("Hotkeys", "General")), StaticString("OpenQuickMenu"),
@ -1807,7 +1826,12 @@ void CommonHostInterface::RegisterGeneralHotkeys()
RegisterHotkey(StaticString(TRANSLATABLE("Hotkeys", "General")), StaticString("ToggleCheats"),
StaticString(TRANSLATABLE("Hotkeys", "Toggle Cheats")), [this](bool pressed) {
if (pressed && System::IsValid())
DoToggleCheats();
{
if (!IsCheevosChallengeModeActive())
DoToggleCheats();
else
DisplayHotkeyBlockedByChallengeModeMessage();
}
});
RegisterHotkey(StaticString(TRANSLATABLE("Hotkeys", "General")), StaticString("PowerOff"),
@ -1838,7 +1862,7 @@ void CommonHostInterface::RegisterGeneralHotkeys()
#else
RegisterHotkey(StaticString(TRANSLATABLE("Hotkeys", "General")), StaticString("TogglePatchCodes"),
StaticString(TRANSLATABLE("Hotkeys", "Toggle Patch Codes")), [this](bool pressed) {
if (pressed && System::IsValid())
if (pressed && System::IsValid() && !IsCheevosChallengeModeActive())
DoToggleCheats();
});
#endif
@ -1858,7 +1882,12 @@ void CommonHostInterface::RegisterGeneralHotkeys()
RegisterHotkey(StaticString(TRANSLATABLE("Hotkeys", "General")), StaticString("FrameStep"),
StaticString(TRANSLATABLE("Hotkeys", "Frame Step")), [this](bool pressed) {
if (pressed && System::IsValid())
DoFrameStep();
{
if (!IsCheevosChallengeModeActive())
DoFrameStep();
else
DisplayHotkeyBlockedByChallengeModeMessage();
}
});
#ifndef __ANDROID__
@ -1866,10 +1895,17 @@ void CommonHostInterface::RegisterGeneralHotkeys()
StaticString(TRANSLATABLE("Hotkeys", "Rewind")), [this](bool pressed) {
if (System::IsValid())
{
AddOSDMessage(pressed ? TranslateStdString("OSDMessage", "Rewinding...") :
TranslateStdString("OSDMessage", "Stopped rewinding."),
5.0f);
System::SetRewinding(pressed);
if (!IsCheevosChallengeModeActive())
{
AddOSDMessage(pressed ? TranslateStdString("OSDMessage", "Rewinding...") :
TranslateStdString("OSDMessage", "Stopped rewinding."),
5.0f);
System::SetRewinding(pressed);
}
else
{
DisplayHotkeyBlockedByChallengeModeMessage();
}
}
});
#endif
@ -1966,7 +2002,12 @@ void CommonHostInterface::RegisterSaveStateHotkeys()
RegisterHotkey(StaticString(TRANSLATABLE("Hotkeys", "Save States")), StaticString("LoadSelectedSaveState"),
StaticString(TRANSLATABLE("Hotkeys", "Load From Selected Slot")), [this](bool 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"),
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),
[this, slot](bool pressed) {
if (pressed)
LoadState(false, slot);
{
if (!IsCheevosChallengeModeActive())
LoadState(false, slot);
else
DisplayHotkeyBlockedByChallengeModeMessage();
}
});
RegisterHotkey(StaticString(TRANSLATABLE("Hotkeys", "Save States")),
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("Load Global State %u", slot), [this, slot](bool pressed) {
if (pressed)
LoadState(true, slot);
{
if (!IsCheevosChallengeModeActive())
LoadState(true, slot);
else
DisplayHotkeyBlockedByChallengeModeMessage();
}
});
RegisterHotkey(StaticString(TRANSLATABLE("Hotkeys", "Save States")),
TinyString::FromFormat("SaveGlobalState%u", slot),
@ -2606,6 +2657,31 @@ void CommonHostInterface::SaveSettings(SettingsInterface& 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)
{
Settings old_settings(std::move(g_settings));
@ -2967,6 +3043,9 @@ bool CommonHostInterface::LoadCheatList(const char* filename)
bool CommonHostInterface::LoadCheatListFromGameTitle()
{
if (IsCheevosChallengeModeActive())
return false;
const std::string filename(GetCheatFileName());
if (filename.empty() || !FileSystem::FileExists(filename.c_str()))
return false;
@ -2976,7 +3055,7 @@ bool CommonHostInterface::LoadCheatListFromGameTitle()
bool CommonHostInterface::LoadCheatListFromDatabase()
{
if (System::GetRunningCode().empty())
if (System::GetRunningCode().empty() || IsCheevosChallengeModeActive())
return false;
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_use_first_disc_from_playlist = GetBoolSettingValue("Cheevos", "UseFirstDiscFromPlaylist", 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() ||
cheevos_use_first_disc_from_playlist != Cheevos::IsUsingFirstDiscFromPlaylist() ||
cheevos_rich_presence != Cheevos::IsRichPresenceEnabled())
cheevos_rich_presence != Cheevos::IsRichPresenceEnabled() ||
cheevos_hardcore != Cheevos::IsChallengeModeEnabled())
{
Cheevos::Shutdown();
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.");
}
}

View File

@ -308,6 +308,9 @@ public:
void DrawOSDMessages();
void DrawDebugWindows();
/// Returns true if features such as save states should be disabled.
bool IsCheevosChallengeModeActive() const;
protected:
enum : u32
{
@ -391,6 +394,9 @@ protected:
/// Saves current settings variables to ini.
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.
virtual void CheckForSettingsChanges(const Settings& old_settings) override;

View File

@ -93,6 +93,15 @@ static void OpenAboutWindow();
static void SetDebugMenuEnabled(bool enabled);
static void UpdateDebugMenuVisibility();
static ALWAYS_INLINE bool IsCheevosHardcoreModeActive()
{
#ifdef WITH_CHEEVOS
return Cheevos::IsChallengeModeActive();
#else
return false;
#endif
}
static CommonHostInterface* s_host_interface;
static MainWindowType s_current_main_window = MainWindowType::Landing;
static std::bitset<static_cast<u32>(FrontendCommon::ControllerNavigationButton::Count)> s_nav_input_values{};
@ -285,14 +294,14 @@ void Shutdown()
void Render()
{
if (s_debug_menu_enabled)
{
DrawDebugMenu();
if (System::IsValid())
s_host_interface->DrawDebugWindows();
}
else if (System::IsValid())
if (System::IsValid())
{
DrawStatsOverlay();
if (!IsCheevosHardcoreModeActive())
s_host_interface->DrawDebugWindows();
}
ImGuiFullscreen::BeginLayout();
@ -707,7 +716,7 @@ void DrawLandingWindow()
BeginMenuButtons(7, 0.5f);
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(); });
ClearImGuiFocus();
@ -725,7 +734,7 @@ void DrawLandingWindow()
if (MenuButton(" " ICON_FA_TOOLBOX " Start BIOS", "Start the console without any disc inserted."))
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);
}
@ -1066,6 +1075,91 @@ static bool ToggleButtonForNonSetting(const char* title, const char* summary, co
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()
{
BeginFullscreenColumns();
@ -1954,23 +2048,45 @@ void DrawSettingsWindow()
BeginMenuButtons();
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(
"Enable RetroAchievements", "When enabled and logged in, DuckStation will scan for achievements on startup.",
"Cheevos", "Enabled", false);
settings_changed |= ToggleButtonForNonSetting(
"Rich Presence",
ICON_FA_USER_FRIENDS " Rich Presence",
"When enabled, rich presence information will be collected and sent to the server where supported.",
"Cheevos", "RichPresence", true);
settings_changed |=
ToggleButtonForNonSetting("Test Mode",
ToggleButtonForNonSetting(ICON_FA_STETHOSCOPE " Test Mode",
"When enabled, DuckStation will assume all achievements are locked and not "
"send any unlock notifications to the server.",
"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 "
"achievements, regardless of which disc is active.",
"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");
if (Cheevos::IsLoggedIn())
{
@ -1991,13 +2107,20 @@ void DrawSettingsWindow()
if (MenuButton(ICON_FA_KEY " Logout", "Logs out of RetroAchievements."))
Cheevos::Logout();
}
else
else if (Cheevos::IsActive())
{
ActiveButton(SmallString::FromFormat(ICON_FA_USER " Not Logged In", Cheevos::GetUsername().c_str()), false,
false, ImGuiFullscreen::LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY);
ActiveButton(ICON_FA_USER " Not Logged In", false, false,
ImGuiFullscreen::LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY);
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");
@ -2220,7 +2343,7 @@ void DrawQuickMenu(MainWindowType type)
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;
OpenSaveStateSelector(true);
@ -2232,7 +2355,7 @@ void DrawQuickMenu(MainWindowType type)
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;
DoCheatsMenu();
@ -3248,9 +3371,7 @@ void DrawDebugSystemMenu()
if (ImGui::MenuItem("Change Disc", nullptr, false, system_enabled))
{
#if 0
DoChangeDisc();
#endif
ClearImGuiFocus();
}
@ -3260,17 +3381,9 @@ void DrawDebugSystemMenu()
ClearImGuiFocus();
}
if (ImGui::MenuItem("Frame Step", nullptr, false, system_enabled))
{
#if 0
s_host_interface->RunLater([]() { DoFrameStep(); });
#endif
ClearImGuiFocus();
}
ImGui::Separator();
if (ImGui::BeginMenu("Load State"))
if (ImGui::BeginMenu("Load State", !IsCheevosHardcoreModeActive()))
{
for (u32 i = 1; i <= CommonHostInterface::GLOBAL_SAVE_STATE_SLOTS; i++)
{
@ -3302,7 +3415,7 @@ void DrawDebugSystemMenu()
ImGui::Separator();
if (ImGui::BeginMenu("Cheats", system_enabled))
if (ImGui::BeginMenu("Cheats", system_enabled && !IsCheevosHardcoreModeActive()))
{
const bool has_cheat_file = System::HasCheatList();
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));
text.Assign(Cheevos::GetGameTitle());
const std::string& developer = Cheevos::GetGameDeveloper();
if (!developer.empty())
text.AppendFormattedString(" (%s)", developer.c_str());
if (Cheevos::IsChallengeModeActive())
text.AppendString(" (Hardcore Mode)");
top += g_large_font->FontSize + spacing;