Path: blob/master/SonicMania/Objects/PGZ/JuggleSaw.c
338 views
// ---------------------------------------------------------------------1// RSDK Project: Sonic Mania2// Object Description: JuggleSaw Object3// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges4// Decompiled by: Rubberduckycooly & RMGRich5// ---------------------------------------------------------------------67#include "Game.h"89ObjectJuggleSaw *JuggleSaw;1011// 🦀 crab in da code1213void JuggleSaw_Update(void)14{15RSDK_THIS(JuggleSaw);1617StateMachine_Run(self->state);18}1920void JuggleSaw_LateUpdate(void) {}2122void JuggleSaw_StaticUpdate(void) {}2324void JuggleSaw_Draw(void)25{26RSDK_THIS(JuggleSaw);2728RSDK.DrawSprite(&self->animator, NULL, false);29}3031void JuggleSaw_Create(void *data)32{33RSDK_THIS(JuggleSaw);3435self->visible = true;36self->drawFX |= FX_FLIP;37self->drawGroup = Zone->objectDrawGroup[0];38self->active = ACTIVE_BOUNDS;39self->updateRange.x = 0xC00000;40self->updateRange.y = 0xC00000;4142if (!SceneInfo->inEditor) {43if (data) {44RSDK.SetSpriteAnimation(JuggleSaw->aniFrames, 6, &self->animator, true, 0);45self->state = JuggleSaw_StateSaw_Handle;46}47else {48self->startPos = self->position;49self->startDir = self->direction;5051switch (self->direction) {52case FLIP_NONE: RSDK.SetSpriteAnimation(JuggleSaw->aniFrames, self->hasSaw == JUGGLESAW_HAS_SAW, &self->animator, true, 0); break;5354case FLIP_X:55self->direction = FLIP_Y;56RSDK.SetSpriteAnimation(JuggleSaw->aniFrames, self->hasSaw == JUGGLESAW_HAS_SAW, &self->animator, true, 0);57break;5859case FLIP_Y:60self->direction = FLIP_NONE;61RSDK.SetSpriteAnimation(JuggleSaw->aniFrames, 4 - (self->hasSaw != JUGGLESAW_HAS_SAW), &self->animator, true, 0);62break;6364case FLIP_XY:65self->direction = FLIP_X;66RSDK.SetSpriteAnimation(JuggleSaw->aniFrames, 4 - (self->hasSaw != JUGGLESAW_HAS_SAW), &self->animator, true, 0);67break;6869default: break;70}7172if (!self->sawSpeed)73self->sawSpeed = 8;7475self->sawSpeed <<= 7;76self->state = JuggleSaw_StateCrab_Setup;77}78}79}8081void JuggleSaw_StageLoad(void)82{83if (RSDK.CheckSceneFolder("PSZ1"))84JuggleSaw->aniFrames = RSDK.LoadSpriteAnimation("PSZ1/JuggleSaw.bin", SCOPE_STAGE);85else if (RSDK.CheckSceneFolder("PSZ2"))86JuggleSaw->aniFrames = RSDK.LoadSpriteAnimation("PSZ2/JuggleSaw.bin", SCOPE_STAGE);8788JuggleSaw->hitboxBadnik.left = -12;89JuggleSaw->hitboxBadnik.top = -18;90JuggleSaw->hitboxBadnik.right = 12;91JuggleSaw->hitboxBadnik.bottom = 18;9293JuggleSaw->hitboxFriendRange.left = -512;94JuggleSaw->hitboxFriendRange.top = -512;95JuggleSaw->hitboxFriendRange.right = 512;96JuggleSaw->hitboxFriendRange.bottom = 512;9798JuggleSaw->hitboxSaw.left = -12;99JuggleSaw->hitboxSaw.top = -12;100JuggleSaw->hitboxSaw.right = 12;101JuggleSaw->hitboxSaw.bottom = 12;102103JuggleSaw->hitboxGrabV.left = -24;104JuggleSaw->hitboxGrabV.top = -38;105JuggleSaw->hitboxGrabV.right = -16;106JuggleSaw->hitboxGrabV.bottom = -30;107108JuggleSaw->hitboxGrabH.left = 38;109JuggleSaw->hitboxGrabH.top = -24;110JuggleSaw->hitboxGrabH.right = 30;111JuggleSaw->hitboxGrabH.bottom = -16;112113DEBUGMODE_ADD_OBJ(JuggleSaw);114115JuggleSaw->sfxExplode = RSDK.GetSfx("Stage/Explosion.wav"); // not actually used it seems116JuggleSaw->sfxJuggle = RSDK.GetSfx("PSZ/Juggle.wav");117JuggleSaw->sfxThrow = RSDK.GetSfx("PSZ/JuggleThrow.wav");118}119120void JuggleSaw_DebugSpawn(void)121{122RSDK_THIS(DebugMode);123124EntityJuggleSaw *badnik = CREATE_ENTITY(JuggleSaw, NULL, self->position.x, self->position.y);125badnik->sawDelay = 30;126}127128void JuggleSaw_DebugDraw(void)129{130RSDK.SetSpriteAnimation(JuggleSaw->aniFrames, 0, &DebugMode->animator, true, 0);131RSDK.DrawSprite(&DebugMode->animator, NULL, false);132}133134void JuggleSaw_CheckPlayerCollisions(void)135{136RSDK_THIS(JuggleSaw);137138foreach_active(Player, player)139{140if (Player_CheckBadnikTouch(player, self, &JuggleSaw->hitboxBadnik) && Player_CheckBadnikBreak(player, self, false)) {141if (self->hasSaw == JUGGLESAW_HAS_SAW) {142int32 debrisX = self->position.x;143int32 debrisY = self->position.y;144if (self->startDir >= FLIP_Y)145debrisX += 0x200000 * ((self->direction & FLIP_X) ? -1 : 1);146else147debrisY += 0x200000 * ((self->direction & FLIP_Y) ? 1 : -1);148EntityDebris *debris = CREATE_ENTITY(Debris, Debris_State_FallAndFlicker, debrisX, debrisY);149150RSDK.SetSpriteAnimation(JuggleSaw->aniFrames, 6, &debris->animator, true, 0);151152int32 minVelX = -4, maxVelX = 5, minVelY = -4, maxVelY = 5;153if (self->startDir >= FLIP_Y)154minVelY = (self->direction & FLIP_X) ? -1 : -4;155else156minVelY = (self->direction & FLIP_Y) ? -4 : -1;157158debris->velocity.x = RSDK.Rand(minVelX, maxVelX) << 16;159debris->velocity.y = RSDK.Rand(minVelY, maxVelY) << 16;160debris->gravityStrength = 0x3800;161debris->drawGroup = self->drawGroup;162debris->updateRange.x = 0x400000;163debris->updateRange.y = 0x400000;164}165166destroyEntity(self);167}168}169}170171void JuggleSaw_CheckOffScreen(void)172{173RSDK_THIS(JuggleSaw);174175if (self->hasSaw != JUGGLESAW_AWAITING_SAW && !RSDK.CheckOnScreen(self, NULL) && !RSDK.CheckPosOnScreen(&self->startPos, &self->updateRange)) {176self->sawSpeed = self->sawSpeed >> 7;177self->position = self->startPos;178self->direction = self->startDir;179JuggleSaw_Create(NULL);180}181}182183void JuggleSaw_StateCrab_Setup(void)184{185RSDK_THIS(JuggleSaw);186187self->active = ACTIVE_NORMAL;188self->friends[0] = NULL;189self->angle = 0;190self->sawTimer = 0;191192self->state = JuggleSaw_StateCrab_Handle;193JuggleSaw_StateCrab_Handle();194}195196void JuggleSaw_StateCrab_Handle(void)197{198RSDK_THIS(JuggleSaw);199200// this was the worst func to decompile so far. -rmg201RSDK.ProcessAnimation(&self->animator);202203switch (self->startDir) {204case FLIP_NONE:205case FLIP_X: self->position.x = (RSDK.Cos256(self->angle) << 10) + self->startPos.x; break;206207case FLIP_Y:208case FLIP_XY: self->position.y = (RSDK.Cos256(self->angle) << 10) + self->startPos.y; break;209210default: break;211}212213if (self->hasSaw != JUGGLESAW_HAS_SAW) {214self->angle += 2;215}216else {217self->angle += 4;218219if (self->animator.frameID == self->animator.frameCount - 1) {220RSDK.PlaySfx(JuggleSaw->sfxJuggle, false, 0xFF);221if (self->startDir >= FLIP_Y)222self->direction ^= FLIP_Y;223else224self->direction ^= FLIP_X;225}226else {227if (self->sawTimer == self->sawDelay - 1)228--self->sawTimer;229}230231if (++self->sawTimer >= self->sawDelay) {232bool32 throwSaw = true;233234if (!self->friends[0] || self->friends[0]->classID != JuggleSaw->classID) {235self->friendCount = 0;236foreach_active(JuggleSaw, newFriend)237{238if (newFriend != self && newFriend->hasSaw == JUGGLESAW_NO_SAW && newFriend->setID == self->setID239&& self->friendCount < JUGGLESAW_MAX_FRIENDS) {240if (RSDK.CheckObjectCollisionTouchBox(newFriend, &JuggleSaw->hitboxBadnik, self, &JuggleSaw->hitboxFriendRange))241self->friends[self->friendCount++] = newFriend;242}243}244245if (self->friendCount) {246self->friends[0] = self->friends[RSDK.Rand(0, self->friendCount)];247248if (self->startDir >= FLIP_Y) {249if (self->position.y < self->friends[0]->position.y) {250if ((self->direction & FLIP_Y))251--self->sawTimer;252}253else {254if (!(self->direction & FLIP_Y))255--self->sawTimer;256}257}258else {259if (self->position.x < self->friends[0]->position.x) {260if ((self->direction & FLIP_X))261--self->sawTimer;262}263else {264if (!(self->direction & FLIP_X))265--self->sawTimer;266}267}268269throwSaw = false;270if (self->sawTimer >= self->sawDelay)271throwSaw = true;272}273else {274throwSaw = false;275}276}277278if (throwSaw) {279RSDK.SetSpriteAnimation(JuggleSaw->aniFrames, self->startDir >= FLIP_Y ? 5 : 2, &self->animator, true, 0);280self->direction ^= (self->startDir >= FLIP_Y) ? FLIP_Y : FLIP_X;281self->state = JuggleSaw_StateCrab_ThrowSaw;282}283}284}285286JuggleSaw_CheckPlayerCollisions();287JuggleSaw_CheckOffScreen();288}289290void JuggleSaw_StateCrab_ThrowSaw(void)291{292RSDK_THIS(JuggleSaw);293294RSDK.ProcessAnimation(&self->animator);295296if (self->animator.frameID == 3) {297EntityJuggleSaw *reciever = self->friends[0];298299if (reciever->classID == JuggleSaw->classID) {300RSDK.PlaySfx(JuggleSaw->sfxThrow, false, 0xFF);301reciever->hasSaw = JUGGLESAW_AWAITING_SAW;302reciever->active = ACTIVE_NORMAL;303304EntityJuggleSaw *saw = CREATE_ENTITY(JuggleSaw, INT_TO_VOID(true), self->position.x, self->position.y);305int32 sx = 0x2C0000, sy = -0xE0000;306if (self->startDir >= FLIP_Y) {307sx = 0xE0000;308sy = 0x2C0000;309}310311saw->position.x += sx * ((self->direction & FLIP_X) ? -1 : 1);312saw->position.y += sy * ((self->direction & FLIP_Y) ? -1 : 1);313314int32 targetX = 0;315int32 targetY = 0;316int32 sawDir = 0;317if (reciever->startDir >= FLIP_Y) {318targetX = reciever->position.x + 0x220000 * ((reciever->direction & FLIP_X) ? -1 : 1);319targetY = reciever->position.y + 0x140000 * (reciever->startPos.y >= self->startPos.y ? 1 : -1);320sawDir = (reciever->direction & FLIP_X) | (reciever->startPos.y >= self->startPos.y ? FLIP_Y : 0);321}322else {323targetX = reciever->position.x + 0x140000 * (reciever->startPos.x >= self->startPos.x ? 1 : -1);324targetY = reciever->position.y + 0x220000 * ((reciever->direction & FLIP_Y) ? 1 : -1);325sawDir = (reciever->direction & FLIP_Y) | (reciever->startPos.x >= self->startPos.x ? FLIP_X : FLIP_NONE);326}327328saw->direction = sawDir;329int32 targetAngle = RSDK.ATan2(targetX - saw->position.x, targetY - saw->position.y);330saw->velocity.x = self->sawSpeed * RSDK.Cos256(targetAngle);331saw->velocity.y = self->sawSpeed * RSDK.Sin256(targetAngle);332saw->friends[0] = reciever;333saw->hasSaw = JUGGLESAW_HAS_SAW;334saw->active = ACTIVE_NORMAL;335self->sawTimer = 0;336self->hasSaw = JUGGLESAW_NO_SAW;337}338else {339RSDK.SetSpriteAnimation(JuggleSaw->aniFrames, self->startDir >= FLIP_Y ? 4 : 1, &self->animator, true, 0);340self->state = JuggleSaw_StateCrab_Handle;341}342343self->friends[0] = NULL;344}345346if (self->animator.frameID == self->animator.frameCount - 1) {347RSDK.SetSpriteAnimation(JuggleSaw->aniFrames, self->startDir >= FLIP_Y ? 3 : 0, &self->animator, true, 0);348self->state = JuggleSaw_StateCrab_Handle;349}350351JuggleSaw_CheckPlayerCollisions();352JuggleSaw_CheckOffScreen();353}354355void JuggleSaw_StateSaw_Handle(void)356{357RSDK_THIS(JuggleSaw);358359self->position.x += self->velocity.x;360self->position.y += self->velocity.y;361362EntityJuggleSaw *reciever = self->friends[0];363int32 oldDir = reciever->direction;364reciever->direction = self->direction;365366Hitbox *hitboxGrab = &JuggleSaw->hitboxGrabV;367if (reciever->startDir >= FLIP_Y)368hitboxGrab = &JuggleSaw->hitboxGrabH;369370// I have decided to imortalize this bit of code that the below code replaces because this cost RMG and I at least 4 hours of our lives371// collectively.372// reciever->direction = oldDir;373// if (RSDK.CheckObjectCollisionTouchBox(reciever, hitboxGrab, self, &JuggleSaw->hitboxSaw)) {374375bool32 collided = RSDK.CheckObjectCollisionTouchBox(reciever, hitboxGrab, self, &JuggleSaw->hitboxSaw);376reciever->direction = oldDir;377378if (collided) {379int32 newDir = 0;380if (reciever->startDir >= FLIP_Y) {381if (self->velocity.y > 0)382newDir = oldDir | FLIP_Y;383else if (self->velocity.y < 0)384newDir = oldDir & ~FLIP_Y;385}386else {387if (self->velocity.x > 0)388newDir = oldDir | FLIP_X;389else if (self->velocity.x < 0)390newDir = oldDir & ~FLIP_X;391}392393reciever->direction = newDir;394395reciever->hasSaw = JUGGLESAW_HAS_SAW;396RSDK.SetSpriteAnimation(JuggleSaw->aniFrames, reciever->startDir >= FLIP_Y ? 4 : 1, &reciever->animator, true, 0);397destroyEntity(self);398}399else if (RSDK.CheckOnScreen(self, &self->updateRange)) {400RSDK.ProcessAnimation(&self->animator);401402foreach_active(Player, player)403{404if (Player_CheckCollisionTouch(player, self, &JuggleSaw->hitboxSaw)) {405#if MANIA_USE_PLUS406if (Player_CheckMightyShellHit(player, self, -0x400, -0x600)) {407self->interaction = false;408self->state = JuggleSaw_StateSaw_Debris;409}410else411#endif412Player_Hurt(player, self);413}414}415}416else if (!self->friends[0] || self->friends[0]->classID != JuggleSaw->classID)417destroyEntity(self);418}419420void JuggleSaw_StateSaw_Debris(void)421{422RSDK_THIS(JuggleSaw);423424self->position.x += self->velocity.x;425self->position.y += self->velocity.y;426self->velocity.y += 0x3800;427428self->visible ^= true;429430if (!RSDK.CheckOnScreen(self, &self->updateRange))431destroyEntity(self);432}433434#if GAME_INCLUDE_EDITOR435void JuggleSaw_EditorDraw(void)436{437RSDK_THIS(JuggleSaw);438439int32 dir = self->direction;440441switch (self->direction) {442case FLIP_NONE: RSDK.SetSpriteAnimation(JuggleSaw->aniFrames, self->hasSaw == JUGGLESAW_HAS_SAW, &self->animator, true, 0); break;443444case FLIP_X:445self->direction = FLIP_Y;446RSDK.SetSpriteAnimation(JuggleSaw->aniFrames, self->hasSaw == JUGGLESAW_HAS_SAW, &self->animator, true, 0);447break;448449case FLIP_Y:450self->direction = FLIP_NONE;451RSDK.SetSpriteAnimation(JuggleSaw->aniFrames, 4 - (self->hasSaw != JUGGLESAW_HAS_SAW), &self->animator, true, 0);452break;453454case FLIP_XY:455self->direction = FLIP_X;456RSDK.SetSpriteAnimation(JuggleSaw->aniFrames, 4 - (self->hasSaw != JUGGLESAW_HAS_SAW), &self->animator, true, 0);457break;458459default: break;460}461462JuggleSaw_Draw();463464if (self->hasSaw == JUGGLESAW_HAS_SAW && showGizmos()) {465RSDK_DRAWING_OVERLAY(true);466467DrawHelpers_DrawHitboxOutline(self->position.x, self->position.y, &JuggleSaw->hitboxFriendRange, self->direction, 0xFF0000);468469RSDK_DRAWING_OVERLAY(false);470}471472self->direction = dir;473}474475void JuggleSaw_EditorLoad(void)476{477if (RSDK.CheckSceneFolder("PSZ1"))478JuggleSaw->aniFrames = RSDK.LoadSpriteAnimation("PSZ1/JuggleSaw.bin", SCOPE_STAGE);479else if (RSDK.CheckSceneFolder("PSZ2"))480JuggleSaw->aniFrames = RSDK.LoadSpriteAnimation("PSZ2/JuggleSaw.bin", SCOPE_STAGE);481482JuggleSaw->hitboxFriendRange.left = -512;483JuggleSaw->hitboxFriendRange.top = -512;484JuggleSaw->hitboxFriendRange.right = 512;485JuggleSaw->hitboxFriendRange.bottom = 512;486487RSDK_ACTIVE_VAR(JuggleSaw, direction);488RSDK_ENUM_VAR("No Flip (Vertical)", FLIP_NONE);489RSDK_ENUM_VAR("Flipped (Vertical)", FLIP_X);490RSDK_ENUM_VAR("No Flip (Horizontal)", FLIP_Y);491RSDK_ENUM_VAR("Flipped (Horizontal)", FLIP_XY);492}493#endif494495void JuggleSaw_Serialize(void)496{497RSDK_EDITABLE_VAR(JuggleSaw, VAR_UINT8, direction);498RSDK_EDITABLE_VAR(JuggleSaw, VAR_UINT16, sawDelay);499RSDK_EDITABLE_VAR(JuggleSaw, VAR_ENUM, sawSpeed);500RSDK_EDITABLE_VAR(JuggleSaw, VAR_BOOL, hasSaw); // liars.501RSDK_EDITABLE_VAR(JuggleSaw, VAR_UINT16, setID);502}503504505