summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTreeki <treeki@gmail.com>2013-02-25 21:58:44 +0100
committerTreeki <treeki@gmail.com>2013-02-25 21:58:44 +0100
commitdc47aaf9dc94ecd7f46e859e165e7ede9849116f (patch)
treefdb84b58267dcf7120e4671bcff8d1a937feb6cf
parentb63de9977962b6ab7d2bcc470579eaacc16c51d4 (diff)
downloadkamek-dc47aaf9dc94ecd7f46e859e165e7ede9849116f.tar.gz
kamek-dc47aaf9dc94ecd7f46e859e165e7ede9849116f.zip
tons and tons of final boss fixes, the usual
Diffstat (limited to '')
-rw-r--r--bossCaptainBowser.yaml4
-rw-r--r--src/bossCaptainBowser.cpp318
2 files changed, 256 insertions, 66 deletions
diff --git a/bossCaptainBowser.yaml b/bossCaptainBowser.yaml
index 354d0dd..7544c56 100644
--- a/bossCaptainBowser.yaml
+++ b/bossCaptainBowser.yaml
@@ -32,6 +32,10 @@ hooks:
# That offset stores a pointer to a table of pointers to strings, followed by four bytes of padding
# Each string is an arcname to load
+ - name: NeverLetCarDismountPlayerIfItTouchesTheGround
+ type: patch
+ addr_pal: 0x80812C84
+ data: '38600000'
################################################
# HOOKS FOR KOOPA THROW
diff --git a/src/bossCaptainBowser.cpp b/src/bossCaptainBowser.cpp
index 5eb8ac7..7b80576 100644
--- a/src/bossCaptainBowser.cpp
+++ b/src/bossCaptainBowser.cpp
@@ -7,6 +7,10 @@
extern "C" void *StageScreen;
+extern u32 GameTimer;
+
+#define time_macro *(u32*)((GameTimer) + 0x4)
+
// const char* effects_name_list [] = {
// "Wm_jr_electricline", // cool
@@ -99,12 +103,22 @@ public:
float sinTimerY;
bool sinTimerXRunning, sinTimerYRunning, stopMoving;
- bool wereEntirelyDone;
+ bool shipAnmFinished;
float explosionBottomBound;
bool deathSequenceRunning;
+ bool forceClownEnds;
+ int timerWhenCrashHappens;
+ int timerForVictoryDance;
void initiateDeathSequence();
+ int clownCount;
+ dEn_c *clownPointers[4];
+ VEC2 clownDests[4];
+
+ int saveTimer;
+ bool exitedFlag;
+
static daCaptainBowser *build();
void bindAnimChr_and_setUpdateRate(const char* name, int unk, float unk2, float rate);
@@ -126,6 +140,7 @@ public:
DECLARE_STATE(Intro);
DECLARE_STATE(FinalAttack);
DECLARE_STATE(Outro);
+ DECLARE_STATE(PanToExit);
};
@@ -149,6 +164,7 @@ daCaptainBowser *daCaptainBowser::build() {
CREATE_STATE(daCaptainBowser, Intro);
CREATE_STATE(daCaptainBowser, FinalAttack);
CREATE_STATE(daCaptainBowser, Outro);
+ CREATE_STATE(daCaptainBowser, PanToExit);
@@ -249,7 +265,7 @@ int daCaptainBowser::onCreate() {
// Prep the goods
this->playerCount = GetActivePlayerCount();
- this->maxDamage = (20 * this->playerCount) + 10;
+ this->maxDamage = 24;
pos.z = 8000.0;
this->scale = (Vec){0.57, 0.57, 0.57};
@@ -292,14 +308,12 @@ int daCaptainBowser::onCreate() {
this->isIntro = 3;
doStateChange(&StateID_Intro);
- // THIS IS FOR TESTING!!!
- damage = 0;
-
return true;
}
int daCaptainBowser::onDelete() {
- prplSound.Stop(0);
+ if (prplSound.Exists())
+ prplSound.Stop(0);
return true;
}
@@ -308,9 +322,22 @@ int daCaptainBowser::afterExecute(int param) {
}
int daCaptainBowser::onExecute() {
+ if (forceClownEnds) {
+ dEn_c *clownIter = 0;
+ while (clownIter = (dEn_c*)dEn_c::search(JR_CLOWN_FOR_PLAYER, clownIter)) {
+ clownIter->counter_500 = 120; // what a terrible hack.
+ float *pPropRotationIncrement = (float*)(((u32)clownIter) + 0x740);
+ *pPropRotationIncrement = 30.0f;
+
+ SmoothRotation((s16*)(((u32)clownIter) + 0xD4A), 0, 0x300);
+ }
+ }
+
acState.execute();
+ if (saveTimer > 0)
+ time_macro = saveTimer;
- if (!prplSound.Exists() && acState.getCurrentState() != &StateID_Outro) {
+ if (!prplSound.Exists() && acState.getCurrentState() != &StateID_Outro && acState.getCurrentState() != &StateID_PanToExit) {
PlaySoundWithFunctionB4(SoundRelatedClass, &prplSound, SE_BOSS_SHIP_PRPL, 1);
}
@@ -345,7 +372,7 @@ int daCaptainBowser::onExecute() {
}
}
- if(this->shipAnm.isAnimationDone() && acState.getCurrentState() != &StateID_Outro) {
+ if(this->shipAnm.isAnimationDone() && acState.getCurrentState() != &StateID_Outro && acState.getCurrentState() != &StateID_PanToExit) {
this->shipAnm.setCurrentFrame(0.0);
}
@@ -744,97 +771,256 @@ void daCaptainBowser::beginState_Outro() {
explosionBottomBound = 0.0f;
timer = 0;
+ timerWhenCrashHappens = 1000000;
+ timerForVictoryDance = 1000000;
}
+extern void *_8042A788;
+extern void playFanfare(void *, int type);
extern dStateBase_c JrClownEndDemoState;
void daCaptainBowser::executeState_Outro() {
- if (wereEntirelyDone)
- return;
-
timer++;
- float frame = shipAnm.getCurrentFrame();
+ if (!shipAnmFinished) {
+ float frame = shipAnm.getCurrentFrame();
+
+ // nuke the things!
+ if (frame == 35.0f) {
+ dActor_c *iter = 0;
+
+ while (iter = (dActor_c*)dActor_c::searchByBaseType(2, iter)) {
+ dStageActor_c *sa = (dStageActor_c*)iter;
+
+ if (sa->name == EN_BIRIKYU_MAKER || sa->name == KAZAN_MGR) {
+ sa->Delete(1);
+ }
+
+ if (sa->name == EN_LINE_BIRIKYU ||
+ sa->name == EN_STAR_COIN ||
+ sa->name == EN_HATENA_BALLOON ||
+ sa->name == EN_ITEM ||
+ sa->name == EN_TARZANROPE || // Meteor
+ sa->name == WM_ANCHOR) { // Koopa Throw
+ sa->killedByLevelClear();
+ sa->Delete(1);
+ }
+ }
- // nuke the things!
- if (frame == 35.0f) {
- dActor_c *iter = 0;
+ // freeze ye olde clowne
+ dEn_c *clownIter = 0;
+ while (clownIter = (dEn_c*)dEn_c::search(JR_CLOWN_FOR_PLAYER, clownIter)) {
+ clownIter->doStateChange(&JrClownEndDemoState);
+ }
+ forceClownEnds = true;
+ saveTimer = time_macro;
- while (iter = (dActor_c*)dActor_c::searchByBaseType(2, iter)) {
- dStageActor_c *sa = (dStageActor_c*)iter;
+ // remove all ship collisions
+ for (int i = 0; i < SHIP_SCOLL_COUNT; i++)
+ shipSColls[i].removeFromList();
- if (sa->name == EN_BIRIKYU_MAKER || sa->name == KAZAN_MGR) {
- sa->Delete(1);
+ } else if (frame == 150.0f) {
+ nw4r::snd::SoundHandle handle;
+ PlaySoundWithFunctionB4(SoundRelatedClass, &handle, SE_BOSS_KOOPA_CRASH, 1);
+ timerWhenCrashHappens = timer;
+ prplSound.Stop(10);
+
+ ClassWithCameraInfo *cwci = ClassWithCameraInfo::instance;
+ Vec efPos = {cwci->screenCentreX+168.0f, cwci->screenTop-cwci->screenHeight, pos.z};
+ SpawnEffect("Wm_bg_volcano", 0, &efPos, &(S16Vec){0,0,0}, &(Vec){4.0, 4.0, 4.0});
+
+ ShakeScreen(StageScreen, 17, 7, 0, 0);
+
+ } else if (shipAnm.isAnimationDone()) {
+ shipAnmFinished = true;
+ }
+
+ if (frame > 30.0f) {
+ if (timer & 4 && explosionBottomBound > -249.0f) {
+ static const char *efs[] = {"Wm_en_explosion", "Wm_ob_cmnboxpiece"};
+
+ int id = MakeRandomNumber(2);
+ Vec efPos = {
+ pos.x - 150.0f + MakeRandomNumber(300),
+ pos.y + explosionBottomBound + MakeRandomNumber(250 + explosionBottomBound),
+ pos.z + 200.0f
+ };
+ float efScale = (float(MakeRandomNumber(30)) / 20.0f);
+
+ SpawnEffect(efs[id], 0, &efPos, &(S16Vec){0,0,0}, &(Vec){efScale,efScale,efScale});
}
- if (sa->name == EN_LINE_BIRIKYU ||
- sa->name == EN_STAR_COIN ||
- sa->name == EN_HATENA_BALLOON ||
- sa->name == EN_ITEM ||
- sa->name == EN_TARZANROPE || // Meteor
- sa->name == WM_ANCHOR) { // Koopa Throw
- sa->killedByLevelClear();
- sa->Delete(1);
+ if ((timer % 12) == 0 && (frame < 150.0f)) {
+ nw4r::snd::SoundHandle handle;
+ PlaySoundWithFunctionB4(SoundRelatedClass, &handle, SE_DEMO_OP_CAKE_CLASH_1210f, 1);
}
+
+ explosionBottomBound -= 0.85f;
}
- // freeze ye olde clowne
+ // handleYSpeed():
+ bowserYSpeed += bowserYAccel;
+ if (bowserYSpeed < bowserMaxYSpeed)
+ bowserYSpeed = bowserMaxYSpeed;
+
+ // doMovement()
+ bowserX += bowserXSpeed;
+ bowserY += bowserYSpeed;
+
+ bowserRotX -= 0xC00;
+ bowserRotY -= 0x100;
+ }
+
+
+ // FUN SHITS.
+ if (timer == (timerWhenCrashHappens + 90)) {
+ playFanfare(_8042A788, 4);
+ timerForVictoryDance = timer + (7*60);
+
+ // Prepare for moving the clowns
+ clownCount = 0;
+
+ dEn_c *unsortedClownPointers[4];
+ dAcPy_c *unsortedClownPlayers[4];
+
dEn_c *clownIter = 0;
while (clownIter = (dEn_c*)dEn_c::search(JR_CLOWN_FOR_PLAYER, clownIter)) {
- clownIter->doStateChange(&JrClownEndDemoState);
+ dAcPy_c *player = *((dAcPy_c**)(((u32)clownIter) + 0x738));
+ if (player) {
+ unsortedClownPointers[clownCount] = clownIter;
+ unsortedClownPlayers[clownCount] = player;
+ clownCount++;
+ }
}
- // remove all ship collisions
- for (int i = 0; i < SHIP_SCOLL_COUNT; i++)
- shipSColls[i].removeFromList();
+ // Now sort them by ID
+ int sortedClownID = 0;
+ for (int playerID = 0; playerID < 4; playerID++) {
+ dAcPy_c *player = (dAcPy_c*)GetSpecificPlayerActor(playerID);
- } else if (frame == 150.0f) {
- nw4r::snd::SoundHandle handle;
- PlaySoundWithFunctionB4(SoundRelatedClass, &handle, SE_BOSS_KOOPA_CRASH, 1);
- prplSound.Stop(10);
+ for (int searchClown = 0; searchClown < clownCount; searchClown++) {
+ if (player == unsortedClownPlayers[searchClown]) {
+ clownPointers[sortedClownID] = unsortedClownPointers[searchClown];
+ sortedClownID++;
+ break;
+ }
+ }
+ }
ClassWithCameraInfo *cwci = ClassWithCameraInfo::instance;
- Vec efPos = {cwci->screenCentreX+168.0f, cwci->screenTop-cwci->screenHeight, pos.z};
- SpawnEffect("Wm_bg_volcano", 0, &efPos, &(S16Vec){0,0,0}, &(Vec){4.0, 4.0, 4.0});
- ShakeScreen(StageScreen, 17, 7, 0, 0);
+ // calculate their end positions
+ // Assuming each clown takes up ~32 width, and we have 16 padding between them ...
+ float clownSpan = (clownCount * 48.0f) - 16.0f;
+ float clownX = cwci->screenCentreX - (clownSpan / 2.0f);
- } else if (shipAnm.isAnimationDone()) {
- wereEntirelyDone = true;
+ for (int i = 0; i < clownCount; i++) {
+ clownDests[i].x = clownX;
+ clownDests[i].y = cwci->screenCentreY;
+ clownX += 48.0f;
+ }
}
- if (frame > 30.0f) {
- if (timer & 4 && explosionBottomBound > -249.0f) {
- static const char *efs[] = {"Wm_en_explosion", "Wm_ob_cmnboxpiece"};
+ if (timer > (timerWhenCrashHappens + 90)) {
+ // Let's move the clowns
+ int playersAtEnd = 0;
- int id = MakeRandomNumber(2);
- Vec efPos = {
- pos.x - 150.0f + MakeRandomNumber(300),
- pos.y + explosionBottomBound + MakeRandomNumber(250 + explosionBottomBound),
- pos.z + 200.0f
- };
- float efScale = (float(MakeRandomNumber(30)) / 20.0f);
+ for (int i = 0; i < clownCount; i++) {
+ dEn_c *clown = clownPointers[i];
+
+ float moveSpeed = 1.2f;
+
+ // Are we there already?
+ float xDiff = abs(clown->pos.x - clownDests[i].x);
+ float yDiff = abs(clown->pos.y - clownDests[i].y);
+
+ int check = 0;
+ if (xDiff < moveSpeed) {
+ clown->pos.x = clownDests[i].x;
+ check |= 1;
+ }
+ if (yDiff < moveSpeed) {
+ clown->pos.y = clownDests[i].y;
+ check |= 2;
+ }
+ if (check == 3) {
+ playersAtEnd++;
+ continue;
+ }
+
+ // Otherwise, move them a bit further
+ VEC3 direction = {clownDests[i].x - clown->pos.x, clownDests[i].y - clown->pos.y, 0.0f};
+ VECNormalize(&direction, &direction);
+ VECScale(&direction, &direction, moveSpeed);
- SpawnEffect(efs[id], 0, &efPos, &(S16Vec){0,0,0}, &(Vec){efScale,efScale,efScale});
+ clown->pos.x += direction.x;
+ clown->pos.y += direction.y;
}
- if ((timer % 12) == 0 && (frame < 150.0f)) {
- nw4r::snd::SoundHandle handle;
- PlaySoundWithFunctionB4(SoundRelatedClass, &handle, SE_DEMO_OP_CAKE_CLASH_1210f, 1);
+ if (playersAtEnd >= clownCount) {
+ //if (timerForVictoryDance == 1000000)
+ // timerForVictoryDance = timer + 45;
+ }
+
+ if (timer == timerForVictoryDance) {
+ static const int vocs[4] = {
+ SE_VOC_MA_CLEAR_LAST_BOSS,
+ SE_VOC_LU_CLEAR_LAST_BOSS,
+ SE_VOC_KO_CLEAR_LAST_BOSS,
+ SE_VOC_KO2_CLEAR_LAST_BOSS
+ };
+ for (int i = 0; i < clownCount; i++) {
+ dAcPy_c *player = *((dAcPy_c**)(((u32)clownPointers[i]) + 0x738));
+ // let's be hacky
+ dPlayerModelHandler_c *pmh = (dPlayerModelHandler_c*)(((u32)player) + 0x2A60);
+ int whatAnim = goal_puton_capB;
+ if (pmh->mdlClass->powerup_id == 4)
+ whatAnim = goal_puton_capB;
+ else if (pmh->mdlClass->powerup_id == 5)
+ whatAnim = goal_puton_capC;
+ pmh->mdlClass->startAnimation(whatAnim, 1.0f, 0.0f, 0.0f);
+
+ nw4r::snd::SoundHandle handle;
+ PlaySoundWithFunctionB4(SoundRelatedClass, &handle, vocs[pmh->mdlClass->player_id_1], 1);
+ }
}
- explosionBottomBound -= 0.85f;
+ if (timer == (timerForVictoryDance + 180)) {
+ doStateChange(&StateID_PanToExit);
+ nw4r::snd::SoundHandle handle;
+ PlaySoundWithFunctionB4(SoundRelatedClass, &handle, SE_PLY_CROWN_ACC, 1);
+ }
+ //dAcPy_c *splayer = *((dAcPy_c**)(((u32)clownPointers[0]) + 0x738));
+ //OSReport("Player has %s\n", splayer->states2.getCurrentState()->getName());
}
+}
+void daCaptainBowser::endState_Outro() { }
- // handleYSpeed():
- bowserYSpeed += bowserYAccel;
- if (bowserYSpeed < bowserMaxYSpeed)
- bowserYSpeed = bowserMaxYSpeed;
- // doMovement()
- bowserX += bowserXSpeed;
- bowserY += bowserYSpeed;
+void daCaptainBowser::beginState_PanToExit() {
+ timer = 0;
+}
+void daCaptainBowser::endState_PanToExit() {
+}
- bowserRotX -= 0xC00;
- bowserRotY -= 0x100;
+void daCaptainBowser::executeState_PanToExit() {
+ float targetClownY = ClassWithCameraInfo::instance->screenCentreY - 160.0f;
+
+ for (int i = 0; i < clownCount; i++) {
+ dEn_c *clown = clownPointers[i];
+ clown->pos.y -= 1.5f;
+ if (clown->pos.y < targetClownY && !exitedFlag) {
+ RESTART_CRSIN_LevelStartStruct.purpose = 0;
+ RESTART_CRSIN_LevelStartStruct.world1 = 7;
+ RESTART_CRSIN_LevelStartStruct.world2 = 7;
+ 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);
+ exitedFlag = true;
+ }
+ }
}
-void daCaptainBowser::endState_Outro() { }
+