diff --git a/scripts/scenes/battle_scene.gd b/scripts/scenes/battle_scene.gd index 50a2c16..183b873 100644 --- a/scripts/scenes/battle_scene.gd +++ b/scripts/scenes/battle_scene.gd @@ -131,6 +131,7 @@ var inventory_label: Label var briefing_panel: PanelContainer var briefing_title_label: Label var briefing_location_label: Label +var briefing_seal_ribbon: HBoxContainer var briefing_objective_panel: PanelContainer var briefing_objective_label: Label var briefing_camp_overview_row: HBoxContainer @@ -182,11 +183,13 @@ var dialogue_speaker_panel: PanelContainer var dialogue_speaker_label: Label var dialogue_text_panel: PanelContainer var dialogue_text_label: Label +var dialogue_seal_ribbon: HBoxContainer var dialogue_progress_label: Label var dialogue_previous_button: Button var dialogue_continue_button: Button var result_panel: PanelContainer var result_label: Label +var result_seal_ribbon: HBoxContainer var result_choice_list: VBoxContainer var result_restart_button: Button var next_battle_button: Button @@ -563,6 +566,49 @@ func _make_scroll_rod(width: float = 0.0, height: float = 4.0) -> HBoxContainer: return row +func _make_seal_ribbon(width: float = 0.0, height: float = 18.0) -> HBoxContainer: + var row := HBoxContainer.new() + row.custom_minimum_size = Vector2(width, height) + row.size_flags_horizontal = Control.SIZE_EXPAND_FILL + row.add_theme_constant_override("separation", 4) + row.add_child(_make_lacquer_clasp(height)) + row.add_child(_make_bronze_ribbon_strip(height)) + row.add_child(_make_seal_cluster(height)) + row.add_child(_make_bronze_ribbon_strip(height)) + row.add_child(_make_lacquer_clasp(height)) + return row + + +func _make_lacquer_clasp(size: float) -> ColorRect: + var clasp := ColorRect.new() + clasp.color = UI_CINNABAR_DARK + clasp.custom_minimum_size = Vector2(size, size) + clasp.mouse_filter = Control.MOUSE_FILTER_IGNORE + return clasp + + +func _make_bronze_ribbon_strip(height: float) -> ColorRect: + var strip := ColorRect.new() + strip.color = Color(UI_TARNISHED_BRONZE.r, UI_TARNISHED_BRONZE.g, UI_TARNISHED_BRONZE.b, 0.92) + strip.custom_minimum_size = Vector2(12, height) + strip.size_flags_horizontal = Control.SIZE_EXPAND_FILL + strip.mouse_filter = Control.MOUSE_FILTER_IGNORE + return strip + + +func _make_seal_cluster(height: float) -> HBoxContainer: + var cluster := HBoxContainer.new() + cluster.custom_minimum_size = Vector2(height * 3.0 + 4.0, height) + cluster.add_theme_constant_override("separation", 2) + for index in range(3): + var tile := ColorRect.new() + tile.color = UI_CINNABAR if index == 1 else UI_CINNABAR_DARK + tile.custom_minimum_size = Vector2(height, height) + tile.mouse_filter = Control.MOUSE_FILTER_IGNORE + cluster.add_child(tile) + return cluster + + func _make_section_caption(text: String, width: float = 0.0) -> Control: var panel := PanelContainer.new() panel.custom_minimum_size = Vector2(width, 24) @@ -1005,6 +1051,9 @@ func _create_hud() -> void: _apply_label_style(briefing_title_label, UI_PARCHMENT_TEXT, 20) briefing_title_panel.add_child(briefing_title_label) + briefing_seal_ribbon = _make_seal_ribbon(680, 18) + briefing_column.add_child(briefing_seal_ribbon) + briefing_location_label = Label.new() briefing_location_label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART briefing_location_label.custom_minimum_size = Vector2(680, 22) @@ -1327,7 +1376,8 @@ func _create_hud() -> void: dialogue_column.add_theme_constant_override("separation", 8) dialogue_row.add_child(dialogue_column) - dialogue_column.add_child(_make_scroll_rod(DIALOGUE_TEXT_SIZE.x, 3)) + dialogue_seal_ribbon = _make_seal_ribbon(DIALOGUE_TEXT_SIZE.x, 18) + dialogue_column.add_child(dialogue_seal_ribbon) dialogue_speaker_panel = PanelContainer.new() dialogue_speaker_panel.custom_minimum_size = Vector2(DIALOGUE_TEXT_SIZE.x, 32) @@ -1398,6 +1448,9 @@ func _create_hud() -> void: result_column.add_child(_make_scroll_rod(520, 4)) + result_seal_ribbon = _make_seal_ribbon(520, 18) + result_column.add_child(result_seal_ribbon) + result_label = Label.new() result_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_LEFT result_label.vertical_alignment = VERTICAL_ALIGNMENT_TOP diff --git a/tools/smoke_visual_assets.gd b/tools/smoke_visual_assets.gd index 77b9825..73dcef6 100644 --- a/tools/smoke_visual_assets.gd +++ b/tools/smoke_visual_assets.gd @@ -1810,6 +1810,10 @@ func _check_ancient_ui_theme(failures: Array[String]) -> void: _check_panel_style_fill(failures, scene.dialogue_portrait_panel, "dialogue portrait panel", Color(0.055, 0.025, 0.016, 1.0)) _check_panel_style_fill(failures, scene.dialogue_speaker_panel, "dialogue speaker seal panel", Color(0.36, 0.030, 0.018, 1.0)) _check_panel_style_fill(failures, scene.dialogue_text_panel, "dialogue text scroll panel", Color(0.69, 0.55, 0.32, 0.995)) + _check_seal_ribbon(failures, scene.briefing_seal_ribbon, "briefing seal ribbon") + _check_seal_ribbon(failures, scene.dialogue_seal_ribbon, "dialogue seal ribbon") + _check_seal_ribbon(failures, scene.result_seal_ribbon, "result seal ribbon") + _check_dialogue_column_budget(failures, scene) if scene.dialogue_continue_button == null or scene.dialogue_continue_button.text != "Next Slip": failures.append("dialogue continue button should use ancient slip text") if scene.dialogue_previous_button == null or scene.dialogue_previous_button.text != "Earlier Slip": @@ -1858,9 +1862,42 @@ func _check_ancient_ui_theme(failures: Array[String]) -> void: if scroll_rod.get_child_count() != 5: failures.append("scroll rod ornament should use five visual strips") scroll_rod.free() + var seal_ribbon := scene._make_seal_ribbon(120, 18) + _check_seal_ribbon(failures, seal_ribbon, "generated seal ribbon") + seal_ribbon.free() scene.free() +func _check_seal_ribbon(failures: Array[String], ribbon: HBoxContainer, label: String) -> void: + if ribbon == null: + failures.append("%s missing" % label) + return + if ribbon.get_child_count() != 5: + failures.append("%s should use five clasp/ribbon/cluster segments" % label) + return + var cluster := ribbon.get_child(2) as HBoxContainer + if cluster == null or cluster.get_child_count() != 3: + failures.append("%s should include a three-seal center cluster" % label) + + +func _check_dialogue_column_budget(failures: Array[String], scene) -> void: + if scene.dialogue_column == null: + failures.append("dialogue column missing") + return + var total_height := 0.0 + var visible_children := 0 + for child in scene.dialogue_column.get_children(): + var control := child as Control + if control == null or not control.visible: + continue + visible_children += 1 + total_height += control.custom_minimum_size.y + if visible_children > 1: + total_height += float(visible_children - 1) * float(scene.dialogue_column.get_theme_constant("separation")) + if total_height > scene.DIALOGUE_COLUMN_SIZE.y: + failures.append("dialogue column decorations exceed fixed height: %.1f > %.1f" % [total_height, scene.DIALOGUE_COLUMN_SIZE.y]) + + func _check_panel_style_fill(failures: Array[String], panel: PanelContainer, label: String, expected: Color) -> void: if panel == null: failures.append("%s missing" % label)