refactor(data): reorganitza data/ i centralitza paths a defaults.hpp

This commit is contained in:
JailDesigner committed 2026-05-07 19:28:28 +02:00
1 parent 9949096fba
commit 05465b791e
54 files changed
+368 -304

No files matched your search

File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+115
View File
@@ -0,0 +1,115 @@
# Tema de la UI: índexs de paleta, timings, fonts i flags visuals. Tota
# clau absent cau al valor compilat a Defaults::UI (veure defaults.hpp).
colors:
render_info_text: 58
render_info_shadow: 16
canvas_bg: 72
notification_text: 232
notification_bg: 64
exit_text: 71
exit_bg: 2
menu_bg: 2
menu_border: 232
menu_title: 237
menu_label: 58
menu_value: 232
menu_cursor: 71
menu_disabled: 16
hud_bg: 9
hud_label: 58
hud_value: 187
hud_flash: 237
# Rètol de transició de sala (ROOM_INTRO i ROOM_OUTRO). Independents
# de notification_* perquè la fase i les notificacions són dos canals
# visuals distints: ací pots canviar el color del rètol sense tocar
# els missatges del HUD.
room_text: 160
room_text_outline: 253
timings:
notification_ms: 4000
exit_ms: 4000
fonts:
hud:
name: "8bithud"
gif: "data/fonts/8bithud.gif"
fnt: "data/fonts/8bithud.fnt"
kerning: 1
placeholder:
name: "ari-w9500-condensed-display"
gif: "data/fonts/ari-w9500-condensed-display.gif"
fnt: "data/fonts/ari-w9500-condensed-display.fnt"
kerning: 1
# Font del rètol de transició de sala (ROOM_INTRO i ROOM_OUTRO).
room_text:
name: "CaesarDressing-Regular"
gif: "data/fonts/CaesarDressing-Regular.gif"
fnt: "data/fonts/CaesarDressing-Regular.fnt"
kerning: 1
menu_title:
name: "ari-w9500-display"
gif: "data/fonts/ari-w9500-display.gif"
fnt: "data/fonts/ari-w9500-display.fnt"
kerning: 0
menu_items:
name: "ari-w9500-condensed-display"
gif: "data/fonts/ari-w9500-condensed-display.gif"
fnt: "data/fonts/ari-w9500-condensed-display.fnt"
kerning: 0
# Copyright de la TITLE: pixel-art estricte (Tiny5-Regular size 5,
# caixa 3×6 px) generat amb font-gen. Diferenciada de la `placeholder`
# que pinta el "press start" — així la jerarquia tipogràfica del peu
# queda neta.
copyright:
name: "Tiny5-Regular"
gif: "data/fonts/Tiny5-Regular.gif"
fnt: "data/fonts/Tiny5-Regular.fnt"
kerning: 1
hud:
bg_enabled: false
entry_ms: 800 # durada de l'animació d'entrada dels tres blocs
flash_ms: 250 # durada del flash quan un jugador rep un hit
shake_ms: 300 # durada del shake que acompanya el flash
# Geometria del popup superior (Notifier). En píxels del canvas, llevat de
# slide_ms (durada en ms de l'animació d'entrada i d'eixida; constant
# independentment de la mida de la caixa). El padding vertical és asimètric a
# propòsit: padding_top > padding_bottom puja una mica el text dins la caixa.
# Corbes disponibles: linear, outQuad, inQuad, inOutQuad, outCubic, inCubic.
notifier:
padding_h: 6
padding_top: 4
padding_bottom: 3
line_gap: 1
margin_top: 3
border_px: 1
slide_ms: 300
slide_in_curve: outCubic
slide_out_curve: inCubic
# Pausa graduada de la GameScene: el món no para d'un colp, s'atura amb
# easing i torna a arrancar amb una altra corba. Els timings es poden
# afinar independentment, i les corbes permeten estils diferents entrant
# i sortint (p.ex. frenar suau i arrancar seca). Corbes disponibles:
# linear, outQuad, inQuad, inOutQuad, outCubic, inCubic.
pause:
enter_ms: 400
exit_ms: 250
enter_curve: outCubic
exit_curve: inCubic
# Sons del menú de servei. Els fitxers viuen a data/audio/sounds/. SELECT
# acompanya navegació (amunt/avall) i back; ACCEPT acompanya modificació
# d'opció (esquerra/dreta/retorn) o entrada a un submenú.
sounds:
menu_select: "menu_select.wav"
menu_accept: "menu_accept.wav"
# Disparat quan un jugador prem START a la TITLE (primera pulsació o
# la del segon jugador dins de la finestra de STARTING).
player_start: "player_start.wav"
# Soroll/scratch sincronitzat amb la fase SCAN de LogoScene (scanline
# reveal). Es dispara al constructor de l'escena.
logo_glitch: "glitch.wav"
File renamed without changes.
File renamed without changes.
@@ -136,7 +136,7 @@ death:
# poden ferir ni matar el jugador (els forats sí que el maten — la # poden ferir ni matar el jugador (els forats sí que el maten — la
# caiguda no és dany convencional). Visualment es manifesta amb un # caiguda no és dany convencional). Visualment es manifesta amb un
# parpadeig que alterna la paleta normal del sprite amb la paleta # parpadeig que alterna la paleta normal del sprite amb la paleta
# `palette` (basename de `data/player/<name>.pal`) cada # `palette` (basename de `data/entities/player/<name>.pal`) cada
# `blink_period_ms` ms. Si `duration_ms` és 0 (o el bloc manca), la # `blink_period_ms` ms. Si `duration_ms` és 0 (o el bloc manca), la
# mecànica queda desactivada i el comportament és l'antic. # mecànica queda desactivada i el comportament és l'antic.
immunity: immunity:
File renamed without changes.
@@ -136,7 +136,7 @@ death:
# poden ferir ni matar el jugador (els forats sí que el maten — la # poden ferir ni matar el jugador (els forats sí que el maten — la
# caiguda no és dany convencional). Visualment es manifesta amb un # caiguda no és dany convencional). Visualment es manifesta amb un
# parpadeig que alterna la paleta normal del sprite amb la paleta # parpadeig que alterna la paleta normal del sprite amb la paleta
# `palette` (basename de `data/player/<name>.pal`) cada # `palette` (basename de `data/entities/player/<name>.pal`) cada
# `blink_period_ms` ms. Si `duration_ms` és 0 (o el bloc manca), la # `blink_period_ms` ms. Si `duration_ms` és 0 (o el bloc manca), la
# mecànica queda desactivada i el comportament és l'antic. # mecànica queda desactivada i el comportament és l'antic.
immunity: immunity:
@@ -1,6 +1,6 @@
# Configuració de la GameScene: timings i corbes de la FSM de sala # Configuració de la GameScene: timings i corbes de la FSM de sala
# (ROOM_INTRO i ROOM_OUTRO). Tots els valors són ms i tota la geometria # (ROOM_INTRO i ROOM_OUTRO). Tots els valors són ms i tota la geometria
# i font del text es reutilitzen del tema UI (data/ui.yaml > pause + # i font del text es reutilitzen del tema UI (data/config/ui.yaml > pause +
# notification). Si manca el fitxer o alguna clau, GameScene cau als # notification). Si manca el fitxer o alguna clau, GameScene cau als
# fallbacks compilats; veure `readSceneConfig` a game_scene.cpp. # fallbacks compilats; veure `readSceneConfig` a game_scene.cpp.
@@ -17,7 +17,7 @@ room_intro:
# single-player s'usa només `player_spawn_delay_ms`. # single-player s'usa només `player_spawn_delay_ms`.
player_spawn_delay_ms: 0 player_spawn_delay_ms: 0
player2_spawn_delay_ms: 300 player2_spawn_delay_ms: 300
# Preset de reverb (catàleg a `data/sounds.yaml`) aplicat al primer # Preset de reverb (catàleg a `data/config/sounds.yaml`) aplicat al primer
# LAND de cada jugador durant la cinemàtica d'entrada. La sala dona # LAND de cada jugador durant la cinemàtica d'entrada. La sala dona
# "més detall" sonor a l'INTRO; els salts del joc i els respawns # "més detall" sonor a l'INTRO; els salts del joc i els respawns
# post-mort cauen al so sec. Buit o absent = sense reverb. # post-mort cauen al so sec. Buit o absent = sense reverb.
@@ -33,7 +33,7 @@ room_outro:
text: text:
# Noms d'easing tal com els resol UiConfig::curveByName (vegeu # Noms d'easing tal com els resol UiConfig::curveByName (vegeu
# `data/ui.yaml`). El text entra suau i surt accelerant. # `data/config/ui.yaml`). El text entra suau i surt accelerant.
enter_curve: outCubic enter_curve: outCubic
exit_curve: inCubic exit_curve: inCubic
+24
View File
@@ -0,0 +1,24 @@
# Configuració de la LogoScene (logotip de l'editora). El revelat del
# logo a la fase SCAN imita un escaneig CRT: una banda lluminosa baixa
# de dalt a baix; per damunt es veu la imatge ja "impressa", per sota
# encara és negre. Al voltant de la banda hi ha glitch (offset
# horitzontal de files amb falloff per distància) i ocasionalment
# apareixen bursts VHS (franges desplaçades) damunt la part ja
# revelada. Quan la banda toca el peu del logo, un flash blanc tanca
# l'efecte i s'entra a MIDDLE (logo estable).
logo:
scan:
duration_ms: 1500 # durada total del scan top→bottom
band_height_px: 4 # alçada (px) de la banda lluminosa
band_alpha: 200 # opacitat (0..255) de la capa blanca de la banda
band_pulse_hz: 20.0 # freqüència del pulse de brillantor (Hz)
band_pulse_depth: 0.45 # profunditat del pulse (0..1; 0 = sense pulse)
# Glitch d'impacte (files al voltant de la banda)
glitch_amplitude_px: 6 # offset horitzontal màxim a la banda
glitch_band_radius_px: 12 # files damunt/sota la banda amb glitch (falloff lineal)
# Bursts VHS sobre la part ja revelada
vhs_burst_per_sec: 3 # bursts/segon mitjà
vhs_burst_duration_ms: 80 # durada de cada burst
vhs_burst_height_px: 8 # alçada de la franja afectada
vhs_burst_amplitude_px: 8 # offset horitzontal del burst
flash_ms: 100 # flash blanc final quan acaba el scan
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+77
View File
@@ -0,0 +1,77 @@
# Configuració de la TitleScene.
# `bg_color` i `text_color` són índexs sobre la paleta "ui" (uzebox.pal):
# 1 = (36,0,0) gairebé negre amb un mínim de càlid; 31 = (255,109,0)
# taronja pur. `duration_ms` és el timeout abans de saltar a la
# següent escena (skipable amb tecla no reservada). Els dos
# `blink_*_ms` defineixen el cicle del prompt "press start": el text
# es veu durant `visible_ms` i s'amaga durant `hidden_ms` repetint-se.
title:
duration_ms: 30000
bg_color: 1
text_color: 31
# Color del text del © de copyright (peu de la TITLE). Off-white càlid:
# índex 183 = (255,218,170), tipus crema/peach, ~90% blanc amb tint càlid.
copyright_color: 183
# Color de l'outline del prompt "PRESS START". Marró fosc càlid (índex
# 19 = 109,72,0), coherent amb la paleta del logo. Es manté separat de
# `copyright_color` perquè l'outline i el text del © tenen rols visuals
# diferents (contrast vs. peu informatiu).
press_start_outline_color: 19
# Posicions Y dels tres elements verticals de la TITLE, en percentatge
# sobre l'alçada del canvas (240 px). El logo s'ancora pel seu top
# (la imatge cau cap avall des d'aquest Y); el prompt i el copyright
# es centren verticalment sobre la línia.
logo_y_percent: 15
prompt_y_percent: 68
copyright_y_percent: 92
# Separació vertical en píxels entre el minilogo i el text del © al peu.
mini_logo_gap_px: 2
blink_visible_ms: 800
blink_hidden_ms: 200
# Fase STARTING (entre la primera pulsació de START i el salt a la
# següent escena). `starting_ms` és la durada fixa; durant aquesta
# fase el parpadeig accelera per `starting_blink_speedup` (2.0 = doble
# de freqüència). Si l'altre jugador prem START dins d'aquesta
# finestra, el comptador es reseteja i s'arrenca amb BOTH.
starting_ms: 3000
# Durant STARTING el prompt commuta a un cicle simètric 50/50
# (visible/ocult) amb aquest període total. 200 ms = 5 Hz, prou
# ràpid per llegir-se com a "pulsació confirmada".
starting_blink_period_ms: 200
# Fade-out estil "mosaic dissolve" durant l'última part de STARTING.
# `fade_out_ms` ha de ser <= starting_ms (els últims X ms del STARTING
# es fan amb el dissolve actiu fins a quedar negre). `fade_out_max_block`
# és la mida màxima de bloc en píxels al final del fade.
fade_out_ms: 800
fade_out_max_block: 32
# Fade-out de `title.ogg` en entrar a STARTING. Independent del visual:
# la música pot acabar abans o després del mosaic dissolve.
music_fade_out_ms: 3000
# Fade-to-black per a la sortida d'attract (timeout cap a LOGO). NO és
# mosaic — capa negra lineal damunt del canvas. La música no es toca:
# `title.ogg` continua sonant cap a LOGO, que ja veurà què en fa.
attract_fade_to_black_ms: 800
# Seqüència d'aparició dels elements de la TITLE en fase IDLE. Tots
# els temps són absoluts des de l'entrada a l'escena. `fade_in_ms` és
# la capa negra inicial que s'esvaeix cap al fons; els altres marquen
# quan apareix cada element. Si l'usuari prem START en qualsevol
# moment, la seqüència es completa instantàniament.
intro:
fade_in_ms: 500 # fade-in negre inicial sobre el fons
game_logo_at_ms: 1500 # visibilitat binària del game_logo
mini_logo_at_ms: 2000 # inici del slide-in del mini-logo
mini_logo_slide_ms: 500 # durada del slide
copyright_at_ms: 2200 # inici del slide-in del copyright
copyright_slide_ms: 500 # durada del slide
slide_curve: outCubic # corba compartida per mini_logo i copyright
press_start_at_ms: 3000 # quan apareix PRESS START amb parpadeig
# Distorsió sinusoidal del fons (efecte de calor del desert).
# `amplitude_px`: desplaçament màxim de cada fila en píxels.
# `wavelength_px`: distància vertical entre dos pics de l'ona.
# `speed_hz`: velocitat amb què avança la fase (cicles per segon).
# Si `enabled` és false, el fons es pinta sense distorsió.
heat_haze:
enabled: true
amplitude_px: 1.5
wavelength_px: 32.0
speed_hz: 0.6
File renamed without changes.
-217
View File
@@ -1,217 +0,0 @@
# Tema de la UI: índexs de paleta, timings, fonts i flags visuals. Tota
# clau absent cau al valor compilat a Defaults::UI (veure defaults.hpp).
colors:
render_info_text: 58
render_info_shadow: 16
canvas_bg: 72
notification_text: 232
notification_bg: 64
exit_text: 71
exit_bg: 2
menu_bg: 2
menu_border: 232
menu_title: 237
menu_label: 58
menu_value: 232
menu_cursor: 71
menu_disabled: 16
hud_bg: 9
hud_label: 58
hud_value: 187
hud_flash: 237
# Rètol de transició de sala (ROOM_INTRO i ROOM_OUTRO). Independents
# de notification_* perquè la fase i les notificacions són dos canals
# visuals distints: ací pots canviar el color del rètol sense tocar
# els missatges del HUD.
room_text: 160
room_text_outline: 253
timings:
notification_ms: 4000
exit_ms: 4000
fonts:
hud:
name: "8bithud"
gif: "data/fonts/8bithud.gif"
fnt: "data/fonts/8bithud.fnt"
kerning: 1
placeholder:
name: "ari-w9500-condensed-display"
gif: "data/fonts/ari-w9500-condensed-display.gif"
fnt: "data/fonts/ari-w9500-condensed-display.fnt"
kerning: 1
# Font del rètol de transició de sala (ROOM_INTRO i ROOM_OUTRO).
room_text:
name: "CaesarDressing-Regular"
gif: "data/fonts/CaesarDressing-Regular.gif"
fnt: "data/fonts/CaesarDressing-Regular.fnt"
kerning: 1
menu_title:
name: "ari-w9500-display"
gif: "data/fonts/ari-w9500-display.gif"
fnt: "data/fonts/ari-w9500-display.fnt"
kerning: 0
menu_items:
name: "ari-w9500-condensed-display"
gif: "data/fonts/ari-w9500-condensed-display.gif"
fnt: "data/fonts/ari-w9500-condensed-display.fnt"
kerning: 0
# Copyright de la TITLE: pixel-art estricte (Tiny5-Regular size 5,
# caixa 3×6 px) generat amb font-gen. Diferenciada de la `placeholder`
# que pinta el "press start" — així la jerarquia tipogràfica del peu
# queda neta.
copyright:
name: "Tiny5-Regular"
gif: "data/fonts/Tiny5-Regular.gif"
fnt: "data/fonts/Tiny5-Regular.fnt"
kerning: 1
hud:
bg_enabled: false
entry_ms: 800 # durada de l'animació d'entrada dels tres blocs
flash_ms: 250 # durada del flash quan un jugador rep un hit
shake_ms: 300 # durada del shake que acompanya el flash
# Geometria del popup superior (Notifier). En píxels del canvas, llevat de
# slide_ms (durada en ms de l'animació d'entrada i d'eixida; constant
# independentment de la mida de la caixa). El padding vertical és asimètric a
# propòsit: padding_top > padding_bottom puja una mica el text dins la caixa.
# Corbes disponibles: linear, outQuad, inQuad, inOutQuad, outCubic, inCubic.
notifier:
padding_h: 6
padding_top: 4
padding_bottom: 3
line_gap: 1
margin_top: 3
border_px: 1
slide_ms: 300
slide_in_curve: outCubic
slide_out_curve: inCubic
# Pausa graduada de la GameScene: el món no para d'un colp, s'atura amb
# easing i torna a arrancar amb una altra corba. Els timings es poden
# afinar independentment, i les corbes permeten estils diferents entrant
# i sortint (p.ex. frenar suau i arrancar seca). Corbes disponibles:
# linear, outQuad, inQuad, inOutQuad, outCubic, inCubic.
pause:
enter_ms: 400
exit_ms: 250
enter_curve: outCubic
exit_curve: inCubic
# Sons del menú de servei. Els fitxers viuen a data/sounds/. SELECT
# acompanya navegació (amunt/avall) i back; ACCEPT acompanya modificació
# d'opció (esquerra/dreta/retorn) o entrada a un submenú.
sounds:
menu_select: "menu_select.wav"
menu_accept: "menu_accept.wav"
# Disparat quan un jugador prem START a la TITLE (primera pulsació o
# la del segon jugador dins de la finestra de STARTING).
player_start: "player_start.wav"
# Soroll/scratch sincronitzat amb la fase SCAN de LogoScene (scanline
# reveal). Es dispara al constructor de l'escena.
logo_glitch: "glitch.wav"
# Escena TITLE (placeholder visual mentre no hi haja artwork).
# `bg_color` i `text_color` són índexs sobre la paleta "ui" (uzebox.pal):
# 1 = (36,0,0) gairebé negre amb un mínim de càlid; 31 = (255,109,0)
# taronja pur. `duration_ms` és el timeout abans de saltar a la
# següent escena (skipable amb tecla no reservada). Els dos
# `blink_*_ms` defineixen el cicle del prompt "press start": el text
# es veu durant `visible_ms` i s'amaga durant `hidden_ms` repetint-se.
title:
duration_ms: 30000
bg_color: 1
text_color: 31
# Color del text del © de copyright (peu de la TITLE). Off-white càlid:
# índex 183 = (255,218,170), tipus crema/peach, ~90% blanc amb tint càlid.
copyright_color: 183
# Color de l'outline del prompt "PRESS START". Marró fosc càlid (índex
# 19 = 109,72,0), coherent amb la paleta del logo. Es manté separat de
# `copyright_color` perquè l'outline i el text del © tenen rols visuals
# diferents (contrast vs. peu informatiu).
press_start_outline_color: 19
# Posicions Y dels tres elements verticals de la TITLE, en percentatge
# sobre l'alçada del canvas (240 px). El logo s'ancora pel seu top
# (la imatge cau cap avall des d'aquest Y); el prompt i el copyright
# es centren verticalment sobre la línia.
logo_y_percent: 15
prompt_y_percent: 68
copyright_y_percent: 92
# Separació vertical en píxels entre el minilogo i el text del © al peu.
mini_logo_gap_px: 2
blink_visible_ms: 800
blink_hidden_ms: 200
# Fase STARTING (entre la primera pulsació de START i el salt a la
# següent escena). `starting_ms` és la durada fixa; durant aquesta
# fase el parpadeig accelera per `starting_blink_speedup` (2.0 = doble
# de freqüència). Si l'altre jugador prem START dins d'aquesta
# finestra, el comptador es reseteja i s'arrenca amb BOTH.
starting_ms: 3000
# Durant STARTING el prompt commuta a un cicle simètric 50/50
# (visible/ocult) amb aquest període total. 200 ms = 5 Hz, prou
# ràpid per llegir-se com a "pulsació confirmada".
starting_blink_period_ms: 200
# Fade-out estil "mosaic dissolve" durant l'última part de STARTING.
# `fade_out_ms` ha de ser <= starting_ms (els últims X ms del STARTING
# es fan amb el dissolve actiu fins a quedar negre). `fade_out_max_block`
# és la mida màxima de bloc en píxels al final del fade.
fade_out_ms: 800
fade_out_max_block: 32
# Fade-out de `title.ogg` en entrar a STARTING. Independent del visual:
# la música pot acabar abans o després del mosaic dissolve.
music_fade_out_ms: 3000
# Fade-to-black per a la sortida d'attract (timeout cap a LOGO). NO és
# mosaic — capa negra lineal damunt del canvas. La música no es toca:
# `title.ogg` continua sonant cap a LOGO, que ja veurà què en fa.
attract_fade_to_black_ms: 800
# Seqüència d'aparició dels elements de la TITLE en fase IDLE. Tots
# els temps són absoluts des de l'entrada a l'escena. `fade_in_ms` és
# la capa negra inicial que s'esvaeix cap al fons; els altres marquen
# quan apareix cada element. Si l'usuari prem START en qualsevol
# moment, la seqüència es completa instantàniament.
intro:
fade_in_ms: 500 # fade-in negre inicial sobre el fons
game_logo_at_ms: 1500 # visibilitat binària del game_logo
mini_logo_at_ms: 2000 # inici del slide-in del mini-logo
mini_logo_slide_ms: 500 # durada del slide
copyright_at_ms: 2200 # inici del slide-in del copyright
copyright_slide_ms: 500 # durada del slide
slide_curve: outCubic # corba compartida per mini_logo i copyright
press_start_at_ms: 3000 # quan apareix PRESS START amb parpadeig
# Distorsió sinusoidal del fons (efecte de calor del desert).
# `amplitude_px`: desplaçament màxim de cada fila en píxels.
# `wavelength_px`: distància vertical entre dos pics de l'ona.
# `speed_hz`: velocitat amb què avança la fase (cicles per segon).
# Si `enabled` és false, el fons es pinta sense distorsió.
heat_haze:
enabled: true
amplitude_px: 1.5
wavelength_px: 32.0
speed_hz: 0.6
# Escena LOGO (logotip de l'editora). El revelat del logo a la fase SCAN
# imita un escaneig CRT: una banda lluminosa baixa de dalt a baix; per
# damunt es veu la imatge ja "impressa", per sota encara és negre. Al
# voltant de la banda hi ha glitch (offset horitzontal de files amb
# falloff per distància) i ocasionalment apareixen bursts VHS (franges
# desplaçades) damunt la part ja revelada. Quan la banda toca el peu del
# logo, un flash blanc tanca l'efecte i s'entra a MIDDLE (logo estable).
logo:
scan:
duration_ms: 1500 # durada total del scan top→bottom
band_height_px: 4 # alçada (px) de la banda lluminosa
band_alpha: 200 # opacitat (0..255) de la capa blanca de la banda
band_pulse_hz: 20.0 # freqüència del pulse de brillantor (Hz)
band_pulse_depth: 0.45 # profunditat del pulse (0..1; 0 = sense pulse)
# Glitch d'impacte (files al voltant de la banda)
glitch_amplitude_px: 6 # offset horitzontal màxim a la banda
glitch_band_radius_px: 12 # files damunt/sota la banda amb glitch (falloff lineal)
# Bursts VHS sobre la part ja revelada
vhs_burst_per_sec: 3 # bursts/segon mitjà
vhs_burst_duration_ms: 80 # durada de cada burst
vhs_burst_height_px: 8 # alçada de la franja afectada
vhs_burst_amplitude_px: 8 # offset horitzontal del burst
flash_ms: 100 # flash blanc final quan acaba el scan
+1 -1
View File
@@ -80,7 +80,7 @@ class Audio {
// --- Control de sons --- // --- Control de sons ---
void playSound(const std::string& name, Group group = Group::GAME); // Reproduir so puntual per nom (muta globals de Ja) void playSound(const std::string& name, Group group = Group::GAME); // Reproduir so puntual per nom (muta globals de Ja)
void playSound(Ja::Sound* sound, Group group = Group::GAME); // Reproduir so puntual per punter (muta globals de Ja) void playSound(Ja::Sound* sound, Group group = Group::GAME); // Reproduir so puntual per punter (muta globals de Ja)
// Reprodueix un so processat per un efecte definit a data/sounds.yaml // Reprodueix un so processat per un efecte definit a data/config/sounds.yaml
// (preset_name busca a SoundEffectsConfig). Si el preset no existeix // (preset_name busca a SoundEffectsConfig). Si el preset no existeix
// o el motor està al cap de canals amb efecte, fa fallback a playSound // o el motor està al cap de canals amb efecte, fa fallback a playSound
// sec — l'usuari sent el so igualment, sense la cua. // sec — l'usuari sent el so igualment, sense la cua.
+1 -1
View File
@@ -5,7 +5,7 @@
#include "core/audio/jail_audio.hpp" // Per a Ja::EchoParams / Ja::ReverbParams #include "core/audio/jail_audio.hpp" // Per a Ja::EchoParams / Ja::ReverbParams
// Catàleg de presets d'efectes carregat des de data/sounds.yaml. La capa // Catàleg de presets d'efectes carregat des de data/config/sounds.yaml. La capa
// Audio (playSoundWithEcho/playSoundWithReverb) hi accedeix per nom: si el // Audio (playSoundWithEcho/playSoundWithReverb) hi accedeix per nom: si el
// preset no existeix, el so es reprodueix sec amb un avís a stderr. // preset no existeix, el so es reprodueix sec amb un avís a stderr.
// //
+2 -2
View File
@@ -26,7 +26,7 @@ namespace GlobalInputs {
// La lliguem a la durada de la notificació EXIT perquè el missatge i // La lliguem a la durada de la notificació EXIT perquè el missatge i
// la confirmació expiren alhora — si no, l'usuari podria veure el // la confirmació expiren alhora — si no, l'usuari podria veure el
// text però ja no ser dins del rang de confirmació (o al revés). // text però ja no ser dins del rang de confirmació (o al revés).
// El valor concret viu a data/ui.yaml (timings.exit_ms) via UiConfig. // El valor concret viu a data/config/ui.yaml (timings.exit_ms) via UiConfig.
constexpr int MIN_ZOOM = 1; constexpr int MIN_ZOOM = 1;
constexpr int MAX_ZOOM = 6; constexpr int MAX_ZOOM = 6;
@@ -161,7 +161,7 @@ namespace GlobalInputs {
// Debug helper: dispara una notificació prou llarga perquè // Debug helper: dispara una notificació prou llarga perquè
// `wrapToWidth` la parteixi en (almenys) dues línies. Útil per a // `wrapToWidth` la parteixi en (almenys) dues línies. Útil per a
// verificar visualment el padding asimètric, el line_gap i la caixa // verificar visualment el padding asimètric, el line_gap i la caixa
// multilinia després de tocar la geometria a `data/ui.yaml`. // multilinia després de tocar la geometria a `data/config/ui.yaml`.
void onDebugLongNotification() { void onDebugLongNotification() {
Notification::notify("Notificació de prova llarga per a comprovar que el text es parteix correctament en dues línies dins la caixa."); Notification::notify("Notificació de prova llarga per a comprovar que el text es parteix correctament en dues línies dins la caixa.");
} }
+1 -1
View File
@@ -5,7 +5,7 @@
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
// Mapeig id → SDL_Scancode carregat des de data/input/keys.yaml. Consumit // Mapeig id → SDL_Scancode carregat des de data/config/input.yaml. Consumit
// per GlobalInputs i (en el futur) per menús de remapat. No té cap cost // per GlobalInputs i (en el futur) per menús de remapat. No té cap cost
// global: si la clau no existeix, retorna SDL_SCANCODE_UNKNOWN i GlobalInputs // global: si la clau no existeix, retorna SDL_SCANCODE_UNKNOWN i GlobalInputs
// ignora l'acció. D'aquesta manera podem afegir nous bindings al YAML sense // ignora l'acció. D'aquesta manera podem afegir nous bindings al YAML sense
@@ -9,7 +9,7 @@
// Temes per a les notificacions de pantalla. Un "preset" captura els dos // Temes per a les notificacions de pantalla. Un "preset" captura els dos
// colors (text i fons, índexs sobre la paleta "ui") i el temps de visibilitat // colors (text i fons, índexs sobre la paleta "ui") i el temps de visibilitat
// en mil·lisegons. Els valors concrets viuen a data/ui.yaml (carregat per // en mil·lisegons. Els valors concrets viuen a data/config/ui.yaml (carregat per
// UiConfig); per llançar una notificació amb un preset concret, cridar // UiConfig); per llançar una notificació amb un preset concret, cridar
// Notification::notify(text, preset). Sense preset s'usa el DEFAULT. // Notification::notify(text, preset). Sense preset s'usa el DEFAULT.
namespace Notification { namespace Notification {
@@ -22,7 +22,7 @@ namespace Notification {
// Preset per defecte: text clar sobre fons fosc. Es construeix en cada // Preset per defecte: text clar sobre fons fosc. Es construeix en cada
// crida a partir d'UiConfig perquè els valors no són constexpr: viuen a // crida a partir d'UiConfig perquè els valors no són constexpr: viuen a
// data/ui.yaml i es carreguen a l'arrencada. // data/config/ui.yaml i es carreguen a l'arrencada.
[[nodiscard]] inline auto defaultPreset() -> Preset { [[nodiscard]] inline auto defaultPreset() -> Preset {
return { return {
.text_color = UiConfig::get().notificationText(), .text_color = UiConfig::get().notificationText(),
+2 -1
View File
@@ -6,6 +6,7 @@
#include <string_view> #include <string_view>
#include "core/resources/resource_pack.hpp" #include "core/resources/resource_pack.hpp"
#include "utils/defaults.hpp"
namespace Resource::Helper { namespace Resource::Helper {
@@ -92,7 +93,7 @@ namespace Resource::Helper {
// carpeta `data/`). // carpeta `data/`).
const auto FROM_PACK = [&filepath]() -> std::vector<std::uint8_t> { const auto FROM_PACK = [&filepath]() -> std::vector<std::uint8_t> {
if (!g_pack_loaded) { return {}; } if (!g_pack_loaded) { return {}; }
constexpr std::string_view PREFIX = "data/"; const std::string_view PREFIX{Defaults::Paths::DATA_ROOT};
std::string key = filepath; std::string key = filepath;
if (key.starts_with(PREFIX)) { key.erase(0, PREFIX.size()); } if (key.starts_with(PREFIX)) { key.erase(0, PREFIX.size()); }
if (g_pack.hasResource(key)) { return g_pack.getResource(key); } if (g_pack.hasResource(key)) { return g_pack.getResource(key); }
+28 -21
View File
@@ -118,22 +118,29 @@ Director::Director() {
Locale::get().load(std::string(Defaults::I18n::LOCALE_DIR) + Options::locale() + ".yaml"); Locale::get().load(std::string(Defaults::I18n::LOCALE_DIR) + Options::locale() + ".yaml");
// Hotkeys globals. GlobalInputs::update() les consumirà a cada frame. // Hotkeys globals. GlobalInputs::update() les consumirà a cada frame.
KeyConfig::get().load("data/input/keys.yaml"); KeyConfig::get().load(Defaults::Paths::INPUT_YAML);
// Tema d'UI (colors, timings, fonts, flags). Qualsevol clau absent a // Tema d'UI (colors, timings, fonts, flags). Qualsevol clau absent a
// data/ui.yaml cau al valor compilat a Defaults::UI. // data/config/ui.yaml cau al valor compilat a Defaults::UI.
UiConfig::get().load("data/ui.yaml"); UiConfig::get().load(Defaults::Paths::UI_YAML);
// Configuració específica de les escenes TITLE i LOGO. Es carreguen
// additivament sobre el mateix UiConfig: cada fitxer només conté la
// seua subclau (`title:` o `logo:`), i les claus absents a la base
// (ui.yaml) o als yamls d'escena cauen al valor compilat a
// Defaults::UI::Title / Defaults::UI::Logo.
UiConfig::get().load(Defaults::Paths::TITLE_YAML);
UiConfig::get().load(Defaults::Paths::LOGO_YAML);
#ifdef _DEBUG #ifdef _DEBUG
// Tema visual de l'editor de tilemap (Debug-only). Claus absents // Tema visual de l'editor de tilemap (Debug-only). Claus absents
// cauen als valors compilats a Defaults::Editor. // cauen als valors compilats a Defaults::Editor.
EditorConfig::get().load("data/editor/editor.yaml"); EditorConfig::get().load(Defaults::Paths::EDITOR_YAML);
#endif #endif
// Recursos compartits d'UI (paleta + fonts). Es carreguen abans que els // Recursos compartits d'UI (paleta + fonts). Es carreguen abans que els
// overlays perquè tots els reaprofiten sense duplicar la lògica. Els // overlays perquè tots els reaprofiten sense duplicar la lògica. Els
// noms de font viuen al fitxer data/ui.yaml via UiConfig. // noms de font viuen al fitxer data/config/ui.yaml via UiConfig.
Resource::Cache::get().loadPalette("ui", "data/palettes/uzebox.pal"); Resource::Cache::get().loadPalette("ui", Defaults::Paths::UI_PALETTE);
const std::string HUD_FONT_GIF_KEY = UiConfig::get().hudFont().name + ".gif"; const std::string HUD_FONT_GIF_KEY = UiConfig::get().hudFont().name + ".gif";
Resource::Cache::get().loadSurface(HUD_FONT_GIF_KEY, UiConfig::get().hudFont().gif); Resource::Cache::get().loadSurface(HUD_FONT_GIF_KEY, UiConfig::get().hudFont().gif);
Resource::Cache::get().getSurface(HUD_FONT_GIF_KEY)->setPalette(Resource::Cache::get().getPalette("ui")); Resource::Cache::get().getSurface(HUD_FONT_GIF_KEY)->setPalette(Resource::Cache::get().getPalette("ui"));
@@ -152,33 +159,33 @@ Director::Director() {
// Pistes de música del cicle de sala (intro/playing/outro). Es preloden // Pistes de música del cicle de sala (intro/playing/outro). Es preloden
// ací perquè formen part del preload d'assets, com la font i la paleta; // ací perquè formen part del preload d'assets, com la font i la paleta;
// la lògica de quina sona en cada estat viu a `GameScene`. // la lògica de quina sona en cada estat viu a `GameScene`.
Resource::Cache::get().loadMusic("room_intro.ogg", "data/music/room_intro.ogg"); Resource::Cache::get().loadMusic("room_intro.ogg", Defaults::Paths::MUSIC_ROOM_INTRO);
Resource::Cache::get().loadMusic("playing.ogg", "data/music/playing.ogg"); Resource::Cache::get().loadMusic("playing.ogg", Defaults::Paths::MUSIC_PLAYING);
Resource::Cache::get().loadMusic("room_outro.ogg", "data/music/room_outro.ogg"); Resource::Cache::get().loadMusic("room_outro.ogg", Defaults::Paths::MUSIC_ROOM_OUTRO);
// Música de la TITLE: arrenca al constructor de l'escena i es fa // Música de la TITLE: arrenca al constructor de l'escena i es fa
// fade-out quan l'escena entra a STARTING. // fade-out quan l'escena entra a STARTING.
Resource::Cache::get().loadMusic("title.ogg", "data/music/title.ogg"); Resource::Cache::get().loadMusic("title.ogg", Defaults::Paths::MUSIC_TITLE);
// Sons del menú de servei. Els noms venen de `data/ui.yaml` (amb // Sons del menú de servei. Els noms venen de `data/config/ui.yaml` (amb
// fallback a `Defaults::UI::MENU_*_SOUND`); el ServiceMenu els // fallback a `Defaults::UI::MENU_*_SOUND`); el ServiceMenu els
// dispara via Audio::Group::INTERFACE. // dispara via Audio::Group::INTERFACE.
const auto& menu_select = UiConfig::get().menuSelectSound(); const auto& menu_select = UiConfig::get().menuSelectSound();
const auto& menu_accept = UiConfig::get().menuAcceptSound(); const auto& menu_accept = UiConfig::get().menuAcceptSound();
Resource::Cache::get().loadSound(menu_select, "data/sounds/" + menu_select); Resource::Cache::get().loadSound(menu_select, std::string{Defaults::Paths::AUDIO_SOUNDS_DIR} + menu_select);
Resource::Cache::get().loadSound(menu_accept, "data/sounds/" + menu_accept); Resource::Cache::get().loadSound(menu_accept, std::string{Defaults::Paths::AUDIO_SOUNDS_DIR} + menu_accept);
// So del START a la TITLE: el dispara TitleScene quan un jugador // So del START a la TITLE: el dispara TitleScene quan un jugador
// prem START (vore enterStarting i el reset del segon jugador). // prem START (vore enterStarting i el reset del segon jugador).
const auto& player_start = UiConfig::get().playerStartSound(); const auto& player_start = UiConfig::get().playerStartSound();
Resource::Cache::get().loadSound(player_start, "data/sounds/" + player_start); Resource::Cache::get().loadSound(player_start, std::string{Defaults::Paths::AUDIO_SOUNDS_DIR} + player_start);
// Soroll de LogoScene (scanline reveal). El dispara LogoScene al // Soroll de LogoScene (scanline reveal). El dispara LogoScene al
// ctor; amb fallback al nom de Defaults si la clau YAML no hi és. // ctor; amb fallback al nom de Defaults si la clau YAML no hi és.
const auto& logo_glitch = UiConfig::get().logoGlitchSound(); const auto& logo_glitch = UiConfig::get().logoGlitchSound();
Resource::Cache::get().loadSound(logo_glitch, "data/sounds/" + logo_glitch); Resource::Cache::get().loadSound(logo_glitch, std::string{Defaults::Paths::AUDIO_SOUNDS_DIR} + logo_glitch);
// Catàleg de presets d'efectes per als sons. Es carrega abans d'Audio // Catàleg de presets d'efectes per als sons. Es carrega abans d'Audio
// perquè els primers playSoundWith* (al començament del joc) ja // perquè els primers playSoundWith* (al començament del joc) ja
// troben els presets disponibles. // troben els presets disponibles.
SoundEffectsConfig::get().load("data/sounds.yaml"); SoundEffectsConfig::get().load(Defaults::Paths::SOUNDS_YAML);
// Audio: singleton manual propietari d'un SDL audio device. Es destrueix // Audio: singleton manual propietari d'un SDL audio device. Es destrueix
// explícitament a ~Director abans que Resource::Cache (Meyers) buide els // explícitament a ~Director abans que Resource::Cache (Meyers) buide els
@@ -216,7 +223,7 @@ Director::Director() {
// Font del menú de servei (F9). El títol va amb la variant `display` // Font del menú de servei (F9). El títol va amb la variant `display`
// i els items amb `condensed-display` (més compacte perquè caben més // i els items amb `condensed-display` (més compacte perquè caben més
// files). Els dos noms i kernings viuen a data/ui.yaml via UiConfig. // files). Els dos noms i kernings viuen a data/config/ui.yaml via UiConfig.
auto load_menu_font = [&](const UiConfig::Font& font) { auto load_menu_font = [&](const UiConfig::Font& font) {
const std::string KEY = font.name + ".gif"; const std::string KEY = font.name + ".gif";
Resource::Cache::get().loadSurface(KEY, font.gif); Resource::Cache::get().loadSurface(KEY, font.gif);
@@ -233,7 +240,7 @@ Director::Director() {
// sobreescrivim amb la "ui" perquè el GIF ja porta els colors finals // sobreescrivim amb la "ui" perquè el GIF ja porta els colors finals
// del logo). // del logo).
constexpr const char* MINI_LOGO_KEY = "logo_jailgames_mini.gif"; constexpr const char* MINI_LOGO_KEY = "logo_jailgames_mini.gif";
Resource::Cache::get().loadSurface(MINI_LOGO_KEY, "data/logo/logo_jailgames_mini.gif"); Resource::Cache::get().loadSurface(MINI_LOGO_KEY, Defaults::Paths::LOGO_MINI_GIF);
auto mini_logo_surface = Resource::Cache::get().getSurface(MINI_LOGO_KEY); auto mini_logo_surface = Resource::Cache::get().getSurface(MINI_LOGO_KEY);
mini_logo_surface_ = mini_logo_surface; mini_logo_surface_ = mini_logo_surface;
@@ -241,20 +248,20 @@ Director::Director() {
// conserva la seua paleta nadiua: els colors finals del logo viuen // conserva la seua paleta nadiua: els colors finals del logo viuen
// dins del propi GIF i no han de passar per la paleta UI. // dins del propi GIF i no han de passar per la paleta UI.
constexpr const char* LOGO_FULL_KEY = "logo_jailgames.gif"; constexpr const char* LOGO_FULL_KEY = "logo_jailgames.gif";
Resource::Cache::get().loadSurface(LOGO_FULL_KEY, "data/logo/logo_jailgames.gif"); Resource::Cache::get().loadSurface(LOGO_FULL_KEY, Defaults::Paths::LOGO_FULL_GIF);
logo_full_surface_ = Resource::Cache::get().getSurface(LOGO_FULL_KEY); logo_full_surface_ = Resource::Cache::get().getSurface(LOGO_FULL_KEY);
// Logotip del joc per a la TITLE (substitueix el text "Aventures en // Logotip del joc per a la TITLE (substitueix el text "Aventures en
// Egipte ARCADE"). Igual que la resta de logos, paleta nadiua — // Egipte ARCADE"). Igual que la resta de logos, paleta nadiua —
// l'art ja porta els colors finals i no passa per la UI. // l'art ja porta els colors finals i no passa per la UI.
constexpr const char* GAME_LOGO_KEY = "game_logo.gif"; constexpr const char* GAME_LOGO_KEY = "game_logo.gif";
Resource::Cache::get().loadSurface(GAME_LOGO_KEY, "data/title/game_logo.gif"); Resource::Cache::get().loadSurface(GAME_LOGO_KEY, Defaults::Paths::TITLE_GAME_LOGO_GIF);
game_logo_surface_ = Resource::Cache::get().getSurface(GAME_LOGO_KEY); game_logo_surface_ = Resource::Cache::get().getSurface(GAME_LOGO_KEY);
// Fons sencer de la TITLE (320×240). Igual que el minilogo, conserva // Fons sencer de la TITLE (320×240). Igual que el minilogo, conserva
// la seua paleta nadiua perquè el GIF ja porta els colors finals. // la seua paleta nadiua perquè el GIF ja porta els colors finals.
constexpr const char* TITLE_BG_KEY = "title_bg.gif"; constexpr const char* TITLE_BG_KEY = "title_bg.gif";
Resource::Cache::get().loadSurface(TITLE_BG_KEY, "data/title/title_bg.gif"); Resource::Cache::get().loadSurface(TITLE_BG_KEY, Defaults::Paths::TITLE_BG_GIF);
auto title_bg_surface = Resource::Cache::get().getSurface(TITLE_BG_KEY); auto title_bg_surface = Resource::Cache::get().getSurface(TITLE_BG_KEY);
title_bg_surface_ = title_bg_surface; title_bg_surface_ = title_bg_surface;
ServiceMenu::get().init(menu_title_text, menu_items_text, ui_palette); ServiceMenu::get().init(menu_title_text, menu_items_text, ui_palette);
+4 -4
View File
@@ -5,7 +5,7 @@
#include <string> #include <string>
// Configuració del tema UI (índexs de paleta, timings, fonts i flags) // Configuració del tema UI (índexs de paleta, timings, fonts i flags)
// carregada des de data/ui.yaml. Cada camp s'inicialitza amb el valor // carregada des de data/config/ui.yaml. Cada camp s'inicialitza amb el valor
// de Defaults::UI com a fallback: si el fitxer falta o li manca una // de Defaults::UI com a fallback: si el fitxer falta o li manca una
// clau, el joc s'executa amb el tema compilat. // clau, el joc s'executa amb el tema compilat.
// //
@@ -21,12 +21,12 @@ class UiConfig {
}; };
// Signatura d'una funció d'easing: t ∈ [0, 1] → valor ∈ [0, 1]. // Signatura d'una funció d'easing: t ∈ [0, 1] → valor ∈ [0, 1].
// Permet triar corbes des de data/ui.yaml per nom (cadena) i guardar // Permet triar corbes des de data/config/ui.yaml per nom (cadena) i guardar
// el punter a la corresponent funció de `utils/easing.hpp`. // el punter a la corresponent funció de `utils/easing.hpp`.
using CurveFn = auto (*)(float) -> float; using CurveFn = auto (*)(float) -> float;
// Geometria del Notifier (popup superior). Carregada des de // Geometria del Notifier (popup superior). Carregada des de
// data/ui.yaml secció `notifier:`; els valors per defecte vénen de // data/config/ui.yaml secció `notifier:`; els valors per defecte vénen de
// Defaults::UI::Notifier. El moviment és per temps (slide_ms) i no per // Defaults::UI::Notifier. El moviment és per temps (slide_ms) i no per
// velocitat, perquè una caixa més gran no triga més a entrar/eixir. // velocitat, perquè una caixa més gran no triga més a entrar/eixir.
struct Notifier { struct Notifier {
@@ -170,7 +170,7 @@ class UiConfig {
[[nodiscard]] static auto curveByName(const std::string& name) -> CurveFn; [[nodiscard]] static auto curveByName(const std::string& name) -> CurveFn;
// Sons del menú de servei. Claus de Resource::Cache::loadSound (els // Sons del menú de servei. Claus de Resource::Cache::loadSound (els
// fitxers viuen a `data/sounds/`). // fitxers viuen a `data/audio/sounds/`).
[[nodiscard]] auto menuSelectSound() const -> const std::string& { return menu_select_sound_; } [[nodiscard]] auto menuSelectSound() const -> const std::string& { return menu_select_sound_; }
[[nodiscard]] auto menuAcceptSound() const -> const std::string& { return menu_accept_sound_; } [[nodiscard]] auto menuAcceptSound() const -> const std::string& { return menu_accept_sound_; }
[[nodiscard]] auto playerStartSound() const -> const std::string& { return player_start_sound_; } [[nodiscard]] auto playerStartSound() const -> const std::string& { return player_start_sound_; }
+1 -1
View File
@@ -234,7 +234,7 @@ void Editor::ensureEditableEntities() {
// llança si no troba — provem primer i, en cas de miss, carreguem. // llança si no troba — provem primer i, en cas de miss, carreguem.
const auto REL = sp["path"].get_value<std::string>(); const auto REL = sp["path"].get_value<std::string>();
const std::string KEY = std::filesystem::path(REL).filename().string(); const std::string KEY = std::filesystem::path(REL).filename().string();
std::string full = "data/entities/"; std::string full = Defaults::Paths::ENTITIES_DIR;
full += name; full += name;
full += '/'; full += '/';
full += REL; full += REL;
+1 -1
View File
@@ -6,7 +6,7 @@
#include <string> #include <string>
// Configuració visual de l'editor de tilemap (Debug-only). Carregada des // Configuració visual de l'editor de tilemap (Debug-only). Carregada des
// de data/editor/editor.yaml; les claus absents cauen als valors compilats // de data/config/editor.yaml; les claus absents cauen als valors compilats
// a Defaults::Editor. Mateix patró que UiConfig (Meyers singleton + load). // a Defaults::Editor. Mateix patró que UiConfig (Meyers singleton + load).
class EditorConfig { class EditorConfig {
public: public:
+2 -1
View File
@@ -6,6 +6,7 @@
#include "core/resources/resource_helper.hpp" #include "core/resources/resource_helper.hpp"
#include "game/entities/entity.hpp" #include "game/entities/entity.hpp"
#include "game/entities/entity_factory.hpp" #include "game/entities/entity_factory.hpp"
#include "utils/defaults.hpp"
namespace EntityLoader { namespace EntityLoader {
@@ -20,7 +21,7 @@ namespace EntityLoader {
} }
auto templatePath(const std::string& name) -> std::string { auto templatePath(const std::string& name) -> std::string {
return "data/entities/" + name + "/" + name + ".yaml"; return std::string{Defaults::Paths::ENTITIES_DIR} + name + "/" + name + ".yaml";
} }
} // namespace } // namespace
@@ -21,6 +21,7 @@
#include "game/entities/entity_manager.hpp" #include "game/entities/entity_manager.hpp"
#include "game/entities/player.hpp" #include "game/entities/player.hpp"
#include "game/map/map.hpp" #include "game/map/map.hpp"
#include "utils/defaults.hpp"
// Render centralitzat al manager per confinar la dependència cap a // Render centralitzat al manager per confinar la dependència cap a
// `Surface`. Les entitats exposen `getSurface()` + `getPixelRect()` i el // `Surface`. Les entitats exposen `getSurface()` + `getPixelRect()` i el
@@ -124,7 +125,7 @@ namespace {
if (s.contains("path")) { if (s.contains("path")) {
const auto REL = s["path"].get_value<std::string>(); const auto REL = s["path"].get_value<std::string>();
info.key = std::filesystem::path(REL).filename().string(); info.key = std::filesystem::path(REL).filename().string();
info.full_path = "data/entities/" + type + "/" + REL; info.full_path = std::string{Defaults::Paths::ENTITIES_DIR} + type + "/" + REL;
info.valid = true; info.valid = true;
} }
if (s.contains("size")) { if (s.contains("size")) {
+10 -9
View File
@@ -179,16 +179,16 @@ void Player::readJumpBlock(const fkyaml::node& yaml) {
if (j.contains("gravity")) { jump_config.gravity_px_per_s2 = j["gravity"].get_value<float>(); } if (j.contains("gravity")) { jump_config.gravity_px_per_s2 = j["gravity"].get_value<float>(); }
if (j.contains("landing_stun_ms")) { jump_config.landing_stun_ms = j["landing_stun_ms"].get_value<int>(); } if (j.contains("landing_stun_ms")) { jump_config.landing_stun_ms = j["landing_stun_ms"].get_value<int>(); }
if (j.contains("shadow_y_offset")) { jump_config.shadow_y_offset = j["shadow_y_offset"].get_value<int>(); } if (j.contains("shadow_y_offset")) { jump_config.shadow_y_offset = j["shadow_y_offset"].get_value<int>(); }
// Sons opcionals: el nom del fitxer (relatiu a data/sounds/) val tant // Sons opcionals: el nom del fitxer (relatiu a Defaults::Paths::AUDIO_SOUNDS_DIR)
// de clau al Resource::Cache com de basename per a la càrrega. Si el // val tant de clau al Resource::Cache com de basename per a la càrrega.
// camp manca, la clau queda buida i `playSound` no es crida. // Si el camp manca, la clau queda buida i `playSound` no es crida.
if (j.contains("sound")) { if (j.contains("sound")) {
jump_config.sound_key = j["sound"].get_value<std::string>(); jump_config.sound_key = j["sound"].get_value<std::string>();
Resource::Cache::get().loadSound(jump_config.sound_key, "data/sounds/" + jump_config.sound_key); Resource::Cache::get().loadSound(jump_config.sound_key, std::string{Defaults::Paths::AUDIO_SOUNDS_DIR} + jump_config.sound_key);
} }
if (j.contains("land_sound")) { if (j.contains("land_sound")) {
jump_config.land_sound_key = j["land_sound"].get_value<std::string>(); jump_config.land_sound_key = j["land_sound"].get_value<std::string>();
Resource::Cache::get().loadSound(jump_config.land_sound_key, "data/sounds/" + jump_config.land_sound_key); Resource::Cache::get().loadSound(jump_config.land_sound_key, std::string{Defaults::Paths::AUDIO_SOUNDS_DIR} + jump_config.land_sound_key);
} }
} }
@@ -201,7 +201,7 @@ void Player::readHurtBlock(const fkyaml::node& yaml) {
// So d'entrada a HURT — mateix patró que `jump.sound` i `whip.sound`. // So d'entrada a HURT — mateix patró que `jump.sound` i `whip.sound`.
if (h.contains("sound")) { if (h.contains("sound")) {
hurt_config.sound_key = h["sound"].get_value<std::string>(); hurt_config.sound_key = h["sound"].get_value<std::string>();
Resource::Cache::get().loadSound(hurt_config.sound_key, "data/sounds/" + hurt_config.sound_key); Resource::Cache::get().loadSound(hurt_config.sound_key, std::string{Defaults::Paths::AUDIO_SOUNDS_DIR} + hurt_config.sound_key);
} }
} }
@@ -220,10 +220,11 @@ void Player::readImmunityBlock(const fkyaml::node& yaml) {
if (im.contains("duration_ms")) { immunity_config.duration_ms = im["duration_ms"].get_value<float>(); } if (im.contains("duration_ms")) { immunity_config.duration_ms = im["duration_ms"].get_value<float>(); }
if (im.contains("blink_period_ms")) { immunity_config.blink_period_ms = im["blink_period_ms"].get_value<int>(); } if (im.contains("blink_period_ms")) { immunity_config.blink_period_ms = im["blink_period_ms"].get_value<int>(); }
// Paleta del blink: el basename val tant de clau al Resource::Cache // Paleta del blink: el basename val tant de clau al Resource::Cache
// com de path (`data/player/<key>.pal`). Mateix patró que els sons. // com de path (`Defaults::Paths::PLAYER_DIR + key + .pal`). Mateix patró
// que els sons.
if (im.contains("palette")) { if (im.contains("palette")) {
immunity_config.palette_key = im["palette"].get_value<std::string>(); immunity_config.palette_key = im["palette"].get_value<std::string>();
Resource::Cache::get().loadPalette(immunity_config.palette_key, "data/player/" + immunity_config.palette_key + ".pal"); Resource::Cache::get().loadPalette(immunity_config.palette_key, std::string{Defaults::Paths::PLAYER_DIR} + immunity_config.palette_key + ".pal");
} }
} }
@@ -239,7 +240,7 @@ void Player::readWhipBlock(const fkyaml::node& yaml) {
// clau al cache i de path. Si manca, queda buit i no es dispara. // clau al cache i de path. Si manca, queda buit i no es dispara.
if (w.contains("sound")) { if (w.contains("sound")) {
whip_config.sound_key = w["sound"].get_value<std::string>(); whip_config.sound_key = w["sound"].get_value<std::string>();
Resource::Cache::get().loadSound(whip_config.sound_key, "data/sounds/" + whip_config.sound_key); Resource::Cache::get().loadSound(whip_config.sound_key, std::string{Defaults::Paths::AUDIO_SOUNDS_DIR} + whip_config.sound_key);
} }
} }
+7 -7
View File
@@ -91,7 +91,7 @@ class Player : public AnimatedSprite {
DYING, DYING,
}; };
// Geometria carregada des del YAML del player (p.ex. `data/player/sam.yaml`). // Geometria carregada des del YAML del player (p.ex. `data/entities/player/sam.yaml`).
// `sprite_*` són // `sprite_*` són
// la mida del frame (sprite 12×24 amb perspectiva falsa: visualment, els // la mida del frame (sprite 12×24 amb perspectiva falsa: visualment, els
// 12 píxels superiors són el cap i els 12 inferiors la base). // 12 píxels superiors són el cap i els 12 inferiors la base).
@@ -362,7 +362,7 @@ class Player : public AnimatedSprite {
// al respawn post-mort: mateixa entrada cinemàtica. // al respawn post-mort: mateixa entrada cinemàtica.
void spawnFromAir(float x, float y); void spawnFromAir(float x, float y);
// Arma un preset de reverb (catàleg a `data/sounds.yaml`) per al // Arma un preset de reverb (catàleg a `data/config/sounds.yaml`) per al
// pròxim aterratge d'aquest jugador. Pensat per a la cinemàtica // pròxim aterratge d'aquest jugador. Pensat per a la cinemàtica
// d'INTRO de sala: GameScene crida aquesta funció just després de // d'INTRO de sala: GameScene crida aquesta funció just després de
// `spawnFromAir`, i el primer LAND consumeix el preset (queda buit // `spawnFromAir`, i el primer LAND consumeix el preset (queda buit
@@ -529,7 +529,7 @@ class Player : public AnimatedSprite {
// gestiona `intended_vx_/vy_` escalats pel resolver. // gestiona `intended_vx_/vy_` escalats pel resolver.
bool being_pushed_{false}; bool being_pushed_{false};
// Preset de reverb (catàleg de `data/sounds.yaml`) que el pròxim // Preset de reverb (catàleg de `data/config/sounds.yaml`) que el pròxim
// LAND ha de fer servir; buit = so sec. L'arma `armNextLandReverb` // LAND ha de fer servir; buit = so sec. L'arma `armNextLandReverb`
// (cridada per GameScene al spawn aeri d'INTRO) i el consumeix // (cridada per GameScene al spawn aeri d'INTRO) i el consumeix
// `integrateJump` quan el jugador toca terra. Cap altre punt // `integrateJump` quan el jugador toca terra. Cap altre punt
@@ -636,7 +636,7 @@ class Player : public AnimatedSprite {
struct HurtConfig { struct HurtConfig {
float initial_speed_px_per_s{0.0F}; // Velocitat amb què surt projectat (px/s). float initial_speed_px_per_s{0.0F}; // Velocitat amb què surt projectat (px/s).
int brake_time_ms{0}; // Temps en que la velocitat decau a 0. int brake_time_ms{0}; // Temps en que la velocitat decau a 0.
// Fitxer .wav reproduït en entrar a HURT (relatiu a `data/sounds/`). // Fitxer .wav reproduït en entrar a HURT (relatiu a `data/audio/sounds/`).
// Mateixa convenció que la resta de sons del jugador: el basename val // Mateixa convenció que la resta de sons del jugador: el basename val
// de clau al Resource::Cache i de path. Buit o absent = entrada // de clau al Resource::Cache i de path. Buit o absent = entrada
// silenciosa. // silenciosa.
@@ -660,7 +660,7 @@ class Player : public AnimatedSprite {
int cooldown_ms{0}; int cooldown_ms{0};
int damage{0}; int damage{0};
// Fitxer .wav reproduït al moment de disparar el swing (relatiu a // Fitxer .wav reproduït al moment de disparar el swing (relatiu a
// `data/sounds/`). Convenció: el basename val tant de clau al // `data/audio/sounds/`). Convenció: el basename val tant de clau al
// Resource::Cache com de path. Buit o absent = swing silenciós. // Resource::Cache com de path. Buit o absent = swing silenciós.
std::string sound_key; std::string sound_key;
}; };
@@ -697,7 +697,7 @@ class Player : public AnimatedSprite {
float duration_ms{0.0F}; float duration_ms{0.0F};
int blink_period_ms{0}; int blink_period_ms{0};
// Clau al Resource::Cache de la paleta plana usada al blink (basename // Clau al Resource::Cache de la paleta plana usada al blink (basename
// del .pal a `data/player/`). Buida = no hi ha alternança visual, // del .pal a `data/entities/player/`). Buida = no hi ha alternança visual,
// només la finestra lògica d'immunitat (que sense feedback visual // només la finestra lògica d'immunitat (que sense feedback visual
// pot ser confusa, però no és incorrecte). // pot ser confusa, però no és incorrecte).
std::string palette_key; std::string palette_key;
@@ -706,7 +706,7 @@ class Player : public AnimatedSprite {
// Llig el bloc `immunity:` del YAML i n'omple `immunity_config`. Si // Llig el bloc `immunity:` del YAML i n'omple `immunity_config`. Si
// hi ha `palette`, registra la paleta corresponent al Resource::Cache // hi ha `palette`, registra la paleta corresponent al Resource::Cache
// (path: `data/player/<palette_key>.pal`). Mateix patró que els altres // (path: `data/entities/player/<palette_key>.pal`). Mateix patró que els altres
// readers — `loadFrom` el crida al final. // readers — `loadFrom` el crida al final.
static void readImmunityBlock(const fkyaml::node& yaml); static void readImmunityBlock(const fkyaml::node& yaml);
+11 -11
View File
@@ -229,10 +229,10 @@ auto GameScene::defaultConfig() -> Config {
// concret de sala — només cap a on apunta la progressió ara mateix. // concret de sala — només cap a on apunta la progressió ara mateix.
return { return {
.map_yaml = Levels::LevelManager::get().currentPath(), .map_yaml = Levels::LevelManager::get().currentPath(),
.player_sprite = Defaults::Pyramid::PLAYER_SPRITE, .player_sprite = Defaults::Pyramid::PLAYER_SAM_GIF,
.player_yaml = Defaults::Pyramid::PLAYER_YAML, .player_yaml = Defaults::Pyramid::PLAYER_SAM_YAML,
.player2_sprite = Defaults::Pyramid::PLAYER_SPRITE_P2, .player2_sprite = Defaults::Pyramid::PLAYER_MORCUS_GIF,
.player2_yaml = Defaults::Pyramid::PLAYER_YAML_P2, .player2_yaml = Defaults::Pyramid::PLAYER_MORCUS_YAML,
.music_track = Defaults::Pyramid::MUSIC_TRACK, .music_track = Defaults::Pyramid::MUSIC_TRACK,
.starting_players = DebugConfig::StartingPlayers::BOTH, .starting_players = DebugConfig::StartingPlayers::BOTH,
}; };
@@ -312,7 +312,7 @@ GameScene::GameScene(Config config)
// També ens subscrivim a `player_jumped` i `player_landed` per // També ens subscrivim a `player_jumped` i `player_landed` per
// spawnejar el polvet de despegue / aterratge a la posició dels // spawnejar el polvet de despegue / aterratge a la posició dels
// peus que el Player ens dóna al payload. // peus que el Player ens dóna al payload.
Resource::Cache::get().loadSurface("dust.gif", "data/entities/dust/dust.gif"); Resource::Cache::get().loadSurface("dust.gif", Defaults::Paths::DUST_GIF);
entity_manager_.getBus().subscribe("player_jumped", [this](const Event& ev) { entity_manager_.getBus().subscribe("player_jumped", [this](const Event& ev) {
const auto* pos = std::get_if<WorldPos>(&ev.payload); const auto* pos = std::get_if<WorldPos>(&ev.payload);
if (pos != nullptr) { spawnDust(pos->x, pos->y, false); } if (pos != nullptr) { spawnDust(pos->x, pos->y, false); }
@@ -325,10 +325,10 @@ GameScene::GameScene(Config config)
// Whip: precarreguem les 4 surfaces (una per cardinal) abans del // Whip: precarreguem les 4 surfaces (una per cardinal) abans del
// primer spawn perquè el Player no facte disc al primer atac. // primer spawn perquè el Player no facte disc al primer atac.
// Subscriu `whip_spawn` per crear el `WhipAttack` corresponent. // Subscriu `whip_spawn` per crear el `WhipAttack` corresponent.
Resource::Cache::get().loadSurface("whip_east.gif", "data/entities/whip_attack/whip_east.gif"); Resource::Cache::get().loadSurface("whip_east.gif", Defaults::Paths::WHIP_EAST_GIF);
Resource::Cache::get().loadSurface("whip_west.gif", "data/entities/whip_attack/whip_west.gif"); Resource::Cache::get().loadSurface("whip_west.gif", Defaults::Paths::WHIP_WEST_GIF);
Resource::Cache::get().loadSurface("whip_north.gif", "data/entities/whip_attack/whip_north.gif"); Resource::Cache::get().loadSurface("whip_north.gif", Defaults::Paths::WHIP_NORTH_GIF);
Resource::Cache::get().loadSurface("whip_south.gif", "data/entities/whip_attack/whip_south.gif"); Resource::Cache::get().loadSurface("whip_south.gif", Defaults::Paths::WHIP_SOUTH_GIF);
entity_manager_.getBus().subscribe("whip_spawn", [this](const Event& ev) { entity_manager_.getBus().subscribe("whip_spawn", [this](const Event& ev) {
const auto* p = std::get_if<WhipSpawnPayload>(&ev.payload); const auto* p = std::get_if<WhipSpawnPayload>(&ev.payload);
if (p != nullptr) { spawnWhip(*p); } if (p != nullptr) { spawnWhip(*p); }
@@ -479,7 +479,7 @@ GameScene::GameScene(Config config)
// Timings i corbes de la FSM de sala. Llegits del YAML una sola // Timings i corbes de la FSM de sala. Llegits del YAML una sola
// vegada; canvis requereixen reiniciar el joc. // vegada; canvis requereixen reiniciar el joc.
transition_config_ = RoomFsm::loadConfig(Defaults::GameScene::CONFIG_YAML); transition_config_ = RoomFsm::loadConfig(Defaults::GameScene::GAME_YAML);
// Cinemàtica d'entrada de la primera sala: arrenca la pista // Cinemàtica d'entrada de la primera sala: arrenca la pista
// `room_intro.ogg` i arma el callback de fi que farà spawn + salt // `room_intro.ogg` i arma el callback de fi que farà spawn + salt
@@ -856,7 +856,7 @@ void GameScene::renderRoomText() {
// l'antic GameCanvas::CENTER_Y per descomptar la franja del marcador // l'antic GameCanvas::CENTER_Y per descomptar la franja del marcador
// i tenir el rètol equilibrat sobre el playfield. // i tenir el rètol equilibrat sobre el playfield.
const int PLAY_CENTER_Y = (GameCanvas::HEIGHT + Map::hud_h) / 2; const int PLAY_CENTER_Y = (GameCanvas::HEIGHT + Map::hud_h) / 2;
// Colors del rètol via UiConfig (`data/ui.yaml > colors.room_text` i // Colors del rètol via UiConfig (`data/config/ui.yaml > colors.room_text` i
// `room_text_outline`). Independents dels colors de notificació. // `room_text_outline`). Independents dels colors de notificació.
const Uint8 FILL = UiConfig::get().roomText(); const Uint8 FILL = UiConfig::get().roomText();
const Uint8 OUTLINE = UiConfig::get().roomTextOutline(); const Uint8 OUTLINE = UiConfig::get().roomTextOutline();
+2 -2
View File
@@ -202,7 +202,7 @@ class GameScene : public Scene {
// Font del rètol de transició de sala (ROOM_INTRO i ROOM_OUTRO). // Font del rètol de transició de sala (ROOM_INTRO i ROOM_OUTRO).
// Distinta de `pause_font_` perquè el rètol de fase té estètica // Distinta de `pause_font_` perquè el rètol de fase té estètica
// pròpia (CaesarDressing per defecte, configurable via // pròpia (CaesarDressing per defecte, configurable via
// `data/ui.yaml > fonts.room_text`). La pausa segueix amb la // `data/config/ui.yaml > fonts.room_text`). La pausa segueix amb la
// placeholder. // placeholder.
std::shared_ptr<Text> room_text_font_; std::shared_ptr<Text> room_text_font_;
@@ -224,7 +224,7 @@ class GameScene : public Scene {
} pause_; } pause_;
// Configuració de la FSM de sala (intro/outro). Carregada al ctor des // Configuració de la FSM de sala (intro/outro). Carregada al ctor des
// de `data/scenes/game.yaml`; valors per defecte si manca el YAML. // de `data/scenes/game/game.yaml`; valors per defecte si manca el YAML.
RoomFsm::Config transition_config_{}; RoomFsm::Config transition_config_{};
// Estat actual de la FSM de sala. S'inicialitza a ROOM_INTRO al ctor // Estat actual de la FSM de sala. S'inicialitza a ROOM_INTRO al ctor
+1 -1
View File
@@ -8,7 +8,7 @@
namespace Placeholder { namespace Placeholder {
// Retorna true si el scancode coincideix amb alguna tecla declarada al // Retorna true si el scancode coincideix amb alguna tecla declarada al
// KeyConfig::get() (les carregades de data/input/keys.yaml). Si KeyConfig // KeyConfig::get() (les carregades de data/config/input.yaml). Si KeyConfig
// no s'ha carregat, totes les consultes retornaran SDL_SCANCODE_UNKNOWN i // no s'ha carregat, totes les consultes retornaran SDL_SCANCODE_UNKNOWN i
// aquesta funció tornarà false, de manera que el test/smoke no depèn de // aquesta funció tornarà false, de manera que el test/smoke no depèn de
// l'estat global de la configuració. // l'estat global de la configuració.
+2 -2
View File
@@ -35,7 +35,7 @@ namespace RoomFsm {
int elapsed_ms{0}; int elapsed_ms{0};
}; };
// Timings i corbes carregats de `data/scenes/game.yaml`. Els valors // Timings i corbes carregats de `data/scenes/game/game.yaml`. Els valors
// per defecte coincideixen amb els del YAML versionat: si manca el // per defecte coincideixen amb els del YAML versionat: si manca el
// fitxer, la FSM funciona igualment amb aquests fallbacks. // fitxer, la FSM funciona igualment amb aquests fallbacks.
struct Config { struct Config {
@@ -94,7 +94,7 @@ namespace RoomFsm {
UiConfig::CurveFn text_enter_curve{nullptr}; UiConfig::CurveFn text_enter_curve{nullptr};
UiConfig::CurveFn text_exit_curve{nullptr}; UiConfig::CurveFn text_exit_curve{nullptr};
// Preset de reverb (catàleg a `data/sounds.yaml`) que GameScene // Preset de reverb (catàleg a `data/config/sounds.yaml`) que GameScene
// arma al jugador al spawn aeri d'INTRO. Es consumeix al primer // arma al jugador al spawn aeri d'INTRO. Es consumeix al primer
// aterratge cinemàtic; els salts posteriors del joc i els // aterratge cinemàtic; els salts posteriors del joc i els
// respawns post-mort cauen al so sec. Buit = sense reverb (la // respawns post-mort cauen al so sec. Buit = sense reverb (la
+1 -1
View File
@@ -17,7 +17,7 @@ class Text;
// Escena TITLE provisional. Pinta dos blocs de text sobre un fons gairebé // Escena TITLE provisional. Pinta dos blocs de text sobre un fons gairebé
// negre i un prompt "press start" intermitent fins que apareix l'artwork // negre i un prompt "press start" intermitent fins que apareix l'artwork
// real. Tota la cosmètica (colors, durada, ritme del parpadeig) viu a // real. Tota la cosmètica (colors, durada, ritme del parpadeig) viu a
// data/ui.yaml secció `title:` per poder afinar-la sense recompilar. // data/config/ui.yaml secció `title:` per poder afinar-la sense recompilar.
class TitleScene : public Scene { class TitleScene : public Scene {
public: public:
// Fases de l'escena. // Fases de l'escena.
+2 -2
View File
@@ -22,7 +22,7 @@
namespace { namespace {
// Els colors del HUD viuen a data/ui.yaml (colors.hud_label/value/flash) // Els colors del HUD viuen a data/config/ui.yaml (colors.hud_label/value/flash)
// via UiConfig. Les etiquetes ("P1", "V", "T") usen un to apagat per // via UiConfig. Les etiquetes ("P1", "V", "T") usen un to apagat per
// crear jerarquia visual respecte als valors; el flash temporal usa un // crear jerarquia visual respecte als valors; el flash temporal usa un
// to càlid que contrasta amb el valor normal. // to càlid que contrasta amb el valor normal.
@@ -73,7 +73,7 @@ Hud::Hud(EventBus& bus, std::shared_ptr<Text> font)
: bus_(bus), : bus_(bus),
font_(std::move(font)) { font_(std::move(font)) {
// Geometria fixa dels tres blocs. Sumen exactament GameCanvas::WIDTH. // Geometria fixa dels tres blocs. Sumen exactament GameCanvas::WIDTH.
// La durada de l'animació d'entrada ve de data/ui.yaml via UiConfig. // La durada de l'animació d'entrada ve de data/config/ui.yaml via UiConfig.
const int ENTRY_MS = UiConfig::get().hudEntryMs(); const int ENTRY_MS = UiConfig::get().hudEntryMs();
blocks_[0] = Block{ blocks_[0] = Block{
.x = 0, .x = 0,
+1 -1
View File
@@ -104,7 +104,7 @@ class Hud {
// Animació d'entrada: ms restants fins a quedar-se a la posició // Animació d'entrada: ms restants fins a quedar-se a la posició
// final. Quan val 0 el bloc està quiet. El Hud ctor l'inicialitza // final. Quan val 0 el bloc està quiet. El Hud ctor l'inicialitza
// amb la durada viva a data/ui.yaml (hud.entry_ms). // amb la durada viva a data/config/ui.yaml (hud.entry_ms).
int entry_ms_left{0}; int entry_ms_left{0};
// Vector inicial des d'on entra: {-LEFT_W,0} per al bloc esquerre, // Vector inicial des d'on entra: {-LEFT_W,0} per al bloc esquerre,
// {0,-HEIGHT_PX} per al central i {+RIGHT_W,0} per al dret. // {0,-HEIGHT_PX} per al central i {+RIGHT_W,0} per al dret.
+61 -8
View File
@@ -107,7 +107,7 @@ namespace Defaults {
} // namespace Player } // namespace Player
// Fallbacks del tema d'UI: índexs de paleta, timings (ms) i fonts. // Fallbacks del tema d'UI: índexs de paleta, timings (ms) i fonts.
// El tema en viu és a data/ui.yaml, carregat per UiConfig a // El tema en viu és a data/config/ui.yaml, carregat per UiConfig a
// l'arrencada; aquests valors només s'apliquen si el fitxer falta o // l'arrencada; aquests valors només s'apliquen si el fitxer falta o
// li manca alguna clau. Ací només cal tocar-los si es vol canviar el // li manca alguna clau. Ací només cal tocar-los si es vol canviar el
// fallback "de fàbrica". // fallback "de fàbrica".
@@ -251,14 +251,14 @@ namespace Defaults {
// Sons del menú de servei. SELECT acompanya navegació (amunt/avall) // Sons del menú de servei. SELECT acompanya navegació (amunt/avall)
// i back; ACCEPT acompanya modificació d'opció (esq/dret/retorn). // i back; ACCEPT acompanya modificació d'opció (esq/dret/retorn).
// Els fitxers viuen a `data/sounds/`; només es referencia el nom. // Els fitxers viuen a `data/audio/sounds/`; només es referencia el nom.
constexpr const char* MENU_SELECT_SOUND = "menu_select.wav"; constexpr const char* MENU_SELECT_SOUND = "menu_select.wav";
constexpr const char* MENU_ACCEPT_SOUND = "menu_accept.wav"; constexpr const char* MENU_ACCEPT_SOUND = "menu_accept.wav";
// So disparat quan un jugador prem START a la TITLE (tant la // So disparat quan un jugador prem START a la TITLE (tant la
// primera pulsació que entra a STARTING com la del segon // primera pulsació que entra a STARTING com la del segon
// jugador que reseteja a BOTH dins de la finestra). Fitxer a // jugador que reseteja a BOTH dins de la finestra). Fitxer a
// `data/sounds/`. // `data/audio/sounds/`.
constexpr const char* PLAYER_START_SOUND = "player_start.wav"; constexpr const char* PLAYER_START_SOUND = "player_start.wav";
// So curt de "soroll/scratch" disparat al constructor de LogoScene // So curt de "soroll/scratch" disparat al constructor de LogoScene
@@ -447,7 +447,7 @@ namespace Defaults {
// Independent de la piràmide concreta — quan un dia hi haja diferents // Independent de la piràmide concreta — quan un dia hi haja diferents
// ritmes per piràmide, aquest YAML pot adoptar variants per nivell. // ritmes per piràmide, aquest YAML pot adoptar variants per nivell.
namespace GameScene { namespace GameScene {
constexpr const char* CONFIG_YAML = "data/scenes/game.yaml"; constexpr const char* GAME_YAML = "data/scenes/game/game.yaml";
} // namespace GameScene } // namespace GameScene
// Rutes d'assets per piràmide. Centralitzats ací perquè `GameScene` no // Rutes d'assets per piràmide. Centralitzats ací perquè `GameScene` no
@@ -460,14 +460,67 @@ namespace Defaults {
// hardcodejar el path d'una sala concreta — pregunteu-li al // hardcodejar el path d'una sala concreta — pregunteu-li al
// `LevelManager` (`currentPath()`) i deixeu que ell decidisca. // `LevelManager` (`currentPath()`) i deixeu que ell decidisca.
constexpr const char* LEVELS_YAML = "data/maps/levels.yaml"; constexpr const char* LEVELS_YAML = "data/maps/levels.yaml";
constexpr const char* PLAYER_SPRITE = "data/player/sam.gif"; constexpr const char* PLAYER_SAM_GIF = "data/entities/player/sam.gif";
constexpr const char* PLAYER_YAML = "data/player/sam.yaml"; constexpr const char* PLAYER_SAM_YAML = "data/entities/player/sam.yaml";
// Personatge del segon jugador. Clonat de sam amb repaletat (roig→blau); // Personatge del segon jugador. Clonat de sam amb repaletat (roig→blau);
// la geometria del sprite i les animacions coincideixen amb les de P1, // la geometria del sprite i les animacions coincideixen amb les de P1,
// així que Player::loadFrom només cal cridar-la amb un dels dos YAMLs. // així que Player::loadFrom només cal cridar-la amb un dels dos YAMLs.
constexpr const char* PLAYER_SPRITE_P2 = "data/player/morcus.gif"; constexpr const char* PLAYER_MORCUS_GIF = "data/entities/player/morcus.gif";
constexpr const char* PLAYER_YAML_P2 = "data/player/morcus.yaml"; constexpr const char* PLAYER_MORCUS_YAML = "data/entities/player/morcus.yaml";
constexpr const char* MUSIC_TRACK = "playing.ogg"; constexpr const char* MUSIC_TRACK = "playing.ogg";
} // namespace Pyramid } // namespace Pyramid
// Rutes a recursos sota `data/`. Centralitzades ací perquè cap `.cpp`
// tinga literals "data/..." hardcoded: si demà es reorganitza
// l'arbre de `data/`, només cal tocar aquest namespace.
//
// Convenció: les constants que acaben en `_DIR` són prefixos (acaben
// en `/`) pensats per concatenar amb una clau coneguda en runtime
// (p.ex. nom de fitxer carregat des d'un YAML). La resta són rutes
// completes a un fitxer concret.
namespace Paths {
// Arrel de tots els recursos del joc. La fan servir el carregador de
// packs (per a stripping al lookup) i qualsevol consumidor que
// necessite saber la prefix lògica abans del path real.
constexpr const char* DATA_ROOT = "data/";
// Directoris (per concatenació amb claus dinàmiques).
constexpr const char* AUDIO_MUSIC_DIR = "data/audio/music/";
constexpr const char* AUDIO_SOUNDS_DIR = "data/audio/sounds/";
constexpr const char* ENTITIES_DIR = "data/entities/";
constexpr const char* PLAYER_DIR = "data/entities/player/";
// Configuració global (tema, sons, input, editor).
constexpr const char* UI_YAML = "data/config/ui.yaml";
constexpr const char* SOUNDS_YAML = "data/config/sounds.yaml";
constexpr const char* INPUT_YAML = "data/config/input.yaml";
constexpr const char* EDITOR_YAML = "data/config/editor.yaml";
constexpr const char* UI_PALETTE = "data/palettes/uzebox.pal";
// Configuració d'escenes (yaml). El de la GameScene viu a
// `Defaults::GameScene::GAME_YAML` per coherència amb la resta de
// valors d'aquella escena.
constexpr const char* LOGO_YAML = "data/scenes/logo/logo.yaml";
constexpr const char* TITLE_YAML = "data/scenes/title/title.yaml";
// Música pre-carregada pel Director a l'arrencada.
constexpr const char* MUSIC_TITLE = "data/audio/music/title.ogg";
constexpr const char* MUSIC_PLAYING = "data/audio/music/playing.ogg";
constexpr const char* MUSIC_ROOM_INTRO = "data/audio/music/room_intro.ogg";
constexpr const char* MUSIC_ROOM_OUTRO = "data/audio/music/room_outro.ogg";
// Gràfics de logo / title pre-carregats pel Director.
constexpr const char* LOGO_MINI_GIF = "data/scenes/logo/logo_jailgames_mini.gif";
constexpr const char* LOGO_FULL_GIF = "data/scenes/logo/logo_jailgames.gif";
constexpr const char* TITLE_GAME_LOGO_GIF = "data/scenes/title/game_logo.gif";
constexpr const char* TITLE_BG_GIF = "data/scenes/title/title_bg.gif";
// Entitats pre-carregades a GameScene (dust + 4 direccions de whip).
constexpr const char* DUST_GIF = "data/entities/dust/dust.gif";
constexpr const char* WHIP_EAST_GIF = "data/entities/whip_attack/whip_east.gif";
constexpr const char* WHIP_WEST_GIF = "data/entities/whip_attack/whip_west.gif";
constexpr const char* WHIP_NORTH_GIF = "data/entities/whip_attack/whip_north.gif";
constexpr const char* WHIP_SOUTH_GIF = "data/entities/whip_attack/whip_south.gif";
} // namespace Paths
} // namespace Defaults } // namespace Defaults
+2 -1
View File
@@ -33,6 +33,7 @@
#include "core/input/key_config.hpp" #include "core/input/key_config.hpp"
#include "game/debug_config.hpp" #include "game/debug_config.hpp"
#include "game/scenes/placeholder_input.hpp" #include "game/scenes/placeholder_input.hpp"
#include "utils/defaults.hpp"
namespace { namespace {
@@ -114,7 +115,7 @@ namespace {
void testIsReservedScancodeAfterLoad() { void testIsReservedScancodeAfterLoad() {
std::cout << "T8 isReservedScancode després de KeyConfig::load\n"; std::cout << "T8 isReservedScancode després de KeyConfig::load\n";
KeyConfig::get().load("data/input/keys.yaml"); KeyConfig::get().load(Defaults::Paths::INPUT_YAML);
CHECK(Placeholder::isReservedScancode(SDL_SCANCODE_F1)); CHECK(Placeholder::isReservedScancode(SDL_SCANCODE_F1));
CHECK(Placeholder::isReservedScancode(SDL_SCANCODE_F12)); CHECK(Placeholder::isReservedScancode(SDL_SCANCODE_F12));
CHECK(Placeholder::isReservedScancode(SDL_SCANCODE_ESCAPE)); CHECK(Placeholder::isReservedScancode(SDL_SCANCODE_ESCAPE));