Path: blob/master/SonicMania/Objects/SSZ/MetalSonic.c
338 views
// ---------------------------------------------------------------------1// RSDK Project: Sonic Mania2// Object Description: MetalSonic Object3// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges4// Decompiled by: Rubberduckycooly & RMGRich5// ---------------------------------------------------------------------67#include "Game.h"89ObjectMetalSonic *MetalSonic;1011void MetalSonic_Update(void)12{13RSDK_THIS(MetalSonic);1415if (self->invincibilityTimer)16self->invincibilityTimer--;1718RSDK.ProcessAnimation(&self->metalSonicAnimator);19RSDK.ProcessAnimation(&self->boosterAnimator);2021StateMachine_Run(self->state);2223if (MetalSonic->invincibilityTimerPanel > 0)24MetalSonic->invincibilityTimerPanel--;2526#if MANIA_USE_PLUS27foreach_active(StarPost, post) { post->bonusStageID = 0; }28#endif29}3031void MetalSonic_LateUpdate(void) {}3233void MetalSonic_StaticUpdate(void) {}3435void MetalSonic_Draw(void)36{37RSDK_THIS(MetalSonic);3839Vector2 drawPos;40drawPos.x = self->position.x;41drawPos.y = self->position.y;42if (self->position.x < 0x8000000)43drawPos.x += 0xE000000;44else45drawPos.x -= 0xE000000;4647if (self->invincibilityTimer & 1) {48RSDK.CopyPalette(2, 240, 0, 240, 8);4950RSDK.DrawSprite(&self->boosterAnimator, &drawPos, false);51RSDK.DrawSprite(&self->metalSonicAnimator, &drawPos, false);52RSDK.DrawSprite(&self->boosterAnimator, NULL, false);53RSDK.DrawSprite(&self->metalSonicAnimator, NULL, false);5455RSDK.CopyPalette(1, 240, 0, 240, 8);56}57else {58RSDK.DrawSprite(&self->boosterAnimator, &drawPos, false);59RSDK.DrawSprite(&self->metalSonicAnimator, &drawPos, false);60RSDK.DrawSprite(&self->boosterAnimator, NULL, false);61RSDK.DrawSprite(&self->metalSonicAnimator, NULL, false);62}63}6465void MetalSonic_Create(void *data)66{67RSDK_THIS(MetalSonic);6869if (!SceneInfo->inEditor) {70if (globals->gameMode == MODE_TIMEATTACK) {71destroyEntity(self);72}73else {74Zone->autoScrollSpeed = 0;75self->active = ACTIVE_BOUNDS;76self->drawFX = FX_FLIP | FX_ROTATE;77self->visible = false;78self->updateRange.x = 0x800000;79self->updateRange.y = 0x800000;80self->tileCollisions = TILECOLLISION_DOWN;81self->collisionLayers = Zone->collisionLayers;8283RSDK.SetSpriteAnimation(MetalSonic->aniFrames, 0, &self->metalSonicAnimator, true, 0);84self->drawGroup = Zone->objectDrawGroup[0];85self->state = MetalSonic_State_SetupArena;86}87}88}8990void MetalSonic_StageLoad(void)91{92MetalSonic->aniFrames = RSDK.LoadSpriteAnimation("SSZ2/MetalSonic.bin", SCOPE_STAGE);9394MetalSonic->hitboxHover.left = -8;95MetalSonic->hitboxHover.top = -8;96MetalSonic->hitboxHover.right = 8;97MetalSonic->hitboxHover.bottom = 8;9899MetalSonic->hitboxDash.left = -16;100MetalSonic->hitboxDash.top = -8;101MetalSonic->hitboxDash.right = 16;102MetalSonic->hitboxDash.bottom = 8;103104MetalSonic->sfxHit = RSDK.GetSfx("Stage/BossHit.wav");105MetalSonic->sfxExplosion2 = RSDK.GetSfx("Stage/Explosion2.wav");106MetalSonic->sfxExplosion3 = RSDK.GetSfx("Stage/Explosion3.wav");107MetalSonic->sfxRumble = RSDK.GetSfx("Stage/Rumble.wav");108MetalSonic->sfxJump2 = RSDK.GetSfx("Stage/Jump2.wav");109MetalSonic->sfxSpecialRing = RSDK.GetSfx("Global/SpecialRing.wav");110MetalSonic->sfxMSElecPulse = RSDK.GetSfx("SSZ2/MSElecPulse.wav");111MetalSonic->sfxMSBall = RSDK.GetSfx("SSZ2/MSBall.wav");112MetalSonic->sfxMSFireball = RSDK.GetSfx("SSZ2/MSFireball.wav");113MetalSonic->sfxBeep3 = RSDK.GetSfx("Stage/Beep3.wav");114MetalSonic->sfxBeep4 = RSDK.GetSfx("Stage/Beep4.wav");115MetalSonic->sfxRockemSockem = RSDK.GetSfx("Stage/RockemSockem.wav");116MetalSonic->sfxMSShoot = RSDK.GetSfx("SSZ2/MSShoot.wav");117MetalSonic->sfxMSChargeFire = RSDK.GetSfx("SSZ2/MSChargeFire.wav");118#if MANIA_USE_PLUS119MetalSonic->sfxMSTransform = RSDK.GetSfx("SSZ2/MSTransform.wav");120MetalSonic->sfxTransform2 = RSDK.GetSfx("Stage/Transform2.wav");121#endif122}123124void MetalSonic_HandleStageWrap(void)125{126RSDK_THIS(MetalSonic);127128EntityPlayer *player = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);129EntityCamera *camera = RSDK_GET_ENTITY(SLOT_CAMERA1, Camera);130131#if !MANIA_USE_PLUS132EntityMetalSonic *marker = RSDK_GET_ENTITY(SceneInfo->entitySlot + 1, MetalSonic);133EntityPlatform *wall = RSDK_GET_ENTITY(SceneInfo->entitySlot + 2, Platform);134if (player->position.y < marker->position.y && !player->collisionPlane) {135Zone->cameraBoundsT[0] = (marker->position.y >> 16) + 16 - ScreenInfo->size.y;136Zone->cameraBoundsB[0] = (marker->position.y >> 16) + 16;137Zone->deathBoundary[0] = (marker->position.y >> 16) + 16;138marker->position.y = -0x200000;139140for (int32 i = 0; i < PLAYER_COUNT; ++i) {141Zone->cameraBoundsL[i] = (wall->position.x >> 16) - 95;142Zone->cameraBoundsR[i] = (wall->position.x >> 16) + 392;143Zone->playerBoundActiveL[i] = true;144Zone->playerBoundActiveR[i] = true;145}146147self->timer = 59;148self->targetPos.x = 0x9100000;149self->targetPos.y = 0x23400000;150151int32 anim = MS_ANI_IDLE;152if (self->position.x >= 0x9100000) {153if (self->direction != FLIP_X) {154self->direction = FLIP_X;155anim = MS_ANI_HOVERTURN;156}157else {158anim = MS_ANI_HOVER;159}160}161else if (self->direction) {162self->direction = FLIP_NONE;163anim = MS_ANI_HOVERTURN;164}165else {166anim = MS_ANI_HOVER;167}168169RSDK.SetSpriteAnimation(MetalSonic->aniFrames, anim, &self->metalSonicAnimator, true, 0);170RSDK.SetSpriteAnimation(MetalSonic->aniFrames, MS_ANI_BOOSTER_WEAK, &self->boosterAnimator, false, 0);171self->state = MetalSonic_State_SetupSpikeWall;172}173#endif174175if (camera->position.x < 0xF000000) {176if (camera->position.x <= 0x1000000) {177player->position.x += 0xE000000;178self->position.x += 0xE000000;179camera->position.x += 0xE000000;180camera->center.x += 0xE00;181MetalSonic_ProcessBGParallax(-0xE0000);182183#if MANIA_USE_PLUS184if (self->classID == GigaMetal->classID) {185camera->boundsL += 0xE00;186camera->boundsR += 0xE00;187Zone->cameraBoundsL[0] += 0xE00;188Zone->cameraBoundsR[0] += 0xE00;189Zone->playerBoundsL[0] += 0xE000000;190Zone->playerBoundsR[0] += 0xE000000;191}192#endif193194foreach_active(MSOrb, orb) { orb->position.x += 0xE000000; }195196#if MANIA_USE_PLUS197foreach_active(MSBomb, bomb) { bomb->position.x += 0xE000000; }198#endif199200foreach_active(Ring, ring) { ring->position.x += 0xE000000; }201foreach_active(Spring, spring) { spring->position.x += 0xE000000; }202foreach_active(Spikes, spikes) { spikes->position.x += 0xE000000; }203foreach_active(Firework, firework) { firework->position.x += 0xE000000; }204foreach_active(EggPrison, prison) { prison->position.x += 0xE000000; }205206foreach_active(SSZSpotlight, spotlight)207{208spotlight->position.x += 0xE000000;209spotlight->originPos.x += 0xE000000;210}211212foreach_active(ImageTrail, trail)213{214trail->position.x += 0xE000000;215trail->currentPos.x += 0xE000000;216for (int32 i = 0; i < IMAGETRAIL_TRACK_COUNT; ++i) trail->statePos[i].x += 0xE000000;217}218219foreach_active(Platform, platform)220{221platform->position.x += 0xE000000;222platform->centerPos.x += 0xE000000;223platform->drawPos.x += 0xE000000;224}225226for (int32 i = 1; i < Player->playerCount; ++i) {227RSDK_GET_ENTITY(i, Player)->position.x += 0xE000000;228}229}230}231else {232player->position.x -= 0xE000000;233self->position.x -= 0xE000000;234camera->position.x -= 0xE000000;235camera->center.x -= 0xE00;236MetalSonic_ProcessBGParallax(0xE0000);237238#if MANIA_USE_PLUS239if (self->classID == GigaMetal->classID) {240camera->boundsL -= 0xE00;241camera->boundsR -= 0xE00;242Zone->cameraBoundsL[0] -= 0xE00;243Zone->cameraBoundsR[0] -= 0xE00;244Zone->playerBoundsL[0] -= 0xE000000;245Zone->playerBoundsR[0] -= 0xE000000;246}247#endif248249foreach_active(MSOrb, orb) { orb->position.x -= 0xE000000; }250251#if MANIA_USE_PLUS252foreach_active(MSBomb, bomb) { bomb->position.x -= 0xE000000; }253254#endif255foreach_active(Ring, ring) { ring->position.x -= 0xE000000; }256foreach_active(Spring, spring) { spring->position.x -= 0xE000000; }257foreach_active(Spikes, spikes) { spikes->position.x -= 0xE000000; }258foreach_active(Firework, firework) { firework->position.x -= 0xE000000; }259foreach_active(EggPrison, prison) { prison->position.x -= 0xE000000; }260261foreach_active(SSZSpotlight, spotlight)262{263spotlight->position.x -= 0xE000000;264spotlight->originPos.x -= 0xE000000;265}266267foreach_active(ImageTrail, trail)268{269trail->position.x -= 0xE000000;270trail->currentPos.x -= 0xE000000;271for (int32 i = 0; i < IMAGETRAIL_TRACK_COUNT; ++i) trail->statePos[i].x -= 0xE000000;272}273274foreach_active(Platform, platform)275{276platform->position.x -= 0xE000000;277platform->centerPos.x -= 0xE000000;278platform->drawPos.x -= 0xE000000;279}280281for (int32 i = 1; i < Player->playerCount; ++i) {282RSDK_GET_ENTITY(i, Player)->position.x -= 0xE000000;283}284}285}286287void MetalSonic_ProcessBGParallax(int32 mult)288{289for (int32 i = 0; i < 2; ++i) {290TileLayer *background = RSDK.GetTileLayer(i);291for (int32 s = 0; s < background->scrollInfoCount; ++s) {292background->scrollInfo[s].scrollPos += mult * background->scrollInfo[s].parallaxFactor;293}294}295296TileLayer *tower = RSDK.GetTileLayer(2);297tower->scrollPos += mult * tower->parallaxFactor;298299foreach_active(EggTower, eggTower) { eggTower->rotationX += (mult >> 8); }300}301302void MetalSonic_HandleVelocity(void)303{304RSDK_THIS(MetalSonic);305306int32 angle = RSDK.ATan2((self->targetPos.x - self->position.x) >> 16, (self->targetPos.y - self->position.y) >> 16);307int32 ang = 2 * angle - self->angle;308309if (abs(ang) >= abs(ang - 0x200)) {310if (abs(ang - 0x200) < abs(ang + 0x200))311angle = ang - 0x200;312else313angle = ang + 0x200;314}315else {316if (abs(ang) < abs(ang + 0x200))317angle = ang;318else319angle = ang + 0x200;320}321322self->angle = (angle / 18 + self->angle) & 0x1FF;323324self->velocity.x = RSDK.Cos512(self->angle) << 9;325self->velocity.y = RSDK.Sin512(self->angle) << 9;326}327328void MetalSonic_HandleAnimDir(void)329{330RSDK_THIS(MetalSonic);331332EntityPlayer *player1 = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);333334if (self->metalSonicAnimator.animationID == MS_ANI_HOVERTURN) {335if (self->metalSonicAnimator.frameID == self->metalSonicAnimator.frameCount - 1)336RSDK.SetSpriteAnimation(MetalSonic->aniFrames, MS_ANI_HOVER, &self->metalSonicAnimator, true, 0);337}338else if (self->position.x <= player1->position.x) {339if (self->direction == FLIP_X) {340self->direction = FLIP_NONE;341RSDK.SetSpriteAnimation(MetalSonic->aniFrames, MS_ANI_HOVERTURN, &self->metalSonicAnimator, true, 0);342}343}344else if (self->direction == FLIP_NONE) {345self->direction = FLIP_X;346RSDK.SetSpriteAnimation(MetalSonic->aniFrames, MS_ANI_HOVERTURN, &self->metalSonicAnimator, true, 0);347}348}349350#if !MANIA_USE_PLUS351void MetalSonic_CheckPlayerCollisions(void)352{353RSDK_THIS(MetalSonic);354355foreach_active(Player, player)356{357if (!self->invincibilityTimer) {358Hitbox *hitbox = self->metalSonicAnimator.animationID == MS_ANI_FLY ? &MetalSonic->hitboxDash : &MetalSonic->hitboxHover;359360if (Player_CheckBadnikTouch(player, self, hitbox) && Player_CheckBossHit(player, self)) {361if (player->velocity.x < 0)362player->velocity.x >>= 2;363364player->velocity.x >>= 1;365player->velocity.y >>= 1;366player->velocity.x += self->velocity.x;367player->velocity.y += self->velocity.y;368player->groundVel = player->velocity.x;369370MetalSonic_Hit();371}372}373}374}375376void MetalSonic_Hit(void)377{378RSDK_THIS(MetalSonic);379380if (!--self->health) {381self->timer = 180;382SceneInfo->timeEnabled = false;383self->velocity.y = -0x1800;384Player_GiveScore(RSDK_GET_ENTITY(SLOT_PLAYER1, Player), 1000);385386RSDK.SetSpriteAnimation(MetalSonic->aniFrames, MS_ANI_DEFEATED, &self->metalSonicAnimator, false, 0);387RSDK.SetSpriteAnimation(-1, MS_ANI_BOOSTER_INTRO, &self->boosterAnimator, false, 0);388self->drawFX |= FX_ROTATE;389self->state = MetalSonic_State_Explode;390}391else {392self->invincibilityTimer = 48;393RSDK.PlaySfx(MetalSonic->sfxHit, false, 0xFF);394}395}396397void MetalSonic_Explode(void)398{399RSDK_THIS(MetalSonic);400401if (!(Zone->timer & 7)) {402RSDK.PlaySfx(MetalSonic->sfxExplosion2, false, 0xFF);403404if (!(Zone->timer & 0xF)) {405int32 x = self->position.x + (RSDK.Rand(-19, 20) << 16);406int32 y = self->position.y + (RSDK.Rand(-24, 25) << 16);407408EntityExplosion *explosion = CREATE_ENTITY(Explosion, INT_TO_VOID((RSDK.Rand(0, 256) > 192) + EXPLOSION_BOSS), x, y);409explosion->drawGroup = Zone->objectDrawGroup[1] + 2;410}411}412}413#endif414415void MetalSonic_State_SetupArena(void)416{417RSDK_THIS(MetalSonic);418419if (++self->timer >= 8) {420self->timer = 0;421422Zone->playerBoundActiveL[0] = true;423Zone->playerBoundActiveR[0] = true;424425Zone->cameraBoundsL[0] = (self->position.x >> 16) - ScreenInfo->center.x;426Zone->cameraBoundsR[0] = (self->position.x >> 16) + ScreenInfo->center.x;427Zone->cameraBoundsT[0] = (self->position.y >> 16) - ScreenInfo->size.y + 52;428Zone->cameraBoundsB[0] = (self->position.y >> 16) + 52;429430self->state = MetalSonic_State_AwaitPlayer;431}432}433434void MetalSonic_State_AwaitPlayer(void)435{436RSDK_THIS(MetalSonic);437438EntityPlayer *player1 = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);439440if (player1->position.x > self->position.x) {441Music_FadeOut(0.0125);442self->state = MetalSonic_State_WaitForHologram;443}444}445446void MetalSonic_State_WaitForHologram(void)447{448RSDK_THIS(MetalSonic);449450foreach_active(MSHologram, hologram)451{452if (hologram->state == MSHologram_State_Destroyed && hologram->timer == 320) {453#if MANIA_USE_PLUS454Music_ClearMusicStack();455#endif456Music_PlayTrack(TRACK_METALSONIC);457RSDK.PlaySfx(MetalSonic->sfxMSFireball, false, 255);458459self->position.y += 0x600000;460self->velocity.y = -0x80000;461self->visible = true;462RSDK.SetSpriteAnimation(MetalSonic->aniFrames, MS_ANI_ENTERPANEL, &self->metalSonicAnimator, false, 6);463RSDK.SetSpriteAnimation(MetalSonic->aniFrames, MS_ANI_BOOSTER_INTRO, &self->boosterAnimator, false, 0);464465self->direction = FLIP_X;466self->metalSonicAnimator.speed = 0;467self->active = ACTIVE_NORMAL;468self->state = MetalSonic_State_Appear;469Camera_ShakeScreen(0, 6, 6);470471foreach_break;472}473}474}475476void MetalSonic_State_Appear(void)477{478RSDK_THIS(MetalSonic);479480self->velocity.y += 0x2000;481self->position.y += self->velocity.y;482483if (self->velocity.y >= 0) {484RSDK.SetSpriteAnimation(MetalSonic->aniFrames, MS_ANI_HOVERTURN, &self->metalSonicAnimator, false, 3);485RSDK.SetSpriteAnimation(-1, 0, &self->boosterAnimator, false, 0);486487self->velocity.x = 0x18000;488self->onGround = false;489self->state = MetalSonic_State_Land;490}491}492493void MetalSonic_State_Land(void)494{495RSDK_THIS(MetalSonic);496497self->velocity.y += 0x2000;498self->outerBox = RSDK.GetHitbox(&self->metalSonicAnimator, 0);499self->innerBox = RSDK.GetHitbox(&self->metalSonicAnimator, 1);500501RSDK.ProcessObjectMovement(self, self->outerBox, self->innerBox);502if (self->onGround) {503RSDK.SetSpriteAnimation(MetalSonic->aniFrames, MS_ANI_TAUNT, &self->metalSonicAnimator, false, 0);504self->state = MetalSonic_State_Taunt;505self->metalSonicAnimator.speed = 0;506self->direction = FLIP_NONE;507}508}509510void MetalSonic_State_Taunt(void)511{512RSDK_THIS(MetalSonic);513514if (++self->timer == 60) {515self->timer = 0;516self->metalSonicAnimator.speed = 1;517self->state = MetalSonic_State_GetReady;518}519}520521void MetalSonic_State_GetReady(void)522{523RSDK_THIS(MetalSonic);524525if (self->metalSonicAnimator.frameID == self->metalSonicAnimator.frameCount - 1) {526RSDK.SetSpriteAnimation(MetalSonic->aniFrames, MS_ANI_READY, &self->metalSonicAnimator, false, 0);527self->state = MetalSonic_State_Ready;528}529}530531void MetalSonic_State_Ready(void)532{533RSDK_THIS(MetalSonic);534535if (++self->timer == 60) {536self->timer = 0;537RSDK.SetSpriteAnimation(MetalSonic->aniFrames, MS_ANI_BOOSTER_WEAK, &self->boosterAnimator, false, 0);538self->state = MetalSonic_State_Start;539540Vector2 size;541RSDK.GetLayerSize(Zone->fgLayer[0], &size, true);542Zone->cameraBoundsR[0] = size.x;543Zone->cameraBoundsT[0] = 0;544}545}546547void MetalSonic_State_Start(void)548{549RSDK_THIS(MetalSonic);550551if (++self->timer == 90) {552self->timer = 0;553Zone->cameraBoundsL[0] = 0;554555RSDK.SetSpriteAnimation(MetalSonic->aniFrames, MS_ANI_BALLATTACK, &self->metalSonicAnimator, false, 0);556self->velocity.x = 0x18000;557self->velocity.y = -0x60000;558RSDK.PlaySfx(MetalSonic->sfxJump2, false, 255);559560self->state = MetalSonic_State_EnterHoverMode;561}562}563564void MetalSonic_State_EnterHoverMode(void)565{566RSDK_THIS(MetalSonic);567568EntityPlayer *player1 = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);569570self->position.x += self->velocity.x;571self->position.y += self->velocity.y;572self->velocity.y += 0x3800;573574if (self->velocity.y >= 0) {575RSDK.SetSpriteAnimation(-1, 0, &self->boosterAnimator, false, 0);576RSDK.SetSpriteAnimation(MetalSonic->aniFrames, MS_ANI_BOOSTER_WEAK, &self->boosterAnimator, false, 0);577RSDK.SetSpriteAnimation(MetalSonic->aniFrames, MS_ANI_HOVERTURN, &self->metalSonicAnimator, false, 6);578self->metalSonicAnimator.speed = 0;579580self->targetPos.x = player1->position.x;581self->targetPos.y = player1->position.y;582self->velocity.x = 0;583self->velocity.y = 0;584self->attackTimer = 240;585self->state = MetalSonic_State_Hovering;586}587}588589void MetalSonic_State_Hovering(void)590{591RSDK_THIS(MetalSonic);592593EntityPlayer *player1 = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);594595if (--self->timer <= 0) {596self->timer = 60;597int32 angle = RSDK.Rand(0, 256);598int32 power = RSDK.Rand(64, 97) << 8;599600self->targetPos.x = (power + (power >> 2)) * RSDK.Cos256(angle);601self->targetPos.y = power * RSDK.Sin256(angle);602}603604self->targetPos.x += player1->position.x;605self->targetPos.y += player1->position.y;606607MetalSonic_HandleVelocity();608MetalSonic_HandleAnimDir();609610if (!self->onScreen) {611if (self->velocity.x <= 0) {612if (player1->velocity.x < self->targetVelocity.x)613self->targetVelocity.x = player1->velocity.x;614615int32 dist = (self->targetPos.x - self->position.x) >> 5;616if (dist < self->targetVelocity.x)617self->targetVelocity.x = dist;618619if (self->position.x < player1->position.x + 244) {620if (player1->velocity.x < 0) {621if (self->targetVelocity.x < 2 * player1->velocity.x) {622self->hoverVelocity.x = 2 * player1->velocity.x;623self->targetVelocity.x = 2 * player1->velocity.x;624}625}626}627}628else {629if (player1->velocity.x > self->targetVelocity.x)630self->targetVelocity.x = player1->velocity.x;631632int32 dist = (self->targetPos.x - self->position.x) >> 5;633if (dist > self->targetVelocity.x)634self->targetVelocity.x = dist;635636if (self->position.x > player1->position.x - 244) {637if (player1->velocity.x > 0) {638if (self->targetVelocity.x > 2 * player1->velocity.x) {639self->hoverVelocity.x = 2 * player1->velocity.x;640self->targetVelocity.x = 2 * player1->velocity.x;641}642}643}644}645646if (self->velocity.y <= 0) {647if (player1->velocity.y < self->targetVelocity.y)648self->targetVelocity.y = player1->velocity.y;649650int32 dist = (self->targetPos.y - self->position.y) >> 5;651if (dist < self->targetVelocity.y)652self->targetVelocity.y = dist;653654if (self->position.y < player1->position.y + 152) {655if (player1->velocity.y < 0) {656if (self->targetVelocity.y < 2 * player1->velocity.y) {657self->hoverVelocity.y = 2 * player1->velocity.y;658self->targetVelocity.y = 2 * player1->velocity.y;659}660}661}662}663else {664if (player1->velocity.y > self->targetVelocity.y)665self->targetVelocity.y = player1->velocity.y;666667int32 dist = (self->targetPos.y - self->position.y) >> 5;668if (dist > self->targetVelocity.y)669self->targetVelocity.y = dist;670671if (self->position.y > player1->position.y - 152) {672if (player1->velocity.y > 0) {673if (self->targetVelocity.y > 2 * player1->velocity.y) {674self->hoverVelocity.y = 2 * player1->velocity.y;675self->targetVelocity.y = 2 * player1->velocity.y;676}677}678}679}680681self->attackTimer--;682if (self->attackTimer < 4)683self->attackTimer = 4;684}685else {686self->targetVelocity.x = player1->velocity.x;687self->targetVelocity.y = player1->velocity.y;688self->attackTimer--;689}690691if (self->attackTimer <= 0) {692self->attackType = RSDK.Rand(0, 6);693while ((1 << self->attackType) & MetalSonic->finishedAttacks) self->attackType = RSDK.Rand(0, 6);694695MetalSonic->finishedAttacks |= 1 << self->attackType;696if (MetalSonic->finishedAttacks == 0x3F)697MetalSonic->finishedAttacks = 0;698699self->attackType >>= 1;700701switch (self->attackType) {702default: break;703704case MS_ATTACK_DASH:705if (RSDK.Rand(0, 2) != 0)706self->targetPos.x = (ScreenInfo->size.x + 72) << 16;707else708self->targetPos.x = -0x480000;709self->targetPos.y = ScreenInfo->center.y << 16;710self->state = MetalSonic_State_PrepareAttack;711break;712713case MS_ATTACK_ELECTRIC:714if (player1->velocity.x >= 0) {715self->targetPos.y = 0x200000;716self->targetPos.x = (ScreenInfo->size.x - 32) << 16;717}718else {719self->targetPos.x = 0x200000;720self->targetPos.y = 0x200000;721}722self->state = MetalSonic_State_PrepareAttack;723break;724725case MS_ATTACK_BALL: {726int32 angle = (RSDK.Rand(0, 2) + 3) << 6;727self->targetPos.x = 0xA000 * RSDK.Cos256(angle) + player1->position.x - (ScreenInfo->position.x << 16);728self->targetPos.y = player1->position.y + 0x7000 * RSDK.Sin256(angle) - (ScreenInfo->position.y << 16);729self->state = MetalSonic_State_PrepareAttack;730break;731}732}733}734else {735self->targetPos.x -= player1->position.x;736self->targetPos.y -= player1->position.y;737738if (self->hoverVelocity.x != self->targetVelocity.x) {739if (self->hoverVelocity.x <= self->targetVelocity.x) {740self->hoverVelocity.x += (0xC00 << (self->hoverVelocity.x < 0));741if (self->hoverVelocity.x > self->targetVelocity.x)742self->hoverVelocity.x = self->targetVelocity.x;743}744else {745self->hoverVelocity.x -= (0xC00 << (self->hoverVelocity.x > 0));746if (self->hoverVelocity.x < self->targetVelocity.x)747self->hoverVelocity.x = self->targetVelocity.x;748}749}750751if (self->hoverVelocity.y != self->targetVelocity.y) {752if (self->hoverVelocity.y <= self->targetVelocity.y) {753self->hoverVelocity.y += (0xC00 << (self->hoverVelocity.y < 0));754if (self->hoverVelocity.y > self->targetVelocity.y)755self->hoverVelocity.y = self->targetVelocity.y;756}757else {758self->hoverVelocity.y -= (0xC00 << (self->hoverVelocity.y > 0));759760if (self->hoverVelocity.y < self->targetVelocity.y)761self->hoverVelocity.y = self->targetVelocity.y;762}763}764765self->position.x += self->hoverVelocity.x + (self->velocity.x >> 1) + (self->velocity.x >> 3);766self->position.y += self->hoverVelocity.y + (self->velocity.y >> 1) + (self->velocity.y >> 3);767}768769MetalSonic_HandleStageWrap();770}771772void MetalSonic_State_PrepareAttack(void)773{774RSDK_THIS(MetalSonic);775776EntityPlayer *player1 = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);777778self->targetPos.x += ScreenInfo->position.x << 16;779self->targetPos.y += ScreenInfo->position.y << 16;780MetalSonic_HandleVelocity();781782self->position.x += self->velocity.x;783self->position.y += self->velocity.y;784self->position.x += player1->velocity.x;785self->position.y += player1->velocity.y;786MetalSonic_HandleAnimDir();787788int32 rx = self->position.x - self->targetPos.x;789int32 ry = self->position.y - self->targetPos.y;790self->targetPos.x = self->targetPos.x - (ScreenInfo->position.x << 16);791self->targetPos.y = self->targetPos.y - (ScreenInfo->position.y << 16);792793if ((rx >> 16) * (rx >> 16) + (ry >> 16) * (ry >> 16) < 0x1000) {794self->attackTimer = 0;795self->position.x &= 0xFFFF0000;796self->position.y &= 0xFFFF0000;797self->targetPos.x &= 0xFFFF0000;798self->targetPos.y &= 0xFFFF0000;799self->state = MetalSonic_State_StartAttack;800}801802MetalSonic_HandleStageWrap();803}804805void MetalSonic_State_StartAttack(void)806{807RSDK_THIS(MetalSonic);808809EntityPlayer *player1 = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);810811self->targetPos.x += ScreenInfo->position.x << 16;812self->targetPos.y += ScreenInfo->position.y << 16;813814self->velocity.x = (self->targetPos.x - self->position.x) >> 4;815self->velocity.y = (self->targetPos.y - self->position.y) >> 4;816817if (self->position.x >= self->targetPos.x)818self->velocity.x -= 0x10000;819else820self->velocity.x += 0x10000;821822if (self->position.y >= self->targetPos.y)823self->velocity.y += 0x10000;824else825self->velocity.y += 0x10000;826827self->position.x += self->velocity.x;828self->position.y += self->velocity.y;829self->position.x += player1->velocity.x;830self->position.y += player1->velocity.y;831832uint8 axisReady = 0;833if (self->velocity.x > 0 && self->position.x > self->targetPos.x) {834axisReady = 1;835self->position.x = self->targetPos.x;836}837else if (self->velocity.x < 0 && self->position.x < self->targetPos.x) {838axisReady = 1;839self->position.x = self->targetPos.x;840}841842if (self->velocity.y > 0 && self->position.y > self->targetPos.y) {843++axisReady;844self->position.y = self->targetPos.y;845}846else if (self->velocity.y < 0 && self->position.y < self->targetPos.y) {847++axisReady;848self->position.y = self->targetPos.y;849}850851self->targetPos.x = self->targetPos.x - (ScreenInfo->position.x << 16);852self->targetPos.y = self->targetPos.y - (ScreenInfo->position.y << 16);853MetalSonic_HandleAnimDir();854855if (axisReady == 2) {856switch (self->attackType) {857default: break;858859case MS_ATTACK_DASH:860self->attackTimer = 60;861RSDK.SetSpriteAnimation(MetalSonic->aniFrames, MS_ANI_DASHATTACK, &self->metalSonicAnimator, true, 0);862RSDK.PlaySfx(MetalSonic->sfxMSChargeFire, false, 255);863self->state = MetalSonic_State_SetupDashAttack_Phase1;864break;865866case MS_ATTACK_ELECTRIC:867self->attackTimer = 60;868RSDK.SetSpriteAnimation(MetalSonic->aniFrames, MS_ANI_ELECTRICATTACK, &self->metalSonicAnimator, true, 0);869RSDK.PlaySfx(MetalSonic->sfxMSElecPulse, false, 255);870self->state = MetalSonic_State_SetupElectricAttack_Phase1;871break;872873case MS_ATTACK_BALL:874self->attackTimer = 60;875self->targetPos.x = self->position.x - player1->position.x;876self->targetPos.y = self->position.y - player1->position.y;877RSDK.SetSpriteAnimation(MetalSonic->aniFrames, MS_ANI_BALLATTACK, &self->metalSonicAnimator, true, 0);878RSDK.PlaySfx(MetalSonic->sfxMSBall, false, 255);879self->state = MetalSonic_State_SetupBallAttack_Phase1;880break;881}882}883884MetalSonic_HandleStageWrap();885}886887void MetalSonic_State_SetupBallAttack_Phase1(void)888{889RSDK_THIS(MetalSonic);890891EntityPlayer *player1 = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);892893self->position.x = player1->position.x + self->targetPos.x;894self->position.y = player1->position.y + self->targetPos.y;895896int32 angle = RSDK.ATan2(player1->position.x - self->position.x, player1->position.y - self->position.y);897self->unusedVec1.x = self->position.x + (RSDK.Cos256(angle + 0xC0) << 12);898self->unusedVec1.y = self->position.y + (RSDK.Sin256(angle + 0xC0) << 12);899self->unusedVec2.x = self->position.x + (RSDK.Cos256(angle + 0x40) << 12);900self->unusedVec2.y = self->position.y + (RSDK.Sin256(angle + 0x40) << 12);901self->unusedVec3.x = self->position.x + (RSDK.Cos256(angle + 0x00) << 14);902self->unusedVec3.y = self->position.y + (RSDK.Sin256(angle + 0x00) << 14);903904if (--self->attackTimer <= 0) {905self->unusedVec1.x = -1;906self->targetPos = player1->position;907self->velocity.x = 0xA00 * RSDK.Cos256(angle);908self->velocity.y = 0xA00 * RSDK.Sin256(angle);909RSDK.PlaySfx(Player->sfxPeelRelease, false, 255);910self->attackTimer = 15;911self->state = MetalSonic_State_BallAttack_Phase1;912}913914MetalSonic_HandleStageWrap();915916foreach_active(Player, player)917{918if (Player_CheckCollisionTouch(player, self, &MetalSonic->hitboxHover))919Player_Hurt(player, self);920}921}922923void MetalSonic_State_BallAttack_Phase1(void)924{925RSDK_THIS(MetalSonic);926EntityPlayer *player1 = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);927928self->position.x += self->velocity.x;929self->position.y += self->velocity.y;930931if (!self->onScreen && --self->attackTimer <= 0) {932self->targetPos = player1->position;933self->velocity.x = 0;934self->velocity.y = 0;935self->timer = 0;936self->attackTimer = 150;937RSDK.SetSpriteAnimation(MetalSonic->aniFrames, MS_ANI_HOVER, &self->metalSonicAnimator, true, 0);938self->state = MetalSonic_State_Hovering;939}940941MetalSonic_HandleStageWrap();942943foreach_active(Player, player)944{945if (Player_CheckCollisionTouch(player, self, &MetalSonic->hitboxHover))946Player_Hurt(player, self);947}948}949950void MetalSonic_State_SetupElectricAttack_Phase1(void)951{952RSDK_THIS(MetalSonic);953EntityPlayer *player1 = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);954955self->position.x = self->targetPos.x + (ScreenInfo->position.x << 16);956self->position.y = self->targetPos.y + (ScreenInfo->position.y << 16);957958if (--self->attackTimer <= 0) {959self->targetPos.x = player1->position.x;960self->targetPos.y = player1->position.y;961RSDK.ATan2(self->targetPos.x - self->position.x, self->targetPos.y - self->position.y);962963self->velocity.x = self->position.x < player1->position.x ? 0x40000 : -0x40000;964self->velocity.y = 0x88000;965self->attackTimer = 15;966self->state = MetalSonic_State_ElectricAttack_Phase1;967}968969MetalSonic_HandleStageWrap();970971foreach_active(Player, player)972{973if (Player_CheckCollisionTouch(player, self, &MetalSonic->hitboxHover))974Player_Hurt(player, self);975}976}977978void MetalSonic_State_ElectricAttack_Phase1(void)979{980RSDK_THIS(MetalSonic);981982EntityPlayer *player1 = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);983984self->position.x += self->velocity.x;985self->position.y += self->velocity.y;986self->velocity.y -= 0x3800;987988if (self->position.y < player1->position.y && !self->onScreen && --self->attackTimer <= 0) {989self->targetPos = player1->position;990self->velocity.x = 0;991self->velocity.y = 0;992self->timer = 0;993self->attackTimer = 150;994995RSDK.SetSpriteAnimation(MetalSonic->aniFrames, MS_ANI_HOVER, &self->metalSonicAnimator, true, 0);996self->state = MetalSonic_State_Hovering;997}998999MetalSonic_HandleStageWrap();10001001foreach_active(Player, player)1002{1003if (Player_CheckCollisionTouch(player, self, &MetalSonic->hitboxHover))1004Player_Hurt(player, self);1005}1006}10071008void MetalSonic_State_SetupDashAttack_Phase1(void)1009{1010RSDK_THIS(MetalSonic);10111012EntityPlayer *player1 = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);10131014self->position.x = self->targetPos.x + (ScreenInfo->position.x << 16);1015self->position.y = self->targetPos.y + (ScreenInfo->position.y << 16);10161017int32 angle = RSDK.ATan2(player1->position.x - self->position.x, player1->position.y - self->position.y);1018self->unusedVec1.x = self->position.x + (RSDK.Cos256(angle + 0xC0) << 12);1019self->unusedVec1.y = self->position.y + (RSDK.Sin256(angle + 0xC0) << 12);1020self->unusedVec2.x = self->position.x + (RSDK.Cos256(angle + 0x40) << 12);1021self->unusedVec2.y = self->position.y + (RSDK.Sin256(angle + 0x40) << 12);1022self->unusedVec3.x = self->position.x + (RSDK.Cos256(angle + 0x00) << 15);1023self->unusedVec3.y = self->position.y + (RSDK.Sin256(angle + 0x00) << 15);10241025if (--self->attackTimer <= 0) {1026self->unusedVec1.x = -1;1027self->targetPos = player1->position;1028self->velocity.x = 0xC00 * RSDK.Cos256(angle);1029self->velocity.y = 0xC00 * RSDK.Sin256(angle);1030RSDK.PlaySfx(MetalSonic->sfxMSFireball, false, 255);10311032self->attackTimer = 15;1033self->state = MetalSonic_State_DashAttack_Phase1;1034}10351036MetalSonic_HandleStageWrap();10371038foreach_active(Player, player)1039{1040if (Player_CheckCollisionTouch(player, self, &MetalSonic->hitboxHover))1041Player_Hurt(player, self);1042}1043}10441045void MetalSonic_State_DashAttack_Phase1(void)1046{1047RSDK_THIS(MetalSonic);10481049EntityPlayer *player1 = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);10501051self->position.x += self->velocity.x;1052self->position.y += self->velocity.y;10531054bool32 finished = true;1055if (self->velocity.x <= 0) {1056if (self->velocity.x >= 0 || self->position.x >= player1->position.x)1057finished = false;1058}1059else if (self->position.x <= player1->position.x) {1060if (self->velocity.x >= 0 || self->position.x >= player1->position.x)1061finished = false;1062}10631064if (finished) {1065if (!self->onScreen && --self->attackTimer <= 0) {1066self->targetPos = player1->position;1067self->velocity.x = 0;1068self->velocity.y = 0;1069self->timer = 0;1070self->attackTimer = 150;10711072RSDK.SetSpriteAnimation(MetalSonic->aniFrames, MS_ANI_HOVER, &self->metalSonicAnimator, true, 0);1073self->state = MetalSonic_State_Hovering;1074}1075}10761077MetalSonic_HandleStageWrap();10781079foreach_active(Player, player)1080{1081if (Player_CheckCollisionTouch(player, self, &MetalSonic->hitboxHover))1082Player_Hurt(player, self);1083}1084}10851086void MetalSonic_State_EnterPanel(void)1087{1088RSDK_THIS(MetalSonic);10891090int32 velX = self->velocity.x;10911092MetalSonic_HandleVelocity();10931094if (self->velocity.x < 0x20000 && velX >= 0x20000) {1095self->direction = FLIP_X;1096RSDK.SetSpriteAnimation(MetalSonic->aniFrames, MS_ANI_HOVERTURN, &self->metalSonicAnimator, true, 0);1097}1098else if (self->velocity.x > -0x20000 && velX <= -0x20000) {1099self->direction = FLIP_NONE;1100RSDK.SetSpriteAnimation(MetalSonic->aniFrames, MS_ANI_HOVERTURN, &self->metalSonicAnimator, true, 0);1101}11021103++self->timer;1104self->position.x += self->velocity.x;1105self->position.y += self->velocity.y;11061107int32 rx = self->position.x - self->targetPos.x;1108int32 ry = self->position.y - self->targetPos.y;11091110if ((rx >> 16) * (rx >> 16) + (ry >> 16) * (ry >> 16) < 4096 && self->timer > 96) {1111self->timer = 0;1112RSDK.SetSpriteAnimation(-1, 0, &self->boosterAnimator, false, 0);1113self->state = MetalSonic_State_StartPanelSequence;1114}1115}11161117void MetalSonic_State_StartPanelSequence(void)1118{1119RSDK_THIS(MetalSonic);11201121++self->timer;1122self->position.x += (self->targetPos.x - self->position.x) >> 4;1123self->position.y += (self->targetPos.y - self->position.y) >> 4;11241125if (self->timer == 32)1126RSDK.SetSpriteAnimation(MetalSonic->aniFrames, MS_ANI_ENTERPANEL, &self->metalSonicAnimator, true, 0);11271128if (self->timer == 59)1129RSDK.PlaySfx(MetalSonic->sfxSpecialRing, false, 255);11301131if (self->timer == 64) {1132int32 id = 0;1133#if MANIA_USE_PLUS1134for (int32 i = 48; i < 82; i += 2) {1135if (id > 0)1136RSDK.CopyTileLayer(Zone->fgLayer[0], 167, i, Zone->fgLayer[1], 222, 218, 2, 2);11371138RSDK.CopyTileLayer(Zone->fgLayer[0], 169, i, Zone->fgLayer[1], 222, 138, 2, 2);1139RSDK.CopyTileLayer(Zone->fgLayer[0], 171, i, Zone->fgLayer[1], 222, 138, 2, 2);1140RSDK.CopyTileLayer(Zone->fgLayer[0], 173, i, Zone->fgLayer[1], 222, 138, 2, 2);1141RSDK.CopyTileLayer(Zone->fgLayer[0], 175, i, Zone->fgLayer[1], 222, 138, 2, 2);1142RSDK.CopyTileLayer(Zone->fgLayer[0], 177, i, Zone->fgLayer[1], 222, 138, 2, 2);1143RSDK.CopyTileLayer(Zone->fgLayer[0], 179, i, Zone->fgLayer[1], 222, 138, 2, 2);1144++id;1145}1146#else1147for (int32 i = 128; i < 82; i += 2) {1148int32 y = i;1149if (id > 0) {1150y = 2 * id + 128;1151RSDK.CopyTileLayer(Zone->fgLayer[0], 167, i, Zone->fgLayer[1], 222, 218, 2, 2);1152}11531154RSDK.CopyTileLayer(Zone->fgLayer[0], 169, y, Zone->fgLayer[1], 222, 218, 2, 2);1155RSDK.CopyTileLayer(Zone->fgLayer[0], 171, y, Zone->fgLayer[1], 222, 218, 2, 2);1156RSDK.CopyTileLayer(Zone->fgLayer[0], 173, y, Zone->fgLayer[1], 222, 218, 2, 2);1157RSDK.CopyTileLayer(Zone->fgLayer[0], 175, y, Zone->fgLayer[1], 222, 218, 2, 2);1158RSDK.CopyTileLayer(Zone->fgLayer[0], 177, y, Zone->fgLayer[1], 222, 218, 2, 2);1159RSDK.CopyTileLayer(Zone->fgLayer[0], 179, y, Zone->fgLayer[1], 222, 218, 2, 2);1160++id;1161}1162#endif11631164EntityMSPanel *panel = self->panel;1165panel->state = MSPanel_State_Active;11661167self->position = self->targetPos;1168self->timer = 16;1169self->attackTimer = MANIA_USE_PLUS ? 240 : 180;1170self->health = MANIA_USE_PLUS ? 6 : 4;1171self->state = MetalSonic_State_OpenFactoryDoor;1172}1173}11741175void MetalSonic_HandlePanelAttack(void)1176{1177RSDK_THIS(MetalSonic);11781179#if MANIA_USE_PLUS1180if (!RSDK.GetEntityCount(MSBomb->classID, true))1181#endif1182--self->attackTimer;11831184if (self->attackTimer == 60) {1185RSDK.PlaySfx(MetalSonic->sfxMSElecPulse, false, 255);1186self->invincibilityTimer = 60;11871188#if MANIA_USE_PLUS1189EntityFXWaveRing *ring = CREATE_ENTITY(FXWaveRing, self, self->position.x, self->position.y);1190ring->radiusOffset = 24;1191ring->timer = 24;1192ring->r = 0xF0;1193ring->g = 0x80;1194ring->b = 0x00;1195ring->shrinkSpeed = 1;1196#endif1197}11981199if (self->attackTimer <= 0) {1200EntityPlayer *player1 = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);12011202self->attackTimer = 45 * self->health + (MANIA_USE_PLUS ? 195 : 135);1203int32 angle = RSDK.ATan2(player1->position.x - self->position.x, player1->position.y - self->position.y);12041205EntityMSOrb *orb = CREATE_ENTITY(MSOrb, NULL, self->position.x, self->position.y);1206orb->velocity.x = 0x280 * RSDK.Cos256(angle);1207orb->velocity.y = 0x280 * RSDK.Sin256(angle);1208RSDK.PlaySfx(MetalSonic->sfxMSShoot, false, 255);1209}1210}12111212void MetalSonic_State_OpenFactoryDoor(void)1213{1214RSDK_THIS(MetalSonic);12151216++self->timer;12171218MetalSonic_HandlePanelAttack();12191220if (self->timer == 60) {1221foreach_active(MSFactory, factory)1222{1223factory->visible = true;1224factory->state = MSFactory_State_OpeningDoor;1225}12261227self->timer = 0;1228self->state = MetalSonic_State_HandleSilverSonics;1229}1230}12311232void MetalSonic_State_HandleSilverSonics(void)1233{1234RSDK_THIS(MetalSonic);12351236++self->timer;1237MetalSonic_HandlePanelAttack();12381239#if MANIA_USE_PLUS1240if (!RSDK.GetEntityCount(SilverSonic->classID, true) && !RSDK.GetEntityCount(MSBomb->classID, true) && self->timer > 60) {1241#else1242if (!RSDK.GetEntityCount(SilverSonic->classID, true) && self->timer > 60) {1243#endif1244self->timer = 0;1245self->state = MetalSonic_State_OpenFactoryDoor;1246}1247}12481249void MetalSonic_State_PanelExplosion(void)1250{1251RSDK_THIS(MetalSonic);12521253EntityMSPanel *panel = self->panel;12541255self->position.y += 0x8000;1256panel->position.y += 0x8000;12571258if (!self->timer)1259panel->state = MSPanel_State_Explode;12601261if (++self->timer == 104) {1262self->timer = 0;1263panel->state = MSPanel_State_Rumbling;1264self->state = MetalSonic_State_ExitFactory;1265}1266}12671268void MetalSonic_State_ExitFactory(void)1269{1270RSDK_THIS(MetalSonic);12711272if (++self->timer == 60) {1273self->timer = 0;1274RSDK.SetSpriteAnimation(MetalSonic->aniFrames, MS_ANI_HOVERTURN, &self->metalSonicAnimator, false, 3);12751276self->velocity.x = 0x18000;1277self->onGround = false;1278self->state = MetalSonic_State_PrepareFinalChase;1279}1280}12811282void MetalSonic_State_PrepareFinalChase(void)1283{1284RSDK_THIS(MetalSonic);12851286self->velocity.y += 0x2000;12871288self->outerBox = RSDK.GetHitbox(&self->metalSonicAnimator, 0);1289self->innerBox = RSDK.GetHitbox(&self->metalSonicAnimator, 1);1290RSDK.ProcessObjectMovement(self, self->outerBox, self->innerBox);12911292if (self->onGround) {1293RSDK.SetSpriteAnimation(MetalSonic->aniFrames, MS_ANI_READY, &self->metalSonicAnimator, false, 0);1294self->direction = FLIP_NONE;1295self->groundVel = 0;1296}12971298if (++self->timer == 120) {1299EntityFXFade *fade = CREATE_ENTITY(FXFade, INT_TO_VOID(0xF0F0F0), self->position.x, self->position.y);1300fade->speedIn = 256;1301fade->wait = 32;1302fade->speedOut = 8;13031304self->panel->state = StateMachine_None;1305self->timer = 0;1306self->attackTimer = 240;1307self->state = MetalSonic_State_Hovering;13081309foreach_active(Player, player)1310{1311RSDK.PlaySfx(SpeedBooster->sfxSpeedBooster, false, 255);1312player->velocity.x = 0xE0000;1313player->groundVel = 0xE0000;1314player->controlLock = 60;1315player->direction = FLIP_NONE;1316RSDK.SetSpriteAnimation(player->aniFrames, ANI_RUN, &player->animator, false, 0);1317player->state = Player_State_Ground;1318}13191320Vector2 size;1321RSDK.GetLayerSize(Zone->fgLayer[0], &size, true);13221323Zone->cameraBoundsL[0] = 0;1324Zone->cameraBoundsR[0] = size.x;1325Zone->cameraBoundsT[0] = 0;13261327Zone->playerBoundActiveL[0] = false;1328Zone->playerBoundActiveR[0] = false;13291330RSDK.PlaySfx(MetalSonic->sfxExplosion3, false, 255);1331}1332}13331334#if MANIA_USE_PLUS1335void MetalSonic_State_WaitForRuby(void)1336{1337RSDK_THIS(MetalSonic);13381339int32 velX = self->velocity.x;1340MetalSonic_HandleVelocity();13411342if (self->velocity.x < 0x20000 && velX >= 0x20000) {1343self->direction = FLIP_X;1344RSDK.SetSpriteAnimation(MetalSonic->aniFrames, MS_ANI_HOVERTURN, &self->metalSonicAnimator, true, 0);1345}1346else if (self->velocity.x > -0x20000 && velX <= -0x20000) {1347self->direction = FLIP_NONE;1348RSDK.SetSpriteAnimation(MetalSonic->aniFrames, MS_ANI_HOVERTURN, &self->metalSonicAnimator, true, 0);1349}13501351++self->timer;1352self->position.x += self->velocity.x;1353self->position.y += self->velocity.y;1354int32 rx = self->position.x - self->targetPos.x;1355int32 ry = self->position.y - self->targetPos.y;13561357if ((rx >> 16) * (rx >> 16) + (ry >> 16) * (ry >> 16) < 4096 && self->timer > 96) {1358self->timer = 0;1359self->direction = FLIP_NONE;1360self->state = MetalSonic_State_ObtainRuby;1361}1362}13631364void MetalSonic_State_ObtainRuby(void)1365{1366RSDK_THIS(MetalSonic);13671368self->targetPos.y += RSDK.Sin256(4 * Zone->timer) << 8;13691370self->position.x += (self->targetPos.x - self->position.x) >> 4;1371self->position.y += (self->targetPos.y - self->position.y) >> 4;13721373foreach_active(PhantomRuby, ruby)1374{1375int32 rx = (self->position.x - ruby->position.x) >> 16;1376int32 ry = (self->position.y - ruby->position.y) >> 16;13771378if (rx * rx + ry * ry < 0x100) {1379ruby->startPos.x = ruby->position.x;1380ruby->startPos.y = ruby->position.y;1381ruby->state = PhantomRuby_State_Oscillate;1382self->state = MetalSonic_State_Transform;1383RSDK.PlaySfx(MetalSonic->sfxMSTransform, false, 255);1384}1385}1386}13871388void MetalSonic_State_Transform(void)1389{1390RSDK_THIS(MetalSonic);13911392self->position.y -= 0x2000;13931394foreach_active(PhantomRuby, ruby) { ruby->startPos.y -= 0x2000; }13951396if (++self->timer == 30) {1397RSDK.SetSpriteAnimation(MetalSonic->aniFrames, -1, &self->boosterAnimator, true, 0);1398RSDK.SetSpriteAnimation(MetalSonic->aniFrames, MS_ANI_ELECTRICATTACK, &self->metalSonicAnimator, true, 0);1399}14001401int32 timer = MIN(self->timer >> 1, 96);14021403if ((self->timer & 0x1F) == 30) {1404EntityFXWaveRing *ring = CREATE_ENTITY(FXWaveRing, self, self->position.x, self->position.y);1405ring->radiusOffset = timer;1406ring->timer = 24;1407ring->r = 0xF0;1408ring->g = 0x00;1409ring->b = 0xF0;1410ring->shrinkSpeed = 2;1411}14121413if (timer >= 32 && (self->timer & 0xF) == 14) {1414EntityFXWaveRing *ring = CREATE_ENTITY(FXWaveRing, self, self->position.x, self->position.y);1415ring->radiusOffset = timer + 64;1416ring->timer = 24;1417ring->r = 0xF0;1418ring->g = 0xF0;1419ring->b = 0x60;1420ring->shrinkSpeed = 4;1421}14221423if (self->timer == 240) {1424self->timer = 0;1425self->active = ACTIVE_NEVER;14261427EntityFXFade *fxFade = CREATE_ENTITY(FXFade, INT_TO_VOID(0xF0F0F0), self->position.x, self->position.y);1428fxFade->speedIn = 256;1429fxFade->wait = 32;1430fxFade->speedOut = 8;14311432RSDK.PlaySfx(MetalSonic->sfxTransform2, false, 255);1433}1434}14351436void MetalSonic_State_Defeated(void)1437{1438RSDK_THIS(MetalSonic);14391440self->position.x += self->velocity.x;1441self->position.y += self->velocity.y;1442self->velocity.y += 0x3800;1443self->visible ^= true;14441445if (!RSDK.CheckOnScreen(self, NULL)) {1446Music_TransitionTrack(TRACK_STAGE, 0.0125);1447EntityEggPrison *prison = CREATE_ENTITY(EggPrison, INT_TO_VOID(EGGPRISON_FLYING), (ScreenInfo->position.x + ScreenInfo->center.x) << 16,1448(ScreenInfo->position.y - 48) << 16);1449prison->velocity.x = 0x10000;1450prison->active = ACTIVE_NORMAL;1451destroyEntity(self);1452}1453}1454#else1455void MetalSonic_State_SetupSpikeWall(void)1456{1457RSDK_THIS(MetalSonic);14581459MetalSonic_HandleVelocity();14601461self->position.x += self->velocity.x;1462self->position.y += self->velocity.y;14631464MetalSonic_HandleStageWrap();14651466self->timer++;14671468EntityPlatform *wall = NULL;1469EntityPlatform *startWall = NULL;14701471switch (self->timer) {1472case 60: wall = RSDK_GET_ENTITY(SceneInfo->entitySlot + 2, Platform); break;1473case 90: wall = RSDK_GET_ENTITY(SceneInfo->entitySlot + 3, Platform); break;1474case 120: wall = RSDK_GET_ENTITY(SceneInfo->entitySlot + 4, Platform); break;1475case 150: wall = RSDK_GET_ENTITY(SceneInfo->entitySlot + 5, Platform); break;1476case 180: wall = RSDK_GET_ENTITY(SceneInfo->entitySlot + 6, Platform); break;1477case 210: wall = RSDK_GET_ENTITY(SceneInfo->entitySlot + 7, Platform); break;1478case 240: wall = RSDK_GET_ENTITY(SceneInfo->entitySlot + 8, Platform); break;1479case 270: wall = RSDK_GET_ENTITY(SceneInfo->entitySlot + 9, Platform); break;1480case 300:1481startWall = RSDK_GET_ENTITY(SceneInfo->entitySlot + 2, Platform);14821483self->targetPos.x = startWall->position.x + 0x800000;1484self->targetPos.y = (Zone->cameraBoundsB[0] << 16) - 0x340000;1485self->state = MetalSonic_State_FlyToSpikeWall;1486break;1487}14881489if (wall) {1490wall->active = ACTIVE_NORMAL;1491wall->state = MetalSonic_StateWall_Fall;1492}1493}1494void MetalSonic_State_FlyToSpikeWall(void)1495{1496RSDK_THIS(MetalSonic);14971498MetalSonic_HandleVelocity();14991500self->position.x += self->velocity.x;1501self->position.y += self->velocity.y;15021503MetalSonic_HandleAnimDir();15041505int32 rx = self->position.x - self->targetPos.x;1506int32 ry = self->position.y - self->targetPos.y;15071508if ((rx >> 16) * (rx >> 16) + (ry >> 16) * (ry >> 16) < 0x1000) {1509self->attackTimer = 0;1510self->position.x &= 0xFFFF0000;1511self->position.y &= 0xFFFF0000;1512self->targetPos.x &= 0xFFFF0000;1513self->targetPos.y &= 0xFFFF0000;1514self->state = MetalSonic_State_LandNearSpikeWall;1515}15161517MetalSonic_HandleStageWrap();1518}1519void MetalSonic_State_LandNearSpikeWall(void)1520{1521RSDK_THIS(MetalSonic);15221523self->velocity.x = (self->targetPos.x - self->position.x) >> 4;1524self->velocity.y = (self->targetPos.y - self->position.y) >> 4;15251526if (self->position.x >= self->targetPos.x)1527self->velocity.x -= 0x10000;1528else1529self->velocity.x += 0x10000;15301531if (self->position.y >= self->targetPos.y)1532self->velocity.y -= 0x10000;1533else1534self->velocity.y += 0x10000;15351536self->position.x += self->velocity.x;1537self->position.y += self->velocity.y;15381539uint8 axisFinished = 0;1540if (self->velocity.x > 0) {1541if (self->position.x > self->targetPos.x) {1542axisFinished = 1;1543self->position.x = self->targetPos.x;1544}1545}1546else if (self->position.x < self->targetPos.x) {1547axisFinished = 1;1548self->position.x = self->targetPos.x;1549}15501551if (self->velocity.y > 0) {1552if (self->position.y > self->targetPos.y) {1553++axisFinished;1554self->position.y = self->targetPos.y;1555}1556}1557else if (self->position.y < self->targetPos.y) {1558++axisFinished;1559self->position.y = self->targetPos.y;1560}15611562MetalSonic_HandleAnimDir();15631564if (axisFinished == 2) {1565self->velocity.x = 0;1566self->velocity.y = 0;1567RSDK.SetSpriteAnimation(MetalSonic->aniFrames, MS_ANI_TAUNT, &self->metalSonicAnimator, false, 0);1568RSDK.SetSpriteAnimation(-1, 0, &self->boosterAnimator, false, 0);15691570self->direction = FLIP_NONE;1571self->state = MetalSonic_State_Taunt_Phase2;1572}15731574MetalSonic_HandleStageWrap();1575}1576void MetalSonic_State_Taunt_Phase2(void)1577{1578RSDK_THIS(MetalSonic);15791580if (self->metalSonicAnimator.frameID == self->metalSonicAnimator.frameCount - 1) {1581self->timer = 0;1582RSDK.SetSpriteAnimation(MetalSonic->aniFrames, MS_ANI_READY, &self->metalSonicAnimator, false, 0);1583self->state = MetalSonic_State_Ready_Phase2;1584}1585MetalSonic_HandleStageWrap();1586}1587void MetalSonic_State_Ready_Phase2(void)1588{1589RSDK_THIS(MetalSonic);15901591self->timer++;1592if (self->timer == 60) {1593self->timer = 0;1594RSDK.SetSpriteAnimation(MetalSonic->aniFrames, MS_ANI_BOOSTER_WEAK, &self->boosterAnimator, false, 0);1595self->state = MetalSonic_State_StartSpikeWallMovement;15961597Vector2 size;1598RSDK.GetLayerSize(Zone->fgLayer[0], &size, true);1599}16001601MetalSonic_HandleStageWrap();1602}1603void MetalSonic_State_StartSpikeWallMovement(void)1604{1605RSDK_THIS(MetalSonic);16061607self->timer++;1608if (self->timer == 90) {1609int32 slot = SceneInfo->entitySlot;1610RSDK_GET_ENTITY(slot + 2, Platform)->state = MetalSonic_StateWall_Move;1611RSDK_GET_ENTITY(slot + 3, Platform)->state = MetalSonic_StateWall_Move;1612RSDK_GET_ENTITY(slot + 4, Platform)->state = MetalSonic_StateWall_Move;1613RSDK_GET_ENTITY(slot + 5, Platform)->state = MetalSonic_StateWall_Move;1614RSDK_GET_ENTITY(slot + 6, Platform)->state = MetalSonic_StateWall_Move;1615RSDK_GET_ENTITY(slot + 7, Platform)->state = MetalSonic_StateWall_Move;1616RSDK_GET_ENTITY(slot + 8, Platform)->state = MetalSonic_StateWall_Move;1617RSDK_GET_ENTITY(slot + 9, Platform)->state = MetalSonic_StateWall_Move;16181619self->timer = 0;1620RSDK.SetSpriteAnimation(MetalSonic->aniFrames, MS_ANI_HOVER, &self->metalSonicAnimator, false, 0);1621self->state = MetalSonic_State_AccelerateSpikeWall;1622}16231624MetalSonic_HandleStageWrap();1625}1626void MetalSonic_State_AccelerateSpikeWall(void)1627{1628RSDK_THIS(MetalSonic);16291630EntityPlatform *wall = RSDK_GET_ENTITY(SceneInfo->entitySlot + 2, Platform);16311632if (wall->velocity.x >= 0x1C000) {1633Vector2 size;1634RSDK.GetLayerSize(Zone->fgLayer[0], &size, true);16351636for (int32 i = 0; i < PLAYER_COUNT; ++i) {1637Zone->cameraBoundsL[i] = 0;1638Zone->cameraBoundsR[i] = size.x + 0x400;1639Zone->playerBoundActiveL[i] = false;1640Zone->playerBoundActiveL[i] = false;1641}16421643if (wall->velocity.x >= 0x54000) {1644self->health = 8;1645self->attackTimer = 120;1646self->state = MetalSonic_State_Hover_Phase2;1647}1648}16491650self->velocity.x = wall->velocity.x;1651self->position.x += self->velocity.x;1652self->position.y += self->velocity.y;16531654MetalSonic_HandleStageWrap();1655}1656void MetalSonic_State_Hover_Phase2(void)1657{1658RSDK_THIS(MetalSonic);1659EntityPlayer *player1 = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);1660EntityPlatform *wall = RSDK_GET_ENTITY(SceneInfo->entitySlot + 2, Platform);16611662if (player1->position.x <= self->position.x) {1663if (self->velocity.x >= player1->velocity.x - 0x60000) {1664self->velocity.x -= 0xC00;1665}1666else1667self->velocity.x += 0xC00;1668}1669else if (self->velocity.x < 0x60000)1670self->velocity.x += 0xC00;16711672self->position.x += self->velocity.x;1673self->position.y += self->velocity.y;16741675if (RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0, 0x140000, true))1676self->velocity.y = 0;16771678if (self->direction == FLIP_X) {1679self->direction = FLIP_NONE;1680RSDK.SetSpriteAnimation(MetalSonic->aniFrames, MS_ANI_HOVERTURN, &self->metalSonicAnimator, true, 0);1681}16821683MetalSonic_HandleStageWrap();16841685if (self->position.x < wall->position.x + 0x800000)1686self->position.x = wall->position.x + 0x800000;16871688if (--self->attackTimer <= 0 && !player1->blinkTimer) {1689if (self->velocity.x < 0x60000)1690self->velocity.x = 0x60000;1691self->attackTimer = 120;16921693self->attackType = RSDK.Rand(0, 6);1694while ((1 << self->attackType) & MetalSonic->finishedAttacks) self->attackType = RSDK.Rand(0, 6);16951696MetalSonic->finishedAttacks |= 1 << self->attackType;1697if (MetalSonic->finishedAttacks == 0x3F)1698MetalSonic->finishedAttacks = 0;16991700self->attackType >>= 1;1701switch (self->attackType) {1702case MS_ATTACK_DASH:1703RSDK.PlaySfx(MetalSonic->sfxMSFireball, false, 0xFF);17041705RSDK.SetSpriteAnimation(MetalSonic->aniFrames, MS_ANI_DASHATTACK, &self->metalSonicAnimator, false, 0);1706RSDK.SetSpriteAnimation(-1, 0, &self->boosterAnimator, false, 0);1707self->attackTimer = 60;1708self->state = MetalSonic_State_DashAttack_Phase2;1709break;17101711case MS_ATTACK_ELECTRIC:1712RSDK.SetSpriteAnimation(MetalSonic->aniFrames, MS_ANI_ELECTRICATTACK, &self->metalSonicAnimator, true, 0);17131714RSDK.PlaySfx(MetalSonic->sfxMSElecPulse, false, 0xFF);1715self->state = MetalSonic_State_SetupElectricAttack_Phase2;1716break;17171718case MS_ATTACK_BALL:1719self->attackTimer = 60;1720self->targetPos.x = (RSDK.Rand(-3, 7) << 14) + 0x78000;1721self->targetPos.y = -0x80000;17221723RSDK.SetSpriteAnimation(MetalSonic->aniFrames, MS_ANI_BALLATTACK, &self->metalSonicAnimator, true, 0);1724RSDK.PlaySfx(MetalSonic->sfxMSBall, false, 0xFF);1725self->state = MetalSonic_State_SetupBallAttack_Phase2;1726break;1727}1728}17291730MetalSonic_CheckPlayerCollisions();1731}1732void MetalSonic_State_SetupElectricAttack_Phase2(void)1733{1734RSDK_THIS(MetalSonic);17351736EntityPlatform *wall = RSDK_GET_ENTITY(SceneInfo->entitySlot + 2, Platform);17371738if (self->velocity.x < 0xB0000)1739self->velocity.x += 0xC00;17401741self->position.x += self->velocity.x;1742self->position.y += self->velocity.y;17431744if (self->position.y <= (ScreenInfo->center.y + ScreenInfo->position.y) << 16) {1745if (self->velocity.y < 0x10000)1746self->velocity.y += 0x1000;1747}1748else {1749if (self->velocity.y >= -0x10000)1750self->velocity.y -= 0x1000;1751}17521753MetalSonic_HandleStageWrap();17541755if (self->position.x < wall->position.x + 0x410000)1756self->position.x = wall->position.x + 0x410000;17571758if (self->position.x > ((ScreenInfo->size.x + ScreenInfo->position.x) << 16) + 0x400000) {1759self->direction = FLIP_X;1760self->state = MetalSonic_State_StartElectricAttack_Phase2;1761}17621763foreach_active(Player, player)1764{1765if (Player_CheckCollisionTouch(player, self, &MetalSonic->hitboxHover))1766Player_Hurt(player, self);1767}1768}1769void MetalSonic_State_StartElectricAttack_Phase2(void)1770{1771RSDK_THIS(MetalSonic);17721773EntityPlayer *player1 = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);1774EntityPlatform *wall = RSDK_GET_ENTITY(SceneInfo->entitySlot + 2, Platform);17751776self->velocity.x = player1->velocity.x - 0x10000;1777self->position.x += self->velocity.x;1778self->position.y += self->velocity.y;17791780if (self->position.y <= (ScreenInfo->center.y + ScreenInfo->position.y) << 16) {1781if (self->velocity.y < 0x10000)1782self->velocity.y += 0x1000;1783}1784else {1785if (self->velocity.y >= -0x10000)1786self->velocity.y -= 0x1000;1787}17881789MetalSonic_HandleStageWrap();17901791if (self->position.x < wall->position.x + 0x410000)1792self->position.x = wall->position.x + 0x410000;17931794if (self->position.x < ((ScreenInfo->position.x + ScreenInfo->size.x) << 16) - 0x180000) {1795self->attackTimer = 120;1796self->position.x = ((ScreenInfo->position.x + ScreenInfo->size.x) << 16) - 0x180000;1797self->state = MetalSonic_State_ElectricAttack_Phase2;1798}17991800foreach_active(Player, player)1801{1802if (Player_CheckCollisionTouch(player, self, &MetalSonic->hitboxHover))1803Player_Hurt(player, self);1804}1805}1806void MetalSonic_State_ElectricAttack_Phase2(void)1807{1808RSDK_THIS(MetalSonic);1809EntityPlayer *player1 = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);1810EntityPlatform *wall = RSDK_GET_ENTITY(SceneInfo->entitySlot + 2, Platform);18111812self->velocity.x = player1->velocity.x;1813self->position.x = ((ScreenInfo->position.x + ScreenInfo->size.x) << 16) - 0x180000;1814self->position.y += self->velocity.y;18151816if (self->position.y <= (ScreenInfo->center.y + ScreenInfo->position.y) << 16) {1817if (self->velocity.y < 0x10000)1818self->velocity.y += 0x1000;1819}1820else {1821if (self->velocity.y >= -0x10000)1822self->velocity.y -= 0x1000;1823}18241825MetalSonic_HandleStageWrap();18261827if (self->position.x < wall->position.x + 0x410000)1828self->position.x = wall->position.x + 0x410000;18291830switch (--self->attackTimer) {1831case 0:1832self->attackTimer = 120;1833self->velocity.y = 0x10000;18341835RSDK.SetSpriteAnimation(MetalSonic->aniFrames, MS_ANI_HOVER, &self->metalSonicAnimator, false, 0);1836self->state = MetalSonic_State_FinishAttack_Phase2;1837break;18381839case 30:1840case 60:1841case 90: {1842EntityMSOrb *orb = CREATE_ENTITY(MSOrb, NULL, self->position.x, self->position.y);1843orb->velocity.x = player1->velocity.x - 0x40000;1844orb->velocity.y = (RSDK.Rand(-1, 2) + 2) << 16;1845RSDK.PlaySfx(MetalSonic->sfxMSShoot, false, 0xFF);1846break;1847}18481849default: break;1850}18511852foreach_active(Player, player)1853{1854if (Player_CheckCollisionTouch(player, self, &MetalSonic->hitboxHover))1855Player_Hurt(player, self);1856}1857}1858void MetalSonic_State_SetupBallAttack_Phase2(void)1859{1860RSDK_THIS(MetalSonic);18611862int32 angle = RSDK.ATan2(self->targetPos.x, self->targetPos.y);1863EntityPlatform *wall = RSDK_GET_ENTITY(SceneInfo->entitySlot + 2, Platform);18641865self->unusedVec1.x = self->position.x + (RSDK.Cos256(angle + 0xC0) << 12);1866self->unusedVec1.y = self->position.y + (RSDK.Sin256(angle - 0x40) << 12);1867self->unusedVec2.x = self->position.x + (RSDK.Cos256(angle + 0x40) << 12);1868self->unusedVec2.y = self->position.y + (RSDK.Sin256(angle + 0x40) << 12);1869self->unusedVec3.x = self->position.x + (RSDK.Cos256(angle + 0x00) << 14);1870self->unusedVec3.y = self->position.y + (RSDK.Sin256(angle + 0x00) << 14);18711872self->position.x += self->velocity.x;1873self->position.y += self->velocity.y;18741875MetalSonic_HandleStageWrap();18761877if (self->position.x < wall->position.x + 0x410000)1878self->position.x = wall->position.x + 0x410000;18791880self->attackTimer--;1881if (self->attackTimer <= 0) {1882self->unusedVec1.x = -1;1883self->attackTimer = 8;1884self->velocity = self->targetPos;1885RSDK.PlaySfx(Player->sfxPeelRelease, false, 0xFF);1886self->state = MetalSonic_State_BallAttack_Phase2;1887}18881889foreach_active(Player, player)1890{1891if (Player_CheckCollisionTouch(player, self, &MetalSonic->hitboxHover))1892Player_Hurt(player, self);1893}1894}1895void MetalSonic_State_BallAttack_Phase2(void)1896{1897RSDK_THIS(MetalSonic);18981899EntityPlatform *wall = RSDK_GET_ENTITY(SceneInfo->entitySlot + 2, Platform);19001901self->position.x += self->velocity.x;1902self->position.y += self->velocity.y;1903self->velocity.y += 0x3800;19041905if (self->position.y >= 0x1F00000) {1906if (self->position.x > ((ScreenInfo->size.x + ScreenInfo->position.x) << 16) + 0x400000 || !--self->attackTimer) {1907self->attackTimer = 120;1908RSDK.SetSpriteAnimation(MetalSonic->aniFrames, MS_ANI_HOVER, &self->metalSonicAnimator, false, 2);1909self->state = MetalSonic_State_FinishAttack_Phase2;1910}1911else {1912self->velocity.y = -0x80000;1913RSDK.PlaySfx(MetalSonic->sfxRockemSockem, false, 0xFF);1914}1915}19161917MetalSonic_HandleStageWrap();19181919if (self->position.x < wall->position.x + 0x410000)1920self->position.x = wall->position.x + 0x410000;19211922foreach_active(Player, player)1923{1924if (Player_CheckCollisionTouch(player, self, &MetalSonic->hitboxHover))1925Player_Hurt(player, self);1926}1927}1928void MetalSonic_State_DashAttack_Phase2(void)1929{1930RSDK_THIS(MetalSonic);19311932EntityPlayer *player1 = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);1933EntityPlatform *wall = RSDK_GET_ENTITY(SceneInfo->entitySlot + 2, Platform);19341935if (self->velocity.x < 0xD0000)1936self->velocity.x += 0x1000;19371938self->position.x += self->velocity.x;1939self->position.y += self->velocity.y;19401941MetalSonic_HandleStageWrap();19421943if (self->position.x < wall->position.x + 0x410000)1944self->position.x = wall->position.x + 0x410000;19451946if (self->attackTimer) {1947self->attackTimer--;1948}1949else if (self->position.x > player1->position.x + 0x400000) {1950self->attackTimer = 120;1951RSDK.SetSpriteAnimation(MetalSonic->aniFrames, MS_ANI_FLY, &self->metalSonicAnimator, false, 2);1952self->state = MetalSonic_State_FinishAttack_Phase2;1953}19541955foreach_active(Player, player)1956{1957if (Player_CheckCollisionTouch(player, self, &MetalSonic->hitboxHover))1958Player_Hurt(player, self);1959}1960}1961void MetalSonic_State_FinishAttack_Phase2(void)1962{1963RSDK_THIS(MetalSonic);19641965EntityPlayer *player1 = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);19661967if (self->velocity.x > 0x20000)1968self->velocity.x -= 0x1800;19691970self->position.x += self->velocity.x;1971self->position.y += self->velocity.y;19721973if (self->position.y >= 0x1EC0000) {1974self->position.y = 0x1EC0000;1975self->velocity.y = 0;1976}19771978if (self->position.x < player1->position.x && self->direction == FLIP_X) {1979self->direction = FLIP_NONE;1980RSDK.SetSpriteAnimation(MetalSonic->aniFrames, MS_ANI_HOVERTURN, &self->metalSonicAnimator, true, 0);1981}19821983MetalSonic_HandleStageWrap();19841985EntityPlatform *wall = RSDK_GET_ENTITY(SceneInfo->entitySlot + 2, Platform);19861987if (self->position.x < wall->position.x + 0x900000) {1988self->position.x = wall->position.x + 0x900000;1989self->attackTimer = 120;1990RSDK.SetSpriteAnimation(MetalSonic->aniFrames, MS_ANI_BOOSTER_WEAK, &self->boosterAnimator, false, 0);1991RSDK.SetSpriteAnimation(MetalSonic->aniFrames, MS_ANI_HOVER, &self->metalSonicAnimator, false, 0);1992self->state = MetalSonic_State_Hover_Phase2;1993}19941995MetalSonic_CheckPlayerCollisions();1996}1997void MetalSonic_State_Explode(void)1998{1999RSDK_THIS(MetalSonic);20002001EntityPlatform *wall1 = RSDK_GET_ENTITY(SceneInfo->entitySlot + 2, Platform);20022003self->position.x += self->velocity.x;2004self->position.y += self->velocity.y;2005self->velocity.x -= 0x1000;2006self->rotation += 6;20072008MetalSonic_Explode();2009MetalSonic_HandleStageWrap();20102011if (self->position.x < wall1->position.x + 0x20000) {2012RSDK.PlaySfx(MetalSonic->sfxExplosion3, false, 0xFF);20132014for (int32 i = 2; i < 10; ++i) {2015EntityPlatform *wall = RSDK_GET_ENTITY(SceneInfo->entitySlot + i, Platform);2016EntityDebris *debris = CREATE_ENTITY(Debris, Debris_State_FallAndFlicker, wall->position.x, wall->position.y);20172018RSDK.SetSpriteAnimation(Platform->aniFrames, 0, &debris->animator, true, 1);2019debris->velocity.x = RSDK.Rand(6, 11) << 16;2020debris->velocity.y = RSDK.Rand(-0x20000, -0x10000);2021debris->gravityStrength = 0x4800;2022debris->drawGroup = wall->drawGroup;2023debris->updateRange.x = 0x800000;2024debris->updateRange.x = 0x800000;20252026destroyEntity(wall);2027}20282029Zone->autoScrollSpeed = 0;2030self->velocity.x = 0x50000;2031self->velocity.y = -0x30000;2032self->rotation = 0;2033self->drawFX &= ~FX_ROTATE;2034self->state = MetalSonic_State_Defeated;2035}2036}2037void MetalSonic_State_Defeated(void)2038{2039RSDK_THIS(MetalSonic);20402041self->position.x += self->velocity.x;2042self->position.y += self->velocity.y;2043self->velocity.y += 0x3800;2044self->visible ^= true;20452046MetalSonic_HandleStageWrap();20472048if (!RSDK.CheckOnScreen(self, &self->updateRange)) {2049self->visible = true;2050self->timer = 90;2051self->state = MetalSonic_State_Finish;2052}2053}2054void MetalSonic_State_Finish(void)2055{2056RSDK_THIS(MetalSonic);20572058MetalSonic_HandleStageWrap();20592060if (!--self->timer) {2061Music_TransitionTrack(TRACK_STAGE, 0.0125);20622063Zone->cameraBoundsL[0] = ScreenInfo->position.x;2064Zone->cameraBoundsR[0] = ScreenInfo->size.x + ScreenInfo->position.x;2065Zone->playerBoundsR[0] = (ScreenInfo->size.x + ScreenInfo->position.x) << 16;2066Zone->playerBoundsL[0] = ScreenInfo->position.x << 16;20672068EntityEggPrison *prison = CREATE_ENTITY(EggPrison, INT_TO_VOID(EGGPRISON_FLYING), (ScreenInfo->position.x + ScreenInfo->center.x) << 16,2069(ScreenInfo->position.y - 48) << 16);20702071prison->velocity.x = 0x10000;2072prison->active = ACTIVE_NORMAL;2073self->state = MetalSonic_State_None;2074}2075}20762077void MetalSonic_State_None(void)2078{2079// common preplus L2080}20812082void MetalSonic_StateWall_Fall(void)2083{2084RSDK_THIS(Platform);20852086self->drawPos.y += self->velocity.y;2087self->centerPos.y = self->drawPos.y;2088self->position.y = self->drawPos.y;20892090self->velocity.y += 0x3800;20912092if (RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0, (self->speed << 21) + 0x100000, true)) {2093self->velocity.y = 0;2094self->drawPos.y = self->position.y;2095self->centerPos.y = self->position.y;2096self->state = Platform_State_Fixed;2097Camera_ShakeScreen(0, 0, 4);2098RSDK.PlaySfx(MetalSonic->sfxHit, false, 0xFF);2099}2100}2101void MetalSonic_StateWall_Move(void)2102{2103RSDK_THIS(Platform);21042105EntityPlayer *player1 = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);21062107bool32 metalInvincibile = false;2108foreach_active(MetalSonic, metal)2109{2110if (metal->invincibilityTimer)2111metalInvincibile = true;2112}21132114if (metalInvincibile || player1->blinkTimer) {2115self->type = 120;2116self->type--;2117if (self->velocity.x > 0x40000)2118self->velocity.x -= 0x1000;2119}2120else {2121if (self->type <= 0) {2122if (self->velocity.x < 0x54000) {2123self->velocity.x += 0x400;2124}2125else {2126self->type--;2127if (self->velocity.x > 0x40000)2128self->velocity.x -= 0x1000;2129}2130}2131else {2132self->type--;2133if (self->velocity.x > 0x40000)2134self->velocity.x -= 0x1000;2135}2136}21372138Zone->autoScrollSpeed = self->velocity.x;2139self->drawPos.x += self->velocity.x;2140self->centerPos.x = self->drawPos.x;2141self->position.x = self->drawPos.x;21422143int32 x = player1->position.x - 0x2000000;2144if (x < self->position.x - 0x2000000 || x > self->position.x) {2145self->drawPos.x = x;2146self->centerPos.x = x;2147self->position.x = x;2148}21492150if (self->speed == 1) {2151EntityPlatform *belowPlat = RSDK_GET_ENTITY(SceneInfo->entitySlot - 1, Platform);2152belowPlat->drawPos.x = self->position.x;2153belowPlat->centerPos.x = self->position.x;2154belowPlat->position.x = self->position.x;2155}2156}2157#endif21582159#if GAME_INCLUDE_EDITOR2160void MetalSonic_EditorDraw(void)2161{2162RSDK_THIS(MetalSonic);21632164self->drawFX = FX_FLIP | FX_ROTATE;2165self->updateRange.x = 0x800000;2166self->updateRange.y = 0x800000;2167self->tileCollisions = TILECOLLISION_DOWN;2168RSDK.SetSpriteAnimation(MetalSonic->aniFrames, MS_ANI_IDLE, &self->metalSonicAnimator, false, 0);21692170RSDK.DrawSprite(&self->boosterAnimator, NULL, false);2171RSDK.DrawSprite(&self->metalSonicAnimator, NULL, false);21722173if (showGizmos()) {2174RSDK_DRAWING_OVERLAY(true);21752176DrawHelpers_DrawArenaBounds(-WIDE_SCR_XCENTER, -SCREEN_YSIZE + 52, WIDE_SCR_XCENTER, 52, 1 | 2 | 4 | 8, 0x00C0F0);21772178RSDK_DRAWING_OVERLAY(false);2179}2180}21812182void MetalSonic_EditorLoad(void) { MetalSonic->aniFrames = RSDK.LoadSpriteAnimation("SSZ2/MetalSonic.bin", SCOPE_STAGE); }2183#endif21842185void MetalSonic_Serialize(void) {}218621872188