Path: blob/master/SonicMania/Objects/SBZ/Orbinaut.c
338 views
// ---------------------------------------------------------------------1// RSDK Project: Sonic Mania2// Object Description: Orbinaut Object3// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges4// Decompiled by: Rubberduckycooly & RMGRich5// ---------------------------------------------------------------------67#include "Game.h"89ObjectOrbinaut *Orbinaut = NULL;1011void Orbinaut_Update(void)12{13RSDK_THIS(Orbinaut);14StateMachine_Run(self->state);15}1617void Orbinaut_LateUpdate(void) {}1819void Orbinaut_StaticUpdate(void) {}2021void Orbinaut_Draw(void)22{23RSDK_THIS(Orbinaut);2425for (int32 o = 0; o < ORBINAUT_ORB_COUNT; ++o) {26if ((1 << o) & self->activeOrbs) {27RSDK.DrawSprite(&self->animatorOrb, &self->orbPositions[o], false);28}29}3031RSDK.DrawSprite(&self->animatorFace, NULL, false);32}3334void Orbinaut_Create(void *data)35{36RSDK_THIS(Orbinaut);3738self->visible = true;39if (self->planeFilter > 0 && ((self->planeFilter - 1) & 2))40self->drawGroup = Zone->objectDrawGroup[1];41else42self->drawGroup = Zone->objectDrawGroup[0];43self->drawFX |= FX_FLIP;44self->startPos = self->position;45self->startDir = self->direction;46self->active = ACTIVE_BOUNDS;47self->updateRange.x = 0x800000;48self->updateRange.y = 0x800000;49self->activeOrbs = 1 | 2 | 4 | 8;50if (data) {51RSDK.SetSpriteAnimation(Orbinaut->aniFrames, 1, &self->animatorFace, true, 0);52self->state = Orbinaut_State_Orb;53}54else {55RSDK.SetSpriteAnimation(Orbinaut->aniFrames, 0, &self->animatorFace, true, 0);56RSDK.SetSpriteAnimation(Orbinaut->aniFrames, 1, &self->animatorOrb, true, 0);57self->state = Orbinaut_State_Init;58if (self->fireOrbs) {59self->velocity.x = 0;60}61else {62if (self->direction == FLIP_NONE)63self->velocity.x = -0x4000;64else65self->velocity.x = 0x4000;66}67}68}6970void Orbinaut_StageLoad(void)71{72if (RSDK.CheckSceneFolder("MMZ"))73Orbinaut->aniFrames = RSDK.LoadSpriteAnimation("MMZ/Orbinaut.bin", SCOPE_STAGE);7475Orbinaut->hitboxBadnik.left = -8;76Orbinaut->hitboxBadnik.top = -8;77Orbinaut->hitboxBadnik.right = 8;78Orbinaut->hitboxBadnik.bottom = 8;7980Orbinaut->hitboxOrb.left = -4;81Orbinaut->hitboxOrb.top = -4;82Orbinaut->hitboxOrb.right = 4;83Orbinaut->hitboxOrb.bottom = 4;8485DEBUGMODE_ADD_OBJ(Orbinaut);86}8788void Orbinaut_DebugSpawn(void)89{90RSDK_THIS(Orbinaut);91CREATE_ENTITY(Orbinaut, NULL, self->position.x, self->position.y);92}9394void Orbinaut_DebugDraw(void)95{96RSDK.SetSpriteAnimation(Orbinaut->aniFrames, 0, &DebugMode->animator, true, 0);97RSDK.DrawSprite(&DebugMode->animator, NULL, false);98}99100void Orbinaut_HandlePlayerInteractions(void)101{102RSDK_THIS(Orbinaut);103104int32 storeX = self->position.x;105int32 storeY = self->position.y;106for (int32 i = 0; i < ORBINAUT_ORB_COUNT; ++i) {107if ((1 << i) & self->activeOrbs) {108self->position.x = self->orbPositions[i].x;109self->position.y = self->orbPositions[i].y;110foreach_active(Player, player)111{112if (self->planeFilter <= 0 || player->collisionPlane == (uint8)((self->planeFilter - 1) & 1)) {113if (Player_CheckCollisionTouch(player, self, &Orbinaut->hitboxOrb)) {114Player_Hurt(player, self);115}116}117}118}119}120121self->position.x = storeX;122self->position.y = storeY;123124foreach_active(Player, player)125{126if (Player_CheckBadnikTouch(player, self, &Orbinaut->hitboxBadnik) && Player_CheckBadnikBreak(player, self, false)) {127int32 angle = self->angle;128for (int32 i = 0; i < ORBINAUT_ORB_COUNT; ++i) {129if ((1 << i) & self->activeOrbs) {130self->position.x = self->orbPositions[i].x;131self->position.y = self->orbPositions[i].y;132EntityOrbinaut *orb = CREATE_ENTITY(Orbinaut, INT_TO_VOID(true), self->orbPositions[i].x, self->orbPositions[i].y);133134orb->state = Orbinaut_State_OrbDebris;135orb->velocity.x = 0x380 * RSDK.Cos256(angle);136orb->velocity.y = 0x380 * RSDK.Sin256(angle);137}138angle += (0x100 / ORBINAUT_ORB_COUNT);139}140destroyEntity(self);141}142}143}144145void Orbinaut_HandleRotation(void)146{147RSDK_THIS(Orbinaut);148149int32 angle = self->angle;150if (self->direction)151self->angle = (angle - 1) & 0xFF;152else153self->angle = (angle + 1) & 0xFF;154155for (int32 i = 0; i < ORBINAUT_ORB_COUNT; ++i) {156if ((1 << i) & self->activeOrbs) {157self->orbPositions[i].x = (RSDK.Cos256(angle) << 12) + self->position.x;158self->orbPositions[i].y = (RSDK.Sin256(angle) << 12) + self->position.y;159}160angle += (0x100 / ORBINAUT_ORB_COUNT);161}162}163164void Orbinaut_CheckOffScreen(void)165{166RSDK_THIS(Orbinaut);167168if (!RSDK.CheckOnScreen(self, NULL) && !RSDK.CheckPosOnScreen(&self->startPos, &self->updateRange)) {169self->position = self->startPos;170self->direction = self->startDir;171Orbinaut_Create(NULL);172}173}174175void Orbinaut_State_Init(void)176{177RSDK_THIS(Orbinaut);178179self->active = ACTIVE_NORMAL;180self->state = Orbinaut_State_Moving;181Orbinaut_State_Moving();182}183184void Orbinaut_State_Moving(void)185{186RSDK_THIS(Orbinaut);187188self->position.x += self->velocity.x;189190Orbinaut_HandleRotation();191Orbinaut_HandlePlayerInteractions();192193if (self->fireOrbs) {194EntityPlayer *playerPtr = NULL;195int32 distanceX = 0x7FFFFFFF;196int32 distanceY = 0x7FFFFFFF;197foreach_active(Player, player)198{199if (abs(player->position.y - self->position.y) < distanceY)200distanceY = abs(player->position.y - self->position.y);201202if (abs(player->position.y - self->position.y) < 0x400000) {203if (!playerPtr) {204if (abs(player->position.x - self->position.x) < distanceX) {205distanceX = abs(player->position.x - self->position.x);206playerPtr = player;207}208}209else {210if (abs(player->position.x - self->position.x) < distanceX) {211distanceX = abs(player->position.x - self->position.x);212playerPtr = player;213}214}215}216}217218if (!playerPtr)219playerPtr = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);220221if (distanceX <= 0x800000) {222self->state = Orbinaut_State_ReleasingOrbs;223self->animatorFace.frameID = 1;224}225226self->direction = playerPtr->position.x >= self->position.x;227}228229Orbinaut_CheckOffScreen();230}231232void Orbinaut_State_ReleasingOrbs(void)233{234RSDK_THIS(Orbinaut);235236uint8 angle = self->angle;237Orbinaut_HandleRotation();238239for (int32 i = 0; i < ORBINAUT_ORB_COUNT; ++i) {240if (angle == 64) {241if ((1 << i) & self->activeOrbs) {242self->activeOrbs &= ~(1 << i);243EntityOrbinaut *orb = CREATE_ENTITY(Orbinaut, INT_TO_VOID(true), self->orbPositions[i].x, self->orbPositions[i].y);244if (self->direction == FLIP_NONE)245orb->velocity.x = -0x20000;246else247orb->velocity.x = 0x20000;248}249}250angle += (0x100 / ORBINAUT_ORB_COUNT);251}252Orbinaut_HandlePlayerInteractions();253254if (!self->activeOrbs) {255self->state = Orbinaut_State_Orbless;256if (self->direction == FLIP_NONE)257self->velocity.x = -0x4000;258else259self->velocity.x = 0x4000;260}261262if (self->animatorFace.timer >= 0x10)263self->animatorFace.frameID = 2;264else265self->animatorFace.timer++;266267Orbinaut_CheckOffScreen();268}269270void Orbinaut_State_Orbless(void)271{272RSDK_THIS(Orbinaut);273274self->position.x += self->velocity.x;275276Orbinaut_HandlePlayerInteractions();277Orbinaut_CheckOffScreen();278}279280void Orbinaut_State_Orb(void)281{282RSDK_THIS(Orbinaut);283284if (RSDK.CheckOnScreen(self, &self->updateRange)) {285self->position.x += self->velocity.x;286287foreach_active(Player, player)288{289if (self->planeFilter <= 0 || player->collisionPlane == (uint8)((self->planeFilter - 1) & 1)) {290if (Player_CheckCollisionTouch(player, self, &Orbinaut->hitboxOrb)) {291Player_Hurt(player, self);292}293}294}295}296else {297destroyEntity(self);298}299}300301void Orbinaut_State_OrbDebris(void)302{303RSDK_THIS(Orbinaut);304305if (RSDK.CheckOnScreen(self, &self->updateRange)) {306self->position.x += self->velocity.x;307self->position.y += self->velocity.y;308self->velocity.y += 0x3800;309}310else {311destroyEntity(self);312}313}314315#if GAME_INCLUDE_EDITOR316void Orbinaut_EditorDraw(void)317{318RSDK_THIS(Orbinaut);319320int32 angle = self->angle;321Orbinaut_HandleRotation();322self->angle = angle;323324Orbinaut_Draw();325}326327void Orbinaut_EditorLoad(void)328{329Orbinaut->aniFrames = RSDK.LoadSpriteAnimation("MMZ/Orbinaut.bin", SCOPE_STAGE);330331RSDK_ACTIVE_VAR(Orbinaut, planeFilter);332RSDK_ENUM_VAR("None", PLANEFILTER_NONE);333RSDK_ENUM_VAR("AL", PLANEFILTER_AL);334RSDK_ENUM_VAR("BL", PLANEFILTER_BL);335RSDK_ENUM_VAR("AH", PLANEFILTER_AH);336RSDK_ENUM_VAR("BH", PLANEFILTER_BH);337338RSDK_ACTIVE_VAR(Orbinaut, direction);339RSDK_ENUM_VAR("Left", FLIP_NONE);340RSDK_ENUM_VAR("Right", FLIP_X);341}342#endif343344void Orbinaut_Serialize(void)345{346RSDK_EDITABLE_VAR(Orbinaut, VAR_UINT8, direction);347RSDK_EDITABLE_VAR(Orbinaut, VAR_ENUM, planeFilter);348RSDK_EDITABLE_VAR(Orbinaut, VAR_BOOL, fireOrbs);349}350351352