#include "Runtime/MP1/CPauseScreen.hpp" #include "Runtime/CSimplePool.hpp" #include "Runtime/GameGlobalObjects.hpp" #include "Runtime/Audio/CSfxManager.hpp" #include "Runtime/GuiSys/CGuiSys.hpp" #include "Runtime/GuiSys/CGuiTextPane.hpp" #include "Runtime/GuiSys/CGuiWidgetDrawParms.hpp" #include "Runtime/Input/ControlMapper.hpp" #include "Runtime/MP1/CLogBookScreen.hpp" #include "Runtime/MP1/COptionsScreen.hpp" namespace metaforce::MP1 { CPauseScreen::CPauseScreen(ESubScreen subscreen, const CDependencyGroup& suitDgrp, const CDependencyGroup& ballDgrp) : x0_initialSubScreen(subscreen) , x14_strgPauseScreen(g_SimplePool->GetObj("STRG_PauseScreen")) , x20_suitDgrp(suitDgrp) , x24_ballDgrp(ballDgrp) , x28_pauseScreenInstructions(g_SimplePool->GetObj("FRME_PauseScreenInstructions")) , x54_frmePauseScreenId(g_ResFactory->GetResourceIdByName("FRME_PauseScreen")->id) { SObjectTag frmeTag(FOURCC('FRME'), x54_frmePauseScreenId); x58_frmePauseScreenBufSz = g_ResFactory->ResourceSize(frmeTag); x5c_frmePauseScreenBuf.reset(new u8[x58_frmePauseScreenBufSz]); 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); } CPauseScreen::~CPauseScreen() { if (x60_loadTok) x60_loadTok->PostCancelRequest(); } std::unique_ptr CPauseScreen::BuildPauseSubScreen(ESubScreen subscreen, const CStateManager& mgr, CGuiFrame& frame) const { switch (subscreen) { case ESubScreen::LogBook: return std::make_unique(mgr, frame, *x14_strgPauseScreen); case ESubScreen::Options: return std::make_unique(mgr, frame, *x14_strgPauseScreen); case ESubScreen::Inventory: return std::make_unique(mgr, frame, *x14_strgPauseScreen, x20_suitDgrp, x24_ballDgrp); default: return {}; } } 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()); x44_textpane_b->TextSupport().SetText(x14_strgPauseScreen->GetString(6)); // LOG BOOK x44_textpane_b->TextSupport().SetFontColor(g_tweakGuiColors->GetPauseItemAmberColor()); x40_textpane_a->SetColor(zeus::skClear); x44_textpane_b->SetColor(zeus::skClear); if (CGuiWidget* deco = x34_loadedPauseScreenInstructions->FindWidget("basewidget_deco")) { zeus::CColor color = g_tweakGuiColors->GetPauseItemAmberColor(); color.a() *= 0.75f; deco->SetColor(color); } x34_loadedPauseScreenInstructions->SetMouseDownCallback( [this](CGuiWidget* caller, bool resume) { OnWidgetMouseDown(caller, resume); }); x34_loadedPauseScreenInstructions->SetMouseUpCallback( [this](CGuiWidget* caller, bool cancel) { OnWidgetMouseUp(caller, cancel); }); } bool CPauseScreen::CheckLoadComplete(const CStateManager& mgr) { if (x90_resourcesLoaded) return true; if (!x14_strgPauseScreen.IsLoaded()) return false; if (!x34_loadedPauseScreenInstructions) { if (!x28_pauseScreenInstructions.IsLoaded()) return false; if (!x28_pauseScreenInstructions->GetIsFinishedLoading()) return false; x34_loadedPauseScreenInstructions = x28_pauseScreenInstructions.GetObj(); x34_loadedPauseScreenInstructions->SetMaxAspect(1.77f); InitializeFrameGlue(); } if (x60_loadTok) { if (!x60_loadTok->IsComplete()) return false; for (int i = 0; i < 2; ++i) { CMemoryInStream s(x5c_frmePauseScreenBuf.get(), x58_frmePauseScreenBufSz); x64_frameInsts.push_back(CGuiFrame::CreateFrame(x54_frmePauseScreenId, *g_GuiSys, s, g_SimplePool)); x64_frameInsts.back()->SetMaxAspect(1.77f); } x5c_frmePauseScreenBuf.reset(); x60_loadTok.reset(); } if (!x64_frameInsts[0]->GetIsFinishedLoading() || !x64_frameInsts[1]->GetIsFinishedLoading()) return false; x90_resourcesLoaded = true; StartTransition(FLT_EPSILON, mgr, x0_initialSubScreen, 2); x91_initialTransition = true; return true; } void CPauseScreen::StartTransition(float time, const CStateManager& mgr, ESubScreen subscreen, int b) { if (subscreen == xc_nextSubscreen) return; xc_nextSubscreen = subscreen; x4_ = b; x10_alphaInterp = time; std::unique_ptr& newScreenSlot = x7c_screens[1 - x78_activeIdx]; std::unique_ptr& newScreenInst = x64_frameInsts[1 - x78_activeIdx]; newScreenSlot = BuildPauseSubScreen(xc_nextSubscreen, mgr, *newScreenInst); if (x7c_screens[x78_activeIdx]) x7c_screens[x78_activeIdx]->TransitioningAway(); x91_initialTransition = false; } bool CPauseScreen::InputEnabled() const { if (xc_nextSubscreen != x8_curSubscreen) return false; if (const std::unique_ptr& screenSlot = x7c_screens[x78_activeIdx]) if (screenSlot->InputDisabled()) return false; if (const std::unique_ptr& screenSlot = x7c_screens[1 - x78_activeIdx]) if (screenSlot->InputDisabled()) return false; return true; } CPauseScreen::ESubScreen CPauseScreen::GetPreviousSubscreen(ESubScreen screen) { switch (screen) { case ESubScreen::Inventory: return ESubScreen::Options; case ESubScreen::Options: return ESubScreen::LogBook; case ESubScreen::LogBook: return ESubScreen::Inventory; default: return ESubScreen::ToGame; } } CPauseScreen::ESubScreen CPauseScreen::GetNextSubscreen(ESubScreen screen) { switch (screen) { case ESubScreen::Inventory: return ESubScreen::LogBook; case ESubScreen::Options: return ESubScreen::Inventory; case ESubScreen::LogBook: return ESubScreen::Options; default: return ESubScreen::ToGame; } } void CPauseScreen::ProcessControllerInput(const CStateManager& mgr, const CFinalInput& input) { if (!IsLoaded()) return; if (x8_curSubscreen == ESubScreen::ToGame) return; m_returnClicked = false; m_nextClicked = false; m_backClicked = false; m_lClicked = false; m_rClicked = false; CFinalInput useInput = input; 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(useInput, parms); useInput.x2e_b31_PStart |= m_returnClicked; useInput.x2d_b28_PA |= m_nextClicked; useInput.x2d_b29_PB |= m_backClicked; if (curScreen->GetMode() == CPauseScreenBase::EMode::LeftTable) bExits = true; curScreen->ProcessControllerInput(useInput); } if (InputEnabled()) { bool invalid = x8_curSubscreen == ESubScreen::ToGame; if (useInput.PStart() || ((useInput.PB() || useInput.PSpecialKey(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, useInput) || 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, useInput) || 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); } } } x38_textpane_l1->TextSupport().SetText(fmt::format( FMT_STRING("&image={};"), g_tweakPlayerRes ->x74_lTrigger[ControlMapper::GetDigitalInput(ControlMapper::ECommands::PreviousPauseScreen, useInput) || m_lDown])); x3c_textpane_r->TextSupport().SetText(fmt::format( FMT_STRING("&image={};"), g_tweakPlayerRes ->x80_rTrigger[ControlMapper::GetDigitalInput(ControlMapper::ECommands::NextPauseScreen, useInput) || m_rDown])); x48_textpane_return->TextSupport().SetText( fmt::format(FMT_STRING("&image={};"), g_tweakPlayerRes->x8c_startButton[useInput.DStart() || m_returnDown])); x50_textpane_back->TextSupport().SetText( fmt::format(FMT_STRING("&image={};"), g_tweakPlayerRes->x98_aButton[useInput.DA() || m_backDown])); x4c_textpane_next->TextSupport().SetText( fmt::format(FMT_STRING("&image={};"), g_tweakPlayerRes->xa4_bButton[useInput.DB() || m_nextDown])); } void CPauseScreen::TransitionComplete() { std::unique_ptr& curScreen = x7c_screens[x78_activeIdx]; curScreen.reset(); x78_activeIdx = 1 - x78_activeIdx; x8_curSubscreen = xc_nextSubscreen; x40_textpane_a->TextSupport().SetText(x14_strgPauseScreen->GetString(int(GetPreviousSubscreen(x8_curSubscreen)) + 6)); 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; std::unique_ptr& curScreen = x7c_screens[x78_activeIdx]; std::unique_ptr& otherScreen = x7c_screens[1 - x78_activeIdx]; if (x8_curSubscreen != xc_nextSubscreen) { x10_alphaInterp = std::max(0.f, x10_alphaInterp - dt); if (!curScreen || !curScreen->InputDisabled()) { if (!otherScreen || otherScreen->IsReady()) { if (x10_alphaInterp == 0.f) TransitionComplete(); } } } if (std::unique_ptr& curScreen = x7c_screens[x78_activeIdx]) { curScreen->Update(dt, rand, archQueue); zeus::CColor color = zeus::skWhite; color.a() = std::min(curScreen->GetAlpha(), x8_curSubscreen != xc_nextSubscreen ? x10_alphaInterp / 0.5f : 1.f); x40_textpane_a->SetColor(color); x44_textpane_b->SetColor(color); } } void CPauseScreen::PreDraw() { if (!IsLoaded()) return; if (std::unique_ptr& curScreen = x7c_screens[x78_activeIdx]) if (curScreen->CanDraw()) curScreen->Touch(); } void CPauseScreen::Draw() { if (!IsLoaded()) return; SCOPED_GRAPHICS_DEBUG_GROUP("CPauseScreen::Draw", zeus::skPurple); float totalAlpha = 0.f; float yOff = 0.f; std::unique_ptr& curScreen = x7c_screens[x78_activeIdx]; if (curScreen && curScreen->CanDraw()) { float useInterp = x10_alphaInterp == 0.f ? 1.f : x10_alphaInterp / 0.5f; float initInterp = std::min(curScreen->GetAlpha(), useInterp); if (xc_nextSubscreen == ESubScreen::ToGame) totalAlpha = useInterp; else if (x91_initialTransition) totalAlpha = initInterp; else totalAlpha = 1.f; curScreen->Draw(x8_curSubscreen != xc_nextSubscreen ? useInterp : 1.f, totalAlpha, 0.f); yOff = curScreen->GetCameraYBias(); } CGuiWidgetDrawParms parms(totalAlpha, zeus::CVector3f{0.f, 15.f * yOff, 0.f}); x34_loadedPauseScreenInstructions->Draw(parms); } bool CPauseScreen::ShouldSwitchToMapScreen() const { return IsLoaded() && x8_curSubscreen == ESubScreen::ToMap && xc_nextSubscreen == ESubScreen::ToMap; } bool CPauseScreen::ShouldSwitchToInGame() const { return IsLoaded() && x8_curSubscreen == ESubScreen::ToGame && xc_nextSubscreen == ESubScreen::ToGame; } float CPauseScreen::GetHelmetCamYOff() const { CPauseScreenBase* screen = x7c_screens[x78_activeIdx].get(); if (screen) return screen->GetCameraYBias(); return 0.f; } } // namespace metaforce::MP1