Path: blob/master/SonicMania/Objects/Common/SpinBooster.c
338 views
// ---------------------------------------------------------------------1// RSDK Project: Sonic Mania2// Object Description: SpinBooster Object3// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges4// Decompiled by: Rubberduckycooly & RMGRich5// ---------------------------------------------------------------------67#include "Game.h"89ObjectSpinBooster *SpinBooster;1011void SpinBooster_Update(void)12{13RSDK_THIS(SpinBooster);1415int32 negAngle = -self->angle & 0xFF;1617foreach_active(Player, player)18{19int32 playerID = 1 << RSDK.GetEntitySlot(player);2021Vector2 pivotPos = player->position;22Zone_RotateOnPivot(&pivotPos, &self->position, negAngle);2324if (abs(pivotPos.x - self->position.x) < TO_FIXED(24) && abs(pivotPos.y - self->position.y) < self->size << 19) {25if (pivotPos.x >= self->position.x) {26if (!(playerID & self->activePlayers)) {27SpinBooster_HandleForceRoll(player);28self->activePlayers |= playerID;29}30}31else {32// Exit Tube33if ((playerID & self->activePlayers) && !self->forwardOnly) {34if (player->state == Player_State_TubeRoll || player->state == Player_State_TubeAirRoll) {35player->nextAirState = StateMachine_None;36player->nextGroundState = StateMachine_None;3738if (!self->allowTubeInput)39player->controlLock = 0;4041player->tileCollisions = TILECOLLISION_DOWN;42player->state = player->onGround ? Player_State_Roll : Player_State_Air;43}44}4546self->activePlayers &= ~playerID;47}48}49else {50if (pivotPos.x >= self->position.x)51self->activePlayers |= playerID;52else53self->activePlayers &= ~playerID;54}55}5657self->visible = DebugMode->debugActive;58}5960void SpinBooster_LateUpdate(void) {}6162void SpinBooster_StaticUpdate(void) {}6364void SpinBooster_Draw(void) { SpinBooster_DrawSprites(); }6566void SpinBooster_Create(void *data)67{68RSDK_THIS(SpinBooster);6970RSDK.SetSpriteAnimation(SpinBooster->aniFrames, 0, &self->animator, true, 0);71self->drawFX |= FX_FLIP;72self->animator.frameID = 4;73self->activePlayers = 0;7475if (SceneInfo->inEditor) {76if (!self->boostPower)77self->boostPower = 15;78}79else {80switch (self->direction) {81case FLIP_NONE: self->angle = 0x00; break;82case FLIP_X: self->angle = 0x40; break;83case FLIP_Y: self->angle = 0x80; break;84case FLIP_XY: self->angle = 0xC0; break;85}8687self->active = ACTIVE_BOUNDS;8889self->updateRange.x = self->size * abs(RSDK.Sin256(self->angle)) << 11;90self->updateRange.x += 0x200000;9192self->updateRange.y = self->size * abs(RSDK.Cos256(self->angle)) << 11;93self->updateRange.y += 0x200000;94self->visible = false;95self->drawGroup = Zone->objectDrawGroup[0];96}97}9899void SpinBooster_StageLoad(void) { SpinBooster->aniFrames = RSDK.LoadSpriteAnimation("Global/PlaneSwitch.bin", SCOPE_STAGE); }100101int32 SpinBooster_GetRollDir(EntityPlayer *player)102{103RSDK_THIS(SpinBooster);104105switch (self->direction) {106case FLIP_NONE:107if (self->autoGrip != 5) {108if ((self->autoGrip == 7 || self->autoGrip == 8) && player->up)109return CMODE_ROOF;110111return CMODE_FLOOR;112}113114if (player->down)115return CMODE_FLOOR;116117if (player->up)118return CMODE_ROOF;119120return !self->bias ? CMODE_FLOOR : CMODE_ROOF;121122case FLIP_X:123if (self->autoGrip != 5) {124if (self->autoGrip == 7) {125if (!player->left)126return -1;127128return CMODE_RWALL;129}130131if (self->autoGrip == 6) {132if (!player->right)133return -1;134135return CMODE_LWALL;136}137138if (self->autoGrip != 8)139return -1;140141if (!player->left) {142if (!player->right)143return -1;144145return CMODE_LWALL;146}147else {148return CMODE_RWALL;149}150}151else {152if (player->left)153return CMODE_RWALL;154155if (player->right)156return CMODE_LWALL;157158return !self->bias ? CMODE_LWALL : CMODE_RWALL;159}160161case FLIP_Y:162if (self->autoGrip != 5) {163if ((self->autoGrip == 6 || self->autoGrip == 8) && player->up)164return CMODE_ROOF;165166return CMODE_FLOOR;167}168169if (player->down)170return CMODE_FLOOR;171172if (player->up)173return CMODE_ROOF;174175return !self->bias ? CMODE_ROOF : CMODE_FLOOR;176177case FLIP_XY:178if (self->autoGrip == 5) {179return !player->left ? CMODE_LWALL : CMODE_RWALL;180}181else if (self->autoGrip == 6) {182if (!player->left)183return -1;184185return CMODE_RWALL;186}187else {188if (self->autoGrip == 7) {189if (!player->right)190return -1;191192return CMODE_LWALL;193}194195if (self->autoGrip != 8)196return -1;197198if (!player->left) {199if (!player->right)200return -1;201202return CMODE_LWALL;203}204else {205return CMODE_RWALL;206}207}208209default: break;210}211212return -1;213}214void SpinBooster_HandleRollDir(EntityPlayer *player)215{216RSDK_THIS(SpinBooster);217218if (self->autoGrip) {219int8 cMode = self->autoGrip - 1;220if (self->autoGrip >= 5)221cMode = SpinBooster_GetRollDir(player);222223if (cMode < 0) {224player->onGround = false;225return;226}227228int32 offsetX = 0;229int32 offsetY = 0;230int32 plrAngle = 0;231int32 angle = 0;232233switch (cMode) {234case CMODE_FLOOR:235plrAngle = 0x00;236angle = 0x40;237break;238239case CMODE_LWALL:240plrAngle = -0x40;241angle = 0x00;242break;243244case CMODE_ROOF:245plrAngle = -0x80;246angle = -0x40;247break;248249case CMODE_RWALL:250plrAngle = 0x40;251angle = -0x80;252break;253254default:255plrAngle = 0x00;256angle = 0x00;257break;258}259260Hitbox *playerHitbox = Player_GetHitbox(player);261switch (cMode) {262case CMODE_FLOOR: offsetY = playerHitbox->bottom << 16; break;263case CMODE_LWALL: offsetX = playerHitbox->right << 16; break;264case CMODE_ROOF: offsetY = playerHitbox->top << 16; break;265case CMODE_RWALL: offsetX = playerHitbox->left << 16; break;266default: break;267}268269player->position.x += RSDK.Cos256(angle) << 8;270player->position.y += RSDK.Sin256(angle) << 8;271RSDK.ObjectTileGrip(player, Zone->collisionLayers, cMode, 0, offsetX, offsetY, 1);272273player->angle = plrAngle;274if (player->onGround) {275uint8 mode = 0;276switch (player->collisionMode) {277case CMODE_FLOOR: mode = CMODE_ROOF; break;278case CMODE_LWALL: mode = CMODE_RWALL; break;279case CMODE_ROOF: mode = CMODE_FLOOR; break;280case CMODE_RWALL: mode = CMODE_LWALL; break;281}282283if (cMode == mode)284player->groundVel = -player->groundVel;285}286else {287switch (cMode) {288case CMODE_FLOOR: player->groundVel = player->velocity.x; break;289case CMODE_LWALL: player->groundVel = -player->velocity.y; break;290case CMODE_ROOF: player->groundVel = -player->velocity.x; break;291case CMODE_RWALL: player->groundVel = player->velocity.y; break;292default: break;293}294}295296player->collisionMode = cMode;297player->onGround = true;298}299}300void SpinBooster_ApplyRollVelocity(EntityPlayer *player)301{302RSDK_THIS(SpinBooster);303304if (player->onGround) {305int32 entAng = RSDK.Cos256(self->angle) + RSDK.Sin256(self->angle);306int32 plrAng = RSDK.Cos256(player->angle) - RSDK.Sin256(player->angle);307int32 power = (self->boostPower << 15) * ((plrAng > 0) - (plrAng < 0)) * ((entAng > 0) - (entAng < 0));308309if (self->boostPower >= 0)310player->groundVel += power;311else312player->groundVel = power;313}314else {315int32 x = (0x80 * RSDK.Cos256(self->angle)) * self->boostPower;316int32 y = (-0x80 * RSDK.Sin256(self->angle)) * self->boostPower;317318if (self->boostPower >= 0) {319player->velocity.x += x;320player->velocity.y += y;321}322else {323player->velocity.x = x;324player->velocity.y = y;325}326}327328if (self->boostPower < 0 && !self->forwardOnly) {329if (player->state == Player_State_TubeRoll || player->state == Player_State_TubeAirRoll) {330player->nextAirState = StateMachine_None;331player->nextGroundState = StateMachine_None;332333if (!self->allowTubeInput)334player->controlLock = 0;335336player->tileCollisions = TILECOLLISION_DOWN;337player->state = player->onGround ? Player_State_Roll : Player_State_Air;338}339}340}341void SpinBooster_DrawArrow(int32 x1, int32 y1, int32 x2, int32 y2, uint32 color)342{343int32 angle = RSDK.ATan2(x1 - x2, y1 - y2);344345RSDK.DrawLine(x1, y1, x2, y2, color, 0x7F, INK_ADD, false);346RSDK.DrawLine(x2, y2, x2 + (RSDK.Cos256(angle + 12) << 12), y2 + (RSDK.Sin256(angle + 12) << 12), color, 0x7F, INK_ADD, false);347RSDK.DrawLine(x2, y2, x2 + (RSDK.Cos256(angle - 12) << 12), y2 + (RSDK.Sin256(angle - 12) << 12), color, 0x7F, INK_ADD, false);348}349void SpinBooster_DrawSprites(void)350{351RSDK_THIS(SpinBooster);352353Vector2 drawPos;354drawPos.x = self->position.x;355drawPos.y = self->position.y - (self->size << 19);356Zone_RotateOnPivot(&drawPos, &self->position, self->angle);357358for (int32 i = 0; i < self->size; ++i) {359RSDK.DrawSprite(&self->animator, &drawPos, false);360drawPos.x += RSDK.Sin256(self->angle) << 12;361drawPos.y += RSDK.Cos256(self->angle) << 12;362}363364if (SceneInfo->inEditor) {365uint8 negAngle = -self->angle & 0xFF;366int32 power = self->boostPower;367int32 x = self->position.x;368int32 y = self->position.y;369int32 clr = ((power >> 31) & 0xFE0001) + 0xFFFF;370if (!power)371power = 1;372373int32 x2 = power * (RSDK.Cos256(negAngle) << 11) + self->position.x;374int32 y2 = power * (RSDK.Sin256(negAngle) << 11) + self->position.y;375SpinBooster_DrawArrow(x, y, x2, y2, clr);376377switch (self->autoGrip) {378default: break;379case 1:380case 2:381case 3:382case 4: {383int8 angle = 0;384385switch (self->autoGrip) {386default: break;387case 1: angle = 0x40; break;388case 2: angle = 0x00; break;389case 3: angle = 0xC0; break;390case 4: angle = 0x80; break;391}392393x2 = (RSDK.Cos256(angle) << 14) + self->position.x;394y2 = (RSDK.Sin256(angle) << 14) + self->position.y;395SpinBooster_DrawArrow(x, y, x2, y2, 0x00FF00);396break;397}398399case 5:400clr = !self->bias ? 0x00FF00 : 0xFFFF00;401402x2 = (RSDK.Cos256((negAngle + 64) & 0xFF) << 14) + self->position.x;403y2 = (RSDK.Sin256((negAngle + 64) & 0xFF) << 14) + self->position.y;404SpinBooster_DrawArrow(x, y, x2, y2, clr);405406x2 = (RSDK.Cos256((negAngle - 64) & 0xFF) << 14) + self->position.x;407y2 = (RSDK.Sin256((negAngle - 64) & 0xFF) << 14) + self->position.y;408SpinBooster_DrawArrow(x, y, x2, y2, clr);409break;410411case 6:412clr = 0xFFFF00;413414x2 = (RSDK.Cos256((negAngle + 64) & 0xFF) << 14) + self->position.x;415y2 = (RSDK.Sin256((negAngle + 64) & 0xFF) << 14) + self->position.y;416SpinBooster_DrawArrow(x, y, x2, y2, clr);417418x2 = (RSDK.Cos256(negAngle) << 14) + self->position.x;419y2 = (RSDK.Sin256(negAngle) << 14) + self->position.y;420SpinBooster_DrawArrow(x, y, x2, y2, 0x00FF00);421break;422423case 0:424case 7:425clr = 0xFFFF00;426427x2 = (RSDK.Cos256((negAngle - 64) & 0xFF) << 14) + self->position.x;428y2 = (RSDK.Sin256((negAngle - 64) & 0xFF) << 14) + self->position.y;429SpinBooster_DrawArrow(x, y, x2, y2, clr);430431x2 = (RSDK.Cos256(negAngle) << 14) + self->position.x;432y2 = (RSDK.Sin256(negAngle) << 14) + self->position.y;433SpinBooster_DrawArrow(x, y, x2, y2, 0x00FF00);434break;435436case 8:437clr = 0xFFFF00;438439x2 = (RSDK.Cos256((negAngle + 64) & 0xFF) << 14) + self->position.x;440y2 = (RSDK.Sin256((negAngle + 64) & 0xFF) << 14) + self->position.y;441SpinBooster_DrawArrow(x, y, x2, y2, clr);442443x2 = (RSDK.Cos256((negAngle - 64) & 0xFF) << 14) + self->position.x;444y2 = (RSDK.Sin256((negAngle - 64) & 0xFF) << 14) + self->position.y;445SpinBooster_DrawArrow(x, y, x2, y2, clr);446447x2 = (RSDK.Cos256(negAngle) << 14) + self->position.x;448y2 = (RSDK.Sin256(negAngle) << 14) + self->position.y;449SpinBooster_DrawArrow(x, y, x2, y2, 0x00FF00);450break;451}452}453}454void SpinBooster_HandleForceRoll(EntityPlayer *player)455{456RSDK_THIS(SpinBooster);457458player->tileCollisions = TILECOLLISION_DOWN;459SpinBooster_HandleRollDir(player);460461if (player->state == Player_State_TubeRoll || player->state == Player_State_TubeAirRoll) {462if (self->boostAlways)463SpinBooster_ApplyRollVelocity(player);464}465else {466if (self->playSound)467RSDK.PlaySfx(Player->sfxRoll, false, 0xFF);468469if (player->animator.animationID != ANI_JUMP) {470RSDK.SetSpriteAnimation(player->aniFrames, ANI_JUMP, &player->animator, false, 0);471if (!player->collisionMode && player->onGround)472player->position.y += player->jumpOffset;473player->pushing = false;474}475476player->nextAirState = StateMachine_None;477player->nextGroundState = StateMachine_None;478479if (!self->allowTubeInput)480player->controlLock = 0xFFFF;481482player->state = player->onGround ? Player_State_TubeRoll : Player_State_TubeAirRoll;483484if (abs(player->groundVel) < TO_FIXED(1))485player->groundVel = (self->direction & FLIP_X) ? -TO_FIXED(4) : TO_FIXED(4);486487SpinBooster_ApplyRollVelocity(player);488}489}490491#if GAME_INCLUDE_EDITOR492void SpinBooster_EditorDraw(void) { SpinBooster_DrawSprites(); }493494void SpinBooster_EditorLoad(void)495{496SpinBooster->aniFrames = RSDK.LoadSpriteAnimation("Global/PlaneSwitch.bin", SCOPE_STAGE);497498RSDK_ACTIVE_VAR(SpinBooster, direction);499RSDK_ENUM_VAR("No Flip", FLIP_NONE);500RSDK_ENUM_VAR("Flip X", FLIP_X);501RSDK_ENUM_VAR("Flip Y", FLIP_Y);502RSDK_ENUM_VAR("Flip XY", FLIP_XY);503504RSDK_ACTIVE_VAR(SpinBooster, bias);505RSDK_ENUM_VAR("No Bias", false);506RSDK_ENUM_VAR("Has Bias", true);507}508#endif509510void SpinBooster_Serialize(void)511{512RSDK_EDITABLE_VAR(SpinBooster, VAR_UINT8, direction);513RSDK_EDITABLE_VAR(SpinBooster, VAR_UINT8, autoGrip);514RSDK_EDITABLE_VAR(SpinBooster, VAR_UINT8, bias);515RSDK_EDITABLE_VAR(SpinBooster, VAR_ENUM, size);516RSDK_EDITABLE_VAR(SpinBooster, VAR_INT32, boostPower);517RSDK_EDITABLE_VAR(SpinBooster, VAR_BOOL, boostAlways);518RSDK_EDITABLE_VAR(SpinBooster, VAR_BOOL, forwardOnly);519RSDK_EDITABLE_VAR(SpinBooster, VAR_BOOL, playSound);520RSDK_EDITABLE_VAR(SpinBooster, VAR_BOOL, allowTubeInput);521}522523524