metaforce/Runtime/MP1/CMFGame.cpp

380 lines
13 KiB
C++
Raw Permalink Normal View History

#include "Runtime/MP1/CMFGame.hpp"
#include <array>
#include "Runtime/CArchitectureQueue.hpp"
#include "Runtime/MP1/CSamusHud.hpp"
#include "Runtime/MP1/MP1.hpp"
#include "Runtime/Audio/CMidiManager.hpp"
#include "Runtime/AutoMapper/CAutoMapper.hpp"
#include "Runtime/Camera/CCinematicCamera.hpp"
#include "Runtime/World/CPlayer.hpp"
#include "TCastTo.hpp" // Generated file, do not modify include path
2015-08-21 18:58:41 -07:00
2021-04-10 01:42:06 -07:00
namespace metaforce::MP1 {
2015-08-21 18:58:41 -07:00
CMFGame::CMFGame(const std::weak_ptr<CStateManager>& stateMgr, const std::weak_ptr<CInGameGuiManager>& guiMgr,
const CArchitectureQueue&)
2021-06-07 12:29:18 -07:00
: CMFGameBase("CMFGame"), x14_stateManager(stateMgr.lock()), x18_guiManager(guiMgr.lock()) {
2018-12-07 21:30:43 -08:00
static_cast<CMain&>(*g_Main).SetMFGameBuilt(true);
}
2018-12-07 21:30:43 -08:00
CMFGame::~CMFGame() {
auto& main = static_cast<CMain&>(*g_Main);
2018-12-07 21:30:43 -08:00
main.SetMFGameBuilt(false);
main.SetScreenFading(false);
CDecalManager::Reinitialize();
2018-03-16 20:41:01 -07:00
}
2018-12-07 21:30:43 -08:00
CIOWin::EMessageReturn CMFGame::OnMessage(const CArchitectureMessage& msg, CArchitectureQueue& queue) {
switch (msg.GetType()) {
case EArchMsgType::FrameBegin:
x14_stateManager->FrameBegin(msg.GetParm<CArchMsgParmInt32>()->x4_parm);
break;
case EArchMsgType::TimerTick: {
bool wasInitialized = x2a_24_initialized;
x2a_24_initialized = true;
float dt = MakeMsg::GetParmTimerTick(msg).x4_parm;
/* URDE addition: this is continuously updated for animated UVs even when game paused */
x14_stateManager->UpdateGraphicsTiming(dt);
switch (x1c_flowState) {
case EGameFlowState::CinematicSkip: {
x20_cineSkipTime += dt;
const CEntity* cam = x14_stateManager->GetCameraManager()->GetCurrentCamera(*x14_stateManager);
TCastToConstPtr<CCinematicCamera> cineCam = cam;
if ((x20_cineSkipTime >= 1.f && x14_stateManager->SpecialSkipCinematic()) || !cineCam ||
(cineCam->GetFlags() & 0x10 && x28_skippedCineCam != cineCam->GetUniqueId())) {
static_cast<CMain&>(*g_Main).SetScreenFading(false);
x1c_flowState = EGameFlowState::InGame;
x18_guiManager->StartFadeIn();
x28_skippedCineCam = kInvalidUniqueId;
2017-02-17 18:19:50 -08:00
break;
2018-12-07 21:30:43 -08:00
}
2019-02-17 21:47:46 -08:00
[[fallthrough]];
2017-02-17 18:19:50 -08:00
}
2018-12-07 21:30:43 -08:00
case EGameFlowState::InGame: {
x14_stateManager->SetActiveRandomToDefault();
switch (x14_stateManager->GetDeferredStateTransition()) {
case EStateManagerTransition::InGame:
x14_stateManager->Update(dt);
if (!x14_stateManager->ShouldQuitGame())
break;
// CGraphics::SetIsBeginSceneClearFb();
2017-02-17 18:19:50 -08:00
break;
2018-12-07 21:30:43 -08:00
case EStateManagerTransition::MapScreen:
EnterMapScreen();
2017-02-17 18:19:50 -08:00
break;
2018-12-07 21:30:43 -08:00
case EStateManagerTransition::PauseGame:
PauseGame();
2017-02-17 18:19:50 -08:00
break;
2018-12-07 21:30:43 -08:00
case EStateManagerTransition::LogBook:
EnterLogBook();
2017-02-17 18:19:50 -08:00
break;
2018-12-07 21:30:43 -08:00
case EStateManagerTransition::SaveGame:
SaveGame();
2017-02-17 18:19:50 -08:00
break;
2018-12-07 21:30:43 -08:00
case EStateManagerTransition::MessageScreen:
EnterMessageScreen(x14_stateManager->GetHUDMessageTime());
2017-02-17 18:19:50 -08:00
break;
2018-12-07 21:30:43 -08:00
}
if (x2a_25_samusAlive && !x14_stateManager->GetPlayerState()->IsPlayerAlive()) {
PlayerDied();
}
x14_stateManager->ClearActiveRandom();
break;
}
case EGameFlowState::Paused: {
if (x18_guiManager->WasInGame() && x18_guiManager->IsInGame()) {
x14_stateManager->SetInSaveUI(x18_guiManager->IsInSaveUI());
UnpauseGame();
if (x14_stateManager->GetPauseHUDMessage().IsValid())
x14_stateManager->IncrementHUDMessageFrameCounter();
}
break;
}
case EGameFlowState::SamusDied: {
if (x14_stateManager->GetPlayer().IsPlayerDeadEnough()) {
static_cast<CMain&>(*g_Main).SetFlowState(EClientFlowStates::LoseGame);
2018-12-07 21:30:43 -08:00
queue.Push(MakeMsg::CreateQuitGameplay(EArchMsgTarget::Game));
} else {
x14_stateManager->SetActiveRandomToDefault();
x14_stateManager->Update(dt);
x14_stateManager->ClearActiveRandom();
}
2019-02-17 21:47:46 -08:00
break;
2018-12-07 21:30:43 -08:00
}
default:
break;
2017-02-17 18:19:50 -08:00
}
2018-12-07 21:30:43 -08:00
x18_guiManager->Update(*x14_stateManager, dt, queue, IsCameraActiveFlow());
if (!wasInitialized)
g_GameState->GetWorldTransitionManager()->EndTransition();
2017-02-17 18:19:50 -08:00
2018-12-07 21:30:43 -08:00
return EMessageReturn::Exit;
}
case EArchMsgType::UserInput: {
2017-02-17 18:19:50 -08:00
if (!x2a_24_initialized)
2018-12-07 21:30:43 -08:00
break;
const CFinalInput& input = MakeMsg::GetParmUserInput(msg).x4_parm;
if (x1c_flowState == EGameFlowState::InGame) {
if (input.ControllerIdx() == 0) {
const CEntity* cam = x14_stateManager->GetCameraManager()->GetCurrentCamera(*x14_stateManager);
TCastToConstPtr<CCinematicCamera> cineCam = cam;
2022-07-29 13:16:55 -07:00
if (input.PStart() || input.PSpecialKey(ESpecialKey::Esc)) {
2018-12-07 21:30:43 -08:00
if (cineCam && x14_stateManager->GetSkipCinematicSpecialFunction() != kInvalidUniqueId) {
CMidiManager::StopAll();
x28_skippedCineCam = cineCam->GetUniqueId();
x1c_flowState = EGameFlowState::CinematicSkip;
x20_cineSkipTime = 0.f;
} else if (!cineCam) {
x14_stateManager->DeferStateTransition(EStateManagerTransition::PauseGame);
}
2022-07-29 13:16:55 -07:00
} else if ((input.PZ() || input.PSpecialKey(ESpecialKey::Tab)) && !cineCam &&
2022-03-22 10:54:58 -07:00
x14_stateManager->CanShowMapScreen()) {
2018-12-07 21:30:43 -08:00
x14_stateManager->DeferStateTransition(EStateManagerTransition::MapScreen);
}
}
2017-02-17 18:19:50 -08:00
2018-12-07 21:30:43 -08:00
x14_stateManager->SetActiveRandomToDefault();
x14_stateManager->ProcessInput(input);
x14_stateManager->ClearActiveRandom();
2017-02-17 18:19:50 -08:00
}
2018-12-07 21:30:43 -08:00
x18_guiManager->ProcessControllerInput(*x14_stateManager, input, queue);
break;
}
case EArchMsgType::FrameEnd: {
x14_stateManager->FrameEnd();
if (x14_stateManager->ShouldQuitGame())
queue.Push(MakeMsg::CreateQuitGameplay(EArchMsgTarget::Game));
break;
}
case EArchMsgType::QuitGameplay:
return EMessageReturn::RemoveIOWin;
default:
break;
}
return EMessageReturn::Normal;
2017-02-17 18:19:50 -08:00
}
2018-12-07 21:30:43 -08:00
void CMFGame::Touch() {
x14_stateManager->TouchSky();
x14_stateManager->TouchPlayerActor();
bool gunVisible = false;
bool ballVisible = false;
bool samusVisible = false;
CPlayer& player = x14_stateManager->GetPlayer();
switch (player.GetMorphballTransitionState()) {
case CPlayer::EPlayerMorphBallState::Unmorphed:
gunVisible = true;
break;
case CPlayer::EPlayerMorphBallState::Morphed:
ballVisible = true;
break;
case CPlayer::EPlayerMorphBallState::Morphing:
ballVisible = true;
samusVisible = true;
break;
case CPlayer::EPlayerMorphBallState::Unmorphing:
gunVisible = true;
samusVisible = true;
break;
}
if (gunVisible)
player.GetPlayerGun()->TouchModel(*x14_stateManager);
if (samusVisible)
player.GetModelData()->Touch(*x14_stateManager, 0);
2018-12-07 21:30:43 -08:00
if (ballVisible)
player.GetMorphBall()->TouchModel(*x14_stateManager);
2017-02-17 18:19:50 -08:00
}
void CMFGame::Draw() {
if (!x2a_24_initialized) {
2018-12-07 21:30:43 -08:00
return;
}
2019-07-21 01:42:52 -07:00
SCOPED_GRAPHICS_DEBUG_GROUP("CMFGame::Draw", zeus::skGreen);
2018-12-07 21:30:43 -08:00
Touch();
2018-12-07 21:30:43 -08:00
if (x18_guiManager->GetIsGameDraw()) {
static_cast<CMain&>(*g_Main).SetGameFrameDrawn();
x14_stateManager->PreRender();
x14_stateManager->DrawWorld();
x14_stateManager->GetPlayer().IsPlayerDeadEnough();
}
x18_guiManager->PreDraw(*x14_stateManager, IsCameraActiveFlow());
x18_guiManager->Draw(*x14_stateManager);
if (x1c_flowState == EGameFlowState::CinematicSkip) {
const float c = std::min(1.f, 1.f - x20_cineSkipTime);
CCameraFilterPass::DrawFilter(EFilterType::Multiply, EFilterShape::Fullscreen, zeus::CColor{c, c, c, c}, nullptr,
1.f);
2018-12-07 21:30:43 -08:00
}
2017-02-17 18:19:50 -08:00
}
2018-12-07 21:30:43 -08:00
void CMFGame::PlayerDied() {
x1c_flowState = EGameFlowState::SamusDied;
x2a_25_samusAlive = false;
2017-02-17 18:19:50 -08:00
}
2018-12-07 21:30:43 -08:00
void CMFGame::UnpauseGame() {
x1c_flowState = EGameFlowState::InGame;
CSfxManager::SetChannel(CSfxManager::ESfxChannels::Game);
x14_stateManager->DeferStateTransition(EStateManagerTransition::InGame);
2017-02-17 18:19:50 -08:00
}
2018-12-07 21:30:43 -08:00
void CMFGame::EnterMessageScreen(float time) {
x1c_flowState = EGameFlowState::Paused;
x18_guiManager->ShowPauseGameHudMessage(*x14_stateManager, x14_stateManager->GetPauseHUDMessage(), time);
2017-02-17 18:19:50 -08:00
}
2018-12-07 21:30:43 -08:00
void CMFGame::SaveGame() {
x1c_flowState = EGameFlowState::Paused;
x18_guiManager->PauseGame(*x14_stateManager, EInGameGuiState::PauseSaveGame);
2017-02-17 18:19:50 -08:00
}
2018-12-07 21:30:43 -08:00
void CMFGame::EnterLogBook() {
x1c_flowState = EGameFlowState::Paused;
x18_guiManager->PauseGame(*x14_stateManager, EInGameGuiState::PauseLogBook);
}
2018-12-07 21:30:43 -08:00
void CMFGame::PauseGame() {
x1c_flowState = EGameFlowState::Paused;
x18_guiManager->PauseGame(*x14_stateManager, EInGameGuiState::PauseGame);
2016-08-15 13:58:07 -07:00
}
2018-12-07 21:30:43 -08:00
void CMFGame::EnterMapScreen() {
x1c_flowState = EGameFlowState::Paused;
x18_guiManager->PauseGame(*x14_stateManager, EInGameGuiState::MapScreen);
x14_stateManager->SetInMapScreen(true);
2016-10-09 00:45:04 -07:00
}
CMFGameLoader::CMFGameLoader() : CMFGameLoaderBase("CMFGameLoader") {
2022-03-08 23:23:56 -08:00
CModel::DisableTextureTimeout();
auto* m = static_cast<CMain*>(g_Main);
2018-12-07 21:30:43 -08:00
switch (m->GetFlowState()) {
case EClientFlowStates::Default:
case EClientFlowStates::StateSetter: {
2018-12-07 21:30:43 -08:00
CAssetId mlvlId = g_GameState->CurrentWorldAssetId();
if (g_MemoryCardSys->HasSaveWorldMemory(mlvlId)) {
const CSaveWorldMemory& savwMem = g_MemoryCardSys->GetSaveWorldMemory(mlvlId);
if (savwMem.GetWorldNameId().IsValid()) {
2019-10-01 00:38:03 -07:00
g_GameState->GetWorldTransitionManager()->EnableTransition(0xB7BBD0B4, savwMem.GetWorldNameId(), 1, false, 0.1f,
2018-12-07 21:30:43 -08:00
16.f, 1.f);
}
}
2019-02-17 21:47:46 -08:00
break;
2018-12-07 21:30:43 -08:00
}
default:
break;
}
if (g_GameState->CurrentWorldAssetId() == 0x158EFE17u && g_GameState->CurrentWorldState().GetCurrentAreaId() == 0) {
2018-12-07 21:30:43 -08:00
const SObjectTag* strgTag = g_ResFactory->GetResourceIdByName("STRG_IntroLevelLoad");
if (strgTag)
g_GameState->GetWorldTransitionManager()->EnableTransition({}, strgTag->id, 0, false, 0.1f, 16.f, 1.f);
2018-12-07 21:30:43 -08:00
}
}
2017-02-11 19:17:18 -08:00
CMFGameLoader::~CMFGameLoader() = default;
2017-02-11 19:17:18 -08:00
2018-12-07 21:30:43 -08:00
void CMFGameLoader::MakeLoadDependencyList() {
static constexpr std::array loadDepPAKs{"TestAnim", "SamusGun", "SamGunFx"};
2018-12-07 21:30:43 -08:00
std::vector<SObjectTag> tags;
for (const auto* const pak : loadDepPAKs) {
g_ResFactory->GetTagListForFile(pak, tags);
}
2017-02-12 15:56:03 -08:00
2018-12-07 21:30:43 -08:00
x1c_loadList.reserve(tags.size());
for (const SObjectTag& tag : tags) {
2018-12-07 21:30:43 -08:00
x1c_loadList.push_back(g_SimplePool->GetObj(tag));
}
2018-12-07 21:30:43 -08:00
}
2017-02-12 15:56:03 -08:00
2018-12-07 21:30:43 -08:00
CIOWin::EMessageReturn CMFGameLoader::OnMessage(const CArchitectureMessage& msg, CArchitectureQueue& queue) {
std::shared_ptr<CWorldTransManager> wtMgr = g_GameState->GetWorldTransitionManager();
switch (msg.GetType()) {
case EArchMsgType::TimerTick: {
const CArchMsgParmReal32& tick = MakeMsg::GetParmTimerTick(msg);
float dt = tick.x4_parm;
if (!x2c_24_initialized) {
if (x1c_loadList.empty()) {
MakeLoadDependencyList();
wtMgr->StartTransition();
return EMessageReturn::Exit;
}
u32 loadingCount = 0;
for (CToken& tok : x1c_loadList) {
tok.Lock();
if (!tok.IsLoaded())
++loadingCount;
}
wtMgr->Update(dt);
if (loadingCount)
2017-02-12 15:56:03 -08:00
return EMessageReturn::Exit;
2018-12-07 21:30:43 -08:00
x2c_24_initialized = true;
} else {
wtMgr->Update(dt);
2017-02-12 15:56:03 -08:00
}
2018-12-07 21:30:43 -08:00
if (!x14_stateMgr) {
CWorldTransManager::WaitForModelsAndTextures();
CWorldState& wldState = g_GameState->CurrentWorldState();
x14_stateMgr = std::make_shared<CStateManager>(wldState.Mailbox(), wldState.MapWorldInfo(),
2018-12-07 21:30:43 -08:00
g_GameState->GetPlayerState(), wtMgr, wldState.GetLayerState());
2015-08-21 18:58:41 -07:00
}
2018-12-07 21:30:43 -08:00
if (x14_stateMgr->xb3c_initPhase != CStateManager::EInitPhase::Done) {
CWorldState& wldState = g_GameState->CurrentWorldState();
x14_stateMgr->InitializeState(wldState.GetWorldAssetId(), wldState.GetCurrentAreaId(),
wldState.GetDesiredAreaAssetId());
return EMessageReturn::Exit;
2015-08-21 18:58:41 -07:00
}
2018-12-07 21:30:43 -08:00
if (!x18_guiMgr) {
g_GameState->CurrentWorldState().SetDesiredAreaAssetId(CAssetId());
2018-12-07 21:30:43 -08:00
x18_guiMgr = std::make_shared<CInGameGuiManager>(*x14_stateMgr, queue);
}
2018-12-07 21:30:43 -08:00
if (!x18_guiMgr->CheckLoadComplete(*x14_stateMgr))
return EMessageReturn::Exit;
x1c_loadList.clear();
2022-03-22 10:54:58 -07:00
// if (!CGraphics::g_BooFactory->areShadersReady())
// return EMessageReturn::Exit;
2018-12-07 21:30:43 -08:00
wtMgr->StartTextFadeOut();
x2c_25_transitionFinished = wtMgr->IsTransitionFinished();
2015-11-20 17:16:07 -08:00
return EMessageReturn::Exit;
2018-12-07 21:30:43 -08:00
}
case EArchMsgType::FrameEnd: {
if (x2c_25_transitionFinished) {
queue.Push(MakeMsg::CreateCreateIOWin(EArchMsgTarget::IOWinManager, 10, 1000,
std::make_shared<CMFGame>(x14_stateMgr, x18_guiMgr, queue)));
2022-03-08 23:23:56 -08:00
CModel::EnableTextureTimeout();
2018-12-07 21:30:43 -08:00
return EMessageReturn::RemoveIOWinAndExit;
}
2019-02-17 21:47:46 -08:00
break;
2018-12-07 21:30:43 -08:00
}
default:
break;
}
return EMessageReturn::Exit;
2015-08-21 18:58:41 -07:00
}
void CMFGameLoader::Draw() {
2019-07-21 01:42:52 -07:00
SCOPED_GRAPHICS_DEBUG_GROUP("CMFGameLoader::Draw", zeus::skGreen);
g_GameState->GetWorldTransitionManager()->Draw();
}
2021-04-10 01:42:06 -07:00
} // namespace metaforce::MP1