From 457a40644f0a492ed8acf8dbf66888bee9035100 Mon Sep 17 00:00:00 2001 From: Treeki Date: Fri, 22 Feb 2013 00:26:14 +0100 Subject: more updates and fixes to the final boss than I can count --- src/bossCaptainBowser.cpp | 554 +++++++++++++++++++++++++++++++--------------- src/bossKoopaThrow.cpp | 31 ++- src/bossPlayerClown.S | 46 ++++ src/bossPlayerClown.cpp | 59 ++++- 4 files changed, 500 insertions(+), 190 deletions(-) create mode 100644 src/bossPlayerClown.S (limited to 'src') diff --git a/src/bossCaptainBowser.cpp b/src/bossCaptainBowser.cpp index cb076c6..5eb8ac7 100644 --- a/src/bossCaptainBowser.cpp +++ b/src/bossCaptainBowser.cpp @@ -45,6 +45,7 @@ public: int onDelete(); int onExecute(); int onDraw(); + int afterExecute(int param); mHeapAllocator_c allocator; nw4r::g3d::ResFile resFile; @@ -56,9 +57,10 @@ public: m3d::anmChr_c chrAnimation; m3d::anmChr_c shipAnm; - static const int SHIP_COLL_COUNT = 7; - ActivePhysics shipCollisions[SHIP_COLL_COUNT]; - ActivePhysics Roar; + nw4r::snd::SoundHandle prplSound; + + static const int SHIP_SCOLL_COUNT = 7; + Physics shipSColls[SHIP_SCOLL_COUNT]; mEf::es2 effect; mEf::es2 shipDmgA; @@ -67,23 +69,49 @@ public: mEf::es2 shipDmgD; mEf::es2 shipDmgE; + mEf::es2 flamethrowerEffect; + mEf::es2 flamethrowerEffectInd; + + nw4r::g3d::ResFile flamethrowerRF; + m3d::mdl_c flamethrowerModel; + m3d::anmTexSrt_c flamethrowerAnim; + bool renderFlamethrowerModel; + ActivePhysics flameCollision; + +#define flameOffsetX -160.0f +#define flameOffsetY 150.0f +#define flameZ 1900.0f + Vec flameScale; + char isAngry; char isInvulnerable; char isIntro; - float scaleIncreaser; - int homingBillCountdown; - int homingBillSlot; int maxDamage; int playerCount; - float sinTimer; float roarLen; + float bowserX, bowserY; + s16 bowserRotX, bowserRotY; + float bowserXSpeed, bowserYSpeed, bowserMaxYSpeed, bowserYAccel; + + s16 shipRotY; + float sinTimerX; + float sinTimerY; + bool sinTimerXRunning, sinTimerYRunning, stopMoving; + + bool wereEntirelyDone; + float explosionBottomBound; + + bool deathSequenceRunning; + void initiateDeathSequence(); + static daCaptainBowser *build(); void bindAnimChr_and_setUpdateRate(const char* name, int unk, float unk2, float rate); void spriteCollision(ActivePhysics *apThis, ActivePhysics *apOther); void playerCollision(ActivePhysics *apThis, ActivePhysics *apOther); + bool collisionCat13_Hammer(ActivePhysics *apThis, ActivePhysics *apOther); void addScoreWhenHit(void *other); @@ -96,6 +124,7 @@ public: DECLARE_STATE(Damage); DECLARE_STATE(Intro); + DECLARE_STATE(FinalAttack); DECLARE_STATE(Outro); }; @@ -118,6 +147,7 @@ daCaptainBowser *daCaptainBowser::build() { CREATE_STATE(daCaptainBowser, Damage); CREATE_STATE(daCaptainBowser, Intro); + CREATE_STATE(daCaptainBowser, FinalAttack); CREATE_STATE(daCaptainBowser, Outro); @@ -125,50 +155,37 @@ daCaptainBowser *daCaptainBowser::build() { //////////////////////// // Collision Functions //////////////////////// - void daCaptainBowser::addScoreWhenHit(void *other) { }; +void daCaptainBowser::addScoreWhenHit(void *other) { }; - void daCaptainBowser::spriteCollision(ActivePhysics *apThis, ActivePhysics *apOther) { - if (apOther->owner->name == 657) { //time to get hurt - if (this->isInvulnerable) { - return; - } - this->damage -= 1; - - spawnHitEffectAtPosition((Vec2){apOther->owner->pos.x, apOther->owner->pos.y}); - - SpawnEffect("Wm_en_burst_m", 0, &apOther->owner->pos, &(S16Vec){0,0,0}, &(Vec){1.0, 1.0, 1.0}); - PlaySound(apOther->owner, SE_BOSS_CMN_STOMPED); - apOther->owner->Delete(1); +bool daCaptainBowser::collisionCat13_Hammer(ActivePhysics *apThis, ActivePhysics *apOther) { + apOther->owner->kill(); + SpawnEffect("Wm_en_burst_m", 0, &apOther->owner->pos, &(S16Vec){0,0,0}, &(Vec){1.0, 1.0, 1.0}); + apThis->someFlagByte |= 2; + return true; +} - if (this->damage == this->maxDamage/2) { doStateChange(&StateID_Roar); } - else if (this->damage < 0) { doStateChange(&StateID_Outro); } - else { doStateChange(&StateID_Damage); } +void daCaptainBowser::spriteCollision(ActivePhysics *apThis, ActivePhysics *apOther) { + if (apOther->owner->name == WM_PAKKUN) { //time to get hurt + if (this->isInvulnerable) { + return; } - } + this->damage -= 1; - void ShipAPhysicsCallback(ActivePhysics *apThis, ActivePhysics *apOther) { - daCaptainBowser *self = (daCaptainBowser*)apThis->owner; - if (apOther->owner->name == 657) { - OSReport("CANNON COLLISION"); - if (self->isInvulnerable) { - return; - } - self->damage -= 1; + spawnHitEffectAtPosition((Vec2){apOther->owner->pos.x, apOther->owner->pos.y}); - SpawnEffect("Wm_en_burst_m", 0, &apOther->owner->pos, &(S16Vec){0,0,0}, &(Vec){1.0, 1.0, 1.0}); - PlaySound(apOther->owner, SE_OBJ_TARU_BREAK); - apOther->owner->Delete(1); + SpawnEffect("Wm_en_burst_m", 0, &apOther->owner->pos, &(S16Vec){0,0,0}, &(Vec){1.0, 1.0, 1.0}); + PlaySound(apOther->owner, SE_BOSS_CMN_STOMPED); + apOther->owner->Delete(1); - if (self->damage == self->maxDamage/2) { self->doStateChange(&daCaptainBowser::StateID_Roar); } - else if (self->damage < 0) { self->doStateChange(&daCaptainBowser::StateID_Outro); } - - apThis->someFlagByte |= 2; - } + if (this->damage == this->maxDamage/2) { doStateChange(&StateID_Roar); } + else if (this->damage < 0) { initiateDeathSequence(); } + else { doStateChange(&StateID_Damage); } } +} - void daCaptainBowser::playerCollision(ActivePhysics *apThis, ActivePhysics *apOther) { - DamagePlayer(this, apThis, apOther); - } +void daCaptainBowser::playerCollision(ActivePhysics *apThis, ActivePhysics *apOther) { + DamagePlayer(this, apThis, apOther); +} @@ -180,6 +197,13 @@ void daCaptainBowser::bindAnimChr_and_setUpdateRate(const char* name, int unk, f } int daCaptainBowser::onCreate() { + bowserX = -148.0f; + bowserY = 122.0f; + bowserRotY = 0xD800; + + shipRotY = 0x4000; + sinTimerXRunning = true; + sinTimerYRunning = true; // Model creation allocator.link(-1, GameHeaps[0], 0, 0x20); @@ -206,6 +230,20 @@ int daCaptainBowser::onCreate() { this->shipModel.bindAnim(&this->shipAnm, 0.0); this->shipAnm.setUpdateRate(1.0); + // Flamethrower + flamethrowerRF.data = getResource("fire_cannon", "g3d/flame_koopa.brres"); + + nw4r::g3d::ResMdl ftResMdl = flamethrowerRF.GetResMdl("fire_effect1x6_right"); + nw4r::g3d::ResAnmTexSrt ftResAnm = flamethrowerRF.GetResAnmTexSrt("fire_effect1x6_right"); + + flamethrowerModel.setup(ftResMdl, &allocator, 0x224, 1, 0); + SetupTextures_MapObj(&flamethrowerModel, 0); + + flamethrowerAnim.setup(ftResMdl, ftResAnm, &allocator, 0, 1); + flamethrowerAnim.bindEntry(&flamethrowerModel, ftResAnm, 0, 0); + flamethrowerModel.bindAnim(&flamethrowerAnim, 0.0f); + flamethrowerAnim.setFrameForEntry(0.0f, 0); + flamethrowerAnim.setUpdateRate(1.0f); allocator.unlink(); @@ -215,47 +253,20 @@ int daCaptainBowser::onCreate() { pos.z = 8000.0; this->scale = (Vec){0.57, 0.57, 0.57}; - this->homingBillCountdown = 270; - this->homingBillSlot = 0; this->damage = this->maxDamage; - - for (int i = 0; i < SHIP_COLL_COUNT; i++) { - shipCollisions[i].owner = this; - shipCollisions[i].info.category1 = 3; - shipCollisions[i].info.category2 = 0; - shipCollisions[i].info.bitfield1 = 0x4F; - shipCollisions[i].info.bitfield2 = 0x8028E; - shipCollisions[i].info.unkShort1C = 0; - shipCollisions[i].info.callback = &ShipAPhysicsCallback; - } - - static const float xToCentres[] = {-56.541185, 161.824968, 106.258581}; - static const float yToCentres[] = {-91.176745, -66.957921, 57.935231}; - static const float xToEdges[] = {39.481380, 11.698187, 24.371222}; - static const float yToEdges[] = {37.040555, 12.821730, 21.844430}; - static const float trpValues0[] = {-39.481380, -11.698187, -24.371222}; - static const float trpValues1[] = {-39.481380, -11.698187, 24.371222}; - static const float trpValues2[] = {-39.481380, -11.698187, -24.371222}; - static const float trpValues3[] = {39.481380, 11.698187, -24.371222}; - static const float scX1[] = {-176.447600, 64.340078, -157.925471, -157.925471}; - static const float scY1[] = {-128.217300, 112.570378, -109.695171, -109.695171}; - static const float scX2[] = {-176.447600, 64.340078, -157.925471, -157.925471}; - static const float scY2[] = {-128.217300, 112.570378, -109.695171, -109.695171}; - - for (int i = 0; i < SHIP_COLL_COUNT; i++) { - shipCollisions[i].info.xDistToCenter = xToCentres[i]; - shipCollisions[i].info.yDistToCenter = yToCentres[i]; - shipCollisions[i].info.xDistToEdge = xToEdges[i]; - shipCollisions[i].info.yDistToEdge = yToEdges[i]; - if (i >= 4) { - int xi = i - 4; - shipCollisions[i].trpValue0 = trpValues0[xi]; - shipCollisions[i].trpValue1 = trpValues1[xi]; - shipCollisions[i].trpValue2 = trpValues2[xi]; - shipCollisions[i].trpValue3 = trpValues3[xi]; - shipCollisions[i].collisionCheckType = 3; - } + static const float scX1[] = {-176.447600, 64.340078, -157.925471, -157.925471, -158.561530, 49.742932, 48.957043}; + static const float scY1[] = {128.217300, 86.427956, 54.136191, -36.090801, 22.765115, 162.568398, 66.849169}; + static const float scX2[] = {-96.022566, 150.126781, 173.523155, 81.887358, -50.343171, 84.419332, 117.889270}; + static const float scY2[] = {54.136191, 54.136191, -36.090801, -79.779661, -26.166291, 142.846802, -2.083058}; + static s16 sRots[] = {-8192, -8192, -8192}; + + for (int i = 0; i < SHIP_SCOLL_COUNT; i++) { + shipSColls[i].setup(this, + scX1[i], scY1[i], scX2[i], scY2[i], + 0, 0, 0, 1, 0); + if (i >= 4) + shipSColls[i].setPtrToRotation(&sRots[i - 4]); } // Bowser Physics! @@ -263,8 +274,8 @@ int daCaptainBowser::onCreate() { BowserPhysics.xDistToCenter = -152.0; BowserPhysics.yDistToCenter = 152.0; - BowserPhysics.xDistToEdge = 38.0; - BowserPhysics.yDistToEdge = 38.0; + BowserPhysics.xDistToEdge = 28.0; + BowserPhysics.yDistToEdge = 26.0; BowserPhysics.category1 = 0x3; BowserPhysics.category2 = 0x0; @@ -277,90 +288,64 @@ int daCaptainBowser::onCreate() { - // Roar Physics! - ActivePhysics::Info RoarStruct; - RoarStruct.xDistToCenter = -186.0; - RoarStruct.yDistToCenter = 138.0; - - RoarStruct.xDistToEdge = 20.0; - RoarStruct.yDistToEdge = 20.0; - - RoarStruct.category1 = 0x3; - RoarStruct.category2 = 0x0; - RoarStruct.bitfield1 = 0x4F; - RoarStruct.bitfield2 = 0x8028E; - RoarStruct.unkShort1C = 0; - RoarStruct.callback = &dEn_c::collisionCallback; - - this->Roar.initWithStruct(this, &RoarStruct); - - // State Changers this->isIntro = 3; doStateChange(&StateID_Intro); + // THIS IS FOR TESTING!!! + damage = 0; + return true; } int daCaptainBowser::onDelete() { + prplSound.Stop(0); return true; } +int daCaptainBowser::afterExecute(int param) { + return dEn_c::afterExecute(param); +} + int daCaptainBowser::onExecute() { acState.execute(); - PlaySound(this, SE_BOSS_SHIP_PRPL); + if (!prplSound.Exists() && acState.getCurrentState() != &StateID_Outro) { + PlaySoundWithFunctionB4(SoundRelatedClass, &prplSound, SE_BOSS_SHIP_PRPL, 1); + } + + aPhysics.info.xDistToCenter = bowserX; + aPhysics.info.yDistToCenter = bowserY + 28.0f; bodyModel._vf1C(); shipModel._vf1C(); - if(this->isIntro == 0) { + for (int i = 0; i < SHIP_SCOLL_COUNT; i++) + shipSColls[i].update(); - float xmod = sin(this->sinTimer * 3.14 / 180.0) * 60.0; - float ymod = sin(this->sinTimer * 3.14 / 130.0) * 84.0; + float xmod = sinTimerXRunning ? (sin(this->sinTimerX * 3.14 / 180.0) * 60.0) : 0.0f; + float ymod = sin(this->sinTimerY * 3.14 / 130.0) * (sinTimerYRunning ? 84.0 : 10.0); + if(this->isIntro == 0) { pos.x = ClassWithCameraInfo::instance->screenCentreX + 200.0 + xmod; pos.y = ClassWithCameraInfo::instance->screenCentreY - 180.0 + ymod; - this->sinTimer++; + sinTimerX++; + if (sinTimerX >= 360) { + sinTimerX = 0; + if (stopMoving) + sinTimerXRunning = false; + } + + sinTimerY++; + if (sinTimerY >= 260) { + sinTimerY = 0; + if (stopMoving) + sinTimerYRunning = false; + } } - // this->homingBillCountdown--; - - // if (this->homingBillCountdown == 0) { - - // Vec tempPos; - - // switch (this->homingBillSlot) { - // case 0: - // this->homingBillSlot++; - // tempPos.x = this->pos.x - 26.0; - // tempPos.y = this->pos.y + 40.0; - // tempPos.z = this->pos.z + 2000.0; - // break; - - // case 1: - // this->homingBillSlot++; - // tempPos.x = this->pos.x + 22.0; - // tempPos.y = this->pos.y + 40.0; - // tempPos.z = this->pos.z + 2000.0; - // break; - - // case 2: - // this->homingBillSlot = 0; - // tempPos.x = this->pos.x + 70.0; - // tempPos.y = this->pos.y + 40.0; - // tempPos.z = this->pos.z + 2000.0; - // break; - // } - - // SpawnEffect("Wm_en_killervanish", 0, &tempPos, &(S16Vec){0,0,0}, &(Vec){0.1, 0.1, 0.1}); - // PlaySoundAsync(this, SE_EMY_SR_KILLER_SHOT); - // CreateActor(EN_SEARCH_KILLER, 0, tempPos, 0, 0); - - // this->homingBillCountdown = (isAngry) ? 90: 180; - // } - - if(this->shipAnm.isAnimationDone()) { + + if(this->shipAnm.isAnimationDone() && acState.getCurrentState() != &StateID_Outro) { this->shipAnm.setCurrentFrame(0.0); } @@ -371,9 +356,8 @@ int daCaptainBowser::onDraw() { if(this->isIntro > 2) { return false; } - matrix.translation(pos.x-146.0, pos.y+122.0, pos.z-200.0); // 136.0 is the bottom of the platform footing - short newrot = rot.y + 0xD800; - matrix.applyRotationYXZ(&rot.x, &newrot, &rot.z); + matrix.translation(pos.x+bowserX, pos.y+bowserY, pos.z-200.0); // 136.0 is the bottom of the platform footing + matrix.applyRotationYXZ(&bowserRotX, &bowserRotY, &rot.z); bodyModel.setDrawMatrix(matrix); bodyModel.setScale(&(Vec){1.0, 1.0, 1.0}); @@ -383,8 +367,7 @@ int daCaptainBowser::onDraw() { matrix.translation(pos.x, pos.y, pos.z); - newrot = rot.y + 0x4000; - matrix.applyRotationYXZ(&rot.x, &newrot, &rot.z); + matrix.applyRotationYXZ(&rot.x, &shipRotY, &rot.z); shipModel.setDrawMatrix(matrix); shipModel.setScale(&scale); @@ -392,6 +375,18 @@ int daCaptainBowser::onDraw() { shipModel.scheduleForDrawing(); + if (renderFlamethrowerModel) { + matrix.translation(pos.x + flameOffsetX, pos.y + flameOffsetY, flameZ); + s16 thing = 0x8000; + matrix.applyRotationZ(&thing); + + flamethrowerModel.setDrawMatrix(matrix); + flamethrowerModel.setScale(&flameScale); + flamethrowerModel.calcWorld(false); + + flamethrowerModel.scheduleForDrawing(); + } + return true; } @@ -430,10 +425,17 @@ int daCaptainBowser::onDraw() { } // Bowser Flies In - if (this->timer == 422) { this->isIntro = 2; } - if ((this->timer > 420) && (this->timer < (420 + roarLen))) { - pos.x = ClassWithCameraInfo::instance->screenCentreX + ((this->timer - 420.0) * 1.5) - ((roarLen * 1.5) - 200.0); - pos.y = ClassWithCameraInfo::instance->screenCentreY - 380.0 + ((this->timer - 420.0) * 1.5) - ((roarLen * 1.5) - 200.0); + if (this->timer == 422) { + this->isIntro = 2; + + for (int i = 0; i < SHIP_SCOLL_COUNT; i++) + shipSColls[i].addToList(); + } + + if (this->timer > 420) { + int effectiveTimer = min(timer, 719U); + pos.x = ClassWithCameraInfo::instance->screenCentreX + ((effectiveTimer - 420.0) * 1.5) - ((roarLen * 1.5) - 200.0); + pos.y = ClassWithCameraInfo::instance->screenCentreY - 380.0 + ((effectiveTimer - 420.0) * 1.5) - ((roarLen * 1.5) - 200.0); } // Bowser does a shitty roar @@ -457,8 +459,6 @@ int daCaptainBowser::onDraw() { } void daCaptainBowser::endState_Intro() { - for (int i = 0; i < SHIP_COLL_COUNT; i++) - shipCollisions[i].addToList(); this->aPhysics.addToList(); this->isInvulnerable = 0; @@ -507,12 +507,12 @@ int daCaptainBowser::onDraw() { if (this->chrAnimation.getCurrentFrame() == 60.0) { // throw back int num = GenerateRandomNumber(4); - CreateActor(0x29F, 0x101 + ((num + 1) * 0x10), (Vec){pos.x-146.0, pos.y+122.0, pos.z}, 0, 0); + CreateActor(0x29F, 0x101 + ((num + 1) * 0x10), (Vec){pos.x+bowserX, pos.y+bowserY, pos.z}, 0, 0); } if (this->chrAnimation.getCurrentFrame() == 126.0) { // throw front int num = GenerateRandomNumber(4); - CreateActor(0x29F, ((num + 1) * 0x10) + 1, (Vec){pos.x-146.0, pos.y+122.0, pos.z}, 0, 0); + CreateActor(0x29F, ((num + 1) * 0x10) + 1, (Vec){pos.x+bowserX, pos.y+bowserY, pos.z}, 0, 0); } if (this->chrAnimation.isAnimationDone()) { @@ -573,39 +573,26 @@ int daCaptainBowser::onDraw() { bindAnimChr_and_setUpdateRate("kp_roar3", 1, 0.0, 1.0); this->isInvulnerable = 1; this->timer = 0; - this->scaleIncreaser = 0.5; - - // this->Roar.info.xDistToEdge = 70.0 * scaleIncreaser; - // this->Roar.info.yDistToEdge = 70.0 * scaleIncreaser; - - // this->Roar.addToList(); } void daCaptainBowser::executeState_Roar() { if (this->chrAnimation.getCurrentFrame() == 53.0) { // This is where the smackdown starts - PlaySound(this, SE_VOC_KP_L_SHOUT); + nw4r::snd::SoundHandle handle; + PlaySoundWithFunctionB4(SoundRelatedClass, &handle, SE_VOC_KP_L_SHOUT, 1); } if (this->chrAnimation.getCurrentFrame() > 53.0) { // This is where the smackdown starts - scaleIncreaser += 0.014285; - effect.spawn("Wm_ko_shout", 0, &(Vec){pos.x-186.0+(scaleIncreaser*16.0), pos.y+138.0+(scaleIncreaser*16.0), pos.z}, &(S16Vec){0,0,0x7000}, &(Vec){scaleIncreaser, scaleIncreaser, scaleIncreaser}); - - // this->Roar.info.xDistToEdge = 70.0 * scaleIncreaser; - // this->Roar.info.yDistToEdge = 70.0 * scaleIncreaser; + effect.spawn("Wm_ko_shout", 0, &(Vec){pos.x-174.0, pos.y+140.0, pos.z}, &(S16Vec){0,0,0x7000}, &(Vec){1.0, 1.0, 1.0}); } - // if (this->chrAnimation.getCurrentFrame() == 197.0) { // This is where the smackdown ends - // this->Roar.removeFromList(); - // } - if (this->chrAnimation.isAnimationDone()) { - doStateChange(&StateID_Wait); + doStateChange(deathSequenceRunning ? &StateID_FinalAttack : &StateID_Wait); } } void daCaptainBowser::endState_Roar() { this->isInvulnerable = 0; - this->isAngry = 1; + this->isAngry = 1; } @@ -633,10 +620,221 @@ int daCaptainBowser::onDraw() { ////////////////// // State Outro ////////////////// - void daCaptainBowser::beginState_Outro() { +void daCaptainBowser::initiateDeathSequence() { + deathSequenceRunning = true; + stopMoving = true; + + StopBGMMusic(); + dFlagMgr_c::instance->set(31, 0, false, false, false); + *((u32*)(((char*)dBgGm_c::instance) + 0x900F0)) = 999; + + doStateChange(&StateID_Roar); +} + +void daCaptainBowser::beginState_FinalAttack() { + isInvulnerable = true; + + bindAnimChr_and_setUpdateRate("mastfail", 1, 0.0, 1.0f); + + timer = 0; + flameScale.x = flameScale.y = flameScale.z = 0.0f; +} + +void daCaptainBowser::executeState_FinalAttack() { + timer++; + + if (timer == 56) { + nw4r::snd::SoundHandle handle; + PlaySoundWithFunctionB4(SoundRelatedClass, &handle, SE_VOC_JR_CHARGE, 1); + handle.SetPitch(0.25f); + } else if (timer == 185) { + nw4r::snd::SoundHandle handle; + PlaySoundWithFunctionB4(SoundRelatedClass, &handle, SE_VOC_KP_SHOUT, 1); + } else if (timer == 348) { + nw4r::snd::SoundHandle handle; + PlaySoundWithFunctionB4(SoundRelatedClass, &handle, SE_EMY_BIG_PAKKUN_DAMAGE_1, 1); + } + + if (timer > 204 && timer < 315) { + if (timer == 205) { + // First thing + renderFlamethrowerModel = true; + + static const ActivePhysics::Info fcInfo = { + 0.0f, 0.0f, 0.0f, 0.0f, // placeholder + 3, 0, 0x4F, 0x8028E, 0, + &dEn_c::collisionCallback + }; + flameCollision.initWithStruct(this, &fcInfo); + flameCollision.addToList(); + } + if (timer < 289) { + if (flameScale.y < 2.0f) { + flameScale.y = flameScale.y = flameScale.z = flameScale.y + 0.1f; + } else { + flameScale.y = flameScale.y = flameScale.z = 2.5f; + } + } + flameScale.x = flameScale.y * 1.5f; + + flameCollision.info.xDistToCenter = flameOffsetX - (48.0f * flameScale.x); + flameCollision.info.yDistToCenter = flameOffsetY; + flameCollision.info.xDistToEdge = 48.0f * flameScale.x; + flameCollision.info.yDistToEdge = 7.0f * flameScale.y; + + Vec efPos = {pos.x + flameOffsetX, pos.y + flameOffsetY, flameZ}; + S16Vec efRot = {-0x4000, 0, 0}; + //flamethrowerEffect.spawn("Wm_en_fireburner", 0, &efPos, &efRot, &flameScale); + flamethrowerEffectInd.spawn("Wm_en_fireburner6ind", 0, &efPos, &efRot, &flameScale); + flamethrowerModel._vf1C(); + flamethrowerAnim.process(); + } else if (timer == 315) { + renderFlamethrowerModel = false; + flameCollision.removeFromList(); + aPhysics.removeFromList(); + + Vec efPos = {pos.x + flameOffsetX - 6.0f, pos.y + flameOffsetY + 1.0f, pos.z}; + float offsets[] = {0.0f, 3.0f, 0.0f, -3.0f}; + for (int i = 0; i < 20; i++) { + efPos.y = pos.y + flameOffsetY + offsets[i & 3]; + SpawnEffect("Wm_mr_fireball_hit01", 0, &efPos, &(S16Vec){0,0,0}, &(Vec){1.5f, 1.5f, 1.5f}); + efPos.x -= 12.0f; + } + + nw4r::snd::SoundHandle handle; + PlaySoundWithFunctionB4(SoundRelatedClass, &handle, SE_OBJ_PAIPO, 1); + } else if (timer == 348) { + nw4r::snd::SoundHandle handle; + PlaySoundWithFunctionB4(SoundRelatedClass, &handle, SE_DEMO_ED_BALLOON_LAND, 1); + + Vec efPos = {pos.x - 72.0f, pos.y + 170.0f, pos.z}; + SpawnEffect("Wm_mr_wallkick_l", 0, &efPos, &(S16Vec){0,0,0}, &(Vec){2.0, 2.0, 2.0}); + } + + if (chrAnimation.isAnimationDone()) { + doStateChange(&StateID_Outro); + } +} + +void daCaptainBowser::endState_FinalAttack() { +} + +void daCaptainBowser::beginState_Outro() { + WLClass::instance->_4 = 5; + WLClass::instance->_8 = 0; + dStage32C_c::instance->freezeMarioBossFlag = 1; + + bowserX += 56.0f; + bindAnimChr_and_setUpdateRate("kp_death1", 1, 0.0, 1.0f); + + //shipRotY = -0x4000; + shipAnm.bind(&shipModel, shipFile.GetResAnmChr("mastfail_after"), 1); + shipModel.bindAnim(&shipAnm, 0.0); + shipAnm.setUpdateRate(0.5f); + + bowserXSpeed = -3.5f; + bowserYSpeed = 8.9f; + bowserMaxYSpeed = -4.0f; + bowserYAccel = -0.24375f; + + nw4r::snd::SoundHandle handle; + PlaySoundWithFunctionB4(SoundRelatedClass, &handle, SE_VOC_KP_L_FALL, 1); + + explosionBottomBound = 0.0f; + + timer = 0; +} + +extern dStateBase_c JrClownEndDemoState; +void daCaptainBowser::executeState_Outro() { + if (wereEntirelyDone) + return; + + timer++; + + 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); + } + } + + // freeze ye olde clowne + dEn_c *clownIter = 0; + while (clownIter = (dEn_c*)dEn_c::search(JR_CLOWN_FOR_PLAYER, clownIter)) { + clownIter->doStateChange(&JrClownEndDemoState); + } + + // remove all ship collisions + for (int i = 0; i < SHIP_SCOLL_COUNT; i++) + shipSColls[i].removeFromList(); + + } else if (frame == 150.0f) { + nw4r::snd::SoundHandle handle; + PlaySoundWithFunctionB4(SoundRelatedClass, &handle, SE_BOSS_KOOPA_CRASH, 1); + 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()) { + wereEntirelyDone = true; } - void daCaptainBowser::executeState_Outro() { + 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 ((timer % 12) == 0 && (frame < 150.0f)) { + nw4r::snd::SoundHandle handle; + PlaySoundWithFunctionB4(SoundRelatedClass, &handle, SE_DEMO_OP_CAKE_CLASH_1210f, 1); + } + + explosionBottomBound -= 0.85f; } - void daCaptainBowser::endState_Outro() { } + + // handleYSpeed(): + bowserYSpeed += bowserYAccel; + if (bowserYSpeed < bowserMaxYSpeed) + bowserYSpeed = bowserMaxYSpeed; + + // doMovement() + bowserX += bowserXSpeed; + bowserY += bowserYSpeed; + + bowserRotX -= 0xC00; + bowserRotY -= 0x100; +} +void daCaptainBowser::endState_Outro() { } diff --git a/src/bossKoopaThrow.cpp b/src/bossKoopaThrow.cpp index 3b07d98..d330651 100644 --- a/src/bossKoopaThrow.cpp +++ b/src/bossKoopaThrow.cpp @@ -21,10 +21,10 @@ struct TypeInfo { static const TypeInfo types[6] = { {"choropoo", "g3d/choropoo.brres", "spanner", "Wm_en_hit", 0, SE_BOSS_JR_FLOOR_BREAK, 0, 8.0f, 2.0f, 0, 0, 0x1000}, - {"choropoo", "g3d/choropoo.brres", "spanner", "Wm_en_burst_s", 0, SE_BOSS_JR_BOMB_BURST, 0, 8.0f, 2.0f, 0, 0, 0x1000}, + {"choropoo", "g3d/choropoo.brres", "spanner", "Wm_en_burst_s", 0, SE_BOSS_JR_BOMB_BURST, 0, 12.0f, 2.0f, 0, 0, 0x1000}, {"koopa_clown_bomb", "g3d/koopa_clown_bomb.brres", "koopa_clown_bomb", "Wm_en_burst_s", SE_EMY_ELCJ_THROW, SE_BOSS_JR_BOMB_BURST, 0, 16.0f, 0.8f, 0x200, 0x800, 0x1000}, {"bros", "g3d/t00.brres", "bros_hammer", "Wm_en_hit", 0, SE_OBJ_HAMMER_HIT_BOTH, SE_EMY_MEGA_BROS_HAMMER, 16.0f, 2.0f, 0, 0, 0x1000}, - {"dossun", "g3d/t00.brres", "dossun", "Wm_en_hit", SE_EMY_DOSSUN, SE_EMY_DOSSUN_DEAD, 0, 16.0f, 1.0f, 0x100, 0x100, 0x100}, + {"dossun", "g3d/t02.brres", "dossun", "Wm_en_hit", SE_EMY_DOSSUN, SE_EMY_DOSSUN_DEAD, 0, 14.0f, 1.0f, 0, 0, 0}, {"KoopaShip", "g3d/present.brres", "PresentBox_penguin", "Wm_dm_presentopen",SE_DEMO_OP_PRESENT_THROW_2400f, SE_DEMO_OP_PRESENT_BOX_BURST, 0, 20.0f, 1.0f, 0x20, 0x40, 0x200} }; @@ -55,6 +55,9 @@ class daKoopaThrow : public dEn_c { int lifespan; u32 cmgr_returnValue; + bool playsAnim; + m3d::anmChr_c chrAnim; + const TypeInfo *currentInfo; static daKoopaThrow *build(); @@ -181,16 +184,29 @@ int daKoopaThrow::onCreate() { allocator.link(-1, GameHeaps[0], 0, 0x20); nw4r::g3d::ResFile rf(getResource(currentInfo->arcName, currentInfo->brresName)); - bodyModel.setup(rf.GetResMdl(currentInfo->modelName), &allocator, 0x224, 1, 0); + nw4r::g3d::ResMdl resMdl = rf.GetResMdl(currentInfo->modelName); + + bodyModel.setup(resMdl, &allocator, (Type == 4 ? 0x224 : 0), 1, 0); SetupTextures_Enemy(&bodyModel, 0); + if (Type == 4) { + // Thwomp + playsAnim = true; + + nw4r::g3d::ResAnmChr anmChr = rf.GetResAnmChr("boss_throw"); + chrAnim.setup(resMdl, anmChr, &allocator, 0); + chrAnim.bind(&bodyModel, anmChr, 1); + bodyModel.bindAnim(&chrAnim, 0.0); + chrAnim.setUpdateRate(1.0); + } + allocator.unlink(); ActivePhysics::Info KoopaJunk; - KoopaJunk.xDistToCenter = -currentInfo->size; - KoopaJunk.yDistToCenter = 0.0; + KoopaJunk.xDistToCenter = 0.0f; + KoopaJunk.yDistToCenter = (Type == 4) ? currentInfo->size : 0.0; KoopaJunk.xDistToEdge = currentInfo->size; KoopaJunk.yDistToEdge = currentInfo->size; @@ -273,6 +289,11 @@ void daKoopaThrow::updateModelMatrices() { int daKoopaThrow::onExecute() { acState.execute(); updateModelMatrices(); + if (playsAnim) { + if (chrAnim.isAnimationDone()) + chrAnim.setCurrentFrame(0.0f); + bodyModel._vf1C(); + } float rect[] = {this->_320, this->_324, this->spriteSomeRectX, this->spriteSomeRectY}; int ret = this->outOfZone(this->pos, (float*)&rect, this->currentZoneID); diff --git a/src/bossPlayerClown.S b/src/bossPlayerClown.S new file mode 100644 index 0000000..b1d00a5 --- /dev/null +++ b/src/bossPlayerClown.S @@ -0,0 +1,46 @@ +.text +.align 4 +.extern ContinueFromClownCarDetectAdjacent +.extern calculateAdjacentCollision__14collisionMgr_cFPf +.global ClownCarDetectAdjacents +ClownCarDetectAdjacents: + addi r3, r30, 0x1EC + li r4, 0 + bl calculateAdjacentCollision__14collisionMgr_cFPf + cmpwi r3, 0 + beq notAdjacent + + # what direction are we in? + lfs f1, 0xE8(r30) # x speed + lis r4, zeroFloat@h + ori r4, r4, zeroFloat@l + lfs f2, 0(r4) + + lbz r4, 0x348(r30) + + cmpwi r4, 1 + beq isLeft + + # RIGHT + fcmpo cr0, f1, f2 # xspeed > 0 + blt notAdjacent + stfs f2, 0xE8(r30) + b notAdjacent + +isLeft: + # LEFT + fcmpo cr0, f1, f2 # xspeed < 0 + bgt notAdjacent + stfs f2, 0xE8(r30) + +notAdjacent: + # END HERE + + mr r3, r30 + b ContinueFromClownCarDetectAdjacent + + +.data +.align 4 +zeroFloat: .float 0.0 + diff --git a/src/bossPlayerClown.cpp b/src/bossPlayerClown.cpp index 3bf1119..0095b6b 100644 --- a/src/bossPlayerClown.cpp +++ b/src/bossPlayerClown.cpp @@ -53,9 +53,24 @@ int CConDraw(dEn_c *clown) { return PClownCarDraw(clown); // run normal clown function } +extern dStateBase_c JrClownEndDemoState; +extern dStateBase_c JrClownDemoWaitState; +extern dStateBase_c ClownDemoWaitState; int CConExecute(dEn_c *clown) { - return PClownCarExecute(clown); + // A REALLY TERRIBLE HACK. + float saveX = clown->pos.x; + float saveY = clown->pos.y; + + int ret = PClownCarExecute(clown); + + dStateBase_c *state = clown->acState.getCurrentState(); + if (state == &JrClownEndDemoState || state == &JrClownDemoWaitState || state == &ClownDemoWaitState) { + clown->pos.x = saveX; + clown->pos.y = saveY; + clown->speed.x = 0.0f; + clown->speed.y = 0.0f; + } } void CCafterCreate(dEn_c *clown, u32 param) { @@ -78,6 +93,17 @@ void CCafterCreate(dEn_c *clown, u32 param) { // Original AfterCreate PClownCarAfterCreate(clown, param); + + int playerCount = 0; + for (int i = 0; i < 4; i++) + if (Player_Active[i]) + playerCount++; + + if ((clown->settings & 0xF) != 0) { + int playerID = (clown->settings & 0xF) - 1; + if (playerID >= playerCount) + clown->Delete(1); + } } void CConExecuteMove(dEn_c *clown) { @@ -104,7 +130,8 @@ void CConExecuteMove(dEn_c *clown) { } SpawnEffect("Wm_en_killervanish", 0, &tempPos, &(S16Vec){0,0,0}, &(Vec){0.1, 0.1, 0.1}); - PlaySoundAsync(clown, SE_OBJ_HOUDAI_S_SHOT); + nw4r::snd::SoundHandle handle; + PlaySoundWithFunctionB4(SoundRelatedClass, &handle, SE_OBJ_HOUDAI_S_SHOT, 1); cTimer = 0; } @@ -112,9 +139,13 @@ void CConExecuteMove(dEn_c *clown) { cTimer++; - float leftBound = ClassWithCameraInfo::instance->screenLeft + 12.0f; + ClassWithCameraInfo *cwci = ClassWithCameraInfo::instance; + float leftBound = cwci->screenLeft + 12.0f; + float rightBound = (cwci->screenLeft + cwci->screenWidth) - 12.0f; if (clown->pos.x < leftBound) clown->pos.x = leftBound; + if (clown->pos.x > rightBound) + clown->pos.x = rightBound; // run normal move PClownCarMove(clown); @@ -151,6 +182,10 @@ void newClownDtor(dEn_c *clown, u32 willDelete) { __dt__20daJrClownForPlayer_cFv(clown, willDelete); } +extern "C" void JrClownForPlayer_playAccelSound() { + nw4r::snd::SoundHandle handle; + PlaySoundWithFunctionB4(SoundRelatedClass, &handle, SE_PLY_CROWN_ACC, 1); +} @@ -214,10 +249,10 @@ int daClownShot::onCreate() { _320 = 0.0f; _324 = 0.0f; - // These structs tell stupid collider what to collide with - these are from koopa troopa - static const lineSensor_s below(SENSOR_BREAK_BRICK | SENSOR_BREAK_BLOCK, 12<<12, 4<<12, 0<<12); - static const pointSensor_s above(SENSOR_BREAK_BRICK | SENSOR_BREAK_BLOCK, 0<<12, 12<<12); - static const lineSensor_s adjacent(SENSOR_BREAK_BRICK | SENSOR_BREAK_BLOCK, 6<<12, 9<<12, 6<<12); + u32 flags = SENSOR_BREAK_BRICK | SENSOR_BREAK_BLOCK | SENSOR_80000000; + static const lineSensor_s below(flags, 12<<12, 4<<12, 0<<12); + static const pointSensor_s above(flags, 0<<12, 12<<12); + static const lineSensor_s adjacent(flags, 6<<12, 9<<12, 6<<12); collMgr.init(this, &below, &above, &adjacent); collMgr.calculateBelowCollisionWithSmokeEffect(); @@ -248,7 +283,17 @@ int daClownShot::onExecute() { HandleXSpeed(); HandleYSpeed(); doSpriteMovement(); + collMgr.calculateBelowCollisionWithSmokeEffect(); + collMgr.calculateAboveCollision(0); + collMgr.calculateAdjacentCollision(); + if (collMgr.outputMaybe) { + SpawnEffect("Wm_en_burst_m", 0, &pos, &(S16Vec){0,0,0}, &(Vec){1.0, 1.0, 1.0}); + nw4r::snd::SoundHandle handle; + PlaySoundWithFunctionB4(SoundRelatedClass, &handle, SE_OBJ_TARU_BREAK, 1); + Delete(1); + return true; + } effect.spawn("Wm_en_killersmoke", 0, &(Vec){pos.x, pos.y, pos.z}, &(S16Vec){0,0,0}, &(Vec){0.7, 0.7, 0.7}); -- cgit v1.2.3