Path: blob/master/SonicMania/Objects/ERZ/ERZOutro.c
338 views
// ---------------------------------------------------------------------1// RSDK Project: Sonic Mania2// Object Description: ERZOutro Object3// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges4// Decompiled by: Rubberduckycooly & RMGRich5// ---------------------------------------------------------------------67#include "Game.h"89ObjectERZOutro *ERZOutro;1011void ERZOutro_Update(void)12{13RSDK_THIS(ERZOutro);1415if (!self->activated) {16CutsceneSeq_StartSequence(self, ERZOutro_Cutscene_AttackEggman, ERZOutro_Cutscene_AttackRecoil, ERZOutro_Cutscene_LoseEmeralds,17ERZOutro_Cutscene_OpenPortal, ERZOutro_Cutscene_EnterPortal, ERZOutro_Cutscene_FadeOut,18ERZOutro_Cutscene_ShowEnding, StateMachine_None);1920#if MANIA_USE_PLUS21CutsceneSeq_SetSkipType(SKIPTYPE_DISABLED);22#endif2324self->activated = true;25}26}2728void ERZOutro_LateUpdate(void) {}2930void ERZOutro_StaticUpdate(void) {}3132void ERZOutro_Draw(void) {}3334void ERZOutro_Create(void *data)35{36RSDK_THIS(ERZOutro);3738INIT_ENTITY(self);39CutsceneRules_SetupEntity(self, &self->size, &self->hitbox);40self->active = ACTIVE_NEVER;41}4243void ERZOutro_StageLoad(void)44{45foreach_all(RubyPortal, portal)46{47ERZOutro->rubyPortal = portal;48foreach_break;49}5051foreach_all(PhantomRuby, ruby)52{53ERZOutro->ruby = ruby;54foreach_break;55}5657foreach_all(FXRuby, fxRuby)58{59ERZOutro->fxRuby = fxRuby;60foreach_break;61}6263foreach_all(PhantomKing, king)64{65if (!king->type)66ERZOutro->king = king;67}6869foreach_all(ChaosEmerald, emerald) { ERZStart->emeralds[emerald->type] = emerald; }7071foreach_all(KleptoMobile, eggman)72{73if (!eggman->type)74ERZOutro->eggman = eggman;75}7677ERZOutro->savedGame = false;78}7980void ERZOutro_SetEmeraldStates(void)81{82EntityPhantomRuby *ruby = ERZOutro->ruby;8384for (int32 e = 0; e < 7; ++e) {85EntityChaosEmerald *emerald = ERZStart->emeralds[e];86emerald->originPos.x = ruby->startPos.x;87emerald->originPos.y = ruby->startPos.y;88emerald->radius += 0x400;89emerald->state = ChaosEmerald_State_Rotate;90emerald->visible = true;91}92}9394void ERZOutro_HandleRubyHover(void)95{96EntityPhantomRuby *ruby = ERZOutro->ruby;97EntityFXRuby *fxRuby = ERZOutro->fxRuby;9899ruby->angle += 2;100int32 amplitude = abs(RSDK.Sin256(Zone->timer)) >> 6;101int32 offset = amplitude == 0 ? 0 : RSDK.Rand(-amplitude, amplitude);102103ruby->position.x = (offset << 16) + ruby->startPos.x;104ruby->position.y = (offset << 16) + ruby->startPos.y + (RSDK.Sin256(ruby->angle) << 8);105106fxRuby->position.x = ruby->position.x;107fxRuby->position.y = ruby->position.y;108}109110bool32 ERZOutro_Cutscene_AttackEggman(EntityCutsceneSeq *host)111{112EntityPlayer *player1 = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);113EntityKleptoMobile *eggman = ERZOutro->eggman;114EntityFXRuby *fxRuby = ERZOutro->fxRuby;115EntityERZOutro *entity = (EntityERZOutro *)host->activeEntity;116117uint16 eggmanSlot = RSDK.GetEntitySlot(eggman);118EntityKleptoMobile *eggmanHand = RSDK_GET_ENTITY(eggmanSlot - 2, KleptoMobile);119EntityKleptoMobile *eggmanArmL = RSDK_GET_ENTITY(eggmanSlot - 1, KleptoMobile);120EntityKleptoMobile *eggmanArmR = RSDK_GET_ENTITY(eggmanSlot + 1, KleptoMobile);121122if (!host->timer) {123host->storedValue = player1->rings;124eggman->state = StateMachine_None;125if (player1->characterID == ID_KNUCKLES)126RSDK.SetSpriteAnimation(player1->aniFrames, ANI_GLIDE, &player1->animator, false, 6);127else128RSDK.SetSpriteAnimation(player1->aniFrames, ANI_RUN, &player1->animator, false, 0);129130player1->state = ERZStart_State_PlayerSuperFly;131player1->nextAirState = StateMachine_None;132player1->nextGroundState = StateMachine_None;133player1->onGround = false;134player1->stateInput = StateMachine_None;135136PhantomRuby_PlaySfx(RUBYSFX_ATTACK4);137fxRuby->fadeWhite = 768;138139Zone->playerBoundActiveT[0] = false;140CutsceneSeq_LockPlayerControl(player1);141SceneInfo->timeEnabled = false;142143foreach_all(RingField, field) { field->running = false; }144foreach_all(Ring, ring) { destroyEntity(ring); }145146ERZOutro->playerPos.x = player1->position.x;147ERZOutro->playerPos.y = player1->position.y;148}149150if (fxRuby->fadeWhite > 0)151fxRuby->fadeWhite -= 8;152153int32 posX = entity->position.x - entity->size.x;154int32 posY = entity->position.y;155156if (host->timer <= 0) {157player1->rings = host->storedValue;158}159else if (host->timer < 120) {160if (player1->characterID == ID_KNUCKLES)161RSDK.SetSpriteAnimation(player1->aniFrames, ANI_GLIDE, &player1->animator, false, 6);162else163RSDK.SetSpriteAnimation(player1->aniFrames, ANI_RUN, &player1->animator, false, 0);164165int32 x = player1->position.x;166int32 y = player1->position.y;167player1->position = MathHelpers_GetBezierPoint((host->timer << 16) / 120, ERZOutro->playerPos.x, ERZOutro->playerPos.y, ERZOutro->playerPos.x,168ERZOutro->playerPos.y - 0x2000000, posX - 0x2000000, posY, posX, posY);169170player1->velocity.y = player1->position.y - y;171player1->velocity.x = player1->position.x - x;172player1->direction = x >= player1->position.x;173player1->rings = host->storedValue;174}175else {176player1->position.x = posX;177player1->position.y = posY;178player1->direction = FLIP_NONE;179player1->right = true;180ERZStart_Player_HandleSuperDash(player1);181player1->velocity.y >>= 1;182player1->right = false;183184eggman->originPos = entity->position;185eggman->originPos.x += entity->size.x;186eggman->position = eggman->originPos;187eggman->velocity.x = 0;188eggman->velocity.y = 0;189eggman->direction = FLIP_NONE;190RSDK.SetSpriteAnimation(KleptoMobile->aniFrames, 13, &eggman->eggmanAnimator, true, 0);191eggman->state = KleptoMobile_State_CutsceneControlled;192eggman->holdingRuby = true;193194eggmanHand->state = KleptoMobile_StateHand_Cutscene;195eggmanHand->originPos.x = eggman->position.x;196eggmanHand->originPos.y = eggman->position.y;197eggmanHand->position.x = eggman->position.x;198eggmanHand->position.y = eggman->position.y;199200eggmanArmL->state = KleptoMobile_StateArm_Cutscene;201eggmanArmL->originPos.x = eggman->position.x;202eggmanArmL->originPos.y = eggman->position.y;203eggmanArmL->position.x = eggman->position.x;204eggmanArmL->position.y = eggman->position.y;205206eggmanArmR->state = KleptoMobile_StateArm_Cutscene;207eggmanArmR->originPos.x = eggman->position.x;208eggmanArmR->originPos.y = eggman->position.y;209eggmanArmR->position.x = eggman->position.x;210eggmanArmR->position.y = eggman->position.y;211return true;212}213214return false;215}216217bool32 ERZOutro_Cutscene_AttackRecoil(EntityCutsceneSeq *host)218{219MANIA_GET_PLAYER(player1, player2, camera);220UNUSED(player2);221222EntityKleptoMobile *eggman = ERZOutro->eggman;223EntityFXRuby *fxRuby = ERZOutro->fxRuby;224EntityRubyPortal *portal = ERZOutro->rubyPortal;225EntityPhantomRuby *ruby = ERZOutro->ruby;226227fxRuby->position = eggman->rubyPos;228int32 x = eggman->position.x - 0x400000;229int32 y = eggman->originPos.y - 0x200000;230231if (!host->values[0]) {232if (player1->position.x >= eggman->position.x - 0x200000) {233host->storedTimer = player1->position.y;234235player1->position.x = eggman->position.x - 0x200000;236player1->velocity.x = -0x40000;237player1->velocity.y = -0x40000;238player1->state = Player_State_Static;239player1->superState = SUPERSTATE_FADEOUT;240player1->shield = SHIELD_NONE;241RSDK.SetSpriteAnimation(player1->aniFrames, ANI_HURT, &player1->animator, true, 0);242243host->values[0] = true;244fxRuby->state = FXRuby_State_Expanding;245fxRuby->drawGroup = Zone->objectDrawGroup[0] - 1;246player1->camera = 0;247camera->target = 0;248Camera_SetupLerp(CAMERA_LERP_NORMAL, 0, x, y, 3);249250portal->position.x = x;251portal->position.y = y;252Music_TransitionTrack(TRACK_EGGMAN1, 0.2);253254RSDK.SetSpriteAnimation(KleptoMobile->aniFrames, 16, &eggman->eggmanAnimator, true, 0);255eggman->holdingRuby = false;256eggman->state = KleptoMobile_State_CutsceneExplode;257eggman->timer = 0;258eggman->invincibilityTimer = 48;259eggman->velocity.x = 0x60000;260RSDK.PlaySfx(KleptoMobile->sfxHit, false, 255);261262ruby->visible = true;263ruby->startPos = eggman->rubyPos;264ruby->position = eggman->rubyPos;265}266}267else {268if (!host->values[1]) {269ruby->startPos.x += 0x20000;270if (eggman->velocity.x <= 0x10000)271host->values[1] = true;272else273eggman->velocity.x -= 0x2000;274}275276if (!host->values[2]) {277player1->velocity.y += 0x3800;278if (player1->velocity.y > 0 && player1->position.y >= host->storedTimer) {279RSDK.SetSpriteAnimation(player1->aniFrames, ANI_FAN, &player1->animator, true, 0);280player1->position.y = host->storedTimer;281player1->velocity.x = 0;282player1->velocity.y = 0;283host->values[2] = true;284}285}286287ERZOutro_HandleRubyHover();288289if (host->values[1] && host->values[2])290return true;291}292293player1->rings = host->storedValue;294return false;295}296297bool32 ERZOutro_Cutscene_LoseEmeralds(EntityCutsceneSeq *host)298{299EntityPhantomRuby *ruby = ERZOutro->ruby;300301ERZOutro_HandleRubyHover();302303if (!host->timer) {304int32 angle = 0;305for (int32 e = 0; e < 7; ++e) {306EntityChaosEmerald *emerald = ERZStart->emeralds[e];307emerald->angle = angle;308emerald->radius = 0;309emerald->scale.x = 0x200;310emerald->scale.y = 0x200;311emerald->groundVel = 0x200;312emerald->state = ChaosEmerald_State_Rotate;313emerald->visible = true;314315angle += 0x2492;316}317}318319if (host->timer >= 30) {320for (int32 e = 0; e < 7; ++e) ERZStart->emeralds[e]->radius = 0x2000;321}322else {323for (int32 e = 0; e < 7; ++e) ERZStart->emeralds[e]->radius = (host->timer << 13) / 30;324}325326for (int32 e = 0; e < 7; ++e) ERZStart->emeralds[e]->originPos = ruby->startPos;327328return host->timer == 90;329}330331bool32 ERZOutro_Cutscene_OpenPortal(EntityCutsceneSeq *host)332{333EntityRubyPortal *portal = ERZOutro->rubyPortal;334335ERZOutro_HandleRubyHover();336337if (host->timer == 90) {338portal->state = RubyPortal_State_Opened;339portal->drawGroup = Zone->objectDrawGroup[0];340portal->visible = true;341PhantomRuby_PlaySfx(RUBYSFX_REDCUBE);342}343344if (host->timer >= 90) {345ERZOutro_SetEmeraldStates();346return portal->state == StateMachine_None;347}348349return false;350}351352bool32 ERZOutro_Cutscene_EnterPortal(EntityCutsceneSeq *host)353{354EntityPlayer *player1 = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);355EntityPhantomRuby *ruby = ERZOutro->ruby;356EntityFXRuby *fxRuby = ERZOutro->fxRuby;357EntityRubyPortal *portal = ERZOutro->rubyPortal;358359ERZOutro_SetEmeraldStates();360361if (!host->timer) {362ERZOutro->rubyPortalAcceleration = 0;363364host->storedTimer = RSDK.ATan2(player1->position.x - portal->position.x, player1->position.y - portal->position.y) << 16;365host->storedValue = MathHelpers_Distance(player1->position.x, player1->position.y, portal->position.x, portal->position.y);366367player1->drawFX |= FX_SCALE;368player1->scale.x = 0x200;369player1->scale.y = 0x200;370}371372if (host->timer == 60)373PhantomRuby_SetupFlash(ruby);374375if (host->timer < 108) {376ERZOutro_HandleRubyHover();377}378else {379if (host->timer == 108) {380ERZOutro_HandleRubyHover();381382ruby->startPos.x = ruby->position.x;383ruby->startPos.y = ruby->position.y;384385ERZOutro->rubyPortalAngle = RSDK.ATan2(ruby->position.x - portal->position.x, ruby->position.y - portal->position.y) << 16;386ERZOutro->rubyPortalRadius = MathHelpers_Distance(ruby->position.x, ruby->position.y, portal->position.x, portal->position.y);387388ruby->drawFX |= FX_SCALE;389ruby->scale.x = 0x200;390ruby->scale.y = 0x200;391PhantomRuby_PlaySfx(RUBYSFX_ATTACK4);392393Music_FadeOut(0.2);394}395396ERZOutro->rubyPortalAcceleration += 0x800;397398host->storedTimer += ERZOutro->rubyPortalAcceleration;399host->storedTimer &= 0xFFFFFF00;400player1->position.x = portal->position.x;401player1->position.y = portal->position.y;402player1->position.x += ((host->storedValue >> 9) & 0xFFFFFF80) * RSDK.Cos512(host->storedTimer >> 15);403player1->position.y += ((host->storedValue >> 9) & 0xFFFFFF80) * RSDK.Sin512(host->storedTimer >> 15);404405ERZOutro->rubyPortalAngle += ERZOutro->rubyPortalAcceleration;406ERZOutro->rubyPortalAngle &= 0xFFFFFF00;407ruby->position.x = portal->position.x;408ruby->position.y = portal->position.y;409ruby->position.x += ((ERZOutro->rubyPortalRadius >> 9) & 0xFFFFFF80) * RSDK.Cos512(ERZOutro->rubyPortalAngle >> 15);410ruby->position.y += ((ERZOutro->rubyPortalRadius >> 9) & 0xFFFFFF80) * RSDK.Sin512(ERZOutro->rubyPortalAngle >> 15);411412if (fxRuby->fadeWhite >= 0x200)413host->values[0] = true;414else415fxRuby->fadeWhite += 2;416417int32 rx = abs(portal->position.x - player1->position.x) >> 16;418int32 ry = abs(portal->position.y - player1->position.y) >> 16;419int32 dist = MathHelpers_SquareRoot(rx * rx + ry * ry);420421player1->scale.x = 8 * MIN(dist, 0x40);422player1->scale.y = 8 * MIN(dist, 0x40);423424rx = abs(portal->position.x - ruby->position.x) >> 16;425ry = abs(portal->position.y - ruby->position.y) >> 16;426dist = MathHelpers_SquareRoot(rx * rx + ry * ry);427ruby->scale.x = 8 * MIN(dist, 0x40);428ruby->scale.y = 8 * MIN(dist, 0x40);429430if (ERZOutro->rubyPortalRadius > 0)431ERZOutro->rubyPortalRadius -= 0x8000;432433if (host->storedValue <= 0)434host->values[1] = true;435else436host->storedValue -= 0x8000;437438return host->values[0] && host->values[1];439}440441return false;442}443444bool32 ERZOutro_Cutscene_FadeOut(EntityCutsceneSeq *host)445{446EntityFXRuby *fxRuby = (EntityFXRuby *)ERZOutro->fxRuby;447ERZOutro_HandleRubyHover();448449if (host->timer >= 90) {450if (fxRuby->fadeBlack < 512)451fxRuby->fadeBlack += 8;452453return host->timer == 150;454}455456return false;457}458459bool32 ERZOutro_Cutscene_ShowEnding(EntityCutsceneSeq *host)460{461if (globals->saveSlotID != NO_SAVE_SLOT) {462if (!host->timer) {463ERZOutro->savedGame = false;464SaveGame_SaveProgress();465GameProgress_GiveEnding(GAMEPROGRESS_ENDING_GOOD);466SaveGame_SaveFile(ERZOutro_SaveFileCB);467UIWaitSpinner_StartWait();468}469470if (!ERZOutro->savedGame)471return false;472473UIWaitSpinner_FinishWait();474}475476API_UnlockAchievement(&achievementList[ACH_GAME_CLEARED]);477478if (CHECK_CHARACTER_ID(ID_KNUCKLES, 1) && CHECK_CHARACTER_ID(ID_KNUCKLES, 2))479RSDK.SetScene("Videos", "True End?");480else481RSDK.SetScene("Videos", "Good End");482483RSDK.LoadScene();484return true;485}486487#if MANIA_USE_PLUS488void ERZOutro_SaveFileCB(bool32 success) { ERZOutro->savedGame = true; }489#else490void ERZOutro_SaveFileCB(void) { ERZOutro->savedGame = true; }491#endif492493#if GAME_INCLUDE_EDITOR494void ERZOutro_EditorDraw(void)495{496RSDK_THIS(ERZOutro);497498CutsceneRules_DrawCutsceneBounds(self, &self->size);499}500501void ERZOutro_EditorLoad(void) {}502#endif503504void ERZOutro_Serialize(void) { RSDK_EDITABLE_VAR(ERZOutro, VAR_VECTOR2, size); }505506507