Path: blob/master/SonicMania/Objects/ERZ/PhantomMystic.c
338 views
// ---------------------------------------------------------------------1// RSDK Project: Sonic Mania2// Object Description: PhantomMystic Object3// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges4// Decompiled by: Rubberduckycooly & RMGRich5// ---------------------------------------------------------------------67#include "Game.h"89ObjectPhantomMystic *PhantomMystic;1011void PhantomMystic_Update(void)12{13RSDK_THIS(PhantomMystic);1415if (self->invincibilityTimer > 0)16self->invincibilityTimer--;1718StateMachine_Run(self->state);1920RSDK.ProcessAnimation(&self->mysticAnimator);21}2223void PhantomMystic_LateUpdate(void) {}2425void PhantomMystic_StaticUpdate(void) {}2627void PhantomMystic_Draw(void)28{29RSDK_THIS(PhantomMystic);3031RSDK.SetActivePalette(4, 0, ScreenInfo[SceneInfo->currentScreenID].size.y);3233if (self->stateDraw) {34StateMachine_Run(self->stateDraw);35}36else {37RSDK.DrawSprite(&self->mysticAnimator, NULL, false);38}3940RSDK.SetActivePalette(0, 0, ScreenInfo[SceneInfo->currentScreenID].size.y);41}4243void PhantomMystic_Create(void *data)44{45RSDK_THIS(PhantomMystic);4647self->drawFX = FX_FLIP;48if (!SceneInfo->inEditor) {49self->visible = true;50self->drawGroup = Zone->objectDrawGroup[0];51self->active = ACTIVE_NEVER;52self->updateRange.x = 0x800000;53self->updateRange.y = 0x800000;5455self->unused1[0] = 0;56self->unused1[1] = 1;57self->unused1[2] = 2;5859self->cupAlpha[0] = 0x60;60self->cupAlpha[1] = 0;61self->cupAlpha[2] = 0x60;6263self->hitbox.left = -12;64self->hitbox.top = -12;65self->hitbox.right = 12;66self->hitbox.bottom = 12;6768self->correctCup = 1;69self->state = PhantomMystic_State_Init;70self->stateDraw = PhantomMystic_Draw_CupSetup;7172RSDK.SetSpriteAnimation(PhantomMystic->aniFrames, 2, &self->mysticAnimator, true, 0);73RSDK.SetSpriteAnimation(PhantomMystic->aniFrames, 0, &self->cupAnimator, true, 0);74RSDK.SetSpriteAnimation(PhantomMystic->aniFrames, 0, &self->cupSilhouetteAnimator, true, 1);75RSDK.SetSpriteAnimation(PhantomMystic->aniFrames, 1, &self->cupSpikeAnimator, true, 0);76}77}7879void PhantomMystic_StageLoad(void)80{81PhantomMystic->aniFrames = RSDK.LoadSpriteAnimation("Phantom/PhantomMystic.bin", SCOPE_STAGE);8283PhantomMystic->sfxCupSwap = RSDK.GetSfx("TMZ3/CupSwap.wav");84PhantomMystic->sfxBigLaser = RSDK.GetSfx("TMZ3/BigLaser.wav");85PhantomMystic->sfxImpact = RSDK.GetSfx("Stage/Impact2.wav");86}8788void PhantomMystic_CheckPlayerCollisions(void)89{90RSDK_THIS(PhantomMystic);9192int32 storeX = self->position.x;93int32 storeY = self->position.y;9495self->position.x = self->mysticPos.x;96self->position.y = self->mysticPos.y;9798foreach_active(Player, player)99{100if (!self->invincibilityTimer && Player_CheckBadnikTouch(player, self, &self->hitbox) && Player_CheckBossHit(player, self)) {101PhantomMystic_Hit();102}103104if (self->cupBlastAnimator.frameID > 8 && self->cupBlastAnimator.frameID < 26) {105for (int32 i = 0; i < 3; ++i) {106if (i != self->correctCup) {107self->position.x = storeX + self->cupPos[i];108if (abs(self->position.x - player->position.x) < 0x400000 && player->position.y > self->position.y)109Player_Hurt(player, self);110}111}112}113114self->position.x = self->mysticPos.x;115}116117self->position.x = storeX;118self->position.y = storeY;119}120121void PhantomMystic_Hit(void)122{123RSDK_THIS(PhantomMystic);124125self->invincibilityTimer = 48;126RSDK.PlaySfx(PhantomEgg->sfxHit, false, 255);127}128129void PhantomMystic_SetupNewCupSwap(void)130{131RSDK_THIS(PhantomMystic);132133self->swapCup1 = RSDK.Rand(0, 3);134135switch (self->swapCup1) {136case 0: self->swapCup2 = (RSDK.Rand(0, 256) > 128) + 1; break;137case 1: self->swapCup2 = RSDK.Rand(0, 256) <= 128 ? 2 : 0; break;138case 2: self->swapCup2 = RSDK.Rand(0, 256) <= 128; break;139}140141self->swapCup1Pos = self->cupPos[self->swapCup1];142self->swapCup1Alpha = self->cupAlpha[self->swapCup1];143144self->swapCup2Pos = self->cupPos[self->swapCup2];145self->swapCup2Alpha = self->cupAlpha[self->swapCup2];146}147148void PhantomMystic_Draw_CupSetup(void)149{150RSDK_THIS(PhantomMystic);151152RSDK.DrawSprite(&self->mysticAnimator, &self->mysticPos, false);153154for (int32 i = 0; i < 3; ++i) {155Vector2 drawPos;156drawPos.x = self->position.x + self->cupPos[i];157if (i == 1) {158drawPos.y = self->middleCupY;159self->drawFX = FX_ROTATE | FX_FLIP;160}161else {162drawPos.y = self->position.y;163}164165self->direction = FLIP_X;166RSDK.DrawSprite(&self->cupAnimator, &drawPos, false);167168self->direction = FLIP_NONE;169RSDK.DrawSprite(&self->cupAnimator, &drawPos, false);170171self->inkEffect = INK_ALPHA;172self->drawFX = FX_FLIP;173self->alpha = self->cupAlpha[i];174self->direction = FLIP_X;175RSDK.DrawSprite(&self->cupSilhouetteAnimator, &drawPos, false);176177self->direction = FLIP_NONE;178RSDK.DrawSprite(&self->cupSilhouetteAnimator, &drawPos, false);179180self->inkEffect = INK_NONE;181}182}183184void PhantomMystic_Draw_CupSwap(void)185{186RSDK_THIS(PhantomMystic);187188Vector2 drawPos = self->position;189if (self->invincibilityTimer & 1) {190RSDK.CopyPalette(6, 128, 4, 128, 128);191192RSDK.DrawSprite(&self->mysticAnimator, &self->mysticPos, false);193194RSDK.CopyPalette(5, 128, 4, 128, 128);195}196else {197RSDK.DrawSprite(&self->mysticAnimator, &self->mysticPos, false);198}199200for (int32 i = 0; i < 3; ++i) {201drawPos.x = self->position.x + self->cupPos[i];202self->direction = FLIP_X;203RSDK.DrawSprite(&self->cupAnimator, &drawPos, false);204205self->direction = FLIP_NONE;206RSDK.DrawSprite(&self->cupAnimator, &drawPos, false);207208self->inkEffect = INK_ALPHA;209self->alpha = self->cupAlpha[i];210self->direction = FLIP_X;211RSDK.DrawSprite(&self->cupSilhouetteAnimator, &drawPos, false);212213self->direction = FLIP_NONE;214RSDK.DrawSprite(&self->cupSilhouetteAnimator, &drawPos, false);215216self->inkEffect = INK_NONE;217if (i != self->correctCup)218RSDK.DrawSprite(&self->cupBlastAnimator, &drawPos, false);219}220}221222void PhantomMystic_State_Init(void)223{224RSDK_THIS(PhantomMystic);225226self->mysticPos.x = self->position.x;227self->velocity.y = 0x40000;228self->mysticVelY = -0x80000;229self->mysticPos.y = self->position.y;230self->middleCupY = self->position.y;231232self->state = PhantomMystic_State_SetupInitialCupPos;233}234235void PhantomMystic_State_SetupInitialCupPos(void)236{237RSDK_THIS(PhantomMystic);238239self->mysticVelY += 0x3800;240self->mysticPos.y += self->mysticVelY;241242self->velocity.y -= 0x2800;243self->middleCupY += self->velocity.y;244245if (self->middleCupY <= self->position.y) {246self->velocity.y = 0;247self->middleCupY = self->position.y;248}249250self->cupPos[0] += (-0x800000 - self->cupPos[0]) >> 4;251self->cupPos[2] += ((0x800000 - self->cupPos[2]) >> 4);252253if (self->rotation < 0x100) {254self->rotation += 0x10;255}256257if (++self->timer == 60) {258self->cupPos[0] = -0x800000;259self->cupPos[2] = 0x800000;260self->timer = 0;261262self->state = PhantomMystic_State_MoveCupsDownwards;263}264}265266void PhantomMystic_State_MoveCupsDownwards(void)267{268RSDK_THIS(PhantomMystic);269270self->mysticVelY += 0x3800;271self->mysticPos.y += self->mysticVelY;272273self->velocity.y += 0x3800;274self->position.y += self->velocity.y;275276if (RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0, 0x380000, true))277self->velocity.y = 0;278279if (self->mysticPos.y >= self->position.y - 0x180000) {280self->mysticPos.y = 0;281self->mysticVelY = 0;282self->onGround = false;283284self->state = PhantomMystic_State_RotateMiddleCup;285}286}287288void PhantomMystic_State_RotateMiddleCup(void)289{290RSDK_THIS(PhantomMystic);291292// This does continue to move the side cups downwards too if they're not on the ground yet293self->velocity.y += 0x4000;294self->position.y += self->velocity.y;295296if (RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0, 0x380000, true)) {297if (!self->onGround)298Camera_ShakeScreen(0, 0, 4);299300self->velocity.y = 0;301self->onGround = true;302}303304if (self->rotation >= 0x200) {305self->rotation = 0;306self->state = PhantomMystic_State_MoveMiddleCupToFloor;307}308else {309self->rotation += 0x10;310}311}312313void PhantomMystic_State_MoveMiddleCupToFloor(void)314{315RSDK_THIS(PhantomMystic);316317self->velocity.y += 0x4000;318self->middleCupY += self->velocity.y;319320if (self->middleCupY >= self->position.y) {321Camera_ShakeScreen(0, 0, 4);322RSDK.PlaySfx(PhantomMystic->sfxImpact, false, 255);323324self->velocity.y = 0;325self->middleCupY = self->position.y;326self->stateDraw = PhantomMystic_Draw_CupSwap;327self->state = PhantomMystic_State_PrepareCupSwap;328}329}330331void PhantomMystic_State_PrepareCupSwap(void)332{333RSDK_THIS(PhantomMystic);334335++self->timer;336if (self->cupAlpha[0] < 0x90) {337self->cupAlpha[0] += 4;338self->cupAlpha[2] += 4;339}340341if (self->timer == 30) {342self->timer = 0;343self->cupSwapCount = 6;344PhantomMystic_SetupNewCupSwap();345RSDK.PlaySfx(PhantomMystic->sfxCupSwap, false, 255);346self->state = PhantomMystic_State_CupSwapping;347}348}349350void PhantomMystic_State_CupSwapping(void)351{352RSDK_THIS(PhantomMystic);353354if (abs(self->swapCup2Pos - self->swapCup1Pos) <= 0x800000)355self->timer += 16;356else357self->timer += 8;358359int32 cup1 = self->swapCup1;360int32 cup2 = self->swapCup2;361362// Use Lerp Math to move each cup to the other's initial position363int32 cup1Pos = self->swapCup1Pos;364if (self->timer > 0) {365if (self->timer < 256)366cup1Pos += ((self->swapCup2Pos - cup1Pos) >> 8) * ((RSDK.Sin512(self->timer + 0x180) >> 2) + 0x80);367else368cup1Pos = self->swapCup2Pos;369}370self->cupPos[cup1] = cup1Pos;371372int32 cup2Pos = self->swapCup2Pos;373if (self->timer > 0) {374if (self->timer < 256)375cup2Pos += ((self->swapCup1Pos - cup2Pos) >> 8) * ((RSDK.Sin512(self->timer + 0x180) >> 2) + 0x80);376else377cup2Pos = self->swapCup1Pos;378}379self->cupPos[cup2] = cup2Pos;380381self->cupAlpha[cup1] = abs(self->cupPos[cup1]) / 0xE38E;382self->cupAlpha[cup2] = abs(self->cupPos[cup2]) / 0xE38E;383384if (self->timer == 0x100) {385self->timer = 0;386387if (self->cupSwapCount <= 1) {388self->middleCupY -= 0x600000;389self->mysticPos.x = self->position.x + self->cupPos[self->correctCup];390self->mysticPos.y = self->position.y;391self->originPos.x = self->mysticPos.x;392self->originPos.y = self->mysticPos.y;393self->velocity.y = -0x10000;394self->state = PhantomMystic_State_RevealMystic;395}396else {397self->cupSwapCount--;398RSDK.PlaySfx(PhantomMystic->sfxCupSwap, false, 255);399PhantomMystic_SetupNewCupSwap();400}401}402}403404void PhantomMystic_State_RevealMystic(void)405{406RSDK_THIS(PhantomMystic);407408self->velocity.y -= 0x3800;409self->position.y += self->velocity.y;410411self->cupAlpha[0] -= self->cupAlpha[0] >> 4;412self->cupAlpha[1] -= self->cupAlpha[1] >> 4;413self->cupAlpha[2] -= self->cupAlpha[2] >> 4;414415if (self->position.y <= self->middleCupY) {416RSDK.SetSpriteAnimation(PhantomMystic->aniFrames, 3, &self->cupBlastAnimator, true, 0);417self->velocity.y = 0;418self->position.y = self->middleCupY;419self->state = PhantomMystic_State_CupBlast;420}421422self->mysticPos.y = BadnikHelpers_Oscillate(self->originPos.y, 4, 11);423424if (self->position.y - self->middleCupY < 0x200000)425PhantomMystic_CheckPlayerCollisions();426}427428void PhantomMystic_State_CupBlast(void)429{430RSDK_THIS(PhantomMystic);431432RSDK.ProcessAnimation(&self->cupBlastAnimator);433434self->cupAlpha[0] -= self->cupAlpha[0] >> 4;435self->cupAlpha[1] -= self->cupAlpha[1] >> 4;436self->cupAlpha[2] -= self->cupAlpha[2] >> 4;437438if (self->cupBlastAnimator.frameID == self->cupBlastAnimator.frameCount - 1) {439self->mysticVelY = 0;440RSDK.PlaySfx(PhantomMystic->sfxCupSwap, false, 255);441self->state = PhantomMystic_State_MoveCupsToMystic;442}443444self->mysticPos.y = BadnikHelpers_Oscillate(self->originPos.y, 4, 11);445446PhantomMystic_CheckPlayerCollisions();447}448449void PhantomMystic_State_MoveCupsToMystic(void)450{451RSDK_THIS(PhantomMystic);452453self->cupPos[0] += (self->cupPos[self->correctCup] - self->cupPos[0]) >> 3;454self->cupPos[1] += (self->cupPos[self->correctCup] - self->cupPos[1]) >> 3;455self->cupPos[2] += (self->cupPos[self->correctCup] - self->cupPos[2]) >> 3;456457self->mysticVelY -= 0x3000;458self->mysticPos.y += self->mysticVelY;459460if (self->mysticPos.y < self->position.y)461self->mysticPos.y = self->position.y;462463PhantomMystic_CheckPlayerCollisions();464465if (++self->timer == 60)466PhantomEgg_SetupWarpFX();467468if (self->timer == 120) {469int32 x = self->position.x;470int32 y = self->position.y;471RSDK.ResetEntity(self, PhantomMystic->classID, NULL);472473self->position.x = x;474self->position.y = y;475}476}477478#if GAME_INCLUDE_EDITOR479void PhantomMystic_EditorDraw(void)480{481RSDK_THIS(PhantomMystic);482483self->mysticPos = self->position;484self->middleCupY = self->position.y;485486self->cupAlpha[0] = 0x60;487self->cupAlpha[1] = 0;488self->cupAlpha[2] = 0x60;489490RSDK.SetSpriteAnimation(PhantomMystic->aniFrames, 2, &self->mysticAnimator, true, 0);491RSDK.SetSpriteAnimation(PhantomMystic->aniFrames, 0, &self->cupAnimator, true, 0);492RSDK.SetSpriteAnimation(PhantomMystic->aniFrames, 0, &self->cupSilhouetteAnimator, true, 1);493RSDK.SetSpriteAnimation(PhantomMystic->aniFrames, 1, &self->cupSpikeAnimator, true, 0);494495PhantomMystic_Draw_CupSetup();496}497498void PhantomMystic_EditorLoad(void) { PhantomMystic->aniFrames = RSDK.LoadSpriteAnimation("Phantom/PhantomMystic.bin", SCOPE_STAGE); }499#endif500501void PhantomMystic_Serialize(void) {}502503504