diff --git a/README.md b/README.md index cdd1aa8..8be5206 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ Godot 4 tactical RPG prototype inspired by classic turn-based Romance of the Thr - Pre-battle briefing shows the campaign chapter, chapter battle number, location, victory/defeat summary, first-clear reward preview, generated battlefield thumbnail, allied portrait/enemy unit force markers, and image-first tactical marker cards for lure lines and supply points. - 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 and battlefield target markers include generated action icons for move, attack, threat, support, and item outcomes. +- 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. - 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 44089f0..a1bd807 100644 --- a/scripts/scenes/battle_scene.gd +++ b/scripts/scenes/battle_scene.gd @@ -5010,20 +5010,26 @@ func _draw_minimap_hover_badge() -> void: if badge_rect.size.x <= 0.0 or badge_rect.size.y <= 0.0: return var color := _hover_info_badge_color(str(badge.get("kind", "terrain"))) - var background := Color(0.035, 0.022, 0.014, 0.93) + var background := Color(0.035, 0.022, 0.014, 0.74) var font := _draw_ui_font(true) - draw_rect(badge_rect, background) - draw_rect(badge_rect.grow(-2.0), Color(color.r, color.g, color.b, 0.12)) - draw_rect(badge_rect, color, false, 2.0) + _draw_generated_badge_panel(badge_rect, color, background, str(badge.get("panel", "hud_jade")), 0.12, 2.0) + var icon_texture := _hover_info_badge_icon_texture(str(badge.get("icon", ""))) + if icon_texture != null: + var icon_background := Rect2(badge_rect.position + Vector2(5.0, 4.0), HOVER_INFO_BADGE_ICON_SIZE + Vector2(4.0, 4.0)) + var icon_rect := Rect2(badge_rect.position + Vector2(7.0, 6.0), HOVER_INFO_BADGE_ICON_SIZE) + draw_rect(icon_background, Color(0.020, 0.018, 0.015, 0.62)) + draw_rect(icon_background, Color(color.r, color.g, color.b, 0.44), false, 1.0) + draw_texture_rect(icon_texture, icon_rect, false, Color(1.0, 1.0, 1.0, 0.94)) for index in range(lines.size()): var line_color := color if index == 0 else UI_PARCHMENT_TEXT + var x_offset := 33.0 if index == 0 and icon_texture != null else 8.0 _draw_ink_text( font, - badge_rect.position + Vector2(8.0, 16.0 + float(index) * 15.0), + badge_rect.position + Vector2(x_offset, 16.0 + float(index) * 15.0), lines[index], HORIZONTAL_ALIGNMENT_LEFT, - badge_rect.size.x - 16.0, + badge_rect.size.x - x_offset - 8.0, 12, line_color ) @@ -7176,19 +7182,24 @@ func _draw_target_preview_badge() -> void: var badge_rect := _target_preview_badge_rect(cell, size) var kind := str(badge.get("kind", "")) var color := _target_preview_badge_color(kind) - var background := Color(0.025, 0.028, 0.034, 0.88) + var background := Color(0.025, 0.028, 0.034, 0.68) var font := _draw_ui_font(true) var text := str(badge.get("text", "")) var icon_texture := _target_preview_badge_icon_texture(kind) var icon_space := TARGET_PREVIEW_BADGE_ICON_SIZE.x + 8.0 if icon_texture != null else 0.0 - draw_rect(badge_rect, background) - draw_rect(badge_rect, color, false, 2.0) + _draw_generated_badge_panel(badge_rect, color, background, str(badge.get("panel", "hud_jade")), 0.08, 2.0) if icon_texture != null: + var icon_background := Rect2( + badge_rect.position + Vector2(3.0, (badge_rect.size.y - TARGET_PREVIEW_BADGE_ICON_SIZE.y) * 0.5 - 2.0), + TARGET_PREVIEW_BADGE_ICON_SIZE + Vector2(4.0, 4.0) + ) var icon_rect := Rect2( badge_rect.position + Vector2(5.0, (badge_rect.size.y - TARGET_PREVIEW_BADGE_ICON_SIZE.y) * 0.5), TARGET_PREVIEW_BADGE_ICON_SIZE ) + draw_rect(icon_background, Color(0.020, 0.018, 0.015, 0.58)) + draw_rect(icon_background, Color(color.r, color.g, color.b, 0.40), false, 1.0) draw_texture_rect(icon_texture, icon_rect, false, Color(1.0, 1.0, 1.0, 0.96)) _draw_ink_text( font, @@ -7201,6 +7212,18 @@ func _draw_target_preview_badge() -> void: ) +func _draw_generated_badge_panel(rect: Rect2, color: Color, background: Color, texture_key: String = "hud_jade", accent_alpha: float = 0.10, border_width: float = 2.0) -> void: + var normalized_key := texture_key.strip_edges().to_lower() + if normalized_key.is_empty(): + normalized_key = "hud_jade" + var panel_texture := _load_art_texture(PANEL_TEXTURE_PATH_TEMPLATE % normalized_key) + if panel_texture != null: + draw_texture_rect(panel_texture, rect, false, Color(0.70, 0.72, 0.66, 0.90)) + draw_rect(rect, background) + draw_rect(rect.grow(-2.0), Color(color.r, color.g, color.b, accent_alpha)) + draw_rect(rect, color, false, border_width) + + func _draw_hover_info_badge() -> void: var badge := _hover_info_badge() if badge.is_empty(): @@ -7213,13 +7236,8 @@ func _draw_hover_info_badge() -> void: var color := _hover_info_badge_color(str(badge.get("kind", "terrain"))) var background := Color(0.035, 0.022, 0.014, 0.72) var font := _draw_ui_font(true) - var panel_texture := _load_art_texture(PANEL_TEXTURE_PATH_TEMPLATE % "hud_jade") - if panel_texture != null: - draw_texture_rect(panel_texture, badge_rect, false, Color(0.70, 0.72, 0.66, 0.92)) - draw_rect(badge_rect, background) - draw_rect(badge_rect.grow(-2.0), Color(color.r, color.g, color.b, 0.10)) - draw_rect(badge_rect, color, false, 2.0) + _draw_generated_badge_panel(badge_rect, color, background, str(badge.get("panel", "hud_jade")), 0.10, 2.0) var icon_texture := _hover_info_badge_icon_texture(str(badge.get("icon", ""))) if icon_texture != null: var icon_background := Rect2(badge_rect.position + Vector2(5.0, 4.0), HOVER_INFO_BADGE_ICON_SIZE + Vector2(4.0, 4.0)) @@ -7268,6 +7286,7 @@ func _hover_info_badge() -> Dictionary: "cell": hover_cell, "kind": _hover_info_badge_kind(hover_cell), "icon": _hover_info_badge_icon_kind(hover_cell), + "panel": "hud_jade", "lines": lines } @@ -7700,7 +7719,8 @@ func _make_target_preview_badge_at(text: String, kind: String, cell: Vector2i) - "text": text, "kind": kind, "cell": cell, - "icon": _target_preview_badge_icon_kind(kind) + "icon": _target_preview_badge_icon_kind(kind), + "panel": "hud_jade" } @@ -7972,6 +7992,8 @@ func _minimap_hover_badge(screen_position: Vector2) -> Dictionary: return { "cell": cell, "kind": _hover_info_badge_kind(cell), + "icon": _hover_info_badge_icon_kind(cell), + "panel": "hud_jade", "lines": lines, "rect": _minimap_hover_badge_rect(screen_position, lines) } @@ -7984,17 +8006,26 @@ func _minimap_hover_badge_lines(cell: Vector2i) -> Array[String]: var terrain_name := _terrain_display_name(str(summary.get("terrain", ""))) var lines: Array[String] = [] var unit: Dictionary = summary.get("unit", {}) + var objective_label := state.get_objective_cell_label(cell) + var event_label := state.get_event_marker_label(cell) + var objective_used_as_title := false + var event_used_as_title := false if not unit.is_empty(): lines.append("%s · %s" % [_short_name(str(unit.get("name", "부대"))), _unit_team_text(str(unit.get("team", "")))]) lines.append("%s · %s" % [_unit_class_display_name(unit), terrain_name]) else: - lines.append("전장도 %s · %s" % [_format_cell_label(cell), terrain_name]) + if not objective_label.is_empty(): + lines.append("목표 %s" % objective_label) + objective_used_as_title = true + elif not event_label.is_empty(): + lines.append("표식 %s" % event_label) + event_used_as_title = true + else: + lines.append("전장도 %s" % terrain_name) var markers: Array[String] = [] - var objective_label := state.get_objective_cell_label(cell) - if not objective_label.is_empty(): + if not objective_label.is_empty() and not objective_used_as_title: markers.append("목표 %s" % objective_label) - var event_label := state.get_event_marker_label(cell) - if not event_label.is_empty(): + if not event_label.is_empty() and not event_used_as_title: markers.append("표식 %s" % event_label) if show_threat_overlay: var threat_names := state.get_threatening_unit_names(cell, BattleState.TEAM_ENEMY) diff --git a/tools/smoke_chapter_one_polish.gd b/tools/smoke_chapter_one_polish.gd index b892298..e7d70f6 100644 --- a/tools/smoke_chapter_one_polish.gd +++ b/tools/smoke_chapter_one_polish.gd @@ -275,6 +275,12 @@ func _check_minimap_navigation_contract(failures: Array[String]) -> void: var first_hover_text := "\n".join(first_hover_lines) if not first_hover_text.contains("클릭/드래그"): failures.append("minimap hover should explain click-drag navigation: %s" % first_hover_text) + if first_hover_text.contains("1,1"): + failures.append("minimap hover should not expose raw grid coordinates in visible text: %s" % first_hover_text) + if str(first_hover_badge.get("icon", "")).strip_edges().is_empty(): + failures.append("minimap hover should carry generated icon metadata: %s" % str(first_hover_badge)) + if str(first_hover_badge.get("panel", "")) != "hud_jade": + failures.append("minimap hover should use generated jade panel metadata: %s" % str(first_hover_badge)) var first_hover_rect: Rect2 = first_hover_badge.get("rect", Rect2()) if first_hover_rect.size.x <= 0.0 or first_hover_rect.size.y <= 0.0 or not view_rect.encloses(first_hover_rect): failures.append("minimap hover badge should stay inside the visible map view: %s within %s" % [str(first_hover_rect), str(view_rect)]) diff --git a/tools/smoke_visual_assets.gd b/tools/smoke_visual_assets.gd index e42d962..9bf193c 100644 --- a/tools/smoke_visual_assets.gd +++ b/tools/smoke_visual_assets.gd @@ -4262,6 +4262,8 @@ func _check_hover_intent_badges(failures: Array[String]) -> void: failures.append("reachable empty tile should show MOVE badge: %s" % str(move_badge)) if str(move_badge.get("icon", "")) != "move": failures.append("MOVE badge should carry a generated icon hint: %s" % str(move_badge)) + if str(move_badge.get("panel", "")) != "hud_jade": + failures.append("MOVE badge should use generated jade panel metadata: %s" % str(move_badge)) if not scene._hover_info_badge().is_empty(): failures.append("hover info badge should yield to active move intent badge") @@ -4271,6 +4273,8 @@ func _check_hover_intent_badges(failures: Array[String]) -> void: failures.append("friendly selectable unit should show SELECT badge: %s" % str(select_badge)) if str(select_badge.get("icon", "")).strip_edges().is_empty(): failures.append("SELECT badge should carry a generated icon hint: %s" % str(select_badge)) + if str(select_badge.get("panel", "")) != "hud_jade": + failures.append("SELECT badge should use generated jade panel metadata: %s" % str(select_badge)) scene.hover_cell = Vector2i(1, 5) var attack_badge := scene._target_preview_badge() @@ -4282,6 +4286,8 @@ func _check_hover_intent_badges(failures: Array[String]) -> void: failures.append("counterable attack badge should use a counter danger color kind: %s" % str(attack_badge)) if str(attack_badge.get("icon", "")) != "threat": failures.append("counterable attack badge should carry a threat icon hint: %s" % str(attack_badge)) + if str(attack_badge.get("panel", "")) != "hud_jade": + failures.append("counterable attack badge should use generated jade panel metadata: %s" % str(attack_badge)) var cao_cao: Dictionary = scene.state.get_unit("cao_cao") cao_cao["moved"] = true @@ -4322,6 +4328,8 @@ func _check_hover_intent_badges(failures: Array[String]) -> void: failures.append("enemy hover info badge should expose enemy identity: %s" % str(enemy_hover_badge)) if str(enemy_hover_badge.get("icon", "")) != "threat": failures.append("enemy hover info badge should use generated threat icon metadata: %s" % str(enemy_hover_badge)) + if str(enemy_hover_badge.get("panel", "")) != "hud_jade": + failures.append("enemy hover info badge should use generated jade panel metadata: %s" % str(enemy_hover_badge)) scene.hover_cell = Vector2i(4, 2) var event_hover_badge := scene._hover_info_badge() if str(event_hover_badge.get("kind", "")) != "event" or not str(event_hover_badge.get("lines", [])).contains("표식 북숲 보급고"):