Path: blob/master/SonicMania/Objects/MSZ/Rattlekiller.c
338 views
// ---------------------------------------------------------------------1// RSDK Project: Sonic Mania2// Object Description: Rattlekiller Object3// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges4// Decompiled by: Rubberduckycooly & RMGRich5// ---------------------------------------------------------------------67#include "Game.h"89ObjectRattlekiller *Rattlekiller;1011void Rattlekiller_Update(void)12{13RSDK_THIS(Rattlekiller);1415if (self->timer) {16self->timer--;1718if (self->bodyStates[0] == RATTLEKILLER_PLAYERDETECTED) {19foreach_active(Player, player)20{21if (abs(self->bodyPositions[0].x - player->position.x) < 0x600000) {22if (abs(self->bodyPositions[0].y - player->position.y) < 0x600000) {23self->targetPos = player->position;24foreach_break;25}26}27}28}29}30else {31foreach_active(Player, player)32{33if (self->bodyPositions[0].x <= self->topBounds.x) {34if (player->position.x >= self->topBounds.x || player->position.x - self->topBounds.x <= -0x600000)35continue;36}37else if (player->position.x <= self->topBounds.x || player->position.x - self->topBounds.x >= 0x600000) {38continue;39}4041if (abs(self->bodyPositions[0].y - player->position.y) < 0x600000) {42int32 delay = 30;43for (int32 i = 0; i < RATTLEKILLER_SEGMENT_COUNT; ++i) {44self->bodyDelays[i] = 30;45self->bodyOriginPos[i] = self->bodyPositions[i];46self->bodyStates[i] = RATTLEKILLER_PLAYERDETECTED;4748delay += 2;49}5051self->targetPos.x = player->position.x;52self->targetPos.y = player->position.y;53self->timer = 480;54foreach_break;55}56}57}5859foreach_active(Player, player)60{61for (int32 i = 0; i < RATTLEKILLER_SEGMENT_COUNT; ++i) {62switch (self->bodyStates[i]) {63case RATTLEKILLER_IDLE:64if (--self->bodyDelays[i] <= 0)65self->bodyStates[i] = RATTLEKILLER_TWIST_DOWN + (self->bodyVelocities[i].y < 0);66break;6768case RATTLEKILLER_TWIST_HORIZONTAL: // circle pole horizontally (no vertical movement)69self->bodyAngles[i] = (self->bodyAngles[i] + 2) & 0xFF;70self->bodyPositions[i].y += self->bodyVelocities[i].y;71self->bodyPositions[i].x = self->topBounds.x - 0x1800 * RSDK.Sin256(self->bodyAngles[i]);72self->bodyDepth[i] = RSDK.Cos256(self->bodyAngles[i]);73if (self->timer < 320) {74if (--self->bodyDelays[i] <= 0)75self->bodyStates[i] = RATTLEKILLER_TWIST_DOWN + (self->bodyVelocities[i].y < 0);76}77break;7879case RATTLEKILLER_TWIST_DOWN: // circle pole (moving downwards)80self->bodyAngles[i] = (self->bodyAngles[i] + 2) & 0xFF;81self->bodyVelocities[i].y += 0x400;82if (self->bodyVelocities[i].y > 0x8000)83self->bodyVelocities[i].y = 0x8000;8485self->bodyPositions[i].y += self->bodyVelocities[i].y;86self->bodyPositions[i].x = self->topBounds.x - 0x1800 * RSDK.Sin256(self->bodyAngles[i]);87self->bodyDepth[i] = RSDK.Cos256(self->bodyAngles[i]);8889if (self->bodyPositions[i].y >= self->bottomBounds.y)90self->bodyStates[i] = RATTLEKILLER_TWIST_UP;91break;9293case RATTLEKILLER_TWIST_UP: // circle pole (moving upwards)94self->bodyAngles[i] = (self->bodyAngles[i] + 2) & 0xFF;95self->bodyVelocities[i].y -= 0x400;96if (self->bodyVelocities[i].y < -0x8000)97self->bodyVelocities[i].y = -0x8000;9899self->bodyPositions[i].y += self->bodyVelocities[i].y;100self->bodyPositions[i].x = self->topBounds.x - 0x1800 * RSDK.Sin256(self->bodyAngles[i]);101self->bodyDepth[i] = RSDK.Cos256(self->bodyAngles[i]);102if (self->bodyPositions[i].y <= self->topBounds.y)103self->bodyStates[i] = RATTLEKILLER_TWIST_DOWN;104break;105106case RATTLEKILLER_PLAYERDETECTED:107if (--self->bodyDelays[i] > 0) {108if (self->bodyDelays[i] < 15 && i > 4) {109self->bodyAngles[i] = (self->bodyAngles[i] + 4) & 0xFF;110self->bodyPositions[i].x = self->topBounds.x - 0x1800 * RSDK.Sin256(self->bodyAngles[i]);111self->bodyDepth[i] = RSDK.Cos256(self->bodyAngles[i]);112}113}114else if (i) {115self->bodyStates[i] = RATTLEKILLER_STRETCHBODY;116}117else {118self->bodyStates[0] = RATTLEKILLER_EXTEND;119RSDK.SetSpriteAnimation(Rattlekiller->aniFrames, (self->bodyPositions[0].x > self->topBounds.x) + 2, &self->headAnimator,120true, 0);121RSDK.PlaySfx(Rattlekiller->sfxRocketJet, false, 255);122}123break;124125case RATTLEKILLER_STRETCHBODY:126if (self->bodyStates[0] < RATTLEKILLER_EXTEND) {127self->bodyPositions[i].y += (self->bodyPositions[0].y - self->bodyPositions[i].y) >> 3;128if (self->bodyStates[i - 1] == RATTLEKILLER_TWIST_HORIZONTAL) {129if (abs(self->bodyPositions[0].y - self->bodyPositions[i].y) < 0x20000) {130self->bodyPositions[i].y = self->bodyPositions[0].y;131self->bodyVelocities[i].x = 0;132self->bodyVelocities[i].y = 0;133self->bodyStates[i] = RATTLEKILLER_TWIST_HORIZONTAL;134self->bodyDelays[i] = 8 * i + self->bodyDelays[0];135self->bodyAngles[i] = self->bodyAngles[i - 1] - 16;136}137}138}139else if (i < RATTLEKILLER_SEGMENT_COUNT - 1) {140self->bodyPositions[i].x = (self->bodyPositions[i - 1].x >> 1) + (self->bodyPositions[i + 1].x >> 1);141self->bodyPositions[i].y = (self->bodyPositions[i - 1].y >> 1) + (self->bodyPositions[i + 1].y >> 1);142}143break;144145case RATTLEKILLER_EXTEND: {146int32 rx = (self->targetPos.x - self->bodyPositions[i].x) >> 16;147int32 ry = (self->targetPos.y - self->bodyPositions[i].y) >> 16;148if (rx * rx + ry * ry >= 0x40) {149int32 angle = RSDK.ATan2(rx, ry);150self->bodyVelocities[i].x = RSDK.Cos256(angle) << 10;151self->bodyPositions[i].x += self->bodyVelocities[i].x;152self->bodyPositions[i].y += RSDK.Sin256(angle) << 10;153self->bodyVelocities[i].y = RSDK.Sin256(angle) << 10;154}155else {156self->bodyStates[i] = RATTLEKILLER_RETRACT;157}158RSDK.ProcessAnimation(&self->headAnimator);159break;160}161162case RATTLEKILLER_RETRACT: {163int32 rx = (self->bodyOriginPos[i].x - self->bodyPositions[i].x) >> 16;164int32 ry = (self->bodyOriginPos[RATTLEKILLER_SEGMENT_COUNT - 1].y - self->bodyPositions[i].y) >> 16;165if (rx * rx + ry * ry >= 0x40) {166int32 angle = RSDK.ATan2(rx, ry);167self->bodyVelocities[i].x = RSDK.Cos256(angle) << 10;168self->bodyPositions[i].x += self->bodyVelocities[i].x;169self->bodyPositions[i].y += RSDK.Sin256(angle) << 10;170self->bodyVelocities[i].y = RSDK.Sin256(angle) << 10;171RSDK.ProcessAnimation(&self->headAnimator);172}173else {174self->bodyStates[i] = RATTLEKILLER_TWIST_HORIZONTAL;175if (i > 0)176self->bodyAngles[i] = self->bodyAngles[i - 1] - 16;177self->bodyPositions[i].x = self->bodyOriginPos[i].x;178self->bodyPositions[i].y = self->bodyOriginPos[RATTLEKILLER_SEGMENT_COUNT - 1].y;179self->bodyDelays[i] = 8 * i;180self->bodyVelocities[i].x = 0;181self->bodyVelocities[i].y = 0;182RSDK.SetSpriteAnimation(Rattlekiller->aniFrames, 0, &self->headAnimator, true, 0);183}184break;185}186187default: break;188}189}190191self->position.x = self->bodyPositions[0].x;192self->position.y = self->bodyPositions[0].y;193if (Player_CheckBadnikTouch(player, self, &Rattlekiller->hitboxSegment) && Player_CheckBadnikBreak(player, self, false)) {194for (int32 i = 1; i < RATTLEKILLER_SEGMENT_COUNT; ++i) {195EntityDebris *debris = CREATE_ENTITY(Debris, Debris_State_FallAndFlicker, self->bodyPositions[i].x, self->bodyPositions[i].y);196197RSDK.SetSpriteAnimation(Rattlekiller->aniFrames, self->bodyAnimators[i]->animationID, &debris->animator, true,198self->bodyAnimators[i]->frameID);199debris->velocity.x = RSDK.Rand(-0x20000, 0x20000);200debris->velocity.y = RSDK.Rand(-0x20000, -0x10000);201debris->gravityStrength = 0x4800;202debris->drawGroup = Zone->objectDrawGroup[1];203debris->updateRange.x = 0x400000;204debris->updateRange.y = 0x400000;205}206207destroyEntity(self);208self->active = ACTIVE_DISABLED;209foreach_break;210}211else {212for (int32 i = 1; i < RATTLEKILLER_SEGMENT_COUNT; ++i) {213if (self->bodyDepth[i] > 0) {214self->position.x = self->bodyPositions[i].x;215self->position.y = self->bodyPositions[i].y;216if (Player_CheckCollisionTouch(player, self, &Rattlekiller->hitboxSegment)) {217#if MANIA_USE_PLUS218if (!Player_CheckMightyUnspin(player, 0x200, 2, &player->uncurlTimer))219#endif220Player_Hurt(player, self);221}222}223}224}225}226227self->position.x = self->bodyPositions[0].x;228self->position.y = self->bodyPositions[0].y;229230Rattlekiller_HandleSorting();231}232233void Rattlekiller_LateUpdate(void) {}234235void Rattlekiller_StaticUpdate(void)236{237foreach_active(Rattlekiller, rattlekiller) { RSDK.AddDrawListRef(Zone->objectDrawGroup[0] - 1, RSDK.GetEntitySlot(rattlekiller)); }238}239240void Rattlekiller_Draw(void)241{242RSDK_THIS(Rattlekiller);243244if (SceneInfo->currentDrawGroup == self->drawGroup) {245for (int32 i = 0; i < RATTLEKILLER_SEGMENT_COUNT; ++i) {246int32 id = self->bodyIDs[i];247248if (self->bodyDepth[id] > 0) {249Animator *animator = self->bodyAnimators[id];250if (animator->animationID < 2)251animator->frameID = self->bodyAngles[id] >> 4;252253RSDK.DrawSprite(animator, &self->bodyPositions[id], false);254}255}256}257else {258for (int32 i = 0; i < RATTLEKILLER_SEGMENT_COUNT; ++i) {259int32 id = self->bodyIDs[i];260261if (self->bodyDepth[id] <= 0) {262Animator *animator = self->bodyAnimators[id];263264if (animator->animationID < 2)265animator->frameID = self->bodyAngles[id] >> 4;266RSDK.DrawSprite(animator, &self->bodyPositions[id], false);267}268}269}270}271272void Rattlekiller_Create(void *data)273{274RSDK_THIS(Rattlekiller);275276if (!SceneInfo->inEditor) {277self->visible = true;278self->drawGroup = Zone->objectDrawGroup[0];279self->topBounds = self->position;280self->bottomBounds = self->position;281self->active = ACTIVE_BOUNDS;282self->updateRange.x = 0x800000;283self->updateRange.y = 0x800000;284285if (data)286self->length = VOID_TO_INT(data);287else if (!self->length)288self->length = 128;289290self->topBounds.y -= self->length << 15;291self->bottomBounds.y += self->length << 15;292293int32 delay = 0;294for (int32 i = 0; i < RATTLEKILLER_SEGMENT_COUNT; ++i) {295self->bodyIDs[i] = i;296self->bodyAnimators[i] = &self->bodyAnimator;297self->bodyDelays[i] = delay;298self->bodyPositions[i] = self->topBounds;299300delay += 8;301}302self->bodyAnimators[0] = &self->headAnimator;303304RSDK.SetSpriteAnimation(Rattlekiller->aniFrames, 0, &self->headAnimator, true, 0);305RSDK.SetSpriteAnimation(Rattlekiller->aniFrames, 1, &self->bodyAnimator, true, 0);306RSDK.SetSpriteAnimation(Rattlekiller->aniFrames, 4, &self->tailAnimator, true, 0);307}308}309310void Rattlekiller_StageLoad(void)311{312Rattlekiller->aniFrames = RSDK.LoadSpriteAnimation("MSZ/Rattlekiller.bin", SCOPE_STAGE);313314Rattlekiller->hitboxSegment.left = -8;315Rattlekiller->hitboxSegment.top = -8;316Rattlekiller->hitboxSegment.right = 8;317Rattlekiller->hitboxSegment.bottom = 8;318319Rattlekiller->sfxRocketJet = RSDK.GetSfx("Stage/RocketJet.wav");320// Idk where it would've been used but "MSZ/RKillerRattle.wav" was prolly intended for this object321322DEBUGMODE_ADD_OBJ(Rattlekiller);323}324325void Rattlekiller_DebugSpawn(void)326{327RSDK_THIS(DebugMode);328329EntityRattlekiller *rattlekiller = CREATE_ENTITY(Rattlekiller, INT_TO_VOID(0x80), self->position.x, self->position.y);330rattlekiller->direction = FLIP_NONE;331}332333void Rattlekiller_DebugDraw(void)334{335RSDK.SetSpriteAnimation(Rattlekiller->aniFrames, 0, &DebugMode->animator, true, 0);336RSDK.DrawSprite(&DebugMode->animator, NULL, false);337}338339void Rattlekiller_HandleSorting(void)340{341RSDK_THIS(Rattlekiller);342343for (int32 i = 0; i < RATTLEKILLER_SEGMENT_COUNT; ++i) {344for (int32 ii = RATTLEKILLER_SEGMENT_COUNT - 1; ii > i; --ii) {345int32 id1 = self->bodyIDs[ii - 1];346int32 id2 = self->bodyIDs[ii];347if (self->bodyDepth[id1] > self->bodyDepth[id2]) {348self->bodyIDs[ii - 1] = id2;349self->bodyIDs[ii] = id1;350}351}352}353}354355#if GAME_INCLUDE_EDITOR356void Rattlekiller_EditorDraw(void)357{358RSDK_THIS(Rattlekiller);359360RSDK.SetSpriteAnimation(Rattlekiller->aniFrames, 0, &self->headAnimator, false, 0);361RSDK.SetSpriteAnimation(Rattlekiller->aniFrames, 1, &self->bodyAnimator, false, 0);362RSDK.SetSpriteAnimation(Rattlekiller->aniFrames, 4, &self->tailAnimator, false, 0);363364self->topBounds = self->position;365self->bottomBounds = self->position;366367int32 length = self->length;368if (!length)369length = 128;370371self->topBounds.y -= length << 15;372self->bottomBounds.y += length << 15;373374int32 delay = 0;375for (int32 i = 0; i < RATTLEKILLER_SEGMENT_COUNT; ++i) {376self->bodyIDs[i] = i;377self->bodyAnimators[i] = &self->bodyAnimator;378self->bodyDelays[i] = delay;379self->bodyPositions[i] = self->position;380381delay += 8;382}383384Rattlekiller_HandleSorting();385386int32 drawGroup = self->drawGroup;387388// Draw Lower Depth389self->drawGroup = -1;390Rattlekiller_Draw();391392// Draw Higher Depth393self->drawGroup = SceneInfo->currentDrawGroup;394Rattlekiller_Draw();395396self->drawGroup = drawGroup;397398if (showGizmos()) {399RSDK_DRAWING_OVERLAY(true);400401DrawHelpers_DrawArrow(self->position.x, self->position.y, self->topBounds.x, self->topBounds.y, 0xFFFF00, INK_NONE, 0xFF);402DrawHelpers_DrawArrow(self->position.x, self->position.y, self->bottomBounds.x, self->bottomBounds.y, 0xFFFF00, INK_NONE, 0xFF);403404RSDK_DRAWING_OVERLAY(false);405}406}407408void Rattlekiller_EditorLoad(void)409{410Rattlekiller->aniFrames = RSDK.LoadSpriteAnimation("MSZ/Rattlekiller.bin", SCOPE_STAGE);411412RSDK_ACTIVE_VAR(Rattlekiller, direction);413RSDK_ENUM_VAR("Left", FLIP_NONE);414RSDK_ENUM_VAR("Right", FLIP_X);415}416#endif417418void Rattlekiller_Serialize(void)419{420RSDK_EDITABLE_VAR(Rattlekiller, VAR_UINT8, direction);421RSDK_EDITABLE_VAR(Rattlekiller, VAR_ENUM, length);422}423424425