summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/bossTopman.cpp708
-rw-r--r--src/electricLine.cpp144
2 files changed, 852 insertions, 0 deletions
diff --git a/src/bossTopman.cpp b/src/bossTopman.cpp
new file mode 100644
index 0000000..a52c66b
--- /dev/null
+++ b/src/bossTopman.cpp
@@ -0,0 +1,708 @@
+#include <common.h>
+#include <game.h>
+#include <g3dhax.h>
+#include <sfx.h>
+#include <stage.h>
+#include "effects.h"
+#include "player.h"
+
+class daDreidel : public dEn_c {
+ int onCreate();
+ int onDelete();
+ int onExecute();
+ int onDraw();
+
+ mHeapAllocator_c allocator;
+ nw4r::g3d::ResFile resFile;
+
+ m3d::mdl_c bodyModel;
+
+ m3d::anmChr_c chrAnimation;
+
+ int timer;
+ int damage;
+ char isDown;
+ float XSpeed;
+ u32 cmgr_returnValue;
+ bool isBouncing;
+ char isInSpace;
+ char fromBehind;
+
+ float dying;
+
+ dEn_c *Kameck;
+
+ static daDreidel *build();
+
+ void bindAnimChr_and_setUpdateRate(const char* name, int unk, float unk2, float rate);
+ void updateModelMatrices();
+ bool calculateTileCollisions();
+
+ void spriteCollision(ActivePhysics *apThis, ActivePhysics *apOther);
+ void playerCollision(ActivePhysics *apThis, ActivePhysics *apOther);
+ void yoshiCollision(ActivePhysics *apThis, ActivePhysics *apOther);
+
+ void collisionCat3_StarPower(ActivePhysics *apThis, ActivePhysics *apOther);
+ void collisionCat14_YoshiFire(ActivePhysics *apThis, ActivePhysics *apOther);
+ void collisionCatD_GroundPound(ActivePhysics *apThis, ActivePhysics *apOther);
+ void collisionCat7_WMWaggleWater(ActivePhysics *apThis, ActivePhysics *apOther);
+ void collisionCat7_WMWaggleWaterYoshi(ActivePhysics *apThis, ActivePhysics *apOther);
+ void collisionCat9_RollingObject(ActivePhysics *apThis, ActivePhysics *apOther);
+ void collisionCat1_Fireball_E_Explosion(ActivePhysics *apThis, ActivePhysics *apOther);
+ bool collisionCat2_IceBall_15_YoshiIce(ActivePhysics *apThis, ActivePhysics *apOther);
+ void collisionCat13_Hammer(ActivePhysics *apThis, ActivePhysics *apOther);
+ void collisionCatA_PenguinMario(ActivePhysics *apThis, ActivePhysics *apOther);
+
+
+ USING_STATES(daDreidel);
+ DECLARE_STATE(Walk);
+ DECLARE_STATE(Turn);
+ DECLARE_STATE(KnockBack);
+
+ DECLARE_STATE(ChargePrep);
+ DECLARE_STATE(Charge);
+ DECLARE_STATE(ChargeRecover);
+ DECLARE_STATE(Damage);
+
+ DECLARE_STATE(Grow);
+ DECLARE_STATE(Outro);
+
+};
+
+daDreidel *daDreidel::build() {
+ void *buffer = AllocFromGameHeap1(sizeof(daDreidel));
+ return new(buffer) daDreidel;
+}
+
+///////////////////////
+// Externs and States
+///////////////////////
+ extern "C" void *PlaySound(dStageActor_c *, int soundID);
+ extern "C" void *PlaySoundAsync(dStageActor_c *, int soundID);
+ extern "C" void *EN_LandbarrelPlayerCollision(dEn_c* t, ActivePhysics *apThis, ActivePhysics *apOther);
+
+ extern "C" dStageActor_c *CreateActor(u16 classID, int settings, Vec pos, char rot, char layer);
+ extern "C" u8 dSprite_c__getXDirectionOfFurthestPlayerRelativeToVEC3(daDreidel *, Vec pos);
+ extern "C" dStageActor_c *GetSpecificPlayerActor(int num);
+// CalculateDistanceFromActorsNextPosToFurthestPlayer
+
+ //FIXME make this dEn_c->used...
+ extern "C" char usedForDeterminingStatePress_or_playerCollision(dEn_c* t, ActivePhysics *apThis, ActivePhysics *apOther, int unk1);
+ extern "C" int SmoothRotation(short* rot, u16 amt, int unk2);
+
+ extern "C" void *StopBGMMusic();
+ extern "C" void *StartBGMMusic();
+
+ extern "C" void *MakeMarioEnterDemoMode();
+ extern "C" void *MakeMarioExitDemoMode();
+ extern "C" void *UpdateGameMgr();
+
+ CREATE_STATE(daDreidel, Walk);
+ CREATE_STATE(daDreidel, Turn);
+ CREATE_STATE(daDreidel, KnockBack);
+
+ CREATE_STATE(daDreidel, ChargePrep);
+ CREATE_STATE(daDreidel, Charge);
+ CREATE_STATE(daDreidel, ChargeRecover);
+ CREATE_STATE(daDreidel, Damage);
+
+ CREATE_STATE(daDreidel, Grow);
+ CREATE_STATE(daDreidel, Outro);
+
+ // begoman_attack2" // wobble back and forth tilted forwards
+ // begoman_attack3" // Leaned forward, antennae extended
+ // begoman_damage" // Bounces back slightly
+ // begoman_damage2" // Stops spinning and wobbles to the ground like a top
+ // begoman_stand" // Stands still, waiting
+ // begoman_wait" // Dizzily Wobbles
+ // begoman_wait2" // spins around just slightly
+ // begoman_attack" // Rocks backwards, and then attacks to an upright position, pulsing out his antennae
+
+
+////////////////////////
+// Collision Functions
+////////////////////////
+
+ void daDreidel::spriteCollision(ActivePhysics *apThis, ActivePhysics *apOther) {
+ if (apOther->owner->name == 250) { //time to get hurt
+ this->damage += 1;
+ doStateChange(&StateID_Damage);
+
+ if (this->damage > 2) { doStateChange(&StateID_Outro); }
+ }
+ else { dEn_c::spriteCollision(apThis, apOther); }
+ }
+
+ void daDreidel::playerCollision(ActivePhysics *apThis, ActivePhysics *apOther) {
+
+ char hitType;
+ hitType = usedForDeterminingStatePress_or_playerCollision(this, apThis, apOther, 0);
+
+ if(hitType == 1) { // regular jump
+ this->_vf220(apOther->owner);
+ }
+ else if(hitType == 3) { // spinning jump or whatever?
+ this->_vf220(apOther->owner);
+ }
+ else if(hitType == 0) {
+ EN_LandbarrelPlayerCollision(this, apThis, apOther);
+ if (this->pos.x > apOther->owner->pos.x) {
+ this->direction = 1;
+ }
+ else {
+ this->direction = 0;
+ }
+ doStateChange(&StateID_KnockBack);
+ }
+
+ // fix multiple player collisions via megazig
+ this->isDead = 0;
+ this->flags_4FC |= (1<<(31-7));
+ if(apOther->owner->which_player < 4) {
+ this->counter_504[apOther->owner->which_player] = 0;
+ }
+ }
+
+ void daDreidel::yoshiCollision(ActivePhysics *apThis, ActivePhysics *apOther) {
+ this->playerCollision(apThis, apOther);
+ }
+
+ void daDreidel::collisionCatD_GroundPound(ActivePhysics *apThis, ActivePhysics *apOther) {
+ this->dEn_c::playerCollision(apThis, apOther);
+ this->_vf220(apOther->owner);
+
+ this->isDead = 0;
+ this->flags_4FC |= (1<<(31-7));
+ if(apOther->owner->which_player < 4) {
+ this->counter_504[apOther->owner->which_player] = 0;
+ }
+ }
+
+ void daDreidel::collisionCat7_WMWaggleWater(ActivePhysics *apThis, ActivePhysics *apOther) {
+ this->collisionCatD_GroundPound(apThis, apOther);
+ }
+
+ void daDreidel::collisionCat7_WMWaggleWaterYoshi(ActivePhysics *apThis, ActivePhysics *apOther) {
+ this->collisionCatD_GroundPound(apThis, apOther);
+ }
+
+ void daDreidel::collisionCat9_RollingObject(ActivePhysics *apThis, ActivePhysics *apOther) {
+ doStateChange(&StateID_KnockBack);
+ }
+
+ void daDreidel::collisionCat3_StarPower(ActivePhysics *apThis, ActivePhysics *apOther){ }
+
+ void daDreidel::collisionCat13_Hammer(ActivePhysics *apThis, ActivePhysics *apOther) { }
+
+ void daDreidel::collisionCatA_PenguinMario(ActivePhysics *apThis, ActivePhysics *apOther){
+ doStateChange(&StateID_KnockBack);
+ }
+
+ void daDreidel::collisionCat14_YoshiFire(ActivePhysics *apThis, ActivePhysics *apOther){ }
+
+ void daDreidel::collisionCat1_Fireball_E_Explosion(ActivePhysics *apThis, ActivePhysics *apOther) { }
+
+ bool daDreidel::collisionCat2_IceBall_15_YoshiIce(ActivePhysics *apThis, ActivePhysics *apOther) { return true; }
+
+
+bool daDreidel::calculateTileCollisions() {
+ // Returns true if sprite should turn, false if not.
+
+ HandleXSpeed();
+ HandleYSpeed();
+ doSpriteMovement();
+
+ cmgr_returnValue = collMgr.CollidedWithTile();
+ collMgr.execute();
+
+ if (isBouncing) {
+ stuffRelatingToCollisions(0.1875f, 1.0f, 0.5f);
+ if (speed.y != 0.0f)
+ isBouncing = false;
+ }
+
+ float xDelta = pos.x - last_pos.x;
+ if (xDelta >= 0.0f)
+ direction = 0;
+ else
+ direction = 1;
+
+ if (collMgr.CollidedWithTile()) {
+ // Walking into a tile branch
+
+ if (cmgr_returnValue == 0)
+ isBouncing = true;
+
+ if (speed.x != 0.0f) {
+ //playWmEnIronEffect();
+ }
+
+ speed.y = 0.0f;
+
+ // u32 blah = collMgr.s_80070760();
+ // u8 one = (blah & 0xFF);
+ // static const float incs[5] = {0.00390625f, 0.0078125f, 0.015625f, 0.0234375f, 0.03125f};
+ // x_speed_inc = incs[one];
+ max_speed.x = (direction == 1) ? -1.0f : 1.0f;
+ } else {
+ x_speed_inc = 0.0f;
+ }
+
+ // Bouncing checks
+ if (_34A & 4) {
+ Vec v = (Vec){0.0f, 1.0f, 0.0f};
+ collMgr.parent_speed_ptr = &v;
+
+ if (collMgr.SomethingSemiImportant(collMgr.bitfield_for_checks))
+ speed.y = 0.0f;
+
+ collMgr.parent_speed_ptr = &speed;
+
+ } else {
+ if (collMgr.SomethingSemiImportant(collMgr.bitfield_for_checks))
+ speed.y = 0.0f;
+ }
+
+ collMgr.s_8006FA40(0);
+
+ // Switch Direction
+ if (collMgr.bitfield_for_checks & (0x15 << direction)) {
+ if (collMgr.CollidedWithTile()) {
+ isBouncing = true;
+ }
+ return true;
+ }
+ return false;
+}
+
+void daDreidel::bindAnimChr_and_setUpdateRate(const char* name, int unk, float unk2, float rate) {
+ nw4r::g3d::ResAnmChr anmChr = this->resFile.GetResAnmChr(name);
+ this->chrAnimation.bind(&this->bodyModel, anmChr, unk);
+ this->bodyModel.bindAnim(&this->chrAnimation, unk2);
+ this->chrAnimation.setUpdateRate(rate);
+}
+
+int daDreidel::onCreate() {
+
+ // Model creation
+ allocator.link(-1, GameHeaps[0], 0, 0x20);
+
+ this->resFile.data = getResource("ben", "g3d/begoman_spike.brres");
+ nw4r::g3d::ResMdl mdl = this->resFile.GetResMdl("begoman");
+ bodyModel.setup(mdl, &allocator, 0x224, 1, 0);
+ SetupTextures_Map(&bodyModel, 0);
+
+
+ // Animations start here
+ nw4r::g3d::ResAnmChr anmChr = this->resFile.GetResAnmChr("begoman_wait");
+ this->chrAnimation.setup(mdl, anmChr, &this->allocator, 0);
+
+ allocator.unlink();
+
+ // Stuff I do understand
+ this->scale = (Vec){0.2, 0.2, 0.2};
+
+ // this->pos.y = this->pos.y + 30.0; // X is vertical axis
+ this->rot.x = 0; // X is vertical axis
+ this->rot.y = 0xD800; // Y is horizontal axis
+ this->rot.z = 0; // Z is ... an axis >.>
+ this->direction = 1; // Heading left.
+
+ this->speed.x = 0.0;
+ this->speed.y = 0.0;
+ this->max_speed.x = 0.8;
+ this->x_speed_inc = 0.0;
+ this->XSpeed = 0.8;
+
+ this->isInSpace = this->settings & 0xF;
+ this->fromBehind = 0;
+
+ ActivePhysics::Info HitMeBaby;
+
+ HitMeBaby.xDistToCenter = 0.0;
+ HitMeBaby.yDistToCenter = 12.0;
+
+ HitMeBaby.xDistToEdge = 14.0;
+ HitMeBaby.yDistToEdge = 12.0;
+
+ HitMeBaby.category1 = 0x3;
+ HitMeBaby.category2 = 0x0;
+ HitMeBaby.bitfield1 = 0x4F;
+ HitMeBaby.bitfield2 = 0xffbafffe;
+ HitMeBaby.unkShort1C = 0;
+ HitMeBaby.callback = &dEn_c::collisionCallback;
+
+ OSReport("Making the Physics Class and adding to the list\n");
+ this->aPhysics.initWithStruct(this, &HitMeBaby);
+ this->aPhysics.addToList();
+
+
+ // Tile collider
+ OSReport("Making the Tile collider Class\n");
+
+ // These fucking rects do something for the tile rect
+ spriteSomeRectX = 28.0f;
+ spriteSomeRectY = 32.0f;
+ _320 = 0.0f;
+ _324 = 16.0f;
+
+ // These structs tell stupid collider what to collide with - these are from koopa troopa
+ static const u8 one[16] = {0,0,0,1, 0,0,0xC0,0, 0,0,0x40,0, 0,0,0,0};
+ static const u8 two[12] = {0,0,0,0, 0,0,0,0, 0,0,0xC0,0};
+ static const u8 three[16] = {0,0,0,1, 0,0,0x60,0, 0,0,0x90,0, 0,0,0x60,0};
+
+ collMgr.Init(this, one, two, three);
+ collMgr.execute();
+
+ cmgr_returnValue = collMgr.CollidedWithTile();
+
+ if (collMgr.CollidedWithTile())
+ isBouncing = false;
+ else
+ isBouncing = true;
+
+
+ // State Changers
+ bindAnimChr_and_setUpdateRate("begoman_wait2", 1, 0.0, 1.0);
+ doStateChange(&StateID_Grow);
+
+ this->onExecute();
+ return true;
+}
+
+int daDreidel::onDelete() {
+ return true;
+}
+
+int daDreidel::onExecute() {
+ acState.execute();
+ updateModelMatrices();
+
+ return true;
+}
+
+int daDreidel::onDraw() {
+ bodyModel.scheduleForDrawing();
+ bodyModel._vf1C();
+
+ return true;
+}
+
+void daDreidel::updateModelMatrices() {
+ matrix.translation(pos.x, pos.y - 2.0, pos.z);
+ matrix.applyRotationYXZ(&rot.x, &rot.y, &rot.z);
+
+ bodyModel.setDrawMatrix(matrix);
+ bodyModel.setScale(&scale);
+ bodyModel.calcWorld(false);
+}
+
+
+
+///////////////
+// Grow State
+///////////////
+ void daDreidel::beginState_Grow() {
+ bindAnimChr_and_setUpdateRate("begoman_wait2", 1, 0.0, 0.75);
+
+ this->timer = 0;
+
+ // Stop the BGM Music
+ StopBGMMusic();
+
+ // Set the necessary Flags and make Mario enter Demo Mode
+ dStage32C_c::instance->freezeMarioBossFlag = 1;
+ WLClass::instance->_4 = 4;
+ WLClass::instance->_8 = 0;
+
+ MakeMarioEnterDemoMode();
+
+ // Make sure to use the correct position
+ Vec pos = (Vec){this->pos.x - 124.0, this->pos.y + 104.0, 3564.0};
+ S16Vec rot = (S16Vec){0, 0, 0};
+
+ // Create And use Kameck
+ Kameck = (daKameckDemo*)createChild(KAMECK_FOR_CASTLE_DEMO, (dStageActor_c*)this, 0, &pos, &rot, 0);
+ Kameck->doStateChange(&daKameckDemo::StateID_DemoWait);
+ }
+
+ void daDreidel::executeState_Grow() {
+
+ if(this->chrAnimation.isAnimationDone()) {
+ this->chrAnimation.setCurrentFrame(0.0);
+ }
+
+ this->timer = this->timer + 1;
+
+ float scaleSpeed, yPosScaling;
+
+
+ if ((this->timer > 150) && (this->timer < 230)) {
+
+ scaleSpeed = 0.005;
+ yPosScaling = 18;
+
+ float modifier;
+
+ modifier = 0.2 + ((this->timer - 150) * scaleSpeed);
+
+ this->scale = (Vec){modifier, modifier, modifier};
+ // this->pos.y = this->pos.y + (yPosScaling/80);
+
+ }
+ if (this->timer > 420) {
+ PlaySound(this, SE_EMY_MECHAKOOPA_BOUND);
+ doStateChange(&StateID_Walk);
+ }
+
+ if (this->timer == 130) { Kameck->doStateChange(&daKameckDemo::StateID_DemoSt); }
+ if (this->timer == 150) { PlaySound(this, SE_BOSS_IGGY_WANWAN_TO_L); }
+ if (this->timer == 400) { Kameck->doStateChange(&daKameckDemo::StateID_DemoSt2); }
+ if (this->timer == 360) {
+ Vec tempPos = (Vec){this->pos.x - 40.0, this->pos.y + 120.0, 3564.0};
+ CreateEffect(&tempPos, &(S16Vec){0,0,0}, &(Vec){1.0, 1.0, 1.0}, 175); // 400 & 401 // 564 // 583 // 754 // 958
+ CreateEffect(&tempPos, &(S16Vec){0,0,0}, &(Vec){1.0, 1.0, 1.0}, 400); // 400 & 401 // 564 // 583 // 754 // 958
+ CreateEffect(&tempPos, &(S16Vec){0,0,0}, &(Vec){1.0, 1.0, 1.0}, 401); // 400 & 401 // 564 // 583 // 754 // 958
+ CreateEffect(&tempPos, &(S16Vec){0,0,0}, &(Vec){1.0, 1.0, 1.0}, 564); // 400 & 401 // 564 // 583 // 754 // 958
+ CreateEffect(&tempPos, &(S16Vec){0,0,0}, &(Vec){1.0, 1.0, 1.0}, 583); // 400 & 401 // 564 // 583 // 754 // 958
+ CreateEffect(&tempPos, &(S16Vec){0,0,0}, &(Vec){1.0, 1.0, 1.0}, 754); // 400 & 401 // 564 // 583 // 754 // 958
+ CreateEffect(&tempPos, &(S16Vec){0,0,0}, &(Vec){1.0, 1.0, 1.0}, 958); // 400 & 401 // 564 // 583 // 754 // 958
+ }
+ }
+ void daDreidel::endState_Grow() {
+ // Clean up the flags and Kameck
+ dStage32C_c::instance->freezeMarioBossFlag = 0;
+ WLClass::instance->_8 = 1;
+
+ MakeMarioExitDemoMode();
+ StartBGMMusic();
+
+ Kameck->Delete(1);
+ }
+
+
+///////////////
+// Walk State
+///////////////
+ void daDreidel::beginState_Walk() {
+ this->max_speed.x = (this->direction) ? -this->XSpeed : this->XSpeed;
+ this->speed.x = (direction) ? -0.8f : 0.8f;
+
+ this->max_speed.y = (this->isInSpace) ? -2.0 : -4.0;
+ this->speed.y = (this->isInSpace) ? -2.0 : -4.0;
+ this->y_speed_inc = (this->isInSpace) ? -0.09375 : -0.1875;
+ }
+ void daDreidel::executeState_Walk() {
+
+ PlaySound(this, SE_BOSS_JR_CROWN_JR_RIDE); // 5
+
+ bool ret = calculateTileCollisions();
+ if (ret) {
+ doStateChange(&StateID_Turn);
+ }
+
+ if(this->chrAnimation.isAnimationDone()) {
+ this->chrAnimation.setCurrentFrame(0.0);
+ }
+ }
+ void daDreidel::endState_Walk() { this->timer += 1; }
+
+
+///////////////
+// Turn State
+///////////////
+ void daDreidel::beginState_Turn() {
+ this->direction ^= 1;
+ this->speed.x = 0.0;
+ }
+ void daDreidel::executeState_Turn() {
+
+ if(this->chrAnimation.isAnimationDone()) {
+ this->chrAnimation.setCurrentFrame(0.0);
+ }
+
+ u16 amt = (this->direction == 0) ? 0x2800 : 0xD800;
+ int done = SmoothRotation(&this->rot.y, amt, 0x800);
+
+ if(done) {
+ this->doStateChange(&StateID_Walk);
+ }
+ }
+ void daDreidel::endState_Turn() { }
+
+
+///////////////
+// Knockback State
+///////////////
+ void daDreidel::beginState_KnockBack() {
+ bindAnimChr_and_setUpdateRate("begoman_damage", 1, 0.0, 0.75);
+
+ this->max_speed.x = (this->direction) ? this->XSpeed*5.0 : -this->XSpeed*5.0;
+ this->speed.x = (this->direction) ? 4.0f : -4.0f;
+ }
+ void daDreidel::executeState_KnockBack() {
+
+ bool ret = calculateTileCollisions();
+ this->speed.x = this->speed.x / 1.1;
+
+ bodyModel._vf1C();
+ if(this->chrAnimation.isAnimationDone()) {
+ doStateChange(&StateID_Walk);
+ }
+
+ }
+ void daDreidel::endState_KnockBack() {
+ if (this->rot.y == 0x2800) {
+ // CreateEffect(&this->pos, &(S16Vec){0,0,0}, &(Vec){1.0, 1.0, 1.0}, 175);
+ this->direction = 0;
+ }
+ else {
+ // CreateEffect(&this->pos, &(S16Vec){0,0,0}, &(Vec){1.0, 1.0, 1.0}, 192);
+ this->direction = 1;
+ }
+ // OSReport("Rotation: %x", this->rot.y);
+ // OSReport("Direction: %d", this->direction);
+ // this->direction ^= 1;
+ bindAnimChr_and_setUpdateRate("begoman_wait2", 1, 0.0, 1.0);
+ }
+
+
+///////////////
+// ChargePrep State
+///////////////
+ void daDreidel::beginState_ChargePrep() {
+ bindAnimChr_and_setUpdateRate("begoman_attack", 1, 0.0, 1.0);
+ }
+ void daDreidel::executeState_ChargePrep() {
+ if(this->chrAnimation.isAnimationDone()) {
+ doStateChange(&StateID_Charge);
+ }
+ }
+ void daDreidel::endState_ChargePrep() { }
+
+
+///////////////
+// Charge State
+///////////////
+ void daDreidel::beginState_Charge() {
+ bindAnimChr_and_setUpdateRate("begoman_attack3", 1, 0.0, 1.0);
+ }
+ void daDreidel::executeState_Charge() {
+ if(this->chrAnimation.isAnimationDone()) {
+ this->chrAnimation.setCurrentFrame(0.0);
+ }
+ }
+ void daDreidel::endState_Charge() { }
+
+
+///////////////
+// ChargeRecover State
+///////////////
+ void daDreidel::beginState_ChargeRecover() {
+ bindAnimChr_and_setUpdateRate("begoman_stand", 1, 0.0, 1.0);
+ }
+ void daDreidel::executeState_ChargeRecover() {
+ if(this->chrAnimation.isAnimationDone()) {
+ doStateChange(&StateID_ChargePrep);
+ }
+ }
+ void daDreidel::endState_ChargeRecover() { }
+
+
+///////////////
+// Damage State
+///////////////
+ void daDreidel::beginState_Damage() {
+ bindAnimChr_and_setUpdateRate("begoman_wait", 1, 0.0, 1.0);
+ }
+ void daDreidel::executeState_Damage() {
+ if(this->chrAnimation.isAnimationDone()) {
+ this->chrAnimation.setCurrentFrame(0.0);
+ }
+ }
+ void daDreidel::endState_Damage() { }
+
+
+///////////////
+// Outro State
+///////////////
+ void daDreidel::beginState_Outro() {
+
+ WLClass::instance->_4 = 5;
+ WLClass::instance->_8 = 0;
+
+ this->removeMyActivePhysics();
+ this->timer = 0;
+ StopBGMMusic();
+
+ dStage32C_c::instance->freezeMarioBossFlag = 1;
+
+ }
+ void daDreidel::executeState_Outro() {
+
+ if (this->dying == 1) {
+ if (this->timer > 180) {
+ ExitStage(WORLD_MAP, 0, BEAT_LEVEL, MARIO_WIPE);
+ }
+
+ if (this->timer == 60) {
+
+ UpdateGameMgr();
+
+ if (GetSpecificPlayerActor(0) != 0) {
+ PlaySound(this, SE_VOC_MA_CLEAR_BOSS);
+ // Send PlBase into DemoGoal State here, kthxbai
+ }
+
+ if (GetSpecificPlayerActor(1) != 0) {
+ PlaySound(this, SE_VOC_LU_CLEAR_BOSS);
+ // Send PlBase into DemoGoal State here, kthxbai
+ }
+
+ if (GetSpecificPlayerActor(2) != 0) {
+ PlaySound(this, SE_VOC_KO_CLEAR_BOSS);
+ // Send PlBase into DemoGoal State here, kthxbai
+ }
+
+ if (GetSpecificPlayerActor(3) != 0) {
+ PlaySound(this, SE_VOC_KO2_CLEAR_BOSS);
+ // Send PlBase into DemoGoal State here, kthxbai
+ }
+ }
+
+ this->timer += 1;
+ return;
+ }
+
+ if (this->scale.x > 0.1) {
+
+ PlaySound(this, SE_EMY_BUBBLE_EXTINCT);
+
+ // Adjust this to equal the scale of your boss / 80.
+ this->scale.x -= 0.0075;
+ this->scale.y -= 0.0075;
+ this->scale.z -= 0.0075;
+
+ if (this->timer == 30) {
+ CreateEffect(&this->pos, &(S16Vec){0,0,0}, &(Vec){2.0, 2.0, 2.0}, 756);
+ CreateEffect(&this->pos, &(S16Vec){0,0,0}, &(Vec){2.0, 2.0, 2.0}, 801);
+ CreateEffect(&this->pos, &(S16Vec){0,0,0}, &(Vec){2.0, 2.0, 2.0}, 957);
+ this->timer = 0;
+ }
+
+ this->timer += 1;
+ }
+ else {
+ this->scale.x = 0.0;
+ this->scale.y = 0.0;
+ this->scale.z = 0.0;
+
+ CreateEffect(&this->pos, &(S16Vec){0,0,0}, &(Vec){2.0, 2.0, 2.0}, 588);
+ this->dying = 1;
+ this->timer = 0;
+
+ PlaySound(this, STRM_BGM_SHIRO_BOSS_CLEAR);
+ MakeMarioEnterDemoMode();
+ }
+ }
+ void daDreidel::endState_Outro() { }
diff --git a/src/electricLine.cpp b/src/electricLine.cpp
new file mode 100644
index 0000000..28822f1
--- /dev/null
+++ b/src/electricLine.cpp
@@ -0,0 +1,144 @@
+#include <common.h>
+#include <game.h>
+#include <g3dhax.h>
+#include <sfx.h>
+#include <stage.h>
+#include "effects.h"
+#include "player.h"
+
+class daElectricLine : public dEn_c {
+ int onCreate();
+ int onDelete();
+ int onExecute();
+ int onDraw();
+
+ mHeapAllocator_c allocator;
+ nw4r::g3d::ResFile resFile;
+
+ dEn_c *Needles;
+ u32 delay;
+ u32 timer;
+ char loops;
+
+ static daElectricLine *build();
+
+ USING_STATES(daElectricLine);
+ DECLARE_STATE(Activate);
+ DECLARE_STATE(Deactivate);
+ DECLARE_STATE(Die);
+};
+
+daElectricLine *daElectricLine::build() {
+ void *buffer = AllocFromGameHeap1(sizeof(daElectricLine));
+ return new(buffer) daElectricLine;
+}
+
+///////////////////////
+// Externs and States
+///////////////////////
+ extern "C" void *PlaySound(dStageActor_c *, int soundID);
+ extern "C" void *PlaySoundAsync(dStageActor_c *, int soundID);
+
+ extern "C" dStageActor_c *CreateActor(u16 classID, int settings, Vec pos, char rot, char layer);
+
+
+ CREATE_STATE(daElectricLine, Activate);
+ CREATE_STATE(daElectricLine, Deactivate);
+ CREATE_STATE(daElectricLine, Die);
+
+
+
+int daElectricLine::onCreate() {
+
+ Vec temppos = this->pos;
+ temppos.x += 24.0;
+
+ // Settings for rotation: 0 = facing right, 1 = facing left, 2 = facing up, 3 = facing down
+ char settings = 0;
+ if (this->settings & 0x1) {
+ settings = 1;
+ temppos.x -= 32.0;
+ }
+
+
+ Needles = (daNeedles*)create(NEEDLE_FOR_KOOPA_JR_B, settings, &temppos, &this->rot, 0);
+ Needles->doStateChange(&daNeedles::StateID_DemoWait);
+
+ // Delay in 1/6ths of a second
+ this->delay = (this->settings >> 16) * 10;
+ this->loops = (this->settings >> 4);
+
+ // State Changers
+ doStateChange(&StateID_Activate);
+
+ this->onExecute();
+ return true;
+}
+
+int daElectricLine::onDelete() {
+ return true;
+}
+
+int daElectricLine::onExecute() {
+ acState.execute();
+ return true;
+}
+
+int daElectricLine::onDraw() {
+ return true;
+}
+
+
+// States:
+//
+// DemoWait - all nullsubs, does nothing
+// DemoAwake - moves the spikes in their respective directions
+// Idle - Fires off an infinity of effects for some reason.
+// Die - removes physics, then nullsubs
+
+
+///////////////
+// Activate State
+///////////////
+ void daElectricLine::beginState_Activate() {
+ this->timer = this->delay;
+ Needles->doStateChange(&daNeedles::StateID_Idle);
+ }
+ void daElectricLine::executeState_Activate() {
+ if (this->loops) {
+ this->timer--;
+ if (this->timer == 0) {
+ this->loops += 1;
+ doStateChange(&StateID_Deactivate);
+ }
+ }
+ }
+ void daElectricLine::endState_Activate() { }
+
+///////////////
+// Deactivate State
+///////////////
+ void daElectricLine::beginState_Deactivate() {
+ this->timer = this->delay;
+ Needles->removeMyActivePhysics();
+ Needles->doStateChange(&daNeedles::StateID_DemoWait);
+ }
+ void daElectricLine::executeState_Deactivate() {
+
+ this->timer--;
+ if (this->timer == 0) {
+ doStateChange(&StateID_Activate);
+ }
+ }
+ void daElectricLine::endState_Deactivate() {
+ Needles->addMyActivePhysics();
+ }
+
+
+///////////////
+// Die State
+///////////////
+ void daElectricLine::beginState_Die() { Needles->doStateChange(&daNeedles::StateID_Die); }
+ void daElectricLine::executeState_Die() { }
+ void daElectricLine::endState_Die() { }
+