From a7383537becb9ed12764c230a801abfd6da68a53 Mon Sep 17 00:00:00 2001 From: Wickedness Date: Sat, 20 Jun 2026 06:25:26 +0900 Subject: [PATCH] Use generated textures for scroll ornaments --- README.md | 2 +- scripts/scenes/battle_scene.gd | 61 ++++++++++++++++++++++------------ tools/smoke_visual_assets.gd | 36 ++++++++++++++++++-- 3 files changed, 74 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index c136179..de8d15c 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Godot 4 tactical RPG prototype inspired by classic turn-based Romance of the Thr - Pre-battle prep commands use compact icon buttons with active selection state and Korean hover labels for chapters, shop, talks, armory, roster, formation, and save records. - Post-move tactic and item pickers use generated command/item icons, compact two-line option rows, and hover details instead of dense single-line text. - Target preview badges, minimap hover badges, and battlefield target markers include generated jade panel surfaces plus action icons for move, attack, threat, support, objective, terrain, and item outcomes. -- Story, briefing, dialogue, mission-detail, and result ribbon/bamboo ornaments use generated seal/panel textures instead of flat color boxes. +- Story, briefing, dialogue, mission-detail, and result scroll/ribbon/binding/bamboo ornaments use generated seal/panel textures instead of flat color boxes. - Battlefield hover info badges use generated jade panel texture plus terrain, supply, tactic, objective, and threat icons, keeping raw grid coordinates out of visible play text. - Battle, top-toolbar, and pre-battle command buttons now prefer generated high-resolution bronze/parchment icon art under `art/ui/icons` and generated lacquer/jade/cinnabar button surfaces under `art/ui/buttons`, with procedural icon drawing and flat button styles kept only as fallbacks. - Battle maps blend generated terrain texture tiles for plains, forests, hills, wasteland, roads, water, villages, and castles over the high-resolution battlefield backdrop, with generated transparent feature overlays for road connections, water, villages, castles, and wasteland accents. diff --git a/scripts/scenes/battle_scene.gd b/scripts/scenes/battle_scene.gd index 2b8f649..a7271bd 100644 --- a/scripts/scenes/battle_scene.gd +++ b/scripts/scenes/battle_scene.gd @@ -1828,16 +1828,22 @@ func _make_scroll_rod(width: float = 0.0, height: float = 4.0) -> HBoxContainer: row.add_theme_constant_override("separation", 2) var cap_width: float = maxf(8.0, height * 3.0) for index in range(5): - var strip := ColorRect.new() - strip.mouse_filter = Control.MOUSE_FILTER_IGNORE - strip.custom_minimum_size = Vector2(cap_width if index != 2 else width, height) + var is_cap := index == 0 or index == 4 + var is_bronze := index == 1 or index == 3 + var strip := _make_generated_ornament_panel( + "GeneratedScrollRodSegment%d" % (index + 1), + Vector2(cap_width if index != 2 else width, height), + "command_seal" if is_cap else "hud_info", + false, + true + ) strip.size_flags_horizontal = Control.SIZE_EXPAND_FILL if index == 2 else Control.SIZE_SHRINK_CENTER - if index == 0 or index == 4: - strip.color = UI_CINNABAR_DARK - elif index == 1 or index == 3: - strip.color = UI_OLD_BRONZE + if is_cap: + strip.modulate = Color(0.72, 0.64, 0.58, 0.96) + elif is_bronze: + strip.modulate = Color(0.90, 0.80, 0.58, 0.94) else: - strip.color = UI_BAMBOO + strip.modulate = Color(0.72, 0.80, 0.60, 0.92) row.add_child(strip) return row @@ -1858,33 +1864,44 @@ func _make_tablet_binding(width: float = 0.0, height: float = 18.0) -> HBoxConta return row -func _make_binding_end_cap(size: float) -> ColorRect: - var cap := ColorRect.new() - cap.color = UI_LACQUER_EDGE - cap.custom_minimum_size = Vector2(size * 1.15, size) - cap.mouse_filter = Control.MOUSE_FILTER_IGNORE +func _make_binding_end_cap(size: float) -> PanelContainer: + var cap := _make_generated_ornament_panel("GeneratedBindingEndCap", Vector2(size * 1.15, size), "command_seal", false, true) + cap.modulate = Color(0.72, 0.64, 0.58, 0.96) return cap -func _make_binding_strip(height: float, color: Color, width: float) -> ColorRect: - var strip := ColorRect.new() - strip.color = color - strip.custom_minimum_size = Vector2(width, height) +func _make_binding_strip(height: float, color: Color, width: float) -> PanelContainer: + var strip := _make_generated_ornament_panel("GeneratedBindingStrip", Vector2(width, height), "hud_info", false, true) strip.size_flags_horizontal = Control.SIZE_EXPAND_FILL if width <= 0.0 else Control.SIZE_SHRINK_CENTER - strip.mouse_filter = Control.MOUSE_FILTER_IGNORE + strip.modulate = _generated_binding_strip_modulate(color) return strip +func _generated_binding_strip_modulate(color: Color) -> Color: + if _colors_close(color, UI_BAMBOO_DARK, 0.08): + return Color(0.64, 0.72, 0.54, 0.92) + if _colors_close(color, UI_TARNISHED_BRONZE, 0.08): + return Color(0.90, 0.80, 0.58, 0.94) + return Color(0.84, 0.78, 0.64, 0.92) + + +func _colors_close(left: Color, right: Color, tolerance: float) -> bool: + return ( + absf(left.r - right.r) <= tolerance + and absf(left.g - right.g) <= tolerance + and absf(left.b - right.b) <= tolerance + and absf(left.a - right.a) <= tolerance + ) + + func _make_seal_knot(height: float) -> HBoxContainer: var knot := HBoxContainer.new() knot.custom_minimum_size = Vector2(height * 2.0 + 3.0, height) knot.mouse_filter = Control.MOUSE_FILTER_IGNORE knot.add_theme_constant_override("separation", 3) for index in range(2): - var tile := ColorRect.new() - tile.color = UI_SEAL_RED if index == 0 else UI_SEAL_RED_DARK - tile.custom_minimum_size = Vector2(height, height) - tile.mouse_filter = Control.MOUSE_FILTER_IGNORE + var tile := _make_generated_ornament_panel("GeneratedSealKnotTile%d" % (index + 1), Vector2(height, height), "command_seal", false, true) + tile.modulate = Color(1.0, 0.92, 0.84, 0.98) if index == 0 else Color(0.76, 0.68, 0.60, 0.96) knot.add_child(tile) return knot diff --git a/tools/smoke_visual_assets.gd b/tools/smoke_visual_assets.gd index 0e874c6..dab80e5 100644 --- a/tools/smoke_visual_assets.gd +++ b/tools/smoke_visual_assets.gd @@ -3653,9 +3653,11 @@ func _check_ancient_ui_theme(failures: Array[String]) -> void: if not scene._format_defeat_result_text().contains("패배"): failures.append("defeat result should use Korean title") var scroll_rod := scene._make_scroll_rod(120, 4) - if scroll_rod.get_child_count() != 5: - failures.append("scroll rod ornament should use five visual strips") + _check_scroll_rod(failures, scroll_rod, "generated scroll rod") scroll_rod.free() + var tablet_binding := scene._make_tablet_binding(120, 16) + _check_tablet_binding(failures, tablet_binding, "generated tablet binding") + tablet_binding.free() var seal_ribbon := scene._make_seal_ribbon(120, 18) _check_seal_ribbon(failures, seal_ribbon, "generated seal ribbon") seal_ribbon.free() @@ -3668,6 +3670,36 @@ func _check_ancient_ui_theme(failures: Array[String]) -> void: scene.free() +func _check_scroll_rod(failures: Array[String], scroll_rod: HBoxContainer, label: String) -> void: + if scroll_rod == null: + failures.append("%s missing" % label) + return + if scroll_rod.get_child_count() != 5: + failures.append("%s should use five visual strips" % label) + return + for index in range(scroll_rod.get_child_count()): + _check_panel_uses_generated_ornament_texture(failures, scroll_rod.get_child(index) as PanelContainer, "%s segment %d" % [label, index]) + + +func _check_tablet_binding(failures: Array[String], binding: HBoxContainer, label: String) -> void: + if binding == null: + failures.append("%s missing" % label) + return + if binding.get_child_count() != 7: + failures.append("%s should use seven clasp/strip/knot segments" % label) + return + for index in range(binding.get_child_count()): + if index == 3: + var knot := binding.get_child(index) as HBoxContainer + if knot == null or knot.get_child_count() != 2: + failures.append("%s should include a two-seal center knot" % label) + continue + for knot_index in range(knot.get_child_count()): + _check_panel_uses_generated_ornament_texture(failures, knot.get_child(knot_index) as PanelContainer, "%s knot seal %d" % [label, knot_index]) + continue + _check_panel_uses_generated_ornament_texture(failures, binding.get_child(index) as PanelContainer, "%s segment %d" % [label, index]) + + func _check_seal_ribbon(failures: Array[String], ribbon: HBoxContainer, label: String) -> void: if ribbon == null: failures.append("%s missing" % label)