#include #include #include class daMrSun_c : public dEn_c { int onCreate(); int onDelete(); int onExecute(); int onDraw(); mHeapAllocator_c allocator; m3d::mdl_c bodyModel; m3d::mdl_c glowModel; bool hasGlow; float Baseline; float SwoopSlope; float SpiralLoop; float yThreshold; float yAccel; Vec swoopTarget; u32 timer; float xSpiralOffset; float ySpiralOffset; float swoopA; float swoopB; float swoopC; float swoopSpeed; float glowPos; float spinReduce; float spinStateOn; static daMrSun_c *build(); void updateModelMatrices(); USING_STATES(daMrSun_c); DECLARE_STATE(Follow); DECLARE_STATE(Swoop); DECLARE_STATE(Spiral); DECLARE_STATE(Spit); DECLARE_STATE(Spin); DECLARE_STATE(Wait); }; daMrSun_c *daMrSun_c::build() { void *buffer = AllocFromGameHeap1(sizeof(daMrSun_c)); return new(buffer) daMrSun_c; } extern "C" void *HandleXSpeed(daMrSun_c *); extern "C" void *HandleYSpeed(daMrSun_c *); extern "C" void *UpdateObjectPosBasedOnSpeedValues_real(daMrSun_c *); extern "C" u32 GenerateRandomNumber(int max); extern "C" u8 dSprite_c__getXDirectionOfFurthestPlayerRelativeToVEC3(daMrSun_c *, Vec pos); extern "C" dStageActor_c *CreateActor(u16 classID, int settings, Vec pos, char rot, char layer); extern "C" dStageActor_c *GetSpecificPlayerActor(int number); CREATE_STATE(daMrSun_c, Follow); CREATE_STATE(daMrSun_c, Swoop); CREATE_STATE(daMrSun_c, Spiral); CREATE_STATE(daMrSun_c, Spit); CREATE_STATE(daMrSun_c, Spin); CREATE_STATE(daMrSun_c, Wait); #define ACTIVATE 1 #define DEACTIVATE 0 int daMrSun_c::onCreate() { OSReport("Creating the Mr.Sun Models"); allocator.link(-1, GameHeaps[0], 0, 0x20); if (this->settings == 0) { // It's a sun hasGlow = true; nw4r::g3d::ResFile rf(getResource("bilikyu", "g3d/sun.brres")); bodyModel.setup(rf.GetResMdl("Sun"), &allocator, 0x224, 1, 0); SetupTextures_Map(&bodyModel, 0); glowModel.setup(rf.GetResMdl("SunGlow"), &allocator, 0x224, 1, 0); SetupTextures_Map(&glowModel, 0); } else { // It's a moon hasGlow = false; nw4r::g3d::ResFile rf(getResource("bilikyu", "g3d/moon.brres")); bodyModel.setup(rf.GetResMdl("Moon"), &allocator, 0x224, 1, 0); SetupTextures_Map(&bodyModel, 0); glowModel.setup(rf.GetResMdl("MoonGlow"), &allocator, 0x224, 1, 0); SetupTextures_Map(&glowModel, 0); } allocator.unlink(); OSReport("Setting Mr.Sun's Size to 4.0"); this->scale = (Vec){0.5, 0.5, 0.5}; OSReport("Creating Mr.Sun's Physics Struct"); ActivePhysics::Info HitMeBaby; HitMeBaby.xDistToCenter = 0.0; HitMeBaby.yDistToCenter = 0.0; HitMeBaby.xDistToEdge = 16.0; HitMeBaby.yDistToEdge = 16.0; HitMeBaby.category1 = 0x3; HitMeBaby.category2 = 0x0; HitMeBaby.bitfield1 = 0x4F; HitMeBaby.bitfield2 = 0x820C; HitMeBaby.unkShort1C = 0; HitMeBaby.callback = &dEn_c::collisionCallback; OSReport("Making the Physics Class and adding to the list"); this->aPhysics.initWithStruct(this, &HitMeBaby); this->aPhysics.addToList(); OSReport("Setting up Mr.Sun's Box of Goodies"); this->Baseline = this->pos.y; this->SwoopSlope = 0.0; this->SpiralLoop = 0; this->yThreshold = 15.0; this->yAccel = 0.2; this->timer = 0; this->xSpiralOffset = 0.0; this->ySpiralOffset = 0.0; this->pos.z = 3300.00; OSReport("Setting Mr.Sun's State"); doStateChange(&StateID_Follow); OSReport("Going to Execute Mr.Sun"); this->onExecute(); return true; } int daMrSun_c::onDelete() { return true; } int daMrSun_c::onExecute() { //OSReport("Oh Mr.Sun, Sun, Mr.Golden Sun"); acState.execute(); updateModelMatrices(); return true; } int daMrSun_c::onDraw() { bodyModel.scheduleForDrawing(); if (hasGlow) glowModel.scheduleForDrawing(); return true; } void daMrSun_c::updateModelMatrices() { // This won't work with wrap because I'm lazy. matrix.translation(pos.x, pos.y, pos.z); matrix.applyRotationYXZ(&rot.x, &rot.y, &rot.z); bodyModel.setDrawMatrix(matrix); bodyModel.setScale(&scale); bodyModel.calcWorld(false); if (hasGlow) { mMtx glowMatrix; short rotZ; float scaleX; glowPos += 0.01666666666666; if (glowPos > 1) { glowPos = 0; } if (this->spinStateOn = 0) { rotZ = (2000 * sin(glowPos * 3.14)) + 1000; } else { rotZ = (0xFFFF * sin(glowPos * 3.14)) + 0x7FFF; } scaleX = (0.2 * sin(glowPos * 3.14)) + 0.5; Vec glowscale = (Vec){scaleX, scaleX, 0.5}; glowMatrix.translation(pos.x, pos.y, pos.z); glowMatrix.applyRotationX(&rot.x); glowMatrix.applyRotationZ(&rotZ); glowModel.setDrawMatrix(glowMatrix); glowModel.setScale(&glowscale); glowModel.calcWorld(false); } } // Follow State void daMrSun_c::beginState_Follow() { OSReport("Mr.Sun is following youuuuu."); this->timer = 0; this->rot.x = 14000; this->rot.y = 0; // this->rot.z = 14000; } void daMrSun_c::executeState_Follow() { if (this->timer > 200) { this->doStateChange(&StateID_Wait); } this->direction = dSprite_c__getXDirectionOfFurthestPlayerRelativeToVEC3(this, this->pos); float speedDelta; if (this->settings == 0) { speedDelta = 0.1; } // It's a sun else { speedDelta = 0.15; } // It's a moon if (this->direction == 0) { this->speed.x = this->speed.x + speedDelta; if (this->speed.x < 0) { this->speed.x = this->speed.x + (speedDelta / 2); } if (this->speed.x < 50.0) { this->speed.x = this->speed.x + (speedDelta * 2); } } else { this->speed.x = this->speed.x - speedDelta; if (this->speed.x > 0) { this->speed.x = this->speed.x - (speedDelta / 2); } if (this->speed.x < 50.0) { this->speed.x = this->speed.x - (speedDelta * 2); } } HandleXSpeed(this); float yDiff; yDiff = (this->Baseline - this->pos.y) / 8; this->speed.y = yDiff; OSReport("YSpeed = %f", this->speed.y); HandleYSpeed(this); UpdateObjectPosBasedOnSpeedValues_real(this); this->timer = this->timer + 1; } void daMrSun_c::endState_Follow() { OSReport("Mr.Sun is coming for you."); this->speed.y = 0; } // Swoop State void daMrSun_c::beginState_Swoop() { OSReport("Swooping down from above, Mr.Sun falls down."); // Not enough space to swoop, spit instead. if (this->swoopTarget.y < (this->pos.y - 50)) { doStateChange(&StateID_Spit); } if (((this->pos.x - 96) < this->swoopTarget.x) && (this->swoopTarget.x < (this->pos.x + 96))) { doStateChange(&StateID_Spit); } if (this->settings == 0) { this->swoopTarget.y = this->swoopTarget.y - 16; } // It's a sun else { this->swoopTarget.y = this->swoopTarget.y - 4; } // It's a moon float x1, x2, x3, y1, y2, y3; x1 = this->pos.x - this->swoopTarget.x; x2 = 0; x3 = -x1; y1 = this->pos.y - this->swoopTarget.y; y2 = 0; y3 = y1; float denominator = (x1 - x2) * (x1 - x3) * (x2 - x3); this->swoopA = (x3 * (y2 - y1) + x2 * (y1 - y3) + x1 * (y3 - y2)) / denominator; this->swoopB = (x3*x3 * (y1 - y2) + x2*x2 * (y3 - y1) + x1*x1 * (y2 - y3)) / denominator; this->swoopC = (x2 * x3 * (x2 - x3) * y1 + x3 * x1 * (x3 - x1) * y2 + x1 * x2 * (x1 - x2) * y3) / denominator; this->swoopSpeed = x3 * 2 / 75; } void daMrSun_c::executeState_Swoop() { // Everything is calculated up top, just need to modify it. this->pos.x = this->pos.x + this->swoopSpeed; this->pos.y = ( this->swoopA*(this->pos.x - this->swoopTarget.x)*(this->pos.x - this->swoopTarget.x) + this->swoopB*(this->pos.x - this->swoopTarget.x) + this->swoopC ) + this->swoopTarget.y; if (this->pos.y > this->Baseline) { doStateChange(&StateID_Follow); } } void daMrSun_c::endState_Swoop() { OSReport("Returning to the sky, Mr.Sun flies into the sunset."); this->speed.y = 0; } // Spiral State void daMrSun_c::beginState_Spiral() { OSReport("Super Spiral Sunspot!"); this->SpiralLoop = 0; this->xSpiralOffset = this->pos.x; this->ySpiralOffset = this->pos.y; } void daMrSun_c::executeState_Spiral() { float Loops; float Magnitude; float Period; Loops = 6.0; Magnitude = 11.0; // Use a period of 0.1 for the moon if (this->settings == 0) { Period = 0.1; } // It's a sun else { Period = 0.125; } // It's a moon this->pos.x = this->xSpiralOffset + Magnitude*((this->SpiralLoop * cos(this->SpiralLoop))); this->pos.y = this->ySpiralOffset + Magnitude*((this->SpiralLoop * sin(this->SpiralLoop))); this->SpiralLoop = this->SpiralLoop + Period; if (this->SpiralLoop > (3.14 * Loops)) { doStateChange(&StateID_Follow); } } void daMrSun_c::endState_Spiral() { OSReport("Nightmare Spiral Attack Ends!"); } // Spit State void daMrSun_c::beginState_Spit() { OSReport("Goodness Gracious Great Balls of Fire!"); this->timer = 0; this->spinStateOn = 1; } void daMrSun_c::executeState_Spit() { if (this->timer == 10) { this->direction = dSprite_c__getXDirectionOfFurthestPlayerRelativeToVEC3(this, this->pos); float neg = -1.0; if (this->direction == 0) { neg = 1.0; } if (this->settings == 0) { dStageActor_c *spawner = CreateActor(106, 0, this->pos, 0, 0); spawner->speed.x = 6.0 * neg; spawner->speed.y = -2.5; spawner->pos.z = 3350.0; spawner = CreateActor(106, 0, this->pos, 0, 0); spawner->speed.x = 0.0 * neg; spawner->speed.y = -6.0; spawner->pos.z = 3350.0; spawner = CreateActor(106, 0, this->pos, 0, 0); spawner->speed.x = 3.5 * neg; spawner->speed.y = -6.0; spawner->pos.z = 3350.0; } // It's a sun else { dStageActor_c *spawner = CreateActor(118, 0, this->pos, 0, 0); spawner->speed.x = 6.0 * neg; spawner->speed.y = -2.5; spawner->pos.z = 3350.0; spawner = CreateActor(118, 0, this->pos, 0, 0); spawner->speed.x = 0.0 * neg; spawner->speed.y = -6.0; spawner->pos.z = 3350.0; spawner = CreateActor(118, 0, this->pos, 0, 0); spawner->speed.x = 3.5 * neg; spawner->speed.y = -6.0; spawner->pos.z = 3350.0; } // It's a moon } this->timer = this->timer + 1; if (this->timer > 30) { doStateChange(&StateID_Follow); } } void daMrSun_c::endState_Spit() { this->spinStateOn = 0; OSReport("Armageddon complete."); } // Spin State void daMrSun_c::beginState_Spin() { OSReport("Hoola hoola hoola hoop."); this->spinReduce = 0; } void daMrSun_c::executeState_Spin() { this->direction = dSprite_c__getXDirectionOfFurthestPlayerRelativeToVEC3(this, this->pos); if (this->direction == 0) { this->speed.x = this->speed.x + 0.2; if (this->speed.x < 0) { this->speed.x = this->speed.x + (0.2 / 2); } if (this->speed.x < 80.0) { this->speed.x = this->speed.x + (0.2 * 2); } } else { this->speed.x = this->speed.x - 0.2; if (this->speed.x > 0) { this->speed.x = this->speed.x - (0.2 / 2); } if (this->speed.x > 80.0) { this->speed.x = this->speed.x - (0.2 * 2); } } HandleXSpeed(this); UpdateObjectPosBasedOnSpeedValues_real(this); this->timer = this->timer + 1; int rotBonus; if (this->timer < 60) { rotBonus = this->timer; } else { rotBonus = 120 - this->timer; } this->rot.z = this->rot.z + (50 * rotBonus); this->rot.y = this->rot.y + (50 * rotBonus); if ((this->spinReduce = 0) && (this->timer < 100)) { this->spinReduce = this->rot.z / 20; } if (this->timer < 100) { this->rot.z = this->rot.z - this->spinReduce; this->rot.y = this->rot.y - this->spinReduce; } int randomBall; randomBall = GenerateRandomNumber(6); if (randomBall == 1) { int direction; direction = GenerateRandomNumber(8); float xlaunch; float ylaunch; if (direction == 0) { xlaunch = 5.0; ylaunch = 0.0; } else if (direction == 1) { // SE xlaunch = 5.0; ylaunch = 5.0; } else if (direction == 2) { // S xlaunch = 0.0; ylaunch = 5.0; } else if (direction == 3) { // SW xlaunch = -5.0; ylaunch = 5.0; } else if (direction == 4) { // W xlaunch = -5.0; ylaunch = 0.0; } else if (direction == 5) { // NW xlaunch = -5.0; ylaunch = -5.0; } else if (direction == 6) { // N xlaunch = 0.0; ylaunch = -5.0; } else if (direction == 7) { // NE xlaunch = 5.0; ylaunch = -5.0; } if (this->settings == 0) { dStageActor_c *spawner = CreateActor(106, 0, this->pos, 0, 0); spawner->speed.x = xlaunch; spawner->speed.y = ylaunch; spawner->pos.z = 3350.0; } // It's a sun else { dStageActor_c *spawner = CreateActor(118, 0, this->pos, 0, 0); spawner->speed.x = xlaunch; spawner->speed.y = ylaunch; spawner->pos.z = 3350.0; } // It's a moon } if (this->timer > 120) { this->doStateChange(&StateID_Follow); } } void daMrSun_c::endState_Spin() { OSReport("K, I is dizzy now."); this->rot.x = 14000; this->rot.y = 0; this->rot.z = 0; this->speed.x = 0; } // Wait State void daMrSun_c::beginState_Wait() { OSReport("Preparing an attack!"); this->timer = 0; this->speed.x = 0.0; dStageActor_c *Player = GetSpecificPlayerActor(0); if (Player == 0) { Player = GetSpecificPlayerActor(1); } if (Player == 0) { Player = GetSpecificPlayerActor(2); } if (Player == 0) { Player = GetSpecificPlayerActor(3); } if (Player == 0) { doStateChange(&StateID_Follow); } this->swoopTarget = Player->pos; } void daMrSun_c::executeState_Wait() { int Choice; int TimerMax; if (this->settings == 0) { TimerMax = 20; } // It's a sun else { TimerMax = 15; } // It's a moon if (this->timer > TimerMax) { // doStateChange(&StateID_Spit); Choice = GenerateRandomNumber(7); OSReport("Choice: %d", Choice); if (Choice == 0) { doStateChange(&StateID_Spit); } else if (Choice == 1) { doStateChange(&StateID_Spit); } else if (Choice == 2) { doStateChange(&StateID_Spin); } else if (Choice == 3) { doStateChange(&StateID_Spiral); } else { doStateChange(&StateID_Swoop); } } this->timer = this->timer + 1; } void daMrSun_c::endState_Wait() { OSReport("Mr.Sun Cometh!"); this->timer = 0; }