Improve Puyang raid battle pacing
This commit is contained in:
@@ -2,14 +2,27 @@
|
||||
"id": "005_puyang_raid",
|
||||
"name": "복양 기습전",
|
||||
"objectives": {
|
||||
"victory": "여포군 전위영을 격파하라.",
|
||||
"defeat": "조조가 퇴각하거나 제11턴에 이르면 패한다."
|
||||
"victory": "복양 전위영을 장악하고 여포군 포위망을 돌파하라.",
|
||||
"defeat": "조조가 퇴각하거나 제18턴이 시작되면 패한다."
|
||||
},
|
||||
"conditions": {
|
||||
"victory": { "type": "all_units_defeated", "team": "enemy", "after_event": "turn_3_lu_bu_arrives" },
|
||||
"victory": {
|
||||
"type": "all",
|
||||
"conditions": [
|
||||
{ "type": "all_units_defeated", "team": "enemy", "after_event": "turn_9_lu_bu_encirclement" },
|
||||
{
|
||||
"type": "unit_reaches_tile",
|
||||
"label": "군영 장악",
|
||||
"team": "player",
|
||||
"unit_ids": ["cao_cao_ch5", "dian_wei_ch5", "xiahou_dun_ch5", "xiahou_yuan_ch5", "cao_ren_ch5"],
|
||||
"officer_ids": ["cao_cao", "dian_wei", "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": 11, "team": "player" }
|
||||
{ "type": "turn_reached", "turn": 18, "team": "player" }
|
||||
]
|
||||
},
|
||||
"briefing": {
|
||||
@@ -18,7 +31,8 @@
|
||||
"lines": [
|
||||
"연주가 흔들리자 여포는 복양을 움켜쥐고 기세를 돋우었다.",
|
||||
"조조는 밤 그늘을 타고 전위영을 찔러, 적 기병이 말고삐를 모으기 전에 그 앞줄을 꺾으려 한다.",
|
||||
"전위가 새로 군문에 들어와 주공의 깃발 곁을 지킨다."
|
||||
"전위가 새로 군문에 들어와 주공의 깃발 곁을 지킨다.",
|
||||
"복양 군영 안쪽을 장악하고 여포의 기병 포위망을 버텨야 새벽길이 열린다."
|
||||
],
|
||||
"camp_conversations": [
|
||||
{
|
||||
@@ -124,11 +138,11 @@
|
||||
"GGGGGHHGGGGGGG",
|
||||
"GGGFFHHGGGFFGG",
|
||||
"GGGFFRRRRRFFGG",
|
||||
"GGGGGRGGGRGGGG",
|
||||
"GGGGGRGGGRCCGG",
|
||||
"RRRRRRRRRRRRRR",
|
||||
"GGGGGRGGGRGGGG",
|
||||
"GGFFFRRRRRFFGG",
|
||||
"GGFFFHHGGGFFGG",
|
||||
"GGGGGRGGGRCCGG",
|
||||
"GGTTFRRRRRFFGG",
|
||||
"GGTTFHHGGGFFGG",
|
||||
"GGGGGHHGGGWWGG",
|
||||
"GGGGGGGGGGWWGG"
|
||||
]
|
||||
@@ -216,6 +230,36 @@
|
||||
"pos": [10, 2],
|
||||
"base": { "hp": 30, "atk": 9, "def": 5 },
|
||||
"equipment": { "weapon": "short_bow" }
|
||||
},
|
||||
{
|
||||
"unit_id": "puyang_camp_sentinel",
|
||||
"name": "복양 군영병",
|
||||
"class_id": "infantry",
|
||||
"team": "enemy",
|
||||
"level": 5,
|
||||
"pos": [8, 3],
|
||||
"base": { "hp": 40, "atk": 11, "def": 8 },
|
||||
"equipment": { "weapon": "training_spear" }
|
||||
},
|
||||
{
|
||||
"unit_id": "puyang_road_guard",
|
||||
"name": "복양 창병",
|
||||
"class_id": "infantry",
|
||||
"team": "enemy",
|
||||
"level": 5,
|
||||
"pos": [8, 5],
|
||||
"base": { "hp": 38, "atk": 11, "def": 8 },
|
||||
"equipment": { "weapon": "training_spear" }
|
||||
},
|
||||
{
|
||||
"unit_id": "puyang_watch_archer",
|
||||
"name": "복양 망루궁병",
|
||||
"class_id": "archer",
|
||||
"team": "enemy",
|
||||
"level": 5,
|
||||
"pos": [7, 2],
|
||||
"base": { "hp": 30, "atk": 10, "def": 5 },
|
||||
"equipment": { "weapon": "short_bow" }
|
||||
}
|
||||
],
|
||||
"events": [
|
||||
@@ -272,8 +316,8 @@
|
||||
},
|
||||
{
|
||||
"type": "set_objective",
|
||||
"victory": "장료의 전위와 달려든 기병을 격파하라.",
|
||||
"defeat": "조조가 퇴각하거나 제11턴에 이르면 패한다."
|
||||
"victory": "전위영을 장악하고 달려든 여포 기병을 격파하라.",
|
||||
"defeat": "조조가 퇴각하거나 제18턴이 시작되면 패한다."
|
||||
},
|
||||
{
|
||||
"type": "spawn_deployments",
|
||||
@@ -312,6 +356,124 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "turn_6_zhang_liao_closes",
|
||||
"once": true,
|
||||
"when": { "type": "turn_start", "team": "enemy", "turn": 6 },
|
||||
"actions": [
|
||||
{ "type": "log", "text": "장료와 고순의 후속대가 야습대의 퇴로를 좁힌다." },
|
||||
{
|
||||
"type": "dialogue",
|
||||
"lines": [
|
||||
{ "speaker": "Zhang Liao", "display_speaker": "장료", "text": "조조가 영채 안으로 깊이 들어왔다. 퇴로를 조이고 군기를 끊어라." },
|
||||
{ "speaker": "Xiahou Dun", "display_speaker": "하후돈", "text": "뒤가 좁아졌습니다. 그렇다면 앞을 더 세게 뚫겠습니다." }
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "spawn_deployments",
|
||||
"deployments": [
|
||||
{
|
||||
"unit_id": "zhang_liao_pursuit_rider",
|
||||
"name": "장료 추격기병",
|
||||
"class_id": "cavalry",
|
||||
"team": "enemy",
|
||||
"level": 5,
|
||||
"pos": [5, 1],
|
||||
"base": { "hp": 40, "atk": 12, "def": 7, "agi": 10 },
|
||||
"equipment": { "weapon": "training_spear" }
|
||||
},
|
||||
{
|
||||
"unit_id": "gao_shun_camp_guard",
|
||||
"name": "고순 군영병",
|
||||
"class_id": "infantry",
|
||||
"team": "enemy",
|
||||
"level": 5,
|
||||
"pos": [5, 7],
|
||||
"base": { "hp": 40, "atk": 11, "def": 9 },
|
||||
"equipment": { "weapon": "training_spear" }
|
||||
},
|
||||
{
|
||||
"unit_id": "puyang_rear_archer",
|
||||
"name": "후방 궁병",
|
||||
"class_id": "archer",
|
||||
"team": "enemy",
|
||||
"level": 5,
|
||||
"pos": [7, 8],
|
||||
"base": { "hp": 30, "atk": 10, "def": 5 },
|
||||
"equipment": { "weapon": "short_bow" }
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "set_ai_target_priority",
|
||||
"unit_id": "xiahou_dun_ch5",
|
||||
"priority": 8,
|
||||
"text": "장료의 후속대가 하후돈의 돌파선을 노린다."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "turn_9_lu_bu_encirclement",
|
||||
"once": true,
|
||||
"when": { "type": "turn_start", "team": "enemy", "turn": 9 },
|
||||
"actions": [
|
||||
{ "type": "log", "text": "여포의 본대가 전위영을 에워싸며 마지막 포위망을 친다." },
|
||||
{
|
||||
"type": "set_objective",
|
||||
"victory": "여포군 포위망을 격파하고 복양 군영을 장악하라.",
|
||||
"defeat": "조조가 퇴각하거나 제18턴이 시작되면 패한다."
|
||||
},
|
||||
{
|
||||
"type": "dialogue",
|
||||
"lines": [
|
||||
{ "speaker": "Lu Bu", "display_speaker": "여포", "text": "밤에 숨어 들어온 군대가 새벽까지 버틸 줄 아느냐. 길을 막고 모두 베어라." },
|
||||
{ "speaker": "Dian Wei", "display_speaker": "전위", "text": "주공, 저 소리는 제가 맡겠습니다. 군영 깃발만 빼앗으십시오." },
|
||||
{ "speaker": "Cao Cao", "display_speaker": "조조", "text": "좋다. 군영을 장악하고 포위망의 이빨을 부러뜨려라." }
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "spawn_deployments",
|
||||
"deployments": [
|
||||
{
|
||||
"unit_id": "lu_bu_encirclement_rider",
|
||||
"name": "포위 기병",
|
||||
"class_id": "elite_cavalry",
|
||||
"team": "enemy",
|
||||
"level": 6,
|
||||
"pos": [13, 2],
|
||||
"base": { "hp": 50, "atk": 14, "def": 8, "agi": 12 },
|
||||
"equipment": { "weapon": "training_spear" }
|
||||
},
|
||||
{
|
||||
"unit_id": "lu_bu_encirclement_guard",
|
||||
"name": "포위 창병",
|
||||
"class_id": "infantry",
|
||||
"team": "enemy",
|
||||
"level": 5,
|
||||
"pos": [13, 6],
|
||||
"base": { "hp": 42, "atk": 12, "def": 9 },
|
||||
"equipment": { "weapon": "training_spear" }
|
||||
},
|
||||
{
|
||||
"unit_id": "lu_bu_encirclement_archer",
|
||||
"name": "포위 궁병",
|
||||
"class_id": "archer",
|
||||
"team": "enemy",
|
||||
"level": 5,
|
||||
"pos": [12, 8],
|
||||
"base": { "hp": 32, "atk": 11, "def": 5 },
|
||||
"equipment": { "weapon": "short_bow" }
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "set_ai_target_priority",
|
||||
"unit_id": "cao_cao_ch5",
|
||||
"priority": 12,
|
||||
"text": "여포의 포위망이 조조의 군기를 노린다."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "turn_5_pressure",
|
||||
"once": true,
|
||||
|
||||
@@ -79,6 +79,18 @@ func _init() -> void:
|
||||
_progress_text("res://data/scenarios/004_qingzhou_campaign.json", false),
|
||||
"촌락 보호"
|
||||
)
|
||||
_check_contains(
|
||||
failures,
|
||||
"005 gated victory progress",
|
||||
_progress_text("res://data/scenarios/005_puyang_raid.json", false),
|
||||
"제9군령에 전공 갱신"
|
||||
)
|
||||
_check_contains(
|
||||
failures,
|
||||
"005 camp capture progress",
|
||||
_progress_text("res://data/scenarios/005_puyang_raid.json", false),
|
||||
"군영 장악"
|
||||
)
|
||||
_check_contains(
|
||||
failures,
|
||||
"007 destination progress",
|
||||
@@ -104,6 +116,7 @@ func _init() -> void:
|
||||
_check_sishui_gate_extended_pressure(failures)
|
||||
_check_xingyang_ambush_extended_pressure(failures)
|
||||
_check_qingzhou_campaign_extended_pressure(failures)
|
||||
_check_puyang_raid_extended_pressure(failures)
|
||||
_check_objective_update(failures)
|
||||
_check_objective_notice(failures)
|
||||
_check_terrain_recovery(failures)
|
||||
@@ -501,6 +514,65 @@ func _check_qingzhou_campaign_extended_pressure(failures: Array[String]) -> void
|
||||
scene.free()
|
||||
|
||||
|
||||
func _check_puyang_raid_extended_pressure(failures: Array[String]) -> void:
|
||||
var state = BattleStateScript.new()
|
||||
if not state.load_battle("res://data/scenarios/005_puyang_raid.json"):
|
||||
failures.append("Puyang Raid pressure smoke could not load scenario")
|
||||
return
|
||||
if state.get_turn_limit() != 17:
|
||||
failures.append("Puyang Raid 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("Puyang Raid should start with 8 enemies, got %d" % state.get_living_units(BattleStateScript.TEAM_ENEMY).size())
|
||||
if state._condition_gate_open({"after_event": "turn_9_lu_bu_encirclement"}):
|
||||
failures.append("Puyang Raid final defeat-all condition should be gated until turn 9 encirclement")
|
||||
var marker_cells := state.get_objective_cells()
|
||||
for camp_cell in [Vector2i(10, 3), Vector2i(11, 3), Vector2i(10, 5), Vector2i(11, 5)]:
|
||||
if not marker_cells.has(camp_cell):
|
||||
failures.append("Puyang Raid should mark camp capture cell %s: %s" % [str(camp_cell), str(marker_cells)])
|
||||
if state.get_objective_cell_label(camp_cell) != "군영 장악":
|
||||
failures.append("Puyang Raid camp marker should expose label at %s" % str(camp_cell))
|
||||
var recovery_summaries := state.get_recovery_terrain_summaries()
|
||||
var has_camp_recovery := false
|
||||
var has_supply_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)) == 8:
|
||||
has_camp_recovery = true
|
||||
if str(summary.get("name", "")) == "마을" and int(summary.get("count", 0)) == 4 and int(summary.get("heal", 0)) == 6:
|
||||
has_supply_recovery = true
|
||||
if not has_camp_recovery:
|
||||
failures.append("Puyang Raid should expose camp recovery terrain: %s" % str(recovery_summaries))
|
||||
if not has_supply_recovery:
|
||||
failures.append("Puyang Raid should expose supply 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_lu_bu_encirclement"}):
|
||||
failures.append("Puyang Raid final gate should open after turn 9 encirclement event")
|
||||
if state.get_living_units(BattleStateScript.TEAM_ENEMY).size() != 17:
|
||||
failures.append("Puyang Raid should field 17 enemies after encirclement, 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("Puyang Raid should not end before camp capture, got %s" % str(state.battle_status))
|
||||
var cao_cao: Dictionary = state.get_unit("cao_cao_ch5")
|
||||
cao_cao["pos"] = Vector2i(10, 3)
|
||||
state._check_battle_status()
|
||||
if str(state.battle_status) != BattleStateScript.STATUS_VICTORY:
|
||||
failures.append("Puyang Raid should end after encirclement falls and camp is captured, got %s" % str(state.battle_status))
|
||||
var scene = BattleSceneScript.new()
|
||||
if not scene.state.load_battle("res://data/scenarios/005_puyang_raid.json"):
|
||||
failures.append("Puyang Raid briefing smoke could not load scenario")
|
||||
scene.free()
|
||||
return
|
||||
var overview := scene._format_briefing_battlefield_overview_text()
|
||||
_check_contains(failures, "005 briefing map size", overview, "14칸 x 10칸")
|
||||
_check_contains(failures, "005 briefing enemy count", overview, "적세 8명")
|
||||
_check_contains(failures, "005 briefing village recovery", overview, "마을 4칸 +6")
|
||||
_check_contains(failures, "005 briefing camp recovery", overview, "성채 4칸 +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