134 lines
6.5 KiB
C++
134 lines
6.5 KiB
C++
#pragma once
|
|
|
|
#include <cstdint>
|
|
#include <string>
|
|
|
|
// FSM secundària de la GameScene que governa el flux "tots els jugadors
|
|
// fora de partida" — CONTINUE? amb countdown → GAME OVER → fade-to-black
|
|
// → transició a LOGO. Viu separada de la `RoomFsm` (que gestiona
|
|
// intro/outro de cada sala) perquè els seus disparadors són ortogonals
|
|
// i la composició entre les dues queda al GameScene.
|
|
//
|
|
// Lògica pura: no toca SDL ni Audio, només temporitzadors. La part
|
|
// visual (text + panel + fade) viu al GameScene reaprofitant la mateixa
|
|
// infraestructura del room text.
|
|
namespace GameOverFsm {
|
|
|
|
// Estats canònics. Phase indices per estat:
|
|
// OFF — joc normal; el GameScene transita a
|
|
// CONTINUE_PROMPT quan detecta 0 jugadors actius.
|
|
// CONTINUE_PROMPT — phases: 0=text_enter, 1=text_hold (countdown
|
|
// visible), 2=text_exit (només si l'usuari
|
|
// cancel·la pulsant START). Si la fase 1 acaba
|
|
// sense cancel·lació → salt a GAME_OVER amb el
|
|
// panel encara amunt (sense exit anim).
|
|
// GAME_OVER — phases: 0=text_hold (apareix sense enter
|
|
// anim, panel ja amunt), 1=text_exit, 2=wait
|
|
// (otro tiempo más abans del fade).
|
|
// FADE_OUT — phases: 0=fade, 1=black_hold (perquè el
|
|
// negre quedi un instant abans de cedir el
|
|
// pas a la LogoScene).
|
|
// DONE — sentinel: el caller (GameScene) ha de
|
|
// demanar la transició cap a LOGO.
|
|
enum class State : std::uint8_t {
|
|
OFF,
|
|
CONTINUE_PROMPT,
|
|
GAME_OVER,
|
|
FADE_OUT,
|
|
DONE,
|
|
};
|
|
|
|
// Sub-fase i temps acumulat dins de l'estat actual. Es reseteja a
|
|
// {0, 0} quan es canvia d'estat (`GameScene::setGameOverState`).
|
|
struct Transition {
|
|
int phase{0};
|
|
int elapsed_ms{0};
|
|
};
|
|
|
|
// Timings llegits de `data/scenes/game/game.yaml` (secció
|
|
// `game_over:`). Si el fitxer no porta cap d'aquests camps, els
|
|
// valors per defecte coincideixen amb els del .yaml versionat.
|
|
struct Config {
|
|
// CONTINUE? — animació d'entrada/sortida idèntica al room text.
|
|
int continue_text_enter_ms{500};
|
|
// Hold = duració total del countdown. Es divideix en
|
|
// (continue_count_start + 1) graons iguals; el cas canònic és
|
|
// 10000 ms / 10 graons d'1 s cadascun.
|
|
int continue_text_hold_ms{10000};
|
|
int continue_text_exit_ms{500};
|
|
// Primer número visible al countdown. La sèrie és
|
|
// [continue_count_start, ..., 1, 0] — sempre acaba en 0 i el
|
|
// valor 0 es manté visible durant l'últim graó abans del salt
|
|
// a GAME_OVER. 9 → "9, 8, ..., 0" (10 graons).
|
|
int continue_count_start{9};
|
|
|
|
// GAME OVER — apareix sense enter anim (el panel ja és amunt
|
|
// del CONTINUE?) i s'esvaeix amb la mateixa exit anim que el
|
|
// room text. `wait_ms` és el "otro tiempo más" abans del fade.
|
|
int game_over_text_hold_ms{2000};
|
|
int game_over_text_exit_ms{500};
|
|
int game_over_wait_ms{500};
|
|
|
|
// Fade final cap a LOGO. `black_hold_ms` és el temps amb el
|
|
// canvas negre opac abans que el GameScene demani la transició.
|
|
int fade_out_ms{500};
|
|
int black_hold_ms{500};
|
|
|
|
// Multiplicador de velocitat de la música mentre dura el
|
|
// CONTINUE_PROMPT. 1.0 = sense canvi, >1 = més ràpid (i amb el
|
|
// to més agut: és l'efecte arcade clàssic dels comptes enrere).
|
|
// Es restableix a 1.0 al sortir del prompt (revive o GAME_OVER).
|
|
float continue_music_speed{1.5F};
|
|
|
|
// Pista de música que sona durant l'estat GAME_OVER (sense loop).
|
|
// Si la pista no està carregada al Resource::Cache, s'omet la
|
|
// reproducció i la fase manté els timings configurats. La durada
|
|
// de la pista determina implícitament `game_over_text_hold_ms`
|
|
// (vegeu `GameScene::setGameOverState`).
|
|
std::string game_over_music_track{"game_over.ogg"};
|
|
|
|
// So que sona cada vegada que apareix un nou número del
|
|
// countdown (al primer cop que es mostra el `start`, cada
|
|
// canvi de número, i quan apareix el 0). NO sona en la
|
|
// transició posterior cap a GAME_OVER. Buit = sense so.
|
|
std::string countdown_sound_key{"countdown.wav"};
|
|
};
|
|
|
|
// Llegeix la configuració des del YAML. Si el fitxer manca o falta
|
|
// alguna clau, els camps no presents conserven els seus fallbacks.
|
|
[[nodiscard]] auto loadConfig(const std::string& yaml_path) -> Config;
|
|
|
|
// Avança la transició consumint `delta_ms` des del temps real.
|
|
// Retorna l'estat resultant. Si retorna un estat diferent, el
|
|
// caller ha de resetejar la `Transition` a {0, 0} abans del següent
|
|
// frame. Funció pura sobre l'argument.
|
|
//
|
|
// Particularitats:
|
|
// - CONTINUE_PROMPT phase 1 (hold) arribar a la fi → GAME_OVER
|
|
// (NO reprodueix exit anim; el caller ja té el panel amunt).
|
|
// - CONTINUE_PROMPT phase 2 (exit) arribar a la fi → OFF (cas
|
|
// "cancel·lació via START": el GameScene ha forçat la fase 2
|
|
// amb `cancelContinuePrompt`).
|
|
// - GAME_OVER phase 2 (wait) arribar a la fi → FADE_OUT.
|
|
// - FADE_OUT phase 1 (black_hold) arribar a la fi → DONE.
|
|
// - DONE i OFF no avancen ni canvien d'estat (sumiders).
|
|
[[nodiscard]] auto advance(State current, Transition& t, const Config& cfg, int delta_ms) -> State;
|
|
|
|
// Salta a la fase 2 (text_exit) del CONTINUE_PROMPT. No fa res si
|
|
// l'estat no és CONTINUE_PROMPT o ja som a la fase 2 (idempotent).
|
|
// Disparat pel GameScene quan un jugador pulsa START dins del
|
|
// countdown — el join real també el fa GameScene; aquesta funció
|
|
// només dispara la sortida visual del rètol.
|
|
void cancelContinuePrompt(State current, Transition& t);
|
|
|
|
// Quants segons "queden" del countdown de CONTINUE?. Retorna un
|
|
// enter en el rang [0, continue_count_steps] perquè es renderitzi
|
|
// com a segona línia del rètol durant la fase 1 (hold). Fora de
|
|
// CONTINUE_PROMPT phase 1, retorna 0 (no s'hauria de pintar).
|
|
[[nodiscard]] auto countdownSecondsRemaining(State current, const Transition& t, const Config& cfg) -> int;
|
|
|
|
// Nom textual per a logs i tests.
|
|
[[nodiscard]] auto stateName(State s) -> const char*;
|
|
|
|
} // namespace GameOverFsm
|