From 05d99e2cf552024116356591be0a88bf862b89c9 Mon Sep 17 00:00:00 2001 From: Colin Noga Date: Thu, 8 Mar 2012 15:38:44 -0600 Subject: Electric line, topman boss, and BROKEN YOSHIS v.2 --- bossTopman.yaml | 10 + electricLine.yaml | 10 + src/bossTopman.cpp | 708 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/electricLine.cpp | 144 +++++++++++ 4 files changed, 872 insertions(+) create mode 100644 bossTopman.yaml create mode 100644 electricLine.yaml create mode 100644 src/bossTopman.cpp create mode 100644 src/electricLine.cpp diff --git a/bossTopman.yaml b/bossTopman.yaml new file mode 100644 index 0000000..94ab3ac --- /dev/null +++ b/bossTopman.yaml @@ -0,0 +1,10 @@ +--- +# Replaces Slow_Quick_Tag + +source_files: [../src/bossTopman.cpp] +hooks: + - name: BossTopmanBuild + type: add_func_pointer + src_addr_pal: 0x8095D018 + target_func: 'daDreidel::build(void)' + diff --git a/electricLine.yaml b/electricLine.yaml new file mode 100644 index 0000000..3b9e856 --- /dev/null +++ b/electricLine.yaml @@ -0,0 +1,10 @@ +--- +# Replaces Ship_Window + +source_files: [../src/electricLine.cpp] +hooks: + - name: electricLineBuild + type: add_func_pointer + src_addr_pal: 0x809622F8 + target_func: 'daElectricLine::build(void)' + 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 +#include +#include +#include +#include +#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 +#include +#include +#include +#include +#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() { } + -- cgit v1.2.3