Path: blob/master/SonicMania/Objects/Global/ActClear.c
338 views
// ---------------------------------------------------------------------1// RSDK Project: Sonic Mania2// Object Description: ActClear Object3// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges4// Decompiled by: Rubberduckycooly & RMGRich5// ---------------------------------------------------------------------67#include "Game.h"89ObjectActClear *ActClear;1011void ActClear_Update(void) {}1213void ActClear_LateUpdate(void)14{15RSDK_THIS(ActClear);1617StateMachine_Run(self->state);18}1920void ActClear_StaticUpdate(void) {}2122void ActClear_Draw(void)23{24RSDK_THIS(ActClear);2526Vector2 drawPos;27Vector2 verts[4];28#if MANIA_USE_PLUS29int32 milliseconds = 0;30int32 seconds = 0;31int32 minutes = 0;32#endif33int32 offset = 0;3435drawPos.x = self->gotThroughPos.x;36drawPos.y = self->gotThroughPos.y;37verts[0].y = drawPos.y - TO_FIXED(20);38verts[1].y = drawPos.y - TO_FIXED(20);39verts[2].y = drawPos.y - TO_FIXED(4);40verts[3].y = drawPos.y - TO_FIXED(4);41if ((GET_CHARACTER_ID(1)) == ID_KNUCKLES) {42int32 center = TO_FIXED(ScreenInfo->center.x + 16);4344drawPos.x = 2 * self->gotThroughPos.x + center;45verts[0].x = drawPos.x - TO_FIXED(145);46verts[1].x = drawPos.x + TO_FIXED(52);47verts[2].x = drawPos.x + TO_FIXED(68);48verts[3].x = drawPos.x - TO_FIXED(129);49RSDK.DrawFace(verts, 4, 0x00, 0x00, 0x00, 0xFF, INK_NONE);5051drawPos.x = 2 * self->playerNamePos.x + center;52drawPos.y = self->playerNamePos.y;53verts[0].x = drawPos.x - TO_FIXED(124);54verts[0].y = drawPos.y + TO_FIXED(28);55verts[1].x = drawPos.x + TO_FIXED(80);56verts[2].x = drawPos.x + TO_FIXED(96);57verts[3].x = drawPos.x - TO_FIXED(108);58verts[1].y = drawPos.y + TO_FIXED(28);59verts[2].y = drawPos.y + TO_FIXED(44);60verts[3].y = drawPos.y + TO_FIXED(44);61RSDK.DrawFace(verts, 4, 0x00, 0x00, 0x00, 0xFF, INK_NONE);6263drawPos.x = self->playerNamePos.x + center;64drawPos.y = self->playerNamePos.y;65RSDK.DrawSprite(&self->playerNameAnimator, &drawPos, true);6667self->gotThroughAnimator.frameID = 2;68RSDK.DrawSprite(&self->gotThroughAnimator, &drawPos, true);6970drawPos.x = self->gotThroughPos.x + center;71drawPos.y = self->gotThroughPos.y;72self->gotThroughAnimator.frameID = 3;73RSDK.DrawSprite(&self->gotThroughAnimator, &drawPos, true);74RSDK.DrawSprite(&self->actNumAnimator, &drawPos, true);7576offset = center - TO_FIXED(10);77}78else {79int32 center = TO_FIXED(ScreenInfo->center.x);8081drawPos.x = 2 * self->gotThroughPos.x + center;82verts[0].x = drawPos.x - TO_FIXED(109);83verts[1].x = drawPos.x + TO_FIXED(52);84verts[2].x = drawPos.x + TO_FIXED(68);85verts[3].x = drawPos.x - TO_FIXED(93);86RSDK.DrawFace(verts, 4, 0x00, 0x00, 0x00, 0xFF, INK_NONE);8788drawPos.x = 2 * self->playerNamePos.x + center;89drawPos.y = self->playerNamePos.y;90verts[0].x = drawPos.x - TO_FIXED(88);91verts[0].y = drawPos.y + TO_FIXED(28);92verts[1].x = drawPos.x + TO_FIXED(80);93verts[2].x = drawPos.x + TO_FIXED(96);94verts[3].x = drawPos.x - TO_FIXED(72);95verts[1].y = drawPos.y + TO_FIXED(28);96verts[2].y = drawPos.y + TO_FIXED(44);97verts[3].y = drawPos.y + TO_FIXED(44);98RSDK.DrawFace(verts, 4, 0x00, 0x00, 0x00, 0xFF, INK_NONE);99100drawPos.x = self->playerNamePos.x + center;101drawPos.y = self->playerNamePos.y;102RSDK.DrawSprite(&self->playerNameAnimator, &drawPos, true);103104#if MANIA_USE_PLUS105if ((GET_CHARACTER_ID(1)) == ID_MIGHTY)106self->gotThroughAnimator.frameID = 2;107else108#endif109self->gotThroughAnimator.frameID = 0;110RSDK.DrawSprite(&self->gotThroughAnimator, &drawPos, true);111112drawPos.x = self->gotThroughPos.x + center;113drawPos.y = self->gotThroughPos.y;114self->gotThroughAnimator.frameID = 1;115RSDK.DrawSprite(&self->gotThroughAnimator, &drawPos, true);116RSDK.DrawSprite(&self->actNumAnimator, &drawPos, true);117118offset = center + TO_FIXED(6);119}120121// Draw "Time" Bonus Sprite122drawPos.x = offset + self->timeBonusPos.x - TO_FIXED(92);123drawPos.y = self->timeBonusPos.y;124self->hudElementsAnimator.frameID = 1;125RSDK.DrawSprite(&self->hudElementsAnimator, &drawPos, true);126127// Draw "Bonus" Sprite128drawPos.x += TO_FIXED(50);129#if MANIA_USE_PLUS130if (globals->gameMode != MODE_TIMEATTACK) {131#endif132self->hudElementsAnimator.frameID = 8; // "Bonus"133RSDK.DrawSprite(&self->hudElementsAnimator, &drawPos, true);134#if MANIA_USE_PLUS135}136#endif137138// Draw Time Bonus BG thingy139self->hudElementsAnimator.frameID = 10;140drawPos.x += TO_FIXED(52);141RSDK.DrawSprite(&self->hudElementsAnimator, &drawPos, true);142143drawPos.x += TO_FIXED(67);144drawPos.y += TO_FIXED(14);145146#if MANIA_USE_PLUS147if (globals->gameMode == MODE_TIMEATTACK) {148drawPos.x -= TO_FIXED(98);149drawPos.y -= TO_FIXED(14);150// Draw Current Time151ActClear_DrawTime(&drawPos, SceneInfo->minutes, SceneInfo->seconds, SceneInfo->milliseconds);152}153else {154#endif155ActClear_DrawNumbers(&drawPos, self->timeBonus, 0); // Draw Time Bonus156#if MANIA_USE_PLUS157}158#endif159160// Draw Ring Bonus161drawPos.x = offset + self->ringBonusPos.x - TO_FIXED(92);162drawPos.y = self->ringBonusPos.y;163#if MANIA_USE_PLUS164if (globals->gameMode == MODE_TIMEATTACK)165self->hudElementsAnimator.frameID = 17; // "Best"166else167#endif168self->hudElementsAnimator.frameID = 5; // "Ring"169RSDK.DrawSprite(&self->hudElementsAnimator, &drawPos, true);170171drawPos.x += TO_FIXED(50);172#if MANIA_USE_PLUS173if (globals->gameMode == MODE_TIMEATTACK) {174drawPos.x -= TO_FIXED(10);175self->hudElementsAnimator.frameID = 1; // "Time"176RSDK.DrawSprite(&self->hudElementsAnimator, &drawPos, true);177drawPos.x += TO_FIXED(10);178}179else {180#endif181self->hudElementsAnimator.frameID = 8; // "Bonus"182RSDK.DrawSprite(&self->hudElementsAnimator, &drawPos, true);183#if MANIA_USE_PLUS184}185#endif186187// Draw Ring Bonus BG thingy188self->hudElementsAnimator.frameID = 10;189drawPos.x += TO_FIXED(52);190RSDK.DrawSprite(&self->hudElementsAnimator, &drawPos, true);191192drawPos.x += TO_FIXED(67);193drawPos.y += TO_FIXED(14);194#if MANIA_USE_PLUS195if (globals->gameMode == MODE_TIMEATTACK) { // Draw Best Time196TimeAttackData_GetUnpackedTime(self->time, &minutes, &seconds, &milliseconds);197drawPos.x -= TO_FIXED(98);198drawPos.y -= TO_FIXED(14);199if (!self->isNewRecord || (self->isNewRecord && (Zone->timer & 8)))200ActClear_DrawTime(&drawPos, minutes, seconds, milliseconds);201}202else {203#endif204ActClear_DrawNumbers(&drawPos, self->ringBonus, 0);205#if MANIA_USE_PLUS206}207#endif208209if (self->showCoolBonus) { // Draw Cool Bonus210drawPos.x = offset + self->coolBonusPos.x - TO_FIXED(92);211drawPos.y = self->coolBonusPos.y;212#if MANIA_USE_PLUS213if (globals->gameMode == MODE_TIMEATTACK)214self->hudElementsAnimator.frameID = 18; // "Rank"215else216#endif217self->hudElementsAnimator.frameID = 15; // "Cool"218RSDK.DrawSprite(&self->hudElementsAnimator, &drawPos, true);219220drawPos.x += TO_FIXED(50);221#if MANIA_USE_PLUS222if (globals->gameMode != MODE_TIMEATTACK) {223#endif224self->hudElementsAnimator.frameID = 8; // "Bonus"225RSDK.DrawSprite(&self->hudElementsAnimator, &drawPos, true);226#if MANIA_USE_PLUS227}228#endif229230// Draw Cool Bonus BG thingy231self->hudElementsAnimator.frameID = 10;232drawPos.x += TO_FIXED(52);233RSDK.DrawSprite(&self->hudElementsAnimator, &drawPos, true);234235drawPos.x += TO_FIXED(67);236drawPos.y += TO_FIXED(14);237#if MANIA_USE_PLUS238if (globals->gameMode != MODE_TIMEATTACK) {239#endif240ActClear_DrawNumbers(&drawPos, self->coolBonus, 0); // Draw Cool bonus241#if MANIA_USE_PLUS242}243else {244// Draw Rank245if (!TimeAttackData->personalRank) {246self->numbersAnimator.frameID = 16;247RSDK.DrawSprite(&self->numbersAnimator, &drawPos, true);248249drawPos.x -= TO_FIXED(9);250}251else if (!self->achievedRank || (self->achievedRank && (Zone->timer & 8)))252ActClear_DrawNumbers(&drawPos, TimeAttackData->personalRank, 0);253}254#endif255}256257drawPos.x = self->totalScorePos.x;258drawPos.y = self->totalScorePos.y;259260#if MANIA_USE_PLUS261if (globals->gameMode == MODE_TIMEATTACK) {262// Draw World Rank263drawPos.x = offset + self->totalScorePos.x - TO_FIXED(92);264self->hudElementsAnimator.frameID = 19; // "World"265RSDK.DrawSprite(&self->hudElementsAnimator, &drawPos, true);266267drawPos.x += TO_FIXED(50);268self->hudElementsAnimator.frameID = 18; // "Rank"269RSDK.DrawSprite(&self->hudElementsAnimator, &drawPos, true);270271// Draw World Rank BG thingy272self->hudElementsAnimator.frameID = 10;273drawPos.x += TO_FIXED(52);274RSDK.DrawSprite(&self->hudElementsAnimator, &drawPos, true);275276drawPos.x += TO_FIXED(67);277drawPos.y += TO_FIXED(14);278if (!TimeAttackData->leaderboardRank) {279self->numbersAnimator.frameID = 16; // "-" (no rank)280RSDK.DrawSprite(&self->numbersAnimator, &drawPos, true);281}282else {283// Draw Rank284ActClear_DrawNumbers(&drawPos, TimeAttackData->leaderboardRank, 0);285}286}287else {288#endif289// Draw Total Score290drawPos.x = offset + self->totalScorePos.x - TO_FIXED(68);291self->hudElementsAnimator.frameID = 9; // "Total"292RSDK.DrawSprite(&self->hudElementsAnimator, &drawPos, true);293294// Draw Total Score BG thingy295self->hudElementsAnimator.frameID = 10;296drawPos.x += TO_FIXED(52);297RSDK.DrawSprite(&self->hudElementsAnimator, &drawPos, true);298299// Draw Total Score300drawPos.x += TO_FIXED(67);301drawPos.y += TO_FIXED(14);302ActClear_DrawNumbers(&drawPos, self->totalScore, 0);303#if MANIA_USE_PLUS304}305#endif306}307308void ActClear_Create(void *data)309{310RSDK_THIS(ActClear);311if (!SceneInfo->inEditor) {312#if MANIA_USE_PLUS313ActClear->actClearActive = true;314#endif315self->active = ACTIVE_NORMAL;316self->visible = true;317self->drawGroup = Zone->hudDrawGroup;318self->state = ActClear_State_EnterText;319self->stageFinishTimer = 0;320self->newRecordTimer = 0;321322EntityPlayer *player1 = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);323self->targetPlayer = player1;324325if (Zone_GetZoneID() > ZONE_INVALID) {326uint16 time = TimeAttackData_GetPackedTime(SceneInfo->minutes, SceneInfo->seconds, SceneInfo->milliseconds);327328#if MANIA_USE_PLUS329StatInfo stat;330switch (GET_CHARACTER_ID(1)) {331case ID_SONIC: TimeAttackData_TrackActClear(&stat, Zone_GetZoneID(), Zone->actID, 1, time, player1->rings, player1->score); break;332case ID_TAILS: TimeAttackData_TrackActClear(&stat, Zone_GetZoneID(), Zone->actID, 2, time, player1->rings, player1->score); break;333case ID_KNUCKLES: TimeAttackData_TrackActClear(&stat, Zone_GetZoneID(), Zone->actID, 3, time, player1->rings, player1->score); break;334case ID_MIGHTY: TimeAttackData_TrackActClear(&stat, Zone_GetZoneID(), Zone->actID, 4, time, player1->rings, player1->score); break;335default:336case ID_RAY:337if ((GET_CHARACTER_ID(1)) == ID_RAY)338TimeAttackData_TrackActClear(&stat, Zone_GetZoneID(), Zone->actID, 5, time, player1->rings, player1->score);339else340TimeAttackData_TrackActClear(&stat, Zone_GetZoneID(), Zone->actID, 1, time, player1->rings, player1->score);341break;342}343API.TryTrackStat(&stat);344#else345switch (GET_CHARACTER_ID(1)) {346case ID_SONIC: APICallback_TrackActClear(Zone_GetZoneID(), Zone->actID, 1, time, player1->rings, player1->score); break;347case ID_TAILS: APICallback_TrackActClear(Zone_GetZoneID(), Zone->actID, 2, time, player1->rings, player1->score); break;348case ID_KNUCKLES: APICallback_TrackActClear(Zone_GetZoneID(), Zone->actID, 3, time, player1->rings, player1->score); break;349default: break;350}351#endif352}353354#if MANIA_USE_PLUS355if (!ActClear->disableTimeBonus) {356#endif357switch (SceneInfo->minutes) {358case 0:359if (SceneInfo->seconds >= 30)360self->timeBonus = SceneInfo->seconds < 45 ? 10000 : 5000;361else362self->timeBonus = 50000;363break;364365case 1: self->timeBonus = SceneInfo->seconds < 30 ? 4000 : 3000; break;366case 2: self->timeBonus = 2000; break;367case 3: self->timeBonus = 1000; break;368case 4: self->timeBonus = 500; break;369case 5: self->timeBonus = 100; break;370371case 9:372if (!SceneInfo->debugMode && globals->gameMode < MODE_TIMEATTACK && SceneInfo->seconds == 59) {373#if MANIA_USE_PLUS374if (globals->gameMode != MODE_ENCORE && !(globals->medalMods & MEDAL_NOTIMEOVER))375#endif376self->timeBonus = 100000;377}378break;379380default: break;381}382#if MANIA_USE_PLUS383}384#endif385386self->ringBonus = 100 * player1->rings;387self->coolBonus = globals->coolBonus[0];388globals->initCoolBonus = false;389#if MANIA_USE_PLUS390if (globals->gameMode == MODE_TIMEATTACK) {391EntityMenuParam *param = MenuParam_GetParam();392self->time =393TimeAttackData_GetScore(param->zoneID, param->actID, param->characterID, SceneInfo->filter == (FILTER_BOTH | FILTER_ENCORE), 1);394self->achievedRank = false;395self->isNewRecord = false;396}397#endif398self->showCoolBonus = true;399self->playerNamePos.x = TO_FIXED(224);400self->playerNamePos.y = TO_FIXED(88);401self->gotThroughPos.x = -TO_FIXED(224);402self->gotThroughPos.y = TO_FIXED(112);403self->timeBonusPos.x = TO_FIXED(488);404self->timeBonusPos.y = TO_FIXED(120);405self->ringBonusPos.x = TO_FIXED(776);406self->ringBonusPos.y = TO_FIXED(136);407self->coolBonusPos.x = TO_FIXED(1064);408self->coolBonusPos.y = TO_FIXED(152);409self->totalScorePos.x = -TO_FIXED(1352);410self->totalScorePos.y = TO_FIXED(192);411412RSDK.SetSpriteAnimation(ActClear->aniFrames, 0, &self->hudElementsAnimator, true, 0);413RSDK.SetSpriteAnimation(ActClear->aniFrames, 1, &self->numbersAnimator, true, 0);414#if MANIA_USE_PLUS415RSDK.SetSpriteAnimation(ActClear->aniFrames, 0, &self->timeElementsAnimator, true, 12);416#endif417418switch (GET_CHARACTER_ID(1)) {419default:420case ID_SONIC: RSDK.SetSpriteAnimation(ActClear->aniFrames, 3, &self->playerNameAnimator, true, 0); break;421case ID_TAILS: RSDK.SetSpriteAnimation(ActClear->aniFrames, 3, &self->playerNameAnimator, true, 1); break;422case ID_KNUCKLES: RSDK.SetSpriteAnimation(ActClear->aniFrames, 3, &self->playerNameAnimator, true, 2); break;423#if MANIA_USE_PLUS424case ID_MIGHTY: RSDK.SetSpriteAnimation(ActClear->aniFrames, 3, &self->playerNameAnimator, true, 3); break;425case ID_RAY: RSDK.SetSpriteAnimation(ActClear->aniFrames, 3, &self->playerNameAnimator, true, 4); break;426#endif427}428RSDK.SetSpriteAnimation(ActClear->aniFrames, 4, &self->gotThroughAnimator, true, 0);429430// Used in cases like OOZ1 outro where the act clear actually happens in OOZ2431if (ActClear->displayedActID <= 0)432RSDK.SetSpriteAnimation(ActClear->aniFrames, 5, &self->actNumAnimator, true, Zone->actID);433else434RSDK.SetSpriteAnimation(ActClear->aniFrames, 5, &self->actNumAnimator, true, ActClear->displayedActID - 1);435}436}437438void ActClear_StageLoad(void)439{440ActClear->aniFrames = RSDK.LoadSpriteAnimation("Global/HUD.bin", SCOPE_STAGE);441442ActClear->sfxScoreAdd = RSDK.GetSfx("Global/ScoreAdd.wav");443ActClear->sfxScoreTotal = RSDK.GetSfx("Global/ScoreTotal.wav");444#if MANIA_USE_PLUS445ActClear->sfxEvent = RSDK.GetSfx("Special/Event.wav");446447ActClear->actClearActive = false;448ActClear->forceNoSave = false;449#endif450}451452#if MANIA_USE_PLUS453void ActClear_DrawTime(Vector2 *drawPosPtr, int32 mins, int32 secs, int32 millisecs)454{455RSDK_THIS(ActClear);456457Vector2 drawPos;458if (!mins && !secs && !millisecs) {459millisecs = -1;460secs = -1;461mins = -1;462}463464// The ":" thing465drawPos.x = drawPosPtr->x + TO_FIXED(50);466drawPos.y = drawPosPtr->y - TO_FIXED(2);467RSDK.DrawSprite(&self->timeElementsAnimator, &drawPos, true);468469// Miliseconds470drawPos.x = drawPosPtr->x + TO_FIXED(97);471drawPos.y = drawPosPtr->y + TO_FIXED(14);472ActClear_DrawNumbers(&drawPos, millisecs, 2);473474// Seconds475drawPos.x -= TO_FIXED(9);476if (!mins && !secs && !millisecs)477secs = -1;478ActClear_DrawNumbers(&drawPos, secs, 2);479480// Minutes481drawPos.x -= TO_FIXED(9);482if (!mins && !secs && !millisecs)483mins = -1;484ActClear_DrawNumbers(&drawPos, mins, 1);485}486#endif487488void ActClear_DrawNumbers(Vector2 *drawPos, int32 value, int32 digitCount)489{490RSDK_THIS(ActClear);491492if (value >= 0) {493if (!digitCount && value > 0) {494int32 v = value;495while (v > 0) {496++digitCount;497v /= 10;498}499}500else {501if (!digitCount && !value)502digitCount = 1;503}504505if (digitCount > 0) {506int32 digit = 1;507while (digitCount--) {508self->numbersAnimator.frameID = value / digit % 10;509RSDK.DrawSprite(&self->numbersAnimator, drawPos, true);510511drawPos->x -= TO_FIXED(9);512digit *= 10;513}514}515}516else {517while (digitCount--) {518self->numbersAnimator.frameID = 16;519RSDK.DrawSprite(&self->numbersAnimator, drawPos, true);520521drawPos->x -= TO_FIXED(9);522}523}524}525void ActClear_CheckPlayerVictory(void)526{527foreach_active(Player, player)528{529if (player->state != Player_State_FlyToPlayer && player->state != Player_State_ReturnToPlayer && player->state != Player_State_Victory530&& player->onGround) {531player->state = Player_State_Victory;532player->nextAirState = StateMachine_None;533player->nextGroundState = StateMachine_None;534if (Zone->shouldRecoverPlayers)535player->stateInput = StateMachine_None;536537RSDK.SetSpriteAnimation(player->aniFrames, ANI_VICTORY, &player->animator, true, 0);538}539}540}541542#if MANIA_USE_PLUS543void ActClear_SaveGameCallback(bool32 success)544{545UIWaitSpinner_FinishWait();546ActClear->isSavingGame = false;547}548#else549void ActClear_SaveGameCallback(void)550{551UIWaitSpinner_FinishWait();552ActClear->isSavingGame = false;553}554#endif555556void ActClear_SetupRecoverPlayers(void)557{558EntityPlayer *player1 = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);559EntityPlayer *player2 = RSDK_GET_ENTITY(SLOT_PLAYER2, Player);560561if (player2 && player2->sidekick) {562if (player2->state != Player_State_FlyToPlayer && player2->state != Player_State_ReturnToPlayer) {563if (player2->position.x <= TO_FIXED(ScreenInfo->size.x + ScreenInfo->position.x)564|| abs(player2->position.y - player1->position.y) > TO_FIXED(16)) {565Player->respawnTimer = 240;566567Entity *entStore = SceneInfo->entity;568SceneInfo->entity = (Entity *)player2;569Player_HandleSidekickRespawn();570SceneInfo->entity = entStore;571572if (player2->state == Player_State_FlyToPlayer || player2->state == Player_State_ReturnToPlayer573|| player2->state == Player_State_HoldRespawn) {574player2->active = ACTIVE_NORMAL;575player2->position.y = TO_FIXED(ScreenInfo->position.y - 16);576}577}578else {579Player->respawnTimer = -3600;580}581}582}583}584585void ActClear_State_EnterText(void)586{587RSDK_THIS(ActClear);588589if (self->playerNamePos.x > 0)590self->playerNamePos.x -= TO_FIXED(16);591592if (self->gotThroughPos.x < 0)593self->gotThroughPos.x += TO_FIXED(16);594595if (!self->timer && Zone->shouldRecoverPlayers)596ActClear_SetupRecoverPlayers();597598if (++self->timer == 48) {599self->timer = 0;600self->state = ActClear_State_AdjustText;601}602603ActClear_CheckPlayerVictory();604}605606void ActClear_State_AdjustText(void)607{608RSDK_THIS(ActClear);609610self->playerNamePos.y -= 0x8000;611self->gotThroughPos.y -= 0x8000;612613if (++self->timer == 48) {614self->timer = 0;615self->state = ActClear_State_EnterResults;616}617618ActClear_CheckPlayerVictory();619}620621void ActClear_State_EnterResults(void)622{623RSDK_THIS(ActClear);624625if (self->timeBonusPos.x > 0)626self->timeBonusPos.x -= TO_FIXED(16);627628if (self->ringBonusPos.x > 0)629self->ringBonusPos.x -= TO_FIXED(16);630631if (self->coolBonusPos.x > 0)632self->coolBonusPos.x -= TO_FIXED(16);633634if (self->totalScorePos.x < -TO_FIXED(8)) {635self->totalScorePos.x += TO_FIXED(16);636}637else {638#if MANIA_USE_PLUS639if (globals->gameMode == MODE_TIMEATTACK) {640if (ActClear->bufferMoveEnabled) {641StateMachine_Run(ActClear->bufferMove_CB);642}643644HUD->showTAPrompt = true;645ActClear->hasSavedReplay = false;646self->newRecordTimer = 240;647self->state = ActClear_State_ShowResultsTA;648RSDK.SetScene("Presentation", "Menu");649}650else {651self->state = ActClear_State_ScoreShownDelay;652}653#else654self->state = ActClear_State_ScoreShownDelay;655#endif656}657658ActClear_CheckPlayerVictory();659}660661void ActClear_State_ScoreShownDelay(void)662{663RSDK_THIS(ActClear);664665if (++self->timer == 120) {666self->timer = 0;667self->state = ActClear_State_TallyScore;668}669670ActClear_CheckPlayerVictory();671}672673void ActClear_State_TallyScore(void)674{675RSDK_THIS(ActClear);676677EntityPlayer *player = self->targetPlayer;678679if (self->timeBonus > 0) {680self->totalScore += 100;681self->timeBonus -= 100;682Player_GiveScore(player, 100);683}684685if (self->ringBonus > 0) {686self->totalScore += 100;687self->ringBonus -= 100;688Player_GiveScore(player, 100);689}690691if (self->coolBonus > 0) {692self->totalScore += 100;693self->coolBonus -= 100;694Player_GiveScore(player, 100);695}696697if (ControllerInfo[player->controllerID].keyA.press || ControllerInfo[player->controllerID].keyStart.press) {698Player_GiveScore(player, self->timeBonus + self->ringBonus + self->coolBonus);699self->totalScore += self->timeBonus + self->ringBonus + self->coolBonus;700self->timeBonus = 0;701self->ringBonus = 0;702self->coolBonus = 0;703}704705if (self->timeBonus + self->ringBonus + self->coolBonus <= 0) {706self->timer = 0;707self->state = ActClear_State_SaveGameProgress;708RSDK.PlaySfx(ActClear->sfxScoreTotal, false, 255);709}710else if (++self->timer == 2) {711self->timer = 0;712RSDK.PlaySfx(ActClear->sfxScoreAdd, false, 255);713}714715Music->nextTrack = TRACK_NONE;716ActClear_CheckPlayerVictory();717}718719void ActClear_State_SaveGameProgress(void)720{721RSDK_THIS(ActClear);722723if (++self->timer == 120) {724self->timer = 0;725globals->specialRingID = 0;726if (ActClear->displayedActID <= 0) {727if (globals->gameMode == MODE_COMPETITION) {728RSDK.SetScene("Presentation", "Menu");729}730#if !MANIA_USE_PLUS731else if (globals->gameMode == MODE_TIMEATTACK) {732EntityMenuParam *param = MenuParam_GetParam();733ActClear->isSavingGame = true;734uint8 characterID = param->characterID;735uint8 zoneID = param->zoneID;736uint8 act = param->actID;737738int32 time = 6000 * SceneInfo->minutes + 100 * SceneInfo->seconds + SceneInfo->milliseconds;739740uint16 *record = TimeAttackData_GetRecordedTime(zoneID, act, characterID, 1);741int32 rank = 0;742for (; rank < 3; ++rank) {743if (!record[rank] || time < record[rank])744break;745}746747if (rank < 3) {748rank++;749TimeAttackData_AddRecord(zoneID, act, characterID, rank, time);750APICallback_TrackTAClear(zoneID, act, characterID, time);751param->timeScore = rank;752SaveGame_SaveFile(ActClear_SaveGameCallback);753}754else {755ActClear->isSavingGame = false;756}757758RSDK.SetScene("Presentation", "Menu");759}760#endif761else {762globals->enableIntro = true;763Player_SaveValues();764SaveGame_ClearRestartData();765StarPost_ResetStarPosts();766if (Zone->actID > 0)767SaveGame_ClearCollectedSpecialRings();768SaveGame_SaveProgress();769#if MANIA_USE_PLUS770if (globals->saveSlotID != NO_SAVE_SLOT && !ActClear->forceNoSave) {771#else772if (globals->gameMode == MODE_MANIA) {773#endif774if (Zone_IsZoneLastAct())775GameProgress_MarkZoneCompleted(Zone_GetZoneID());776777ActClear->isSavingGame = true;778SaveGame_SaveFile(ActClear_SaveGameCallback);779}780781++SceneInfo->listPos;782if (!RSDK.CheckValidScene())783RSDK.SetScene("Presentation", "Title Screen");784}785}786else {787Player_SaveValues();788SaveGame_ClearRestartData();789StarPost_ResetStarPosts();790SaveGame_SaveProgress();791792#if MANIA_USE_PLUS793if (globals->saveSlotID != NO_SAVE_SLOT && !ActClear->forceNoSave) {794#else795if (globals->gameMode == MODE_MANIA) {796#endif797ActClear->isSavingGame = true;798SaveGame_SaveFile(ActClear_SaveGameCallback);799}800}801802if (ActClear->isSavingGame)803UIWaitSpinner_StartWait();804805self->state = ActClear_State_WaitForSave;806ActClear_State_WaitForSave();807}808}809810#if MANIA_USE_PLUS811void ActClear_State_ShowResultsTA(void)812{813RSDK_THIS(ActClear);814815if (self->newRecordTimer > 0) {816if (TimeAttackData->personalRank > 0 && !ReplayRecorder->hasSetupGhostView) {817if (self->newRecordTimer == 120) {818if (TimeAttackData->personalRank == 1)819self->isNewRecord = true;820821self->achievedRank = true;822RSDK.PlaySfx(ActClear->sfxEvent, false, 255);823}824825if (self->newRecordTimer == 30) {826if (TimeAttackData->personalRank == 1)827RSDK.PlaySfx(Announcer->sfxNewRecordTop, false, 255);828else if (TimeAttackData->personalRank <= 3)829RSDK.PlaySfx(Announcer->sfxNewRecordMid, false, 255);830}831}832--self->newRecordTimer;833}834835if (!ActClear->isSavingGame && !ActClear->disableResultsInput) {836if (ControllerInfo->keyY.press) {837if (!ActClear->hasSavedReplay) {838if (HUD->replaySaveEnabled) {839if (!UIDialog->activeDialog) {840if (API.CheckDLC(DLC_PLUS)) {841StateMachine_Run(ActClear->saveReplay_CB);842ActClear->hasSavedReplay = true;843ActClear->disableResultsInput = true;844return;845}846}847}848}849}850851if (ControllerInfo->keyStart.press) {852RSDK.PlaySfx(UIWidgets->sfxAccept, false, 255);853854ActClear_State_WaitForSave();855}856}857}858#endif859860void ActClear_State_WaitForSave(void)861{862RSDK_THIS(ActClear);863864if (!ActClear->isSavingGame) {865if (ActClear->displayedActID > 0 || Zone->stageFinishCallback) {866self->state = ActClear_State_ExitActClear;867}868else {869self->state = StateMachine_None;870Zone_StartFadeOut(10, 0x000000);871}872}873}874875void ActClear_State_ExitActClear(void)876{877RSDK_THIS(ActClear);878879self->playerNamePos.x += TO_FIXED(32);880self->gotThroughPos.x -= TO_FIXED(32);881882if (self->playerNamePos.x > TO_FIXED(64))883self->timeBonusPos.x += TO_FIXED(32);884885if (self->timeBonusPos.x > TO_FIXED(64))886self->ringBonusPos.x += TO_FIXED(32);887888if (self->ringBonusPos.x > TO_FIXED(64))889self->coolBonusPos.x += TO_FIXED(32);890891if (self->coolBonusPos.x > TO_FIXED(64))892self->totalScorePos.x -= TO_FIXED(32);893894if (self->totalScorePos.x < -TO_FIXED(512)) {895if (ActClear->displayedActID <= 0) {896if (Zone->stageFinishCallback) {897if (Zone->shouldRecoverPlayers) {898self->timer = 0;899self->state = ActClear_State_RecoverPlayers;900}901else {902foreach_active(Animals, animal)903{904if (animal->behaviour == ANIMAL_BEHAVE_FOLLOW)905animal->behaviour = ANIMAL_BEHAVE_FREE;906}907#if RETRO_USE_MOD_LOADER908StateMachine_Run(Zone->stageFinishCallback);909#else910Zone->stageFinishCallback();911#endif912Zone->stageFinishCallback = StateMachine_None;913}914}915}916else {917ActClear->finished = true;918ActClear->displayedActID = 0;919SceneInfo->milliseconds = 0;920SceneInfo->seconds = 0;921SceneInfo->minutes = 0;922foreach_active(Player, player)923{924player->ringExtraLife = 100;925player->rings = 0;926}927}928929if (self->state != ActClear_State_RecoverPlayers)930destroyEntity(self);931}932}933934void ActClear_State_RecoverPlayers(void)935{936RSDK_THIS(ActClear);937938EntityPlayer *player1 = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);939EntityPlayer *player2 = RSDK_GET_ENTITY(SLOT_PLAYER2, Player);940941bool32 finishedP2 = false;942bool32 finishedP1 = false;943int32 screenOffX = TO_FIXED(ScreenInfo->position.x + ScreenInfo->size.x - 16);944player1->up = false;945player1->down = false;946player1->jumpPress = false;947player1->jumpHold = false;948949if (player1->position.x >= screenOffX) {950player1->stateInput = StateMachine_None;951player1->state = Player_State_Ground;952player1->groundVel = -0x40000;953player1->left = true;954player1->right = false;955}956else {957if ((!player1->onGround || player1->groundVel) && player1->position.x < screenOffX - (ScreenInfo->center.x << 15)) {958player1->right = true;959if (!player1->skidding) {960if (!player1->left)961player1->right = false;962else963player1->left = false;964}965}966967if (player1->onGround && !player1->groundVel)968finishedP1 = true;969}970971if (player2->classID != Player->classID) {972finishedP2 = true;973}974else {975player2->up = false;976player2->down = false;977player2->jumpPress = false;978player2->jumpHold = false;979980if (player2->state == Player_State_FlyToPlayer || player2->state == Player_State_ReturnToPlayer) {981if (player2->position.x < screenOffX) {982if (player2->onGround && !player2->groundVel) {983RSDK.SetSpriteAnimation(player2->aniFrames, ANI_IDLE, &player2->animator, false, 0);984player2->direction = FLIP_NONE;985finishedP2 = true;986}987}988}989else if (player2->position.x >= screenOffX) {990player2->stateInput = Player_Input_P2_AI;991RSDK.SetSpriteAnimation(player2->aniFrames, ANI_RUN, &player2->animator, false, 0);992player2->state = Player_State_Ground;993player2->groundVel = -TO_FIXED(4);994player2->left = true;995player2->right = false;996997if (player2->position.x < screenOffX) {998if (player2->onGround && !player2->groundVel) {999RSDK.SetSpriteAnimation(player2->aniFrames, ANI_IDLE, &player2->animator, false, 0);1000player2->direction = FLIP_NONE;1001finishedP2 = true;1002}1003}1004}1005else {1006if (player2->onGround && !player2->groundVel) {1007RSDK.SetSpriteAnimation(player2->aniFrames, ANI_IDLE, &player2->animator, false, 0);1008player2->direction = FLIP_NONE;1009finishedP2 = true;1010}1011}1012}10131014if (finishedP1) {1015RSDK.SetSpriteAnimation(player1->aniFrames, ANI_IDLE, &player1->animator, false, 0);1016player1->direction = FLIP_NONE;1017}10181019++self->stageFinishTimer;1020if ((finishedP1 && finishedP2) || self->stageFinishTimer >= 900) {1021if (self->timer >= 10) {1022Player->respawnTimer = 0;1023StateMachine_Run(Zone->stageFinishCallback);1024Zone->stageFinishCallback = StateMachine_None;1025destroyEntity(self);1026}1027else {1028self->timer++;1029}1030}1031}10321033#if GAME_INCLUDE_EDITOR1034void ActClear_EditorDraw(void) {}10351036void ActClear_EditorLoad(void) {}1037#endif10381039void ActClear_Serialize(void) {}104010411042