diff --git a/data/scenarios/001_yellow_turbans.json b/data/scenarios/001_yellow_turbans.json index 2284a55..0c2f024 100644 --- a/data/scenarios/001_yellow_turbans.json +++ b/data/scenarios/001_yellow_turbans.json @@ -9,7 +9,7 @@ "victory": { "type": "all", "conditions": [ - { "type": "all_units_defeated", "team": "enemy", "after_event": "turn_9_western_reserve" }, + { "type": "all_units_defeated", "team": "enemy", "after_event": "turn_11_last_rally" }, { "type": "unit_reaches_tile", "label": "성채 장악", @@ -393,7 +393,7 @@ }, { "type": "set_objective", - "victory": "성채를 장악한 채 마지막 황건대까지 모두 격파하라." + "victory": "성채를 장악하고 서쪽 숲 마지막 잔당이 드러날 때까지 전열을 유지하라." }, { "type": "spawn_deployments", @@ -435,6 +435,64 @@ } ] }, + { + "id": "turn_11_last_rally", + "once": true, + "when": { "type": "turn_start", "team": "enemy", "turn": 11 }, + "actions": [ + { "type": "log", "text": "흩어진 황건 잔당이 서쪽 둔덕에서 마지막 반격을 시도한다." }, + { + "type": "dialogue", + "lines": [ + { "speaker": "Scout", "display_speaker": "척후", "side": "right", "text": "서쪽 둔덕에 남은 깃발이 있습니다. 성채를 보고 마지막으로 모여듭니다!" }, + { "speaker": "Xiahou Dun", "display_speaker": "하후돈", "side": "right", "text": "제 뒤를 물려는 놈들입니다. 성채 앞줄은 그대로 두고, 돌아드는 길만 끊겠습니다." }, + { "speaker": "Cao Cao", "display_speaker": "조조", "side": "left", "text": "좋다. 이제 도망길도, 기대어 설 깃발도 없다. 성채를 붙들고 남은 황건대를 모두 거두어라." } + ] + }, + { + "type": "set_objective", + "victory": "성채를 장악한 채 마지막 황건 잔당까지 모두 격파하라." + }, + { + "type": "spawn_deployments", + "deployments": [ + { + "unit_id": "yellow_turban_last_rally_1", + "name": "황건 잔당", + "class_id": "infantry", + "team": "enemy", + "level": 1, + "pos": [1, 8], + "base": { "hp": 34, "atk": 10, "def": 6 } + }, + { + "unit_id": "yellow_turban_last_rally_2", + "name": "황건 궁수", + "class_id": "archer", + "team": "enemy", + "level": 1, + "pos": [2, 8], + "base": { "hp": 26, "atk": 9, "def": 4 } + }, + { + "unit_id": "yellow_turban_last_rally_3", + "name": "황건 유격병", + "class_id": "bandit", + "team": "enemy", + "level": 1, + "pos": [4, 9], + "base": { "hp": 32, "atk": 11, "def": 5 } + } + ] + }, + { + "type": "set_ai_target_priority", + "unit_ids": ["cao_cao", "xiahou_dun"], + "priority": 13, + "text": "마지막 황건 잔당이 조조와 하후돈의 후미를 노린다." + } + ] + }, { "id": "zhang_mancheng_falls", "once": true, diff --git a/tools/smoke_chapter_one_polish.gd b/tools/smoke_chapter_one_polish.gd index 720d899..37924d0 100644 --- a/tools/smoke_chapter_one_polish.gd +++ b/tools/smoke_chapter_one_polish.gd @@ -299,6 +299,7 @@ func _check_opening_battle_event_dialogue_structure(failures: Array[String]) -> "turn_4_eastern_reserve", "turn_7_southern_raiders", "turn_9_western_reserve", + "turn_11_last_rally", "zhang_mancheng_falls" ]: var event := _event_by_id(state, event_id) @@ -732,14 +733,15 @@ func _check_opening_battle_story_beats(failures: Array[String]) -> void: state._run_events("turn_start", BattleStateScript.TEAM_ENEMY, 4) state._run_events("turn_start", BattleStateScript.TEAM_ENEMY, 7) state._run_events("turn_start", BattleStateScript.TEAM_ENEMY, 9) + state._run_events("turn_start", BattleStateScript.TEAM_ENEMY, 11) - if dialogue_batches.size() < 4: + if dialogue_batches.size() < 5: failures.append("opening battle should add dialogue beats for each major reinforcement phase") var victory_text := str(state.objectives.get("victory", "")) - if not victory_text.contains("마지막 황건대"): - failures.append("opening battle turn 9 event should update the victory objective after the final reserve arrives") - if not state._condition_gate_open({"after_event": "turn_9_western_reserve"}): - failures.append("opening battle final objective gate should open after the turn 9 story beat") + if not victory_text.contains("마지막 황건 잔당"): + failures.append("opening battle turn 11 event should update the victory objective after the final rally arrives") + if not state._condition_gate_open({"after_event": "turn_11_last_rally"}): + failures.append("opening battle final objective gate should open after the turn 11 story beat") func _check_sishui_gate_story_beats(failures: Array[String]) -> void: diff --git a/tools/smoke_objective_progress.gd b/tools/smoke_objective_progress.gd index b171024..8018b59 100644 --- a/tools/smoke_objective_progress.gd +++ b/tools/smoke_objective_progress.gd @@ -35,7 +35,7 @@ func _init() -> void: failures, "001 late reserve gate", _progress_text("res://data/scenarios/001_yellow_turbans.json", false), - "제9군령에 전공 갱신" + "제11군령에 전공 갱신" ) _check_contains( failures, @@ -351,8 +351,14 @@ func _check_opening_battle_requires_castle_capture(failures: Array[String]) -> v for enemy in state.get_living_units(BattleStateScript.TEAM_ENEMY): enemy["alive"] = false state._check_battle_status() + if str(state.battle_status) != BattleStateScript.STATUS_ACTIVE: + failures.append("opening battle should wait for the turn 11 last rally before victory, got %s" % str(state.battle_status)) + state._run_events("turn_start", BattleStateScript.TEAM_ENEMY, 11) + for enemy in state.get_living_units(BattleStateScript.TEAM_ENEMY): + enemy["alive"] = false + state._check_battle_status() if str(state.battle_status) != BattleStateScript.STATUS_VICTORY: - failures.append("opening battle should end after late reserve falls and castle is captured, got %s" % str(state.battle_status)) + failures.append("opening battle should end after the turn 11 last rally falls and castle is captured, got %s" % str(state.battle_status)) func _check_log_contains(failures: Array[String], logs: Array, expected: String) -> void: @@ -404,15 +410,32 @@ func _check_opening_battle_extended_pressure(failures: Array[String]) -> void: failures.append("opening battle should allow play through turn 17, got limit %d" % state.get_turn_limit()) if state.get_living_units(BattleStateScript.TEAM_ENEMY).size() != 12: failures.append("opening battle should start with 12 enemies, got %d" % state.get_living_units(BattleStateScript.TEAM_ENEMY).size()) - if state._condition_gate_open({"after_event": "turn_9_western_reserve"}): - failures.append("opening battle final defeat-all condition should be gated until turn 9 reserve") + if state._condition_gate_open({"after_event": "turn_11_last_rally"}): + failures.append("opening battle final defeat-all condition should be gated until turn 11 last rally") state._run_events("turn_start", BattleStateScript.TEAM_ENEMY, 4) + if state.get_living_units(BattleStateScript.TEAM_ENEMY).size() != 14: + failures.append("opening battle should field 14 enemies after turn 4 reserve, got %d" % state.get_living_units(BattleStateScript.TEAM_ENEMY).size()) + if int(state.get_unit("xiahou_dun").get("ai_target_priority", 0)) < 9: + failures.append("opening battle turn 4 reserve should pressure Xiahou Dun's vanguard") state._run_events("turn_start", BattleStateScript.TEAM_ENEMY, 7) + if state.get_living_units(BattleStateScript.TEAM_ENEMY).size() != 16: + failures.append("opening battle should field 16 enemies after turn 7 raiders, got %d" % state.get_living_units(BattleStateScript.TEAM_ENEMY).size()) + if int(state.get_unit("cao_cao").get("ai_target_priority", 0)) < 11: + failures.append("opening battle turn 7 raiders should pressure Cao Cao") state._run_events("turn_start", BattleStateScript.TEAM_ENEMY, 9) - if not state._condition_gate_open({"after_event": "turn_9_western_reserve"}): - failures.append("opening battle final gate should open after turn 9 reserve event") if state.get_living_units(BattleStateScript.TEAM_ENEMY).size() != 19: failures.append("opening battle should field 19 enemies after late reserve, got %d" % state.get_living_units(BattleStateScript.TEAM_ENEMY).size()) + if int(state.get_unit("cao_cao").get("ai_target_priority", 0)) < 12: + failures.append("opening battle turn 9 reserve should keep pressure on Cao Cao") + if state._condition_gate_open({"after_event": "turn_11_last_rally"}): + failures.append("opening battle should stay open-ended until the turn 11 last rally arrives") + state._run_events("turn_start", BattleStateScript.TEAM_ENEMY, 11) + if not state._condition_gate_open({"after_event": "turn_11_last_rally"}): + failures.append("opening battle final gate should open after turn 11 last rally event") + if state.get_living_units(BattleStateScript.TEAM_ENEMY).size() != 22: + failures.append("opening battle should field 22 enemies after final rally, got %d" % state.get_living_units(BattleStateScript.TEAM_ENEMY).size()) + if int(state.get_unit("cao_cao").get("ai_target_priority", 0)) < 13 or int(state.get_unit("xiahou_dun").get("ai_target_priority", 0)) < 13: + failures.append("opening battle turn 11 last rally should pressure both Cao Cao and Xiahou Dun") func _check_sishui_gate_extended_pressure(failures: Array[String]) -> void: