From 1b27275eda87241b083d07c5d19e920e6fe952e6 Mon Sep 17 00:00:00 2001 From: Wickedness Date: Sat, 20 Jun 2026 12:16:14 +0900 Subject: [PATCH] Clarify enemy lure distance feedback --- scripts/scenes/battle_scene.gd | 50 ++++++++++++++++++++++++++++++---- tools/smoke_visual_assets.gd | 10 +++++++ 2 files changed, 54 insertions(+), 6 deletions(-) diff --git a/scripts/scenes/battle_scene.gd b/scripts/scenes/battle_scene.gd index d56bf4f..6064f1c 100644 --- a/scripts/scenes/battle_scene.gd +++ b/scripts/scenes/battle_scene.gd @@ -9631,15 +9631,16 @@ func _unit_ai_behavior_text(unit: Dictionary) -> String: var behavior := str(unit.get("ai_behavior", "")).strip_edges().to_lower() if behavior == "guard": var guard_radius := int(unit.get("ai_guard_radius", 0)) - return "수비: 거점 경계 반경 %d 안에서 길목을 지킵니다." % guard_radius + return "수비: 거점 경계 반경 %d 안에서 길목을 지킵니다. %s" % [guard_radius, _unit_ai_anchor_pressure_text(unit, "ai_guard_anchor", guard_radius, "거점")] if behavior == "sentry": var sentry_radius := int(unit.get("ai_sentry_radius", 0)) var activation_turn := int(unit.get("ai_sentry_activation_turn", 0)) if bool(unit.get("ai_awake", false)): return "초병: 경계가 풀려 추격 중입니다. 유인 반경 %d" % sentry_radius + var pressure_text := _unit_ai_anchor_pressure_text(unit, "ai_sentry_anchor", sentry_radius, "유인") if activation_turn > 0: - return "초병: 유인 반경 %d 또는 제%d군령에 움직입니다." % [sentry_radius, activation_turn] - return "초병: 유인 반경 %d 안에 들어오면 움직입니다." % sentry_radius + return "초병: 유인 반경 %d 또는 제%d군령에 움직입니다. %s" % [sentry_radius, activation_turn, pressure_text] + return "초병: 유인 반경 %d 안에 들어오면 움직입니다. %s" % [sentry_radius, pressure_text] return "" @@ -9648,18 +9649,55 @@ func _unit_ai_behavior_hover_line(unit: Dictionary) -> String: return "" var behavior := str(unit.get("ai_behavior", "")).strip_edges().to_lower() if behavior == "guard": - return "수비 · 거점 반경 %d" % int(unit.get("ai_guard_radius", 0)) + var guard_radius := int(unit.get("ai_guard_radius", 0)) + return "수비 · 거점 %d · %s" % [guard_radius, _unit_ai_anchor_pressure_badge_text(unit, "ai_guard_anchor", guard_radius, "거점")] if behavior == "sentry": var sentry_radius := int(unit.get("ai_sentry_radius", 0)) if bool(unit.get("ai_awake", false)): return "초병 경계 · 유인 반경 %d" % sentry_radius + var pressure_badge := _unit_ai_anchor_pressure_badge_text(unit, "ai_sentry_anchor", sentry_radius, "유인") var activation_turn := int(unit.get("ai_sentry_activation_turn", 0)) if activation_turn > 0: - return "초병 대기 · 유인 %d · 제%d군령" % [sentry_radius, activation_turn] - return "초병 대기 · 유인 반경 %d" % sentry_radius + return "초병 대기 · 유인 %d · %s · 제%d군령" % [sentry_radius, pressure_badge, activation_turn] + return "초병 대기 · 유인 %d · %s" % [sentry_radius, pressure_badge] return "" +func _unit_ai_anchor_pressure_text(unit: Dictionary, anchor_key: String, radius: int, label: String) -> String: + var distance := _nearest_player_distance_to_ai_anchor(unit, anchor_key) + if distance < 0: + return "%s 거리를 읽을 수 없습니다." % label + if distance <= radius: + return "아군이 %s 범위 안에 있습니다." % label + return "가장 가까운 아군은 %s 밖 %d칸입니다." % [label, distance - radius] + + +func _unit_ai_anchor_pressure_badge_text(unit: Dictionary, anchor_key: String, radius: int, label: String) -> String: + var distance := _nearest_player_distance_to_ai_anchor(unit, anchor_key) + if distance < 0: + return "%s 미확인" % label + if distance <= radius: + return "%s 범위 안" % label + return "%s 밖 %d칸" % [label, distance - radius] + + +func _nearest_player_distance_to_ai_anchor(unit: Dictionary, anchor_key: String) -> int: + var anchor: Vector2i = unit.get(anchor_key, unit.get("pos", Vector2i(-1, -1))) + if not state.is_inside(anchor): + anchor = unit.get("pos", Vector2i(-1, -1)) + if not state.is_inside(anchor): + return -1 + var best_distance := 9999 + for player in state.get_living_units(BattleState.TEAM_PLAYER): + if not bool(player.get("deployed", true)): + continue + var player_cell: Vector2i = player.get("pos", Vector2i(-1, -1)) + if not state.is_inside(player_cell): + continue + best_distance = mini(best_distance, abs(player_cell.x - anchor.x) + abs(player_cell.y - anchor.y)) + return -1 if best_distance == 9999 else best_distance + + func _unit_ai_behavior_badge_text(unit: Dictionary) -> String: if str(unit.get("team", "")) != BattleState.TEAM_ENEMY: return "" diff --git a/tools/smoke_visual_assets.gd b/tools/smoke_visual_assets.gd index 5302d01..895c001 100644 --- a/tools/smoke_visual_assets.gd +++ b/tools/smoke_visual_assets.gd @@ -4561,6 +4561,8 @@ func _check_battle_unit_list_panel(failures: Array[String]) -> void: failures.append("enemy battle unit list tooltips should retain enemy detail: %s" % enemy_tooltips) if not enemy_tooltips.contains("유인 반경") or not enemy_tooltips.contains("거점 경계 반경"): failures.append("enemy battle unit list tooltips should explain sentry and guard behavior: %s" % enemy_tooltips) + if not enemy_tooltips.contains("가장 가까운 아군은 유인 밖") or not enemy_tooltips.contains("가장 가까운 아군은 거점 밖"): + failures.append("enemy battle unit list tooltips should expose current lure/guard distance: %s" % enemy_tooltips) if not _has_descendant_texture(scene.battle_unit_list_rows): failures.append("enemy battle unit list should show unit sprite artwork") if _find_descendant_by_name(scene.battle_unit_list_rows, "BattleUnitListClassIcon") == null: @@ -4822,10 +4824,18 @@ func _check_hover_intent_badges(failures: Array[String]) -> void: var sentry_hover_text := str(sentry_hover_badge.get("lines", [])) if not sentry_hover_text.contains("초병 대기") or not sentry_hover_text.contains("제4군령"): failures.append("sleeping sentry hover badge should expose lure timing compactly: %s" % str(sentry_hover_badge)) + if not sentry_hover_text.contains("유인 밖 4칸"): + failures.append("sleeping sentry hover badge should expose current lure distance: %s" % str(sentry_hover_badge)) central_sentry["ai_awake"] = true var awake_sentry_hover_badge := scene._hover_info_badge() if not str(awake_sentry_hover_badge.get("lines", [])).contains("초병 경계"): failures.append("awake sentry hover badge should show the changed AI state: %s" % str(awake_sentry_hover_badge)) + var village_guard: Dictionary = scene.state.get_unit("yellow_turban_4") + scene.hover_cell = village_guard.get("pos", Vector2i(7, 5)) + var guard_hover_badge := scene._hover_info_badge() + var guard_hover_text := str(guard_hover_badge.get("lines", [])) + if not guard_hover_text.contains("수비") or not guard_hover_text.contains("거점 밖 4칸"): + failures.append("guard hover badge should expose current guard-zone distance: %s" % str(guard_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("표식 북숲 보급고"):