Path: blob/master/SonicMania/Objects/TMZ/TurboTurtle.c
338 views
// ---------------------------------------------------------------------1// RSDK Project: Sonic Mania2// Object Description: TurboTurtle Object3// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges4// Decompiled by: Rubberduckycooly & RMGRich5// ---------------------------------------------------------------------67#include "Game.h"89ObjectTurboTurtle *TurboTurtle;1011void TurboTurtle_Update(void)12{13RSDK_THIS(TurboTurtle);1415RSDK.ProcessAnimation(&self->animator);1617if (self->animator.animationID == 1) {18if (!self->animator.frameID && self->animator.timer == 1)19RSDK.PlaySfx(TurboTurtle->sfxWalk, false, 255);2021if (self->animator.frameID == 5 && self->animator.timer == 1)22RSDK.PlaySfx(TurboTurtle->sfxWalk2, false, 255);23}2425self->fanActiveTop = false;26self->leftFanActive = false;27self->rightFanActive = false;2829StateMachine_Run(self->state);3031TurboTurtle_CheckPlayerCollisions();3233if (self->state != TurboTurtle_State_Init) {34if (!RSDK.CheckOnScreen(self, NULL) && !RSDK.CheckPosOnScreen(&self->startPos, &self->updateRange)) {35self->direction = self->startDir;36self->position = self->startPos;37TurboTurtle_Create(NULL);38}39}40}4142void TurboTurtle_LateUpdate(void) {}4344void TurboTurtle_StaticUpdate(void) {}4546void TurboTurtle_Draw(void)47{48RSDK_THIS(TurboTurtle);4950RSDK.DrawSprite(&self->animator, NULL, false);51}5253void TurboTurtle_Create(void *data)54{55RSDK_THIS(TurboTurtle);5657self->visible = true;58self->drawGroup = Zone->objectDrawGroup[0];59self->startPos = self->position;60self->startDir = self->direction;61self->drawFX = FX_FLIP;62self->active = ACTIVE_BOUNDS;63self->updateRange.x = 0x800000;64self->updateRange.y = 0x800000;6566self->updateRange.x = abs(0x70000 * (self->stepCount * (2 * (self->initialSide == 0) - 1) + self->startPos.x - self->startPos.x)) + 0x800000;6768if (!self->leftFanDuration)69self->leftFanDuration = 60;7071if (!self->rightFanDuration)72self->rightFanDuration = 60;7374if (!self->leftFanLength)75self->leftFanLength = 128;7677if (!self->rightFanLength)78self->rightFanLength = 128;7980if (!self->leftFanStrength)81self->leftFanStrength = 18;8283if (!self->rightFanStrength)84self->rightFanStrength = 18;8586self->hitboxFanT.left = -24;87self->hitboxFanT.top = -19;88self->hitboxFanT.right = 24;89self->hitboxFanT.bottom = -19;9091self->hitboxFanR.left = -19;92self->hitboxFanR.top = -24;93self->hitboxFanR.right = 19;94self->hitboxFanR.bottom = 24;9596self->hitboxFanL.left = -20;97self->hitboxFanL.top = -24;98self->hitboxFanL.right = -20;99self->hitboxFanL.bottom = 24;100101self->state = TurboTurtle_State_Init;102}103104void TurboTurtle_StageLoad(void)105{106TurboTurtle->aniFrames = RSDK.LoadSpriteAnimation("TMZ1/TurboTurtle.bin", SCOPE_STAGE);107108TurboTurtle->hitboxBadnik.left = -13;109TurboTurtle->hitboxBadnik.top = -12;110TurboTurtle->hitboxBadnik.right = 13;111TurboTurtle->hitboxBadnik.bottom = 16;112113DEBUGMODE_ADD_OBJ(TurboTurtle);114115TurboTurtle->sfxWalk = RSDK.GetSfx("TMZ1/TurtleWalk.wav");116TurboTurtle->sfxWalk2 = RSDK.GetSfx("TMZ1/TurtleWalk2.wav");117118Soundboard_LoadSfx("HCZ/SmallFan.wav", 37404, TurboTurtle_SfxCheck_SmallFan, StateMachine_None);119}120121void TurboTurtle_DebugSpawn(void)122{123RSDK_THIS(DebugMode);124125EntityTurboTurtle *turboTurtle = CREATE_ENTITY(TurboTurtle, NULL, self->position.x, self->position.y);126turboTurtle->direction = self->direction;127turboTurtle->startDir = self->direction;128}129130void TurboTurtle_DebugDraw(void)131{132RSDK.SetSpriteAnimation(TurboTurtle->aniFrames, 0, &DebugMode->animator, true, 0);133RSDK.DrawSprite(&DebugMode->animator, NULL, false);134}135136void TurboTurtle_CheckPlayerCollisions(void)137{138RSDK_THIS(TurboTurtle);139140foreach_active(Player, player)141{142if (Player_CheckBadnikTouch(player, self, &TurboTurtle->hitboxBadnik))143Player_CheckBadnikBreak(player, self, true);144}145}146147void TurboTurtle_SetupState(void)148{149RSDK_THIS(TurboTurtle);150151int32 dir = self->currentSide ? self->rightFanDir : self->leftFanDir;152self->timer = 0;153154switch (dir) {155case TURBOTURTLE_FANDIR_TOP:156RSDK.SetSpriteAnimation(TurboTurtle->aniFrames, 2, &self->animator, true, 0);157self->state = TurboTurtle_State_FanTop;158break;159160case TURBOTURTLE_FANDIR_RIGHT:161RSDK.SetSpriteAnimation(TurboTurtle->aniFrames, 4, &self->animator, true, 0);162self->direction = FLIP_NONE;163self->state = TurboTurtle_State_TurnFanRight;164break;165166case TURBOTURTLE_FANDIR_LEFT:167RSDK.SetSpriteAnimation(TurboTurtle->aniFrames, 4, &self->animator, true, 0);168self->direction = FLIP_X;169self->state = TurboTurtle_State_TurnFanLeft;170break;171}172}173174void TurboTurtle_HandleFans(void)175{176RSDK_THIS(TurboTurtle);177178int32 storeDir = self->direction;179self->direction = FLIP_NONE;180181int32 strength = self->currentSide ? self->rightFanStrength : self->leftFanStrength;182183int32 length = self->currentSide ? self->rightFanLength : self->leftFanLength;184185if (self->fanActiveTop) {186length += RSDK.Sin256(2 * Zone->timer) >> 5;187self->hitboxFanT.top = self->hitboxFanT.bottom - length;188189foreach_active(Player, player)190{191if (Player_CheckCollisionTouch(player, self, &self->hitboxFanT)) {192int32 anim = player->animator.animationID;193if (anim != ANI_CLING && anim != ANI_SHAFT_SWING) {194if (!player->onGround) {195player->velocity.y -= player->gravityStrength;196if (player->velocity.y > 0)197player->velocity.y -= (player->velocity.y >> 3);198}199200int32 thisY = self->position.y;201int32 bottom = thisY + (self->hitboxFanT.bottom << 16);202int32 top = (self->hitboxFanT.top << 16) + thisY;203if (player->position.y > top)204top = player->position.y;205206player->position.y -= ((strength * (((length << 16) - bottom + top != 0 ? (length << 16) - bottom + top : 0) / length)) >> 1);207}208}209}210211TurboTurtle_HandleFanParticles(TURBOTURTLE_FANDIR_TOP, strength, length << 16);212}213214if (self->leftFanActive) {215self->hitboxFanL.left = self->hitboxFanL.right - length;216217foreach_active(Player, player)218{219if (Player_CheckCollisionTouch(player, self, &self->hitboxFanL)) {220int32 anim = player->animator.animationID;221if (anim != ANI_CLING && anim != ANI_SHAFT_SWING) {222int32 left = (self->hitboxFanL.left << 16) + self->position.x;223if (player->position.x > left)224left = player->position.x;225226int32 pos = (length << 16) - (self->position.x + (self->hitboxFanL.right << 16)) + left;227player->position.x -= (strength * ((pos & -(pos != 0)) / length)) >> 1;228}229}230}231232TurboTurtle_HandleFanParticles(TURBOTURTLE_FANDIR_LEFT, strength, length << 16);233}234235if (self->rightFanActive) {236self->hitboxFanR.right = length + self->hitboxFanR.left;237238foreach_active(Player, player)239{240if (Player_CheckCollisionTouch(player, self, &self->hitboxFanR)) {241int32 anim = player->animator.animationID;242if (anim != ANI_CLING && anim != ANI_SHAFT_SWING) {243int32 right = (self->hitboxFanR.right << 16) + self->position.x;244if (player->position.x < right)245right = player->position.x;246247int32 pos = self->position.x + (self->hitboxFanR.left << 16);248player->position.x += (strength * ((((length << 16) - right + pos != 0) ? (length << 16) - right + pos : 0) / length)) >> 1;249}250}251}252253TurboTurtle_HandleFanParticles(TURBOTURTLE_FANDIR_RIGHT, strength, length << 16);254}255256self->direction = storeDir;257}258259void TurboTurtle_HandleFanParticles(uint8 type, int32 strength, int32 length)260{261RSDK_THIS(TurboTurtle);262263if (!(Zone->timer % 3)) {264for (int32 i = 0; i < RSDK.Rand(1, 2); ++i) {265int32 timer = 0;266int32 anim = (RSDK.Rand(0, 10) > 7) + 6;267int32 frame = RSDK.Rand(0, 3);268269int32 spawnX = 0, spawnY = 0;270int32 velX = 0, velY = 0;271272switch (type) {273case TURBOTURTLE_FANDIR_TOP:274spawnY = self->position.y + (self->hitboxFanT.bottom << 16);275spawnX = (RSDK.Rand(-13, 13) << 16) + self->position.x;276velX = (spawnX - self->position.x) >> 7;277RSDK.Rand(0, 4);278velY = -0x8000 * strength;279timer = length / abs(-0x8000 * strength);280break;281282case TURBOTURTLE_FANDIR_RIGHT:283spawnX = self->position.x + (self->hitboxFanR.left << 16);284spawnY = (RSDK.Rand(-13, 13) << 16) + self->position.y;285RSDK.Rand(0, 4);286velX = strength << 15;287velY = (spawnY - self->position.y) >> 7;288timer = length / abs(strength << 15);289break;290291case TURBOTURTLE_FANDIR_LEFT:292spawnX = self->position.x - (self->hitboxFanR.left << 16);293spawnY = (RSDK.Rand(-13, 13) << 16) + self->position.y;294RSDK.Rand(0, 4);295velX = -0x8000 * strength;296velY = (spawnY - self->position.y) >> 7;297timer = length / abs(-0x8000 * strength);298break;299default: break;300}301302timer += RSDK.Rand(-5, 5);303304EntityDebris *debris = CREATE_ENTITY(Debris, Debris_State_Move, spawnX, spawnY);305RSDK.SetSpriteAnimation(TurboTurtle->aniFrames, anim, &debris->animator, true, frame);306debris->velocity.x = velX;307debris->velocity.y = velY;308debris->drawGroup = Zone->objectDrawGroup[0] - 1;309debris->timer = timer;310}311}312}313314bool32 TurboTurtle_SfxCheck_SmallFan(void)315{316int32 count = 0;317318foreach_all(TurboTurtle, turtle)319{320if (turtle->state == TurboTurtle_State_FanTop || turtle->state == TurboTurtle_State_FanRight || turtle->state == TurboTurtle_State_FanLeft)321++count;322}323324return count > 0;325}326327void TurboTurtle_State_Init(void)328{329RSDK_THIS(TurboTurtle);330331self->active = ACTIVE_NORMAL;332333RSDK.SetSpriteAnimation(TurboTurtle->aniFrames, 0, &self->animator, true, 0);334self->direction = self->startDir;335self->position = self->startPos;336self->currentSide = self->initialSide;337338TurboTurtle_SetupState();339}340341void TurboTurtle_State_Walking(void)342{343RSDK_THIS(TurboTurtle);344345int32 offsets[] = { 0, 0, 0, 0, 1, 1, 0, 0 };346347self->position.x += (2 * (self->currentSide == 1) - 1) * (offsets[self->animator.frameID] << 16);348if (!RSDK.ObjectTileGrip(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0, 0x100000, 2)) {349self->stepTimer = 0;350TurboTurtle_SetupState();351}352else if (self->animator.frameID == self->animator.frameCount - 1) {353if (self->animator.timer == self->animator.frameDuration) {354if (self->stepTimer < self->stepCount) {355self->stepTimer++;356}357else {358self->stepTimer = 0;359TurboTurtle_SetupState();360}361}362}363}364365void TurboTurtle_State_TurnFanUp(void)366{367RSDK_THIS(TurboTurtle);368369if (self->animator.animationID == 5) {370if (self->animator.frameID == self->animator.frameCount - 1) {371uint8 dir = self->currentSide != FLIP_NONE;372self->currentSide = !self->currentSide;373self->direction = dir;374self->stepTimer = 0;375RSDK.SetSpriteAnimation(TurboTurtle->aniFrames, 1, &self->animator, true, 0);376self->state = TurboTurtle_State_Walking;377}378}379}380381void TurboTurtle_State_FanTop(void)382{383RSDK_THIS(TurboTurtle);384385int32 duration = self->currentSide ? self->rightFanDuration : self->leftFanDuration;386387if (self->stationary || self->timer < duration) {388self->fanActiveTop = true;389TurboTurtle_HandleFans();390391if (!self->stationary)392++self->timer;393}394else {395uint8 dir = self->currentSide != 0;396self->currentSide = !self->currentSide;397self->direction = dir;398self->stepTimer = 0;399RSDK.SetSpriteAnimation(TurboTurtle->aniFrames, 1, &self->animator, true, 0);400self->state = TurboTurtle_State_Walking;401}402}403404void TurboTurtle_State_TurnFanRight(void)405{406RSDK_THIS(TurboTurtle);407408if (self->animator.animationID == 4) {409if (self->animator.frameID == self->animator.frameCount - 1) {410RSDK.SetSpriteAnimation(TurboTurtle->aniFrames, 3, &self->animator, true, 0);411self->state = TurboTurtle_State_FanRight;412}413}414}415416void TurboTurtle_State_FanRight(void)417{418RSDK_THIS(TurboTurtle);419420int32 duration = self->currentSide ? self->rightFanDuration : self->leftFanDuration;421422if (self->stationary || self->timer < duration) {423self->rightFanActive = true;424TurboTurtle_HandleFans();425426if (!self->stationary)427++self->timer;428}429else {430RSDK.SetSpriteAnimation(TurboTurtle->aniFrames, 5, &self->animator, true, 0);431self->state = TurboTurtle_State_TurnFanUp;432}433}434435void TurboTurtle_State_TurnFanLeft(void)436{437RSDK_THIS(TurboTurtle);438439if (self->animator.animationID == 4) {440if (self->animator.frameID == self->animator.frameCount - 1) {441RSDK.SetSpriteAnimation(TurboTurtle->aniFrames, 3, &self->animator, true, 0);442self->state = TurboTurtle_State_FanLeft;443}444}445}446447void TurboTurtle_State_FanLeft(void)448{449RSDK_THIS(TurboTurtle);450451int32 duration = self->currentSide ? self->rightFanDuration : self->leftFanDuration;452453if (self->stationary || self->timer < duration) {454self->leftFanActive = true;455TurboTurtle_HandleFans();456457if (!self->stationary)458++self->timer;459}460else {461RSDK.SetSpriteAnimation(TurboTurtle->aniFrames, 5, &self->animator, true, 0);462self->state = TurboTurtle_State_TurnFanUp;463}464}465466#if GAME_INCLUDE_EDITOR467void TurboTurtle_EditorDraw(void)468{469RSDK_THIS(TurboTurtle);470471self->visible = true;472self->drawGroup = Zone->objectDrawGroup[0];473self->startPos = self->position;474self->direction = self->initialSide ^ FLIP_X;475self->startDir = self->direction;476477self->updateRange.x = abs(0x70000 * (self->stepCount * (2 * (self->initialSide == 0) - 1) + self->startPos.x - self->startPos.x)) + 0x800000;478479RSDK.SetSpriteAnimation(TurboTurtle->aniFrames, 0, &self->animator, true, 0);480self->direction = self->startDir;481482TurboTurtle_Draw();483}484485void TurboTurtle_EditorLoad(void)486{487TurboTurtle->aniFrames = RSDK.LoadSpriteAnimation("TMZ1/TurboTurtle.bin", SCOPE_STAGE);488489RSDK_ACTIVE_VAR(TurboTurtle, initialSide);490RSDK_ENUM_VAR("Left", FLIP_NONE);491RSDK_ENUM_VAR("Right", FLIP_X);492493RSDK_ACTIVE_VAR(TurboTurtle, leftFanDir);494RSDK_ENUM_VAR("Top", TURBOTURTLE_FANDIR_TOP);495RSDK_ENUM_VAR("Right", TURBOTURTLE_FANDIR_RIGHT);496RSDK_ENUM_VAR("Left", TURBOTURTLE_FANDIR_LEFT);497498RSDK_ACTIVE_VAR(TurboTurtle, rightFanDir);499RSDK_ENUM_VAR("Top", TURBOTURTLE_FANDIR_TOP);500RSDK_ENUM_VAR("Right", TURBOTURTLE_FANDIR_RIGHT);501RSDK_ENUM_VAR("Left", TURBOTURTLE_FANDIR_LEFT);502}503#endif504505void TurboTurtle_Serialize(void)506{507RSDK_EDITABLE_VAR(TurboTurtle, VAR_UINT16, stepCount);508RSDK_EDITABLE_VAR(TurboTurtle, VAR_UINT8, initialSide);509RSDK_EDITABLE_VAR(TurboTurtle, VAR_BOOL, stationary);510RSDK_EDITABLE_VAR(TurboTurtle, VAR_UINT8, leftFanDir);511RSDK_EDITABLE_VAR(TurboTurtle, VAR_UINT32, leftFanDuration);512RSDK_EDITABLE_VAR(TurboTurtle, VAR_UINT32, leftFanStrength);513RSDK_EDITABLE_VAR(TurboTurtle, VAR_UINT32, leftFanLength);514RSDK_EDITABLE_VAR(TurboTurtle, VAR_UINT8, rightFanDir);515RSDK_EDITABLE_VAR(TurboTurtle, VAR_UINT32, rightFanDuration);516RSDK_EDITABLE_VAR(TurboTurtle, VAR_UINT32, rightFanStrength);517RSDK_EDITABLE_VAR(TurboTurtle, VAR_UINT32, rightFanLength);518}519520521