From 0e59451ed43016c06098bad887d6ff6a2ea5c1d5 Mon Sep 17 00:00:00 2001 From: Wickedness Date: Sat, 20 Jun 2026 04:10:43 +0900 Subject: [PATCH] Refine opening prologue layout --- README.md | 2 +- docs/ARCHITECTURE.md | 2 +- scripts/scenes/battle_scene.gd | 97 +++++++++++++++++----------------- tools/smoke_title_menu.gd | 4 ++ 4 files changed, 55 insertions(+), 50 deletions(-) diff --git a/README.md b/README.md index 4bd2ed3..dd90b5a 100644 --- a/README.md +++ b/README.md @@ -126,7 +126,7 @@ Godot 4 tactical RPG prototype inspired by classic turn-based Romance of the Thr - Campaign completion screen. - New campaign save reset. - Manual campaign checkpoint save/load. -- Cinematic title screen uses a dedicated ancient-war-camp dawn backdrop and Cao Cao portrait art, offers start/load/settings, leads new campaigns through a generated four-panel Cao Cao decision and Xiahou Dun opening prologue, exposes the same audio/edge-scroll settings from the top in-game toolbar, and persists BGM/SFX volume, sound toggles, and edge-scroll preference in `user://heros_settings.json`. +- Cinematic title screen uses a dedicated ancient-war-camp dawn backdrop and Cao Cao portrait art, offers start/load/settings, leads new campaigns through a generated four-panel Cao Cao decision and Xiahou Dun opening prologue with wide story artwork plus a bottom caption panel, exposes the same audio/edge-scroll settings from the top in-game toolbar, and persists BGM/SFX volume, sound toggles, and edge-scroll preference in `user://heros_settings.json`. - Victory and defeat result overlay. - Dialogue portrait slot stays fixed across speaker and narration lines, with officer default image paths, optional per-line overrides, and speaker-initial or record fallback. - Initial AI-generated photorealistic officer portraits for Cao Cao, Xiahou Dun, Xiahou Yuan, Cao Ren, Dian Wei, Guo Jia, and Zhang He. diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 8ed6a13..103f2d5 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -36,7 +36,7 @@ 1. Load battle data. 2. Hydrate deployments through `DataCatalog`. 3. Dispatch battle-start scenario events. -4. New campaigns first show a short title-to-briefing prologue using the battlefield backdrop and Cao Cao portrait, then continue into the first scenario briefing. +4. New campaigns first show a short title-to-briefing prologue using wide generated story artwork with a bottom caption panel, then continue into the first scenario briefing. 5. Show scenario briefing with the campaign chapter header, battle header, objective summary, chapter overview, selectable camp Talk conversations, manual checkpoint menu, and optional pre-battle shop, Armory, Roster, and Formation setup. 6. Player selects a unit. 7. Briefing completion dispatches battle-begin events, including opening dialogue. diff --git a/scripts/scenes/battle_scene.gd b/scripts/scenes/battle_scene.gd index 4bb7596..712574a 100644 --- a/scripts/scenes/battle_scene.gd +++ b/scripts/scenes/battle_scene.gd @@ -2905,89 +2905,90 @@ func _create_hud() -> void: var opening_panel := PanelContainer.new() opening_panel.name = "OpeningProloguePanel" - opening_panel.position = Vector2(104, 58) - opening_panel.size = Vector2(1072, 604) - opening_panel.custom_minimum_size = Vector2(1072, 604) - _apply_panel_style(opening_panel, "paper") + opening_panel.position = Vector2(82, 44) + opening_panel.size = Vector2(1116, 632) + opening_panel.custom_minimum_size = Vector2(1116, 632) + _apply_panel_style(opening_panel, "lacquer") opening_prologue_root.add_child(opening_panel) - var opening_shell := HBoxContainer.new() - opening_shell.custom_minimum_size = Vector2(1016, 548) - opening_shell.add_theme_constant_override("separation", 18) + var opening_shell := VBoxContainer.new() + opening_shell.custom_minimum_size = Vector2(1060, 576) + opening_shell.add_theme_constant_override("separation", 10) opening_panel.add_child(opening_shell) - opening_shell.add_child(_make_bamboo_gutter(22, 548)) + opening_shell.add_child(_make_scroll_rod(1060, 6)) + + var opening_image_frame := PanelContainer.new() + opening_image_frame.custom_minimum_size = Vector2(1060, 396) + _apply_panel_style(opening_image_frame, "command_seal") + opening_shell.add_child(opening_image_frame) opening_prologue_scene_texture_rect = TextureRect.new() opening_prologue_scene_texture_rect.name = "OpeningStoryImage" - opening_prologue_scene_texture_rect.custom_minimum_size = Vector2(520, 548) + opening_prologue_scene_texture_rect.custom_minimum_size = Vector2(1032, 372) opening_prologue_scene_texture_rect.expand_mode = TextureRect.EXPAND_IGNORE_SIZE opening_prologue_scene_texture_rect.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_COVERED opening_prologue_scene_texture_rect.texture = _load_art_texture(OPENING_PROLOGUE_REBELLION_PATH) opening_prologue_scene_texture_rect.modulate = Color(0.98, 0.96, 0.91, 0.98) opening_prologue_scene_texture_rect.mouse_filter = Control.MOUSE_FILTER_IGNORE - opening_shell.add_child(opening_prologue_scene_texture_rect) + opening_image_frame.add_child(opening_prologue_scene_texture_rect) - var opening_story_column := VBoxContainer.new() - opening_story_column.custom_minimum_size = Vector2(422, 548) - opening_story_column.add_theme_constant_override("separation", 14) - opening_shell.add_child(opening_story_column) - opening_shell.add_child(_make_bamboo_gutter(22, 548)) + var opening_caption_row := HBoxContainer.new() + opening_caption_row.custom_minimum_size = Vector2(1060, 142) + opening_caption_row.add_theme_constant_override("separation", 12) + opening_shell.add_child(opening_caption_row) - opening_story_column.add_child(_make_scroll_rod(422, 6)) - opening_story_column.add_child(_make_seal_ribbon(422, 18)) + var opening_title_column := VBoxContainer.new() + opening_title_column.custom_minimum_size = Vector2(236, 142) + opening_title_column.add_theme_constant_override("separation", 8) + opening_caption_row.add_child(opening_title_column) + opening_title_column.add_child(_make_seal_ribbon(236, 18)) opening_prologue_title_label = Label.new() - opening_prologue_title_label.custom_minimum_size = Vector2(422, 52) + opening_prologue_title_label.custom_minimum_size = Vector2(236, 64) opening_prologue_title_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER opening_prologue_title_label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER _apply_label_style(opening_prologue_title_label, UI_PARCHMENT_TEXT, 26) - opening_story_column.add_child(opening_prologue_title_label) - - var opening_body_panel := PanelContainer.new() - opening_body_panel.custom_minimum_size = Vector2(422, 250) - _apply_panel_style(opening_body_panel, "edict") - opening_story_column.add_child(opening_body_panel) - - var opening_body_row := HBoxContainer.new() - opening_body_row.add_theme_constant_override("separation", 10) - opening_body_panel.add_child(opening_body_row) - opening_body_row.add_child(_make_edict_marker_stack(["", "", ""], 206)) - - opening_prologue_body_label = Label.new() - opening_prologue_body_label.custom_minimum_size = Vector2(322, 206) - opening_prologue_body_label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART - opening_prologue_body_label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER - _apply_label_style(opening_prologue_body_label, UI_AGED_INK, 20) - opening_body_row.add_child(opening_prologue_body_label) - opening_body_row.add_child(_make_edict_marker_stack(["", "", ""], 206)) + opening_title_column.add_child(opening_prologue_title_label) opening_prologue_step_label = Label.new() - opening_prologue_step_label.custom_minimum_size = Vector2(422, 26) + opening_prologue_step_label.custom_minimum_size = Vector2(236, 30) opening_prologue_step_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER opening_prologue_step_label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER _apply_label_style(opening_prologue_step_label, UI_OLD_BRONZE, 14) - opening_story_column.add_child(opening_prologue_step_label) + opening_title_column.add_child(opening_prologue_step_label) - var opening_button_row := HBoxContainer.new() - opening_button_row.custom_minimum_size = Vector2(422, 44) - opening_button_row.add_theme_constant_override("separation", 10) - opening_story_column.add_child(opening_button_row) + var opening_body_panel := PanelContainer.new() + opening_body_panel.custom_minimum_size = Vector2(562, 142) + _apply_panel_style(opening_body_panel, "edict") + opening_caption_row.add_child(opening_body_panel) + + opening_prologue_body_label = Label.new() + opening_prologue_body_label.custom_minimum_size = Vector2(526, 110) + opening_prologue_body_label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART + opening_prologue_body_label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER + _apply_label_style(opening_prologue_body_label, UI_AGED_INK, 20) + opening_body_panel.add_child(opening_prologue_body_label) + + var opening_button_column := VBoxContainer.new() + opening_button_column.custom_minimum_size = Vector2(226, 142) + opening_button_column.add_theme_constant_override("separation", 8) + opening_caption_row.add_child(opening_button_column) opening_prologue_skip_button = Button.new() opening_prologue_skip_button.text = "건너뛰기" - opening_prologue_skip_button.custom_minimum_size = Vector2(132, 42) + opening_prologue_skip_button.custom_minimum_size = Vector2(226, 42) opening_prologue_skip_button.tooltip_text = "오프닝을 닫고 군막으로 이동합니다." opening_prologue_skip_button.pressed.connect(_on_opening_prologue_skip_pressed) - opening_button_row.add_child(opening_prologue_skip_button) opening_prologue_next_button = Button.new() opening_prologue_next_button.text = "다음" - opening_prologue_next_button.custom_minimum_size = Vector2(280, 42) + opening_prologue_next_button.custom_minimum_size = Vector2(226, 48) opening_prologue_next_button.tooltip_text = "다음 이야기로 넘깁니다." opening_prologue_next_button.pressed.connect(_on_opening_prologue_next_pressed) - opening_button_row.add_child(opening_prologue_next_button) + opening_button_column.add_child(opening_prologue_next_button) + opening_button_column.add_child(opening_prologue_skip_button) - opening_story_column.add_child(_make_scroll_rod(422, 5)) + opening_shell.add_child(_make_scroll_rod(1060, 5)) briefing_panel = PanelContainer.new() briefing_panel.visible = false diff --git a/tools/smoke_title_menu.gd b/tools/smoke_title_menu.gd index 63ecaf9..e51e37a 100644 --- a/tools/smoke_title_menu.gd +++ b/tools/smoke_title_menu.gd @@ -124,6 +124,10 @@ func _check_title_menu_start_load_and_settings(failures: Array[String]) -> void: failures.append("opening prologue should give Cao Cao, decision, Xiahou Dun, and Yingchuan their own beats") if scene.opening_prologue_scene_texture_rect == null or scene.opening_prologue_scene_texture_rect.texture == null: failures.append("opening prologue should show generated story artwork") + elif scene.opening_prologue_scene_texture_rect.custom_minimum_size.x <= scene.opening_prologue_scene_texture_rect.custom_minimum_size.y: + failures.append("opening prologue story artwork should use a wide cinematic frame") + if scene.opening_prologue_body_label != null and scene.opening_prologue_body_label.custom_minimum_size.x < 500: + failures.append("opening prologue body text should have enough caption width for Korean copy") var first_story_texture: Texture2D = null if scene.opening_prologue_scene_texture_rect != null: first_story_texture = scene.opening_prologue_scene_texture_rect.texture