diff --git a/data/scenarios/001_yellow_turbans.json b/data/scenarios/001_yellow_turbans.json index e166eb5..0934e43 100644 --- a/data/scenarios/001_yellow_turbans.json +++ b/data/scenarios/001_yellow_turbans.json @@ -12,6 +12,7 @@ { "type": "all_units_defeated", "team": "enemy" }, { "type": "unit_reaches_tile", + "label": "성채 장악", "team": "player", "unit_ids": ["cao_cao", "xiahou_dun"], "cells": [[12, 0], [13, 0], [12, 1], [13, 1]] diff --git a/scripts/core/battle_state.gd b/scripts/core/battle_state.gd index 2ff9e76..4190bf5 100644 --- a/scripts/core/battle_state.gd +++ b/scripts/core/battle_state.gd @@ -1613,6 +1613,12 @@ func get_objective_cells() -> Array[Vector2i]: return result +func get_objective_cell_label(cell: Vector2i) -> String: + if not is_inside(cell): + return "" + return _objective_cell_label_for_condition(battle_conditions.get("victory", {}), cell) + + func get_objective_progress_lines(include_defeat_risks := false, include_turn_limit := true) -> Array[String]: var result: Array[String] = [] _append_condition_progress_lines(battle_conditions.get("victory", {}), result, "victory") @@ -3630,7 +3636,8 @@ func _append_destination_progress_line(result: Array[String], condition: Diction if targets.is_empty(): return var status := "도달" if _unit_reaches_tile(condition) else "미도달" - _append_progress_line(result, "전장 표식 %s · %s" % [_format_cells(targets), status], pending) + var label := _condition_destination_label(condition) + _append_progress_line(result, "%s %s · %s" % [label, _format_cells(targets), status], pending) func _append_turn_limit_progress_line(result: Array[String]) -> void: @@ -3662,7 +3669,17 @@ func _append_event_destination_progress_line(result: Array[String], when: Dictio if targets.is_empty(): return var status := "도달" if _unit_reaches_tile(when) else "미도달" - _append_progress_line(result, "전장 표식 %s · %s" % [_format_cells(targets), status]) + var label := _condition_destination_label(when) + _append_progress_line(result, "%s %s · %s" % [label, _format_cells(targets), status]) + + +func _condition_destination_label(condition: Dictionary) -> String: + var label := str(condition.get("label", "")).strip_edges() + if label.is_empty(): + label = str(condition.get("objective_label", "")).strip_edges() + if label.is_empty(): + return "전장 표식" + return label func _append_turn_condition_progress_line(result: Array[String], condition: Dictionary, mode: String, pending := false) -> void: @@ -3936,6 +3953,44 @@ func _collect_after_event_objective_cells(event_id: String, result: Array[Vector result.append(cell) +func _objective_cell_label_for_condition(condition_group, cell: Vector2i) -> String: + if typeof(condition_group) == TYPE_ARRAY: + for condition in condition_group: + var label := _objective_cell_label_for_condition(condition, cell) + if not label.is_empty(): + return label + return "" + if typeof(condition_group) != TYPE_DICTIONARY: + return "" + if not _condition_gate_open(condition_group): + return _objective_cell_label_for_after_event(str(condition_group.get("after_event", "")), cell) + + var condition_type := str(condition_group.get("type", "")) + if condition_type == "all" or condition_type == "any": + return _objective_cell_label_for_condition(condition_group.get("conditions", []), cell) + if condition_type != "unit_reaches_tile": + return "" + if _condition_cells(condition_group).has(cell): + return _condition_destination_label(condition_group) + return "" + + +func _objective_cell_label_for_after_event(event_id: String, cell: Vector2i) -> String: + if event_id.is_empty() or fired_event_ids.has(event_id): + return "" + var event := _event_by_id(event_id) + if event.is_empty(): + return "" + var when: Dictionary = event.get("when", {}) + if str(when.get("type", "")) != "unit_reaches_tile": + return "" + if not _event_gate_open(when) or not _campaign_flags_match(when.get("campaign_flags", {})): + return "" + if _condition_cells(when).has(cell): + return _condition_destination_label(when) + return "" + + func _find_turn_limit(condition_group) -> int: if typeof(condition_group) == TYPE_ARRAY: var best_limit := 0 diff --git a/scripts/scenes/battle_scene.gd b/scripts/scenes/battle_scene.gd index 776b870..d32078e 100644 --- a/scripts/scenes/battle_scene.gd +++ b/scripts/scenes/battle_scene.gd @@ -4170,8 +4170,9 @@ func _update_cell_info() -> void: var heal := int(summary.get("heal", 0)) if heal > 0: text += " 회복 +%d" % heal - if state.get_objective_cells().has(cell): - text += "\n조서 표식" + var objective_cell_label := state.get_objective_cell_label(cell) + if not objective_cell_label.is_empty(): + text += "\n목표: %s" % objective_cell_label if show_threat_overlay: var threat_names := state.get_threatening_unit_names(cell, BattleState.TEAM_ENEMY) if not threat_names.is_empty(): diff --git a/tools/smoke_objective_progress.gd b/tools/smoke_objective_progress.gd index f9d0617..377eca3 100644 --- a/tools/smoke_objective_progress.gd +++ b/tools/smoke_objective_progress.gd @@ -13,6 +13,12 @@ func _init() -> void: _progress_text("res://data/scenarios/001_yellow_turbans.json", false), "적군 격파 0/" ) + _check_contains( + failures, + "001 castle capture progress", + _progress_text("res://data/scenarios/001_yellow_turbans.json", false), + "성채 장악" + ) _check_contains( failures, "001 commander defeat risk", @@ -209,6 +215,8 @@ func _check_opening_battle_requires_castle_capture(failures: Array[String]) -> v for castle_cell in [Vector2i(12, 0), Vector2i(13, 0), Vector2i(12, 1), Vector2i(13, 1)]: if not marker_cells.has(castle_cell): failures.append("opening battle should mark castle capture cell %s: %s" % [str(castle_cell), str(marker_cells)]) + if state.get_objective_cell_label(castle_cell) != "성채 장악": + failures.append("opening battle castle marker should expose label at %s" % str(castle_cell)) for enemy in state.get_living_units(BattleStateScript.TEAM_ENEMY): enemy["alive"] = false state._check_battle_status() diff --git a/tools/smoke_visual_assets.gd b/tools/smoke_visual_assets.gd index 546abe7..75ee87b 100644 --- a/tools/smoke_visual_assets.gd +++ b/tools/smoke_visual_assets.gd @@ -3524,6 +3524,13 @@ func _check_terrain_and_unit_presentation(failures: Array[String]) -> void: failures.append("village terrain should expose Korean name and healing") if scene.state.get_terrain_heal(Vector2i(12, 1)) != 8: failures.append("castle terrain should expose stronger healing") + scene._create_hud() + scene.hover_cell = Vector2i(12, 1) + scene._update_cell_info() + if scene.cell_info_label == null or not scene.cell_info_label.text.contains("목표: 성채 장악") or not scene.cell_info_label.text.contains("회복 +8"): + failures.append("castle objective cell info should expose capture label and healing: %s" % scene.cell_info_label.text) + scene.cell_info_label.free() + scene.cell_info_label = null var background_fill: Color = scene._terrain_fill_color(Vector2i(0, 0), "G", true) var fallback_fill: Color = scene._terrain_fill_color(Vector2i(0, 0), "G", false) if background_fill.a >= 0.20: