Improve Sishui Gate battle pacing
This commit is contained in:
@@ -2,14 +2,27 @@
|
||||
"id": "002_sishui_gate",
|
||||
"name": "사수관 선봉전",
|
||||
"objectives": {
|
||||
"victory": "화웅의 선봉대를 격파하라.",
|
||||
"defeat": "조조가 퇴각하거나 제9턴에 이르면 패한다."
|
||||
"victory": "사수관 입구를 장악하고 화웅의 원군까지 격파하라.",
|
||||
"defeat": "조조가 퇴각하거나 제17턴이 시작되면 패한다."
|
||||
},
|
||||
"conditions": {
|
||||
"victory": { "type": "all_units_defeated", "team": "enemy", "after_event": "turn_2_warning" },
|
||||
"victory": {
|
||||
"type": "all",
|
||||
"conditions": [
|
||||
{ "type": "all_units_defeated", "team": "enemy", "after_event": "turn_8_gate_reserve" },
|
||||
{
|
||||
"type": "unit_reaches_tile",
|
||||
"label": "관문 장악",
|
||||
"team": "player",
|
||||
"unit_ids": ["cao_cao_ch2", "xiahou_dun_ch2", "xiahou_yuan_ch2", "cao_ren_ch2"],
|
||||
"officer_ids": ["cao_cao", "xiahou_dun", "xiahou_yuan", "cao_ren"],
|
||||
"cells": [[10, 3], [11, 3], [10, 4], [11, 4], [10, 5], [11, 5]]
|
||||
}
|
||||
]
|
||||
},
|
||||
"defeat": [
|
||||
{ "type": "any_officer_defeated", "team": "player", "officer_ids": ["cao_cao"] },
|
||||
{ "type": "turn_reached", "turn": 9, "team": "player" }
|
||||
{ "type": "turn_reached", "turn": 17, "team": "player" }
|
||||
]
|
||||
},
|
||||
"briefing": {
|
||||
@@ -17,7 +30,8 @@
|
||||
"location": "사수관, 초평 원년",
|
||||
"lines": [
|
||||
"동탁을 토벌하기 위해 제후의 군기가 사수관 아래 모였다.",
|
||||
"조조는 작은 선봉을 이끌고 화웅의 진을 먼저 시험하려 한다."
|
||||
"조조는 작은 선봉을 이끌고 화웅의 진을 먼저 시험하려 한다.",
|
||||
"서남쪽 마을과 관문 안쪽 성채를 차지하면 병력을 고칠 수 있으나, 화웅의 후속 원군이 뒤따른다."
|
||||
],
|
||||
"camp_conversations": [
|
||||
{
|
||||
@@ -85,7 +99,7 @@
|
||||
}
|
||||
},
|
||||
"roster": {
|
||||
"max_units": 3,
|
||||
"max_units": 4,
|
||||
"required_officers": ["cao_cao"]
|
||||
},
|
||||
"formation": {
|
||||
@@ -99,11 +113,11 @@
|
||||
"GGGGGRRGGGGG",
|
||||
"GGGFFRRGHHGG",
|
||||
"GGGFFRRGHHGG",
|
||||
"GGGGGRRGGGGG",
|
||||
"RRRRRRRRRRRR",
|
||||
"GGGGGRRGGGGG",
|
||||
"GGHGGFFGGGGG",
|
||||
"GGHGGFFGGWWG",
|
||||
"GGGGGRRGGGCC",
|
||||
"RRRRRRRRRRCC",
|
||||
"GGGGGRRGGGCC",
|
||||
"GGHTTFFGGGGG",
|
||||
"GGHTTFFGGWWG",
|
||||
"GGGGGGGGGWWG"
|
||||
]
|
||||
},
|
||||
@@ -169,6 +183,42 @@
|
||||
"level": 2,
|
||||
"pos": [10, 2],
|
||||
"base": { "hp": 28, "atk": 10, "def": 4 }
|
||||
},
|
||||
{
|
||||
"unit_id": "gate_guard_1",
|
||||
"name": "관문 수비병",
|
||||
"class_id": "infantry",
|
||||
"team": "enemy",
|
||||
"level": 2,
|
||||
"pos": [10, 3],
|
||||
"base": { "hp": 36, "atk": 11, "def": 8 }
|
||||
},
|
||||
{
|
||||
"unit_id": "gate_guard_2",
|
||||
"name": "관문 궁병",
|
||||
"class_id": "archer",
|
||||
"team": "enemy",
|
||||
"level": 2,
|
||||
"pos": [10, 5],
|
||||
"base": { "hp": 28, "atk": 10, "def": 5 }
|
||||
},
|
||||
{
|
||||
"unit_id": "liang_outrider",
|
||||
"name": "양주 기마척후",
|
||||
"class_id": "cavalry",
|
||||
"team": "enemy",
|
||||
"level": 2,
|
||||
"pos": [7, 6],
|
||||
"base": { "hp": 34, "atk": 12, "def": 6 }
|
||||
},
|
||||
{
|
||||
"unit_id": "liang_gate_sentinel",
|
||||
"name": "관문 창병",
|
||||
"class_id": "infantry",
|
||||
"team": "enemy",
|
||||
"level": 2,
|
||||
"pos": [9, 5],
|
||||
"base": { "hp": 34, "atk": 11, "def": 7 }
|
||||
}
|
||||
],
|
||||
"events": [
|
||||
@@ -202,8 +252,8 @@
|
||||
{ "type": "log", "text": "화웅의 병사들이 진형을 조여 왔다." },
|
||||
{
|
||||
"type": "set_objective",
|
||||
"victory": "화웅의 선봉대와 원군을 모두 격파하라.",
|
||||
"defeat": "조조가 퇴각하거나 제9턴에 이르면 패한다."
|
||||
"victory": "관문 입구를 장악하고 화웅의 선봉과 원군을 격파하라.",
|
||||
"defeat": "조조가 퇴각하거나 제17턴이 시작되면 패한다."
|
||||
},
|
||||
{
|
||||
"type": "spawn_deployments",
|
||||
@@ -229,6 +279,98 @@
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "turn_5_ridge_patrol",
|
||||
"once": true,
|
||||
"when": { "type": "turn_start", "team": "enemy", "turn": 5 },
|
||||
"actions": [
|
||||
{ "type": "log", "text": "북쪽 능선에서 화웅의 정찰대가 전장으로 내려온다." },
|
||||
{
|
||||
"type": "spawn_deployments",
|
||||
"deployments": [
|
||||
{
|
||||
"unit_id": "liang_ridge_archer",
|
||||
"name": "능선 궁병",
|
||||
"class_id": "archer",
|
||||
"team": "enemy",
|
||||
"level": 2,
|
||||
"pos": [9, 1],
|
||||
"base": { "hp": 28, "atk": 10, "def": 4 }
|
||||
},
|
||||
{
|
||||
"unit_id": "liang_ridge_spearman",
|
||||
"name": "능선 창병",
|
||||
"class_id": "infantry",
|
||||
"team": "enemy",
|
||||
"level": 2,
|
||||
"pos": [8, 1],
|
||||
"base": { "hp": 34, "atk": 11, "def": 6 }
|
||||
},
|
||||
{
|
||||
"unit_id": "liang_ridge_cavalry",
|
||||
"name": "능선 기병",
|
||||
"class_id": "cavalry",
|
||||
"team": "enemy",
|
||||
"level": 2,
|
||||
"pos": [9, 2],
|
||||
"base": { "hp": 34, "atk": 12, "def": 6 }
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "set_ai_target_priority",
|
||||
"unit_id": "xiahou_dun_ch2",
|
||||
"priority": 8,
|
||||
"text": "능선 정찰대가 하후돈의 선봉을 노린다."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "turn_8_gate_reserve",
|
||||
"once": true,
|
||||
"when": { "type": "turn_start", "team": "enemy", "turn": 8 },
|
||||
"actions": [
|
||||
{ "type": "log", "text": "관문 뒤편에서 화웅의 예비대가 마지막으로 밀려 나온다." },
|
||||
{
|
||||
"type": "spawn_deployments",
|
||||
"deployments": [
|
||||
{
|
||||
"unit_id": "liang_gate_reserve_cavalry",
|
||||
"name": "관문 기병",
|
||||
"class_id": "cavalry",
|
||||
"team": "enemy",
|
||||
"level": 2,
|
||||
"pos": [11, 2],
|
||||
"base": { "hp": 36, "atk": 13, "def": 6 }
|
||||
},
|
||||
{
|
||||
"unit_id": "liang_gate_reserve_guard",
|
||||
"name": "관문 호위병",
|
||||
"class_id": "infantry",
|
||||
"team": "enemy",
|
||||
"level": 2,
|
||||
"pos": [11, 6],
|
||||
"base": { "hp": 36, "atk": 11, "def": 7 }
|
||||
},
|
||||
{
|
||||
"unit_id": "liang_gate_reserve_archer",
|
||||
"name": "관문 궁병",
|
||||
"class_id": "archer",
|
||||
"team": "enemy",
|
||||
"level": 2,
|
||||
"pos": [11, 7],
|
||||
"base": { "hp": 28, "atk": 10, "def": 4 }
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "set_ai_target_priority",
|
||||
"unit_id": "cao_cao_ch2",
|
||||
"priority": 11,
|
||||
"text": "화웅의 예비대가 조조의 선봉 깃발을 노린다."
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"post_battle_choices": [
|
||||
|
||||
@@ -41,7 +41,7 @@ func _init() -> void:
|
||||
failures,
|
||||
"002 gated victory progress",
|
||||
_progress_text("res://data/scenarios/002_sishui_gate.json", false),
|
||||
"제2군령에 전공 갱신"
|
||||
"제8군령에 전공 갱신"
|
||||
)
|
||||
_check_contains(
|
||||
failures,
|
||||
@@ -49,6 +49,12 @@ func _init() -> void:
|
||||
_progress_text("res://data/scenarios/002_sishui_gate.json", false),
|
||||
"적군 격파 0/"
|
||||
)
|
||||
_check_contains(
|
||||
failures,
|
||||
"002 gate capture progress",
|
||||
_progress_text("res://data/scenarios/002_sishui_gate.json", false),
|
||||
"관문 장악"
|
||||
)
|
||||
_check_contains(
|
||||
failures,
|
||||
"007 destination progress",
|
||||
@@ -71,6 +77,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_sishui_gate_extended_pressure(failures)
|
||||
_check_objective_update(failures)
|
||||
_check_objective_notice(failures)
|
||||
_check_terrain_recovery(failures)
|
||||
@@ -304,6 +311,55 @@ func _check_opening_battle_extended_pressure(failures: Array[String]) -> void:
|
||||
failures.append("opening battle should field 19 enemies after late reserve, got %d" % state.get_living_units(BattleStateScript.TEAM_ENEMY).size())
|
||||
|
||||
|
||||
func _check_sishui_gate_extended_pressure(failures: Array[String]) -> void:
|
||||
var state = BattleStateScript.new()
|
||||
if not state.load_battle("res://data/scenarios/002_sishui_gate.json"):
|
||||
failures.append("Sishui Gate pressure smoke could not load scenario")
|
||||
return
|
||||
if state.get_turn_limit() != 16:
|
||||
failures.append("Sishui Gate should allow play through turn 16, got limit %d" % state.get_turn_limit())
|
||||
if state.get_living_units(BattleStateScript.TEAM_ENEMY).size() != 8:
|
||||
failures.append("Sishui Gate should start with 8 enemies, got %d" % state.get_living_units(BattleStateScript.TEAM_ENEMY).size())
|
||||
if state._condition_gate_open({"after_event": "turn_8_gate_reserve"}):
|
||||
failures.append("Sishui Gate final defeat-all condition should be gated until turn 8 reserve")
|
||||
var marker_cells := state.get_objective_cells()
|
||||
for gate_cell in [Vector2i(10, 3), Vector2i(11, 3), Vector2i(10, 4), Vector2i(11, 4), Vector2i(10, 5), Vector2i(11, 5)]:
|
||||
if not marker_cells.has(gate_cell):
|
||||
failures.append("Sishui Gate should mark gate capture cell %s: %s" % [str(gate_cell), str(marker_cells)])
|
||||
if state.get_objective_cell_label(gate_cell) != "관문 장악":
|
||||
failures.append("Sishui Gate gate marker should expose label at %s" % str(gate_cell))
|
||||
var recovery_summaries := state.get_recovery_terrain_summaries()
|
||||
var has_gate_recovery := false
|
||||
var has_village_recovery := false
|
||||
for summary in recovery_summaries:
|
||||
if str(summary.get("name", "")) == "성채" and int(summary.get("count", 0)) >= 6 and int(summary.get("heal", 0)) == 8:
|
||||
has_gate_recovery = true
|
||||
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_gate_recovery:
|
||||
failures.append("Sishui Gate should expose castle recovery terrain: %s" % str(recovery_summaries))
|
||||
if not has_village_recovery:
|
||||
failures.append("Sishui Gate should expose village recovery terrain: %s" % str(recovery_summaries))
|
||||
state._run_events("turn_start", BattleStateScript.TEAM_ENEMY, 2)
|
||||
state._run_events("turn_start", BattleStateScript.TEAM_ENEMY, 5)
|
||||
state._run_events("turn_start", BattleStateScript.TEAM_ENEMY, 8)
|
||||
if not state._condition_gate_open({"after_event": "turn_8_gate_reserve"}):
|
||||
failures.append("Sishui Gate final gate should open after turn 8 reserve event")
|
||||
if state.get_living_units(BattleStateScript.TEAM_ENEMY).size() != 16:
|
||||
failures.append("Sishui Gate should field 16 enemies after gate reserve, got %d" % state.get_living_units(BattleStateScript.TEAM_ENEMY).size())
|
||||
var scene = BattleSceneScript.new()
|
||||
if not scene.state.load_battle("res://data/scenarios/002_sishui_gate.json"):
|
||||
failures.append("Sishui Gate briefing smoke could not load scenario")
|
||||
scene.free()
|
||||
return
|
||||
var overview := scene._format_briefing_battlefield_overview_text()
|
||||
_check_contains(failures, "002 briefing map size", overview, "12칸 x 9칸")
|
||||
_check_contains(failures, "002 briefing enemy count", overview, "적세 8명")
|
||||
_check_contains(failures, "002 briefing village recovery", overview, "마을 4칸 +6")
|
||||
_check_contains(failures, "002 briefing castle recovery", overview, "성채 6칸 +8")
|
||||
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