diff --git a/Common/GPU/Vulkan/VulkanMemory.h b/Common/GPU/Vulkan/VulkanMemory.h index 9f51990691..f218de3605 100644 --- a/Common/GPU/Vulkan/VulkanMemory.h +++ b/Common/GPU/Vulkan/VulkanMemory.h @@ -5,6 +5,7 @@ #include #include +#include "Common/Data/Collections/FastVec.h" #include "Common/GPU/Vulkan/VulkanContext.h" #include "Common/GPU/GPUBackendCommon.h" @@ -205,4 +206,3 @@ private: uint32_t usage_ = 0; bool grow_; }; - diff --git a/Common/System/OSD.cpp b/Common/System/OSD.cpp index 818c569fb1..8013463e95 100644 --- a/Common/System/OSD.cpp +++ b/Common/System/OSD.cpp @@ -2,6 +2,7 @@ #include "Common/System/OSD.h" #include "Common/TimeUtil.h" +#include "Common/Log.h" OnScreenDisplay g_OSD; @@ -146,6 +147,11 @@ void OnScreenDisplay::ShowChallengeIndicator(int achievementID, bool show) { } } + if (!show) { + // Sanity check + return; + } + // OK, let's make a new side-entry. Entry entry; entry.numericID = achievementID; @@ -172,13 +178,20 @@ void OnScreenDisplay::ShowLeaderboardTracker(int leaderboardTrackerID, const cha } } + if (!show) { + // Sanity check + return; + } + // OK, let's make a new side-entry. Entry entry; entry.numericID = leaderboardTrackerID; entry.type = OSDType::LEADERBOARD_TRACKER; entry.startTime = now; entry.endTime = now + 10000000.0; // Don't auto-fadeout - entry.text = trackerText; + if (trackerText) { + entry.text = trackerText; + } sideEntries_.insert(sideEntries_.begin(), entry); } diff --git a/Core/Config.cpp b/Core/Config.cpp index 3bb09ab770..d2b6835d11 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -266,7 +266,6 @@ static bool DefaultSasThread() { static const ConfigSetting achievementSettings[] = { ConfigSetting("AchievementsEnable", &g_Config.bAchievementsEnable, true, CfgFlag::DEFAULT), - ConfigSetting("AchievementsRichPresence", &g_Config.bAchievementsRichPresence, true, CfgFlag::DEFAULT), ConfigSetting("AchievementsChallengeMode", &g_Config.bAchievementsChallengeMode, false, CfgFlag::DEFAULT), ConfigSetting("AchievementsEncoreMode", &g_Config.bAchievementsEncoreMode, false, CfgFlag::DEFAULT), ConfigSetting("AchievementsUnofficial", &g_Config.bAchievementsUnofficial, false, CfgFlag::DEFAULT), diff --git a/Core/Config.h b/Core/Config.h index 97d67f4a00..3f01bb68c5 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -488,7 +488,6 @@ public: // Retro Achievement settings // Copied from Duckstation, we might want to remove some. bool bAchievementsEnable; - bool bAchievementsRichPresence; bool bAchievementsChallengeMode; bool bAchievementsEncoreMode; bool bAchievementsUnofficial; diff --git a/Core/CwCheat.cpp b/Core/CwCheat.cpp index 59d0143d8a..857f50cc69 100644 --- a/Core/CwCheat.cpp +++ b/Core/CwCheat.cpp @@ -19,6 +19,7 @@ #include "Core/System.h" #include "Core/HLE/sceCtrl.h" #include "Core/MIPS/JitCommon/JitCommon.h" +#include "Core/RetroAchievements.h" #include "GPU/Common/PostShader.h" #ifdef _WIN32 @@ -319,9 +320,11 @@ void __CheatDoState(PointerWrap &p) { } void hleCheat(u64 userdata, int cyclesLate) { - if (cheatsEnabled != g_Config.bEnableCheats) { + bool shouldBeEnabled = !Achievements::ChallengeModeActive() && g_Config.bEnableCheats; + + if (cheatsEnabled != shouldBeEnabled) { // Okay, let's move to the desired state, then. - if (g_Config.bEnableCheats) { + if (shouldBeEnabled) { __CheatStart(); } else { __CheatStop(); @@ -1193,6 +1196,10 @@ void CWCheatEngine::ExecuteOp(const CheatOperation &op, const CheatCode &cheat, } void CWCheatEngine::Run() { + if (Achievements::ChallengeModeActive()) { + return; + } + for (CheatCode cheat : cheats_) { // InterpretNextOp and ExecuteOp move i. for (size_t i = 0; i < cheat.lines.size(); ) { @@ -1207,8 +1214,7 @@ bool CWCheatEngine::HasCheats() { } bool CheatsInEffect() { - if (!cheatEngine || !cheatsEnabled) + if (!cheatEngine || !cheatsEnabled || Achievements::ChallengeModeActive()) return false; return cheatEngine->HasCheats(); } - diff --git a/Core/HLE/sceDisplay.cpp b/Core/HLE/sceDisplay.cpp index b5039cabd3..13e2c9310b 100644 --- a/Core/HLE/sceDisplay.cpp +++ b/Core/HLE/sceDisplay.cpp @@ -49,6 +49,7 @@ #include "Core/HLE/sceKernelInterrupt.h" #include "Core/HW/Display.h" #include "Core/Util/PPGeDraw.h" +#include "Core/RetroAchievements.h" #include "GPU/GPU.h" #include "GPU/GPUState.h" @@ -348,12 +349,15 @@ void __DisplaySetWasPaused() { } static int FrameTimingLimit() { - if (PSP_CoreParameter().fpsLimit == FPSLimit::CUSTOM1) - return g_Config.iFpsLimit1; - if (PSP_CoreParameter().fpsLimit == FPSLimit::CUSTOM2) - return g_Config.iFpsLimit2; - if (PSP_CoreParameter().fpsLimit == FPSLimit::ANALOG) - return PSP_CoreParameter().analogFpsLimit; + if (!Achievements::ChallengeModeActive()) { + if (PSP_CoreParameter().fpsLimit == FPSLimit::CUSTOM1) + return g_Config.iFpsLimit1; + if (PSP_CoreParameter().fpsLimit == FPSLimit::CUSTOM2) + return g_Config.iFpsLimit2; + if (PSP_CoreParameter().fpsLimit == FPSLimit::ANALOG) + return PSP_CoreParameter().analogFpsLimit; + } + // Note: Fast-forward is OK in challenge mode. if (PSP_CoreParameter().fastForward) return 0; return framerate; diff --git a/Core/RetroAchievements.cpp b/Core/RetroAchievements.cpp index 872f713a81..c5c77a6841 100644 --- a/Core/RetroAchievements.cpp +++ b/Core/RetroAchievements.cpp @@ -74,8 +74,6 @@ namespace Achievements { // It's the name of the secret, not a secret name - the value is not secret :) static const char *RA_TOKEN_SECRET_NAME = "retroachievements"; -static u32 GetGameID(); - static Achievements::Statistics g_stats; const std::string g_gameIconCachePrefix = "game:"; @@ -84,8 +82,6 @@ const std::string g_iconCachePrefix = "badge:"; Path s_game_path; std::string s_game_hash; -bool g_challengeMode = true; - bool g_isIdentifying = false; // rc_client implementation @@ -101,10 +97,6 @@ bool IsLoggedIn() { return rc_client_get_user_info(g_rcClient) != nullptr; } -bool ChallengeModeActive() { - return g_challengeMode; -} - bool EncoreModeActive() { if (!g_rcClient) { return false; @@ -119,15 +111,33 @@ bool UnofficialEnabled() { return rc_client_get_unofficial_enabled(g_rcClient); } -bool IsActive() { - return GetGameID() != 0; +bool ChallengeModeActive() { + if (!g_rcClient) { + return false; + } + return rc_client_get_hardcore_enabled(g_rcClient); +} + +bool WarnUserIfChallengeModeActive(const char *message) { + if (!ChallengeModeActive()) { + return false; + } + + const char *showMessage = message; + if (!message) { + auto ac = GetI18NCategory(I18NCat::ACHIEVEMENTS); + showMessage = ac->T("This feature is not available in Challenge Mode"); + } + + g_OSD.Show(OSDType::MESSAGE_WARNING, showMessage, 3.0f); + return true; } bool IsBlockingExecution() { return g_isIdentifying; } -u32 GetGameID() { +static u32 GetGameID() { if (!g_rcClient) { return 0; } @@ -139,6 +149,10 @@ u32 GetGameID() { return info->id; // 0 if not identified } +bool IsActive() { + return GetGameID() != 0; +} + // This is the function the rc_client will use to read memory for the emulator. we don't need it yet, // so just provide a dummy function that returns "no memory read". static uint32_t read_memory_callback(uint32_t address, uint8_t *buffer, uint32_t num_bytes, rc_client_t *client) { @@ -260,12 +274,12 @@ static void event_handler_callback(const rc_client_event_t *event, rc_client_t * break; case RC_CLIENT_EVENT_LEADERBOARD_FAILED: NOTICE_LOG(ACHIEVEMENTS, "Leaderboard attempt failed: %s", event->leaderboard->title); - g_OSD.Show(OSDType::MESSAGE_INFO, ReplaceAll(ac->T("%1: Failed"), "%1", event->leaderboard->title), 3.0f); + g_OSD.Show(OSDType::MESSAGE_INFO, ReplaceAll(ac->T("%1: Leaderboard attempt failed"), "%1", event->leaderboard->title), 3.0f); // A leaderboard attempt has failed. break; case RC_CLIENT_EVENT_LEADERBOARD_SUBMITTED: NOTICE_LOG(ACHIEVEMENTS, "Leaderboard result submitted: %s", event->leaderboard->title); - g_OSD.Show(OSDType::MESSAGE_SUCCESS, ReplaceAll(ac->T("%1: Submitting successful score!"), "%1", event->leaderboard->title), event->leaderboard->description, 3.0f); + g_OSD.Show(OSDType::MESSAGE_SUCCESS, ReplaceAll(ReplaceAll(ac->T("%1: Submitting leaderboard score: %2!"), "%1", event->leaderboard->title), "%2", event->leaderboard->tracker_value), event->leaderboard->description, 3.0f); // A leaderboard attempt was completed.The handler may show a message with the leaderboard title and /or description indicating the final value being submitted to the server. break; case RC_CLIENT_EVENT_ACHIEVEMENT_CHALLENGE_INDICATOR_SHOW: @@ -288,7 +302,7 @@ static void event_handler_callback(const rc_client_event_t *event, rc_client_t * g_OSD.ShowAchievementProgress(event->achievement->id, 2.0f); break; case RC_CLIENT_EVENT_LEADERBOARD_TRACKER_SHOW: - NOTICE_LOG(ACHIEVEMENTS, "Leaderboard tracker show: %s", event->leaderboard_tracker->display); + NOTICE_LOG(ACHIEVEMENTS, "Leaderboard tracker show: '%s' (id %d)", event->leaderboard_tracker->display, event->leaderboard_tracker->id); // A leaderboard_tracker has become active. The handler should show the tracker text on screen. // Multiple active leaderboards may share a single tracker if they have the same definition and value. // As such, the leaderboard tracker IDs are unique amongst the leaderboard trackers, and have no correlation to the active leaderboard(s). @@ -297,13 +311,13 @@ static void event_handler_callback(const rc_client_event_t *event, rc_client_t * break; case RC_CLIENT_EVENT_LEADERBOARD_TRACKER_HIDE: // A leaderboard_tracker has become inactive. The handler should hide the tracker text from the screen. - NOTICE_LOG(ACHIEVEMENTS, "Leaderboard tracker hide: %s", event->leaderboard_tracker->display); + NOTICE_LOG(ACHIEVEMENTS, "Leaderboard tracker hide: '%s' (id %d)", event->leaderboard_tracker->display, event->leaderboard_tracker->id); g_OSD.ShowLeaderboardTracker(event->leaderboard_tracker->id, nullptr, false); break; case RC_CLIENT_EVENT_LEADERBOARD_TRACKER_UPDATE: // A leaderboard_tracker value has been updated. The handler should update the tracker text on the screen. - NOTICE_LOG(ACHIEVEMENTS, "Leaderboard tracker update: %s", event->leaderboard_tracker->display); - g_OSD.ShowLeaderboardTracker(event->leaderboard_tracker->id, event->leaderboard_tracker->display, false); + NOTICE_LOG(ACHIEVEMENTS, "Leaderboard tracker update: '%s' (id %d)", event->leaderboard_tracker->display, event->leaderboard_tracker->id); + g_OSD.ShowLeaderboardTracker(event->leaderboard_tracker->id, event->leaderboard_tracker->display, true); break; case RC_CLIENT_EVENT_RESET: WARN_LOG(ACHIEVEMENTS, "Resetting game due to achievement setting change!"); @@ -328,16 +342,10 @@ void Initialize() { } _assert_msg_(g_Config.bAchievementsEnable, "Achievements are enabled"); - g_challengeMode = true; // the default g_rcClient = rc_client_create(read_memory_callback, server_call_callback); // Provide a logging function to simplify debugging rc_client_enable_logging(g_rcClient, RC_CLIENT_LOG_LEVEL_VERBOSE, log_message_callback); - // FOR NOW: Disable hardcore - if we goof something up in the implementation, we don't want our - // account disabled for cheating. - rc_client_set_hardcore_enabled(g_rcClient, 0); - g_challengeMode = false; - // Disable SSL for now. rc_client_set_host(g_rcClient, "http://retroachievements.org"); @@ -590,6 +598,7 @@ void SetGame(const Path &path) { g_isIdentifying = true; // Apply pre-load settings. + rc_client_set_hardcore_enabled(g_rcClient, g_Config.bAchievementsChallengeMode ? 1 : 0); rc_client_set_encore_mode_enabled(g_rcClient, g_Config.bAchievementsEncoreMode ? 1 : 0); rc_client_set_unofficial_enabled(g_rcClient, g_Config.bAchievementsUnofficial ? 1 : 0); diff --git a/Core/RetroAchievements.h b/Core/RetroAchievements.h index d035fc5f77..10e219dfe7 100644 --- a/Core/RetroAchievements.h +++ b/Core/RetroAchievements.h @@ -51,14 +51,24 @@ bool IsLoggedIn(); // Returns true if in a game, and achievements are active in the current game. bool IsActive(); +// Returns true if unofficial achievements are enabled. +bool UnofficialEnabled(); + // Returns true if the emulator should hold off on executing game code, such as during game identification. bool IsBlockingExecution(); -/// Returns true if features such as save states should be disabled. +// Returns true if features such as save states should be disabled. +// This should only be used for controlling functionality of the following things, which are banned in Challenge/Hardcore mode: +// +// * Savestates +// * Slowdown time (though hard to fully prevent, could use crazy post shaders or software rendering...) bool ChallengeModeActive(); -// Returns true if unofficial achievements are enabled. -bool UnofficialEnabled(); +// Same as ChallengeModeActive but comes with a convenient user message. Don't use for every-frame checks or UI enablement, +// only for shortcut keys and commands. You should look up the message in I18NCat::ACHIEVEMENTS. +// If no message is specified, a standard "This feature is not available in Challenge Mode" message will be shown. +// Also returns true if challenge mode is active. +bool WarnUserIfChallengeModeActive(const char *message = nullptr); // The new API is so much nicer that we can use it directly instead of wrapping it. So let's expose the client. // Will of course return nullptr if not active. diff --git a/Core/SaveState.cpp b/Core/SaveState.cpp index 4d689460b4..99ba2e3e06 100644 --- a/Core/SaveState.cpp +++ b/Core/SaveState.cpp @@ -399,6 +399,11 @@ namespace SaveState void Enqueue(SaveState::Operation op) { + if (Achievements::ChallengeModeActive()) { + // No savestate operations are permitted, let's just ignore it. + return; + } + std::lock_guard guard(mutex); pending.push_back(op); diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index 60c9e4a331..efb114cda5 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -582,7 +582,7 @@ void EmuScreen::onVKey(int virtualKeyCode, bool down) { break; case VIRTKEY_SPEED_TOGGLE: - if (down) { + if (down && !Achievements::WarnUserIfChallengeModeActive()) { // Cycle through enabled speeds. if (PSP_CoreParameter().fpsLimit == FPSLimit::NORMAL && g_Config.iFpsLimit1 >= 0) { PSP_CoreParameter().fpsLimit = FPSLimit::CUSTOM1; @@ -598,28 +598,32 @@ void EmuScreen::onVKey(int virtualKeyCode, bool down) { break; case VIRTKEY_SPEED_CUSTOM1: - if (down) { - if (PSP_CoreParameter().fpsLimit == FPSLimit::NORMAL) { - PSP_CoreParameter().fpsLimit = FPSLimit::CUSTOM1; - g_OSD.Show(OSDType::MESSAGE_INFO, sc->T("fixed", "Speed: alternate"), 1.0); - } - } else { - if (PSP_CoreParameter().fpsLimit == FPSLimit::CUSTOM1) { - PSP_CoreParameter().fpsLimit = FPSLimit::NORMAL; - g_OSD.Show(OSDType::MESSAGE_INFO, sc->T("standard", "Speed: standard"), 1.0); + if (!Achievements::WarnUserIfChallengeModeActive()) { + if (down) { + if (PSP_CoreParameter().fpsLimit == FPSLimit::NORMAL) { + PSP_CoreParameter().fpsLimit = FPSLimit::CUSTOM1; + g_OSD.Show(OSDType::MESSAGE_INFO, sc->T("fixed", "Speed: alternate"), 1.0); + } + } else { + if (PSP_CoreParameter().fpsLimit == FPSLimit::CUSTOM1) { + PSP_CoreParameter().fpsLimit = FPSLimit::NORMAL; + g_OSD.Show(OSDType::MESSAGE_INFO, sc->T("standard", "Speed: standard"), 1.0); + } } } break; case VIRTKEY_SPEED_CUSTOM2: - if (down) { - if (PSP_CoreParameter().fpsLimit == FPSLimit::NORMAL) { - PSP_CoreParameter().fpsLimit = FPSLimit::CUSTOM2; - g_OSD.Show(OSDType::MESSAGE_INFO, sc->T("SpeedCustom2", "Speed: alternate 2"), 1.0); - } - } else { - if (PSP_CoreParameter().fpsLimit == FPSLimit::CUSTOM2) { - PSP_CoreParameter().fpsLimit = FPSLimit::NORMAL; - g_OSD.Show(OSDType::MESSAGE_INFO, sc->T("standard", "Speed: standard"), 1.0); + if (!Achievements::WarnUserIfChallengeModeActive()) { + if (down) { + if (PSP_CoreParameter().fpsLimit == FPSLimit::NORMAL) { + PSP_CoreParameter().fpsLimit = FPSLimit::CUSTOM2; + g_OSD.Show(OSDType::MESSAGE_INFO, sc->T("SpeedCustom2", "Speed: alternate 2"), 1.0); + } + } else { + if (PSP_CoreParameter().fpsLimit == FPSLimit::CUSTOM2) { + PSP_CoreParameter().fpsLimit = FPSLimit::NORMAL; + g_OSD.Show(OSDType::MESSAGE_INFO, sc->T("standard", "Speed: standard"), 1.0); + } } } break; @@ -635,13 +639,15 @@ void EmuScreen::onVKey(int virtualKeyCode, bool down) { break; case VIRTKEY_FRAME_ADVANCE: - if (down) { - // If game is running, pause emulation immediately. Otherwise, advance a single frame. - if (Core_IsStepping()) { - frameStep_ = true; - Core_EnableStepping(false); - } else if (!frameStep_) { - Core_EnableStepping(true, "ui.frameAdvance", 0); + if (!Achievements::WarnUserIfChallengeModeActive()) { + if (down) { + // If game is running, pause emulation immediately. Otherwise, advance a single frame. + if (Core_IsStepping()) { + frameStep_ = true; + Core_EnableStepping(false); + } else if (!frameStep_) { + Core_EnableStepping(true, "ui.frameAdvance", 0); + } } } break; @@ -691,7 +697,7 @@ void EmuScreen::onVKey(int virtualKeyCode, bool down) { #endif case VIRTKEY_REWIND: - if (down) { + if (down && !Achievements::WarnUserIfChallengeModeActive()) { if (SaveState::CanRewind()) { SaveState::Rewind(&AfterSaveStateAction); } else { @@ -700,21 +706,21 @@ void EmuScreen::onVKey(int virtualKeyCode, bool down) { } break; case VIRTKEY_SAVE_STATE: - if (down) + if (down && !Achievements::WarnUserIfChallengeModeActive()) SaveState::SaveSlot(gamePath_, g_Config.iCurrentStateSlot, &AfterSaveStateAction); break; case VIRTKEY_LOAD_STATE: - if (down) + if (down && !Achievements::WarnUserIfChallengeModeActive()) SaveState::LoadSlot(gamePath_, g_Config.iCurrentStateSlot, &AfterSaveStateAction); break; case VIRTKEY_PREVIOUS_SLOT: - if (down) { + if (down && !Achievements::WarnUserIfChallengeModeActive()) { SaveState::PrevSlot(); System_PostUIMessage("savestate_displayslot", ""); } break; case VIRTKEY_NEXT_SLOT: - if (down) { + if (down && !Achievements::WarnUserIfChallengeModeActive()) { SaveState::NextSlot(); System_PostUIMessage("savestate_displayslot", ""); } diff --git a/UI/RetroAchievementScreens.cpp b/UI/RetroAchievementScreens.cpp index 40e8b4ba17..d38dbc9357 100644 --- a/UI/RetroAchievementScreens.cpp +++ b/UI/RetroAchievementScreens.cpp @@ -275,7 +275,6 @@ void RetroAchievementsSettingsScreen::CreateSettingsTab(UI::ViewGroup *viewGroup viewGroup->Add(new CheckBox(&g_Config.bAchievementsChallengeMode, ac->T("Challenge Mode (no savestates)"))); viewGroup->Add(new CheckBox(&g_Config.bAchievementsEncoreMode, ac->T("Encore Mode"))); viewGroup->Add(new CheckBox(&g_Config.bAchievementsUnofficial, ac->T("Unofficial achievements"))); - viewGroup->Add(new CheckBox(&g_Config.bAchievementsRichPresence, ac->T("Rich Presence")))->SetEnabledPtr(&g_Config.bAchievementsEnable); // viewGroup->Add(new CheckBox(&g_Config.bAchievementsSoundEffects, ac->T("Sound Effects")))->SetEnabledPtr(&g_Config.bAchievementsEnable); // not yet implemented viewGroup->Add(new CheckBox(&g_Config.bAchievementsLogBadMemReads, ac->T("Log bad memory accesses")))->SetEnabledPtr(&g_Config.bAchievementsEnable); diff --git a/Windows/MainWindowMenu.cpp b/Windows/MainWindowMenu.cpp index 43c6c7bc99..2e7101f76f 100644 --- a/Windows/MainWindowMenu.cpp +++ b/Windows/MainWindowMenu.cpp @@ -51,6 +51,7 @@ #include "Core/HLE/sceUmd.h" #include "Core/SaveState.h" #include "Core/Core.h" +#include "Core/RetroAchievements.h" extern bool g_TakeScreenshot; @@ -69,14 +70,23 @@ namespace MainWindow { LRESULT CALLBACK AboutDlgProc(HWND, UINT, WPARAM, LPARAM); void SetIngameMenuItemStates(HMENU menu, const GlobalUIState state) { - UINT menuEnable = state == UISTATE_INGAME || state == UISTATE_EXCEPTION ? MF_ENABLED : MF_GRAYED; + bool menuEnableBool = state == UISTATE_INGAME || state == UISTATE_EXCEPTION; + + bool saveStateEnableBool = menuEnableBool; + if (Achievements::ChallengeModeActive()) { + saveStateEnableBool = false; + } + + UINT menuEnable = menuEnableBool ? MF_ENABLED : MF_GRAYED; + UINT saveStateEnable = saveStateEnableBool ? MF_ENABLED : MF_GRAYED; UINT menuInGameEnable = state == UISTATE_INGAME ? MF_ENABLED : MF_GRAYED; UINT umdSwitchEnable = state == UISTATE_INGAME && getUMDReplacePermit() ? MF_ENABLED : MF_GRAYED; - EnableMenuItem(menu, ID_FILE_SAVESTATEFILE, menuEnable); - EnableMenuItem(menu, ID_FILE_LOADSTATEFILE, menuEnable); - EnableMenuItem(menu, ID_FILE_QUICKSAVESTATE, menuEnable); - EnableMenuItem(menu, ID_FILE_QUICKLOADSTATE, menuEnable); + EnableMenuItem(menu, ID_FILE_SAVESTATE_SLOT_MENU, saveStateEnable); + EnableMenuItem(menu, ID_FILE_SAVESTATEFILE, saveStateEnable); + EnableMenuItem(menu, ID_FILE_LOADSTATEFILE, saveStateEnable); + EnableMenuItem(menu, ID_FILE_QUICKSAVESTATE, saveStateEnable); + EnableMenuItem(menu, ID_FILE_QUICKLOADSTATE, saveStateEnable); EnableMenuItem(menu, ID_EMULATION_PAUSE, menuEnable); EnableMenuItem(menu, ID_EMULATION_STOP, menuEnable); EnableMenuItem(menu, ID_EMULATION_RESET, menuEnable); @@ -517,70 +527,87 @@ namespace MainWindow { } break; case ID_FILE_LOADSTATEFILE: - if (W32Util::BrowseForFileName(true, hWnd, L"Load state", 0, L"Save States (*.ppst)\0*.ppst\0All files\0*.*\0\0", L"ppst", fn)) { - SetCursor(LoadCursor(0, IDC_WAIT)); - SaveState::Load(Path(fn), -1, SaveStateActionFinished); + if (!Achievements::WarnUserIfChallengeModeActive()) { + if (W32Util::BrowseForFileName(true, hWnd, L"Load state", 0, L"Save States (*.ppst)\0*.ppst\0All files\0*.*\0\0", L"ppst", fn)) { + SetCursor(LoadCursor(0, IDC_WAIT)); + SaveState::Load(Path(fn), -1, SaveStateActionFinished); + } } break; case ID_FILE_SAVESTATEFILE: - if (W32Util::BrowseForFileName(false, hWnd, L"Save state", 0, L"Save States (*.ppst)\0*.ppst\0All files\0*.*\0\0", L"ppst", fn)) { - SetCursor(LoadCursor(0, IDC_WAIT)); - SaveState::Save(Path(fn), -1, SaveStateActionFinished); + if (!Achievements::WarnUserIfChallengeModeActive()) { + if (W32Util::BrowseForFileName(false, hWnd, L"Save state", 0, L"Save States (*.ppst)\0*.ppst\0All files\0*.*\0\0", L"ppst", fn)) { + SetCursor(LoadCursor(0, IDC_WAIT)); + SaveState::Save(Path(fn), -1, SaveStateActionFinished); + } } break; case ID_FILE_SAVESTATE_NEXT_SLOT: { - SaveState::NextSlot(); - System_PostUIMessage("savestate_displayslot", ""); - break; - } - - case ID_FILE_SAVESTATE_NEXT_SLOT_HC: - { - if (!KeyMap::PspButtonHasMappings(VIRTKEY_NEXT_SLOT)) { + if (!Achievements::WarnUserIfChallengeModeActive()) { SaveState::NextSlot(); System_PostUIMessage("savestate_displayslot", ""); } break; } - case ID_FILE_SAVESTATE_SLOT_1: g_Config.iCurrentStateSlot = 0; break; - case ID_FILE_SAVESTATE_SLOT_2: g_Config.iCurrentStateSlot = 1; break; - case ID_FILE_SAVESTATE_SLOT_3: g_Config.iCurrentStateSlot = 2; break; - case ID_FILE_SAVESTATE_SLOT_4: g_Config.iCurrentStateSlot = 3; break; - case ID_FILE_SAVESTATE_SLOT_5: g_Config.iCurrentStateSlot = 4; break; - - case ID_FILE_QUICKLOADSTATE: + case ID_FILE_SAVESTATE_NEXT_SLOT_HC: { - SetCursor(LoadCursor(0, IDC_WAIT)); - SaveState::LoadSlot(PSP_CoreParameter().fileToStart, g_Config.iCurrentStateSlot, SaveStateActionFinished); + if (!Achievements::WarnUserIfChallengeModeActive()) { + if (!KeyMap::PspButtonHasMappings(VIRTKEY_NEXT_SLOT)) { + SaveState::NextSlot(); + System_PostUIMessage("savestate_displayslot", ""); + } + } break; } - case ID_FILE_QUICKLOADSTATE_HC: - { - if (!KeyMap::PspButtonHasMappings(VIRTKEY_LOAD_STATE)) - { + case ID_FILE_SAVESTATE_SLOT_1: + case ID_FILE_SAVESTATE_SLOT_2: + case ID_FILE_SAVESTATE_SLOT_3: + case ID_FILE_SAVESTATE_SLOT_4: + case ID_FILE_SAVESTATE_SLOT_5: + if (!Achievements::WarnUserIfChallengeModeActive()) { + g_Config.iCurrentStateSlot = wmId - ID_FILE_SAVESTATE_SLOT_1; + } + break; + + case ID_FILE_QUICKLOADSTATE: + if (!Achievements::WarnUserIfChallengeModeActive()) { SetCursor(LoadCursor(0, IDC_WAIT)); SaveState::LoadSlot(PSP_CoreParameter().fileToStart, g_Config.iCurrentStateSlot, SaveStateActionFinished); } break; + + case ID_FILE_QUICKLOADSTATE_HC: + { + if (!Achievements::WarnUserIfChallengeModeActive()) { + if (!KeyMap::PspButtonHasMappings(VIRTKEY_LOAD_STATE)) { + SetCursor(LoadCursor(0, IDC_WAIT)); + SaveState::LoadSlot(PSP_CoreParameter().fileToStart, g_Config.iCurrentStateSlot, SaveStateActionFinished); + } + } + break; } case ID_FILE_QUICKSAVESTATE: { - SetCursor(LoadCursor(0, IDC_WAIT)); - SaveState::SaveSlot(PSP_CoreParameter().fileToStart, g_Config.iCurrentStateSlot, SaveStateActionFinished); + if (!Achievements::WarnUserIfChallengeModeActive()) { + SetCursor(LoadCursor(0, IDC_WAIT)); + SaveState::SaveSlot(PSP_CoreParameter().fileToStart, g_Config.iCurrentStateSlot, SaveStateActionFinished); + } break; } case ID_FILE_QUICKSAVESTATE_HC: { - if (!KeyMap::PspButtonHasMappings(VIRTKEY_SAVE_STATE)) - { - SetCursor(LoadCursor(0, IDC_WAIT)); - SaveState::SaveSlot(PSP_CoreParameter().fileToStart, g_Config.iCurrentStateSlot, SaveStateActionFinished); - break; + if (!Achievements::WarnUserIfChallengeModeActive()) { + if (!KeyMap::PspButtonHasMappings(VIRTKEY_SAVE_STATE)) + { + SetCursor(LoadCursor(0, IDC_WAIT)); + SaveState::SaveSlot(PSP_CoreParameter().fileToStart, g_Config.iCurrentStateSlot, SaveStateActionFinished); + break; + } } break; } diff --git a/assets/lang/en_US.ini b/assets/lang/en_US.ini index f18edebc1f..fe31752454 100644 --- a/assets/lang/en_US.ini +++ b/assets/lang/en_US.ini @@ -24,6 +24,9 @@ [Achievements] %d achievements, %d points = %d achievements, %d points +%1: Leaderboard attempt started = %1: Leaderboard attempt started +%1: Leaderboard attempt failed = %1: Leaderboard attempt failed +%1: Submitting leaderboard score: %2! = %1: Submitting leaderboard score: %2! Account = Account Achievements = Achievements Achievements are disabled = Achievements are disabled @@ -38,7 +41,7 @@ Links = Links Locked achievements = Locked achievements Log bad memory accesses = Log bad memory accesses Mastered %1 = Mastered %1 -Not available in Challenge Mode = Not available in Challenge Mode +This feature is not available in Challenge Mode = This feature is not available in Challenge Mode Save states not available in Challenge Mode = Save states not available in Challenge Mode Register on www.retroachievements.org = Register on www.retroachievements.org RetroAchievements are not available for this game = RetroAchievements are not available for this game