Initial mouse events for pause screen

This commit is contained in:
Jack Andersen 2019-01-20 18:10:34 -10:00
parent 47c6b5cba8
commit f3f9924309
25 changed files with 620 additions and 176 deletions

View File

@ -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) {

View File

@ -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);

View File

@ -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) {

View File

@ -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> CGuiFrame::CreateFrame(CAssetId frmeId, CGuiSys& sys, CInputStream& in, CSimplePool* sp) {
in.readInt32Big();
int a = in.readInt32Big();

View File

@ -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<void(CGuiWidget*, CGuiWidget*)> m_mouseOverChangeCb;
std::function<void(CGuiWidget*)> m_mouseDownCb;
std::function<void(CGuiWidget*)> m_mouseUpCb;
std::function<void(CGuiWidget*, bool)> m_mouseDownCb;
std::function<void(CGuiWidget*, bool)> 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<void(CGuiWidget*, CGuiWidget*)>&& cb) {
m_mouseOverChangeCb = std::move(cb);
}
void SetMouseDownCallback(std::function<void(CGuiWidget*)>&& cb) {
void SetMouseDownCallback(std::function<void(CGuiWidget*, bool)>&& cb) {
m_mouseDownCb = std::move(cb);
}
void SetMouseUpCallback(std::function<void(CGuiWidget*)>&& cb) {
void SetMouseUpCallback(std::function<void(CGuiWidget*, bool)>&& 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; }

View File

@ -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;

View File

@ -28,8 +28,6 @@ private:
std::function<void(CGuiTableGroup*)> xec_doMenuCancel;
std::function<void(CGuiTableGroup*, int)> 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; }

View File

@ -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<CGuiWidget> CGuiTextPane::Create(CGuiFrame* frame, CInputStream& in, CSimplePool* sp) {
CGuiWidgetParms parms = ReadWidgetHeader(frame, in);
zeus::CVector2f dim = zeus::CVector2f::ReadBig(in);

View File

@ -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<CGuiWidget> Create(CGuiFrame* frame, CInputStream& in, CSimplePool* sp);
};

View File

@ -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());

View File

@ -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

View File

@ -61,6 +61,13 @@ struct CFinalInput {
std::experimental::optional<CKeyboardMouseControllerData> 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<CKeyboardMouseControllerData>& GetKBM() const { return m_kbm; }
};

View File

@ -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) {

View File

@ -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<ControlMapper::EKBMFunctionList>;
return ControlMapper::EKBMFunctionList(static_cast<T>(a) + static_cast<T>(b));
}
constexpr ControlMapper::EKBMFunctionList operator+(ControlMapper::EKBMFunctionList a, boo::ESpecialKey b) {
using T = std::underlying_type_t<ControlMapper::EKBMFunctionList>;
return ControlMapper::EKBMFunctionList(static_cast<T>(a) + static_cast<T>(b));
}
constexpr ControlMapper::EKBMFunctionList operator+(ControlMapper::EKBMFunctionList a, boo::EMouseButton b) {
using T = std::underlying_type_t<ControlMapper::EKBMFunctionList>;
return ControlMapper::EKBMFunctionList(static_cast<T>(a) + static_cast<T>(b));
}
} // namespace urde

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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<CArtifactDoll>();
@ -256,6 +256,12 @@ void CLogBookScreen::Update(float dt, CRandom16& rand, CArchitectureQueue& archQ
else
x254_viewInterp = std::max(0.f, x254_viewInterp - 4.f * dt);
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);
@ -269,10 +275,6 @@ void CLogBookScreen::Update(float dt, CRandom16& rand, CArchitectureQueue& archQ
for (CAuiImagePane* pane : xf0_imagePanes)
pane->SetDeResFactor(1.f - x254_viewInterp);
if (x254_viewInterp == 0.f && x25c_leavePauseState == ELeavePauseState::InPause)
ChangeMode(EMode::RightTable);
}
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);
}

View File

@ -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<CCinematicCamera> 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);
}
}

View File

@ -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()) {

View File

@ -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<CQuitGameScreen>(EQuitType::QuitGame);
} else {
x19c_quitGame->ProcessUserInput(input);

View File

@ -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<CPauseScreenBase> CPauseScreen::BuildPauseSubScreen(ESubScreen s
void CPauseScreen::InitializeFrameGlue() {
x38_textpane_l1 = static_cast<CGuiTextPane*>(x34_loadedPauseScreenInstructions->FindWidget("textpane_l1"));
x38_textpane_l1->SetMouseActive(true);
x3c_textpane_r = static_cast<CGuiTextPane*>(x34_loadedPauseScreenInstructions->FindWidget("textpane_r"));
x3c_textpane_r->SetMouseActive(true);
x40_textpane_a = static_cast<CGuiTextPane*>(x34_loadedPauseScreenInstructions->FindWidget("textpane_a"));
x40_textpane_a->SetMouseActive(true);
x44_textpane_b = static_cast<CGuiTextPane*>(x34_loadedPauseScreenInstructions->FindWidget("textpane_b"));
x44_textpane_b->SetMouseActive(true);
x48_textpane_return = static_cast<CGuiTextPane*>(x34_loadedPauseScreenInstructions->FindWidget("textpane_return"));
x48_textpane_return->SetMouseActive(true);
x4c_textpane_next = static_cast<CGuiTextPane*>(x34_loadedPauseScreenInstructions->FindWidget("textpane_next"));
x4c_textpane_next->SetMouseActive(true);
x50_textpane_back = static_cast<CGuiTextPane*>(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<CPauseScreenBase>& 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;

View File

@ -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<CPauseScreenBase> 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();

View File

@ -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<CGuiModel*>(x8_frame.FindWidget("model_righthighlight"));
x90_model_textarrowtop = static_cast<CGuiModel*>(x8_frame.FindWidget("model_textarrowtop"));
x90_model_textarrowtop->SetMouseActive(true);
x94_model_textarrowbottom = static_cast<CGuiModel*>(x8_frame.FindWidget("model_textarrowbottom"));
x94_model_textarrowbottom->SetMouseActive(true);
x98_model_scrollleftup = static_cast<CGuiModel*>(x8_frame.FindWidget("model_scrollleftup"));
x9c_model_scrollleftdown = static_cast<CGuiModel*>(x8_frame.FindWidget("model_scrollleftdown"));
xa0_model_scrollrightup = static_cast<CGuiModel*>(x8_frame.FindWidget("model_scrollrightup"));
xa4_model_scrollrightdown = static_cast<CGuiModel*>(x8_frame.FindWidget("model_scrollrightdown"));
x94_model_textarrowbottom = static_cast<CGuiModel*>(x8_frame.FindWidget("model_textarrowbottom"));
x178_textpane_title = static_cast<CGuiTextPane*>(x8_frame.FindWidget("textpane_title"));
x178_textpane_title->TextSupport().SetFontColor(g_tweakGuiColors->GetPauseItemAmberColor());
x174_textpane_body = static_cast<CGuiTextPane*>(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<CGuiModel*>(x8_frame.FindWidget("model_textalpha"));
@ -85,6 +89,9 @@ void CPauseScreenBase::InitializeFrameGlue() {
static_cast<CGuiTextPane*>(x8_frame.FindWidget(hecl::Format("textpane_title%d", i + 1))));
xd8_textpane_titles.back()->TextSupport().SetText(u"");
x144_model_titles.push_back(static_cast<CGuiModel*>(x8_frame.FindWidget(hecl::Format("model_title%d", i + 1))));
m_model_lefttitledecos.push_back(
static_cast<CGuiModel*>(x8_frame.FindWidget(hecl::Format("model_lefttitledeco%d", i))));
m_model_lefttitledecos.back()->SetMouseActive(true);
x15c_model_righttitledecos.push_back(
static_cast<CGuiModel*>(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,6 +201,7 @@ void CPauseScreenBase::ChangeMode(EMode mode) {
x84_tablegroup_rightlog->SetIsActive(false);
break;
case EMode::TextScroll:
if (playSfx)
CSfxManager::SfxStart(SFXui_table_change_mode, 1.f, 0.f, false, 0x7f, false, kInvalidAreaId);
break;
default:
@ -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"};

View File

@ -59,6 +59,7 @@ protected:
rstl::reserved_vector<CGuiTextPane*, 5> xd8_textpane_titles;
rstl::reserved_vector<CAuiImagePane*, 20> xf0_imagePanes;
rstl::reserved_vector<CGuiModel*, 5> x144_model_titles;
rstl::reserved_vector<CGuiModel*, 5> m_model_lefttitledecos;
rstl::reserved_vector<CGuiModel*, 5> 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;

View File

@ -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;
}