summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTreeki <treeki@gmail.com>2013-02-22 00:26:14 +0100
committerTreeki <treeki@gmail.com>2013-02-22 00:26:14 +0100
commit457a40644f0a492ed8acf8dbf66888bee9035100 (patch)
tree759ceec3d2d7a8ecaad6d60ed682284441678db7 /src
parent1aa3c19834f16d5153fba34c7ef9dc5a66be9466 (diff)
downloadkamek-457a40644f0a492ed8acf8dbf66888bee9035100.tar.gz
kamek-457a40644f0a492ed8acf8dbf66888bee9035100.zip
more updates and fixes to the final boss than I can count
Diffstat (limited to 'src')
-rw-r--r--src/bossCaptainBowser.cpp554
-rw-r--r--src/bossKoopaThrow.cpp31
-rw-r--r--src/bossPlayerClown.S46
-rw-r--r--src/bossPlayerClown.cpp59
4 files changed, 500 insertions, 190 deletions
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});