Path: blob/master/SonicMania/Objects/SPZ/LoveTester.c
338 views
// ---------------------------------------------------------------------1// RSDK Project: Sonic Mania2// Object Description: LoveTester Object3// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges4// Decompiled by: Rubberduckycooly & RMGRich5// ---------------------------------------------------------------------67#include "Game.h"89ObjectLoveTester *LoveTester;1011void LoveTester_Update(void)12{13RSDK_THIS(LoveTester);1415StateMachine_Run(self->state);16StateMachine_Run(self->stateLights);1718for (int32 i = 0; i < 10; ++i) RSDK.ProcessAnimation(&self->lightAnimator[i]);19}2021void LoveTester_LateUpdate(void) {}2223void LoveTester_StaticUpdate(void)24{25foreach_active(LoveTester, loveTester) { RSDK.AddDrawListRef(Zone->objectDrawGroup[1], RSDK.GetEntitySlot(loveTester)); }26}2728void LoveTester_Draw(void)29{30RSDK_THIS(LoveTester);3132if (self->state == LoveTester_State_HeartParticles)33RSDK.DrawSprite(&self->mainAnimator, NULL, false);34else35LoveTester_DrawSprites();36}3738void LoveTester_Create(void *data)39{40RSDK_THIS(LoveTester);4142self->active = ACTIVE_BOUNDS;43self->drawGroup = Zone->objectDrawGroup[0];44self->startPos = self->position;45self->visible = true;46self->drawFX = FX_FLIP;47self->updateRange.x = 0x800000;48self->updateRange.y = 0x800000;4950LoveTester_SetupHitboxes();5152if (data) {53self->updateRange.x = 0x100000;54self->updateRange.y = 0x100000;55self->active = ACTIVE_NORMAL;56self->drawGroup = Zone->objectDrawGroup[1];57self->state = LoveTester_State_HeartParticles;58}59else {60self->state = LoveTester_State_Init;61}62}6364void LoveTester_StageLoad(void)65{66LoveTester->aniFrames = RSDK.LoadSpriteAnimation("SPZ2/LoveTester.bin", SCOPE_STAGE);6768LoveTester_SetupHitboxes();69LoveTester_SetupLightOffsets();7071LoveTester->tvOffsetTop.x = 0;72LoveTester->tvOffsetTop.y = -0x300000;73LoveTester->tvOffsetBottom.x = 0;74LoveTester->tvOffsetBottom.y = 0x320000;7576LoveTester->active = ACTIVE_ALWAYS;77LoveTester->sfxScore = RSDK.GetSfx("SPZ/Score.wav");78}7980void LoveTester_SetupHitboxes(void)81{82LoveTester->hitboxEntry.left = -16;83LoveTester->hitboxEntry.top = -16;84LoveTester->hitboxEntry.right = 16;85LoveTester->hitboxEntry.bottom = 16;8687LoveTester->hitboxL.left = -24;88LoveTester->hitboxL.top = -20;89LoveTester->hitboxL.right = -18;90LoveTester->hitboxL.bottom = 20;9192LoveTester->hitboxR.left = 18;93LoveTester->hitboxR.top = -20;94LoveTester->hitboxR.right = 24;95LoveTester->hitboxR.bottom = 20;96}9798void LoveTester_SetupLightOffsets(void)99{100LoveTester->lightOffset[0].x = -0x1C0000;101LoveTester->lightOffset[0].y = -0x1F0000;102LoveTester->lightOffset[1].x = 0x1C0000;103LoveTester->lightOffset[1].y = -0x1F0000;104LoveTester->lightOffset[2].x = -0x1C0000;105LoveTester->lightOffset[2].y = -0xF0000;106LoveTester->lightOffset[3].x = 0x1C0000;107LoveTester->lightOffset[3].y = -0xF0000;108LoveTester->lightOffset[4].x = -0x1C0000;109LoveTester->lightOffset[4].y = 0x10000;110LoveTester->lightOffset[5].x = 0x1C0000;111LoveTester->lightOffset[5].y = 0x10000;112LoveTester->lightOffset[6].x = -0x1C0000;113LoveTester->lightOffset[6].y = 0x110000;114LoveTester->lightOffset[7].x = 0x1C0000;115LoveTester->lightOffset[7].y = 0x110000;116LoveTester->lightOffset[8].x = -0x1C0000;117LoveTester->lightOffset[8].y = 0x210000;118LoveTester->lightOffset[9].x = 0x1C0000;119LoveTester->lightOffset[9].y = 0x210000;120}121122void LoveTester_DrawSprites(void)123{124RSDK_THIS(LoveTester);125126int32 storeX = self->position.x;127int32 storeY = self->position.y;128129if (SceneInfo->currentDrawGroup != Zone->objectDrawGroup[1] || SceneInfo->inEditor) {130RSDK.SetSpriteAnimation(LoveTester->aniFrames, 1, &self->mainAnimator, true, 0);131RSDK.DrawSprite(&self->mainAnimator, NULL, false);132133for (int32 i = 0; i < 10; ++i) {134self->position.x = storeX + LoveTester->lightOffset[i].x;135self->position.y = storeY + LoveTester->lightOffset[i].y;136RSDK.DrawSprite(&self->lightAnimator[i], NULL, false);137}138139self->position.x = storeX + LoveTester->tvOffsetTop.x;140self->position.y = storeY + LoveTester->tvOffsetTop.y;141LoveTester_DrawTVDisplay(self->tvDisplayTop, self->tvFrameTop, self->isTVActiveTop);142143self->position.x = storeX + LoveTester->tvOffsetBottom.x;144self->position.y = storeY + LoveTester->tvOffsetBottom.y;145LoveTester_DrawTVDisplay(self->tvDisplayBottom, self->tvFrameBottom, self->isTVActiveBottom);146147self->position.x = storeX;148self->position.y = storeY;149}150151if (SceneInfo->currentDrawGroup == Zone->objectDrawGroup[1] || SceneInfo->inEditor) {152RSDK.SetSpriteAnimation(LoveTester->aniFrames, 0, &self->mainAnimator, true, 0);153RSDK.DrawSprite(&self->mainAnimator, NULL, false);154}155}156157void LoveTester_DrawTVDisplay(uint8 displayList, uint8 frame, bool32 isTVActive)158{159RSDK_THIS(LoveTester);160161// Draw TV (off)162RSDK.SetSpriteAnimation(LoveTester->aniFrames, 3, &self->mainAnimator, true, 0);163RSDK.DrawSprite(&self->mainAnimator, NULL, false);164165if (isTVActive) {166// Draw TV (on)167RSDK.SetSpriteAnimation(LoveTester->aniFrames, 3, &self->mainAnimator, true, 1);168RSDK.DrawSprite(&self->mainAnimator, NULL, false);169}170171// Draw Extras172switch (displayList) {173case LOVETESTER_LIST_SONIC:174case LOVETESTER_LIST_TAILS:175case LOVETESTER_LIST_KNUX:176case LOVETESTER_LIST_EGGMAN:177case LOVETESTER_LIST_AMY:178case LOVETESTER_LIST_HEART:179case LOVETESTER_LIST_HEARTBROKEN:180RSDK.SetSpriteAnimation(LoveTester->aniFrames, 4 + displayList, &self->mainAnimator, true, frame);181RSDK.DrawSprite(&self->mainAnimator, NULL, false);182break;183184default: break;185}186}187188void LoveTester_CheckPlayerCollisions_Solid(void)189{190RSDK_THIS(LoveTester);191192foreach_active(Player, player)193{194int32 storeX = player->position.x;195int32 storeY = player->position.y;196int32 velX = player->velocity.x;197int32 velY = player->velocity.y;198int32 sideL = Player_CheckCollisionBox(player, self, &LoveTester->hitboxL);199int32 sideR = Player_CheckCollisionBox(player, self, &LoveTester->hitboxR);200201if (sideL == C_TOP || sideL == C_BOTTOM || sideR == C_TOP || sideR == C_BOTTOM) {202player->onGround = false;203player->velocity.x = velX;204player->velocity.y = velY;205player->position.x = storeX;206player->position.y = storeY;207}208}209}210211void LoveTester_CheckPlayerCollisions_Entry(bool32 allowSidekick)212{213RSDK_THIS(LoveTester);214215foreach_active(Player, player)216{217int32 playerID = RSDK.GetEntitySlot(player);218if (allowSidekick || !player->sidekick) {219if (!((1 << playerID) & self->activePlayers)) {220if (Player_CheckBadnikTouch(player, self, &LoveTester->hitboxEntry)) {221self->activePlayers |= 1 << playerID;222RSDK.SetSpriteAnimation(player->aniFrames, ANI_JUMP, &player->animator, true, 0);223224player->nextGroundState = StateMachine_None;225player->nextAirState = StateMachine_None;226player->velocity.x >>= 15;227player->velocity.y >>= 15;228player->onGround = false;229player->state = Player_State_Static;230231if (!self->playerPtr) {232self->playerPtr = player;233if (player->camera) {234player->camera->target = (Entity *)self;235player->camera->disableYOffset = false;236}237}238}239}240241if ((1 << playerID) & self->activePlayers) {242RSDK.SetSpriteAnimation(player->aniFrames, ANI_JUMP, &player->animator, false, 0);243player->position.x += (self->position.x - player->position.x) >> 1;244player->position.y += (self->position.y + 0x10000 - player->position.y) >> 1;245player->state = Player_State_Static;246247if (self->matchingFinished) {248self->activePlayers &= ~(1 << playerID);249player->state = Player_State_Air;250player->tileCollisions = TILECOLLISION_DOWN;251player->onGround = false;252player->velocity.x = 0;253player->velocity.y = 0;254if (player->camera && self->playerPtr == player) {255player->camera->target = (Entity *)player;256player->camera->disableYOffset = true;257}258}259}260}261}262}263264void LoveTester_GiveScore(EntityPlayer *player)265{266EntityScoreBonus *bonus = CREATE_ENTITY(ScoreBonus, NULL, player->position.x, player->position.y);267bonus->drawGroup = Zone->objectDrawGroup[1];268bonus->animator.frameID = 0;269270Player_GiveScore(player, 100);271RSDK.PlaySfx(LoveTester->sfxScore, false, 255);272}273274void LoveTester_CreateHeartParticles(void)275{276RSDK_THIS(LoveTester);277278for (int32 velX = 0, frame = 0; velX < 0x10000; velX += 0x4000, ++frame) {279EntityLoveTester *child = CREATE_ENTITY(LoveTester, INT_TO_VOID(true), self->position.x, self->position.y);280RSDK.SetSpriteAnimation(LoveTester->aniFrames, 4, &child->mainAnimator, true, frame & 1);281child->velocity.x = velX - 0x6000;282}283}284285void LoveTester_State_Init(void)286{287RSDK_THIS(LoveTester);288289for (int32 i = 0; i < 10; ++i) RSDK.SetSpriteAnimation(LoveTester->aniFrames, 2, &self->lightAnimator[i], true, 5);290291self->playerPtr = NULL;292self->matchingFinished = false;293self->activePlayers = 0;294295self->state = LoveTester_State_WaitForActivated;296LoveTester_State_WaitForActivated();297}298299void LoveTester_State_WaitForActivated(void)300{301RSDK_THIS(LoveTester);302303LoveTester_CheckPlayerCollisions_Solid();304LoveTester_CheckPlayerCollisions_Entry(false);305306if (self->playerPtr) {307self->timer = 0;308self->isTVActiveTop = true;309self->isTVActiveBottom = true;310self->tvDisplayTop = LOVETESTER_LIST_NONE;311self->tvFrameTop = 0;312self->tvDisplayBottom = LOVETESTER_LIST_NONE;313self->tvFrameBottom = 0;314self->state = LoveTester_State_SetupTopDisplay;315}316}317318void LoveTester_State_SetupTopDisplay(void)319{320RSDK_THIS(LoveTester);321322LoveTester_CheckPlayerCollisions_Solid();323LoveTester_CheckPlayerCollisions_Entry(true);324325if (self->timer >= 8) {326EntityPlayer *player = self->playerPtr;327self->timer = 0;328self->isTVActiveTop = true;329self->isTVActiveBottom = true;330331switch (player->characterID) {332case ID_SONIC: self->tvDisplayTop = LOVETESTER_LIST_SONIC; break;333case ID_TAILS: self->tvDisplayTop = LOVETESTER_LIST_TAILS; break;334case ID_KNUCKLES: self->tvDisplayTop = LOVETESTER_LIST_KNUX; break;335}336337self->nextDisplayBottom = self->tvDisplayTop;338while (self->nextDisplayBottom == self->tvDisplayTop) {339self->nextDisplayBottom = RSDK.Rand(LOVETESTER_LIST_SONIC, LOVETESTER_LIST_HEART);340}341342self->state = LoveTester_State_SetupMatching;343}344else {345self->isTVActiveTop = !(self->timer & 2);346self->isTVActiveBottom = !(self->timer & 2);347self->timer++;348}349}350351void LoveTester_State_SetupMatching(void)352{353RSDK_THIS(LoveTester);354355LoveTester_CheckPlayerCollisions_Solid();356LoveTester_CheckPlayerCollisions_Entry(true);357358if (self->timer < 168) {359int32 timer = self->timer & 0b10000000000000000000000000000011;360361bool32 shouldChangeDisplay = !timer;362if (timer < 0)363shouldChangeDisplay = (int32)((timer - 1) | 0xFFFFFFFC) == -1;364365if (shouldChangeDisplay) {366int32 displayBottom = self->tvDisplayBottom;367int32 displayTop = self->tvDisplayTop;368369while (true) {370self->tvDisplayBottom = displayTop;371if (displayTop != self->tvDisplayTop && displayTop != displayBottom)372break;373displayTop = RSDK.Rand(LOVETESTER_LIST_SONIC, LOVETESTER_LIST_HEART);374}375}376377if (self->timer >= 128)378self->tvDisplayBottom = LOVETESTER_LIST_NONE;379380switch (self->timer++) {381default: break;382383case 0:384self->lightsID = 0;385self->stateLights = LoveTester_StateLights_FlashSlow;386break;387388case 80:389self->lightsID = 0;390self->stateLights = LoveTester_StateLights_FlashMed;391break;392393case 128:394self->lightsID = 0;395self->stateLights = LoveTester_StateLights_FlashFast;396break;397}398}399else {400EntityPlayer *player = self->playerPtr;401self->lightsID = 0;402self->stateLights = StateMachine_None;403404switch (player->characterID) {405case ID_SONIC:406if (self->nextDisplayBottom == LOVETESTER_LIST_EGGMAN)407self->state = LoveTester_State_BadMatch;408else if (self->nextDisplayBottom == LOVETESTER_LIST_AMY)409self->state = LoveTester_State_UnluckyMatch;410else411self->state = LoveTester_State_GoodMatch;412break;413414case ID_TAILS:415if (self->nextDisplayBottom == LOVETESTER_LIST_SONIC)416self->state = LoveTester_State_UnluckyMatch;417else if (self->nextDisplayBottom == LOVETESTER_LIST_EGGMAN)418self->state = LoveTester_State_UnluckyMatch;419else420self->state = LoveTester_State_GoodMatch;421break;422423case ID_KNUCKLES:424if (self->nextDisplayBottom == LOVETESTER_LIST_SONIC)425self->state = LoveTester_State_BadMatch;426else if (self->nextDisplayBottom == LOVETESTER_LIST_EGGMAN)427self->state = LoveTester_State_UnluckyMatch;428else429self->state = LoveTester_State_GoodMatch;430break;431}432433if (self->state == LoveTester_State_UnluckyMatch) {434self->tvFrameTop = 1;435LoveTester_CreateHeartParticles();436}437else if (self->state == LoveTester_State_BadMatch) {438self->tvFrameTop = 2;439}440441self->tvDisplayBottom = self->nextDisplayBottom;442self->timer = 0;443}444}445446void LoveTester_State_UnluckyMatch(void)447{448RSDK_THIS(LoveTester);449EntityPlayer *player = self->playerPtr;450451if (self->timer >= 64) {452self->timer = 0;453self->tvDisplayBottom = self->nextDisplayBottom;454self->matchingFinished = true;455self->state = LoveTester_State_ReleasePlayers;456}457else {458switch (self->timer++ % 32) {459default: break;460461case 0:462self->tvDisplayBottom = self->nextDisplayBottom;463LoveTester_GiveScore(player);464break;465466case 16:467self->tvDisplayBottom = 6;468LoveTester_GiveScore(player);469break;470}471}472473LoveTester_CheckPlayerCollisions_Solid();474LoveTester_CheckPlayerCollisions_Entry(true);475}476477void LoveTester_State_GoodMatch(void)478{479RSDK_THIS(LoveTester);480481if (self->timer >= 24) {482self->timer = 0;483self->matchingFinished = true;484self->state = LoveTester_State_ReleasePlayers;485}486else {487if (!self->timer)488LoveTester_GiveScore(self->playerPtr);489++self->timer;490}491492LoveTester_CheckPlayerCollisions_Solid();493LoveTester_CheckPlayerCollisions_Entry(true);494}495496void LoveTester_State_BadMatch(void)497{498RSDK_THIS(LoveTester);499500if (self->timer >= 64) {501self->timer = 0;502self->tvDisplayBottom = self->nextDisplayBottom;503self->matchingFinished = true;504self->state = LoveTester_State_ReleasePlayers;505}506else {507switch (self->timer++ % 32) {508default: break;509case 0: self->tvDisplayBottom = self->nextDisplayBottom; break;510case 16: self->tvDisplayBottom = 7; break;511}512}513514LoveTester_CheckPlayerCollisions_Solid();515LoveTester_CheckPlayerCollisions_Entry(true);516}517518void LoveTester_State_ReleasePlayers(void)519{520RSDK_THIS(LoveTester);521522LoveTester_CheckPlayerCollisions_Solid();523524foreach_active(Player, player)525{526if (player == self->playerPtr) {527if (!Player_CheckCollisionTouch(player, self, &LoveTester->hitboxEntry)) {528self->activePlayers = 0;529self->state = LoveTester_State_Init;530}531}532}533}534535void LoveTester_State_HeartParticles(void)536{537RSDK_THIS(LoveTester);538539self->velocity.y -= 0x700;540self->position.x += self->velocity.x;541self->position.y += self->velocity.y;542543if (!RSDK.CheckOnScreen(self, &self->updateRange))544destroyEntity(self);545}546547void LoveTester_StateLights_FlashSlow(void)548{549RSDK_THIS(LoveTester);550551switch (self->lightsID % 40) {552case 0:553RSDK.SetSpriteAnimation(LoveTester->aniFrames, 2, &self->lightAnimator[1], true, 0);554RSDK.SetSpriteAnimation(LoveTester->aniFrames, 2, &self->lightAnimator[8], true, 0);555break;556557case 8:558RSDK.SetSpriteAnimation(LoveTester->aniFrames, 2, &self->lightAnimator[3], true, 0);559RSDK.SetSpriteAnimation(LoveTester->aniFrames, 2, &self->lightAnimator[6], true, 0);560break;561562case 16:563RSDK.SetSpriteAnimation(LoveTester->aniFrames, 2, &self->lightAnimator[5], true, 0);564RSDK.SetSpriteAnimation(LoveTester->aniFrames, 2, &self->lightAnimator[4], true, 0);565break;566567case 24:568RSDK.SetSpriteAnimation(LoveTester->aniFrames, 2, &self->lightAnimator[7], true, 0);569RSDK.SetSpriteAnimation(LoveTester->aniFrames, 2, &self->lightAnimator[2], true, 0);570break;571572case 32:573RSDK.SetSpriteAnimation(LoveTester->aniFrames, 2, &self->lightAnimator[9], true, 0);574RSDK.SetSpriteAnimation(LoveTester->aniFrames, 2, &self->lightAnimator[0], true, 0);575break;576}577578++self->lightsID;579}580581void LoveTester_StateLights_FlashMed(void)582{583RSDK_THIS(LoveTester);584585switch (self->lightsID % 24) {586case 0:587RSDK.SetSpriteAnimation(LoveTester->aniFrames, 2, &self->lightAnimator[0], true, 0);588RSDK.SetSpriteAnimation(LoveTester->aniFrames, 2, &self->lightAnimator[1], true, 0);589RSDK.SetSpriteAnimation(LoveTester->aniFrames, 2, &self->lightAnimator[8], true, 0);590RSDK.SetSpriteAnimation(LoveTester->aniFrames, 2, &self->lightAnimator[9], true, 0);591break;592593case 8:594RSDK.SetSpriteAnimation(LoveTester->aniFrames, 2, &self->lightAnimator[2], true, 0);595RSDK.SetSpriteAnimation(LoveTester->aniFrames, 2, &self->lightAnimator[3], true, 0);596RSDK.SetSpriteAnimation(LoveTester->aniFrames, 2, &self->lightAnimator[6], true, 0);597RSDK.SetSpriteAnimation(LoveTester->aniFrames, 2, &self->lightAnimator[7], true, 0);598break;599600case 16:601RSDK.SetSpriteAnimation(LoveTester->aniFrames, 2, &self->lightAnimator[4], true, 0);602RSDK.SetSpriteAnimation(LoveTester->aniFrames, 2, &self->lightAnimator[5], true, 0);603break;604}605606++self->lightsID;607}608609void LoveTester_StateLights_FlashFast(void)610{611RSDK_THIS(LoveTester);612613switch (self->lightsID % 20) {614case 0:615RSDK.SetSpriteAnimation(LoveTester->aniFrames, 2, &self->lightAnimator[0], true, 0);616RSDK.SetSpriteAnimation(LoveTester->aniFrames, 2, &self->lightAnimator[1], true, 0);617break;618619case 2:620RSDK.SetSpriteAnimation(LoveTester->aniFrames, 2, &self->lightAnimator[2], true, 0);621RSDK.SetSpriteAnimation(LoveTester->aniFrames, 2, &self->lightAnimator[3], true, 0);622break;623624case 4:625RSDK.SetSpriteAnimation(LoveTester->aniFrames, 2, &self->lightAnimator[4], true, 0);626RSDK.SetSpriteAnimation(LoveTester->aniFrames, 2, &self->lightAnimator[5], true, 0);627break;628629case 6:630RSDK.SetSpriteAnimation(LoveTester->aniFrames, 2, &self->lightAnimator[6], true, 0);631RSDK.SetSpriteAnimation(LoveTester->aniFrames, 2, &self->lightAnimator[7], true, 0);632break;633634case 8:635RSDK.SetSpriteAnimation(LoveTester->aniFrames, 2, &self->lightAnimator[8], true, 0);636RSDK.SetSpriteAnimation(LoveTester->aniFrames, 2, &self->lightAnimator[9], true, 0);637break;638}639640++self->lightsID;641}642643#if GAME_INCLUDE_EDITOR644void LoveTester_EditorDraw(void)645{646RSDK_THIS(LoveTester);647648for (int32 i = 0; i < 10; ++i) RSDK.SetSpriteAnimation(LoveTester->aniFrames, 2, &self->lightAnimator[i], true, 5);649650LoveTester_Draw();651}652653void LoveTester_EditorLoad(void)654{655LoveTester->aniFrames = RSDK.LoadSpriteAnimation("SPZ2/LoveTester.bin", SCOPE_STAGE);656657LoveTester_SetupHitboxes();658LoveTester_SetupLightOffsets();659}660#endif661662void LoveTester_Serialize(void) {}663664665