#include "CFrontEndUI.hpp" #include "CArchitectureMessage.hpp" #include "CArchitectureQueue.hpp" #include "CDvdFile.hpp" #include "CSimplePool.hpp" #include "GameGlobalObjects.hpp" #include "MP1.hpp" #include "CSlideShow.hpp" #include "Audio/CSfxManager.hpp" #include "Graphics/CMoviePlayer.hpp" #include "CSaveUI.hpp" #include "GuiSys/CGuiTextPane.hpp" #include "GuiSys/CGuiFrame.hpp" #include "GuiSys/CStringTable.hpp" #include "GuiSys/CGuiTableGroup.hpp" #include "GuiSys/CGuiModel.hpp" #include "CGameState.hpp" #include "CDependencyGroup.hpp" #include "Audio/CAudioGroupSet.hpp" #include "GuiSys/CGuiWidgetDrawParms.hpp" #include "CNESEmulator.hpp" #include "CQuitScreen.hpp" namespace urde { namespace MP1 { /* Music volume constants */ #define FE1_VOL 0.7421875f #define FE2_VOL 0.7421875f /* L/R Stereo transition cues */ static const u16 FETransitionBackSFX[3][2] = { {1090, 1097}, {1098, 1099}, {1100, 1101} }; static const u16 FETransitionForwardSFX[3][2] = { {1102, 1103}, {1104, 1105}, {1106, 1107} }; struct FEMovie { const char* path; bool loop; }; static const FEMovie FEMovies[] = { {"Video/00_first_start.thp", false}, {"Video/01_startloop.thp", true}, {"Video/02_start_fileselect_A.thp", false}, {"Video/03_fileselectloop.thp", true}, {"Video/04_fileselect_playgame_A.thp", false}, {"Video/06_fileselect_GBA.thp", false}, {"Video/07_GBAloop.thp", true}, {"Video/08_GBA_fileselect.thp", false}, {"Video/08_GBA_fileselect.thp", false}, }; SObjectTag g_DefaultWorldTag = {FOURCC('MLVL'), 0x158efe17}; void CFrontEndUI::PlayAdvanceSfx() { CSfxManager::SfxStart(1096, 1.f, 0.f, false, 0x7f, false, kInvalidAreaId); CSfxManager::SfxStart(1091, 1.f, 0.f, false, 0x7f, false, kInvalidAreaId); } CFrontEndUI::SNewFileSelectFrame::SNewFileSelectFrame(CSaveUI* sui, u32 rnd) : x0_rnd(rnd), x4_saveUI(sui) { x10_frme = g_SimplePool->GetObj("FRME_NewFileSelect"); } void CFrontEndUI::SNewFileSelectFrame::FinishedLoading() { x20_tablegroup_fileselect = static_cast(x1c_loadedFrame->FindWidget("tablegroup_fileselect")); x24_model_erase = static_cast(x1c_loadedFrame->FindWidget("model_erase")); xf8_model_erase_position = x24_model_erase->GetLocalPosition(); x28_textpane_erase = FindTextPanePair(x1c_loadedFrame, "textpane_erase"); x38_textpane_gba = FindTextPanePair(x1c_loadedFrame, "textpane_gba"); x30_textpane_cheats = FindTextPanePair(x1c_loadedFrame, "textpane_cheats"); x48_textpane_popupadvance = FindTextPanePair(x1c_loadedFrame, "textpane_popupadvance"); x50_textpane_popupcancel = FindTextPanePair(x1c_loadedFrame, "textpane_popupcancel"); x58_textpane_popupextra = FindTextPanePair(x1c_loadedFrame, "textpane_popupextra"); x40_tablegroup_popup = static_cast(x1c_loadedFrame->FindWidget("tablegroup_popup")); x44_model_dash7 = static_cast(x1c_loadedFrame->FindWidget("model_dash7")); x60_textpane_cancel = static_cast(x1c_loadedFrame->FindWidget("textpane_cancel")); FindAndSetPairText(x1c_loadedFrame, "textpane_title", g_MainStringTable->GetString(97)); CGuiTextPane* proceed = static_cast(x1c_loadedFrame->FindWidget("textpane_proceed")); if (proceed) proceed->TextSupport()->SetText(g_MainStringTable->GetString(85)); x40_tablegroup_popup->SetIsVisible(false); x40_tablegroup_popup->SetIsActive(false); x40_tablegroup_popup->SetD1(false); CGuiWidget* worker = x40_tablegroup_popup->GetWorkerWidget(2); worker->SetB627(false); worker->SetVisibility(false, ETraversalMode::Children); x20_tablegroup_fileselect->SetMenuAdvanceCallback( std::bind(&SNewFileSelectFrame::DoFileMenuAdvance, this, std::placeholders::_1)); x20_tablegroup_fileselect->SetMenuSelectionChangeCallback( std::bind(&SNewFileSelectFrame::DoSelectionChange, this, std::placeholders::_1)); x20_tablegroup_fileselect->SetMenuCancelCallback( std::bind(&SNewFileSelectFrame::DoFileMenuCancel, this, std::placeholders::_1)); x40_tablegroup_popup->SetMenuAdvanceCallback( std::bind(&SNewFileSelectFrame::DoPopupAdvance, this, std::placeholders::_1)); x40_tablegroup_popup->SetMenuSelectionChangeCallback( std::bind(&SNewFileSelectFrame::DoSelectionChange, this, std::placeholders::_1)); x40_tablegroup_popup->SetMenuCancelCallback( std::bind(&SNewFileSelectFrame::DoPopupCancel, this, std::placeholders::_1)); for (int i=0 ; i<3 ; ++i) x64_fileSelections[i] = FindFileSelectOption(x1c_loadedFrame, i); x104_rowPitch = (x64_fileSelections[1].x0_base->GetLocalPosition() - x64_fileSelections[0].x0_base->GetLocalPosition()).z; } bool CFrontEndUI::SNewFileSelectFrame::PumpLoad() { if (x1c_loadedFrame) return true; if (x10_frme.IsLoaded()) { if (x10_frme->GetIsFinishedLoading()) { x1c_loadedFrame = x10_frme.GetObj(); FinishedLoading(); return true; } } return false; } bool CFrontEndUI::SNewFileSelectFrame::IsTextDoneAnimating() const { if (x64_fileSelections[0].x28_ != 4) return false; if (x64_fileSelections[1].x28_ != 4) return false; if (x64_fileSelections[2].x28_ != 4) return false; if (!x28_textpane_erase.x0_panes[0]->GetTextSupport()->IsAnimationDone()) return false; return x38_textpane_gba.x0_panes[0]->GetTextSupport()->IsAnimationDone(); } CFrontEndUI::SNewFileSelectFrame::EAction CFrontEndUI::SNewFileSelectFrame::ProcessUserInput(const CFinalInput& input) { if (x8_subMenu != ESubMenu::Two) x4_saveUI->ProcessUserInput(input); if (IsTextDoneAnimating()) x108_curTime = std::min(0.5f, x108_curTime + input.DeltaTime()); if (x108_curTime < 0.5f) return xc_action; if (x10c_inputEnable) x1c_loadedFrame->ProcessUserInput(input); if (x10d_needsExistingToggle) { if (x40_tablegroup_popup->GetIsActive()) DeactivateExistingGamePopup(); else ActivateExistingGamePopup(); x10d_needsExistingToggle = false; } if (x10e_needsNewToggle) { if (x40_tablegroup_popup->GetIsActive()) DeactivateNewGamePopup(); else ActivateNewGamePopup(); x10e_needsNewToggle = false; } return xc_action; } void CFrontEndUI::SNewFileSelectFrame::Draw() const { if (x1c_loadedFrame && x10c_inputEnable) x1c_loadedFrame->Draw(CGuiWidgetDrawParms::Default); } void CFrontEndUI::SNewFileSelectFrame::HandleActiveChange(CGuiTableGroup* active) { if (!active) return; active->SetColors(zeus::CColor::skWhite, zeus::CColor{0.627450f, 0.627450f, 0.627450f, 0.784313f}); if (active == x20_tablegroup_fileselect) x24_model_erase->SetLocalTransform(zeus::CTransform::Translate( zeus::CVector3f{0.f, 0.f, active->GetUserSelection() * x104_rowPitch} + xf8_model_erase_position)); if (x8_subMenu == ESubMenu::Zero || x8_subMenu == ESubMenu::Three) x24_model_erase->SetIsVisible(false); else x24_model_erase->SetIsVisible(true); } void CFrontEndUI::SNewFileSelectFrame::DeactivateExistingGamePopup() { x40_tablegroup_popup->SetIsActive(false); x40_tablegroup_popup->SetIsVisible(false); x20_tablegroup_fileselect->SetIsActive(true); HandleActiveChange(x20_tablegroup_fileselect); x64_fileSelections[x20_tablegroup_fileselect->GetUserSelection()]. x0_base->SetColor(zeus::CColor::skWhite); } void CFrontEndUI::SNewFileSelectFrame::ActivateExistingGamePopup() { x40_tablegroup_popup->SetIsActive(true); x40_tablegroup_popup->SetIsVisible(true); x40_tablegroup_popup->SetLocalTransform( zeus::CTransform::Translate(0.f, 0.f, x20_tablegroup_fileselect->GetUserSelection() * x104_rowPitch) * x40_tablegroup_popup->GetTransform()); x20_tablegroup_fileselect->SetIsActive(false); x8_subMenu = ESubMenu::Two; HandleActiveChange(x40_tablegroup_popup); x48_textpane_popupadvance.SetPairText(g_MainStringTable->GetString(95)); x50_textpane_popupcancel.SetPairText(g_MainStringTable->GetString(38)); x64_fileSelections[x20_tablegroup_fileselect->GetUserSelection()]. x0_base->SetColor(zeus::CColor{1.f, 1.f, 1.f, 0.f}); x44_model_dash7->SetVisibility(false, ETraversalMode::Children); } void CFrontEndUI::SNewFileSelectFrame::DeactivateNewGamePopup() { x40_tablegroup_popup->SetIsActive(false); x40_tablegroup_popup->SetIsVisible(false); x20_tablegroup_fileselect->SetIsActive(true); CGuiWidget* worker = x40_tablegroup_popup->GetWorkerWidget(2); worker->SetB627(false); worker->SetVisibility(false, ETraversalMode::Children); x44_model_dash7->SetVisibility(false, ETraversalMode::Children); HandleActiveChange(x20_tablegroup_fileselect); x64_fileSelections[x20_tablegroup_fileselect->GetUserSelection()]. x0_base->SetColor(zeus::CColor::skWhite); x60_textpane_cancel->TextSupport()->SetText(""); } void CFrontEndUI::SNewFileSelectFrame::ActivateNewGamePopup() { x40_tablegroup_popup->SetIsActive(true); x40_tablegroup_popup->SetIsVisible(true); x40_tablegroup_popup->SetUserSelection(0); x40_tablegroup_popup->SetLocalTransform( zeus::CTransform::Translate(0.f, 0.f, x20_tablegroup_fileselect->GetUserSelection() * x104_rowPitch) * x40_tablegroup_popup->GetTransform()); x20_tablegroup_fileselect->SetIsActive(false); x8_subMenu = ESubMenu::Three; HandleActiveChange(x40_tablegroup_popup); x64_fileSelections[x20_tablegroup_fileselect->GetUserSelection()]. x0_base->SetColor(zeus::CColor{1.f, 1.f, 1.f, 0.f}); PlayAdvanceSfx(); if (g_GameState->SystemOptions().GetPlayerBeatNormalMode()) { x48_textpane_popupadvance.SetPairText(g_MainStringTable->GetString(102)); x50_textpane_popupcancel.SetPairText(g_MainStringTable->GetString(94)); x58_textpane_popupextra.SetPairText(g_MainStringTable->GetString(101)); CGuiWidget* worker = x40_tablegroup_popup->GetWorkerWidget(2); worker->SetB627(true); worker->SetVisibility(true, ETraversalMode::Children); x44_model_dash7->SetVisibility(true, ETraversalMode::Children); } else { x48_textpane_popupadvance.SetPairText(g_MainStringTable->GetString(67)); x50_textpane_popupcancel.SetPairText(g_MainStringTable->GetString(94)); x44_model_dash7->SetVisibility(false, ETraversalMode::Children); } x60_textpane_cancel->TextSupport()->SetText(g_MainStringTable->GetString(82)); } void CFrontEndUI::SNewFileSelectFrame::ResetFrame() { x8_subMenu = ESubMenu::Zero; x38_textpane_gba.x0_panes[0]->SetB627(true); x38_textpane_gba.x0_panes[0]->TextSupport()->SetFontColor(zeus::CColor::skWhite); x30_textpane_cheats.x0_panes[0]->SetB627(true); x30_textpane_cheats.x0_panes[0]->TextSupport()->SetFontColor(zeus::CColor::skWhite); ClearFrameContents(); for (int i=2 ; i>=0 ; --i) x20_tablegroup_fileselect->GetWorkerWidget(i)->SetB627(true); x60_textpane_cancel->TextSupport()->SetText(""); } void CFrontEndUI::SNewFileSelectFrame::ClearFrameContents() { x108_curTime = 0.f; bool hasSave = false; for (int i=0 ; i<3 ; ++i) { if (x4_saveUI->GetGameData(i)) hasSave = true; SFileMenuOption& option = x64_fileSelections[i]; option.x2c_ = SFileMenuOption::ComputeRandom(); option.x28_ = -1; for (int j=0 ; j<4 ; ++j) option.x4_textpanes[j].SetPairText(L""); } StartTextAnimating(x28_textpane_erase.x0_panes[0], g_MainStringTable->GetString(38), 60.f); StartTextAnimating(x38_textpane_gba.x0_panes[0], g_MainStringTable->GetString(37), 60.f); StartTextAnimating(x30_textpane_cheats.x0_panes[0], g_MainStringTable->GetString(96), 60.f); StartTextAnimating(x28_textpane_erase.x0_panes[1], g_MainStringTable->GetString(38), 60.f); StartTextAnimating(x38_textpane_gba.x0_panes[1], g_MainStringTable->GetString(37), 60.f); StartTextAnimating(x30_textpane_cheats.x0_panes[1], g_MainStringTable->GetString(96), 60.f); if (hasSave) { x28_textpane_erase.x0_panes[0]->SetB627(true); x28_textpane_erase.x0_panes[0]->TextSupport()->SetFontColor(zeus::CColor::skWhite); } else { x28_textpane_erase.x0_panes[0]->SetB627(false); zeus::CColor color = zeus::CColor::skGrey; color.a = 0.5f; x28_textpane_erase.x0_panes[0]->TextSupport()->SetFontColor(color); } x20_tablegroup_fileselect->SetUserSelection(0); CGuiTextPane* cheats = static_cast(x20_tablegroup_fileselect->GetWorkerWidget(5)); if (CSlideShow::SlideShowGalleryFlags()) { cheats->SetB627(true); x30_textpane_cheats.x0_panes[0]->TextSupport()->SetFontColor(zeus::CColor::skWhite); } else { cheats->SetB627(false); zeus::CColor color = zeus::CColor::skGrey; color.a = 0.5f; x30_textpane_cheats.x0_panes[0]->TextSupport()->SetFontColor(color); } HandleActiveChange(x20_tablegroup_fileselect); } void CFrontEndUI::SNewFileSelectFrame::SetupFrameContents() { for (int i=0 ; i<3 ; ++i) { SFileMenuOption& option = x64_fileSelections[i]; if (option.x28_ == 4) continue; SGuiTextPair* pair = (option.x28_ == -1) ? nullptr : &option.x4_textpanes[option.x28_]; if (pair) { //pair->x0_panes[0]->GetTextSupport()->GetNumCharsPrinted() } } } void CFrontEndUI::SNewFileSelectFrame::DoPopupCancel(CGuiTableGroup* caller) { if (x8_subMenu == ESubMenu::Two) { CSfxManager::SfxStart(1094, 1.f, 0.f, false, 0x7f, false, kInvalidAreaId); x8_subMenu = ESubMenu::One; x10d_needsExistingToggle = true; } else { CSfxManager::SfxStart(1094, 1.f, 0.f, false, 0x7f, false, kInvalidAreaId); x8_subMenu = ESubMenu::Zero; x10e_needsNewToggle = true; } } void CFrontEndUI::SNewFileSelectFrame::DoPopupAdvance(CGuiTableGroup* caller) { if (x8_subMenu == ESubMenu::Two) { if (x40_tablegroup_popup->GetUserSelection() == 1) { x4_saveUI->EraseGame(x20_tablegroup_fileselect->GetUserSelection()); ResetFrame(); } else x8_subMenu = ESubMenu::One; x10d_needsExistingToggle = true; } else { if (g_GameState->SystemOptions().GetPlayerBeatNormalMode()) { if (x40_tablegroup_popup->GetUserSelection() == 1) { PlayAdvanceSfx(); xc_action = EAction::One; return; } g_GameState->SetHardMode(x20_tablegroup_fileselect->GetUserSelection()); x4_saveUI->StartGame(x40_tablegroup_popup->GetUserSelection()); } else { if (x40_tablegroup_popup->GetUserSelection() == 1) { PlayAdvanceSfx(); xc_action = EAction::One; return; } x4_saveUI->StartGame(x40_tablegroup_popup->GetUserSelection()); } } } void CFrontEndUI::SNewFileSelectFrame::DoFileMenuCancel(CGuiTableGroup* caller) { if (x8_subMenu == ESubMenu::One) { CSfxManager::SfxStart(1094, 1.f, 0.f, false, 0x7f, false, kInvalidAreaId); ResetFrame(); } } void CFrontEndUI::SNewFileSelectFrame::DoSelectionChange(CGuiTableGroup* caller) { HandleActiveChange(caller); CSfxManager::SfxStart(1093, 1.f, 0.f, false, 0x7f, false, kInvalidAreaId); } void CFrontEndUI::SNewFileSelectFrame::DoFileMenuAdvance(CGuiTableGroup* caller) { } CFrontEndUI::SFileMenuOption CFrontEndUI::SNewFileSelectFrame::FindFileSelectOption(CGuiFrame* frame, int idx) { SFileMenuOption ret; ret.x0_base = frame->FindWidget(hecl::Format("basewidget_file%d", idx).c_str()); ret.x4_textpanes[0] = FindTextPanePair(frame, hecl::Format("textpane_filename%d", idx).c_str()); ret.x4_textpanes[1] = FindTextPanePair(frame, hecl::Format("textpane_world%d", idx).c_str()); ret.x4_textpanes[2] = FindTextPanePair(frame, hecl::Format("textpane_playtime%d", idx).c_str()); ret.x4_textpanes[3] = FindTextPanePair(frame, hecl::Format("textpane_date%d", idx).c_str()); return ret; } void CFrontEndUI::SNewFileSelectFrame::StartTextAnimating(CGuiTextPane* text, const std::wstring& str, float chRate) { text->TextSupport()->SetText(str); text->TextSupport()->SetTypeWriteEffectOptions(true, 0.1f, chRate); } CFrontEndUI::SGBASupportFrame::SGBASupportFrame() { x4_gbaSupport = std::make_unique(); xc_gbaScreen = g_SimplePool->GetObj("FRME_GBAScreen"); x18_gbaLink = g_SimplePool->GetObj("FRME_GBALink"); } void CFrontEndUI::SGBASupportFrame::SGBALinkFrame::SetUIText(EUIType tp) { int instructions = -1; int yes = -1; int no = -1; bool cableVisible = false; bool circleGcVisible = false; bool circleGbaVisible = false; bool circleStartVisible = false; bool pakoutVisible = false; bool gbaScreenVisible = false; bool connectVisible = false; switch (tp) { case EUIType::InsertPak: instructions = 73; // Insert Game Pak no = 82; yes = 83; pakoutVisible = true; circleGbaVisible = true; break; case EUIType::ConnectSocket: instructions = 68; // Connect socket no = 82; yes = 83; cableVisible = true; circleGcVisible = true; circleGbaVisible = true; break; case EUIType::PressStartAndSelect: instructions = 74; // Hold start and select no = 82; yes = 83; cableVisible = true; circleStartVisible = true; gbaScreenVisible = true; break; case EUIType::BeginLink: instructions = 75; // Begin link? no = 82; yes = 83; cableVisible = true; gbaScreenVisible = true; break; case EUIType::TurnOffGBA: instructions = 76; // Turn off GBA no = 82; yes = 83; cableVisible = true; gbaScreenVisible = true; circleStartVisible = true; break; case EUIType::Linking: x4_gbaSupport->StartLink(); instructions = 72; // Linking cableVisible = true; gbaScreenVisible = true; connectVisible = true; break; case EUIType::LinkFailed: instructions = 69; // Link failed no = 82; yes = 83; cableVisible = true; circleGcVisible = true; circleGbaVisible = true; circleStartVisible = true; gbaScreenVisible = true; break; case EUIType::LinkCompleteOrLinking: yes = 83; instructions = x40_linkInProgress + 71; // Complete or linking cableVisible = true; gbaScreenVisible = true; break; case EUIType::Complete: case EUIType::Cancelled: default: break; } std::wstring instructionsStr; if (instructions != -1) instructionsStr = g_MainStringTable->GetString(instructions); xc_textpane_instructions.SetPairText(instructionsStr); std::wstring yesStr; if (yes != -1) yesStr = g_MainStringTable->GetString(yes); x14_textpane_yes->TextSupport()->SetText(yesStr); std::wstring noStr; if (no != -1) noStr = g_MainStringTable->GetString(no); x18_textpane_no->TextSupport()->SetText(noStr); x1c_model_gc->SetVisibility(true, ETraversalMode::Children); x20_model_gba->SetVisibility(true, ETraversalMode::Children); x24_model_cable->SetVisibility(cableVisible, ETraversalMode::Children); x28_model_circlegcport->SetVisibility(circleGcVisible, ETraversalMode::Children); x2c_model_circlegbaport->SetVisibility(circleGbaVisible, ETraversalMode::Children); x30_model_circlestartselect->SetVisibility(circleStartVisible, ETraversalMode::Children); x34_model_pakout->SetVisibility(pakoutVisible, ETraversalMode::Children); x38_model_gbascreen->SetVisibility(gbaScreenVisible, ETraversalMode::Children); x3c_model_connect->SetVisibility(connectVisible, ETraversalMode::Children); x0_uiType = tp; } static const CFrontEndUI::SGBASupportFrame::SGBALinkFrame::EUIType NextLinkUI[] = { CFrontEndUI::SGBASupportFrame::SGBALinkFrame::EUIType::ConnectSocket, CFrontEndUI::SGBASupportFrame::SGBALinkFrame::EUIType::PressStartAndSelect, CFrontEndUI::SGBASupportFrame::SGBALinkFrame::EUIType::BeginLink, CFrontEndUI::SGBASupportFrame::SGBALinkFrame::EUIType::Linking, CFrontEndUI::SGBASupportFrame::SGBALinkFrame::EUIType::Empty, CFrontEndUI::SGBASupportFrame::SGBALinkFrame::EUIType::TurnOffGBA, CFrontEndUI::SGBASupportFrame::SGBALinkFrame::EUIType::Complete, CFrontEndUI::SGBASupportFrame::SGBALinkFrame::EUIType::InsertPak, CFrontEndUI::SGBASupportFrame::SGBALinkFrame::EUIType::Empty, CFrontEndUI::SGBASupportFrame::SGBALinkFrame::EUIType::Empty }; static const CFrontEndUI::SGBASupportFrame::SGBALinkFrame::EUIType PrevLinkUI[] = { CFrontEndUI::SGBASupportFrame::SGBALinkFrame::EUIType::Cancelled, CFrontEndUI::SGBASupportFrame::SGBALinkFrame::EUIType::Cancelled, CFrontEndUI::SGBASupportFrame::SGBALinkFrame::EUIType::Cancelled, CFrontEndUI::SGBASupportFrame::SGBALinkFrame::EUIType::Cancelled, CFrontEndUI::SGBASupportFrame::SGBALinkFrame::EUIType::Empty, CFrontEndUI::SGBASupportFrame::SGBALinkFrame::EUIType::Cancelled, CFrontEndUI::SGBASupportFrame::SGBALinkFrame::EUIType::Empty, CFrontEndUI::SGBASupportFrame::SGBALinkFrame::EUIType::Cancelled, CFrontEndUI::SGBASupportFrame::SGBALinkFrame::EUIType::Empty, CFrontEndUI::SGBASupportFrame::SGBALinkFrame::EUIType::Empty }; CFrontEndUI::SGBASupportFrame::SGBALinkFrame::EAction CFrontEndUI::SGBASupportFrame::SGBALinkFrame::ProcessUserInput(const CFinalInput &input, bool linkInProgress) { if (linkInProgress != x40_linkInProgress) { x40_linkInProgress = linkInProgress; SetUIText(x0_uiType); } switch (x0_uiType) { case EUIType::InsertPak: case EUIType::ConnectSocket: case EUIType::PressStartAndSelect: case EUIType::BeginLink: case EUIType::LinkFailed: case EUIType::LinkCompleteOrLinking: case EUIType::TurnOffGBA: if (input.PA()) { PlayAdvanceSfx(); SetUIText(NextLinkUI[int(x0_uiType)]); } else if (input.PB()) { EUIType prevUi = PrevLinkUI[int(x0_uiType)]; if (prevUi == EUIType::Empty) break; CSfxManager::SfxStart(1094, 1.f, 0.f, false, 0x7f, false, kInvalidAreaId); SetUIText(prevUi); } break; case EUIType::Linking: if (x4_gbaSupport->GetPhase() == CGBASupport::EPhase::Complete) { if (x4_gbaSupport->IsFusionLinked()) g_GameState->SystemOptions().SetPlayerLinkedFusion(true); if (x4_gbaSupport->IsFusionBeat()) g_GameState->SystemOptions().SetPlayerBeatFusion(true); if (x4_gbaSupport->IsFusionLinked()) { PlayAdvanceSfx(); SetUIText(EUIType::LinkCompleteOrLinking); } else { CSfxManager::SfxStart(1094, 1.f, 0.f, false, 0x7f, false, kInvalidAreaId); SetUIText(EUIType::LinkFailed); } } break; case EUIType::Complete: return EAction::Complete; case EUIType::Cancelled: return EAction::Cancelled; default: break; } return EAction::None; } void CFrontEndUI::SGBASupportFrame::SGBALinkFrame::Update(float dt) { x4_gbaSupport->Update(dt); x8_frme->Update(dt); } void CFrontEndUI::SGBASupportFrame::SGBALinkFrame::FinishedLoading() { xc_textpane_instructions = FindTextPanePair(x8_frme, "textpane_instructions"); x14_textpane_yes = static_cast(x8_frme->FindWidget("textpane_yes")); x18_textpane_no = static_cast(x8_frme->FindWidget("textpane_no")); x1c_model_gc = static_cast(x8_frme->FindWidget("model_gc")); x20_model_gba = static_cast(x8_frme->FindWidget("model_gba")); x24_model_cable = static_cast(x8_frme->FindWidget("model_cable")); x28_model_circlegcport = static_cast(x8_frme->FindWidget("model_circlegcport")); x2c_model_circlegbaport = static_cast(x8_frme->FindWidget("model_circlegbaport")); x30_model_circlestartselect = static_cast(x8_frme->FindWidget("model_circlestartselect")); x34_model_pakout = static_cast(x8_frme->FindWidget("model_pakout")); x38_model_gbascreen = static_cast(x8_frme->FindWidget("model_gbascreen")); x3c_model_connect = static_cast(x8_frme->FindWidget("model_connect")); SetUIText(EUIType::InsertPak); } void CFrontEndUI::SGBASupportFrame::SGBALinkFrame::Draw() { x8_frme->Draw(CGuiWidgetDrawParms::Default); } CFrontEndUI::SGBASupportFrame::SGBALinkFrame::SGBALinkFrame(CGuiFrame* linkFrame, CGBASupport* support, bool linkInProgress) : x4_gbaSupport(support), x8_frme(linkFrame), x40_linkInProgress(linkInProgress) { support->InitializeSupport(); FinishedLoading(); } void CFrontEndUI::SGBASupportFrame::FinishedLoading() { x28_tablegroup_options = static_cast(x24_loadedFrame->FindWidget("tablegroup_options")); x2c_tablegroup_fusionsuit = static_cast(x24_loadedFrame->FindWidget("tablegroup_fusionsuit")); x30_textpane_instructions = FindTextPanePair(x24_loadedFrame, "textpane_instructions"); FindAndSetPairText(x24_loadedFrame, "textpane_nes", g_MainStringTable->GetString(66)); FindAndSetPairText(x24_loadedFrame, "textpane_fusionsuit", g_MainStringTable->GetString(63)); FindAndSetPairText(x24_loadedFrame, "textpane_fusionsuitno", g_MainStringTable->GetString(65)); FindAndSetPairText(x24_loadedFrame, "textpane_fusionsuityes", g_MainStringTable->GetString(64)); FindAndSetPairText(x24_loadedFrame, "textpane_title", g_MainStringTable->GetString(100)); static_cast(x24_loadedFrame->FindWidget("textpane_proceed"))-> TextSupport()->SetText(g_MainStringTable->GetString(85)); static_cast(x24_loadedFrame->FindWidget("textpane_cancel"))-> TextSupport()->SetText(g_MainStringTable->GetString(82)); x2c_tablegroup_fusionsuit->SetIsActive(false); x2c_tablegroup_fusionsuit->SetIsVisible(false); x2c_tablegroup_fusionsuit->SetD1(false); x2c_tablegroup_fusionsuit->SetUserSelection(g_GameState->SystemOptions().GetPlayerFusionSuitActive()); SetTableColors(x28_tablegroup_options); SetTableColors(x2c_tablegroup_fusionsuit); x28_tablegroup_options->SetMenuAdvanceCallback( std::bind(&SGBASupportFrame::DoAdvance, this, std::placeholders::_1)); x28_tablegroup_options->SetMenuSelectionChangeCallback( std::bind(&SGBASupportFrame::DoSelectionChange, this, std::placeholders::_1)); x28_tablegroup_options->SetMenuCancelCallback( std::bind(&SGBASupportFrame::DoCancel, this, std::placeholders::_1)); x2c_tablegroup_fusionsuit->SetMenuSelectionChangeCallback( std::bind(&SGBASupportFrame::DoSelectionChange, this, std::placeholders::_1)); } bool CFrontEndUI::SGBASupportFrame::PumpLoad() { if (x24_loadedFrame) return true; if (!xc_gbaScreen.IsLoaded()) return false; if (!x18_gbaLink.IsLoaded()) return false; if (!x4_gbaSupport->IsReady()) return false; if (!xc_gbaScreen->GetIsFinishedLoading()) return false; x24_loadedFrame = xc_gbaScreen.GetObj(); FinishedLoading(); return true; } void CFrontEndUI::SGBASupportFrame::SetTableColors(CGuiTableGroup* tbgp) const { tbgp->SetColors(zeus::CColor::skWhite, zeus::CColor{0.627450f, 0.627450f, 0.627450f, 0.784313f}); } void CFrontEndUI::SGBASupportFrame::Update(float dt, CSaveUI* saveUI) { bool doUpdate = false; if (saveUI) if (saveUI->GetUIType() == CSaveUI::EUIType::SaveProgress) doUpdate = true; if (doUpdate != x38_lastDoUpdate) { x38_lastDoUpdate = doUpdate; ResetCompletionFlags(); } if (x0_gbaLinkFrame) x0_gbaLinkFrame->Update(dt); else if (x24_loadedFrame) x24_loadedFrame->Update(dt); bool showFusionSuit = g_GameState->SystemOptions().GetPlayerLinkedFusion() && g_GameState->SystemOptions().GetPlayerBeatNormalMode(); bool showFusionSuitProceed = showFusionSuit && x28_tablegroup_options->GetUserSelection() == 1; x2c_tablegroup_fusionsuit->SetIsActive(showFusionSuitProceed); x2c_tablegroup_fusionsuit->SetIsVisible(showFusionSuitProceed); x24_loadedFrame->FindWidget("textpane_proceed")->SetIsVisible(showFusionSuitProceed); std::wstring instructionStr; if (x28_tablegroup_options->GetUserSelection() == 1) { /* Fusion Suit */ if (x3a_mpNotComplete) instructionStr = g_MainStringTable->GetString(80); // MP not complete else if (!showFusionSuit) instructionStr = g_MainStringTable->GetString(78); // To enable fusion suit } else { /* NES Metroid */ if (x39_fusionNotComplete) instructionStr = g_MainStringTable->GetString(79); // You have not completed fusion else if (!g_GameState->SystemOptions().GetPlayerBeatFusion()) instructionStr = g_MainStringTable->GetString(77); // To play NES Metroid } x30_textpane_instructions.SetPairText(instructionStr); } CFrontEndUI::SGBASupportFrame::EAction CFrontEndUI::SGBASupportFrame::ProcessUserInput(const CFinalInput& input, CSaveUI* sui) { x8_action = EAction::None; if (sui) sui->ProcessUserInput(input); if (x38_lastDoUpdate) { if (x0_gbaLinkFrame) { SGBALinkFrame::EAction action = x0_gbaLinkFrame->ProcessUserInput(input, sui); if (action != SGBALinkFrame::EAction::None) { x0_gbaLinkFrame.reset(); if (action == SGBALinkFrame::EAction::Complete) { if (x28_tablegroup_options->GetUserSelection() == 0 && !g_GameState->SystemOptions().GetPlayerBeatFusion()) x39_fusionNotComplete = true; else if (sui) sui->SaveNESState(); else if (x24_loadedFrame) x24_loadedFrame->ProcessUserInput(input); } } } } return x8_action; } void CFrontEndUI::SGBASupportFrame::Draw() const { if (!x38_lastDoUpdate) return; if (x0_gbaLinkFrame) x0_gbaLinkFrame->Draw(); else if (x24_loadedFrame) x24_loadedFrame->Draw(CGuiWidgetDrawParms::Default); } void CFrontEndUI::SGBASupportFrame::DoCancel(CGuiTableGroup* caller) { if (x39_fusionNotComplete || x3a_mpNotComplete) { CSfxManager::SfxStart(1094, 1.f, 0.f, false, 0x7f, false, kInvalidAreaId); } else { x8_action = EAction::GoBack; x28_tablegroup_options->SetUserSelection(0); x2c_tablegroup_fusionsuit->SetIsActive(false); x30_textpane_instructions.SetPairText(L""); SetTableColors(x28_tablegroup_options); } } void CFrontEndUI::SGBASupportFrame::DoSelectionChange(CGuiTableGroup* caller) { if (caller == x28_tablegroup_options) { CSfxManager::SfxStart(1093, 1.f, 0.f, false, 0x7f, false, kInvalidAreaId); x3a_mpNotComplete = false; x39_fusionNotComplete = false; } else { CSfxManager::SfxStart(1095, 1.f, 0.f, false, 0x7f, false, kInvalidAreaId); bool fusionActive = x2c_tablegroup_fusionsuit->GetUserSelection() == 1; g_GameState->SystemOptions().SetPlayerFusionSuitActive(fusionActive); g_GameState->GetPlayerState()->SetIsFusionEnabled(fusionActive); } SetTableColors(caller); } void CFrontEndUI::SGBASupportFrame::DoAdvance(CGuiTableGroup* caller) { switch (x28_tablegroup_options->GetUserSelection()) { case 1: /* Fusion Suit */ if (x3a_mpNotComplete) { x3a_mpNotComplete = false; PlayAdvanceSfx(); } else if (g_GameState->SystemOptions().GetPlayerBeatNormalMode()) { if (g_GameState->SystemOptions().GetPlayerLinkedFusion()) return; x0_gbaLinkFrame = std::make_unique(x18_gbaLink.GetObj(), x4_gbaSupport.get(), false); PlayAdvanceSfx(); } else { x3a_mpNotComplete = true; CSfxManager::SfxStart(1094, 1.f, 0.f, false, 0x7f, false, kInvalidAreaId); } break; case 0: /* NES Metroid */ if (x39_fusionNotComplete) { x39_fusionNotComplete = false; PlayAdvanceSfx(); } else if (g_GameState->SystemOptions().GetPlayerBeatFusion()) { x8_action = EAction::PlayNESMetroid; } else { x0_gbaLinkFrame = std::make_unique(x18_gbaLink.GetObj(), x4_gbaSupport.get(), false); PlayAdvanceSfx(); } break; default: break; } } void CFrontEndUI::SGuiTextPair::SetPairText(const std::wstring& str) { x0_panes[0]->TextSupport()->SetText(str); x0_panes[1]->TextSupport()->SetText(str); } CFrontEndUI::SGuiTextPair CFrontEndUI::FindTextPanePair(CGuiFrame* frame, const char* name) { SGuiTextPair ret; ret.x0_panes[0] = static_cast(frame->FindWidget(name)); ret.x0_panes[1] = static_cast(frame->FindWidget(hecl::Format("%sb", name).c_str())); return ret; } void CFrontEndUI::FindAndSetPairText(CGuiFrame* frame, const char* name, const std::wstring& str) { CGuiTextPane* w1 = static_cast(frame->FindWidget(name)); w1->TextSupport()->SetText(str); CGuiTextPane* w2 = static_cast(frame->FindWidget(hecl::Format("%sb", name).c_str())); w2->TextSupport()->SetText(str); } void CFrontEndUI::SFrontEndFrame::FinishedLoading() { x18_tablegroup_mainmenu = static_cast(x14_loadedFrme->FindWidget("tablegroup_mainmenu")); x1c_gbaPair = FindTextPanePair(x14_loadedFrme, "textpane_gba"); x1c_gbaPair.SetPairText(g_MainStringTable->GetString(37)); x24_cheatPair = FindTextPanePair(x14_loadedFrme, "textpane_cheats"); x24_cheatPair.SetPairText(g_MainStringTable->GetString(96)); FindAndSetPairText(x14_loadedFrme, "textpane_start", g_MainStringTable->GetString(67)); FindAndSetPairText(x14_loadedFrme, "textpane_options", g_MainStringTable->GetString(94)); FindAndSetPairText(x14_loadedFrme, "textpane_title", g_MainStringTable->GetString(98)); CGuiTextPane* proceed = static_cast(x14_loadedFrme->FindWidget("textpane_proceed")); if (proceed) proceed->TextSupport()->SetText(g_MainStringTable->GetString(85)); x18_tablegroup_mainmenu->SetMenuAdvanceCallback( std::bind(&SFrontEndFrame::DoAdvance, this, std::placeholders::_1)); x18_tablegroup_mainmenu->SetMenuSelectionChangeCallback( std::bind(&SFrontEndFrame::DoSelectionChange, this, std::placeholders::_1)); x18_tablegroup_mainmenu->SetMenuCancelCallback( std::bind(&SFrontEndFrame::DoCancel, this, std::placeholders::_1)); } bool CFrontEndUI::SFrontEndFrame::PumpLoad() { if (x14_loadedFrme) return true; if (x8_frme.IsLoaded()) { if (CGuiFrame* frme = x8_frme.GetObj()) { if (frme->GetIsFinishedLoading()) { x14_loadedFrme = frme; FinishedLoading(); return true; } } } return false; } CFrontEndUI::SFrontEndFrame::EAction CFrontEndUI::SFrontEndFrame::ProcessUserInput(const CFinalInput& input) { x4_action = EAction::Zero; x14_loadedFrme->ProcessUserInput(input); return x4_action; } void CFrontEndUI::SFrontEndFrame::Draw() const { x14_loadedFrme->Draw(CGuiWidgetDrawParms::Default); } void CFrontEndUI::SFrontEndFrame::DoCancel(CGuiTableGroup* caller) { } void CFrontEndUI::SFrontEndFrame::DoSelectionChange(CGuiTableGroup* caller) { } void CFrontEndUI::SFrontEndFrame::DoAdvance(CGuiTableGroup* caller) { } CFrontEndUI::SFrontEndFrame::SFrontEndFrame(u32 rnd) : x0_rnd(rnd) { x8_frme = g_SimplePool->GetObj("FRME_FrontEndPL"); } CFrontEndUI::SNesEmulatorFrame::SNesEmulatorFrame() { x4_nesEmu = std::make_unique(); const SObjectTag* deface = g_ResFactory->GetResourceIdByName("FONT_Deface14B"); CGuiTextProperties props(false, true, EJustification::Left, EVerticalJustification::Center, ETextDirection::Horizontal); xc_textSupport = std::make_unique(deface->id, props, zeus::CColor::skWhite, zeus::CColor::skBlack, zeus::CColor::skWhite, 0, 0, g_SimplePool); } void CFrontEndUI::SNesEmulatorFrame::SetMode(EMode mode) { switch (mode) { case EMode::Emulator: x8_quitScreen.reset(); break; case EMode::SaveProgress: x8_quitScreen = std::make_unique(EQuitType::SaveProgress); break; case EMode::ContinuePlaying: x8_quitScreen = std::make_unique(EQuitType::ContinuePlaying); break; case EMode::QuitNESMetroid: x8_quitScreen = std::make_unique(EQuitType::QuitNESMetroid); break; default: break; } x0_mode = mode; } void CFrontEndUI::SNesEmulatorFrame::ProcessUserInput(const CFinalInput& input, CSaveUI* sui) { bool processInput = true; if (sui && sui->GetUIType() != CSaveUI::EUIType::SaveProgress) processInput = false; if (sui) sui->ProcessUserInput(input); if (!processInput) return; switch (x0_mode) { case EMode::Emulator: x4_nesEmu->ProcessUserInput(input, 4); if (input.ControllerIdx() == 0 && input.PL()) SetMode(EMode::QuitNESMetroid); break; case EMode::SaveProgress: case EMode::ContinuePlaying: case EMode::QuitNESMetroid: x8_quitScreen->ProcessUserInput(input); break; default: break; } } bool CFrontEndUI::SNesEmulatorFrame::Update(float dt, CSaveUI* saveUi) { bool doUpdate = (saveUi && saveUi->GetUIType() != CSaveUI::EUIType::SaveProgress) ? false : true; x10_remTime = std::max(x10_remTime - dt, 0.f); zeus::CColor geomCol(zeus::CColor::skWhite); geomCol.a = std::min(x10_remTime, 1.f); xc_textSupport->SetGeometryColor(geomCol); if (xc_textSupport->GetIsTextSupportFinishedLoading()) { xc_textSupport->AutoSetExtent(); xc_textSupport->ClearRenderBuffer(); } if (!doUpdate) return false; switch (x0_mode) { case EMode::Emulator: { x4_nesEmu->Update(); if (!x4_nesEmu->WantsQuit()) x14_emulationSuspended = false; if (x4_nesEmu->WantsQuit() && !x14_emulationSuspended) { x14_emulationSuspended = true; if (saveUi && !saveUi->IsSavingDisabled()) { SetMode(EMode::SaveProgress); break; } SetMode(EMode::ContinuePlaying); break; } if (x4_nesEmu->WantsLoad() && saveUi) x4_nesEmu->LoadState(g_GameState->SystemOptions().GetNESState()); break; } case EMode::SaveProgress: { if (saveUi) { EQuitAction action = x8_quitScreen->Update(dt); if (action == EQuitAction::Yes) { memmove(g_GameState->SystemOptions().GetNESState(), x4_nesEmu->GetSaveState(), 18); saveUi->SaveNESState(); SetMode(EMode::ContinuePlaying); } else if (action == EQuitAction::No) SetMode(EMode::ContinuePlaying); } else SetMode(EMode::ContinuePlaying); break; } case EMode::ContinuePlaying: { EQuitAction action = x8_quitScreen->Update(dt); if (action == EQuitAction::Yes) SetMode(EMode::Emulator); else if (action == EQuitAction::No) return true; break; } case EMode::QuitNESMetroid: { EQuitAction action = x8_quitScreen->Update(dt); if (action == EQuitAction::Yes) return true; else if (action == EQuitAction::No) SetMode(EMode::Emulator); break; } default: break; } return false; } void CFrontEndUI::SNesEmulatorFrame::Draw(CSaveUI* saveUi) const { zeus::CColor mulColor = zeus::CColor::skWhite; bool doDraw = (saveUi && saveUi->GetUIType() != CSaveUI::EUIType::SaveProgress) ? false : true; if (doDraw) mulColor = zeus::CColor::skBlack; else if (x8_quitScreen) mulColor = zeus::CColor{0.376470f, 0.376470f, 0.376470f, 1.f}; x4_nesEmu->Draw(mulColor, x15_enableFiltering); if (!doDraw && x8_quitScreen) x8_quitScreen->Draw(); if (x10_remTime >= 7.5f) return; if (x10_remTime <= 0.f) return; if (xc_textSupport->GetIsTextSupportFinishedLoading()) { CGraphics::SetModelMatrix(zeus::CTransform::Translate(-280.f, 0.f, -160.f)); xc_textSupport->Render(); } } CFrontEndUI::SOptionsFrontEndFrame::SOptionsFrontEndFrame() { x4_frme = g_SimplePool->GetObj("FRME_OptionsFrontEnd"); x10_pauseScreen = g_SimplePool->GetObj("STRG_PauseScreen"); } bool CFrontEndUI::SOptionsFrontEndFrame::ProcessUserInput(const CFinalInput& input, CSaveUI* sui) { return true; } void CFrontEndUI::SOptionsFrontEndFrame::Draw() const { } CFrontEndUI::CFrontEndUI(CArchitectureQueue& queue) : CIOWin("FrontEndUI") { x18_rndA = std::min(rand() * 3 / RAND_MAX, 2); x1c_rndB = std::min(rand() * 3 / RAND_MAX, 2); x20_depsGroup = g_SimplePool->GetObj("FrontEnd_DGRP"); x38_pressStart = g_SimplePool->GetObj("TXTR_PressStart"); x44_frontendAudioGrp = g_SimplePool->GetObj("FrontEnd_AGSC"); g_Main->ResetGameState(); g_GameState->SetCurrentWorldId(g_DefaultWorldTag.id); for (int i=0 ; CDvdFile::FileExists(GetAttractMovieFileName(i).c_str()) ; ++i) ++xc0_attractCount; } void CFrontEndUI::OnSliderSelectionChange(CGuiSliderGroup* grp, float) {} void CFrontEndUI::OnCheckBoxSelectionChange(CGuiTableGroup* grp) {} void CFrontEndUI::OnOptionSubMenuCancel(CGuiTableGroup* grp) {} void CFrontEndUI::OnOptionsMenuCancel(CGuiTableGroup* grp) {} void CFrontEndUI::OnNewGameMenuCancel(CGuiTableGroup* grp) {} void CFrontEndUI::OnFileMenuCancel(CGuiTableGroup* grp) {} void CFrontEndUI::OnGenericMenuSelectionChange(CGuiTableGroup* grp, int, int) {} void CFrontEndUI::OnOptionsMenuAdvance(CGuiTableGroup* grp) {} void CFrontEndUI::OnNewGameMenuAdvance(CGuiTableGroup* grp) {} void CFrontEndUI::OnFileMenuAdvance(CGuiTableGroup* grp) {} void CFrontEndUI::OnMainMenuAdvance(CGuiTableGroup* grp) {} void CFrontEndUI::StartSlideShow(CArchitectureQueue& queue) { queue.Push(MakeMsg::CreateCreateIOWin(EArchMsgTarget::IOWinManager, 12, 11, new CSlideShow())); } std::string CFrontEndUI::GetAttractMovieFileName(int idx) { return hecl::Format("Video/attract%d.thp", idx); } std::string CFrontEndUI::GetNextAttractMovieFileName() { std::string ret = GetAttractMovieFileName(xbc_nextAttract); xbc_nextAttract = (xbc_nextAttract + 1) % xc0_attractCount; return ret; } void CFrontEndUI::SetCurrentMovie(EMenuMovie movie) { if (xb8_curMovie == movie) return; StopAttractMovie(); if (xb8_curMovie != EMenuMovie::Stopped) { xcc_curMoviePtr->SetPlayMode(CMoviePlayer::EPlayMode::Stopped); xcc_curMoviePtr->Rewind(); } xb8_curMovie = movie; if (xb8_curMovie != EMenuMovie::Stopped) { xcc_curMoviePtr = x70_menuMovies[int(xb8_curMovie)].get(); xcc_curMoviePtr->SetPlayMode(CMoviePlayer::EPlayMode::Playing); } else xcc_curMoviePtr = nullptr; } void CFrontEndUI::StopAttractMovie() { if (!xc4_attractMovie) return; xc4_attractMovie.reset(); xcc_curMoviePtr = nullptr; } void CFrontEndUI::StartAttractMovie() { if (xc4_attractMovie) return; SetCurrentMovie(EMenuMovie::Stopped); xc4_attractMovie = std::make_unique(GetNextAttractMovieFileName().c_str(), 0.f, false, true); xcc_curMoviePtr = xc4_attractMovie.get(); } void CFrontEndUI::UpdateMenuHighlights(CGuiTableGroup* grp) {} void CFrontEndUI::CompleteStateTransition() {} bool CFrontEndUI::CanBuild(const SObjectTag& tag) { return false; } void CFrontEndUI::StartStateTransition(EScreen screen) { switch (x50_curScreen) { case EScreen::One: if (screen != EScreen::Three) break; SetCurrentMovie(EMenuMovie::StartFileSelectA); SetMovieSeconds(xcc_curMoviePtr->GetTotalSeconds()); break; case EScreen::Three: if (screen == EScreen::Five) { SetCurrentMovie(EMenuMovie::FileSelectPlayGameA); SetMovieSeconds(xcc_curMoviePtr->GetTotalSeconds()); } else if (screen == EScreen::Four) { SetCurrentMovie(EMenuMovie::FileSelectGBA); SetMovieSeconds(xcc_curMoviePtr->GetTotalSeconds()); CSfxManager::SfxStart(1108, 1.f, 0.f, false, 0x7f, false, kInvalidAreaId); CSfxManager::SfxStart(1109, 1.f, 0.f, false, 0x7f, false, kInvalidAreaId); } break; case EScreen::Four: if (screen == EScreen::Five) { SetCurrentMovie(EMenuMovie::GBAFileSelectB); SetMovieSeconds(xcc_curMoviePtr->GetTotalSeconds()); } else if (screen == EScreen::Three) { SetCurrentMovie(EMenuMovie::GBAFileSelectA); SetMovieSeconds(xcc_curMoviePtr->GetTotalSeconds()); CSfxManager::SfxStart(1110, 1.f, 0.f, false, 0x7f, false, kInvalidAreaId); CSfxManager::SfxStart(1111, 1.f, 0.f, false, 0x7f, false, kInvalidAreaId); } default: break; } switch (screen) { case EScreen::Zero: case EScreen::One: SetCurrentMovie(EMenuMovie::FirstStart); SetMovieSeconds(xcc_curMoviePtr->GetTotalSeconds()); break; case EScreen::Two: StartAttractMovie(); SetMovieSecondsDeferred(); default: break; } x54_nextScreen = screen; } void CFrontEndUI::HandleDebugMenuReturnValue(CGameDebug::EReturnValue val, CArchitectureQueue& queue) {} void CFrontEndUI::Draw() const { //printf("DRAW\n"); if (x14_phase < EPhase::Four) return; if (xec_emuFrme) xec_emuFrme->Draw(xdc_saveUI.get()); else { //g_Renderer->SetDepthReadWrite(false, false); g_Renderer->SetViewportOrtho(false, -4096.f, 4096.f); if (xcc_curMoviePtr && xcc_curMoviePtr->GetIsFullyCached()) { auto vidDimensions = xcc_curMoviePtr->GetVideoDimensions(); float aspectRatio = vidDimensions.first / float(vidDimensions.second); float verticalOff = (CGraphics::g_ViewportResolution.x / aspectRatio - CGraphics::g_ViewportResolution.y) * 0.5f; xcc_curMoviePtr->SetFrame(zeus::CVector3f(0.f, -verticalOff, 0.f), zeus::CVector3f(CGraphics::g_ViewportResolution.x, verticalOff, 0.f), zeus::CVector3f(0.f, CGraphics::g_ViewportResolution.y + verticalOff, 0.f), zeus::CVector3f(CGraphics::g_ViewportResolution.x, CGraphics::g_ViewportResolution.y + verticalOff, 0.f)); xcc_curMoviePtr->DrawFrame(); } if (x50_curScreen == EScreen::Three && x54_nextScreen == EScreen::Three) { if (xf0_optionsFrme) xf0_optionsFrme->Draw(); else if (xe0_newFileSel) xe0_newFileSel->Draw(); else xe8_frontendFrme->Draw(); } else if (x50_curScreen == EScreen::Four && x54_nextScreen == EScreen::Four) xe4_gbaSupportFrme->Draw(); if (x64_pressStartAlpha > 0.f && x38_pressStart.IsLoaded() && m_pressStartQuad) { float nativeRatio = CGraphics::g_ViewportResolution.x / 640.f; float hOffset = x38_pressStart->GetWidth() / 2.f * nativeRatio; float vOffset = x38_pressStart->GetHeight() / 2.f * nativeRatio; zeus::CRectangle rect(CGraphics::g_ViewportResolutionHalf.x - hOffset, 72.f * nativeRatio - vOffset, x38_pressStart->GetWidth() * nativeRatio, x38_pressStart->GetHeight() * nativeRatio); zeus::CColor color = zeus::CColor::skWhite; color.a = x64_pressStartAlpha; const_cast(*m_pressStartQuad).draw(color, 1.f, rect); } if (xc0_attractCount > 0) { if (((x50_curScreen == EScreen::One && x54_nextScreen == EScreen::One) || x54_nextScreen == EScreen::Two) && x58_movieSeconds < 1.f) { zeus::CColor color = zeus::CColor::skBlack; color.a = 1.f - x58_movieSeconds; const_cast(m_fadeToBlack).draw(color); } } if (xd0_) { if (x54_nextScreen == EScreen::One && x50_curScreen == EScreen::Zero) { zeus::CColor color = zeus::CColor::skBlack; color.a = zeus::clamp(0.f, 1.f - x58_movieSeconds, 1.f); const_cast(m_fadeToBlack).draw(color); } else if (x54_nextScreen == EScreen::One && x50_curScreen == EScreen::One) { zeus::CColor color = zeus::CColor::skBlack; color.a = 1.f - zeus::clamp(0.f, 30.f - x58_movieSeconds, 1.f); const_cast(m_fadeToBlack).draw(color); } } if (xdc_saveUI) { if ((IsSaveUIConditional() && !xdc_saveUI->IsDrawConditional()) || ((x50_curScreen == EScreen::Three && x54_nextScreen == EScreen::Three) || (x50_curScreen == EScreen::Four && x54_nextScreen == EScreen::Four))) xdc_saveUI->Draw(); } } } void CFrontEndUI::UpdateMovies(float dt) { if (xcc_curMoviePtr && x5c_movieSecondsNeeded) { x5c_movieSecondsNeeded = false; x58_movieSeconds = xcc_curMoviePtr->GetTotalSeconds(); } for (auto& movie : x70_menuMovies) if (movie) movie->Update(dt); if (xc4_attractMovie) xc4_attractMovie->Update(dt); } void CFrontEndUI::FinishedLoadingDepsGroup() { const CDependencyGroup* dgrp = x20_depsGroup.GetObj(); x2c_deps.reserve(dgrp->GetObjectTagVector().size()); for (const SObjectTag& tag : dgrp->GetObjectTagVector()) x2c_deps.push_back(g_SimplePool->GetObj(tag)); x44_frontendAudioGrp.Lock(); } bool CFrontEndUI::PumpLoad() { for (CToken& tok : x2c_deps) if (!tok.IsLoaded()) return false; if (!x44_frontendAudioGrp.IsLoaded()) return false; /* Ready to construct texture quads */ m_pressStartQuad.emplace(CCameraFilterPass::EFilterType::Blend, x38_pressStart); return true; } bool CFrontEndUI::PumpMovieLoad() { if (xd1_moviesLoaded) return true; for (int i=0 ; i<9 ; ++i) { if (!x70_menuMovies[i]) { const FEMovie& movie = FEMovies[i]; x70_menuMovies[i] = std::make_unique(movie.path, 0.05f, movie.loop, false); x70_menuMovies[i]->SetPlayMode(CMoviePlayer::EPlayMode::Stopped); return false; } } xd1_moviesLoaded = true; return true; } void CFrontEndUI::ProcessUserInput(const CFinalInput& input, CArchitectureQueue& queue) { if (static_cast(g_Main)->GetBardBusy()) return; if (input.ControllerIdx() > 1) return; if (xec_emuFrme) { xec_emuFrme->ProcessUserInput(input, xdc_saveUI.get()); return; } if (x14_phase != EPhase::Four || input.ControllerIdx() != 0) return; if (x50_curScreen != x54_nextScreen) { if (x54_nextScreen == EScreen::Two && (input.PStart() || input.PA())) { SetMovieSeconds(std::min(1.f, x58_movieSeconds)); PlayAdvanceSfx(); return; } if (input.PA() || input.PStart()) { if (x50_curScreen == EScreen::Zero && x54_nextScreen == EScreen::One && x58_movieSeconds > 1.f) { xd0_ = true; SetMovieSeconds(1.f); return; } } } else { if (x50_curScreen == EScreen::One) { if (input.PStart() || input.PA()) { if (x58_movieSeconds < 30.f - g_tweakGame->GetPressStartDelay()) { CSfxManager::SfxStart(FETransitionBackSFX[x18_rndA][0], 1.f, 0.f, false, 0x7f, false, kInvalidAreaId); CSfxManager::SfxStart(FETransitionBackSFX[x18_rndA][1], 1.f, 0.f, false, 0x7f, false, kInvalidAreaId); StartStateTransition(EScreen::Three); return; } } } else if (x50_curScreen == EScreen::Three && x54_nextScreen == EScreen::Three) { if (xf0_optionsFrme) { if (xf0_optionsFrme->ProcessUserInput(input, xdc_saveUI.get())) return; xf0_optionsFrme.reset(); return; } else if (xe0_newFileSel) { switch (xe0_newFileSel->ProcessUserInput(input)) { case SNewFileSelectFrame::EAction::Two: StartStateTransition(EScreen::Four); return; case SNewFileSelectFrame::EAction::One: xf0_optionsFrme = std::make_unique(); return; case SNewFileSelectFrame::EAction::Three: xd2_ = true; StartSlideShow(queue); return; default: return; } } else { switch (xe8_frontendFrme->ProcessUserInput(input)) { case SFrontEndFrame::EAction::Two: StartStateTransition(EScreen::Four); return; case SFrontEndFrame::EAction::Three: xf0_optionsFrme = std::make_unique(); return; case SFrontEndFrame::EAction::One: TransitionToFive(); return; case SFrontEndFrame::EAction::Four: xd2_ = true; StartSlideShow(queue); return; default: return; } } } else if (x50_curScreen == EScreen::Four && x54_nextScreen == EScreen::Four) { switch (xe4_gbaSupportFrme->ProcessUserInput(input, xdc_saveUI.get())) { case SGBASupportFrame::EAction::GoBack: StartStateTransition(EScreen::Three); return; case SGBASupportFrame::EAction::PlayNESMetroid: xf4_curAudio->StopMixing(); xec_emuFrme = std::make_unique(); if (xdc_saveUI) xdc_saveUI->SetInGame(true); return; default: return; } } } } void CFrontEndUI::TransitionToFive() { if (x14_phase >= EPhase::Five) return; const u16* sfx = FETransitionForwardSFX[x1c_rndB]; CSfxManager::SfxStart(sfx[0], 1.f, 0.f, false, 0x7f, false, kInvalidAreaId); CSfxManager::SfxStart(sfx[1], 1.f, 0.f, false, 0x7f, false, kInvalidAreaId); x14_phase = EPhase::Five; StartStateTransition(EScreen::Five); } void CFrontEndUI::UpdateMusicVolume() { float volMul = (xf4_curAudio == xd4_audio1.get()) ? FE1_VOL : FE2_VOL; if (xf4_curAudio) { float vol = volMul * x68_musicVol * (g_GameState->GameOptions().GetMusicVolume() / 127.f); xf4_curAudio->SetVolume(vol); } } CIOWin::EMessageReturn CFrontEndUI::Update(float dt, CArchitectureQueue& queue) { if (xdc_saveUI && x50_curScreen >= EScreen::Three) { switch (xdc_saveUI->Update(dt)) { case EMessageReturn::Exit: TransitionToFive(); break; case EMessageReturn::RemoveIOWinAndExit: case EMessageReturn::RemoveIOWin: xe0_newFileSel.reset(); xdc_saveUI.reset(); default: break; } } UpdateMusicVolume(); switch (x14_phase) { case EPhase::Zero: if (!x20_depsGroup.IsLoaded()) return EMessageReturn::Exit; FinishedLoadingDepsGroup(); x20_depsGroup.Unlock(); x14_phase = EPhase::One; case EPhase::One: if (PumpLoad()) { xe0_newFileSel = std::make_unique(xdc_saveUI.get(), x1c_rndB); xe4_gbaSupportFrme = std::make_unique(); xe8_frontendFrme = std::make_unique(x1c_rndB); x38_pressStart.GetObj(); CAudioSys::AddAudioGroup(x44_frontendAudioGrp->GetAudioGroupData()); xd4_audio1 = std::make_unique("Audio/frontend_1.rsf", 416480, 1973664); xd8_audio2 = std::make_unique("Audio/frontend_2.rsf", 273556, 1636980); x14_phase = EPhase::Two; } if (x14_phase == EPhase::One) return EMessageReturn::Exit; case EPhase::Two: if (!xd4_audio1->IsReady() || !xd8_audio2->IsReady() || !xe0_newFileSel->PumpLoad() || !xe4_gbaSupportFrme->PumpLoad() || !xe8_frontendFrme->PumpLoad() || !xdc_saveUI->PumpLoad()) return EMessageReturn::Exit; xf4_curAudio = xd4_audio1.get(); xf4_curAudio->StartMixing(); x14_phase = EPhase::Three; case EPhase::Three: { bool moviesReady = true; if (PumpMovieLoad()) { UpdateMovies(dt); for (int i=0 ; i<9 ; ++i) { if (!x70_menuMovies[i]->GetIsFullyCached()) { moviesReady = false; break; } } } else moviesReady = false; if (moviesReady) { x14_phase = EPhase::Four; StartStateTransition(EScreen::One); } else return EMessageReturn::Exit; } case EPhase::Four: case EPhase::Five: if (xec_emuFrme) { if (xec_emuFrme->Update(dt, xdc_saveUI.get())) { xec_emuFrme.reset(); xf4_curAudio->StartMixing(); } break; } } return EMessageReturn::Exit; } CIOWin::EMessageReturn CFrontEndUI::OnMessage(const CArchitectureMessage& msg, CArchitectureQueue& queue) { switch (msg.GetType()) { case EArchMsgType::UserInput: { const CArchMsgParmUserInput& input = MakeMsg::GetParmUserInput(msg); ProcessUserInput(input.x4_parm, queue); break; } case EArchMsgType::TimerTick: { float dt = MakeMsg::GetParmTimerTick(msg).x4_parm; return Update(dt, queue); } case EArchMsgType::QuitGameplay: { x14_phase = EPhase::Six; break; } default: break; } return EMessageReturn::Normal; } void CFrontEndUI::StartGame() {} void CFrontEndUI::InitializeFrame() {} } }