diff --git a/NESEmulator/CNESEmulator.cpp b/NESEmulator/CNESEmulator.cpp index 439dab9f2..bbc04063b 100644 --- a/NESEmulator/CNESEmulator.cpp +++ b/NESEmulator/CNESEmulator.cpp @@ -569,20 +569,21 @@ void CNESEmulator::ProcessUserInput(const CFinalInput& input, int) { if (GetPasswordEntryState() != EPasswordEntryState::NotPasswordScreen) { // Don't swap A/B - inValReads[BUTTON_A] = input.DA(); - inValReads[BUTTON_B] = input.DB(); + inValReads[BUTTON_A] = input.DA() || input.DSpecialKey(boo::ESpecialKey::Enter) || + input.DMouseButton(boo::EMouseButton::Primary); + inValReads[BUTTON_B] = input.DB() || input.DSpecialKey(boo::ESpecialKey::Esc); } else { // Prime controls (B jumps, A shoots) - inValReads[BUTTON_B] = input.DA() | input.DY(); - inValReads[BUTTON_A] = input.DB() | input.DX(); + inValReads[BUTTON_B] = input.DA() || input.DY() || input.DMouseButton(boo::EMouseButton::Primary); + inValReads[BUTTON_A] = input.DB() || input.DX() || input.DKey(' '); } - inValReads[BUTTON_UP] = input.DDPUp() | input.DLAUp(); - inValReads[BUTTON_DOWN] = input.DDPDown() | input.DLADown(); - inValReads[BUTTON_LEFT] = input.DDPLeft() | input.DLALeft(); - inValReads[BUTTON_RIGHT] = input.DDPRight() | input.DLARight(); - inValReads[BUTTON_SELECT] = input.DZ(); - inValReads[BUTTON_START] = input.DStart(); + inValReads[BUTTON_UP] = input.DDPUp() || input.DLAUp(); + inValReads[BUTTON_DOWN] = input.DDPDown() || input.DLADown(); + inValReads[BUTTON_LEFT] = input.DDPLeft() || input.DLALeft(); + inValReads[BUTTON_RIGHT] = input.DDPRight() || input.DLARight(); + inValReads[BUTTON_SELECT] = input.DZ() || input.DKey('\t'); + inValReads[BUTTON_START] = input.DStart() || input.DSpecialKey(boo::ESpecialKey::Esc); } bool CNESEmulator::CheckForGameOver(const u8* vram, u8* passwordOut) { diff --git a/Runtime/AutoMapper/CAutoMapper.cpp b/Runtime/AutoMapper/CAutoMapper.cpp index 57c925598..e4158d47b 100644 --- a/Runtime/AutoMapper/CAutoMapper.cpp +++ b/Runtime/AutoMapper/CAutoMapper.cpp @@ -743,9 +743,10 @@ void CAutoMapper::SetShouldRotatingSoundBePlaying(bool b) { void CAutoMapper::ProcessMapScreenInput(const CFinalInput& input, const CStateManager& mgr) { zeus::CMatrix3f camRot = xa8_renderStates[0].x8_camOrientation.toTransform().buildMatrix3f(); if (x1bc_state == EAutoMapperState::MapScreen) { - if (input.PA() && x328_ == 0 && HasCurrentMapUniverseWorld()) + if ((input.PA() || input.PSpecialKey(boo::ESpecialKey::Enter)) && x328_ == 0 && HasCurrentMapUniverseWorld()) BeginMapperStateTransition(EAutoMapperState::MapScreenUniverse, mgr); - } else if (x1bc_state == EAutoMapperState::MapScreenUniverse && input.PA()) { + } else if (x1bc_state == EAutoMapperState::MapScreenUniverse && + (input.PA() || input.PSpecialKey(boo::ESpecialKey::Enter))) { const CMapUniverse::CMapWorldData& mapuWld = x8_mapu->GetMapWorldData(x9c_worldIdx); zeus::CVector3f pointLocal = mapuWld.GetWorldTransform().inverse() * xa8_renderStates[0].x20_areaPoint; if (mapuWld.GetWorldAssetId() != g_GameState->CurrentWorldAssetId()) { @@ -760,7 +761,7 @@ void CAutoMapper::ProcessMapScreenInput(const CFinalInput& input, const CStateMa } x2f4_aButtonPos = 0; - if (input.PA()) + if (input.PA() || input.PSpecialKey(boo::ESpecialKey::Enter)) x2f4_aButtonPos = 1; if (IsInMapperState(EAutoMapperState::MapScreen) || IsInMapperState(EAutoMapperState::MapScreenUniverse)) { @@ -1022,7 +1023,7 @@ void CAutoMapper::ProcessControllerInput(const CFinalInput& input, CStateManager } } - if (input.PZ() || input.PB()) { + if (input.PZ() || input.PKey('\t') || input.PB() || input.PSpecialKey(boo::ESpecialKey::Esc)) { if (x328_ == 0) { if (CanLeaveMapScreenInternal(mgr)) { LeaveMapScreen(mgr); diff --git a/Runtime/CGameOptions.cpp b/Runtime/CGameOptions.cpp index 830583318..06d5298ad 100644 --- a/Runtime/CGameOptions.cpp +++ b/Runtime/CGameOptions.cpp @@ -372,7 +372,7 @@ void CGameOptions::TryRestoreDefaults(const CFinalInput& input, int category, in if (options.second[option].option != EGameOption::RestoreDefaults) return; - if (!forceRestore && !input.PA()) + if (!forceRestore && !input.PA() && !input.PSpecialKey(boo::ESpecialKey::Enter)) return; if (frontend) { diff --git a/Runtime/GuiSys/CGuiFrame.cpp b/Runtime/GuiSys/CGuiFrame.cpp index fcd120243..81584f51a 100644 --- a/Runtime/GuiSys/CGuiFrame.cpp +++ b/Runtime/GuiSys/CGuiFrame.cpp @@ -179,28 +179,6 @@ void CGuiFrame::LoadWidgetsInGame(CInputStream& in, CSimplePool* sp) { } void CGuiFrame::ProcessUserInput(const CFinalInput& input) const { - if (const auto& kbm = input.GetKBM()) { - zeus::CVector2f point(kbm->m_mouseCoord.norm[0] * 2.f - 1.f, - kbm->m_mouseCoord.norm[1] * 2.f - 1.f); - CGuiWidget* hit = BestCursorHit(point, {}); - if (!m_inMouseDown && kbm->m_mouseButtons[int(boo::EMouseButton::Primary)]) { - m_inMouseDown = true; - m_mouseDownWidget = hit; - if (m_mouseDownCb) - m_mouseDownCb(hit); - } else if (m_inMouseDown && !kbm->m_mouseButtons[int(boo::EMouseButton::Primary)]) { - m_inMouseDown = false; - if (m_mouseUpCb) - m_mouseUpCb(m_mouseDownWidget); - } - if (hit != m_lastMouseOverWidget) { - if (m_inMouseDown) - hit = nullptr; - if (m_mouseOverChangeCb) - m_mouseOverChangeCb(m_lastMouseOverWidget, hit); - m_lastMouseOverWidget = hit; - } - } if (input.ControllerIdx() != 0) return; for (auto& widget : x2c_widgets) { @@ -209,6 +187,43 @@ void CGuiFrame::ProcessUserInput(const CFinalInput& input) const { } } +bool CGuiFrame::ProcessMouseInput(const CFinalInput& input, const CGuiWidgetDrawParms& parms) const { + if (const auto& kbm = input.GetKBM()) { + zeus::CVector2f point(kbm->m_mouseCoord.norm[0] * 2.f - 1.f, + kbm->m_mouseCoord.norm[1] * 2.f - 1.f); + CGuiWidget* hit = BestCursorHit(point, parms); + if (hit != m_lastMouseOverWidget) { + if (m_inMouseDown && m_mouseDownWidget != hit) { + m_inCancel = true; + if (m_mouseUpCb) + m_mouseUpCb(m_mouseDownWidget, true); + } else if (m_inCancel && m_mouseDownWidget == hit) { + m_inCancel = false; + if (m_mouseDownCb) + m_mouseDownCb(m_mouseDownWidget, true); + } + if (m_mouseOverChangeCb) + m_mouseOverChangeCb(m_lastMouseOverWidget, hit); + m_lastMouseOverWidget = hit; + } + if (!m_inMouseDown && kbm->m_mouseButtons[int(boo::EMouseButton::Primary)]) { + m_inMouseDown = true; + m_inCancel = false; + m_mouseDownWidget = hit; + if (m_mouseDownCb) + m_mouseDownCb(hit, false); + if (hit) + return true; + } else if (m_inMouseDown && !kbm->m_mouseButtons[int(boo::EMouseButton::Primary)]) { + m_inMouseDown = false; + m_inCancel = false; + if (m_mouseUpCb && m_mouseDownWidget == m_lastMouseOverWidget) + m_mouseUpCb(m_mouseDownWidget, false); + } + } + return false; +} + std::unique_ptr CGuiFrame::CreateFrame(CAssetId frmeId, CGuiSys& sys, CInputStream& in, CSimplePool* sp) { in.readInt32Big(); int a = in.readInt32Big(); diff --git a/Runtime/GuiSys/CGuiFrame.hpp b/Runtime/GuiSys/CGuiFrame.hpp index 4833f619b..457b6e4b6 100644 --- a/Runtime/GuiSys/CGuiFrame.hpp +++ b/Runtime/GuiSys/CGuiFrame.hpp @@ -42,11 +42,12 @@ private: float m_maxAspect = -1.f; mutable bool m_inMouseDown = false; + mutable bool m_inCancel = false; mutable CGuiWidget* m_mouseDownWidget = nullptr; mutable CGuiWidget* m_lastMouseOverWidget = nullptr; std::function m_mouseOverChangeCb; - std::function m_mouseDownCb; - std::function m_mouseUpCb; + std::function m_mouseDownCb; + std::function m_mouseUpCb; public: CGuiFrame(CAssetId id, CGuiSys& sys, int a, int b, int c, CSimplePool* sp); @@ -76,10 +77,10 @@ public: void SetMouseOverChangeCallback(std::function&& cb) { m_mouseOverChangeCb = std::move(cb); } - void SetMouseDownCallback(std::function&& cb) { + void SetMouseDownCallback(std::function&& cb) { m_mouseDownCb = std::move(cb); } - void SetMouseUpCallback(std::function&& cb) { + void SetMouseUpCallback(std::function&& cb) { m_mouseUpCb = std::move(cb); } @@ -89,6 +90,7 @@ public: void Initialize(); void LoadWidgetsInGame(CInputStream& in, CSimplePool* sp); void ProcessUserInput(const CFinalInput& input) const; + bool ProcessMouseInput(const CFinalInput& input, const CGuiWidgetDrawParms& parms) const; CGuiWidgetIdDB& GetWidgetIdDB() { return x18_idDB; } diff --git a/Runtime/GuiSys/CGuiTableGroup.cpp b/Runtime/GuiSys/CGuiTableGroup.cpp index e0bf5dc03..009a27b23 100644 --- a/Runtime/GuiSys/CGuiTableGroup.cpp +++ b/Runtime/GuiSys/CGuiTableGroup.cpp @@ -32,9 +32,9 @@ CGuiTableGroup::CGuiTableGroup(const CGuiWidgetParms& parms, int elementCount, i , xd0_selectWraparound(selectWraparound) {} void CGuiTableGroup::ProcessUserInput(const CFinalInput& input) { - if (input.PA()) { + if (input.PA() || input.PSpecialKey(boo::ESpecialKey::Enter)) { DoAdvance(); - } else if (input.PB()) { + } else if (input.PB() || input.PSpecialKey(boo::ESpecialKey::Esc)) { DoCancel(); } else { bool decrement; diff --git a/Runtime/GuiSys/CGuiTableGroup.hpp b/Runtime/GuiSys/CGuiTableGroup.hpp index 03c11454b..0249f5b6e 100644 --- a/Runtime/GuiSys/CGuiTableGroup.hpp +++ b/Runtime/GuiSys/CGuiTableGroup.hpp @@ -28,8 +28,6 @@ private: std::function xec_doMenuCancel; std::function x104_doMenuSelChange; - bool IsWorkerSelectable(int) const; - void SelectWorker(int); void DeactivateWorker(CGuiWidget* widget); void ActivateWorker(CGuiWidget* widget); @@ -78,6 +76,10 @@ public: int GetUserSelection() const { return xc4_userSelection; } + bool IsWorkerSelectable(int) const; + + void SelectWorker(int); + void ProcessUserInput(const CFinalInput& input); bool AddWorkerWidget(CGuiWidget* worker) { return true; } diff --git a/Runtime/GuiSys/CGuiTextPane.cpp b/Runtime/GuiSys/CGuiTextPane.cpp index accbc4a66..fa0a2885f 100644 --- a/Runtime/GuiSys/CGuiTextPane.cpp +++ b/Runtime/GuiSys/CGuiTextPane.cpp @@ -92,6 +92,36 @@ void CGuiTextPane::Draw(const CGuiWidgetDrawParms& parms) const { #endif } +static const zeus::CVector3f NormalPoints[] = { + {0.f, 0.f, -1.f}, + {1.f, 0.f, -1.f}, + {1.f, 0.f, 0.f}, + {0.f, 0.f, 0.f} +}; + +static bool testProjectedLine(const zeus::CVector2f& a, const zeus::CVector2f& b, const zeus::CVector2f& point) { + zeus::CVector2f normal = (b - a).perpendicularVector().normalized(); + return point.dot(normal) >= a.dot(normal); +} + +bool CGuiTextPane::TestCursorHit(const zeus::CMatrix4f& vp, const zeus::CVector2f& point) const { + zeus::CVector2f dims = GetDimensions(); + zeus::CTransform local = zeus::CTransform::Translate(xc0_verts.front().m_pos + xc8_scaleCenter) * + zeus::CTransform::Scale(dims.x(), 1.f, dims.y()); + zeus::CMatrix4f mvp = vp * (x34_worldXF * local).toMatrix4f(); + + zeus::CVector2f projPoints[4]; + for (int i = 0; i < 4; ++i) + projPoints[i] = mvp.multiplyOneOverW(NormalPoints[i]).toVec2f(); + + int j; + for (j = 0; j < 3; ++j) { + if (!testProjectedLine(projPoints[j], projPoints[j + 1], point)) + break; + } + return j == 3 && testProjectedLine(projPoints[3], projPoints[0], point); +} + std::shared_ptr CGuiTextPane::Create(CGuiFrame* frame, CInputStream& in, CSimplePool* sp) { CGuiWidgetParms parms = ReadWidgetHeader(frame, in); zeus::CVector2f dim = zeus::CVector2f::ReadBig(in); diff --git a/Runtime/GuiSys/CGuiTextPane.hpp b/Runtime/GuiSys/CGuiTextPane.hpp index 9d671dedb..f6dc8a1f5 100644 --- a/Runtime/GuiSys/CGuiTextPane.hpp +++ b/Runtime/GuiSys/CGuiTextPane.hpp @@ -22,6 +22,7 @@ public: void SetDimensions(const zeus::CVector2f& dim, bool initVBO); void ScaleDimensions(const zeus::CVector3f& scale); void Draw(const CGuiWidgetDrawParms& parms) const; + bool TestCursorHit(const zeus::CMatrix4f& vp, const zeus::CVector2f& point) const; static std::shared_ptr Create(CGuiFrame* frame, CInputStream& in, CSimplePool* sp); }; diff --git a/Runtime/GuiSys/CScanDisplay.cpp b/Runtime/GuiSys/CScanDisplay.cpp index 0430e53f9..ebf97cd9e 100644 --- a/Runtime/GuiSys/CScanDisplay.cpp +++ b/Runtime/GuiSys/CScanDisplay.cpp @@ -76,7 +76,7 @@ void CScanDisplay::ProcessInput(const CFinalInput& input) { return; if (xc_state == EScanState::DownloadComplete && x1a4_xAlpha == 0.f) { - if (input.PA()) { + if (input.PA() || input.PSpecialKey(boo::ESpecialKey::Enter) || input.PMouseButton(boo::EMouseButton::Primary)) { if (xa8_message->TextSupport().GetCurTime() < xa8_message->TextSupport().GetTotalAnimationTime()) { xa8_message->TextSupport().SetCurTime(xa8_message->TextSupport().GetTotalAnimationTime()); } else { @@ -88,7 +88,8 @@ void CScanDisplay::ProcessInput(const CFinalInput& input) { } else if (xc_state == EScanState::ViewingScan) { int oldCounter = x1ac_pageCounter; int totalPages = xac_scrollMessage->TextSupport().GetTotalPageCount(); - if (input.PA() && totalPages != -1) { + if ((input.PA() || input.PSpecialKey(boo::ESpecialKey::Enter) || input.PMouseButton(boo::EMouseButton::Primary)) && + totalPages != -1) { CGuiTextSupport& supp = !x1ac_pageCounter ? xa8_message->TextSupport() : xac_scrollMessage->TextSupport(); if (supp.GetCurTime() < supp.GetTotalAnimationTime()) supp.SetCurTime(supp.GetTotalAnimationTime()); diff --git a/Runtime/Input/CFinalInput.cpp b/Runtime/Input/CFinalInput.cpp index 183e1fec2..9b4e7c0fa 100644 --- a/Runtime/Input/CFinalInput.cpp +++ b/Runtime/Input/CFinalInput.cpp @@ -92,51 +92,15 @@ CFinalInput::CFinalInput(int cIdx, float dt, const boo::DolphinControllerState& , x2e_b30_PDPLeft(DDPLeft() && !prevInput.DDPLeft()) , x2e_b31_PStart(DStart() && !prevInput.DStart()) {} -static float KBToAnaLeftX(const CKeyboardMouseControllerData& data) { - float retval = 0.0; - if (data.m_charKeys[int('a')]) - retval -= 1.0; - if (data.m_charKeys[int('d')]) - retval += 1.0; - return retval; -} - -static float KBToAnaLeftY(const CKeyboardMouseControllerData& data) { - float retval = 0.0; - if (data.m_charKeys[int('s')]) - retval -= 1.0; - if (data.m_charKeys[int('w')]) - retval += 1.0; - return retval; -} - -static float KBToAnaRightX(const CKeyboardMouseControllerData& data) { - float retval = 0.0; - if (data.m_charKeys[int('2')]) - retval -= 1.0; - if (data.m_charKeys[int('4')]) - retval += 1.0; - return retval; -} - -static float KBToAnaRightY(const CKeyboardMouseControllerData& data) { - float retval = 0.0; - if (data.m_charKeys[int('3')]) - retval -= 1.0; - if (data.m_charKeys[int('1')]) - retval += 1.0; - return retval; -} - CFinalInput::CFinalInput(int cIdx, float dt, const CKeyboardMouseControllerData& data, const CFinalInput& prevInput) : x0_dt(dt) , x4_controllerIdx(cIdx) -, x8_anaLeftX(KBToAnaLeftX(data)) -, xc_anaLeftY(KBToAnaLeftY(data)) -, x10_anaRightX(KBToAnaRightX(data)) -, x14_anaRightY(KBToAnaRightY(data)) -, x18_anaLeftTrigger(data.m_charKeys[int('q')] ? 1.0 : 0.0) -, x1c_anaRightTrigger(data.m_charKeys[int('e')] ? 1.0 : 0.0) +, x8_anaLeftX(0.f) +, xc_anaLeftY(0.f) +, x10_anaRightX(0.f) +, x14_anaRightY(0.f) +, x18_anaLeftTrigger(false) +, x1c_anaRightTrigger(false) , x20_enableAnaLeftXP(DLARight() && !prevInput.DLARight()) , x20_enableAnaLeftNegXP(DLALeft() && !prevInput.DLALeft()) , x21_enableAnaLeftYP(DLAUp() && !prevInput.DLAUp()) @@ -147,13 +111,13 @@ CFinalInput::CFinalInput(int cIdx, float dt, const CKeyboardMouseControllerData& , x23_enableAnaRightNegYP(DRADown() && !prevInput.DRADown()) , x24_anaLeftTriggerP(DLTrigger() && !prevInput.DLTrigger()) , x28_anaRightTriggerP(DRTrigger() && !prevInput.DRTrigger()) -, x2c_b24_A(data.m_mouseButtons[int(boo::EMouseButton::Primary)]) -, x2c_b25_B(data.m_charKeys[int(' ')]) -, x2c_b26_X(data.m_charKeys[int('c')]) -, x2c_b27_Y(data.m_mouseButtons[int(boo::EMouseButton::Secondary)]) -, x2c_b28_Z(data.m_charKeys[int('\t')]) -, x2c_b29_L(data.m_charKeys[int('q')]) -, x2c_b30_R(data.m_charKeys[int('e')]) +, x2c_b24_A(false) +, x2c_b25_B(false) +, x2c_b26_X(false) +, x2c_b27_Y(false) +, x2c_b28_Z(false) +, x2c_b29_L(false) +, x2c_b30_R(false) , x2c_b31_DPUp(data.m_specialKeys[int(boo::ESpecialKey::Up)]) , x2d_b24_DPRight(data.m_specialKeys[int(boo::ESpecialKey::Right)]) , x2d_b25_DPDown(data.m_specialKeys[int(boo::ESpecialKey::Down)]) @@ -172,15 +136,13 @@ CFinalInput::CFinalInput(int cIdx, float dt, const CKeyboardMouseControllerData& , x2e_b30_PDPLeft(DDPLeft() && !prevInput.DDPLeft()) , x2e_b31_PStart(DStart() && !prevInput.DStart()) , m_kbm(data) { - if (x8_anaLeftX || xc_anaLeftY) { - float len = std::sqrt(x8_anaLeftX * x8_anaLeftX + xc_anaLeftY * xc_anaLeftY); - x8_anaLeftX /= len; - xc_anaLeftY /= len; - } - if (x10_anaRightX || x14_anaRightY) { - float len = std::sqrt(x10_anaRightX * x10_anaRightX + x14_anaRightY * x14_anaRightY); - x10_anaRightX /= len; - x14_anaRightY /= len; + if (prevInput.m_kbm) { + for (int i = 0; i < 256; ++i) + m_PCharKeys[i] = data.m_charKeys[i] && !prevInput.m_kbm->m_charKeys[i]; + for (int i = 0; i < 26; ++i) + m_PSpecialKeys[i] = data.m_specialKeys[i] && !prevInput.m_kbm->m_specialKeys[i]; + for (int i = 0; i < 6; ++i) + m_PMouseButtons[i] = data.m_mouseButtons[i] && !prevInput.m_kbm->m_mouseButtons[i]; } } @@ -231,8 +193,15 @@ CFinalInput& CFinalInput::operator|=(const CFinalInput& other) { x2e_b29_PDPDown |= other.x2e_b29_PDPDown; x2e_b30_PDPLeft |= other.x2e_b30_PDPLeft; x2e_b31_PStart |= other.x2e_b31_PStart; - if (other.m_kbm) + if (other.m_kbm) { m_kbm = other.m_kbm; + for (int i = 0; i < 256; ++i) + m_PCharKeys[i] = other.m_PCharKeys[i]; + for (int i = 0; i < 26; ++i) + m_PSpecialKeys[i] = other.m_PSpecialKeys[i]; + for (int i = 0; i < 6; ++i) + m_PMouseButtons[i] = other.m_PMouseButtons[i]; + } return *this; } @@ -242,6 +211,8 @@ CFinalInput CFinalInput::ScaleAnalogueSticks(float leftDiv, float rightDiv) cons ret.xc_anaLeftY = zeus::clamp(-1.f, xc_anaLeftY / leftDiv, 1.f); ret.x10_anaRightX = zeus::clamp(-1.f, x10_anaRightX / rightDiv, 1.f); ret.x14_anaRightY = zeus::clamp(-1.f, x14_anaRightY / rightDiv, 1.f); + ret.m_leftMul = 1.f / leftDiv; + ret.m_rightMul = 1.f / rightDiv; return ret; } } // namespace urde diff --git a/Runtime/Input/CFinalInput.hpp b/Runtime/Input/CFinalInput.hpp index ded521b34..1b7a70480 100644 --- a/Runtime/Input/CFinalInput.hpp +++ b/Runtime/Input/CFinalInput.hpp @@ -61,6 +61,13 @@ struct CFinalInput { std::experimental::optional m_kbm; + bool m_PCharKeys[256] = {}; + bool m_PSpecialKeys[26] = {}; + bool m_PMouseButtons[6] = {}; + + float m_leftMul = 1.f; + float m_rightMul = 1.f; + CFinalInput(); CFinalInput(int cIdx, float dt, const boo::DolphinControllerState& data, const CFinalInput& prevInput, float leftDiv, float rightDiv); @@ -146,6 +153,16 @@ struct CFinalInput { CFinalInput ScaleAnalogueSticks(float leftDiv, float rightDiv) const; + bool PKey(char k) const { return m_kbm && m_PCharKeys[k]; } + bool PSpecialKey(boo::ESpecialKey k) const { return m_kbm && m_PSpecialKeys[int(k)]; } + bool PMouseButton(boo::EMouseButton k) const { return m_kbm && m_PMouseButtons[int(k)]; } + bool DKey(char k) const { return m_kbm && m_kbm->m_charKeys[k]; } + bool DSpecialKey(boo::ESpecialKey k) const { return m_kbm && m_kbm->m_specialKeys[int(k)]; } + bool DMouseButton(boo::EMouseButton k) const { return m_kbm && m_kbm->m_mouseButtons[int(k)]; } + bool AKey(char k) const { return DKey(k) ? 1.f : 0.f; } + bool ASpecialKey(boo::ESpecialKey k) const { return DSpecialKey(k) ? 1.f : 0.f; } + bool AMouseButton(boo::EMouseButton k) const { return DMouseButton(k) ? 1.f : 0.f; } + const std::experimental::optional& GetKBM() const { return m_kbm; } }; diff --git a/Runtime/Input/ControlMapper.cpp b/Runtime/Input/ControlMapper.cpp index 3e86b37e0..c9c69784d 100644 --- a/Runtime/Input/ControlMapper.cpp +++ b/Runtime/Input/ControlMapper.cpp @@ -123,6 +123,79 @@ static FloatReturnFn skAnalogFuncs[] = {nullptr, &CFinalInput::AStart, nullptr}; +static const ControlMapper::EKBMFunctionList skKBMMapping[] = { + ControlMapper::EKBMFunctionList::KeyPress + 'w', // Forward, + ControlMapper::EKBMFunctionList::KeyPress + 's', // Backward, + ControlMapper::EKBMFunctionList::KeyPress + 'a', // TurnLeft, + ControlMapper::EKBMFunctionList::KeyPress + 'd', // TurnRight, + ControlMapper::EKBMFunctionList::KeyPress + 'a', // StrafeLeft, + ControlMapper::EKBMFunctionList::KeyPress + 'd', // StrafeRight, + ControlMapper::EKBMFunctionList::KeyPress + 'a', // LookLeft, + ControlMapper::EKBMFunctionList::KeyPress + 'd', // LookRight, + ControlMapper::EKBMFunctionList::KeyPress + 's', // LookUp, + ControlMapper::EKBMFunctionList::KeyPress + 'w', // LookDown, + ControlMapper::EKBMFunctionList::KeyPress + ' ', // JumpOrBoost = 10, + ControlMapper::EKBMFunctionList::MousePress + boo::EMouseButton::Primary, // FireOrBomb = 11, + ControlMapper::EKBMFunctionList::MousePress + boo::EMouseButton::Secondary, // MissileOrPowerBomb = 12, + ControlMapper::EKBMFunctionList::KeyPress + 'c', // Morph, + ControlMapper::EKBMFunctionList::None, // AimUp, + ControlMapper::EKBMFunctionList::None, // AimDown, + ControlMapper::EKBMFunctionList::None, // CycleBeamUp, + ControlMapper::EKBMFunctionList::None, // CycleBeamDown, + ControlMapper::EKBMFunctionList::None, // CycleItem, + ControlMapper::EKBMFunctionList::KeyPress + '1', // PowerBeam, + ControlMapper::EKBMFunctionList::KeyPress + '3', // IceBeam, + ControlMapper::EKBMFunctionList::KeyPress + '2', // WaveBeam, + ControlMapper::EKBMFunctionList::KeyPress + '4', // PlasmaBeam, + ControlMapper::EKBMFunctionList::None, // ToggleHolster = 23, + ControlMapper::EKBMFunctionList::None, // OrbitClose, + ControlMapper::EKBMFunctionList::KeyPress + 'q', // OrbitFar, + ControlMapper::EKBMFunctionList::KeyPress + 'q', // OrbitObject, + ControlMapper::EKBMFunctionList::None, // OrbitSelect, + ControlMapper::EKBMFunctionList::None, // OrbitConfirm, + ControlMapper::EKBMFunctionList::KeyPress + 'a', // OrbitLeft, + ControlMapper::EKBMFunctionList::KeyPress + 'd', // OrbitRight, + ControlMapper::EKBMFunctionList::KeyPress + 'w', // OrbitUp, + ControlMapper::EKBMFunctionList::KeyPress + 's', // OrbitDown, + ControlMapper::EKBMFunctionList::KeyPress + 'e', // LookHold1, + ControlMapper::EKBMFunctionList::None, // LookHold2, + ControlMapper::EKBMFunctionList::None, // LookZoomIn, + ControlMapper::EKBMFunctionList::None, // LookZoomOut, + ControlMapper::EKBMFunctionList::None, // AimHold, + ControlMapper::EKBMFunctionList::KeyPress + 's', // MapCircleUp, + ControlMapper::EKBMFunctionList::KeyPress + 'w', // MapCircleDown, + ControlMapper::EKBMFunctionList::KeyPress + 'a', // MapCircleLeft, + ControlMapper::EKBMFunctionList::KeyPress + 'd', // MapCircleRight, + ControlMapper::EKBMFunctionList::SpecialKeyPress + boo::ESpecialKey::Up, // MapMoveForward, + ControlMapper::EKBMFunctionList::SpecialKeyPress + boo::ESpecialKey::Down, // MapMoveBack, + ControlMapper::EKBMFunctionList::SpecialKeyPress + boo::ESpecialKey::Left, // MapMoveLeft, + ControlMapper::EKBMFunctionList::SpecialKeyPress + boo::ESpecialKey::Right, // MapMoveRight, + ControlMapper::EKBMFunctionList::KeyPress + 'e', // MapZoomIn, + ControlMapper::EKBMFunctionList::KeyPress + 'q', // MapZoomOut, + ControlMapper::EKBMFunctionList::KeyPress + 'e', // SpiderBall, + ControlMapper::EKBMFunctionList::KeyPress + 'q', // ChaseCamera, + ControlMapper::EKBMFunctionList::SpecialKeyPress + boo::ESpecialKey::Right, // XrayVisor = 50, + ControlMapper::EKBMFunctionList::SpecialKeyPress + boo::ESpecialKey::Down, // ThermoVisor = 51, + ControlMapper::EKBMFunctionList::SpecialKeyPress + boo::ESpecialKey::Left, // InviroVisor = 52, + ControlMapper::EKBMFunctionList::SpecialKeyPress + boo::ESpecialKey::Up, // NoVisor = 53, + ControlMapper::EKBMFunctionList::None, // VisorMenu, + ControlMapper::EKBMFunctionList::None, // VisorUp, + ControlMapper::EKBMFunctionList::None, // VisorDown, + ControlMapper::EKBMFunctionList::KeyPress + 'e', // ShowCrosshairs, + ControlMapper::EKBMFunctionList::None, // UNKNOWN + ControlMapper::EKBMFunctionList::None, // UseSheild = 0x3B, + ControlMapper::EKBMFunctionList::KeyPress + 'q', // ScanItem = 0x3C, + ControlMapper::EKBMFunctionList::None, // UNKNOWN + ControlMapper::EKBMFunctionList::None, // UNKNOWN + ControlMapper::EKBMFunctionList::None, // UNKNOWN + ControlMapper::EKBMFunctionList::None, // UNKNOWN + ControlMapper::EKBMFunctionList::KeyPress + 'q', // PreviousPauseScreen = 0x41, + ControlMapper::EKBMFunctionList::KeyPress + 'e', // NextPauseScreen = 0x42, + ControlMapper::EKBMFunctionList::None, // UNKNOWN, + ControlMapper::EKBMFunctionList::None, // None, + ControlMapper::EKBMFunctionList::None +}; + #define kCommandFilterCount 67 static bool skCommandFilterFlag[kCommandFilterCount] = {true}; @@ -136,37 +209,149 @@ void ControlMapper::ResetCommandFilters() { bool ControlMapper::GetPressInput(ECommands cmd, const CFinalInput& input) { if (!skCommandFilterFlag[int(cmd)]) return false; + bool ret = false; EFunctionList func = EFunctionList(g_currentPlayerControl->GetMapping(atUint32(cmd))); - if (func > EFunctionList::MAX) - return false; - BoolReturnFn fn = skPressFuncs[int(func)]; - if (!fn) - return false; - return (input.*fn)(); + if (func < EFunctionList::MAX) { + if (BoolReturnFn fn = skPressFuncs[int(func)]) + ret = (input.*fn)(); + } + if (const auto& kbm = input.GetKBM()) { + EKBMFunctionList kbmfunc = skKBMMapping[int(cmd)]; + if (kbmfunc < EKBMFunctionList::MAX) { + if (kbmfunc >= EKBMFunctionList::MousePress) + ret |= input.m_PMouseButtons[int(kbmfunc) - int(EKBMFunctionList::MousePress)]; + else if (kbmfunc >= EKBMFunctionList::SpecialKeyPress) + ret |= input.m_PSpecialKeys[int(kbmfunc) - int(EKBMFunctionList::SpecialKeyPress)]; + else if (kbmfunc >= EKBMFunctionList::KeyPress) + ret |= input.m_PCharKeys[int(kbmfunc) - int(EKBMFunctionList::KeyPress)]; + } + } + return ret; } bool ControlMapper::GetDigitalInput(ECommands cmd, const CFinalInput& input) { if (!skCommandFilterFlag[int(cmd)]) return false; + bool ret = false; EFunctionList func = EFunctionList(g_currentPlayerControl->GetMapping(atUint32(cmd))); - if (func > EFunctionList::MAX) - return false; - BoolReturnFn fn = skDigitalFuncs[int(func)]; - if (!fn) - return false; - return (input.*fn)(); + if (func < EFunctionList::MAX) { + if (BoolReturnFn fn = skDigitalFuncs[int(func)]) + ret = (input.*fn)(); + } + if (const auto& kbm = input.GetKBM()) { + EKBMFunctionList kbmfunc = skKBMMapping[int(cmd)]; + if (kbmfunc < EKBMFunctionList::MAX) { + if (kbmfunc >= EKBMFunctionList::MousePress) + ret |= kbm->m_mouseButtons[int(kbmfunc) - int(EKBMFunctionList::MousePress)]; + else if (kbmfunc >= EKBMFunctionList::SpecialKeyPress) + ret |= kbm->m_specialKeys[int(kbmfunc) - int(EKBMFunctionList::SpecialKeyPress)]; + else if (kbmfunc >= EKBMFunctionList::KeyPress) + ret |= kbm->m_charKeys[int(kbmfunc) - int(EKBMFunctionList::KeyPress)]; + } + } + return ret; +} + +static float KBToWASDX(const CKeyboardMouseControllerData& data) { + float retval = 0.0; + if (data.m_charKeys[int('a')]) + retval -= 1.0; + if (data.m_charKeys[int('d')]) + retval += 1.0; + return retval; +} + +static float KBToWASDY(const CKeyboardMouseControllerData& data) { + float retval = 0.0; + if (data.m_charKeys[int('s')]) + retval -= 1.0; + if (data.m_charKeys[int('w')]) + retval += 1.0; + return retval; +} + +static float KBToArrowsX(const CKeyboardMouseControllerData& data) { + float retval = 0.0; + if (data.m_specialKeys[int(boo::ESpecialKey::Left)]) + retval -= 1.0; + if (data.m_specialKeys[int(boo::ESpecialKey::Right)]) + retval += 1.0; + return retval; +} + +static float KBToArrowsY(const CKeyboardMouseControllerData& data) { + float retval = 0.0; + if (data.m_specialKeys[int(boo::ESpecialKey::Down)]) + retval -= 1.0; + if (data.m_specialKeys[int(boo::ESpecialKey::Up)]) + retval += 1.0; + return retval; } float ControlMapper::GetAnalogInput(ECommands cmd, const CFinalInput& input) { if (!skCommandFilterFlag[int(cmd)]) - return 0.0; + return 0.f; + float ret = 0.f; EFunctionList func = EFunctionList(g_currentPlayerControl->GetMapping(atUint32(cmd))); - if (func > EFunctionList::MAX) - return 0.0; - FloatReturnFn fn = skAnalogFuncs[int(func)]; - if (!fn) - return 0.0; - return (input.*fn)(); + if (func < EFunctionList::MAX) { + if (FloatReturnFn fn = skAnalogFuncs[int(func)]) + ret = (input.*fn)(); + } + if (const auto& kbm = input.GetKBM()) { + switch (cmd) { + case ECommands::Forward: + case ECommands::LookDown: + case ECommands::OrbitUp: + case ECommands::MapCircleDown: + ret = std::max(ret, KBToWASDY(*kbm) * input.m_leftMul); + break; + case ECommands::Backward: + case ECommands::LookUp: + case ECommands::OrbitDown: + case ECommands::MapCircleUp: + ret = std::max(ret, -KBToWASDY(*kbm) * input.m_leftMul); + break; + case ECommands::TurnLeft: + case ECommands::StrafeLeft: + case ECommands::LookLeft: + case ECommands::OrbitLeft: + case ECommands::MapCircleLeft: + ret = std::max(ret, -KBToWASDX(*kbm) * input.m_leftMul); + break; + case ECommands::TurnRight: + case ECommands::StrafeRight: + case ECommands::LookRight: + case ECommands::OrbitRight: + case ECommands::MapCircleRight: + ret = std::max(ret, KBToWASDX(*kbm) * input.m_leftMul); + break; + case ECommands::MapMoveForward: + ret = std::max(ret, KBToArrowsY(*kbm)); + break; + case ECommands::MapMoveBack: + ret = std::max(ret, -KBToArrowsY(*kbm)); + break; + case ECommands::MapMoveLeft: + ret = std::max(ret, -KBToArrowsX(*kbm)); + break; + case ECommands::MapMoveRight: + ret = std::max(ret, KBToArrowsX(*kbm)); + break; + default: { + EKBMFunctionList kbmfunc = skKBMMapping[int(cmd)]; + if (kbmfunc < EKBMFunctionList::MAX) { + if (kbmfunc >= EKBMFunctionList::MousePress) + ret = std::max(ret, kbm->m_mouseButtons[int(kbmfunc) - int(EKBMFunctionList::MousePress)] ? 1.f : 0.f); + else if (kbmfunc >= EKBMFunctionList::SpecialKeyPress) + ret = std::max(ret, kbm->m_specialKeys[int(kbmfunc) - int(EKBMFunctionList::SpecialKeyPress)] ? 1.f : 0.f); + else if (kbmfunc >= EKBMFunctionList::KeyPress) + ret = std::max(ret, kbm->m_charKeys[int(kbmfunc) - int(EKBMFunctionList::KeyPress)] ? 1.f : 0.f); + } + break; + } + } + } + return ret; } const char* ControlMapper::GetDescriptionForCommand(ECommands cmd) { diff --git a/Runtime/Input/ControlMapper.hpp b/Runtime/Input/ControlMapper.hpp index ddac068f4..6015113ff 100644 --- a/Runtime/Input/ControlMapper.hpp +++ b/Runtime/Input/ControlMapper.hpp @@ -1,5 +1,7 @@ #pragma once +#include "boo/IWindow.hpp" + namespace urde { struct CFinalInput; @@ -100,6 +102,14 @@ public: MAX // default case }; + enum class EKBMFunctionList { + None, + KeyPress, + SpecialKeyPress = 259, + MousePress = 285, + MAX = 291 /* Provide space for keys/buttons within base actions */ + }; + static void SetCommandFiltered(ECommands cmd, bool filtered); static void ResetCommandFilters(); static bool GetPressInput(ECommands cmd, const CFinalInput& input); @@ -109,4 +119,19 @@ public: static const char* GetDescriptionForFunction(EFunctionList func); }; +constexpr ControlMapper::EKBMFunctionList operator+(ControlMapper::EKBMFunctionList a, char b) { + using T = std::underlying_type_t; + return ControlMapper::EKBMFunctionList(static_cast(a) + static_cast(b)); +} + +constexpr ControlMapper::EKBMFunctionList operator+(ControlMapper::EKBMFunctionList a, boo::ESpecialKey b) { + using T = std::underlying_type_t; + return ControlMapper::EKBMFunctionList(static_cast(a) + static_cast(b)); +} + +constexpr ControlMapper::EKBMFunctionList operator+(ControlMapper::EKBMFunctionList a, boo::EMouseButton b) { + using T = std::underlying_type_t; + return ControlMapper::EKBMFunctionList(static_cast(a) + static_cast(b)); +} + } // namespace urde diff --git a/Runtime/MP1/CFrontEndUI.cpp b/Runtime/MP1/CFrontEndUI.cpp index 8d94a60b0..9d4eee9cb 100644 --- a/Runtime/MP1/CFrontEndUI.cpp +++ b/Runtime/MP1/CFrontEndUI.cpp @@ -746,10 +746,14 @@ CFrontEndUI::SFusionBonusFrame::SGBALinkFrame::EAction CFrontEndUI::SFusionBonus case EUIType::LinkFailed: case EUIType::LinkCompleteOrLinking: case EUIType::TurnOffGBA: - if (input.PA() || tbAction == CFrontEndUITouchBar::EAction::Confirm) { + if (input.PA() || + input.PSpecialKey(boo::ESpecialKey::Enter) || + input.PMouseButton(boo::EMouseButton::Primary) || + tbAction == CFrontEndUITouchBar::EAction::Confirm) { PlayAdvanceSfx(); SetUIText(NextLinkUI[int(x0_uiType)]); - } else if (input.PB() || tbAction == CFrontEndUITouchBar::EAction::Back) { + } else if (input.PB() || input.PSpecialKey(boo::ESpecialKey::Esc) || + tbAction == CFrontEndUITouchBar::EAction::Back) { EUIType prevUi = PrevLinkUI[int(x0_uiType)]; if (prevUi == EUIType::Empty) break; @@ -938,7 +942,7 @@ CFrontEndUI::SFusionBonusFrame::EAction CFrontEndUI::SFusionBonusFrame::ProcessU } } else if (x24_loadedFrame) { CFinalInput useInput = input; - if (input.PZ()) { + if (input.PZ() || input.PKey('\t')) { useInput.x2d_b28_PA = true; m_gbaOverride = true; } @@ -1251,7 +1255,7 @@ void CFrontEndUI::SNesEmulatorFrame::ProcessUserInput(const CFinalInput& input, switch (x0_mode) { case EMode::Emulator: x4_nesEmu->ProcessUserInput(input, 4); - if (input.ControllerIdx() == 0 && input.PL()) + if ((input.ControllerIdx() == 0 && input.PL()) || input.PSpecialKey(boo::ESpecialKey::Esc)) SetMode(EMode::QuitNESMetroid); break; case EMode::SaveProgress: @@ -1592,7 +1596,7 @@ bool CFrontEndUI::SOptionsFrontEndFrame::ProcessUserInput(const CFinalInput& inp if (sui) sui->ProcessUserInput(input); if (x1c_loadedFrame && x134_24_visible) { - if (input.PB() && x24_tablegroup_leftmenu->GetIsActive()) { + if ((input.PB() || input.PSpecialKey(boo::ESpecialKey::Esc)) && x24_tablegroup_leftmenu->GetIsActive()) { x134_25_exitOptions = true; CSfxManager::SfxStart(SFXfnt_back, 1.f, 0.f, false, 0x7f, false, kInvalidAreaId); } else { @@ -2034,14 +2038,22 @@ void CFrontEndUI::ProcessUserInput(const CFinalInput& input, CArchitectureQueue& if (x50_curScreen != x54_nextScreen) { if (x54_nextScreen == EScreen::AttractMovie && - (input.PStart() || input.PA() || touchBarAction == CFrontEndUITouchBar::EAction::Start)) { + (input.PStart() || input.PA() || + input.PSpecialKey(boo::ESpecialKey::Esc) || + input.PSpecialKey(boo::ESpecialKey::Enter) || + input.PMouseButton(boo::EMouseButton::Primary) || + touchBarAction == CFrontEndUITouchBar::EAction::Start)) { /* Player wants to return to opening credits from attract movie */ SetFadeBlackTimer(std::min(1.f, x58_fadeBlackTimer)); PlayAdvanceSfx(); return; } - if (input.PA() || input.PStart() || touchBarAction == CFrontEndUITouchBar::EAction::Start) { + if (input.PA() || input.PStart() || + input.PSpecialKey(boo::ESpecialKey::Esc) || + input.PSpecialKey(boo::ESpecialKey::Enter) || + input.PMouseButton(boo::EMouseButton::Primary) || + touchBarAction == CFrontEndUITouchBar::EAction::Start) { if (x50_curScreen == EScreen::OpenCredits && x54_nextScreen == EScreen::Title && x58_fadeBlackTimer > 1.f) { /* Player is too impatient to view opening credits */ xd0_playerSkipToTitle = true; @@ -2051,7 +2063,11 @@ void CFrontEndUI::ProcessUserInput(const CFinalInput& input, CArchitectureQueue& } } else { if (x50_curScreen == EScreen::Title) { - if (input.PStart() || input.PA() || touchBarAction == CFrontEndUITouchBar::EAction::Start) { + if (input.PStart() || input.PA() || + input.PSpecialKey(boo::ESpecialKey::Esc) || + input.PSpecialKey(boo::ESpecialKey::Enter) || + input.PMouseButton(boo::EMouseButton::Primary) || + touchBarAction == CFrontEndUITouchBar::EAction::Start) { if (x58_fadeBlackTimer < 30.f - g_tweakGame->GetPressStartDelay()) { /* Proceed to file select UI */ CSfxManager::SfxStart(FETransitionBackSFX[x18_rndA][0], 1.f, 0.f, false, 0x7f, false, kInvalidAreaId); diff --git a/Runtime/MP1/CInventoryScreen.cpp b/Runtime/MP1/CInventoryScreen.cpp index de19a61fe..016ee4ead 100644 --- a/Runtime/MP1/CInventoryScreen.cpp +++ b/Runtime/MP1/CInventoryScreen.cpp @@ -91,11 +91,13 @@ void CInventoryScreen::Update(float dt, CRandom16& rand, CArchitectureQueue& arc x1a4_textBodyAlpha = std::min(4.f * dt + x1a4_textBodyAlpha, 1.f); else x1a4_textBodyAlpha = std::max(0.f, x1a4_textBodyAlpha - 4.f * dt); - x174_textpane_body->SetColor(zeus::CColor(1.f, x1a4_textBodyAlpha)); - x180_basewidget_yicon->SetColor(zeus::CColor(1.f, 1.f - x1a4_textBodyAlpha)); if (x1a4_textBodyAlpha == 0.f && x1a8_state == EState::Active) ChangeMode(EMode::RightTable); + } else { + x1a4_textBodyAlpha = std::max(0.f, x1a4_textBodyAlpha - 4.f * dt); } + x174_textpane_body->SetColor(zeus::CColor(1.f, x1a4_textBodyAlpha)); + x180_basewidget_yicon->SetColor(zeus::CColor(1.f, 1.f - x1a4_textBodyAlpha)); x19c_samusDoll->SetInMorphball(x70_tablegroup_leftlog->GetUserSelection() == 1 && x10_mode != EMode::LeftTable); UpdateSamusDollPulses(); @@ -121,7 +123,7 @@ void CInventoryScreen::ProcessControllerInput(const CFinalInput& input) { if (input.PStart()) { x19c_samusDoll->BeginViewInterpolate(false); x198_26_exitPauseScreen = true; - } else if (input.PB()) { + } else if (input.PB() || input.PSpecialKey(boo::ESpecialKey::Esc)) { x19c_samusDoll->BeginViewInterpolate(false); } } @@ -152,9 +154,10 @@ void CInventoryScreen::ProcessControllerInput(const CFinalInput& input) { int totalCount = x174_textpane_body->TextSupport().GetTotalPageCount(); bool lastPage = totalCount - 1 == oldPage; if (totalCount != -1) { - if (input.PLAUp()) + if (input.PLAUp() || m_bodyUpClicked) newPage = std::max(oldPage - 1, 0); - else if (input.PLADown() || (input.PA() && !lastPage)) + else if (input.PLADown() || m_bodyDownClicked || + ((input.PA() || input.PSpecialKey(boo::ESpecialKey::Enter) || m_bodyClicked) && !lastPage)) newPage = std::min(oldPage + 1, totalCount - 1); x174_textpane_body->TextSupport().SetPage(newPage); if (oldPage != newPage) @@ -166,7 +169,8 @@ void CInventoryScreen::ProcessControllerInput(const CFinalInput& input) { x198_28_pulseTextArrowTop = false; } if (!x1ac_textLeaveRequested) - x1ac_textLeaveRequested = input.PB() || (input.PA() && lastPage); + x1ac_textLeaveRequested = input.PB() || input.PSpecialKey(boo::ESpecialKey::Esc) || + ((input.PA() || m_bodyClicked || input.PSpecialKey(boo::ESpecialKey::Enter)) && lastPage); x1ad_textViewing = !x1ac_textLeaveRequested; } else { x198_29_pulseTextArrowBottom = false; @@ -176,6 +180,7 @@ void CInventoryScreen::ProcessControllerInput(const CFinalInput& input) { if (x1a8_state != EState::Active) x1ad_textViewing = false; + CPauseScreenBase::ProcessMouseInput(input, absViewInterp); CPauseScreenBase::ProcessControllerInput(input); } } diff --git a/Runtime/MP1/CLogBookScreen.cpp b/Runtime/MP1/CLogBookScreen.cpp index 5e6df9f32..82c23ba03 100644 --- a/Runtime/MP1/CLogBookScreen.cpp +++ b/Runtime/MP1/CLogBookScreen.cpp @@ -8,7 +8,7 @@ namespace urde::MP1 { CLogBookScreen::CLogBookScreen(const CStateManager& mgr, CGuiFrame& frame, const CStringTable& pauseStrg) -: CPauseScreenBase(mgr, frame, pauseStrg) { +: CPauseScreenBase(mgr, frame, pauseStrg, true) { x19c_scanCompletes.resize(5); x200_viewScans.resize(5); x258_artifactDoll = std::make_unique(); @@ -256,23 +256,25 @@ void CLogBookScreen::Update(float dt, CRandom16& rand, CArchitectureQueue& archQ else x254_viewInterp = std::max(0.f, x254_viewInterp - 4.f * dt); - zeus::CColor color(1.f, x254_viewInterp); - x74_basewidget_leftguages->SetColor(color); - x88_basewidget_rightguages->SetColor(color); - - zeus::CColor invColor(1.f, 1.f - x254_viewInterp); - x70_tablegroup_leftlog->SetColor(invColor); - x84_tablegroup_rightlog->SetColor(invColor); - x17c_model_textalpha->SetColor(invColor); - x174_textpane_body->SetColor(color); - - for (CAuiImagePane* pane : xf0_imagePanes) - pane->SetDeResFactor(1.f - x254_viewInterp); - if (x254_viewInterp == 0.f && x25c_leavePauseState == ELeavePauseState::InPause) ChangeMode(EMode::RightTable); + } else { + x254_viewInterp = std::max(0.f, x254_viewInterp - 4.f * dt); } + zeus::CColor color(1.f, x254_viewInterp); + x74_basewidget_leftguages->SetColor(color); + x88_basewidget_rightguages->SetColor(color); + + zeus::CColor invColor(1.f, 1.f - x254_viewInterp); + x70_tablegroup_leftlog->SetColor(invColor); + x84_tablegroup_rightlog->SetColor(invColor); + x17c_model_textalpha->SetColor(invColor); + x174_textpane_body->SetColor(color); + + for (CAuiImagePane* pane : xf0_imagePanes) + pane->SetDeResFactor(1.f - x254_viewInterp); + if (x25c_leavePauseState == ELeavePauseState::LeavingPause && x254_viewInterp == 0.f) x25c_leavePauseState = ELeavePauseState::LeftPause; } @@ -293,9 +295,10 @@ void CLogBookScreen::ProcessControllerInput(const CFinalInput& input) { int pageCount = x174_textpane_body->TextSupport().GetTotalPageCount(); bool lastPage = (pageCount - 1) == oldPage; if (pageCount != -1) { - if (input.PLAUp()) + if (input.PLAUp() || m_bodyUpClicked) newPage = std::max(oldPage - 1, 0); - else if (input.PLADown() || (input.PA() && !lastPage)) + else if (input.PLADown() || m_bodyDownClicked || + ((input.PA() || input.PSpecialKey(boo::ESpecialKey::Enter) || m_bodyClicked) && !lastPage)) newPage = std::min(oldPage + 1, pageCount - 1); x174_textpane_body->TextSupport().SetPage(newPage); if (oldPage != newPage) @@ -308,7 +311,8 @@ void CLogBookScreen::ProcessControllerInput(const CFinalInput& input) { } if (!x260_26_exitTextScroll) - x260_26_exitTextScroll = input.PB() || (input.PA() && lastPage); + x260_26_exitTextScroll = input.PB() || input.PSpecialKey(boo::ESpecialKey::Esc) || + ((input.PA() || input.PSpecialKey(boo::ESpecialKey::Enter) || m_bodyClicked) && lastPage); if (g_tweakGui->GetLatchArticleText()) x260_25_inTextScroll = !x260_26_exitTextScroll; @@ -322,6 +326,7 @@ void CLogBookScreen::ProcessControllerInput(const CFinalInput& input) { if (x25c_leavePauseState == ELeavePauseState::LeavingPause) x260_25_inTextScroll = false; + CPauseScreenBase::ProcessMouseInput(input, 0.f); CPauseScreenBase::ProcessControllerInput(input); } diff --git a/Runtime/MP1/CMFGame.cpp b/Runtime/MP1/CMFGame.cpp index 4516f77f9..ee735e460 100644 --- a/Runtime/MP1/CMFGame.cpp +++ b/Runtime/MP1/CMFGame.cpp @@ -120,7 +120,7 @@ CIOWin::EMessageReturn CMFGame::OnMessage(const CArchitectureMessage& msg, CArch if (input.ControllerIdx() == 0) { const CEntity* cam = x14_stateManager->GetCameraManager()->GetCurrentCamera(*x14_stateManager); TCastToConstPtr cineCam = cam; - if (input.PStart()) { + if (input.PStart() && input.PSpecialKey(boo::ESpecialKey::Esc)) { if (cineCam && x14_stateManager->GetSkipCinematicSpecialFunction() != kInvalidUniqueId) { CMidiManager::StopAll(); x28_skippedCineCam = cineCam->GetUniqueId(); @@ -129,7 +129,7 @@ CIOWin::EMessageReturn CMFGame::OnMessage(const CArchitectureMessage& msg, CArch } else if (!cineCam) { x14_stateManager->DeferStateTransition(EStateManagerTransition::PauseGame); } - } else if (input.PZ() && !cineCam && x14_stateManager->CanShowMapScreen()) { + } else if ((input.PZ() || input.PKey('\t')) && !cineCam && x14_stateManager->CanShowMapScreen()) { x14_stateManager->DeferStateTransition(EStateManagerTransition::MapScreen); } } diff --git a/Runtime/MP1/CMessageScreen.cpp b/Runtime/MP1/CMessageScreen.cpp index 8d4f56b8c..a203ecca4 100644 --- a/Runtime/MP1/CMessageScreen.cpp +++ b/Runtime/MP1/CMessageScreen.cpp @@ -17,7 +17,9 @@ CMessageScreen::CMessageScreen(CAssetId msg, float delayTime) : x74_delayTime(de } void CMessageScreen::ProcessControllerInput(const CFinalInput& input) { - if (!x18_loadedMsgScreen || x74_delayTime > 0.f || !input.PA()) + if (!x18_loadedMsgScreen || x74_delayTime > 0.f || !(input.PA() || + input.PSpecialKey(boo::ESpecialKey::Enter) || + input.PMouseButton(boo::EMouseButton::Primary))) return; if (x1c_textpane_message->TextSupport().GetCurTime() < x1c_textpane_message->TextSupport().GetTotalAnimationTime()) { diff --git a/Runtime/MP1/COptionsScreen.cpp b/Runtime/MP1/COptionsScreen.cpp index 2644ee6e3..db2a9cfc0 100644 --- a/Runtime/MP1/COptionsScreen.cpp +++ b/Runtime/MP1/COptionsScreen.cpp @@ -140,9 +140,11 @@ void COptionsScreen::Touch() { void COptionsScreen::ProcessControllerInput(const CFinalInput& input) { if (!x19c_quitGame) { + CPauseScreenBase::ProcessMouseInput(input, 0.f); CPauseScreenBase::ProcessControllerInput(input); CGameOptions::TryRestoreDefaults(input, x70_tablegroup_leftlog->GetUserSelection(), x1c_rightSel, false, false); - if (x70_tablegroup_leftlog->GetUserSelection() == 4 && input.PA()) + if (x70_tablegroup_leftlog->GetUserSelection() == 4 && (input.PA() || + input.PSpecialKey(boo::ESpecialKey::Enter))) x19c_quitGame = std::make_unique(EQuitType::QuitGame); } else { x19c_quitGame->ProcessUserInput(input); diff --git a/Runtime/MP1/CPauseScreen.cpp b/Runtime/MP1/CPauseScreen.cpp index b0b6e071c..2afc024c5 100644 --- a/Runtime/MP1/CPauseScreen.cpp +++ b/Runtime/MP1/CPauseScreen.cpp @@ -24,6 +24,11 @@ CPauseScreen::CPauseScreen(ESubScreen subscreen, const CDependencyGroup& suitDgr x60_loadTok = g_ResFactory->LoadResourceAsync(frmeTag, x5c_frmePauseScreenBuf.get()); CSfxManager::SfxStart(SFXui_pause_screen_enter, 1.f, 0.f, false, 0x7f, false, kInvalidAreaId); x7c_screens.resize(2); + m_returnDown = false; + m_nextDown = false; + m_backDown = false; + m_lDown = false; + m_rDown = false; } CPauseScreen::~CPauseScreen() { @@ -47,12 +52,19 @@ std::unique_ptr CPauseScreen::BuildPauseSubScreen(ESubScreen s void CPauseScreen::InitializeFrameGlue() { x38_textpane_l1 = static_cast(x34_loadedPauseScreenInstructions->FindWidget("textpane_l1")); + x38_textpane_l1->SetMouseActive(true); x3c_textpane_r = static_cast(x34_loadedPauseScreenInstructions->FindWidget("textpane_r")); + x3c_textpane_r->SetMouseActive(true); x40_textpane_a = static_cast(x34_loadedPauseScreenInstructions->FindWidget("textpane_a")); + x40_textpane_a->SetMouseActive(true); x44_textpane_b = static_cast(x34_loadedPauseScreenInstructions->FindWidget("textpane_b")); + x44_textpane_b->SetMouseActive(true); x48_textpane_return = static_cast(x34_loadedPauseScreenInstructions->FindWidget("textpane_return")); + x48_textpane_return->SetMouseActive(true); x4c_textpane_next = static_cast(x34_loadedPauseScreenInstructions->FindWidget("textpane_next")); + x4c_textpane_next->SetMouseActive(true); x50_textpane_back = static_cast(x34_loadedPauseScreenInstructions->FindWidget("textpane_back")); + x50_textpane_back->SetMouseActive(true); x40_textpane_a->TextSupport().SetText(x14_strgPauseScreen->GetString(7)); // OPTIONS x40_textpane_a->TextSupport().SetFontColor(g_tweakGuiColors->GetPauseItemAmberColor()); @@ -66,6 +78,11 @@ void CPauseScreen::InitializeFrameGlue() { color.a() *= 0.75f; deco->SetColor(color); } + + x34_loadedPauseScreenInstructions->SetMouseDownCallback(std::bind(&CPauseScreen::OnWidgetMouseDown, this, + std::placeholders::_1, std::placeholders::_2)); + x34_loadedPauseScreenInstructions->SetMouseUpCallback(std::bind(&CPauseScreen::OnWidgetMouseUp, this, + std::placeholders::_1, std::placeholders::_2)); } bool CPauseScreen::CheckLoadComplete(const CStateManager& mgr) { @@ -163,8 +180,20 @@ void CPauseScreen::ProcessControllerInput(const CStateManager& mgr, const CFinal if (x8_curSubscreen == ESubScreen::ToGame) return; + m_returnClicked = false; + m_nextClicked = false; + m_backClicked = false; + m_lClicked = false; + m_rClicked = false; + bool bExits = false; if (std::unique_ptr& curScreen = x7c_screens[x78_activeIdx]) { + float yOff = 0.f; + if (curScreen->CanDraw()) + yOff = curScreen->GetCameraYBias(); + CGuiWidgetDrawParms parms(1.f, zeus::CVector3f{0.f, 15.f * yOff, 0.f}); + x34_loadedPauseScreenInstructions->ProcessMouseInput(input, parms); + if (curScreen->GetMode() == CPauseScreenBase::EMode::LeftTable) bExits = true; curScreen->ProcessControllerInput(input); @@ -172,15 +201,16 @@ void CPauseScreen::ProcessControllerInput(const CStateManager& mgr, const CFinal if (InputEnabled()) { bool invalid = x8_curSubscreen == ESubScreen::ToGame; - if (input.PStart() || (input.PB() && bExits) || + if (input.PStart() || m_returnClicked || + ((input.PB() || m_backClicked || input.PSpecialKey(boo::ESpecialKey::Esc)) && bExits) || (x7c_screens[x78_activeIdx] && x7c_screens[x78_activeIdx]->ShouldExitPauseScreen())) { CSfxManager::SfxStart(SFXui_pause_screen_exit, 1.f, 0.f, false, 0x7f, false, kInvalidAreaId); StartTransition(0.5f, mgr, ESubScreen::ToGame, 2); } else { - if (ControlMapper::GetPressInput(ControlMapper::ECommands::PreviousPauseScreen, input)) { + if (ControlMapper::GetPressInput(ControlMapper::ECommands::PreviousPauseScreen, input) || m_lClicked) { CSfxManager::SfxStart(SFXui_pause_screen_change, 1.f, 0.f, false, 0x7f, false, kInvalidAreaId); StartTransition(0.5f, mgr, GetPreviousSubscreen(x8_curSubscreen), invalid ? 2 : 0); - } else if (ControlMapper::GetPressInput(ControlMapper::ECommands::NextPauseScreen, input)) { + } else if (ControlMapper::GetPressInput(ControlMapper::ECommands::NextPauseScreen, input) || m_rClicked) { CSfxManager::SfxStart(SFXui_pause_screen_change, 1.f, 0.f, false, 0x7f, false, kInvalidAreaId); StartTransition(0.5f, mgr, GetNextSubscreen(x8_curSubscreen), invalid ? 2 : 1); } @@ -188,15 +218,15 @@ void CPauseScreen::ProcessControllerInput(const CStateManager& mgr, const CFinal } x38_textpane_l1->TextSupport().SetText( - hecl::Format("&image=%8.8X;", u32(g_tweakPlayerRes->x74_lTrigger[input.DLTrigger()].Value()))); + hecl::Format("&image=%8.8X;", u32(g_tweakPlayerRes->x74_lTrigger[input.DLTrigger() || m_lDown].Value()))); x3c_textpane_r->TextSupport().SetText( - hecl::Format("&image=%8.8X;", u32(g_tweakPlayerRes->x80_rTrigger[input.DRTrigger()].Value()))); + hecl::Format("&image=%8.8X;", u32(g_tweakPlayerRes->x80_rTrigger[input.DRTrigger() || m_rDown].Value()))); x48_textpane_return->TextSupport().SetText( - hecl::Format("&image=%8.8X;", u32(g_tweakPlayerRes->x8c_startButton[input.DStart()].Value()))); + hecl::Format("&image=%8.8X;", u32(g_tweakPlayerRes->x8c_startButton[input.DStart() || m_returnDown].Value()))); x50_textpane_back->TextSupport().SetText( - hecl::Format("&image=%8.8X;", u32(g_tweakPlayerRes->x98_aButton[input.DA()].Value()))); + hecl::Format("&image=%8.8X;", u32(g_tweakPlayerRes->x98_aButton[input.DA() || m_backDown].Value()))); x4c_textpane_next->TextSupport().SetText( - hecl::Format("&image=%8.8X;", u32(g_tweakPlayerRes->xa4_bButton[input.DB()].Value()))); + hecl::Format("&image=%8.8X;", u32(g_tweakPlayerRes->xa4_bButton[input.DB() || m_nextDown].Value()))); } void CPauseScreen::TransitionComplete() { @@ -208,6 +238,44 @@ void CPauseScreen::TransitionComplete() { x44_textpane_b->TextSupport().SetText(x14_strgPauseScreen->GetString(int(GetNextSubscreen(x8_curSubscreen)) + 6)); } +void CPauseScreen::OnWidgetMouseDown(CGuiWidget* widget, bool resume) { + if (widget == x48_textpane_return) + m_returnDown = true; + else if (widget == x4c_textpane_next) + m_backDown = true; + else if (widget == x50_textpane_back) + m_nextDown = true; + else if (widget == x38_textpane_l1 || widget == x40_textpane_a) + m_lDown = true; + else if (widget == x3c_textpane_r || widget == x44_textpane_b) + m_rDown = true; +} + +void CPauseScreen::OnWidgetMouseUp(CGuiWidget* widget, bool cancel) { + if (widget == x48_textpane_return) + m_returnDown = false; + else if (widget == x4c_textpane_next) + m_backDown = false; + else if (widget == x50_textpane_back) + m_nextDown = false; + else if (widget == x38_textpane_l1 || widget == x40_textpane_a) + m_lDown = false; + else if (widget == x3c_textpane_r || widget == x44_textpane_b) + m_rDown = false; + if (cancel) + return; + if (widget == x48_textpane_return) + m_returnClicked = true; + else if (widget == x4c_textpane_next) + m_backClicked = true; + else if (widget == x50_textpane_back) + m_nextClicked = true; + else if (widget == x38_textpane_l1 || widget == x40_textpane_a) + m_lClicked = true; + else if (widget == x3c_textpane_r || widget == x44_textpane_b) + m_rClicked = true; +} + void CPauseScreen::Update(float dt, const CStateManager& mgr, CRandom16& rand, CArchitectureQueue& archQueue) { if (!CheckLoadComplete(mgr)) return; diff --git a/Runtime/MP1/CPauseScreen.hpp b/Runtime/MP1/CPauseScreen.hpp index 6dae07e6e..a51a0ef6c 100644 --- a/Runtime/MP1/CPauseScreen.hpp +++ b/Runtime/MP1/CPauseScreen.hpp @@ -41,6 +41,17 @@ private: bool x90_resourcesLoaded = false; bool x91_initialTransition = true; + bool m_returnClicked : 1; + bool m_nextClicked : 1; + bool m_backClicked : 1; + bool m_lClicked : 1; + bool m_rClicked : 1; + bool m_returnDown : 1; + bool m_nextDown : 1; + bool m_backDown : 1; + bool m_lDown : 1; + bool m_rDown : 1; + std::unique_ptr BuildPauseSubScreen(ESubScreen subscreen, const CStateManager& mgr, CGuiFrame& frame) const; void StartTransition(float time, const CStateManager& mgr, ESubScreen subscreen, int); @@ -51,6 +62,9 @@ private: static ESubScreen GetNextSubscreen(ESubScreen screen); void TransitionComplete(); + void OnWidgetMouseDown(CGuiWidget* widget, bool resume); + void OnWidgetMouseUp(CGuiWidget* widget, bool cancel); + public: CPauseScreen(ESubScreen subscreen, const CDependencyGroup& suitDgrp, const CDependencyGroup& ballDgrp); ~CPauseScreen(); diff --git a/Runtime/MP1/CPauseScreenBase.cpp b/Runtime/MP1/CPauseScreenBase.cpp index 022b38f1d..d80d04bea 100644 --- a/Runtime/MP1/CPauseScreenBase.cpp +++ b/Runtime/MP1/CPauseScreenBase.cpp @@ -13,8 +13,10 @@ namespace urde::MP1 { -CPauseScreenBase::CPauseScreenBase(const CStateManager& mgr, CGuiFrame& frame, const CStringTable& pauseStrg) +CPauseScreenBase::CPauseScreenBase(const CStateManager& mgr, CGuiFrame& frame, const CStringTable& pauseStrg, + bool isLogBook) : x4_mgr(mgr), x8_frame(frame), xc_pauseStrg(pauseStrg) { + m_isLogBook = isLogBook; InitializeFrameGlue(); } @@ -34,12 +36,13 @@ void CPauseScreenBase::InitializeFrameGlue() { x88_basewidget_rightguages->SetColor(zeus::CColor(1.f, 0.f)); x8c_model_righthighlight = static_cast(x8_frame.FindWidget("model_righthighlight")); x90_model_textarrowtop = static_cast(x8_frame.FindWidget("model_textarrowtop")); + x90_model_textarrowtop->SetMouseActive(true); x94_model_textarrowbottom = static_cast(x8_frame.FindWidget("model_textarrowbottom")); + x94_model_textarrowbottom->SetMouseActive(true); x98_model_scrollleftup = static_cast(x8_frame.FindWidget("model_scrollleftup")); x9c_model_scrollleftdown = static_cast(x8_frame.FindWidget("model_scrollleftdown")); xa0_model_scrollrightup = static_cast(x8_frame.FindWidget("model_scrollrightup")); xa4_model_scrollrightdown = static_cast(x8_frame.FindWidget("model_scrollrightdown")); - x94_model_textarrowbottom = static_cast(x8_frame.FindWidget("model_textarrowbottom")); x178_textpane_title = static_cast(x8_frame.FindWidget("textpane_title")); x178_textpane_title->TextSupport().SetFontColor(g_tweakGuiColors->GetPauseItemAmberColor()); x174_textpane_body = static_cast(x8_frame.FindWidget("textpane_body")); @@ -51,6 +54,7 @@ void CPauseScreenBase::InitializeFrameGlue() { x174_textpane_body->TextSupport().SetJustification(EJustification::Left); x174_textpane_body->TextSupport().SetVerticalJustification(EVerticalJustification::Top); x174_textpane_body->TextSupport().SetControlTXTRMap(&g_GameState->GameOptions().GetControlTXTRMap()); + x174_textpane_body->SetMouseActive(true); x180_basewidget_yicon = x8_frame.FindWidget("basewidget_yicon"); x180_basewidget_yicon->SetVisibility(false, ETraversalMode::Children); x17c_model_textalpha = static_cast(x8_frame.FindWidget("model_textalpha")); @@ -85,6 +89,9 @@ void CPauseScreenBase::InitializeFrameGlue() { static_cast(x8_frame.FindWidget(hecl::Format("textpane_title%d", i + 1)))); xd8_textpane_titles.back()->TextSupport().SetText(u""); x144_model_titles.push_back(static_cast(x8_frame.FindWidget(hecl::Format("model_title%d", i + 1)))); + m_model_lefttitledecos.push_back( + static_cast(x8_frame.FindWidget(hecl::Format("model_lefttitledeco%d", i)))); + m_model_lefttitledecos.back()->SetMouseActive(true); x15c_model_righttitledecos.push_back( static_cast(x8_frame.FindWidget(hecl::Format("model_righttitledeco%d", i + 1)))); x15c_model_righttitledecos.back()->SetMouseActive(true); @@ -152,6 +159,9 @@ void CPauseScreenBase::InitializeFrameGlue() { x18c_slidergroup_slider->SetSelectionChangedCallback({}); x190_tablegroup_double->SetMenuSelectionChangeCallback({}); x194_tablegroup_triple->SetMenuSelectionChangeCallback({}); + + x8_frame.SetMouseUpCallback(std::bind(&CPauseScreenBase::OnWidgetMouseUp, this, + std::placeholders::_1, std::placeholders::_2)); } bool CPauseScreenBase::IsReady() { @@ -168,7 +178,7 @@ bool CPauseScreenBase::IsReady() { return false; } -void CPauseScreenBase::ChangeMode(EMode mode) { +void CPauseScreenBase::ChangeMode(EMode mode, bool playSfx) { if (x10_mode == mode) return; @@ -191,7 +201,8 @@ void CPauseScreenBase::ChangeMode(EMode mode) { x84_tablegroup_rightlog->SetIsActive(false); break; case EMode::TextScroll: - CSfxManager::SfxStart(SFXui_table_change_mode, 1.f, 0.f, false, 0x7f, false, kInvalidAreaId); + if (playSfx) + CSfxManager::SfxStart(SFXui_table_change_mode, 1.f, 0.f, false, 0x7f, false, kInvalidAreaId); break; default: break; @@ -201,7 +212,7 @@ void CPauseScreenBase::ChangeMode(EMode mode) { switch (x10_mode) { case EMode::LeftTable: - if (oldMode == EMode::RightTable) + if (playSfx && oldMode == EMode::RightTable) CSfxManager::SfxStart(SFXui_table_change_mode, 1.f, 0.f, false, 0x7f, false, kInvalidAreaId); x6c_basewidget_leftlog->SetColor(color); x70_tablegroup_leftlog->SetIsActive(true); @@ -305,6 +316,14 @@ void CPauseScreenBase::ProcessControllerInput(const CFinalInput& input) { x8_frame.ProcessUserInput(input); } +bool CPauseScreenBase::ProcessMouseInput(const CFinalInput& input, float yOff) { + m_bodyUpClicked = false; + m_bodyDownClicked = false; + m_bodyClicked = false; + CGuiWidgetDrawParms parms(1.f, zeus::CVector3f{0.f, 15.f * yOff, 0.f}); + return x8_frame.ProcessMouseInput(input, parms); +} + void CPauseScreenBase::Draw(float mainAlpha, float frameAlpha, float yOff) { zeus::CColor color = zeus::CColor::skWhite; color.a() = mainAlpha * x14_alpha; @@ -366,6 +385,60 @@ void CPauseScreenBase::OnTableSelectionChange(CGuiTableGroup* caller, int oldSel void CPauseScreenBase::OnRightTableCancel(CGuiTableGroup* caller) { ChangeMode(EMode::LeftTable); } +void CPauseScreenBase::OnWidgetMouseUp(CGuiWidget* widget, bool cancel) { + if (cancel || !widget) + return; + if (widget->GetParent() == x70_tablegroup_leftlog) { + if (m_isLogBook && x10_mode == EMode::TextScroll) + return; + int idx = int(std::find(m_model_lefttitledecos.begin(), m_model_lefttitledecos.end(), widget) - + m_model_lefttitledecos.begin()); + if (x70_tablegroup_leftlog->IsWorkerSelectable(idx)) { + /* Simulate change to left table */ + if (x10_mode == EMode::TextScroll) + ChangeMode(EMode::RightTable, false); + if (x10_mode == EMode::RightTable) + ChangeMode(EMode::LeftTable, false); + /* Simulate selection change */ + int oldSel = x70_tablegroup_leftlog->GetUserSelection(); + x70_tablegroup_leftlog->SelectWorker(idx); + OnTableSelectionChange(x70_tablegroup_leftlog, oldSel); + /* Simulate change to right table if able */ + if (ShouldLeftTableAdvance()) + ChangeMode(EMode::RightTable, false); + } + } else if (widget->GetParent() == x84_tablegroup_rightlog) { + if (m_isLogBook && x10_mode == EMode::TextScroll) + return; + int idx = int(std::find(x15c_model_righttitledecos.begin(), x15c_model_righttitledecos.end(), widget) - + x15c_model_righttitledecos.begin()) + 1; + if (x10_mode == EMode::LeftTable) { + if (ShouldLeftTableAdvance()) + ChangeMode(EMode::RightTable, false); + else + return; + } + if (x84_tablegroup_rightlog->IsWorkerSelectable(idx)) { + /* Simulate change to right table */ + if (x10_mode == EMode::TextScroll) + ChangeMode(EMode::RightTable, false); + /* Simulate selection change */ + int oldSel = x84_tablegroup_rightlog->GetUserSelection(); + x84_tablegroup_rightlog->SelectWorker(idx); + OnTableSelectionChange(x84_tablegroup_rightlog, oldSel); + /* Simulate change to text scroll if able */ + if (ShouldRightTableAdvance()) + ChangeMode(EMode::TextScroll, false); + } + } else if (widget == x174_textpane_body) { + m_bodyClicked = true; + } else if (widget == x90_model_textarrowtop) { + m_bodyUpClicked = true; + } else if (widget == x94_model_textarrowbottom) { + m_bodyDownClicked = true; + } +} + static const char* PaneSuffixes[] = {"0", "1", "2", "3", "01", "12", "23", "012", "123", "0123", "4", "5", "6", "7", "45", "56", "67", "456", "567", "4567"}; diff --git a/Runtime/MP1/CPauseScreenBase.hpp b/Runtime/MP1/CPauseScreenBase.hpp index e0de48a3a..176423c4d 100644 --- a/Runtime/MP1/CPauseScreenBase.hpp +++ b/Runtime/MP1/CPauseScreenBase.hpp @@ -59,6 +59,7 @@ protected: rstl::reserved_vector xd8_textpane_titles; rstl::reserved_vector xf0_imagePanes; rstl::reserved_vector x144_model_titles; + rstl::reserved_vector m_model_lefttitledecos; rstl::reserved_vector x15c_model_righttitledecos; CGuiTextPane* x174_textpane_body = nullptr; CGuiTextPane* x178_textpane_title = nullptr; @@ -77,11 +78,15 @@ protected: bool x198_27_canDraw : 1; bool x198_28_pulseTextArrowTop : 1; bool x198_29_pulseTextArrowBottom : 1; + bool m_isLogBook : 1; + bool m_bodyUpClicked : 1; + bool m_bodyDownClicked : 1; + bool m_bodyClicked : 1; }; u32 _dummy = 0; }; void InitializeFrameGlue(); - void ChangeMode(EMode mode); + void ChangeMode(EMode mode, bool playSfx = true); void UpdateSideTable(CGuiTableGroup* table); void SetRightTableSelection(int oldSel, int newSel); @@ -90,10 +95,12 @@ protected: void OnTableSelectionChange(CGuiTableGroup* caller, int oldSel); void OnRightTableCancel(CGuiTableGroup* caller); + void OnWidgetMouseUp(CGuiWidget* widget, bool cancel); + public: static std::string GetImagePaneName(u32 i); - CPauseScreenBase(const CStateManager& mgr, CGuiFrame& frame, const CStringTable& pauseStrg); + CPauseScreenBase(const CStateManager& mgr, CGuiFrame& frame, const CStringTable& pauseStrg, bool isLogBook = false); bool ShouldExitPauseScreen() const { return x198_26_exitPauseScreen; } bool IsReady(); @@ -107,6 +114,7 @@ public: virtual void Update(float dt, CRandom16& rand, CArchitectureQueue& archQueue); virtual void Touch() {} virtual void ProcessControllerInput(const CFinalInput& input); + bool ProcessMouseInput(const CFinalInput& input, float yOff); virtual void Draw(float transInterp, float totalAlpha, float yOff); virtual float GetCameraYBias() const { return 0.f; } virtual bool VReady() const = 0; diff --git a/Runtime/MP1/CQuitGameScreen.cpp b/Runtime/MP1/CQuitGameScreen.cpp index 585ca96bb..e0a406a75 100644 --- a/Runtime/MP1/CQuitGameScreen.cpp +++ b/Runtime/MP1/CQuitGameScreen.cpp @@ -84,7 +84,7 @@ void CQuitGameScreen::ProcessUserInput(const CFinalInput& input) { if (!x10_loadedFrame) return; x10_loadedFrame->ProcessUserInput(input); - if (input.PB() && x0_type != EQuitType::ContinueFromLastSave) + if ((input.PB() || input.PSpecialKey(boo::ESpecialKey::Esc)) && x0_type != EQuitType::ContinueFromLastSave) x18_action = EQuitAction::No; }