#include #include #include #include #include #include "boss.h" extern "C" void *ShakeScreen(void *, unsigned int, unsigned int, unsigned int, unsigned int); extern "C" void *StageScreen; // const char* effects_name_list [] = { // "Wm_jr_electricline", // cool // "Wm_jr_fireattack", // cool // "Wm_jr_firehit", // cool // "Wm_jr_fireplace", // cool // "Wm_jr_fireplace_ind", // cool // "Wm_jr_shot", // "Wm_jr_sweat", // "Wm_ko_fireattack", // cool // "Wm_ko_firehit", // cool // "Wm_ko_firehitdie01", // cool // "Wm_ko_firehitdie02", // cool // "Wm_ko_firehitdie03", // cool // "Wm_ko_magmapocha", // "Wm_ko_magmapochabig", // "Wm_ko_shout", // cool // "Wm_ko_shout02", // cool // "Wm_seacloudout", // cool // }; const char* CBarcNameList [] = { "KoopaShip", "koopa", "choropoo", "koopa_clown_bomb", "dossun", NULL }; class daCaptainBowser : public daBoss { public: int onCreate(); int onDelete(); int onExecute(); int onDraw(); mHeapAllocator_c allocator; nw4r::g3d::ResFile resFile; nw4r::g3d::ResFile shipFile; m3d::mdl_c bodyModel; m3d::mdl_c shipModel; m3d::anmChr_c chrAnimation; m3d::anmChr_c shipAnm; Physics ShipPhysics; ActivePhysics Roar; mEf::es2 effect; mEf::es2 shipDmgA; mEf::es2 shipDmgB; mEf::es2 shipDmgC; mEf::es2 shipDmgD; mEf::es2 shipDmgE; char isAngry; char isInvulnerable; char isIntro; float scaleIncreaser; int homingBillCountdown; int homingBillSlot; int maxDamage; int playerCount; float sinTimer; float roarLen; 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); void addScoreWhenHit(void *other); USING_STATES(daCaptainBowser); DECLARE_STATE(Wait); DECLARE_STATE(Throw); DECLARE_STATE(Fire); DECLARE_STATE(Roar); DECLARE_STATE(Damage); DECLARE_STATE(Intro); DECLARE_STATE(Outro); }; daCaptainBowser *daCaptainBowser::build() { void *buffer = AllocFromGameHeap1(sizeof(daCaptainBowser)); return new(buffer) daCaptainBowser; } /////////////////////// // Externs and States /////////////////////// extern "C" u32 GetActivePlayerCount(); CREATE_STATE(daCaptainBowser, Wait); CREATE_STATE(daCaptainBowser, Throw); CREATE_STATE(daCaptainBowser, Fire); CREATE_STATE(daCaptainBowser, Roar); CREATE_STATE(daCaptainBowser, Damage); CREATE_STATE(daCaptainBowser, Intro); CREATE_STATE(daCaptainBowser, Outro); //////////////////////// // Collision Functions //////////////////////// 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); if (this->damage == this->maxDamage/2) { doStateChange(&StateID_Roar); } else if (this->damage < 0) { doStateChange(&StateID_Outro); } else { doStateChange(&StateID_Damage); } } } void ShipPhysicsCallback(daCaptainBowser *self, dEn_c *other) { if (other->name == 657) { OSReport("CANNON COLLISION"); if (self->isInvulnerable) { return; } self->damage -= 1; SpawnEffect("Wm_en_burst_m", 0, &other->pos, &(S16Vec){0,0,0}, &(Vec){1.0, 1.0, 1.0}); PlaySound(other, SE_OBJ_TARU_BREAK); other->Delete(1); if (self->damage == self->maxDamage/2) { self->doStateChange(&daCaptainBowser::StateID_Roar); } else if (self->damage < 0) { self->doStateChange(&daCaptainBowser::StateID_Outro); } } } void daCaptainBowser::playerCollision(ActivePhysics *apThis, ActivePhysics *apOther) { DamagePlayer(this, apThis, apOther); } void daCaptainBowser::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 daCaptainBowser::onCreate() { // Model creation allocator.link(-1, GameHeaps[0], 0, 0x20); // B-b-b-bad boy Bowsaa this->resFile.data = getResource("koopa", "g3d/koopa.brres"); nw4r::g3d::ResMdl mdl = this->resFile.GetResMdl("koopa"); bodyModel.setup(mdl, &allocator, 0x224, 1, 0); SetupTextures_Boss(&bodyModel, 0); nw4r::g3d::ResAnmChr anmChr = this->resFile.GetResAnmChr("kp_wait"); this->chrAnimation.setup(mdl, anmChr, &this->allocator, 0); // A ship off the ol' block this->shipFile.data = getResource("KoopaShip", "g3d/KoopaShip.brres"); nw4r::g3d::ResMdl mdlShip = this->shipFile.GetResMdl("KoopaShip"); shipModel.setup(mdlShip, &allocator, 0x224, 1, 0); // SetupTextures_MapObj(&shipModel, 0); nw4r::g3d::ResAnmChr anmChrShip = this->shipFile.GetResAnmChr("KoopaShip"); this->shipAnm.setup(mdlShip, anmChrShip, &this->allocator, 0); this->shipAnm.bind(&this->shipModel, anmChrShip, 1); this->shipModel.bindAnim(&this->shipAnm, 0.0); this->shipAnm.setUpdateRate(1.0); allocator.unlink(); // Prep the goods this->playerCount = GetActivePlayerCount(); this->maxDamage = (10 * this->playerCount) + 10; pos.z = 8000.0; this->scale = (Vec){0.57, 0.57, 0.57}; this->homingBillCountdown = 270; this->homingBillSlot = 0; this->damage = this->maxDamage; // Ship Physics! // Normal rects are { left, top, right, bottom } // Callbacks are Touching upwards, Touching Downwards, and unknown ShipPhysics.baseSetup(this, &ShipPhysicsCallback, 0, 0, 1, 0); ShipPhysics.x = 8.0; ShipPhysics.y = 20.0; ShipPhysics.diameter = 12.0 * 16.0; ShipPhysics.isRound = 1; this->ShipPhysics.addToList(); // Bowser Physics! ActivePhysics::Info BowserPhysics; BowserPhysics.xDistToCenter = -152.0; BowserPhysics.yDistToCenter = 152.0; BowserPhysics.xDistToEdge = 38.0; BowserPhysics.yDistToEdge = 38.0; BowserPhysics.category1 = 0x3; BowserPhysics.category2 = 0x0; BowserPhysics.bitfield1 = 0x4F; BowserPhysics.bitfield2 = 0x8028E; BowserPhysics.unkShort1C = 0; BowserPhysics.callback = &dEn_c::collisionCallback; this->aPhysics.initWithStruct(this, &BowserPhysics); this->aPhysics.addToList(); // 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); return true; } int daCaptainBowser::onDelete() { return true; } int daCaptainBowser::onExecute() { acState.execute(); this->ShipPhysics.update(); PlaySound(this, SE_BOSS_SHIP_PRPL); bodyModel._vf1C(); shipModel._vf1C(); if(this->isIntro == 0) { float xmod = sin(this->sinTimer * 3.14 / 180.0) * 60.0; float ymod = sin(this->sinTimer * 3.14 / 130.0) * 84.0; pos.x = ClassWithCameraInfo::instance->screenCentreX + 200.0 + xmod; pos.y = ClassWithCameraInfo::instance->screenCentreY - 180.0 + ymod; this->sinTimer++; } // 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()) { this->shipAnm.setCurrentFrame(0.0); } return true; } 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); bodyModel.setDrawMatrix(matrix); bodyModel.setScale(&(Vec){1.0, 1.0, 1.0}); bodyModel.calcWorld(false); bodyModel.scheduleForDrawing(); matrix.translation(pos.x, pos.y, pos.z); newrot = rot.y + 0x4000; matrix.applyRotationYXZ(&rot.x, &newrot, &rot.z); shipModel.setDrawMatrix(matrix); shipModel.setScale(&scale); shipModel.calcWorld(false); shipModel.scheduleForDrawing(); return true; } ////////////////// // State Intro ////////////////// void daCaptainBowser::beginState_Intro() { this->timer = 0; bindAnimChr_and_setUpdateRate("kp_wait", 1, 0.0, 1.5); this->isInvulnerable = 1; roarLen = 300; } void daCaptainBowser::executeState_Intro() { if (this->chrAnimation.isAnimationDone()) { // End the intro if (this->isIntro == 1) { OSReport("We're done: %d", this->timer); doStateChange(&StateID_Wait); return; } this->chrAnimation.setCurrentFrame(0.0); } // Screen Rumble if ((this->timer > 180) && (this->timer < 420)) { // if (this->timer == 180) { // Do Rumbly - 807CD3AC pos.x = ClassWithCameraInfo::instance->screenCentreX; pos.y = ClassWithCameraInfo::instance->screenCentreY; ShakeScreen(StageScreen, 2, 1, 0, 0); PlaySoundAsync(this, SE_BOSS_KOOPA_RUMBLE1); // 0x5D4 // Stage80::instance->ShakeScreen(self, 5, 1, 0); } // 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); } // Bowser does a shitty roar if (this->timer == (roarLen - 190 + 420)) { this->isIntro = 1; bindAnimChr_and_setUpdateRate("kp_roar3", 1, 0.0, 1.0); } if (this->timer > (roarLen - 190 + 420)) { if (this->chrAnimation.getCurrentFrame() == 53.0) { PlaySound(this, SE_VOC_KP_L_SHOUT); } if (this->chrAnimation.getCurrentFrame() > 53.0) { ShakeScreen(StageScreen, 2, 2, 0, 0); effect.spawn("Wm_ko_shout", 0, &(Vec){pos.x-182.0, pos.y+132.0, pos.z}, &(S16Vec){0,0,0x7000}, &(Vec){1.0, 1.0, 1.0}); } } this->timer++; } void daCaptainBowser::endState_Intro() { this->isInvulnerable = 0; this->isIntro = 0; } ////////////////// // State Wait ////////////////// void daCaptainBowser::beginState_Wait() { if (this->isAngry == 0) { bindAnimChr_and_setUpdateRate("kp_wait", 1, 0.0, 1.5); } else { bindAnimChr_and_setUpdateRate("kp_wait", 1, 0.0, 2.0); } } void daCaptainBowser::executeState_Wait() { if (this->chrAnimation.isAnimationDone()) { this->chrAnimation.setCurrentFrame(0.0); int num = GenerateRandomNumber(4); if (num == 0) { doStateChange(&StateID_Fire); } else{ doStateChange(&StateID_Throw); } } } void daCaptainBowser::endState_Wait() { } ////////////////// // State Throw ////////////////// void daCaptainBowser::beginState_Throw() { bindAnimChr_and_setUpdateRate("break", 1, 0.0, 1.0); this->timer = 0; } void daCaptainBowser::executeState_Throw() { if (this->chrAnimation.getCurrentFrame() == 60.0) { // throw back int num = GenerateRandomNumber(5); CreateActor(0x29F, 0x101 + ((num + 1) * 0x10), (Vec){pos.x-146.0, pos.y+122.0, 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); } if (this->chrAnimation.isAnimationDone()) { this->chrAnimation.setCurrentFrame(0.0); if (this->isAngry == 1) { if (this->timer == 1) { doStateChange(&StateID_Wait); } } else { doStateChange(&StateID_Wait); } this->timer++; } } void daCaptainBowser::endState_Throw() { } ////////////////// // State Fire ////////////////// void daCaptainBowser::beginState_Fire() { bindAnimChr_and_setUpdateRate("fire1", 1, 0.0, 1.5); this->timer = 0; } void daCaptainBowser::executeState_Fire() { if (this->chrAnimation.getCurrentFrame() == 70.5) { // spit fire PlaySound(this, SE_BOSS_KOOPA_L_FIRE_SHOT); CreateActor(WM_ANTLION, 0, (Vec){pos.x-172.0, pos.y+152.0, pos.z}, 0, 0); } if (this->chrAnimation.isAnimationDone()) { this->chrAnimation.setCurrentFrame(0.0); if (this->isAngry == 1) { if (this->timer == 1) { doStateChange(&StateID_Wait); } } else { doStateChange(&StateID_Wait); } this->timer++; } } void daCaptainBowser::endState_Fire() { } ////////////////// // State Roar ////////////////// void daCaptainBowser::beginState_Roar() { 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); } 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; } // if (this->chrAnimation.getCurrentFrame() == 197.0) { // This is where the smackdown ends // this->Roar.removeFromList(); // } if (this->chrAnimation.isAnimationDone()) { doStateChange(&StateID_Wait); } } void daCaptainBowser::endState_Roar() { this->isInvulnerable = 0; this->isAngry = 1; } ////////////////// // State Damage ////////////////// void daCaptainBowser::beginState_Damage() { bindAnimChr_and_setUpdateRate("grow_big", 1, 0.0, 1.0); this->isInvulnerable = 1; this->chrAnimation.setCurrentFrame(9.0); PlaySound(this, SE_VOC_KP_DAMAGE_HPDP); } void daCaptainBowser::executeState_Damage() { if (this->chrAnimation.getCurrentFrame() == 65.0) { // stop it here before it's too late doStateChange(&StateID_Wait); } } void daCaptainBowser::endState_Damage() { this->isInvulnerable = 0; } ////////////////// // State Outro ////////////////// void daCaptainBowser::beginState_Outro() { } void daCaptainBowser::executeState_Outro() { } void daCaptainBowser::endState_Outro() { }