Path: blob/master/SonicMania/Objects/TMZ/CrashTest.c
338 views
// ---------------------------------------------------------------------1// RSDK Project: Sonic Mania2// Object Description: CrashTest Object3// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges4// Decompiled by: Rubberduckycooly & RMGRich5// ---------------------------------------------------------------------67#include "Game.h"89ObjectCrashTest *CrashTest;1011void CrashTest_Update(void)12{13RSDK_THIS(CrashTest);1415StateMachine_Run(self->state);1617CrashTest_HandleLightAnims();1819RSDK.ProcessAnimation(&self->driverAnimator);20RSDK.ProcessAnimation(&self->carAnimator);21}2223void CrashTest_LateUpdate(void) {}2425void CrashTest_StaticUpdate(void)26{27foreach_active(CrashTest, crashtest) { RSDK.AddDrawListRef(Zone->playerDrawGroup[0] + 1, RSDK.GetEntitySlot(crashtest)); }28}2930void CrashTest_Draw(void)31{32RSDK_THIS(CrashTest);3334Vector2 lightPos = self->startPos;35lightPos.x += 0x300000 * (2 * (self->direction != FLIP_NONE) - 1);3637Vector2 carPos = self->startPos;38carPos.x += self->travelDistance * (2 * (self->direction != FLIP_NONE) - 1);3940Vector2 stopperPos;41stopperPos.x =42(2 * (self->direction != FLIP_NONE) - 1) * (self->length << 16) + self->startPos.x + 0x340000 * (2 * (self->direction != FLIP_NONE) - 1);43stopperPos.y = self->startPos.y;4445if (SceneInfo->currentDrawGroup == Zone->playerDrawGroup[0] + 1) {46if (self->state != CrashTest_State_Crashed)47RSDK.DrawSprite(&self->carAnimator, &carPos, false);48}49else {50RSDK.DrawSprite(&self->lightAnimator, &lightPos, false);51RSDK.DrawSprite(&self->stopperAnimator, &stopperPos, false);5253if (self->state != CrashTest_State_Crashed)54RSDK.DrawSprite(&self->driverAnimator, &carPos, false);55}56}5758void CrashTest_Create(void *data)59{60RSDK_THIS(CrashTest);6162self->active = ACTIVE_BOUNDS;63self->drawGroup = Zone->objectDrawGroup[0];64self->startPos = self->position;65self->visible = true;66self->drawFX = FX_FLIP;67self->updateRange.x = (self->length + 128) << 16;68self->updateRange.y = 0x800000;6970CrashTest_SetupHitboxes();7172Vector2 positions[] = { { -0x100000, -0x180000 }, { 0x80000, -0x1A0000 }, { -0x100000, -0x180000 }, { 0x00000, -0x100000 },73{ -0x200000, -0x80000 }, { 0x100000, -0x100000 }, { -0x40000, -0x180000 }, { -0x40000, -0x80000 } };7475for (int32 i = 0; i < 8; ++i) {76self->debrisOffsets[i].x = positions[i].x;77self->debrisOffsets[i].y = positions[i].y;78}7980self->state = CrashTest_State_Init;81}8283void CrashTest_StageLoad(void)84{85CrashTest->active = ACTIVE_ALWAYS;8687CrashTest->aniFrames = RSDK.LoadSpriteAnimation("TMZ1/CrashTest.bin", SCOPE_STAGE);8889CrashTest->sfxExplosion = RSDK.GetSfx("Stage/Explosion2.wav");90CrashTest->sfxCrash = RSDK.GetSfx("TMZ1/Crash.wav");91CrashTest->sfxTrafficLight = RSDK.GetSfx("TMZ1/TrafficLight.wav");92CrashTest->sfxCarRev = RSDK.GetSfx("TMZ1/CarRev.wav");93CrashTest->sfxSpeedBooster = RSDK.GetSfx("Stage/SpeedBooster.wav");94}9596void CrashTest_SetupHitboxes(void)97{98RSDK_THIS(CrashTest);99100self->hitboxSeat.left = -22;101self->hitboxSeat.top = -16;102self->hitboxSeat.right = 14;103self->hitboxSeat.bottom = 4;104105self->hitboxFront.left = -40;106self->hitboxFront.top = -16;107self->hitboxFront.right = -22;108self->hitboxFront.bottom = 0;109110self->hitboxFloor.left = -22;111self->hitboxFloor.top = -4;112self->hitboxFloor.right = 14;113self->hitboxFloor.bottom = 0;114115self->hitboxBack.left = 14;116self->hitboxBack.top = -36;117self->hitboxBack.right = 25;118self->hitboxBack.bottom = 0;119120self->hitboxStopper.left = -12;121self->hitboxStopper.top = -24;122self->hitboxStopper.right = 12;123self->hitboxStopper.bottom = 0;124125self->hitboxBooster.left = 28;126self->hitboxBooster.top = -22;127self->hitboxBooster.right = 51;128self->hitboxBooster.bottom = -2;129}130131void CrashTest_CheckOffScreen(void)132{133RSDK_THIS(CrashTest);134135if (!RSDK.CheckOnScreen(self, NULL) && !RSDK.CheckPosOnScreen(&self->startPos, &self->updateRange)) {136self->position = self->startPos;137self->active = ACTIVE_BOUNDS;138self->state = CrashTest_State_Init;139}140}141142void CrashTest_HandlePlayerCrash(void)143{144RSDK_THIS(CrashTest);145146foreach_active(Player, player)147{148int32 playerID = RSDK.GetEntitySlot(player);149if ((1 << playerID) & self->activePlayers) {150self->activePlayers &= ~(1 << playerID);151bool32 isSidekick = player->sidekick;152153player->sidekick = true;154Player_Hit(player);155156player->sidekick = isSidekick;157}158}159}160161void CrashTest_CheckPlayerCollisionsSolid(void)162{163RSDK_THIS(CrashTest);164165int32 storeDir = self->direction;166167int32 storeX = self->position.x;168int32 storeY = self->position.y;169170int32 stopperX = (2 * (storeDir != FLIP_NONE) - 1) * (self->length << 16) + self->startPos.x + 0x340000 * (2 * (storeDir != FLIP_NONE) - 1);171int32 stopperY = self->startPos.y;172173int32 carX = (2 * (storeDir != FLIP_NONE) - 1) + self->startPos.x;174int32 carY = self->startPos.y;175176foreach_active(Player, player)177{178RSDK.GetEntitySlot(player);179if (self->state != CrashTest_State_Crashed) {180self->position.y = carY;181self->position.x = carX;182self->direction = storeDir;183184Player_CheckCollisionBox(player, self, &self->hitboxFront);185Player_CheckCollisionBox(player, self, &self->hitboxFloor);186Player_CheckCollisionBox(player, self, &self->hitboxBack);187188if (self->boosterActive) {189if (Player_CheckCollisionTouch(player, self, &self->hitboxBooster)) {190Player_ElementHurt(player, self, SHIELD_FIRE);191}192}193}194195self->position.x = stopperX;196self->position.y = stopperY;197self->direction = FLIP_NONE;198Player_CheckCollisionBox(player, self, &self->hitboxStopper);199}200201self->position.x = storeX;202self->position.y = storeY;203self->direction = storeDir;204}205206void CrashTest_CheckPlayerRide(void)207{208RSDK_THIS(CrashTest);209210int32 storeX = self->position.x;211int32 storeY = self->position.y;212213self->position.x = self->travelDistance * (2 * (self->direction != FLIP_NONE) - 1) + self->startPos.x;214self->position.y = self->startPos.y;215216foreach_active(Player, player)217{218int32 playerID = RSDK.GetEntitySlot(player);219220if (!((1 << playerID) & self->activePlayers) && !self->playerTimers[playerID]) {221if (Player_CheckCollisionTouch(player, self, &self->hitboxSeat)) {222self->activePlayers |= 1 << playerID;223player->groundVel = 0;224225RSDK.PlaySfx(Player->sfxGrab, false, 0xFF);226RSDK.SetSpriteAnimation(player->aniFrames, ANI_HURT, &player->animator, false, 4);227228player->nextGroundState = StateMachine_None;229player->nextAirState = StateMachine_None;230player->state = Player_State_Static;231}232}233234if (self->playerTimers[playerID] > 0)235self->playerTimers[playerID]--;236}237238self->position.x = storeX;239self->position.y = storeY;240}241242void CrashTest_CheckPlayerJump(void)243{244RSDK_THIS(CrashTest);245246int32 x = self->startPos.x + (self->travelDistance * (2 * (self->direction != FLIP_NONE) - 1));247int32 y = self->startPos.y;248249foreach_active(Player, player)250{251int32 playerID = RSDK.GetEntitySlot(player);252253if ((1 << playerID) & self->activePlayers) {254player->velocity.x = 0;255player->velocity.y = 0;256257player->velocity.x = self->direction == FLIP_NONE ? -self->velocity.x : self->velocity.x;258player->direction = self->direction == FLIP_NONE;259260player->position.x = x;261player->position.y = y;262player->position.y -= 0x100000;263264if (player->jumpPress) {265self->activePlayers &= ~(1 << playerID);266Player_Action_Jump(player);267player->velocity.x = self->direction == FLIP_NONE ? -self->velocity.x : self->velocity.x;268self->playerTimers[playerID] = 10;269}270}271}272}273274void CrashTest_HandleLightAnims(void)275{276RSDK_THIS(CrashTest);277278if (self->turningGreen != self->prevTurningGreen) {279if (self->turningGreen)280RSDK.SetSpriteAnimation(CrashTest->aniFrames, 7, &self->lightAnimator, true, 0);281else282RSDK.SetSpriteAnimation(CrashTest->aniFrames, 9, &self->lightAnimator, true, 0);283}284285// finished "Turning [clr]" Animation286if (self->lightAnimator.speed == 1 && self->lightAnimator.frameID == self->lightAnimator.frameCount - 1) {287if (self->turningGreen)288RSDK.SetSpriteAnimation(CrashTest->aniFrames, 8, &self->lightAnimator, false, 0);289else290RSDK.SetSpriteAnimation(CrashTest->aniFrames, 6, &self->lightAnimator, false, 0);291}292293self->prevTurningGreen = self->turningGreen;294295RSDK.ProcessAnimation(&self->lightAnimator);296}297298void CrashTest_State_Init(void)299{300RSDK_THIS(CrashTest);301302RSDK.SetSpriteAnimation(CrashTest->aniFrames, 0, &self->carAnimator, true, 0);303RSDK.SetSpriteAnimation(CrashTest->aniFrames, 2, &self->driverAnimator, true, 0);304RSDK.SetSpriteAnimation(CrashTest->aniFrames, 6, &self->lightAnimator, true, 0);305RSDK.SetSpriteAnimation(CrashTest->aniFrames, 4, &self->stopperAnimator, true, 0);306307self->travelDistance = 0;308self->timer = 0;309self->activePlayers = 0;310self->velocity.x = 0;311self->boosterActive = false;312self->turningGreen = false;313self->prevTurningGreen = false;314315self->state = CrashTest_State_AwaitPlayer;316}317318void CrashTest_State_AwaitPlayer(void)319{320RSDK_THIS(CrashTest);321322CrashTest_CheckPlayerCollisionsSolid();323CrashTest_CheckPlayerRide();324CrashTest_CheckPlayerJump();325326if (self->activePlayers & 1) {327self->active = ACTIVE_NORMAL;328self->timer = 40;329self->state = CrashTest_State_Rev;330RSDK.PlaySfx(CrashTest->sfxTrafficLight, false, 255);331}332}333334void CrashTest_State_Rev(void)335{336RSDK_THIS(CrashTest);337338if (self->timer <= 0) {339self->boosterActive = true;340341RSDK.SetSpriteAnimation(CrashTest->aniFrames, 1, &self->carAnimator, true, 0);342RSDK.SetSpriteAnimation(CrashTest->aniFrames, 3, &self->driverAnimator, true, 0);343344self->active = ACTIVE_NORMAL;345self->turningGreen = true;346self->state = CrashTest_State_Move;347RSDK.PlaySfx(CrashTest->sfxCarRev, false, 255);348}349else {350self->timer--;351}352}353354void CrashTest_State_Move(void)355{356RSDK_THIS(CrashTest);357358if (self->velocity.x < 0x100000) {359self->velocity.x += 0x2000;360361if (self->velocity.x > 0x100000)362self->velocity.x = 0x100000;363}364365self->travelDistance += self->velocity.x;366367bool32 crashed = false;368if (self->travelDistance >= self->length << 16) {369self->travelDistance = self->length << 16;370crashed = true;371}372373CrashTest_CheckPlayerCollisionsSolid();374CrashTest_CheckPlayerRide();375CrashTest_CheckPlayerJump();376CrashTest_CheckOffScreen();377378if (crashed) {379int32 x = self->travelDistance * (2 * (self->direction != FLIP_NONE) - 1) + self->startPos.x;380381Camera_ShakeScreen(0, 5, 5);382CrashTest_HandlePlayerCrash();383384self->timer = 0;385RSDK.PlaySfx(CrashTest->sfxCrash, false, 255);386387int32 storeX = self->position.x;388int32 storeY = self->position.y;389390self->state = CrashTest_State_Crashed;391self->turningGreen = false;392393for (int32 i = 0; i < 8; ++i) {394EntityDebris *debris = CREATE_ENTITY(Debris, Debris_State_Fall, x + self->debrisOffsets[i].x * (2 * (self->direction == FLIP_NONE) - 1),395self->startPos.y + self->debrisOffsets[i].y);396RSDK.SetSpriteAnimation(CrashTest->aniFrames, 5, &debris->animator, true, i);397debris->drawFX |= FX_ROTATE;398399debris->rotSpeed = self->direction == FLIP_NONE ? -8 : 8;400debris->drawGroup = Zone->objectDrawGroup[1];401debris->gravityStrength = 0x3800;402debris->direction = self->direction;403debris->velocity.x = (RSDK.Rand(-32, 32) << 12) + (self->velocity.x >> 1) * (2 * (self->direction != FLIP_NONE) - 1);404debris->velocity.y = -0x1000 * RSDK.Rand(32, 128);405}406407self->position.x = storeX;408self->position.y = storeY;409}410}411412void CrashTest_State_Crashed(void)413{414RSDK_THIS(CrashTest);415416CrashTest_CheckOffScreen();417CrashTest_CheckPlayerCollisionsSolid();418419if (self->timer >= 30) {420Vector2 range = { 0x200000, 0x200000 };421422if (!RSDK.CheckPosOnScreen(&self->startPos, &range))423self->state = CrashTest_State_Init;424}425else {426int32 startX = self->travelDistance * (2 * (self->direction != FLIP_NONE) - 1) + self->startPos.x;427428if (!(Zone->timer % 3)) {429RSDK.PlaySfx(CrashTest->sfxExplosion, false, 255);430431if (Zone->timer & 4) {432int32 x = startX + (RSDK.Rand(-16, 16) << 16);433int32 y = self->startPos.y + (RSDK.Rand(-22, 0) << 16);434EntityExplosion *explosion = CREATE_ENTITY(Explosion, INT_TO_VOID((RSDK.Rand(0, 256) > 192) + 2), x, y);435explosion->drawGroup = Zone->objectDrawGroup[1];436}437}438439++self->timer;440}441}442443#if GAME_INCLUDE_EDITOR444void CrashTest_EditorDraw(void)445{446RSDK_THIS(CrashTest);447448RSDK.SetSpriteAnimation(CrashTest->aniFrames, 0, &self->carAnimator, false, 0);449RSDK.SetSpriteAnimation(CrashTest->aniFrames, 2, &self->driverAnimator, false, 0);450RSDK.SetSpriteAnimation(CrashTest->aniFrames, 6, &self->lightAnimator, false, 0);451RSDK.SetSpriteAnimation(CrashTest->aniFrames, 4, &self->stopperAnimator, false, 0);452453Vector2 lightPos = self->startPos;454lightPos.x += 0x300000 * (2 * (self->direction != FLIP_NONE) - 1);455456Vector2 carPos = self->startPos;457carPos.x += self->travelDistance * (2 * (self->direction != FLIP_NONE) - 1);458459Vector2 stopperPos;460stopperPos.x =461(2 * (self->direction != FLIP_NONE) - 1) * (self->length << 16) + self->startPos.x + 0x340000 * (2 * (self->direction != FLIP_NONE) - 1);462stopperPos.y = self->startPos.y;463464RSDK.DrawSprite(&self->lightAnimator, &lightPos, false);465RSDK.DrawSprite(&self->stopperAnimator, &stopperPos, false);466RSDK.DrawSprite(&self->driverAnimator, &carPos, false);467RSDK.DrawSprite(&self->carAnimator, &carPos, false);468}469470void CrashTest_EditorLoad(void)471{472CrashTest->aniFrames = RSDK.LoadSpriteAnimation("TMZ1/CrashTest.bin", SCOPE_STAGE);473474RSDK_ACTIVE_VAR(CrashTest, direction);475RSDK_ENUM_VAR("Left", FLIP_NONE);476RSDK_ENUM_VAR("Right", FLIP_X);477478// dunno what "debugParticles" is, maybe a way for the devs to test the "particles" of this object in editor?479}480#endif481482void CrashTest_Serialize(void)483{484RSDK_EDITABLE_VAR(CrashTest, VAR_UINT8, direction);485RSDK_EDITABLE_VAR(CrashTest, VAR_INT32, length);486RSDK_EDITABLE_VAR(CrashTest, VAR_BOOL, debugParticles);487}488489490