Add Ye siege camp content

This commit is contained in:
2026-06-19 01:14:34 +09:00
parent dfdba012aa
commit cc2eecd7ff
5 changed files with 383 additions and 3 deletions

View File

@@ -171,7 +171,7 @@
}, },
"roster": { "roster": {
"max_units": 7, "max_units": 7,
"required_officers": ["cao_cao", "guo_jia"] "required_officers": ["cao_cao", "guo_jia", "zhang_he"]
}, },
"formation": { "formation": {
"cells": [[1, 3], [1, 4], [1, 5], [2, 2], [2, 3], [2, 4], [2, 5], [2, 6], [3, 2], [3, 3], [3, 4], [3, 5], [3, 6]] "cells": [[1, 3], [1, 4], [1, 5], [2, 2], [2, 3], [2, 4], [2, 5], [2, 6], [3, 2], [3, 3], [3, 4], [3, 5], [3, 6]]

View File

@@ -32,9 +32,116 @@
"Rumors spread through Ye that Yuan Tan has been abandoned, and some defenders hesitate before answering Yuan Shang's orders." "Rumors spread through Ye that Yuan Tan has been abandoned, and some defenders hesitate before answering Yuan Shang's orders."
] ]
} }
],
"camp_conversations": [
{
"id": "ye_siege_inner_gate_council",
"group": "topic",
"label": "Inner Gate Council",
"speaker": "Cao Cao",
"summary": "Set the assault plan for Ye's inner gate.",
"lines": [
{
"speaker": "Cao Cao",
"side": "left",
"text": "The outer wall is broken, but a city does not surrender until its inner gate believes it is alone."
},
{
"speaker": "Guo Jia",
"side": "right",
"text": "Then we make the gate answer two fears: our ladders outside, and Yuan distrust inside."
},
{
"speaker": "Zhang He",
"side": "right",
"text": "The palace road is narrow. If the first line yields, the second will have nowhere clean to stand."
}
]
},
{
"id": "ye_siege_zhang_he_streets",
"group": "officer",
"officer_id": "zhang_he",
"label": "Zhang He - Inner Streets",
"speaker": "Zhang He",
"summary": "Read Ye's inner streets before the gate assault.",
"lines": [
{
"speaker": "Zhang He",
"side": "right",
"text": "Yuan Shang trusts the broad road because he can see it from the palace. That is why every ambush will face it."
},
{
"speaker": "Cao Cao",
"side": "left",
"text": "Then we show him the cost of watching one road too closely."
}
]
},
{
"id": "ye_siege_ladder_rations",
"campaign_flags": { "pressed_ye_siege": true },
"group": "topic",
"label": "Ladder Team Rations",
"summary": "Claim light rations packed for the direct inner gate assault.",
"lines": [
{
"speaker": "Xiahou Dun",
"side": "right",
"text": "The ladder teams carry beans and rope. Nothing that slows a man with both hands full."
},
{
"speaker": "Cao Cao",
"side": "left",
"text": "Then let the walls learn how little baggage a determined army needs."
}
],
"effects": [
{
"type": "grant_item",
"item_id": "bean",
"count": 1,
"text": "The ladder team rations add a Bean to the field supplies."
}
]
},
{
"id": "ye_siege_defector_medicine",
"campaign_flags": { "split_yuan_heirs": true },
"group": "topic",
"label": "Defector Medicine",
"summary": "Claim medicine sent through frightened Yuan defectors.",
"lines": [
{
"speaker": "Guo Jia",
"side": "left",
"text": "The defectors sent a medicine chest with their first message. Fear is learning to be practical."
},
{
"speaker": "Cao Ren",
"side": "right",
"text": "The seals are clean. If the Yuan officers want our trust, this is a useful beginning."
}
],
"effects": [
{
"type": "grant_item",
"item_id": "panacea",
"count": 1,
"text": "The defector medicine adds a Panacea to the field supplies."
}
]
}
] ]
}, },
"shop": { "shop": {
"merchant": {
"name": "Ye Gate Sutler",
"lines": [
"The inner gate makes men spend faster than any market bell.",
"Buy now, my lord. Once the palace road opens, merchants and cowards will both look for side streets."
]
},
"items": [ "items": [
"bean", "bean",
"wine", "wine",
@@ -59,7 +166,7 @@
}, },
"roster": { "roster": {
"max_units": 7, "max_units": 7,
"required_officers": ["cao_cao", "guo_jia"] "required_officers": ["cao_cao", "guo_jia", "zhang_he"]
}, },
"formation": { "formation": {
"cells": [[1, 3], [1, 4], [1, 5], [2, 2], [2, 3], [2, 4], [2, 5], [2, 6], [3, 2], [3, 3], [3, 4], [3, 5], [3, 6]] "cells": [[1, 3], [1, 4], [1, 5], [2, 2], [2, 3], [2, 4], [2, 5], [2, 6], [3, 2], [3, 3], [3, 4], [3, 5], [3, 6]]

View File

@@ -59,7 +59,7 @@
}, },
"roster": { "roster": {
"max_units": 7, "max_units": 7,
"required_officers": ["cao_cao", "guo_jia"] "required_officers": ["cao_cao", "guo_jia", "zhang_he"]
}, },
"formation": { "formation": {
"cells": [[1, 3], [1, 4], [1, 5], [2, 2], [2, 3], [2, 4], [2, 5], [2, 6], [3, 2], [3, 3], [3, 4], [3, 5], [3, 6]] "cells": [[1, 3], [1, 4], [1, 5], [2, 2], [2, 3], [2, 4], [2, 5], [2, 6], [3, 2], [3, 3], [3, 4], [3, 5], [3, 6]]

View File

@@ -58,6 +58,10 @@ const YE_RAPID_CONVERSATION_ID := "ye_rapid_march_rations"
const YE_CROSSING_CONVERSATION_ID := "ye_crossing_medicine" const YE_CROSSING_CONVERSATION_ID := "ye_crossing_medicine"
const YE_SIEGE_SCENARIO_ID := "016_ye_siege" const YE_SIEGE_SCENARIO_ID := "016_ye_siege"
const YE_SIEGE_SCENARIO_PATH := "res://data/scenarios/016_ye_siege.json" const YE_SIEGE_SCENARIO_PATH := "res://data/scenarios/016_ye_siege.json"
const YE_SIEGE_PRESSED_CONVERSATION_ID := "ye_siege_ladder_rations"
const YE_SIEGE_SPLIT_CONVERSATION_ID := "ye_siege_defector_medicine"
const YE_SURRENDER_SCENARIO_ID := "017_ye_surrender"
const YE_SURRENDER_SCENARIO_PATH := "res://data/scenarios/017_ye_surrender.json"
const SAVE_PATH := "user://campaign_save.json" const SAVE_PATH := "user://campaign_save.json"
const MANUAL_SAVE_PATH := "user://campaign_manual_save.json" const MANUAL_SAVE_PATH := "user://campaign_manual_save.json"
@@ -82,6 +86,7 @@ func _init() -> void:
_check_wuchao_post_battle_choice_bridges_to_cangting(failures) _check_wuchao_post_battle_choice_bridges_to_cangting(failures)
_check_cangting_post_battle_choice_bridges_to_ye(failures) _check_cangting_post_battle_choice_bridges_to_ye(failures)
_check_ye_post_battle_choice_bridges_to_ye_siege(failures) _check_ye_post_battle_choice_bridges_to_ye_siege(failures)
_check_ye_siege_post_battle_choice_bridges_to_surrender(failures)
_check_manual_checkpoint_reverts_claim(failures) _check_manual_checkpoint_reverts_claim(failures)
_check_completed_replay_cannot_claim(failures) _check_completed_replay_cannot_claim(failures)
_check_conditional_camp_conversations(failures) _check_conditional_camp_conversations(failures)
@@ -89,6 +94,7 @@ func _init() -> void:
_check_wuchao_branch_camp_conversations(failures) _check_wuchao_branch_camp_conversations(failures)
_check_cangting_branch_camp_conversations(failures) _check_cangting_branch_camp_conversations(failures)
_check_ye_branch_camp_conversations(failures) _check_ye_branch_camp_conversations(failures)
_check_ye_siege_branch_camp_conversations(failures)
_check_talk_menu_closes_on_cancel_and_reload(failures) _check_talk_menu_closes_on_cancel_and_reload(failures)
if not _restore_user_file(SAVE_PATH, save_backup): if not _restore_user_file(SAVE_PATH, save_backup):
@@ -999,6 +1005,8 @@ func _check_ye_post_battle_choice_bridges_to_ye_siege(failures: Array[String]) -
"press_ye_siege", "press_ye_siege",
"pressed_ye_siege", "pressed_ye_siege",
"split_yuan_heirs", "split_yuan_heirs",
YE_SIEGE_PRESSED_CONVERSATION_ID,
YE_SIEGE_SPLIT_CONVERSATION_ID,
"war_drum", "war_drum",
"imperial_seal" "imperial_seal"
) )
@@ -1007,6 +1015,27 @@ func _check_ye_post_battle_choice_bridges_to_ye_siege(failures: Array[String]) -
"split_yuan_heirs", "split_yuan_heirs",
"split_yuan_heirs", "split_yuan_heirs",
"pressed_ye_siege", "pressed_ye_siege",
YE_SIEGE_SPLIT_CONVERSATION_ID,
YE_SIEGE_PRESSED_CONVERSATION_ID,
"imperial_seal",
"war_drum"
)
func _check_ye_siege_post_battle_choice_bridges_to_surrender(failures: Array[String]) -> void:
_check_ye_siege_choice_branch_to_surrender(
failures,
"force_ye_surrender",
"forced_ye_surrender",
"negotiated_yuan_defections",
"war_drum",
"imperial_seal"
)
_check_ye_siege_choice_branch_to_surrender(
failures,
"negotiate_yuan_defections",
"negotiated_yuan_defections",
"forced_ye_surrender",
"imperial_seal", "imperial_seal",
"war_drum" "war_drum"
) )
@@ -1126,6 +1155,8 @@ func _check_cangting_choice_branch_to_ye(
return return
if scene.state.get_unit("zhang_he_ch15").is_empty(): if scene.state.get_unit("zhang_he_ch15").is_empty():
failures.append("Cangting choice bridge %s should deploy Zhang He in Ye" % choice_id) failures.append("Cangting choice bridge %s should deploy Zhang He in Ye" % choice_id)
elif not scene.state.is_required_deployment("zhang_he_ch15"):
failures.append("Cangting choice bridge %s should require Zhang He in Ye" % choice_id)
if scene._camp_conversation_by_id(expected_conversation_id).is_empty(): if scene._camp_conversation_by_id(expected_conversation_id).is_empty():
failures.append("Cangting choice bridge %s should expose %s" % [choice_id, expected_conversation_id]) failures.append("Cangting choice bridge %s should expose %s" % [choice_id, expected_conversation_id])
if not scene._camp_conversation_by_id(hidden_conversation_id).is_empty(): if not scene._camp_conversation_by_id(hidden_conversation_id).is_empty():
@@ -1143,6 +1174,8 @@ func _check_ye_choice_branch_to_ye_siege(
choice_id: String, choice_id: String,
expected_flag: String, expected_flag: String,
cleared_flag: String, cleared_flag: String,
expected_conversation_id: String,
hidden_conversation_id: String,
expected_shop_item_id: String, expected_shop_item_id: String,
hidden_shop_item_id: String hidden_shop_item_id: String
) -> void: ) -> void:
@@ -1201,6 +1234,12 @@ func _check_ye_choice_branch_to_ye_siege(
return return
if scene.state.get_unit("zhang_he_ch16").is_empty(): if scene.state.get_unit("zhang_he_ch16").is_empty():
failures.append("Ye choice bridge %s should deploy Zhang He in Ye Siege" % choice_id) failures.append("Ye choice bridge %s should deploy Zhang He in Ye Siege" % choice_id)
elif not scene.state.is_required_deployment("zhang_he_ch16"):
failures.append("Ye choice bridge %s should require Zhang He in Ye Siege" % choice_id)
if scene._camp_conversation_by_id(expected_conversation_id).is_empty():
failures.append("Ye choice bridge %s should expose %s" % [choice_id, expected_conversation_id])
if not scene._camp_conversation_by_id(hidden_conversation_id).is_empty():
failures.append("Ye choice bridge %s should hide %s" % [choice_id, hidden_conversation_id])
var shop_items: Array = scene.state.get_shop_item_ids() var shop_items: Array = scene.state.get_shop_item_ids()
if not shop_items.has(expected_shop_item_id): if not shop_items.has(expected_shop_item_id):
failures.append("Ye choice bridge %s should expose shop item %s" % [choice_id, expected_shop_item_id]) failures.append("Ye choice bridge %s should expose shop item %s" % [choice_id, expected_shop_item_id])
@@ -1209,6 +1248,79 @@ func _check_ye_choice_branch_to_ye_siege(
scene.free() scene.free()
func _check_ye_siege_choice_branch_to_surrender(
failures: Array[String],
choice_id: String,
expected_flag: String,
cleared_flag: String,
expected_shop_item_id: String,
hidden_shop_item_id: String
) -> void:
var scene = _new_prebattle_scene_for(failures, "Ye Siege choice bridge %s" % choice_id, YE_SIEGE_SCENARIO_ID, YE_SIEGE_SCENARIO_PATH)
if scene == null:
return
if not scene.campaign_state.joined_officers.has("zhang_he"):
scene.campaign_state.joined_officers.append("zhang_he")
if not scene.state.load_battle(
YE_SIEGE_SCENARIO_PATH,
scene.campaign_state.get_roster_overrides(),
scene.campaign_state.get_inventory_snapshot(),
scene.campaign_state.get_flags_snapshot(),
scene.campaign_state.get_joined_officers_snapshot()
):
failures.append("Ye Siege choice bridge %s could not reload Ye Siege with Zhang He joined" % choice_id)
scene.free()
return
scene.state.battle_status = "victory"
var result: Dictionary = scene.campaign_state.apply_battle_result(scene.state)
if not bool(result.get("saved", false)):
failures.append("Ye Siege choice bridge %s should save 016 victory" % choice_id)
scene.free()
return
if not scene.campaign_state.get_joined_officers_snapshot().has("zhang_he"):
failures.append("Ye Siege choice bridge %s should keep Zhang He before Ye surrender" % choice_id)
if bool(result.get("choice_applied", true)):
failures.append("Ye Siege choice bridge %s should wait for a selected post-battle choice" % choice_id)
if scene.campaign_state.pending_post_battle_choice_scenario_id != YE_SIEGE_SCENARIO_ID:
failures.append("Ye Siege choice bridge %s should mark Ye Siege choice pending" % choice_id)
var choice := _find_choice_by_id(result.get("post_battle_choices", []), choice_id)
if choice.is_empty():
failures.append("Ye Siege choice bridge missing choice: %s" % choice_id)
scene.free()
return
if not scene.campaign_state.try_apply_post_battle_choice(choice, YE_SIEGE_SCENARIO_ID):
failures.append("Ye Siege choice bridge %s should save selected choice" % choice_id)
scene.free()
return
var flags: Dictionary = scene.campaign_state.get_flags_snapshot()
if flags.get(expected_flag, false) != true:
failures.append("Ye Siege choice bridge %s should set %s" % [choice_id, expected_flag])
if flags.get(cleared_flag, true) != false:
failures.append("Ye Siege choice bridge %s should clear %s" % [choice_id, cleared_flag])
if scene.campaign_state.current_scenario_id != YE_SURRENDER_SCENARIO_ID:
failures.append("Ye Siege choice bridge %s should advance to Ye Surrender, got %s" % [choice_id, scene.campaign_state.current_scenario_id])
if not scene.state.load_battle(
YE_SURRENDER_SCENARIO_PATH,
scene.campaign_state.get_roster_overrides(),
scene.campaign_state.get_inventory_snapshot(),
flags,
scene.campaign_state.get_joined_officers_snapshot()
):
failures.append("Ye Siege choice bridge %s could not load Ye Surrender" % choice_id)
scene.free()
return
if scene.state.get_unit("zhang_he_ch17").is_empty():
failures.append("Ye Siege choice bridge %s should deploy Zhang He in Ye Surrender" % choice_id)
elif not scene.state.is_required_deployment("zhang_he_ch17"):
failures.append("Ye Siege choice bridge %s should require Zhang He in Ye Surrender" % choice_id)
var shop_items: Array = scene.state.get_shop_item_ids()
if not shop_items.has(expected_shop_item_id):
failures.append("Ye Siege choice bridge %s should expose shop item %s" % [choice_id, expected_shop_item_id])
if shop_items.has(hidden_shop_item_id):
failures.append("Ye Siege choice bridge %s should hide shop item %s" % [choice_id, hidden_shop_item_id])
scene.free()
func _find_choice_by_id(choices, choice_id: String) -> Dictionary: func _find_choice_by_id(choices, choice_id: String) -> Dictionary:
if typeof(choices) != TYPE_ARRAY: if typeof(choices) != TYPE_ARRAY:
return {} return {}
@@ -1638,6 +1750,88 @@ func _check_ye_branch_camp_conversations(failures: Array[String]) -> void:
crossing_scene.free() crossing_scene.free()
func _check_ye_siege_branch_camp_conversations(failures: Array[String]) -> void:
var base_scene = _new_prebattle_scene_for(failures, "Ye Siege base camp", YE_SIEGE_SCENARIO_ID, YE_SIEGE_SCENARIO_PATH)
if base_scene != null:
if base_scene._camp_conversation_by_id("ye_siege_inner_gate_council").is_empty():
failures.append("Ye Siege should expose the inner gate council conversation")
if base_scene._camp_conversation_by_id("ye_siege_zhang_he_streets").is_empty():
failures.append("Ye Siege should expose Zhang He's inner streets conversation")
if not base_scene._camp_conversation_by_id(YE_SIEGE_PRESSED_CONVERSATION_ID).is_empty():
failures.append("Ye Siege ladder rations should be hidden without pressed siege flag")
if not base_scene._camp_conversation_by_id(YE_SIEGE_SPLIT_CONVERSATION_ID).is_empty():
failures.append("Ye Siege defector medicine should be hidden without split heirs flag")
var merchant: Dictionary = base_scene.state.get_shop_merchant()
if str(merchant.get("name", "")) != "Ye Gate Sutler":
failures.append("Ye Siege shop merchant name should be present")
var merchant_lines: Array = merchant.get("lines", [])
if merchant_lines.size() < 2:
failures.append("Ye Siege shop merchant should expose flavor lines")
if base_scene._format_talk_status_text(base_scene._camp_conversation_entries()) != "Camp conversations | 2 topics":
failures.append("Ye Siege base talk status should summarize two non-supply topics")
base_scene.free()
var pressed_scene = _new_prebattle_scene_for(
failures,
"Ye Siege pressed camp",
YE_SIEGE_SCENARIO_ID,
YE_SIEGE_SCENARIO_PATH,
{"pressed_ye_siege": true}
)
if pressed_scene != null:
var ladder_rations: Dictionary = pressed_scene._camp_conversation_by_id(YE_SIEGE_PRESSED_CONVERSATION_ID)
if ladder_rations.is_empty():
failures.append("pressed Ye siege flag should expose ladder rations")
if not pressed_scene._camp_conversation_by_id(YE_SIEGE_SPLIT_CONVERSATION_ID).is_empty():
failures.append("pressed Ye siege flag should not expose defector medicine")
if not ladder_rations.is_empty():
if pressed_scene._format_talk_status_text(pressed_scene._camp_conversation_entries()) != "Camp conversations | 3 topics | 1 supplies ready":
failures.append("Ye Siege pressed talk status should show one ready supply")
if not pressed_scene._format_camp_conversation_button_text(ladder_rations).contains("Supply Bean"):
failures.append("Ye Siege ladder rations button should show Bean supply")
var before_bean := int(pressed_scene.campaign_state.get_inventory_snapshot().get("bean", 0))
pressed_scene._apply_camp_conversation_effects(ladder_rations)
if int(pressed_scene.campaign_state.get_inventory_snapshot().get("bean", 0)) != before_bean + 1:
failures.append("Ye Siege ladder rations should add Bean to campaign inventory")
if int(pressed_scene.state.get_inventory_snapshot().get("bean", 0)) != before_bean + 1:
failures.append("Ye Siege ladder rations should refresh battle Bean inventory")
if not pressed_scene.campaign_state.has_claimed_camp_conversation_effects(YE_SIEGE_SCENARIO_ID, YE_SIEGE_PRESSED_CONVERSATION_ID):
failures.append("Ye Siege ladder rations claim should be saved")
if pressed_scene._format_talk_status_text(pressed_scene._camp_conversation_entries()) != "Camp conversations | 3 topics | 1 claimed":
failures.append("Ye Siege pressed talk status should show claimed supply after claim")
pressed_scene.free()
var split_scene = _new_prebattle_scene_for(
failures,
"Ye Siege split heirs camp",
YE_SIEGE_SCENARIO_ID,
YE_SIEGE_SCENARIO_PATH,
{"split_yuan_heirs": true}
)
if split_scene != null:
var defector_medicine: Dictionary = split_scene._camp_conversation_by_id(YE_SIEGE_SPLIT_CONVERSATION_ID)
if defector_medicine.is_empty():
failures.append("split Yuan heirs flag should expose Ye Siege defector medicine")
if not split_scene._camp_conversation_by_id(YE_SIEGE_PRESSED_CONVERSATION_ID).is_empty():
failures.append("split Yuan heirs flag should not expose ladder rations")
if not defector_medicine.is_empty():
if split_scene._format_talk_status_text(split_scene._camp_conversation_entries()) != "Camp conversations | 3 topics | 1 supplies ready":
failures.append("Ye Siege split heirs talk status should show one ready supply")
if not split_scene._format_camp_conversation_button_text(defector_medicine).contains("Supply Panacea"):
failures.append("Ye Siege defector medicine button should show Panacea supply")
var before_panacea := int(split_scene.campaign_state.get_inventory_snapshot().get("panacea", 0))
split_scene._apply_camp_conversation_effects(defector_medicine)
if int(split_scene.campaign_state.get_inventory_snapshot().get("panacea", 0)) != before_panacea + 1:
failures.append("Ye Siege defector medicine should add Panacea to campaign inventory")
if int(split_scene.state.get_inventory_snapshot().get("panacea", 0)) != before_panacea + 1:
failures.append("Ye Siege defector medicine should refresh battle Panacea inventory")
if not split_scene.campaign_state.has_claimed_camp_conversation_effects(YE_SIEGE_SCENARIO_ID, YE_SIEGE_SPLIT_CONVERSATION_ID):
failures.append("Ye Siege defector medicine claim should be saved")
if split_scene._format_talk_status_text(split_scene._camp_conversation_entries()) != "Camp conversations | 3 topics | 1 claimed":
failures.append("Ye Siege split heirs talk status should show claimed supply after claim")
split_scene.free()
func _check_talk_menu_closes_on_cancel_and_reload(failures: Array[String]) -> void: func _check_talk_menu_closes_on_cancel_and_reload(failures: Array[String]) -> void:
var scene = _new_prebattle_scene(failures, "talk menu close guards") var scene = _new_prebattle_scene(failures, "talk menu close guards")
if scene == null: if scene == null:

View File

@@ -870,6 +870,85 @@ func _check_battle_visual_data(failures: Array[String]) -> void:
).is_empty(): ).is_empty():
failures.append("015 old Cangting flags should not expose crossing medicine") failures.append("015 old Cangting flags should not expose crossing medicine")
var ye_siege_state = BattleStateScript.new()
if not ye_siege_state.load_battle("res://data/scenarios/016_ye_siege.json"):
failures.append("could not load Ye Siege camp data")
else:
_check_shop_items_unique(failures, ye_siege_state, "016 base")
var ye_siege_conversations: Array = ye_siege_state.get_briefing().get("camp_conversations", [])
if ye_siege_conversations.size() != 2:
failures.append("016 base briefing should expose exactly two camp conversations")
else:
_check_camp_conversation(failures, ye_siege_conversations[0], "ye_siege_inner_gate_council", "topic", "")
_check_camp_conversation(failures, ye_siege_conversations[1], "ye_siege_zhang_he_streets", "officer", "zhang_he")
var ye_siege_merchant := ye_siege_state.get_shop_merchant()
if str(ye_siege_merchant.get("name", "")) != "Ye Gate Sutler":
failures.append("016 shop should expose Ye Gate merchant name")
if (ye_siege_merchant.get("lines", []) as Array).size() < 2:
failures.append("016 shop should expose merchant flavor lines")
_check_shop_item_visibility(failures, ye_siege_state, "war_drum", false, "016 base")
_check_shop_item_visibility(failures, ye_siege_state, "imperial_seal", false, "016 base")
_check_shop_item_visibility(failures, ye_siege_state, "iron_armor", true, "016 base")
var ye_siege_pressed_state = BattleStateScript.new()
if not ye_siege_pressed_state.load_battle("res://data/scenarios/016_ye_siege.json", {}, {}, {"pressed_ye_siege": true}):
failures.append("could not load Ye Siege pressed camp data")
else:
_check_shop_items_unique(failures, ye_siege_pressed_state, "016 pressed Ye siege")
var ladder_rations: Dictionary = _find_camp_conversation(
ye_siege_pressed_state.get_briefing().get("camp_conversations", []),
"ye_siege_ladder_rations"
)
if ladder_rations.is_empty():
failures.append("016 pressed Ye siege flag should expose ladder rations")
else:
_check_camp_conversation_effect(failures, ladder_rations, "bean", 1)
if not _find_camp_conversation(
ye_siege_pressed_state.get_briefing().get("camp_conversations", []),
"ye_siege_defector_medicine"
).is_empty():
failures.append("016 pressed Ye siege flag should not expose defector medicine")
_check_shop_item_visibility(failures, ye_siege_pressed_state, "war_drum", true, "016 pressed Ye siege")
_check_shop_item_visibility(failures, ye_siege_pressed_state, "imperial_seal", false, "016 pressed Ye siege")
var ye_siege_split_state = BattleStateScript.new()
if not ye_siege_split_state.load_battle("res://data/scenarios/016_ye_siege.json", {}, {}, {"split_yuan_heirs": true}):
failures.append("could not load Ye Siege split heirs camp data")
else:
_check_shop_items_unique(failures, ye_siege_split_state, "016 split Yuan heirs")
var defector_medicine: Dictionary = _find_camp_conversation(
ye_siege_split_state.get_briefing().get("camp_conversations", []),
"ye_siege_defector_medicine"
)
if defector_medicine.is_empty():
failures.append("016 split Yuan heirs flag should expose defector medicine")
else:
_check_camp_conversation_effect(failures, defector_medicine, "panacea", 1)
if not _find_camp_conversation(
ye_siege_split_state.get_briefing().get("camp_conversations", []),
"ye_siege_ladder_rations"
).is_empty():
failures.append("016 split Yuan heirs flag should not expose ladder rations")
_check_shop_item_visibility(failures, ye_siege_split_state, "war_drum", false, "016 split Yuan heirs")
_check_shop_item_visibility(failures, ye_siege_split_state, "imperial_seal", true, "016 split Yuan heirs")
var ye_siege_old_flags_state = BattleStateScript.new()
if not ye_siege_old_flags_state.load_battle("res://data/scenarios/016_ye_siege.json", {}, {}, {"advanced_to_ye": true, "secured_hebei_crossings": true}):
failures.append("could not load Ye Siege old Ye flag camp data")
else:
_check_shop_item_visibility(failures, ye_siege_old_flags_state, "war_drum", false, "016 old Ye flags")
_check_shop_item_visibility(failures, ye_siege_old_flags_state, "imperial_seal", false, "016 old Ye flags")
if not _find_camp_conversation(
ye_siege_old_flags_state.get_briefing().get("camp_conversations", []),
"ye_siege_ladder_rations"
).is_empty():
failures.append("016 old Ye flags should not expose ladder rations")
if not _find_camp_conversation(
ye_siege_old_flags_state.get_briefing().get("camp_conversations", []),
"ye_siege_defector_medicine"
).is_empty():
failures.append("016 old Ye flags should not expose defector medicine")
for item_id in ["bronze_sword", "training_spear", "short_bow", "hand_axe", "iron_armor", "panacea"]: for item_id in ["bronze_sword", "training_spear", "short_bow", "hand_axe", "iron_armor", "panacea"]:
var item := state.get_item_def(item_id) var item := state.get_item_def(item_id)
if item.is_empty(): if item.is_empty():