Add story beats to Xian Emperor Escort
This commit is contained in:
@@ -313,6 +313,11 @@
|
||||
{ "speaker": "Cao Cao", "text": "그렇다면 사자를 지체시킬 수 없다. 앞으로 나아가라." }
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "set_objective",
|
||||
"victory": "천자 사자를 지키며 동도 호송로까지 조조를 전진시켜라.",
|
||||
"defeat": "조조나 천자 사자가 퇴각하거나 제18군령이 시작되면 패한다."
|
||||
},
|
||||
{
|
||||
"type": "spawn_deployments",
|
||||
"deployments": [
|
||||
@@ -350,6 +355,10 @@
|
||||
{ "speaker": "Cao Cao", "text": "길 자체가 미끼였군. 사자를 감싸고 그대로 돌파하라." }
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "set_objective",
|
||||
"victory": "중간 매복을 뚫고 천자 사자를 보호하며 동도 호송로를 장악하라."
|
||||
},
|
||||
{
|
||||
"type": "spawn_deployments",
|
||||
"deployments": [
|
||||
@@ -499,6 +508,44 @@
|
||||
"text": "마지막 잔당이 조조와 천자 사자를 함께 노린다."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "li_jue_vanguard_falls",
|
||||
"once": true,
|
||||
"when": { "type": "unit_defeated", "team": "enemy", "unit_ids": ["li_jue_vanguard"] },
|
||||
"actions": [
|
||||
{
|
||||
"type": "dialogue",
|
||||
"lines": [
|
||||
{ "speaker": "Li Jue", "display_speaker": "이각", "side": "right", "text": "선봉이 밀린다 해도 동도 길목은 아직 쉽게 열리지 않는다." },
|
||||
{ "speaker": "Imperial Envoy", "display_speaker": "천자 사자", "side": "right", "text": "길 앞의 먼지가 조금 걷혔습니다. 거가가 멈추지 않게 해 주십시오." },
|
||||
{ "speaker": "Cao Cao", "display_speaker": "조조", "side": "left", "text": "이각의 선봉을 꺾었다. 사자를 가운데 두고 동도 호송로까지 밀어라." }
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "set_objective",
|
||||
"victory": "이각 선봉을 꺾었다. 천자 사자를 지키며 동도 호송로를 장악하라."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "final_escort_rider_falls",
|
||||
"once": true,
|
||||
"when": { "type": "unit_defeated", "team": "enemy", "unit_ids": ["final_escort_rider"] },
|
||||
"actions": [
|
||||
{
|
||||
"type": "dialogue",
|
||||
"lines": [
|
||||
{ "speaker": "Li Jue", "display_speaker": "이각", "side": "right", "text": "마지막 추격기마저 물러난다고? 곽사, 길목을 놓치지 마라!" },
|
||||
{ "speaker": "Dian Wei", "display_speaker": "전위", "side": "right", "text": "추격 기병의 앞줄이 멎었습니다. 사자 곁을 비우지 않고 남은 잔당을 밀겠습니다." },
|
||||
{ "speaker": "Cao Cao", "display_speaker": "조조", "side": "left", "text": "마지막 추격을 꺾었다. 동도 호송로를 붙들고 남은 잔당을 정리하라." }
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "set_objective",
|
||||
"victory": "마지막 추격기를 꺾었다. 동도 호송로를 지키며 남은 잔당을 격파하라."
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"rewards": {
|
||||
|
||||
@@ -29,12 +29,14 @@ func _init() -> void:
|
||||
_check_qingzhou_campaign_event_dialogue_structure(failures)
|
||||
_check_puyang_raid_event_dialogue_structure(failures)
|
||||
_check_dingtao_counterattack_event_dialogue_structure(failures)
|
||||
_check_xian_emperor_escort_event_dialogue_structure(failures)
|
||||
_check_opening_battle_story_beats(failures)
|
||||
_check_sishui_gate_story_beats(failures)
|
||||
_check_xingyang_ambush_story_beats(failures)
|
||||
_check_qingzhou_campaign_story_beats(failures)
|
||||
_check_puyang_raid_story_beats(failures)
|
||||
_check_dingtao_counterattack_story_beats(failures)
|
||||
_check_xian_emperor_escort_story_beats(failures)
|
||||
_check_pixel_unit_helpers(failures)
|
||||
|
||||
if failures.is_empty():
|
||||
@@ -507,6 +509,57 @@ func _check_dingtao_counterattack_event_dialogue_structure(failures: Array[Strin
|
||||
failures.append("Dingtao Counterattack second charge event should clarify the final objective")
|
||||
|
||||
|
||||
func _check_xian_emperor_escort_event_dialogue_structure(failures: Array[String]) -> void:
|
||||
var state = BattleStateScript.new()
|
||||
if not state.load_battle("res://data/scenarios/007_xian_emperor_escort.json"):
|
||||
failures.append("could not load Xian Emperor Escort for event dialogue structure")
|
||||
return
|
||||
for event_id in [
|
||||
"opening_dialogue",
|
||||
"turn_3_rear_pressure",
|
||||
"midroad_ambush",
|
||||
"turn_5_road_marker",
|
||||
"turn_6_envoy_pincher",
|
||||
"turn_9_final_escort_pressure",
|
||||
"li_jue_vanguard_falls",
|
||||
"final_escort_rider_falls"
|
||||
]:
|
||||
var event := _event_by_id(state, event_id)
|
||||
if event.is_empty():
|
||||
failures.append("Xian Emperor Escort missing event: %s" % event_id)
|
||||
continue
|
||||
if not _event_has_dialogue_action(event):
|
||||
failures.append("Xian Emperor Escort event should include contextual dialogue: %s" % event_id)
|
||||
var li_jue_event := _event_by_id(state, "li_jue_vanguard_falls")
|
||||
if not li_jue_event.is_empty():
|
||||
var when: Dictionary = li_jue_event.get("when", {})
|
||||
if str(when.get("type", "")) != "unit_defeated":
|
||||
failures.append("Li Jue vanguard defeat event should trigger when the unit is defeated")
|
||||
var unit_ids: Array = when.get("unit_ids", [])
|
||||
if not unit_ids.has("li_jue_vanguard"):
|
||||
failures.append("Li Jue vanguard defeat event should watch li_jue_vanguard")
|
||||
if not _event_has_set_objective_action(li_jue_event):
|
||||
failures.append("Li Jue vanguard defeat event should clarify the escort objective")
|
||||
var final_rider_event := _event_by_id(state, "final_escort_rider_falls")
|
||||
if not final_rider_event.is_empty():
|
||||
var when: Dictionary = final_rider_event.get("when", {})
|
||||
if str(when.get("type", "")) != "unit_defeated":
|
||||
failures.append("Final escort rider defeat event should trigger when the unit is defeated")
|
||||
var unit_ids: Array = when.get("unit_ids", [])
|
||||
if not unit_ids.has("final_escort_rider"):
|
||||
failures.append("Final escort rider defeat event should watch final_escort_rider")
|
||||
if not _event_has_set_objective_action(final_rider_event):
|
||||
failures.append("Final escort rider defeat event should clarify the final escort objective")
|
||||
for objective_event_id in [
|
||||
"turn_3_rear_pressure",
|
||||
"midroad_ambush",
|
||||
"turn_9_final_escort_pressure"
|
||||
]:
|
||||
var objective_event := _event_by_id(state, objective_event_id)
|
||||
if not objective_event.is_empty() and not _event_has_set_objective_action(objective_event):
|
||||
failures.append("Xian Emperor Escort event should update the active objective: %s" % objective_event_id)
|
||||
|
||||
|
||||
func _check_opening_battle_story_beats(failures: Array[String]) -> void:
|
||||
var state = BattleStateScript.new()
|
||||
if not state.load_battle("res://data/scenarios/001_yellow_turbans.json"):
|
||||
@@ -758,6 +811,60 @@ func _check_dingtao_counterattack_story_beats(failures: Array[String]) -> void:
|
||||
failures.append("Lu Bu second charge break objective should still point to the center and remaining charge")
|
||||
|
||||
|
||||
func _check_xian_emperor_escort_story_beats(failures: Array[String]) -> void:
|
||||
var state = BattleStateScript.new()
|
||||
if not state.load_battle("res://data/scenarios/007_xian_emperor_escort.json"):
|
||||
failures.append("could not load Xian Emperor Escort for story beat checks")
|
||||
return
|
||||
|
||||
var dialogue_batches: Array = []
|
||||
state.dialogue_requested.connect(func(lines: Array) -> void:
|
||||
dialogue_batches.append(lines)
|
||||
)
|
||||
|
||||
state._run_events("turn_start", BattleStateScript.TEAM_ENEMY, 3)
|
||||
var cao_cao: Dictionary = state.get_unit("cao_cao_ch7")
|
||||
cao_cao["pos"] = Vector2i(7, 4)
|
||||
state._run_events("unit_reaches_tile", BattleStateScript.TEAM_PLAYER, 3, cao_cao)
|
||||
state._run_events("turn_start", BattleStateScript.TEAM_PLAYER, 5)
|
||||
state._run_events("turn_start", BattleStateScript.TEAM_ENEMY, 6)
|
||||
state._run_events("turn_start", BattleStateScript.TEAM_ENEMY, 9)
|
||||
|
||||
if dialogue_batches.size() < 5:
|
||||
failures.append("Xian Emperor Escort should add dialogue beats for each major escort pressure phase")
|
||||
var victory_text := str(state.objectives.get("victory", ""))
|
||||
if not victory_text.contains("동도 호송로") or not victory_text.contains("마지막 잔당"):
|
||||
failures.append("Xian Emperor Escort turn 9 event should update the victory objective for final escort pressure")
|
||||
if not state._condition_gate_open({"after_event": "turn_9_final_escort_pressure"}):
|
||||
failures.append("Xian Emperor Escort final objective gate should open after the turn 9 final pressure")
|
||||
if int(state.get_unit("imperial_envoy_ch7").get("ai_target_priority", 0)) != 12:
|
||||
failures.append("Xian Emperor Escort final pressure should keep the imperial envoy under threat")
|
||||
|
||||
var li_jue: Dictionary = state.get_unit("li_jue_vanguard")
|
||||
if li_jue.is_empty():
|
||||
failures.append("Xian Emperor Escort should include Li Jue vanguard for the road-opening story beat")
|
||||
else:
|
||||
li_jue["alive"] = false
|
||||
state._run_events("unit_defeated", BattleStateScript.TEAM_ENEMY, 9, li_jue)
|
||||
if dialogue_batches.size() < 6:
|
||||
failures.append("Xian Emperor Escort should show dialogue when Li Jue vanguard falls")
|
||||
var li_jue_objective_text := str(state.objectives.get("victory", ""))
|
||||
if not li_jue_objective_text.contains("천자 사자") or not li_jue_objective_text.contains("동도 호송로"):
|
||||
failures.append("Li Jue vanguard defeat objective should still point to the envoy and east road")
|
||||
|
||||
var final_rider: Dictionary = state.get_unit("final_escort_rider")
|
||||
if final_rider.is_empty():
|
||||
failures.append("Xian Emperor Escort should include final escort rider for the last pressure story beat")
|
||||
else:
|
||||
final_rider["alive"] = false
|
||||
state._run_events("unit_defeated", BattleStateScript.TEAM_ENEMY, 9, final_rider)
|
||||
if dialogue_batches.size() < 7:
|
||||
failures.append("Xian Emperor Escort should show dialogue when final escort rider falls")
|
||||
var final_objective_text := str(state.objectives.get("victory", ""))
|
||||
if not final_objective_text.contains("동도 호송로") or not final_objective_text.contains("잔당"):
|
||||
failures.append("Final escort rider defeat objective should still point to the east road and remaining enemies")
|
||||
|
||||
|
||||
func _event_by_id(state, event_id: String) -> Dictionary:
|
||||
for event in state.battle_events:
|
||||
if typeof(event) == TYPE_DICTIONARY and str(event.get("id", "")) == event_id:
|
||||
|
||||
@@ -32,12 +32,12 @@ func _check_condition_cells(failures: Array[String]) -> void:
|
||||
if not objective_cells.has(Vector2i(2, 3)) or not objective_cells.has(Vector2i(2, 4)):
|
||||
failures.append("objective cells missing multi-cell destination: %s" % str(objective_cells))
|
||||
var progress: String = state.get_objective_progress_text(false)
|
||||
if not progress.contains("(3, 4), (3, 5): not reached"):
|
||||
if not progress.contains("전장 표식 (3, 4), (3, 5) · 미도달"):
|
||||
failures.append("multi-cell progress text mismatch before reach: %s" % progress)
|
||||
var cao_cao: Dictionary = state.get_unit("cao_cao")
|
||||
cao_cao["pos"] = Vector2i(2, 4)
|
||||
progress = state.get_objective_progress_text(false)
|
||||
if not progress.contains("(3, 4), (3, 5): reached"):
|
||||
if not progress.contains("전장 표식 (3, 4), (3, 5) · 도달"):
|
||||
failures.append("multi-cell progress text mismatch after reach: %s" % progress)
|
||||
if not state._is_condition_met(state.battle_conditions["victory"]):
|
||||
failures.append("multi-cell unit_reaches_tile condition should be met")
|
||||
|
||||
Reference in New Issue
Block a user