Path: blob/master/SonicMania/Objects/Cutscene/RubyPortal.c
338 views
// ---------------------------------------------------------------------1// RSDK Project: Sonic Mania2// Object Description: RubyPortal Object3// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges4// Decompiled by: Rubberduckycooly & RMGRich5// ---------------------------------------------------------------------67#include "Game.h"89ObjectRubyPortal *RubyPortal;1011void RubyPortal_Update(void)12{13RSDK_THIS(RubyPortal);1415RSDK.ProcessAnimation(&self->animator);1617StateMachine_Run(self->state);18}1920void RubyPortal_LateUpdate(void) {}2122void RubyPortal_StaticUpdate(void) {}2324void RubyPortal_Draw(void)25{26RSDK_THIS(RubyPortal);2728RSDK.CopyPalette(0, 160, 1, 160, 16);29RSDK.CopyPalette(2, 160, 0, 160, 16);3031RSDK.DrawSprite(&self->animator, NULL, false);3233RSDK.CopyPalette(1, 160, 0, 160, 16);34}3536void RubyPortal_Create(void *data)37{38RSDK_THIS(RubyPortal);3940self->drawFX = FX_SCALE;41self->inkEffect = INK_ALPHA;4243if (!SceneInfo->inEditor) {44self->active = ACTIVE_BOUNDS;45self->visible = true;46self->drawGroup = Zone->objectDrawGroup[0];47self->updateRange.x = TO_FIXED(128);48self->updateRange.y = TO_FIXED(128);4950RSDK.SetSpriteAnimation(RubyPortal->aniFrames, 0, &self->animator, true, 0);5152#if MANIA_USE_PLUS53if (data) {54self->state = (Type_StateMachine)data;55}56else if (RSDK.CheckSceneFolder("ERZ")) {57self->state = StateMachine_None;58}59else if (RSDK.CheckSceneFolder("TMZ2")) {60EntityWarpDoor *door = RSDK_GET_ENTITY(SceneInfo->entitySlot - 1, WarpDoor);6162if (door->classID == WarpDoor->classID) {63self->hitbox = door->hitbox;64door->hitbox.left = 0;65door->hitbox.top = 0x7FFF;66door->hitbox.right = 0;67door->hitbox.bottom = 0x7FFF;68}6970self->state = RubyPortal_State_AwaitOpenTMZ2;7172if (StarPost->postIDs[0])73TMZ2Setup_DrawDynTiles_Ruby();74else75TMZ2Setup_DrawDynTiles_Eggman();76}77else {78self->state = RubyPortal_State_Opening;79}80#else81self->state = StateMachine_None;8283if (!RSDK.CheckSceneFolder("ERZ")) {84EntityWarpDoor *door = RSDK_GET_ENTITY(SceneInfo->entitySlot - 1, WarpDoor);8586if (door->classID == WarpDoor->classID) {87self->hitbox = door->hitbox;88door->hitbox.left = 0;89door->hitbox.top = 0x7FFF;90door->hitbox.right = 0;91door->hitbox.bottom = 0x7FFF;92}9394self->state = RubyPortal_State_AwaitOpenTMZ2;9596if (StarPost->postIDs[0])97TMZ2Setup_DrawDynTiles_Ruby();98else99TMZ2Setup_DrawDynTiles_Eggman();100}101#endif102}103}104105void RubyPortal_StageLoad(void)106{107if (RSDK.CheckSceneFolder("ERZ"))108RubyPortal->aniFrames = RSDK.LoadSpriteAnimation("Phantom/Portal.bin", SCOPE_STAGE);109#if MANIA_USE_PLUS110else if (RSDK.CheckSceneFolder("AIZ"))111RubyPortal->aniFrames = RSDK.LoadSpriteAnimation("AIZ/Portal.bin", SCOPE_STAGE);112else113#else // preplus has an explicit check114else if (RSDK.CheckSceneFolder("TMZ2"))115#endif116RubyPortal->aniFrames = RSDK.LoadSpriteAnimation("TMZ1/Portal.bin", SCOPE_STAGE);117118RubyPortal->hitbox.left = -24;119RubyPortal->hitbox.top = -24;120RubyPortal->hitbox.right = 24;121RubyPortal->hitbox.bottom = 24;122123#if MANIA_USE_PLUS124RubyPortal->openPortal = false;125RSDK.AddViewableVariable("Open Portal", &RubyPortal->openPortal, VIEWVAR_BOOL, false, true);126#endif127}128129#if MANIA_USE_PLUS130void RubyPortal_HandleTileDestruction(void)131{132RSDK_THIS(RubyPortal);133134if (!(Zone->timer & 1)) {135int32 tx = ((self->position.x - 0x180000) >> 20);136int32 spawnX = (tx << 20) + 0x80000;137138for (int32 x = 0; x < 4; ++x) {139int32 ty = (self->position.y >> 20) - 8;140int32 spawnY = (ty << 20) + 0x80000;141142for (int32 y = 4; y < 52; y += 3) {143uint16 tile = RSDK.GetTile(Zone->fgLayer[0], tx, ty);144if (tile != (uint16)-1) {145EntityBreakableWall *wall = CREATE_ENTITY(BreakableWall, INT_TO_VOID(BREAKWALL_TILE_FIXED), spawnX, spawnY);146147wall->drawGroup = Zone->objectDrawGroup[0] + 1;148wall->targetLayer = Zone->fgLayer[0];149wall->tileInfo = tile;150wall->drawFX = FX_SCALE | FX_ROTATE | FX_FLIP;151wall->tilePos.x = tx;152wall->tilePos.y = ty;153wall->timer = y;154wall->scale.x = 0x200;155wall->scale.y = 0x200;156wall->velocity.x = RSDK.Rand(-0x20000, 0x20000);157wall->velocity.y = RSDK.Rand(-0x20000, 0x20000);158wall->gravityStrength = 0;159wall->active = ACTIVE_NORMAL;160161RSDK.SetTile(Zone->fgLayer[0], tx, ty, -1);162}163164tile = RSDK.GetTile(Zone->fgLayer[1], tx, ty);165if (tile != (uint16)-1) {166EntityBreakableWall *wall = CREATE_ENTITY(BreakableWall, INT_TO_VOID(BREAKWALL_TILE_FIXED), spawnX, spawnY);167168wall->drawGroup = Zone->objectDrawGroup[1];169wall->targetLayer = Zone->fgLayer[1];170wall->tileInfo = tile;171wall->drawFX = FX_SCALE | FX_ROTATE | FX_FLIP;172wall->tilePos.x = tx;173wall->tilePos.y = ty;174wall->timer = y;175wall->scale.x = 0x200;176wall->scale.y = 0x200;177wall->velocity.x = RSDK.Rand(-0x20000, 0x20000);178wall->velocity.y = RSDK.Rand(-0x20000, 0x20000);179wall->gravityStrength = 0;180wall->active = ACTIVE_NORMAL;181182RSDK.SetTile(Zone->fgLayer[1], tx, ty, -1);183}184185spawnY += 0x100000;186ty++;187}188189spawnX += 0x100000;190tx++;191}192}193}194#endif195196void RubyPortal_State_AwaitOpenTMZ2(void)197{198RSDK_THIS(RubyPortal);199200#if MANIA_USE_PLUS201if (TMZBarrier->clearedBarriers == (1 | 2 | 4 | 8) || RubyPortal->openPortal)202#else203if (TMZBarrier->clearedBarriers == (1 | 2 | 4 | 8))204#endif205self->state = RubyPortal_State_Opening;206}207208void RubyPortal_State_Opening(void)209{210RSDK_THIS(RubyPortal);211212if (++self->timer >= 120) {213self->visible = true;214215#if MANIA_USE_PLUS216if (globals->gameMode == MODE_MANIA)217self->state = RubyPortal_State_Opened;218else if (!isMainGameMode())219self->state = RubyPortal_State_Open_WarpDoor;220else if (WarpDoor)221self->state = RubyPortal_State_Opened;222else if (self->timer >= 240)223self->state = RubyPortal_State_Open_Cutscene;224#else225if (!isMainGameMode())226self->state = RubyPortal_State_Open_WarpDoor;227else228self->state = RubyPortal_State_Opened;229#endif230}231}232233void RubyPortal_State_Opened(void)234{235RSDK_THIS(RubyPortal);236237if (self->alpha >= 0x100) {238if (RSDK.CheckSceneFolder("ERZ")) {239self->state = StateMachine_None;240}241else {242EntityPlayer *player1 = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);243if (Player_CheckCollisionTouch(player1, self, &RubyPortal->hitbox)) {244for (int32 p = 0; p < Player->playerCount; ++p) StarPost->postIDs[p] = 0;245246SaveGame_SavePlayerState();247248#if !MANIA_USE_PLUS && GAME_VERSION != VER_100249if (player1->superState == SUPERSTATE_SUPER)250globals->restartPowerups |= 0x80;251#endif252253globals->suppressAutoMusic = true;254globals->suppressTitlecard = true;255256if (player1->invincibleTimer <= 1) {257if (player1->speedShoesTimer > 1)258player1->speedShoesTimer = 1;259}260else {261player1->invincibleTimer = 1;262}263264++SceneInfo->listPos;265if (!RSDK.CheckValidScene())266RSDK.SetScene("Presentation", "Title Screen");267268Zone_StartFadeOut(16, 0xF0F0F0);269270#if MANIA_USE_PLUS271self->state = RubyPortal_State_SaveGameState;272#else273self->state = StateMachine_None;274#endif275276int32 sfx = RSDK.Rand(0, RUBYSFX_ATTACK6);277int32 channel = RSDK.PlaySfx(WarpDoor->sfxRubyAttackL[sfx], false, 0x00);278RSDK.SetChannelAttributes(channel, 1.0, -1.0, 1.0);279280channel = RSDK.PlaySfx(WarpDoor->sfxRubyAttackR[sfx], false, 0x00);281RSDK.SetChannelAttributes(channel, 1.0, 1.0, 1.0);282}283}284}285else {286self->scale.x += 8;287self->scale.y += 8;288self->alpha += 4;289}290}291292#if MANIA_USE_PLUS293void RubyPortal_State_SaveGameState(void)294{295EntityPlayer *player = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);296297if (player->superState == SUPERSTATE_SUPER || player->state == Player_State_Transform)298globals->restartPowerups |= 0x80;299300globals->restartMusicID = Music->activeTrack;301}302#endif303304void RubyPortal_State_Open_WarpDoor(void)305{306RSDK_THIS(RubyPortal);307308if (self->alpha >= 0x100) {309EntityWarpDoor *warpDoor = RSDK_GET_ENTITY(SceneInfo->entitySlot - 1, WarpDoor);310if (warpDoor->classID == WarpDoor->classID)311warpDoor->hitbox = self->hitbox;312313self->state = StateMachine_None;314}315else {316self->scale.x += 8;317self->scale.y += 8;318319self->alpha += 4;320}321}322323void RubyPortal_State_Open_Cutscene(void)324{325RSDK_THIS(RubyPortal);326327if (self->alpha >= 0x100) {328self->state = StateMachine_None;329}330else {331self->scale.x += 8;332self->scale.y += 8;333self->alpha += 4;334}335}336337#if MANIA_USE_PLUS338void RubyPortal_State_EncoreEnd(void)339{340RSDK_THIS(RubyPortal);341342if (!self->timer)343self->visible = true;344345self->timer++;346if (self->alpha >= 0x100) {347if (self->timer == 240) {348self->timer = 0;349self->state = RubyPortal_State_EncoreRampage;350351EntityFXFade *fade = CREATE_ENTITY(FXFade, INT_TO_VOID(0xF0F0F0), self->position.x, self->position.y);352fade->speedIn = 512;353fade->wait = 16;354fade->speedOut = 16;355356PhantomRuby_PlaySfx(RUBYSFX_ATTACK1);357}358}359else {360self->scale.x += 8;361self->scale.y += 8;362self->alpha += 4;363}364}365366void RubyPortal_State_EncoreRampage(void)367{368RSDK_THIS(RubyPortal);369370RubyPortal_HandleTileDestruction();371372self->position.x += self->velocity.x;373374foreach_active(BreakableWall, wall)375{376int32 rx = (self->position.x - wall->position.x) >> 16;377int32 ry = (self->position.y - wall->position.y) >> 16;378int32 angle = RSDK.ATan2(rx, ry);379380wall->velocity.x += 8 * RSDK.Cos256(angle);381wall->velocity.y += 8 * RSDK.Sin256(angle);382wall->position.x += self->velocity.x;383384++wall->timer;385if (wall->timer == 60) {386wall->inkEffect = INK_ALPHA;387wall->alpha = 0x100;388}389else if (wall->timer > 60) {390wall->alpha -= 8;391}392393if (rx * rx + ry * ry < 0x900) {394wall->scale.x -= 0x0C;395wall->scale.y -= 0x0C;396wall->velocity.x = (self->position.x - wall->position.x) >> 3;397wall->velocity.y = (self->position.y - wall->position.y) >> 3;398399if (wall->scale.x <= 0)400destroyEntity(wall);401}402}403404foreach_active(Debris, debris)405{406int32 rx = (self->position.x - debris->position.x) >> 16;407int32 ry = (self->position.y - debris->position.y) >> 16;408if (rx * rx + ry * ry < 0x900) {409debris->scale.x -= 0x0C;410debris->scale.y -= 0x0C;411412debris->gravityStrength = 0;413debris->position.x += self->velocity.x;414debris->velocity.x = (self->position.x - debris->position.x) >> 3;415debris->velocity.y = (self->position.y - debris->position.y) >> 3;416417if (debris->scale.x <= 0)418destroyEntity(debris);419}420}421422foreach_active(PhantomRuby, ruby) { ruby->position.x += self->velocity.x; }423}424#endif425426#if GAME_INCLUDE_EDITOR427void RubyPortal_EditorDraw(void)428{429RSDK_THIS(RubyPortal);430431self->visible = true;432self->drawGroup = Zone->objectDrawGroup[0];433self->scale.x = 0x200;434self->scale.y = 0x200;435self->alpha = 0xFF;436RSDK.SetSpriteAnimation(RubyPortal->aniFrames, 0, &self->animator, true, 0);437438RSDK.DrawSprite(&self->animator, NULL, false);439}440441void RubyPortal_EditorLoad(void)442{443if (RSDK.CheckSceneFolder("ERZ"))444RubyPortal->aniFrames = RSDK.LoadSpriteAnimation("Phantom/Portal.bin", SCOPE_STAGE);445#if MANIA_USE_PLUS446else if (RSDK.CheckSceneFolder("AIZ"))447RubyPortal->aniFrames = RSDK.LoadSpriteAnimation("AIZ/Portal.bin", SCOPE_STAGE);448else449#else // preplus has an explicit check450else if (RSDK.CheckSceneFolder("TMZ2"))451#endif452RubyPortal->aniFrames = RSDK.LoadSpriteAnimation("TMZ1/Portal.bin", SCOPE_STAGE);453}454#endif455456void RubyPortal_Serialize(void) {}457458459