Path: blob/master/SonicMania/Objects/SSZ/Beanstalk.c
338 views
// ---------------------------------------------------------------------1// RSDK Project: Sonic Mania2// Object Description: Beanstalk Object3// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges4// Decompiled by: Rubberduckycooly & RMGRich5// ---------------------------------------------------------------------67#include "Game.h"89ObjectBeanstalk *Beanstalk;1011void Beanstalk_Update(void)12{13RSDK_THIS(Beanstalk);1415RSDK.ProcessAnimation(&self->nodeAnimator);1617if (self->type > BEANSTALK_NODE)18RSDK.ProcessAnimation(&self->plantAnimator);1920StateMachine_Run(self->state);21}2223void Beanstalk_LateUpdate(void) {}2425void Beanstalk_StaticUpdate(void) {}2627void Beanstalk_Draw(void)28{29RSDK_THIS(Beanstalk);3031if (self->shown) {32Beanstalk_DrawNodes();33Beanstalk_DrawCreationNode();3435self->scale.x = self->size;36self->scale.y = self->size;37self->drawFX = FX_SCALE | FX_FLIP;38RSDK.DrawSprite(&self->nodeAnimator, NULL, false);3940if (self->type > BEANSTALK_NODE)41RSDK.DrawSprite(&self->plantAnimator, NULL, false);4243self->drawFX = FX_FLIP;44self->scale.x = 0x200;45self->scale.y = 0x200;46}47}4849void Beanstalk_Create(void *data)50{51RSDK_THIS(Beanstalk);5253self->active = ACTIVE_BOUNDS;54self->visible = true;55self->drawFX = FX_FLIP;56self->drawGroup = Zone->objectDrawGroup[0];57self->bezCtrlAngle = self->bezCtrlAngle & 0xFF;5859self->updateRange.x = 0x1000000;60self->updateRange.y = 0x1000000;61self->curBezierPos = -1;62if (self->type == BEANSTALK_BEGIN) {63self->size = 512;64self->active = ACTIVE_NORMAL;65}66else {67self->size = 0;68}6970self->startPos = self->position;71self->platformPos = self->position;72self->stoodAngle = 0;73self->timer = 0;74self->chomperOffset = 0;75self->state = Beanstalk_State_Init;76}7778void Beanstalk_StageLoad(void)79{80Beanstalk->aniFrames = RSDK.LoadSpriteAnimation("SSZ1/Beanstalk.bin", SCOPE_STAGE);8182Beanstalk->sfxImpact = RSDK.GetSfx("Stage/Impact6.wav");83Beanstalk->sfxBeanNode = RSDK.GetSfx("SSZ1/BeanNode.wav");84Beanstalk->sfxBeanChomp = RSDK.GetSfx("SSZ1/BeanChomp.wav");8586Beanstalk->hitboxSeed.left = -1;87Beanstalk->hitboxSeed.top = -64;88Beanstalk->hitboxSeed.right = 1;89Beanstalk->hitboxSeed.bottom = 1;9091Beanstalk->hitboxPlatform.left = 0;92Beanstalk->hitboxPlatform.top = -3;93Beanstalk->hitboxPlatform.right = 46;94Beanstalk->hitboxPlatform.bottom = 13;9596Beanstalk->hitboxPlant.left = 8;97Beanstalk->hitboxPlant.top = -8;98Beanstalk->hitboxPlant.right = 44;99Beanstalk->hitboxPlant.bottom = 8;100}101102int32 Beanstalk_GetNextNodeDistance(void)103{104RSDK_THIS(Beanstalk);105106EntityBeanstalk *next = RSDK_GET_ENTITY(RSDK.GetEntitySlot(self) + 1, Beanstalk);107108if (self->forceEnd || next->classID != Beanstalk->classID)109return 0;110111int32 thisX = ((self->bezCtrlLength * RSDK.Cos256(self->bezCtrlAngle)) << 9) + self->position.x;112int32 thisY = ((self->bezCtrlLength * RSDK.Sin256(self->bezCtrlAngle)) << 9) + self->position.y;113114uint8 angle = (next->bezCtrlAngle + 0x80);115int32 nextX = ((next->bezCtrlLength * RSDK.Cos256(angle)) << 9) + next->position.x;116int32 nextY = ((next->bezCtrlLength * RSDK.Sin256(angle)) << 9) + next->position.y;117return MathHelpers_GetBezierCurveLength(self->position.x, self->position.y, thisX, thisY, nextX, nextY, next->position.x, next->position.y)118/ 0xA0000;119}120121int32 Beanstalk_GetRemainingDistance(void)122{123RSDK_THIS(Beanstalk);124125int32 len = 0;126while (self->type) {127EntityBeanstalk *prev = RSDK_GET_ENTITY(RSDK.GetEntitySlot(self) - 1, Beanstalk);128if (prev->classID != Beanstalk->classID)129break;130131int32 prevX = ((prev->bezCtrlLength * RSDK.Cos256(prev->bezCtrlAngle)) << 9) + prev->position.x;132int32 prevY = ((prev->bezCtrlLength * RSDK.Sin256(prev->bezCtrlAngle)) << 9) + prev->position.y;133134uint8 angle = (self->bezCtrlAngle + 0x80);135int32 thisX = ((self->bezCtrlLength * RSDK.Cos256(angle)) << 9) + self->position.x;136int32 thisY = ((self->bezCtrlLength * RSDK.Sin256(angle)) << 9) + self->position.y;137len += MathHelpers_GetBezierCurveLength(prev->position.x, prev->position.y, prevX, prevY, thisX, thisY, self->position.x, self->position.y);138139self = prev;140}141142return len;143}144145int32 Beanstalk_GetBezierInc(void)146{147RSDK_THIS(Beanstalk);148149EntityBeanstalk *next = RSDK_GET_ENTITY(RSDK.GetEntitySlot(self) + 1, Beanstalk);150151if (self->forceEnd || next->classID != Beanstalk->classID)152return 0;153154int32 thisX = ((self->bezCtrlLength * RSDK.Cos256(self->bezCtrlAngle)) << 9) + self->position.x;155int32 thisY = ((self->bezCtrlLength * RSDK.Sin256(self->bezCtrlAngle)) << 9) + self->position.y;156157uint8 angle = (next->bezCtrlAngle + 0x80);158int32 nextX = ((next->bezCtrlLength * RSDK.Cos256(angle)) << 9) + next->position.x;159int32 nextY = ((next->bezCtrlLength * RSDK.Sin256(angle)) << 9) + next->position.y;160return 0x10000161/ (MathHelpers_GetBezierCurveLength(self->position.x, self->position.y, thisX, thisY, nextX, nextY, next->position.x, next->position.y)162/ 0x32000);163}164165void Beanstalk_DrawNodes(void)166{167RSDK_THIS(Beanstalk);168169if (!self->forceEnd) {170EntityBeanstalk *next = RSDK_GET_ENTITY(RSDK.GetEntitySlot(self) + 1, Beanstalk);171172if (next->classID == Beanstalk->classID) {173if (SceneInfo->inEditor) {174self->curBezierPos = Beanstalk_GetNextNodeDistance();175self->bezierPos = 0x10000;176}177178if (self->curBezierPos == (uint16)-1)179self->curBezierPos = Beanstalk_GetNextNodeDistance();180181if (self->curBezierPos) {182if (!self->setupDecorNodeID || SceneInfo->inEditor) {183int32 distance = Beanstalk_GetRemainingDistance();184self->setupDecorNodeID = true;185self->curDecorID = (distance / 0xA0000 / 3) % 9;186self->curNodeID = 3 * ((distance / 0xA0000 / 3) + 1) - distance / 0xA0000;187}188189int32 thisX = self->position.x + ((self->bezCtrlLength * RSDK.Cos256(self->bezCtrlAngle + 0x00)) << 9);190int32 thisY = self->position.y + ((self->bezCtrlLength * RSDK.Sin256(self->bezCtrlAngle + 0x00)) << 9);191int32 nextX = next->position.x + ((next->bezCtrlLength * RSDK.Cos256(next->bezCtrlAngle + 0x80)) << 9);192int32 nextY = next->position.y + ((next->bezCtrlLength * RSDK.Sin256(next->bezCtrlAngle + 0x80)) << 9);193194int32 bezInc = 0x10000 / self->curBezierPos;195196RSDK.SetSpriteAnimation(Beanstalk->aniFrames, 1, &self->fillerAnimator, true, 0);197for (int32 bezPos = (0x10000 / self->curBezierPos) >> 1; bezPos <= 0x10000; bezPos += bezInc) {198if (bezPos >= self->bezierPos)199break;200201Vector2 drawPos = MathHelpers_GetBezierPoint(bezPos, self->position.x, self->position.y, thisX, thisY, nextX, nextY,202next->position.x, next->position.y);203204RSDK.DrawSprite(&self->fillerAnimator, &drawPos, false);205}206207int32 nodeID = self->curNodeID;208int32 decorID = self->curDecorID;209for (int32 bezPos = (0x10000 / self->curBezierPos) >> 1; bezPos <= 0x10000; ++nodeID) {210if (bezPos >= self->bezierPos)211break;212213Vector2 drawPos = MathHelpers_GetBezierPoint(bezPos, self->position.x, self->position.y, thisX, thisY, nextX, nextY,214next->position.x, next->position.y);215216if (!(nodeID % 3)) {217RSDK.SetSpriteAnimation(Beanstalk->aniFrames, decorID + 5, &self->fillerAnimator, true, 0);218RSDK.DrawSprite(&self->fillerAnimator, &drawPos, false);219220decorID = (decorID + 1) % 9;221}222223bezPos += bezInc;224}225}226}227}228}229230void Beanstalk_DrawCreationNode(void)231{232RSDK_THIS(Beanstalk);233234// Draw the node that "walks" along the path and "creates" the beanstalk behind it235if (!self->forceEnd) {236EntityBeanstalk *next = RSDK_GET_ENTITY(RSDK.GetEntitySlot(self) + 1, Beanstalk);237238if (next->classID == Beanstalk->classID) {239if (self->curBezierPos) {240int32 thisX = self->position.x + ((self->bezCtrlLength * RSDK.Cos256(self->bezCtrlAngle + 0x00)) << 9);241int32 thisY = self->position.y + ((self->bezCtrlLength * RSDK.Sin256(self->bezCtrlAngle + 0x00)) << 9);242int32 nextX = next->position.x + ((next->bezCtrlLength * RSDK.Cos256(next->bezCtrlAngle + 0x80)) << 9);243int32 nextY = next->position.y + ((next->bezCtrlLength * RSDK.Sin256(next->bezCtrlAngle + 0x80)) << 9);244245Vector2 drawPos = MathHelpers_GetBezierPoint(self->bezierPos, self->position.x, self->position.y, thisX, thisY, nextX, nextY,246next->position.x, next->position.y);247RSDK.SetSpriteAnimation(Beanstalk->aniFrames, 1, &self->fillerAnimator, true, 0);248RSDK.DrawSprite(&self->fillerAnimator, &drawPos, false);249}250}251}252}253254void Beanstalk_HandleNodeMovement(void)255{256RSDK_THIS(Beanstalk);257258if (!self->finished) {259EntityBeanstalk *node = NULL;260261if (!self->forceEnd) {262node = RSDK_GET_ENTITY(RSDK.GetEntitySlot(self) + 1, Beanstalk);263if (node->classID != Beanstalk->classID)264node = NULL;265}266267if (self->forceEnd || !node)268self->bezierPos = 0x10000;269270if (self->bezierPos < 0x10000) {271if (!self->bezierInc)272self->bezierInc = Beanstalk_GetBezierInc();273274self->bezierPos += self->bezierInc;275}276277if (self->bezierPos > 0x10000)278self->bezierPos = 0x10000;279280if (self->bezierPos == 0x10000) {281self->finished = true;282self->active = ACTIVE_BOUNDS;283284if (node) {285node->shown = true;286node->active = ACTIVE_NORMAL;287}288}289}290}291292void Beanstalk_HandleNodeAppear(void)293{294RSDK_THIS(Beanstalk);295296self->size = (self->timer << 9) / 20;297if (self->timer < 20) {298if (!self->timer) {299if (RSDK.CheckOnScreen(self, NULL))300RSDK.PlaySfx(Beanstalk->sfxBeanNode, false, 255);301}302303++self->timer;304}305}306307void Beanstalk_CheckPlayerCollisions_Platform(void)308{309RSDK_THIS(Beanstalk);310311int32 storeX = self->position.x;312int32 storeY = self->position.y;313314self->position = self->platformPos;315self->position.x = ((RSDK.Sin512(2 * self->moveAngle) << 9) + self->position.x) & 0xFFFF0000;316self->position.y &= 0xFFFF0000;317318if (!self->activePlayers) {319if (self->stoodAngle > 0)320self->stoodAngle -= 4;321}322else {323if (self->stoodAngle < 64)324self->stoodAngle += 4;325}326327self->activePlayers = 0;328foreach_active(Player, player)329{330int32 playerID = RSDK.GetEntitySlot(player);331if (Player_CheckCollisionPlatform(player, self, &Beanstalk->hitboxPlatform)) {332player->position.x += self->position.x - storeX;333334if (self->position.y - storeY > 0)335player->position.y += self->position.y - storeY;336337player->position.y += 0x10000;338player->position.y &= 0xFFFF0000;339self->activePlayers |= 1 << playerID;340}341}342343self->platformPos.x = self->startPos.x;344self->platformPos.y = self->startPos.y + (RSDK.Sin256(self->stoodAngle) << 10);345}346347void Beanstalk_CheckPlayerCollisions_Chomper(void)348{349RSDK_THIS(Beanstalk);350351int32 mult = 0;352if (self->chomperOffset >= 15) {353if (self->chomperOffset >= 60) {354self->chomperOffset = 0;355}356else {357mult = 0x15540 - 0x5B0 * self->chomperOffset;358self->chomperOffset++;359}360}361else {362mult = 0x1111 * self->chomperOffset;363self->chomperOffset++;364}365366self->position = self->startPos;367if (self->direction == FLIP_X)368self->position.x += mult * -16;369else370self->position.x += mult * 16;371372foreach_active(Player, player)373{374if (Player_CheckCollisionTouch(player, self, &Beanstalk->hitboxPlant)) {375#if MANIA_USE_PLUS376if (player->state == Player_State_MightyHammerDrop) {377CREATE_ENTITY(Explosion, INT_TO_VOID(EXPLOSION_ENEMY), self->position.x, self->position.y)->drawGroup = Zone->objectDrawGroup[1];378RSDK.PlaySfx(Explosion->sfxDestroy, false, 255);379self->state = Beanstalk_State_Node;380RSDK.SetSpriteAnimation(Beanstalk->aniFrames, 0, &self->plantAnimator, true, 0);381}382else if (!Player_CheckMightyUnspin(player, 0x400, 2, &player->uncurlTimer)) {383#endif384Player_Hurt(player, self);385#if MANIA_USE_PLUS386}387#endif388}389}390}391392void Beanstalk_State_Init(void)393{394RSDK_THIS(Beanstalk);395396switch (self->type) {397case BEANSTALK_BEGIN:398RSDK.SetSpriteAnimation(Beanstalk->aniFrames, 4, &self->nodeAnimator, true, 9);399self->state = Beanstalk_StateDirt_WaitForStart;400break;401402case BEANSTALK_NODE:403RSDK.SetSpriteAnimation(Beanstalk->aniFrames, 0, &self->nodeAnimator, true, 0);404self->state = Beanstalk_State_Node;405break;406407case BEANSTALK_PLATFORM:408RSDK.SetSpriteAnimation(Beanstalk->aniFrames, 0, &self->nodeAnimator, true, 0);409RSDK.SetSpriteAnimation(Beanstalk->aniFrames, 2, &self->plantAnimator, true, 0);410self->state = Beanstalk_State_Platform;411break;412413case BEANSTALK_CHOMPER:414RSDK.SetSpriteAnimation(Beanstalk->aniFrames, 0, &self->nodeAnimator, true, 0);415RSDK.SetSpriteAnimation(Beanstalk->aniFrames, 3, &self->plantAnimator, true, 0);416self->state = Beanstalk_State_Chomper;417break;418419default: break;420}421}422423void Beanstalk_StateDirt_WaitForStart(void)424{425RSDK_THIS(Beanstalk);426427if (self->startGrowth) {428self->state = Beanstalk_StateDirt_GrowthDelay;429self->timer = 15;430}431}432433void Beanstalk_StateDirt_GrowthDelay(void)434{435RSDK_THIS(Beanstalk);436437if (self->timer <= 0) {438RSDK.PlaySfx(Beanstalk->sfxImpact, false, 255);439Camera_ShakeScreen(0, 0, 5);440441RSDK.SetSpriteAnimation(Beanstalk->aniFrames, 4, &self->nodeAnimator, true, 0);442self->shown = true;443self->active = ACTIVE_NORMAL;444self->state = Beanstalk_StateDirt_Grow;445}446else {447self->timer--;448}449}450451void Beanstalk_StateDirt_Grow(void) { Beanstalk_HandleNodeMovement(); }452453void Beanstalk_State_Node(void)454{455RSDK_THIS(Beanstalk);456457if (self->shown) {458Beanstalk_HandleNodeMovement();459Beanstalk_HandleNodeAppear();460461self->position = self->startPos;462self->position.x = ((RSDK.Sin512(2 * self->moveAngle) << 9) + self->position.x) & 0xFFFF0000;463self->position.y &= 0xFFFF0000;464465++self->moveAngle;466}467}468469void Beanstalk_State_Platform(void)470{471RSDK_THIS(Beanstalk);472473if (self->shown) {474Beanstalk_HandleNodeMovement();475Beanstalk_HandleNodeAppear();476477Beanstalk_CheckPlayerCollisions_Platform();478479++self->moveAngle;480}481}482483void Beanstalk_State_Chomper(void)484{485RSDK_THIS(Beanstalk);486487if (self->shown) {488Beanstalk_HandleNodeMovement();489Beanstalk_HandleNodeAppear();490491Beanstalk_CheckPlayerCollisions_Chomper();492493if (RSDK.CheckOnScreen(self, NULL)) {494if (self->plantAnimator.frameID == 5 && self->plantAnimator.timer == 1)495RSDK.PlaySfx(Beanstalk->sfxBeanChomp, false, 255);496}497}498}499500#if GAME_INCLUDE_EDITOR501void Beanstalk_EditorDraw(void)502{503RSDK_THIS(Beanstalk);504505self->bezCtrlAngle &= 0xFF;506self->curBezierPos = -1;507self->size = 0x200;508self->startPos = self->position;509self->platformPos = self->position;510self->stoodAngle = 0;511self->timer = 0;512self->chomperOffset = 0;513514switch (self->type) {515case BEANSTALK_BEGIN: RSDK.SetSpriteAnimation(Beanstalk->aniFrames, 4, &self->nodeAnimator, true, 9); break;516517case BEANSTALK_NODE: RSDK.SetSpriteAnimation(Beanstalk->aniFrames, 0, &self->nodeAnimator, true, 0); break;518519case BEANSTALK_PLATFORM:520RSDK.SetSpriteAnimation(Beanstalk->aniFrames, 0, &self->nodeAnimator, true, 0);521RSDK.SetSpriteAnimation(Beanstalk->aniFrames, 2, &self->plantAnimator, true, 0);522break;523524case BEANSTALK_CHOMPER:525RSDK.SetSpriteAnimation(Beanstalk->aniFrames, 0, &self->nodeAnimator, true, 0);526RSDK.SetSpriteAnimation(Beanstalk->aniFrames, 3, &self->plantAnimator, true, 0);527break;528529default: break;530}531532RSDK_DRAWING_OVERLAY(true);533Beanstalk_DrawNodes();534RSDK_DRAWING_OVERLAY(false);535536self->scale.x = self->size;537self->scale.y = self->size;538self->drawFX = FX_SCALE | FX_FLIP;539RSDK.DrawSprite(&self->nodeAnimator, NULL, false);540541if (self->type > BEANSTALK_NODE)542RSDK.DrawSprite(&self->plantAnimator, NULL, false);543544self->drawFX = FX_FLIP;545self->scale.x = 0x200;546self->scale.y = 0x200;547}548549void Beanstalk_EditorLoad(void)550{551Beanstalk->aniFrames = RSDK.LoadSpriteAnimation("SSZ1/Beanstalk.bin", SCOPE_STAGE);552553RSDK_ACTIVE_VAR(Beanstalk, type);554RSDK_ENUM_VAR("Dirt Splash", BEANSTALK_BEGIN);555RSDK_ENUM_VAR("Node", BEANSTALK_NODE);556RSDK_ENUM_VAR("Platform", BEANSTALK_PLATFORM);557RSDK_ENUM_VAR("Chomper", BEANSTALK_CHOMPER);558559RSDK_ACTIVE_VAR(Beanstalk, direction);560RSDK_ENUM_VAR("Right", FLIP_NONE);561RSDK_ENUM_VAR("Left", FLIP_X);562}563#endif564565void Beanstalk_Serialize(void)566{567RSDK_EDITABLE_VAR(Beanstalk, VAR_UINT8, type);568RSDK_EDITABLE_VAR(Beanstalk, VAR_UINT8, direction);569RSDK_EDITABLE_VAR(Beanstalk, VAR_INT32, bezCtrlAngle);570RSDK_EDITABLE_VAR(Beanstalk, VAR_INT32, bezCtrlLength);571RSDK_EDITABLE_VAR(Beanstalk, VAR_BOOL, forceEnd);572}573574575