diff options
-rw-r--r-- | NewerProjectKP.yaml | 1 | ||||
-rw-r--r-- | endingMgr.yaml | 16 | ||||
-rw-r--r-- | src/endingMgr.cpp | 307 | ||||
-rw-r--r-- | tools/UsedProfileAndSpriteList.txt | 1 |
4 files changed, 325 insertions, 0 deletions
diff --git a/NewerProjectKP.yaml b/NewerProjectKP.yaml index e49f7ea..f224db8 100644 --- a/NewerProjectKP.yaml +++ b/NewerProjectKP.yaml @@ -5,6 +5,7 @@ modules: - processed/corseClear.yaml - processed/apDebug.yaml # - processed/layoutDebug.yaml + - processed/endingMgr.yaml - processed/flipblock.yaml - processed/fileselect.yaml - processed/magicplatform.yaml diff --git a/endingMgr.yaml b/endingMgr.yaml new file mode 100644 index 0000000..beb057b --- /dev/null +++ b/endingMgr.yaml @@ -0,0 +1,16 @@ +--- +source_files: [../src/endingMgr.cpp] +hooks: + - name: BuildEndingMgr + type: add_func_pointer + src_addr_pal: 0x8095D018 + target_func: 'dEndingMgr_c::build(void)' + + - name: DisablePeachThankMP + type: nop_insn + area_pal: 0x80B4A020 + + - name: DisablePeachDmEscort + type: nop_insn + area_pal: 0x80B49E80 + diff --git a/src/endingMgr.cpp b/src/endingMgr.cpp new file mode 100644 index 0000000..ef40613 --- /dev/null +++ b/src/endingMgr.cpp @@ -0,0 +1,307 @@ +#include <game.h> +#include <playerAnim.h> +#include <sfx.h> +#include <stage.h> +extern void *SoundRelatedClass; + +class dEndingMgr_c : public daBossDemo_c { + int onCreate(); + int onDelete(); + + void init(); + Vec2 _vf70(); + + USING_STATES(dEndingMgr_c); + DECLARE_STATE_VIRTUAL(DemoSt); + DECLARE_STATE(GoRight); + DECLARE_STATE(LookUp); + DECLARE_STATE(JumpOntoSwitch); + DECLARE_STATE(ThanksPeach); + + dAcPy_c *players[4]; + + int timer; + + static dEndingMgr_c *build(); +}; + +dEndingMgr_c *dEndingMgr_c::build() { + void *buf = AllocFromGameHeap1(sizeof(dEndingMgr_c)); + return new(buf) dEndingMgr_c; +} + + +int dEndingMgr_c::onCreate() { + if (StageE4::instance->currentBossDemo) { + fBase_c::Delete(); + return false; + } + StageE4::instance->currentBossDemo = this; + + init(); + + acState.setState(&StateID_DemoSt); + acState.executeNextStateThisTick(); + + return true; +} + +int dEndingMgr_c::onDelete() { + daBossDemo_c::onDelete(); + WLClass::instance->disableDemoControl(true); + return true; +} + + +void dEndingMgr_c::init() { + dStageActorMgr_c::instance->_BCA = true; + WLClass::instance->demoControlAllPlayers(); + BalloonRelatedClass::instance->_20 = 1; +} + + +CREATE_STATE(dEndingMgr_c, DemoSt); + +void dEndingMgr_c::beginState_DemoSt() { + _360 = 1; +} +void dEndingMgr_c::endState_DemoSt() { +} +void dEndingMgr_c::executeState_DemoSt() { + for (int i = 0; i < 4; i++) { + dAcPy_c *player; + if (player = dAcPy_c::findByID(i)) { + if (!player->isReadyForDemoControlAction()) + return; + } + } + acState.setState(&StateID_GoRight); +} + +static float manipFourPlayerPos(int id, float pos) { + int fromRight = 3 - id; + return pos - (fromRight * 20.0f); +} + +CREATE_STATE(dEndingMgr_c, GoRight); +void dEndingMgr_c::beginState_GoRight() { + timer = 0; + + // Sort the players into a list + // We shall first find the rightmost player, then the second + // rightmost, then ... + float maxBound = 50000.0f; + for (int targetOffs = 3; targetOffs >= 0; targetOffs--) { + float maxX = 0.0f; + dAcPy_c *maxPlayer = 0; + + for (int check = 0; check < 4; check++) { + if (dAcPy_c *player = dAcPy_c::findByID(check)) { + if (player->pos.x >= maxBound) + continue; + + if (player->pos.x > maxX) { + maxX = player->pos.x; + maxPlayer = player; + } + } + } + + maxBound = maxX; + players[targetOffs] = maxPlayer; + } + + // And now move them + for (int i = 0; i < 4; i++) { + if (dAcPy_c *player = players[i]) { + float target = manipFourPlayerPos(i, 1060.0f); + float speed = 2.0f; + player->moveInDirection(&target, &speed); + } + } +} + +void dEndingMgr_c::endState_GoRight() { } + +void dEndingMgr_c::executeState_GoRight() { + for (int i = 0; i < 4; i++) { + if (dAcPy_c *player = players[i]) { + if (player->pos.x > manipFourPlayerPos(i, 920.0f)) { + player->demoMoveSpeed *= 0.994f; + } + } + } + + // Can we leave this state yet? + for (int i = 0; i < 4; i++) { + if (dAcPy_c *player = players[i]) { + if (!player->isReadyForDemoControlAction()) + return; + } + } + + // WE CAN LEAVE YAY + timer++; + if (timer >= 20) + acState.setState(&StateID_LookUp); +} + +CREATE_STATE(dEndingMgr_c, LookUp); +void dEndingMgr_c::beginState_LookUp() { + _120 |= 8; + lookAtMode = 2; // Higher maximum distance + + timer = 0; +} + +void dEndingMgr_c::endState_LookUp() { +} + +void dEndingMgr_c::executeState_LookUp() { + timer++; + + if (timer >= 60) + _120 &= ~8; + + if (timer >= 90) + acState.setState(&StateID_JumpOntoSwitch); +} + + +CREATE_STATE(dEndingMgr_c, JumpOntoSwitch); +void dEndingMgr_c::beginState_JumpOntoSwitch() { + for (int i = 0; i < 4; i++) { + if (dAcPy_c *player = players[i]) { + float target = manipFourPlayerPos(i, 1144.0f); + float speed = 2.0f; + player->moveInDirection(&target, &speed); + } + } + + timer = 0; +} +void dEndingMgr_c::endState_JumpOntoSwitch() { +} +void dEndingMgr_c::executeState_JumpOntoSwitch() { + dAcPy_c *player = players[3]; + + if (timer > 60) { + acState.setState(&StateID_ThanksPeach); + } else if (player->isReadyForDemoControlAction()) { + player->input.setTransientForcedButtons(WPAD_DOWN); + } else if (timer > 30) { + player->input.unsetPermanentForcedButtons(WPAD_TWO); + } else if (timer > 15) { + player->input.setPermanentForcedButtons(WPAD_TWO); + } + + timer++; +} + +static daEnBossKoopaDemoPeach_c *getPeach() { + return (daEnBossKoopaDemoPeach_c*)dEn_c::search(EN_BOSS_KOOPA_DEMO_PEACH); +} + +CREATE_STATE(dEndingMgr_c, ThanksPeach); +void dEndingMgr_c::beginState_ThanksPeach() { + timer = -1; + getPeach()->doStateChange(&daEnBossKoopaDemoPeach_c::StateID_Turn); +} +void dEndingMgr_c::endState_ThanksPeach() { +} +void dEndingMgr_c::executeState_ThanksPeach() { + daEnBossKoopaDemoPeach_c *peach = getPeach(); + dStateBase_c *peachSt = peach->acState.getCurrentState(); + + if (peach->stage == 1 && peachSt == &peach->StateID_Turn) { + timer++; + if (timer == 1) { + sub_8019C390(_8042A788, 6); + } + if (timer > 20) { + peach->doStateChange(&peach->StateID_Open); + peach->_120 |= 8; + timer = -1; + } + } + + if (peach->stage == 1 && peachSt == &peach->StateID_Open) { + peach->doStateChange(&peach->StateID_Rescue); + } + + if (peach->stage == 3 && peachSt == &peach->StateID_Rescue) { + peach->doStateChange(&peach->StateID_Thank); + } + + if (peachSt == &peach->StateID_Thank) { + // 1. Freeze Peach by changing to Stage 8 as soon as she's almost done + // 2. Do our thing + // 3. Go back! + if (peach->stage == 0 && peach->counter == 33 && timer == -1) { + peach->stage = 8; + timer = 0; + } else if (peach->stage == 8) { + timer++; + if (timer == 8) { + float target = peach->pos.x - 20.0f; + float speed = 1.5f; + players[3]->moveInDirection(&target, &speed); + } else if (timer == 90) { + peach->stage = 0; + players[3]->setAnimePlayWithAnimID(dm_escort); + } + } else if (peach->stage == 7) { + // All the players are glad + timer = 0; + peach->stage = 9; + for (int i = 0; i < 4; i++) { + if (dAcPy_c *player = players[i]) { + OSReport("Going to dmglad\n"); + OSReport("Player %d states: %s and %s\n", i, player->states2.getCurrentState()->getName(), player->demoStates.getCurrentState()->getName()); + player->setAnimePlayWithAnimID(dm_glad); + + static const int vocs[4] = { + SE_VOC_MA_SAVE_PRINCESS, + SE_VOC_LU_SAVE_PRINCESS, + SE_VOC_KO_SAVE_PRINCESS, + SE_VOC_KO2_SAVE_PRINCESS + }; + dPlayerModelHandler_c *pmh = (dPlayerModelHandler_c*)(((u32)player) + 0x2A60); + int voc = vocs[pmh->mdlClass->player_id_1]; + nw4r::snd::SoundHandle handle; + PlaySoundWithFunctionB4(SoundRelatedClass, &handle, voc, 1); + + int powerup = *((u32*)( 0x1090 + ((u8*)player) )); + handle.SetPitch(powerup == 3 ? 1.5f : 1.0f); + } + } + } else if (peach->stage == 9) { + timer++; + if (timer == 90) { + RESTART_CRSIN_LevelStartStruct.purpose = 0; + RESTART_CRSIN_LevelStartStruct.world1 = 6; + RESTART_CRSIN_LevelStartStruct.world2 = 6; + RESTART_CRSIN_LevelStartStruct.level1 = 40; + RESTART_CRSIN_LevelStartStruct.level2 = 40; + RESTART_CRSIN_LevelStartStruct.areaMaybe = 0; + RESTART_CRSIN_LevelStartStruct.entrance = 0xFF; + RESTART_CRSIN_LevelStartStruct.unk4 = 0; // load replay + DontShowPreGame = true; + ExitStage(RESTART_CRSIN, 0, BEAT_LEVEL, MARIO_WIPE); + } + } + } +} + + + + +Vec2 dEndingMgr_c::_vf70() { + // HACK OF THE MILLENIUM + // DON'T TRY THIS AT HOME. + Vec2 *v = (Vec2*)this; + v->x = 1195.0f; + v->y = -394.0f; + return (const Vec2){12345.0f, 67890.f}; +} + diff --git a/tools/UsedProfileAndSpriteList.txt b/tools/UsedProfileAndSpriteList.txt index 7370670..3f5c95d 100644 --- a/tools/UsedProfileAndSpriteList.txt +++ b/tools/UsedProfileAndSpriteList.txt @@ -35,6 +35,7 @@ 213 : BRANCH : Captain Bowser 239 : MIST_INTERMITTENT : Event Block 244 : RIVER_MGR : Line God +245 : HANA_MOUNTAIN : Ending Manager 246 : TAG_THUNDER : Level Special 250 : KAWANAGARE : Electric Line 251 : SLOW_QUICK_TAG : Topman Boss |