Path: blob/master/SonicMania/Objects/LRZ/BuckwildBall.c
338 views
// ---------------------------------------------------------------------1// RSDK Project: Sonic Mania2// Object Description: BuckwildBall Object3// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges4// Decompiled by: Rubberduckycooly & RMGRich5// ---------------------------------------------------------------------67#include "Game.h"89ObjectBuckwildBall *BuckwildBall;1011void BuckwildBall_Update(void)12{13RSDK_THIS(BuckwildBall);1415StateMachine_Run(self->state);1617if (self->state != BuckwildBall_State_AwaitDetection && self->state != BuckwildBall_State_Debris && self->state != BuckwildBall_State_Init) {18if (RSDK.ObjectTileGrip(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0, 0x1C0000, 2)) {19if (self->particleDelay-- <= 0) {20BuckwildBall_SpawnDebris();21BuckwildBall_HandleTimerSfx();22self->particleDelay = RSDK.Rand(8, 15);23}24}2526BuckwildBall_CheckPlayerCollisions();27BuckwildBall_HandleRollCrush();2829RSDK.ProcessAnimation(&self->animator);3031if (self->timerSfx > 0)32self->timerSfx--;33}34}3536void BuckwildBall_LateUpdate(void) {}3738void BuckwildBall_StaticUpdate(void) {}3940void BuckwildBall_Draw(void)41{42RSDK_THIS(BuckwildBall);4344RSDK.DrawSprite(&self->animator, NULL, false);45}4647void BuckwildBall_Create(void *data)48{49RSDK_THIS(BuckwildBall);5051if (!SceneInfo->inEditor) {52self->active = ACTIVE_BOUNDS;53self->drawGroup = Zone->objectDrawGroup[0];54self->startPos = self->position;55self->visible = true;56self->drawFX = FX_FLIP;57self->updateRange.x = 0x800000;58self->updateRange.y = 0x800000;59self->bossBallSlot = -1;6061if (self->mode != BUCKWILDBALL_ROLLING)62self->updateRange.x = (self->amplitude + 0x80) << 16;6364self->state = BuckwildBall_State_Init;6566if (!self->speed)67self->speed = 2;68}69}7071void BuckwildBall_StageLoad(void)72{73BuckwildBall->aniFrames = RSDK.LoadSpriteAnimation("LRZ1/BuckwildBall.bin", SCOPE_STAGE);74BuckwildBall->particleFrames = RSDK.LoadSpriteAnimation("LRZ1/Particles.bin", SCOPE_STAGE);7576BuckwildBall->sfxImpact = RSDK.GetSfx("Stage/Impact2.wav");77BuckwildBall->sfxSharp = RSDK.GetSfx("Stage/Sharp.wav");7879BuckwildBall->hitbox.left = -28;80BuckwildBall->hitbox.top = -28;81BuckwildBall->hitbox.right = 28;82BuckwildBall->hitbox.bottom = 28;83}8485void BuckwildBall_HandleTimerSfx(void)86{87RSDK_THIS(BuckwildBall);8889if (self->timerSfx > 0) {90LogHelpers_Print("timerSfx = %d", self->timerSfx);91}92else {93RSDK.PlaySfx(BuckwildBall->sfxImpact, false, 255);94self->timerSfx = 8;95}96}9798void BuckwildBall_CheckOffScreen(void)99{100RSDK_THIS(BuckwildBall);101102if (!RSDK.CheckPosOnScreen(&self->startPos, &self->updateRange) && !RSDK.CheckPosOnScreen(&self->position, &self->updateRange)) {103if (self->respawn) {104self->position = self->startPos;105self->state = BuckwildBall_State_Init;106self->active = ACTIVE_BOUNDS;107self->visible = false;108}109else {110destroyEntity(self);111}112}113}114115void BuckwildBall_SpawnDebris(void)116{117RSDK_THIS(BuckwildBall);118119int32 x = self->position.x;120int32 y = self->position.y + 0x1C0000;121122int32 sizeX = (BuckwildBall->hitbox.right - BuckwildBall->hitbox.left) >> 1;123int32 spawnX = x + ((RSDK.Rand(0, 64) - 32) << 16);124int32 spawnY = y + ((RSDK.Rand(0, 8) - 4) << 15);125126EntityDebris *debris = CREATE_ENTITY(Debris, Debris_State_Fall, spawnX, spawnY);127RSDK.SetSpriteAnimation(BuckwildBall->particleFrames, 1, &debris->animator, true, 0);128debris->drawGroup = Zone->objectDrawGroup[1];129debris->gravityStrength = 0x3800;130debris->velocity.x = 0x180 * (abs(spawnX - x) >> 8) / sizeX;131132if (debris->position.x < self->position.x) {133debris->direction = FLIP_X;134debris->velocity.x = -debris->velocity.x;135}136137debris->velocity.y = -0x1000 * RSDK.Rand(32, 54);138}139140void BuckwildBall_CheckPlayerCollisions(void)141{142RSDK_THIS(BuckwildBall);143144foreach_active(Player, player)145{146if (Player_CheckCollisionTouch(player, self, &BuckwildBall->hitbox)) {147#if MANIA_USE_PLUS148if (!Player_CheckMightyUnspin(player, 0x600, false, &player->uncurlTimer))149#endif150Player_Hurt(player, self);151}152}153}154155void BuckwildBall_HandleRollCrush(void)156{157RSDK_THIS(BuckwildBall);158159Hitbox crushHitbox;160crushHitbox.left = -8;161crushHitbox.top = -8;162crushHitbox.right = 8;163crushHitbox.bottom = 8;164165foreach_active(Iwamodoki, iwamodoki)166{167if (RSDK.CheckObjectCollisionTouchBox(self, &BuckwildBall->hitbox, iwamodoki, &crushHitbox)) {168BadnikHelpers_BadnikBreak(iwamodoki, true, true);169}170}171172foreach_active(Fireworm, fireworm)173{174if (RSDK.CheckObjectCollisionTouchBox(self, &BuckwildBall->hitbox, fireworm, &crushHitbox)) {175BadnikHelpers_BadnikBreak(fireworm, true, true);176}177}178179foreach_active(Toxomister, toxomister)180{181if (RSDK.CheckObjectCollisionTouchBox(self, &BuckwildBall->hitbox, toxomister, &crushHitbox)) {182if (toxomister->state == Toxomister_State_CreateClouds) {183BadnikHelpers_BadnikBreak(toxomister, true, true);184}185else if (!toxomister->grabbedPlayer) {186destroyEntity(toxomister);187}188}189}190191Hitbox spikeHitbox;192spikeHitbox.left = -16;193spikeHitbox.top = -16;194spikeHitbox.right = 16;195spikeHitbox.bottom = 16;196197foreach_active(Spikes, spikes)198{199if (RSDK.CheckObjectCollisionTouchBox(self, &BuckwildBall->hitbox, spikes, &spikeHitbox)) {200for (int32 i = 0; i < 2; ++i) {201int32 x = spikes->position.x + (((2 * (i != 0) - 1) * (spikes->type == SPIKES_UP)) << 19);202int32 y = spikes->position.y + (((2 * (i != 0) - 1) * (spikes->type != SPIKES_UP)) << 19);203EntityDebris *debris = CREATE_ENTITY(Debris, Debris_State_Fall, x, y);204205RSDK.SetSpriteAnimation(BuckwildBall->particleFrames, 4, &debris->animator, true, spikes->type >> 1);206debris->drawGroup = Zone->objectDrawGroup[1];207debris->direction = spikes->direction;208debris->drawFX |= FX_ROTATE;209debris->gravityStrength = 0x3800;210debris->rotSpeed = RSDK.Rand(-32, 32);211debris->velocity.x = RSDK.Rand(-0x28000, 0x28000);212debris->velocity.y = -0x1000 * RSDK.Rand(32, 96);213}214215destroyEntity(spikes);216217RSDK.PlaySfx(BuckwildBall->sfxSharp, false, 255);218RSDK.PlaySfx(BuckwildBall->sfxImpact, false, 255);219self->timerSfx = 8;220}221}222}223224void BuckwildBall_State_Init(void)225{226RSDK_THIS(BuckwildBall);227228RSDK.SetSpriteAnimation(BuckwildBall->aniFrames, 0, &self->animator, true, 0);229230self->timerSfx = 0;231232switch (self->mode) {233case BUCKWILDBALL_PATROLLING: self->state = BuckwildBall_State_Patrolling; break;234235case BUCKWILDBALL_ROLLING:236self->visible = false;237self->state = BuckwildBall_State_AwaitDetection;238self->drawGroup = Zone->objectDrawGroup[0];239240self->detectHitbox.left = -(self->detectSize.x >> 17);241self->detectHitbox.top = -(self->detectSize.y >> 17);242self->detectHitbox.right = self->detectSize.x >> 17;243self->detectHitbox.bottom = self->detectSize.y >> 17;244245self->velocity.x = 0;246self->ballPos.x = self->startPos.x + self->detectOffset.x;247self->ballPos.y = self->startPos.y + self->detectOffset.y;248self->velocity.y = 0;249break;250}251}252253void BuckwildBall_State_Patrolling(void)254{255RSDK_THIS(BuckwildBall);256257int32 angle = ((self->speed & 0xFFFF) * (Zone->timer & 0xFFFF)) & 0x3FF;258self->position.x = (self->amplitude << 6) * RSDK.Sin1024(angle) + self->startPos.x;259self->direction = (angle - 0x100) > 0x200;260}261262void BuckwildBall_State_AwaitDetection(void)263{264RSDK_THIS(BuckwildBall);265266self->position.x = self->ballPos.x;267self->position.y = self->ballPos.y;268269foreach_active(Player, player)270{271if (!player->sidekick) {272if (Player_CheckCollisionTouch(player, self, &self->detectHitbox)) {273self->visible = true;274self->active = ACTIVE_NORMAL;275self->state = BuckwildBall_State_Falling;276}277}278}279280self->position.x = self->startPos.x;281self->position.y = self->startPos.y;282}283284void BuckwildBall_State_Falling(void)285{286RSDK_THIS(BuckwildBall);287288self->velocity.y += 0x3800;289self->position.x += self->velocity.x;290self->position.y += self->velocity.y;291292if (RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0, 0x1C0000, true)) {293if (!RSDK.GetEntityCount(Drillerdroid->classID, true) || (Drillerdroid->platformActive[self->bossBallSlot] == true)) {294self->velocity.y = 0;295self->state = BuckwildBall_State_Rolling;296self->velocity.x = abs(self->speed << 15) * (2 * (self->direction != FLIP_NONE) - 1);297}298else if (Drillerdroid->platformActive[self->bossBallSlot]) {299self->state = BuckwildBall_State_Debris;300self->velocity.x = 0;301self->velocity.y = -0x40000;302self->animator.speed = 0;303self->drawGroup = Zone->objectDrawGroup[1];304}305else {306int32 slot = RSDK.GetEntitySlot(Drillerdroid->boss);307RSDK_GET_ENTITY(slot + 6 + self->bossBallSlot, CollapsingPlatform)->collapseDelay = 1;308Drillerdroid->platformActive[self->bossBallSlot] = -1;309self->velocity.y = -0x40000;310}311312BuckwildBall_HandleTimerSfx();313Camera_ShakeScreen(0, 0, 5);314}315316if (self->bossBallSlot > -1)317BuckwildBall_CheckOffScreen();318}319320void BuckwildBall_State_Rolling(void)321{322RSDK_THIS(BuckwildBall);323324self->velocity.x += abs(self->speed << 10) * (2 * !(self->direction == FLIP_NONE) - 1);325self->velocity.y += 0x3800;326327self->position.x += self->velocity.x;328self->position.y += self->velocity.y;329330if (RSDK.ObjectTileGrip(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0, 0x1C0000, 2)) {331self->velocity.y = 0;332if (abs(self->velocity.x) > 0x20000 && RSDK.Rand(0, 100) > 0x50) {333BuckwildBall_SpawnDebris();334BuckwildBall_HandleTimerSfx();335self->velocity.y = -0x18000;336}337}338339bool32 collidedWall = false;340if (self->direction == FLIP_X)341collidedWall = RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_LWALL, 0, 0x1C0000, 0, true);342else if (self->direction == FLIP_NONE)343collidedWall = RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_RWALL, 0, -0x1C0000, 0, true);344345if (collidedWall) {346self->state = BuckwildBall_State_Debris;347BuckwildBall_HandleTimerSfx();348Camera_ShakeScreen(0, 0, 5);349self->velocity.x = 0;350self->velocity.y = -0x40000;351self->animator.speed = 0;352self->drawGroup = Zone->objectDrawGroup[1];353}354355if (self->bossBallSlot > -1)356BuckwildBall_CheckOffScreen();357}358359void BuckwildBall_State_Debris(void)360{361RSDK_THIS(BuckwildBall);362363self->velocity.y += 0x3800;364self->position.x += self->velocity.x;365self->position.y += self->velocity.y;366367self->visible = (Zone->timer % 4) < 2;368369BuckwildBall_CheckOffScreen();370}371372#if GAME_INCLUDE_EDITOR373void BuckwildBall_EditorDraw(void)374{375RSDK_THIS(BuckwildBall);376377RSDK.SetSpriteAnimation(BuckwildBall->aniFrames, 0, &self->animator, true, 0);378379self->updateRange.x = 0x800000;380self->updateRange.y = 0x800000;381self->startPos = self->position;382383BuckwildBall_Draw();384385if (showGizmos()) {386387RSDK_DRAWING_OVERLAY(true);388switch (self->mode) {389case BUCKWILDBALL_PATROLLING:390self->updateRange.x = (self->amplitude + 0x80) << 16;391392self->inkEffect = INK_BLEND;393394self->position.x = (self->amplitude << 6) * RSDK.Sin1024(0x100) + self->startPos.x;395int32 x1 = self->position.x;396BuckwildBall_Draw();397398self->position.x = (self->amplitude << 6) * RSDK.Sin1024(0x300) + self->startPos.x;399BuckwildBall_Draw();400401RSDK.DrawLine(x1, self->position.y, self->position.x, self->position.y, 0x00FF00, 0xFF, INK_BLEND, false);402403self->inkEffect = INK_NONE;404break;405406case BUCKWILDBALL_ROLLING:407self->detectHitbox.left = -(self->detectSize.x >> 17);408self->detectHitbox.top = -(self->detectSize.y >> 17);409self->detectHitbox.right = self->detectSize.x >> 17;410self->detectHitbox.bottom = self->detectSize.y >> 17;411self->ballPos = self->position;412self->ballPos.x = self->position.x + self->detectOffset.x;413self->ballPos.y = self->position.y + self->detectOffset.y;414415DrawHelpers_DrawHitboxOutline(self->ballPos.x, self->ballPos.y, &self->detectHitbox, FLIP_NONE, 0xFF0000);416417self->velocity.x = abs(self->speed << 15) * (2 * (self->direction != FLIP_NONE) - 1);418DrawHelpers_DrawArrow(self->position.x, self->position.y, self->position.x + (self->velocity.x << 3), self->position.y, 0xFFFF00,419INK_NONE, 0xFF);420break;421}422423RSDK_DRAWING_OVERLAY(false);424}425}426427void BuckwildBall_EditorLoad(void)428{429BuckwildBall->aniFrames = RSDK.LoadSpriteAnimation("LRZ1/BuckwildBall.bin", SCOPE_STAGE);430431RSDK_ACTIVE_VAR(BuckwildBall, direction);432RSDK_ENUM_VAR("Left", FLIP_NONE);433RSDK_ENUM_VAR("Right", FLIP_X);434435RSDK_ACTIVE_VAR(BuckwildBall, mode);436RSDK_ENUM_VAR("Patrolling", BUCKWILDBALL_PATROLLING);437RSDK_ENUM_VAR("Rolling", BUCKWILDBALL_ROLLING);438}439#endif440441void BuckwildBall_Serialize(void)442{443RSDK_EDITABLE_VAR(BuckwildBall, VAR_UINT32, amplitude);444RSDK_EDITABLE_VAR(BuckwildBall, VAR_UINT8, direction);445RSDK_EDITABLE_VAR(BuckwildBall, VAR_UINT8, mode);446RSDK_EDITABLE_VAR(BuckwildBall, VAR_ENUM, speed);447RSDK_EDITABLE_VAR(BuckwildBall, VAR_VECTOR2, detectOffset);448RSDK_EDITABLE_VAR(BuckwildBall, VAR_VECTOR2, detectSize);449RSDK_EDITABLE_VAR(BuckwildBall, VAR_BOOL, respawn);450}451452453