Path: blob/master/SonicMania/Objects/CPZ/Ball.c
338 views
// ---------------------------------------------------------------------1// RSDK Project: Sonic Mania2// Object Description: Ball Object3// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges4// Decompiled by: Rubberduckycooly & RMGRich5// ---------------------------------------------------------------------67#include "Game.h"89ObjectBall *Ball = NULL;1011void Ball_Update(void)12{13RSDK_THIS(Ball);1415StateMachine_Run(self->state);16}1718void Ball_LateUpdate(void) {}1920void Ball_StaticUpdate(void) {}2122void Ball_Draw(void)23{24RSDK_THIS(Ball);2526RSDK.DrawSprite(&self->animator, NULL, false);27}2829void Ball_Create(void *data)30{31RSDK_THIS(Ball);3233self->visible = true;34self->drawGroup = Zone->objectDrawGroup[0];35self->active = ACTIVE_BOUNDS;36self->updateRange.x = 0x800000;37self->updateRange.y = 0x800000;3839if (data) {40RSDK.SetSpriteAnimation(Ball->aniFrames, 2, &self->animator, true, 0);41self->state = Ball_State_Splash;42}43else {44self->startPos = self->position;45if (!self->type) {46RSDK.SetSpriteAnimation(Ball->aniFrames, 0, &self->animator, true, 0);47self->state = Ball_State_Init;48}49else {50self->state = Ball_State_Spawner;51}52}53}5455void Ball_StageLoad(void)56{57if (RSDK.CheckSceneFolder("CPZ"))58Ball->aniFrames = RSDK.LoadSpriteAnimation("CPZ/Ball.bin", SCOPE_STAGE);5960Ball->hitboxBall.left = -10;61Ball->hitboxBall.top = -10;62Ball->hitboxBall.right = 10;63Ball->hitboxBall.bottom = 10;6465Ball->hitboxRange.left = -128;66Ball->hitboxRange.top = -128;67Ball->hitboxRange.right = 128;68Ball->hitboxRange.bottom = 128;6970Ball->sfxSplash = RSDK.GetSfx("Stage/Splash2.wav");7172DEBUGMODE_ADD_OBJ(Ball);73}7475void Ball_DebugSpawn(void)76{77RSDK_THIS(Ball);7879CREATE_ENTITY(Ball, NULL, self->position.x, self->position.y);80}8182void Ball_DebugDraw(void)83{84RSDK.SetSpriteAnimation(Ball->aniFrames, 0, &DebugMode->animator, true, 0);85RSDK.DrawSprite(&DebugMode->animator, NULL, false);86}8788void Ball_HandleInteractions(void)89{90RSDK_THIS(Ball);9192foreach_active(Player, player)93{94if (Player_CheckCollisionTouch(player, self, &Ball->hitboxBall)) {95Player_Hurt(player, self);9697CREATE_ENTITY(Explosion, INT_TO_VOID(EXPLOSION_ENEMY), self->position.x, self->position.y)->drawGroup = Zone->objectDrawGroup[1];98RSDK.PlaySfx(Explosion->sfxDestroy, false, 255);99100self->velocity.y = 0;101RSDK.SetSpriteAnimation(Ball->aniFrames, 1, &self->animator, true, 0);102self->state = Ball_State_ChemicalDrop;103}104}105}106107void Ball_CheckOffScreen(void)108{109RSDK_THIS(Ball);110111if (!RSDK.CheckOnScreen(self, NULL) && !RSDK.CheckPosOnScreen(&self->startPos, &self->updateRange)) {112self->position = self->startPos;113self->direction = FLIP_NONE;114self->velocity.x = 0;115self->velocity.y = 0;116Ball_Create(NULL);117}118}119120void Ball_SpawnSplashes(void)121{122RSDK_THIS(Ball);123124RSDK.PlaySfx(Ball->sfxSplash, false, 255);125126for (int32 i = 0; i < 5; ++i) {127EntityBall *ball = CREATE_ENTITY(Ball, INT_TO_VOID(true), self->position.x, self->position.y);128ball->drawGroup = Zone->objectDrawGroup[1];129ball->velocity.x = RSDK.Rand(-0x100, 0x100) << 10;130if (ball->velocity.x < 0)131ball->velocity.x += 0x20000;132133ball->velocity.x -= 0x10000;134if (i > 0)135ball->velocity.y = RSDK.Rand(-0x400, 0x400) << 8;136ball->velocity.y -= self->velocity.y >> 1;137}138139destroyEntity(self);140}141142void Ball_State_Init(void)143{144RSDK_THIS(Ball);145146self->active = ACTIVE_NORMAL;147148self->state = Ball_State_AwaitPlayer;149Ball_State_AwaitPlayer();150}151152void Ball_State_AwaitPlayer(void)153{154RSDK_THIS(Ball);155156if (self->direction == FLIP_X) {157self->velocity.y += 0x800;158if (self->velocity.y >= 0xC000)159self->direction = FLIP_NONE;160}161else {162self->velocity.y -= 0x800;163if (self->velocity.y <= -0xC000)164self->direction = FLIP_X;165}166self->position.y += self->velocity.y;167168RSDK.ProcessAnimation(&self->animator);169170foreach_active(Player, player)171{172if (Player_CheckCollisionTouch(player, self, &Ball->hitboxRange)) {173self->targetPlayer = player;174self->state = Ball_State_TargetingPlayer;175}176}177178Ball_HandleInteractions();179Ball_CheckOffScreen();180}181182void Ball_State_TargetingPlayer(void)183{184RSDK_THIS(Ball);185186EntityPlayer *targetPlayer = self->targetPlayer;187if (self->position.x <= targetPlayer->position.x) {188self->velocity.x += 0x1000;189if (self->velocity.x > 0x20000)190self->velocity.x = 0x20000;191}192else {193self->velocity.x -= 0x1000;194if (self->velocity.x < -0x20000)195self->velocity.x = -0x20000;196}197198if (self->position.y <= targetPlayer->position.y - 0x400000) {199self->velocity.y += 0x1000;200if (self->velocity.y > 0x20000)201self->velocity.y = 0x20000;202}203else {204self->velocity.y -= 0x1000;205if (self->velocity.y < -0x20000)206self->velocity.y = -0x20000;207}208209self->position.x += self->velocity.x;210self->position.y += self->velocity.y;211212if (abs(self->position.x - targetPlayer->position.x) < 0x100000 && abs(0x500000 + self->position.y - targetPlayer->position.y) < 0x100000) {213if (RSDK.CheckOnScreen(self, &self->updateRange)) {214CREATE_ENTITY(Explosion, INT_TO_VOID(EXPLOSION_ENEMY), self->position.x, self->position.y)->drawGroup = Zone->objectDrawGroup[1];215RSDK.PlaySfx(Explosion->sfxDestroy, false, 255);216217self->velocity.y = 0;218RSDK.SetSpriteAnimation(Ball->aniFrames, 1, &self->animator, true, 0);219self->state = Ball_State_ChemicalDrop;220}221}222223RSDK.ProcessAnimation(&self->animator);224225Ball_HandleInteractions();226Ball_CheckOffScreen();227}228229void Ball_State_ChemicalDrop(void)230{231RSDK_THIS(Ball);232233RSDK.ProcessAnimation(&self->animator);234235if (RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0, 0xB0000, false)) {236Ball_SpawnSplashes();237}238else {239self->position.y += self->velocity.y;240self->velocity.y += 0x3800;241242foreach_active(Player, player)243{244if (Player_CheckCollisionTouch(player, self, &Ball->hitboxBall)) {245Player_ElementHurt(player, self, SHIELD_BUBBLE);246247Ball_SpawnSplashes();248}249}250251if (!RSDK.CheckOnScreen(self, &self->updateRange))252destroyEntity(self);253}254}255256void Ball_State_Splash(void)257{258RSDK_THIS(Ball);259260self->position.x += self->velocity.x;261self->position.y += self->velocity.y;262self->velocity.y += 0x3800;263264if (!RSDK.CheckOnScreen(self, &self->updateRange))265destroyEntity(self);266}267268void Ball_State_StraightMovement(void)269{270RSDK_THIS(Ball);271272RSDK.ProcessAnimation(&self->animator);273274self->position.x += self->velocity.x;275self->position.y += self->velocity.y;276277if (self->velocity.x < 0)278self->velocity.x += 0x400;279if (self->velocity.x > 0)280self->velocity.x -= 0x400;281282if (self->velocity.y < 0)283self->velocity.y += 0x400;284if (self->velocity.y > 0)285self->velocity.y -= 0x400;286287if (!self->velocity.x && !self->velocity.y) {288self->startPos.x = self->position.x;289self->startPos.y = self->position.y;290self->state = Ball_State_AwaitPlayer;291}292293Ball_HandleInteractions();294}295296void Ball_State_Spawner(void)297{298RSDK_THIS(Ball);299300EntityBall *child = RSDK_GET_ENTITY(SceneInfo->entitySlot - 1, Ball);301if (child->classID != Ball->classID) {302RSDK.ResetEntity(child, Ball->classID, NULL);303child->active = ACTIVE_NORMAL;304child->position.x = self->position.x;305child->position.y = self->position.y;306child->state = Ball_State_StraightMovement;307switch (self->type) {308case BALL_SPAWN_LEFT: child->velocity.x = -0x20000; break;309case BALL_SPAWN_UP: child->velocity.y = -0x20000; break;310case BALL_SPAWN_RIGHT: child->velocity.x = 0x20000; break;311case BALL_SPAWN_DOWN: child->velocity.y = 0x20000; break;312default: break;313}314}315}316317#if GAME_INCLUDE_EDITOR318void Ball_EditorDraw(void)319{320RSDK_THIS(Ball);321322self->startPos = self->position;323RSDK.SetSpriteAnimation(Ball->aniFrames, 0, &self->animator, true, 0);324325Ball_Draw();326327if (showGizmos()) {328switch (self->type) {329case BALL_SPAWN_LEFT:330DrawHelpers_DrawArrow(self->position.x, self->position.y, self->position.x - 0x200000, self->position.y, 0xFFFF00, INK_NONE, 0xFF);331break;332333case BALL_SPAWN_UP:334DrawHelpers_DrawArrow(self->position.x, self->position.y, self->position.x, self->position.y - 0x200000, 0xFFFF00, INK_NONE, 0xFF);335break;336337case BALL_SPAWN_RIGHT:338DrawHelpers_DrawArrow(self->position.x, self->position.y, self->position.x + 0x200000, self->position.y, 0xFFFF00, INK_NONE, 0xFF);339break;340341case BALL_SPAWN_DOWN:342DrawHelpers_DrawArrow(self->position.x, self->position.y, self->position.x, self->position.y + 0x200000, 0xFFFF00, INK_NONE, 0xFF);343break;344345default: break;346}347}348}349350void Ball_EditorLoad(void)351{352Ball->aniFrames = RSDK.LoadSpriteAnimation("CPZ/Ball.bin", SCOPE_STAGE);353354RSDK_ACTIVE_VAR(Ball, type);355RSDK_ENUM_VAR("Single Ball", BALL_SINGLE);356RSDK_ENUM_VAR("Spawner (Left)", BALL_SPAWN_LEFT);357RSDK_ENUM_VAR("Spawner (Up)", BALL_SPAWN_UP);358RSDK_ENUM_VAR("Spawner (Right)", BALL_SPAWN_RIGHT);359RSDK_ENUM_VAR("Spawner (Down)", BALL_SPAWN_DOWN);360}361#endif362363void Ball_Serialize(void) { RSDK_EDITABLE_VAR(Ball, VAR_UINT8, type); }364365366