Clarify opening and battle start cues

This commit is contained in:
2026-06-20 14:07:16 +09:00
parent 7fb27f29fc
commit 6f92f832cf
3 changed files with 70 additions and 4 deletions

View File

@@ -650,6 +650,7 @@ var recent_sfx_keys: Array[String] = []
var last_announced_battle_status := ""
var floating_texts: Array[Dictionary] = []
var objective_notice_timer := 0.0
var battle_start_notice_pending := false
var unit_motion_by_unit: Dictionary = {}
var unit_action_motion_by_unit: Dictionary = {}
var battle_presentation_sequence_active := false
@@ -2676,7 +2677,7 @@ func _make_opening_story_beat_card(page: Dictionary, index: int, is_current: boo
card_style.content_margin_right = 5
card_style.content_margin_top = 4
card_style.content_margin_bottom = 3
card.modulate = Color(1.0, 1.0, 1.0, 1.0) if is_current else Color(0.56, 0.55, 0.50, 0.88)
card.modulate = Color(1.0, 1.0, 1.0, 1.0) if is_current else Color(0.72, 0.70, 0.64, 0.94)
var column := VBoxContainer.new()
column.custom_minimum_size = Vector2(126, 66)
@@ -2692,7 +2693,7 @@ func _make_opening_story_beat_card(page: Dictionary, index: int, is_current: boo
var seal := _make_seal_tile("%d" % (index + 1), 18)
seal.name = "OpeningStoryBeatSeal"
seal.modulate = Color(1.0, 1.0, 1.0, 1.0) if is_current else Color(0.70, 0.68, 0.62, 0.90)
seal.modulate = Color(1.0, 1.0, 1.0, 1.0) if is_current else Color(0.92, 0.87, 0.74, 0.96)
title_row.add_child(seal)
var label := Label.new()
@@ -2703,7 +2704,9 @@ func _make_opening_story_beat_card(page: Dictionary, index: int, is_current: boo
label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
label.clip_text = true
label.tooltip_text = tooltip
_apply_label_style(label, UI_PARCHMENT_TEXT if is_current else UI_OLD_BRONZE, 9)
var label_color := UI_TITLE_TEXT if is_current else UI_TITLE_MUTED_TEXT
_apply_label_style(label, label_color, 10 if is_current else 9)
_apply_strong_text_legibility(label, label_color, 10 if is_current else 9)
title_row.add_child(label)
var image_frame := PanelContainer.new()
@@ -11003,6 +11006,34 @@ func _on_objective_updated(victory: String, defeat: String) -> void:
_show_command_notice("군령 갱신", _join_strings(body_lines, "\n"))
func _show_battle_start_notice_if_ready() -> void:
if not battle_start_notice_pending or _is_dialogue_visible():
return
battle_start_notice_pending = false
_show_command_notice("전투 개시", _format_battle_start_notice_body())
func _format_battle_start_notice_body() -> String:
var lines: Array[String] = []
var progress_lines := state.get_objective_progress_lines(false, false)
if not progress_lines.is_empty():
lines.append("목표: %s" % _short_preview_text(_join_strings(progress_lines, " · "), 52))
else:
var victory := str(state.objectives.get("victory", "")).strip_edges()
if not victory.is_empty():
lines.append("목표: %s" % _short_preview_text(victory, 52))
var risk_lines := state.get_defeat_progress_lines()
if not risk_lines.is_empty():
lines.append("주의: %s" % _short_preview_text(_join_strings(risk_lines, " · "), 42))
else:
var defeat := str(state.objectives.get("defeat", "")).strip_edges()
if not defeat.is_empty():
lines.append("주의: %s" % _short_preview_text(defeat, 42))
if lines.is_empty():
lines.append("목표를 확인하고 첫 군령을 내리십시오.")
return _join_strings(lines, "\n")
func _show_command_notice(title: String, body: String) -> void:
var notice_lines := [title]
var normalized_body := body.strip_edges()
@@ -11638,9 +11669,10 @@ func _advance_dialogue() -> void:
_render_dialogue_line()
return
_hide_dialogue_panel()
if _can_show_dialogue_now():
if _can_show_dialogue_now() and not dialogue_queue.is_empty():
_show_next_dialogue()
else:
_show_battle_start_notice_if_ready()
_update_hud()
queue_redraw()
@@ -11832,6 +11864,7 @@ func _on_restart_pressed() -> void:
if log_box != null:
log_box.clear()
battle_started = false
battle_start_notice_pending = false
battle_result_applied = false
battle_result_summary.clear()
post_battle_dialogue_started = false
@@ -11880,6 +11913,7 @@ func _load_scenario(scenario_id: String) -> void:
push_error("Missing scenario path for %s." % active_scenario_id)
return
battle_started = false
battle_start_notice_pending = false
battle_result_applied = false
battle_result_summary.clear()
post_battle_dialogue_started = false
@@ -12543,6 +12577,7 @@ func _on_begin_battle_pressed() -> void:
func _start_battle_from_briefing() -> void:
battle_started = true
battle_start_notice_pending = true
_play_bgm("battle")
if briefing_panel != null:
briefing_panel.visible = false
@@ -12558,6 +12593,7 @@ func _start_battle_from_briefing() -> void:
state.run_battle_begin_events()
_focus_board_on_player_deployment(true)
_show_next_dialogue()
_show_battle_start_notice_if_ready()
_update_hud()
queue_redraw()

View File

@@ -23,6 +23,7 @@ func _init() -> void:
_check_minimap_navigation_contract(failures)
_check_map_focus_contract(failures)
_check_battle_presentation_sequence_contract(failures)
_check_battle_start_notice_sequence(failures)
_check_readability_contract(failures)
_check_korean_fallback_labels(failures)
_check_dialogue_localization_and_side(failures)
@@ -550,6 +551,33 @@ func _check_battle_presentation_sequence_contract(failures: Array[String]) -> vo
scene.free()
func _check_battle_start_notice_sequence(failures: Array[String]) -> void:
var scene = BattleSceneScript.new()
scene._ready()
scene._load_scenario("001_yellow_turbans")
scene._show_briefing()
scene._start_battle_from_briefing()
if not scene._is_dialogue_visible():
failures.append("opening battle should begin with contextual dialogue before command notices")
if scene.objective_notice_label != null and scene.objective_notice_label.text.contains("전투 개시"):
failures.append("battle start notice should wait until opening dialogue is closed")
var guard := 0
while scene._is_dialogue_visible() and guard < 12:
scene._advance_dialogue()
guard += 1
if scene._is_dialogue_visible():
failures.append("opening battle dialogue should be advanceable during start notice test")
if scene.objective_notice_panel == null or not scene.objective_notice_panel.visible:
failures.append("battle start should show a compact tactical command notice after dialogue")
elif scene.objective_notice_label == null or not scene.objective_notice_label.text.contains("전투 개시"):
failures.append("battle start notice should use a clear Korean title: %s" % ("" if scene.objective_notice_label == null else scene.objective_notice_label.text))
elif not scene.objective_notice_label.text.contains("목표:") or not scene.objective_notice_label.text.contains("주의:"):
failures.append("battle start notice should summarize objective and risk: %s" % scene.objective_notice_label.text)
if scene.objective_notice_icon_strip == null or scene.objective_notice_icon_strip.get_child_count() < 2:
failures.append("battle start notice should use generated objective and warning icons")
scene.free()
func _check_readability_contract(failures: Array[String]) -> void:
var scene = BattleSceneScript.new()
scene._create_hud()

View File

@@ -259,6 +259,8 @@ func _check_title_menu_start_load_and_settings(failures: Array[String]) -> void:
failures.append("opening story beat artwork should stay readable in the strip: %s" % str(beat_image.custom_minimum_size))
if beat_label == null or beat_label.text.strip_edges().is_empty():
failures.append("opening story beat card should name its scene")
elif beat_label.get_theme_color("font_color").get_luminance() < 0.66 or beat_label.get_theme_constant("outline_size") < 3:
failures.append("opening story beat label should remain readable over generated artwork: %s" % beat_label.text)
if bool(card_node.get_meta("current_story_beat", false)):
current_count += 1
current_index = opening_story_cards.find(opening_story_card) + 1