From feac924a1cdd105578d0ab0c4375947d3de75ad1 Mon Sep 17 00:00:00 2001 From: Wickedness Date: Fri, 19 Jun 2026 18:44:48 +0900 Subject: [PATCH] Add opening battle capture events --- data/scenarios/001_yellow_turbans.json | 151 +++++++++++++++++++++++++ tools/smoke_chapter_one_polish.gd | 9 ++ tools/smoke_objective_progress.gd | 34 ++++++ 3 files changed, 194 insertions(+) diff --git a/data/scenarios/001_yellow_turbans.json b/data/scenarios/001_yellow_turbans.json index 64d7a59..4cf39aa 100644 --- a/data/scenarios/001_yellow_turbans.json +++ b/data/scenarios/001_yellow_turbans.json @@ -611,6 +611,157 @@ } ] }, + { + "id": "village_supply_secured", + "once": true, + "when": { + "type": "unit_reaches_tile", + "team": "player", + "cells": [ + [ + 6, + 5 + ], + [ + 7, + 5 + ], + [ + 6, + 6 + ], + [ + 7, + 6 + ], + [ + 13, + 8 + ], + [ + 14, + 8 + ], + [ + 13, + 9 + ], + [ + 14, + 9 + ] + ] + }, + "actions": [ + { + "type": "log", + "text": "마을 치료소와 창고를 확보했다." + }, + { + "type": "grant_item", + "item_id": "bean" + }, + { + "type": "grant_gold", + "amount": 80, + "text": "마을 창고에서 군자금 80냥을 거두었다." + }, + { + "type": "dialogue", + "lines": [ + { + "speaker": "Scout", + "display_speaker": "척후", + "side": "right", + "text": "마을 사람 몇이 숨겨 둔 약과 곡식을 내놓았습니다. 이곳을 붙들면 다친 병사를 돌릴 수 있습니다." + }, + { + "speaker": "Cao Cao", + "display_speaker": "조조", + "side": "left", + "text": "백성을 해치지 말고 창고만 거두어라. 전열을 고친 뒤 성채의 깃발을 꺾는다." + } + ] + }, + { + "type": "set_objective", + "victory": "마을 보급을 확보했다. 동쪽 성채를 장악하고 제11군령 이후 잔당까지 격파하라." + } + ] + }, + { + "id": "castle_gate_secured", + "once": true, + "when": { + "type": "unit_reaches_tile", + "team": "player", + "cells": [ + [ + 19, + 0 + ], + [ + 20, + 0 + ], + [ + 21, + 0 + ], + [ + 19, + 1 + ], + [ + 20, + 1 + ], + [ + 21, + 1 + ], + [ + 19, + 2 + ], + [ + 20, + 2 + ], + [ + 21, + 2 + ] + ] + }, + "actions": [ + { + "type": "log", + "text": "조조군이 동쪽 성채에 발을 들였다." + }, + { + "type": "dialogue", + "lines": [ + { + "speaker": "Xiahou Dun", + "display_speaker": "하후돈", + "side": "right", + "text": "성채 문루가 흔들립니다. 적은 아직 들판과 숲에 잔병을 숨겨 두었습니다." + }, + { + "speaker": "Cao Cao", + "display_speaker": "조조", + "side": "left", + "text": "성채를 놓치지 마라. 마지막 깃발이 모습을 드러날 때까지 이곳을 발판으로 삼는다." + } + ] + }, + { + "type": "set_objective", + "victory": "성채를 장악했다. 제11군령 이후 나타나는 마지막 황건 잔당까지 모두 격파하라." + } + ] + }, { "id": "turn_2_warning", "once": true, diff --git a/tools/smoke_chapter_one_polish.gd b/tools/smoke_chapter_one_polish.gd index a337bc3..ddce6b6 100644 --- a/tools/smoke_chapter_one_polish.gd +++ b/tools/smoke_chapter_one_polish.gd @@ -476,6 +476,8 @@ func _check_opening_battle_event_dialogue_structure(failures: Array[String]) -> for event_id in [ "opening_dialogue", "northern_woods_cache", + "village_supply_secured", + "castle_gate_secured", "turn_2_warning", "turn_4_eastern_reserve", "turn_7_southern_raiders", @@ -495,6 +497,13 @@ func _check_opening_battle_event_dialogue_structure(failures: Array[String]) -> var unit_ids: Array = when.get("unit_ids", []) if not unit_ids.has("yellow_turban_1"): failures.append("Zhang Mancheng defeat event should watch yellow_turban_1") + for objective_event_id in [ + "village_supply_secured", + "castle_gate_secured" + ]: + 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("opening battle capture event should update the active objective: %s" % objective_event_id) func _check_sishui_gate_event_dialogue_structure(failures: Array[String]) -> void: diff --git a/tools/smoke_objective_progress.gd b/tools/smoke_objective_progress.gd index 2b3a335..8310624 100644 --- a/tools/smoke_objective_progress.gd +++ b/tools/smoke_objective_progress.gd @@ -173,6 +173,7 @@ func _init() -> void: _check_event_gated_multi_cell_objective_markers(failures) _check_turn_gated_objective_does_not_create_marker(failures) _check_opening_battle_requires_castle_capture(failures) + _check_opening_battle_capture_events(failures) _check_sishui_gate_extended_pressure(failures) _check_xingyang_ambush_extended_pressure(failures) _check_qingzhou_campaign_extended_pressure(failures) @@ -361,6 +362,39 @@ func _check_opening_battle_requires_castle_capture(failures: Array[String]) -> v 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_opening_battle_capture_events(failures: Array[String]) -> void: + var state = BattleStateScript.new() + if not state.load_battle("res://data/scenarios/001_yellow_turbans.json"): + failures.append("opening capture event smoke could not load scenario") + return + + var dialogue_batches := [] + state.dialogue_requested.connect(func(lines: Array) -> void: + dialogue_batches.append(lines) + ) + + var cao_cao: Dictionary = state.get_unit("cao_cao") + cao_cao["pos"] = Vector2i(6, 5) + state._run_events("unit_reaches_tile", BattleStateScript.TEAM_PLAYER, 3, cao_cao) + if int(state.get_inventory_snapshot().get("bean", 0)) != 1: + failures.append("opening village capture should grant one Bean") + if state.get_battle_gold_reward() != 80: + failures.append("opening village capture should grant 80 battle gold, got %d" % state.get_battle_gold_reward()) + var village_objective := str(state.objectives.get("victory", "")) + if not village_objective.contains("마을 보급") or not village_objective.contains("동쪽 성채"): + failures.append("opening village capture should update the active objective: %s" % village_objective) + if dialogue_batches.size() < 1: + failures.append("opening village capture should show contextual dialogue") + + cao_cao["pos"] = Vector2i(20, 1) + state._run_events("unit_reaches_tile", BattleStateScript.TEAM_PLAYER, 4, cao_cao) + var castle_objective := str(state.objectives.get("victory", "")) + if not castle_objective.contains("성채를 장악") or not castle_objective.contains("마지막 황건 잔당"): + failures.append("opening castle capture should update the active objective: %s" % castle_objective) + if dialogue_batches.size() < 2: + failures.append("opening castle capture should show contextual dialogue") + + func _check_log_contains(failures: Array[String], logs: Array, expected: String) -> void: for log_entry in logs: if str(log_entry) == expected: