Path: blob/master/SonicMania/Objects/MSZ/DBTower.c
338 views
// ---------------------------------------------------------------------1// RSDK Project: Sonic Mania2// Object Description: DBTower Object3// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges4// Decompiled by: Rubberduckycooly & RMGRich5// ---------------------------------------------------------------------67#include "Game.h"89ObjectDBTower *DBTower;1011void DBTower_Update(void)12{13RSDK_THIS(DBTower);1415StateMachine_Run(self->state);16}1718void DBTower_LateUpdate(void) {}1920void DBTower_StaticUpdate(void) {}2122void DBTower_Draw(void)23{24RSDK_THIS(DBTower);2526if (self->connectedSegmentCount <= 0) {27self->bodyAnimator.frameID = self->rotation >> 5;28RSDK.DrawSprite(self->segmentAnimators[0], &self->bodyPositions[0], false);29}30else {31self->direction ^= FLIP_X;32for (int32 i = self->connectedSegmentCount; i > 0; --i) {33self->rotation = (2 * self->bodyAngles[i] - 15) & 0x1E;34self->bodyAnimator.frameID = self->bodyAngles[i] >> 4;35RSDK.DrawSprite(self->segmentAnimators[i], &self->bodyPositions[i], false);36}3738self->direction ^= FLIP_X;39self->rotation = 0;4041if (self->invincibilityTimer & 1)42RSDK.SetPaletteEntry(0, 160, 0xE0E0E0);4344RSDK.DrawSprite(self->segmentAnimators[0], &self->bodyPositions[0], false);45RSDK.SetPaletteEntry(0, 160, 0x200000);46}47}4849void DBTower_Create(void *data)50{51RSDK_THIS(DBTower);5253if (!SceneInfo->inEditor) {54if (globals->gameMode < MODE_TIMEATTACK) {55self->drawFX = FX_ROTATE | FX_FLIP;56self->updateRange.x = 0x400000;57self->updateRange.y = 0x400000;58self->visible = true;5960if (data) {61self->active = ACTIVE_NORMAL;62self->drawGroup = Zone->objectDrawGroup[0];63RSDK.SetSpriteAnimation(DBTower->aniFrames, 2, &self->bodyAnimator, true, 0);64self->segmentAnimators[0] = &self->bodyAnimator;65self->bodyPositions[0].x = self->position.x;66self->bodyPositions[0].y = self->position.y;67self->state = (Type_StateMachine)data;68}69else {70self->active = ACTIVE_BOUNDS;71self->drawGroup = Zone->objectDrawGroup[0] + 1;72self->timer = 0;73self->direction = FLIP_X;7475for (int32 i = 0; i < DBTOWER_SEGMENT_COUNT; ++i) {76self->segmentAnimators[i] = &self->bodyAnimator;77self->segmentUnused3[i] = 0;78self->bodyAngles[i] = 0xC0;79}80self->segmentAnimators[0] = &self->headAnimator;81self->bodyPositions[0].x = self->position.x + ((ScreenInfo->center.x - 64) << 16);82self->bodyPositions[0].y = self->position.y + 0xA20000;8384self->originPos = self->position;85self->health = 6;86self->wobbleAngleVel = 640;87self->xOffsetAngle = 64;88self->connectedSegmentCount = 0;8990RSDK.SetSpriteAnimation(DBTower->aniFrames, 0, &self->headAnimator, true, 0);91RSDK.SetSpriteAnimation(DBTower->aniFrames, 2, &self->bodyAnimator, true, 0);9293self->state = DBTower_State_SetupArena;94}95}96else {97destroyEntity(self);98}99}100}101102void DBTower_StageLoad(void)103{104DBTower->aniFrames = RSDK.LoadSpriteAnimation("MSZ/Sandworm.bin", SCOPE_STAGE);105106DBTower->hitboxSegment.left = -27;107DBTower->hitboxSegment.top = -27;108DBTower->hitboxSegment.right = 27;109DBTower->hitboxSegment.bottom = 27;110111DBTower->defeated = false;112DBTower->active = ACTIVE_ALWAYS;113114DBTower->sfxRocketJet = RSDK.GetSfx("Stage/RocketJet.wav");115DBTower->sfxHit = RSDK.GetSfx("Stage/BossHit.wav");116DBTower->sfxExplosion2 = RSDK.GetSfx("Stage/Explosion2.wav");117DBTower->sfxExplosion3 = RSDK.GetSfx("Stage/Explosion3.wav");118DBTower->sfxBumper3 = RSDK.GetSfx("Stage/Bumper3.wav");119DBTower->sfxAssemble = RSDK.GetSfx("Stage/Assemble.wav");120DBTower->sfxRocketJet2 = RSDK.GetSfx("Stage/RocketJet.wav");121DBTower->sfxRockemSockem = RSDK.GetSfx("Stage/RockemSockem.wav");122}123124void DBTower_CheckPlayerCollisions_Head(void)125{126RSDK_THIS(DBTower);127128if (self->invincibilityTimer > 0) {129self->invincibilityTimer--;130}131else {132foreach_active(Player, player)133{134int32 playerID = RSDK.GetEntitySlot(player);135136if (self->playerTimers[playerID]) {137--self->playerTimers[playerID];138}139else {140self->position.x = self->bodyPositions[0].x;141self->position.y = self->bodyPositions[0].y;142143if (Player_CheckBadnikTouch(player, self, &DBTower->hitboxSegment) && Player_CheckBossHit(player, self)) {144self->wobbleAngleVel = 2048;145146if (--self->health <= 0) {147SceneInfo->timeEnabled = false;148Player_GiveScore(RSDK_GET_ENTITY(SLOT_PLAYER1, Player), 1000);149RSDK.PlaySfx(DBTower->sfxExplosion2, false, 255);150151self->timer = 120;152self->state = DBTower_State_Destroyed;153}154else {155self->invincibilityTimer = 48;156RSDK.PlaySfx(DBTower->sfxHit, false, 255);157}158159foreach_break;160}161else {162for (int32 i = 1; i <= self->connectedSegmentCount; ++i) {163self->position.x = self->bodyPositions[i].x;164self->position.y = self->bodyPositions[i].y;165166uint8 angle = RSDK.ATan2(player->position.x - self->position.x, player->position.y - self->position.y) - self->bodyAngles[i];167if (Player_CheckBadnikTouch(player, self, &DBTower->hitboxSegment)) {168if (angle >= 0x80) {169#if MANIA_USE_PLUS170if (!Player_CheckMightyUnspin(player, 0x300, true, &player->uncurlTimer))171#endif172Player_Hurt(player, self);173}174else if (Player_CheckBossHit(player, self)) {175RSDK.PlaySfx(DBTower->sfxBumper3, false, 255);176self->playerTimers[playerID] = 30;177break;178}179}180}181}182}183}184}185186self->position.x = self->bodyPositions[0].x;187self->position.y = self->bodyPositions[0].y;188}189190void DBTower_Explode(void)191{192RSDK_THIS(DBTower);193194if (!(Zone->timer & 3)) {195RSDK.PlaySfx(UberCaterkiller->sfxExplosion2, false, 255);196197if (!(Zone->timer & 7)) {198int32 x = self->position.x + (RSDK.Rand(-19, 20) << 16);199int32 y = self->position.y + (RSDK.Rand(-24, 25) << 16);200EntityExplosion *explosion = CREATE_ENTITY(Explosion, INT_TO_VOID((RSDK.Rand(0, 256) > 192) + EXPLOSION_BOSS), x, y);201explosion->drawGroup = Zone->objectDrawGroup[1] + 2;202}203}204}205206void DBTower_State_SetupArena(void)207{208RSDK_THIS(DBTower);209210if (RSDK_GET_ENTITY(SLOT_PLAYER1, Player)->position.x > self->position.x) {211Zone->playerBoundActiveL[0] = true;212Zone->playerBoundActiveR[0] = true;213Zone->cameraBoundsL[0] = (self->position.x >> 16) - ScreenInfo->center.x;214Zone->cameraBoundsR[0] = (self->position.x >> 16) + ScreenInfo->center.x;215216self->active = ACTIVE_NORMAL;217self->timer = 0;218self->position.x += (ScreenInfo->center.x - 64) << 16;219220self->originPos.x = self->position.x;221self->originPos.y += 0xA20000;222223self->bodyPositions[0].x = self->position.x;224self->bodyPositions[0].y = self->originPos.y;225for (int32 i = 1; i < DBTOWER_SEGMENT_COUNT; ++i) {226self->bodyPositions[i].x = self->originPos.x;227self->bodyPositions[i].y = 0x7FFF0000;228}229230Music_TransitionTrack(TRACK_MINIBOSS, 0.0125);231232#if MANIA_USE_PLUS233if (SceneInfo->filter == (FILTER_BOTH | FILTER_ENCORE)) {234self->timer = 60;235self->state = DBTower_State_Setup_Encore;236}237else {238#endif239RSDK.PlaySfx(DBTower->sfxAssemble, false, 255);240self->bodyPositions[++self->connectedSegmentCount].y = 0x7FFF0000;241self->segmentOffsetY += 0x360000;242self->timer = 0;243self->state = DBTower_State_HandleBoss;244#if MANIA_USE_PLUS245}246#endif247}248}249250#if MANIA_USE_PLUS251void DBTower_State_Setup_Encore(void)252{253RSDK_THIS(DBTower);254255if (--self->timer <= 0) {256RSDK.PlaySfx(DBTower->sfxAssemble, false, 255);257self->bodyPositions[++self->connectedSegmentCount].y = 0x7FFF0000;258self->segmentOffsetY += 0x360000;259self->timer = 0;260self->state = DBTower_State_HandleBoss;261}262}263#endif264265void DBTower_State_HandleBoss(void)266{267RSDK_THIS(DBTower);268269++self->xOffsetAngle;270self->angle = (RSDK.Sin256(self->wobbleAngle >> 8) >> 5) + 0xC0;271272if (self->headAnimator.frameID != 0)273RSDK.ProcessAnimation(&self->headAnimator);274275int32 x = 0x3600 * ((DBTOWER_SEGMENT_COUNT - 1) - self->connectedSegmentCount) * RSDK.Cos256(self->angle);276self->bodyPositions[self->connectedSegmentCount].x = self->originPos.x + x + (RSDK.Cos256(self->xOffsetAngle) << 12);277self->bodyPositions[self->connectedSegmentCount].y = self->originPos.y + self->segmentOffsetY;278279for (int32 i = self->connectedSegmentCount - 1; i >= 0; --i) {280self->bodyPositions[i].x = 0x3600 * RSDK.Cos256(self->angle) + self->bodyPositions[i + 1].x;281self->bodyPositions[i].y = 0x3600 * RSDK.Sin256(self->angle) + self->bodyPositions[i + 1].y;282}283284self->wobbleAngle += self->wobbleAngleVel;285286if (self->wobbleAngleVel > 640) {287self->wobbleAngleVel -= 8;288RSDK.ProcessAnimation(&self->headAnimator);289}290291if (self->segmentOffsetY < 0) {292self->segmentOffsetY += self->velocity.y;293if (self->segmentOffsetY < 0) {294self->velocity.y += 0x2800;295}296else {297self->segmentOffsetY = 0;298self->velocity.y = 0;299}300}301else if (self->segmentOffsetY <= 0) {302if (++self->timer >= 120 || !self->connectedSegmentCount) {303self->timer = 0;304if (self->connectedSegmentCount > 0) {305RSDK.PlaySfx(DBTower->sfxRocketJet2, false, 255);306307EntityDBTower *child = NULL;308if (!(self->connectedSegmentCount & 1)) {309child = CREATE_ENTITY(DBTower, DBTower_State_BodyRolling, self->bodyPositions[self->connectedSegmentCount].x,310self->bodyPositions[self->connectedSegmentCount].y);311}312else {313child = CREATE_ENTITY(DBTower, DBTower_State_BodyBouncing, self->bodyPositions[self->connectedSegmentCount].x,314self->bodyPositions[self->connectedSegmentCount].y);315child->velocity.x = -0x20000;316child->velocity.y = -0x80000;317}318child->bodyAngles[0] = self->bodyAngles[self->connectedSegmentCount];319child->rotation = 2 * self->bodyAngles[self->connectedSegmentCount];320}321322if (!(--self->connectedSegmentCount & 0x80)) {323self->segmentOffsetY -= 0x360000;324}325else {326RSDK.PlaySfx(DBTower->sfxAssemble, false, 255);327self->connectedSegmentCount += 2;328self->bodyPositions[self->connectedSegmentCount].y = 0x7FFF0000;329self->segmentOffsetY += 0x360000;330}331}332}333else {334self->segmentOffsetY -= 0x10000;335336if (self->segmentOffsetY <= 0) {337if (self->connectedSegmentCount < DBTOWER_SEGMENT_COUNT - 1) {338self->connectedSegmentCount++;339self->bodyPositions[self->connectedSegmentCount].y = 0x7FFF0000;340self->segmentOffsetY += 0x360000;341}342}343}344DBTower_CheckPlayerCollisions_Head();345}346347void DBTower_State_Destroyed(void)348{349RSDK_THIS(DBTower);350351DBTower_Explode();352353if (--self->timer <= 0) {354EntityFXFade *fxFade = CREATE_ENTITY(FXFade, INT_TO_VOID(0xF0F0F0), self->position.x, self->position.y);355fxFade->speedIn = 256;356fxFade->speedOut = 32;357RSDK.PlaySfx(DBTower->sfxExplosion3, false, 255);358359for (int32 i = 1; i < DBTOWER_SEGMENT_COUNT; ++i) {360EntityDebris *debris = CREATE_ENTITY(Debris, Debris_State_FallAndFlicker, self->bodyPositions[i].x, self->bodyPositions[i].y);361RSDK.SetSpriteAnimation(DBTower->aniFrames, self->segmentAnimators[i]->animationID, &debris->animator, true,362self->segmentAnimators[i]->frameID);363debris->velocity.x = 4 * RSDK.Rand(-0x20000, 0x20000);364debris->velocity.y = 4 * RSDK.Rand(-0x20000, -0x10000);365debris->gravityStrength = 0x4800;366debris->drawGroup = Zone->objectDrawGroup[1];367debris->updateRange.x = 0x400000;368debris->updateRange.y = 0x400000;369self->bodyPositions[i].x = -0x800000;370self->bodyPositions[i].y = -0x800000;371}372373self->velocity.y = -0x40000;374self->state = DBTower_State_Finish;375}376}377378void DBTower_State_Finish(void)379{380RSDK_THIS(DBTower);381382DBTower_Explode();383384self->position.y += self->velocity.y;385self->velocity.y += 0x3800;386387self->bodyPositions[0].y = self->position.y;388389if (!RSDK.CheckOnScreen(self, &self->updateRange)) {390DBTower->defeated = true;391Music_TransitionTrack(TRACK_STAGE, 0.0125);392393#if MANIA_USE_PLUS394if (SceneInfo->filter == (FILTER_BOTH | FILTER_ENCORE)) {395self->timer = 0;396self->state = DBTower_State_SpawnSignPost;397}398else {399#endif400Zone->cameraBoundsR[0] += 848;401Zone->playerBoundActiveR[0] = false;402Zone->cameraBoundsB[0] = 304;403destroyEntity(self);404#if MANIA_USE_PLUS405}406#endif407}408}409410#if MANIA_USE_PLUS411void DBTower_State_SpawnSignPost(void)412{413RSDK_THIS(DBTower);414415if (++self->timer == 48) {416foreach_all(SignPost, signPost)417{418signPost->position.x = self->position.x;419signPost->state = SignPost_State_Falling;420RSDK.PlaySfx(SignPost->sfxTwinkle, false, 255);421}422destroyEntity(self);423}424}425#endif426427void DBTower_CheckPlayerCollisions_Body(void)428{429RSDK_THIS(DBTower);430431foreach_active(Player, player)432{433int32 playerID = RSDK.GetEntitySlot(player);434435if (self->playerTimers[playerID]) {436self->playerTimers[playerID]--;437}438else {439uint8 angle = (RSDK.ATan2(player->position.x - self->position.x, player->position.y - self->position.y) - self->bodyAngles[0]);440if (Player_CheckBadnikTouch(player, self, &DBTower->hitboxSegment)) {441if (angle >= 0x80) {442#if MANIA_USE_PLUS443if (Player_CheckMightyUnspin(player, 0x300, 2, &player->uncurlTimer))444self->playerTimers[playerID] = 30;445else446#endif447Player_Hurt(player, self);448}449else if (450#if MANIA_USE_PLUS451(player->characterID == ID_MIGHTY && player->animator.animationID == ANI_CROUCH) ||452#endif453Player_CheckBossHit(player, self)) {454RSDK.PlaySfx(DBTower->sfxBumper3, false, 255);455self->playerTimers[playerID] = 30;456foreach_break;457}458}459}460}461}462463void DBTower_State_BodyBouncing(void)464{465RSDK_THIS(DBTower);466467self->position.x += self->velocity.x;468self->position.y += self->velocity.y;469self->velocity.y += 0x3800;470471if (RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0, 0x1B0000, true)) {472RSDK.PlaySfx(DBTower->sfxRockemSockem, false, 255);473self->velocity.y = -0x80000;474}475476self->bodyPositions[0] = self->position;477self->bodyAngles[0] = (self->bodyAngles[0] - 8) & 0xFF;478self->rotation = self->bodyAngles[0] << 1;479480if (RSDK.CheckOnScreen(self, &self->updateRange))481DBTower_CheckPlayerCollisions_Body();482else483destroyEntity(self);484}485486void DBTower_State_BodyRolling(void)487{488RSDK_THIS(DBTower);489490self->position.x += self->velocity.x;491self->velocity.x -= 0x2800;492493self->bodyPositions[0] = self->position;494self->bodyPositions[0] = self->position;495self->bodyAngles[0] = (self->bodyAngles[0] - 8) & 0xFF;496self->rotation = self->bodyAngles[0] << 1;497498if (RSDK.CheckOnScreen(self, &self->updateRange))499DBTower_CheckPlayerCollisions_Body();500else501destroyEntity(self);502}503504#if GAME_INCLUDE_EDITOR505void DBTower_EditorDraw(void)506{507RSDK_THIS(DBTower);508509RSDK.SetSpriteAnimation(DBTower->aniFrames, 0, &self->headAnimator, true, 0);510RSDK.DrawSprite(&self->headAnimator, NULL, false);511512if (showGizmos()) {513RSDK_DRAWING_OVERLAY(true);514515DrawHelpers_DrawArenaBounds(-WIDE_SCR_XCENTER, -SCREEN_YCENTER, WIDE_SCR_XCENTER, SCREEN_YCENTER, 1 | 0 | 4 | 0, 0x00C0F0);516517RSDK_DRAWING_OVERLAY(false);518}519}520521void DBTower_EditorLoad(void) { DBTower->aniFrames = RSDK.LoadSpriteAnimation("MSZ/Sandworm.bin", SCOPE_STAGE); }522#endif523524void DBTower_Serialize(void) {}525526527