Path: blob/master/SonicMania/Objects/CPZ/DNARiser.c
338 views
// ---------------------------------------------------------------------1// RSDK Project: Sonic Mania2// Object Description: DNARiser Object3// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges4// Decompiled by: Rubberduckycooly & RMGRich5// ---------------------------------------------------------------------67#include "Game.h"89ObjectDNARiser *DNARiser;1011void DNARiser_Update(void)12{13RSDK_THIS(DNARiser);1415if (self->scaleTimer)16self->scaleTimer--;1718if (self->sfxTimer > 0)19self->sfxTimer--;2021StateMachine_Run(self->state);2223if (self->popped) {24if (self->popAnimator.frameID == self->popAnimator.loopIndex)25self->popped = false;26else27RSDK.ProcessAnimation(&self->popAnimator);28}29}3031void DNARiser_LateUpdate(void) {}3233void DNARiser_StaticUpdate(void)34{35foreach_active(DNARiser, entity) { RSDK.AddDrawListRef(Zone->objectDrawGroup[1], RSDK.GetEntitySlot(entity)); }36}3738void DNARiser_Draw(void)39{40RSDK_THIS(DNARiser);4142StateMachine_Run(self->stateDraw);43}4445void DNARiser_Create(void *data)46{47RSDK_THIS(DNARiser);48self->visible = true;49self->active = ACTIVE_BOUNDS;50self->drawGroup = Zone->objectDrawGroup[0] + 1;51self->amplitude = 0x2E0000;5253if (SceneInfo->inEditor) {54self->speed.x = 0;55if (!self->speed.y)56self->speed.y = 0x60000;57if (!self->height)58self->height = 128;59}6061self->updateRange.x = 0x800000;62self->updateRange.y = 0x800000;63self->state = DNARiser_State_Init;64}6566void DNARiser_StageLoad(void)67{68DNARiser->aniFrames = RSDK.LoadSpriteAnimation("CPZ/DNARiser.bin", SCOPE_STAGE);6970DNARiser->hitbox.top = -16;71DNARiser->hitbox.bottom = 16;72DNARiser->hitbox.left = -16;73DNARiser->hitbox.right = 16;7475DNARiser->active = ACTIVE_ALWAYS;7677DNARiser->sfxBurst = RSDK.GetSfx("CPZ/DNABurst.wav");78DNARiser->sfxGrab = RSDK.GetSfx("CPZ/DNAGrab.wav");79DNARiser->sfxScan = RSDK.GetSfx("CPZ/DNAScan.wav");80DNARiser->sfxTiny[0] = RSDK.GetSfx("CPZ/DNATiny0.wav");81DNARiser->sfxTiny[1] = RSDK.GetSfx("CPZ/DNATiny1.wav");82DNARiser->sfxTiny[2] = RSDK.GetSfx("CPZ/DNATiny2.wav");83DNARiser->sfxTiny[3] = RSDK.GetSfx("CPZ/DNATiny3.wav");84DNARiser->sfxTiny[4] = RSDK.GetSfx("CPZ/DNATiny4.wav");85DNARiser->sfxTiny[5] = RSDK.GetSfx("CPZ/DNATiny5.wav");86}8788void DNARiser_State_BubbleBurst(void)89{90RSDK_THIS(DNARiser);9192RSDK.PlaySfx(DNARiser->sfxBurst, false, 255);9394self->popPos = self->position;95self->popped = true;96RSDK.SetSpriteAnimation(DNARiser->aniFrames, 5, &self->popAnimator, true, 0);97}9899void DNARiser_SetupBurst(void)100{101RSDK_THIS(DNARiser);102103DNARiser_State_BubbleBurst();104105self->maxSpeed = self->speed;106self->noBubbleScaling = true;107self->velocity.x = 0;108self->velocity.y = 0;109self->state = DNARiser_State_HelixBurst;110self->timer = 0;111}112113Vector2 DNARiser_CalculateScale(Vector2 *scalePtr)114{115RSDK_THIS(DNARiser);116117Vector2 scale;118int32 x = 0x200;119int32 y = 0x200;120if (scalePtr) {121x = scalePtr->x;122y = scalePtr->y;123}124125int32 timer = (30 - self->scaleTimer);126int32 sine = RSDK.Sin1024(((timer * (0x40000000 / ((10983 * timer + 286520) >> 7))) >> 11) & 0x3FF);127scale.x = (((timer - 30) * (sine << 6) / 100 + 0x10000) * x) >> 16;128scale.y = (((30 - timer) * (sine << 6) / 100 + 0x10000) * y) >> 16;129return scale;130}131132void DNARiser_State_Init(void)133{134RSDK_THIS(DNARiser);135136self->startPos = self->position;137self->active = ACTIVE_BOUNDS;138self->speed.x = 0;139self->velocity.x = 0;140self->speed.y = -abs(self->speed.y);141self->timer = 0;142self->risePos = 0;143self->canDestroySelf = false;144self->firstChild = NULL;145self->child = 0;146self->helixPos = 0;147self->activePlayers = 0;148self->noBubbleScaling = false;149self->lastSfxID = 0;150self->sfxTimer = 0;151self->scanSfxDir = 0;152self->velocity.y = 0;153self->stateDraw = DNARiser_Draw_Main;154self->state = DNARiser_State_HandleInteractions;155self->bubbleScale = 0x200;156RSDK.SetSpriteAnimation(DNARiser->aniFrames, 0, &self->bubbleAnimator, true, 0);157DNARiser_State_HandleInteractions();158}159160void DNARiser_State_HandleInteractions(void)161{162RSDK_THIS(DNARiser);163164foreach_active(Player, player)165{166int32 playerID = RSDK.GetEntitySlot(player);167168if (!((1 << playerID) & self->activePlayers)) {169if (Player_CheckCollisionTouch(player, self, &DNARiser->hitbox)) {170RSDK.PlaySfx(DNARiser->sfxGrab, false, 255);171self->scaleTimer = 30;172self->sfxTimer = 30;173RSDK.SetSpriteAnimation(player->aniFrames, ANI_JUMP, &player->animator, false, 0);174player->groundVel = 0;175player->drawGroup = 1;176player->jumpAbilityState = 1;177player->onGround = false;178player->tileCollisions = TILECOLLISION_NONE;179player->state = Player_State_Static;180player->nextAirState = StateMachine_None;181player->nextGroundState = StateMachine_None;182self->activePlayers |= 1 << playerID;183}184}185186if (((1 << playerID) & self->activePlayers)) {187if (player->state == Player_State_Static) {188player->position.x = self->position.x;189player->position.y = self->position.y;190player->velocity.x = 0;191player->velocity.y = 0;192if (!player->sidekick) {193self->risePos = 0;194self->active = ACTIVE_NORMAL;195self->state = DNARiser_State_HelixRise;196}197}198else {199self->activePlayers &= ~(1 << playerID);200}201}202}203}204205void DNARiser_State_HelixRise(void)206{207RSDK_THIS(DNARiser);208if (self->risePos >= self->height << 16) {209DNARiser_SetupBurst();210}211else {212if (self->velocity.y >= abs(self->speed.y))213self->velocity.y = abs(self->speed.y);214else215self->velocity.y += 0x1200;216217self->risePos += self->velocity.y;218if (self->height << 16 < self->risePos)219self->risePos = self->height << 16;220221int32 angle = (((0x57262 * (self->risePos >> 16)) >> 16) + 250) & 0x3FF;222if (angle >= 0x200 && !self->scanSfxDir) {223self->scanSfxDir = 1;224RSDK.PlaySfx(DNARiser->sfxScan, false, 255);225}226else if (angle <= 0x1FF && self->scanSfxDir) {227self->scanSfxDir = 0;228RSDK.PlaySfx(DNARiser->sfxScan, false, 255);229}230231self->position.y = self->startPos.y - self->risePos;232for (; self->helixPos <= (self->risePos >> 18) + 1; ++self->helixPos) {233if (!(self->helixPos & 1) || !(self->helixPos % 5)) {234if (!self->sfxTimer) {235int32 sfxID = 0;236if (!self->lastSfxID) {237while (sfxID == self->lastSfxID) sfxID = ZONE_RAND(0, 5);238}239240RSDK.PlaySfx(DNARiser->sfxTiny[sfxID], false, 255);241self->lastSfxID = sfxID;242self->sfxTimer = ZONE_RAND(2, 8);243}244245EntityDNARiser *child = CREATE_ENTITY(DNARiser, self, self->startPos.x, self->startPos.y - (self->helixPos << 18));246child->state = DNARiser_State_OrbSetup;247child->active = ACTIVE_NORMAL;248child->startHelixPos = self->helixPos;249child->parent = self;250child->angle = (((0x57262 * (4 * self->helixPos)) >> 16) + 100) & 0x3FF;251child->amplitude = 0x2E0000;252child->drawGroup = self->drawGroup - 1;253if (!self->firstChild)254self->firstChild = child;255256if (self->child) {257child->lastChild = self->child;258self->child->sibling = child;259}260self->child = child;261}262}263}264265bool32 popped = false;266self->bubbleScale = (0x10000 - 85 * ((self->risePos / self->height) >> 8)) >> 7;267268foreach_active(Player, player)269{270int32 playerID = RSDK.GetEntitySlot(player);271if (!((1 << playerID) & self->activePlayers)) {272if (Player_CheckCollisionTouch(player, self, &DNARiser->hitbox)) {273RSDK.PlaySfx(DNARiser->sfxGrab, false, 255);274self->sfxTimer = 30;275self->scaleTimer = 30;276self->activePlayers |= (1 << playerID);277}278}279280if ((1 << playerID) & self->activePlayers) {281bool32 playerActive = false;282if (!Player_CheckValidState(player)) {283self->activePlayers &= ~(1 << playerID);284if (self->activePlayers)285playerActive = true;286else287DNARiser_SetupBurst();288}289290if (!playerActive) {291if (player->jumpPress) {292player->velocity.y = 0;293player->velocity.x = 0;294Player_Action_Jump(player);295DNARiser_SetupBurst();296}297298if (self->state == DNARiser_State_HelixBurst) {299popped = true;300}301else {302RSDK.SetSpriteAnimation(player->aniFrames, ANI_JUMP, &player->animator, false, 0);303player->groundVel = 0;304player->drawGroup = 1;305player->jumpAbilityState = 1;306player->onGround = false;307player->tileCollisions = TILECOLLISION_NONE;308player->state = Player_State_Static;309player->nextAirState = StateMachine_None;310player->nextGroundState = StateMachine_None;311player->velocity.x = 0;312player->velocity.y = -self->velocity.y;313player->position.x = self->position.x;314player->position.y = self->position.y;315}316}317}318}319320if (popped) {321foreach_active(Player, playerPtr)322{323int32 playerID = RSDK.GetEntitySlot(playerPtr);324if (((1 << playerID) & self->activePlayers)) {325playerPtr->drawGroup = Zone->playerDrawGroup[0];326playerPtr->tileCollisions = TILECOLLISION_DOWN;327playerPtr->state = Player_State_Air;328playerPtr->velocity.x = self->speed.x;329playerPtr->velocity.y = self->speed.y;330self->activePlayers &= ~(1 << playerID);331}332}333}334}335336void DNARiser_State_HelixBurst(void)337{338RSDK_THIS(DNARiser);339340if (self->timer <= 0) {341if (!self->timer) {342if (!self->canDestroySelf) {343EntityDNARiser *child = self->child;344if (child) {345self->canDestroySelf = true;346child->timer = 0;347child->velocity.x = 0;348child->state = DNARiser_State_OrbFall;349child->velocity.y = self->maxSpeed.y >> 1;350child->maxSpeed.y = self->maxSpeed.y >> 1;351}352}353if (self->position.y < self->startPos.y) {354self->velocity.y += 0x38000;355self->position.y += self->velocity.y;356}357358int32 posY = self->startPos.y;359if (self->position.y < self->startPos.y)360posY = self->position.y;361362self->position.y = posY;363self->risePos = self->startPos.y - posY;364if (posY == self->startPos.y) {365self->state = DNARiser_State_ResetRiser;366self->timer = 60;367}368}369}370else {371self->timer--;372}373}374375void DNARiser_State_ResetRiser(void)376{377RSDK_THIS(DNARiser);378379if (!self->firstChild) {380if (self->timer <= 0) {381if (RSDK.CheckOnScreen(self, &self->updateRange)) {382DNARiser_State_BubbleBurst();383DNARiser_State_Init();384self->scaleTimer = 30;385}386else {387self->state = DNARiser_State_Init;388}389}390else {391self->timer--;392}393}394}395396void DNARiser_State_OrbSetup(void)397{398RSDK_THIS(DNARiser);399400self->active = ACTIVE_NORMAL;401self->stateDraw = DNARiser_Draw_Helix;402self->state = DNARiser_State_OrbIdle;403}404405void DNARiser_State_OrbIdle(void)406{407// 20220614 rdc said i could come back and comment these >:]408}409410void DNARiser_State_OrbFall(void)411{412RSDK_THIS(DNARiser);413EntityDNARiser *parent = self->parent;414415if (self->timer <= 0) {416if (self->canDestroySelf) {417if (!RSDK.CheckOnScreen(self, &self->updateRange))418destroyEntity(self);419}420else {421EntityDNARiser *child = self->lastChild;422self->canDestroySelf = true;423if (child) {424while (true) {425if (RSDK.CheckOnScreen(child, &child->updateRange)) {426child->velocity.y = 0;427child->timer = 1;428child->state = DNARiser_State_OrbFall;429child->velocity.x = 0;430child->velocity.y = (self->maxSpeed.y >> 1) + (self->maxSpeed.y >> 2);431child->maxSpeed.y = (self->maxSpeed.y >> 1) + (self->maxSpeed.y >> 2);432break;433}434else {435EntityDNARiser *grandChild = child->lastChild;436437if (child == parent->child)438parent->child = grandChild;439destroyEntity(child);440441child = grandChild;442if (!grandChild)443break;444}445}446}447448if (!child)449parent->firstChild = NULL;450451if (self->canDestroySelf) {452if (!RSDK.CheckOnScreen(self, &self->updateRange))453destroyEntity(self);454}455}456}457else {458self->timer--;459}460461self->velocity.y += 0x3800;462self->position.y += self->velocity.y;463self->amplitude += 0x20000;464}465466void DNARiser_Draw_Main(void)467{468RSDK_THIS(DNARiser);469470bool32 isYellowBig = false;471int32 angle = ((0x57262 * (self->risePos >> 16)) >> 16) + 100;472473Animator orbAnimator;474memset(&orbAnimator, 0, sizeof(orbAnimator));475if ((uint32)((angle & 0x3FF) - 0x100) <= 0x200)476isYellowBig = true;477478int32 sineOff = (RSDK.Sin1024(angle & 0x3FF) << 6) * (self->amplitude >> 16);479self->alpha = 0x100;480self->inkEffect = INK_NONE;481482Vector2 drawPos;483drawPos = self->position;484485self->scale.x = 0x200;486self->scale.y = 0x200;487self->drawFX = FX_NONE;488if (SceneInfo->currentDrawGroup == Zone->objectDrawGroup[1]) {489if (isYellowBig) {490drawPos.x = sineOff + self->position.x;491drawPos.y = self->position.y;492RSDK.SetSpriteAnimation(DNARiser->aniFrames, 4, &orbAnimator, true, 0);493}494else {495drawPos.x = self->position.x - sineOff;496drawPos.y = self->position.y;497RSDK.SetSpriteAnimation(DNARiser->aniFrames, 2, &orbAnimator, true, 0);498}499500RSDK.DrawSprite(&orbAnimator, &drawPos, false);501if (!self->noBubbleScaling) {502drawPos = self->position;503self->drawFX = FX_SCALE;504self->inkEffect = INK_BLEND;505self->alpha = 0x80;506Vector2 scale;507scale.x = self->bubbleScale;508scale.y = self->bubbleScale;509self->scale = DNARiser_CalculateScale(&scale);510RSDK.DrawSprite(&self->bubbleAnimator, &drawPos, false);511}512513if (self->popped) {514drawPos = self->popPos;515self->scale.x = 0x200;516self->scale.y = 0x200;517self->drawFX = FX_NONE;518self->inkEffect = INK_NONE;519RSDK.DrawSprite(&self->popAnimator, &drawPos, false);520}521}522else {523if (isYellowBig) {524drawPos.y = self->position.y;525drawPos.x = self->position.x - sineOff;526RSDK.SetSpriteAnimation(DNARiser->aniFrames, 2, &orbAnimator, true, 0);527}528else {529drawPos.x = sineOff + self->position.x;530drawPos.y = self->position.y;531RSDK.SetSpriteAnimation(DNARiser->aniFrames, 4, &orbAnimator, true, 0);532}533RSDK.DrawSprite(&orbAnimator, &drawPos, false);534}535}536537void DNARiser_Draw_Helix(void)538{539RSDK_THIS(DNARiser);540541bool32 isYellowBig = false;542EntityDNARiser *parent = self->parent;543544Animator orbAnimator;545memset(&orbAnimator, 0, sizeof(orbAnimator));546if ((uint32)(self->angle - 0x100) <= 0x200)547isYellowBig = true;548549int32 sineOff = (RSDK.Sin1024(self->angle) << 6) * (self->amplitude >> 16);550self->alpha = 0x100;551self->inkEffect = INK_NONE;552553Vector2 drawPos;554drawPos = self->position;555556self->scale.x = 0x200;557self->scale.y = 0x200;558self->drawFX = FX_NONE;559self->drawFX = INK_NONE;560if (SceneInfo->currentDrawGroup != Zone->objectDrawGroup[1] && !(self->startHelixPos & 1)) {561if (isYellowBig) {562drawPos.x = self->position.x - sineOff;563drawPos.y = self->position.y;564RSDK.SetSpriteAnimation(DNARiser->aniFrames, 2, &orbAnimator, true, 0);565}566else {567drawPos.x = self->position.x + sineOff;568drawPos.y = self->position.y;569RSDK.SetSpriteAnimation(DNARiser->aniFrames, 4, &orbAnimator, true, 0);570}571RSDK.DrawSprite(&orbAnimator, &drawPos, false);572}573574if (!(self->startHelixPos % 5)) {575int32 distance = (parent->helixPos - self->startHelixPos >= 8) ? 4 : ((parent->helixPos - self->startHelixPos) / 2);576int32 sine = (RSDK.Sin1024(self->angle) << 6) * ((self->amplitude >> 16) - 12);577drawPos.y = self->position.y;578if (isYellowBig)579drawPos.x = self->position.x - sine;580else581drawPos.x = self->position.x + sine;582int32 startX = drawPos.x;583sine = 2 * sine / 7;584585bool32 drawFlags[8];586drawFlags[0] = distance >= 1;587drawFlags[1] = distance >= 2;588drawFlags[2] = distance >= 3;589drawFlags[3] = distance >= 4;590drawFlags[4] = drawFlags[3];591drawFlags[5] = drawFlags[2];592drawFlags[6] = drawFlags[1];593drawFlags[7] = drawFlags[0];594595for (int32 i = 0; i < 8; ++i) {596bool32 isYellowSmall = (isYellowBig && i <= 3) || (!isYellowBig && i >= 4);597bool32 canDraw = SceneInfo->currentDrawGroup == Zone->objectDrawGroup[1]598? ((isYellowBig && !isYellowSmall) || (!isYellowBig && isYellowSmall))599: ((isYellowBig && isYellowSmall) || (!isYellowBig && !isYellowSmall));600601if (drawFlags[i] && canDraw) {602if (!isYellowSmall)603RSDK.SetSpriteAnimation(DNARiser->aniFrames, 3, &orbAnimator, true, 0);604else605RSDK.SetSpriteAnimation(DNARiser->aniFrames, 1, &orbAnimator, true, 0);606drawPos.x = startX + sine * i * (2 * isYellowBig - 1);607RSDK.DrawSprite(&orbAnimator, &drawPos, false);608}609}610}611612if (SceneInfo->currentDrawGroup == Zone->objectDrawGroup[1] && !(self->startHelixPos & 1)) {613if (isYellowBig) {614drawPos.x = self->position.x + sineOff;615drawPos.y = self->position.y;616RSDK.SetSpriteAnimation(DNARiser->aniFrames, 4, &orbAnimator, true, 0);617}618else {619drawPos.x = self->position.x - sineOff;620drawPos.y = self->position.y;621RSDK.SetSpriteAnimation(DNARiser->aniFrames, 2, &orbAnimator, true, 0);622}623RSDK.DrawSprite(&orbAnimator, &drawPos, false);624}625}626627#if GAME_INCLUDE_EDITOR628void DNARiser_EditorDraw(void)629{630RSDK_THIS(DNARiser);631632self->startPos = self->position;633self->active = ACTIVE_BOUNDS;634self->speed.x = 0;635self->velocity.x = 0;636self->speed.y = -abs(self->speed.y);637self->timer = 0;638self->risePos = self->height << 16;639self->canDestroySelf = false;640self->firstChild = NULL;641self->child = 0;642self->helixPos = 0;643self->activePlayers = 0;644self->noBubbleScaling = false;645self->lastSfxID = 0;646self->sfxTimer = 0;647self->scanSfxDir = 0;648self->velocity.y = 0;649self->bubbleScale = 0x200;650RSDK.SetSpriteAnimation(DNARiser->aniFrames, 0, &self->bubbleAnimator, true, 0);651652int32 group = SceneInfo->currentDrawGroup;653654SceneInfo->currentDrawGroup = -1;655DNARiser_Draw_Main();656657SceneInfo->currentDrawGroup = Zone->objectDrawGroup[1];658DNARiser_Draw_Main();659660SceneInfo->currentDrawGroup = group;661662if (showGizmos()) {663RSDK_DRAWING_OVERLAY(true);664665Vector2 drawPos;666drawPos.x = self->position.x;667drawPos.y = self->position.y - self->risePos;668669RSDK.SetSpriteAnimation(DNARiser->aniFrames, 5, &self->bubbleAnimator, true, 0);670RSDK.DrawSprite(&self->bubbleAnimator, &drawPos, false);671672DrawHelpers_DrawArrow(self->position.x, self->position.y, drawPos.x, drawPos.y, 0xFFFF00, INK_NONE, 0xFF);673674RSDK_DRAWING_OVERLAY(false);675}676}677678void DNARiser_EditorLoad(void) { DNARiser->aniFrames = RSDK.LoadSpriteAnimation("CPZ/DNARiser.bin", SCOPE_STAGE); }679#endif680681void DNARiser_Serialize(void)682{683RSDK_EDITABLE_VAR(DNARiser, VAR_UINT32, height);684RSDK_EDITABLE_VAR(DNARiser, VAR_VECTOR2, speed);685}686687688