From 05465b791e4cbece24f0de69e0b2290e7ff05d0b Mon Sep 17 00:00:00 2001 From: Sergio Valor Date: Thu, 7 May 2026 19:28:28 +0200 Subject: [PATCH] refactor(data): reorganitza data/ i centralitza paths a defaults.hpp --- data/{ => audio}/music/playing.ogg | Bin data/{ => audio}/music/pyramid_1.ogg | Bin data/{ => audio}/music/room_intro.ogg | Bin data/{ => audio}/music/room_outro.ogg | Bin data/{ => audio}/music/title.ogg | Bin data/{ => audio}/sounds/glitch.wav | Bin data/{ => audio}/sounds/hurt.wav | Bin data/{ => audio}/sounds/jump.wav | Bin data/{ => audio}/sounds/land.wav | Bin data/{ => audio}/sounds/menu_accept.wav | Bin data/{ => audio}/sounds/menu_select.wav | Bin data/{ => audio}/sounds/player_start.wav | Bin data/{ => audio}/sounds/whip.wav | Bin data/{editor => config}/editor.yaml | 0 data/{input/keys.yaml => config/input.yaml} | 0 data/{ => config}/sounds.yaml | 0 data/config/ui.yaml | 115 ++++++++++ data/{ => entities}/player/immune.pal | 0 data/{ => entities}/player/morcus.gif | Bin data/{ => entities}/player/morcus.yaml | 2 +- data/{ => entities}/player/sam.gif | Bin data/{ => entities}/player/sam.yaml | 2 +- data/scenes/{ => game}/game.yaml | 6 +- data/scenes/logo/logo.yaml | 24 ++ data/{ => scenes}/logo/logo_jailgames.gif | Bin .../{ => scenes}/logo/logo_jailgames_mini.gif | Bin data/{ => scenes}/logo/logo_since_1998.gif | Bin data/{ => scenes}/title/game_logo.gif | Bin data/scenes/title/title.yaml | 77 +++++++ data/{ => scenes}/title/title_bg.gif | Bin data/ui.yaml | 217 ------------------ source/core/audio/audio.hpp | 2 +- source/core/audio/sound_effects_config.hpp | 2 +- source/core/input/global_inputs.cpp | 4 +- source/core/input/key_config.hpp | 2 +- .../core/rendering/notification_presets.hpp | 4 +- source/core/resources/resource_helper.cpp | 3 +- source/core/system/director.cpp | 49 ++-- source/core/ui/ui_config.hpp | 8 +- source/game/editor/editor.cpp | 2 +- source/game/editor/editor_config.hpp | 2 +- source/game/entities/entity_loader.cpp | 3 +- .../entities/entity_manager_loadlevel.cpp | 3 +- source/game/entities/player.cpp | 19 +- source/game/entities/player.hpp | 14 +- source/game/scenes/game_scene.cpp | 22 +- source/game/scenes/game_scene.hpp | 4 +- source/game/scenes/placeholder_input.hpp | 2 +- source/game/scenes/room_fsm.hpp | 4 +- source/game/scenes/title_scene.hpp | 2 +- source/game/ui/hud.cpp | 4 +- source/game/ui/hud.hpp | 2 +- source/utils/defaults.hpp | 69 +++++- tests/test_scene_flow.cpp | 3 +- 54 files changed, 368 insertions(+), 304 deletions(-) rename data/{ => audio}/music/playing.ogg (100%) rename data/{ => audio}/music/pyramid_1.ogg (100%) rename data/{ => audio}/music/room_intro.ogg (100%) rename data/{ => audio}/music/room_outro.ogg (100%) rename data/{ => audio}/music/title.ogg (100%) rename data/{ => audio}/sounds/glitch.wav (100%) rename data/{ => audio}/sounds/hurt.wav (100%) rename data/{ => audio}/sounds/jump.wav (100%) rename data/{ => audio}/sounds/land.wav (100%) rename data/{ => audio}/sounds/menu_accept.wav (100%) rename data/{ => audio}/sounds/menu_select.wav (100%) rename data/{ => audio}/sounds/player_start.wav (100%) rename data/{ => audio}/sounds/whip.wav (100%) rename data/{editor => config}/editor.yaml (100%) rename data/{input/keys.yaml => config/input.yaml} (100%) rename data/{ => config}/sounds.yaml (100%) create mode 100644 data/config/ui.yaml rename data/{ => entities}/player/immune.pal (100%) rename data/{ => entities}/player/morcus.gif (100%) rename data/{ => entities}/player/morcus.yaml (98%) rename data/{ => entities}/player/sam.gif (100%) rename data/{ => entities}/player/sam.yaml (98%) rename data/scenes/{ => game}/game.yaml (90%) create mode 100644 data/scenes/logo/logo.yaml rename data/{ => scenes}/logo/logo_jailgames.gif (100%) rename data/{ => scenes}/logo/logo_jailgames_mini.gif (100%) rename data/{ => scenes}/logo/logo_since_1998.gif (100%) rename data/{ => scenes}/title/game_logo.gif (100%) create mode 100644 data/scenes/title/title.yaml rename data/{ => scenes}/title/title_bg.gif (100%) delete mode 100644 data/ui.yaml diff --git a/data/music/playing.ogg b/data/audio/music/playing.ogg similarity index 100% rename from data/music/playing.ogg rename to data/audio/music/playing.ogg diff --git a/data/music/pyramid_1.ogg b/data/audio/music/pyramid_1.ogg similarity index 100% rename from data/music/pyramid_1.ogg rename to data/audio/music/pyramid_1.ogg diff --git a/data/music/room_intro.ogg b/data/audio/music/room_intro.ogg similarity index 100% rename from data/music/room_intro.ogg rename to data/audio/music/room_intro.ogg diff --git a/data/music/room_outro.ogg b/data/audio/music/room_outro.ogg similarity index 100% rename from data/music/room_outro.ogg rename to data/audio/music/room_outro.ogg diff --git a/data/music/title.ogg b/data/audio/music/title.ogg similarity index 100% rename from data/music/title.ogg rename to data/audio/music/title.ogg diff --git a/data/sounds/glitch.wav b/data/audio/sounds/glitch.wav similarity index 100% rename from data/sounds/glitch.wav rename to data/audio/sounds/glitch.wav diff --git a/data/sounds/hurt.wav b/data/audio/sounds/hurt.wav similarity index 100% rename from data/sounds/hurt.wav rename to data/audio/sounds/hurt.wav diff --git a/data/sounds/jump.wav b/data/audio/sounds/jump.wav similarity index 100% rename from data/sounds/jump.wav rename to data/audio/sounds/jump.wav diff --git a/data/sounds/land.wav b/data/audio/sounds/land.wav similarity index 100% rename from data/sounds/land.wav rename to data/audio/sounds/land.wav diff --git a/data/sounds/menu_accept.wav b/data/audio/sounds/menu_accept.wav similarity index 100% rename from data/sounds/menu_accept.wav rename to data/audio/sounds/menu_accept.wav diff --git a/data/sounds/menu_select.wav b/data/audio/sounds/menu_select.wav similarity index 100% rename from data/sounds/menu_select.wav rename to data/audio/sounds/menu_select.wav diff --git a/data/sounds/player_start.wav b/data/audio/sounds/player_start.wav similarity index 100% rename from data/sounds/player_start.wav rename to data/audio/sounds/player_start.wav diff --git a/data/sounds/whip.wav b/data/audio/sounds/whip.wav similarity index 100% rename from data/sounds/whip.wav rename to data/audio/sounds/whip.wav diff --git a/data/editor/editor.yaml b/data/config/editor.yaml similarity index 100% rename from data/editor/editor.yaml rename to data/config/editor.yaml diff --git a/data/input/keys.yaml b/data/config/input.yaml similarity index 100% rename from data/input/keys.yaml rename to data/config/input.yaml diff --git a/data/sounds.yaml b/data/config/sounds.yaml similarity index 100% rename from data/sounds.yaml rename to data/config/sounds.yaml diff --git a/data/config/ui.yaml b/data/config/ui.yaml new file mode 100644 index 0000000..d5875a7 --- /dev/null +++ b/data/config/ui.yaml @@ -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" diff --git a/data/player/immune.pal b/data/entities/player/immune.pal similarity index 100% rename from data/player/immune.pal rename to data/entities/player/immune.pal diff --git a/data/player/morcus.gif b/data/entities/player/morcus.gif similarity index 100% rename from data/player/morcus.gif rename to data/entities/player/morcus.gif diff --git a/data/player/morcus.yaml b/data/entities/player/morcus.yaml similarity index 98% rename from data/player/morcus.yaml rename to data/entities/player/morcus.yaml index 6d38939..03247e6 100644 --- a/data/player/morcus.yaml +++ b/data/entities/player/morcus.yaml @@ -136,7 +136,7 @@ death: # poden ferir ni matar el jugador (els forats sí que el maten — la # caiguda no és dany convencional). Visualment es manifesta amb un # parpadeig que alterna la paleta normal del sprite amb la paleta -# `palette` (basename de `data/player/.pal`) cada +# `palette` (basename de `data/entities/player/.pal`) cada # `blink_period_ms` ms. Si `duration_ms` és 0 (o el bloc manca), la # mecànica queda desactivada i el comportament és l'antic. immunity: diff --git a/data/player/sam.gif b/data/entities/player/sam.gif similarity index 100% rename from data/player/sam.gif rename to data/entities/player/sam.gif diff --git a/data/player/sam.yaml b/data/entities/player/sam.yaml similarity index 98% rename from data/player/sam.yaml rename to data/entities/player/sam.yaml index bfcc650..ccca89d 100644 --- a/data/player/sam.yaml +++ b/data/entities/player/sam.yaml @@ -136,7 +136,7 @@ death: # poden ferir ni matar el jugador (els forats sí que el maten — la # caiguda no és dany convencional). Visualment es manifesta amb un # parpadeig que alterna la paleta normal del sprite amb la paleta -# `palette` (basename de `data/player/.pal`) cada +# `palette` (basename de `data/entities/player/.pal`) cada # `blink_period_ms` ms. Si `duration_ms` és 0 (o el bloc manca), la # mecànica queda desactivada i el comportament és l'antic. immunity: diff --git a/data/scenes/game.yaml b/data/scenes/game/game.yaml similarity index 90% rename from data/scenes/game.yaml rename to data/scenes/game/game.yaml index 285d25b..6c9f0e6 100644 --- a/data/scenes/game.yaml +++ b/data/scenes/game/game.yaml @@ -1,6 +1,6 @@ # 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 -# 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 # fallbacks compilats; veure `readSceneConfig` a game_scene.cpp. @@ -17,7 +17,7 @@ room_intro: # single-player s'usa només `player_spawn_delay_ms`. player_spawn_delay_ms: 0 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 # "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. @@ -33,7 +33,7 @@ room_outro: text: # 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 exit_curve: inCubic diff --git a/data/scenes/logo/logo.yaml b/data/scenes/logo/logo.yaml new file mode 100644 index 0000000..01d65c8 --- /dev/null +++ b/data/scenes/logo/logo.yaml @@ -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 diff --git a/data/logo/logo_jailgames.gif b/data/scenes/logo/logo_jailgames.gif similarity index 100% rename from data/logo/logo_jailgames.gif rename to data/scenes/logo/logo_jailgames.gif diff --git a/data/logo/logo_jailgames_mini.gif b/data/scenes/logo/logo_jailgames_mini.gif similarity index 100% rename from data/logo/logo_jailgames_mini.gif rename to data/scenes/logo/logo_jailgames_mini.gif diff --git a/data/logo/logo_since_1998.gif b/data/scenes/logo/logo_since_1998.gif similarity index 100% rename from data/logo/logo_since_1998.gif rename to data/scenes/logo/logo_since_1998.gif diff --git a/data/title/game_logo.gif b/data/scenes/title/game_logo.gif similarity index 100% rename from data/title/game_logo.gif rename to data/scenes/title/game_logo.gif diff --git a/data/scenes/title/title.yaml b/data/scenes/title/title.yaml new file mode 100644 index 0000000..040dcd3 --- /dev/null +++ b/data/scenes/title/title.yaml @@ -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 diff --git a/data/title/title_bg.gif b/data/scenes/title/title_bg.gif similarity index 100% rename from data/title/title_bg.gif rename to data/scenes/title/title_bg.gif diff --git a/data/ui.yaml b/data/ui.yaml deleted file mode 100644 index b0b4802..0000000 --- a/data/ui.yaml +++ /dev/null @@ -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 diff --git a/source/core/audio/audio.hpp b/source/core/audio/audio.hpp index 9c4c387..26b94c1 100644 --- a/source/core/audio/audio.hpp +++ b/source/core/audio/audio.hpp @@ -80,7 +80,7 @@ class Audio { // --- Control de sons --- 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) - // 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 // o el motor està al cap de canals amb efecte, fa fallback a playSound // sec — l'usuari sent el so igualment, sense la cua. diff --git a/source/core/audio/sound_effects_config.hpp b/source/core/audio/sound_effects_config.hpp index c5878f8..aa1d447 100644 --- a/source/core/audio/sound_effects_config.hpp +++ b/source/core/audio/sound_effects_config.hpp @@ -5,7 +5,7 @@ #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 // preset no existeix, el so es reprodueix sec amb un avís a stderr. // diff --git a/source/core/input/global_inputs.cpp b/source/core/input/global_inputs.cpp index 8e2cdba..96454a1 100644 --- a/source/core/input/global_inputs.cpp +++ b/source/core/input/global_inputs.cpp @@ -26,7 +26,7 @@ namespace GlobalInputs { // La lliguem a la durada de la notificació EXIT perquè el missatge i // 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). - // 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 MAX_ZOOM = 6; @@ -161,7 +161,7 @@ namespace GlobalInputs { // Debug helper: dispara una notificació prou llarga perquè // `wrapToWidth` la parteixi en (almenys) dues línies. Útil per a // 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() { Notification::notify("Notificació de prova llarga per a comprovar que el text es parteix correctament en dues línies dins la caixa."); } diff --git a/source/core/input/key_config.hpp b/source/core/input/key_config.hpp index 89be7fe..8484fe4 100644 --- a/source/core/input/key_config.hpp +++ b/source/core/input/key_config.hpp @@ -5,7 +5,7 @@ #include #include -// 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 // 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 diff --git a/source/core/rendering/notification_presets.hpp b/source/core/rendering/notification_presets.hpp index bfd068c..ad9575c 100644 --- a/source/core/rendering/notification_presets.hpp +++ b/source/core/rendering/notification_presets.hpp @@ -9,7 +9,7 @@ // 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 -// 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 // Notification::notify(text, preset). Sense preset s'usa el DEFAULT. namespace Notification { @@ -22,7 +22,7 @@ namespace Notification { // 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 - // data/ui.yaml i es carreguen a l'arrencada. + // data/config/ui.yaml i es carreguen a l'arrencada. [[nodiscard]] inline auto defaultPreset() -> Preset { return { .text_color = UiConfig::get().notificationText(), diff --git a/source/core/resources/resource_helper.cpp b/source/core/resources/resource_helper.cpp index 86cf03b..1b9571b 100644 --- a/source/core/resources/resource_helper.cpp +++ b/source/core/resources/resource_helper.cpp @@ -6,6 +6,7 @@ #include #include "core/resources/resource_pack.hpp" +#include "utils/defaults.hpp" namespace Resource::Helper { @@ -92,7 +93,7 @@ namespace Resource::Helper { // carpeta `data/`). const auto FROM_PACK = [&filepath]() -> std::vector { if (!g_pack_loaded) { return {}; } - constexpr std::string_view PREFIX = "data/"; + const std::string_view PREFIX{Defaults::Paths::DATA_ROOT}; std::string key = filepath; if (key.starts_with(PREFIX)) { key.erase(0, PREFIX.size()); } if (g_pack.hasResource(key)) { return g_pack.getResource(key); } diff --git a/source/core/system/director.cpp b/source/core/system/director.cpp index bd341b9..ede5663 100644 --- a/source/core/system/director.cpp +++ b/source/core/system/director.cpp @@ -118,22 +118,29 @@ Director::Director() { Locale::get().load(std::string(Defaults::I18n::LOCALE_DIR) + Options::locale() + ".yaml"); // 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 - // data/ui.yaml cau al valor compilat a Defaults::UI. - UiConfig::get().load("data/ui.yaml"); + // data/config/ui.yaml cau al valor compilat a Defaults::UI. + 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 // Tema visual de l'editor de tilemap (Debug-only). Claus absents // cauen als valors compilats a Defaults::Editor. - EditorConfig::get().load("data/editor/editor.yaml"); + EditorConfig::get().load(Defaults::Paths::EDITOR_YAML); #endif // Recursos compartits d'UI (paleta + fonts). Es carreguen abans que els // overlays perquè tots els reaprofiten sense duplicar la lògica. Els - // noms de font viuen al fitxer data/ui.yaml via UiConfig. - Resource::Cache::get().loadPalette("ui", "data/palettes/uzebox.pal"); + // noms de font viuen al fitxer data/config/ui.yaml via UiConfig. + Resource::Cache::get().loadPalette("ui", Defaults::Paths::UI_PALETTE); 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().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 // 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`. - Resource::Cache::get().loadMusic("room_intro.ogg", "data/music/room_intro.ogg"); - Resource::Cache::get().loadMusic("playing.ogg", "data/music/playing.ogg"); - Resource::Cache::get().loadMusic("room_outro.ogg", "data/music/room_outro.ogg"); + Resource::Cache::get().loadMusic("room_intro.ogg", Defaults::Paths::MUSIC_ROOM_INTRO); + Resource::Cache::get().loadMusic("playing.ogg", Defaults::Paths::MUSIC_PLAYING); + 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 // 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 // dispara via Audio::Group::INTERFACE. const auto& menu_select = UiConfig::get().menuSelectSound(); const auto& menu_accept = UiConfig::get().menuAcceptSound(); - Resource::Cache::get().loadSound(menu_select, "data/sounds/" + menu_select); - Resource::Cache::get().loadSound(menu_accept, "data/sounds/" + menu_accept); + Resource::Cache::get().loadSound(menu_select, std::string{Defaults::Paths::AUDIO_SOUNDS_DIR} + menu_select); + 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 // prem START (vore enterStarting i el reset del segon jugador). 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 // ctor; amb fallback al nom de Defaults si la clau YAML no hi és. 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 // perquè els primers playSoundWith* (al començament del joc) ja // 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 // 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` // 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) { const std::string KEY = font.name + ".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 // del logo). 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); mini_logo_surface_ = mini_logo_surface; @@ -241,20 +248,20 @@ Director::Director() { // conserva la seua paleta nadiua: els colors finals del logo viuen // dins del propi GIF i no han de passar per la paleta UI. 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); // Logotip del joc per a la TITLE (substitueix el text "Aventures en // Egipte ARCADE"). Igual que la resta de logos, paleta nadiua — // l'art ja porta els colors finals i no passa per la UI. 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); // Fons sencer de la TITLE (320×240). Igual que el minilogo, conserva // la seua paleta nadiua perquè el GIF ja porta els colors finals. 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); title_bg_surface_ = title_bg_surface; ServiceMenu::get().init(menu_title_text, menu_items_text, ui_palette); diff --git a/source/core/ui/ui_config.hpp b/source/core/ui/ui_config.hpp index efe61ed..a6e78b8 100644 --- a/source/core/ui/ui_config.hpp +++ b/source/core/ui/ui_config.hpp @@ -5,7 +5,7 @@ #include // 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 // 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]. - // 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`. using CurveFn = auto (*)(float) -> float; // 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 // velocitat, perquè una caixa més gran no triga més a entrar/eixir. struct Notifier { @@ -170,7 +170,7 @@ class UiConfig { [[nodiscard]] static auto curveByName(const std::string& name) -> CurveFn; // 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 menuAcceptSound() const -> const std::string& { return menu_accept_sound_; } [[nodiscard]] auto playerStartSound() const -> const std::string& { return player_start_sound_; } diff --git a/source/game/editor/editor.cpp b/source/game/editor/editor.cpp index 2e05696..a5adaac 100644 --- a/source/game/editor/editor.cpp +++ b/source/game/editor/editor.cpp @@ -234,7 +234,7 @@ void Editor::ensureEditableEntities() { // llança si no troba — provem primer i, en cas de miss, carreguem. const auto REL = sp["path"].get_value(); 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 += '/'; full += REL; diff --git a/source/game/editor/editor_config.hpp b/source/game/editor/editor_config.hpp index 57673b5..3666332 100644 --- a/source/game/editor/editor_config.hpp +++ b/source/game/editor/editor_config.hpp @@ -6,7 +6,7 @@ #include // 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). class EditorConfig { public: diff --git a/source/game/entities/entity_loader.cpp b/source/game/entities/entity_loader.cpp index 34c8a85..f03d7e3 100644 --- a/source/game/entities/entity_loader.cpp +++ b/source/game/entities/entity_loader.cpp @@ -6,6 +6,7 @@ #include "core/resources/resource_helper.hpp" #include "game/entities/entity.hpp" #include "game/entities/entity_factory.hpp" +#include "utils/defaults.hpp" namespace EntityLoader { @@ -20,7 +21,7 @@ namespace EntityLoader { } 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 diff --git a/source/game/entities/entity_manager_loadlevel.cpp b/source/game/entities/entity_manager_loadlevel.cpp index c562772..cc8894f 100644 --- a/source/game/entities/entity_manager_loadlevel.cpp +++ b/source/game/entities/entity_manager_loadlevel.cpp @@ -21,6 +21,7 @@ #include "game/entities/entity_manager.hpp" #include "game/entities/player.hpp" #include "game/map/map.hpp" +#include "utils/defaults.hpp" // Render centralitzat al manager per confinar la dependència cap a // `Surface`. Les entitats exposen `getSurface()` + `getPixelRect()` i el @@ -124,7 +125,7 @@ namespace { if (s.contains("path")) { const auto REL = s["path"].get_value(); 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; } if (s.contains("size")) { diff --git a/source/game/entities/player.cpp b/source/game/entities/player.cpp index 00b47f3..f009bf2 100644 --- a/source/game/entities/player.cpp +++ b/source/game/entities/player.cpp @@ -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(); } if (j.contains("landing_stun_ms")) { jump_config.landing_stun_ms = j["landing_stun_ms"].get_value(); } if (j.contains("shadow_y_offset")) { jump_config.shadow_y_offset = j["shadow_y_offset"].get_value(); } - // Sons opcionals: el nom del fitxer (relatiu a data/sounds/) val tant - // de clau al Resource::Cache com de basename per a la càrrega. Si el - // camp manca, la clau queda buida i `playSound` no es crida. + // Sons opcionals: el nom del fitxer (relatiu a Defaults::Paths::AUDIO_SOUNDS_DIR) + // val tant de clau al Resource::Cache com de basename per a la càrrega. + // Si el camp manca, la clau queda buida i `playSound` no es crida. if (j.contains("sound")) { jump_config.sound_key = j["sound"].get_value(); - 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")) { jump_config.land_sound_key = j["land_sound"].get_value(); - 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`. if (h.contains("sound")) { hurt_config.sound_key = h["sound"].get_value(); - 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(); } if (im.contains("blink_period_ms")) { immunity_config.blink_period_ms = im["blink_period_ms"].get_value(); } // Paleta del blink: el basename val tant de clau al Resource::Cache - // com de path (`data/player/.pal`). Mateix patró que els sons. + // com de path (`Defaults::Paths::PLAYER_DIR + key + .pal`). Mateix patró + // que els sons. if (im.contains("palette")) { immunity_config.palette_key = im["palette"].get_value(); - 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. if (w.contains("sound")) { whip_config.sound_key = w["sound"].get_value(); - 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); } } diff --git a/source/game/entities/player.hpp b/source/game/entities/player.hpp index b60b451..86fa705 100644 --- a/source/game/entities/player.hpp +++ b/source/game/entities/player.hpp @@ -91,7 +91,7 @@ class Player : public AnimatedSprite { 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 // 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). @@ -362,7 +362,7 @@ class Player : public AnimatedSprite { // al respawn post-mort: mateixa entrada cinemàtica. 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 // d'INTRO de sala: GameScene crida aquesta funció just després de // `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. 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` // (cridada per GameScene al spawn aeri d'INTRO) i el consumeix // `integrateJump` quan el jugador toca terra. Cap altre punt @@ -636,7 +636,7 @@ class Player : public AnimatedSprite { struct HurtConfig { 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. - // 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 // de clau al Resource::Cache i de path. Buit o absent = entrada // silenciosa. @@ -660,7 +660,7 @@ class Player : public AnimatedSprite { int cooldown_ms{0}; int damage{0}; // 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. std::string sound_key; }; @@ -697,7 +697,7 @@ class Player : public AnimatedSprite { float duration_ms{0.0F}; int blink_period_ms{0}; // 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 // pot ser confusa, però no és incorrecte). std::string palette_key; @@ -706,7 +706,7 @@ class Player : public AnimatedSprite { // Llig el bloc `immunity:` del YAML i n'omple `immunity_config`. Si // hi ha `palette`, registra la paleta corresponent al Resource::Cache - // (path: `data/player/.pal`). Mateix patró que els altres + // (path: `data/entities/player/.pal`). Mateix patró que els altres // readers — `loadFrom` el crida al final. static void readImmunityBlock(const fkyaml::node& yaml); diff --git a/source/game/scenes/game_scene.cpp b/source/game/scenes/game_scene.cpp index 4b0afd5..9b46187 100644 --- a/source/game/scenes/game_scene.cpp +++ b/source/game/scenes/game_scene.cpp @@ -229,10 +229,10 @@ auto GameScene::defaultConfig() -> Config { // concret de sala — només cap a on apunta la progressió ara mateix. return { .map_yaml = Levels::LevelManager::get().currentPath(), - .player_sprite = Defaults::Pyramid::PLAYER_SPRITE, - .player_yaml = Defaults::Pyramid::PLAYER_YAML, - .player2_sprite = Defaults::Pyramid::PLAYER_SPRITE_P2, - .player2_yaml = Defaults::Pyramid::PLAYER_YAML_P2, + .player_sprite = Defaults::Pyramid::PLAYER_SAM_GIF, + .player_yaml = Defaults::Pyramid::PLAYER_SAM_YAML, + .player2_sprite = Defaults::Pyramid::PLAYER_MORCUS_GIF, + .player2_yaml = Defaults::Pyramid::PLAYER_MORCUS_YAML, .music_track = Defaults::Pyramid::MUSIC_TRACK, .starting_players = DebugConfig::StartingPlayers::BOTH, }; @@ -312,7 +312,7 @@ GameScene::GameScene(Config config) // També ens subscrivim a `player_jumped` i `player_landed` per // spawnejar el polvet de despegue / aterratge a la posició dels // 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) { const auto* pos = std::get_if(&ev.payload); 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 // primer spawn perquè el Player no facte disc al primer atac. // 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_west.gif", "data/entities/whip_attack/whip_west.gif"); - Resource::Cache::get().loadSurface("whip_north.gif", "data/entities/whip_attack/whip_north.gif"); - Resource::Cache::get().loadSurface("whip_south.gif", "data/entities/whip_attack/whip_south.gif"); + Resource::Cache::get().loadSurface("whip_east.gif", Defaults::Paths::WHIP_EAST_GIF); + Resource::Cache::get().loadSurface("whip_west.gif", Defaults::Paths::WHIP_WEST_GIF); + Resource::Cache::get().loadSurface("whip_north.gif", Defaults::Paths::WHIP_NORTH_GIF); + Resource::Cache::get().loadSurface("whip_south.gif", Defaults::Paths::WHIP_SOUTH_GIF); entity_manager_.getBus().subscribe("whip_spawn", [this](const Event& ev) { const auto* p = std::get_if(&ev.payload); 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 // 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 // `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 // i tenir el rètol equilibrat sobre el playfield. 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ó. const Uint8 FILL = UiConfig::get().roomText(); const Uint8 OUTLINE = UiConfig::get().roomTextOutline(); diff --git a/source/game/scenes/game_scene.hpp b/source/game/scenes/game_scene.hpp index 46aab54..c139d9a 100644 --- a/source/game/scenes/game_scene.hpp +++ b/source/game/scenes/game_scene.hpp @@ -202,7 +202,7 @@ class GameScene : public Scene { // 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 // 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. std::shared_ptr room_text_font_; @@ -224,7 +224,7 @@ class GameScene : public Scene { } pause_; // 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_{}; // Estat actual de la FSM de sala. S'inicialitza a ROOM_INTRO al ctor diff --git a/source/game/scenes/placeholder_input.hpp b/source/game/scenes/placeholder_input.hpp index ff27318..6de6ade 100644 --- a/source/game/scenes/placeholder_input.hpp +++ b/source/game/scenes/placeholder_input.hpp @@ -8,7 +8,7 @@ namespace Placeholder { // 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 // aquesta funció tornarà false, de manera que el test/smoke no depèn de // l'estat global de la configuració. diff --git a/source/game/scenes/room_fsm.hpp b/source/game/scenes/room_fsm.hpp index 7ca8a60..3e1ddc3 100644 --- a/source/game/scenes/room_fsm.hpp +++ b/source/game/scenes/room_fsm.hpp @@ -35,7 +35,7 @@ namespace RoomFsm { 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 // fitxer, la FSM funciona igualment amb aquests fallbacks. struct Config { @@ -94,7 +94,7 @@ namespace RoomFsm { UiConfig::CurveFn text_enter_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 // aterratge cinemàtic; els salts posteriors del joc i els // respawns post-mort cauen al so sec. Buit = sense reverb (la diff --git a/source/game/scenes/title_scene.hpp b/source/game/scenes/title_scene.hpp index 6fcfd5b..dba00da 100644 --- a/source/game/scenes/title_scene.hpp +++ b/source/game/scenes/title_scene.hpp @@ -17,7 +17,7 @@ class Text; // Escena TITLE provisional. Pinta dos blocs de text sobre un fons gairebé // negre i un prompt "press start" intermitent fins que apareix l'artwork // 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 { public: // Fases de l'escena. diff --git a/source/game/ui/hud.cpp b/source/game/ui/hud.cpp index 6c402c3..a65332d 100644 --- a/source/game/ui/hud.cpp +++ b/source/game/ui/hud.cpp @@ -22,7 +22,7 @@ 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 // crear jerarquia visual respecte als valors; el flash temporal usa un // to càlid que contrasta amb el valor normal. @@ -73,7 +73,7 @@ Hud::Hud(EventBus& bus, std::shared_ptr font) : bus_(bus), font_(std::move(font)) { // 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(); blocks_[0] = Block{ .x = 0, diff --git a/source/game/ui/hud.hpp b/source/game/ui/hud.hpp index e8a9a3c..3a4486a 100644 --- a/source/game/ui/hud.hpp +++ b/source/game/ui/hud.hpp @@ -104,7 +104,7 @@ class Hud { // 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 - // 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}; // 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. diff --git a/source/utils/defaults.hpp b/source/utils/defaults.hpp index d58e7aa..fd80dac 100644 --- a/source/utils/defaults.hpp +++ b/source/utils/defaults.hpp @@ -107,7 +107,7 @@ namespace Defaults { } // namespace Player // 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 // li manca alguna clau. Ací només cal tocar-los si es vol canviar el // fallback "de fàbrica". @@ -251,14 +251,14 @@ namespace Defaults { // Sons del menú de servei. SELECT acompanya navegació (amunt/avall) // 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_ACCEPT_SOUND = "menu_accept.wav"; // So disparat quan un jugador prem START a la TITLE (tant la // primera pulsació que entra a STARTING com la del segon // 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"; // 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 // ritmes per piràmide, aquest YAML pot adoptar variants per nivell. namespace GameScene { - constexpr const char* CONFIG_YAML = "data/scenes/game.yaml"; + constexpr const char* GAME_YAML = "data/scenes/game/game.yaml"; } // namespace GameScene // 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 // `LevelManager` (`currentPath()`) i deixeu que ell decidisca. constexpr const char* LEVELS_YAML = "data/maps/levels.yaml"; - constexpr const char* PLAYER_SPRITE = "data/player/sam.gif"; - constexpr const char* PLAYER_YAML = "data/player/sam.yaml"; + constexpr const char* PLAYER_SAM_GIF = "data/entities/player/sam.gif"; + constexpr const char* PLAYER_SAM_YAML = "data/entities/player/sam.yaml"; // Personatge del segon jugador. Clonat de sam amb repaletat (roig→blau); // 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. - constexpr const char* PLAYER_SPRITE_P2 = "data/player/morcus.gif"; - constexpr const char* PLAYER_YAML_P2 = "data/player/morcus.yaml"; + constexpr const char* PLAYER_MORCUS_GIF = "data/entities/player/morcus.gif"; + constexpr const char* PLAYER_MORCUS_YAML = "data/entities/player/morcus.yaml"; constexpr const char* MUSIC_TRACK = "playing.ogg"; } // 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 diff --git a/tests/test_scene_flow.cpp b/tests/test_scene_flow.cpp index 533853f..1eb8097 100644 --- a/tests/test_scene_flow.cpp +++ b/tests/test_scene_flow.cpp @@ -33,6 +33,7 @@ #include "core/input/key_config.hpp" #include "game/debug_config.hpp" #include "game/scenes/placeholder_input.hpp" +#include "utils/defaults.hpp" namespace { @@ -114,7 +115,7 @@ namespace { void testIsReservedScancodeAfterLoad() { 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_F12)); CHECK(Placeholder::isReservedScancode(SDL_SCANCODE_ESCAPE));