Path: blob/master/SonicMania/Objects/SSZ/Firework.c
338 views
// ---------------------------------------------------------------------1// RSDK Project: Sonic Mania2// Object Description: Firework Object3// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges4// Decompiled by: Rubberduckycooly & RMGRich5// ---------------------------------------------------------------------67#include "Game.h"89ObjectFirework *Firework;1011void Firework_Update(void)12{13RSDK_THIS(Firework);1415if (self->mainAnimator.animationID < 3) {16RSDK.ProcessAnimation(&self->mainAnimator);17}18else if (self->timer == 10) {19if (self->mainAnimator.frameID < self->mainAnimator.frameCount - 1)20RSDK.ProcessAnimation(&self->mainAnimator);2122if (self->sparkAnimator.frameID < self->sparkAnimator.frameCount - 1)23RSDK.ProcessAnimation(&self->sparkAnimator);24}2526StateMachine_Run(self->state);27Firework_HandlePlayerTimers();28}2930void Firework_LateUpdate(void) {}3132void Firework_StaticUpdate(void)33{34bool32 fireworkActive = false;3536if (RSDK_GET_ENTITY(SLOT_PAUSEMENU, PauseMenu)->classID != PauseMenu->classID) {37foreach_active(Firework, firework)38{39if (firework->rideActive) {40if (!Firework->playingFlameSfx) {41RSDK.PlaySfx(Firework->sfxFlame, true, 255);42Firework->playingFlameSfx = true;43}4445fireworkActive = true;46foreach_break;47}48}49}5051if (!fireworkActive) {52if (Firework->playingFlameSfx) {53RSDK.StopSfx(Firework->sfxFlame);54Firework->playingFlameSfx = false;55}56}57}5859void Firework_Draw(void)60{61RSDK_THIS(Firework);6263self->rotation = ((self->angle >> 1) + 0x80) & 0x1FF;64if (self->state == Firework_State_Explode) {65if (self->timer > 0)66RSDK.FillScreen(0xF0F0F0, self->timer - 128, self->timer - 256, self->timer);67}68else {69RSDK.DrawSprite(&self->mainAnimator, &self->position, false);70}7172if (self->mainAnimator.animationID >= 3) {73self->inkEffect = INK_ADD;74RSDK.DrawSprite(&self->sparkAnimator, NULL, false);75self->inkEffect = INK_NONE;76}77}7879void Firework_Create(void *data)80{81RSDK_THIS(Firework);8283self->active = ACTIVE_BOUNDS;84self->visible = true;85self->drawFX = FX_ROTATE | FX_FLIP;86self->drawGroup = Zone->objectDrawGroup[0];87self->updateRange.x = 0x800000;88self->updateRange.y = 0x800000;8990if (!self->innerRadius)91self->innerRadius = 64;9293if (!self->outerRadius)94self->outerRadius = 128;9596if (!self->distance)97self->distance = 512;9899self->startPos = self->position;100101self->state = Firework_State_Init;102}103104void Firework_StageLoad(void)105{106Firework->aniFrames = RSDK.LoadSpriteAnimation("SSZ2/Firework.bin", SCOPE_STAGE);107108Firework->hitboxFireworkGrab.left = -11;109Firework->hitboxFireworkGrab.top = -32;110Firework->hitboxFireworkGrab.right = 10;111Firework->hitboxFireworkGrab.bottom = 15;112113Firework->hitboxTileCheck.left = -10;114Firework->hitboxTileCheck.top = -10;115Firework->hitboxTileCheck.right = 10;116Firework->hitboxTileCheck.bottom = 10;117118Firework->sfxRocketJet = RSDK.GetSfx("Stage/RocketJet.wav");119Firework->sfxFlame = RSDK.GetSfx("Stage/Flame2.wav");120Firework->sfxExplosion2 = RSDK.GetSfx("Stage/Explosion2.wav");121Firework->sfxExplosion = RSDK.GetSfx("Stage/Explosion.wav");122123Firework->active = ACTIVE_ALWAYS;124}125126void Firework_CheckPlayerCollisions(void)127{128RSDK_THIS(Firework);129130foreach_active(Player, player)131{132int32 playerID = RSDK.GetEntitySlot(player);133134if (!((1 << playerID) & self->activePlayers)) {135if (player->state != Player_State_Static && !self->playerTimers[playerID]136&& Player_CheckCollisionTouch(player, self, &Firework->hitboxFireworkGrab)) {137player->tileCollisions = TILECOLLISION_NONE;138RSDK.SetSpriteAnimation(player->aniFrames, ANI_PULLEY_HOLD, &player->animator, false, 0);139140player->state = Player_State_Static;141self->activePlayers |= 1 << playerID;142RSDK.PlaySfx(Player->sfxGrab, false, 255);143144player->direction = player->position.x > self->position.x;145if (player->sidekick == false)146self->activated = true;147}148}149150if ((1 << playerID) & self->activePlayers) {151if (player->state == Player_State_Static) {152player->velocity.x = 0;153player->velocity.y = 0;154player->groundVel = 0;155player->angle = self->angle >> 1;156157if (player->direction == FLIP_NONE)158player->rotation = ((self->angle >> 1) + 0xC0) % 511;159else160player->rotation = ((self->angle >> 1) + 0x444) % 511;161162player->position.x = self->position.x;163player->position.y = self->position.y;164165int32 power = player->direction == FLIP_NONE ? 16 : -16;166167player->position.x += power * (RSDK.Sin1024(self->angle) << 6);168player->position.y -= power * (RSDK.Cos1024(self->angle) << 6);169player->position.x += -0x100 * RSDK.Cos1024(self->angle);170player->position.y -= -0x100 * RSDK.Sin1024(self->angle);171}172else {173self->activePlayers &= ~(1 << playerID);174}175}176}177}178179void Firework_HandlePlayerTimers(void)180{181RSDK_THIS(Firework);182183foreach_active(Player, player)184{185int32 playerID = RSDK.GetEntitySlot(player);186187if (self->playerTimers[playerID])188self->playerTimers[playerID]--;189}190}191192void Firework_RemovePlayers(bool32 crashed)193{194foreach_active(Player, player)195{196RSDK.GetEntitySlot(player); // so true tbh197Firework_HandlePlayerRemoval(player, crashed);198}199}200201void Firework_HandlePlayerRemoval(EntityPlayer *player, bool32 crashed)202{203RSDK_THIS(Firework);204205int32 playerID = RSDK.GetEntitySlot(player);206207if ((1 << playerID) & self->activePlayers) {208player->state = Player_State_Air;209player->onGround = false;210player->tileCollisions = TILECOLLISION_DOWN;211player->velocity = self->velocity;212213self->playerTimers[playerID] = 30;214if (crashed) {215bool32 isSidekick = player->sidekick;216player->sidekick = true;217Player_Hit(player);218player->sidekick = isSidekick;219}220else {221RSDK.SetSpriteAnimation(player->aniFrames, ANI_JUMP, &player->animator, false, 0);222}223224self->activePlayers &= ~(1 << playerID);225}226}227228void Firework_HandlePlayerJump(void)229{230RSDK_THIS(Firework);231232foreach_active(Player, player)233{234if ((1 << RSDK.GetEntitySlot(player)) & self->activePlayers && player->jumpPress) {235int32 playerID = RSDK.GetEntitySlot(player);236237if ((1 << playerID) & self->activePlayers) {238player->state = Player_State_Air;239player->onGround = false;240player->tileCollisions = TILECOLLISION_DOWN;241player->velocity.x = self->velocity.x;242player->velocity.y = self->velocity.y;243self->playerTimers[playerID] = 30;244RSDK.SetSpriteAnimation(player->aniFrames, ANI_JUMP, &player->animator, false, 0);245246self->activePlayers &= ~(1 << playerID);247}248}249}250}251252void Firework_HandlePlayerControl(void)253{254RSDK_THIS(Firework);255256foreach_active(Player, player)257{258if (!player->sidekick && (1 << RSDK.GetEntitySlot(player)) & self->activePlayers) {259if (player->left)260--self->angle;261else if (player->right)262++self->angle;263}264}265}266267void Firework_HandleMoveDir(void)268{269RSDK_THIS(Firework);270271if (self->moveVelocity < 0x80000)272self->moveVelocity += 0x2000;273274if (self->moveVelocity > 0x80000)275self->moveVelocity = 0x80000;276277self->velocity.x = (self->moveVelocity >> 10) * RSDK.Cos1024(self->angle);278self->velocity.y = (self->moveVelocity >> 10) * RSDK.Sin1024(self->angle);279self->position.x += self->velocity.x;280self->position.y += self->velocity.y;281282int32 rx = abs(self->lastPosition.x - self->position.x) >> 16;283int32 ry = abs(self->lastPosition.y - self->position.y) >> 16;284self->ridePos += MathHelpers_SquareRoot(rx * rx + ry * ry);285286self->lastPosition.x = self->position.x;287self->lastPosition.y = self->position.y;288}289290void Firework_HandleDebrisSpawn(void)291{292RSDK_THIS(Firework);293294if (!(self->timer % 5)) {295EntityDebris *debris = CREATE_ENTITY(Debris, Debris_State_Move, self->position.x, self->position.y);296297RSDK.SetSpriteAnimation(Explosion->aniFrames, 3, &debris->animator, true, 0);298debris->position.x -= 0x600 * RSDK.Cos1024(self->angle);299debris->position.y -= 0x600 * RSDK.Sin1024(self->angle);300debris->drawGroup = Zone->objectDrawGroup[0];301debris->timer = 52;302}303}304305void Firework_HandleTileCollisions(void)306{307RSDK_THIS(Firework);308309bool32 collided = RSDK.ObjectTileGrip(self, Zone->collisionLayers, CMODE_LWALL, 0, Firework->hitboxTileCheck.right << 13, 0, 4);310collided |= RSDK.ObjectTileGrip(self, Zone->collisionLayers, CMODE_ROOF, 0, 0, Firework->hitboxTileCheck.top << 13, 4);311collided |= RSDK.ObjectTileGrip(self, Zone->collisionLayers, CMODE_RWALL, 0, Firework->hitboxTileCheck.left << 13, 0, 4);312313if (collided) {314Camera_ShakeScreen(0, 0, 4);315Firework_HandleRideEnd(true);316}317}318319void Firework_HandleRideEnd(bool32 crashed)320{321RSDK_THIS(Firework);322323self->rideActive = false;324325if (crashed) {326// Watch out! you're gonna crash! ah!327CREATE_ENTITY(Explosion, INT_TO_VOID(EXPLOSION_BOSSPUFF), self->position.x, self->position.y)->drawGroup = Zone->objectDrawGroup[1];328RSDK.PlaySfx(Firework->sfxExplosion2, false, 255);329330Firework_RemovePlayers(true);331self->state = Firework_State_Explode;332}333else {334int32 angle = 0;335336for (int32 i = 0; i < 8; ++i) {337int32 x = (RSDK.Cos1024(angle) << 6) * self->innerRadius + self->position.x;338int32 y = (RSDK.Sin1024(angle) << 6) * self->innerRadius + self->position.y;339340EntityFirework *firework = CREATE_ENTITY(Firework, NULL, x, y);341firework->velocity.x = 0x30 * RSDK.Cos1024(angle);342firework->velocity.y = 0x30 * RSDK.Sin1024(angle);343firework->state = Firework_State_SparkSetup;344firework->angle = angle;345firework->sparkID = 0;346347x = (RSDK.Cos1024(angle) << 6) * self->outerRadius + self->position.x;348y = (RSDK.Sin1024(angle) << 6) * self->outerRadius + self->position.y;349firework = CREATE_ENTITY(Firework, NULL, x, y);350firework->velocity.x = 0x20 * RSDK.Cos1024(angle);351firework->velocity.y = 0x20 * RSDK.Sin1024(angle);352firework->angle = angle;353firework->state = Firework_State_SparkSetup;354firework->sparkID = 1;355356angle += 0x80;357}358359self->timer = 512;360self->drawGroup = Zone->hudDrawGroup;361RSDK.PlaySfx(Firework->sfxExplosion, false, 255);362363Firework_RemovePlayers(false);364self->state = Firework_State_Explode;365}366}367368void Firework_CheckOffScreen(void)369{370RSDK_THIS(Firework);371372if (self->state == Firework_State_Explode) {373if (self->timer <= 0) {374if (!RSDK.CheckPosOnScreen(&self->startPos, &self->updateRange)) {375self->position = self->startPos;376self->state = Firework_State_ResetOffScreen;377self->visible = false;378self->direction = FLIP_NONE;379}380}381}382else {383if (!RSDK.CheckOnScreen(self, NULL)) {384if (!RSDK.CheckPosOnScreen(&self->startPos, &self->updateRange)) {385self->position = self->startPos;386self->state = Firework_State_ResetOffScreen;387self->visible = false;388self->direction = FLIP_NONE;389}390}391}392}393394void Firework_HandleSparkAnimations(int32 sparkID, int16 angle, Animator *fireworkAnimator, Animator *sparkAnimator, uint8 *direction)395{396uint16 ang = angle & 0x3FF;397int32 anim = 4 * (sparkID != 0) + 3;398399if (ang <= 0x40 || ang > 0x3C0) {400if (direction)401*direction = FLIP_NONE;402403if (fireworkAnimator)404RSDK.SetSpriteAnimation(Firework->aniFrames, anim, fireworkAnimator, true, 0);405}406else if (ang <= 0xC0) {407if (direction)408*direction = FLIP_Y;409410if (fireworkAnimator)411RSDK.SetSpriteAnimation(Firework->aniFrames, anim + 2, fireworkAnimator, true, 0);412}413else if (ang <= 0x140) {414if (direction)415*direction = FLIP_Y;416417if (fireworkAnimator)418RSDK.SetSpriteAnimation(Firework->aniFrames, anim + 1, fireworkAnimator, true, 0);419}420else if (ang <= 0x1C0) {421if (direction)422*direction = FLIP_XY;423424if (fireworkAnimator)425RSDK.SetSpriteAnimation(Firework->aniFrames, anim + 2, fireworkAnimator, true, 0);426}427else if (ang <= 0x240) {428if (direction)429*direction = FLIP_X;430431if (fireworkAnimator)432RSDK.SetSpriteAnimation(Firework->aniFrames, anim, fireworkAnimator, true, 0);433}434else if (ang <= 0x2C0) {435if (direction)436*direction = FLIP_X;437438if (fireworkAnimator)439RSDK.SetSpriteAnimation(Firework->aniFrames, anim + 2, fireworkAnimator, true, 0);440}441else if (ang > 0x340) {442if (direction)443*direction = FLIP_NONE;444445if (fireworkAnimator)446RSDK.SetSpriteAnimation(Firework->aniFrames, anim + 2, fireworkAnimator, true, 0);447}448else {449if (direction)450*direction = FLIP_NONE;451else if (fireworkAnimator)452RSDK.SetSpriteAnimation(Firework->aniFrames, anim + 1, fireworkAnimator, true, 0);453}454455if (sparkAnimator)456RSDK.SetSpriteAnimation(Firework->aniFrames, anim + 3, sparkAnimator, true, 0);457}458459void Firework_State_Init(void)460{461RSDK_THIS(Firework);462463self->position = self->startPos;464self->lastPosition = self->startPos;465self->visible = true;466self->activePlayers = 0;467self->rotation = 0;468self->angle = 0x300;469self->timer = 0;470self->activated = false;471self->moveVelocity = 0;472self->ridePos = 0;473self->drawGroup = Zone->objectDrawGroup[0];474475RSDK.SetSpriteAnimation(Firework->aniFrames, 0, &self->mainAnimator, true, 0);476self->state = Firework_State_AwaitPlayerRide;477}478479void Firework_State_AwaitPlayerRide(void)480{481RSDK_THIS(Firework);482483Firework_CheckPlayerCollisions();484485if (self->activated) {486RSDK.PlaySfx(Firework->sfxRocketJet, false, 255);487RSDK.SetSpriteAnimation(Firework->aniFrames, 1, &self->mainAnimator, true, 0);488self->timer = 30;489self->state = Firework_State_PlayerGrabDelay;490}491}492493void Firework_State_PlayerGrabDelay(void)494{495RSDK_THIS(Firework);496497if (self->timer <= 0) {498self->rideActive = true;499RSDK.SetSpriteAnimation(Firework->aniFrames, 2, &self->mainAnimator, true, 0);500501self->lastPosition = self->position;502self->timer = 0;503self->state = Firework_State_Riding;504}505else {506self->timer--;507}508509Firework_CheckPlayerCollisions();510Firework_HandlePlayerJump();511}512513void Firework_State_Riding(void)514{515RSDK_THIS(Firework);516517Firework_HandleMoveDir();518Firework_HandleDebrisSpawn();519Firework_CheckPlayerCollisions();520Firework_HandlePlayerJump();521Firework_HandlePlayerControl();522523if (self->ridePos > self->distance)524Firework_HandleRideEnd(false);525526Firework_HandleTileCollisions();527Firework_CheckOffScreen();528529++self->timer;530}531532void Firework_State_Explode(void)533{534RSDK_THIS(Firework);535536if (self->timer <= 0) {537self->activePlayers = 0;538Firework_CheckOffScreen();539self->visible = false;540}541else {542self->timer -= 0x40;543}544}545546void Firework_State_ResetOffScreen(void)547{548RSDK_THIS(Firework);549550if (RSDK.CheckOnScreen(self, &self->updateRange)) {551self->state = Firework_State_Init;552Firework_Create(NULL);553}554}555556void Firework_State_SparkSetup(void)557{558RSDK_THIS(Firework);559560self->visible = true;561self->rotation = 0;562self->timer = 0;563self->state = Firework_State_Spark;564}565566void Firework_State_Spark(void)567{568RSDK_THIS(Firework);569570if (self->timer >= 10) {571if (self->timer == 10) {572self->position.x += self->velocity.x;573self->position.y += self->velocity.y;574575if (self->mainAnimator.frameID == self->mainAnimator.frameCount - 1)576destroyEntity(self);577}578}579else {580Firework_HandleSparkAnimations(self->sparkID, self->angle, &self->mainAnimator, &self->sparkAnimator, &self->direction);581++self->timer;582}583}584585#if GAME_INCLUDE_EDITOR586void Firework_EditorDraw(void)587{588RSDK_THIS(Firework);589590RSDK.SetSpriteAnimation(Firework->aniFrames, 0, &self->mainAnimator, false, 0);591592Firework_Draw();593594if (showGizmos()) {595RSDK_DRAWING_OVERLAY(true);596597DrawHelpers_DrawArrow(self->position.x, self->position.y, self->position.x, self->position.y - (self->distance << 16), 0xFFFF00, INK_NONE,5980xFF);599600RSDK_DRAWING_OVERLAY(false);601}602}603604void Firework_EditorLoad(void) { Firework->aniFrames = RSDK.LoadSpriteAnimation("SSZ2/Firework.bin", SCOPE_STAGE); }605#endif606607void Firework_Serialize(void)608{609RSDK_EDITABLE_VAR(Firework, VAR_INT32, distance);610RSDK_EDITABLE_VAR(Firework, VAR_INT32, innerRadius);611RSDK_EDITABLE_VAR(Firework, VAR_INT32, outerRadius);612}613614615