Path: blob/master/SonicMania/Objects/TMZ/TeeterTotter.c
338 views
// ---------------------------------------------------------------------1// RSDK Project: Sonic Mania2// Object Description: TeeterTotter Object3// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges4// Decompiled by: Rubberduckycooly & RMGRich5// ---------------------------------------------------------------------67#include "Game.h"89ObjectTeeterTotter *TeeterTotter;1011void TeeterTotter_Update(void)12{13RSDK_THIS(TeeterTotter);1415StateMachine_Run(self->state);1617RSDK.ProcessAnimation(&self->animator);18}1920void TeeterTotter_LateUpdate(void) {}2122void TeeterTotter_StaticUpdate(void) {}2324void TeeterTotter_Draw(void)25{26RSDK_THIS(TeeterTotter);2728int32 x = self->position.x;29int32 y = self->position.y;30int32 offsetX = 0x100000 - (self->length << 21) + x;3132for (uint32 i = 0; i < 2 * self->length; ++i) {33if (!((1 << i) & self->inactiveSegments)) {34Vector2 drawPos;35drawPos.x = (offsetX + (i << 21)) & 0xFFFF0000;36drawPos.y = (self->segmentPosition[i] + y) & 0xFFFF0000;3738RSDK.SetSpriteAnimation(TeeterTotter->aniFrames, 0, &self->animator, true, (i + self->color) % 2);3940RSDK.DrawSprite(&self->animator, &drawPos, false);41}42}43}4445void TeeterTotter_Create(void *data)46{47RSDK_THIS(TeeterTotter);4849self->length = CLAMP(self->length, 1, TEETERTOTTER_SEGMENT_COUNT / 2);50self->active = ACTIVE_BOUNDS;51self->drawGroup = Zone->objectDrawGroup[0];52self->origin = self->position;53self->updateRange.x = (self->length + 2) << 22;54self->visible = true;55self->drawFX = FX_FLIP;56self->updateRange.y = (self->length + 4) << 21;5758self->hitbox.left = -16;59self->hitbox.top = -16;60self->hitbox.right = 16;61self->hitbox.bottom = 16;6263self->state = TeeterTotter_State_Init;64}6566void TeeterTotter_StageLoad(void)67{68if (RSDK.CheckSceneFolder("TMZ1") || RSDK.CheckSceneFolder("TMZ2"))69TeeterTotter->aniFrames = RSDK.LoadSpriteAnimation("TMZ1/TeeterTotter.bin", SCOPE_STAGE);70}7172int32 TeeterTotter_CheckPlayerCollisions(void)73{74RSDK_THIS(TeeterTotter);7576int32 heaviestSegment = -1;77int32 stoodSegmentIDs[] = { -1, -1, -1, -1 };7879int32 storeX = self->position.x;80int32 storeY = self->position.y;8182int32 x = 0x100000 - (self->length << 21) + self->position.x;8384for (uint32 s = 0; s < 2 * self->length; ++s) {85if (!((1 << heaviestSegment) & self->inactiveSegments)) {86self->position.x = (x + (s << 21)) & 0xFFFF0000;87self->position.y = (self->segmentPosition[s] + storeY) & 0xFFFF0000;8889foreach_active(Player, player)90{91int32 playerID = RSDK.GetEntitySlot(player);92if (self->playerIDs[playerID] == (int32)s) {93player->position.y += self->segmentVelocity[s];94player->position.y += 0x10000;95}9697if (Player_CheckCollisionBox(player, self, &self->hitbox) == C_TOP) {98if (!player->sidekick)99heaviestSegment = s;100101stoodSegmentIDs[playerID] = s;102}103}104}105}106107self->position.x = storeX;108self->position.y = storeY;109110for (int32 i = 0; i < PLAYER_COUNT; ++i) self->playerIDs[i] = stoodSegmentIDs[i];111112return heaviestSegment;113}114115void TeeterTotter_ProcessSegmentGravity(void)116{117RSDK_THIS(TeeterTotter);118119int32 x = self->position.x;120int32 y = self->position.y;121int32 offsetX = x + (0x100000 - (self->length << 21));122123for (uint32 i = 0; i < 2 * self->length; ++i) {124if (!((1 << i) & self->inactiveSegments)) {125self->segmentVelocity[i] += 0x3800;126self->segmentPosition[i] += self->segmentVelocity[i];127128Vector2 segmentPos;129segmentPos.x = (offsetX + (i << 21)) & 0xFFFF0000;130segmentPos.y = (y + self->segmentPosition[i]) & 0xFFFF0000;131if (!RSDK.CheckPosOnScreen(&segmentPos, &self->updateRange))132self->inactiveSegments |= 1 << i;133}134}135}136137void TeeterTotter_HandleSegmentPositions(void)138{139RSDK_THIS(TeeterTotter);140141uint8 len = self->length;142for (uint32 i = 0; i < 2 * self->length; ++i) {143int8 pos = i - len;144if (pos >= 0)145pos++;146147self->segmentPosition[i] = (self->fallPos >> 1) * (int8)(2 * pos + 2 * ((int8)(2 * pos) <= 0) - 1);148}149}150151void TeeterTotter_State_Init(void)152{153RSDK_THIS(TeeterTotter);154155self->unused2 = 0;156self->fallPos = 0;157self->fallVelocity = 0;158159for (uint32 i = 0; i < 2 * self->length; ++i) {160self->segmentPosition[i] = 0;161self->segmentVelocity[i] = 0;162}163self->inactiveSegments = 0;164165self->visible = true;166self->active = ACTIVE_NORMAL;167self->state = TeeterTotter_State_Teeter;168}169170void TeeterTotter_State_Teeter(void)171{172RSDK_THIS(TeeterTotter);173174int32 prevVal[TEETERTOTTER_SEGMENT_COUNT];175for (uint32 i = 0; i < 2 * self->length; ++i) {176prevVal[i] = self->segmentPosition[i];177}178179TeeterTotter_HandleSegmentPositions();180181for (uint32 i = 0; i < 2 * self->length; ++i) {182self->segmentVelocity[i] = self->segmentPosition[i] - prevVal[i];183}184185int32 id = TeeterTotter_CheckPlayerCollisions();186if (id > -1) {187int32 segment = id - self->length;188if (segment >= 0)189++segment;190191self->fallVelocity += 32 * segment;192}193194self->fallPos += self->fallVelocity;195196if (abs(self->fallPos) > 0x200000)197self->state = TeeterTotter_State_Fall;198}199200void TeeterTotter_State_Fall(void)201{202RSDK_THIS(TeeterTotter);203204TeeterTotter_ProcessSegmentGravity();205206bool32 fullyInactive = true;207for (uint32 i = 0; i < 2 * self->length; ++i) fullyInactive &= ((1 << i) & self->inactiveSegments) != 0;208209if (fullyInactive || !(2 * self->length)) {210if (!RSDK.CheckOnScreen(self, NULL) && !RSDK.CheckPosOnScreen(&self->origin, &self->updateRange)) {211self->position = self->origin;212self->visible = false;213self->active = ACTIVE_BOUNDS;214self->state = TeeterTotter_State_Init;215}216}217}218219#if GAME_INCLUDE_EDITOR220void TeeterTotter_EditorDraw(void)221{222RSDK_THIS(TeeterTotter);223224self->length = CLAMP(self->length, 1, TEETERTOTTER_SEGMENT_COUNT / 2);225self->origin = self->position;226self->updateRange.x = (self->length + 2) << 22;227self->updateRange.y = (self->length + 4) << 21;228229TeeterTotter_Draw();230}231232void TeeterTotter_EditorLoad(void)233{234TeeterTotter->aniFrames = RSDK.LoadSpriteAnimation("TMZ1/TeeterTotter.bin", SCOPE_STAGE);235236RSDK_ACTIVE_VAR(TeeterTotter, color);237RSDK_ENUM_VAR("Orange, Blue", TEETERTOTTER_COLOR_ORANGEBLUE);238RSDK_ENUM_VAR("Blue, Orange", TEETERTOTTER_COLOR_BLUEORANGE);239}240#endif241242void TeeterTotter_Serialize(void)243{244RSDK_EDITABLE_VAR(TeeterTotter, VAR_UINT8, color);245RSDK_EDITABLE_VAR(TeeterTotter, VAR_UINT32, length);246}247248249