mirror of https://github.com/AxioDL/metaforce.git
361 lines
14 KiB
C++
361 lines
14 KiB
C++
#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<CPauseScreenBase> CPauseScreen::BuildPauseSubScreen(ESubScreen subscreen, const CStateManager& mgr,
|
|
CGuiFrame& frame) const {
|
|
switch (subscreen) {
|
|
case ESubScreen::LogBook:
|
|
return std::make_unique<CLogBookScreen>(mgr, frame, *x14_strgPauseScreen);
|
|
case ESubScreen::Options:
|
|
return std::make_unique<COptionsScreen>(mgr, frame, *x14_strgPauseScreen);
|
|
case ESubScreen::Inventory:
|
|
return std::make_unique<CInventoryScreen>(mgr, frame, *x14_strgPauseScreen, x20_suitDgrp, x24_ballDgrp);
|
|
default:
|
|
return {};
|
|
}
|
|
}
|
|
|
|
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());
|
|
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<CPauseScreenBase>& newScreenSlot = x7c_screens[1 - x78_activeIdx];
|
|
std::unique_ptr<CGuiFrame>& 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<CPauseScreenBase>& screenSlot = x7c_screens[x78_activeIdx])
|
|
if (screenSlot->InputDisabled())
|
|
return false;
|
|
|
|
if (const std::unique_ptr<CPauseScreenBase>& 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<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(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(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, 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<CPauseScreenBase>& 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<CPauseScreenBase>& curScreen = x7c_screens[x78_activeIdx];
|
|
std::unique_ptr<CPauseScreenBase>& 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<CPauseScreenBase>& 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<CPauseScreenBase>& 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<CPauseScreenBase>& 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
|