summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--NewerProjectKP.yaml1
-rw-r--r--endingMgr.yaml16
-rw-r--r--src/endingMgr.cpp307
-rw-r--r--tools/UsedProfileAndSpriteList.txt1
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