From 8e121a7e5187fb1f30b13b2d520c4303e2cd81db Mon Sep 17 00:00:00 2001 From: TakaRikka Date: Sat, 25 Apr 2026 21:12:51 -0700 Subject: [PATCH] update timer impl --- files.cmake | 1 + include/dusk/settings.h | 3 +- src/d/actor/d_a_alink_demo.inc | 10 ++ src/d/d_bright_check.cpp | 8 ++ src/d/d_s_name.cpp | 20 +++- src/dusk/imgui/ImGuiConsole.cpp | 9 +- src/dusk/imgui/ImGuiConsole.hpp | 7 +- src/dusk/imgui/ImGuiMenuGame.cpp | 121 +++++++++++++++++++++- src/dusk/imgui/ImGuiMenuGame.hpp | 22 ++++ src/dusk/imgui/ImGuiMenuSpeedrunTimer.cpp | 96 ----------------- src/dusk/imgui/ImGuiMenuTools.cpp | 9 ++ src/dusk/settings.cpp | 6 +- src/f_op/f_op_scene_req.cpp | 21 +++- 13 files changed, 215 insertions(+), 118 deletions(-) delete mode 100644 src/dusk/imgui/ImGuiMenuSpeedrunTimer.cpp diff --git a/files.cmake b/files.cmake index af101b6c47..91b0c0fab7 100644 --- a/files.cmake +++ b/files.cmake @@ -1461,6 +1461,7 @@ set(DUSK_FILES src/dusk/imgui/ImGuiStateShare.hpp src/dusk/imgui/ImGuiStateShare.cpp src/dusk/iso_validate.cpp + src/dusk/livesplit.cpp src/dusk/offset_ptr.cpp src/dusk/OSContext.cpp src/dusk/OSThread.cpp diff --git a/include/dusk/settings.h b/include/dusk/settings.h index 522e172e7c..7fb8c85a51 100644 --- a/include/dusk/settings.h +++ b/include/dusk/settings.h @@ -119,8 +119,7 @@ struct UserSettings { ConfigVar enableTurboKeybind; // Tools - ConfigVar speedrunTimer; - ConfigVar speedrunTimerOverlay; + ConfigVar speedrunMode; ConfigVar liveSplitEnabled; } game; diff --git a/src/d/actor/d_a_alink_demo.inc b/src/d/actor/d_a_alink_demo.inc index aa77b24129..b46af5cacb 100644 --- a/src/d/actor/d_a_alink_demo.inc +++ b/src/d/actor/d_a_alink_demo.inc @@ -23,6 +23,7 @@ #include "d/actor/d_a_npc_tkc.h" #include +#include "dusk/imgui/ImGuiConsole.hpp" #include "dusk/settings.h" BOOL daAlink_c::checkEventRun() const { @@ -4005,6 +4006,15 @@ int daAlink_c::procGanonFinishInit() { field_0x37c8 = current.pos; onEndResetFlg1(ERFLG1_SHIELD_BACKBONE); + +#if TARGET_PC + if (dusk::getSettings().game.speedrunMode) { + if (dusk::g_imguiConsole.isSpeedrunStart()) { + dusk::g_imguiConsole.stopSpeedrun(); + } + } +#endif + return 1; } diff --git a/src/d/d_bright_check.cpp b/src/d/d_bright_check.cpp index 2c683eb819..88d0b7a2d8 100644 --- a/src/d/d_bright_check.cpp +++ b/src/d/d_bright_check.cpp @@ -10,6 +10,7 @@ #include "JSystem/J2DGraph/J2DTextBox.h" #include "d/d_msg_string.h" #include "dusk/livesplit.h" +#include "dusk/imgui/ImGuiConsole.hpp" #include "m_Do/m_Do_controller_pad.h" dBrightCheck_c::dBrightCheck_c(JKRArchive* i_archive) { @@ -141,6 +142,13 @@ void dBrightCheck_c::modeMove() { mDoAud_seStart(Z2SE_ENTER_GAME, NULL, 0, 0); #ifdef TARGET_PC dusk::speedrun::start(); + + if (dusk::getSettings().game.speedrunMode && !dusk::getSettings().game.hideTvSettingsScreen) { + // start a new run if a run isn't already in progress + if (!dusk::g_imguiConsole.isSpeedrunStart()) { + dusk::g_imguiConsole.startSpeedrun(); + } + } #endif mCompleteCheck = true; mMode = MODE_WAIT_e; diff --git a/src/d/d_s_name.cpp b/src/d/d_s_name.cpp index 735ce4d0ca..9a20ca6caa 100644 --- a/src/d/d_s_name.cpp +++ b/src/d/d_s_name.cpp @@ -5,19 +5,20 @@ #include "d/dolzel.h" // IWYU pragma: keep -#include "d/d_s_name.h" #include "JSystem/JKernel/JKRExpHeap.h" #include "d/d_com_inf_game.h" #include "d/d_meter2_info.h" +#include "d/d_s_name.h" +#include "dusk/imgui/ImGuiConsole.hpp" +#include "dusk/memory.h" +#include "dusk/settings.h" +#include "f_op/f_op_overlap_mng.h" #include "f_op/f_op_scene_mng.h" #include "m_Do/m_Do_Reset.h" #include "m_Do/m_Do_graphic.h" #include "m_Do/m_Do_machine.h" -#include "m_Do/m_Do_mtx.h" #include "m_Do/m_Do_main.h" -#include "f_op/f_op_overlap_mng.h" -#include "dusk/memory.h" -#include "dusk/settings.h" +#include "m_Do/m_Do_mtx.h" #if TARGET_PC #define SHOW_TV_SETTINGS_SCREEN (this->mShowTvSettingsScreen) @@ -412,6 +413,15 @@ void dScnName_c::changeGameScene() { dKy_clear_game_init(); dComIfGs_resetDan(); dComIfGs_setRestartRoomParam(0); + +#if TARGET_PC + if (dusk::getSettings().game.speedrunMode && dusk::getSettings().game.hideTvSettingsScreen) { + // start a new run on file load if a run isn't already in progress + if (!dusk::g_imguiConsole.isSpeedrunStart()) { + dusk::g_imguiConsole.startSpeedrun(); + } + } +#endif } } diff --git a/src/dusk/imgui/ImGuiConsole.cpp b/src/dusk/imgui/ImGuiConsole.cpp index c64314a806..955cef3920 100644 --- a/src/dusk/imgui/ImGuiConsole.cpp +++ b/src/dusk/imgui/ImGuiConsole.cpp @@ -334,7 +334,6 @@ namespace dusk { if (showMenu && ImGui::BeginMainMenuBar()) { m_menuGame.draw(); m_menuTools.draw(); - m_menuSpeedrunTimer.draw(); const auto fpsLabel = fmt::format(FMT_STRING("FPS: {:.2f}\n"), ImGui::GetIO().Framerate); @@ -366,12 +365,11 @@ namespace dusk { } } - m_menuSpeedrunTimer.drawOverlay(); - UpdateDragScroll(); m_menuGame.windowControllerConfig(); m_menuGame.windowInputViewer(); + m_menuGame.drawSpeedrunTimerOverlay(); if (getSettings().game.liveSplitEnabled) { dusk::speedrun::updateLiveSplit(); @@ -381,7 +379,7 @@ namespace dusk { AddToast("LiveSplit disconnected"); } - if (dusk::IsGameLaunched) { + if (dusk::IsGameLaunched && !dusk::getSettings().game.speedrunMode) { m_menuTools.ShowDebugOverlay(); m_menuTools.ShowCameraOverlay(); m_menuTools.ShowProcessManager(); @@ -392,8 +390,9 @@ namespace dusk { m_menuTools.ShowPlayerInfo(); m_menuTools.ShowAudioDebug(); m_menuTools.ShowSaveEditor(); + m_menuTools.ShowStateShare(); } - m_menuTools.ShowStateShare(); + DuskDebugPad(); // temporary, remove later // Hide mouse cursor if the F1 menu is not open and the cursor is idle for 3 seconds. diff --git a/src/dusk/imgui/ImGuiConsole.hpp b/src/dusk/imgui/ImGuiConsole.hpp index 85e65d21a1..5e9f2aa523 100644 --- a/src/dusk/imgui/ImGuiConsole.hpp +++ b/src/dusk/imgui/ImGuiConsole.hpp @@ -10,7 +10,6 @@ #include "ImGuiFirstRunPreset.hpp" #include "ImGuiMenuGame.hpp" -#include "ImGuiMenuSpeedrunTimer.hpp" #include "ImGuiMenuTools.hpp" #include "ImGuiPreLaunchWindow.hpp" #include "imgui.h" @@ -30,6 +29,11 @@ public: static bool CheckMenuViewToggle(ImGuiKey key, bool& active); void AddToast(std::string_view message, float duration = 3.f); + bool isSpeedrunStart() const { return m_menuGame.isRunStarted(); } + void startSpeedrun() { m_menuGame.startRun(); } + void stopSpeedrun() { m_menuGame.stopRun(); } + void incSpeedrunTotalLoadTime(OSTime time) { m_menuGame.incTotalLoadTime(time); } + private: struct Toast { std::string message; @@ -53,7 +57,6 @@ private: ImGuiFirstRunPreset m_firstRunPreset; ImGuiMenuGame m_menuGame; - ImGuiMenuSpeedrunTimer m_menuSpeedrunTimer; ImGuiPreLaunchWindow m_preLaunchWindow; // Keep always last diff --git a/src/dusk/imgui/ImGuiMenuGame.cpp b/src/dusk/imgui/ImGuiMenuGame.cpp index 7e54f2ffa3..fbea49bcf9 100644 --- a/src/dusk/imgui/ImGuiMenuGame.cpp +++ b/src/dusk/imgui/ImGuiMenuGame.cpp @@ -12,12 +12,15 @@ #include "dusk/main.h" #include "dusk/hotkeys.h" #include "dusk/settings.h" +#include "dusk/livesplit.h" #include "m_Do/m_Do_controller_pad.h" #include "m_Do/m_Do_graphic.h" #include #include +#include "m_Do/m_Do_main.h" + namespace { constexpr int kInternalResolutionScaleMax = 12; } // namespace @@ -199,6 +202,7 @@ namespace dusk { ImGui::SeparatorText("Difficulty"); + ImGui::BeginDisabled(getSettings().game.speedrunMode); config::ImGuiSliderInt("Damage Multiplier", getSettings().game.damageMultiplier, 1, 8, "x%d"); config::ImGuiCheckbox("Instant Death", getSettings().game.instantDeath); @@ -211,6 +215,7 @@ namespace dusk { ImGui::SetTooltip("Hearts will never drop from enemies,\n" "pots and various other places."); } + ImGui::EndDisabled(); ImGui::SeparatorText("Quality of Life"); @@ -280,12 +285,39 @@ namespace dusk { ImGui::SetTooltip("Transform instantly by pressing R and Y simultaneously."); } + ImGui::SeparatorText("Speedrunning"); + if (config::ImGuiCheckbox("Speedrun Mode", getSettings().game.speedrunMode)) { + resetForSpeedrunMode(); + } + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Enables Speedrunning options, while restricting certain gameplay modifiers."); + } + + ImGui::BeginDisabled(!getSettings().game.speedrunMode); + bool prevLiveSplit = getSettings().game.liveSplitEnabled; + config::ImGuiCheckbox("LiveSplit Connection", getSettings().game.liveSplitEnabled); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Connect to LiveSplit server on localhost:16834."); + } + ImGui::EndDisabled(); + + if ((bool)getSettings().game.liveSplitEnabled != prevLiveSplit) { + if (getSettings().game.liveSplitEnabled) { + dusk::speedrun::connectLiveSplit(); + } else { + dusk::speedrun::disconnectLiveSplit(); + DuskToast("LiveSplit disconnected", 3.f); + } + } + ImGui::EndMenu(); } } void ImGuiMenuGame::drawCheatsMenu() { if (ImGui::BeginMenu("Cheats")) { + ImGui::BeginDisabled(getSettings().game.speedrunMode); + ImGui::SeparatorText("Resources"); config::ImGuiCheckbox("Infinite Hearts", getSettings().game.infiniteHearts); config::ImGuiCheckbox("Infinite Arrows", getSettings().game.infiniteArrows); @@ -293,8 +325,8 @@ namespace dusk { config::ImGuiCheckbox("Infinite Oil", getSettings().game.infiniteOil); config::ImGuiCheckbox("Infinite Oxygen", getSettings().game.infiniteOxygen); config::ImGuiCheckbox("Infinite Rupees", getSettings().game.infiniteRupees); - config::ImGuiCheckbox("Items Don't Despawn", getSettings().game.enableIndefiniteItemDrops); - ImGui::SetItemTooltip("Items Don't Despawn Unless You Load A Different Room In Which Case They Do But Even Under Some Circumstances They Don't, It Is Quite Rare Though"); + config::ImGuiCheckbox("No Item Timer", getSettings().game.enableIndefiniteItemDrops); + ImGui::SetItemTooltip("Item drops such as Rupees, Hearts, etc. will never disappear after they drop."); ImGui::SeparatorText("Abilities"); config::ImGuiCheckbox("Moon Jump (R+A)", getSettings().game.moonJump); @@ -317,6 +349,8 @@ namespace dusk { ImGui::SetTooltip("Makes the magic armor work without rupees."); } + ImGui::EndDisabled(); + ImGui::EndMenu(); } } @@ -431,10 +465,12 @@ namespace dusk { ImGui::SeparatorText("Tools"); + ImGui::BeginDisabled(getSettings().game.speedrunMode); config::ImGuiCheckbox("Turbo Key", getSettings().game.enableTurboKeybind); if (ImGui::IsItemHovered()) { ImGui::SetTooltip("Hold TAB to increase game speed by up to 4x."); } + ImGui::EndDisabled(); ImGui::Checkbox("Show Input Viewer", &m_showInputViewer); @@ -971,4 +1007,85 @@ namespace dusk { ImGui::End(); } + + static std::string GetFormattedTime(OSTime ticks) { + OSCalendarTime time; + OSTicksToCalendarTime(ticks, &time); + + return fmt::format("{0:02}:{1:02}:{2:02}.{3:03}", time.hour, time.min, time.sec, time.msec); + } + + void ImGuiMenuGame::resetForSpeedrunMode() { + // reset settings that should be off for speedrun mode + mDoMain::developmentMode = -1; + + getSettings().game.damageMultiplier.setValue(1); + getSettings().game.instantDeath.setValue(false); + getSettings().game.noHeartDrops.setValue(false); + + getSettings().game.infiniteHearts.setValue(false); + getSettings().game.infiniteArrows.setValue(false); + getSettings().game.infiniteBombs.setValue(false); + getSettings().game.infiniteOil.setValue(false); + getSettings().game.infiniteOxygen.setValue(false); + getSettings().game.infiniteRupees.setValue(false); + getSettings().game.enableIndefiniteItemDrops.setValue(false); + + getSettings().game.moonJump.setValue(false); + getSettings().game.superClawshot.setValue(false); + getSettings().game.alwaysGreatspin.setValue(false); + getSettings().game.enableFastIronBoots.setValue(false); + getSettings().game.canTransformAnywhere.setValue(false); + getSettings().game.fastSpinner.setValue(false); + getSettings().game.freeMagicArmor.setValue(false); + + getSettings().game.enableTurboKeybind.setValue(false); + } + + void ImGuiMenuGame::drawSpeedrunTimerOverlay() { + if (!getSettings().game.speedrunMode) { + return; + } + + // L+R+A+Start to reset timer + if (mDoCPd_c::getHoldL(PAD_1) && mDoCPd_c::getHoldR(PAD_1) && mDoCPd_c::getHoldA(PAD_1) && mDoCPd_c::getTrigStart(PAD_1)) { + m_speedrunInfo.m_endTimestamp = 0; + m_speedrunInfo.m_startTimestamp = 0; + m_speedrunInfo.m_totalLoadTime = 0; + m_speedrunInfo.m_isRunStarted = false; + } + + // L+R+A+Z to manually stop timer + if (mDoCPd_c::getHoldL(PAD_1) && mDoCPd_c::getHoldR(PAD_1) && mDoCPd_c::getHoldA(PAD_1) && mDoCPd_c::getTrigZ(PAD_1)) { + if (m_speedrunInfo.m_isRunStarted) { + m_speedrunInfo.m_endTimestamp = OSGetTime() - m_speedrunInfo.m_startTimestamp; + m_speedrunInfo.m_isRunStarted = false; + } + } + + ImGui::SetNextWindowBgAlpha(0.65f); + ImGuiWindowFlags flags = + ImGuiWindowFlags_NoResize + | ImGuiWindowFlags_NoDocking + | ImGuiWindowFlags_NoTitleBar + | ImGuiWindowFlags_NoScrollbar; + + if (ImGui::Begin("##SpeedrunTimerWindow", nullptr, flags)) { + OSTime elapsedTime = 0; + if (m_speedrunInfo.m_isRunStarted) { + elapsedTime = OSGetTime() - m_speedrunInfo.m_startTimestamp; + } else if (m_speedrunInfo.m_endTimestamp != 0) { + elapsedTime = m_speedrunInfo.m_endTimestamp; + } + + ImGui::Text("RTA"); + ImGui::SameLine(60.0f); + ImGuiStringViewText(GetFormattedTime(elapsedTime)); + + ImGui::Text("IGT"); + ImGui::SameLine(60.0f); + ImGuiStringViewText(GetFormattedTime(elapsedTime - m_speedrunInfo.m_totalLoadTime)); + } + ImGui::End(); + } } diff --git a/src/dusk/imgui/ImGuiMenuGame.hpp b/src/dusk/imgui/ImGuiMenuGame.hpp index e21374c8f4..795cf5f446 100644 --- a/src/dusk/imgui/ImGuiMenuGame.hpp +++ b/src/dusk/imgui/ImGuiMenuGame.hpp @@ -15,9 +15,23 @@ namespace dusk { void windowInputViewer(); void windowControllerConfig(); + void drawSpeedrunTimerOverlay(); static void ToggleFullscreen(); + static void resetForSpeedrunMode(); + bool isRunStarted() const { return m_speedrunInfo.m_isRunStarted; } + void startRun() { + resetForSpeedrunMode(); + m_speedrunInfo.m_isRunStarted = true; + m_speedrunInfo.m_startTimestamp = OSGetTime(); + } + void stopRun() { + m_speedrunInfo.m_isRunStarted = false; + m_speedrunInfo.m_endTimestamp = OSGetTime() - m_speedrunInfo.m_startTimestamp; + } + void incTotalLoadTime(OSTime time) { m_speedrunInfo.m_totalLoadTime += time; } + private: void drawAudioMenu(); void drawInputMenu(); @@ -40,6 +54,14 @@ namespace dusk { bool m_showInputViewerGyro = false; int m_inputOverlayCorner = 3; std::string m_controllerName; + + struct { + bool m_showTimerWindow = false; + bool m_isRunStarted = false; + OSTime m_startTimestamp = 0; + OSTime m_endTimestamp = 0; + OSTime m_totalLoadTime = 0; + } m_speedrunInfo; }; } diff --git a/src/dusk/imgui/ImGuiMenuSpeedrunTimer.cpp b/src/dusk/imgui/ImGuiMenuSpeedrunTimer.cpp deleted file mode 100644 index 6edbb7e084..0000000000 --- a/src/dusk/imgui/ImGuiMenuSpeedrunTimer.cpp +++ /dev/null @@ -1,96 +0,0 @@ -#include "fmt/format.h" -#include "imgui.h" - -#include "ImGuiMenuSpeedrunTimer.hpp" -#include "ImGuiConfig.hpp" -#include "ImGuiConsole.hpp" -#include "dusk/livesplit.h" -#include "dusk/settings.h" - -namespace dusk { - static auto formatTime(uint64_t frames) { - const uint64_t totalSec = frames / 30; - - return fmt::format( - FMT_STRING("{:d}:{:02d}:{:02d}.{:02d}"), - totalSec / 3600, - (totalSec / 60) % 60, - totalSec % 60, - (int)(((f32)(frames % 30) / 30.0f) * 100.0f) - ); - } - - void ImGuiMenuSpeedrunTimer::draw() { - if (!getSettings().game.speedrunTimer) return; - - const uint64_t frames = dusk::speedrun::getFrameCount(); - - if (ImGui::BeginMenu("Timer##speedrun_timer")) { - ImGui::TextUnformatted(formatTime(frames).c_str()); - - ImGui::Separator(); - - if (ImGui::MenuItem("Reset")) { - dusk::speedrun::reset(); - } - - config::ImGuiCheckbox("Show Overlay", getSettings().game.speedrunTimerOverlay); - - bool prevLiveSplit = getSettings().game.liveSplitEnabled; - config::ImGuiCheckbox("LiveSplit Connection", getSettings().game.liveSplitEnabled); - - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Connect to LiveSplit server on localhost:16834."); - } - - if ((bool)getSettings().game.liveSplitEnabled != prevLiveSplit) { - if (getSettings().game.liveSplitEnabled) { - dusk::speedrun::connectLiveSplit(); - } else { - dusk::speedrun::disconnectLiveSplit(); - DuskToast("LiveSplit disconnected", 3.f); - } - } - - ImGui::EndMenu(); - } - - } - - void ImGuiMenuSpeedrunTimer::drawOverlay() { - if (!getSettings().game.speedrunTimer || !getSettings().game.speedrunTimerOverlay) { - return; - } - - const uint64_t frames = dusk::speedrun::getFrameCount(); - const ImGuiViewport* viewport = ImGui::GetMainViewport(); - - const float padding = 10.f; - - ImGui::SetNextWindowPos( - ImVec2( - viewport->WorkPos.x + viewport->WorkSize.x - padding, - viewport->WorkPos.y + viewport->WorkSize.y - padding - ), - ImGuiCond_Always, ImVec2(1.f, 1.f) - ); - - ImGui::SetNextWindowBgAlpha(0.65f); - - const float fixedWidth = ImGui::CalcTextSize("9:59:59.99").x; - - ImGui::SetNextWindowContentSize(ImVec2(fixedWidth, 0.f)); - - if ( - ImGui::Begin("##speedrun_overlay", nullptr, - ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoInputs | - ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | - ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | - ImGuiWindowFlags_NoNav - ) - ) { - ImGui::TextUnformatted(formatTime(frames).c_str()); - } - ImGui::End(); - } -} diff --git a/src/dusk/imgui/ImGuiMenuTools.cpp b/src/dusk/imgui/ImGuiMenuTools.cpp index 00a03e635b..5dd5a62d84 100644 --- a/src/dusk/imgui/ImGuiMenuTools.cpp +++ b/src/dusk/imgui/ImGuiMenuTools.cpp @@ -50,10 +50,14 @@ namespace dusk { ImGui::BeginDisabled(); } + ImGui::BeginDisabled(getSettings().game.speedrunMode); + ImGui::MenuItem("Save Editor", hotkeys::SHOW_SAVE_EDITOR, &m_showSaveEditor); ImGui::MenuItem("Map Loader", hotkeys::SHOW_MAP_LOADER, &m_showMapLoader); ImGui::MenuItem("State Share", hotkeys::SHOW_STATE_SHARE, &m_showStateShare); + ImGui::EndDisabled(); + if (!dusk::IsGameLaunched) { ImGui::EndDisabled(); } @@ -69,6 +73,8 @@ namespace dusk { } if (ImGui::BeginMenu("Debug")) { + ImGui::BeginDisabled(getSettings().game.speedrunMode); + bool developmentMode = mDoMain::developmentMode == 1; if (ImGui::Checkbox("Development Mode", &developmentMode)) { mDoMain::developmentMode = developmentMode ? 1 : -1; @@ -117,6 +123,9 @@ namespace dusk { } ImGui::MenuItem("OSReport Force", nullptr, &OSReportReallyForceEnable); + + ImGui::EndDisabled(); + ImGui::EndMenu(); } } diff --git a/src/dusk/settings.cpp b/src/dusk/settings.cpp index bddc30cb84..843dd4b133 100644 --- a/src/dusk/settings.cpp +++ b/src/dusk/settings.cpp @@ -92,8 +92,7 @@ UserSettings g_userSettings = { .enableTurboKeybind {"game.enableTurboKeybind", false}, // Tools - .speedrunTimer {"game.speedrunTimer", false}, - .speedrunTimerOverlay {"game.speedrunTimerOverlay", false}, + .speedrunMode {"game.speedrunMode", false}, .liveSplitEnabled {"game.liveSplitEnabled", false} }, @@ -162,8 +161,7 @@ void registerSettings() { Register(g_userSettings.game.noLowHpSound); Register(g_userSettings.game.midnasLamentNonStop); Register(g_userSettings.game.enableTurboKeybind); - Register(g_userSettings.game.speedrunTimer); - Register(g_userSettings.game.speedrunTimerOverlay); + Register(g_userSettings.game.speedrunMode); Register(g_userSettings.game.liveSplitEnabled); Register(g_userSettings.game.fastSpinner); Register(g_userSettings.game.infiniteHearts); diff --git a/src/f_op/f_op_scene_req.cpp b/src/f_op/f_op_scene_req.cpp index 79b87eee4c..e4ce889266 100644 --- a/src/f_op/f_op_scene_req.cpp +++ b/src/f_op/f_op_scene_req.cpp @@ -4,13 +4,14 @@ */ #include "f_op/f_op_scene_req.h" +#include +#include "dusk/imgui/ImGuiConsole.hpp" +#include "dusk/logging.h" #include "f_op/f_op_overlap_mng.h" #include "f_op/f_op_scene.h" #include "f_op/f_op_scene_pause.h" #include "f_pc/f_pc_executor.h" #include "f_pc/f_pc_manager.h" -#include -#include "dusk/logging.h" static cPhs_Step fopScnRq_phase_ClearOverlap(scene_request_class* i_sceneReq) { return fopOvlpM_ClearOfReq() == 1 ? cPhs_NEXT_e : cPhs_INIT_e; @@ -39,6 +40,10 @@ static cPhs_Step fopScnRq_phase_IsDoneOverlap(scene_request_class* i_sceneReq) { static BOOL l_fopScnRq_IsUsingOfOverlap; +#if TARGET_PC +static OSTime l_fopScnRq_StartTime = 0; +#endif + static cPhs_Step fopScnRq_phase_Done(scene_request_class* i_sceneReq) { if (i_sceneReq->create_request.parameters != 1) { @@ -48,6 +53,14 @@ static cPhs_Step fopScnRq_phase_Done(scene_request_class* i_sceneReq) { } l_fopScnRq_IsUsingOfOverlap = FALSE; + #if TARGET_PC + if (dusk::getSettings().game.speedrunMode) { + if (dusk::g_imguiConsole.isSpeedrunStart()) { + dusk::g_imguiConsole.incSpeedrunTotalLoadTime(OSGetTime() - l_fopScnRq_StartTime); + } + } + #endif + return cPhs_NEXT_e; } @@ -88,6 +101,10 @@ static scene_request_class* fopScnRq_FadeRequest(s16 i_procname, u16 i_peektime) req = fopOvlpM_Request(i_procname, i_peektime); if (req != NULL) { l_fopScnRq_IsUsingOfOverlap = TRUE; + + #if TARGET_PC + l_fopScnRq_StartTime = OSGetTime(); + #endif } }