step 7: secreta_scene amb swap de tomba1→tomba2 i red pulse animat
This commit is contained in:
@@ -27,6 +27,7 @@
|
||||
#include "scenes/mort_scene.hpp"
|
||||
#include "scenes/scene.hpp"
|
||||
#include "scenes/scene_registry.hpp"
|
||||
#include "scenes/secreta_scene.hpp"
|
||||
#include "scenes/slides_scene.hpp"
|
||||
|
||||
// Cheats del joc original — declarats a jinput.cpp
|
||||
@@ -43,7 +44,7 @@ namespace {
|
||||
void gameFiberEntry() {
|
||||
info::ctx.num_habitacio = Options::game.habitacio_inicial;
|
||||
info::ctx.num_piramide = Options::game.piramide_inicial;
|
||||
info::ctx.diners = 0;
|
||||
info::ctx.diners = Options::game.diners_inicial;
|
||||
info::ctx.diamants = Options::game.diamants_inicial;
|
||||
info::ctx.vida = Options::game.vides;
|
||||
info::ctx.momies = 0;
|
||||
@@ -130,6 +131,7 @@ void Director::init() {
|
||||
// l'usuari no té prou diners per a la Secreta)
|
||||
registry.registerScene(1, [] { return std::make_unique<scenes::SlidesScene>(); });
|
||||
registry.registerScene(7, [] { return std::make_unique<scenes::SlidesScene>(); });
|
||||
registry.registerScene(6, [] { return std::make_unique<scenes::SecretaScene>(); });
|
||||
registry.registerScene(8, [] { return std::make_unique<scenes::CreditsScene>(); });
|
||||
// IntroNewLogoScene només es registra quan `use_new_logo` està actiu;
|
||||
// si no, la factory retorna nullptr i el gameFiberEntry cau al vell
|
||||
|
||||
@@ -58,6 +58,7 @@ namespace Defaults::Game {
|
||||
constexpr int PIRAMIDE_INICIAL = 255;
|
||||
constexpr int VIDES = 5;
|
||||
constexpr int DIAMANTS_INICIAL = 0;
|
||||
constexpr int DINERS_INICIAL = 0;
|
||||
constexpr bool USE_NEW_LOGO = true;
|
||||
constexpr bool SHOW_TITLE_CREDITS = true;
|
||||
} // namespace Defaults::Game
|
||||
|
||||
@@ -41,9 +41,7 @@ int ModuleSequence::Go() {
|
||||
// case 0 (Menú) → migrat a scenes::MenuScene.
|
||||
// case 1 i 7 (Slides) → migrat a scenes::SlidesScene.
|
||||
// case 2..5 (Pre-piràmide) → migrat a scenes::BannerScene.
|
||||
case 6: // Pre-Secreta
|
||||
doSecreta();
|
||||
break;
|
||||
// case 6 (Pre-Secreta) → migrat a scenes::SecretaScene.
|
||||
// case 8 (Credits) → migrat a scenes::CreditsScene.
|
||||
// case 100 (Mort) → migrat a scenes::MortScene, dispatch via SceneRegistry.
|
||||
}
|
||||
@@ -822,92 +820,7 @@ void ModuleSequence::doIntroSprites(JD8_Surface gfx) {
|
||||
|
||||
// doBanner() — migrat a scenes::BannerScene (source/scenes/banner_scene.cpp)
|
||||
|
||||
void ModuleSequence::doSecreta() {
|
||||
play_music("00000002.ogg");
|
||||
JG_SetUpdateTicks(20);
|
||||
JD8_FadeOut();
|
||||
JD8_Surface gfx = JD8_LoadSurface("tomba1.gif");
|
||||
JD8_Palette pal_aux = JD8_LoadPalette("tomba1.gif");
|
||||
JD8_Palette pal = (JD8_Palette)malloc(768);
|
||||
memcpy(pal, pal_aux, 768);
|
||||
JD8_ClearScreen(255);
|
||||
JD8_SetScreenPalette(pal);
|
||||
|
||||
bool exit = false;
|
||||
int step = 0;
|
||||
contador = 1;
|
||||
while (!exit && !JG_Quitting()) {
|
||||
if (JG_ShouldUpdate()) {
|
||||
JI_Update();
|
||||
|
||||
if (JI_AnyKey()) {
|
||||
exit = true;
|
||||
}
|
||||
|
||||
switch (step) {
|
||||
case 0:
|
||||
JD8_Blit(70, 60, gfx, 0, contador, 178, 70); // Put_Sprite(from, where, 0 + (320 * i), 178, 70, 70, 60);
|
||||
JD8_BlitCK(70, 60, gfx, 178, contador >> 1, 142, 70, 255); // Put_Sprite(from, where, 178 + (320 * (i div 2)), 142, 70, 70, 60);
|
||||
JD8_Flip();
|
||||
contador++;
|
||||
if (contador == 128) step++;
|
||||
break;
|
||||
case 1:
|
||||
case 4:
|
||||
case 7:
|
||||
case 9:
|
||||
contador--;
|
||||
if (contador == 0) step++;
|
||||
break;
|
||||
case 2:
|
||||
JD8_ClearScreen(255);
|
||||
JD8_Flip();
|
||||
gfx = JD8_LoadSurface("tomba2.gif");
|
||||
pal_aux = JD8_LoadPalette("tomba2.gif");
|
||||
memcpy(pal, pal_aux, 768);
|
||||
JD8_SetScreenPalette(pal);
|
||||
step++;
|
||||
break;
|
||||
case 3:
|
||||
JD8_Blit(55, 53, gfx, 0, 158 - contador, 211, contador); // Put_Sprite(from, where, 0 + ((158 - i) * 320), 211, i, 55, 53);
|
||||
JD8_Flip();
|
||||
contador++;
|
||||
if (contador == 94) step++;
|
||||
break;
|
||||
case 5:
|
||||
JD8_ClearScreen(0);
|
||||
JD8_Flip();
|
||||
JD8_SetPaletteColor(254, 12, 11, 11);
|
||||
JD8_SetPaletteColor(253, 12, 11, 11);
|
||||
step++;
|
||||
break;
|
||||
case 6:
|
||||
JD8_Blit(80, 68, gfx, 160 - (contador * 2), 0, contador * 2, 64); // Put_Sprite(from, where, 160 - (i * 2), (i * 2), 64, 80, 68);
|
||||
JD8_Flip();
|
||||
contador++;
|
||||
if (contador == 80) step++;
|
||||
break;
|
||||
case 8:
|
||||
JD8_SetPaletteColor(254, contador + 12, 11, 11);
|
||||
JD8_SetPaletteColor(253, (contador + 12) >> 1, 11, 11);
|
||||
JD8_Flip();
|
||||
contador++;
|
||||
if (contador == 51) step++;
|
||||
break;
|
||||
case 10:
|
||||
JD8_FadeOut();
|
||||
memcpy(pal, pal_aux, 768);
|
||||
JD8_ClearScreen(255);
|
||||
JA_FadeOutMusic(250);
|
||||
exit = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JD8_FreeSurface(gfx);
|
||||
free(pal_aux);
|
||||
}
|
||||
// doSecreta() — migrat a scenes::SecretaScene (source/scenes/secreta_scene.cpp)
|
||||
|
||||
// doCredits() — migrat a scenes::CreditsScene (source/scenes/credits_scene.cpp)
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ class ModuleSequence {
|
||||
// doMenu() → migrat a scenes::MenuScene
|
||||
// doSlides() → migrat a scenes::SlidesScene
|
||||
// doBanner() → migrat a scenes::BannerScene
|
||||
void doSecreta();
|
||||
// doSecreta() → migrat a scenes::SecretaScene
|
||||
// doCredits() → migrat a scenes::CreditsScene
|
||||
// doMort() → migrat a scenes::MortScene
|
||||
|
||||
|
||||
@@ -146,6 +146,8 @@ namespace Options {
|
||||
game.vides = node["vides"].get_value<int>();
|
||||
if (node.contains("diamants_inicial"))
|
||||
game.diamants_inicial = node["diamants_inicial"].get_value<int>();
|
||||
if (node.contains("diners_inicial"))
|
||||
game.diners_inicial = node["diners_inicial"].get_value<int>();
|
||||
if (node.contains("use_new_logo"))
|
||||
game.use_new_logo = node["use_new_logo"].get_value<bool>();
|
||||
if (node.contains("show_title_credits"))
|
||||
@@ -281,6 +283,7 @@ namespace Options {
|
||||
file << " piramide_inicial: " << game.piramide_inicial << "\n";
|
||||
file << " vides: " << game.vides << "\n";
|
||||
file << " diamants_inicial: " << game.diamants_inicial << "\n";
|
||||
file << " diners_inicial: " << game.diners_inicial << "\n";
|
||||
file << " use_new_logo: " << (game.use_new_logo ? "true" : "false") << "\n";
|
||||
file << " show_title_credits: " << (game.show_title_credits ? "true" : "false") << "\n";
|
||||
file << "\n";
|
||||
|
||||
@@ -84,6 +84,7 @@ namespace Options {
|
||||
int piramide_inicial{Defaults::Game::PIRAMIDE_INICIAL};
|
||||
int vides{Defaults::Game::VIDES};
|
||||
int diamants_inicial{Defaults::Game::DIAMANTS_INICIAL};
|
||||
int diners_inicial{Defaults::Game::DINERS_INICIAL};
|
||||
bool use_new_logo{Defaults::Game::USE_NEW_LOGO};
|
||||
bool show_title_credits{Defaults::Game::SHOW_TITLE_CREDITS};
|
||||
};
|
||||
|
||||
205
source/scenes/secreta_scene.cpp
Normal file
205
source/scenes/secreta_scene.cpp
Normal file
@@ -0,0 +1,205 @@
|
||||
#include "scenes/secreta_scene.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
#include "core/jail/jail_audio.hpp"
|
||||
#include "core/jail/jdraw8.hpp"
|
||||
#include "core/jail/jinput.hpp"
|
||||
#include "game/info.hpp"
|
||||
#include "scenes/scene_utils.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr int TICK_MS = 20; // JG_SetUpdateTicks(20) del vell doSecreta
|
||||
|
||||
// Durades per fase, derivades dels contador-thresholds del vell:
|
||||
// tomba1 scroll: 127 passos (contador 1→128) × 20ms
|
||||
// tomba1 hold: 128 passos (contador 128→0) × 20ms
|
||||
// tomba2 scroll: 94 passos × 20ms
|
||||
// tomba2 hold: 94 passos × 20ms
|
||||
// reveal horit: 80 passos × 20ms
|
||||
// reveal hold: 80 passos × 20ms
|
||||
// red pulse: 51 passos × 20ms
|
||||
// red pulse hold: 51 passos × 20ms
|
||||
constexpr int TOMBA1_SCROLL_MS = 127 * TICK_MS;
|
||||
constexpr int TOMBA1_HOLD_MS = 128 * TICK_MS;
|
||||
constexpr int TOMBA2_SCROLL_MS = 94 * TICK_MS;
|
||||
constexpr int TOMBA2_HOLD_MS = 94 * TICK_MS;
|
||||
constexpr int TOMBA2_REVEAL_MS = 80 * TICK_MS;
|
||||
constexpr int TOMBA2_REVEAL_HOLD_MS = 80 * TICK_MS;
|
||||
constexpr int RED_PULSE_MS = 51 * TICK_MS;
|
||||
constexpr int RED_PULSE_HOLD_MS = 51 * TICK_MS;
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace scenes {
|
||||
|
||||
SecretaScene::~SecretaScene() {
|
||||
if (pal_aux_) std::free(pal_aux_);
|
||||
// pal_active_ NO s'allibera: propietat de main_palette via SetScreenPalette.
|
||||
}
|
||||
|
||||
void SecretaScene::onEnter() {
|
||||
playMusic("00000002.ogg");
|
||||
|
||||
// Fade-out de la paleta anterior. Els assets es carreguen ja
|
||||
// però no fem SetScreenPalette fins que acabe el fade — així
|
||||
// el fade opera sobre la paleta del mòdul anterior.
|
||||
fade_.startFadeOut();
|
||||
|
||||
gfx_ = SurfaceHandle("tomba1.gif");
|
||||
pal_aux_ = JD8_LoadPalette("tomba1.gif");
|
||||
pal_active_ = static_cast<JD8_Palette>(std::malloc(768));
|
||||
std::memcpy(pal_active_, pal_aux_, 768);
|
||||
|
||||
phase_ = Phase::InitialFadeOut;
|
||||
phase_acc_ms_ = 0;
|
||||
}
|
||||
|
||||
void SecretaScene::swapToTomba2() {
|
||||
JD8_ClearScreen(255);
|
||||
gfx_.reset("tomba2.gif");
|
||||
|
||||
std::free(pal_aux_);
|
||||
pal_aux_ = JD8_LoadPalette("tomba2.gif");
|
||||
// pal_active_ continua sent el mateix buffer: només actualitzem
|
||||
// el seu contingut. main_palette ja apunta ací.
|
||||
std::memcpy(pal_active_, pal_aux_, 768);
|
||||
}
|
||||
|
||||
void SecretaScene::beginRedPulseSetup() {
|
||||
JD8_ClearScreen(0);
|
||||
JD8_SetPaletteColor(254, 12, 11, 11);
|
||||
JD8_SetPaletteColor(253, 12, 11, 11);
|
||||
}
|
||||
|
||||
void SecretaScene::beginFinalFade() {
|
||||
JA_FadeOutMusic(250);
|
||||
fade_.startFadeOut();
|
||||
phase_ = Phase::FinalFadeOut;
|
||||
}
|
||||
|
||||
void SecretaScene::tick(int delta_ms) {
|
||||
// Skip per tecla (després del fade inicial, no mentre). Salta
|
||||
// directament al FinalFadeOut. Mateix patró que el vell, on
|
||||
// qualsevol tecla sortia del loop.
|
||||
if (!skip_triggered_ && phase_ != Phase::InitialFadeOut && JI_AnyKey()) {
|
||||
skip_triggered_ = true;
|
||||
beginFinalFade();
|
||||
}
|
||||
|
||||
switch (phase_) {
|
||||
case Phase::InitialFadeOut:
|
||||
fade_.tick(delta_ms);
|
||||
if (fade_.done()) {
|
||||
// Ara main_palette (la vella) té tots els canals a 0.
|
||||
// SetScreenPalette allibera la vella i adopta pal_active_
|
||||
// — des d'ara main_palette == pal_active_, així que les
|
||||
// futures escriptures a pal_active_ afecten la pantalla.
|
||||
JD8_SetScreenPalette(pal_active_);
|
||||
JD8_ClearScreen(255);
|
||||
phase_ = Phase::Tomba1ScrollIn;
|
||||
phase_acc_ms_ = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case Phase::Tomba1ScrollIn: {
|
||||
phase_acc_ms_ += delta_ms;
|
||||
const int contador = std::min(128, phase_acc_ms_ / TICK_MS + 1);
|
||||
// Dos blits solapats: el primer avança a velocitat completa,
|
||||
// el segon (contingut de la dreta del src) a meitat (contador>>1).
|
||||
JD8_Blit(70, 60, gfx_, 0, contador, 178, 70);
|
||||
JD8_BlitCK(70, 60, gfx_, 178, contador >> 1, 142, 70, 255);
|
||||
if (phase_acc_ms_ >= TOMBA1_SCROLL_MS) {
|
||||
phase_ = Phase::Tomba1Hold;
|
||||
phase_acc_ms_ = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Phase::Tomba1Hold:
|
||||
phase_acc_ms_ += delta_ms;
|
||||
if (phase_acc_ms_ >= TOMBA1_HOLD_MS) {
|
||||
swapToTomba2();
|
||||
phase_ = Phase::Tomba2ScrollIn;
|
||||
phase_acc_ms_ = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case Phase::Tomba2ScrollIn: {
|
||||
phase_acc_ms_ += delta_ms;
|
||||
const int contador = std::min(94, phase_acc_ms_ / TICK_MS + 1);
|
||||
JD8_Blit(55, 53, gfx_, 0, 158 - contador, 211, contador);
|
||||
if (phase_acc_ms_ >= TOMBA2_SCROLL_MS) {
|
||||
phase_ = Phase::Tomba2Hold;
|
||||
phase_acc_ms_ = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Phase::Tomba2Hold:
|
||||
phase_acc_ms_ += delta_ms;
|
||||
if (phase_acc_ms_ >= TOMBA2_HOLD_MS) {
|
||||
beginRedPulseSetup();
|
||||
phase_ = Phase::Tomba2Reveal;
|
||||
phase_acc_ms_ = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case Phase::Tomba2Reveal: {
|
||||
phase_acc_ms_ += delta_ms;
|
||||
const int contador = std::min(80, phase_acc_ms_ / TICK_MS + 1);
|
||||
// Revelat horitzontal simètric: l'amplada creix 2px per tick
|
||||
// i el src_x es desplaça a l'esquerra el mateix.
|
||||
JD8_Blit(80, 68, gfx_, 160 - (contador * 2), 0, contador * 2, 64);
|
||||
if (phase_acc_ms_ >= TOMBA2_REVEAL_MS) {
|
||||
phase_ = Phase::Tomba2RevealHold;
|
||||
phase_acc_ms_ = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Phase::Tomba2RevealHold:
|
||||
phase_acc_ms_ += delta_ms;
|
||||
if (phase_acc_ms_ >= TOMBA2_REVEAL_HOLD_MS) {
|
||||
phase_ = Phase::RedPulse;
|
||||
phase_acc_ms_ = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case Phase::RedPulse: {
|
||||
phase_acc_ms_ += delta_ms;
|
||||
const int contador = std::min(51, phase_acc_ms_ / TICK_MS);
|
||||
// Anima el canal R dels índexs 254 i 253 (aquest a la meitat
|
||||
// de brillantor). Va de (12,11,11) fins a (63,11,11) / (31,11,11).
|
||||
JD8_SetPaletteColor(254, contador + 12, 11, 11);
|
||||
JD8_SetPaletteColor(253, (contador + 12) >> 1, 11, 11);
|
||||
if (phase_acc_ms_ >= RED_PULSE_MS) {
|
||||
phase_ = Phase::RedPulseHold;
|
||||
phase_acc_ms_ = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Phase::RedPulseHold:
|
||||
phase_acc_ms_ += delta_ms;
|
||||
if (phase_acc_ms_ >= RED_PULSE_HOLD_MS) {
|
||||
beginFinalFade();
|
||||
}
|
||||
break;
|
||||
|
||||
case Phase::FinalFadeOut:
|
||||
fade_.tick(delta_ms);
|
||||
if (fade_.done()) {
|
||||
phase_ = Phase::Done;
|
||||
}
|
||||
break;
|
||||
|
||||
case Phase::Done:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace scenes
|
||||
66
source/scenes/secreta_scene.hpp
Normal file
66
source/scenes/secreta_scene.hpp
Normal file
@@ -0,0 +1,66 @@
|
||||
#pragma once
|
||||
|
||||
#include "core/jail/jdraw8.hpp"
|
||||
#include "scenes/palette_fade.hpp"
|
||||
#include "scenes/scene.hpp"
|
||||
#include "scenes/surface_handle.hpp"
|
||||
|
||||
namespace scenes {
|
||||
|
||||
// Pre-Secreta. Reemplaça `ModuleSequence::doSecreta()`.
|
||||
//
|
||||
// Flux:
|
||||
// 1. Arranca música "00000002.ogg" i fa fade-out de la paleta anterior.
|
||||
// 2. Carrega tomba1.gif + paleta i pinta un scroll vertical doble
|
||||
// (dos blits solapats, un a velocitat meitat que l'altre) durant
|
||||
// ~2.5 s + ~2.5 s de pausa.
|
||||
// 3. Swap a tomba2.gif + reset de paleta, scroll vertical del segon
|
||||
// asset (~1.9 s + ~1.9 s de pausa).
|
||||
// 4. ClearScreen a 0, set colors 253/254 a vermell fosc (12,11,11)
|
||||
// i pinta un revelat horitzontal (~1.6 s + ~1.6 s de pausa).
|
||||
// 5. "Red pulse": anima els colors 253/254 incrementant el canal R
|
||||
// de 12 a 62 durant ~1 s (+ ~1 s de pausa).
|
||||
// 6. FadeOut + JA_FadeOutMusic(250).
|
||||
// 7. Retorna nextState=0 per entrar al ModuleGame amb num_piramide=6.
|
||||
//
|
||||
// Registrada al SceneRegistry amb state_key = 6.
|
||||
class SecretaScene : public Scene {
|
||||
public:
|
||||
SecretaScene() = default;
|
||||
~SecretaScene() override;
|
||||
|
||||
void onEnter() override;
|
||||
void tick(int delta_ms) override;
|
||||
bool done() const override { return phase_ == Phase::Done; }
|
||||
int nextState() const override { return 0; }
|
||||
|
||||
private:
|
||||
enum class Phase {
|
||||
InitialFadeOut,
|
||||
Tomba1ScrollIn,
|
||||
Tomba1Hold,
|
||||
Tomba2ScrollIn,
|
||||
Tomba2Hold,
|
||||
Tomba2Reveal,
|
||||
Tomba2RevealHold,
|
||||
RedPulse,
|
||||
RedPulseHold,
|
||||
FinalFadeOut,
|
||||
Done,
|
||||
};
|
||||
|
||||
void swapToTomba2();
|
||||
void beginRedPulseSetup();
|
||||
void beginFinalFade();
|
||||
|
||||
SurfaceHandle gfx_;
|
||||
JD8_Palette pal_aux_{nullptr};
|
||||
JD8_Palette pal_active_{nullptr}; // propietat transferida a main_palette
|
||||
PaletteFade fade_;
|
||||
|
||||
Phase phase_{Phase::InitialFadeOut};
|
||||
int phase_acc_ms_{0};
|
||||
bool skip_triggered_{false};
|
||||
};
|
||||
|
||||
} // namespace scenes
|
||||
Reference in New Issue
Block a user