Path: blob/master/SonicMania/Objects/ERZ/ERZMystic.c
338 views
// ---------------------------------------------------------------------1// RSDK Project: Sonic Mania2// Object Description: ERZMystic Object3// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges4// Decompiled by: Rubberduckycooly & RMGRich5// ---------------------------------------------------------------------67#include "Game.h"89ObjectERZMystic *ERZMystic;1011void ERZMystic_Update(void)12{13RSDK_THIS(ERZMystic);1415if (self->invincibilityTimer > 0)16self->invincibilityTimer--;1718StateMachine_Run(self->state);1920RSDK.ProcessAnimation(&self->mysticAnimator);21}2223void ERZMystic_LateUpdate(void) {}2425void ERZMystic_StaticUpdate(void) {}2627void ERZMystic_Draw(void)28{29RSDK_THIS(ERZMystic);3031if (self->stateDraw) {32StateMachine_Run(self->stateDraw);33}34else {35RSDK.DrawSprite(&self->mysticAnimator, NULL, false);36}37}3839void ERZMystic_Create(void *data)40{41RSDK_THIS(ERZMystic);4243self->drawFX = FX_FLIP;4445if (!SceneInfo->inEditor) {46self->visible = true;47self->drawGroup = Zone->objectDrawGroup[0];48self->active = ACTIVE_NORMAL;49self->updateRange.x = 0x800000;50self->updateRange.y = 0x800000;5152self->unused1[0] = 0;53self->unused1[1] = 1;54self->unused1[2] = 2;5556self->cupAlpha[0] = 0xC0;57self->cupAlpha[1] = 0x00;58self->cupAlpha[2] = 0xC0;5960self->hitbox.left = -12;61self->hitbox.top = -12;62self->hitbox.right = 12;63self->hitbox.bottom = 12;6465self->correctCup = 1;66self->state = ERZMystic_State_Init;67self->stateDraw = ERZMystic_Draw_CupSetup;6869RSDK.SetSpriteAnimation(ERZMystic->aniFrames, 2, &self->mysticAnimator, true, 0);70RSDK.SetSpriteAnimation(ERZMystic->aniFrames, 0, &self->cupAnimator, true, 0);71RSDK.SetSpriteAnimation(ERZMystic->aniFrames, 0, &self->cupSilhouetteAnimator, true, 1);72RSDK.SetSpriteAnimation(ERZMystic->aniFrames, 1, &self->cupSpikeAnimator, true, 0);73}74}7576void ERZMystic_StageLoad(void) { ERZMystic->aniFrames = RSDK.LoadSpriteAnimation("Phantom/PhantomMystic.bin", SCOPE_STAGE); }7778void ERZMystic_CheckPlayerCollisions(void)79{80RSDK_THIS(ERZMystic);8182int32 storeX = self->position.x;83int32 storeY = self->position.y;8485self->position.x = self->mysticPos.x;86self->position.y = self->mysticPos.y;8788foreach_active(Player, player)89{90if (!self->invincibilityTimer && Player_CheckBadnikTouch(player, self, &self->hitbox) && Player_CheckBossHit(player, self)) {91ERZMystic_Hit();92}9394if (self->cupBlastAnimator.frameID > 8 && self->cupBlastAnimator.frameID < 26) {95for (int32 i = 0; i < 3; ++i) {96if (i != self->correctCup) {97self->position.x = storeX + self->cupPos[i];98if (abs(self->position.x - player->position.x) < 0x400000 && player->position.y > self->position.y)99Player_Hurt(player, self);100}101}102}103104self->position.x = self->mysticPos.x;105}106107self->position.x = storeX;108self->position.y = storeY;109}110111void ERZMystic_Hit(void)112{113RSDK_THIS(ERZMystic);114115self->invincibilityTimer = 48;116RSDK.PlaySfx(ERZKing->sfxHit, false, 255);117}118119void ERZMystic_SetupNewCupSwap(void)120{121RSDK_THIS(ERZMystic);122123self->swapCup1 = RSDK.Rand(0, 3);124125switch (self->swapCup1) {126case 0: self->swapCup2 = (RSDK.Rand(0, 256) > 128) + 1; break;127case 1: self->swapCup2 = RSDK.Rand(0, 256) <= 128 ? 2 : 0; break;128case 2: self->swapCup2 = RSDK.Rand(0, 256) <= 128; break;129}130131self->swapCup1Pos = self->cupPos[self->swapCup1];132self->swapCup1Alpha = self->cupAlpha[self->swapCup1];133134self->swapCup2Pos = self->cupPos[self->swapCup2];135self->swapCup2Alpha = self->cupAlpha[self->swapCup2];136}137138void ERZMystic_Draw_CupSetup(void)139{140RSDK_THIS(ERZMystic);141142RSDK.DrawSprite(&self->mysticAnimator, &self->mysticPos, false);143144for (int32 i = 0; i < 3; ++i) {145Vector2 drawPos;146drawPos.x = self->position.x + self->cupPos[i];147if (i == 1) {148drawPos.y = self->middleCupY;149self->drawFX = FX_ROTATE | FX_FLIP;150}151else {152drawPos.y = self->position.y;153}154155self->direction = FLIP_X;156RSDK.DrawSprite(&self->cupAnimator, &drawPos, false);157158self->direction = FLIP_NONE;159RSDK.DrawSprite(&self->cupAnimator, &drawPos, false);160161self->inkEffect = INK_ALPHA;162self->drawFX = FX_FLIP;163self->alpha = self->cupAlpha[i];164self->direction = FLIP_X;165RSDK.DrawSprite(&self->cupSilhouetteAnimator, &drawPos, false);166167self->direction = FLIP_NONE;168RSDK.DrawSprite(&self->cupSilhouetteAnimator, &drawPos, false);169170self->inkEffect = INK_NONE;171}172}173174void ERZMystic_Draw_CupSwap(void)175{176RSDK_THIS(ERZMystic);177178Vector2 drawPos = self->position;179if (self->invincibilityTimer & 1) {180RSDK.CopyPalette(2, 128, 0, 128, 128);181182RSDK.DrawSprite(&self->mysticAnimator, &self->mysticPos, false);183184RSDK.CopyPalette(1, 128, 0, 128, 128);185}186else {187RSDK.DrawSprite(&self->mysticAnimator, &self->mysticPos, false);188}189190for (int32 i = 0; i < 3; ++i) {191drawPos.x = self->position.x + self->cupPos[i];192self->direction = FLIP_X;193RSDK.DrawSprite(&self->cupAnimator, &drawPos, false);194195self->direction = FLIP_NONE;196RSDK.DrawSprite(&self->cupAnimator, &drawPos, false);197198self->inkEffect = INK_ALPHA;199self->alpha = self->cupAlpha[i];200self->direction = FLIP_X;201RSDK.DrawSprite(&self->cupSilhouetteAnimator, &drawPos, false);202203self->direction = FLIP_NONE;204RSDK.DrawSprite(&self->cupSilhouetteAnimator, &drawPos, false);205206self->inkEffect = INK_NONE;207if (i != self->correctCup)208RSDK.DrawSprite(&self->cupBlastAnimator, &drawPos, false);209}210}211212void ERZMystic_State_Init(void)213{214RSDK_THIS(ERZMystic);215216self->mysticPos.x = self->position.x;217self->velocity.y = 0x40000;218self->mysticVelY = -0x80000;219self->mysticPos.y = self->position.y;220self->middleCupY = self->position.y;221222self->state = ERZMystic_State_SetupInitialCupPos;223}224225void ERZMystic_State_SetupInitialCupPos(void)226{227RSDK_THIS(ERZMystic);228229self->mysticVelY += 0x3800;230self->mysticPos.y += self->mysticVelY;231232self->velocity.y -= 0x2800;233self->middleCupY += self->velocity.y;234235if (self->middleCupY <= self->position.y) {236self->velocity.y = 0;237self->middleCupY = self->position.y;238}239240self->cupPos[0] += (-0x800000 - self->cupPos[0]) >> 4;241self->cupPos[2] += ((0x800000 - self->cupPos[2]) >> 4);242243if (self->rotation < 256) {244self->rotation += 16;245}246247if (++self->timer == 60) {248self->cupPos[0] = -0x800000;249self->cupPos[2] = 0x800000;250self->timer = 0;251self->state = ERZMystic_State_MoveCupsDownwards;252}253}254255void ERZMystic_State_MoveCupsDownwards(void)256{257RSDK_THIS(ERZMystic);258259self->mysticVelY += 0x3800;260self->mysticPos.y += self->mysticVelY;261262self->velocity.y += 0x3800;263self->position.y += self->velocity.y;264265if (RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0, 0x380000, true))266self->velocity.y = 0;267268if (self->mysticPos.y >= self->position.y - 0x180000) {269self->mysticPos.y = 0;270self->mysticVelY = 0;271self->onGround = false;272self->state = ERZMystic_State_RotateMiddleCup;273}274}275276void ERZMystic_State_RotateMiddleCup(void)277{278RSDK_THIS(ERZMystic);279280// This does continue to move the side cups downwards too if they're not on the ground yet281self->velocity.y += 0x4000;282self->position.y += self->velocity.y;283284if (RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0, 0x380000, true)) {285if (!self->onGround)286Camera_ShakeScreen(0, 0, 4);287288self->velocity.y = 0;289self->onGround = true;290}291292if (self->rotation >= 512) {293self->rotation = 0;294self->state = ERZMystic_State_MoveMiddleCupToFloor;295}296else {297self->rotation += 16;298}299}300301void ERZMystic_State_MoveMiddleCupToFloor(void)302{303RSDK_THIS(ERZMystic);304305self->velocity.y += 0x4000;306self->middleCupY += self->velocity.y;307308if (self->middleCupY >= self->position.y) {309Camera_ShakeScreen(0, 0, 4);310self->velocity.y = 0;311self->middleCupY = self->position.y;312self->stateDraw = ERZMystic_Draw_CupSwap;313self->state = ERZMystic_State_PrepareCupSwap;314}315}316317void ERZMystic_State_PrepareCupSwap(void)318{319RSDK_THIS(ERZMystic);320321++self->timer;322if (self->cupAlpha[0] < 0x90) {323self->cupAlpha[0] += 4;324self->cupAlpha[2] += 4;325}326327if (self->timer == 30) {328self->timer = 0;329self->cupSwapCount = 6;330ERZMystic_SetupNewCupSwap();331self->state = ERZMystic_State_CupSwapping;332}333}334335void ERZMystic_State_CupSwapping(void)336{337RSDK_THIS(ERZMystic);338339if (abs(self->swapCup2Pos - self->swapCup1Pos) <= 0x800000)340self->timer += 16;341else342self->timer += 8;343344int32 cup1 = self->swapCup1;345int32 cup2 = self->swapCup2;346347// Use Lerp Math to move each cup to the other's initial position348int32 cup1Pos = self->swapCup1Pos;349if (self->timer > 0) {350if (self->timer < 256)351cup1Pos += ((self->swapCup2Pos - cup1Pos) >> 8) * ((RSDK.Sin512(self->timer + 0x180) >> 2) + 0x80);352else353cup1Pos = self->swapCup2Pos;354}355self->cupPos[cup1] = cup1Pos;356357int32 cup2Pos = self->swapCup2Pos;358if (self->timer > 0) {359if (self->timer < 256)360cup2Pos += ((self->swapCup1Pos - cup2Pos) >> 8) * ((RSDK.Sin512(self->timer + 0x180) >> 2) + 0x80);361else362cup2Pos = self->swapCup1Pos;363}364self->cupPos[cup2] = cup2Pos;365366self->cupAlpha[cup1] = abs(self->cupPos[cup1]) / 0xE38E;367self->cupAlpha[cup2] = abs(self->cupPos[cup2]) / 0xE38E;368369if (self->timer == 0x100) {370self->timer = 0;371372if (self->cupSwapCount <= 1) {373self->middleCupY -= 0x600000;374self->mysticPos.x = self->position.x + self->cupPos[self->correctCup];375self->mysticPos.y = self->position.y;376self->originPos.x = self->mysticPos.x;377self->originPos.y = self->mysticPos.y;378self->velocity.y = -0x10000;379self->state = ERZMystic_State_RevealMystic;380}381else {382self->cupSwapCount--;383RSDK.PlaySfx(PhantomMystic->sfxCupSwap, false, 255);384ERZMystic_SetupNewCupSwap();385}386}387}388389void ERZMystic_State_RevealMystic(void)390{391RSDK_THIS(ERZMystic);392393self->velocity.y -= 0x3800;394self->position.y += self->velocity.y;395396self->cupAlpha[0] -= self->cupAlpha[0] >> 4;397self->cupAlpha[1] -= self->cupAlpha[1] >> 4;398self->cupAlpha[2] -= self->cupAlpha[2] >> 4;399400if (self->position.y <= self->middleCupY) {401RSDK.SetSpriteAnimation(ERZMystic->aniFrames, 3, &self->cupBlastAnimator, true, 0);402self->velocity.y = 0;403self->position.y = self->middleCupY;404self->state = ERZMystic_State_CupBlast;405}406407self->mysticPos.y = BadnikHelpers_Oscillate(self->originPos.y, 4, 11);408409if (self->position.y - self->middleCupY < 0x200000)410ERZMystic_CheckPlayerCollisions();411}412413void ERZMystic_State_CupBlast(void)414{415RSDK_THIS(ERZMystic);416417RSDK.ProcessAnimation(&self->cupBlastAnimator);418419self->cupAlpha[0] -= self->cupAlpha[0] >> 4;420self->cupAlpha[1] -= self->cupAlpha[1] >> 4;421self->cupAlpha[2] -= self->cupAlpha[2] >> 4;422423if (self->cupBlastAnimator.frameID == self->cupBlastAnimator.frameCount - 1) {424self->mysticVelY = 0;425self->state = ERZMystic_State_MoveCupsToMystic;426}427428self->mysticPos.y = BadnikHelpers_Oscillate(self->originPos.y, 4, 11);429430ERZMystic_CheckPlayerCollisions();431}432433void ERZMystic_State_MoveCupsToMystic(void)434{435RSDK_THIS(ERZMystic);436437self->cupPos[0] += (self->cupPos[self->correctCup] - self->cupPos[0]) >> 3;438self->cupPos[1] += (self->cupPos[self->correctCup] - self->cupPos[1]) >> 3;439self->cupPos[2] += (self->cupPos[self->correctCup] - self->cupPos[2]) >> 3;440441self->mysticVelY -= 0x3000;442self->mysticPos.y += self->mysticVelY;443444if (self->mysticPos.y < self->position.y)445self->mysticPos.y = self->position.y;446447ERZMystic_CheckPlayerCollisions();448if (++self->timer == 60) {449foreach_all(ERZKing, king)450{451king->active = ACTIVE_NORMAL;452king->position.x = self->mysticPos.x;453}454destroyEntity(self);455}456}457458#if GAME_INCLUDE_EDITOR459void ERZMystic_EditorDraw(void)460{461RSDK_THIS(ERZMystic);462463self->mysticPos = self->position;464self->middleCupY = self->position.y;465466self->cupAlpha[0] = 0x60;467self->cupAlpha[1] = 0;468self->cupAlpha[2] = 0x60;469470RSDK.SetSpriteAnimation(ERZMystic->aniFrames, 2, &self->mysticAnimator, true, 0);471RSDK.SetSpriteAnimation(ERZMystic->aniFrames, 0, &self->cupAnimator, true, 0);472RSDK.SetSpriteAnimation(ERZMystic->aniFrames, 0, &self->cupSilhouetteAnimator, true, 1);473RSDK.SetSpriteAnimation(ERZMystic->aniFrames, 1, &self->cupSpikeAnimator, true, 0);474475ERZMystic_Draw_CupSetup();476}477478void ERZMystic_EditorLoad(void) { ERZMystic->aniFrames = RSDK.LoadSpriteAnimation("Phantom/PhantomMystic.bin", SCOPE_STAGE); }479#endif480481void ERZMystic_Serialize(void) {}482483484