#include "game/scenes/slides_scene.hpp" #include #include #include #include "core/audio/audio.hpp" #include "core/jail/jdraw8.hpp" #include "core/jail/jinput.hpp" #include "game/info.hpp" #include "game/scenes/scene_utils.hpp" #include "utils/easing.hpp" namespace { constexpr int SCROLL_MS = 1600; // 80 iters × 20 ms del vell doSlides constexpr int HOLD_MS = 4600; // 230 iters × 20 ms (80 + 150) del vell constexpr int SLIDE_Y = 65; constexpr int SLIDE_H = 65; constexpr int BG_COLOR_INDEX = 255; // Desplaçament inicial del slide segons direcció del wipe. // Slide 1 i 3: "scroll in from right" (POS_X va de 320 → 0). // Slide 2: "wipe reverse" (POS_X va de -320 → 0), el mateix efecte // estrany del doSlides vell on la imatge es desplaça des de l'esquerra // però revela primer el lateral dret del src. constexpr int SLIDE_START_X[3] = {320, -320, 320}; } // namespace namespace Scenes { SlidesScene::~SlidesScene() { delete[] pal_aux_; // pal_active_ NO s'allibera: propietat de main_palette via SetScreenPalette. } void SlidesScene::onEnter() { num_piramide_at_start_ = Info::ctx.num_piramide; const char* arxiu = nullptr; if (num_piramide_at_start_ == 7) { // loop=1 per replicar el vell `play_music("final.ogg", 1)`. playMusic("music/final.ogg", 1); arxiu = (Info::ctx.diners < 200) ? "gfx/intro2.gif" : "gfx/intro3.gif"; } else { arxiu = "gfx/intro.gif"; } gfx_ = SurfaceHandle(arxiu); pal_aux_ = Jd8::loadPalette(arxiu); // Còpia editable de la paleta. `pal_active_` comparteix memòria amb // main_palette després del SetScreenPalette — modificar-la modifica // main_palette directament. `pal_aux_` es manté intacte per a poder // restaurar després de cada fade-out intermedi. pal_active_ = new Color[256]; std::memcpy(pal_active_, pal_aux_, 768); Jd8::setScreenPalette(pal_active_); Jd8::clearScreen(BG_COLOR_INDEX); phase_ = Phase::SLIDE1_ENTER; phase_acc_ms_ = 0; next_state_ = 0; } void SlidesScene::drawSlide(int slide_idx, int pos_x) { const int SRC_Y = slide_idx * SLIDE_H; // Clipping manual: translada un rect de 320×65 des de (POS_X, SLIDE_Y) // a l'àrea visible (0..319, SLIDE_Y..SLIDE_Y+64). int dst_x = pos_x; int src_x = 0; int w = 320; if (dst_x < 0) { src_x = -dst_x; w = 320 + dst_x; dst_x = 0; } else if (dst_x > 0) { w = 320 - dst_x; } if (w > 0) { Jd8::blit(dst_x, SLIDE_Y, gfx_, src_x, SRC_Y, w, SLIDE_H); } } void SlidesScene::restorePalette() { std::memcpy(pal_active_, pal_aux_, 768); } void SlidesScene::beginFinalFade() { if (num_piramide_at_start_ != 7) { Audio::get()->fadeOutMusic(250); } fade_.startFadeOut(); phase_ = Phase::FADE_FINAL; } void SlidesScene::triggerSkip() { skip_triggered_ = true; if (num_piramide_at_start_ != 7) { Audio::get()->fadeOutMusic(250); } fade_.startFadeOut(); phase_ = Phase::FADE_FINAL; } void SlidesScene::tickSlideEnter(int delta_ms) { phase_acc_ms_ += delta_ms; int slide_idx = 2; if (phase_ == Phase::SLIDE1_ENTER) { slide_idx = 0; } else if (phase_ == Phase::SLIDE2_ENTER) { slide_idx = 1; } const float T = std::min(1.0F, static_cast(phase_acc_ms_) / static_cast(SCROLL_MS)); const float EASED = Easing::outCubic(T); drawSlide(slide_idx, Easing::lerpInt(SLIDE_START_X[slide_idx], 0, EASED)); if (phase_acc_ms_ < SCROLL_MS) { return; } drawSlide(slide_idx, 0); switch (phase_) { case Phase::SLIDE1_ENTER: phase_ = Phase::SLIDE1_HOLD; break; case Phase::SLIDE2_ENTER: phase_ = Phase::SLIDE2_HOLD; break; default: phase_ = Phase::SLIDE3_HOLD; break; } phase_acc_ms_ = 0; } void SlidesScene::tickHoldIntermediate(int delta_ms) { phase_acc_ms_ += delta_ms; if (phase_acc_ms_ < HOLD_MS) { return; } fade_.startFadeOut(); phase_ = (phase_ == Phase::SLIDE1_HOLD) ? Phase::FADE_OUT1 : Phase::FADE_OUT2; phase_acc_ms_ = 0; } void SlidesScene::tickFadeOutIntermediate(int delta_ms) { fade_.tick(delta_ms); if (!fade_.done()) { return; } restorePalette(); Jd8::clearScreen(BG_COLOR_INDEX); phase_ = (phase_ == Phase::FADE_OUT1) ? Phase::SLIDE2_ENTER : Phase::SLIDE3_ENTER; phase_acc_ms_ = 0; } void SlidesScene::tickFinalFade(int delta_ms) { fade_.tick(delta_ms); if (!fade_.done()) { return; } if (num_piramide_at_start_ == 7) { Info::ctx.num_piramide = 8; next_state_ = 1; } else { next_state_ = 0; } phase_ = Phase::DONE; } void SlidesScene::tick(int delta_ms) { if (!skip_triggered_ && Ji::anyKey()) { triggerSkip(); } switch (phase_) { case Phase::SLIDE1_ENTER: case Phase::SLIDE2_ENTER: case Phase::SLIDE3_ENTER: tickSlideEnter(delta_ms); break; case Phase::SLIDE1_HOLD: case Phase::SLIDE2_HOLD: tickHoldIntermediate(delta_ms); break; case Phase::SLIDE3_HOLD: phase_acc_ms_ += delta_ms; if (phase_acc_ms_ >= HOLD_MS) { beginFinalFade(); } break; case Phase::FADE_OUT1: case Phase::FADE_OUT2: tickFadeOutIntermediate(delta_ms); break; case Phase::FADE_FINAL: tickFinalFade(delta_ms); break; case Phase::DONE: break; } } } // namespace Scenes