#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() { }