Improve Qingzhou campaign battle pacing
This commit is contained in:
@@ -2,14 +2,27 @@
|
||||
"id": "004_qingzhou_campaign",
|
||||
"name": "청주 평정전",
|
||||
"objectives": {
|
||||
"victory": "황건 잔당의 우두머리를 격파하라.",
|
||||
"defeat": "조조가 퇴각하거나 제12턴에 이르면 패한다."
|
||||
"victory": "청주 촌락을 지키고 황건 잔당을 평정하라.",
|
||||
"defeat": "조조가 퇴각하거나 제18턴이 시작되면 패한다."
|
||||
},
|
||||
"conditions": {
|
||||
"victory": { "type": "all_units_defeated", "team": "enemy", "after_event": "turn_3_bandit_push" },
|
||||
"victory": {
|
||||
"type": "all",
|
||||
"conditions": [
|
||||
{ "type": "all_units_defeated", "team": "enemy", "after_event": "turn_9_village_last_stand" },
|
||||
{
|
||||
"type": "unit_reaches_tile",
|
||||
"label": "촌락 보호",
|
||||
"team": "player",
|
||||
"unit_ids": ["cao_cao_ch4", "xiahou_dun_ch4", "xiahou_yuan_ch4", "cao_ren_ch4"],
|
||||
"officer_ids": ["cao_cao", "xiahou_dun", "xiahou_yuan", "cao_ren"],
|
||||
"cells": [[10, 3], [11, 3], [10, 5], [11, 5]]
|
||||
}
|
||||
]
|
||||
},
|
||||
"defeat": [
|
||||
{ "type": "any_officer_defeated", "team": "player", "officer_ids": ["cao_cao"] },
|
||||
{ "type": "turn_reached", "turn": 12, "team": "player" }
|
||||
{ "type": "turn_reached", "turn": 18, "team": "player" }
|
||||
]
|
||||
},
|
||||
"briefing": {
|
||||
@@ -18,7 +31,8 @@
|
||||
"lines": [
|
||||
"연합군이 흩어진 뒤 조조는 청주로 눈을 돌렸다.",
|
||||
"황건 잔당이 마을과 상로를 어지럽히며 백성을 겁박한다.",
|
||||
"길목을 장악하고 적장을 베어, 흩어진 장정을 군율 아래 모아라."
|
||||
"길목을 장악하고 적장을 베어, 흩어진 장정을 군율 아래 모아라.",
|
||||
"동쪽 촌락을 지키며 잔당의 마지막 반격까지 꺾으면, 백성을 지키던 무사 전위가 조조군을 지켜볼 것이다."
|
||||
],
|
||||
"conditional_lines": [
|
||||
{
|
||||
@@ -127,9 +141,9 @@
|
||||
"GGGGGGGGGGGGGG",
|
||||
"GGGFFFGGGHHGGG",
|
||||
"GGGFFFGRRHHGGG",
|
||||
"GGGGGGRRRGGGGG",
|
||||
"GGGGGGRRRGTTGG",
|
||||
"RRRRRRRRRRRRRR",
|
||||
"GGGGGGRRRGGGGG",
|
||||
"GGGGGGRRRGTTGG",
|
||||
"GGHGGGFFFGGGGG",
|
||||
"GGHHGGFFFGGWWG",
|
||||
"GGGGGGGFFGGWWG",
|
||||
@@ -207,6 +221,33 @@
|
||||
"level": 4,
|
||||
"pos": [11, 6],
|
||||
"base": { "hp": 32, "mp": 16, "atk": 7, "def": 4, "int": 11 }
|
||||
},
|
||||
{
|
||||
"unit_id": "qingzhou_village_guard",
|
||||
"name": "촌락 약탈병",
|
||||
"class_id": "bandit",
|
||||
"team": "enemy",
|
||||
"level": 4,
|
||||
"pos": [10, 3],
|
||||
"base": { "hp": 36, "atk": 13, "def": 5 }
|
||||
},
|
||||
{
|
||||
"unit_id": "qingzhou_road_spearman",
|
||||
"name": "상로 창병",
|
||||
"class_id": "infantry",
|
||||
"team": "enemy",
|
||||
"level": 4,
|
||||
"pos": [8, 4],
|
||||
"base": { "hp": 40, "atk": 13, "def": 7 }
|
||||
},
|
||||
{
|
||||
"unit_id": "qingzhou_hill_archer",
|
||||
"name": "언덕 궁병",
|
||||
"class_id": "archer",
|
||||
"team": "enemy",
|
||||
"level": 4,
|
||||
"pos": [11, 2],
|
||||
"base": { "hp": 30, "atk": 12, "def": 5 }
|
||||
}
|
||||
],
|
||||
"events": [
|
||||
@@ -248,8 +289,8 @@
|
||||
},
|
||||
{
|
||||
"type": "set_objective",
|
||||
"victory": "청주 두령과 모든 약탈병을 격파하라.",
|
||||
"defeat": "조조가 퇴각하거나 제12턴에 이르면 패한다."
|
||||
"victory": "촌락 길목을 지키며 청주 두령과 약탈병을 격파하라.",
|
||||
"defeat": "조조가 퇴각하거나 제18턴이 시작되면 패한다."
|
||||
},
|
||||
{
|
||||
"type": "spawn_deployments",
|
||||
@@ -298,6 +339,117 @@
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "turn_6_village_raiders",
|
||||
"once": true,
|
||||
"when": { "type": "turn_start", "team": "enemy", "turn": 6 },
|
||||
"actions": [
|
||||
{ "type": "log", "text": "마을 뒤편에서 잔당의 별동대가 다시 약탈길을 연다." },
|
||||
{
|
||||
"type": "dialogue",
|
||||
"lines": [
|
||||
{ "speaker": "Cao Ren", "display_speaker": "조인", "text": "마을 뒤쪽에 또 다른 약탈병입니다. 길목을 비우면 백성들이 먼저 베입니다." },
|
||||
{ "speaker": "Cao Cao", "display_speaker": "조조", "text": "적을 쫓는 칼보다 백성을 등지는 발이 더 무겁다. 촌락을 붙들어라." }
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "spawn_deployments",
|
||||
"deployments": [
|
||||
{
|
||||
"unit_id": "qingzhou_village_raider_west",
|
||||
"name": "촌락 약탈병",
|
||||
"class_id": "bandit",
|
||||
"team": "enemy",
|
||||
"level": 4,
|
||||
"pos": [5, 6],
|
||||
"base": { "hp": 34, "atk": 13, "def": 5 }
|
||||
},
|
||||
{
|
||||
"unit_id": "qingzhou_village_raider_spear",
|
||||
"name": "촌락 창병",
|
||||
"class_id": "infantry",
|
||||
"team": "enemy",
|
||||
"level": 4,
|
||||
"pos": [8, 6],
|
||||
"base": { "hp": 38, "atk": 13, "def": 7 }
|
||||
},
|
||||
{
|
||||
"unit_id": "qingzhou_village_raider_archer",
|
||||
"name": "촌락 궁병",
|
||||
"class_id": "archer",
|
||||
"team": "enemy",
|
||||
"level": 4,
|
||||
"pos": [12, 6],
|
||||
"base": { "hp": 30, "atk": 12, "def": 4 }
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "set_ai_target_priority",
|
||||
"unit_id": "xiahou_dun_ch4",
|
||||
"priority": 8,
|
||||
"text": "촌락 별동대가 하후돈의 엄호선을 노린다."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "turn_9_village_last_stand",
|
||||
"once": true,
|
||||
"when": { "type": "turn_start", "team": "enemy", "turn": 9 },
|
||||
"actions": [
|
||||
{ "type": "log", "text": "청주 두령의 마지막 무리가 촌락 입구로 몰려든다." },
|
||||
{
|
||||
"type": "set_objective",
|
||||
"victory": "마지막 잔당을 격파하고 촌락 길목을 지켜라.",
|
||||
"defeat": "조조가 퇴각하거나 제18턴이 시작되면 패한다."
|
||||
},
|
||||
{
|
||||
"type": "dialogue",
|
||||
"lines": [
|
||||
{ "speaker": "Dian Wei", "display_speaker": "전위", "text": "백성을 등지고 달아나는 군대가 아니라면, 그 길목을 끝까지 지켜 보십시오." },
|
||||
{ "speaker": "Cao Cao", "display_speaker": "조조", "text": "듣던 무사가 저 자인가. 좋다. 청주의 길목에서 우리 군율을 보이겠다." }
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "spawn_deployments",
|
||||
"deployments": [
|
||||
{
|
||||
"unit_id": "qingzhou_last_guard",
|
||||
"name": "잔당 호위병",
|
||||
"class_id": "infantry",
|
||||
"team": "enemy",
|
||||
"level": 4,
|
||||
"pos": [12, 3],
|
||||
"base": { "hp": 42, "atk": 14, "def": 8 }
|
||||
},
|
||||
{
|
||||
"unit_id": "qingzhou_last_rider",
|
||||
"name": "잔당 기병",
|
||||
"class_id": "cavalry",
|
||||
"team": "enemy",
|
||||
"level": 4,
|
||||
"pos": [13, 4],
|
||||
"base": { "hp": 42, "atk": 15, "def": 7 }
|
||||
},
|
||||
{
|
||||
"unit_id": "qingzhou_last_archer",
|
||||
"name": "잔당 궁병",
|
||||
"class_id": "archer",
|
||||
"team": "enemy",
|
||||
"level": 4,
|
||||
"pos": [12, 5],
|
||||
"base": { "hp": 30, "atk": 12, "def": 4 }
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "set_ai_target_priority",
|
||||
"unit_id": "cao_cao_ch4",
|
||||
"priority": 11,
|
||||
"text": "마지막 잔당이 조조의 깃발을 향해 달려든다."
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"rewards": {
|
||||
|
||||
@@ -67,6 +67,18 @@ func _init() -> void:
|
||||
_progress_text("res://data/scenarios/003_xingyang_ambush.json", false),
|
||||
"동쪽 길목"
|
||||
)
|
||||
_check_contains(
|
||||
failures,
|
||||
"004 gated victory progress",
|
||||
_progress_text("res://data/scenarios/004_qingzhou_campaign.json", false),
|
||||
"제9군령에 전공 갱신"
|
||||
)
|
||||
_check_contains(
|
||||
failures,
|
||||
"004 village protection progress",
|
||||
_progress_text("res://data/scenarios/004_qingzhou_campaign.json", false),
|
||||
"촌락 보호"
|
||||
)
|
||||
_check_contains(
|
||||
failures,
|
||||
"007 destination progress",
|
||||
@@ -91,6 +103,7 @@ func _init() -> void:
|
||||
_check_opening_battle_requires_castle_capture(failures)
|
||||
_check_sishui_gate_extended_pressure(failures)
|
||||
_check_xingyang_ambush_extended_pressure(failures)
|
||||
_check_qingzhou_campaign_extended_pressure(failures)
|
||||
_check_objective_update(failures)
|
||||
_check_objective_notice(failures)
|
||||
_check_terrain_recovery(failures)
|
||||
@@ -435,6 +448,59 @@ func _check_xingyang_ambush_extended_pressure(failures: Array[String]) -> void:
|
||||
scene.free()
|
||||
|
||||
|
||||
func _check_qingzhou_campaign_extended_pressure(failures: Array[String]) -> void:
|
||||
var state = BattleStateScript.new()
|
||||
if not state.load_battle("res://data/scenarios/004_qingzhou_campaign.json"):
|
||||
failures.append("Qingzhou Campaign pressure smoke could not load scenario")
|
||||
return
|
||||
if state.get_turn_limit() != 17:
|
||||
failures.append("Qingzhou Campaign should allow play through turn 17, got limit %d" % state.get_turn_limit())
|
||||
if state.get_living_units(BattleStateScript.TEAM_ENEMY).size() != 8:
|
||||
failures.append("Qingzhou Campaign should start with 8 enemies, got %d" % state.get_living_units(BattleStateScript.TEAM_ENEMY).size())
|
||||
if state._condition_gate_open({"after_event": "turn_9_village_last_stand"}):
|
||||
failures.append("Qingzhou Campaign final defeat-all condition should be gated until turn 9 last stand")
|
||||
var marker_cells := state.get_objective_cells()
|
||||
for village_cell in [Vector2i(10, 3), Vector2i(11, 3), Vector2i(10, 5), Vector2i(11, 5)]:
|
||||
if not marker_cells.has(village_cell):
|
||||
failures.append("Qingzhou Campaign should mark village protection cell %s: %s" % [str(village_cell), str(marker_cells)])
|
||||
if state.get_objective_cell_label(village_cell) != "촌락 보호":
|
||||
failures.append("Qingzhou Campaign village marker should expose label at %s" % str(village_cell))
|
||||
var recovery_summaries := state.get_recovery_terrain_summaries()
|
||||
var has_village_recovery := false
|
||||
for summary in recovery_summaries:
|
||||
if str(summary.get("name", "")) == "마을" and int(summary.get("count", 0)) == 4 and int(summary.get("heal", 0)) == 6:
|
||||
has_village_recovery = true
|
||||
if not has_village_recovery:
|
||||
failures.append("Qingzhou Campaign should expose village recovery terrain: %s" % str(recovery_summaries))
|
||||
state._run_events("turn_start", BattleStateScript.TEAM_ENEMY, 3)
|
||||
state._run_events("turn_start", BattleStateScript.TEAM_ENEMY, 6)
|
||||
state._run_events("turn_start", BattleStateScript.TEAM_ENEMY, 9)
|
||||
if not state._condition_gate_open({"after_event": "turn_9_village_last_stand"}):
|
||||
failures.append("Qingzhou Campaign final gate should open after turn 9 last stand event")
|
||||
if state.get_living_units(BattleStateScript.TEAM_ENEMY).size() != 17:
|
||||
failures.append("Qingzhou Campaign should field 17 enemies after last stand, got %d" % state.get_living_units(BattleStateScript.TEAM_ENEMY).size())
|
||||
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("Qingzhou Campaign should not end before village protection, got %s" % str(state.battle_status))
|
||||
var cao_cao: Dictionary = state.get_unit("cao_cao_ch4")
|
||||
cao_cao["pos"] = Vector2i(10, 3)
|
||||
state._check_battle_status()
|
||||
if str(state.battle_status) != BattleStateScript.STATUS_VICTORY:
|
||||
failures.append("Qingzhou Campaign should end after last stand falls and village is protected, got %s" % str(state.battle_status))
|
||||
var scene = BattleSceneScript.new()
|
||||
if not scene.state.load_battle("res://data/scenarios/004_qingzhou_campaign.json"):
|
||||
failures.append("Qingzhou Campaign briefing smoke could not load scenario")
|
||||
scene.free()
|
||||
return
|
||||
var overview := scene._format_briefing_battlefield_overview_text()
|
||||
_check_contains(failures, "004 briefing map size", overview, "14칸 x 10칸")
|
||||
_check_contains(failures, "004 briefing enemy count", overview, "적세 8명")
|
||||
_check_contains(failures, "004 briefing village recovery", overview, "마을 4칸 +6")
|
||||
scene.free()
|
||||
|
||||
|
||||
func _check_opening_board_avoids_side_panel(failures: Array[String]) -> void:
|
||||
var state = BattleStateScript.new()
|
||||
if not state.load_battle("res://data/scenarios/001_yellow_turbans.json"):
|
||||
|
||||
Reference in New Issue
Block a user