diff --git a/config/GM8E01_00/symbols.txt b/config/GM8E01_00/symbols.txt index a7872083..8803ce2b 100644 --- a/config/GM8E01_00/symbols.txt +++ b/config/GM8E01_00/symbols.txt @@ -449,17 +449,17 @@ StartSlideShow__11CFrontEndUIFR18CArchitectureQueue = .text:0x8001BAEC; // type: SetFadeBlackWithMovie__11CFrontEndUIFv = .text:0x8001BB78; // type:function size:0x14 scope:global SetFadeBlackTimer__11CFrontEndUIFf = .text:0x8001BB8C; // type:function size:0x10 scope:global GetAttractMovieFileName__11CFrontEndUIFi = .text:0x8001BB9C; // type:function size:0x34 scope:global -GetNextAttractMovieFileName__11CFrontEndUIFi = .text:0x8001BBD0; // type:function size:0x4C scope:global +GetNextAttractMovieFileName__11CFrontEndUIFv = .text:0x8001BBD0; // type:function size:0x4C scope:global SetCurrentMovie__11CFrontEndUIFQ211CFrontEndUI10EMenuMovie = .text:0x8001BC1C; // type:function size:0x9C scope:global StopAttractMovie__11CFrontEndUIFv = .text:0x8001BCB8; // type:function size:0xA0 scope:global -StartAttractMovie__11CFrontEndUIFi = .text:0x8001BD58; // type:function size:0x100 scope:global +StartAttractMovie__11CFrontEndUIFv = .text:0x8001BD58; // type:function size:0x100 scope:global CompleteStateTransition__11CFrontEndUIFv = .text:0x8001BE58; // type:function size:0xF0 scope:global StartStateTransition__11CFrontEndUIFQ211CFrontEndUI7EScreen = .text:0x8001BF48; // type:function size:0x1F4 scope:global CanShowSaveUI__11CFrontEndUIFv = .text:0x8001C13C; // type:function size:0x38 scope:global Draw__11CFrontEndUICFv = .text:0x8001C174; // type:function size:0x560 scope:global ProcessUserInput__11CFrontEndUIFRC11CFinalInputR18CArchitectureQueue = .text:0x8001C6D4; // type:function size:0x400 scope:global UpdateMovies__11CFrontEndUIFf = .text:0x8001CAD4; // type:function size:0xCC scope:global -PumpMovieLoad__11CFrontEndUI = .text:0x8001CBA0; // type:function size:0x1A8 scope:global +PumpMovieLoad__11CFrontEndUIFv = .text:0x8001CBA0; // type:function size:0x1A8 scope:global Update__11CFrontEndUIFfR18CArchitectureQueue = .text:0x8001CD48; // type:function size:0x888 scope:global PumpLoad__11CFrontEndUIFv = .text:0x8001D5D0; // type:function size:0xAC scope:global FinishedLoadingDepsGroup__11CFrontEndUIFv = .text:0x8001D67C; // type:function size:0x114 scope:global @@ -469,84 +469,84 @@ TransitionToFive__11CFrontEndUIFv = .text:0x8001D8BC; // type:function size:0xBC __dt__11CFrontEndUIFv = .text:0x8001D978; // type:function size:0x260 scope:global __ct__11CFrontEndUIFv = .text:0x8001DBD8; // type:function size:0x344 scope:global CanBuild__11CResFactoryFRC10SObjectTag = .text:0x8001DF1C; // type:function size:0x24 scope:global -DoOptionsCancel__17SFusionBonusFrameFPC14CGuiTableGroup = .text:0x8001DF40; // type:function size:0xC8 scope:global -DoSelectionChange__17SFusionBonusFrameFPC14CGuiTableGroup = .text:0x8001E008; // type:function size:0xF4 scope:global -DoOptionsAdvance__17SFusionBonusFrameFPC14CGuiTableGroup = .text:0x8001E0FC; // type:function size:0x184 scope:global -SetTableColors__17SFusionBonusFrameFP14CGuiTableGroup = .text:0x8001E280; // type:function size:0x58 scope:global -fn_8001E2D8 = .text:0x8001E2D8; // type:function size:0x10 -FinishedLoading__17SFusionBonusFrameFv = .text:0x8001E2E8; // type:function size:0x390 scope:global -fn_8001E678 = .text:0x8001E678; // type:function size:0x64 -fn_8001E6DC = .text:0x8001E6DC; // type:function size:0x54 -PumpLoad__17SFusionBonusFrameFv = .text:0x8001E730; // type:function size:0x128 scope:global -ProcessUserInput__17SFusionBonusFrameFRC11CFinalInputRC15CSaveGameScreen = .text:0x8001E858; // type:function size:0xFC scope:global -Update__17SFusionBonusFrameFv = .text:0x8001E954; // type:function size:0x1BC scope:global -Draw__17SFusionBonusFrameFv = .text:0x8001EB10; // type:function size:0x58 scope:global -__dt__17SFusionBonusFrameFv = .text:0x8001EB68; // type:function size:0xAC scope:global -__ct__17SFusionBonusFrameFv = .text:0x8001EC14; // type:function size:0x138 scope:global -DoPopupCancel__19SNewFileSelectFrameFPC14CGuiTableGroup = .text:0x8001ED4C; // type:function size:0x9C scope:global -DoPopupAdvance__19SNewFileSelectFrameFPC14CGuiTableGroup = .text:0x8001EDE8; // type:function size:0x11C scope:global -DoFileselectCancel__19SNewFileSelectFrameFPC14CGuiTableGroup = .text:0x8001EF04; // type:function size:0x60 scope:global -DoSelectionChange__19SNewFileSelectFrameFPC14CGuiTableGroup = .text:0x8001EF64; // type:function size:0x44 scope:global -IsTextDoneAnimating__19SNewFileSelectFrameFv = .text:0x8001EFA8; // type:function size:0xDC scope:global -DeactivateExistingGamePopup__19SNewFileSelectFrameFv = .text:0x8001F084; // type:function size:0x88 scope:global -ActivateExistingGamePopup__19SNewFileSelectFrameFv = .text:0x8001F10C; // type:function size:0x180 scope:global -DeactivateNewGamePopup__19SNewFileSelectFrameFv = .text:0x8001F28C; // type:function size:0x114 scope:global -ActivateNewGamePopup__19SNewFileSelectFrameFv = .text:0x8001F3A0; // type:function size:0x2AC scope:global -ResetFrame__19SNewFileSelectFrameFv = .text:0x8001F64C; // type:function size:0xFC scope:global -EnterErase__19SNewFileSelectFrameFv = .text:0x8001F748; // type:function size:0x1D0 scope:global -ClearFrameContents__19SNewFileSelectFrameFv = .text:0x8001F918; // type:function size:0x338 scope:global -SetupFrameContents__19SNewFileSelectFrameFv = .text:0x8001FC50; // type:function size:0x414 scope:global -fn_80020064 = .text:0x80020064; // type:function size:0x5C -DoFileselectAdvance__19SNewFileSelectFrameFPC14CGuiTableGroup = .text:0x800200C0; // type:function size:0xD8 scope:global -HandleActiveChange__19SNewFileSelectFrameFP10CGuiWidget = .text:0x80020198; // type:function size:0x13C scope:global -Draw__19SNewFileSelectFrameFv = .text:0x800202D4; // type:function size:0x44 scope:global -ProcessUserInput__19SNewFileSelectFrameFRC11CFinalInput = .text:0x80020318; // type:function size:0x14C scope:global +DoOptionsCancel__Q211CFrontEndUI17SFusionBonusFrameFPC14CGuiTableGroup = .text:0x8001DF40; // type:function size:0xC8 scope:global +DoSelectionChange__Q211CFrontEndUI17SFusionBonusFrameFPC14CGuiTableGroup = .text:0x8001E008; // type:function size:0xF4 scope:global +DoOptionsAdvance__Q211CFrontEndUI17SFusionBonusFrameFPC14CGuiTableGroup = .text:0x8001E0FC; // type:function size:0x184 scope:global +SetTableColors__Q211CFrontEndUI17SFusionBonusFrameFP14CGuiTableGroup = .text:0x8001E280; // type:function size:0x58 scope:global +ResetCompletionFlags__Q211CFrontEndUI17SFusionBonusFrameFv = .text:0x8001E2D8; // type:function size:0x10 scope:global +FinishedLoading__Q211CFrontEndUI17SFusionBonusFrameFv = .text:0x8001E2E8; // type:function size:0x390 scope:global +Thunk__35TFunctor3FPvPvP14CGuiTableGroupi = .text:0x8001E678; // type:function size:0x64 scope:global +Thunk__29TFunctor1FPvPvP14CGuiTableGroup = .text:0x8001E6DC; // type:function size:0x54 scope:global +PumpLoad__Q211CFrontEndUI17SFusionBonusFrameFv = .text:0x8001E730; // type:function size:0x128 scope:global +ProcessUserInput__Q211CFrontEndUI17SFusionBonusFrameFRC11CFinalInputPC15CSaveGameScreen = .text:0x8001E858; // type:function size:0xFC scope:global +Update__Q211CFrontEndUI17SFusionBonusFrameFfPC15CSaveGameScreen = .text:0x8001E954; // type:function size:0x1BC scope:global +Draw__Q211CFrontEndUI17SFusionBonusFrameFv = .text:0x8001EB10; // type:function size:0x58 scope:global +__dt__Q211CFrontEndUI17SFusionBonusFrameFv = .text:0x8001EB68; // type:function size:0xAC scope:global +__ct__Q211CFrontEndUI17SFusionBonusFrameFv = .text:0x8001EC14; // type:function size:0x138 scope:global +DoPopupCancel__Q211CFrontEndUI19SNewFileSelectFrameFPC14CGuiTableGroup = .text:0x8001ED4C; // type:function size:0x9C scope:global +DoPopupAdvance__Q211CFrontEndUI19SNewFileSelectFrameFPC14CGuiTableGroup = .text:0x8001EDE8; // type:function size:0x11C scope:global +DoFileselectCancel__Q211CFrontEndUI19SNewFileSelectFrameFPC14CGuiTableGroup = .text:0x8001EF04; // type:function size:0x60 scope:global +DoSelectionChange__Q211CFrontEndUI19SNewFileSelectFrameFPC14CGuiTableGroup = .text:0x8001EF64; // type:function size:0x44 scope:global +IsTextDoneAnimating__Q211CFrontEndUI19SNewFileSelectFrameFv = .text:0x8001EFA8; // type:function size:0xDC scope:global +DeactivateExistingGamePopup__Q211CFrontEndUI19SNewFileSelectFrameFv = .text:0x8001F084; // type:function size:0x88 scope:global +ActivateExistingGamePopup__Q211CFrontEndUI19SNewFileSelectFrameFv = .text:0x8001F10C; // type:function size:0x180 scope:global +DeactivateNewGamePopup__Q211CFrontEndUI19SNewFileSelectFrameFv = .text:0x8001F28C; // type:function size:0x114 scope:global +ActivateNewGamePopup__Q211CFrontEndUI19SNewFileSelectFrameFv = .text:0x8001F3A0; // type:function size:0x2AC scope:global +ResetFrame__Q211CFrontEndUI19SNewFileSelectFrameFv = .text:0x8001F64C; // type:function size:0xFC scope:global +EnterErase__Q211CFrontEndUI19SNewFileSelectFrameFv = .text:0x8001F748; // type:function size:0x1D0 scope:global +ClearFrameContents__Q211CFrontEndUI19SNewFileSelectFrameFv = .text:0x8001F918; // type:function size:0x338 scope:global +SetupFrameContents__Q211CFrontEndUI19SNewFileSelectFrameFv = .text:0x8001FC50; // type:function size:0x414 scope:global +__pl__4rstlFRCQ24rstl66basic_string,Q24rstl17rmemory_allocator>RCQ24rstl66basic_string,Q24rstl17rmemory_allocator> = .text:0x80020064; // type:function size:0x5C scope:global +DoFileselectAdvance__Q211CFrontEndUI19SNewFileSelectFrameFPC14CGuiTableGroup = .text:0x800200C0; // type:function size:0xD8 scope:global +HandleActiveChange__Q211CFrontEndUI19SNewFileSelectFrameFP10CGuiWidget = .text:0x80020198; // type:function size:0x13C scope:global +Draw__Q211CFrontEndUI19SNewFileSelectFrameCFv = .text:0x800202D4; // type:function size:0x44 scope:global +ProcessUserInput__Q211CFrontEndUI19SNewFileSelectFrameFRC11CFinalInput = .text:0x80020318; // type:function size:0x14C scope:global GetIsActive__10CGuiWidgetCFv = .text:0x80020464; // type:function size:0xC scope:global -Update__19SNewFileSelectFrameFf = .text:0x80020470; // type:function size:0xBC scope:global -GetUserFileSelection__19SNewFileSelectFrameCFv = .text:0x8002052C; // type:function size:0x24 scope:global -FinishedLoading__19SNewFileSelectFrame = .text:0x80020550; // type:function size:0x5E4 scope:global -fn_80020B34 = .text:0x80020B34; // type:function size:0x64 -fn_80020B98 = .text:0x80020B98; // type:function size:0x54 -PumpLoad__19SNewFileSelectFrameFv = .text:0x80020BEC; // type:function size:0xC4 scope:global -__dt__19SNewFileSelectFrameFv = .text:0x80020CB0; // type:function size:0x100 scope:global -__ct__19SNewFileSelectFrameFv = .text:0x80020DB0; // type:function size:0x128 scope:global -FindFileSelectOption__19SNewFileSelectFrameFP9CGuiFramei = .text:0x80020ED8; // type:function size:0x200 scope:global -StartTextAnimating__19SNewFileSelectFrameFP12CGuiTextPaneQ24rstl7wstring = .text:0x800210D8; // type:function size:0x90 scope:global -ComputeRandom__17SFileSelectOption = .text:0x80021168; // type:function size:0x4C scope:global -DoCancel__14SFrontEndFrameFPC14CGuiTableGroup = .text:0x800211B4; // type:function size:0x4 scope:global -HandleActiveChange__14SFrontEndFrameFPC14CGuiTableGroup = .text:0x800211B8; // type:function size:0x58 scope:global -DoSelectionChange__14SFrontEndFrameFPC14CGuiTableGroup = .text:0x80021210; // type:function size:0x64 scope:global -DoAdvance__14SFrontEndFrameFPC14CGuiTableGroup = .text:0x80021274; // type:function size:0x100 scope:global -Draw__14SFrontEndFrameFv = .text:0x80021374; // type:function size:0x2C scope:global -ProcessUserInput__14SFrontEndFrameFRC11CFinalInput = .text:0x800213A0; // type:function size:0x3C scope:global -Update__14SFrontEndFrameFf = .text:0x800213DC; // type:function size:0xF4 scope:global -FinishedLoading__14SFrontEndFrameFv = .text:0x800214D0; // type:function size:0x298 scope:global -fn_80021768 = .text:0x80021768; // type:function size:0x64 -fn_800217CC = .text:0x800217CC; // type:function size:0x54 -PumpLoad__14SFrontEndFrameFv = .text:0x80021820; // type:function size:0xC4 scope:global -__dt__14SFrontEndFrameFv = .text:0x800218E4; // type:function size:0x68 scope:global -__ct__14SFrontEndFrameFv = .text:0x8002194C; // type:function size:0xAC scope:global -OnMessage__16CStateSetterFlowFv = .text:0x800219F8; // type:function size:0x40 scope:global +Update__Q211CFrontEndUI19SNewFileSelectFrameFf = .text:0x80020470; // type:function size:0xBC scope:global +GetUserFileSelection__Q211CFrontEndUI19SNewFileSelectFrameCFv = .text:0x8002052C; // type:function size:0x24 scope:global +FinishedLoading__Q211CFrontEndUI19SNewFileSelectFrameFv = .text:0x80020550; // type:function size:0x5E4 scope:global +Thunk__35TFunctor3FPvPvP14CGuiTableGroupi = .text:0x80020B34; // type:function size:0x64 scope:local +Thunk__29TFunctor1FPvPvP14CGuiTableGroup = .text:0x80020B98; // type:function size:0x54 scope:local +PumpLoad__Q211CFrontEndUI19SNewFileSelectFrameFv = .text:0x80020BEC; // type:function size:0xC4 scope:global +__dt__Q211CFrontEndUI19SNewFileSelectFrameFv = .text:0x80020CB0; // type:function size:0x100 scope:global +__ct__Q211CFrontEndUI19SNewFileSelectFrameFP15CSaveGameScreenUi = .text:0x80020DB0; // type:function size:0x128 scope:global +FindFileSelectOption__Q211CFrontEndUI19SNewFileSelectFrameFP9CGuiFramei = .text:0x80020ED8; // type:function size:0x200 scope:global +StartTextAnimating__Q211CFrontEndUI19SNewFileSelectFrameFP12CGuiTextPaneQ24rstl66basic_string,Q24rstl17rmemory_allocator>f = .text:0x800210D8; // type:function size:0x90 scope:global +ComputeRandom__Q211CFrontEndUI17SFileSelectOptionFv = .text:0x80021168; // type:function size:0x4C scope:global +DoCancel__Q211CFrontEndUI14SFrontEndFrameFPC14CGuiTableGroup = .text:0x800211B4; // type:function size:0x4 scope:global +HandleActiveChange__Q211CFrontEndUI14SFrontEndFrameFPC14CGuiTableGroup = .text:0x800211B8; // type:function size:0x58 scope:global +DoSelectionChange__Q211CFrontEndUI14SFrontEndFrameFPC14CGuiTableGroup = .text:0x80021210; // type:function size:0x64 scope:global +DoAdvance__Q211CFrontEndUI14SFrontEndFrameFPC14CGuiTableGroup = .text:0x80021274; // type:function size:0x100 scope:global +Draw__Q211CFrontEndUI14SFrontEndFrameFv = .text:0x80021374; // type:function size:0x2C scope:global +ProcessUserInput__Q211CFrontEndUI14SFrontEndFrameFRC11CFinalInput = .text:0x800213A0; // type:function size:0x3C scope:global +Update__Q211CFrontEndUI14SFrontEndFrameFf = .text:0x800213DC; // type:function size:0xF4 scope:global +FinishedLoading__Q211CFrontEndUI14SFrontEndFrameFv = .text:0x800214D0; // type:function size:0x298 scope:global +Thunk__35TFunctor3FPvPvP14CGuiTableGroupi = .text:0x80021768; // type:function size:0x64 scope:local +Thunk__29TFunctor1FPvPvP14CGuiTableGroup = .text:0x800217CC; // type:function size:0x54 scope:local +PumpLoad__Q211CFrontEndUI14SFrontEndFrameFv = .text:0x80021820; // type:function size:0xC4 scope:global +__dt__Q211CFrontEndUI14SFrontEndFrameFv = .text:0x800218E4; // type:function size:0x68 scope:global +__ct__Q211CFrontEndUI14SFrontEndFrameFUi = .text:0x8002194C; // type:function size:0xAC scope:global +OnMessage__16CStateSetterFlowFRC20CArchitectureMessageR18CArchitectureQueue = .text:0x800219F8; // type:function size:0x40 scope:global __dt__16CStateSetterFlowFv = .text:0x80021A38; // type:function size:0x60 scope:global __ct__16CStateSetterFlowFv = .text:0x80021A98; // type:function size:0x60 scope:global -SetUIText__13SGBALinkFrameF7EUIType = .text:0x80021AF8; // type:function size:0x30C scope:global -ProcessUserInput__13SGBALinkFrameFRC11CFinalInputb = .text:0x80021E04; // type:function size:0x20C scope:global -Update__13SGBALinkFrameFf = .text:0x80022010; // type:function size:0x48 scope:global -FinishedLoading__13SGBALinkFrameFv = .text:0x80022058; // type:function size:0x164 scope:global -Draw__13SGBALinkFrameFv = .text:0x800221BC; // type:function size:0x2C scope:global -__dt__13SGBALinkFrameFv = .text:0x800221E8; // type:function size:0x3C scope:global -__ct__13SGBALinkFrameFPC9CGuiFrameP11CGBASupportb = .text:0x80022224; // type:function size:0xA0 scope:global -Draw__17SNesEmulatorFrameFRC15CSaveGameScreen = .text:0x800222C4; // type:function size:0x184 scope:global -ProcessUserInput__17SNesEmulatorFrameFRC11CFinalInputPC15CSaveGameScreen = .text:0x80022448; // type:function size:0xD4 scope:global -Update__17SNesEmulatorFrameFfR15CSaveGameScreen = .text:0x8002251C; // type:function size:0x310 scope:global -SetMode__17SNesEmulatorFrameF5EMode = .text:0x8002282C; // type:function size:0x27C scope:global -__dt__17SNesEmulatorFrameFv = .text:0x80022AA8; // type:function size:0xB4 scope:global -__ct__17SNesEmulatorFrameFv = .text:0x80022B5C; // type:function size:0x1B4 scope:global -fn_80022D10 = .text:0x80022D10; // type:function size:0x58 -SetPairText__12SGuiTextPairFRCQ24rstl7wstring = .text:0x80022D68; // type:function size:0x90 scope:global -FindTextPanePair__14SFrontEndFrameFPC9CGuiFramePCc = .text:0x80022DF8; // type:function size:0x7C scope:global -__ct__12SGuiTextPairFv = .text:0x80022E74; // type:function size:0x10 scope:global -FindAndSetPairText__14SFrontEndFrameFR9CGuiFramePCcRCQ24rstl7wstring = .text:0x80022E84; // type:function size:0xD0 scope:global +SetUIText__Q311CFrontEndUI17SFusionBonusFrame13SGBALinkFrameFQ411CFrontEndUI17SFusionBonusFrame13SGBALinkFrame7EUIType = .text:0x80021AF8; // type:function size:0x30C scope:global +ProcessUserInput__Q311CFrontEndUI17SFusionBonusFrame13SGBALinkFrameFRC11CFinalInputb = .text:0x80021E04; // type:function size:0x20C scope:global +Update__Q311CFrontEndUI17SFusionBonusFrame13SGBALinkFrameFf = .text:0x80022010; // type:function size:0x48 scope:global +FinishedLoading__Q311CFrontEndUI17SFusionBonusFrame13SGBALinkFrameFv = .text:0x80022058; // type:function size:0x164 scope:global +Draw__Q311CFrontEndUI17SFusionBonusFrame13SGBALinkFrameFv = .text:0x800221BC; // type:function size:0x2C scope:global +__dt__Q311CFrontEndUI17SFusionBonusFrame13SGBALinkFrameFv = .text:0x800221E8; // type:function size:0x3C scope:global +__ct__Q311CFrontEndUI17SFusionBonusFrame13SGBALinkFrameFPC9CGuiFrameP11CGBASupportb = .text:0x80022224; // type:function size:0xA0 scope:global +Draw__Q211CFrontEndUI17SNesEmulatorFrameFRC15CSaveGameScreen = .text:0x800222C4; // type:function size:0x184 scope:global +ProcessUserInput__Q211CFrontEndUI17SNesEmulatorFrameFRC11CFinalInputPC15CSaveGameScreen = .text:0x80022448; // type:function size:0xD4 scope:global +Update__Q211CFrontEndUI17SNesEmulatorFrameFfR15CSaveGameScreen = .text:0x8002251C; // type:function size:0x310 scope:global +SetMode__Q211CFrontEndUI17SNesEmulatorFrameFQ311CFrontEndUI17SNesEmulatorFrame5EMode = .text:0x8002282C; // type:function size:0x27C scope:global +__dt__Q211CFrontEndUI17SNesEmulatorFrameFv = .text:0x80022AA8; // type:function size:0xB4 scope:global +__ct__Q211CFrontEndUI17SNesEmulatorFrameFv = .text:0x80022B5C; // type:function size:0x1B4 scope:global +SetPairText__Q211CFrontEndUI12SGuiTextPairFRCQ24rstl66basic_string,Q24rstl17rmemory_allocator> = .text:0x80022D10; // type:function size:0x58 scope:global +SetPairText__Q211CFrontEndUI12SGuiTextPairFPCw = .text:0x80022D68; // type:function size:0x90 scope:global +FindTextPanePair__Q211CFrontEndUI14SFrontEndFrameFPC9CGuiFramePCc = .text:0x80022DF8; // type:function size:0x7C scope:global +__ct__Q211CFrontEndUI12SGuiTextPairFv = .text:0x80022E74; // type:function size:0x10 scope:global +FindAndSetPairText__Q211CFrontEndUI14SFrontEndFrameFR9CGuiFramePCcPCw = .text:0x80022E84; // type:function size:0xD0 scope:global PlayAdvanceSfx__11CFrontEndUIFv = .text:0x80022F54; // type:function size:0x64 scope:global __sinit_CFrontEndUI_cpp = .text:0x80022FB8; // type:function size:0x20 scope:local Update__15CInputGeneratorFfR18CArchitectureQueue = .text:0x80022FD8; // type:function size:0x4DC scope:global @@ -9027,12 +9027,12 @@ __ct__11CWorldStateFUi = .text:0x801D5070; // type:function size:0x138 scope:glo SetAutoMapperKeyState__12CSystemStateFi = .text:0x801D51A8; // type:function size:0x8 scope:global SetAllItemsCollected__12CSystemStateFb = .text:0x801D51B0; // type:function size:0x10 scope:global SetHasFusion__12CSystemStateFb = .text:0x801D51C0; // type:function size:0x10 scope:global -fn_801D51D0 = .text:0x801D51D0; // type:function size:0x10 +SetFusionBeat__12CSystemStateFb = .text:0x801D51D0; // type:function size:0x10 scope:global SetHardModeBeat__12CSystemStateFb = .text:0x801D51E0; // type:function size:0x10 scope:global SetHasHardMode__12CSystemStateFb = .text:0x801D51F0; // type:function size:0x10 scope:global SetLogScanCount__12CSystemStateFi = .text:0x801D5200; // type:function size:0x8 scope:global GetLogScanCount__12CSystemStateFv = .text:0x801D5208; // type:function size:0x8 scope:global -fn_801D5210 = .text:0x801D5210; // type:function size:0x10 +SetFusionLinked__12CSystemStateFb = .text:0x801D5210; // type:function size:0x10 scope:global IncrementPowerBombAmmoCount__12CSystemStateFv = .text:0x801D5220; // type:function size:0x34 scope:global GetShowPowerBombAmmoMessage__12CSystemStateCFv = .text:0x801D5254; // type:function size:0x1C scope:global IncrementFrozenBallCount__12CSystemStateFv = .text:0x801D5270; // type:function size:0x34 scope:global @@ -10430,7 +10430,7 @@ fn_8024479C = .text:0x8024479C; // type:function size:0x64 fn_80244800 = .text:0x80244800; // type:function size:0x54 DoSelectionChange__15CQuitGameScreenFP14CGuiTableGroup = .text:0x80244854; // type:function size:0x44 scope:global DoAdvance__15CQuitGameScreenFP14CGuiTableGroup = .text:0x80244898; // type:function size:0x90 scope:global -Update__15CQuitGameScreenFv = .text:0x80244928; // type:function size:0x94 scope:global +Update__15CQuitGameScreenFf = .text:0x80244928; // type:function size:0x94 scope:global Draw__15CQuitGameScreenFv = .text:0x802449BC; // type:function size:0xE4 scope:global ProcessUserInput__15CQuitGameScreenFRC11CFinalInput = .text:0x80244AA0; // type:function size:0x70 scope:global __ct__15CQuitGameScreenF9EQuitType = .text:0x80244B10; // type:function size:0x98 scope:global @@ -10652,7 +10652,7 @@ fn_8024FCD4 = .text:0x8024FCD4; // type:function size:0x64 fn_8024FD38 = .text:0x8024FD38; // type:function size:0x54 ResetCardDriver__15CSaveGameScreenFv = .text:0x8024FD8C; // type:function size:0x98 scope:global __dt__15CSaveGameScreenFv = .text:0x8024FE24; // type:function size:0x158 scope:global -__ct__15CSaveGameScreen = .text:0x8024FF7C; // type:function size:0x33C scope:global +__ct__15CSaveGameScreenFiUx = .text:0x8024FF7C; // type:function size:0x33C scope:global ConstructCardDriver__15CSaveGameScreen = .text:0x802502B8; // type:function size:0xD4 scope:global SetUIText__15CSaveGameScreenFv = .text:0x8025038C; // type:function size:0x498 scope:global SelectUIType__15CSaveGameScreenFv = .text:0x80250824; // type:function size:0x130 scope:global @@ -12241,8 +12241,8 @@ _GetIsTextSupportFinishedLoading__15CGuiTextSupportCFv = .text:0x802C9B70; // ty GetIsTextSupportFinishedLoading__15CGuiTextSupportCFv = .text:0x802C9C64; // type:function size:0x34 scope:global __dt__15CGuiTextSupportFv = .text:0x802C9C98; // type:function size:0x154 scope:global fn_802C9DEC = .text:0x802C9DEC; // type:function size:0x50 -__ct__15CGuiTextSupportFv = .text:0x802C9E3C; // type:function size:0x208 scope:global -__ct__18CGuiTextPropertiesFv = .text:0x802CA044; // type:function size:0x18 scope:global +__ct__15CGuiTextSupportFUiRC18CGuiTextPropertiesRC6CColorRC6CColorRC6CColoriiP11CSimplePool = .text:0x802C9E3C; // type:function size:0x208 scope:global +__ct__18CGuiTextPropertiesFbb14EJustification22EVerticalJustificationPCQ24rstl55vector,Q24rstl17rmemory_allocator> = .text:0x802CA044; // type:function size:0x18 scope:global fn_802CA05C = .text:0x802CA05C; // type:function size:0x94 __dt__Q24rstl25list<17CTextRenderBuffer>Fv = .text:0x802CA0F0; // type:function size:0x94 scope:global reserve__Q24rstl58vector<21TToken<11CRasterFont>,Q24rstl17rmemory_allocator>Fi = .text:0x802CA184; // type:function size:0xF4 @@ -14647,7 +14647,7 @@ fn_8034BF14 = .text:0x8034BF14; // type:function size:0x4C fn_8034BF60 = .text:0x8034BF60; // type:function size:0x84 SysUnloadSampleData__9CAudioSysFRCQ24rstl66basic_string,Q24rstl17rmemory_allocator> = .text:0x8034BFE4; // type:function size:0x74 scope:global SysIsGroupSetLoaded__9CAudioSysFRCQ24rstl66basic_string,Q24rstl17rmemory_allocator> = .text:0x8034C058; // type:function size:0x50 scope:global -SysLoadGroupSet__9CAudioSysF30TLockedToken<14CAudioGroupSet>Q24rstl66basic_string,Q24rstl17rmemory_allocator>Ui = .text:0x8034C0A8; // type:function size:0x208 scope:global +SysLoadGroupSet__9CAudioSysFRC6CTokenRCQ24rstl66basic_string,Q24rstl17rmemory_allocator>Ui = .text:0x8034C0A8; // type:function size:0x208 scope:global SysLoadGroupSet__9CAudioSysFP11CSimplePoolUi = .text:0x8034C2B0; // type:function size:0x23C scope:global SysSetSfxVolume__9CAudioSysFUcUsUcUc = .text:0x8034C4EC; // type:function size:0x30 scope:global SysSetVolume__9CAudioSysFUcUsUc = .text:0x8034C51C; // type:function size:0x2C scope:global @@ -15018,8 +15018,8 @@ __ct__17CTextRenderBufferFQ217CTextRenderBuffer5EMode = .text:0x8035B57C; // typ SetSfxVolume__12CMoviePlayerFUc = .text:0x8035B5DC; // type:function size:0x30 scope:global fn_8035B60C = .text:0x8035B60C; // type:function size:0x8 fn_8035B614 = .text:0x8035B614; // type:function size:0x8 -fn_8035B61C = .text:0x8035B61C; // type:function size:0x8 -fn_8035B624 = .text:0x8035B624; // type:function size:0x8 +GetHeight__12CMoviePlayerCFv = .text:0x8035B61C; // type:function size:0x8 scope:global +GetWidth__12CMoviePlayerCFv = .text:0x8035B624; // type:function size:0x8 scope:global VerifyCallbackStatus__12CMoviePlayerFv = .text:0x8035B62C; // type:function size:0x44 scope:global MixAudio__12CMoviePlayerFPsPCsUl = .text:0x8035B670; // type:function size:0x214 scope:global StaticMyAudioCallback__12CMoviePlayerFv = .text:0x8035B884; // type:function size:0xC0 scope:global @@ -15041,7 +15041,7 @@ __dt__12CMoviePlayerFv = .text:0x8035C7B8; // type:function size:0x184 scope:glo __dt__Q24rstl67vectorFv = .text:0x8035C93C; // type:function size:0x8C scope:global __dt__Q24rstl56vector,Q24rstl17rmemory_allocator>Fv = .text:0x8035C9C8; // type:function size:0xB8 scope:global PumpIndexLoad__12CMoviePlayerFv = .text:0x8035CA80; // type:function size:0x49C scope:global -__ct__12CMoviePlayerFPCcfb = .text:0x8035CF1C; // type:function size:0x204 scope:global +__ct__12CMoviePlayerFPCcfbb = .text:0x8035CF1C; // type:function size:0x204 scope:global MyTHPYuv2RgbTextureSetup__FPvPvPvUsUs = .text:0x8035D120; // type:function size:0x174 scope:global MyTHPGXYuv2RgbSetup__Fbb = .text:0x8035D294; // type:function size:0x51C scope:global MyTHPGXRestore__Fv = .text:0x8035D7B0; // type:function size:0x84 scope:global @@ -15162,7 +15162,7 @@ StopAudio__19CStreamAudioManagerFv = .text:0x8036574C; // type:function size:0x6 StopOneShot__19CStreamAudioManagerFv = .text:0x803657B8; // type:function size:0xEC scope:global StopAll__19CStreamAudioManagerFv = .text:0x803658A4; // type:function size:0x24 scope:global SetMusicUnmute__19CStreamAudioManagerFb = .text:0x803658C8; // type:function size:0x44 scope:global -fn_8036590C__19CStreamAudioManagerFf = .text:0x8036590C; // type:function size:0xE0 scope:global +FadeBackIn__19CStreamAudioManagerFf = .text:0x8036590C; // type:function size:0xE0 scope:global AreStringsNotEqual__21CStreamedAudioManagerFPCcPCc = .text:0x803659EC; // type:function size:0x30 scope:global SetSfxVolume__19CStreamAudioManagerFUi = .text:0x80365A1C; // type:function size:0x18 scope:global SetMusicVolume__19CStreamAudioManagerFUi = .text:0x80365A34; // type:function size:0x38 scope:global @@ -15291,7 +15291,7 @@ predictor_zero__FP10g72x_state = .text:0x8036BA30; // type:function size:0x7C sc g72x_init_state__FP10g72x_state = .text:0x8036BAAC; // type:function size:0x78 scope:global fmult__Fii = .text:0x8036BB24; // type:function size:0xE0 scope:local quan__FiPsi = .text:0x8036BC04; // type:function size:0x30 scope:local -SetVolume__18CStaticAudioPlayerFc = .text:0x8036BC34; // type:function size:0x28 scope:global +SetVolume__18CStaticAudioPlayerFUc = .text:0x8036BC34; // type:function size:0x28 scope:global DecodeMonoAndMix__18CStaticAudioPlayerFPUsPUsiiiiiR10g72x_state = .text:0x8036BC5C; // type:function size:0x194 scope:global Decode__18CStaticAudioPlayerFPCUsPUsi = .text:0x8036BDF0; // type:function size:0x124 scope:global DoMix__18CStaticAudioPlayerFv = .text:0x8036BF14; // type:function size:0xBC scope:global @@ -16718,23 +16718,13 @@ skRightStepSounds = .rodata:0x803CC4C8; // type:object size:0x30 scope:local dat @stringBase0 = .rodata:0x803CC4F8; // type:object size:0x47 scope:local data:string_table lbl_803CC540 = .rodata:0x803CC540; // type:object size:0x48 data:4byte MetroidBuildInfo = .rodata:0x803CC588; // type:object size:0x3C scope:global data:string -lbl_803CC5C4 = .rodata:0x803CC5C4; // type:object size:0xC data:2byte -lbl_803CC5D0 = .rodata:0x803CC5D0; // type:object size:0xC data:2byte +FETransitionBackSFX = .rodata:0x803CC5C4; // type:object size:0xC scope:local data:2byte +FETransitionForwardSFX = .rodata:0x803CC5D0; // type:object size:0xC scope:local data:2byte lbl_803CC5DC = .rodata:0x803CC5DC; // type:object size:0xC data:float lbl_803CC5E8 = .rodata:0x803CC5E8; // type:object size:0xC data:float lbl_803CC5F4 = .rodata:0x803CC5F4; // type:object size:0x28 lbl_803CC61C = .rodata:0x803CC61C; // type:object size:0x28 -lbl_803CC644 = .rodata:0x803CC644; // type:object size:0x19 data:string -lbl_803CC65D = .rodata:0x803CC65D; // type:object size:0x17 data:string -lbl_803CC674 = .rodata:0x803CC674; // type:object size:0x20 data:string -lbl_803CC694 = .rodata:0x803CC694; // type:object size:0x1C data:string -lbl_803CC6B0 = .rodata:0x803CC6B0; // type:object size:0x23 data:string -lbl_803CC6D3 = .rodata:0x803CC6D3; // type:object size:0x1C data:string -lbl_803CC6EF = .rodata:0x803CC6EF; // type:object size:0x15 data:string -lbl_803CC704 = .rodata:0x803CC704; // type:object size:0x1C data:string -lbl_803CC720 = .rodata:0x803CC720; // type:object size:0x15 data:string -lbl_803CC735 = .rodata:0x803CC735; // type:object size:0x15 data:string -lbl_803CC74A = .rodata:0x803CC74A; // type:object size:0x356 +@stringBase0 = .rodata:0x803CC644; // type:object size:0x45C scope:local data:string_table @stringBase0 = .rodata:0x803CCAA0; // type:object size:0x7 scope:local data:string_table @stringBase0 = .rodata:0x803CCAA8; // type:object size:0x10 scope:local data:string_table lbl_803CCAB8 = .rodata:0x803CCAB8; // type:object size:0xE data:string @@ -18005,9 +17995,9 @@ jumptable_803D978C = .data:0x803D978C; // type:object size:0x58 scope:local __vt__19CCollisionPrimitive = .data:0x803D97E4; // type:object size:0x2C scope:global __vt__21CArchMsgParmUserInput = .data:0x803D9810; // type:object size:0xC scope:global lbl_803D9820 = .data:0x803D9820; // type:object size:0x9C data:4byte -lbl_803D98BC = .data:0x803D98BC; // type:object size:0x1C +__vt__11CFrontEndUI = .data:0x803D98BC; // type:object size:0x1C scope:global jumptable_803D98D8 = .data:0x803D98D8; // type:object size:0x28 scope:local -lbl_803D9900 = .data:0x803D9900; // type:object size:0x28 +__vt__16CStateSetterFlow = .data:0x803D9900; // type:object size:0x28 scope:global __vt__9CMainFlow = .data:0x803D9928; // type:object size:0x1C scope:global jumptable_803D9944 = .data:0x803D9944; // type:object size:0x44 scope:local lbl_803D9988 = .data:0x803D9988; // type:object size:0x10 data:4byte @@ -22687,9 +22677,9 @@ lbl_805A9F90 = .sdata2:0x805A9F90; // type:object size:0x8 align:8 data:double lbl_805A9F98 = .sdata2:0x805A9F98; // type:object size:0x8 align:8 data:double lbl_805A9FA0 = .sdata2:0x805A9FA0; // type:object size:0x8 align:4 data:float BuildTime = .sdata2:0x805A9FA8; // type:object size:0x4 scope:global data:4byte -lbl_805A9FAC = .sdata2:0x805A9FAC; // type:object size:0x4 data:4byte -lbl_805A9FB0 = .sdata2:0x805A9FB0; // type:object size:0x4 data:4byte -lbl_805A9FB4 = .sdata2:0x805A9FB4; // type:object size:0x4 data:4byte +kAudioFrontend1Path = .sdata2:0x805A9FAC; // type:object size:0x4 scope:local data:4byte +kAudioFrontend2Path = .sdata2:0x805A9FB0; // type:object size:0x4 scope:local data:4byte +kFrontEndAGSCName = .sdata2:0x805A9FB4; // type:object size:0x4 scope:local data:4byte lbl_805A9FB8 = .sdata2:0x805A9FB8; // type:object size:0x4 align:4 data:float lbl_805A9FBC = .sdata2:0x805A9FBC; // type:object size:0x4 align:4 data:float lbl_805A9FC0 = .sdata2:0x805A9FC0; // type:object size:0x4 align:4 data:float diff --git a/include/GuiSys/CGuiFrame.hpp b/include/GuiSys/CGuiFrame.hpp index 716c7c29..92a886c1 100644 --- a/include/GuiSys/CGuiFrame.hpp +++ b/include/GuiSys/CGuiFrame.hpp @@ -4,6 +4,7 @@ #include "GuiSys/CGuiWidgetIdDB.hpp" #include "rstl/string.hpp" +class CFinalInput; class CGuiWidget; class CGuiCamera; class CGuiLight; @@ -13,8 +14,10 @@ class CGuiFrame { public: void Update(float dt); void Draw(const CGuiWidgetDrawParms& parms) const; + void ProcessUserInput(const CFinalInput& input); CGuiWidget* FindWidget(const char* name) const; CGuiWidget* FindWidget(const rstl::string& name) const; + bool GetIsFinishedLoading() const; CGuiCamera* GetFrameCamera() const { return x14_camera; } void SetFrameCamera(CGuiCamera* camera); diff --git a/include/GuiSys/CGuiTableGroup.hpp b/include/GuiSys/CGuiTableGroup.hpp index d654063b..4ec73dbf 100644 --- a/include/GuiSys/CGuiTableGroup.hpp +++ b/include/GuiSys/CGuiTableGroup.hpp @@ -1,9 +1,12 @@ #ifndef _CGUITABLEGROUP #define _CGUITABLEGROUP -#include "GuiSys/CGuiObject.hpp" +#include "GuiSys/CGuiCompoundWidget.hpp" +#include "Kyoto/TFunctor.hpp" -class CGuiTableGroup { +class CColor; + +class CGuiTableGroup : public CGuiCompoundWidget { public: class CRepeatState { CRepeatState(); @@ -11,6 +14,27 @@ class CGuiTableGroup { private: float x0_timer; }; + + void SetColors(const CColor& selected, const CColor& unselected) const; + int GetUserSelection() const { return xc4_userSelection; } + void SetUserSelection(int sel) { + xc8_prevUserSelection = xc4_userSelection; + xc4_userSelection = sel; + } + void SetMenuAdvanceCallback(const TFunctor1< CGuiTableGroup* const >& cb); + void SetMenuSelectionChangeCallback( + const TFunctor3< CGuiTableGroup* const, const int, const int >& cb); + void SetMenuCancelCallback(const TFunctor1< CGuiTableGroup* const >& cb); + + void SetVertical(bool v) { xd1_vertical = v; } + +private: + char xb8_pad[0xc4 - 0xb8]; + int xc4_userSelection; + int xc8_prevUserSelection; + int xcc_defaultUserSelection; + bool xd0_selectWraparound; + bool xd1_vertical; }; #endif // _CGUITABLEGROUP diff --git a/include/GuiSys/CGuiTextSupport.hpp b/include/GuiSys/CGuiTextSupport.hpp index 01335f4d..e0bd20d0 100644 --- a/include/GuiSys/CGuiTextSupport.hpp +++ b/include/GuiSys/CGuiTextSupport.hpp @@ -3,6 +3,7 @@ #include "Kyoto/SObjectTag.hpp" +#include "Kyoto/Math/CVector2i.hpp" #include "Kyoto/Text/TextCommon.hpp" #include "rstl/pair.hpp" @@ -21,12 +22,7 @@ class CGuiTextProperties { public: CGuiTextProperties(bool wordWrap, bool horizontal, EJustification justification, EVerticalJustification vertJustification, - const rstl::vector< rstl::pair< CAssetId, CAssetId > >* txtrMap = nullptr) - : x0_wordWrap(wordWrap) - , x1_horizontal(horizontal) - , x4_justification(justification) - , x8_vertJustification(vertJustification) - , xc_txtrMap(txtrMap) {} + const rstl::vector< rstl::pair< CAssetId, CAssetId > >* txtrMap = nullptr); private: bool x0_wordWrap; @@ -43,7 +39,8 @@ class CGuiTextSupport { public: CGuiTextSupport(CAssetId fontId, const CGuiTextProperties& props, const CColor& fontCol, const CColor& outlineCol, const CColor& geomCol, int extX, int extY, - CSimplePool* store, int /*CGuiWidget::EGuiModelDrawFlags*/ drawFlags); + CSimplePool* store); + ~CGuiTextSupport(); void SetText(const rstl::wstring&, bool clearRenderBuffer = false); void SetText(const rstl::string&, bool multipage = false); @@ -51,9 +48,28 @@ class CGuiTextSupport { void ClearRenderBuffer(); void SetImageBaseline(bool baseline); bool SetTypeWriteEffectOptions(bool enable, float fadeTime, float rate); + void SetGeometryColor(const CColor& col); void SetOutlineColor(const CColor& col); void SetFontColor(const CColor& col); - void Render() const; + void Render(); + const rstl::pair< CVector2i, CVector2i >& GetBounds(); + bool GetIsTextSupportFinishedLoading() const; + + void SetExtentX(int extent) { + x34_extentX = extent; + ClearRenderBuffer(); + } + void SetExtentY(int extent) { + x38_extentY = extent; + ClearRenderBuffer(); + } + + float GetNumCharsTotal() const; + float GetNumCharactersPrinted() const; + float GetTotalAnimationTime() const; + bool IsAnimationDone() const { return x3c_curTime >= GetTotalAnimationTime(); } + float GetCurTime() const { return x3c_curTime; } + void SetCurTime(float t) { x3c_curTime = t; } static void Initialize(CTextExecuteBuffer* buf, CTextParser* parser) { gpExecBuf = buf; @@ -61,7 +77,11 @@ class CGuiTextSupport { } private: - char x0_pad[0x30c]; + char x0_pad[0x34]; + int x34_extentX; + int x38_extentY; + float x3c_curTime; + char x40_pad[0x30c - 0x40]; }; #endif // _CGUITEXTSUPPORT diff --git a/include/GuiSys/CGuiWidget.hpp b/include/GuiSys/CGuiWidget.hpp index 4d98ea22..d2c663c6 100644 --- a/include/GuiSys/CGuiWidget.hpp +++ b/include/GuiSys/CGuiWidget.hpp @@ -61,6 +61,7 @@ class CGuiWidget : public CGuiObject { short GetWorkerId() const { return xb4_workerId; } void SetDepthTest(bool depthTest) { xb6_31_depthTest = depthTest; } + void SetIsSelectable(bool selectable) { xb6_27_isSelectable = selectable; } void SetIsVisible(bool visible); void SetIsActive(bool active); void SetColor(const CColor& color); diff --git a/include/GuiSys/CGuiWidgetDrawParms.hpp b/include/GuiSys/CGuiWidgetDrawParms.hpp index d45c1769..1bb6005f 100644 --- a/include/GuiSys/CGuiWidgetDrawParms.hpp +++ b/include/GuiSys/CGuiWidgetDrawParms.hpp @@ -4,10 +4,9 @@ #include "Kyoto/Math/CVector3f.hpp" class CGuiWidgetDrawParms { -private: +public: static CGuiWidgetDrawParms sDefaultDrawParms; -public: CGuiWidgetDrawParms(float alpha) : mAlpha(alpha), mCameraOffset(0.f, 0.f, 0.f) {} CGuiWidgetDrawParms(float alpha, const CVector3f& offset) : mAlpha(alpha), mCameraOffset(offset) {} float GetAlpha() const { return mAlpha; } diff --git a/include/Kyoto/Audio/CAudioSys.hpp b/include/Kyoto/Audio/CAudioSys.hpp index 8107e014..81a41d15 100644 --- a/include/Kyoto/Audio/CAudioSys.hpp +++ b/include/Kyoto/Audio/CAudioSys.hpp @@ -95,7 +95,7 @@ class CAudioSys { static void SysSetVolume(uchar, ushort, uchar); static void SysSetSfxVolume(uchar, ushort, uchar, uchar); static bool SysLoadGroupSet(CSimplePool*, uint); - static bool SysLoadGroupSet(TLockedToken< CAudioGroupSet >, rstl::string, uint); + static bool SysLoadGroupSet(const CToken&, const rstl::string&, uint); static const rstl::string& SysGetGroupSetName(uint); static bool SysPushGroupIntoARAM(const rstl::string& name, uchar); static void SysPopGroupFromARAM(); diff --git a/include/Kyoto/Audio/CStaticAudioPlayer.hpp b/include/Kyoto/Audio/CStaticAudioPlayer.hpp index 92d8deec..7fed9278 100644 --- a/include/Kyoto/Audio/CStaticAudioPlayer.hpp +++ b/include/Kyoto/Audio/CStaticAudioPlayer.hpp @@ -28,7 +28,7 @@ class CStaticAudioPlayer { void DecodeMonoAndMix(ushort* bufIn, ushort* bufOut, int numSamples, int curSample, int sampleEnd, int sampleStart, int vol, g72x_state& state); - void SetVolume(char vol); + void SetVolume(uchar vol); private: rstl::string x0_filepath; diff --git a/include/Kyoto/Audio/CStreamAudioManager.hpp b/include/Kyoto/Audio/CStreamAudioManager.hpp index 21644070..63c085f9 100644 --- a/include/Kyoto/Audio/CStreamAudioManager.hpp +++ b/include/Kyoto/Audio/CStreamAudioManager.hpp @@ -34,6 +34,7 @@ class CStreamAudioManager { static void Update(float dt); static void StopAll(); + static void FadeBackIn(float time); static void StopOneShot(); static void SetMusicVolume(uint vol); static void SetSfxVolume(uint vol); @@ -53,7 +54,7 @@ class CStreamAudioManager { static void fn_803653F8(float fadeTime); static void fn_80365424(float fadeTime); - static void fn_8036590C(float fadeTime); + // static void fn_8036590C(float fadeTime); // renamed to FadeBackIn private: static void HandleMusicUnmute(); diff --git a/include/Kyoto/CResFactory.hpp b/include/Kyoto/CResFactory.hpp index b65eeaac..0739511b 100644 --- a/include/Kyoto/CResFactory.hpp +++ b/include/Kyoto/CResFactory.hpp @@ -14,19 +14,21 @@ class CResFactory : public IFactory { public: CResFactory(); - ~CResFactory(); - CFactoryFnReturn Build(const SObjectTag&, const CVParamTransfer&); - void BuildAsync(const SObjectTag&, const CVParamTransfer&, IObj**); - void CancelBuild(const SObjectTag&); - bool CanBuild(const SObjectTag&); - const SObjectTag* GetResourceIdByName(const char* name) const; + ~CResFactory() override; + CFactoryFnReturn Build(const SObjectTag&, const CVParamTransfer&) override; + void BuildAsync(const SObjectTag&, const CVParamTransfer&, IObj**) override; + void CancelBuild(const SObjectTag&) override; + bool CanBuild(const SObjectTag&) override; + const SObjectTag* GetResourceIdByName(const char* name) const override; + + FourCC GetResourceTypeById(CAssetId id) { return GetResLoader().GetResourceTypeById(id); } uint ResourceSize(const SObjectTag& tag) const { return x4_resLoader.ResourceSize(tag); } void AsyncIdle(uint time); CResLoader& GetResLoader() { return x4_resLoader; } - FourCC GetResourceTypeById(CAssetId id) { return GetResLoader().GetResourceTypeById(id); } + CInputStream* LoadResourceFromMemorySync(const SObjectTag& tag, const void* extBuf) { return x4_resLoader.LoadResourceFromMemorySync(tag, extBuf); } diff --git a/include/Kyoto/CResLoader.hpp b/include/Kyoto/CResLoader.hpp index 36a836bd..c037f44a 100644 --- a/include/Kyoto/CResLoader.hpp +++ b/include/Kyoto/CResLoader.hpp @@ -34,6 +34,7 @@ class CResLoader { CDvdRequest* LoadResourceAsync(const SObjectTag& tag, char*); FourCC GetResourceTypeById(CAssetId) const; + bool ResourceExists(const SObjectTag& tag) const; uint ResourceSize(const SObjectTag& tag) const; private: diff --git a/include/Kyoto/Graphics/CGraphics.hpp b/include/Kyoto/Graphics/CGraphics.hpp index 3849a747..bd5a1ed2 100644 --- a/include/Kyoto/Graphics/CGraphics.hpp +++ b/include/Kyoto/Graphics/CGraphics.hpp @@ -340,9 +340,9 @@ class CGraphics { static void VideoPostCallback(u32 retraceCount); static const CViewport& GetViewport() { return mViewport; } - static void GetViewport(int& left, int& bottom, int& width, int& height) { + static void GetViewport(int& left, int& top, int& width, int& height) { left = mViewport.mLeft; - bottom = mViewport.mTop; + top = mViewport.mTop; width = mViewport.mWidth; height = mViewport.mHeight; } diff --git a/include/Kyoto/Graphics/CMoviePlayer.hpp b/include/Kyoto/Graphics/CMoviePlayer.hpp index 8615097b..5024e254 100644 --- a/include/Kyoto/Graphics/CMoviePlayer.hpp +++ b/include/Kyoto/Graphics/CMoviePlayer.hpp @@ -2,6 +2,7 @@ #define _CMOVIEPLAYER #include "Kyoto/CDvdFile.hpp" +#include "Kyoto/Math/CVector3f.hpp" #include "types.h" class CMoviePlayer { @@ -18,6 +19,11 @@ class CMoviePlayer { uint GetAudioSamplesConsumed() const; void SetAudioSamplesConsumed(uint); }; + enum EPlayMode { + kPM_Stopped = 0, + kPM_Playing = 1 + }; + static void SetSfxVolume(uchar); CMoviePlayer(const char*, float, bool, bool); @@ -25,20 +31,29 @@ class CMoviePlayer { void Update(float); bool DrawVideo() const; + void DrawFrame(const CVector3f& v1, const CVector3f& v2, const CVector3f& v3, const CVector3f& v4); + int GetWidth() const; + int GetHeight() const; + bool CanDrawVideo() const { return xac_drawState == 0; } + bool PumpIndexLoad(); + void Rewind(); + void SetPlayMode(EPlayMode mode); + float GetTotalSeconds() const; + bool GetIsFullyCached() const; + bool GetIsMovieFinishedPlaying() const; + bool IsLooping() const { return (xf4_flags & 0x80) != 0; } + float GetPlayedSeconds() const; private: CDvdFile x0_movieFile; - uint x84_; - uint x88_; - uint x8c_; - uchar x90_; - uint x94_; - uint x98_; - uint x9c_; - uint xa0_; - uint xa4_; - uint xa8_; - // char x0_pad[0x100]; + char x28_pad1[0x6c - sizeof(CDvdFile)]; + int x6c_width; + int x70_height; + char x74_pad2[0xac - 0x74]; + uint xac_drawState; + char xb0_pad3[0xf4 - 0xb0]; + uchar xf4_flags; + char xf5_pad4[0x100 - 0xf5]; }; #endif // _CMOVIEPLAYER diff --git a/include/Kyoto/IFactory.hpp b/include/Kyoto/IFactory.hpp index 84b3e337..8d5a2428 100644 --- a/include/Kyoto/IFactory.hpp +++ b/include/Kyoto/IFactory.hpp @@ -2,6 +2,7 @@ #define _IFACTORY #include +#include class SObjectTag; class CVParamTransfer; diff --git a/include/Kyoto/TFunctor.hpp b/include/Kyoto/TFunctor.hpp new file mode 100644 index 00000000..a795ed64 --- /dev/null +++ b/include/Kyoto/TFunctor.hpp @@ -0,0 +1,82 @@ +#ifndef _TFUNCTOR +#define _TFUNCTOR + +#include "types.h" +#include + +template < class A1 > +class TFunctor1 { +public: + typedef void (*CallOp)(void*, void*, A1); + + TFunctor1() : x0_callop(nullptr), x4_obj(nullptr) { + x8_ptmf[0] = 0; + x8_ptmf[1] = 0; + x8_ptmf[2] = 0; + } + + template < class T, class MFn > + TFunctor1(T* obj, MFn fn) { + int ptmf[3]; + memcpy(ptmf, &fn, sizeof(ptmf)); + x0_callop = &Thunk< T >; + x4_obj = obj; + memcpy(x8_ptmf, ptmf, sizeof(x8_ptmf)); + } + + void operator()(A1 a1) const { x0_callop(x4_obj, const_cast< int* >(x8_ptmf), a1); } + +private: + template < class T > + static void Thunk(void* obj, void* ptmf_data, A1 a1) { + void (T::*fn)(A1); + memcpy(&fn, ptmf_data, sizeof(fn)); + (static_cast< T* >(obj)->*fn)(a1); + } + + CallOp x0_callop; + void* x4_obj; + int x8_ptmf[3]; + int x14_pad; +}; + +template < class A1, class A2, class A3 > +class TFunctor3 { +public: + typedef void (*CallOp)(void*, void*, A1, A2); + + TFunctor3() : x0_callop(nullptr), x4_obj(nullptr) { + x8_ptmf[0] = 0; + x8_ptmf[1] = 0; + x8_ptmf[2] = 0; + } + + template < class T, class MFn > + TFunctor3(T* obj, MFn fn) { + int ptmf[3]; + memcpy(ptmf, &fn, sizeof(ptmf)); + x0_callop = &Thunk< T >; + x4_obj = obj; + memcpy(x8_ptmf, ptmf, sizeof(x8_ptmf)); + } + + void operator()(A1 a1, A2 a2, A3 a3) const { + x0_callop(x4_obj, const_cast< int* >(x8_ptmf), a1, a2); + } + +private: + template < class T > + static void Thunk(void* obj, void* ptmf_data, A1 a1, A2 a2) { + typedef void (T::*Fn)(A1, A2); + Fn fn; + memcpy(&fn, ptmf_data, sizeof(fn)); + (static_cast< T* >(obj)->*fn)(a1, a2); + } + + CallOp x0_callop; + void* x4_obj; + int x8_ptmf[3]; + int x14_pad; +}; + +#endif // _TFUNCTOR diff --git a/include/MetroidPrime/CFrontEndUI.hpp b/include/MetroidPrime/CFrontEndUI.hpp index efcc30d0..5ded2504 100644 --- a/include/MetroidPrime/CFrontEndUI.hpp +++ b/include/MetroidPrime/CFrontEndUI.hpp @@ -3,8 +3,162 @@ #include "MetroidPrime/CIOWin.hpp" +#include "Kyoto/CToken.hpp" +#include "Kyoto/TToken.hpp" + +#include "Kyoto/Math/CVector3f.hpp" + +#include "rstl/auto_ptr.hpp" +#include "rstl/reserved_vector.hpp" +#include "rstl/single_ptr.hpp" +#include "rstl/string.hpp" +#include "rstl/vector.hpp" + +class CArchitectureQueue; +class CAudioGroupSet; +class CDependencyGroup; +class CGuiFrame; +class CGuiModel; +class CGuiSliderGroup; +class CGuiTableGroup; +class CGuiTextPane; +class CGuiWidget; +class CMoviePlayer; +class CStaticAudioPlayer; +class CTexture; +class CGBASupport; +class CNESEmulator; +class CSaveGameScreen; +class CQuitGameScreen; +class CGuiTextSupport; +class CFinalInput; +class CRumbleGenerator; +class SOptionsFrontEndFrame; + class CFrontEndUI : public CIOWin { public: + enum EPhase { + kP_LoadDepsGroup = 0, + kP_LoadDeps, + kP_LoadFrames, + kP_LoadMovies, + kP_DisplayFrontEnd, + kP_ToPlayGame, + kP_ExitFrontEnd + }; + + enum EScreen { + kS_OpenCredits = 0, + kS_Title, + kS_AttractMovie, + kS_FileSelect, + kS_FusionBonus, + kS_ToPlayGame + }; + + enum EMenuMovie { + kMM_Stopped = -1, + kMM_FirstStart = 0, + kMM_StartLoop, + kMM_StartFileSelectA, + kMM_FileSelectLoop, + kMM_FileSelectPlayGameA, + kMM_FileSelectGBA, + kMM_GBALoop, + kMM_GBAFileSelectA, + kMM_GBAFileSelectB + }; + + struct SGuiTextPair { + CGuiTextPane* x0_panes[2]; + + SGuiTextPair(); + SGuiTextPair& operator=(const SGuiTextPair& other) { + x0_panes[0] = other.x0_panes[0]; + x0_panes[1] = other.x0_panes[1]; + return *this; + } + void SetPairText(const rstl::wstring& str); + void SetPairText(const wchar_t* str); + }; + + struct SFileSelectOption { + CGuiWidget* x0_base; + rstl::reserved_vector< SGuiTextPair, 4 > x4_textpanes; + int x28_curField; + float x2c_chRate; + + static float ComputeRandom(); + }; + + struct SNewFileSelectFrame { + enum ESubMenu { + kSM_Root = 0, + kSM_EraseGame, + kSM_EraseGamePopup, + kSM_NewGamePopup + }; + + enum EAction { + kA_None = 0, + kA_GameOptions, + kA_FusionBonus, + kA_SlideShow + }; + + uint x0_rnd; + CSaveGameScreen* x4_saveUI; + ESubMenu x8_subMenu; + EAction xc_action; + TCachedToken< CGuiFrame > x10_frme; + CGuiFrame* x1c_loadedFrame; + CGuiTableGroup* x20_tablegroup_fileselect; + CGuiModel* x24_model_erase; + SGuiTextPair x28_textpane_erase; + SGuiTextPair x30_textpane_cheats; + SGuiTextPair x38_textpane_gba; + CGuiTableGroup* x40_tablegroup_popup; + CGuiModel* x44_model_dash7; + SGuiTextPair x48_textpane_popupadvance; + SGuiTextPair x50_textpane_popupcancel; + SGuiTextPair x58_textpane_popupextra; + CGuiTextPane* x60_textpane_cancel; + rstl::reserved_vector< SFileSelectOption, 3 > x64_fileSelections; + CVector3f xf8_model_erase_position; + float x104_rowPitch; + float x108_curTime; + bool x10c_saveReady; + bool x10d_needsEraseToggle; + bool x10e_needsNewToggle; + + SNewFileSelectFrame(CSaveGameScreen* saveUI, uint rnd); + ~SNewFileSelectFrame(); + bool PumpLoad(); + void FinishedLoading(); + uint GetUserFileSelection() const; + void Update(float dt); + EAction ProcessUserInput(const CFinalInput& input); + void Draw() const; + void HandleActiveChange(CGuiWidget* active); + void DoFileselectAdvance(const CGuiTableGroup* caller); + void SetupFrameContents(); + void ClearFrameContents(); + void EnterErase(); + void ResetFrame(); + void ActivateNewGamePopup(); + void DeactivateNewGamePopup(); + void ActivateExistingGamePopup(); + void DeactivateExistingGamePopup(); + bool IsTextDoneAnimating(); + void DoSelectionChange(const CGuiTableGroup* caller); + void DoFileselectCancel(const CGuiTableGroup* caller); + void DoPopupAdvance(const CGuiTableGroup* caller); + void DoPopupCancel(const CGuiTableGroup* caller); + + static SFileSelectOption FindFileSelectOption(CGuiFrame* frame, int idx); + static void StartTextAnimating(CGuiTextPane* text, rstl::wstring str, float chRate); + }; + struct SFusionBonusFrame { struct SGBALinkFrame { enum EUIType { @@ -20,14 +174,196 @@ class CFrontEndUI : public CIOWin { kUIT_Complete = 8, kUIT_Cancelled = 9 }; + + enum EAction { + kGA_None = 0, + kGA_Complete = 1, + kGA_Cancelled = 2 + }; + + EUIType x0_uiType; + CGBASupport* x4_gbaSupport; + CGuiFrame* x8_frme; + SGuiTextPair xc_textpane_instructions; + CGuiTextPane* x14_textpane_yes; + CGuiTextPane* x18_textpane_no; + CGuiModel* x1c_model_gc; + CGuiModel* x20_model_gba; + CGuiModel* x24_model_cable; + CGuiModel* x28_model_circlegcport; + CGuiModel* x2c_model_circlegbaport; + CGuiModel* x30_model_circlestartselect; + CGuiModel* x34_model_pakout; + CGuiModel* x38_model_gbascreen; + CGuiModel* x3c_model_connect; + bool x40_linkInProgress; + + SGBALinkFrame(const CGuiFrame* frme, CGBASupport* support, bool linkInProgress); + ~SGBALinkFrame(); + void Draw(); + void FinishedLoading(); + void Update(float dt); + EAction ProcessUserInput(const CFinalInput& input, bool linkInProgress); + void SetUIText(EUIType tp); + }; + + enum EAction { + kFA_None = 0, + kFA_GoBack = 1, + kFA_PlayNESMetroid = 2 }; + + rstl::single_ptr< SGBALinkFrame > x0_gbaLinkFrame; + rstl::single_ptr< CGBASupport > x4_gbaSupport; + EAction x8_action; + TCachedToken< CGuiFrame > xc_gbaScreen; + TCachedToken< CGuiFrame > x18_gbaLink; + CGuiFrame* x24_loadedFrame; + CGuiTableGroup* x28_tablegroup_options; + CGuiTableGroup* x2c_tablegroup_fusionsuit; + SGuiTextPair x30_textpane_instructions; + bool x38_lastDoDraw; + bool x39_fusionNotComplete; + bool x3a_mpNotComplete; + + SFusionBonusFrame(); + ~SFusionBonusFrame(); + void Draw(); + void Update(float dt, const CSaveGameScreen* saveUI); + EAction ProcessUserInput(const CFinalInput& input, const CSaveGameScreen* saveUI); + bool PumpLoad(); + void FinishedLoading(); + void ResetCompletionFlags(); + void SetTableColors(CGuiTableGroup* tbgp); + void DoOptionsAdvance(const CGuiTableGroup* caller); + void DoSelectionChange(const CGuiTableGroup* caller); + void DoOptionsCancel(const CGuiTableGroup* caller); }; + + struct SFrontEndFrame { + enum EAction { + kEA_None = 0, + kEA_StartGame, + kEA_FusionBonus, + kEA_GameOptions, + kEA_SlideShow + }; + + uint x0_rnd; + EAction x4_action; + TCachedToken< CGuiFrame > x8_frme; + CGuiFrame* x14_loadedFrme; + CGuiTableGroup* x18_tablegroup_mainmenu; + SGuiTextPair x1c_gbaPair; + SGuiTextPair x24_cheatPair; + + SFrontEndFrame(uint rnd); + ~SFrontEndFrame(); + bool PumpLoad(); + void FinishedLoading(); + void Update(float dt); + EAction ProcessUserInput(const CFinalInput& input); + void Draw(); + void DoAdvance(const CGuiTableGroup* caller); + void DoSelectionChange(const CGuiTableGroup* caller); + void HandleActiveChange(const CGuiTableGroup* caller); + void DoCancel(const CGuiTableGroup* caller); + + static SGuiTextPair FindTextPanePair(const CGuiFrame* frame, const char* name); + static void FindAndSetPairText(CGuiFrame& frame, const char* name, const wchar_t* str); + }; + + struct SNesEmulatorFrame { + enum EMode { + kEM_Emulator = 0, + kEM_SaveProgress, + kEM_ContinuePlaying, + kEM_QuitNESMetroid + }; + + EMode x0_mode; + rstl::single_ptr< CNESEmulator > x4_nesEmu; + rstl::single_ptr< CQuitGameScreen > x8_quitScreen; + rstl::single_ptr< CGuiTextSupport > xc_textSupport; + float x10_remTime; + bool x14_emulationSuspended; + bool x15_enableFiltering; + + SNesEmulatorFrame(); + ~SNesEmulatorFrame(); + void SetMode(EMode mode); + int Update(float dt, CSaveGameScreen& saveUi); + void ProcessUserInput(const CFinalInput& input, const CSaveGameScreen* sui); + void Draw(const CSaveGameScreen& saveUi); + }; + CFrontEndUI(); + ~CFrontEndUI(); + + EMessageReturn OnMessage(const CArchitectureMessage& message, CArchitectureQueue& queue) override; + void Draw() const override; - EMessageReturn OnMessage(const CArchitectureMessage& message, CArchitectureQueue& queue); + static void PlayAdvanceSfx(); private: - uchar pad[0xe4]; + void TransitionToFive(); + void UpdateMusicVol(); + void FinishedLoadingDepsGroup(); + bool PumpLoad(); + EMessageReturn Update(float dt, CArchitectureQueue& queue); + bool PumpMovieLoad(); + void UpdateMovies(float dt); + void ProcessUserInput(const CFinalInput& input, CArchitectureQueue& queue); + bool IsInScreenNotTransitioning(EScreen screen) const { + return x50_curScreen == screen && x54_nextScreen == screen; + } + bool GetHasAttractMovies() const { return xc0_attractCount > 0; } + bool CanShowSaveUI(); + void StartStateTransition(EScreen screen); + void CompleteStateTransition(); + void StartAttractMovie(); + void StopAttractMovie(); + void SetCurrentMovie(EMenuMovie movie); + const char* GetNextAttractMovieFileName(); + static const char* GetAttractMovieFileName(int idx); + void SetFadeBlackTimer(float seconds); + void SetFadeBlackWithMovie(); + void StartSlideShow(CArchitectureQueue& queue); + + EPhase x14_phase; + uint x18_rndA; + uint x1c_rndB; + TToken< CDependencyGroup > x20_depsGroup; + rstl::vector< CToken > x28_deps; + TCachedToken< CTexture > x38_pressStart; + TCachedToken< CAudioGroupSet > x44_frontendAudioGrp; + EScreen x50_curScreen; + EScreen x54_nextScreen; + float x58_fadeBlackTimer; + bool x5c_fadeBlackWithMovie; + float x60_pressStartTime; + float x64_pressStartAlpha; + float x68_musicVol; + rstl::reserved_vector< rstl::auto_ptr< CMoviePlayer >, 9 > x6c_menuMovies; + EMenuMovie xb8_curMovie; + int xbc_nextAttract; + int xc0_attractCount; + rstl::auto_ptr< CMoviePlayer > xc4_attractMovie; + CMoviePlayer* xcc_curMoviePtr; + bool xd0_playerSkipToTitle; + bool xd1_moviesLoaded; + bool xd2_deferSlideShow; + rstl::single_ptr< CStaticAudioPlayer > xd4_audio1; + rstl::single_ptr< CStaticAudioPlayer > xd8_audio2; + rstl::single_ptr< CSaveGameScreen > xdc_saveUI; + rstl::single_ptr< SNewFileSelectFrame > xe0_frontendCardFrme; + rstl::single_ptr< SFusionBonusFrame > xe4_fusionBonusFrme; + rstl::single_ptr< SFrontEndFrame > xe8_frontendNoCardFrme; + rstl::single_ptr< SNesEmulatorFrame > xec_emuFrme; + rstl::single_ptr< SOptionsFrontEndFrame > xf0_optionsFrme; + CStaticAudioPlayer* xf4_curAudio; }; +CHECK_SIZEOF(CFrontEndUI, 0xf8) + #endif // _CFRONTENDUI diff --git a/include/MetroidPrime/CMain.hpp b/include/MetroidPrime/CMain.hpp index 71a2d501..17f520b7 100644 --- a/include/MetroidPrime/CMain.hpp +++ b/include/MetroidPrime/CMain.hpp @@ -81,6 +81,7 @@ class CMain { void SetRestartMode(const ERestartMode s) { x12c_restartMode = s; } ERestartMode GetRestartMode() const { return x12c_restartMode; } void SetCardBusy(bool v) { x160_31_cardBusy = v; } + bool GetCardBusy() const { return x160_31_cardBusy; } void SetMaxSpeed(bool v) { // ? diff --git a/include/MetroidPrime/CMemoryCard.hpp b/include/MetroidPrime/CMemoryCard.hpp index 1fcf91c7..e45d50ec 100644 --- a/include/MetroidPrime/CMemoryCard.hpp +++ b/include/MetroidPrime/CMemoryCard.hpp @@ -7,11 +7,16 @@ #include "MetroidPrime/TGameTypes.hpp" #include "MetroidPrime/Player/CWorldSaveGameInfo.hpp" +class CSaveWorldMemory; + class CMemoryCard { public: ~CMemoryCard(); // TODO + bool HasSaveWorldMemory(int wldId); + const CSaveWorldMemory& GetSaveWorldMemory(int wldId) const; + rstl::pair< CAssetId, TAreaId > GetAreaAndWorldIdForSaveId(int saveId) const; typedef rstl::pair< CAssetId, CWorldSaveGameInfo::EScanCategory > ScanState; diff --git a/include/MetroidPrime/CNESEmulator.hpp b/include/MetroidPrime/CNESEmulator.hpp new file mode 100644 index 00000000..fa1b6e72 --- /dev/null +++ b/include/MetroidPrime/CNESEmulator.hpp @@ -0,0 +1,28 @@ +#ifndef _CNESEMULATOR +#define _CNESEMULATOR + +#include "types.h" + +class CColor; +class CFinalInput; + +class CNESEmulator { +public: + CNESEmulator(); + ~CNESEmulator(); + + void Draw(const CColor& color, bool enableFiltering); + void Update(); + void ProcessUserInput(const CFinalInput& input, int); + + const char* GetPassword(); + bool IsGameOver(); + void LoadPassword(const char* password); + int GetPasswordEntryState(); + +private: + char x0_pad[0x54]; +}; +CHECK_SIZEOF(CNESEmulator, 0x54) + +#endif // _CNESEMULATOR diff --git a/include/MetroidPrime/CQuitGameScreen.hpp b/include/MetroidPrime/CQuitGameScreen.hpp new file mode 100644 index 00000000..ffd5caa0 --- /dev/null +++ b/include/MetroidPrime/CQuitGameScreen.hpp @@ -0,0 +1,44 @@ +#ifndef _CQUITGAMESCREEN +#define _CQUITGAMESCREEN + +#include "Kyoto/TToken.hpp" + +class CGuiFrame; +class CGuiTableGroup; +class CFinalInput; + +enum EQuitType { + kQT_QuitGame, + kQT_ContinueFromLastSave, + kQT_SaveProgress, + kQT_QuitNESMetroid, + kQT_ContinuePlaying +}; + +enum EQuitAction { + kQA_None, + kQA_Yes, + kQA_No +}; + +class CQuitGameScreen { +public: + CQuitGameScreen(EQuitType type); + + void SetColors(); + void FinishedLoading(); + void DoSelectionChange(CGuiTableGroup* caller); + void DoAdvance(CGuiTableGroup* caller); + EQuitAction Update(float dt); + void Draw(); + void ProcessUserInput(const CFinalInput& input); + +private: + EQuitType x0_type; + TLockedToken< CGuiFrame > x4_frame; + CGuiFrame* x10_loadedFrame; + CGuiTableGroup* x14_tablegroup_quitgame; + EQuitAction x18_action; +}; + +#endif // _CQUITGAMESCREEN diff --git a/include/MetroidPrime/CSaveGameScreen.hpp b/include/MetroidPrime/CSaveGameScreen.hpp new file mode 100644 index 00000000..f8419a8d --- /dev/null +++ b/include/MetroidPrime/CSaveGameScreen.hpp @@ -0,0 +1,39 @@ +#ifndef _CSAVEGAMESCREEN +#define _CSAVEGAMESCREEN + +#include "types.h" + +class CFinalInput; + +class CSaveGameScreen { +public: + enum EUIType { + kUIT_SaveReady = 16 + }; + + CSaveGameScreen(int saveContext, u64 cardSerial); + ~CSaveGameScreen(); + int Update(float dt); + bool PumpLoad(); + + int GetUIType() const { return x10_uiType; } + bool IsSavingDisabled() const { return x92_savingDisabled; } + const void* GetGameData(int idx); + void EraseGame(int idx); + void StartGame(int idx); + void ResetCardDriver(); + void ProcessUserInput(const CFinalInput& input); + void Draw(); + bool IsHiddenFromFrontEnd(); + void SetInGame(bool inGame); + void SaveNESState(); + +private: + uchar x0_pad[0x10]; + int x10_uiType; + uchar x14_pad[0x92 - 0x14]; + bool x92_savingDisabled; + uchar x93_pad[0x98 - 0x93]; +}; + +#endif // _CSAVEGAMESCREEN diff --git a/include/MetroidPrime/CSaveWorldMemory.hpp b/include/MetroidPrime/CSaveWorldMemory.hpp new file mode 100644 index 00000000..4824078a --- /dev/null +++ b/include/MetroidPrime/CSaveWorldMemory.hpp @@ -0,0 +1,11 @@ +#ifndef _CSAVEWORLDMEMORY +#define _CSAVEWORLDMEMORY + +#include "types.h" + +class CSaveWorldMemory { +public: + const wchar_t* GetFrontEndName() const; +}; + +#endif // _CSAVEWORLDMEMORY diff --git a/include/MetroidPrime/CSlideShow.hpp b/include/MetroidPrime/CSlideShow.hpp new file mode 100644 index 00000000..b5d44a42 --- /dev/null +++ b/include/MetroidPrime/CSlideShow.hpp @@ -0,0 +1,21 @@ +#ifndef _CSLIDESHOW +#define _CSLIDESHOW + +#include "MetroidPrime/CIOWin.hpp" + +class CSlideShow : public CIOWin { +public: + CSlideShow(); + + EMessageReturn OnMessage(const CArchitectureMessage&, CArchitectureQueue&) override; + bool GetIsContinueDraw() const override; + void Draw() const override; + + static uint SlideShowGalleryFlags(); + +private: + u8 x14_pad[0x138 - 0x14]; +}; +CHECK_SIZEOF(CSlideShow, 0x138) + +#endif // _CSLIDESHOW diff --git a/include/MetroidPrime/CStateSetterFlow.hpp b/include/MetroidPrime/CStateSetterFlow.hpp index cd9787b8..11a29974 100644 --- a/include/MetroidPrime/CStateSetterFlow.hpp +++ b/include/MetroidPrime/CStateSetterFlow.hpp @@ -6,7 +6,8 @@ class CStateSetterFlow : public CIOWin { public: CStateSetterFlow(); - EMessageReturn OnMessage(const CArchitectureMessage& message, CArchitectureQueue& queue); + ~CStateSetterFlow(); + EMessageReturn OnMessage(const CArchitectureMessage& message, CArchitectureQueue& queue) override; }; #endif // _CSTATESETTERFLOW diff --git a/include/MetroidPrime/Player/CGameOptions.hpp b/include/MetroidPrime/Player/CGameOptions.hpp index e0948676..46716f7b 100644 --- a/include/MetroidPrime/Player/CGameOptions.hpp +++ b/include/MetroidPrime/Player/CGameOptions.hpp @@ -35,6 +35,7 @@ class CGameOptions { void SetMusicVolume(const int,const bool); void SetSurroundMode(CAudioSys::ESurroundModes, bool); + int GetMusicVolume() const { return x5c_musicVol; } const float GetHudAlpha() const; const float GetHelmetAlpha() const; void SetHelmetAlpha(const int); diff --git a/include/MetroidPrime/Player/CGameState.hpp b/include/MetroidPrime/Player/CGameState.hpp index 271d8e4a..a451b324 100644 --- a/include/MetroidPrime/Player/CGameState.hpp +++ b/include/MetroidPrime/Player/CGameState.hpp @@ -47,6 +47,7 @@ class CGameState { void SetCardSerial(u64 serial) { x210_cardSerial = serial; } u64 GetCardSerial() const { return x210_cardSerial; } bool GetHardMode() const { return x228_24_hardMode; } + void SetHardMode(bool v); float GetHardModeWeaponMultiplier() const; rstl::rc_ptr< CWorldTransManager >& WorldTransitionManager(); // { return x9c_transManager.GetPtr(); } diff --git a/include/MetroidPrime/Player/CSystemState.hpp b/include/MetroidPrime/Player/CSystemState.hpp index 479b21db..219e1b69 100644 --- a/include/MetroidPrime/Player/CSystemState.hpp +++ b/include/MetroidPrime/Player/CSystemState.hpp @@ -16,7 +16,12 @@ class CSystemState { ~CSystemState(); void PutTo(COutputStream&) const; + void SetFusionLinked(bool v); + void SetFusionBeat(bool v); void SetHasFusion(bool v); + bool GetFusionLinked() const { return xd0_24_fusionLinked; } + bool GetNormalModeBeat() const { return xd0_25_normalModeBeat; } + bool GetFusionBeat() const { return xd0_27_fusionBeat; } bool GetHasFusion() const { return xd0_28_fusionSuitActive; } bool GetCinematicState(rstl::pair< CAssetId, TEditorId > cineId) const; @@ -28,6 +33,8 @@ class CSystemState { bool GetShowPowerBombAmmoMessage() const; void IncrementPowerBombAmmoCount(); + char* GetNESState() { return reinterpret_cast< char* >(x0_nesState.data()); } + bool GetAllItemsCollected() const { return xd0_29_allItemsCollected; } void SetAllItemsCollected(bool); diff --git a/include/MetroidPrime/SOptionsFrontEndFrame.hpp b/include/MetroidPrime/SOptionsFrontEndFrame.hpp new file mode 100644 index 00000000..ea659ee5 --- /dev/null +++ b/include/MetroidPrime/SOptionsFrontEndFrame.hpp @@ -0,0 +1,21 @@ +#ifndef _SOPTIONSFRONTENDFRAME +#define _SOPTIONSFRONTENDFRAME + +#include "types.h" + +class CFinalInput; +class CSaveGameScreen; + +class SOptionsFrontEndFrame { +public: + SOptionsFrontEndFrame(); + ~SOptionsFrontEndFrame(); + void Update(float dt, const CSaveGameScreen* saveUI); + bool ProcessUserInput(const CFinalInput& input, const CSaveGameScreen* saveUI); + void Draw(); + +private: + uchar x0_pad[0x138]; +}; + +#endif // _SOPTIONSFRONTENDFRAME diff --git a/include/rstl/string.hpp b/include/rstl/string.hpp index b8a84ecd..79efd32f 100644 --- a/include/rstl/string.hpp +++ b/include/rstl/string.hpp @@ -160,6 +160,7 @@ string string_l(const char* data); // } string operator+(const string& a, const string& b); +wstring operator+(const wstring& a, const wstring& b); // { // string result(a); // result.append(b); diff --git a/src/Kyoto/Audio/CStaticAudioPlayer.cpp b/src/Kyoto/Audio/CStaticAudioPlayer.cpp index 88c2dd72..646e2282 100644 --- a/src/Kyoto/Audio/CStaticAudioPlayer.cpp +++ b/src/Kyoto/Audio/CStaticAudioPlayer.cpp @@ -223,7 +223,7 @@ void CStaticAudioPlayer::DecodeMonoAndMix(ushort* bufIn, ushort* bufOut, int num } } -void CStaticAudioPlayer::SetVolume(char vol) { +void CStaticAudioPlayer::SetVolume(uchar vol) { if (static_cast< uchar >(vol) > 127) { vol = 127; } diff --git a/src/Kyoto/Audio/CStreamAudioManager.cpp b/src/Kyoto/Audio/CStreamAudioManager.cpp index b10270a3..08de1ac5 100644 --- a/src/Kyoto/Audio/CStreamAudioManager.cpp +++ b/src/Kyoto/Audio/CStreamAudioManager.cpp @@ -326,7 +326,7 @@ bool CStreamedAudioManager::AreStringsNotEqual(const char* lhs, const char* rhs) return CPatterned::CompareStateString(lhs, rhs, -1) != 0; } -void CStreamAudioManager::fn_8036590C(float fadeTime) { +void CStreamAudioManager::FadeBackIn(float fadeTime) { if (fadeTime == 0.f) { mVolumeIncrement2 = mCurrentVolume; mVolumeIncrement = mTargetVolume; diff --git a/src/Kyoto/Audio/DolphinCAudioSys.cpp b/src/Kyoto/Audio/DolphinCAudioSys.cpp index 37bc3796..dc74ad44 100644 --- a/src/Kyoto/Audio/DolphinCAudioSys.cpp +++ b/src/Kyoto/Audio/DolphinCAudioSys.cpp @@ -242,14 +242,16 @@ bool CAudioSys::SysLoadGroupSet(CSimplePool* pool, const uint id) { return SysLoadGroupSet(group, group->GetName(), id); } -bool CAudioSys::SysLoadGroupSet(TLockedToken< CAudioGroupSet > group, rstl::string name, +bool CAudioSys::SysLoadGroupSet(const CToken& group, const rstl::string& name, const uint id) { if (FindGroupSet(name)) { return true; } + CToken tok(group); + CAudioGroupSet* grpSet = reinterpret_cast< CAudioGroupSet* >(tok.GetObj()->GetContents()); mpGroupSetDB->insert(rstl::pair< rstl::string, rstl::ncrc_ptr< CAudioGroupSet > >( - name, rstl::ncrc_ptr< CAudioGroupSet >(group.GetT()))); + name, rstl::ncrc_ptr< CAudioGroupSet >(grpSet))); mpGroupSetResNameDB->insert(rstl::pair< uint, rstl::string >(id, name)); return false; } diff --git a/src/MetroidPrime/CCredits.cpp b/src/MetroidPrime/CCredits.cpp index e9971741..b7ca5f86 100644 --- a/src/MetroidPrime/CCredits.cpp +++ b/src/MetroidPrime/CCredits.cpp @@ -72,8 +72,7 @@ CIOWin::EMessageReturn CCredits::Update(float dt, CArchitectureQueue& queue) { ->GetId(), CGuiTextProperties(true, true, kJustification_Center, kVerticalJustification_Top), gpTweakGui->GetCreditsTextFontColor(), gpTweakGui->GetCreditsTextBorderColor(), - CColor::White(), CGraphics::GetViewport().mWidth - 64, 0, gpSimplePool, - CGuiWidget::kGMDF_Alpha), + CColor::White(), CGraphics::GetViewport().mWidth - 64, 0, gpSimplePool), CVector2i(0, 0))); // x30_text.back().first->SetText(x18_creditsTable->GetString(i)); } diff --git a/src/MetroidPrime/CFrontEndUI.cpp b/src/MetroidPrime/CFrontEndUI.cpp index 431fb0e5..e34651cd 100644 --- a/src/MetroidPrime/CFrontEndUI.cpp +++ b/src/MetroidPrime/CFrontEndUI.cpp @@ -1,8 +1,61 @@ +#pragma inline_max_size(250) + #include "MetroidPrime/CFrontEndUI.hpp" + +#include "Kyoto/Audio/CAudioGroupSet.hpp" +#include "Kyoto/Audio/CSfxManager.hpp" +#include "Kyoto/Audio/CAudioSys.hpp" +#include "Kyoto/Audio/CStaticAudioPlayer.hpp" +#include "Kyoto/Audio/CStreamAudioManager.hpp" +#include "Kyoto/Basics/CBasics.hpp" #include "Kyoto/Basics/RAssertDolphin.hpp" +#include "Kyoto/Graphics/CColor.hpp" +#include "Kyoto/CDependencyGroup.hpp" +#include "Kyoto/CDvdFile.hpp" +#include "Kyoto/CResFactory.hpp" +#include "Kyoto/CSimplePool.hpp" +#include "Kyoto/Graphics/CMoviePlayer.hpp" +#include "Kyoto/Graphics/CTexture.hpp" +#include "Kyoto/Text/CStringTable.hpp" #include "Kyoto/SObjectTag.hpp" -#include "MetroidPrime/SFX/FrontEnd.h" + +#include "GuiSys/CGuiFrame.hpp" +#include "GuiSys/CGuiModel.hpp" +#include "GuiSys/CGuiTableGroup.hpp" +#include "GuiSys/CGuiTextPane.hpp" +#include "GuiSys/CGuiTextSupport.hpp" +#include "GuiSys/CGuiWidget.hpp" +#include "GuiSys/CGuiWidgetDrawParms.hpp" + +#include "MetroidPrime/Decode.hpp" +#include "MetroidPrime/CMain.hpp" +#include "MetroidPrime/CMemoryCard.hpp" +#include "MetroidPrime/CSaveWorldMemory.hpp" +#include "MetroidPrime/CSlideShow.hpp" +#include "MetroidPrime/CGBASupport.hpp" +#include "MetroidPrime/CNESEmulator.hpp" +#include "MetroidPrime/CQuitGameScreen.hpp" +#include "MetroidPrime/CSaveGameScreen.hpp" +#include "MetroidPrime/SOptionsFrontEndFrame.hpp" +#include "MetroidPrime/CStateSetterFlow.hpp" #include "MetroidPrime/DefaultWorld.hpp" +#include "MetroidPrime/Player/CGameState.hpp" +#include "MetroidPrime/Tweaks/CTweakGame.hpp" + +#include "MetroidPrime/SFX/FrontEnd.h" + +#include "Kyoto/Input/CFinalInput.hpp" +#include "Kyoto/Graphics/CGraphics.hpp" +#include "Kyoto/Math/CTransform4f.hpp" +#include "MetaRender/CCubeRenderer.hpp" +#include "MetroidPrime/Cameras/CCameraFilterPass.hpp" + +#include "rstl/math.hpp" +#include "rstl/StringExtras.hpp" + +#include +#include +#include struct FEMovie { const char* path; @@ -18,24 +71,28 @@ static const FEMovie FEMovies[] = { {"Video/06_fileselect_GBA.thp", false}, {"Video/07_GBAloop.thp", true}, {"Video/08_GBA_fileselect.thp", false}, - {nullptr, false}, + {"Video/08_GBA_fileselect.thp", false}, }; const char MetroidBuildInfo[] = BUILD_INFO; const char* BuildTime = MetroidBuildInfo + BUILD_INFO_TAG_SIZE; -static const u16 FETransitionBackSFX[3][2] = { +static const s16 FETransitionBackSFX[3][2] = { {SFXfnt_transfore_00L, SFXfnt_transfore_00R}, {SFXfnt_transfore_01L, SFXfnt_transfore_01R}, {SFXfnt_transfore_02L, SFXfnt_transfore_02R}, }; -static const u16 FETransitionForwardSFX[3][2] = { +static const s16 FETransitionForwardSFX[3][2] = { {SFXfnt_transback_00L, SFXfnt_transback_00R}, {SFXfnt_transback_01L, SFXfnt_transback_01R}, {SFXfnt_transback_02L, SFXfnt_transback_02R}, }; +static const char* kFrontEndAGSCName = "FrontEnd_AGSC"; +static const char* kAudioFrontend1Path = "Audio/frontend_1.rsf"; +static const char* kAudioFrontend2Path = "Audio/frontend_2.rsf"; + static const float AudioFadeTimeB[3] = { 4.1999998f, 6.0999999f, @@ -73,3 +130,2325 @@ static const CFrontEndUI::SFusionBonusFrame::SGBALinkFrame::EUIType PrevLinkUI[1 CFrontEndUI::SFusionBonusFrame::SGBALinkFrame::kUIT_Empty, CFrontEndUI::SFusionBonusFrame::SGBALinkFrame::kUIT_Empty, }; + +// PlayAdvanceSfx +void CFrontEndUI::PlayAdvanceSfx() { + CSfxManager::SfxStart(SFXui_x_start_00); + CSfxManager::SfxStart(SFXui_x_start_00r); +} + +// SFrontEndFrame::FindAndSetPairText +void CFrontEndUI::SFrontEndFrame::FindAndSetPairText(CGuiFrame& frame, const char* name, + const wchar_t* str) { + CGuiTextPane* w1 = static_cast< CGuiTextPane* >(frame.FindWidget(name)); + w1->TextSupport().SetText(rstl::wstring(str)); + CGuiTextPane* w2 = + static_cast< CGuiTextPane* >(frame.FindWidget(CBasics::Stringize("%sb", name))); + w2->TextSupport().SetText(rstl::wstring(str)); +} + +// SGuiTextPair::SGuiTextPair +CFrontEndUI::SGuiTextPair::SGuiTextPair() { + x0_panes[0] = nullptr; + x0_panes[1] = nullptr; +} + +// SFrontEndFrame::FindTextPanePair +CFrontEndUI::SGuiTextPair CFrontEndUI::SFrontEndFrame::FindTextPanePair(const CGuiFrame* frame, + const char* name) { + SGuiTextPair ret; + ret.x0_panes[0] = static_cast< CGuiTextPane* >(frame->FindWidget(name)); + ret.x0_panes[1] = + static_cast< CGuiTextPane* >(frame->FindWidget(CBasics::Stringize("%sb", name))); + return ret; +} + +// SGuiTextPair::SetPairText +void CFrontEndUI::SGuiTextPair::SetPairText(const wchar_t* str) { + x0_panes[0]->TextSupport().SetText(rstl::wstring(str)); + x0_panes[1]->TextSupport().SetText(rstl::wstring(str)); +} + +// SGuiTextPair::SetPairText (wstring overload) +void CFrontEndUI::SGuiTextPair::SetPairText(const rstl::wstring& str) { + x0_panes[0]->TextSupport().SetText(str); + x0_panes[1]->TextSupport().SetText(str); +} + +// SNesEmulatorFrame::SNesEmulatorFrame +CFrontEndUI::SNesEmulatorFrame::SNesEmulatorFrame() +: x0_mode(kEM_Emulator) +, x4_nesEmu(rs_new CNESEmulator()) +, x8_quitScreen(nullptr) +, xc_textSupport(nullptr) +, x10_remTime(8.f) +, x14_emulationSuspended(false) +, x15_enableFiltering(true) { + xc_textSupport = + rs_new CGuiTextSupport(gpResourceFactory->GetResourceIdByName("FONT_Deface14B")->GetId(), + CGuiTextProperties(false, true, kJustification_Left, + kVerticalJustification_Center, nullptr), + CColor(0xFFFFFFFFu), CColor::Black(), CColor(0xFFFFFFFFu), 0, 0, + gpSimplePool); + xc_textSupport->SetText(rstl::wstring_l(gpStringTable->GetString(0x67))); + xc_textSupport->SetExtentX(xc_textSupport->GetBounds().second.GetX()); + xc_textSupport->SetExtentY(xc_textSupport->GetBounds().second.GetY()); +} + +// SNesEmulatorFrame::~SNesEmulatorFrame +CFrontEndUI::SNesEmulatorFrame::~SNesEmulatorFrame() {} + +// SNesEmulatorFrame::SetMode +void CFrontEndUI::SNesEmulatorFrame::SetMode(EMode mode) { + switch (mode) { + case kEM_Emulator: + x8_quitScreen = nullptr; + break; + case kEM_SaveProgress: + x8_quitScreen = nullptr; + x8_quitScreen = rs_new CQuitGameScreen(kQT_SaveProgress); + break; + case kEM_ContinuePlaying: + x8_quitScreen = nullptr; + x8_quitScreen = rs_new CQuitGameScreen(kQT_ContinuePlaying); + break; + case kEM_QuitNESMetroid: + x8_quitScreen = nullptr; + x8_quitScreen = rs_new CQuitGameScreen(kQT_QuitNESMetroid); + break; + default: + break; + } + x0_mode = mode; +} + +// SNesEmulatorFrame::Update +int CFrontEndUI::SNesEmulatorFrame::Update(float dt, CSaveGameScreen& saveUi) { + bool doUpdate = true; + if (&saveUi != nullptr && saveUi.GetUIType() != 0x10) { + doUpdate = false; + } + + x10_remTime = rstl::max_val(0.f, x10_remTime - dt); + + CGuiTextSupport* textSupport = xc_textSupport.get(); + const CColor& geomCol = CColor::White().WithAlphaOf(rstl::min_val(x10_remTime, 1.f)); + textSupport->SetGeometryColor(geomCol); + + if (xc_textSupport->GetIsTextSupportFinishedLoading()) { + xc_textSupport->SetExtentX(xc_textSupport->GetBounds().second.GetX()); + xc_textSupport->SetExtentY(xc_textSupport->GetBounds().second.GetY()); + } + + if (doUpdate) { + switch (x0_mode) { + case kEM_Emulator: { + x4_nesEmu->Update(); + if (!x4_nesEmu->IsGameOver()) { + x14_emulationSuspended = false; + } + if (x4_nesEmu->IsGameOver() && !x14_emulationSuspended) { + x14_emulationSuspended = true; + if (&saveUi != nullptr && !saveUi.IsSavingDisabled()) { + SetMode(kEM_SaveProgress); + break; + } + SetMode(kEM_ContinuePlaying); + break; + } + if (x4_nesEmu->GetPasswordEntryState() == 1) { + if (&saveUi != nullptr) { + x4_nesEmu->LoadPassword(gpGameState->SystemState().GetNESState()); + } + } + break; + } + case kEM_SaveProgress: { + if (&saveUi != nullptr) { + EQuitAction action = x8_quitScreen->Update(dt); + if (action == kQA_Yes) { + memcpy(gpGameState->SystemState().GetNESState(), x4_nesEmu->GetPassword(), 0x12); + saveUi.SaveNESState(); + SetMode(kEM_ContinuePlaying); + } else if (action == kQA_No) { + SetMode(kEM_ContinuePlaying); + } + } else { + SetMode(kEM_ContinuePlaying); + } + break; + } + case kEM_ContinuePlaying: { + EQuitAction action = x8_quitScreen->Update(dt); + if (action == kQA_Yes) { + SetMode(kEM_Emulator); + } else if (action == kQA_No) { + return true; + } + break; + } + case kEM_QuitNESMetroid: { + EQuitAction action = x8_quitScreen->Update(dt); + if (action == kQA_Yes) { + return true; + } else if (action == kQA_No) { + SetMode(kEM_Emulator); + } + break; + } + default: + break; + } + } + + return false; +} + +// SNesEmulatorFrame::ProcessUserInput +void CFrontEndUI::SNesEmulatorFrame::ProcessUserInput(const CFinalInput& input, + const CSaveGameScreen* sui) { + bool doInput = true; + if (sui != nullptr && sui->GetUIType() != 0x10) { + doInput = false; + } + + if (sui != nullptr) { + const_cast< CSaveGameScreen* >(sui)->ProcessUserInput(input); + } + + if (!doInput) { + return; + } + + switch (x0_mode) { + case kEM_Emulator: + x4_nesEmu->ProcessUserInput(input, 4); + if (input.ControllerNumber() == 0 && input.PL()) { + SetMode(kEM_QuitNESMetroid); + } + break; + case kEM_SaveProgress: + case kEM_ContinuePlaying: + case kEM_QuitNESMetroid: + x8_quitScreen->ProcessUserInput(input); + break; + default: + break; + } +} + +// SNesEmulatorFrame::Draw +void CFrontEndUI::SNesEmulatorFrame::Draw(const CSaveGameScreen& saveUi) { + CColor mulColor = CColor::White(); + CColor dimColor(static_cast< uchar >(0x60), static_cast< uchar >(0x60), + static_cast< uchar >(0x60), static_cast< uchar >(0xFF)); + + bool blackout = false; + if (&saveUi != nullptr && saveUi.GetUIType() != 0x10) { + blackout = true; + } + + if (blackout) { + mulColor = CColor(0u); + } else if (x8_quitScreen.get() != nullptr) { + mulColor = dimColor; + } + + x4_nesEmu->Draw(mulColor, x15_enableFiltering); + + if (!blackout && x8_quitScreen.get() != nullptr) { + x8_quitScreen->Draw(); + } else { + CGraphics::SetUseVideoFilter(x15_enableFiltering); + } + + if (x10_remTime < 7.5f && x10_remTime > 0.f) { + if (xc_textSupport->GetIsTextSupportFinishedLoading()) { + CGraphics::SetCullMode(kCM_None); + gpRender->SetViewportOrtho(true, -4096.f, 4096.f); + gpRender->SetBlendMode_AlphaBlended(); + gpRender->SetDepthReadWrite(false, false); + CGraphics::SetModelMatrix(CTransform4f::Translate(-280.f, 0.f, -160.f)); + xc_textSupport->Render(); + } + } +} + +// SGBALinkFrame::SGBALinkFrame +CFrontEndUI::SFusionBonusFrame::SGBALinkFrame::SGBALinkFrame(const CGuiFrame* frme, + CGBASupport* support, + bool linkInProgress) +: x0_uiType(kUIT_Empty) +, x4_gbaSupport(support) +, x8_frme(const_cast< CGuiFrame* >(frme)) +, xc_textpane_instructions() +, x14_textpane_yes(nullptr) +, x18_textpane_no(nullptr) +, x1c_model_gc(nullptr) +, x20_model_gba(nullptr) +, x24_model_cable(nullptr) +, x28_model_circlegcport(nullptr) +, x2c_model_circlegbaport(nullptr) +, x30_model_circlestartselect(nullptr) +, x34_model_pakout(nullptr) +, x38_model_gbascreen(nullptr) +, x3c_model_connect(nullptr) +, x40_linkInProgress(linkInProgress) { + support->InitializeSupport(); + FinishedLoading(); +} + +// SGBALinkFrame::~SGBALinkFrame +CFrontEndUI::SFusionBonusFrame::SGBALinkFrame::~SGBALinkFrame() {} + +// SGBALinkFrame::Draw +void CFrontEndUI::SFusionBonusFrame::SGBALinkFrame::Draw() { + x8_frme->Draw(CGuiWidgetDrawParms::sDefaultDrawParms); +} + +// SGBALinkFrame::FinishedLoading +void CFrontEndUI::SFusionBonusFrame::SGBALinkFrame::FinishedLoading() { + xc_textpane_instructions = SFrontEndFrame::FindTextPanePair(x8_frme, "textpane_instructions"); + x14_textpane_yes = static_cast< CGuiTextPane* >(x8_frme->FindWidget("textpane_yes")); + x18_textpane_no = static_cast< CGuiTextPane* >(x8_frme->FindWidget("textpane_no")); + x1c_model_gc = static_cast< CGuiModel* >(x8_frme->FindWidget("model_gc")); + x20_model_gba = static_cast< CGuiModel* >(x8_frme->FindWidget("model_gba")); + x24_model_cable = static_cast< CGuiModel* >(x8_frme->FindWidget("model_cable")); + x28_model_circlegcport = static_cast< CGuiModel* >(x8_frme->FindWidget("model_circlegcport")); + x2c_model_circlegbaport = static_cast< CGuiModel* >(x8_frme->FindWidget("model_circlegbaport")); + x30_model_circlestartselect = static_cast< CGuiModel* >(x8_frme->FindWidget("model_circlestartselect")); + x34_model_pakout = static_cast< CGuiModel* >(x8_frme->FindWidget("model_pakout")); + x38_model_gbascreen = static_cast< CGuiModel* >(x8_frme->FindWidget("model_gbascreen")); + x3c_model_connect = static_cast< CGuiModel* >(x8_frme->FindWidget("model_connect")); + SetUIText(kUIT_InsertPak); +} + +// SGBALinkFrame::Update +void CFrontEndUI::SFusionBonusFrame::SGBALinkFrame::Update(float dt) { + x4_gbaSupport->Update(dt); + x8_frme->Update(dt); +} + +// SGBALinkFrame::ProcessUserInput +CFrontEndUI::SFusionBonusFrame::SGBALinkFrame::EAction +CFrontEndUI::SFusionBonusFrame::SGBALinkFrame::ProcessUserInput(const CFinalInput& input, + bool linkInProgress) { + if (linkInProgress != x40_linkInProgress) { + x40_linkInProgress = linkInProgress; + SetUIText(x0_uiType); + } + + switch (x0_uiType) { + case kUIT_InsertPak: + case kUIT_ConnectSocket: + case kUIT_PressStartAndSelect: + case kUIT_BeginLink: + case kUIT_LinkFailed: + case kUIT_LinkCompleteOrLinking: + case kUIT_TurnOffGBA: + if (input.PA()) { + PlayAdvanceSfx(); + SetUIText(NextLinkUI[x0_uiType]); + } else if (input.PB()) { + if (PrevLinkUI[x0_uiType] == kUIT_Empty) + break; + CSfxManager::SfxStart(SFXfnt_back, 0x7f, 0x40, false, CSfxManager::kMedPriority, false, + CSfxManager::kAllAreas); + SetUIText(PrevLinkUI[x0_uiType]); + } + break; + case kUIT_Linking: { + if (x4_gbaSupport->GetPhase() == CGBASupport::kP_Complete) { + if (x4_gbaSupport->IsFusionLinked()) + gpGameState->SystemState().SetFusionLinked(true); + if (x4_gbaSupport->IsFusionBeat()) + gpGameState->SystemState().SetFusionBeat(true); + if (x4_gbaSupport->IsFusionLinked()) { + PlayAdvanceSfx(); + SetUIText(kUIT_LinkCompleteOrLinking); + } else { + CSfxManager::SfxStart(SFXfnt_back, 0x7f, 0x40, false, CSfxManager::kMedPriority, false, + CSfxManager::kAllAreas); + SetUIText(kUIT_LinkFailed); + } + } else if (x4_gbaSupport->GetPhase() == CGBASupport::kP_Failed) { + CSfxManager::SfxStart(SFXfnt_back, 0x7f, 0x40, false, CSfxManager::kMedPriority, false, + CSfxManager::kAllAreas); + SetUIText(kUIT_LinkFailed); + } + break; + } + case kUIT_Complete: + return kGA_Complete; + case kUIT_Cancelled: + return kGA_Cancelled; + default: + break; + } + + return kGA_None; +} + +// SGBALinkFrame::SetUIText +void CFrontEndUI::SFusionBonusFrame::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 kUIT_InsertPak: + instructions = 0x49; + no = 0x52; + yes = 0x53; + pakoutVisible = true; + circleGbaVisible = true; + break; + case kUIT_ConnectSocket: + instructions = 0x44; + no = 0x52; + yes = 0x53; + cableVisible = true; + circleGcVisible = true; + circleGbaVisible = true; + break; + case kUIT_PressStartAndSelect: + instructions = 0x4a; + no = 0x52; + yes = 0x53; + cableVisible = true; + circleStartVisible = true; + gbaScreenVisible = true; + break; + case kUIT_BeginLink: + instructions = 0x4b; + no = 0x52; + yes = 0x53; + cableVisible = true; + gbaScreenVisible = true; + break; + case kUIT_TurnOffGBA: + instructions = 0x4c; + no = 0x52; + yes = 0x53; + cableVisible = true; + gbaScreenVisible = true; + circleStartVisible = true; + break; + case kUIT_Linking: + x4_gbaSupport->StartLink(); + instructions = 0x48; + cableVisible = true; + gbaScreenVisible = true; + connectVisible = true; + break; + case kUIT_LinkFailed: + instructions = 0x45; + no = 0x52; + yes = 0x54; + cableVisible = true; + circleGcVisible = true; + circleGbaVisible = true; + circleStartVisible = true; + gbaScreenVisible = true; + break; + case kUIT_LinkCompleteOrLinking: + yes = 0x53; + cableVisible = true; + gbaScreenVisible = true; + instructions = x40_linkInProgress ? 0x46 : 0x47; + break; + case kUIT_Complete: + case kUIT_Cancelled: + default: + break; + } + + rstl::wstring emptyStr = rstl::wstring_l(L""); + + xc_textpane_instructions.SetPairText( + instructions == -1 ? emptyStr : rstl::wstring_l(gpStringTable->GetString(instructions))); + + x14_textpane_yes->TextSupport().SetText( + yes == -1 ? emptyStr : rstl::wstring_l(gpStringTable->GetString(yes)), false); + + x18_textpane_no->TextSupport().SetText( + no == -1 ? emptyStr : rstl::wstring_l(gpStringTable->GetString(no)), false); + + x1c_model_gc->SetVisibility(true, kTM_Children); + x20_model_gba->SetVisibility(true, kTM_Children); + x24_model_cable->SetVisibility(cableVisible, kTM_Children); + x28_model_circlegcport->SetVisibility(circleGcVisible, kTM_Children); + x2c_model_circlegbaport->SetVisibility(circleGbaVisible, kTM_Children); + x30_model_circlestartselect->SetVisibility(circleStartVisible, kTM_Children); + x34_model_pakout->SetVisibility(pakoutVisible, kTM_Children); + x38_model_gbascreen->SetVisibility(gbaScreenVisible, kTM_Children); + x3c_model_connect->SetVisibility(connectVisible, kTM_Children); + + x0_uiType = tp; +} + +// CStateSetterFlow::CStateSetterFlow +CStateSetterFlow::CStateSetterFlow() +: CIOWin(rstl::string_l("")) {} + +// CStateSetterFlow::~CStateSetterFlow +CStateSetterFlow::~CStateSetterFlow() {} + +// CStateSetterFlow::OnMessage +CIOWin::EMessageReturn CStateSetterFlow::OnMessage(const CArchitectureMessage& message, + CArchitectureQueue& queue) { + switch (message.GetType()) { + case kAM_TimerTick: + gpMain->RefreshGameState(); + return kMR_RemoveIOWinAndExit; + default: + return kMR_Exit; + } +} + +// SFrontEndFrame::SFrontEndFrame +CFrontEndUI::SFrontEndFrame::SFrontEndFrame(uint rnd) +: x0_rnd(rnd) +, x4_action(kEA_None) +, x8_frme(gpSimplePool->GetObj("FRME_FrontEndPL")) +, x14_loadedFrme(nullptr) +, x18_tablegroup_mainmenu(nullptr) +, x1c_gbaPair() +, x24_cheatPair() { + x8_frme.Lock(); +} + +// SFrontEndFrame::~SFrontEndFrame +CFrontEndUI::SFrontEndFrame::~SFrontEndFrame() {} + +// SFrontEndFrame::PumpLoad +bool CFrontEndUI::SFrontEndFrame::PumpLoad() { + if (x14_loadedFrme) { + return true; + } + if (x8_frme.TryCache()) { + CGuiFrame* frme = x8_frme.GetObject(); + if (frme->GetIsFinishedLoading()) { + x14_loadedFrme = frme; + FinishedLoading(); + return true; + } + } + return false; +} + +// SFrontEndFrame::FinishedLoading +void CFrontEndUI::SFrontEndFrame::FinishedLoading() { + x18_tablegroup_mainmenu = + static_cast< CGuiTableGroup* >(x14_loadedFrme->FindWidget("tablegroup_mainmenu")); + + x1c_gbaPair = FindTextPanePair(x14_loadedFrme, "textpane_gba"); + x1c_gbaPair.SetPairText(gpStringTable->GetString(0x25)); + + x24_cheatPair = FindTextPanePair(x14_loadedFrme, "textpane_cheats"); + x24_cheatPair.SetPairText(gpStringTable->GetString(0x60)); + + FindAndSetPairText(*x14_loadedFrme, "textpane_start", gpStringTable->GetString(0x43)); + FindAndSetPairText(*x14_loadedFrme, "textpane_options", gpStringTable->GetString(0x5e)); + FindAndSetPairText(*x14_loadedFrme, "textpane_title", gpStringTable->GetString(0x62)); + + CGuiTextPane* proceed = + static_cast< CGuiTextPane* >(x14_loadedFrme->FindWidget("textpane_proceed")); + if (proceed) { + proceed->TextSupport().SetText(rstl::wstring_l(gpStringTable->GetString(0x55))); + } + + x18_tablegroup_mainmenu->SetMenuAdvanceCallback( + TFunctor1< CGuiTableGroup* const >(this, &SFrontEndFrame::DoAdvance)); + x18_tablegroup_mainmenu->SetMenuSelectionChangeCallback( + TFunctor3< CGuiTableGroup* const, const int, const int >( + this, &SFrontEndFrame::DoSelectionChange)); + x18_tablegroup_mainmenu->SetMenuCancelCallback( + TFunctor1< CGuiTableGroup* const >(this, &SFrontEndFrame::DoCancel)); + + HandleActiveChange(x18_tablegroup_mainmenu); +} + +// SFrontEndFrame::Update +void CFrontEndUI::SFrontEndFrame::Update(float dt) { + CGuiWidget* imageGallery = x18_tablegroup_mainmenu->GetWorkerWidget(3); + + if (CSlideShow::SlideShowGalleryFlags()) { + imageGallery->SetIsSelectable(true); + x24_cheatPair.x0_panes[0]->TextSupport().SetFontColor(CColor::White()); + } else { + imageGallery->SetIsSelectable(false); + CGuiTextSupport& textSupport = x24_cheatPair.x0_panes[0]->TextSupport(); + CColor color = CColor::Grey().WithAlphaOf(0.5f); + textSupport.SetFontColor(color); + } + + x14_loadedFrme->Update(dt); +} + +// SFrontEndFrame::ProcessUserInput +CFrontEndUI::SFrontEndFrame::EAction +CFrontEndUI::SFrontEndFrame::ProcessUserInput(const CFinalInput& input) { + x4_action = kEA_None; + x14_loadedFrme->ProcessUserInput(input); + return x4_action; +} + +// SFrontEndFrame::Draw +void CFrontEndUI::SFrontEndFrame::Draw() { + x14_loadedFrme->Draw(CGuiWidgetDrawParms::sDefaultDrawParms); +} + +// SFrontEndFrame::DoAdvance +void CFrontEndUI::SFrontEndFrame::DoAdvance(const CGuiTableGroup* caller) { + switch (x18_tablegroup_mainmenu->GetUserSelection()) { + case 0: + CSfxManager::SfxStart(FETransitionForwardSFX[x0_rnd][0], 0x7f, 0x40, false, + CSfxManager::kMedPriority, false, CSfxManager::kAllAreas); + CSfxManager::SfxStart(FETransitionForwardSFX[x0_rnd][1], 0x7f, 0x40, false, + CSfxManager::kMedPriority, false, CSfxManager::kAllAreas); + x4_action = kEA_StartGame; + break; + case 1: + x4_action = kEA_FusionBonus; + break; + case 2: + PlayAdvanceSfx(); + x4_action = kEA_GameOptions; + break; + case 3: + PlayAdvanceSfx(); + x4_action = kEA_SlideShow; + break; + default: + break; + } +} + +// SFrontEndFrame::DoSelectionChange +void CFrontEndUI::SFrontEndFrame::DoSelectionChange(const CGuiTableGroup* caller) { + CSfxManager::SfxStart(SFXfnt_selection_change, 0x7f, 0x40, false, CSfxManager::kMedPriority, false, + CSfxManager::kAllAreas); + HandleActiveChange(caller); +} + +// SFrontEndFrame::HandleActiveChange +void CFrontEndUI::SFrontEndFrame::HandleActiveChange(const CGuiTableGroup* caller) { + CColor selected((uchar)0xFF, (uchar)0xFF, (uchar)0xFF, (uchar)0xFF); + CColor unselected((uchar)0xA0, (uchar)0xA0, (uchar)0xA0, (uchar)0xC8); + caller->SetColors(selected, unselected); +} + +// SFrontEndFrame::DoCancel +void CFrontEndUI::SFrontEndFrame::DoCancel(const CGuiTableGroup* caller) {} + +// SFileSelectOption::ComputeRandom +float CFrontEndUI::SFileSelectOption::ComputeRandom() { + return rand() / static_cast< float >(RAND_MAX) * 30.f + 30.f; +} + +// SNewFileSelectFrame::StartTextAnimating +void CFrontEndUI::SNewFileSelectFrame::StartTextAnimating(CGuiTextPane* text, rstl::wstring str, + float chRate) { + text->TextSupport().SetText(rstl::wstring_l(L"")); + text->TextSupport().SetText(str); + text->TextSupport().SetTypeWriteEffectOptions(true, 0.1f, chRate); +} + +// SNewFileSelectFrame::FindFileSelectOption +CFrontEndUI::SFileSelectOption +CFrontEndUI::SNewFileSelectFrame::FindFileSelectOption(CGuiFrame* frame, int idx) { + SFileSelectOption opt; + opt.x0_base = frame->FindWidget(CBasics::Stringize("basewidget_file%d", idx)); + opt.x28_curField = 0; + opt.x2c_chRate = SFileSelectOption::ComputeRandom(); + + char buf[44]; + sprintf(buf, "textpane_filename%d", idx); + opt.x4_textpanes.push_back(SFrontEndFrame::FindTextPanePair(frame, buf)); + + sprintf(buf, "textpane_world%d", idx); + opt.x4_textpanes.push_back(SFrontEndFrame::FindTextPanePair(frame, buf)); + + sprintf(buf, "textpane_playtime%d", idx); + opt.x4_textpanes.push_back(SFrontEndFrame::FindTextPanePair(frame, buf)); + + sprintf(buf, "textpane_date%d", idx); + opt.x4_textpanes.push_back(SFrontEndFrame::FindTextPanePair(frame, buf)); + + return opt; +} + +// SNewFileSelectFrame::SNewFileSelectFrame +CFrontEndUI::SNewFileSelectFrame::SNewFileSelectFrame(CSaveGameScreen* saveUI, uint rnd) +: x0_rnd(rnd) +, x4_saveUI(saveUI) +, x8_subMenu(kSM_Root) +, xc_action(kA_None) +, x10_frme(gpSimplePool->GetObj("FRME_NewFileSelect")) +, x1c_loadedFrame(nullptr) +, x20_tablegroup_fileselect(nullptr) +, x24_model_erase(nullptr) +, x28_textpane_erase() +, x30_textpane_cheats() +, x38_textpane_gba() +, x40_tablegroup_popup(nullptr) +, x44_model_dash7(nullptr) +, x48_textpane_popupadvance() +, x50_textpane_popupcancel() +, x58_textpane_popupextra() +, x60_textpane_cancel(nullptr) +, x64_fileSelections() +, xf8_model_erase_position(CVector3f::Zero()) +, x104_rowPitch(0.f) +, x108_curTime(0.f) +, x10c_saveReady(false) +, x10d_needsEraseToggle(false) +, x10e_needsNewToggle(false) { + x10_frme.Lock(); +} + +// SNewFileSelectFrame::~SNewFileSelectFrame +CFrontEndUI::SNewFileSelectFrame::~SNewFileSelectFrame() {} + +// SNewFileSelectFrame::PumpLoad +bool CFrontEndUI::SNewFileSelectFrame::PumpLoad() { + if (x1c_loadedFrame) { + return true; + } + if (x10_frme.TryCache()) { + CGuiFrame* frme = x10_frme.GetObject(); + if (frme->GetIsFinishedLoading()) { + x1c_loadedFrame = frme; + FinishedLoading(); + return true; + } + } + return false; +} + +// fn_80020B98 (stub) +// fn_80020B34 (stub) + +// SNewFileSelectFrame::FinishedLoading +void CFrontEndUI::SNewFileSelectFrame::FinishedLoading() { + x20_tablegroup_fileselect = + static_cast< CGuiTableGroup* >(x1c_loadedFrame->FindWidget("tablegroup_fileselect")); + x24_model_erase = + static_cast< CGuiModel* >(x1c_loadedFrame->FindWidget("model_erase")); + xf8_model_erase_position = x24_model_erase->GetLocalPosition(); + + x28_textpane_erase = SFrontEndFrame::FindTextPanePair(x1c_loadedFrame, "textpane_erase"); + x38_textpane_gba = SFrontEndFrame::FindTextPanePair(x1c_loadedFrame, "textpane_gba"); + x30_textpane_cheats = SFrontEndFrame::FindTextPanePair(x1c_loadedFrame, "textpane_cheats"); + x48_textpane_popupadvance = + SFrontEndFrame::FindTextPanePair(x1c_loadedFrame, "textpane_popupadvance"); + x50_textpane_popupcancel = + SFrontEndFrame::FindTextPanePair(x1c_loadedFrame, "textpane_popupcancel"); + x58_textpane_popupextra = + SFrontEndFrame::FindTextPanePair(x1c_loadedFrame, "textpane_popupextra"); + + x40_tablegroup_popup = + static_cast< CGuiTableGroup* >(x1c_loadedFrame->FindWidget("tablegroup_popup")); + x44_model_dash7 = + static_cast< CGuiModel* >(x1c_loadedFrame->FindWidget("model_dash7")); + x60_textpane_cancel = + static_cast< CGuiTextPane* >(x1c_loadedFrame->FindWidget("textpane_cancel")); + + SFrontEndFrame::FindAndSetPairText(*x1c_loadedFrame, "textpane_title", + gpStringTable->GetString(0x61)); + + CGuiTextPane* proceed = + static_cast< CGuiTextPane* >(x1c_loadedFrame->FindWidget("textpane_proceed")); + if (proceed) { + proceed->TextSupport().SetText(rstl::wstring_l(gpStringTable->GetString(0x55))); + } + + x40_tablegroup_popup->SetIsVisible(false); + x40_tablegroup_popup->SetIsActive(false); + x40_tablegroup_popup->SetVertical(false); + x40_tablegroup_popup->GetWorkerWidget(2)->SetIsSelectable(false); + x40_tablegroup_popup->GetWorkerWidget(2)->SetVisibility(false, kTM_Children); + + x20_tablegroup_fileselect->SetMenuAdvanceCallback( + TFunctor1< CGuiTableGroup* const >(this, &SNewFileSelectFrame::DoFileselectAdvance)); + x20_tablegroup_fileselect->SetMenuSelectionChangeCallback( + TFunctor3< CGuiTableGroup* const, const int, const int >( + this, &SNewFileSelectFrame::DoSelectionChange)); + x20_tablegroup_fileselect->SetMenuCancelCallback( + TFunctor1< CGuiTableGroup* const >(this, &SNewFileSelectFrame::DoFileselectCancel)); + + x40_tablegroup_popup->SetMenuAdvanceCallback( + TFunctor1< CGuiTableGroup* const >(this, &SNewFileSelectFrame::DoPopupAdvance)); + x40_tablegroup_popup->SetMenuSelectionChangeCallback( + TFunctor3< CGuiTableGroup* const, const int, const int >( + this, &SNewFileSelectFrame::DoSelectionChange)); + x40_tablegroup_popup->SetMenuCancelCallback( + TFunctor1< CGuiTableGroup* const >(this, &SNewFileSelectFrame::DoPopupCancel)); + + for (int i = 0; i < 3; ++i) { + x64_fileSelections.push_back(FindFileSelectOption(x1c_loadedFrame, i)); + } + + x104_rowPitch = + (x64_fileSelections[1].x0_base->GetLocalPosition() - + x64_fileSelections[0].x0_base->GetLocalPosition()).GetZ(); +} + +// SNewFileSelectFrame::GetUserFileSelection +uint CFrontEndUI::SNewFileSelectFrame::GetUserFileSelection() const { + int sel = x20_tablegroup_fileselect->GetUserSelection(); + return sel < 3 ? sel : 0; +} + +// SNewFileSelectFrame::Update +void CFrontEndUI::SNewFileSelectFrame::Update(float dt) { + bool saveReady = x4_saveUI->GetUIType() == 0x10; + if (saveReady != x10c_saveReady) { + if (saveReady) { + ClearFrameContents(); + } else { + if (x8_subMenu != kSM_Root) { + ResetFrame(); + DeactivateExistingGamePopup(); + DeactivateNewGamePopup(); + x8_subMenu = kSM_Root; + } + } + x10c_saveReady = saveReady; + } + if (x10c_saveReady) { + SetupFrameContents(); + } + x1c_loadedFrame->Update(dt); +} + +// CGuiWidget::GetIsActive (weak function emitted here) +bool CGuiWidget::GetIsActive() const { + return xb6_26_isActive; +} + +// SNewFileSelectFrame::ProcessUserInput +CFrontEndUI::SNewFileSelectFrame::EAction +CFrontEndUI::SNewFileSelectFrame::ProcessUserInput(const CFinalInput& input) { + xc_action = kA_None; + + if (x8_subMenu != kSM_EraseGamePopup) { + x4_saveUI->ProcessUserInput(input); + } + + if (IsTextDoneAnimating()) { + x108_curTime = rstl::min_val(0.5f, x108_curTime + input.Time()); + } + + if (x108_curTime < 0.5f) { + return xc_action; + } + + if (x10c_saveReady) { + x1c_loadedFrame->ProcessUserInput(input); + } + + if (x10d_needsEraseToggle) { + if (x40_tablegroup_popup->GetIsActive()) { + DeactivateExistingGamePopup(); + } else { + ActivateExistingGamePopup(); + } + x10d_needsEraseToggle = false; + } + + if (x10e_needsNewToggle) { + if (x40_tablegroup_popup->GetIsActive()) { + DeactivateNewGamePopup(); + } else { + ActivateNewGamePopup(); + } + x10e_needsNewToggle = false; + } + + return xc_action; +} + +// SNewFileSelectFrame::Draw +void CFrontEndUI::SNewFileSelectFrame::Draw() const { + if (x1c_loadedFrame != NULL && x10c_saveReady) { + x1c_loadedFrame->Draw(CGuiWidgetDrawParms::sDefaultDrawParms); + } +} + +// SNewFileSelectFrame::HandleActiveChange +void CFrontEndUI::SNewFileSelectFrame::HandleActiveChange(CGuiWidget* active) { + if (active != NULL) { + int sel = static_cast< CGuiTableGroup* >(active)->GetUserSelection(); + CColor selected((uchar)0xFF, (uchar)0xFF, (uchar)0xFF, (uchar)0xFF); + CColor unselected((uchar)0xA0, (uchar)0xA0, (uchar)0xA0, (uchar)0xC8); + static_cast< CGuiTableGroup* >(active)->SetColors(selected, unselected); + if (active == x20_tablegroup_fileselect) { + CVector3f pos = + xf8_model_erase_position + CVector3f(0.f, 0.f, sel * x104_rowPitch); + const CTransform4f& xf = CTransform4f::Translate(pos); + CGuiModel* erase = x24_model_erase; + erase->LocalTransform() = xf; + erase->RecalculateTransforms(); + } + bool shouldHide = (x8_subMenu == kSM_Root || x8_subMenu == kSM_NewGamePopup); + if (shouldHide) { + x24_model_erase->SetIsVisible(false); + } else { + x24_model_erase->SetIsVisible(true); + } + } +} + +// SNewFileSelectFrame::DoFileselectAdvance +void CFrontEndUI::SNewFileSelectFrame::DoFileselectAdvance(const CGuiTableGroup* caller) { + int userSel = x20_tablegroup_fileselect->GetUserSelection(); + if (userSel < 3) { + if (x8_subMenu == kSM_EraseGame) { + if (x4_saveUI->GetGameData(userSel) != NULL) { + PlayAdvanceSfx(); + x10d_needsEraseToggle = true; + } + } else { + if (x4_saveUI->GetGameData(userSel) != NULL) { + x4_saveUI->StartGame(userSel); + } else { + x10e_needsNewToggle = true; + } + } + } else if (userSel == 3) { + PlayAdvanceSfx(); + EnterErase(); + } else if (userSel == 4) { + xc_action = kA_FusionBonus; + } else if (userSel == 5) { + xc_action = kA_SlideShow; + } +} + +// SNewFileSelectFrame::SetupFrameContents +void CFrontEndUI::SNewFileSelectFrame::SetupFrameContents() { + for (int i = 0; i < 3; ++i) { + SFileSelectOption& option = x64_fileSelections[i]; + if (option.x28_curField == 4) + continue; + + CGuiTextPane* curPane; + if (option.x28_curField == -1) { + curPane = NULL; + } else { + curPane = option.x4_textpanes[option.x28_curField].x0_panes[0]; + } + + if (curPane != NULL) { + float total = curPane->TextSupport().GetNumCharsTotal(); + float printed = curPane->TextSupport().GetNumCharactersPrinted(); + if (!(printed >= total)) + continue; + } + + ++option.x28_curField; + if (option.x28_curField >= 4) + continue; + + const CGameState::GameFileStateInfo* data = + static_cast< const CGameState::GameFileStateInfo* >(x4_saveUI->GetGameData(i)); + SGuiTextPair& populatePair = option.x4_textpanes[option.x28_curField]; + CGuiTextPane* pane0 = populatePair.x0_panes[0]; + CGuiTextPane* pane1 = populatePair.x0_panes[1]; + rstl::wstring str; + + switch (option.x28_curField) { + case 0: + if (data != NULL) { + char buf[32]; + sprintf(buf, " %02d%%", data->x18_itemPercent); + int strIdx = data->x20_hardMode ? 0x6a : 0x27; + str = rstl::wstring_l(gpStringTable->GetString(strIdx + i)) + + CStringExtras::ConvertToUNICODE(rstl::string_l(buf)); + } else { + str = rstl::wstring(gpStringTable->GetString(0x24)); + } + break; + case 1: + if (data != NULL) { + const wchar_t* worldName = NULL; + if (gpMemoryCard->HasSaveWorldMemory(data->x8_mlvlId)) { + worldName = gpMemoryCard->GetSaveWorldMemory(data->x8_mlvlId).GetFrontEndName(); + } + str = rstl::wstring_l(worldName != NULL ? worldName : L""); + } else { + str = rstl::wstring_l(gpStringTable->GetString(0x33)); + } + break; + case 2: + if (data != NULL) { + int seconds = static_cast< int >(data->x0_playTime); + int hours = seconds / 3600; + int minutes = (seconds % 3600) / 60; + char buf[32]; + sprintf(buf, "%02d:%02d", hours, minutes); + str = CStringExtras::ConvertToUNICODE(rstl::string_l(buf)); + } else { + str = rstl::wstring_l(gpStringTable->GetString(0x34)); + } + break; + case 3: + if (data != NULL) { + str = rstl::wstring_l(gpStringTable->GetString(0x36)); + } else { + str = rstl::wstring_l(gpStringTable->GetString(0x35)); + } + break; + } + + StartTextAnimating(pane0, str, option.x2c_chRate); + StartTextAnimating(pane1, str, option.x2c_chRate); + } +} + +// SNewFileSelectFrame::ClearFrameContents +void CFrontEndUI::SNewFileSelectFrame::ClearFrameContents() { + x108_curTime = 0.f; + bool hasSave = false; + for (int i = 0; i < 3; ++i) { + if (x4_saveUI->GetGameData(i) != NULL) { + hasSave = true; + } + x64_fileSelections[i].x2c_chRate = SFileSelectOption::ComputeRandom(); + x64_fileSelections[i].x28_curField = -1; + for (int j = 0; j < 4; ++j) { + x64_fileSelections[i].x4_textpanes[j].x0_panes[0]->TextSupport().SetText( + rstl::wstring_l(L""), false); + x64_fileSelections[i].x4_textpanes[j].x0_panes[1]->TextSupport().SetText( + rstl::wstring_l(L""), false); + } + } + + StartTextAnimating(x28_textpane_erase.x0_panes[0], + rstl::wstring_l(gpStringTable->GetString(0x26)), 60.f); + StartTextAnimating(x38_textpane_gba.x0_panes[0], + rstl::wstring_l(gpStringTable->GetString(0x25)), 60.f); + StartTextAnimating(x30_textpane_cheats.x0_panes[0], + rstl::wstring_l(gpStringTable->GetString(0x60)), 60.f); + + StartTextAnimating(x28_textpane_erase.x0_panes[1], + rstl::wstring_l(gpStringTable->GetString(0x26)), 60.f); + StartTextAnimating(x38_textpane_gba.x0_panes[1], + rstl::wstring_l(gpStringTable->GetString(0x25)), 60.f); + StartTextAnimating(x30_textpane_cheats.x0_panes[1], + rstl::wstring_l(gpStringTable->GetString(0x60)), 60.f); + + CGuiTextPane* erasePane = x28_textpane_erase.x0_panes[0]; + if (hasSave) { + erasePane->SetIsSelectable(true); + erasePane->TextSupport().SetFontColor(CColor::White()); + } else { + erasePane->SetIsSelectable(false); + erasePane->TextSupport().SetFontColor(CColor::Grey().WithAlphaOf(0.5f)); + } + + x20_tablegroup_fileselect->SetUserSelection(0); + CGuiTextPane* cheats = + static_cast< CGuiTextPane* >(x20_tablegroup_fileselect->GetWorkerWidget(5)); + if (CSlideShow::SlideShowGalleryFlags()) { + cheats->SetIsSelectable(true); + x30_textpane_cheats.x0_panes[0]->TextSupport().SetFontColor(CColor::White()); + } else { + cheats->SetIsSelectable(false); + x30_textpane_cheats.x0_panes[0]->TextSupport().SetFontColor( + CColor::Grey().WithAlphaOf(0.5f)); + } + + HandleActiveChange(x20_tablegroup_fileselect); +} + +// SNewFileSelectFrame::EnterErase +void CFrontEndUI::SNewFileSelectFrame::EnterErase() { + x8_subMenu = kSM_EraseGame; + + x28_textpane_erase.x0_panes[0]->SetIsSelectable(false); + CGuiTextSupport& eraseTS = x28_textpane_erase.x0_panes[0]->TextSupport(); + eraseTS.SetFontColor(CColor::Grey().WithAlphaOf(0.5f)); + + x38_textpane_gba.x0_panes[0]->SetIsSelectable(false); + CGuiTextSupport& gbaTS = x38_textpane_gba.x0_panes[0]->TextSupport(); + gbaTS.SetFontColor(CColor::Grey().WithAlphaOf(0.5f)); + + x30_textpane_cheats.x0_panes[0]->SetIsSelectable(false); + CGuiTextSupport& cheatsTS = x30_textpane_cheats.x0_panes[0]->TextSupport(); + cheatsTS.SetFontColor(CColor::Grey().WithAlphaOf(0.5f)); + + for (int i = 2; i >= 0; --i) { + if (x4_saveUI->GetGameData(i)) { + x64_fileSelections[i].x0_base->SetIsSelectable(true); + x20_tablegroup_fileselect->SetUserSelection(i); + } else { + x64_fileSelections[i].x0_base->SetIsSelectable(false); + } + } + + x60_textpane_cancel->TextSupport().SetText(rstl::wstring_l(gpStringTable->GetString(0x52))); + HandleActiveChange(x20_tablegroup_fileselect); +} + +// SNewFileSelectFrame::ResetFrame +void CFrontEndUI::SNewFileSelectFrame::ResetFrame() { + x8_subMenu = kSM_Root; + + x38_textpane_gba.x0_panes[0]->SetIsSelectable(true); + x38_textpane_gba.x0_panes[0]->TextSupport().SetFontColor(CColor::White()); + + x30_textpane_cheats.x0_panes[0]->SetIsSelectable(true); + x30_textpane_cheats.x0_panes[0]->TextSupport().SetFontColor(CColor::White()); + + ClearFrameContents(); + + for (int i = 2; i >= 0; --i) { + x20_tablegroup_fileselect->GetWorkerWidget(i)->SetIsSelectable(true); + } + + x60_textpane_cancel->TextSupport().SetText(rstl::wstring_l(L"")); +} + +// SNewFileSelectFrame::ActivateNewGamePopup +void CFrontEndUI::SNewFileSelectFrame::ActivateNewGamePopup() { + x40_tablegroup_popup->SetIsActive(true); + x40_tablegroup_popup->SetIsVisible(true); + x40_tablegroup_popup->SetUserSelection(0); + const CTransform4f& xf = + CTransform4f::Translate(0.f, 0.f, + x104_rowPitch * x20_tablegroup_fileselect->GetUserSelection()) * + x40_tablegroup_popup->GetTransform(); + CGuiTableGroup* popup = x40_tablegroup_popup; + popup->LocalTransform() = xf; + popup->RecalculateTransforms(); + x20_tablegroup_fileselect->SetIsActive(false); + x8_subMenu = kSM_NewGamePopup; + HandleActiveChange(x40_tablegroup_popup); + CColor col(static_cast< uchar >(0xff), static_cast< uchar >(0xff), + static_cast< uchar >(0xff), static_cast< uchar >(0x00)); + x64_fileSelections[x20_tablegroup_fileselect->GetUserSelection()].x0_base->SetColor(col); + + PlayAdvanceSfx(); + + if (gpGameState->SystemState().GetNormalModeBeat()) { + x48_textpane_popupadvance.SetPairText(rstl::wstring_l(gpStringTable->GetString(0x66))); + x50_textpane_popupcancel.SetPairText(rstl::wstring_l(gpStringTable->GetString(0x5e))); + x58_textpane_popupextra.SetPairText(rstl::wstring_l(gpStringTable->GetString(0x65))); + + x40_tablegroup_popup->GetWorkerWidget(2)->SetIsSelectable(true); + x40_tablegroup_popup->GetWorkerWidget(2)->SetVisibility(true, kTM_Children); + x44_model_dash7->SetVisibility(true, kTM_Children); + } else { + x48_textpane_popupadvance.SetPairText(rstl::wstring_l(gpStringTable->GetString(0x43))); + x50_textpane_popupcancel.SetPairText(rstl::wstring_l(gpStringTable->GetString(0x5e))); + x44_model_dash7->SetVisibility(false, kTM_Children); + } + x60_textpane_cancel->TextSupport().SetText(rstl::wstring_l(gpStringTable->GetString(0x52))); +} + +// SNewFileSelectFrame::DeactivateNewGamePopup +void CFrontEndUI::SNewFileSelectFrame::DeactivateNewGamePopup() { + x40_tablegroup_popup->SetIsActive(false); + x40_tablegroup_popup->SetIsVisible(false); + x20_tablegroup_fileselect->SetIsActive(true); + + x40_tablegroup_popup->GetWorkerWidget(2)->SetIsSelectable(false); + x40_tablegroup_popup->GetWorkerWidget(2)->SetVisibility(false, kTM_Children); + + x44_model_dash7->SetVisibility(false, kTM_Children); + + x10e_needsNewToggle = false; + HandleActiveChange(x20_tablegroup_fileselect); + CColor white(static_cast< uchar >(0xff), static_cast< uchar >(0xff), + static_cast< uchar >(0xff), static_cast< uchar >(0xff)); + x64_fileSelections[x20_tablegroup_fileselect->GetUserSelection()].x0_base->SetColor(white); + x60_textpane_cancel->TextSupport().SetText(rstl::wstring_l(L"")); +} + +// SNewFileSelectFrame::ActivateExistingGamePopup +void CFrontEndUI::SNewFileSelectFrame::ActivateExistingGamePopup() { + x40_tablegroup_popup->SetIsActive(true); + x40_tablegroup_popup->SetIsVisible(true); + x40_tablegroup_popup->SetUserSelection(0); + const CTransform4f& xf = + CTransform4f::Translate(0.f, 0.f, + x104_rowPitch * x20_tablegroup_fileselect->GetUserSelection()) * + x40_tablegroup_popup->GetTransform(); + CGuiTableGroup* popup = x40_tablegroup_popup; + popup->LocalTransform() = xf; + popup->RecalculateTransforms(); + x20_tablegroup_fileselect->SetIsActive(false); + x8_subMenu = kSM_EraseGamePopup; + HandleActiveChange(x40_tablegroup_popup); + x48_textpane_popupadvance.SetPairText(rstl::wstring_l(gpStringTable->GetString(0x5f))); + x50_textpane_popupcancel.SetPairText(rstl::wstring_l(gpStringTable->GetString(0x26))); + CColor col(static_cast< uchar >(0xff), static_cast< uchar >(0xff), + static_cast< uchar >(0xff), static_cast< uchar >(0x00)); + x64_fileSelections[x20_tablegroup_fileselect->GetUserSelection()].x0_base->SetColor(col); + x44_model_dash7->SetVisibility(false, kTM_Children); +} + +// SNewFileSelectFrame::DeactivateExistingGamePopup +void CFrontEndUI::SNewFileSelectFrame::DeactivateExistingGamePopup() { + x40_tablegroup_popup->SetIsActive(false); + x40_tablegroup_popup->SetIsVisible(false); + x20_tablegroup_fileselect->SetIsActive(true); + HandleActiveChange(x20_tablegroup_fileselect); + CColor white(static_cast< uchar >(0xff), static_cast< uchar >(0xff), + static_cast< uchar >(0xff), static_cast< uchar >(0xff)); + x64_fileSelections[x20_tablegroup_fileselect->GetUserSelection()].x0_base->SetColor(white); +} + +// SNewFileSelectFrame::IsTextDoneAnimating +bool CFrontEndUI::SNewFileSelectFrame::IsTextDoneAnimating() { + for (int i = 0; i < 3; ++i) { + if (x64_fileSelections[i].x28_curField != 4) + return false; + } + + const CGuiTextSupport& ts1 = x28_textpane_erase.x0_panes[0]->GetTextSupport(); + float curTime = ts1.GetCurTime(); + if (curTime < ts1.GetTotalAnimationTime()) + return false; + + const CGuiTextSupport& ts2 = x30_textpane_cheats.x0_panes[0]->GetTextSupport(); + curTime = ts2.GetCurTime(); + if (curTime < ts2.GetTotalAnimationTime()) + return false; + + const CGuiTextSupport& ts3 = x38_textpane_gba.x0_panes[0]->GetTextSupport(); + curTime = ts3.GetCurTime(); + return !(curTime < ts3.GetTotalAnimationTime()); +} + +// SNewFileSelectFrame::DoSelectionChange +void CFrontEndUI::SNewFileSelectFrame::DoSelectionChange(const CGuiTableGroup* caller) { + HandleActiveChange(const_cast< CGuiTableGroup* >(caller)); + CSfxManager::SfxStart(SFXfnt_selection_change, 0x7f, 0x40, false, CSfxManager::kMedPriority, false, + CSfxManager::kAllAreas); +} + +// SNewFileSelectFrame::DoFileselectCancel +void CFrontEndUI::SNewFileSelectFrame::DoFileselectCancel(const CGuiTableGroup* caller) { + if (x8_subMenu == kSM_EraseGame) { + CSfxManager::SfxStart(SFXfnt_back, 0x7f, 0x40, false, CSfxManager::kMedPriority, false, + CSfxManager::kAllAreas); + ResetFrame(); + } +} + +// SNewFileSelectFrame::DoPopupAdvance +void CFrontEndUI::SNewFileSelectFrame::DoPopupAdvance(const CGuiTableGroup* caller) { + if (x8_subMenu == kSM_EraseGamePopup) { + if (x40_tablegroup_popup->GetUserSelection() == 1) { + int fileSelection = x20_tablegroup_fileselect->GetUserSelection(); + PlayAdvanceSfx(); + x4_saveUI->EraseGame(fileSelection); + ResetFrame(); + } else { + x8_subMenu = kSM_EraseGame; + } + x10d_needsEraseToggle = true; + } else { + if (gpGameState->SystemState().GetNormalModeBeat()) { + if (x40_tablegroup_popup->GetUserSelection() == 1) { + PlayAdvanceSfx(); + xc_action = kA_GameOptions; + return; + } + int fileSelection = GetUserFileSelection(); + gpGameState->SetHardMode(!x40_tablegroup_popup->GetUserSelection()); + x4_saveUI->StartGame(fileSelection); + } else { + if (x40_tablegroup_popup->GetUserSelection() == 1) { + PlayAdvanceSfx(); + xc_action = kA_GameOptions; + return; + } + int fileSelection = GetUserFileSelection(); + x4_saveUI->StartGame(fileSelection); + } + } +} + +// SNewFileSelectFrame::DoPopupCancel +void CFrontEndUI::SNewFileSelectFrame::DoPopupCancel(const CGuiTableGroup* caller) { + if (x8_subMenu == kSM_EraseGamePopup) { + CSfxManager::SfxStart(SFXfnt_back, 0x7f, 0x40, false, CSfxManager::kMedPriority, false, + CSfxManager::kAllAreas); + x8_subMenu = kSM_EraseGame; + x10d_needsEraseToggle = true; + } else { + CSfxManager::SfxStart(SFXfnt_back, 0x7f, 0x40, false, CSfxManager::kMedPriority, false, + CSfxManager::kAllAreas); + x8_subMenu = kSM_Root; + x10e_needsNewToggle = true; + } +} + +// SFusionBonusFrame::SFusionBonusFrame +CFrontEndUI::SFusionBonusFrame::SFusionBonusFrame() +: x0_gbaLinkFrame(nullptr) +, x4_gbaSupport(rs_new CGBASupport()) +, x8_action(kFA_None) +, xc_gbaScreen(gpSimplePool->GetObj("FRME_GBAScreen")) +, x18_gbaLink(gpSimplePool->GetObj("FRME_GBALink")) +, x24_loadedFrame(nullptr) +, x28_tablegroup_options(nullptr) +, x2c_tablegroup_fusionsuit(nullptr) +, x30_textpane_instructions() +, x38_lastDoDraw(false) +, x39_fusionNotComplete(false) +, x3a_mpNotComplete(false) { + xc_gbaScreen.Lock(); + x18_gbaLink.Lock(); +} + +// SFusionBonusFrame::~SFusionBonusFrame +CFrontEndUI::SFusionBonusFrame::~SFusionBonusFrame() {} + +// SFusionBonusFrame::Draw +void CFrontEndUI::SFusionBonusFrame::Draw() { + if (!x38_lastDoDraw) + return; + if (x0_gbaLinkFrame.get() != nullptr) { + x0_gbaLinkFrame->Draw(); + } else if (x24_loadedFrame != nullptr) { + x24_loadedFrame->Draw(CGuiWidgetDrawParms::sDefaultDrawParms); + } +} + +// SFusionBonusFrame::Update +void CFrontEndUI::SFusionBonusFrame::Update(float dt, const CSaveGameScreen* saveUI) { + bool doDraw = saveUI == nullptr || saveUI->GetUIType() == 0x10; + + if (doDraw != x38_lastDoDraw) { + x38_lastDoDraw = doDraw; + if (x38_lastDoDraw) { + ResetCompletionFlags(); + } + } + + if (x0_gbaLinkFrame.get() != nullptr) { + x0_gbaLinkFrame->Update(dt); + } else if (x24_loadedFrame != nullptr) { + x24_loadedFrame->Update(dt); + } + + bool showFusionSuit = false; + int sel = x28_tablegroup_options->GetUserSelection(); + if (gpGameState->SystemState().GetFusionLinked()) { + if (gpGameState->SystemState().GetNormalModeBeat()) { + showFusionSuit = true; + } + } + + bool fusionBeat = gpGameState->SystemState().GetFusionBeat(); + bool showProceed = false; + if (sel == 1 && showFusionSuit) { + showProceed = true; + } + + x2c_tablegroup_fusionsuit->SetIsActive(showProceed); + x2c_tablegroup_fusionsuit->SetIsVisible(showProceed); + x24_loadedFrame->FindWidget("textpane_proceed")->SetIsVisible(!showProceed); + + const wchar_t* text1; + if (x3a_mpNotComplete) { + text1 = gpStringTable->GetString(0x50); + } else if (showFusionSuit) { + text1 = L""; + } else { + text1 = gpStringTable->GetString(0x4e); + } + + const wchar_t* text0; + if (x39_fusionNotComplete) { + text0 = gpStringTable->GetString(0x4f); + } else if (fusionBeat) { + text0 = L""; + } else { + text0 = gpStringTable->GetString(0x4d); + } + + x30_textpane_instructions.SetPairText(sel == 1 ? text1 : text0); +} + +// SFusionBonusFrame::ProcessUserInput +CFrontEndUI::SFusionBonusFrame::EAction +CFrontEndUI::SFusionBonusFrame::ProcessUserInput(const CFinalInput& input, + const CSaveGameScreen* saveUI) { + x8_action = kFA_None; + + if (saveUI != nullptr) { + const_cast< CSaveGameScreen* >(saveUI)->ProcessUserInput(input); + } + + if (x38_lastDoDraw) { + if (x0_gbaLinkFrame.get() != nullptr) { + SGBALinkFrame::EAction action = + x0_gbaLinkFrame->ProcessUserInput(input, saveUI != nullptr); + if (action != SGBALinkFrame::kGA_None) { + x0_gbaLinkFrame = nullptr; + if (action == SGBALinkFrame::kGA_Complete) { + if (x28_tablegroup_options->GetUserSelection() == 0 && + !gpGameState->SystemState().GetFusionBeat()) { + x39_fusionNotComplete = true; + } else if (saveUI != nullptr) { + const_cast< CSaveGameScreen* >(saveUI)->SaveNESState(); + } + } + } + } else if (x24_loadedFrame != nullptr) { + x24_loadedFrame->ProcessUserInput(input); + } + } + + return x8_action; +} + +// SFusionBonusFrame::PumpLoad +bool CFrontEndUI::SFusionBonusFrame::PumpLoad() { + if (x24_loadedFrame) { + return true; + } + if (xc_gbaScreen.TryCache()) { + if (x18_gbaLink.TryCache()) { + if (x4_gbaSupport->IsReady()) { + CGuiFrame* frme = xc_gbaScreen.GetObject(); + if (frme->GetIsFinishedLoading()) { + x24_loadedFrame = frme; + FinishedLoading(); + return true; + } + } + } + } + return false; +} + +// SFusionBonusFrame::FinishedLoading +void CFrontEndUI::SFusionBonusFrame::FinishedLoading() { + x28_tablegroup_options = + static_cast< CGuiTableGroup* >(x24_loadedFrame->FindWidget("tablegroup_options")); + x2c_tablegroup_fusionsuit = + static_cast< CGuiTableGroup* >(x24_loadedFrame->FindWidget("tablegroup_fusionsuit")); + x30_textpane_instructions = SFrontEndFrame::FindTextPanePair(x24_loadedFrame, "textpane_instructions"); + + SFrontEndFrame::FindAndSetPairText(*x24_loadedFrame, "textpane_nes", + gpStringTable->GetString(0x42)); + SFrontEndFrame::FindAndSetPairText(*x24_loadedFrame, "textpane_fusionsuit", + gpStringTable->GetString(0x3f)); + SFrontEndFrame::FindAndSetPairText(*x24_loadedFrame, "textpane_fusionsuitno", + gpStringTable->GetString(0x41)); + SFrontEndFrame::FindAndSetPairText(*x24_loadedFrame, "textpane_fusionsuityes", + gpStringTable->GetString(0x40)); + SFrontEndFrame::FindAndSetPairText(*x24_loadedFrame, "textpane_title", + gpStringTable->GetString(0x64)); + + CGuiTextPane* proceed = + static_cast< CGuiTextPane* >(x24_loadedFrame->FindWidget("textpane_proceed")); + proceed->TextSupport().SetText(rstl::wstring_l(gpStringTable->GetString(0x55))); + + CGuiTextPane* cancel = + static_cast< CGuiTextPane* >(x24_loadedFrame->FindWidget("textpane_cancel")); + cancel->TextSupport().SetText(rstl::wstring_l(gpStringTable->GetString(0x52))); + + x2c_tablegroup_fusionsuit->SetIsActive(false); + x2c_tablegroup_fusionsuit->SetIsVisible(false); + x2c_tablegroup_fusionsuit->SetVertical(false); + x2c_tablegroup_fusionsuit->SetUserSelection(gpGameState->SystemState().GetHasFusion() ? 1 : 0); + + SetTableColors(x28_tablegroup_options); + SetTableColors(x2c_tablegroup_fusionsuit); + + x28_tablegroup_options->SetMenuAdvanceCallback( + TFunctor1< CGuiTableGroup* const >(this, &SFusionBonusFrame::DoOptionsAdvance)); + x28_tablegroup_options->SetMenuSelectionChangeCallback( + TFunctor3< CGuiTableGroup* const, const int, const int >( + this, &SFusionBonusFrame::DoSelectionChange)); + x28_tablegroup_options->SetMenuCancelCallback( + TFunctor1< CGuiTableGroup* const >(this, &SFusionBonusFrame::DoOptionsCancel)); + x2c_tablegroup_fusionsuit->SetMenuSelectionChangeCallback( + TFunctor3< CGuiTableGroup* const, const int, const int >( + this, &SFusionBonusFrame::DoSelectionChange)); +} + +// SFusionBonusFrame::ResetCompletionFlags +void CFrontEndUI::SFusionBonusFrame::ResetCompletionFlags() { + x3a_mpNotComplete = false; + x39_fusionNotComplete = false; +} + +// SFusionBonusFrame::SetTableColors +void CFrontEndUI::SFusionBonusFrame::SetTableColors(CGuiTableGroup* tbgp) { + CColor selected(uchar(0xff), uchar(0xff), uchar(0xff), uchar(0xff)); + CColor unselected(uchar(0xa0), uchar(0xa0), uchar(0xa0), uchar(0xc8)); + tbgp->SetColors(selected, unselected); +} + +// SFusionBonusFrame::DoOptionsAdvance +void CFrontEndUI::SFusionBonusFrame::DoOptionsAdvance(const CGuiTableGroup* caller) { + int sel = x28_tablegroup_options->GetUserSelection(); + uchar flags = reinterpret_cast< const uchar* >(gpGameState)[0x178]; + bool normalModeBeat = (flags >> 6) & 1; + bool fusionLinked = (flags >> 7) & 1; + bool fusionBeat = (flags >> 4) & 1; + + switch (sel) { + case 1: + if (x3a_mpNotComplete) { + x3a_mpNotComplete = false; + PlayAdvanceSfx(); + } else if (normalModeBeat) { + if (fusionLinked) + break; + x0_gbaLinkFrame = + rs_new SGBALinkFrame(x18_gbaLink.GetObject(), x4_gbaSupport.get(), false); + PlayAdvanceSfx(); + } else { + x3a_mpNotComplete = true; + CSfxManager::SfxStart(SFXfnt_back, 0x7f, 0x40, false, CSfxManager::kMedPriority, false, + CSfxManager::kAllAreas); + } + break; + case 0: + if (x39_fusionNotComplete) { + x39_fusionNotComplete = false; + PlayAdvanceSfx(); + } else if (fusionBeat) { + x8_action = kFA_PlayNESMetroid; + } else { + x0_gbaLinkFrame = + rs_new SGBALinkFrame(x18_gbaLink.GetObject(), x4_gbaSupport.get(), false); + PlayAdvanceSfx(); + } + break; + default: + break; + } +} + +// SFusionBonusFrame::DoSelectionChange +void CFrontEndUI::SFusionBonusFrame::DoSelectionChange(const CGuiTableGroup* caller) { + if (caller == x28_tablegroup_options) { + CSfxManager::SfxStart(SFXfnt_selection_change, 0x7f, 0x40, false, CSfxManager::kMedPriority, + false, CSfxManager::kAllAreas); + x3a_mpNotComplete = false; + x39_fusionNotComplete = false; + } else { + CSfxManager::SfxStart(SFXfnt_enum_change, 0x7f, 0x40, false, CSfxManager::kMedPriority, false, + CSfxManager::kAllAreas); + gpGameState->SystemState().SetHasFusion( + x2c_tablegroup_fusionsuit->GetUserSelection() == 1); + gpGameState->PlayerState()->SetIsFusionEnabled( + x2c_tablegroup_fusionsuit->GetUserSelection() == 1); + } + SetTableColors(const_cast< CGuiTableGroup* >(caller)); +} + +// SFusionBonusFrame::DoOptionsCancel +void CFrontEndUI::SFusionBonusFrame::DoOptionsCancel(const CGuiTableGroup* caller) { + if (x39_fusionNotComplete || x3a_mpNotComplete) { + x3a_mpNotComplete = false; + x39_fusionNotComplete = false; + CSfxManager::SfxStart(SFXfnt_back, 0x7f, 0x40, false, CSfxManager::kMedPriority, false, + CSfxManager::kAllAreas); + } else { + x8_action = kFA_GoBack; + x28_tablegroup_options->SetUserSelection(0); + x2c_tablegroup_fusionsuit->SetIsActive(false); + x30_textpane_instructions.SetPairText(rstl::wstring_l(L"")); + SetTableColors(x28_tablegroup_options); + } +} + +// CResFactory::CanBuild (weak function emitted here) +bool CResFactory::CanBuild(const SObjectTag& tag) { + return x4_resLoader.ResourceExists(tag); +} + +// CFrontEndUI::CFrontEndUI +CFrontEndUI::CFrontEndUI() +: CIOWin(rstl::string_l("FrontEndUI")) +, x14_phase(kP_LoadDepsGroup) +, x18_rndA(rand() % 3) +, x1c_rndB(rand() % 3) +, x20_depsGroup(gpSimplePool->GetObj("FrontEnd_DGRP")) +, x28_deps() +, x38_pressStart(gpSimplePool->GetObj("TXTR_PressStart")) +, x44_frontendAudioGrp(gpSimplePool->GetObj(kFrontEndAGSCName)) +, x50_curScreen(kS_OpenCredits) +, x54_nextScreen(kS_OpenCredits) +, x58_fadeBlackTimer(0.f) +, x5c_fadeBlackWithMovie(false) +, x60_pressStartTime(0.f) +, x64_pressStartAlpha(0.f) +, x68_musicVol(1.f) +, x6c_menuMovies(rstl::auto_ptr< CMoviePlayer >()) +, xb8_curMovie(kMM_Stopped) +, xbc_nextAttract(0) +, xc0_attractCount(0) +, xc4_attractMovie() +, xcc_curMoviePtr(nullptr) +, xd0_playerSkipToTitle(false) +, xd1_moviesLoaded(false) +, xd2_deferSlideShow(false) +, xd4_audio1(nullptr) +, xd8_audio2(nullptr) +, xdc_saveUI(rs_new CSaveGameScreen(0, gpGameState->GetCardSerial())) +, xe0_frontendCardFrme(nullptr) +, xe4_fusionBonusFrme(nullptr) +, xe8_frontendNoCardFrme(nullptr) +, xec_emuFrme(nullptr) +, xf0_optionsFrme(nullptr) +, xf4_curAudio(nullptr) { + gpMain->ResetGameState(); + gpGameState->SetCurrentWorldId(skDefaultWorld.GetId()); + gpGameState->GameOptions().ResetToDefaults(); + gpGameState->WriteBackupBuf(); + gpResourceFactory->CanBuild(skDefaultWorld); + x20_depsGroup.Lock(); + { + int i = 0; + loop: + if (!CDvdFile::FileExists(GetAttractMovieFileName(i))) + goto done; + ++xc0_attractCount; + ++i; + goto loop; + done:; + } +} + +// CFrontEndUI::~CFrontEndUI +CFrontEndUI::~CFrontEndUI() { + if (x14_phase >= kP_DisplayFrontEnd) { + CAudioSys::SysPopGroupFromARAM(); + CAudioGroupSet* agsc = x44_frontendAudioGrp.GetObject(); + const rstl::string groupName( + *reinterpret_cast< const rstl::string* >( + reinterpret_cast< const uchar* >(agsc) + 0x20)); + CAudioSys::SysUnloadGroupSet(groupName); + } + CStreamAudioManager::FadeBackIn(0.f); +} + +// CFrontEndUI::TransitionToFive +void CFrontEndUI::TransitionToFive() { + if (x14_phase < kP_ToPlayGame) { + CSfxManager::SfxStart(FETransitionForwardSFX[x1c_rndB][0], 0x7f, 0x40, false, + CSfxManager::kMedPriority, false, CSfxManager::kAllAreas); + CSfxManager::SfxStart(FETransitionForwardSFX[x1c_rndB][1], 0x7f, 0x40, false, + CSfxManager::kMedPriority, false, CSfxManager::kAllAreas); + x14_phase = kP_ToPlayGame; + StartStateTransition(kS_ToPlayGame); + } +} + +// CFrontEndUI::OnMessage +CIOWin::EMessageReturn CFrontEndUI::OnMessage(const CArchitectureMessage& message, + CArchitectureQueue& queue) { + switch (message.GetType()) { + case kAM_TimerTick: { + float dt = MakeMsg::GetParmTimerTick(message).GetReal(); + return Update(dt, queue); + } + case kAM_UserInput: { + const CFinalInput& input = MakeMsg::GetParmUserInput(message).GetUserInput(); + ProcessUserInput(input, queue); + break; + } + case kAM_QuitGameplay: + x14_phase = kP_ExitFrontEnd; + break; + default: + break; + } + return kMR_Normal; +} + +// CFrontEndUI::UpdateMusicVol +void CFrontEndUI::UpdateMusicVol() { + float volMul = (xf4_curAudio == xd4_audio1.get()) ? 0.7421875f : 0.7421875f; + if (xf4_curAudio != nullptr) { + xf4_curAudio->SetVolume( + CCast::ToUint8(volMul * x68_musicVol * (float)gpGameState->GameOptions().GetMusicVolume())); + } +} + +// CFrontEndUI::FinishedLoadingDepsGroup +void CFrontEndUI::FinishedLoadingDepsGroup() { + CDependencyGroup* dgrp = x20_depsGroup.GetT(); + const rstl::vector< SObjectTag >& tags = dgrp->GetObjectTagVector(); + x28_deps.reserve(tags.size()); + for (const SObjectTag* it = tags.data(); it != tags.data() + tags.size(); ++it) { + CToken tok(gpSimplePool->GetObj(*it)); + tok.Lock(); + x28_deps.push_back(tok); + } + x44_frontendAudioGrp.Lock(); +} + +// CFrontEndUI::PumpLoad +bool CFrontEndUI::PumpLoad() { + for (int i = 0; i < x28_deps.size(); ++i) { + if (!x28_deps[i].IsLoaded()) + return false; + } + return x44_frontendAudioGrp.TryCache(); +} + +// CFrontEndUI::Update +CIOWin::EMessageReturn CFrontEndUI::Update(float dt, CArchitectureQueue& queue) { + // Update save UI if active and past file select phase + if (xdc_saveUI.get() != nullptr && x50_curScreen >= kS_FileSelect) { + int saveResult = xdc_saveUI->Update(dt); + if (saveResult == 1) { + TransitionToFive(); + } else if (saveResult == 3 || saveResult == 2) { + xe0_frontendCardFrme = nullptr; + xdc_saveUI = nullptr; + } + } + + UpdateMusicVol(); + + switch (x14_phase) { + case kP_LoadDepsGroup: + if (x20_depsGroup.IsLoaded()) { + FinishedLoadingDepsGroup(); + x20_depsGroup.Unlock(); + x14_phase = kP_LoadDeps; + } else { + return kMR_Exit; + } + // fallthrough + case kP_LoadDeps: + if (PumpLoad()) { + xe0_frontendCardFrme = rs_new SNewFileSelectFrame(xdc_saveUI.get(), x1c_rndB); + xe4_fusionBonusFrme = rs_new SFusionBonusFrame(); + xe8_frontendNoCardFrme = rs_new SFrontEndFrame(x1c_rndB); + + x38_pressStart.Lock(); + if (x38_pressStart.GetObject() == nullptr && x38_pressStart.IsLocked() && x38_pressStart.CToken::IsLoaded()) { + x38_pressStart.ForceCache(); + } + + const SObjectTag* tag = gpResourceFactory->GetResourceIdByName(kFrontEndAGSCName); + CAudioGroupSet* audioGrp = x44_frontendAudioGrp.GetObject(); + const rstl::string& audioGrpName = audioGrp->GetName(); + CAudioSys::SysLoadGroupSet(x44_frontendAudioGrp, audioGrpName, tag->GetId()); + CAudioSys::SysPushGroupIntoARAM(audioGrpName, 0x26); + CAudioSys::SysUnloadSampleData(audioGrpName); + + xd4_audio1 = rs_new CStaticAudioPlayer(rstl::string_l(kAudioFrontend1Path), 416480, 1973664); + + xd8_audio2 = rs_new CStaticAudioPlayer(rstl::string_l(kAudioFrontend2Path), 273556, 1636980); + + x14_phase = kP_LoadFrames; + } + if (x14_phase == kP_LoadDeps) { + return kMR_Exit; + } + // fallthrough + case kP_LoadFrames: + if (!xd4_audio1->IsReady() || + !xd8_audio2->IsReady() || + !xe0_frontendCardFrme->PumpLoad() || + !xe4_fusionBonusFrme->PumpLoad() || + !xe8_frontendNoCardFrme->PumpLoad() || + !xdc_saveUI->PumpLoad()) { + return kMR_Exit; + } + + xf4_curAudio = xd4_audio1.get(); + xf4_curAudio->StartMixOut(); + x14_phase = kP_LoadMovies; + // fallthrough + case kP_LoadMovies: { + bool moviesReady = true; + if (!PumpMovieLoad()) { + moviesReady = false; + } else { + UpdateMovies(dt); + for (int i = 0; i < 9; ++i) { + if (!x6c_menuMovies[i]->GetIsFullyCached()) { + moviesReady = false; + break; + } + } + } + if (moviesReady) { + x14_phase = kP_DisplayFrontEnd; + StartStateTransition(kS_Title); + } else { + return kMR_Exit; + } + // fallthrough + } + case kP_DisplayFrontEnd: + case kP_ToPlayGame: + if (xec_emuFrme.get() != nullptr) { + if (xec_emuFrme->Update(dt, *xdc_saveUI) == 1) { + xec_emuFrme = nullptr; + if (xdc_saveUI.get() != nullptr) { + xdc_saveUI->SetInGame(false); + } + xf4_curAudio->StartMixOut(); + } + } else { + if (xd2_deferSlideShow) { + xd2_deferSlideShow = false; + xf4_curAudio->StartMixOut(); + if (xdc_saveUI.get() != nullptr) { + xdc_saveUI->ResetCardDriver(); + } + } + + if (IsInScreenNotTransitioning(kS_FileSelect)) { + if (xf0_optionsFrme.get() == nullptr) { + if (xe0_frontendCardFrme.get() == nullptr) { + xe8_frontendNoCardFrme->Update(dt); + } else { + xe0_frontendCardFrme->Update(dt); + } + } else { + CSaveGameScreen* saveUI = xdc_saveUI.get(); + bool optionsActive = true; + if (saveUI != nullptr && saveUI->GetUIType() != CSaveGameScreen::kUIT_SaveReady) { + optionsActive = false; + } + if (optionsActive) { + xf0_optionsFrme->Update(dt, xdc_saveUI.get()); + } else { + xf0_optionsFrme = nullptr; + } + } + } else if (IsInScreenNotTransitioning(kS_FusionBonus)) { + xe4_fusionBonusFrme->Update(dt, xdc_saveUI.get()); + } + + // Check movie transition completion + if (x50_curScreen != x54_nextScreen) { + if (xcc_curMoviePtr != nullptr && xcc_curMoviePtr->CanDrawVideo()) { + if (xcc_curMoviePtr->GetIsMovieFinishedPlaying() || xcc_curMoviePtr->IsLooping()) { + CompleteStateTransition(); + } + } + } + + // Handle fade timer + if (x58_fadeBlackTimer > 0.f && !x5c_fadeBlackWithMovie) { + SetFadeBlackTimer(rstl::max_val(x58_fadeBlackTimer - dt, 0.f)); + if (x58_fadeBlackTimer == 0.f) { + if (IsInScreenNotTransitioning(kS_Title)) { + if (xc0_attractCount > 0) { + StartStateTransition(kS_AttractMovie); + } + } else if (x54_nextScreen == kS_AttractMovie) { + CompleteStateTransition(); + } else if (x50_curScreen != x54_nextScreen) { + CompleteStateTransition(); + } + } + } + + // Update movies + UpdateMovies(dt); + + // Press start pulsing + if (x50_curScreen == kS_Title && x54_nextScreen == kS_Title) { + if (x58_fadeBlackTimer < 30.f - gpTweakGame->GetPressStartDelay()) { + x60_pressStartTime = static_cast< float >(fmod(x60_pressStartTime + dt, 1.0)); + float halfTime = 0.5f; + float alpha; + if (x60_pressStartTime < halfTime) { + alpha = x60_pressStartTime / halfTime; + } else { + alpha = (1.f - x60_pressStartTime) / halfTime; + } + x64_pressStartAlpha = alpha; + } + } else { + x60_pressStartTime = 0.f; + x64_pressStartAlpha = 0.f; + } + } + + // Music volume fade + if (x50_curScreen == kS_Title && x54_nextScreen == kS_FileSelect) { + if (xcc_curMoviePtr->CanDrawVideo()) { + float delay = AudioFadeTimeA[x18_rndA]; + float t = (xcc_curMoviePtr->GetPlayedSeconds() - delay) / 2.5f; + x68_musicVol = 1.f - CMath::Clamp(0.f, t, 1.f); + } + } else if (x54_nextScreen == kS_ToPlayGame) { + if (xcc_curMoviePtr->CanDrawVideo()) { + float delay = AudioFadeTimeB[x1c_rndB]; + float played = xcc_curMoviePtr->GetPlayedSeconds(); + float total = xcc_curMoviePtr->GetTotalSeconds(); + float t = (played - delay) / (total - delay); + x68_musicVol = 1.f - CMath::Clamp(0.f, t, 1.f); + } + } else { + x68_musicVol = 1.f; + } + + return kMR_Exit; + + case kP_ExitFrontEnd: + return kMR_RemoveIOWin; + + default: + break; + } + + return kMR_Exit; +} + +// CFrontEndUI::PumpMovieLoad +bool CFrontEndUI::PumpMovieLoad() { + if (xd1_moviesLoaded) { + return true; + } + + for (int i = 0; i < 9; ++i) { + if (x6c_menuMovies[i].null()) { + const FEMovie* movie = &FEMovies[i]; + char path[256]; + strcpy(path, movie->path); + + if (i == 2) { + path[strlen(path) - 5] = static_cast< char >(x18_rndA + 'A'); + } else if (i == 4) { + path[strlen(path) - 5] = static_cast< char >(x1c_rndB + 'A'); + } + + CMoviePlayer* mp = rs_new CMoviePlayer(path, 0.05f, movie->loop, true); + x6c_menuMovies[i] = rstl::auto_ptr< CMoviePlayer >(mp); + x6c_menuMovies[i]->SetPlayMode(CMoviePlayer::kPM_Stopped); + return false; + } + + if (x6c_menuMovies[i]->PumpIndexLoad()) { + return false; + } + } + + xd1_moviesLoaded = true; + return true; +} + +// CFrontEndUI::UpdateMovies +void CFrontEndUI::UpdateMovies(float dt) { + if (xcc_curMoviePtr != nullptr) { + if (!xcc_curMoviePtr->PumpIndexLoad()) { + if (x5c_fadeBlackWithMovie) { + x5c_fadeBlackWithMovie = false; + x58_fadeBlackTimer = xcc_curMoviePtr->GetTotalSeconds(); + } + } + } + + for (int i = 0; i < 9; ++i) { + if (!x6c_menuMovies[i].null()) { + x6c_menuMovies[i]->Update(dt); + } + } + + CMoviePlayer* attractPlayer = xc4_attractMovie.get(); + if (attractPlayer != nullptr) { + if (!attractPlayer->PumpIndexLoad()) { + xc4_attractMovie->Update(dt); + } + } +} + +// CFrontEndUI::ProcessUserInput +void CFrontEndUI::ProcessUserInput(const CFinalInput& input, CArchitectureQueue& queue) { + if (gpMain->GetCardBusy()) + return; + if (input.ControllerNumber() > 1) + return; + + if (xec_emuFrme.get() != nullptr) { + xec_emuFrme->ProcessUserInput(input, xdc_saveUI.get()); + return; + } + + if (x14_phase != kP_DisplayFrontEnd) + return; + if (input.ControllerNumber() != 0) + return; + + if (x50_curScreen != x54_nextScreen) { + if (x54_nextScreen == kS_AttractMovie) { + if (input.PStart() || input.PA()) { + SetFadeBlackTimer(rstl::min_val(x58_fadeBlackTimer, 1.f)); + PlayAdvanceSfx(); + return; + } + } + if (input.PA() || input.PStart()) { + if (x50_curScreen == kS_OpenCredits && x54_nextScreen == kS_Title && + x58_fadeBlackTimer > 1.f) { + xd0_playerSkipToTitle = true; + SetFadeBlackTimer(1.f); + return; + } + } + } else { + if (x50_curScreen == kS_Title) { + if (input.PStart() || input.PA()) { + if (x58_fadeBlackTimer < 30.f - gpTweakGame->GetPressStartDelay()) { + CSfxManager::SfxStart(FETransitionBackSFX[x18_rndA][0], 0x7f, 0x40, false, + CSfxManager::kMedPriority, false, CSfxManager::kAllAreas); + CSfxManager::SfxStart(FETransitionBackSFX[x18_rndA][1], 0x7f, 0x40, false, + CSfxManager::kMedPriority, false, CSfxManager::kAllAreas); + StartStateTransition(kS_FileSelect); + return; + } + } + } else { + bool isFileSelect = + x50_curScreen == kS_FileSelect && x54_nextScreen == kS_FileSelect; + if (isFileSelect) { + if (xf0_optionsFrme.get() == nullptr) { + if (xe0_frontendCardFrme.get() == nullptr) { + SFrontEndFrame::EAction action = xe8_frontendNoCardFrme->ProcessUserInput(input); + if (action == SFrontEndFrame::kEA_FusionBonus) { + StartStateTransition(kS_FusionBonus); + return; + } else if (action == SFrontEndFrame::kEA_GameOptions) { + xf0_optionsFrme = rs_new SOptionsFrontEndFrame(); + return; + } else if (action == SFrontEndFrame::kEA_StartGame) { + TransitionToFive(); + return; + } else if (action == SFrontEndFrame::kEA_SlideShow) { + xd2_deferSlideShow = true; + StartSlideShow(queue); + return; + } + } else { + SNewFileSelectFrame::EAction action = xe0_frontendCardFrme->ProcessUserInput(input); + if (action == SNewFileSelectFrame::kA_FusionBonus) { + StartStateTransition(kS_FusionBonus); + return; + } else if (action == SNewFileSelectFrame::kA_GameOptions) { + xf0_optionsFrme = rs_new SOptionsFrontEndFrame(); + return; + } else if (action == SNewFileSelectFrame::kA_SlideShow) { + xd2_deferSlideShow = true; + StartSlideShow(queue); + return; + } + } + } else { + if (xf0_optionsFrme->ProcessUserInput(input, xdc_saveUI.get())) + return; + xf0_optionsFrme = nullptr; + return; + } + } else { + bool isFusionBonus = + x50_curScreen == kS_FusionBonus && x54_nextScreen == kS_FusionBonus; + if (isFusionBonus) { + SFusionBonusFrame::EAction action = + xe4_fusionBonusFrme->ProcessUserInput(input, xdc_saveUI.get()); + if (action == SFusionBonusFrame::kFA_GoBack) { + StartStateTransition(kS_FileSelect); + return; + } else if (action == SFusionBonusFrame::kFA_PlayNESMetroid) { + xf4_curAudio->StopMixOut(); + xec_emuFrme = rs_new SNesEmulatorFrame(); + if (xdc_saveUI.get() != nullptr) { + xdc_saveUI->SetInGame(true); + } + return; + } + } + } + } + } +} + +// CFrontEndUI::Draw +void CFrontEndUI::Draw() const { + if (x14_phase < kP_DisplayFrontEnd) + return; + + if (xec_emuFrme.get() != nullptr) { + xec_emuFrme->Draw(*xdc_saveUI); + goto press_start; + } + + gpRender->SetDepthReadWrite(false, false); + gpRender->SetViewportOrtho(false, -4096.f, 4096.f); + + int vpLeft = CGraphics::mViewport.mLeft; + int vpTop = CGraphics::mViewport.mTop; + int vpWidth = CGraphics::mViewport.mWidth; + int vpHeight = CGraphics::mViewport.mHeight; + + if (xcc_curMoviePtr != NULL && xcc_curMoviePtr->CanDrawVideo()) { + int vidWidth = xcc_curMoviePtr->GetWidth(); + int vidHeight = xcc_curMoviePtr->GetHeight(); + int centerX = static_cast< int >(static_cast< uint >(vidWidth - vpWidth) >> 1); + int centerY = static_cast< int >(static_cast< uint >(vidHeight - vpHeight) >> 1); + int vl = vpLeft - centerX; + int vr = vpLeft + vpWidth + centerX; + int vb = vpTop + vpHeight + centerY; + int vt = vpTop - centerY; + CVector3f v1(static_cast< float >(vl), 0.f, static_cast< float >(vb)); + CVector3f v2(static_cast< float >(vr), 0.f, static_cast< float >(vb)); + CVector3f v3(static_cast< float >(vl), 0.f, static_cast< float >(vt)); + CVector3f v4(static_cast< float >(vr), 0.f, static_cast< float >(vt)); + xcc_curMoviePtr->DrawFrame(v1, v2, v3, v4); + } + + if (IsInScreenNotTransitioning(kS_FileSelect)) { + if (xf0_optionsFrme.get() == nullptr) { + if (xe0_frontendCardFrme.get() == nullptr) + xe8_frontendNoCardFrme->Draw(); + else + xe0_frontendCardFrme->Draw(); + } else { + xf0_optionsFrme->Draw(); + } + } else if (IsInScreenNotTransitioning(kS_FusionBonus)) { + xe4_fusionBonusFrme->Draw(); + } + +press_start: + if (x64_pressStartAlpha > 0.f && x38_pressStart.GetObject() != NULL) { + CTexture* tex = x38_pressStart.GetObject(); + int width = tex->GetWidth(); + int height = tex->GetHeight(); + CGraphics::SetTevOp(kTS_Stage0, CGraphics::kEnvModulate); + CGraphics::SetTevOp(kTS_Stage1, CGraphics::kEnvPassthru); + gpRender->SetBlendMode_AdditiveAlpha(); + gpRender->SetDepthReadWrite(false, false); + CColor color = CColor::White().WithAlphaOf(x64_pressStartAlpha); + CGraphics::Render2D(*tex, 320 - width / 2, 72 - height / 2, width, height, color); + } + + if (GetHasAttractMovies()) { + if (IsInScreenNotTransitioning(kS_Title) || x54_nextScreen == kS_AttractMovie) { + if (x58_fadeBlackTimer < 1.f) { + CColor color = CColor::Black().WithAlphaOf(1.f - x58_fadeBlackTimer); + CCameraFilterPass::DrawFilter(CCameraFilterPass::kFT_Blend, + CCameraFilterPass::kFS_Fullscreen, color, NULL, 1.f); + } + } + } + + if (xd0_playerSkipToTitle) { + if (x54_nextScreen == kS_Title && x50_curScreen == kS_OpenCredits) { + float t = CMath::Clamp(0.f, x58_fadeBlackTimer, 1.f); + CColor color = CColor::Black().WithAlphaOf(1.f - t); + CCameraFilterPass::DrawFilter(CCameraFilterPass::kFT_Blend, + CCameraFilterPass::kFS_Fullscreen, color, NULL, 1.f); + } else if (x54_nextScreen == kS_Title && x50_curScreen == kS_Title) { + float t = CMath::Clamp(0.f, 30.f - x58_fadeBlackTimer, 1.f); + CColor color = CColor::Black().WithAlphaOf(1.f - t); + CCameraFilterPass::DrawFilter(CCameraFilterPass::kFT_Blend, + CCameraFilterPass::kFS_Fullscreen, color, NULL, 1.f); + } + } + + if (xdc_saveUI.get() != NULL) { + if ((const_cast< CFrontEndUI* >(this)->CanShowSaveUI() && !xdc_saveUI->IsHiddenFromFrontEnd()) || + IsInScreenNotTransitioning(kS_FileSelect) || + IsInScreenNotTransitioning(kS_FusionBonus)) { + xdc_saveUI->Draw(); + } + } +} + +// CFrontEndUI::CanShowSaveUI +bool CFrontEndUI::CanShowSaveUI() { + return (x50_curScreen == kS_FileSelect || x50_curScreen == kS_FusionBonus) && + (x54_nextScreen == kS_FileSelect || x54_nextScreen == kS_FusionBonus); +} + +// CFrontEndUI::StartStateTransition +void CFrontEndUI::StartStateTransition(EScreen screen) { + switch (x50_curScreen) { + case kS_OpenCredits: + break; + case kS_Title: + if (screen == kS_FileSelect) { + SetCurrentMovie(kMM_StartFileSelectA); + SetFadeBlackTimer(xcc_curMoviePtr->GetTotalSeconds()); + } + break; + case kS_AttractMovie: + break; + case kS_FileSelect: + if (screen == kS_ToPlayGame) { + SetCurrentMovie(kMM_FileSelectPlayGameA); + SetFadeBlackTimer(xcc_curMoviePtr->GetTotalSeconds()); + } else if (screen == kS_FusionBonus) { + SetCurrentMovie(kMM_FileSelectGBA); + SetFadeBlackTimer(xcc_curMoviePtr->GetTotalSeconds()); + CSfxManager::SfxStart(SFXfnt_tofusion_L); + CSfxManager::SfxStart(SFXfnt_tofusion_R); + } + break; + case kS_FusionBonus: + if (screen == kS_ToPlayGame) { + SetCurrentMovie(kMM_GBAFileSelectB); + SetFadeBlackTimer(xcc_curMoviePtr->GetTotalSeconds()); + } else if (screen == kS_FileSelect) { + SetCurrentMovie(kMM_GBAFileSelectA); + SetFadeBlackTimer(xcc_curMoviePtr->GetTotalSeconds()); + CSfxManager::SfxStart(SFXfnt_fromfusion_L); + CSfxManager::SfxStart(SFXfnt_fromfusion_R); + } + break; + default: + break; + } + + switch (screen) { + case kS_OpenCredits: + case kS_Title: + SetCurrentMovie(kMM_FirstStart); + SetFadeBlackTimer(xcc_curMoviePtr->GetTotalSeconds()); + break; + case kS_AttractMovie: + StartAttractMovie(); + SetFadeBlackWithMovie(); + break; + case kS_FileSelect: + default: + break; + } + + x54_nextScreen = screen; +} + +// CFrontEndUI::CompleteStateTransition +void CFrontEndUI::CompleteStateTransition() { + EScreen oldScreen = x50_curScreen; + x50_curScreen = x54_nextScreen; + + switch (x50_curScreen) { + case kS_AttractMovie: + x54_nextScreen = kS_OpenCredits; + x50_curScreen = kS_OpenCredits; + xd0_playerSkipToTitle = false; + StartStateTransition(kS_Title); + break; + + case kS_Title: + SetCurrentMovie(kMM_StartLoop); + SetFadeBlackTimer(30.f); + break; + + case kS_FileSelect: + SetCurrentMovie(kMM_FileSelectLoop); + if (oldScreen == kS_Title) { + xf4_curAudio->StopMixOut(); + xf4_curAudio = xd8_audio2.get(); + xf4_curAudio->StartMixOut(); + } + if (xdc_saveUI.get() != nullptr) { + xdc_saveUI->ResetCardDriver(); + } + break; + + case kS_FusionBonus: + SetCurrentMovie(kMM_GBALoop); + break; + + case kS_ToPlayGame: + x14_phase = kP_ExitFrontEnd; + break; + + default: + break; + } +} + +// CFrontEndUI::StartAttractMovie +void CFrontEndUI::StartAttractMovie() { + if (!xc4_attractMovie.null()) { + return; + } + SetCurrentMovie(kMM_Stopped); + const char* name = GetNextAttractMovieFileName(); + xc4_attractMovie = rstl::auto_ptr< CMoviePlayer >(rs_new CMoviePlayer(name, 0.f, false, false)); + xcc_curMoviePtr = xc4_attractMovie.get(); +} + +// CFrontEndUI::StopAttractMovie +void CFrontEndUI::StopAttractMovie() { + if (xc4_attractMovie.null()) { + return; + } + xc4_attractMovie = rstl::auto_ptr< CMoviePlayer >(); + xcc_curMoviePtr = nullptr; +} + +// CFrontEndUI::SetCurrentMovie +void CFrontEndUI::SetCurrentMovie(EMenuMovie movie) { + if (movie == xb8_curMovie) { + return; + } + StopAttractMovie(); + if (xb8_curMovie != kMM_Stopped) { + xcc_curMoviePtr->SetPlayMode(CMoviePlayer::kPM_Stopped); + xcc_curMoviePtr->Rewind(); + } + xb8_curMovie = movie; + if (xb8_curMovie != kMM_Stopped) { + xcc_curMoviePtr = x6c_menuMovies[movie].get(); + xcc_curMoviePtr->SetPlayMode(CMoviePlayer::kPM_Playing); + } else { + xcc_curMoviePtr = nullptr; + } +} + +// CFrontEndUI::GetNextAttractMovieFileName +const char* CFrontEndUI::GetNextAttractMovieFileName() { + const char* ret = GetAttractMovieFileName(xbc_nextAttract); + xbc_nextAttract = (xbc_nextAttract + 1) % xc0_attractCount; + return ret; +} + +// CFrontEndUI::GetAttractMovieFileName +const char* CFrontEndUI::GetAttractMovieFileName(int idx) { + return CBasics::Stringize("Video/attract%d.thp", idx); +} + +// CFrontEndUI::SetFadeBlackTimer +void CFrontEndUI::SetFadeBlackTimer(float seconds) { + x58_fadeBlackTimer = seconds; + x5c_fadeBlackWithMovie = false; +} + +// CFrontEndUI::SetFadeBlackWithMovie +void CFrontEndUI::SetFadeBlackWithMovie() { + x58_fadeBlackTimer = 1000000.f; + x5c_fadeBlackWithMovie = true; +} + +// CFrontEndUI::StartSlideShow +void CFrontEndUI::StartSlideShow(CArchitectureQueue& queue) { + xf4_curAudio->StopMixOut(); + queue.Push(MakeMsg::CreateCreateIOWin(kAMT_IOWinManager, kFrontEndUIMsgPriority, + kFrontEndUIDrawPriority, rs_new CSlideShow())); +} diff --git a/src/MetroidPrime/ScriptObjects/CScriptStreamedMusic.cpp b/src/MetroidPrime/ScriptObjects/CScriptStreamedMusic.cpp index 4cce5126..a1890216 100644 --- a/src/MetroidPrime/ScriptObjects/CScriptStreamedMusic.cpp +++ b/src/MetroidPrime/ScriptObjects/CScriptStreamedMusic.cpp @@ -119,7 +119,7 @@ void CScriptStreamedMusic::sub_8020c414(CStateManager& mgr) { } void CScriptStreamedMusic::sub_8020c3f0(CStateManager& mgr) { - CStreamAudioManager::fn_8036590C(x4c_fadeOut); + CStreamAudioManager::FadeBackIn(x4c_fadeOut); } void CScriptStreamedMusic::StartStream(CStateManager& mgr) {