Add Changban camp and Jiangling bridge

This commit is contained in:
2026-06-19 03:50:15 +09:00
parent 3ca9d9bb05
commit 113cafc864
4 changed files with 354 additions and 2 deletions

View File

@@ -32,6 +32,59 @@
"The secured Han River road keeps Cao Cao's columns ordered, letting the army press Changban without fraying its own supply line." "The secured Han River road keeps Cao Cao's columns ordered, letting the army press Changban without fraying its own supply line."
] ]
} }
],
"camp_conversations": [
{
"id": "changban_bridge_council",
"group": "topic",
"label": "Bridge Council",
"speaker": "Cao Cao",
"summary": "Set the pursuit's measure before Changban Bridge turns Liu Bei's flight into legend.",
"lines": [
{ "speaker": "Cao Cao", "side": "left", "text": "At Changban, one bridge can become a hundred rumors. We must cross before fear learns poetry." },
{ "speaker": "Guo Jia", "side": "right", "text": "Liu Bei's retreat carries families, banners, and excuses. Break the bridge guard and the story limps." },
{ "speaker": "Zhang He", "side": "right", "text": "Zhang Fei will spend noise where he lacks soldiers. A loud bridge is still only a bridge." }
]
},
{
"id": "changban_zhang_he_bridge_shadow",
"group": "officer",
"officer_id": "zhang_he",
"label": "Zhang He - Bridge Shadow",
"summary": "Hear Zhang He's reading of the Changban bridge line before the pursuit tightens.",
"lines": [
{ "speaker": "Zhang He", "side": "right", "text": "Their strongest guard stands where the road narrows. That means every other road is weaker than it looks." },
{ "speaker": "Cao Cao", "side": "left", "text": "Then let the narrow place teach the wide road obedience." }
]
},
{
"id": "changban_vanguard_rations",
"group": "topic",
"label": "Vanguard Rations",
"summary": "The fast Xinye pursuit leaves hard rations for the first soldiers to reach Changban.",
"campaign_flags": { "pressed_xinye_vanguard": true },
"effects": [
{ "type": "grant_item", "item_id": "bean", "count": 1, "text": "The vanguard rations add a Bean to the field supplies." }
],
"lines": [
{ "speaker": "Xiahou Yuan", "side": "left", "text": "The men who outran Xinye kept dry beans in their sleeves. They would rather chew than slow." },
{ "speaker": "Cao Cao", "side": "right", "text": "Good. Feed the feet that reach the bridge first." }
]
},
{
"id": "changban_han_supply_medicine",
"group": "topic",
"label": "Han Supply Medicine",
"summary": "Secured Han River wagons send clean medicine into the Changban pursuit.",
"campaign_flags": { "secured_han_river_supply": true },
"effects": [
{ "type": "grant_item", "item_id": "panacea", "count": 1, "text": "The Han River medicine adds a Panacea to the field supplies." }
],
"lines": [
{ "speaker": "Cao Ren", "side": "left", "text": "The Han River wagons arrived under seal. Medicine, bindings, and clerks who can still count in the mud." },
{ "speaker": "Cao Cao", "side": "right", "text": "Order that reaches the wounded reaches the battle as well." }
]
}
] ]
}, },
"shop": { "shop": {
@@ -55,7 +108,14 @@
"campaign_flags": { "secured_han_river_supply": true }, "campaign_flags": { "secured_han_river_supply": true },
"items": ["imperial_seal"] "items": ["imperial_seal"]
} }
] ],
"merchant": {
"name": "Changban Bridge Sutler",
"lines": [
"Changban charges by the plank, my lord. I charge less, and my goods complain less.",
"Buy before Zhang Fei's shouting makes every bridge pole think itself a spear."
]
}
}, },
"roster": { "roster": {
"max_units": 7, "max_units": 7,

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

@@ -98,6 +98,10 @@ const XINYE_ORDERED_MEDICINE_CONVERSATION_ID := "xinye_ordered_medicine"
const XINYE_AUTHORITY_WINE_CONVERSATION_ID := "xinye_authority_wine" const XINYE_AUTHORITY_WINE_CONVERSATION_ID := "xinye_authority_wine"
const CHANGBAN_SCENARIO_ID := "026_changban_pursuit" const CHANGBAN_SCENARIO_ID := "026_changban_pursuit"
const CHANGBAN_SCENARIO_PATH := "res://data/scenarios/026_changban_pursuit.json" const CHANGBAN_SCENARIO_PATH := "res://data/scenarios/026_changban_pursuit.json"
const CHANGBAN_VANGUARD_RATIONS_CONVERSATION_ID := "changban_vanguard_rations"
const CHANGBAN_HAN_MEDICINE_CONVERSATION_ID := "changban_han_supply_medicine"
const JIANGLING_SCENARIO_ID := "027_jiangling_chase"
const JIANGLING_SCENARIO_PATH := "res://data/scenarios/027_jiangling_chase.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"
@@ -132,6 +136,7 @@ func _init() -> void:
_check_white_wolf_post_battle_choice_bridges_to_liaodong(failures) _check_white_wolf_post_battle_choice_bridges_to_liaodong(failures)
_check_liaodong_post_battle_choice_bridges_to_xinye(failures) _check_liaodong_post_battle_choice_bridges_to_xinye(failures)
_check_xinye_post_battle_choice_bridges_to_changban(failures) _check_xinye_post_battle_choice_bridges_to_changban(failures)
_check_changban_post_battle_choice_bridges_to_jiangling(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)
@@ -149,6 +154,7 @@ func _init() -> void:
_check_white_wolf_branch_camp_conversations(failures) _check_white_wolf_branch_camp_conversations(failures)
_check_liaodong_branch_camp_conversations(failures) _check_liaodong_branch_camp_conversations(failures)
_check_xinye_branch_camp_conversations(failures) _check_xinye_branch_camp_conversations(failures)
_check_changban_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):
@@ -1274,6 +1280,25 @@ func _check_xinye_post_battle_choice_bridges_to_changban(failures: Array[String]
) )
func _check_changban_post_battle_choice_bridges_to_jiangling(failures: Array[String]) -> void:
_check_changban_choice_branch_to_jiangling(
failures,
"press_jiangling_chase",
"pressed_jiangling_chase",
"secured_changban_crossings",
"war_drum",
"imperial_seal"
)
_check_changban_choice_branch_to_jiangling(
failures,
"secure_changban_crossings",
"secured_changban_crossings",
"pressed_jiangling_chase",
"imperial_seal",
"war_drum"
)
func _check_wuchao_choice_branch_to_cangting( func _check_wuchao_choice_branch_to_cangting(
failures: Array[String], failures: Array[String],
choice_id: String, choice_id: String,
@@ -2223,6 +2248,79 @@ func _check_xinye_choice_branch_to_changban(
scene.free() scene.free()
func _check_changban_choice_branch_to_jiangling(
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, "Changban choice bridge %s" % choice_id, CHANGBAN_SCENARIO_ID, CHANGBAN_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(
CHANGBAN_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("Changban choice bridge %s could not reload Changban 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("Changban choice bridge %s should save 026 victory" % choice_id)
scene.free()
return
if not scene.campaign_state.get_joined_officers_snapshot().has("zhang_he"):
failures.append("Changban choice bridge %s should keep Zhang He before Jiangling" % choice_id)
if bool(result.get("choice_applied", true)):
failures.append("Changban choice bridge %s should wait for a selected post-battle choice" % choice_id)
if scene.campaign_state.pending_post_battle_choice_scenario_id != CHANGBAN_SCENARIO_ID:
failures.append("Changban choice bridge %s should mark Changban choice pending" % choice_id)
var choice := _find_choice_by_id(result.get("post_battle_choices", []), choice_id)
if choice.is_empty():
failures.append("Changban choice bridge missing choice: %s" % choice_id)
scene.free()
return
if not scene.campaign_state.try_apply_post_battle_choice(choice, CHANGBAN_SCENARIO_ID):
failures.append("Changban 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("Changban choice bridge %s should set %s" % [choice_id, expected_flag])
if flags.get(cleared_flag, true) != false:
failures.append("Changban choice bridge %s should clear %s" % [choice_id, cleared_flag])
if scene.campaign_state.current_scenario_id != JIANGLING_SCENARIO_ID:
failures.append("Changban choice bridge %s should advance to Jiangling, got %s" % [choice_id, scene.campaign_state.current_scenario_id])
if not scene.state.load_battle(
JIANGLING_SCENARIO_PATH,
scene.campaign_state.get_roster_overrides(),
scene.campaign_state.get_inventory_snapshot(),
flags,
scene.campaign_state.get_joined_officers_snapshot()
):
failures.append("Changban choice bridge %s could not load Jiangling" % choice_id)
scene.free()
return
if scene.state.get_unit("zhang_he_ch27").is_empty():
failures.append("Changban choice bridge %s should deploy Zhang He in Jiangling" % choice_id)
elif not scene.state.is_required_deployment("zhang_he_ch27"):
failures.append("Changban choice bridge %s should require Zhang He in Jiangling" % choice_id)
var shop_items: Array = scene.state.get_shop_item_ids()
if not shop_items.has(expected_shop_item_id):
failures.append("Changban choice bridge %s should expose shop item %s" % [choice_id, expected_shop_item_id])
if shop_items.has(hidden_shop_item_id):
failures.append("Changban 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 {}
@@ -3483,6 +3581,121 @@ func _check_xinye_branch_camp_conversations(failures: Array[String]) -> void:
authority_scene.free() authority_scene.free()
func _check_changban_branch_camp_conversations(failures: Array[String]) -> void:
var base_scene = _new_prebattle_scene_for(failures, "Changban base camp", CHANGBAN_SCENARIO_ID, CHANGBAN_SCENARIO_PATH)
if base_scene != null:
if not base_scene.campaign_state.joined_officers.has("zhang_he"):
base_scene.campaign_state.joined_officers.append("zhang_he")
if not base_scene.state.load_battle(
CHANGBAN_SCENARIO_PATH,
base_scene.campaign_state.get_roster_overrides(),
base_scene.campaign_state.get_inventory_snapshot(),
base_scene.campaign_state.get_flags_snapshot(),
base_scene.campaign_state.get_joined_officers_snapshot()
):
failures.append("Changban base camp should reload with Zhang He joined")
else:
if base_scene._camp_conversation_by_id("changban_bridge_council").is_empty():
failures.append("Changban should expose the bridge council conversation")
if base_scene._camp_conversation_by_id("changban_zhang_he_bridge_shadow").is_empty():
failures.append("Changban should expose Zhang He's bridge shadow conversation")
if not base_scene._camp_conversation_by_id(CHANGBAN_VANGUARD_RATIONS_CONVERSATION_ID).is_empty():
failures.append("Changban vanguard rations should be hidden without pressed Xinye flag")
if not base_scene._camp_conversation_by_id(CHANGBAN_HAN_MEDICINE_CONVERSATION_ID).is_empty():
failures.append("Changban Han medicine should be hidden without secured Han flag")
var merchant: Dictionary = base_scene.state.get_shop_merchant()
if str(merchant.get("name", "")) != "Changban Bridge Sutler":
failures.append("Changban shop merchant name should be present")
var merchant_lines: Array = merchant.get("lines", [])
if merchant_lines.size() < 2:
failures.append("Changban shop merchant should expose flavor lines")
if base_scene._format_talk_status_text(base_scene._camp_conversation_entries()) != "Camp conversations | 2 topics":
failures.append("Changban base talk status should summarize two non-supply topics")
base_scene.free()
var vanguard_scene = _new_prebattle_scene_for(
failures,
"Changban pressed Xinye camp",
CHANGBAN_SCENARIO_ID,
CHANGBAN_SCENARIO_PATH,
{"pressed_xinye_vanguard": true}
)
if vanguard_scene != null:
if not vanguard_scene.campaign_state.joined_officers.has("zhang_he"):
vanguard_scene.campaign_state.joined_officers.append("zhang_he")
if not vanguard_scene.state.load_battle(
CHANGBAN_SCENARIO_PATH,
vanguard_scene.campaign_state.get_roster_overrides(),
vanguard_scene.campaign_state.get_inventory_snapshot(),
vanguard_scene.campaign_state.get_flags_snapshot(),
vanguard_scene.campaign_state.get_joined_officers_snapshot()
):
failures.append("Changban pressed camp should reload with Zhang He joined")
else:
var vanguard_rations: Dictionary = vanguard_scene._camp_conversation_by_id(CHANGBAN_VANGUARD_RATIONS_CONVERSATION_ID)
if vanguard_rations.is_empty():
failures.append("pressed Xinye vanguard flag should expose Changban vanguard rations")
if not vanguard_scene._camp_conversation_by_id(CHANGBAN_HAN_MEDICINE_CONVERSATION_ID).is_empty():
failures.append("pressed Xinye vanguard flag should not expose Changban Han medicine")
if not vanguard_rations.is_empty():
if vanguard_scene._format_talk_status_text(vanguard_scene._camp_conversation_entries()) != "Camp conversations | 3 topics | 1 supplies ready":
failures.append("Changban vanguard talk status should show one ready supply")
if not vanguard_scene._format_camp_conversation_button_text(vanguard_rations).contains("Supply Bean"):
failures.append("Changban vanguard rations button should show Bean supply")
var before_bean := int(vanguard_scene.campaign_state.get_inventory_snapshot().get("bean", 0))
vanguard_scene._apply_camp_conversation_effects(vanguard_rations)
if int(vanguard_scene.campaign_state.get_inventory_snapshot().get("bean", 0)) != before_bean + 1:
failures.append("Changban vanguard rations should add Bean to campaign inventory")
if int(vanguard_scene.state.get_inventory_snapshot().get("bean", 0)) != before_bean + 1:
failures.append("Changban vanguard rations should refresh battle Bean inventory")
if not vanguard_scene.campaign_state.has_claimed_camp_conversation_effects(CHANGBAN_SCENARIO_ID, CHANGBAN_VANGUARD_RATIONS_CONVERSATION_ID):
failures.append("Changban vanguard rations claim should be saved")
if vanguard_scene._format_talk_status_text(vanguard_scene._camp_conversation_entries()) != "Camp conversations | 3 topics | 1 claimed":
failures.append("Changban vanguard talk status should show claimed supply after claim")
vanguard_scene.free()
var supply_scene = _new_prebattle_scene_for(
failures,
"Changban secured Han camp",
CHANGBAN_SCENARIO_ID,
CHANGBAN_SCENARIO_PATH,
{"secured_han_river_supply": true}
)
if supply_scene != null:
if not supply_scene.campaign_state.joined_officers.has("zhang_he"):
supply_scene.campaign_state.joined_officers.append("zhang_he")
if not supply_scene.state.load_battle(
CHANGBAN_SCENARIO_PATH,
supply_scene.campaign_state.get_roster_overrides(),
supply_scene.campaign_state.get_inventory_snapshot(),
supply_scene.campaign_state.get_flags_snapshot(),
supply_scene.campaign_state.get_joined_officers_snapshot()
):
failures.append("Changban secured camp should reload with Zhang He joined")
else:
var han_medicine: Dictionary = supply_scene._camp_conversation_by_id(CHANGBAN_HAN_MEDICINE_CONVERSATION_ID)
if han_medicine.is_empty():
failures.append("secured Han supply flag should expose Changban Han medicine")
if not supply_scene._camp_conversation_by_id(CHANGBAN_VANGUARD_RATIONS_CONVERSATION_ID).is_empty():
failures.append("secured Han supply flag should not expose Changban vanguard rations")
if not han_medicine.is_empty():
if supply_scene._format_talk_status_text(supply_scene._camp_conversation_entries()) != "Camp conversations | 3 topics | 1 supplies ready":
failures.append("Changban secured talk status should show one ready supply")
if not supply_scene._format_camp_conversation_button_text(han_medicine).contains("Supply Panacea"):
failures.append("Changban Han medicine button should show Panacea supply")
var before_panacea := int(supply_scene.campaign_state.get_inventory_snapshot().get("panacea", 0))
supply_scene._apply_camp_conversation_effects(han_medicine)
if int(supply_scene.campaign_state.get_inventory_snapshot().get("panacea", 0)) != before_panacea + 1:
failures.append("Changban Han medicine should add Panacea to campaign inventory")
if int(supply_scene.state.get_inventory_snapshot().get("panacea", 0)) != before_panacea + 1:
failures.append("Changban Han medicine should refresh battle Panacea inventory")
if not supply_scene.campaign_state.has_claimed_camp_conversation_effects(CHANGBAN_SCENARIO_ID, CHANGBAN_HAN_MEDICINE_CONVERSATION_ID):
failures.append("Changban Han medicine claim should be saved")
if supply_scene._format_talk_status_text(supply_scene._camp_conversation_entries()) != "Camp conversations | 3 topics | 1 claimed":
failures.append("Changban secured talk status should show claimed supply after claim")
supply_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

@@ -1671,6 +1671,17 @@ func _check_battle_visual_data(failures: Array[String]) -> void:
failures.append("could not load Changban Pursuit data") failures.append("could not load Changban Pursuit data")
else: else:
_check_shop_items_unique(failures, changban_state, "026 base") _check_shop_items_unique(failures, changban_state, "026 base")
var changban_conversations: Array = changban_state.get_briefing().get("camp_conversations", [])
if changban_conversations.size() != 2:
failures.append("026 base briefing should expose exactly two camp conversations")
else:
_check_camp_conversation(failures, changban_conversations[0], "changban_bridge_council", "topic", "")
_check_camp_conversation(failures, changban_conversations[1], "changban_zhang_he_bridge_shadow", "officer", "zhang_he")
var changban_merchant := changban_state.get_shop_merchant()
if str(changban_merchant.get("name", "")) != "Changban Bridge Sutler":
failures.append("026 shop should expose Changban Bridge merchant name")
if (changban_merchant.get("lines", []) as Array).size() < 2:
failures.append("026 shop should expose merchant flavor lines")
if changban_state.get_unit("zhang_he_ch26").is_empty() or not changban_state.is_required_deployment("zhang_he_ch26"): if changban_state.get_unit("zhang_he_ch26").is_empty() or not changban_state.is_required_deployment("zhang_he_ch26"):
failures.append("026 should deploy Zhang He as a required officer") failures.append("026 should deploy Zhang He as a required officer")
_check_shop_item_visibility(failures, changban_state, "war_drum", false, "026 base") _check_shop_item_visibility(failures, changban_state, "war_drum", false, "026 base")
@@ -1680,6 +1691,19 @@ func _check_battle_visual_data(failures: Array[String]) -> void:
if not changban_vanguard_state.load_battle("res://data/scenarios/026_changban_pursuit.json", {}, {}, {"pressed_xinye_vanguard": true}, ["zhang_he"]): if not changban_vanguard_state.load_battle("res://data/scenarios/026_changban_pursuit.json", {}, {}, {"pressed_xinye_vanguard": true}, ["zhang_he"]):
failures.append("could not load Changban pressed Xinye vanguard data") failures.append("could not load Changban pressed Xinye vanguard data")
else: else:
var vanguard_rations: Dictionary = _find_camp_conversation(
changban_vanguard_state.get_briefing().get("camp_conversations", []),
"changban_vanguard_rations"
)
if vanguard_rations.is_empty():
failures.append("026 pressed Xinye vanguard should expose vanguard rations")
else:
_check_camp_conversation_effect(failures, vanguard_rations, "bean", 1)
if not _find_camp_conversation(
changban_vanguard_state.get_briefing().get("camp_conversations", []),
"changban_han_supply_medicine"
).is_empty():
failures.append("026 pressed Xinye vanguard should not expose Han supply medicine")
_check_shop_item_visibility(failures, changban_vanguard_state, "war_drum", true, "026 pressed Xinye vanguard") _check_shop_item_visibility(failures, changban_vanguard_state, "war_drum", true, "026 pressed Xinye vanguard")
_check_shop_item_visibility(failures, changban_vanguard_state, "imperial_seal", false, "026 pressed Xinye vanguard") _check_shop_item_visibility(failures, changban_vanguard_state, "imperial_seal", false, "026 pressed Xinye vanguard")
@@ -1687,6 +1711,19 @@ func _check_battle_visual_data(failures: Array[String]) -> void:
if not changban_supply_state.load_battle("res://data/scenarios/026_changban_pursuit.json", {}, {}, {"secured_han_river_supply": true}, ["zhang_he"]): if not changban_supply_state.load_battle("res://data/scenarios/026_changban_pursuit.json", {}, {}, {"secured_han_river_supply": true}, ["zhang_he"]):
failures.append("could not load Changban secured Han supply data") failures.append("could not load Changban secured Han supply data")
else: else:
var han_medicine: Dictionary = _find_camp_conversation(
changban_supply_state.get_briefing().get("camp_conversations", []),
"changban_han_supply_medicine"
)
if han_medicine.is_empty():
failures.append("026 secured Han supply should expose Han supply medicine")
else:
_check_camp_conversation_effect(failures, han_medicine, "panacea", 1)
if not _find_camp_conversation(
changban_supply_state.get_briefing().get("camp_conversations", []),
"changban_vanguard_rations"
).is_empty():
failures.append("026 secured Han supply should not expose vanguard rations")
_check_shop_item_visibility(failures, changban_supply_state, "imperial_seal", true, "026 secured Han supply") _check_shop_item_visibility(failures, changban_supply_state, "imperial_seal", true, "026 secured Han supply")
_check_shop_item_visibility(failures, changban_supply_state, "war_drum", false, "026 secured Han supply") _check_shop_item_visibility(failures, changban_supply_state, "war_drum", false, "026 secured Han supply")
@@ -1697,6 +1734,48 @@ func _check_battle_visual_data(failures: Array[String]) -> void:
_check_shop_items_unique(failures, changban_old_flags_state, "026 old Xinye setup flags") _check_shop_items_unique(failures, changban_old_flags_state, "026 old Xinye setup flags")
_check_shop_item_visibility(failures, changban_old_flags_state, "war_drum", false, "026 old Xinye setup flags") _check_shop_item_visibility(failures, changban_old_flags_state, "war_drum", false, "026 old Xinye setup flags")
_check_shop_item_visibility(failures, changban_old_flags_state, "imperial_seal", false, "026 old Xinye setup flags") _check_shop_item_visibility(failures, changban_old_flags_state, "imperial_seal", false, "026 old Xinye setup flags")
if not _find_camp_conversation(
changban_old_flags_state.get_briefing().get("camp_conversations", []),
"changban_vanguard_rations"
).is_empty():
failures.append("026 old Xinye setup flags should not expose vanguard rations")
if not _find_camp_conversation(
changban_old_flags_state.get_briefing().get("camp_conversations", []),
"changban_han_supply_medicine"
).is_empty():
failures.append("026 old Xinye setup flags should not expose Han supply medicine")
var jiangling_state = BattleStateScript.new()
if not jiangling_state.load_battle("res://data/scenarios/027_jiangling_chase.json", {}, {}, {}, ["zhang_he"]):
failures.append("could not load Jiangling Chase data")
else:
_check_shop_items_unique(failures, jiangling_state, "027 base")
if jiangling_state.get_unit("zhang_he_ch27").is_empty() or not jiangling_state.is_required_deployment("zhang_he_ch27"):
failures.append("027 should deploy Zhang He as a required officer")
_check_shop_item_visibility(failures, jiangling_state, "war_drum", false, "027 base")
_check_shop_item_visibility(failures, jiangling_state, "imperial_seal", false, "027 base")
var jiangling_chase_state = BattleStateScript.new()
if not jiangling_chase_state.load_battle("res://data/scenarios/027_jiangling_chase.json", {}, {}, {"pressed_jiangling_chase": true}, ["zhang_he"]):
failures.append("could not load Jiangling pressed chase data")
else:
_check_shop_item_visibility(failures, jiangling_chase_state, "war_drum", true, "027 pressed Jiangling chase")
_check_shop_item_visibility(failures, jiangling_chase_state, "imperial_seal", false, "027 pressed Jiangling chase")
var jiangling_crossings_state = BattleStateScript.new()
if not jiangling_crossings_state.load_battle("res://data/scenarios/027_jiangling_chase.json", {}, {}, {"secured_changban_crossings": true}, ["zhang_he"]):
failures.append("could not load Jiangling secured crossings data")
else:
_check_shop_item_visibility(failures, jiangling_crossings_state, "imperial_seal", true, "027 secured Changban crossings")
_check_shop_item_visibility(failures, jiangling_crossings_state, "war_drum", false, "027 secured Changban crossings")
var jiangling_old_flags_state = BattleStateScript.new()
if not jiangling_old_flags_state.load_battle("res://data/scenarios/027_jiangling_chase.json", {}, {}, {"pressed_xinye_vanguard": true, "secured_han_river_supply": true}, ["zhang_he"]):
failures.append("could not load Jiangling old Changban setup flag data")
else:
_check_shop_items_unique(failures, jiangling_old_flags_state, "027 old Changban setup flags")
_check_shop_item_visibility(failures, jiangling_old_flags_state, "war_drum", false, "027 old Changban setup flags")
_check_shop_item_visibility(failures, jiangling_old_flags_state, "imperial_seal", false, "027 old Changban setup flags")
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)