Path: blob/master/SonicMania/Objects/CPZ/Grabber.c
338 views
// ---------------------------------------------------------------------1// RSDK Project: Sonic Mania2// Object Description: Grabber Object3// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges4// Decompiled by: Rubberduckycooly & RMGRich5// ---------------------------------------------------------------------67#include "Game.h"89ObjectGrabber *Grabber;1011void Grabber_Update(void)12{13RSDK_THIS(Grabber);1415StateMachine_Run(self->state);16}1718void Grabber_LateUpdate(void) {}1920void Grabber_StaticUpdate(void) {}2122void Grabber_Draw(void)23{24RSDK_THIS(Grabber);2526if (SceneInfo->currentDrawGroup == self->drawGroup) {27RSDK.DrawLine(self->position.x, self->startPos.y - 0x100000, self->position.x, self->position.y, 0x202020, 0x00, INK_NONE, false);28RSDK.DrawLine(self->position.x - 0x10000, self->startPos.y - 0x100000, self->position.x - 0x10000, self->position.y, 0xE0E0E0, 0x00, INK_NONE,29false);3031Vector2 drawPos;32int32 storeDir = self->direction;33drawPos.x = self->position.x;34drawPos.y = self->startPos.y;35self->direction = 0;36RSDK.DrawSprite(&self->wheelAnimator, &drawPos, false);3738self->direction = storeDir;39RSDK.DrawSprite(&self->bodyAnimator, NULL, false);4041if (!SceneInfo->currentScreenID)42RSDK.AddDrawListRef(Zone->objectDrawGroup[1], SceneInfo->entitySlot);43}44else {45RSDK.DrawSprite(&self->clampAnimator, NULL, false);46}47}4849void Grabber_Create(void *data)50{51RSDK_THIS(Grabber);5253self->visible = true;54self->drawGroup = Zone->objectDrawGroup[0];55self->startPos = self->position;56self->startDir = self->direction;57self->active = ACTIVE_BOUNDS;5859self->velocity.x = !self->direction ? -0x4000 : 0x4000;60self->updateRange.x = 0x800000;61self->updateRange.y = 0x800000;62self->drawFX = FX_FLIP;63RSDK.SetSpriteAnimation(Grabber->aniFrames, 0, &self->bodyAnimator, true, 0);64RSDK.SetSpriteAnimation(Grabber->aniFrames, 1, &self->clampAnimator, true, 0);65RSDK.SetSpriteAnimation(Grabber->aniFrames, 4, &self->wheelAnimator, true, 0);66self->state = Grabber_State_Init;67}6869void Grabber_StageLoad(void)70{71Grabber->aniFrames = RSDK.LoadSpriteAnimation("CPZ/Grabber.bin", SCOPE_STAGE);7273Grabber->hitboxBadnik.left = -8;74Grabber->hitboxBadnik.top = -8;75Grabber->hitboxBadnik.right = 8;76Grabber->hitboxBadnik.bottom = 8;7778Grabber->hitboxRange.left = -64;79Grabber->hitboxRange.top = 0;80Grabber->hitboxRange.right = 64;81Grabber->hitboxRange.bottom = 128;8283Grabber->hitboxGrab.left = -8;84Grabber->hitboxGrab.top = 0;85Grabber->hitboxGrab.right = 8;86Grabber->hitboxGrab.bottom = 16;8788DEBUGMODE_ADD_OBJ(Grabber);8990Grabber->sfxGrab = RSDK.GetSfx("Global/Grab.wav");91Grabber->sfxDestroy = RSDK.GetSfx("Global/Destroy.wav");92}9394void Grabber_DebugDraw(void)95{96RSDK.SetSpriteAnimation(Grabber->aniFrames, 0, &DebugMode->animator, true, 0);97RSDK.DrawSprite(&DebugMode->animator, NULL, false);98}99100void Grabber_DebugSpawn(void)101{102RSDK_THIS(Grabber);103EntityGrabber *grabber = CREATE_ENTITY(Grabber, NULL, self->position.x, self->position.y);104grabber->direction = self->direction;105grabber->startDir = self->direction;106grabber->velocity.x = !self->direction ? -0x4000 : 0x4000;107}108109void Grabber_CheckPlayerCollisions(void)110{111RSDK_THIS(Grabber);112113foreach_active(Player, player)114{115if (player != self->grabbedPlayer) {116if (self->state == Grabber_State_TryToGrab) {117if (Player_CheckCollisionTouch(player, self, &Grabber->hitboxGrab)) {118RSDK.PlaySfx(Grabber->sfxGrab, false, 255);119self->state = Grabber_State_GrabbedPlayer;120self->isPermanent = true;121self->grabbedPlayer = player;122player->velocity.x = 0;123player->velocity.y = 0;124player->groundVel = 0;125player->state = Player_State_Static;126player->nextAirState = StateMachine_None;127player->nextGroundState = StateMachine_None;128player->onGround = false;129player->direction = self->direction;130RSDK.SetSpriteAnimation(player->aniFrames, ANI_FAN, &player->animator, true, 0);131player->animator.speed = 0;132player->direction = self->direction ^ FLIP_X;133}134}135136if (player != self->grabbedPlayer && !self->grabDelay && Player_CheckBadnikTouch(player, self, &Grabber->hitboxBadnik)137&& Player_CheckBadnikBreak(player, self, false)) {138EntityPlayer *playerPtr = self->grabbedPlayer;139if (playerPtr)140playerPtr->state = Player_State_Air;141destroyEntity(self);142}143}144}145}146147void Grabber_CheckOffScreen(void)148{149RSDK_THIS(Grabber);150151if (!RSDK.CheckOnScreen(self, NULL) && !RSDK.CheckPosOnScreen(&self->startPos, &self->updateRange)) {152self->position = self->startPos;153self->struggleDelay = 0;154self->struggleTimer = 0;155self->struggleFlags = 0;156self->direction = self->startDir;157self->grabbedPlayer = NULL;158self->turnTimer = 0;159self->timer = 0;160Grabber_Create(NULL);161}162}163164void Grabber_HandleExplode(void)165{166RSDK_THIS(Grabber);167168if (!--self->turnTimer) {169self->bodyAnimator.frameID ^= 1;170self->turnTimer = self->timer;171172if (!--self->timer) {173EntityPlayer *player = self->grabbedPlayer;174if (player && player->state == Player_State_Static) {175Player_Hurt(player, self);176if (player->state != Player_State_Hurt && Player_CheckValidState(player))177player->state = Player_State_Air;178self->grabbedPlayer = NULL;179}180181CREATE_ENTITY(Explosion, INT_TO_VOID(EXPLOSION_ENEMY), self->position.x, self->position.y)->drawGroup = Zone->objectDrawGroup[1];182RSDK.PlaySfx(Explosion->sfxDestroy, false, 255);183destroyEntity(self);184}185}186}187188void Grabber_State_Init(void)189{190RSDK_THIS(Grabber);191192self->active = ACTIVE_NORMAL;193self->state = Grabber_State_CheckForGrab;194Grabber_State_CheckForGrab();195}196197void Grabber_State_CheckForGrab(void)198{199RSDK_THIS(Grabber);200201RSDK.ProcessAnimation(&self->wheelAnimator);202203if (++self->turnTimer >= 256) {204self->turnTimer = 0;205RSDK.SetSpriteAnimation(Grabber->aniFrames, 3, &self->bodyAnimator, true, 0);206RSDK.SetSpriteAnimation(-1, 0, &self->clampAnimator, true, 0);207self->state = Grabber_State_HandleTurn;208}209self->position.x += self->velocity.x;210211foreach_active(Player, player)212{213if (Player_CheckCollisionTouch(player, self, &Grabber->hitboxRange)) {214self->timer = 16;215self->state = Grabber_State_GrabDelay;216}217}218219Grabber_CheckPlayerCollisions();220Grabber_CheckOffScreen();221}222223void Grabber_State_GrabDelay(void)224{225RSDK_THIS(Grabber);226227if (--self->timer < 0) {228self->timer = 32;229self->state = Grabber_State_TryToGrab;230}231232Grabber_CheckPlayerCollisions();233Grabber_CheckOffScreen();234}235236void Grabber_State_HandleTurn(void)237{238RSDK_THIS(Grabber);239240RSDK.ProcessAnimation(&self->bodyAnimator);241242if (self->bodyAnimator.frameID == self->bodyAnimator.frameCount - 1) {243RSDK.SetSpriteAnimation(Grabber->aniFrames, 0, &self->bodyAnimator, true, 0);244RSDK.SetSpriteAnimation(Grabber->aniFrames, 1, &self->clampAnimator, true, 0);245if (self->direction == FLIP_X)246self->position.x -= 0x10000;247else248self->position.x += 0x10000;249250self->state = Grabber_State_CheckForGrab;251self->velocity.x = -self->velocity.x;252self->direction ^= FLIP_X;253Grabber_State_CheckForGrab();254}255else {256Grabber_CheckPlayerCollisions();257Grabber_CheckOffScreen();258}259}260261void Grabber_State_TryToGrab(void)262{263RSDK_THIS(Grabber);264265if (--self->timer < 0)266self->state = Grabber_State_RiseUp;267268self->position.y += 0x20000;269270Grabber_CheckPlayerCollisions();271Grabber_CheckOffScreen();272}273274void Grabber_State_RiseUp(void)275{276RSDK_THIS(Grabber);277278if (++self->timer >= 32) {279self->timer = 0;280self->state = Grabber_State_CheckForGrab;281}282283self->position.y -= 0x20000;284Grabber_CheckPlayerCollisions();285Grabber_CheckOffScreen();286}287288void Grabber_State_GrabbedPlayer(void)289{290RSDK_THIS(Grabber);291292RSDK.ProcessAnimation(&self->bodyAnimator);293RSDK.ProcessAnimation(&self->clampAnimator);294295if (++self->timer < 32) {296self->position.y -= 0x20000;297298EntityPlayer *player = self->grabbedPlayer;299if (player) {300player->animator.speed = 0;301player->position.x = self->position.x;302player->position.y = self->position.y + 0x100000;303player->velocity.x = 0;304player->velocity.y = 0;305player->direction = self->direction ^ FLIP_X;306}307Grabber_CheckPlayerCollisions();308}309else if (self->bodyAnimator.frameID != self->bodyAnimator.frameCount - 1) {310Grabber_CheckPlayerCollisions();311}312else {313self->turnTimer = 1;314self->timer = 16;315RSDK.SetSpriteAnimation(Grabber->aniFrames, 2, &self->bodyAnimator, true, 0);316self->state = Grabber_State_Struggle;317Grabber_CheckPlayerCollisions();318}319320Grabber_CheckOffScreen();321}322323void Grabber_State_Struggle(void)324{325RSDK_THIS(Grabber);326327EntityPlayer *player = self->grabbedPlayer;328if (player) {329player->animator.speed = 0;330if (self->struggleFlags) {331player->velocity.x = 0;332player->velocity.y = 0;333if (self->struggleDelay) {334self->struggleDelay--;335336uint8 struggleFlags = 0;337if (player->left)338struggleFlags = 1;339340if (player->right)341struggleFlags |= 2;342343if (struggleFlags) {344if (struggleFlags != 3 && struggleFlags != self->struggleFlags) {345self->struggleFlags = struggleFlags;346if (++self->struggleTimer >= 4) {347player->state = Player_State_Air;348self->grabbedPlayer = 0;349self->grabDelay = 16;350self->state = Grabber_State_PlayerEscaped;351}352}353}354}355else {356self->struggleTimer = 0;357self->struggleFlags = 0;358}359}360else {361if (player->left) {362self->struggleFlags = 1;363self->struggleDelay = 64;364}365else if (player->right) {366self->struggleFlags = 2;367self->struggleDelay = 64;368}369}370371player->position.x = self->position.x;372player->position.y = self->position.y + 0x100000;373player->direction = self->direction ^ FLIP_X;374}375376Grabber_CheckPlayerCollisions();377Grabber_HandleExplode();378Grabber_CheckOffScreen();379}380381void Grabber_State_PlayerEscaped(void)382{383RSDK_THIS(Grabber);384385if (self->grabDelay)386self->grabDelay--;387388Grabber_CheckPlayerCollisions();389Grabber_HandleExplode();390Grabber_CheckOffScreen();391}392393#if GAME_INCLUDE_EDITOR394void Grabber_EditorDraw(void)395{396RSDK_THIS(Grabber);397398self->startPos = self->position;399400RSDK.DrawLine(self->position.x, self->startPos.y - 0x100000, self->position.x, self->position.y, 0x202020, 0, INK_NONE, false);401RSDK.DrawLine(self->position.x - 0x10000, self->startPos.y - 0x100000, self->position.x - 0x10000, self->position.y, 0xE0E0E0, 0, INK_NONE,402false);403404Vector2 drawPos;405int32 dir = self->direction;406drawPos.x = self->position.x;407drawPos.y = self->startPos.y;408self->direction = FLIP_NONE;409RSDK.DrawSprite(&self->wheelAnimator, &drawPos, false);410411self->direction = dir;412RSDK.DrawSprite(&self->bodyAnimator, NULL, false);413RSDK.DrawSprite(&self->clampAnimator, NULL, false);414}415416void Grabber_EditorLoad(void)417{418Grabber->aniFrames = RSDK.LoadSpriteAnimation("CPZ/Grabber.bin", SCOPE_STAGE);419420RSDK_ACTIVE_VAR(Grabber, direction);421RSDK_ENUM_VAR("Left", FLIP_NONE);422RSDK_ENUM_VAR("Right", FLIP_X);423}424#endif425426void Grabber_Serialize(void) { RSDK_EDITABLE_VAR(Grabber, VAR_UINT8, direction); }427428429