#include "scenes/credits_scene.hpp" #include #include #include "core/audio/audio.hpp" #include "core/jail/jdraw8.hpp" #include "core/jail/jinput.hpp" #include "game/info.hpp" #include "scenes/scene_utils.hpp" namespace { // Frames del cotxe: 8 posicions dins del sprite sheet gfx/final.gif. El // vell doCredits tenia aquesta taula inline — la reproduïm idèntica. struct CocheFrame { Uint16 x, y; }; constexpr CocheFrame COCHE_FRAMES[8] = { {214, 152}, {214, 104}, {214, 56}, {214, 104}, {214, 152}, {214, 8}, {108, 152}, {214, 8}, }; constexpr int CONTADOR_MAX = 3100; // ~62 s de crèdits a 20 ms/tick constexpr int TICK_MS = 20; // JG_SetUpdateTicks heretat del doSlides previ constexpr int BG_INDEX = 255; } // namespace namespace scenes { CreditsScene::~CreditsScene() { // No toquem la paleta activa: SetScreenPalette n'ha pres ownership. } void CreditsScene::onEnter() { // El vell doCredits no tocava música — heretava la del doSlides // previ ("music/final.ogg"). Si l'escena s'arrenca directament (test // amb piramide_inicial=8) no hi ha res que heretar, així que // arranquem la mateixa pista només si no sona res. Inocu en el // flux normal: JA_MUSIC_PLAYING fa que no la tornem a tocar. if (Audio::getRealMusicState() != Audio::MusicState::PLAYING) { playMusic("music/final.ogg"); } vaddr2_ = SurfaceHandle("gfx/final.gif"); vaddr3_ = SurfaceHandle("gfx/finals.gif"); JD8_Palette pal = JD8_LoadPalette("gfx/final.gif"); JD8_SetScreenPalette(pal); // `pal` passa a ser propietat de main_palette — no l'alliberem. phase_ = Phase::Rolling; contador_ = 1; contador_acc_ms_ = 0; } void CreditsScene::render() { JD8_ClearScreen(BG_INDEX); // Columna 1: scroll vertical del bloc (0,0,80,200) pujant des de // y=200 fins que el contador supera 2750. if (contador_ < 2750) { JD8_BlitCKCut(115, 200 - (contador_ / 6), vaddr2_, 0, 0, 80, 200, 0); } // Columna 2: scroll vertical del bloc (85,0,120,140), arrenca // a contador 1200 i s'atura (fix en y=20) a partir de 2250. if ((contador_ > 1200) && (contador_ < 2280)) { JD8_BlitCKCut(100, 200 - ((contador_ - 1200) / 6), vaddr2_, 85, 0, 120, 140, 0); } else if (contador_ >= 2250) { JD8_BlitCK(100, 20, vaddr2_, 85, 0, 120, 140, 0); } // Fons: 4 capes parallax + cotxe només si l'usuari ha aconseguit // tots els diamants (final "bo"). Altrament fons estàtic. if (info::ctx.diamants == 16) { JD8_BlitCKScroll(50, vaddr3_, ((contador_ >> 3) % 320) + 1, 0, 50, 255); JD8_BlitCKScroll(50, vaddr3_, ((contador_ >> 2) % 320) + 1, 50, 50, 255); JD8_BlitCKScroll(50, vaddr3_, ((contador_ >> 1) % 320) + 1, 100, 50, 255); JD8_BlitCKScroll(50, vaddr3_, (contador_ % 320) + 1, 150, 50, 255); const CocheFrame& cf = COCHE_FRAMES[coche_.frame()]; JD8_BlitCK(100, 50, vaddr2_, cf.x, cf.y, 106, 48, 255); } else { JD8_BlitCK(0, 50, vaddr3_, 0, 0, 320, 50, 255); JD8_BlitCK(0, 50, vaddr3_, 0, 50, 320, 50, 255); } // Barres de marc que cobreixen els extrems del scroll vertical. JD8_FillSquare(0, 50, BG_INDEX); JD8_FillSquare(100, 10, BG_INDEX); } void CreditsScene::writeTrickIni() { FILE* ini = std::fopen("trick.ini", "wb"); if (ini) { std::fwrite("1", 1, 1, ini); std::fclose(ini); } info::ctx.nou_personatge = true; } void CreditsScene::tick(int delta_ms) { switch (phase_) { case Phase::Rolling: { // Avancem el contador en passos discrets de 20 ms, igual // que feia JG_ShouldUpdate(20) al vell doCredits. contador_acc_ms_ += delta_ms; while (contador_acc_ms_ >= TICK_MS) { contador_acc_ms_ -= TICK_MS; ++contador_; } coche_.tick(delta_ms); render(); if (JI_AnyKey() || contador_ >= CONTADOR_MAX) { writeTrickIni(); fade_.startFadeOut(); phase_ = Phase::FadingOut; } break; } case Phase::FadingOut: fade_.tick(delta_ms); if (fade_.done()) { info::ctx.num_piramide = 255; phase_ = Phase::Done; } break; case Phase::Done: break; } } } // namespace scenes