Path: blob/master/SonicMania/Objects/GHZ/CheckerBall.c
338 views
// ---------------------------------------------------------------------1// RSDK Project: Sonic Mania2// Object Description: CheckerBall Object3// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges4// Decompiled by: Rubberduckycooly & RMGRich5// ---------------------------------------------------------------------67#include "Game.h"89ObjectCheckerBall *CheckerBall;1011void CheckerBall_Update(void)12{13RSDK_THIS(CheckerBall);14self->active = ACTIVE_NORMAL;15CheckerBall_HandlePlayerMovement();16self->ballAngle += self->angleVel;17CheckerBall_HandlePhysics();18RSDK.ProcessObjectMovement(self, &CheckerBall->outerBox, &CheckerBall->innerBox);19CheckerBall_HandleObjectCollisions();20CheckerBall_HandlePlayerInteractions();21self->roundedPos.x = self->position.x & 0xFFFF0000;22self->roundedPos.y = self->position.y & 0xFFFF0000;23}2425void CheckerBall_LateUpdate(void) {}2627void CheckerBall_StaticUpdate(void) {}2829void CheckerBall_Draw(void)30{31RSDK_THIS(CheckerBall);32self->animator.frameID = (((self->ballAngle >> 14) + 8) >> 4) & 7;33RSDK.DrawSprite(&self->animator, NULL, false);34}3536void CheckerBall_Create(void *data)37{38RSDK_THIS(CheckerBall);39self->visible = true;40self->drawGroup = Zone->objectDrawGroup[0];41self->active = ACTIVE_BOUNDS;42self->updateRange.x = 0x400000;43self->updateRange.y = 0x400000;44self->onGround = false;45self->tileCollisions = TILECOLLISION_DOWN;46self->collisionLayers = Zone->collisionLayers;47self->roundedPos.x = self->position.x;48self->roundedPos.y = self->position.y;49self->collisionPlane = 0;50RSDK.SetSpriteAnimation(CheckerBall->aniFrames, 0, &self->animator, true, 0);51}5253void CheckerBall_StageLoad(void)54{55if (RSDK.CheckSceneFolder("GHZ"))56CheckerBall->aniFrames = RSDK.LoadSpriteAnimation("GHZ/CheckerBall.bin", SCOPE_STAGE);57else if (RSDK.CheckSceneFolder("Blueprint"))58CheckerBall->aniFrames = RSDK.LoadSpriteAnimation("Blueprint/CheckerBall.bin", SCOPE_STAGE);5960CheckerBall->outerBox.left = -9;61CheckerBall->outerBox.top = -22;62CheckerBall->outerBox.right = 9;63CheckerBall->outerBox.bottom = 22;6465CheckerBall->innerBox.left = -8;66CheckerBall->innerBox.top = -22;67CheckerBall->innerBox.right = 8;68CheckerBall->innerBox.bottom = 22;6970CheckerBall->hitboxBall.left = -22;71CheckerBall->hitboxBall.top = -22;72CheckerBall->hitboxBall.right = 22;73CheckerBall->hitboxBall.bottom = 22;7475DEBUGMODE_ADD_OBJ(CheckerBall);7677CheckerBall->heightArray[0] = 0;78CheckerBall->heightArray[1] = 0;79CheckerBall->heightArray[2] = 0;80CheckerBall->heightArray[3] = 0;81CheckerBall->heightArray[4] = 1;82CheckerBall->heightArray[5] = 1;83CheckerBall->heightArray[6] = 1;84CheckerBall->heightArray[7] = 1;85CheckerBall->heightArray[8] = 2;86CheckerBall->heightArray[9] = 2;87CheckerBall->heightArray[10] = 3;88CheckerBall->heightArray[11] = 3;89CheckerBall->heightArray[12] = 4;90CheckerBall->heightArray[13] = 4;91CheckerBall->heightArray[14] = 5;92CheckerBall->heightArray[15] = 6;93CheckerBall->heightArray[16] = 7;94CheckerBall->heightArray[17] = 8;95CheckerBall->heightArray[18] = 9;96CheckerBall->heightArray[19] = 10;97CheckerBall->heightArray[20] = 12;98CheckerBall->heightArray[21] = 14;99CheckerBall->heightArray[22] = 16;100CheckerBall->heightArray[23] = 20;101102// an unused array, here since the ye olde days of v4103CheckerBall->unusedArray[0] = 253;104CheckerBall->unusedArray[1] = 251;105CheckerBall->unusedArray[2] = 248;106CheckerBall->unusedArray[3] = 245;107CheckerBall->unusedArray[4] = 243;108CheckerBall->unusedArray[5] = 240;109CheckerBall->unusedArray[6] = 237;110CheckerBall->unusedArray[7] = 235;111CheckerBall->unusedArray[8] = 232;112CheckerBall->unusedArray[9] = 229;113CheckerBall->unusedArray[10] = 226;114CheckerBall->unusedArray[11] = 224;115CheckerBall->unusedArray[12] = 221;116CheckerBall->unusedArray[13] = 219;117CheckerBall->unusedArray[14] = 216;118CheckerBall->unusedArray[15] = 213;119CheckerBall->unusedArray[16] = 210;120CheckerBall->unusedArray[17] = 208;121CheckerBall->unusedArray[18] = 205;122CheckerBall->unusedArray[19] = 203;123CheckerBall->unusedArray[20] = 200;124CheckerBall->unusedArray[21] = 197;125CheckerBall->unusedArray[22] = 195;126CheckerBall->unusedArray[23] = 192;127}128129void CheckerBall_DebugSpawn(void)130{131RSDK_THIS(DebugMode);132133CREATE_ENTITY(CheckerBall, NULL, self->position.x, self->position.y);134}135136void CheckerBall_DebugDraw(void)137{138RSDK.SetSpriteAnimation(CheckerBall->aniFrames, 0, &DebugMode->animator, true, 0);139RSDK.DrawSprite(&DebugMode->animator, NULL, false);140}141142void CheckerBall_HandlePhysics(void)143{144RSDK_THIS(CheckerBall);145if (self->onGround) {146int32 spd = RSDK.Sin256(self->angle) << 13 >> 8;147self->groundVel += spd;148self->angleVel = self->groundVel;149if (!spd && !self->playerControlled) {150if (self->groundVel <= 0) {151self->groundVel += 0x400;152if (self->groundVel > 0)153self->groundVel = 0;154}155else {156self->groundVel -= 0x400;157if (self->groundVel < 0)158self->groundVel = 0;159}160}161self->velocity.x = self->groundVel * RSDK.Cos256(self->angle) >> 8;162self->velocity.y = self->groundVel * RSDK.Sin256(self->angle) >> 8;163}164else {165self->velocity.y += 0x3800;166self->groundVel = self->velocity.x;167}168self->playerControlled = false;169}170171void CheckerBall_HandlePlayerMovement(void)172{173RSDK_THIS(CheckerBall);174175Hitbox hitbox;176hitbox.top = -22;177hitbox.bottom = 22;178179int32 playerID = 0;180self->activePlayers = 0;181foreach_active(Player, player)182{183Hitbox *playerHitbox = Player_GetHitbox(player);184int32 acc = player->acceleration >> 1;185if (player->onGround) {186if (player->position.x <= self->position.x) {187hitbox.left = -23;188hitbox.right = 0;189if (Player_CheckCollisionTouch(player, self, &hitbox)) {190if (!player->right) {191if (self->velocity.x > 0 && player->groundVel > self->groundVel) {192player->velocity.x -= 0x10000;193player->groundVel -= 0x10000;194}195}196else {197self->activePlayers |= 1 << playerID;198if (self->groundVel < player->topSpeed)199self->groundVel += acc;200self->playerControlled = true;201player->position.x = self->roundedPos.x + ((playerHitbox->left - 22) << 16);202player->groundVel = 0;203}204}205}206else {207hitbox.left = 0;208hitbox.right = 23;209if (Player_CheckCollisionTouch(player, self, &hitbox)) {210if (!player->left) {211if (self->velocity.x < 0 && player->groundVel < self->groundVel) {212player->velocity.x += 0x10000;213player->groundVel += 0x10000;214}215}216else {217self->activePlayers |= 1 << playerID;218if (self->groundVel > -player->topSpeed)219self->groundVel -= acc;220self->playerControlled = true;221player->position.x = self->roundedPos.x + ((playerHitbox->right + 22) << 16);222player->groundVel = 0;223}224}225}226}227++playerID;228}229}230231void CheckerBall_HandlePlayerInteractions(void)232{233RSDK_THIS(CheckerBall);234int32 x = ((self->position.x - self->collisionOffset.x) & 0xFFFF0000) - self->roundedPos.x;235int32 y = ((self->position.y - self->collisionOffset.y) & 0xFFFF0000) - self->roundedPos.y;236int32 startX = self->position.x;237int32 startY = self->position.y;238self->position.x = self->roundedPos.x;239self->position.y = self->roundedPos.y;240241int32 playerID = 0;242foreach_active(Player, player)243{244Hitbox *playerHitbox = Player_GetHitbox(player);245if ((1 << playerID) & self->activePlayers) {246if (player->position.x >= self->position.x)247player->position.x = (22 - playerHitbox->left) << 16;248else249player->position.x = (-22 - playerHitbox->right) << 16;250player->position.x += startX;251}252else {253int32 side = Player_CheckCollisionBox(player, self, &CheckerBall->hitboxBall);254if (side == C_BOTTOM && self->velocity.y >= 0 && player->onGround) {255player->deathType = PLAYER_DEATH_DIE_USESFX;256}257else if (side == C_TOP) {258player->position.x += x + (x >> 1) + self->collisionOffset.x;259player->position.y += y + self->collisionOffset.y;260261if (player->velocity.x) {262if (player->velocity.x <= 0)263self->groundVel += player->acceleration >> 2;264else265self->groundVel -= player->acceleration >> 2;266self->playerControlled = true;267}268self->position.x = startX;269self->position.y = startY;270self->position.x = self->roundedPos.x;271self->position.y = self->roundedPos.y;272if (!Player_CheckCollisionBox(player, self, &CheckerBall->hitboxBall)) {273player->groundVel += x + (x >> 1);274player->velocity.x = player->groundVel;275player->onGround = false;276player->controlLock = 15;277}278}279}280++playerID;281}282self->position.x = startX;283self->position.y = startY;284self->collisionOffset.x = 0;285self->collisionOffset.y = 0;286}287288void CheckerBall_BadnikBreak(void *b, Hitbox *hitbox)289{290RSDK_THIS(CheckerBall);291Entity *badnik = (Entity *)b;292293if (RSDK.CheckObjectCollisionTouchBox(badnik, hitbox, self, &CheckerBall->hitboxBall)) {294BadnikHelpers_BadnikBreakUnseeded(badnik, false, true);295296EntityPlayer *player1 = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);297EntityScoreBonus *bonus = CREATE_ENTITY(ScoreBonus, NULL, badnik->position.x, badnik->position.y);298bonus->drawGroup = Zone->objectDrawGroup[1];299bonus->animator.frameID = player1->scoreBonus;300switch (player1->scoreBonus) {301case 0: Player_GiveScore(player1, 100); break;302case 1: Player_GiveScore(player1, 200); break;303case 2: Player_GiveScore(player1, 500); break;304case 3:305case 4:306case 5:307case 6:308case 7:309case 8:310case 9:311case 10:312case 11:313case 12:314case 13:315case 14: Player_GiveScore(player1, 1000); break;316case 15: Player_GiveScore(player1, 10000); break;317default: break;318}319320if (player1->scoreBonus < 15)321player1->scoreBonus++;322323destroyEntity(badnik);324}325}326327void CheckerBall_HandleObjectCollisions(void)328{329RSDK_THIS(CheckerBall);330EntityPlayer *player1 = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);331332foreach_active(PlaneSwitch, planeSwitch)333{334PlaneSwitch_CheckCollisions(planeSwitch, self, planeSwitch->flags, planeSwitch->size, true, Zone->playerDrawGroup[0],335Zone->playerDrawGroup[1]);336}337338foreach_active(CheckerBall, checkerBall)339{340if (checkerBall != self && self->collisionPlane == checkerBall->collisionPlane) {341int32 pos = MIN(abs(self->position.x - checkerBall->position.x) >> 17, 23);342343Hitbox hitboxBall;344hitboxBall.top = CheckerBall->heightArray[pos] - 22 + (CheckerBall->heightArray[pos] >> 1);345hitboxBall.bottom = -hitboxBall.top;346hitboxBall.left = -22;347hitboxBall.right = 22;348349switch (RSDK.CheckObjectCollisionBox(checkerBall, &hitboxBall, self, &hitboxBall, true)) {350case C_TOP:351if (self->position.x >= checkerBall->position.x) {352self->groundVel += 0xC00;353self->velocity.x += 0xC00;354checkerBall->groundVel -= 0xC00;355checkerBall->velocity.x -= 0xC00;356checkerBall->angleVel -= 0xC00;357}358else {359self->groundVel -= 0xC00;360self->velocity.x -= 0xC00;361checkerBall->groundVel += 0xC00;362checkerBall->velocity.x += 0xC00;363checkerBall->angleVel += 0xC00;364}365break;366367case C_LEFT:368case C_RIGHT:369if (self->groundVel <= 0) {370if (self->groundVel < 0 && self->position.x > checkerBall->position.x) {371self->velocity.x = checkerBall->velocity.x;372self->groundVel = checkerBall->groundVel;373}374}375else if (self->position.x < checkerBall->position.x) {376self->velocity.x = checkerBall->velocity.x;377self->groundVel = checkerBall->groundVel;378checkerBall->groundVel = self->groundVel;379checkerBall->velocity.x = self->velocity.x;380}381else if (self->groundVel < 0 && self->position.x > checkerBall->position.x) {382self->velocity.x = checkerBall->velocity.x;383self->groundVel = checkerBall->groundVel;384}385break;386387case C_BOTTOM:388if (self->velocity.y <= 0) {389if (self->velocity.y < 0 && self->position.y > checkerBall->position.y) {390self->velocity.y = checkerBall->velocity.y;391checkerBall->velocity.y = self->velocity.y;392393if (self->onGround) {394self->velocity.x = checkerBall->velocity.x;395self->groundVel = checkerBall->groundVel;396}397398if (checkerBall->onGround) {399checkerBall->groundVel = self->groundVel;400checkerBall->velocity.x = self->velocity.x;401}402}403}404405if (self->position.y < checkerBall->position.y) {406self->velocity.y = checkerBall->velocity.y;407checkerBall->velocity.y = self->velocity.y;408409if (self->onGround) {410self->velocity.x = checkerBall->velocity.x;411self->groundVel = checkerBall->groundVel;412}413414if (checkerBall->onGround) {415checkerBall->groundVel = self->groundVel;416checkerBall->velocity.x = self->velocity.x;417}418}419else {420if (self->velocity.y < 0 && self->position.y > checkerBall->position.y) {421self->velocity.y = checkerBall->velocity.y;422checkerBall->velocity.y = self->velocity.y;423424if (self->onGround) {425self->velocity.x = checkerBall->velocity.x;426self->groundVel = checkerBall->groundVel;427}428429if (checkerBall->onGround) {430checkerBall->groundVel = self->groundVel;431checkerBall->velocity.x = self->velocity.x;432}433}434}435break;436437default: break;438}439440if (RSDK.CheckObjectCollisionTouchBox(checkerBall, &hitboxBall, self, &hitboxBall)) {441if (self->position.x >= checkerBall->position.x)442self->position.x += 0x10000;443else444self->position.x -= 0x10000;445446if (self->position.y >= checkerBall->position.y)447self->position.y += 0x10000;448else449self->position.y -= 0x10000;450}451}452}453454foreach_active(Platform, platform)455{456if (platform->state != Platform_State_Falling2 && platform->state != Platform_State_Hold) {457platform->position.x = platform->drawPos.x - platform->collisionOffset.x;458platform->position.y = platform->drawPos.y - platform->collisionOffset.y;459460int32 side = C_NONE;461if (platform->collision)462side = RSDK.CheckObjectCollisionBox(platform, &platform->hitbox, self, &CheckerBall->hitboxBall, true);463else464side = RSDK.CheckObjectCollisionPlatform(platform, &platform->hitbox, self, &CheckerBall->hitboxBall, true);465466if (side == C_TOP) {467if (platform->state == Platform_State_Fall && !platform->timer)468platform->timer = 30;469platform->stood = true;470self->position.x += platform->collisionOffset.x;471self->position.y += platform->collisionOffset.y;472self->position.y &= 0xFFFF0000;473self->onGround = true;474self->collisionOffset.x = platform->collisionOffset.x;475self->collisionOffset.y = platform->collisionOffset.y;476}477platform->position.x = platform->centerPos.x;478platform->position.y = platform->centerPos.y;479}480}481482foreach_active(Bridge, bridge) { Bridge_HandleCollisions(self, bridge, &CheckerBall->hitboxBall, true, false); }483484foreach_active(Batbrain, batBrain) { CheckerBall_BadnikBreak(batBrain, &Batbrain->hitboxBadnik); }485486foreach_active(BuzzBomber, buzzBomber)487{488if (buzzBomber->state == BuzzBomber_State_ProjectileCharge || buzzBomber->state == BuzzBomber_State_ProjectileShot) {489if (RSDK.CheckObjectCollisionTouchBox(buzzBomber, &BuzzBomber->hitboxProjectile, self, &CheckerBall->hitboxBall)) {490int32 angle = RSDK.ATan2(self->position.x - buzzBomber->position.x, self->position.y - buzzBomber->position.y);491buzzBomber->velocity.x = -0x800 * RSDK.Cos256(angle);492buzzBomber->velocity.y = -0x800 * RSDK.Sin256(angle);493}494}495else {496CheckerBall_BadnikBreak(buzzBomber, &BuzzBomber->hitboxBadnik);497}498}499500foreach_active(Chopper, chopper) { CheckerBall_BadnikBreak(chopper, &Chopper->hitboxJump); }501502foreach_active(Crabmeat, crabmeat)503{504if (crabmeat->state == Crabmeat_State_Projectile) {505if (RSDK.CheckObjectCollisionTouchBox(crabmeat, &Crabmeat->hitboxProjectile, self, &CheckerBall->hitboxBall)) {506int32 angle = RSDK.ATan2(self->position.x - crabmeat->position.x, self->position.y - crabmeat->position.y);507crabmeat->velocity.x = -0x800 * RSDK.Cos256(angle);508crabmeat->velocity.y = -0x800 * RSDK.Sin256(angle);509}510}511else {512CheckerBall_BadnikBreak(crabmeat, &Crabmeat->hitboxBadnik);513}514}515516foreach_active(Motobug, motobug)517{518if (motobug->state != Motobug_State_Smoke)519CheckerBall_BadnikBreak(motobug, &Motobug->hitboxBadnik);520}521522foreach_active(Newtron, newtron)523{524if (newtron->state == Newtron_State_Projectile) {525if (RSDK.CheckObjectCollisionTouchBox(newtron, &Newtron->hitboxProjectile, self, &CheckerBall->hitboxBall)) {526int32 angle = RSDK.ATan2(self->position.x - newtron->position.x, self->position.y - newtron->position.y);527newtron->velocity.x = -0x800 * RSDK.Cos256(angle);528newtron->velocity.y = -0x800 * RSDK.Sin256(angle);529}530}531else {532if (newtron->type == NEWTRON_FLY)533CheckerBall_BadnikBreak(newtron, &Newtron->hitboxFly);534else535CheckerBall_BadnikBreak(newtron, &Newtron->hitboxShoot);536}537}538539foreach_active(Splats, splats) { CheckerBall_BadnikBreak(splats, &Splats->hitboxBadnikGHZ); }540541foreach_active(ItemBox, itemBox)542{543if ((itemBox->state == ItemBox_State_Idle || itemBox->state == ItemBox_State_Falling)544&& RSDK.CheckObjectCollisionTouchBox(itemBox, &ItemBox->hitboxItemBox, self, &CheckerBall->hitboxBall)) {545546// This code is basically "ItemBox_Break"547// "ItemBox_Break" was updated for plus stuff (mighty, swap monitors, etc)548// But this is cant be in comp or effect mighty's velocity this was left unchanged549550RSDK.CreateEntity(TYPE_BLANK, NULL, itemBox->position.x, itemBox->position.y);551itemBox->storedEntity = (Entity *)player1;552itemBox->alpha = 0x100;553itemBox->contentsSpeed = -0x38000;554itemBox->active = ACTIVE_ALWAYS;555itemBox->velocity.y = -0x20000;556itemBox->state = ItemBox_State_Break;557RSDK.SetSpriteAnimation(ItemBox->aniFrames, 1, &itemBox->boxAnimator, true, 0);558itemBox->boxAnimator.frameID = ItemBox->brokenFrame++;559ItemBox->brokenFrame %= 3;560RSDK.SetSpriteAnimation(-1, 0, &itemBox->overlayAnimator, true, 0);561RSDK.SetSpriteAnimation(-1, 0, &itemBox->debrisAnimator, true, 0);562CREATE_ENTITY(Explosion, INT_TO_VOID(EXPLOSION_ITEMBOX), itemBox->position.x, itemBox->position.y - 0x100000);563564for (int32 i = 0; i < 6; ++i) {565EntityDebris *debris = CREATE_ENTITY(Debris, NULL, itemBox->position.x + RSDK.Rand(-0x80000, 0x80000),566itemBox->position.y + RSDK.Rand(-0x80000, 0x80000));567debris->state = Debris_State_Fall;568debris->gravityStrength = 0x4000;569debris->velocity.x = RSDK.Rand(0, 0x20000);570if (debris->position.x < itemBox->position.x)571debris->velocity.x = -debris->velocity.x;572debris->velocity.y = RSDK.Rand(-0x40000, -0x10000);573debris->drawFX = FX_FLIP;574debris->direction = i & 3;575debris->drawGroup = Zone->objectDrawGroup[1];576RSDK.SetSpriteAnimation(ItemBox->aniFrames, 6, &debris->animator, true, RSDK.Rand(0, 4));577}578579RSDK.PlaySfx(ItemBox->sfxDestroy, false, 0xFF);580itemBox->active = ACTIVE_NORMAL;581if (itemBox->type == ITEMBOX_RANDOM) {582if (itemBox->type == ITEMBOX_1UP_SONIC) {583switch (player1->characterID) {584case ID_SONIC: itemBox->type = ITEMBOX_1UP_SONIC; break;585case ID_TAILS: itemBox->type = ITEMBOX_1UP_TAILS; break;586case ID_KNUCKLES: itemBox->type = ITEMBOX_1UP_KNUX; break;587#if MANIA_USE_PLUS588case ID_MIGHTY: itemBox->type = ITEMBOX_1UP_MIGHTY; break;589case ID_RAY: itemBox->type = ITEMBOX_1UP_RAY; break;590#endif591default: break;592}593}594itemBox->contentsAnimator.frameID = itemBox->type;595}596}597}598599foreach_active(BreakableWall, breakableWall)600{601if (breakableWall->state == BreakableWall_State_Wall602&& RSDK.CheckObjectCollisionTouchBox(breakableWall, &breakableWall->hitbox, self, &CheckerBall->hitboxBall)) {603int32 *offsets = BreakableWall->breakOffsets;604605int32 *velocities = NULL;606if (self->position.x >= breakableWall->position.x)607velocities = BreakableWall->breakVelocitiesR;608else609velocities = BreakableWall->breakVelocitiesL;610611for (int32 y = 0; y < 4; ++y) {612for (int32 x = 0; x < 2; ++x) {613int32 tx = breakableWall->position.x + offsets[0];614int32 ty = breakableWall->position.y + offsets[1];615EntityBreakableWall *tile = CREATE_ENTITY(BreakableWall, INT_TO_VOID(BREAKWALL_TILE_FIXED), tx, ty);616tile->tileInfo = RSDK.GetTile(Zone->fgLayer[1], tx >> 20, ty >> 20);617tile->velocity.x = velocities[0];618tile->velocity.y = velocities[1];619RSDK.SetTile(Zone->fgLayer[1], tx >> 20, ty >> 20, -1);620offsets += 2;621velocities += 2;622}623}624625RSDK.PlaySfx(BreakableWall->sfxBreak, false, 0xFF);626destroyEntity(breakableWall);627}628}629630foreach_active(CollapsingPlatform, collapsingPlatform)631{632if (RSDK.CheckObjectCollisionTouchBox(collapsingPlatform, &collapsingPlatform->hitboxTrigger, self, &CheckerBall->hitboxBall)633&& self->onGround)634collapsingPlatform->stoodPos.x = self->position.x;635}636637foreach_active(Spikes, spikes)638{639if (RSDK.CheckObjectCollisionBox(spikes, &spikes->hitbox, self, &CheckerBall->hitboxBall, true)) {640self->onGround = true;641self->position.x += spikes->collisionOffset.x;642self->position.y += spikes->collisionOffset.y;643}644}645646foreach_active(Spring, spring)647{648int32 side = RSDK.CheckObjectCollisionBox(spring, &spring->hitbox, self, &CheckerBall->hitboxBall, true);649if (side) {650bool32 bounced = false;651652if (spring->state == Spring_State_Vertical) {653if ((spring->direction && side == C_BOTTOM) || (!spring->direction && side == C_TOP))654bounced = true;655}656else {657if (spring->state == Spring_State_Diagonal) {658if (self->onGround || self->velocity.y >= 0 || abs(self->velocity.x) > -self->velocity.y)659bounced = true;660}661else if (spring->state == Spring_State_Horizontal && (!spring->onGround || self->onGround)) {662if ((!spring->direction && side == C_RIGHT) || (spring->direction && side == C_LEFT))663bounced = true;664}665}666667if (bounced) {668if (spring->state != Spring_State_Vertical) {669self->groundVel = spring->velocity.x;670self->velocity.x = spring->velocity.x;671}672673if (spring->state != Spring_State_Horizontal) {674self->onGround = false;675self->velocity.y = spring->velocity.y;676}677678RSDK.SetSpriteAnimation(Spring->aniFrames, spring->type, &spring->animator, true, 0);679RSDK.PlaySfx(Spring->sfxSpring, false, 0xFF);680}681}682}683}684685#if GAME_INCLUDE_EDITOR686void CheckerBall_EditorDraw(void) { CheckerBall_Draw(); }687688void CheckerBall_EditorLoad(void)689{690if (RSDK.CheckSceneFolder("GHZ"))691CheckerBall->aniFrames = RSDK.LoadSpriteAnimation("GHZ/CheckerBall.bin", SCOPE_STAGE);692else if (RSDK.CheckSceneFolder("Blueprint"))693CheckerBall->aniFrames = RSDK.LoadSpriteAnimation("Blueprint/CheckerBall.bin", SCOPE_STAGE);694}695#endif696697void CheckerBall_Serialize(void) {}698699700