Path: blob/master/SonicMania/Objects/OOZ/Sol.c
338 views
// ---------------------------------------------------------------------1// RSDK Project: Sonic Mania2// Object Description: Sol Object3// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges4// Decompiled by: Rubberduckycooly & RMGRich5// ---------------------------------------------------------------------67#include "Game.h"89ObjectSol *Sol;1011void Sol_Update(void)12{13RSDK_THIS(Sol);1415StateMachine_Run(self->state);16}1718void Sol_LateUpdate(void) {}1920void Sol_StaticUpdate(void) {}2122void Sol_Draw(void)23{24RSDK_THIS(Sol);2526for (int32 i = 0; i < SOL_FLAMEORB_COUNT; ++i) {27if ((1 << i) & self->activeOrbs)28RSDK.DrawSprite(&self->ballAnimator, &self->positions[i], false);29}3031RSDK.DrawSprite(&self->mainAnimator, NULL, false);32}3334void Sol_Create(void *data)35{36RSDK_THIS(Sol);3738self->visible = true;39self->drawGroup = Zone->objectDrawGroup[0];40self->drawFX = FX_FLIP;4142if (data) {43RSDK.SetSpriteAnimation(Sol->aniFrames, 1, &self->mainAnimator, true, 0);44self->active = ACTIVE_NORMAL;45self->drawFX |= FX_ROTATE;46self->updateRange.x = 0x1000000;47self->updateRange.y = 0x1000000;48self->state = Sol_State_SmallFireball;49}50else {51self->startPos = self->position;52self->startDir = self->direction;53self->active = ACTIVE_BOUNDS;54self->updateRange.x = 0x800000;55self->updateRange.y = 0x800000;56self->activeOrbs = 2 | 8;5758RSDK.SetSpriteAnimation(Sol->aniFrames, 0, &self->mainAnimator, true, 0);59RSDK.SetSpriteAnimation(Sol->aniFrames, 1, &self->ballAnimator, true, 0);60self->state = Sol_State_Init;61self->velocity.x = self->direction == FLIP_NONE ? -0x4000 : 0x4000;62}63}6465void Sol_StageLoad(void)66{67if (RSDK.CheckSceneFolder("OOZ1") || RSDK.CheckSceneFolder("OOZ2"))68Sol->aniFrames = RSDK.LoadSpriteAnimation("OOZ/Sol.bin", SCOPE_STAGE);6970Sol->hitboxBadnik.left = -8;71Sol->hitboxBadnik.top = -8;72Sol->hitboxBadnik.right = 8;73Sol->hitboxBadnik.bottom = 8;7475Sol->hitboxOrb.left = -4;76Sol->hitboxOrb.top = -4;77Sol->hitboxOrb.right = 4;78Sol->hitboxOrb.bottom = 4;7980DEBUGMODE_ADD_OBJ(Sol);81}8283void Sol_DebugSpawn(void)84{85RSDK_THIS(Sol);8687CREATE_ENTITY(Sol, NULL, self->position.x, self->position.y);88}8990void Sol_DebugDraw(void)91{92RSDK.SetSpriteAnimation(Sol->aniFrames, 0, &DebugMode->animator, true, 0);93RSDK.DrawSprite(&DebugMode->animator, 0, false);94}9596void Sol_HandlePlayerInteractions(void)97{98RSDK_THIS(Sol);99100int32 storeX = self->position.x;101int32 storeY = self->position.y;102103for (int32 i = 0; i < SOL_FLAMEORB_COUNT; ++i) {104if ((1 << i) & self->activeOrbs) {105self->position.x = self->positions[i].x;106self->position.y = self->positions[i].y;107108foreach_active(Player, player)109{110#if MANIA_USE_PLUS111if (player->state != Player_State_MightyHammerDrop) {112#endif113Sol_HandlePlayerHurt();114#if MANIA_USE_PLUS115}116#endif117}118}119}120121self->position.x = storeX;122self->position.y = storeY;123124foreach_active(Player, player)125{126if (Player_CheckBadnikTouch(player, self, &Sol->hitboxBadnik) && Player_CheckBadnikBreak(player, self, false)) {127int32 angle = self->angle;128for (int32 i = 0; i < SOL_FLAMEORB_COUNT; ++i) {129if ((1 << i) & self->activeOrbs) {130self->position.x = self->positions[i].x;131self->position.y = self->positions[i].y;132133EntitySol *sol = CREATE_ENTITY(Sol, INT_TO_VOID(true), self->positions[i].x, self->positions[i].y);134135sol->state = Sol_State_ActiveFireball;136#if MANIA_USE_PLUS137if (player->state == Player_State_MightyHammerDrop)138sol->interaction = false;139#endif140sol->velocity.x = 0x380 * RSDK.Cos256(angle);141sol->velocity.y = 0x380 * RSDK.Sin256(angle);142}143144angle += (0x100 / SOL_FLAMEORB_COUNT);145}146147destroyEntity(self);148}149}150}151152void Sol_HandlePlayerHurt(void)153{154RSDK_THIS(Sol);155156foreach_active(Player, player)157{158if (Player_CheckCollisionTouch(player, self, &Sol->hitboxOrb)) {159Player_ElementHurt(player, self, SHIELD_FIRE);160}161}162}163164void Sol_HandleRotation(void)165{166RSDK_THIS(Sol);167168int32 angle = self->angle;169if (self->direction)170self->angle = (angle - 1) & 0xFF;171else172self->angle = (angle + 1) & 0xFF;173174for (int32 i = 0; i < SOL_FLAMEORB_COUNT; ++i) {175if ((1 << i) & self->activeOrbs) {176self->positions[i].x = (RSDK.Cos256(angle) << 12) + self->position.x;177self->positions[i].y = (RSDK.Sin256(angle) << 12) + self->position.y;178}179180angle += (0x100 / SOL_FLAMEORB_COUNT);181}182}183184void Sol_CheckOffScreen(void)185{186RSDK_THIS(Sol);187188if (!RSDK.CheckOnScreen(self, NULL) && !RSDK.CheckPosOnScreen(&self->startPos, &self->updateRange)) {189self->position = self->startPos;190self->direction = self->startDir;191Sol_Create(NULL);192}193}194195void Sol_State_Init(void)196{197RSDK_THIS(Sol);198199self->active = ACTIVE_NORMAL;200201self->state = Sol_State_Moving;202Sol_State_Moving();203}204205void Sol_State_Moving(void)206{207RSDK_THIS(Sol);208209RSDK.ProcessAnimation(&self->ballAnimator);210211self->position.x += self->velocity.x;212self->position.y = (RSDK.Sin256(self->oscillateAngle) << 10) + self->startPos.y;213self->oscillateAngle += 4;214215Sol_HandleRotation();216Sol_HandlePlayerInteractions();217218if (self->fireOrbs) {219EntityPlayer *playerPtr = NULL;220int32 distanceX = 0x7FFFFFFF;221int32 distanceY = 0x7FFFFFFF;222223foreach_active(Player, player)224{225if (abs(player->position.y - self->position.y) < distanceY)226distanceY = abs(player->position.y - self->position.y);227228if (abs(player->position.y - self->position.y) < 0x400000) {229if (!playerPtr) {230if (abs(player->position.x - self->position.x) < distanceX) {231distanceX = abs(player->position.x - self->position.x);232playerPtr = player;233}234}235else {236if (abs(player->position.x - self->position.x) < distanceX) {237distanceX = abs(player->position.x - self->position.x);238playerPtr = player;239}240}241}242}243244if (!playerPtr)245playerPtr = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);246247if (distanceX <= 0x800000) {248self->state = Sol_State_ShootingOrbs;249self->mainAnimator.frameID = 1;250}251252self->direction = playerPtr->position.x >= self->position.x;253}254255Sol_CheckOffScreen();256}257258void Sol_State_ShootingOrbs(void)259{260RSDK_THIS(Sol);261262RSDK.ProcessAnimation(&self->ballAnimator);263264self->position.x += self->velocity.x;265self->position.y = (RSDK.Sin256(self->oscillateAngle) << 10) + self->startPos.y;266self->oscillateAngle += 4;267268uint8 angle = self->angle;269Sol_HandleRotation();270271for (int32 i = 0; i < SOL_FLAMEORB_COUNT; ++i) {272if (angle == 0x40) {273if ((1 << i) & self->activeOrbs) {274self->activeOrbs &= ~(1 << i);275EntitySol *sol = CREATE_ENTITY(Sol, INT_TO_VOID(true), self->positions[i].x, self->positions[i].y);276sol->velocity.x = self->direction == FLIP_NONE ? -0x20000 : 0x20000;277}278}279280angle += (0x100 / SOL_FLAMEORB_COUNT);281}282283Sol_HandlePlayerInteractions();284285if (!self->activeOrbs) {286self->state = Sol_State_NoOrbs;287self->velocity.x = self->direction == FLIP_NONE ? -0x4000 : 0x4000;288}289290if (self->mainAnimator.timer >= 0x10)291self->mainAnimator.frameID = 2;292else293self->mainAnimator.timer++;294295Sol_CheckOffScreen();296}297298void Sol_State_NoOrbs(void)299{300RSDK_THIS(Sol);301302RSDK.ProcessAnimation(&self->ballAnimator);303304self->position.x += self->velocity.x;305self->position.y = (RSDK.Sin256(self->oscillateAngle) << 10) + self->startPos.y;306self->oscillateAngle += 4;307308Sol_HandleRotation();309Sol_HandlePlayerInteractions();310Sol_CheckOffScreen();311}312313void Sol_State_SmallFireball(void)314{315RSDK_THIS(Sol);316317RSDK.ProcessAnimation(&self->mainAnimator);318319self->position.x += self->velocity.x;320321if (RSDK.CheckOnScreen(self, &self->updateRange))322Sol_HandlePlayerHurt();323else324destroyEntity(self);325}326327void Sol_State_ActiveFireball(void)328{329RSDK_THIS(Sol);330331if (RSDK.CheckOnScreen(self, &self->updateRange)) {332self->position.x += self->velocity.x;333self->position.y += self->velocity.y;334self->velocity.y += 0x3800;335336self->rotation = 2 * RSDK.ATan2(self->velocity.x >> 16, self->velocity.y >> 16) + 384;337338int32 offsetX = RSDK.Sin512(512 - self->rotation) << 10;339int32 offsetY = RSDK.Cos512(512 - self->rotation) << 10;340int32 cmode = 3 - (((self->rotation - 0x40) >> 7) & 3);341342bool32 collided = RSDK.ObjectTileCollision(self, Zone->collisionLayers, cmode, 1, offsetX, offsetY, true);343if (!collided)344collided = RSDK.ObjectTileCollision(self, Zone->collisionLayers, cmode, 0, offsetX, offsetY, true);345346if (collided) {347RSDK.SetSpriteAnimation(Sol->aniFrames, 2, &self->mainAnimator, true, 0);348self->state = Sol_State_FlameDissipate;349self->rotation = (self->rotation + 64) & 0x180;350}351352int32 spawnX = self->position.x + offsetX;353int32 spawnY = self->position.y + offsetY;354uint16 tile = RSDK.GetTile(Zone->fgLayer[1], spawnX >> 20, (spawnY - 0x10000) >> 20);355if (tile == (uint16)-1)356tile = RSDK.GetTile(Zone->fgLayer[0], spawnX >> 20, (spawnY - 0x10000) >> 20);357358int32 tileFlags = RSDK.GetTileFlags(tile, 0);359if (((tileFlags == OOZ_TFLAGS_OILSTRIP || tileFlags == OOZ_TFLAGS_OILSLIDE) && collided) || tileFlags == OOZ_TFLAGS_OILPOOL) {360self->position.x = spawnX - 0x40000;361self->position.y = spawnY - 0x80000;362self->rotation = 0;363self->velocity.x = -0x40000;364self->velocity.y = 0;365RSDK.SetSpriteAnimation(Sol->aniFrames, 3, &self->mainAnimator, true, 0);366self->state = Sol_State_FireballOilFlame;367368EntitySol *sol = CREATE_ENTITY(Sol, INT_TO_VOID(true), spawnX, spawnY - 0x80000);369sol->velocity.x = 0x40000;370sol->velocity.y = 0;371RSDK.SetSpriteAnimation(Sol->aniFrames, 3, &sol->mainAnimator, true, 0);372sol->state = Sol_State_FireballOilFlame;373sol->oscillateAngle = sol->position.x & 0xF00000;374375if (tileFlags == OOZ_TFLAGS_OILPOOL) {376self->position.y = (self->position.y & 0xFFF00000) + 0x20000;377sol->position.y = (sol->position.y & 0xFFF00000) + 0x20000;378sol->state = Sol_State_OilFlame;379self->state = Sol_State_OilFlame;380}381else {382self->position.y -= 0x80000;383}384}385386if (self->interaction)387Sol_HandlePlayerHurt();388}389else {390destroyEntity(self);391}392}393394void Sol_State_FlameDissipate(void)395{396RSDK_THIS(Sol);397398RSDK.ProcessAnimation(&self->mainAnimator);399400if (!RSDK.CheckOnScreen(self, &self->updateRange) || self->mainAnimator.frameID == self->mainAnimator.frameCount - 1) {401destroyEntity(self);402}403}404405void Sol_State_FireballOilFlame(void)406{407RSDK_THIS(Sol);408409if (RSDK.CheckOnScreen(self, &self->updateRange)) {410bool32 collided = RSDK.ObjectTileGrip(self, Zone->collisionLayers, CMODE_FLOOR, 1, 0, 0x80000, 16);411if (!collided)412collided = RSDK.ObjectTileGrip(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0, 0x80000, 16);413414if (collided) {415uint16 tile = RSDK.GetTile(Zone->fgLayer[1], self->position.x >> 20, (self->position.y + 0x90000) >> 20);416if (tile == (uint16)-1)417tile = RSDK.GetTile(Zone->fgLayer[0], self->position.x >> 20, (self->position.y + 0x90000) >> 20);418419self->rotation = 2 * RSDK.GetTileAngle(tile, 0, 0);420}421422uint16 tile = RSDK.GetTile(Zone->fgLayer[1], self->position.x >> 20, (self->position.y + 0x70000) >> 20);423if (tile == (uint16)-1)424tile = RSDK.GetTile(Zone->fgLayer[0], self->position.x >> 20, (self->position.y + 0x70000) >> 20);425426int32 tileFlags = RSDK.GetTileFlags(tile, 0);427if (tileFlags == OOZ_TFLAGS_NORMAL || tileFlags == OOZ_TFLAGS_OILFALL) {428if (collided) {429RSDK.SetSpriteAnimation(Sol->aniFrames, 2, &self->mainAnimator, true, 0);430self->state = Sol_State_FlameDissipate;431}432else {433self->state = Sol_State_ActiveFireball;434}435}436else {437self->position.y -= 0x80000;438if ((self->position.x & 0xF00000) != self->oscillateAngle)439OOZSetup_StartFire((self->position.x & 0xFFF00000) + 0x70000, self->position.y & 0xFFFF0000, self->rotation >> 1);440441self->oscillateAngle = self->position.x & 0xF00000;442}443444self->position.x += self->velocity.x;445self->position.y += 0x80000;446447RSDK.ProcessAnimation(&self->mainAnimator);448449Sol_HandlePlayerHurt();450}451else {452destroyEntity(self);453}454}455456void Sol_State_OilFlame(void)457{458RSDK_THIS(Sol);459460if (RSDK.CheckOnScreen(self, &self->updateRange)) {461uint16 tile = RSDK.GetTile(Zone->fgLayer[1], self->position.x >> 20, (self->position.y + 0xF0000) >> 20);462if (tile == (uint16)-1)463tile = RSDK.GetTile(Zone->fgLayer[0], self->position.x >> 20, (self->position.y + 0xF0000) >> 20);464465if (RSDK.GetTileFlags(tile, 0) == OOZ_TFLAGS_OILPOOL) {466if ((self->position.x & 0xF00000) != self->oscillateAngle)467OOZSetup_StartFire((self->position.x & 0xFFF00000) + 0x70000, self->position.y & 0xFFFF0000, self->rotation >> 1);468469self->oscillateAngle = self->position.x & 0xF00000;470}471else {472RSDK.SetSpriteAnimation(Sol->aniFrames, 2, &self->mainAnimator, true, 0);473self->state = Sol_State_FlameDissipate;474}475476self->position.x += self->velocity.x;477478RSDK.ProcessAnimation(&self->mainAnimator);479480Sol_HandlePlayerHurt();481}482else {483destroyEntity(self);484}485}486487#if GAME_INCLUDE_EDITOR488void Sol_EditorDraw(void)489{490RSDK_THIS(Sol);491492int32 angle = self->angle;493Sol_HandleRotation();494self->angle = angle;495496Sol_Draw();497}498499void Sol_EditorLoad(void)500{501Sol->aniFrames = RSDK.LoadSpriteAnimation("OOZ/Sol.bin", SCOPE_STAGE);502503RSDK_ACTIVE_VAR(Sol, direction);504RSDK_ENUM_VAR("Left", FLIP_NONE);505RSDK_ENUM_VAR("Right", FLIP_X);506}507#endif508509void Sol_Serialize(void)510{511RSDK_EDITABLE_VAR(Sol, VAR_UINT8, direction);512RSDK_EDITABLE_VAR(Sol, VAR_BOOL, fireOrbs);513}514515516