Path: blob/master/SonicMania/Objects/FBZ/BigSqueeze.c
338 views
// ---------------------------------------------------------------------1// RSDK Project: Sonic Mania2// Object Description: BigSqueeze Object3// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges4// Decompiled by: Rubberduckycooly & RMGRich5// ---------------------------------------------------------------------67#include "Game.h"89ObjectBigSqueeze *BigSqueeze;1011void BigSqueeze_Update(void)12{13RSDK_THIS(BigSqueeze);1415StateMachine_Run(self->state);16}1718void BigSqueeze_LateUpdate(void) {}1920void BigSqueeze_StaticUpdate(void) {}2122void BigSqueeze_Draw(void)23{24RSDK_THIS(BigSqueeze);2526if (self->stateDraw) {27StateMachine_Run(self->stateDraw);28}29else {30RSDK.DrawSprite(&self->animator, NULL, false);31}32}3334void BigSqueeze_Create(void *data)35{36RSDK_THIS(BigSqueeze);3738if (!SceneInfo->inEditor) {39if (globals->gameMode < MODE_TIMEATTACK) {40self->active = ACTIVE_BOUNDS;4142switch (self->type) {43case BIGSQUEEZE_MANAGER:44self->updateRange.x = 0x800000;45self->updateRange.y = 0x800000;46self->visible = false;4748self->hitbox.left = -256;49self->hitbox.top = 0;50self->hitbox.right = 256;51self->hitbox.bottom = 32;5253self->state = BigSqueeze_StateManager_SetupIntro;54break;5556case BIGSQUEEZE_BOSS:57self->updateRange.x = 0x8000000;58self->updateRange.y = 0x1000000;59self->visible = true;60self->drawGroup = Zone->objectDrawGroup[1];6162self->hitbox.left = -32;63self->hitbox.top = -16;64self->hitbox.right = 32;65self->hitbox.bottom = 16;6667self->timer = 6;68RSDK.SetSpriteAnimation(BigSqueeze->aniFrames, 1, &self->animator, true, 0);69RSDK.SetSpriteAnimation(BigSqueeze->aniFrames, 2, &self->domeAnimator, true, 0);70RSDK.SetSpriteAnimation(BigSqueeze->aniFrames, 3, &self->prongsAnimator, true, 0);71RSDK.SetSpriteAnimation(BigSqueeze->aniFrames, 4, &self->wheelAnimator, true, 0);7273self->stateDraw = BigSqueeze_Draw_Boss;74break;7576case BIGSQUEEZE_CRUSHER_L:77case BIGSQUEEZE_CRUSHER_R:78if (self->type == BIGSQUEEZE_CRUSHER_R) {79self->direction = FLIP_X;80self->drawFX = FX_FLIP;81}82self->updateRange.x = 0x8000000;83self->updateRange.y = 0x1000000;84self->visible = true;85self->drawGroup = Zone->objectDrawGroup[1];8687RSDK.SetSpriteAnimation(BigSqueeze->aniFrames, 0, &self->animator, true, 0);8889self->hitbox.left = -24;90self->hitbox.top = -120;91self->hitbox.right = 24;92self->hitbox.bottom = 120;9394self->stateDraw = BigSqueeze_Draw_Crusher;95break;9697default: break;98}99}100else {101destroyEntity(self);102}103}104}105106void BigSqueeze_StageLoad(void)107{108BigSqueeze->active = ACTIVE_ALWAYS;109110BigSqueeze->aniFrames = RSDK.LoadSpriteAnimation("FBZ/BigSqueeze.bin", SCOPE_STAGE);111112BigSqueeze->sfxBossHit = RSDK.GetSfx("Stage/BossHit.wav");113BigSqueeze->sfxExplosion2 = RSDK.GetSfx("Stage/Explosion2.wav");114BigSqueeze->sfxMagnet = RSDK.GetSfx("FBZ/Magnet.wav");115BigSqueeze->sfxOrbinaut = RSDK.GetSfx("FBZ/Orbinaut.wav");116117BigSqueeze->crushTimer = 0;118BigSqueeze->isCrushing = false;119120Soundboard_LoadSfx("Stage/Rumble.wav", true, BigSqueeze_SfxCheck_Rumble, StateMachine_None);121}122123bool32 BigSqueeze_SfxCheck_Rumble(void) { return BigSqueeze->isCrushing && SceneInfo->state == ENGINESTATE_REGULAR; }124125void BigSqueeze_HandleWallCollisions(void)126{127RSDK_THIS(BigSqueeze);128129foreach_active(Player, player)130{131int32 side = Player_CheckCollisionBox(player, self, &self->hitbox);132133if (side == C_RIGHT)134player->collisionFlagH |= 2;135else if (side == C_LEFT)136player->collisionFlagH |= 1;137}138139foreach_active(SignPost, signPost)140{141if (signPost->state == SignPost_State_Falling) {142if (signPost->velocity.x >= 0) {143if (signPost->position.x > self->position.x + ((self->hitbox.left - 24) << 16) && signPost->position.x < self->position.x)144signPost->velocity.x = -signPost->velocity.x;145}146else {147if (signPost->position.x < self->position.x + ((self->hitbox.right + 24) << 16) && signPost->position.x > self->position.x)148signPost->velocity.x = -signPost->velocity.x;149}150}151}152}153154void BigSqueeze_CheckPlayerCollisions_Vulnerable(void)155{156RSDK_THIS(BigSqueeze);157158if (!self->invincible) {159if (self->invincibilityTimer > 0)160self->invincibilityTimer--;161162foreach_active(Player, player)163{164if (!self->invincibilityTimer && Player_CheckBadnikTouch(player, self, &self->hitbox) && Player_CheckBossHit(player, self))165BigSqueeze_Hit();166}167}168}169170void BigSqueeze_CheckPlayerCollisions_Electrified(void)171{172RSDK_THIS(BigSqueeze);173174if (!self->invincible) {175if (self->invincibilityTimer > 0)176self->invincibilityTimer--;177178foreach_active(Player, player)179{180if (!self->invincibilityTimer && Player_CheckBadnikTouch(player, self, &self->hitbox)) {181if (player->invincibleTimer || player->blinkTimer > 0 || player->shield == SHIELD_LIGHTNING) {182if (Player_CheckBossHit(player, self))183BigSqueeze_Hit();184}185else {186Player_Hurt(player, self);187}188}189}190}191}192193void BigSqueeze_Hit(void)194{195RSDK_THIS(BigSqueeze);196197if (--self->timer <= 0) {198foreach_active(BigSqueeze, boss)199{200if (boss->type == BIGSQUEEZE_CRUSHER_L || boss->type == BIGSQUEEZE_CRUSHER_R)201boss->state = BigSqueeze_HandleWallCollisions;202}203204RSDK.SetSpriteAnimation(-1, 0, &self->electricAnimator, true, 0);205206self->state = BigSqueeze_StateBoss_Destroyed;207self->setupTimer = 0;208SceneInfo->timeEnabled = false;209EntityPlayer *player = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);210Player_GiveScore(player, 1000);211}212else {213self->invincibilityTimer = 48;214RSDK.PlaySfx(BigSqueeze->sfxBossHit, false, 255);215}216}217218void BigSqueeze_Explode(void)219{220RSDK_THIS(BigSqueeze);221222if (!(Zone->timer % 3)) {223RSDK.PlaySfx(BigSqueeze->sfxExplosion2, false, 0xFF);224225if (Zone->timer & 4) {226int32 x = (RSDK.Rand(self->hitbox.left, self->hitbox.right) << 16) + self->position.x;227int32 y = (RSDK.Rand(self->hitbox.top, self->hitbox.bottom) << 16) + self->position.y;228CREATE_ENTITY(Explosion, INT_TO_VOID((RSDK.Rand(0, 256) > 192) + EXPLOSION_BOSS), x, y)->drawGroup = Zone->objectDrawGroup[1];229}230}231}232233void BigSqueeze_HandleBossMovement(void)234{235RSDK_THIS(BigSqueeze);236237if (BigSqueeze->crushTimer < 10)238self->position.x += self->velocity.x;239240foreach_active(BigSqueeze, boss)241{242if (boss->type == BIGSQUEEZE_CRUSHER_L) {243if (self->position.x < boss->position.x + 0x340000 && self->velocity.x < 0)244self->velocity.x = -self->velocity.x;245}246else if (boss->type == BIGSQUEEZE_CRUSHER_R) {247if (self->position.x > boss->position.x - 0x340000 && self->velocity.x > 0)248self->velocity.x = -self->velocity.x;249}250}251252RSDK.ProcessAnimation(&self->wheelAnimator);253}254255// debrisInfo format:256// - count257// <for count entries>258// - frameID259// - velocityX260// - velocityY261262void BigSqueeze_SpawnDebris(int32 *debrisInfo)263{264RSDK_THIS(BigSqueeze);265if (debrisInfo) {266int32 count = debrisInfo[0];267debrisInfo++;268269for (int32 i = 0; i < count; ++i) {270EntityDebris *debris = CREATE_ENTITY(Debris, Debris_State_FallAndFlicker, self->position.x, self->position.y);271272RSDK.SetSpriteAnimation(BigSqueeze->aniFrames, 6, &debris->animator, true, debrisInfo[0]);273debris->velocity.x = debrisInfo[1];274debris->velocity.y = debrisInfo[2];275debris->gravityStrength = 0x3800;276debris->drawGroup = Zone->objectDrawGroup[1];277debris->updateRange.x = 0x800000;278debris->updateRange.y = 0x800000;279280debrisInfo += 3;281}282}283}284285void BigSqueeze_Draw_Boss(void)286{287RSDK_THIS(BigSqueeze);288Vector2 drawPos;289290if (self->invincibilityTimer & 1) {291RSDK.SetPaletteEntry(0, 156, 0xE0E0E0);292RSDK.SetPaletteEntry(0, 33, 0xE0E0E0);293}294295RSDK.DrawSprite(&self->animator, NULL, false);296RSDK.DrawSprite(&self->domeAnimator, NULL, false);297RSDK.DrawSprite(&self->prongsAnimator, NULL, false);298RSDK.DrawSprite(&self->electricAnimator, NULL, false);299300RSDK.SetPaletteEntry(0, 156, 0x202020);301RSDK.SetPaletteEntry(0, 33, 0x303840);302drawPos.x = self->position.x;303drawPos.y = self->position.y;304305drawPos.x -= 0x140000;306RSDK.DrawSprite(&self->wheelAnimator, &drawPos, false);307308drawPos.x += 0x280000;309RSDK.DrawSprite(&self->wheelAnimator, &drawPos, false);310}311312void BigSqueeze_Draw_Crusher(void)313{314RSDK_THIS(BigSqueeze);315316self->animator.frameID = 0;317RSDK.DrawSprite(&self->animator, NULL, false);318319self->animator.frameID = 1;320RSDK.DrawSprite(&self->animator, NULL, false);321322self->animator.frameID = 2;323RSDK.DrawSprite(&self->animator, NULL, false);324}325326void BigSqueeze_StateManager_SetupIntro(void)327{328RSDK_THIS(BigSqueeze);329330if (++self->setupTimer >= 8) {331self->setupTimer = 0;332foreach_all(CollapsingPlatform, platform)333{334platform->collapseDelay = 1;335platform->active = ACTIVE_NEVER;336}337338foreach_active(Eggman, eggman) { eggman->direction = FLIP_X; }339340Zone->playerBoundActiveL[0] = true;341Zone->playerBoundActiveR[0] = true;342Zone->cameraBoundsL[0] = (self->position.x >> 16) - WIDE_SCR_XCENTER;343Zone->cameraBoundsR[0] = (self->position.x >> 16) + 308;344self->state = BigSqueeze_StateManager_SetupEggman;345}346}347348void BigSqueeze_StateManager_SetupEggman(void)349{350RSDK_THIS(BigSqueeze);351352if (self->setupTimer) {353self->setupTimer++;354EntityEggman *eggmanPtr = self->eggman;355356if (self->setupTimer == 104)357RSDK.SetSpriteAnimation(Eggman->aniFrames, 5, &eggmanPtr->animator, true, 0);358359if (self->setupTimer == 120) {360self->setupTimer = 0;361self->state = BigSqueeze_StateManager_SetupArena;362eggmanPtr->onGround = false;363eggmanPtr->velocity.x = -0x10000;364eggmanPtr->velocity.y = -0x40000;365eggmanPtr->state = Eggman_State_ProcessAirThenSet;366eggmanPtr->animID = 2;367}368}369else {370if (RSDK_GET_ENTITY(SLOT_PLAYER1, Player)->position.x > self->position.x) {371Music_TransitionTrack(TRACK_MINIBOSS, 0.0125);372++self->setupTimer;373374foreach_active(LightBarrier, barrier) { barrier->enabled = true; }375376foreach_active(Eggman, eggman)377{378self->eggman = eggman;379RSDK.SetSpriteAnimation(Eggman->aniFrames, 2, &eggman->animator, true, 0);380eggman->state = Eggman_State_ProcessThenSet;381eggman->animID = 0;382}383}384}385}386387void BigSqueeze_StateManager_SetupArena(void)388{389RSDK_THIS(BigSqueeze);390391EntityEggman *eggman = self->eggman;392if (eggman->state == Eggman_State_ProcessAnimation) {393foreach_all(CollapsingPlatform, platform) { platform->active = ACTIVE_BOUNDS; }394395Zone->cameraBoundsR[0] = (self->position.x >> 16) + WIDE_SCR_XCENTER;396Zone->cameraBoundsB[0] = 1792;397Zone->cameraBoundsT[0] = Zone->cameraBoundsB[0] - ScreenInfo->size.y;398399BigSqueeze->boundsB = (Zone->cameraBoundsB[0] - 16) << 16;400eggman->state = Eggman_State_ProcessThenSet;401eggman->animID = 0;402self->state = BigSqueeze_StateManager_SetupBoss;403}404}405406void BigSqueeze_StateManager_SetupBoss(void)407{408RSDK_THIS(BigSqueeze);409410if (++self->setupTimer == 48) {411foreach_active(BigSqueeze, boss)412{413switch (boss->type) {414default: break;415416case BIGSQUEEZE_BOSS:417boss->invincible = true;418boss->state = BigSqueeze_StateBoss_Idle;419boss->velocity.x = -0x10000;420break;421422case BIGSQUEEZE_CRUSHER_L:423boss->state = BigSqueeze_StateCrusher_BeginCrushing;424boss->velocity.x = 0x8000;425boss->hitbox.top = -0x7FFF;426break;427428case BIGSQUEEZE_CRUSHER_R:429boss->state = BigSqueeze_StateCrusher_BeginCrushing;430boss->velocity.x = -0x8000;431boss->hitbox.top = -0x7FFF;432break;433}434}435436self->state = BigSqueeze_StateManager_HandleBoss;437}438}439440void BigSqueeze_StateBoss_Idle(void)441{442RSDK_THIS(BigSqueeze);443444if (self->setupTimer > 30)445BigSqueeze_HandleBossMovement();446447if (++self->setupTimer == 180) {448self->invincible = false;449self->setupTimer = 0;450RSDK.SetSpriteAnimation(BigSqueeze->aniFrames, 5, &self->electricAnimator, true, 0);451self->state = BigSqueeze_StateBoss_Electrified;452}453454BigSqueeze_CheckPlayerCollisions_Vulnerable();455}456457void BigSqueeze_StateBoss_Electrified(void)458{459RSDK_THIS(BigSqueeze);460461RSDK.ProcessAnimation(&self->domeAnimator);462463// Uncomment this line if you want the prongs to animate when the boss is attacking464// This is all that's needed to get them animating with no issues, so I assume this line being absent was prolly an oversight?465// RSDK.ProcessAnimation(&self->prongsAnimator);466467RSDK.ProcessAnimation(&self->electricAnimator);468469if (!self->setupTimer)470RSDK.PlaySfx(BigSqueeze->sfxOrbinaut, false, 255);471472if (++self->setupTimer == 16)473FBZTrash_SummonOrbinaut(self->position.x, self->position.y + 0x300000);474475if (self->setupTimer == 120) {476self->setupTimer = 0;477RSDK.SetSpriteAnimation(BigSqueeze->aniFrames, 2, &self->domeAnimator, true, 0);478RSDK.SetSpriteAnimation(-1, 0, &self->electricAnimator, true, 0);479self->state = BigSqueeze_StateBoss_Idle;480}481482if (!(Zone->timer & 0xF))483RSDK.PlaySfx(BigSqueeze->sfxMagnet, false, 255);484485BigSqueeze_CheckPlayerCollisions_Electrified();486}487488void BigSqueeze_StateBoss_Destroyed(void)489{490RSDK_THIS(BigSqueeze);491492BigSqueeze_Explode();493494++self->setupTimer;495if (self->type == BIGSQUEEZE_BOSS) {496switch (self->setupTimer) {497case 20:498BigSqueeze_SpawnDebris(BigSqueeze->prongDebrisInfo);499RSDK.SetSpriteAnimation(-1, 0, &self->prongsAnimator, true, 0);500break;501502case 40:503BigSqueeze_SpawnDebris(BigSqueeze->domeDebrisInfo);504RSDK.SetSpriteAnimation(-1, 0, &self->domeAnimator, true, 0);505break;506507case 60:508BigSqueeze_SpawnDebris(BigSqueeze->baseDebrisInfo);509RSDK.SetSpriteAnimation(-1, 0, &self->animator, true, 0);510RSDK.SetSpriteAnimation(-1, 0, &self->wheelAnimator, true, 0);511break;512513case 80:514Music_TransitionTrack(TRACK_STAGE, 0.0125);515self->setupTimer = 0;516self->visible = false;517self->state = BigSqueeze_StateBoss_DropSignPost;518foreach_active(FBZTrash, trash)519{520if (trash->state != FBZTrash_State_LooseTrash) {521CREATE_ENTITY(Explosion, INT_TO_VOID(EXPLOSION_ENEMY), trash->position.x, trash->position.y)->drawGroup =522Zone->objectDrawGroup[1];523RSDK.PlaySfx(Explosion->sfxDestroy, false, 255);524destroyEntity(trash);525}526}527break;528}529}530else if (self->timer == 80) {531destroyEntity(self);532}533}534535void BigSqueeze_StateBoss_DropSignPost(void)536{537RSDK_THIS(BigSqueeze);538539BigSqueeze->isCrushing = false;540if (++self->setupTimer == 48) {541foreach_all(SignPost, signPost)542{543signPost->position.x = self->position.x;544signPost->active = ACTIVE_NORMAL;545signPost->state = SignPost_State_Falling;546RSDK.PlaySfx(SignPost->sfxTwinkle, false, 255);547}548549self->state = StateMachine_None;550}551}552553void BigSqueeze_StateManager_HandleOutro(void)554{555RSDK_THIS(BigSqueeze);556557self->position.y = BigSqueeze->boundsB;558}559560void BigSqueeze_StateManager_HandleBoss(void)561{562RSDK_THIS(BigSqueeze);563564self->position.y = BigSqueeze->boundsB;565566foreach_active(Player, player)567{568if (Player_CheckCollisionPlatform(player, self, &self->hitbox)) {569if (abs(player->groundVel) > 0x20000 && !(Zone->timer & 7)) {570int32 x = player->position.x + RSDK.Rand(-0x40000, 0x40000);571int32 y = player->position.y + 0x40000 + RSDK.Rand(-0x40000, 0x40000);572EntityDebris *debris = CREATE_ENTITY(Debris, Debris_State_Fall, x, y);573574RSDK.SetSpriteAnimation(FBZTrash->aniFrames, RSDK.Rand(0, 2) + 9, &debris->animator, false, 0);575debris->velocity.x = RSDK.Rand(-0x20000, 0x20000);576debris->velocity.y = -0x20000;577debris->gravityStrength = 0x3800;578debris->drawGroup = Zone->objectDrawGroup[0];579debris->updateRange.x = 0x200000;580debris->updateRange.y = 0x200000;581}582}583}584585foreach_active(FBZSinkTrash, sinkTrash)586{587sinkTrash->position.y = BigSqueeze->boundsB + (sinkTrash->size.y >> 1);588sinkTrash->size.x = BigSqueeze->crusherX[BIGSQUEEZE_CRUSHER_R] - BigSqueeze->crusherX[BIGSQUEEZE_CRUSHER_L];589}590}591592void BigSqueeze_StateCrusher_BeginCrushing(void)593{594RSDK_THIS(BigSqueeze);595596BigSqueeze_HandleWallCollisions();597598BigSqueeze->crusherX[self->type] = self->position.x;599if (++self->setupTimer == 8) {600BigSqueeze->isCrushing = false;601}602603if (self->setupTimer == 300) {604self->setupTimer = 0;605self->state = BigSqueeze_StateCrusher_Crushing;606BigSqueeze->isCrushing = true;607if (self->velocity.x > 0)608++BigSqueeze->crushTimer;609}610}611612void BigSqueeze_StateCrusher_Crushing(void)613{614RSDK_THIS(BigSqueeze);615616BigSqueeze_HandleWallCollisions();617618self->position.x += self->velocity.x;619BigSqueeze->crusherX[self->type] = self->position.x;620621if (!(Zone->timer & 3))622Camera_ShakeScreen(0, 0, 4);623624if (self->type == BIGSQUEEZE_CRUSHER_L)625BigSqueeze->boundsB -= 0x4000;626627if (++self->setupTimer == 32 && BigSqueeze->crushTimer < 10) {628self->setupTimer = 0;629self->state = BigSqueeze_StateCrusher_BeginCrushing;630}631}632633#if GAME_INCLUDE_EDITOR634void BigSqueeze_EditorDraw(void)635{636RSDK_THIS(BigSqueeze);637638switch (self->type) {639case BIGSQUEEZE_MANAGER:640self->updateRange.x = 0x800000;641self->updateRange.y = 0x800000;642643RSDK.SetSpriteAnimation(BigSqueeze->aniFrames, 4, &self->wheelAnimator, true, 0);644RSDK.DrawSprite(&self->wheelAnimator, NULL, false); // an odd sprite, but it beats no sprite645break;646647case BIGSQUEEZE_BOSS:648self->updateRange.x = 0x8000000;649self->updateRange.y = 0x1000000;650self->drawGroup = Zone->objectDrawGroup[1];651RSDK.SetSpriteAnimation(BigSqueeze->aniFrames, 1, &self->animator, true, 0);652RSDK.SetSpriteAnimation(BigSqueeze->aniFrames, 2, &self->domeAnimator, true, 0);653RSDK.SetSpriteAnimation(BigSqueeze->aniFrames, 3, &self->prongsAnimator, true, 0);654RSDK.SetSpriteAnimation(BigSqueeze->aniFrames, 4, &self->wheelAnimator, true, 0);655BigSqueeze_Draw_Boss();656break;657658case BIGSQUEEZE_CRUSHER_L:659case BIGSQUEEZE_CRUSHER_R:660if (self->type == BIGSQUEEZE_CRUSHER_R) {661self->direction = FLIP_X;662self->drawFX = FX_FLIP;663}664self->updateRange.x = 0x8000000;665self->updateRange.y = 0x1000000;666self->drawGroup = Zone->objectDrawGroup[1];667RSDK.SetSpriteAnimation(BigSqueeze->aniFrames, 0, &self->animator, true, 0);668BigSqueeze_Draw_Crusher();669break;670671default: break;672}673}674675void BigSqueeze_EditorLoad(void)676{677BigSqueeze->aniFrames = RSDK.LoadSpriteAnimation("FBZ/BigSqueeze.bin", SCOPE_STAGE);678679RSDK_ACTIVE_VAR(BigSqueeze, type);680RSDK_ENUM_VAR("Manager", BIGSQUEEZE_MANAGER);681RSDK_ENUM_VAR("Boss", BIGSQUEEZE_BOSS);682RSDK_ENUM_VAR("Left Crusher", BIGSQUEEZE_CRUSHER_L);683RSDK_ENUM_VAR("Right Crusher", BIGSQUEEZE_CRUSHER_R);684}685#endif686687void BigSqueeze_Serialize(void) { RSDK_EDITABLE_VAR(BigSqueeze, VAR_ENUM, type); }688689690