#include #include #include #include #include "boss.h" extern "C" void *SoundRelatedClass; extern "C" void *MapSoundPlayer(void *SoundRelatedClass, int soundID, int unk); const char* SSarcNameList [] = { "Shynja", NULL }; void ChucksAndKnucks(ActivePhysics *apThis, ActivePhysics *apOther); class daSamurshai : public daBoss { int onCreate(); int onDelete(); int onExecute(); int onDraw(); mHeapAllocator_c allocator; nw4r::g3d::ResFile resFile; m3d::mdl_c bodyModel; m3d::anmChr_c chrAnimation; mEf::es2 effect; int isBigBoss; int jumpCounter; char isDown; Vec initialPos; float XSpeed; u32 cmgr_returnValue; dStageActor_c *chosenOne; bool topHurts; bool slowDown; bool isBouncing; bool walkStateIsCharging; float amountCharged; ActivePhysics Chuckles; ActivePhysics Knuckles; static daSamurshai *build(); void bindAnimChr_and_setUpdateRate(const char* name, int unk, float unk2, float rate); void updateModelMatrices(); bool calculateTileCollisions(); void powBlockActivated(bool isNotMPGP); void playerCollision(ActivePhysics *apThis, ActivePhysics *apOther); void yoshiCollision(ActivePhysics *apThis, ActivePhysics *apOther); bool collisionCat3_StarPower(ActivePhysics *apThis, ActivePhysics *apOther); bool collisionCat14_YoshiFire(ActivePhysics *apThis, ActivePhysics *apOther); bool collisionCatD_Drill(ActivePhysics *apThis, ActivePhysics *apOther); bool collisionCat7_GroundPound(ActivePhysics *apThis, ActivePhysics *apOther); bool collisionCat7_GroundPoundYoshi(ActivePhysics *apThis, ActivePhysics *apOther); bool collisionCat9_RollingObject(ActivePhysics *apThis, ActivePhysics *apOther); bool collisionCat1_Fireball_E_Explosion(ActivePhysics *apThis, ActivePhysics *apOther); bool collisionCat2_IceBall_15_YoshiIce(ActivePhysics *apThis, ActivePhysics *apOther); bool collisionCat13_Hammer(ActivePhysics *apThis, ActivePhysics *apOther); bool collisionCatA_PenguinMario(ActivePhysics *apThis, ActivePhysics *apOther); void addScoreWhenHit(void *other); int randomPlayer(); bool isNearWall(); USING_STATES(daSamurshai); DECLARE_STATE(Intro); DECLARE_STATE(Walk); DECLARE_STATE(Turn); DECLARE_STATE(Chop); DECLARE_STATE(ChargeSlash); DECLARE_STATE(Uppercut); DECLARE_STATE(SpinAttack); DECLARE_STATE(Damage); DECLARE_STATE(Outro); }; daSamurshai *daSamurshai::build() { void *buffer = AllocFromGameHeap1(sizeof(daSamurshai)); return new(buffer) daSamurshai; } /////////////////////// // Externs and States /////////////////////// extern "C" int SmoothRotation(short* rot, u16 amt, int unk2); CREATE_STATE(daSamurshai, Intro); CREATE_STATE(daSamurshai, Walk); CREATE_STATE(daSamurshai, Turn); CREATE_STATE(daSamurshai, Chop); CREATE_STATE(daSamurshai, ChargeSlash); CREATE_STATE(daSamurshai, Uppercut); CREATE_STATE(daSamurshai, SpinAttack); CREATE_STATE(daSamurshai, Damage); CREATE_STATE(daSamurshai, Outro); //////////////////////// // Collision Functions //////////////////////// void ChucksAndKnucks(ActivePhysics *apThis, ActivePhysics *apOther) { ((dEn_c*)apThis->owner)->_vf220(apOther->owner); } void daSamurshai::playerCollision(ActivePhysics *apThis, ActivePhysics *apOther) { char hitType = 0; // this is shit code dStateBase_c *whatState = acState.getCurrentState(); if (whatState == &StateID_Damage) { // nothing } else if (whatState == &StateID_Walk && walkStateIsCharging) { // also nothing } else { hitType = usedForDeterminingStatePress_or_playerCollision(this, apThis, apOther, 2); } if (hitType == 2) { // Mini jump apOther->someFlagByte |= 2; } else if (hitType > 0) { apOther->someFlagByte |= 2; if (this->isDown == 0) { this->playEnemyDownSound1(); damage += 5; if (damage >= 15) { doStateChange(&StateID_Outro); } else { doStateChange(&StateID_Damage); } } } else { this->dEn_c::playerCollision(apThis, apOther); this->_vf220(apOther->owner); } deathInfo.isDead = 0; this->flags_4FC |= (1<<(31-7)); this->counter_504[apOther->owner->which_player] = 0; } void daSamurshai::yoshiCollision(ActivePhysics *apThis, ActivePhysics *apOther) { this->playerCollision(apThis, apOther); } bool daSamurshai::collisionCatD_Drill(ActivePhysics *apThis, ActivePhysics *apOther) { return collisionCat7_GroundPound(apThis, apOther); } bool daSamurshai::collisionCat7_GroundPound(ActivePhysics *apThis, ActivePhysics *apOther) { apOther->someFlagByte |= 2; if (this->isDown == 0) { damage += 5; if (damage >= 15) { doStateChange(&StateID_Outro); } else { doStateChange(&StateID_Damage); } } deathInfo.isDead = 0; this->flags_4FC |= (1<<(31-7)); this->counter_504[apOther->owner->which_player] = 5; bouncePlayerWhenJumpedOn(apOther->owner); return true; } bool daSamurshai::collisionCat7_GroundPoundYoshi(ActivePhysics *apThis, ActivePhysics *apOther) { return this->collisionCat7_GroundPound(apThis, apOther); } bool daSamurshai::collisionCat9_RollingObject(ActivePhysics *apThis, ActivePhysics *apOther) { if (this->isDown == 0) { damage += 3; if (damage >= 15) { doStateChange(&StateID_Outro); } else { doStateChange(&StateID_Damage); } } return true; } bool daSamurshai::collisionCat3_StarPower(ActivePhysics *apThis, ActivePhysics *apOther){ return true; } bool daSamurshai::collisionCatA_PenguinMario(ActivePhysics *apThis, ActivePhysics *apOther){ dAcPy_vf3F8(apOther->owner, this, 3); deathInfo.isDead = 0; this->flags_4FC |= (1<<(31-7)); this->counter_504[apOther->owner->which_player] = 0; return true; } bool daSamurshai::collisionCat14_YoshiFire(ActivePhysics *apThis, ActivePhysics *apOther){ //damage += 4; //SpawnEffect("Wm_mr_fireball_hit", 0, &apOther->owner->pos, &apOther->owner->rot, &apOther->owner->scale); //PlaySoundAsync(this, SE_OBJ_FIREBALL_DISAPP); //if (damage >= 15) { doStateChange(&StateID_Outro); } return true; } bool daSamurshai::collisionCat1_Fireball_E_Explosion(ActivePhysics *apThis, ActivePhysics *apOther) { //damage += 1; //SpawnEffect("Wm_mr_fireball_hit", 0, &apOther->owner->pos, &apOther->owner->rot, &apOther->owner->scale); //PlaySoundAsync(this, SE_OBJ_FIREBALL_DISAPP); //if (damage >= 15) { doStateChange(&StateID_Outro); } return true; } bool daSamurshai::collisionCat2_IceBall_15_YoshiIce(ActivePhysics *apThis, ActivePhysics *apOther) { return true; } bool daSamurshai::collisionCat13_Hammer(ActivePhysics *apThis, ActivePhysics *apOther) { //damage += 2; //this->spawnHitEffectAtPosition((Vec2){apOther->owner->pos.x, apOther->owner->pos.y}); //if (damage >= 15) { doStateChange(&StateID_Outro); } return true; } void daSamurshai::addScoreWhenHit(void *other) { } void daSamurshai::powBlockActivated(bool isNotMPGP) { } bool daSamurshai::calculateTileCollisions() { // Returns true if sprite should turn, false if not. HandleXSpeed(); HandleYSpeed(); doSpriteMovement(); cmgr_returnValue = collMgr.isOnTopOfTile(); collMgr.calculateBelowCollisionWithSmokeEffect(); if (isBouncing) { stuffRelatingToCollisions(0.1875f, 1.0f, 0.5f); if (speed.y != 0.0f) isBouncing = false; } if (collMgr.isOnTopOfTile()) { // Walking into a tile branch if (cmgr_returnValue == 0) isBouncing = true; speed.y = 0.0f; } // Bouncing checks if (_34A & 4) { Vec v = (Vec){0.0f, 1.0f, 0.0f}; collMgr.pSpeed = &v; if (collMgr.calculateAboveCollision(collMgr.outputMaybe)) speed.y = 0.0f; collMgr.pSpeed = &speed; } else { if (collMgr.calculateAboveCollision(collMgr.outputMaybe)) speed.y = 0.0f; } collMgr.calculateAdjacentCollision(0); // Switch Direction if (collMgr.outputMaybe & (0x15 << direction)) { if (collMgr.isOnTopOfTile()) { isBouncing = true; } pos.x = direction ? pos.x + speed.x : pos.x - speed.x; return true; } return false; } void daSamurshai::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 daSamurshai::onCreate() { isBigBoss = settings & 0xF; // Model Setup allocator.link(-1, GameHeaps[0], 0, 0x20); this->resFile.data = getResource("Shynja", "g3d/Shynja.brres"); nw4r::g3d::ResMdl mdl = this->resFile.GetResMdl("Shynja"); bodyModel.setup(mdl, &allocator, 0x224, 1, 0); // Animations start here nw4r::g3d::ResAnmChr anmChr = this->resFile.GetResAnmChr("c18_IDLE_R"); this->chrAnimation.setup(mdl, anmChr, &this->allocator, 0); allocator.unlink(); // Character Setup scale = (Vec){25.0, 25.0, 25.0}; pos.y = pos.y - 16.0 * 3.0; rot.x = 0; // X is vertical axis rot.y = 0xD800; // Y is horizontal axis rot.z = 0; // Z is ... an axis >.> direction = 1; // Heading left. speed.x = 0.0; speed.y = 0.0; XSpeed = 2.5; max_speed.x = 50.0; initialPos = pos; topHurts = false; // Physics ActivePhysics::Info HitMeBaby; HitMeBaby.xDistToCenter = 0.0; HitMeBaby.yDistToCenter = 15.0; HitMeBaby.xDistToEdge = 13.0; HitMeBaby.yDistToEdge = 15.0; HitMeBaby.category1 = 0x3; HitMeBaby.category2 = 0x0; HitMeBaby.bitfield1 = 0x4F; HitMeBaby.bitfield2 = 0xffbafffe; HitMeBaby.unkShort1C = 0; HitMeBaby.callback = &dEn_c::collisionCallback; this->aPhysics.initWithStruct(this, &HitMeBaby); this->aPhysics.addToList(); // Tile collider // These fucking rects do something for the tile rect spriteSomeRectX = 48.0f; spriteSomeRectY = 36.0f; _320 = 0.0f; _324 = 18.0f; // These structs tell stupid collider what to collide with - these are from koopa troopa static const lineSensor_s below(12<<12, 4<<12, 0<<12); static const pointSensor_s above(0<<12, 12<<12); static const lineSensor_s adjacent(6<<12, 9<<12, 6<<12); collMgr.init(this, &below, &above, &adjacent); collMgr.calculateBelowCollisionWithSmokeEffect(); cmgr_returnValue = collMgr.isOnTopOfTile(); if (collMgr.isOnTopOfTile()) isBouncing = false; else isBouncing = true; // Sword Physics // Chuckles is left, Knuckles is Right ActivePhysics::Info iChuckles; ActivePhysics::Info iKnuckles; iChuckles.xDistToCenter = -27.0; iChuckles.yDistToCenter = 8.0; iChuckles.xDistToEdge = 27.0; iChuckles.yDistToEdge = 6.0; iKnuckles.xDistToCenter = 27.0; iKnuckles.yDistToCenter = 8.0; iKnuckles.xDistToEdge = 27.0; iKnuckles.yDistToEdge = 6.0; iKnuckles.category1 = iChuckles.category1 = 0x3; iKnuckles.category2 = iChuckles.category2 = 0x0; iKnuckles.bitfield1 = iChuckles.bitfield1 = 0x4F; iKnuckles.bitfield2 = iChuckles.bitfield2 = 0x6; iKnuckles.unkShort1C = iChuckles.unkShort1C = 0x0; iKnuckles.callback = iChuckles.callback = ChucksAndKnucks; Chuckles.initWithStruct(this, &iChuckles); Knuckles.initWithStruct(this, &iKnuckles); doStateChange(&StateID_Intro); this->onExecute(); return true; } int daSamurshai::onDelete() { return true; } int daSamurshai::onExecute() { acState.execute(); updateModelMatrices(); return true; } int daSamurshai::onDraw() { bodyModel.scheduleForDrawing(); bodyModel._vf1C(); return true; } void daSamurshai::updateModelMatrices() { // This won't work with wrap because I'm lazy. matrix.translation(pos.x, pos.y + 0.0, pos.z); matrix.applyRotationYXZ(&rot.x, &rot.y, &rot.z); bodyModel.setDrawMatrix(matrix); bodyModel.setScale(&scale); bodyModel.calcWorld(false); } /////////////// // Intro State /////////////// void daSamurshai::beginState_Intro() { 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 KamekPos = (Vec){pos.x - 124.0, pos.y + 104.0, 3564.0}; S16Vec KamekRot = (S16Vec){0, 0, 0}; rot.y = 0x2800; // Y is horizontal axis speed.x = 0.0; speed.y = 0.0; pos.x = pos.x - 224.0; pos.y = pos.y + 320.0; // Create And use Kameck Kameck = (daKameckDemo*)createChild(KAMECK_FOR_CASTLE_DEMO, (dStageActor_c*)this, 0, &KamekPos, &KamekRot, 0); Kameck->doStateChange(&daKameckDemo::StateID_DemoSt); Kameck->pos.x = Kameck->pos.x - 32.0; } void daSamurshai::executeState_Intro() { this->timer += 1; OSReport("Timer: %d", timer); if (timer == 230) { bindAnimChr_and_setUpdateRate("c18_INTRO", 1, 0.0, 1.0); } if ((timer > 220) && (timer < 240)) { pos.x += (224.0 / 20.0); pos.y -= (320.0 / 20.0); } if (timer == 230) { SpawnEffect("Wm_en_hanapetal", 0, &pos, &(S16Vec){0,0,0}, &(Vec){1.5, 1.5, 1.5}); SpawnEffect("Wm_ob_itemget_ring", 0, &(Vec){pos.x, pos.y + 16.0, pos.z}, &(S16Vec){0,0,0}, &(Vec){8.0, 0.1, 1.5}); MapSoundPlayer(SoundRelatedClass, SE_OBJ_WOOD_BOX_BREAK, 1); MapSoundPlayer(SoundRelatedClass, SE_BOSS_KAMECK_DOWN, 1); this->Kameck->doStateChange(&daKameckDemo::StateID_DieFall); } if ((timer > 230) && (timer < 350)) { Kameck->pos.x += (200.0 / 120.0); Kameck->pos.y -= (260.0 / 120.0); } int done = 0; if ((timer > 330) && (done == 0)) { u16 amt = (this->direction == 0) ? 0x2800 : 0xD800; done = SmoothRotation(&this->rot.y, amt, 0x2000); } if (timer == 400) { bindAnimChr_and_setUpdateRate("c18_IDLE_R", 1, 0.0, 1.0); } if (timer == 500) { MapSoundPlayer(SoundRelatedClass, SE_BOSS_WENDY_RING_BOUND, 1); walkStateIsCharging = false; doStateChange(&StateID_Walk); } } void daSamurshai::endState_Intro() { CleanupKameck(this, Kameck); rot.y = 0xD800; // Y is horizontal axis direction = 1; // Heading left. XSpeed = 2.0; max_speed.x = 50.0; } /////////////// // Walk State /////////////// int daSamurshai::randomPlayer() { int players[4]; int playerCount = 0; for (int i = 0; i < 4; i++) { if (Player_Active[i] != 0 && Player_Lives[Player_ID[i]] > 0) { players[playerCount] = i; playerCount++; } } return players[MakeRandomNumber(playerCount)]; } void daSamurshai::beginState_Walk() { Chuckles.removeFromList(); Knuckles.removeFromList(); bindAnimChr_and_setUpdateRate(walkStateIsCharging ? "c18_CHARGE" : "c18_RUNNING", 1, 0.0, 0.5); chosenOne = GetSpecificPlayerActor(this->randomPlayer()); speed.x = (this->direction) ? -this->XSpeed : this->XSpeed; if (walkStateIsCharging) speed.x *= 1.7f; this->max_speed.y = -4.0; this->speed.y = -4.0; this->y_speed_inc = -0.1875; OSReport("Speed: %f / %f", speed.x, max_speed.x); } void daSamurshai::executeState_Walk() { MapSoundPlayer(SoundRelatedClass, SE_EMY_MOUSE_WALK, 1); float xDistance = pos.x - chosenOne->pos.x; float yDistance = pos.y - chosenOne->pos.y; // OSReport("Distance: %f, %f", xDistance, yDistance); if (!walkStateIsCharging && (xDistance > 64.0) && (direction == 0)) { doStateChange(&StateID_Turn); } if (!walkStateIsCharging && (xDistance < -64.0) && (direction == 1)) { doStateChange(&StateID_Turn); } if (xDistance < 0.0) { xDistance = -xDistance; } if (walkStateIsCharging) { amountCharged += abs(speed.x); // should we stop charging? if (amountCharged > 480.0f && !isNearWall()) { speed.x = (this->direction) ? -this->XSpeed : this->XSpeed; doStateChange(&StateID_Uppercut); } } // Condition for Chop if (!walkStateIsCharging && xDistance < 32.0) { doStateChange(&StateID_Chop); } // Condition For Charge Slash if (!walkStateIsCharging && isBigBoss) { if ((xDistance < 96.0) && (xDistance > 64.0)) { int charge = MakeRandomNumber(100); if (charge > 95) { doStateChange(&StateID_ChargeSlash); } } } // Aerial Attacks! if (!walkStateIsCharging && yDistance < -24.0) { // Condition For Spin Attack // if (xDistance < 32.0) { doStateChange(&StateID_SpinAttack); } // Condition for Uppercut if ((xDistance > 48.0) && (xDistance < 64.0) && !isNearWall()) doStateChange(&StateID_Uppercut); } bool ret = calculateTileCollisions(); if (ret) { doStateChange(&StateID_Turn); } if(this->chrAnimation.isAnimationDone()) { this->chrAnimation.setCurrentFrame(0.0); } } void daSamurshai::endState_Walk() { } /////////////// // Turn State /////////////// void daSamurshai::beginState_Turn() { bindAnimChr_and_setUpdateRate("c18_RUNNING", 1, 0.0, 0.5); this->speed.x = (direction) ? 0.5f : -0.5f; this->direction ^= 1; x_speed_inc = 0.0; } void daSamurshai::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, 0x1000); if(done) { this->doStateChange(&StateID_Walk); } } void daSamurshai::endState_Turn() { } /////////////// // Chop State /////////////// void daSamurshai::beginState_Chop() { bindAnimChr_and_setUpdateRate("c18_H_CUT_R", 1, 0.0, 1.0); chrAnimation.setCurrentFrame(0.0); timer = 0; } void daSamurshai::executeState_Chop() { speed.x = speed.x / 1.5; if (chrAnimation.getCurrentFrame() == 15.0) { MapSoundPlayer(SoundRelatedClass, SE_EMY_CRASHER_PUNCH, 1); if (this->direction == 1) { SpawnEffect("Wm_ob_itemget_ring", 0, &(Vec){pos.x - 18.0, pos.y + 16.0, pos.z-200.0}, &(S16Vec){0,0,0}, &(Vec){2.5, 0.5, 1.5}); Chuckles.addToList(); } else { SpawnEffect("Wm_ob_itemget_ring", 0, &(Vec){pos.x + 18.0, pos.y + 16.0, pos.z-200.0}, &(S16Vec){0,0,0}, &(Vec){2.5, 0.5, 1.5}); Knuckles.addToList(); } } if (chrAnimation.getCurrentFrame() == 20.0) { MapSoundPlayer(SoundRelatedClass, SE_OBJ_WOOD_BOX_BREAK, 1); if (this->direction == 1) { SpawnEffect("Wm_en_hit", 0, &(Vec){pos.x - 38.0, pos.y + 16.0, pos.z}, &(S16Vec){0,0,0}, &(Vec){1.0, 1.0, 1.0}); SpawnEffect("Wm_en_hanapetal", 0, &(Vec){pos.x - 38.0, pos.y + 16.0, pos.z}, &(S16Vec){0,0,0}, &(Vec){2.0, 2.0, 2.0}); Chuckles.removeFromList(); } else { SpawnEffect("Wm_en_hit", 0, &(Vec){pos.x + 38.0, pos.y + 16.0, pos.z}, &(S16Vec){0,0,0}, &(Vec){1.0, 1.0, 1.0}); SpawnEffect("Wm_en_hanapetal", 0, &(Vec){pos.x + 38.0, pos.y + 16.0, pos.z}, &(S16Vec){0,0,0}, &(Vec){2.0, 2.0, 2.0}); Knuckles.removeFromList(); } } if(this->chrAnimation.isAnimationDone()) { timer += 1; if (timer > 45) { walkStateIsCharging = false; doStateChange(&StateID_Walk); } } } void daSamurshai::endState_Chop() { } /////////////// // ChargeSlash State /////////////// void daSamurshai::beginState_ChargeSlash() { timer = 0; slowDown = false; topHurts = false; speed.x = 0.0; } void daSamurshai::executeState_ChargeSlash() { // End if the animation is finally over if ((chrAnimation.isAnimationDone()) && (slowDown) ) { walkStateIsCharging = false; doStateChange(&StateID_Walk); return; } // What to do if he hits a wall bool ret = calculateTileCollisions(); if (ret) { OSReport("Hit the wall"); bindAnimChr_and_setUpdateRate("c18_R_BLOCK_BREAK_R", 1, 0.0, 1.0); speed.x = (direction) ? 0.5f : -0.5f; topHurts = false; slowDown = true; timer = 500; } if (timer == 500) { speed.x = speed.x / 1.05; return; } // Begin the charge effect if (timer == 0) { bindAnimChr_and_setUpdateRate("c18_OB_IDLE_R", 1, 0.0, 0.5); if (direction == 1) SpawnEffect("Wm_ob_keyget02_lighit", 0, &(Vec){pos.x + 7.0, pos.y + 14.0, pos.z - 5500.0}, &(S16Vec){0,0,0}, &(Vec){0.8, 0.8, 0.8}); else SpawnEffect("Wm_ob_keyget02_lighit", 0, &(Vec){pos.x - 7.0, pos.y + 14.0, pos.z + 5500.0}, &(S16Vec){0,0,0}, &(Vec){0.8, 0.8, 0.8}); } // Start to cut if (timer == 60) { bindAnimChr_and_setUpdateRate("c18_H_CUT_R", 1, 0.0, 1.0); } // After enough charging, speed on! if (timer == 70) { speed.x = (direction) ? -16.0f : 16.0f; chrAnimation.setUpdateRate(0.0); } // He should not be able to be hurt for a while if (timer == 72) { topHurts = true; } OSReport("Speed: %f @ %d", speed.x, timer); float absSpeed; if (speed.x < 0.0) { absSpeed = -speed.x; } else { absSpeed = speed.x; } // Can be bopped again when he gets slow enough if (absSpeed < 1.0) { topHurts = false; chrAnimation.setUpdateRate(1.0); } // During the dash if (absSpeed > 0.0) { // Slow that horsey down, tiger if (slowDown) { speed.x = speed.x / 1.5; return; } effect.spawn("Wm_mr_p_iceslip", 0, &(Vec){pos.x, pos.y+8.0, pos.z}, &(S16Vec){0,0,0}, &(Vec){1.5, 1.5, 1.5}); SpawnEffect("Wm_en_hanapetal", 0, &pos, &(S16Vec){0,0,0}, &(Vec){1.5, 1.5, 1.5}); SpawnEffect("Wm_ob_itemget_ring", 0, &(Vec){pos.x, pos.y + 16.0, pos.z}, &(S16Vec){0,0,0}, &(Vec){4.0, 0.1, 1.5}); if (timer == 75) { slowDown = true; } // Positive if Mario is left of Samurai, negative if he is to the right // float xDistance = pos.x - chosenOne->pos.x; // // direction 1 is going left, direction 0 is going right // if ((xDistance > 0) && (direction == 0)) { // SpawnEffect("Wm_ob_itemget_ring", 0, &(Vec){pos.x, pos.y + 16.0, pos.z}, &(S16Vec){0,0,0}, &(Vec){4.0, 0.1, 1.5}); // slowDown = true; } // if ((xDistance < 0) && (direction == 1)) { // SpawnEffect("Wm_ob_itemget_ring", 0, &(Vec){pos.x, pos.y + 16.0, pos.z}, &(S16Vec){0,0,0}, &(Vec){4.0, 0.1, 1.5}); // slowDown = true; } } this->timer += 1; } void daSamurshai::endState_ChargeSlash() { slowDown = false; } /////////////// // Uppercut State /////////////// void daSamurshai::beginState_Uppercut() { bindAnimChr_and_setUpdateRate("c18_H_SHOT_R", 1, 0.0, 2.0); slowDown = false; timer = 0; } void daSamurshai::executeState_Uppercut() { if ((slowDown) && (this->chrAnimation.isAnimationDone())) { timer++; if (timer > 45) { walkStateIsCharging = false; doStateChange(&StateID_Walk); } } if (slowDown) { return; } if (this->chrAnimation.getCurrentFrame() == 34.0) { topHurts = true; MapSoundPlayer(SoundRelatedClass, SE_EMY_CRASHER_PUNCH, 1); MapSoundPlayer(SoundRelatedClass, SE_BOSS_CMN_JUMP_M, 1); speed.y = 4.0; y_speed_inc = -0.1875; if (this->direction == 1) { effect.spawn("Wm_ob_itemget_ring", 0, &(Vec){pos.x - 48.0, pos.y + 32.0, pos.z}, &(S16Vec){0,0,0}, &(Vec){0.5, 1.5, 1.5}); Chuckles.addToList(); } else { effect.spawn("Wm_ob_itemget_ring", 0, &(Vec){pos.x + 48.0, pos.y + 32.0, pos.z}, &(S16Vec){0,0,0}, &(Vec){0.5, 1.5, 1.5}); Knuckles.addToList(); } } if (this->chrAnimation.getCurrentFrame() == 64.0) { if (topHurts) { if (this->direction == 1) { SpawnEffect("Wm_en_hit", 0, &(Vec){pos.x - 38.0, pos.y + 16.0, pos.z}, &(S16Vec){0,0,0}, &(Vec){1.0, 1.0, 1.0}); SpawnEffect("Wm_en_hanapetal", 0, &(Vec){pos.x - 38.0, pos.y + 16.0, pos.z}, &(S16Vec){0,0,0}, &(Vec){2.0, 2.0, 2.0}); Chuckles.removeFromList(); } else { SpawnEffect("Wm_en_hit", 0, &(Vec){pos.x + 38.0, pos.y + 16.0, pos.z}, &(S16Vec){0,0,0}, &(Vec){1.0, 1.0, 1.0}); SpawnEffect("Wm_en_hanapetal", 0, &(Vec){pos.x + 38.0, pos.y + 16.0, pos.z}, &(S16Vec){0,0,0}, &(Vec){2.0, 2.0, 2.0}); Knuckles.removeFromList(); } MapSoundPlayer(SoundRelatedClass, SE_OBJ_WOOD_BOX_BREAK, 1); topHurts = false; } } if ((this->chrAnimation.getCurrentFrame() > 34.0) && (speed.y == 0)) { speed.x = 0.0f; } if ((this->chrAnimation.isAnimationDone()) && (speed.y == 0.0)) { bindAnimChr_and_setUpdateRate("c18_DIVING_STEAL_R", 1, 0.0, 1.0); slowDown = true; } bool ret = calculateTileCollisions(); } void daSamurshai::endState_Uppercut() { slowDown = false; } /////////////// // SpinAttack State /////////////// void daSamurshai::beginState_SpinAttack() { bindAnimChr_and_setUpdateRate("c18_NORMAL_STEAL_R", 1, 0.0, 1.0); } void daSamurshai::executeState_SpinAttack() { if((int)this->chrAnimation.getCurrentFrame() == 20) { topHurts = true; PlaySoundAsync(this, SE_EMY_CRASHER_PUNCH); speed.y = 3.0; y_speed_inc = -0.1875; if (this->direction == 1) { Chuckles.addToList(); } else { Knuckles.addToList(); } } if (((int)chrAnimation.getCurrentFrame() > 20) && ((int)this->chrAnimation.getCurrentFrame() < 60)) { scale = (Vec){1.0, 1.0, 1.0}; if (this->direction == 1) { effect.spawn("Wm_mr_spinjump", 0, &(Vec){pos.x - 18.0, pos.y + 16.0, pos.z}, &(S16Vec){0,0,0}, &scale); } else { effect.spawn("Wm_mr_spinjump", 0, &(Vec){pos.x + 18.0, pos.y + 16.0, pos.z}, &(S16Vec){0,0,0}, &scale); } } if((int)this->chrAnimation.getCurrentFrame() == 65) { topHurts = false; PlaySoundAsync(this, SE_EMY_CRASHER_PUNCH); if (this->direction == 1) { Chuckles.removeFromList(); } else { Knuckles.removeFromList(); } } if ((this->chrAnimation.isAnimationDone()) && (speed.y == 0.0)) { walkStateIsCharging = false; doStateChange(&StateID_Walk); } bool ret = calculateTileCollisions(); } void daSamurshai::endState_SpinAttack() { } /////////////// // Damage State /////////////// void daSamurshai::beginState_Damage() { bindAnimChr_and_setUpdateRate("c18_L_DMG_F_1_R", 1, 0.0, 1.0); this->max_speed.x = 0; this->speed.x = 0; this->x_speed_inc = 0; this->max_speed.y = -2.0; this->speed.y = -2.0; this->y_speed_inc = -0.1875; this->timer = 0; this->isDown = 1; Chuckles.removeFromList(); Knuckles.removeFromList(); aPhysics.removeFromList(); SpawnEffect("Wm_ob_switch", 0, &(Vec){pos.x, pos.y + 16.0, pos.z}, &(S16Vec){0,0,0}, &(Vec){1.0, 1.0, 1.0}); MapSoundPlayer(SoundRelatedClass, SE_BOSS_CMN_DAMAGE_DEF, 1); } void daSamurshai::executeState_Damage() { calculateTileCollisions(); effect.spawn("Wm_en_spindamage", 0, &(Vec){pos.x, pos.y + 40.0, 0}, &(S16Vec){0,0,0}, &(Vec){1.0, 1.0, 1.0}); if (this->chrAnimation.isAnimationDone()) { if (timer == 0) { bindAnimChr_and_setUpdateRate("c18_L_DMG_F_3_R", 1, 0.0, 1.0); timer = 1; } else if (timer == 1) { bindAnimChr_and_setUpdateRate("c18_L_DMG_F_4_R", 1, 0.0, 1.0); timer = 2; } else if (timer == 2) { walkStateIsCharging = true; amountCharged = 0.0f; doStateChange(&StateID_Walk); } } } void daSamurshai::endState_Damage() { aPhysics.addToList(); this->isDown = 0; this->rot.y = (direction) ? 0xD800 : 0x2800; } /////////////// // Outro State /////////////// void daSamurshai::beginState_Outro() { bindAnimChr_and_setUpdateRate("c18_SP_BLOCK_R", 1, 0.0, 1.0); OutroSetup(this); aPhysics.removeFromList(); this->max_speed.x = 0; this->speed.x = 0; this->x_speed_inc = 0; this->max_speed.y = -2.0; this->speed.y = -2.0; this->y_speed_inc = -0.1875; this->timer = 0; this->isDown = 1; Chuckles.removeFromList(); Knuckles.removeFromList(); MapSoundPlayer(SoundRelatedClass, SE_BOSS_CMN_DAMAGE_LAST, 1); } void daSamurshai::executeState_Outro() { calculateTileCollisions(); if (this->dying == 1) { if (this->timer > 180) { ExitStage(WORLD_MAP, 0, BEAT_LEVEL, MARIO_WIPE); } if (this->timer == 60) { PlayerVictoryCries(this); } this->timer += 1; return; } if ((chrAnimation.getCurrentFrame() == 41.0) || (chrAnimation.getCurrentFrame() == 62.0)) { SpawnEffect("Wm_en_landsmoke_s", 0, &(Vec){pos.x, pos.y - 8.0, pos.z + 500.0}, &(S16Vec){0,0,0}, &(Vec){1.0, 1.0, 1.0}); } if (chrAnimation.isAnimationDone()) { SpawnEffect("Wm_ob_cmnshotstar", 0, &(Vec){pos.x + 8.0, pos.y - 8.0, pos.z + 500.0}, &(S16Vec){0,0,0}, &(Vec){1.75, 1.75, 1.75}); SpawnEffect("Wm_mr_wirehit_hit", 0, &(Vec){pos.x + 8.0, pos.y, pos.z + 500.0}, &(S16Vec){0,0,0}, &(Vec){1.0, 1.0, 1.0}); MapSoundPlayer(SoundRelatedClass, STRM_BGM_SHIRO_BOSS_CLEAR, 1); BossGoalForAllPlayers(); this->dying = 1; this->timer = 0; } this->timer += 1; } void daSamurshai::endState_Outro() { } bool daSamurshai::isNearWall() { // back up our current settings VEC3 savePos = pos; VEC3 saveSpeed = speed; int saveDirection = direction; float checkLeft = (direction == 0) ? 8.0f : 104.0f; float checkRight = (direction == 0) ? 104.0f : 8.0f; bool result = false; speed.x = -0.1f; speed.y = 0.0f; pos.x = savePos.x - checkLeft; direction = 1; // left if (collMgr.calculateAdjacentCollision()) result = true; speed.x = 0.1f; speed.y = 0.0f; pos.x = savePos.x + checkRight; direction = 0; // right if (collMgr.calculateAdjacentCollision()) result = true; // restore our settings pos = savePos; speed = saveSpeed; direction = saveDirection; return result; }