Path: blob/master/SonicMania/Objects/MMZ/RPlaneShifter.c
338 views
// ---------------------------------------------------------------------1// RSDK Project: Sonic Mania2// Object Description: RPlaneShifter Object3// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges4// Decompiled by: Rubberduckycooly & RMGRich5// ---------------------------------------------------------------------67#include "Game.h"89ObjectRPlaneShifter *RPlaneShifter;1011void RPlaneShifter_Update(void)12{13RSDK_THIS(RPlaneShifter);1415self->prevActivePlayers = self->activePlayers;1617if (self->baseAnimator.animationID == 1)18RSDK.ProcessAnimation(&self->baseAnimator);1920StateMachine_Run(self->state);21}2223void RPlaneShifter_LateUpdate(void) {}2425void RPlaneShifter_StaticUpdate(void)26{27foreach_active(RPlaneShifter, shifter) { RSDK.AddDrawListRef(Zone->playerDrawGroup[1] + 1, RSDK.GetEntitySlot(shifter)); }28}2930void RPlaneShifter_Draw(void) { RPlaneShifter_DrawSprites(); }3132void RPlaneShifter_Create(void *data)33{34RSDK_THIS(RPlaneShifter);3536self->visible = true;37self->drawGroup = Zone->objectDrawGroup[0];38self->active = ACTIVE_BOUNDS;39self->angle = 0;4041if (SceneInfo->inEditor && !self->height)42self->height = 10;4344self->updateRange.x = 0x800000;45self->updateRange.y = 0x800000;4647RSDK.SetSpriteAnimation(RPlaneShifter->aniFrames, 1, &self->baseAnimator, true, 0);48RSDK.SetSpriteAnimation(RPlaneShifter->aniFrames, 2, &RPlaneShifter->barAnimator, true, 0);49self->state = RPlaneShifter_State_Init;50}5152void RPlaneShifter_StageLoad(void)53{54RPlaneShifter->active = ACTIVE_ALWAYS;5556RPlaneShifter->aniFrames = RSDK.LoadSpriteAnimation("MMZ/RPlaneShifter.bin", SCOPE_STAGE);5758RPlaneShifter->sfxTicTock = RSDK.GetSfx("MMZ/TicTock.wav");59}6061void RPlaneShifter_DrawSprites(void)62{63RSDK_THIS(RPlaneShifter);6465Vector2 drawPos = self->position;66if (SceneInfo->inEditor || SceneInfo->currentDrawGroup == Zone->playerDrawGroup[1] + 1)67RSDK.DrawSprite(&self->baseAnimator, &drawPos, false);6869drawPos.y -= 0x80000;7071uint8 poleAngles[3];72poleAngles[0] = self->angle + 21;73poleAngles[1] = self->angle + 106;74poleAngles[2] = self->angle - 64;7576for (uint32 i = 0; i < self->height; ++i) {77drawPos.y -= 0x100000;78for (int32 p = 0; p < 3; ++p) {79drawPos.x = self->position.x;8081if (SceneInfo->inEditor) {82drawPos.x += 0x1C00 * RSDK.Cos256(poleAngles[p]);83RSDK.DrawSprite(&RPlaneShifter->barAnimator, &drawPos, false);84}85else if (SceneInfo->currentDrawGroup != Zone->playerDrawGroup[1] + 1) {86if ((poleAngles[p] >= 0 && poleAngles[p] < 0x80) || SceneInfo->currentDrawGroup == Zone->playerDrawGroup[1] + 1) {87drawPos.x += 0x1C00 * RSDK.Cos256(poleAngles[p]);88RSDK.DrawSprite(&RPlaneShifter->barAnimator, &drawPos, false);89}90}91else if (poleAngles[p] >= 0x80) {92drawPos.x += 0x1C00 * RSDK.Cos256(poleAngles[p]);93RSDK.DrawSprite(&RPlaneShifter->barAnimator, &drawPos, false);94}95}96}9798drawPos.x = self->position.x;99drawPos.y -= 0x80000;100if (SceneInfo->inEditor || SceneInfo->currentDrawGroup == Zone->playerDrawGroup[1] + 1)101RSDK.DrawSprite(&self->baseAnimator, &drawPos, false);102}103104void RPlaneShifter_HandlePlaneShift(EntityPlayer *player)105{106RSDK_THIS(RPlaneShifter);107108player->state = Player_State_Ground;109player->onGround = true;110player->nextGroundState = StateMachine_None;111player->nextAirState = StateMachine_None;112player->groundVel = 0;113114RSDK.SetSpriteAnimation(player->aniFrames, ANI_IDLE, &player->animator, false, 0);115116EntityPlayer *player1 = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);117if (player->sidekick && (!player->sidekick || (self->prevActivePlayers & 1))) {118player->collisionPlane = player1->collisionPlane;119player->drawGroup = player1->drawGroup - 1;120player->direction = player->direction == FLIP_NONE;121}122else {123if (self->flags) {124player->drawGroup = player->collisionPlane ? Zone->playerDrawGroup[0] : Zone->playerDrawGroup[1];125player->collisionPlane = player->collisionPlane ? 0 : 1;126}127else {128player->drawGroup = player->collisionPlane ? Zone->playerDrawGroup[1] : Zone->playerDrawGroup[0];129player->collisionPlane = player->collisionPlane ? 0 : 1;130}131132player->direction = player->direction == FLIP_NONE;133}134}135136void RPlaneShifter_State_Init(void)137{138RSDK_THIS(RPlaneShifter);139140self->active = ACTIVE_BOUNDS;141self->visible = true;142143self->hitbox.left = -2;144self->hitbox.top = -8 - (16 * self->height);145self->hitbox.right = 2;146self->hitbox.bottom = -8;147148self->unused = 0;149RSDK.SetSpriteAnimation(RPlaneShifter->aniFrames, 0, &self->baseAnimator, true, 0);150151self->state = RPlaneShifter_State_AwaitPlayer;152RPlaneShifter_State_AwaitPlayer();153}154155void RPlaneShifter_State_AwaitPlayer(void)156{157RSDK_THIS(RPlaneShifter);158159foreach_active(Player, player)160{161int32 playerID = RSDK.GetEntitySlot(player);162163if (!((1 << playerID) & self->activePlayers) && !((1 << playerID) & self->stoodPlayers)) {164if (Player_CheckCollisionTouch(player, self, &self->hitbox) && player->onGround && !player->isChibi) {165self->activePlayers |= 1 << playerID;166self->stoodPlayers |= 1 << playerID;167168player->groundVel = 0;169player->velocity.x = 0;170player->velocity.y = 0;171player->position.x = self->position.x;172173RSDK.SetSpriteAnimation(player->aniFrames, ANI_IDLE, &player->animator, false, 0);174player->state = Player_State_Static;175player->nextGroundState = StateMachine_None;176player->nextAirState = StateMachine_None;177player->onGround = true;178179if (!player->sidekick) {180self->startAngle = self->angle << 16;181self->spinAngle = 0;182RSDK.SetSpriteAnimation(RPlaneShifter->aniFrames, 1, &self->baseAnimator, true, 0);183RSDK.PlaySfx(RPlaneShifter->sfxTicTock, false, 255);184self->state = RPlaneShifter_State_Spinning;185}186else {187player->abilityValues[0] = player->left;188player->abilityValues[1] = player->right;189}190}191}192193if (player->sidekick) {194if (self->activePlayers & (1 << playerID)) {195if (player->jumpPress) {196self->activePlayers &= ~(1 << playerID);197self->stoodPlayers &= ~(1 << playerID);198Player_Action_Jump(player);199}200201if (!player->abilityValues[0] && player->left) {202self->activePlayers &= ~(1 << playerID);203self->stoodPlayers &= ~(1 << playerID);204player->state = Player_State_Ground;205}206207if (!player->abilityValues[1] && player->right) {208self->activePlayers &= ~(1 << playerID);209self->stoodPlayers &= ~(1 << playerID);210player->state = Player_State_Ground;211}212213player->abilityValues[0] = player->left;214player->abilityValues[1] = player->right;215}216}217218if (Player_CheckCollisionTouch(player, self, &self->hitbox))219self->stoodPlayers |= 1 << playerID;220else221self->stoodPlayers &= ~(1 << playerID);222}223}224225void RPlaneShifter_State_Spinning(void)226{227RSDK_THIS(RPlaneShifter);228229if (abs(self->spinAngle >> 16) < 128) {230uint8 updateSpinSpeed = 1;231if (self->rotateDir && self->spinAngle >> 16 > -65)232updateSpinSpeed = 0;233else if (!self->rotateDir && self->spinAngle >> 16 < 65)234updateSpinSpeed = 0;235236int32 speed = self->rotateDir ? -0x3800 : 0x3800;237238if (updateSpinSpeed) {239self->spinSpeed -= speed;240if (self->rotateDir && self->spinSpeed > -0x3800) {241self->spinSpeed = speed;242updateSpinSpeed = 2;243}244else if (!self->rotateDir && self->spinSpeed < 0x3800) {245self->spinSpeed = speed;246updateSpinSpeed = 2;247}248}249else {250self->spinSpeed += speed;251}252253if (self->rotateDir && self->spinSpeed > -0x3800 && updateSpinSpeed != 2) {254self->spinSpeed = speed;255}256257self->spinAngle += self->spinSpeed;258self->angle = (self->startAngle + self->spinAngle) >> 16;259260if (self->angle < 0)261262self->angle += 0x100;263self->angle &= 0xFF;264}265266if (abs(self->spinAngle >> 16) >= 128) {267self->spinSpeed = 0;268self->spinAngle = 128 << 16;269if (!self->rotateDir)270self->spinAngle = -self->spinAngle;271272self->angle = (self->startAngle + self->spinAngle) >> 16;273if (self->angle < 0)274self->angle += 0x100;275self->angle &= 0xFF;276277RSDK.SetSpriteAnimation(RPlaneShifter->aniFrames, 0, &self->baseAnimator, true, 0);278self->state = RPlaneShifter_State_FinishSpin;279}280281foreach_active(Player, player)282{283int32 playerID = RSDK.GetEntitySlot(player);284285if (!((1 << playerID) & self->activePlayers) && !((1 << playerID) & self->stoodPlayers)286&& Player_CheckCollisionTouch(player, self, &self->hitbox) && player->onGround && !player->isChibi) {287self->activePlayers |= 1 << playerID;288player->groundVel = 0;289player->velocity.x = 0;290player->velocity.y = 0;291player->position.x = self->position.x;292293RSDK.SetSpriteAnimation(player->aniFrames, ANI_IDLE, &player->animator, false, 0);294player->state = Player_State_Static;295player->nextGroundState = StateMachine_None;296player->nextAirState = StateMachine_None;297player->onGround = true;298}299300if ((1 << playerID) & self->activePlayers) {301RSDK.SetSpriteAnimation(player->aniFrames, ANI_TWISTER, &player->animator, false, 0);302303int32 angle = (self->spinAngle >> 16) & 0xFF;304int32 negAngle = 0xFF - angle;305if (player->direction)306negAngle = angle;307308int32 frame = 0;309switch (negAngle >> 6) {310case 0:311case 1: frame = 9 * negAngle / 128; break;312case 2:313case 3: frame = 16 * (negAngle - 128) / 128 + 9; break;314default: break;315}316317player->animator.frameID = frame % 24;318player->animator.speed = 0;319}320321if (Player_CheckCollisionTouch(player, self, &self->hitbox))322self->stoodPlayers |= 1 << playerID;323else324self->stoodPlayers &= ~(1 << playerID);325}326}327328void RPlaneShifter_State_FinishSpin(void)329{330RSDK_THIS(RPlaneShifter);331foreach_active(Player, player)332{333int32 playerID = RSDK.GetEntitySlot(player);334335if ((1 << playerID) & self->activePlayers) {336self->activePlayers &= ~(1 << playerID);337RPlaneShifter_HandlePlaneShift(player);338}339340if (Player_CheckCollisionTouch(player, self, &self->hitbox))341self->stoodPlayers |= 1 << playerID;342else343self->stoodPlayers &= ~(1 << playerID);344345// wait for P1 to get out of the spinner346if (!player->sidekick && !((1 << playerID) & self->activePlayers) && !((1 << playerID) & self->stoodPlayers)) {347self->activePlayers = 0;348self->spinAngle = 0;349self->startAngle = 0;350self->rotateDir = !self->rotateDir;351self->state = RPlaneShifter_State_AwaitPlayer;352}353}354}355356#if GAME_INCLUDE_EDITOR357void RPlaneShifter_EditorDraw(void) { RPlaneShifter_DrawSprites(); }358359void RPlaneShifter_EditorLoad(void)360{361RPlaneShifter->aniFrames = RSDK.LoadSpriteAnimation("MMZ/RPlaneShifter.bin", SCOPE_STAGE);362363RSDK_ACTIVE_VAR(RPlaneShifter, flags);364RSDK_ENUM_VAR("Plane A -> Low Draw Group, Plane B -> High Draw Group", 0);365RSDK_ENUM_VAR("Plane A -> High Draw Group, Plane B -> Low Draw Group", 1);366}367#endif368369void RPlaneShifter_Serialize(void)370{371RSDK_EDITABLE_VAR(RPlaneShifter, VAR_UINT32, height);372RSDK_EDITABLE_VAR(RPlaneShifter, VAR_UINT8, flags);373}374375376