diff --git a/CHANGELOG.md b/CHANGELOG.md index dc29c37d9c..ee814a444a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -237,6 +237,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - Fixed the palette being mangled to 6bit/color on load. - Fixed allegro not loading alpha of image with alpha by using SDL_image instead. + - Fixed `MOSprite:UnRotateOffset()` giving the wrong results on HFLipped sprites. - Various fixes and improvements to inventory management when dual-wielding or carrying a shield, to stop situations where the actor unexpectedly puts their items away. @@ -247,6 +248,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - Fixed several issues with the way pie menus and aiming interacts between players, such as opening the pie menu always resetting the M&KB player's aim and pie selection, as well as another issue where the pie menu would fail to appear entirely for some players. +- Fixed an issue where pie menu selection could become unresponsive at low framerates. + - Fixed issue where scripts applied to `MovableObject`s could become disordered in certain circumstances. - Fixed a minor inconsistency where `ACDropShip`s were frequently referred to as `ACDropship`s in Lua, the lower case 's' invalidating keywords where the typo occured. diff --git a/Source/Entities/PieMenu.cpp b/Source/Entities/PieMenu.cpp index a0ab6f4e58..5dfce2e8d5 100644 --- a/Source/Entities/PieMenu.cpp +++ b/Source/Entities/PieMenu.cpp @@ -541,14 +541,6 @@ void PieMenu::Update() { SetPos(affectedObjectAsActor ? affectedObjectAsActor->GetCPUPos() : m_AffectedObject->GetPos()); } - if (m_MenuMode == MenuMode::Wobble) { - UpdateWobbling(); - } else if (m_MenuMode == MenuMode::Freeze) { - m_EnabledState = EnabledState::Enabling; - } else if (m_EnabledState == EnabledState::Enabling || m_EnabledState == EnabledState::Disabling) { - UpdateEnablingAndDisablingProgress(); - } - if (controller->IsDisabled()) { SetEnabled(false); return; @@ -566,13 +558,16 @@ void PieMenu::Update() { bool anyInput = false; bool skipInputBecauseActiveSubPieMenuWasJustDisabled = false; + if (m_ActiveSubPieMenu) { m_CursorAngle = m_HoveredPieSlice->GetMidAngle() + GetRotAngle(); m_CursorInVisiblePosition = false; m_HoverTimer.Reset(); + if (m_ActiveSubPieMenu->IsVisible()) { m_ActiveSubPieMenu->Update(); } + if (!m_ActiveSubPieMenu->IsEnabled()) { m_ActivatedPieSlice = m_ActiveSubPieMenu->m_ActivatedPieSlice; Directions activeSubPieMenuDirection = m_ActiveSubPieMenu->m_DirectionIfSubPieMenu; @@ -584,6 +579,7 @@ void PieMenu::Update() { m_CursorInVisiblePosition = true; } else { bool shouldClearHoveredSlice = controller->IsState(ControlState::PIE_MENU_ACTIVE_ANALOG); + // If a keyboard-only sub-PieMenu is exited by going off the sides, the parent PieMenu should handle input so the next PieSlice can be naturally stepped to. if (activeSubPieMenuDirection != Directions::None) { for (const auto& [controlState, controlStateDirection]: c_ControlStateDirections) { @@ -593,6 +589,7 @@ void PieMenu::Update() { } } } + if (shouldClearHoveredSlice) { SetHoveredPieSlice(nullptr); skipInputBecauseActiveSubPieMenuWasJustDisabled = true; @@ -600,6 +597,7 @@ void PieMenu::Update() { } } } + if (!m_ActiveSubPieMenu && !skipInputBecauseActiveSubPieMenuWasJustDisabled) { if (controller->IsState(PIE_MENU_ACTIVE_ANALOG)) { anyInput = HandleAnalogInput(controller->GetAnalogCursor()); @@ -611,10 +609,6 @@ void PieMenu::Update() { if (anyInput) { m_HoverTimer.Reset(); } - - if (!IsSubPieMenu() && m_HoverTimer.IsPastRealTimeLimit()) { - SetHoveredPieSlice(nullptr); - } } if (m_HoveredPieSlice && m_EnabledState != EnabledState::Disabled && !m_ActiveSubPieMenu) { @@ -623,9 +617,21 @@ void PieMenu::Update() { if (!IsSubPieMenu()) { SetEnabled(controller->IsState(ControlState::PIE_MENU_ACTIVE)); + + if (m_HoverTimer.IsPastRealTimeLimit()) { + SetHoveredPieSlice(nullptr); + } } } + if (m_MenuMode == MenuMode::Wobble) { + UpdateWobbling(); + } else if (m_MenuMode == MenuMode::Freeze) { + m_EnabledState = EnabledState::Enabling; + } else if (m_EnabledState == EnabledState::Enabling || m_EnabledState == EnabledState::Disabling) { + UpdateEnablingAndDisablingProgress(); + } + if (m_BGBitmapNeedsRedrawing && m_EnabledState != EnabledState::Disabled) { UpdatePredrawnMenuBackgroundBitmap(); } diff --git a/Source/Main.cpp b/Source/Main.cpp index 7acde12cb0..de3fcb7abd 100644 --- a/Source/Main.cpp +++ b/Source/Main.cpp @@ -245,6 +245,7 @@ void PollSDLEvents() { /// Game menus loop. /// void RunMenuLoop() { + g_MenuMan.SetIsInMenuScreen(true); g_UInputMan.DisableKeys(false); g_UInputMan.TrapMousePos(false); @@ -282,6 +283,8 @@ void RunMenuLoop() { g_WindowMan.GetScreenBuffer()->End(); g_WindowMan.UploadFrame(); } + + g_MenuMan.SetIsInMenuScreen(false); } /// diff --git a/Source/Managers/MenuMan.cpp b/Source/Managers/MenuMan.cpp index 577d4665e0..060293c770 100644 --- a/Source/Managers/MenuMan.cpp +++ b/Source/Managers/MenuMan.cpp @@ -29,6 +29,7 @@ void MenuMan::Initialize(bool firstTimeInit) { m_GUIInput = std::make_unique(-1, g_UInputMan.GetJoystickCount() > 0); if (firstTimeInit) { + m_IsInMenuScreen = false; g_LoadingScreen.Create(m_GUIScreen.get(), m_GUIInput.get(), g_SettingsMan.GetLoadingScreenProgressReportDisabled()); } @@ -129,12 +130,6 @@ void MenuMan::HandleTransitionIntoMenuLoop() { } bool MenuMan::Update() { - // If we're in the menu but the activity isn't set as paused, then exit - // This can mismatch sometimes like when loading a saved game - if (m_ActiveMenu != ActiveMenu::MenusDisabled && !g_ActivityMan.ActivityPaused()) { - return true; - } - m_TitleScreen->Update(); SetActiveMenu(); diff --git a/Source/Managers/MenuMan.h b/Source/Managers/MenuMan.h index d03ce96b14..571266de75 100644 --- a/Source/Managers/MenuMan.h +++ b/Source/Managers/MenuMan.h @@ -44,6 +44,16 @@ namespace RTE { void Draw() const; #pragma endregion +#pragma region Getters/Setters + /// Checks if we're currently in a menu screen. + /// @return True if in a menu screen; false otherwise. + bool GetIsInMenuScreen() const { return m_IsInMenuScreen; } + + /// Sets if we're currently in a menu screen. + /// @param isInMenuScreen Whether we're in any menu screen. + void SetIsInMenuScreen(bool isInMenuScreen) { m_IsInMenuScreen = isInMenuScreen; } +#pragma endregion + private: /// Enumeration for the different menu screens that are active based on transition states. enum ActiveMenu { @@ -54,6 +64,7 @@ namespace RTE { PauseMenuActive, }; + bool m_IsInMenuScreen; //!< Whether we're currently in a menu screen. ActiveMenu m_ActiveMenu; //!< The currently active menu screen that is being updated and drawn. See ActiveMenu enumeration. std::unique_ptr m_GUIInput; //!< The GUIInput interface of this MenuMan. diff --git a/Source/Managers/UInputMan.cpp b/Source/Managers/UInputMan.cpp index 2446366ca7..882b481c42 100644 --- a/Source/Managers/UInputMan.cpp +++ b/Source/Managers/UInputMan.cpp @@ -8,6 +8,7 @@ #include "ConsoleMan.h" #include "PresetMan.h" #include "PerformanceMan.h" +#include "MenuMan.h" #include "Icon.h" #include "GameActivity.h" #include "System.h" @@ -72,7 +73,6 @@ int UInputMan::Initialize() { m_MouseStates[0] = {}; - int controllerIndex = 0; int joystickCount = 0; SDL_JoystickID* joysticks = SDL_GetGamepads(&joystickCount); @@ -1049,7 +1049,7 @@ void UInputMan::EndFrame() { } m_TextInput.clear(); - for (auto& [mouseID, mouse]: m_MouseStates) { + for (auto& [mouseID, mouse] : m_MouseStates) { mouse.wheelChange = 0; mouse.relativeMotion.Reset(); mouse.change.fill(false); @@ -1178,7 +1178,7 @@ void UInputMan::UpdateMouseInput() { // The mouse cursor is visible and can move about the screen/window, but it should still be contained within the mouse player's part of the window for (int player = PlayerOne; player < MaxPlayerCount; player++) { if (m_ControlScheme[player].GetDevice() == InputDevice::DEVICE_MOUSE_KEYB) { - ForceMouseWithinPlayerScreen(g_ActivityMan.IsInActivity(), player); + ForceMouseWithinPlayerScreen(g_ActivityMan.IsInActivity() && !g_MenuMan.GetIsInMenuScreen(), player); } } } diff --git a/Source/Menus/BuyMenuGUI.cpp b/Source/Menus/BuyMenuGUI.cpp index d9b4176f87..ae00f1cd35 100644 --- a/Source/Menus/BuyMenuGUI.cpp +++ b/Source/Menus/BuyMenuGUI.cpp @@ -487,6 +487,7 @@ void BuyMenuGUI::SetEnabled(bool enable) { g_UInputMan.SetMousePos(mousePos, m_pController->GetPlayer()); // Default focus to the menu button + m_LastHoveredMouseIndex = 0; m_MenuFocus = OK; m_FocusChange = true; UpdateTotalCostLabel(m_pController->GetTeam()); diff --git a/Source/System/Controller.cpp b/Source/System/Controller.cpp index bf7b92a5fa..1ea45a8199 100644 --- a/Source/System/Controller.cpp +++ b/Source/System/Controller.cpp @@ -370,13 +370,15 @@ void Controller::UpdatePlayerPieMenuInput(std::arrayGetPieMenu()->IsInNormalAnimationMode() && !m_ControlledActor->GetPieMenu()->IsVisible()) { m_ControlStates[ControlState::PIE_MENU_OPENED] = true; } m_ControlStates[ControlState::PIE_MENU_ACTIVE] = true; - m_ControlStates[ControlState::PIE_MENU_ACTIVE_ANALOG] = g_UInputMan.ElementHeld(m_Player, InputElements::INPUT_PIEMENU_ANALOG); - m_ControlStates[ControlState::PIE_MENU_ACTIVE_DIGITAL] = g_UInputMan.ElementHeld(m_Player, InputElements::INPUT_PIEMENU_DIGITAL); + m_ControlStates[ControlState::PIE_MENU_ACTIVE_ANALOG] = activeAnalog; + m_ControlStates[ControlState::PIE_MENU_ACTIVE_DIGITAL] = activeDigital; // Make sure that firing and aiming are ignored while the pie menu is open, since it consumes those inputs. m_ControlStates[ControlState::WEAPON_FIRE] = false;