Refine battle flow prompts and opening
This commit is contained in:
@@ -638,6 +638,13 @@ func _check_opening_battle_event_dialogue_structure(failures: Array[String]) ->
|
||||
continue
|
||||
if not _event_has_dialogue_action(event):
|
||||
failures.append("opening battle event should include contextual dialogue: %s" % event_id)
|
||||
var opening_event := _event_by_id(state, "opening_dialogue")
|
||||
if not opening_event.is_empty():
|
||||
var opening_text := _event_dialogue_text(opening_event)
|
||||
if not opening_text.contains("젊은 조조") or not opening_text.contains("하후돈") or not opening_text.contains("첫 군령"):
|
||||
failures.append("opening battle should first explain Cao Cao, Xiahou Dun, and why the first battle begins")
|
||||
if opening_text.find("젊은 조조") > opening_text.find("황건의 깃발"):
|
||||
failures.append("opening battle prologue should come before the tactical battlefield order")
|
||||
var boss_event := _event_by_id(state, "zhang_mancheng_falls")
|
||||
if not boss_event.is_empty():
|
||||
var when: Dictionary = boss_event.get("when", {})
|
||||
@@ -1520,6 +1527,21 @@ func _event_has_dialogue_action(event: Dictionary) -> bool:
|
||||
return false
|
||||
|
||||
|
||||
func _event_dialogue_text(event: Dictionary) -> String:
|
||||
var parts: Array[String] = []
|
||||
var actions: Array = event.get("actions", [])
|
||||
for action in actions:
|
||||
if typeof(action) != TYPE_DICTIONARY or str(action.get("type", "")) != "dialogue":
|
||||
continue
|
||||
var lines: Array = (action as Dictionary).get("lines", [])
|
||||
for line in lines:
|
||||
if typeof(line) == TYPE_DICTIONARY:
|
||||
parts.append(str((line as Dictionary).get("text", "")))
|
||||
elif typeof(line) == TYPE_STRING:
|
||||
parts.append(str(line))
|
||||
return "\n".join(parts)
|
||||
|
||||
|
||||
func _event_has_set_objective_action(event: Dictionary) -> bool:
|
||||
var actions: Array = event.get("actions", [])
|
||||
for action in actions:
|
||||
|
||||
@@ -7,6 +7,7 @@ const BattleSceneScript := preload("res://scripts/scenes/battle_scene.gd")
|
||||
func _init() -> void:
|
||||
var failures: Array[String] = []
|
||||
_check_deferred_move_events(failures)
|
||||
_check_auto_end_turn_prompt_flow(failures)
|
||||
_check_scene_post_move_menu_flow(failures)
|
||||
_check_scene_post_move_edge_positioning(failures)
|
||||
_check_scene_post_move_scrolled_view_positioning(failures)
|
||||
@@ -79,6 +80,63 @@ func _check_deferred_move_events(failures: Array[String]) -> void:
|
||||
failures.append("pending move commit should fire deferred movement event")
|
||||
|
||||
|
||||
func _check_auto_end_turn_prompt_flow(failures: Array[String]) -> void:
|
||||
var scene = BattleSceneScript.new()
|
||||
scene._create_hud()
|
||||
if not scene.state.load_battle("res://data/scenarios/001_yellow_turbans.json"):
|
||||
failures.append("could not load opening battle for auto end turn prompt")
|
||||
scene.free()
|
||||
return
|
||||
scene.battle_started = true
|
||||
scene.campaign_complete_screen = false
|
||||
scene.briefing_panel.visible = false
|
||||
scene.result_panel.visible = false
|
||||
scene._clear_pending_move_state()
|
||||
scene.state.selected_unit_id = ""
|
||||
|
||||
if scene.auto_end_turn_prompt_panel == null:
|
||||
failures.append("auto end turn prompt should be created with the HUD")
|
||||
scene.free()
|
||||
return
|
||||
|
||||
for unit in scene.state.units:
|
||||
if str(unit.get("team", "")) == BattleStateScript.TEAM_PLAYER and bool(unit.get("controllable", true)):
|
||||
unit["acted"] = false
|
||||
scene._update_hud()
|
||||
if scene.auto_end_turn_prompt_panel.visible:
|
||||
failures.append("auto end turn prompt should stay hidden while a controllable ally can still act")
|
||||
|
||||
for unit in scene.state.units:
|
||||
if str(unit.get("team", "")) == BattleStateScript.TEAM_PLAYER and bool(unit.get("alive", true)) and bool(unit.get("deployed", true)) and bool(unit.get("controllable", true)):
|
||||
unit["acted"] = true
|
||||
unit["moved"] = true
|
||||
scene._update_hud()
|
||||
if not scene.auto_end_turn_prompt_panel.visible:
|
||||
failures.append("auto end turn prompt should appear once every controllable ally has acted")
|
||||
if not scene._is_input_locked():
|
||||
failures.append("auto end turn prompt should lock board input while visible")
|
||||
|
||||
if not scene._handle_cancel_input():
|
||||
failures.append("right-click cancel should dismiss the auto end turn prompt")
|
||||
if scene.auto_end_turn_prompt_panel.visible:
|
||||
failures.append("auto end turn prompt should hide after cancel")
|
||||
scene._update_hud()
|
||||
if scene.auto_end_turn_prompt_panel.visible:
|
||||
failures.append("declined auto end turn prompt should not reopen in the same turn")
|
||||
|
||||
scene.auto_end_turn_prompt_declined_turn = -1
|
||||
scene._update_hud()
|
||||
if not scene.auto_end_turn_prompt_panel.visible:
|
||||
failures.append("auto end turn prompt should reopen after the declined-turn guard is cleared")
|
||||
var turn_before: int = scene.state.turn_number
|
||||
scene._on_auto_end_turn_yes_pressed()
|
||||
if scene.auto_end_turn_prompt_panel.visible:
|
||||
failures.append("auto end turn prompt should hide after confirming turn end")
|
||||
if scene.state.turn_number <= turn_before and scene.state.battle_status == BattleStateScript.STATUS_ACTIVE:
|
||||
failures.append("confirming auto end turn should advance through the enemy phase")
|
||||
scene.free()
|
||||
|
||||
|
||||
func _check_scene_post_move_menu_flow(failures: Array[String]) -> void:
|
||||
var scene = BattleSceneScript.new()
|
||||
scene._create_hud()
|
||||
@@ -710,8 +768,9 @@ func _check_scene_auto_attack_safe_origin_and_counter_preview(failures: Array[St
|
||||
risky_scene.hover_cell = Vector2i(5, 3)
|
||||
risky_scene._update_forecast()
|
||||
var risky_forecast: String = risky_scene.forecast_label.text
|
||||
if not risky_forecast.contains("행공") or not risky_forecast.contains("반격"):
|
||||
failures.append("risky auto attack forecast should show counter risk: %s" % risky_forecast)
|
||||
var risky_detail := str(risky_scene.forecast_label.tooltip_text)
|
||||
if not risky_forecast.contains("행공") or not risky_detail.contains("반격"):
|
||||
failures.append("risky auto attack forecast should summarize on the label and keep counter risk in the tooltip: %s / %s" % [risky_forecast, risky_detail])
|
||||
risky_enemy["controllable"] = false
|
||||
var escort_preview := risky_scene._auto_attack_preview_for_origin(risky_attacker, risky_enemy, Vector2i(4, 3))
|
||||
if bool(escort_preview.get("counter_in_range", false)):
|
||||
|
||||
@@ -3222,16 +3222,14 @@ func _check_ancient_ui_theme(failures: Array[String]) -> void:
|
||||
_check_bamboo_gutter_row(failures, scene.mission_detail_panel, "mission detail bamboo gutters")
|
||||
_check_edict_marker_stack(failures, scene.briefing_objective_panel, "briefing objective edict markers")
|
||||
_check_edict_marker_stack(failures, scene.mission_detail_panel, "mission detail edict markers")
|
||||
var cell_info_panel: PanelContainer = null
|
||||
if scene.cell_info_label != null:
|
||||
cell_info_panel = scene.cell_info_label.get_parent() as PanelContainer
|
||||
_check_panel_style_fill(failures, cell_info_panel, "HUD terrain info panel", Color(0.075, 0.050, 0.034, 0.88))
|
||||
_check_panel_style_frame(failures, cell_info_panel, "HUD terrain info panel", Color(0.31, 0.22, 0.12, 0.96), 3)
|
||||
var forecast_panel: PanelContainer = null
|
||||
if scene.forecast_label != null:
|
||||
forecast_panel = scene.forecast_label.get_parent() as PanelContainer
|
||||
_check_panel_style_fill(failures, forecast_panel, "HUD forecast info panel", Color(0.075, 0.050, 0.034, 0.88))
|
||||
_check_panel_style_frame(failures, forecast_panel, "HUD forecast info panel", Color(0.31, 0.22, 0.12, 0.96), 3)
|
||||
_check_panel_style_fill(failures, scene.cell_info_panel, "HUD terrain info panel", Color(0.075, 0.050, 0.034, 0.88))
|
||||
_check_panel_style_frame(failures, scene.cell_info_panel, "HUD terrain info panel", Color(0.31, 0.22, 0.12, 0.96), 3)
|
||||
_check_panel_style_fill(failures, scene.forecast_panel, "HUD forecast info panel", Color(0.075, 0.050, 0.034, 0.88))
|
||||
_check_panel_style_frame(failures, scene.forecast_panel, "HUD forecast info panel", Color(0.31, 0.22, 0.12, 0.96), 3)
|
||||
if scene.cell_info_icon == null:
|
||||
failures.append("HUD terrain info panel should expose an icon chip")
|
||||
if scene.forecast_icon == null:
|
||||
failures.append("HUD forecast info panel should expose an icon chip")
|
||||
_check_hanging_tassel(failures, scene.dialogue_left_tassel, "dialogue left tassel")
|
||||
_check_hanging_tassel(failures, scene.dialogue_right_tassel, "dialogue right tassel")
|
||||
_check_dialogue_column_budget(failures, scene)
|
||||
@@ -3258,10 +3256,16 @@ func _check_ancient_ui_theme(failures: Array[String]) -> void:
|
||||
if right_lines.is_empty():
|
||||
failures.append("dialogue normalization should keep right-side lines")
|
||||
else:
|
||||
var portrait_index_before: int = scene.dialogue_row.get_children().find(scene.dialogue_portrait_panel)
|
||||
scene.active_dialogue_lines = right_lines
|
||||
scene.active_dialogue_index = 0
|
||||
scene._render_dialogue_line()
|
||||
_check_right_side_dialogue_layout(failures, scene)
|
||||
var portrait_index_after: int = scene.dialogue_row.get_children().find(scene.dialogue_portrait_panel)
|
||||
if portrait_index_after != portrait_index_before:
|
||||
failures.append("right-side dialogue should not move the portrait panel between lines")
|
||||
if scene.dialogue_continue_button == null or scene.dialogue_continue_button.text != "다음":
|
||||
failures.append("dialogue continue button should stay stable even on the final line")
|
||||
scene._hide_dialogue_panel()
|
||||
if scene._ui_font(false) == null:
|
||||
failures.append("ancient UI regular font should load from project assets")
|
||||
@@ -3426,10 +3430,10 @@ func _check_right_side_dialogue_layout(failures: Array[String], scene) -> void:
|
||||
return
|
||||
if scene.dialogue_row.get_child(0) != scene.dialogue_left_tassel:
|
||||
failures.append("right-side dialogue should keep the left tassel at the outer edge")
|
||||
if scene.dialogue_row.get_child(1) != scene.dialogue_column:
|
||||
failures.append("right-side dialogue should place speech scroll before the portrait")
|
||||
if scene.dialogue_row.get_child(2) != scene.dialogue_portrait_panel:
|
||||
failures.append("right-side dialogue should place portrait near the right tassel")
|
||||
if scene.dialogue_row.get_child(1) != scene.dialogue_portrait_panel:
|
||||
failures.append("right-side dialogue should keep the portrait fixed beside the left tassel")
|
||||
if scene.dialogue_row.get_child(2) != scene.dialogue_column:
|
||||
failures.append("right-side dialogue should keep the speech scroll in its fixed column")
|
||||
if scene.dialogue_row.get_child(3) != scene.dialogue_right_tassel:
|
||||
failures.append("right-side dialogue should keep the right tassel at the outer edge")
|
||||
if scene.dialogue_speaker_label == null or scene.dialogue_speaker_label.horizontal_alignment != HORIZONTAL_ALIGNMENT_RIGHT:
|
||||
@@ -3895,15 +3899,17 @@ func _check_terrain_and_unit_presentation(failures: Array[String]) -> void:
|
||||
failures.append("idle forecast panel should stay hidden instead of showing empty tactical text")
|
||||
scene.hover_cell = Vector2i(20, 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"):
|
||||
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)
|
||||
if scene.cell_info_label != null and not scene.cell_info_label.tooltip_text.contains("21,2"):
|
||||
failures.append("castle objective cell info should keep coordinates in the hover tooltip: %s" % scene.cell_info_label.tooltip_text)
|
||||
if scene.cell_info_panel == null or not scene.cell_info_panel.visible:
|
||||
failures.append("cell info panel should be visible for a hovered battlefield cell")
|
||||
if scene.cell_info_label.text.contains("20,2"):
|
||||
failures.append("visible cell info should stay compact and leave coordinates to tooltip/badge: %s" % scene.cell_info_label.text)
|
||||
scene.hover_cell = Vector2i(4, 2)
|
||||
scene._update_cell_info()
|
||||
if scene.cell_info_label == null or not scene.cell_info_label.text.contains("표식: 북숲 보급고"):
|
||||
if scene.cell_info_label == null or not scene.cell_info_label.text.contains("표식 북숲 보급고"):
|
||||
failures.append("side event marker cell info should expose the supply label: %s" % scene.cell_info_label.text)
|
||||
scene.hover_cell = Vector2i(-1, -1)
|
||||
scene._update_cell_info()
|
||||
|
||||
Reference in New Issue
Block a user