Add Cangting camp content

This commit is contained in:
2026-06-19 00:56:55 +09:00
parent febba2baec
commit 258cdeb60c
3 changed files with 442 additions and 0 deletions

View File

@@ -32,9 +32,116 @@
"Captured stores from Wuchao keep the pursuit fed, letting Cao Cao press north without stretching the supply train." "Captured stores from Wuchao keep the pursuit fed, letting Cao Cao press north without stretching the supply train."
] ]
} }
],
"camp_conversations": [
{
"id": "cangting_pursuit_council",
"group": "topic",
"label": "Pursuit Council",
"speaker": "Cao Cao",
"summary": "Set the pace for striking Yuan Shao's retreating rear guard.",
"lines": [
{
"speaker": "Cao Cao",
"side": "left",
"text": "Wuchao burned their grain. Cangting must burn the belief that retreat can become order."
},
{
"speaker": "Xiahou Dun",
"side": "right",
"text": "Then we do not chase noise. We strike the soldiers still listening to commands."
},
{
"speaker": "Guo Jia",
"side": "right",
"text": "A broken army still has a spine if Zhang He holds the rear. Break that, and the rest becomes road dust."
}
]
},
{
"id": "cangting_guo_jia_rearguard",
"group": "officer",
"officer_id": "guo_jia",
"label": "Guo Jia - Rear Guard",
"speaker": "Guo Jia",
"summary": "Read Zhang He's discipline before the pursuit closes.",
"lines": [
{
"speaker": "Guo Jia",
"side": "right",
"text": "Most of Yuan Shao's men are running from hunger. Zhang He is running toward duty."
},
{
"speaker": "Cao Cao",
"side": "left",
"text": "A man who can still choose duty in a rout is worth watching."
}
]
},
{
"id": "cangting_fast_pursuit_beans",
"campaign_flags": { "pressed_yuan_rout": true },
"group": "topic",
"label": "Fast Pursuit Rations",
"summary": "Claim the light rations packed for a forced pursuit.",
"lines": [
{
"speaker": "Xiahou Yuan",
"side": "right",
"text": "The riders packed beans instead of baggage. They can eat in the saddle and keep Yuan Shao looking over his shoulder."
},
{
"speaker": "Cao Cao",
"side": "left",
"text": "Good. A pursuit that pauses to cook has already become a parade."
}
],
"effects": [
{
"type": "grant_item",
"item_id": "bean",
"count": 1,
"text": "The fast pursuit rations add a Bean to the field supplies."
}
]
},
{
"id": "cangting_wuchao_store_medicine",
"campaign_flags": { "secured_wuchao_stores": true },
"group": "topic",
"label": "Wuchao Store Medicine",
"summary": "Claim medicine sorted from the captured Wuchao stores.",
"lines": [
{
"speaker": "Cao Ren",
"side": "right",
"text": "The captured Wuchao stores held more than grain. The physicians sorted clean medicine before the march resumed."
},
{
"speaker": "Guo Jia",
"side": "left",
"text": "Then the stores have bought us speed twice: once by starving Yuan Shao, once by keeping our wounded moving."
}
],
"effects": [
{
"type": "grant_item",
"item_id": "panacea",
"count": 1,
"text": "The Wuchao store medicine adds a Panacea to the field supplies."
}
]
}
] ]
}, },
"shop": { "shop": {
"merchant": {
"name": "Cangting Road Sutler",
"lines": [
"The road north is full of abandoned Yuan packs. I sell only what can survive a pursuit.",
"Buy before the rear guard rallies. Once Zhang He steadies them, even a wine jar will need armor."
]
},
"items": [ "items": [
"bean", "bean",
"wine", "wine",

View File

@@ -48,6 +48,12 @@ const GUANDU_SECURED_CONVERSATION_ID := "guandu_secured_line_medicine"
const GUANDU_SCOUTED_CONVERSATION_ID := "guandu_wuchao_scout_wine" const GUANDU_SCOUTED_CONVERSATION_ID := "guandu_wuchao_scout_wine"
const WUCHAO_SCENARIO_ID := "013_wuchao_raid" const WUCHAO_SCENARIO_ID := "013_wuchao_raid"
const WUCHAO_SCENARIO_PATH := "res://data/scenarios/013_wuchao_raid.json" const WUCHAO_SCENARIO_PATH := "res://data/scenarios/013_wuchao_raid.json"
const CANGTING_SCENARIO_ID := "014_cangting_pursuit"
const CANGTING_SCENARIO_PATH := "res://data/scenarios/014_cangting_pursuit.json"
const CANGTING_PRESSED_CONVERSATION_ID := "cangting_fast_pursuit_beans"
const CANGTING_STORES_CONVERSATION_ID := "cangting_wuchao_store_medicine"
const YE_SCENARIO_ID := "015_ye_campaign"
const YE_SCENARIO_PATH := "res://data/scenarios/015_ye_campaign.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"
@@ -69,11 +75,14 @@ func _init() -> void:
_check_yan_ford_branch_camp_conversations(failures) _check_yan_ford_branch_camp_conversations(failures)
_check_guandu_branch_camp_conversations(failures) _check_guandu_branch_camp_conversations(failures)
_check_guandu_post_battle_choice_bridges_to_wuchao(failures) _check_guandu_post_battle_choice_bridges_to_wuchao(failures)
_check_wuchao_post_battle_choice_bridges_to_cangting(failures)
_check_cangting_post_battle_choice_bridges_to_ye(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)
_check_qingzhou_branch_camp_conversations(failures) _check_qingzhou_branch_camp_conversations(failures)
_check_wuchao_branch_camp_conversations(failures) _check_wuchao_branch_camp_conversations(failures)
_check_cangting_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):
@@ -932,6 +941,168 @@ func _check_guandu_choice_branch_to_wuchao(
scene.free() scene.free()
func _check_wuchao_post_battle_choice_bridges_to_cangting(failures: Array[String]) -> void:
_check_wuchao_choice_branch_to_cangting(
failures,
"press_yuan_rout",
"pressed_yuan_rout",
"secured_wuchao_stores",
CANGTING_PRESSED_CONVERSATION_ID,
CANGTING_STORES_CONVERSATION_ID,
"war_drum",
"imperial_seal"
)
_check_wuchao_choice_branch_to_cangting(
failures,
"secure_wuchao_stores",
"secured_wuchao_stores",
"pressed_yuan_rout",
CANGTING_STORES_CONVERSATION_ID,
CANGTING_PRESSED_CONVERSATION_ID,
"imperial_seal",
"war_drum"
)
func _check_cangting_post_battle_choice_bridges_to_ye(failures: Array[String]) -> void:
_check_cangting_choice_branch_to_ye(
failures,
"advance_to_ye",
"advanced_to_ye",
"secured_hebei_crossings",
"war_drum",
"imperial_seal"
)
_check_cangting_choice_branch_to_ye(
failures,
"secure_hebei_crossings",
"secured_hebei_crossings",
"advanced_to_ye",
"imperial_seal",
"war_drum"
)
func _check_wuchao_choice_branch_to_cangting(
failures: Array[String],
choice_id: String,
expected_flag: String,
cleared_flag: String,
expected_conversation_id: String,
hidden_conversation_id: String,
expected_shop_item_id: String,
hidden_shop_item_id: String
) -> void:
var scene = _new_prebattle_scene_for(failures, "Wuchao choice bridge %s" % choice_id, WUCHAO_SCENARIO_ID, WUCHAO_SCENARIO_PATH)
if scene == null:
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("Wuchao choice bridge %s should save 013 victory" % choice_id)
scene.free()
return
if bool(result.get("choice_applied", true)):
failures.append("Wuchao choice bridge %s should wait for a selected post-battle choice" % choice_id)
if scene.campaign_state.pending_post_battle_choice_scenario_id != WUCHAO_SCENARIO_ID:
failures.append("Wuchao choice bridge %s should mark Wuchao choice pending" % choice_id)
var choice := _find_choice_by_id(result.get("post_battle_choices", []), choice_id)
if choice.is_empty():
failures.append("Wuchao choice bridge missing choice: %s" % choice_id)
scene.free()
return
if not scene.campaign_state.try_apply_post_battle_choice(choice, WUCHAO_SCENARIO_ID):
failures.append("Wuchao 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("Wuchao choice bridge %s should set %s" % [choice_id, expected_flag])
if flags.get(cleared_flag, true) != false:
failures.append("Wuchao choice bridge %s should clear %s" % [choice_id, cleared_flag])
if scene.campaign_state.current_scenario_id != CANGTING_SCENARIO_ID:
failures.append("Wuchao choice bridge %s should advance to Cangting, got %s" % [choice_id, scene.campaign_state.current_scenario_id])
if not scene.state.load_battle(
CANGTING_SCENARIO_PATH,
scene.campaign_state.get_roster_overrides(),
scene.campaign_state.get_inventory_snapshot(),
flags,
scene.campaign_state.get_joined_officers_snapshot()
):
failures.append("Wuchao choice bridge %s could not load Cangting" % choice_id)
scene.free()
return
if scene._camp_conversation_by_id(expected_conversation_id).is_empty():
failures.append("Wuchao 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("Wuchao choice bridge %s should hide %s" % [choice_id, hidden_conversation_id])
var shop_items: Array = scene.state.get_shop_item_ids()
if not shop_items.has(expected_shop_item_id):
failures.append("Wuchao choice bridge %s should expose shop item %s" % [choice_id, expected_shop_item_id])
if shop_items.has(hidden_shop_item_id):
failures.append("Wuchao choice bridge %s should hide shop item %s" % [choice_id, hidden_shop_item_id])
scene.free()
func _check_cangting_choice_branch_to_ye(
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, "Cangting choice bridge %s" % choice_id, CANGTING_SCENARIO_ID, CANGTING_SCENARIO_PATH)
if scene == null:
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("Cangting choice bridge %s should save 014 victory" % choice_id)
scene.free()
return
if not scene.campaign_state.get_joined_officers_snapshot().has("zhang_he"):
failures.append("Cangting choice bridge %s should add Zhang He before Ye" % choice_id)
if bool(result.get("choice_applied", true)):
failures.append("Cangting choice bridge %s should wait for a selected post-battle choice" % choice_id)
if scene.campaign_state.pending_post_battle_choice_scenario_id != CANGTING_SCENARIO_ID:
failures.append("Cangting choice bridge %s should mark Cangting choice pending" % choice_id)
var choice := _find_choice_by_id(result.get("post_battle_choices", []), choice_id)
if choice.is_empty():
failures.append("Cangting choice bridge missing choice: %s" % choice_id)
scene.free()
return
if not scene.campaign_state.try_apply_post_battle_choice(choice, CANGTING_SCENARIO_ID):
failures.append("Cangting 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("Cangting choice bridge %s should set %s" % [choice_id, expected_flag])
if flags.get(cleared_flag, true) != false:
failures.append("Cangting choice bridge %s should clear %s" % [choice_id, cleared_flag])
if scene.campaign_state.current_scenario_id != YE_SCENARIO_ID:
failures.append("Cangting choice bridge %s should advance to Ye, got %s" % [choice_id, scene.campaign_state.current_scenario_id])
if not scene.state.load_battle(
YE_SCENARIO_PATH,
scene.campaign_state.get_roster_overrides(),
scene.campaign_state.get_inventory_snapshot(),
flags,
scene.campaign_state.get_joined_officers_snapshot()
):
failures.append("Cangting choice bridge %s could not load Ye" % choice_id)
scene.free()
return
if scene.state.get_unit("zhang_he_ch15").is_empty():
failures.append("Cangting choice bridge %s should deploy Zhang He in Ye" % choice_id)
var shop_items: Array = scene.state.get_shop_item_ids()
if not shop_items.has(expected_shop_item_id):
failures.append("Cangting choice bridge %s should expose shop item %s" % [choice_id, expected_shop_item_id])
if shop_items.has(hidden_shop_item_id):
failures.append("Cangting 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 {}
@@ -1197,6 +1368,88 @@ func _check_wuchao_branch_camp_conversations(failures: Array[String]) -> void:
defense_scene.free() defense_scene.free()
func _check_cangting_branch_camp_conversations(failures: Array[String]) -> void:
var base_scene = _new_prebattle_scene_for(failures, "Cangting base camp", CANGTING_SCENARIO_ID, CANGTING_SCENARIO_PATH)
if base_scene != null:
if base_scene._camp_conversation_by_id("cangting_pursuit_council").is_empty():
failures.append("Cangting should expose the pursuit council conversation")
if base_scene._camp_conversation_by_id("cangting_guo_jia_rearguard").is_empty():
failures.append("Cangting should expose Guo Jia's rear guard conversation")
if not base_scene._camp_conversation_by_id(CANGTING_PRESSED_CONVERSATION_ID).is_empty():
failures.append("Cangting fast pursuit rations should be hidden without pressed rout flag")
if not base_scene._camp_conversation_by_id(CANGTING_STORES_CONVERSATION_ID).is_empty():
failures.append("Cangting Wuchao store medicine should be hidden without secured stores flag")
var merchant: Dictionary = base_scene.state.get_shop_merchant()
if str(merchant.get("name", "")) != "Cangting Road Sutler":
failures.append("Cangting shop merchant name should be present")
var merchant_lines: Array = merchant.get("lines", [])
if merchant_lines.size() < 2:
failures.append("Cangting shop merchant should expose flavor lines")
if base_scene._format_talk_status_text(base_scene._camp_conversation_entries()) != "Camp conversations | 2 topics":
failures.append("Cangting base talk status should summarize two non-supply topics")
base_scene.free()
var pressed_scene = _new_prebattle_scene_for(
failures,
"Cangting pressed rout camp",
CANGTING_SCENARIO_ID,
CANGTING_SCENARIO_PATH,
{"pressed_yuan_rout": true}
)
if pressed_scene != null:
var fast_rations: Dictionary = pressed_scene._camp_conversation_by_id(CANGTING_PRESSED_CONVERSATION_ID)
if fast_rations.is_empty():
failures.append("pressed Yuan rout flag should expose Cangting fast pursuit rations")
if not pressed_scene._camp_conversation_by_id(CANGTING_STORES_CONVERSATION_ID).is_empty():
failures.append("pressed Yuan rout flag should not expose Cangting Wuchao store medicine")
if not fast_rations.is_empty():
if pressed_scene._format_talk_status_text(pressed_scene._camp_conversation_entries()) != "Camp conversations | 3 topics | 1 supplies ready":
failures.append("Cangting pressed rout talk status should show one ready supply")
if not pressed_scene._format_camp_conversation_button_text(fast_rations).contains("Supply Bean"):
failures.append("Cangting fast pursuit 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(fast_rations)
if int(pressed_scene.campaign_state.get_inventory_snapshot().get("bean", 0)) != before_bean + 1:
failures.append("Cangting fast pursuit rations should add Bean to campaign inventory")
if int(pressed_scene.state.get_inventory_snapshot().get("bean", 0)) != before_bean + 1:
failures.append("Cangting fast pursuit rations should refresh battle Bean inventory")
if not pressed_scene.campaign_state.has_claimed_camp_conversation_effects(CANGTING_SCENARIO_ID, CANGTING_PRESSED_CONVERSATION_ID):
failures.append("Cangting fast pursuit 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("Cangting pressed rout talk status should show claimed supply after claim")
pressed_scene.free()
var stores_scene = _new_prebattle_scene_for(
failures,
"Cangting secured Wuchao stores camp",
CANGTING_SCENARIO_ID,
CANGTING_SCENARIO_PATH,
{"secured_wuchao_stores": true}
)
if stores_scene != null:
var store_medicine: Dictionary = stores_scene._camp_conversation_by_id(CANGTING_STORES_CONVERSATION_ID)
if store_medicine.is_empty():
failures.append("secured Wuchao stores flag should expose Cangting store medicine")
if not stores_scene._camp_conversation_by_id(CANGTING_PRESSED_CONVERSATION_ID).is_empty():
failures.append("secured Wuchao stores flag should not expose Cangting fast pursuit rations")
if not store_medicine.is_empty():
if stores_scene._format_talk_status_text(stores_scene._camp_conversation_entries()) != "Camp conversations | 3 topics | 1 supplies ready":
failures.append("Cangting secured stores talk status should show one ready supply")
if not stores_scene._format_camp_conversation_button_text(store_medicine).contains("Supply Panacea"):
failures.append("Cangting store medicine button should show Panacea supply")
var before_panacea := int(stores_scene.campaign_state.get_inventory_snapshot().get("panacea", 0))
stores_scene._apply_camp_conversation_effects(store_medicine)
if int(stores_scene.campaign_state.get_inventory_snapshot().get("panacea", 0)) != before_panacea + 1:
failures.append("Cangting store medicine should add Panacea to campaign inventory")
if int(stores_scene.state.get_inventory_snapshot().get("panacea", 0)) != before_panacea + 1:
failures.append("Cangting store medicine should refresh battle Panacea inventory")
if not stores_scene.campaign_state.has_claimed_camp_conversation_effects(CANGTING_SCENARIO_ID, CANGTING_STORES_CONVERSATION_ID):
failures.append("Cangting store medicine claim should be saved")
if stores_scene._format_talk_status_text(stores_scene._camp_conversation_entries()) != "Camp conversations | 3 topics | 1 claimed":
failures.append("Cangting secured stores talk status should show claimed supply after claim")
stores_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

@@ -707,6 +707,88 @@ func _check_battle_visual_data(failures: Array[String]) -> void:
).is_empty(): ).is_empty():
failures.append("013 old Guandu flags should not expose reserve wagon supplies") failures.append("013 old Guandu flags should not expose reserve wagon supplies")
var cangting_state = BattleStateScript.new()
if not cangting_state.load_battle("res://data/scenarios/014_cangting_pursuit.json"):
failures.append("could not load Cangting Pursuit camp data")
else:
_check_shop_items_unique(failures, cangting_state, "014 base")
var cangting_conversations: Array = cangting_state.get_briefing().get("camp_conversations", [])
if cangting_conversations.size() != 2:
failures.append("014 base briefing should expose exactly two camp conversations")
else:
_check_camp_conversation(failures, cangting_conversations[0], "cangting_pursuit_council", "topic", "")
_check_camp_conversation(failures, cangting_conversations[1], "cangting_guo_jia_rearguard", "officer", "guo_jia")
var cangting_merchant := cangting_state.get_shop_merchant()
if str(cangting_merchant.get("name", "")) != "Cangting Road Sutler":
failures.append("014 shop should expose Cangting merchant name")
if (cangting_merchant.get("lines", []) as Array).size() < 2:
failures.append("014 shop should expose merchant flavor lines")
_check_shop_item_visibility(failures, cangting_state, "war_drum", false, "014 base")
_check_shop_item_visibility(failures, cangting_state, "imperial_seal", false, "014 base")
_check_shop_item_visibility(failures, cangting_state, "dragon_spear", false, "014 base")
var cangting_pressed_state = BattleStateScript.new()
if not cangting_pressed_state.load_battle("res://data/scenarios/014_cangting_pursuit.json", {}, {}, {"pressed_yuan_rout": true}):
failures.append("could not load Cangting pressed rout camp data")
else:
_check_shop_items_unique(failures, cangting_pressed_state, "014 pressed Yuan rout")
var fast_rations: Dictionary = _find_camp_conversation(
cangting_pressed_state.get_briefing().get("camp_conversations", []),
"cangting_fast_pursuit_beans"
)
if fast_rations.is_empty():
failures.append("014 pressed Yuan rout flag should expose fast pursuit rations")
else:
_check_camp_conversation_effect(failures, fast_rations, "bean", 1)
if not _find_camp_conversation(
cangting_pressed_state.get_briefing().get("camp_conversations", []),
"cangting_wuchao_store_medicine"
).is_empty():
failures.append("014 pressed Yuan rout flag should not expose Wuchao store medicine")
_check_shop_item_visibility(failures, cangting_pressed_state, "war_drum", true, "014 pressed Yuan rout")
_check_shop_item_visibility(failures, cangting_pressed_state, "imperial_seal", false, "014 pressed Yuan rout")
_check_shop_item_visibility(failures, cangting_pressed_state, "dragon_spear", false, "014 pressed Yuan rout")
var cangting_stores_state = BattleStateScript.new()
if not cangting_stores_state.load_battle("res://data/scenarios/014_cangting_pursuit.json", {}, {}, {"secured_wuchao_stores": true}):
failures.append("could not load Cangting secured Wuchao stores camp data")
else:
_check_shop_items_unique(failures, cangting_stores_state, "014 secured Wuchao stores")
var store_medicine: Dictionary = _find_camp_conversation(
cangting_stores_state.get_briefing().get("camp_conversations", []),
"cangting_wuchao_store_medicine"
)
if store_medicine.is_empty():
failures.append("014 secured Wuchao stores flag should expose store medicine")
else:
_check_camp_conversation_effect(failures, store_medicine, "panacea", 1)
if not _find_camp_conversation(
cangting_stores_state.get_briefing().get("camp_conversations", []),
"cangting_fast_pursuit_beans"
).is_empty():
failures.append("014 secured Wuchao stores flag should not expose fast pursuit rations")
_check_shop_item_visibility(failures, cangting_stores_state, "war_drum", false, "014 secured Wuchao stores")
_check_shop_item_visibility(failures, cangting_stores_state, "imperial_seal", true, "014 secured Wuchao stores")
_check_shop_item_visibility(failures, cangting_stores_state, "dragon_spear", false, "014 secured Wuchao stores")
var cangting_old_flags_state = BattleStateScript.new()
if not cangting_old_flags_state.load_battle("res://data/scenarios/014_cangting_pursuit.json", {}, {}, {"prepared_wuchao_raid": true, "strengthened_guandu_defense": true}):
failures.append("could not load Cangting old Wuchao flag camp data")
else:
_check_shop_item_visibility(failures, cangting_old_flags_state, "war_drum", false, "014 old Wuchao flags")
_check_shop_item_visibility(failures, cangting_old_flags_state, "imperial_seal", false, "014 old Wuchao flags")
_check_shop_item_visibility(failures, cangting_old_flags_state, "dragon_spear", false, "014 old Wuchao flags")
if not _find_camp_conversation(
cangting_old_flags_state.get_briefing().get("camp_conversations", []),
"cangting_fast_pursuit_beans"
).is_empty():
failures.append("014 old Wuchao flags should not expose fast pursuit rations")
if not _find_camp_conversation(
cangting_old_flags_state.get_briefing().get("camp_conversations", []),
"cangting_wuchao_store_medicine"
).is_empty():
failures.append("014 old Wuchao flags should not expose Wuchao store 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():