diff --git a/data/fonts/PixeloidSans-Bold.fnt b/data/fonts/PixeloidSans-Bold.fnt new file mode 100644 index 0000000..375dd08 --- /dev/null +++ b/data/fonts/PixeloidSans-Bold.fnt @@ -0,0 +1,133 @@ +# Font: PixeloidSans-Bold — generado desde PixeloidSans-Bold.ttf size 9 +# Generado con font_gen.py + +box_width 10 +box_height 11 +columns 15 + +# codepoint_decimal ancho_visual +32 4 # U+0020 +33 2 # ! +34 5 # " +35 7 # # +36 7 # $ +37 6 # % +38 7 # & +39 2 # ' +40 4 # ( +41 4 # ) +42 5 # * +43 4 # + +44 2 # , +45 4 # - +46 2 # . +47 6 # / +48 6 # 0 +49 6 # 1 +50 6 # 2 +51 6 # 3 +52 6 # 4 +53 6 # 5 +54 6 # 6 +55 6 # 7 +56 6 # 8 +57 6 # 9 +58 2 # : +59 2 # ; +60 4 # < +61 4 # = +62 4 # > +63 6 # ? +64 6 # @ +65 6 # A +66 6 # B +67 6 # C +68 6 # D +69 6 # E +70 6 # F +71 6 # G +72 6 # H +73 4 # I +74 5 # J +75 6 # K +76 6 # L +77 8 # M +78 7 # N +79 6 # O +80 6 # P +81 6 # Q +82 6 # R +83 6 # S +84 6 # T +85 6 # U +86 6 # V +87 8 # W +88 6 # X +89 6 # Y +90 6 # Z +91 5 # [ +92 6 # \ +93 5 # ] +94 6 # ^ +95 4 # _ +96 3 # ` +97 6 # a +98 6 # b +99 6 # c +100 6 # d +101 6 # e +102 4 # f +103 6 # g +104 6 # h +105 2 # i +106 5 # j +107 5 # k +108 2 # l +109 8 # m +110 6 # n +111 6 # o +112 6 # p +113 6 # q +114 5 # r +115 6 # s +116 4 # t +117 6 # u +118 6 # v +119 8 # w +120 6 # x +121 6 # y +122 6 # z +123 5 # { +124 2 # | +125 5 # } +126 7 # ~ +192 6 # À +193 6 # Á +200 6 # È +201 6 # É +204 4 # Ì +205 4 # Í +210 6 # Ò +211 6 # Ó +217 6 # Ù +218 6 # Ú +209 7 # Ñ +199 6 # Ç +224 6 # à +225 6 # á +232 6 # è +233 6 # é +236 3 # ì +237 3 # í +242 6 # ò +243 6 # ó +249 6 # ù +250 6 # ú +241 6 # ñ +231 6 # ç +161 2 # ¡ +191 6 # ¿ +171 7 # « +187 7 # » +183 2 # · +169 9 # © diff --git a/data/fonts/PixeloidSans-Bold.gif b/data/fonts/PixeloidSans-Bold.gif new file mode 100644 index 0000000..1711fc6 Binary files /dev/null and b/data/fonts/PixeloidSans-Bold.gif differ diff --git a/data/title/game_logo.gif b/data/title/game_logo.gif new file mode 100644 index 0000000..0d61106 Binary files /dev/null and b/data/title/game_logo.gif differ diff --git a/data/ui.yaml b/data/ui.yaml index 1fa63b0..98da804 100644 --- a/data/ui.yaml +++ b/data/ui.yaml @@ -58,6 +58,14 @@ fonts: 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 (PixeloidSans-Bold size 9 + # generat amb font-gen). Diferenciada de la `placeholder` que pinta + # el "press start" — així la jerarquia tipogràfica del peu queda neta. + copyright: + name: "PixeloidSans-Bold" + gif: "data/fonts/PixeloidSans-Bold.gif" + fnt: "data/fonts/PixeloidSans-Bold.fnt" + kerning: 1 hud: bg_enabled: false @@ -113,7 +121,7 @@ title: duration_ms: 30000 bg_color: 1 text_color: 31 - copyright_color: 246 + copyright_color: 19 blink_visible_ms: 800 blink_hidden_ms: 200 # Fase STARTING (entre la primera pulsació de START i el salt a la diff --git a/source/core/system/director.cpp b/source/core/system/director.cpp index 5add947..582d707 100644 --- a/source/core/system/director.cpp +++ b/source/core/system/director.cpp @@ -200,6 +200,16 @@ Director::Director() { placeholder_text->setDefaultKerning(UiConfig::get().placeholderFont().kerning); placeholder_text_ = placeholder_text; + // Font del copyright de la TITLE (PixeloidSans-Bold). Pixel-art + // estricte; va amb la paleta UI per compartir índex de color amb la + // resta de textos placeholder. + const std::string COPYRIGHT_FONT_GIF_KEY = UiConfig::get().copyrightFont().name + ".gif"; + Resource::Cache::get().loadSurface(COPYRIGHT_FONT_GIF_KEY, UiConfig::get().copyrightFont().gif); + Resource::Cache::get().getSurface(COPYRIGHT_FONT_GIF_KEY)->setPalette(Resource::Cache::get().getPalette("ui")); + auto copyright_text = std::make_shared(Resource::Cache::get().getSurface(COPYRIGHT_FONT_GIF_KEY), UiConfig::get().copyrightFont().fnt); + copyright_text->setDefaultKerning(UiConfig::get().copyrightFont().kerning); + copyright_text_ = copyright_text; + // 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. @@ -213,7 +223,6 @@ Director::Director() { }; auto menu_title_text = load_menu_font(UiConfig::get().menuTitleFont()); auto menu_items_text = load_menu_font(UiConfig::get().menuItemsFont()); - menu_title_text_ = menu_title_text; // Mini-logo del peu de la TITLE. Es preloda ací per consistència // amb la resta d'assets d'UI; manté la seua paleta original (no la @@ -231,6 +240,13 @@ Director::Director() { Resource::Cache::get().loadSurface(LOGO_FULL_KEY, "data/logo/logo_jailgames.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"); + 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"; @@ -437,7 +453,7 @@ auto Director::buildScene(SceneId id, const SceneParams& params) -> std::unique_ return std::make_unique(logo_full_surface_, p.reset); } case SceneId::TITLE: - return std::make_unique(menu_title_text_, placeholder_text_, title_bg_surface_, mini_logo_surface_); + return std::make_unique(placeholder_text_, copyright_text_, title_bg_surface_, game_logo_surface_, mini_logo_surface_); case SceneId::INTRO: { const auto& p = std::get(params); return std::make_unique(placeholder_text_, p.starting_players); diff --git a/source/core/system/director.hpp b/source/core/system/director.hpp index 2269b10..5c5ee98 100644 --- a/source/core/system/director.hpp +++ b/source/core/system/director.hpp @@ -30,8 +30,9 @@ class Director { // escena. No són `static`/Meyers perquè depenen de l'inici d'SDL i // de Resource::Cache. std::shared_ptr placeholder_text_; - std::shared_ptr menu_title_text_; + std::shared_ptr copyright_text_; std::shared_ptr title_bg_surface_; + std::shared_ptr game_logo_surface_; std::shared_ptr mini_logo_surface_; std::shared_ptr logo_full_surface_; diff --git a/source/core/ui/ui_config.cpp b/source/core/ui/ui_config.cpp index 536c37e..8944ad9 100644 --- a/source/core/ui/ui_config.cpp +++ b/source/core/ui/ui_config.cpp @@ -123,6 +123,7 @@ UiConfig::UiConfig() room_text_font_{.name = Defaults::UI::Font::ROOM_TEXT_NAME, .gif = Defaults::UI::Font::ROOM_TEXT_GIF, .fnt = Defaults::UI::Font::ROOM_TEXT_FNT, .kerning = Defaults::UI::Font::ROOM_TEXT_KERNING}, menu_title_font_{.name = Defaults::UI::Font::MENU_TITLE_NAME, .gif = Defaults::UI::Font::MENU_TITLE_GIF, .fnt = Defaults::UI::Font::MENU_TITLE_FNT, .kerning = Defaults::UI::Font::MENU_TITLE_KERNING}, menu_items_font_{.name = Defaults::UI::Font::MENU_ITEMS_NAME, .gif = Defaults::UI::Font::MENU_ITEMS_GIF, .fnt = Defaults::UI::Font::MENU_ITEMS_FNT, .kerning = Defaults::UI::Font::MENU_ITEMS_KERNING}, + copyright_font_{.name = Defaults::UI::Font::COPYRIGHT_NAME, .gif = Defaults::UI::Font::COPYRIGHT_GIF, .fnt = Defaults::UI::Font::COPYRIGHT_FNT, .kerning = Defaults::UI::Font::COPYRIGHT_KERNING}, notifier_{ .padding_h = Defaults::UI::Notifier::PADDING_H, .padding_top = Defaults::UI::Notifier::PADDING_TOP, @@ -200,6 +201,7 @@ void UiConfig::load(const std::string& file_path) { readFont(f, "room_text", room_text_font_); readFont(f, "menu_title", menu_title_font_); readFont(f, "menu_items", menu_items_font_); + readFont(f, "copyright", copyright_font_); } if (yaml.contains("hud")) { diff --git a/source/core/ui/ui_config.hpp b/source/core/ui/ui_config.hpp index 193facf..aee03e3 100644 --- a/source/core/ui/ui_config.hpp +++ b/source/core/ui/ui_config.hpp @@ -127,6 +127,7 @@ class UiConfig { [[nodiscard]] auto roomTextFont() const -> const Font& { return room_text_font_; } [[nodiscard]] auto menuTitleFont() const -> const Font& { return menu_title_font_; } [[nodiscard]] auto menuItemsFont() const -> const Font& { return menu_items_font_; } + [[nodiscard]] auto copyrightFont() const -> const Font& { return copyright_font_; } // Geometria del Notifier. [[nodiscard]] auto notifier() const -> const Notifier& { return notifier_; } @@ -193,6 +194,7 @@ class UiConfig { Font room_text_font_; Font menu_title_font_; Font menu_items_font_; + Font copyright_font_; Notifier notifier_; diff --git a/source/game/scenes/title_scene.cpp b/source/game/scenes/title_scene.cpp index 9b25de2..53507f2 100644 --- a/source/game/scenes/title_scene.cpp +++ b/source/game/scenes/title_scene.cpp @@ -32,11 +32,6 @@ namespace { // docs/audit-core-rendering.md). const char* const SCENE_NAME = "TITLE"; - // Textos hardcodejats fins que tinguem artwork. Quan apareguen com - // a sprites, aquesta secció desapareix sencera. - const char* const TITLE_LINE_1 = "Aventures en Egipte"; - const char* const TITLE_LINE_2 = "A R C A D E"; - constexpr int TITLE_Y_PERCENT = 25; constexpr int PROMPT_Y_PERCENT = 60; constexpr int COPYRIGHT_Y_PERCENT = 90; @@ -63,14 +58,6 @@ namespace { }); } - // Separació vertical entre la primera i segona línia del títol. Una - // alçada de línia és l'opció més llegible al canvas de 240 px sense - // entrar a configuració extra; si demà cal afinar-ho, mou-se a - // ui.yaml. - [[nodiscard]] auto titleLineGap(const Text& font) -> int { - return font.getLineHeight(); - } - // Reproducció del so de START. Centralitzat ací per disparar-lo des // dels punts on una pulsació té efecte real (entrada a STARTING o // upgrade a BOTH); l'attract timeout no l'ha de tocar. @@ -82,10 +69,11 @@ namespace { } // namespace -TitleScene::TitleScene(std::shared_ptr display_font, std::shared_ptr condensed_font, std::shared_ptr background, std::shared_ptr mini_logo) - : display_font_(std::move(display_font)), - condensed_font_(std::move(condensed_font)), +TitleScene::TitleScene(std::shared_ptr condensed_font, std::shared_ptr copyright_font, std::shared_ptr background, std::shared_ptr game_logo, std::shared_ptr mini_logo) + : condensed_font_(std::move(condensed_font)), + copyright_font_(std::move(copyright_font)), background_(std::move(background)), + game_logo_(std::move(game_logo)), mini_logo_(std::move(mini_logo)), timer_ms_(UiConfig::get().titleDurationMs()) { std::cout << "[scene] " << SCENE_NAME << " start\n"; @@ -275,24 +263,14 @@ void TitleScene::render() { constexpr Uint8 OUTLINE_DIST = 1; constexpr Uint8 STROKE4 = Text::CENTER_FLAG | Text::COLOR_FLAG | Text::STROKE4_FLAG; - if (display_font_) { - const int TITLE_Y = (GameCanvas::HEIGHT * TITLE_Y_PERCENT) / 100; - display_font_->writeDX(STROKE4, - GameCanvas::CENTER_X, - TITLE_Y, - TITLE_LINE_1, - display_font_->getDefaultKerning(), - TEXT_COLOR, - OUTLINE_DIST, - OUTLINE_COLOR); - display_font_->writeDX(STROKE4, - GameCanvas::CENTER_X, - TITLE_Y + titleLineGap(*display_font_), - TITLE_LINE_2, - display_font_->getDefaultKerning(), - TEXT_COLOR, - OUTLINE_DIST, - OUTLINE_COLOR); + // Logotip del joc: GIF amb la seua paleta nadiua, centrat + // horitzontalment al canvas i ancorat al mateix Y on abans naixia + // la primera línia del text. Substitueix els dos `display_font_` + // que pintaven "Aventures en Egipte" + "A R C A D E". + if (game_logo_) { + const int LOGO_Y = (GameCanvas::HEIGHT * TITLE_Y_PERCENT) / 100; + const int LOGO_X = GameCanvas::CENTER_X - (game_logo_->getWidth() / 2); + game_logo_->render(LOGO_X, LOGO_Y); } if (condensed_font_) { @@ -326,20 +304,21 @@ void TitleScene::render() { // Footer: minilogo centrat horitzontalment damunt del © de // copyright. El text va al 90% Y, el logo just damunt amb un petit - // gap (LOGO_GAP_PX). Tots dos blocs són hardcodejats fins que - // tinguem artwork final. - if (condensed_font_) { + // gap (LOGO_GAP_PX). El copyright fa servir una font pixel-art + // pròpia (PixeloidSans-Bold) — més neta i petita que la del + // "press start" perquè la jerarquia tipogràfica del peu quedi clara. + if (copyright_font_) { const int COPY_Y = (GameCanvas::HEIGHT * COPYRIGHT_Y_PERCENT) / 100; if (mini_logo_) { const int LOGO_X = GameCanvas::CENTER_X - (mini_logo_->getWidth() / 2); const int LOGO_Y = COPY_Y - mini_logo_->getHeight() - LOGO_GAP_PX; mini_logo_->render(LOGO_X, LOGO_Y); } - condensed_font_->writeDX(Text::CENTER_FLAG | Text::COLOR_FLAG, + copyright_font_->writeDX(Text::CENTER_FLAG | Text::COLOR_FLAG, GameCanvas::CENTER_X, COPY_Y, "© 2026 JailDesigner", - condensed_font_->getDefaultKerning() - 1, + copyright_font_->getDefaultKerning(), ui_config.titleCopyrightColor()); } diff --git a/source/game/scenes/title_scene.hpp b/source/game/scenes/title_scene.hpp index 61197e3..1fa08f6 100644 --- a/source/game/scenes/title_scene.hpp +++ b/source/game/scenes/title_scene.hpp @@ -34,7 +34,7 @@ class TitleScene : public Scene { STARTING, ATTRACT_OUT }; - TitleScene(std::shared_ptr display_font, std::shared_ptr condensed_font, std::shared_ptr background, std::shared_ptr mini_logo); + TitleScene(std::shared_ptr condensed_font, std::shared_ptr copyright_font, std::shared_ptr background, std::shared_ptr game_logo, std::shared_ptr mini_logo); ~TitleScene() override; void update(int delta_ms) override; @@ -49,9 +49,10 @@ class TitleScene : public Scene { void advanceToIntro(DebugConfig::StartingPlayers players); void advanceToLogo(); - std::shared_ptr display_font_; std::shared_ptr condensed_font_; + std::shared_ptr copyright_font_; std::shared_ptr background_; + std::shared_ptr game_logo_; std::shared_ptr mini_logo_; int timer_ms_; int blink_elapsed_ms_{0}; diff --git a/source/utils/defaults.hpp b/source/utils/defaults.hpp index 413688b..67d63c7 100644 --- a/source/utils/defaults.hpp +++ b/source/utils/defaults.hpp @@ -156,6 +156,16 @@ namespace Defaults { constexpr const char* MENU_ITEMS_GIF = "data/fonts/ari-w9500-condensed-display.gif"; constexpr const char* MENU_ITEMS_FNT = "data/fonts/ari-w9500-condensed-display.fnt"; constexpr int MENU_ITEMS_KERNING = 0; + + // Copyright al peu de la TITLE: pixel-art estricte, generat amb + // font-gen a partir de PixeloidSans-Bold size 9. La separem + // de la `placeholder` (que la fa servir el "press start") per + // diferenciar tipogràficament jerarquia: prompt destacat amb + // outline gros, copyright net i petit a baix. + constexpr const char* COPYRIGHT_NAME = "PixeloidSans-Bold"; + constexpr const char* COPYRIGHT_GIF = "data/fonts/PixeloidSans-Bold.gif"; + constexpr const char* COPYRIGHT_FNT = "data/fonts/PixeloidSans-Bold.fnt"; + constexpr int COPYRIGHT_KERNING = 0; } // namespace Font // Overlay de RenderInfo (F12).