diff --git a/scripts/scenes/battle_scene.gd b/scripts/scenes/battle_scene.gd index 4356128..37f030f 100644 --- a/scripts/scenes/battle_scene.gd +++ b/scripts/scenes/battle_scene.gd @@ -12986,16 +12986,17 @@ func _make_battle_unit_list_row(unit: Dictionary) -> HBoxContainer: badge_row.tooltip_text = tooltip_text column.add_child(badge_row) - var badge_texts := _format_battle_unit_list_row_badges(unit) - for badge_index in range(badge_texts.size()): - var badge_text = badge_texts[badge_index] - var text := str(badge_text).strip_edges() - if text.is_empty(): + var badge_entries := _battle_unit_list_badge_entries(unit, tooltip_text) + for badge_entry in badge_entries: + if typeof(badge_entry) != TYPE_DICTIONARY: continue + var text := str((badge_entry as Dictionary).get("text", "")) + var badge_tooltip := str((badge_entry as Dictionary).get("tooltip", tooltip_text)) + var icon_texture: Texture2D = (badge_entry as Dictionary).get("icon", null) badge_row.add_child(_make_battle_unit_list_badge( text, - tooltip_text, - _battle_unit_list_badge_icon(unit, badge_index, text) + badge_tooltip, + icon_texture )) return row @@ -13063,15 +13064,32 @@ func _format_battle_unit_list_row_text(unit: Dictionary) -> String: return str(unit.get("name", "부대")) -func _format_battle_unit_list_row_badges(unit: Dictionary) -> Array: +func _battle_unit_list_badge_entries(unit: Dictionary, row_tooltip: String) -> Array: var hp := int(unit.get("hp", 0)) var max_hp := maxi(1, int(unit.get("max_hp", 1))) var hp_percent := int(round(float(hp) * 100.0 / float(max_hp))) + var zone_text := _battle_zone_label(unit.get("pos", Vector2i(-1, -1))) return [ - _unit_class_display_name(unit), - "병 %d%%" % hp_percent, - _battle_unit_action_state_text(unit), - _battle_zone_label(unit.get("pos", Vector2i(-1, -1))) + { + "text": "", + "tooltip": "%s\n%s" % [_unit_class_display_name(unit), row_tooltip], + "icon": _load_unit_class_icon_texture(unit) + }, + { + "text": "%d%%" % hp_percent, + "tooltip": "병력 %d/%d\n%s" % [hp, max_hp, row_tooltip], + "icon": _make_toolbar_icon("status") + }, + { + "text": _battle_unit_action_state_text(unit), + "tooltip": "%s\n%s" % [_battle_unit_action_state_tooltip(unit), row_tooltip], + "icon": _make_toolbar_icon(_battle_unit_action_icon_kind(unit)) + }, + { + "text": zone_text, + "tooltip": "전장 위치\n%s" % row_tooltip, + "icon": _make_toolbar_icon(_battle_zone_icon_kind(zone_text)) + } ] @@ -13100,7 +13118,12 @@ func _make_battle_unit_list_badge(text: String, tooltip_text: String, icon_textu icon.tooltip_text = tooltip_text row.add_child(icon) + if text.strip_edges().is_empty(): + row.alignment = BoxContainer.ALIGNMENT_CENTER + return panel + var label := Label.new() + label.name = "BattleUnitListBadgeLabel" label.custom_minimum_size = Vector2(44, BATTLE_UNIT_LIST_BADGE_SIZE.y - 4.0) label.size_flags_horizontal = Control.SIZE_EXPAND_FILL label.horizontal_alignment = HORIZONTAL_ALIGNMENT_LEFT if icon_texture != null else HORIZONTAL_ALIGNMENT_CENTER @@ -13112,20 +13135,6 @@ func _make_battle_unit_list_badge(text: String, tooltip_text: String, icon_textu return panel -func _battle_unit_list_badge_icon(unit: Dictionary, badge_index: int, badge_text: String) -> Texture2D: - match badge_index: - 0: - return _load_unit_class_icon_texture(unit) - 1: - return _make_toolbar_icon("status") - 2: - return _make_toolbar_icon(_battle_unit_action_icon_kind(unit)) - 3: - return _make_toolbar_icon(_battle_zone_icon_kind(badge_text)) - _: - return null - - func _battle_unit_action_icon_kind(unit: Dictionary) -> String: if not bool(unit.get("alive", true)): return "cancel" @@ -13169,6 +13178,18 @@ func _battle_unit_action_state_text(unit: Dictionary) -> String: return "행동" +func _battle_unit_action_state_tooltip(unit: Dictionary) -> String: + if not bool(unit.get("alive", true)): + return "전장을 이탈했습니다." + if str(unit.get("team", "")) == BattleState.TEAM_ENEMY: + return "적군 부대입니다." + if not bool(unit.get("controllable", true)): + return "호위 대상이라 직접 명령할 수 없습니다." + if bool(unit.get("acted", false)): + return "이번 차례의 행동을 마쳤습니다." + return "아직 명령할 수 있습니다." + + func _can_select_from_battle_unit_list() -> bool: return ( battle_started diff --git a/tools/smoke_visual_assets.gd b/tools/smoke_visual_assets.gd index d72f765..968b3f9 100644 --- a/tools/smoke_visual_assets.gd +++ b/tools/smoke_visual_assets.gd @@ -4198,6 +4198,30 @@ func _collect_child_text(root: Node) -> String: return "\n".join(parts) +func _collect_descendant_text_by_name(root: Node, node_name: String) -> String: + if root == null: + return "" + var parts: Array[String] = [] + _collect_descendant_text_by_name_into(root, node_name, parts) + return "\n".join(parts) + + +func _collect_descendant_text_by_name_into(root: Node, node_name: String, parts: Array[String]) -> void: + if root == null: + return + if str(root.name).begins_with(node_name): + if root is Button: + var button_text := str((root as Button).text).strip_edges() + if not button_text.is_empty(): + parts.append(button_text) + elif root is Label: + var label_text := str((root as Label).text).strip_edges() + if not label_text.is_empty(): + parts.append(label_text) + for child in root.get_children(): + _collect_descendant_text_by_name_into(child, node_name, parts) + + func _collect_child_text_into(root: Node, parts: Array[String]) -> void: if root == null: return @@ -4418,14 +4442,18 @@ func _check_battle_unit_list_panel(failures: Array[String]) -> void: elif not _row_texts_contain(scene.battle_unit_list_rows, "조조") or not _row_texts_contain(scene.battle_unit_list_rows, "하후돈"): failures.append("ally battle unit list should show Cao Cao and Xiahou Dun") var ally_visible_text := _collect_child_text(scene.battle_unit_list_rows) + var ally_badge_text := _collect_descendant_text_by_name(scene.battle_unit_list_rows, "BattleUnitListBadgeLabel") var ally_tooltips := _collect_child_tooltips(scene.battle_unit_list_rows) - if not ally_visible_text.contains("지휘관") or not ally_visible_text.contains("병 ") or not ally_visible_text.contains("서측"): - failures.append("ally battle unit list should show compact class, HP, and zone badges: %s" % ally_visible_text) + if not ally_badge_text.contains("100%") or not ally_badge_text.contains("서측"): + failures.append("ally battle unit list should show compact HP percent and zone badges: %s" % ally_badge_text) + for class_label in ["지휘관", "기병", "보병", "궁병", "책사"]: + if ally_badge_text.contains(class_label): + failures.append("ally battle unit list should move class names into icon hover text: %s" % ally_badge_text) if ally_visible_text.contains("좌 "): failures.append("ally battle unit list should keep raw coordinates out of visible badges: %s" % ally_visible_text) if ally_visible_text.contains("군령:") or ally_visible_text.contains("행군 4") or ally_visible_text.contains("타격 1-1"): failures.append("ally battle unit list rows should keep dense combat detail in hover text: %s" % ally_visible_text) - if not ally_tooltips.contains("군세") or not ally_tooltips.contains("클릭하면 이 장수를 선택"): + if not ally_tooltips.contains("군세") or not ally_tooltips.contains("클릭하면 이 장수를 선택") or not ally_tooltips.contains("지휘관") or not ally_tooltips.contains("병력"): failures.append("ally battle unit list tooltips should retain selection detail: %s" % ally_tooltips) if not _has_descendant_texture(scene.battle_unit_list_rows): failures.append("ally battle unit list should show officer portrait artwork") @@ -4449,11 +4477,15 @@ func _check_battle_unit_list_panel(failures: Array[String]) -> void: elif not _row_texts_contain(scene.battle_unit_list_rows, "장만성"): failures.append("enemy battle unit list should include the enemy commander") var enemy_visible_text := _collect_child_text(scene.battle_unit_list_rows) + var enemy_badge_text := _collect_descendant_text_by_name(scene.battle_unit_list_rows, "BattleUnitListBadgeLabel") var enemy_tooltips := _collect_child_tooltips(scene.battle_unit_list_rows) - if not enemy_visible_text.contains("적") or not enemy_visible_text.contains("병 "): - failures.append("enemy battle unit list should show compact status badges: %s" % enemy_visible_text) - if not enemy_visible_text.contains("성채") and not enemy_visible_text.contains("동측"): - failures.append("enemy battle unit list should show a readable zone badge instead of raw coordinates: %s" % enemy_visible_text) + if not enemy_badge_text.contains("적") or not enemy_badge_text.contains("%"): + failures.append("enemy battle unit list should show compact status and HP percent badges: %s" % enemy_badge_text) + if not enemy_badge_text.contains("성채") and not enemy_badge_text.contains("동측"): + failures.append("enemy battle unit list should show a readable zone badge instead of raw coordinates: %s" % enemy_badge_text) + for class_label in ["지휘관", "기병", "보병", "궁병", "책사"]: + if enemy_badge_text.contains(class_label): + failures.append("enemy battle unit list should move class names into icon hover text: %s" % enemy_badge_text) if enemy_visible_text.contains("좌 "): failures.append("enemy battle unit list should keep raw coordinates out of visible badges: %s" % enemy_visible_text) if enemy_visible_text.contains("군령:") or enemy_visible_text.contains("직접 명령"):