Path: blob/master/SonicMania/Objects/SPZ/LEDPanel.c
338 views
// ---------------------------------------------------------------------1// RSDK Project: Sonic Mania2// Object Description: LEDPanel Object3// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges4// Decompiled by: Rubberduckycooly & RMGRich5// ---------------------------------------------------------------------67#include "Game.h"89ObjectLEDPanel *LEDPanel;1011void LEDPanel_Update(void)12{13RSDK_THIS(LEDPanel);1415for (self->row = 0; self->row < LEDPANEL_ROW_COUNT; ++self->row) {16StateMachine_Run(self->stateRow[self->row]);17}18}1920void LEDPanel_LateUpdate(void) {}2122void LEDPanel_StaticUpdate(void) {}2324void LEDPanel_Draw(void)25{26RSDK_THIS(LEDPanel);2728RSDK.DrawRect(self->position.x - (self->size.x >> 1) + 0x80000, self->position.y - (self->size.y >> 1), self->size.x - 0x100000, self->size.y,29LEDPanel->panelColor, 512, INK_NONE, false);3031RSDKScreenInfo *screen = &ScreenInfo[SceneInfo->currentScreenID];3233int32 clipX1 = screen->clipBound_X1;34int32 clipX2 = screen->clipBound_X2;35int32 clipY1 = screen->clipBound_Y1;36int32 clipY2 = screen->clipBound_Y2;3738int32 clipBound_X1 = self->left - screen->position.x + (self->position.x >> 16) + 8;39int32 clipBound_X2 = self->right - screen->position.x + (self->position.x >> 16) - 8;40int32 clipBound_Y1 = (self->position.y >> 16) + self->top - screen->position.y;41int32 clipBound_Y2 = (self->position.y >> 16) + self->bottom - screen->position.y;4243RSDK.SetClipBounds(SceneInfo->currentScreenID, clipBound_X1, clipBound_Y1, clipBound_X2, clipBound_Y2);4445for (int32 r = 0; r < LEDPANEL_ROW_COUNT; ++r)46RSDK.DrawText(&self->animatorText, &self->textPos[r], &self->activeText[r], 0, self->activeText[r].length, ALIGN_CENTER, 0, 0, NULL, false);4748screen->clipBound_X1 = clipX1;49screen->clipBound_X2 = clipX2;50screen->clipBound_Y1 = clipY1;51screen->clipBound_Y2 = clipY2;52RSDK.SetClipBounds(SceneInfo->currentScreenID, clipX1, clipY1, clipX2, clipY2);53}5455void LEDPanel_Create(void *data)56{57RSDK_THIS(LEDPanel);5859self->active = ACTIVE_BOUNDS;60self->visible = true;61self->drawGroup = Zone->objectDrawGroup[0];62self->updateRange = self->size;63RSDK.SetSpriteAnimation(LEDPanel->aniFrames, 0, &self->animatorText, true, 0);6465if (!SceneInfo->inEditor) {66for (int32 i = 0; i < LEDPANEL_TEXT_COUNT; ++i) {67RSDK.SetSpriteString(LEDPanel->aniFrames, 0, &self->text[i]);68self->textPtrs[i] = &self->text[i];69}7071self->left = -(self->size.x >> 17);72self->right = self->size.x >> 17;73self->top = -(self->size.y >> 17);74self->bottom = self->size.y >> 17;7576self->curXBoundaryL = (self->size.x >> 1);77self->newXBoundaryL = (self->size.x >> 1);78self->curYBoundaryT = -(self->size.y >> 1);79self->newYBoundaryT = -(self->size.y >> 1);80self->curXBoundaryR = -(self->size.x >> 1);81self->newXBoundaryR = -(self->size.x >> 1);82self->curYBoundaryB = -(self->size.y >> 1);83self->newYBoundaryB = -(self->size.y >> 1);8485self->boundsMoveSpeed.x = 0x10000;86self->boundsMoveSpeed.y = 0x10000;8788int32 offset = 0;89for (int32 r = 0; r < LEDPANEL_ROW_COUNT; ++r) {90LEDPanel_SetupActiveText(r, self->textPtrs[r]);9192self->seqPtrs[r] = &self->seq[r];93self->textMoveVel[r].x = 0x10000;94self->textMoveVel[r].y = 0x10000;9596self->textPos[r].x = self->position.x;97self->textPos[r].y = self->position.y;98self->textPos[r].x += (self->activeText[r].length << 20) - (self->size.x >> 1) + 0x80000;99self->textPos[r].y += (0x100000 + offset) - (self->size.y >> 1);100101self->textMovePos[r].x = 0;102self->textMovePos[r].y = offset;103104self->textTargetPos[r].x = 0;105self->textTargetPos[r].y = offset;106107self->stateRow[r] = StateMachine_None;108109offset += 0x200000;110}111112for (self->row = 0; self->row < LEDPANEL_ROW_COUNT; ++self->row) LEDPanel_HandleCharacters();113}114}115116void LEDPanel_StageLoad(void)117{118if (RSDK.CheckSceneFolder("SPZ1"))119LEDPanel->aniFrames = RSDK.LoadSpriteAnimation("SPZ1/LED.bin", SCOPE_STAGE);120121RSDK.InitString(&LEDPanel->text, " ", 0);122123LEDPanel->panelColor = RSDK.GetPaletteEntry(0, 190);124}125126void LEDPanel_SetupActiveText(int32 row, String *src)127{128RSDK_THIS(LEDPanel);129130RSDK.CopyString(&self->activeText[row], src);131132self->activeTextSize[row] = self->activeText[row].length;133for (int32 i = 0; i < self->activeText[row].length; ++i) {134if (self->activeText[row].chars[i] != 27) {135self->activeTextSize[row] = i;136break;137}138}139140self->activeTextLen[row] = 0;141for (int32 i = self->activeText[row].length - 1; i >= 0; --i) {142if (self->activeText[row].chars[i] != 27) {143self->activeTextLen[row] = i;144break;145}146}147}148149void LEDPanel_SetupTextPos(int32 row, int32 x, int32 y)150{151RSDK_THIS(LEDPanel);152153self->textPos[row].x = self->position.x + ((self->activeText[row].length << 20) - (self->size.x >> 1) + x + 0x80000);154self->textPos[row].y = self->position.y + (y - (self->size.y >> 1) + 0x100000);155}156157void LEDPanel_HandleCharacters(void)158{159RSDK_THIS(LEDPanel);160161self->rowSignaled[self->row] = false;162bool32 finished = false;163164while (!finished) {165int32 action = -1;166int32 subAction = -1;167168if (self->rowSeqPos[self->row] < self->seqPtrs[self->row]->length)169action = self->seqPtrs[self->row]->chars[self->rowSeqPos[self->row]++];170171switch (action) {172case 'A':173subAction = self->seqPtrs[self->row]->chars[self->rowSeqPos[self->row]++] - '0';174switch (subAction) {175case 0:176self->textMovePos[self->row].x = -0x100000 * self->activeText[self->row].length;177self->textTargetPos[self->row].x = self->textMovePos[self->row].x;178break;179180case 1:181self->textMovePos[self->row].x = 0;182self->textTargetPos[self->row].x = 0;183break;184185case 2:186self->textMovePos[self->row].x = (self->size.x >> 1) - (self->activeText[self->row].length << 19) - 0x80000;187self->textTargetPos[self->row].x = self->textMovePos[self->row].x;188break;189190case 3:191self->textMovePos[self->row].x = self->size.x - (self->activeText[self->row].length << 20) - 0x100000;192self->textTargetPos[self->row].x = self->textMovePos[self->row].x;193break;194195case 4:196self->textMovePos[self->row].x = self->size.x;197self->textTargetPos[self->row].x = self->textMovePos[self->row].x;198break;199200default: break;201}202203LEDPanel_SetupTextPos(self->row, self->textMovePos[self->row].x, self->textMovePos[self->row].y);204break;205206case 'B':207subAction = self->seqPtrs[self->row]->chars[self->rowSeqPos[self->row]++] - '0';208switch (subAction) {209case 0:210self->textMovePos[self->row].y = -0x200000;211self->textTargetPos[self->row].y = -0x200000;212break;213214case 1:215self->textMovePos[self->row].y = 0;216self->textTargetPos[self->row].y = 0;217break;218219case 2:220self->textMovePos[self->row].y = (self->size.y >> 1) - 0x100000;221self->textTargetPos[self->row].y = self->textMovePos[self->row].y;222break;223224case 3:225self->textMovePos[self->row].y = self->size.y - 0x200000;226self->textTargetPos[self->row].y = self->textMovePos[self->row].y;227break;228229case 4:230self->textMovePos[self->row].y = self->size.y;231self->textTargetPos[self->row].y = self->textMovePos[self->row].y;232break;233234default: break;235}236237LEDPanel_SetupTextPos(self->row, self->textMovePos[self->row].x, self->textMovePos[self->row].y);238break;239240case 'C':241subAction = self->seqPtrs[self->row]->chars[self->rowSeqPos[self->row]++] - '0';242switch (subAction) {243case 0: self->textTargetPos[self->row].x = -0x100000 * self->activeText[self->row].length; break;244case 1: self->textTargetPos[self->row].x = 0; break;245case 2: self->textTargetPos[self->row].x = (self->size.x >> 1) - (self->activeText[self->row].length << 19) - 0x80000; break;246case 3: self->textTargetPos[self->row].x = self->size.x - (self->activeText[self->row].length << 20) - 0x100000; break;247case 4: self->textTargetPos[self->row].x = self->size.x; break;248default: break;249}250break;251252case 'D':253subAction = self->seqPtrs[self->row]->chars[self->rowSeqPos[self->row]++] - '0';254255switch (subAction) {256case 0: self->textTargetPos[self->row].y = -0x200000; break;257case 1: self->textTargetPos[self->row].y = 0; break;258case 2: self->textTargetPos[self->row].y = (self->size.y >> 1) - 0x100000; break;259case 3: self->textTargetPos[self->row].y = self->size.y - 0x200000; break;260case 4: self->textTargetPos[self->row].y = self->size.y; break;261default: break;262}263break;264265case 'E':266self->stateRow[self->row] = LEDPanel_StateText_Move;267LEDPanel_StateText_Move();268finished = true;269break;270271case 'F':272subAction = self->seqPtrs[self->row]->chars[self->rowSeqPos[self->row]++] - '0';273274switch (subAction) {275default: break;276277case 0:278++self->activeTextLen[self->row];279LEDPanel->text.chars[0] = self->seqPtrs[self->row]->chars[self->rowSeqPos[self->row]++];280RSDK.SetSpriteString(LEDPanel->aniFrames, 0, &LEDPanel->text);281self->activeText[self->row].chars[self->activeTextLen[self->row]] = LEDPanel->text.chars[0];282break;283284case 1:285--self->activeTextSize[self->row];286LEDPanel->text.chars[0] = self->seqPtrs[self->row]->chars[self->rowSeqPos[self->row]++];287RSDK.SetSpriteString(LEDPanel->aniFrames, 0, &LEDPanel->text);288self->activeText[self->row].chars[self->activeTextSize[self->row]] = LEDPanel->text.chars[0];289break;290}291break;292293case 'G':294subAction = self->seqPtrs[self->row]->chars[self->rowSeqPos[self->row]++] - '0';295296switch (subAction) {297default: break;298299case 0: self->activeText[self->row].chars[self->activeTextLen[self->row]--] = 27; break;300301case 1: self->activeText[self->row].chars[self->activeTextSize[self->row]++] = 27; break;302}303break;304305case 'H':306self->stateRow[self->row] = LEDPanel_StateText_WaitForSignal;307LEDPanel_StateText_WaitForSignal();308finished = true;309break;310311case 'I':312self->rowSignaled[self->row] = true;313self->stateRow[self->row] = LEDPanel_HandleCharacters;314finished = true;315break;316317case 'J':318subAction = self->seqPtrs[self->row]->chars[self->rowSeqPos[self->row]++] - '0';319LEDPanel_SetupActiveText(self->row, self->textPtrs[subAction]);320break;321322case 'K':323self->rowDelay[self->row] = 15;324self->stateRow[self->row] = LEDPanel_StateText_Delay;325finished = true;326break;327328case 'L': self->textMoveVel[self->row].x = (self->seqPtrs[self->row]->chars[self->rowSeqPos[self->row]++] - '/') << 15; break;329case 'M': self->textMoveVel[self->row].y = (self->seqPtrs[self->row]->chars[self->rowSeqPos[self->row]++] - '/') << 15; break;330case 'N': self->boundsMoveSpeed.x = (self->seqPtrs[self->row]->chars[self->rowSeqPos[self->row]++] - '/') << 15; break;331case 'O': self->boundsMoveSpeed.y = (self->seqPtrs[self->row]->chars[self->rowSeqPos[self->row]++] - '/') << 15; break;332333case 'P':334subAction = self->seqPtrs[self->row]->chars[self->rowSeqPos[self->row]++] - '0';335336switch (subAction) {337default: break;338339case 1:340self->newXBoundaryL = -(self->size.x >> 1);341self->curXBoundaryL = -(self->size.x >> 1);342self->left = self->curXBoundaryL >> 16;343break;344345case 2:346self->curXBoundaryL = 0;347self->newXBoundaryL = 0;348self->left = 0;349break;350351case 3:352self->newXBoundaryL = self->size.x >> 1;353self->curXBoundaryL = self->size.x >> 1;354self->left = self->curXBoundaryL >> 16;355break;356}357break;358359case 'Q':360subAction = self->seqPtrs[self->row]->chars[self->rowSeqPos[self->row]++] - '0';361362switch (subAction) {363default: break;364365case 1:366self->newYBoundaryT = -(self->size.y >> 1);367self->curYBoundaryT = -(self->size.y >> 1);368self->top = self->curYBoundaryT >> 16;369break;370371case 2:372self->curYBoundaryT = 0;373self->newYBoundaryT = 0;374self->top = 0;375break;376377case 3:378self->newYBoundaryT = self->size.y >> 1;379self->curYBoundaryT = self->size.y >> 1;380self->top = self->curYBoundaryT >> 16;381break;382}383break;384385case 'R':386subAction = self->seqPtrs[self->row]->chars[self->rowSeqPos[self->row]++] - '0';387388switch (subAction) {389default: break;390391case 1:392self->newXBoundaryR = -(self->size.x >> 1);393self->curXBoundaryR = -(self->size.x >> 1);394self->right = self->curXBoundaryR >> 16;395break;396397case 2:398self->curXBoundaryR = 0;399self->newXBoundaryR = 0;400self->right = 0;401break;402403case 3:404self->newXBoundaryR = self->size.x >> 1;405self->curXBoundaryR = self->size.x >> 1;406self->right = self->curXBoundaryR >> 16;407break;408}409break;410411case 'S':412subAction = self->seqPtrs[self->row]->chars[self->rowSeqPos[self->row]++] - '0';413414switch (subAction) {415default: break;416case 1:417self->newYBoundaryB = -(self->size.y >> 1);418self->curYBoundaryB = -(self->size.y >> 1);419self->bottom = self->curYBoundaryB >> 16;420break;421case 2:422self->curYBoundaryB = 0;423self->newYBoundaryB = 0;424self->bottom = 0;425break;426case 3:427self->newYBoundaryB = self->size.y >> 1;428self->curYBoundaryB = self->size.y >> 1;429self->bottom = self->curYBoundaryB >> 16;430break;431}432break;433434case 'T':435subAction = self->seqPtrs[self->row]->chars[self->rowSeqPos[self->row]++] - '0';436437switch (subAction) {438default: break;439case 1: self->newXBoundaryL = -(self->size.x >> 1); break;440case 2: self->newXBoundaryL = 0; break;441case 3: self->newXBoundaryL = self->size.x >> 1; break;442}443break;444445case 'U':446subAction = self->seqPtrs[self->row]->chars[self->rowSeqPos[self->row]++] - '0';447448switch (subAction) {449default: break;450case 1: self->newYBoundaryT = -(self->size.y >> 1); break;451case 2: self->newYBoundaryT = 0; break;452case 3: self->newYBoundaryT = self->size.y >> 1; break;453}454break;455456case 'V':457subAction = self->seqPtrs[self->row]->chars[self->rowSeqPos[self->row]++] - '0';458459switch (subAction) {460default: break;461case 1: self->newXBoundaryR = -(self->size.x >> 1); break;462case 2: self->newXBoundaryR = 0; break;463case 3: self->newXBoundaryR = self->size.x >> 1; break;464}465break;466467case 'W':468subAction = self->seqPtrs[self->row]->chars[self->rowSeqPos[self->row]++] - '0';469470switch (subAction) {471default: break;472case 1: self->newYBoundaryB = -(self->size.y >> 1); break;473case 2: self->newYBoundaryB = 0; break;474case 3: self->newYBoundaryB = self->size.y >> 1; break;475}476break;477478case 'X':479self->stateRow[self->row] = LEDPanel_StateText_ChangeClipBounds;480LEDPanel_StateText_ChangeClipBounds();481finished = true;482break;483484default: self->rowSeqPos[self->row] = 0; break;485}486}487}488489void LEDPanel_StateText_Move(void)490{491RSDK_THIS(LEDPanel);492493if (self->textMovePos[self->row].x != self->textTargetPos[self->row].x) {494if (self->textMovePos[self->row].x >= self->textTargetPos[self->row].x) {495self->textMovePos[self->row].x -= self->textMoveVel[self->row].x;496497if (self->textMovePos[self->row].x < self->textTargetPos[self->row].x)498self->textMovePos[self->row].x = self->textTargetPos[self->row].x;499}500else {501self->textMovePos[self->row].x += self->textMoveVel[self->row].x;502503if (self->textMovePos[self->row].x > self->textTargetPos[self->row].x)504self->textMovePos[self->row].x = self->textTargetPos[self->row].x;505}506}507508if (self->textMovePos[self->row].y != self->textTargetPos[self->row].y) {509if (self->textMovePos[self->row].y >= self->textTargetPos[self->row].y) {510self->textMovePos[self->row].y -= self->textMoveVel[self->row].y;511512if (self->textMovePos[self->row].y < self->textTargetPos[self->row].y)513self->textMovePos[self->row].y = self->textTargetPos[self->row].y;514}515else {516self->textMovePos[self->row].y += self->textMoveVel[self->row].y;517518if (self->textMovePos[self->row].y > self->textTargetPos[self->row].y)519self->textMovePos[self->row].y = self->textTargetPos[self->row].y;520}521}522523self->textPos[self->row].x = self->position.x;524self->textPos[self->row].y = self->position.y;525self->textPos[self->row].x += (self->activeText[self->row].length << 20) - (self->size.x >> 1) + self->textMovePos[self->row].x + 0x80000;526self->textPos[self->row].y += self->textMovePos[self->row].y - (self->size.y >> 1) + 0x100000;527528if (self->textMovePos[self->row].x == self->textTargetPos[self->row].x && self->textMovePos[self->row].y == self->textTargetPos[self->row].y)529LEDPanel_HandleCharacters();530}531532void LEDPanel_StateText_Delay(void)533{534RSDK_THIS(LEDPanel);535536if (--self->rowDelay[self->row] <= 0)537LEDPanel_HandleCharacters();538}539540void LEDPanel_StateText_ChangeClipBounds(void)541{542RSDK_THIS(LEDPanel);543544int32 count = 0;545546if (self->curXBoundaryL == self->newXBoundaryL) {547count = 1;548}549else if (self->curXBoundaryL >= self->newXBoundaryL) {550self->curXBoundaryL -= self->boundsMoveSpeed.x;551if (self->curXBoundaryL < self->newXBoundaryL)552self->curXBoundaryL = self->newXBoundaryL;553}554else {555self->curXBoundaryL += self->boundsMoveSpeed.x;556if (self->curXBoundaryL > self->newXBoundaryL)557self->curXBoundaryL = self->newXBoundaryL;558}559560if (self->curXBoundaryR == self->newXBoundaryR) {561++count;562}563else {564if (self->curXBoundaryR < self->newXBoundaryR) {565self->curXBoundaryR += self->boundsMoveSpeed.x;566if (self->curXBoundaryR > self->newXBoundaryR)567self->curXBoundaryR = self->newXBoundaryR;568}569else {570self->curXBoundaryR -= self->boundsMoveSpeed.x;571if (self->curXBoundaryR < self->newXBoundaryR)572self->curXBoundaryR = self->newXBoundaryR;573}574}575576if (self->curYBoundaryT == self->newYBoundaryT) {577++count;578}579else if (self->curYBoundaryT >= self->newYBoundaryT) {580self->curYBoundaryT -= self->boundsMoveSpeed.y;581if (self->curYBoundaryT < self->newYBoundaryT)582self->curYBoundaryT = self->newYBoundaryT;583}584else {585self->curYBoundaryT += self->boundsMoveSpeed.y;586if (self->curYBoundaryT > self->newYBoundaryT)587self->curYBoundaryT = self->newYBoundaryT;588}589590if (self->curYBoundaryB == self->newYBoundaryB) {591++count;592}593else {594if (self->curYBoundaryB < self->newYBoundaryB) {595self->curYBoundaryB += self->boundsMoveSpeed.y;596if (self->curYBoundaryB > self->newYBoundaryB)597self->curYBoundaryB = self->newYBoundaryB;598}599else {600self->curYBoundaryB -= self->boundsMoveSpeed.y;601if (self->curYBoundaryB < self->newYBoundaryB)602self->curYBoundaryB = self->newYBoundaryB;603}604}605606self->left = self->curXBoundaryL >> 16;607self->top = self->curYBoundaryT >> 16;608self->right = self->curXBoundaryR >> 16;609self->bottom = self->curYBoundaryB >> 16;610611if (count == 4)612LEDPanel_HandleCharacters();613}614615void LEDPanel_StateText_WaitForSignal(void)616{617RSDK_THIS(LEDPanel);618619int32 row = self->row ^ 1;620if (self->rowSignaled[row]) {621self->rowSignaled[row] = false;622self->stateRow[self->row] = StateMachine_None;623LEDPanel_HandleCharacters();624}625}626627#if GAME_INCLUDE_EDITOR628void LEDPanel_EditorDraw(void)629{630RSDK_THIS(LEDPanel);631Vector2 drawPos = self->position;632633const char *text = "LEDPANEL";634635drawPos.x -= 4 * 0x100000;636637for (int32 i = 0; i < 8; ++i) {638self->animatorText.frameID = text[i] - 'A';639640RSDK.DrawSprite(&self->animatorText, &drawPos, false);641642drawPos.x += 0x100000;643}644645if (showGizmos()) {646RSDK_DRAWING_OVERLAY(true);647648Hitbox hitbox;649hitbox.left = -(self->size.x >> 17);650hitbox.right = self->size.x >> 17;651hitbox.top = -(self->size.y >> 17);652hitbox.bottom = self->size.y >> 17;653654DrawHelpers_DrawHitboxOutline(self->position.x, self->position.y, &hitbox, FLIP_NONE, 0xFFFF00);655656RSDK_DRAWING_OVERLAY(false);657}658}659660void LEDPanel_EditorLoad(void) { LEDPanel->aniFrames = RSDK.LoadSpriteAnimation("SPZ1/LED.bin", SCOPE_STAGE); }661#endif662663void LEDPanel_Serialize(void)664{665RSDK_EDITABLE_ARRAY(LEDPanel, VAR_STRING, text, LEDPANEL_TEXT_COUNT, String);666RSDK_EDITABLE_ARRAY(LEDPanel, VAR_STRING, seq, LEDPANEL_ROW_COUNT, String);667RSDK_EDITABLE_VAR(LEDPanel, VAR_VECTOR2, size);668}669670671