Add Red Cliffs fleet camp and fire bridge

This commit is contained in:
2026-06-19 04:08:08 +09:00
parent 0073f049fe
commit af7e41eafd
4 changed files with 354 additions and 2 deletions

View File

@@ -32,6 +32,59 @@
"Xiakou's secured harbor gives Cao Cao time to chain ships and steady seasick troops before facing the coalition vanguard." "Xiakou's secured harbor gives Cao Cao time to chain ships and steady seasick troops before facing the coalition vanguard."
] ]
} }
],
"camp_conversations": [
{
"id": "red_cliffs_fleet_council",
"group": "topic",
"label": "Fleet Council",
"speaker": "Cao Cao",
"summary": "Set the chained fleet's purpose before Red Cliffs turns the river into a battlefield.",
"lines": [
{ "speaker": "Cao Cao", "side": "left", "text": "On land, a road obeys the army. On this river, even courage rocks underfoot." },
{ "speaker": "Guo Jia", "side": "right", "text": "Then chain order to the ships before fear learns to move with the waves." },
{ "speaker": "Zhang He", "side": "right", "text": "The coalition is probing the line, not striking it. They want to know whether our fleet can bend." }
]
},
{
"id": "red_cliffs_zhang_he_chain_line",
"group": "officer",
"officer_id": "zhang_he",
"label": "Zhang He - Chain Line",
"summary": "Hear Zhang He's reading of the coalition vanguard before the chained fleet is tested.",
"lines": [
{ "speaker": "Zhang He", "side": "right", "text": "A chained fleet steadies frightened men, but it also tells the enemy where every ship must answer." },
{ "speaker": "Cao Cao", "side": "left", "text": "Then make the answer heavy enough that they stop asking." }
]
},
{
"id": "red_cliffs_forward_deck_beans",
"group": "topic",
"label": "Forward Deck Beans",
"summary": "The pressed fleet keeps hard beans ready for crews sent forward before the river line settles.",
"campaign_flags": { "pressed_red_cliffs_fleet": true },
"effects": [
{ "type": "grant_item", "item_id": "bean", "count": 1, "text": "The forward deck beans add a Bean to the field supplies." }
],
"lines": [
{ "speaker": "Xiahou Dun", "side": "left", "text": "The forward decks moved before the cooks found steady flame. The crews saved beans because soup would not stay in a pot." },
{ "speaker": "Cao Cao", "side": "right", "text": "Then feed them what the river cannot spill." }
]
},
{
"id": "red_cliffs_harbor_medicine",
"group": "topic",
"label": "Harbor Medicine",
"summary": "Secured Xiakou harbor sends clean medicine into the chained fleet.",
"campaign_flags": { "secured_xiakou_harbor": true },
"effects": [
{ "type": "grant_item", "item_id": "panacea", "count": 1, "text": "The Xiakou harbor medicine adds a Panacea to the field supplies." }
],
"lines": [
{ "speaker": "Cao Ren", "side": "left", "text": "Xiakou's harbor stores reached the chain line. Medicine, dry cloth, and men who know which ropes are not bandages." },
{ "speaker": "Cao Cao", "side": "right", "text": "Good. The river can shake them, but it need not sicken them." }
]
}
] ]
}, },
"shop": { "shop": {
@@ -55,7 +108,14 @@
"campaign_flags": { "secured_xiakou_harbor": true }, "campaign_flags": { "secured_xiakou_harbor": true },
"items": ["imperial_seal"] "items": ["imperial_seal"]
} }
] ],
"merchant": {
"name": "Red Cliffs Deck Sutler",
"lines": [
"The river prices courage by the wave, my lord. I still take coin.",
"Buy before the wind decides whether these decks are road, wall, or tinder."
]
}
}, },
"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

@@ -110,6 +110,10 @@ const XIAKOU_ENVOY_BEANS_CONVERSATION_ID := "xiakou_envoy_chase_beans"
const XIAKOU_STOREHOUSE_MEDICINE_CONVERSATION_ID := "xiakou_storehouse_medicine" const XIAKOU_STOREHOUSE_MEDICINE_CONVERSATION_ID := "xiakou_storehouse_medicine"
const RED_CLIFFS_SCENARIO_ID := "029_red_cliffs_fleet" const RED_CLIFFS_SCENARIO_ID := "029_red_cliffs_fleet"
const RED_CLIFFS_SCENARIO_PATH := "res://data/scenarios/029_red_cliffs_fleet.json" const RED_CLIFFS_SCENARIO_PATH := "res://data/scenarios/029_red_cliffs_fleet.json"
const RED_CLIFFS_FORWARD_BEANS_CONVERSATION_ID := "red_cliffs_forward_deck_beans"
const RED_CLIFFS_HARBOR_MEDICINE_CONVERSATION_ID := "red_cliffs_harbor_medicine"
const RED_CLIFFS_FIRE_SCENARIO_ID := "030_red_cliffs_fire"
const RED_CLIFFS_FIRE_SCENARIO_PATH := "res://data/scenarios/030_red_cliffs_fire.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"
@@ -147,6 +151,7 @@ func _init() -> void:
_check_changban_post_battle_choice_bridges_to_jiangling(failures) _check_changban_post_battle_choice_bridges_to_jiangling(failures)
_check_jiangling_post_battle_choice_bridges_to_xiakou(failures) _check_jiangling_post_battle_choice_bridges_to_xiakou(failures)
_check_xiakou_post_battle_choice_bridges_to_red_cliffs(failures) _check_xiakou_post_battle_choice_bridges_to_red_cliffs(failures)
_check_red_cliffs_post_battle_choice_bridges_to_fire(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)
@@ -167,6 +172,7 @@ func _init() -> void:
_check_changban_branch_camp_conversations(failures) _check_changban_branch_camp_conversations(failures)
_check_jiangling_branch_camp_conversations(failures) _check_jiangling_branch_camp_conversations(failures)
_check_xiakou_branch_camp_conversations(failures) _check_xiakou_branch_camp_conversations(failures)
_check_red_cliffs_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):
@@ -1349,6 +1355,25 @@ func _check_xiakou_post_battle_choice_bridges_to_red_cliffs(failures: Array[Stri
) )
func _check_red_cliffs_post_battle_choice_bridges_to_fire(failures: Array[String]) -> void:
_check_red_cliffs_choice_branch_to_fire(
failures,
"reinforce_chain_line",
"reinforced_chain_line",
"ordered_night_raid",
"imperial_seal",
"war_drum"
)
_check_red_cliffs_choice_branch_to_fire(
failures,
"order_night_raid",
"ordered_night_raid",
"reinforced_chain_line",
"war_drum",
"imperial_seal"
)
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,
@@ -2517,6 +2542,79 @@ func _check_xiakou_choice_branch_to_red_cliffs(
scene.free() scene.free()
func _check_red_cliffs_choice_branch_to_fire(
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, "Red Cliffs choice bridge %s" % choice_id, RED_CLIFFS_SCENARIO_ID, RED_CLIFFS_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(
RED_CLIFFS_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("Red Cliffs choice bridge %s could not reload Red Cliffs 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("Red Cliffs choice bridge %s should save 029 victory" % choice_id)
scene.free()
return
if not scene.campaign_state.get_joined_officers_snapshot().has("zhang_he"):
failures.append("Red Cliffs choice bridge %s should keep Zhang He before Red Cliffs Fire" % choice_id)
if bool(result.get("choice_applied", true)):
failures.append("Red Cliffs choice bridge %s should wait for a selected post-battle choice" % choice_id)
if scene.campaign_state.pending_post_battle_choice_scenario_id != RED_CLIFFS_SCENARIO_ID:
failures.append("Red Cliffs choice bridge %s should mark Red Cliffs choice pending" % choice_id)
var choice := _find_choice_by_id(result.get("post_battle_choices", []), choice_id)
if choice.is_empty():
failures.append("Red Cliffs choice bridge missing choice: %s" % choice_id)
scene.free()
return
if not scene.campaign_state.try_apply_post_battle_choice(choice, RED_CLIFFS_SCENARIO_ID):
failures.append("Red Cliffs 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("Red Cliffs choice bridge %s should set %s" % [choice_id, expected_flag])
if flags.get(cleared_flag, true) != false:
failures.append("Red Cliffs choice bridge %s should clear %s" % [choice_id, cleared_flag])
if scene.campaign_state.current_scenario_id != RED_CLIFFS_FIRE_SCENARIO_ID:
failures.append("Red Cliffs choice bridge %s should advance to Red Cliffs Fire, got %s" % [choice_id, scene.campaign_state.current_scenario_id])
if not scene.state.load_battle(
RED_CLIFFS_FIRE_SCENARIO_PATH,
scene.campaign_state.get_roster_overrides(),
scene.campaign_state.get_inventory_snapshot(),
flags,
scene.campaign_state.get_joined_officers_snapshot()
):
failures.append("Red Cliffs choice bridge %s could not load Red Cliffs Fire" % choice_id)
scene.free()
return
if scene.state.get_unit("zhang_he_ch30").is_empty():
failures.append("Red Cliffs choice bridge %s should deploy Zhang He in Red Cliffs Fire" % choice_id)
elif not scene.state.is_required_deployment("zhang_he_ch30"):
failures.append("Red Cliffs choice bridge %s should require Zhang He in Red Cliffs Fire" % choice_id)
var shop_items: Array = scene.state.get_shop_item_ids()
if not shop_items.has(expected_shop_item_id):
failures.append("Red Cliffs choice bridge %s should expose shop item %s" % [choice_id, expected_shop_item_id])
if shop_items.has(hidden_shop_item_id):
failures.append("Red Cliffs 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 {}
@@ -4122,6 +4220,121 @@ func _check_xiakou_branch_camp_conversations(failures: Array[String]) -> void:
storehouse_scene.free() storehouse_scene.free()
func _check_red_cliffs_branch_camp_conversations(failures: Array[String]) -> void:
var base_scene = _new_prebattle_scene_for(failures, "Red Cliffs base camp", RED_CLIFFS_SCENARIO_ID, RED_CLIFFS_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(
RED_CLIFFS_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("Red Cliffs base camp should reload with Zhang He joined")
else:
if base_scene._camp_conversation_by_id("red_cliffs_fleet_council").is_empty():
failures.append("Red Cliffs should expose the fleet council conversation")
if base_scene._camp_conversation_by_id("red_cliffs_zhang_he_chain_line").is_empty():
failures.append("Red Cliffs should expose Zhang He's chain line conversation")
if not base_scene._camp_conversation_by_id(RED_CLIFFS_FORWARD_BEANS_CONVERSATION_ID).is_empty():
failures.append("Red Cliffs forward beans should be hidden without pressed fleet flag")
if not base_scene._camp_conversation_by_id(RED_CLIFFS_HARBOR_MEDICINE_CONVERSATION_ID).is_empty():
failures.append("Red Cliffs harbor medicine should be hidden without secured harbor flag")
var merchant: Dictionary = base_scene.state.get_shop_merchant()
if str(merchant.get("name", "")) != "Red Cliffs Deck Sutler":
failures.append("Red Cliffs shop merchant name should be present")
var merchant_lines: Array = merchant.get("lines", [])
if merchant_lines.size() < 2:
failures.append("Red Cliffs shop merchant should expose flavor lines")
if base_scene._format_talk_status_text(base_scene._camp_conversation_entries()) != "Camp conversations | 2 topics":
failures.append("Red Cliffs base talk status should summarize two non-supply topics")
base_scene.free()
var pressed_scene = _new_prebattle_scene_for(
failures,
"Red Cliffs pressed fleet camp",
RED_CLIFFS_SCENARIO_ID,
RED_CLIFFS_SCENARIO_PATH,
{"pressed_red_cliffs_fleet": true}
)
if pressed_scene != null:
if not pressed_scene.campaign_state.joined_officers.has("zhang_he"):
pressed_scene.campaign_state.joined_officers.append("zhang_he")
if not pressed_scene.state.load_battle(
RED_CLIFFS_SCENARIO_PATH,
pressed_scene.campaign_state.get_roster_overrides(),
pressed_scene.campaign_state.get_inventory_snapshot(),
pressed_scene.campaign_state.get_flags_snapshot(),
pressed_scene.campaign_state.get_joined_officers_snapshot()
):
failures.append("Red Cliffs pressed fleet camp should reload with Zhang He joined")
else:
var forward_beans: Dictionary = pressed_scene._camp_conversation_by_id(RED_CLIFFS_FORWARD_BEANS_CONVERSATION_ID)
if forward_beans.is_empty():
failures.append("pressed Red Cliffs fleet flag should expose forward deck beans")
if not pressed_scene._camp_conversation_by_id(RED_CLIFFS_HARBOR_MEDICINE_CONVERSATION_ID).is_empty():
failures.append("pressed Red Cliffs fleet flag should not expose harbor medicine")
if not forward_beans.is_empty():
if pressed_scene._format_talk_status_text(pressed_scene._camp_conversation_entries()) != "Camp conversations | 3 topics | 1 supplies ready":
failures.append("Red Cliffs pressed talk status should show one ready supply")
if not pressed_scene._format_camp_conversation_button_text(forward_beans).contains("Supply Bean"):
failures.append("Red Cliffs forward beans 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(forward_beans)
if int(pressed_scene.campaign_state.get_inventory_snapshot().get("bean", 0)) != before_bean + 1:
failures.append("Red Cliffs forward beans should add Bean to campaign inventory")
if int(pressed_scene.state.get_inventory_snapshot().get("bean", 0)) != before_bean + 1:
failures.append("Red Cliffs forward beans should refresh battle Bean inventory")
if not pressed_scene.campaign_state.has_claimed_camp_conversation_effects(RED_CLIFFS_SCENARIO_ID, RED_CLIFFS_FORWARD_BEANS_CONVERSATION_ID):
failures.append("Red Cliffs forward beans claim should be saved")
if pressed_scene._format_talk_status_text(pressed_scene._camp_conversation_entries()) != "Camp conversations | 3 topics | 1 claimed":
failures.append("Red Cliffs pressed talk status should show claimed supply after claim")
pressed_scene.free()
var harbor_scene = _new_prebattle_scene_for(
failures,
"Red Cliffs secured harbor camp",
RED_CLIFFS_SCENARIO_ID,
RED_CLIFFS_SCENARIO_PATH,
{"secured_xiakou_harbor": true}
)
if harbor_scene != null:
if not harbor_scene.campaign_state.joined_officers.has("zhang_he"):
harbor_scene.campaign_state.joined_officers.append("zhang_he")
if not harbor_scene.state.load_battle(
RED_CLIFFS_SCENARIO_PATH,
harbor_scene.campaign_state.get_roster_overrides(),
harbor_scene.campaign_state.get_inventory_snapshot(),
harbor_scene.campaign_state.get_flags_snapshot(),
harbor_scene.campaign_state.get_joined_officers_snapshot()
):
failures.append("Red Cliffs secured harbor camp should reload with Zhang He joined")
else:
var harbor_medicine: Dictionary = harbor_scene._camp_conversation_by_id(RED_CLIFFS_HARBOR_MEDICINE_CONVERSATION_ID)
if harbor_medicine.is_empty():
failures.append("secured Xiakou harbor flag should expose Red Cliffs harbor medicine")
if not harbor_scene._camp_conversation_by_id(RED_CLIFFS_FORWARD_BEANS_CONVERSATION_ID).is_empty():
failures.append("secured Xiakou harbor flag should not expose Red Cliffs forward beans")
if not harbor_medicine.is_empty():
if harbor_scene._format_talk_status_text(harbor_scene._camp_conversation_entries()) != "Camp conversations | 3 topics | 1 supplies ready":
failures.append("Red Cliffs harbor talk status should show one ready supply")
if not harbor_scene._format_camp_conversation_button_text(harbor_medicine).contains("Supply Panacea"):
failures.append("Red Cliffs harbor medicine button should show Panacea supply")
var before_panacea := int(harbor_scene.campaign_state.get_inventory_snapshot().get("panacea", 0))
harbor_scene._apply_camp_conversation_effects(harbor_medicine)
if int(harbor_scene.campaign_state.get_inventory_snapshot().get("panacea", 0)) != before_panacea + 1:
failures.append("Red Cliffs harbor medicine should add Panacea to campaign inventory")
if int(harbor_scene.state.get_inventory_snapshot().get("panacea", 0)) != before_panacea + 1:
failures.append("Red Cliffs harbor medicine should refresh battle Panacea inventory")
if not harbor_scene.campaign_state.has_claimed_camp_conversation_effects(RED_CLIFFS_SCENARIO_ID, RED_CLIFFS_HARBOR_MEDICINE_CONVERSATION_ID):
failures.append("Red Cliffs harbor medicine claim should be saved")
if harbor_scene._format_talk_status_text(harbor_scene._camp_conversation_entries()) != "Camp conversations | 3 topics | 1 claimed":
failures.append("Red Cliffs harbor talk status should show claimed supply after claim")
harbor_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

@@ -1908,6 +1908,17 @@ func _check_battle_visual_data(failures: Array[String]) -> void:
failures.append("could not load Red Cliffs Fleet data") failures.append("could not load Red Cliffs Fleet data")
else: else:
_check_shop_items_unique(failures, red_cliffs_state, "029 base") _check_shop_items_unique(failures, red_cliffs_state, "029 base")
var red_cliffs_conversations: Array = red_cliffs_state.get_briefing().get("camp_conversations", [])
if red_cliffs_conversations.size() != 2:
failures.append("029 base briefing should expose exactly two camp conversations")
else:
_check_camp_conversation(failures, red_cliffs_conversations[0], "red_cliffs_fleet_council", "topic", "")
_check_camp_conversation(failures, red_cliffs_conversations[1], "red_cliffs_zhang_he_chain_line", "officer", "zhang_he")
var red_cliffs_merchant := red_cliffs_state.get_shop_merchant()
if str(red_cliffs_merchant.get("name", "")) != "Red Cliffs Deck Sutler":
failures.append("029 shop should expose Red Cliffs Deck merchant name")
if (red_cliffs_merchant.get("lines", []) as Array).size() < 2:
failures.append("029 shop should expose merchant flavor lines")
if red_cliffs_state.get_unit("zhang_he_ch29").is_empty() or not red_cliffs_state.is_required_deployment("zhang_he_ch29"): if red_cliffs_state.get_unit("zhang_he_ch29").is_empty() or not red_cliffs_state.is_required_deployment("zhang_he_ch29"):
failures.append("029 should deploy Zhang He as a required officer") failures.append("029 should deploy Zhang He as a required officer")
_check_shop_item_visibility(failures, red_cliffs_state, "war_drum", false, "029 base") _check_shop_item_visibility(failures, red_cliffs_state, "war_drum", false, "029 base")
@@ -1917,6 +1928,19 @@ func _check_battle_visual_data(failures: Array[String]) -> void:
if not red_cliffs_pressed_state.load_battle("res://data/scenarios/029_red_cliffs_fleet.json", {}, {}, {"pressed_red_cliffs_fleet": true}, ["zhang_he"]): if not red_cliffs_pressed_state.load_battle("res://data/scenarios/029_red_cliffs_fleet.json", {}, {}, {"pressed_red_cliffs_fleet": true}, ["zhang_he"]):
failures.append("could not load Red Cliffs pressed fleet data") failures.append("could not load Red Cliffs pressed fleet data")
else: else:
var forward_beans: Dictionary = _find_camp_conversation(
red_cliffs_pressed_state.get_briefing().get("camp_conversations", []),
"red_cliffs_forward_deck_beans"
)
if forward_beans.is_empty():
failures.append("029 pressed Red Cliffs fleet should expose forward deck beans")
else:
_check_camp_conversation_effect(failures, forward_beans, "bean", 1)
if not _find_camp_conversation(
red_cliffs_pressed_state.get_briefing().get("camp_conversations", []),
"red_cliffs_harbor_medicine"
).is_empty():
failures.append("029 pressed Red Cliffs fleet should not expose harbor medicine")
_check_shop_item_visibility(failures, red_cliffs_pressed_state, "war_drum", true, "029 pressed Red Cliffs fleet") _check_shop_item_visibility(failures, red_cliffs_pressed_state, "war_drum", true, "029 pressed Red Cliffs fleet")
_check_shop_item_visibility(failures, red_cliffs_pressed_state, "imperial_seal", false, "029 pressed Red Cliffs fleet") _check_shop_item_visibility(failures, red_cliffs_pressed_state, "imperial_seal", false, "029 pressed Red Cliffs fleet")
@@ -1924,6 +1948,19 @@ func _check_battle_visual_data(failures: Array[String]) -> void:
if not red_cliffs_harbor_state.load_battle("res://data/scenarios/029_red_cliffs_fleet.json", {}, {}, {"secured_xiakou_harbor": true}, ["zhang_he"]): if not red_cliffs_harbor_state.load_battle("res://data/scenarios/029_red_cliffs_fleet.json", {}, {}, {"secured_xiakou_harbor": true}, ["zhang_he"]):
failures.append("could not load Red Cliffs secured Xiakou harbor data") failures.append("could not load Red Cliffs secured Xiakou harbor data")
else: else:
var harbor_medicine: Dictionary = _find_camp_conversation(
red_cliffs_harbor_state.get_briefing().get("camp_conversations", []),
"red_cliffs_harbor_medicine"
)
if harbor_medicine.is_empty():
failures.append("029 secured Xiakou harbor should expose harbor medicine")
else:
_check_camp_conversation_effect(failures, harbor_medicine, "panacea", 1)
if not _find_camp_conversation(
red_cliffs_harbor_state.get_briefing().get("camp_conversations", []),
"red_cliffs_forward_deck_beans"
).is_empty():
failures.append("029 secured Xiakou harbor should not expose forward deck beans")
_check_shop_item_visibility(failures, red_cliffs_harbor_state, "imperial_seal", true, "029 secured Xiakou harbor") _check_shop_item_visibility(failures, red_cliffs_harbor_state, "imperial_seal", true, "029 secured Xiakou harbor")
_check_shop_item_visibility(failures, red_cliffs_harbor_state, "war_drum", false, "029 secured Xiakou harbor") _check_shop_item_visibility(failures, red_cliffs_harbor_state, "war_drum", false, "029 secured Xiakou harbor")
@@ -1934,6 +1971,48 @@ func _check_battle_visual_data(failures: Array[String]) -> void:
_check_shop_items_unique(failures, red_cliffs_old_flags_state, "029 old Xiakou setup flags") _check_shop_items_unique(failures, red_cliffs_old_flags_state, "029 old Xiakou setup flags")
_check_shop_item_visibility(failures, red_cliffs_old_flags_state, "war_drum", false, "029 old Xiakou setup flags") _check_shop_item_visibility(failures, red_cliffs_old_flags_state, "war_drum", false, "029 old Xiakou setup flags")
_check_shop_item_visibility(failures, red_cliffs_old_flags_state, "imperial_seal", false, "029 old Xiakou setup flags") _check_shop_item_visibility(failures, red_cliffs_old_flags_state, "imperial_seal", false, "029 old Xiakou setup flags")
if not _find_camp_conversation(
red_cliffs_old_flags_state.get_briefing().get("camp_conversations", []),
"red_cliffs_forward_deck_beans"
).is_empty():
failures.append("029 old Xiakou setup flags should not expose forward deck beans")
if not _find_camp_conversation(
red_cliffs_old_flags_state.get_briefing().get("camp_conversations", []),
"red_cliffs_harbor_medicine"
).is_empty():
failures.append("029 old Xiakou setup flags should not expose harbor medicine")
var red_fire_state = BattleStateScript.new()
if not red_fire_state.load_battle("res://data/scenarios/030_red_cliffs_fire.json", {}, {}, {}, ["zhang_he"]):
failures.append("could not load Red Cliffs Fire data")
else:
_check_shop_items_unique(failures, red_fire_state, "030 base")
if red_fire_state.get_unit("zhang_he_ch30").is_empty() or not red_fire_state.is_required_deployment("zhang_he_ch30"):
failures.append("030 should deploy Zhang He as a required officer")
_check_shop_item_visibility(failures, red_fire_state, "war_drum", false, "030 base")
_check_shop_item_visibility(failures, red_fire_state, "imperial_seal", false, "030 base")
var red_fire_chain_state = BattleStateScript.new()
if not red_fire_chain_state.load_battle("res://data/scenarios/030_red_cliffs_fire.json", {}, {}, {"reinforced_chain_line": true}, ["zhang_he"]):
failures.append("could not load Red Cliffs Fire reinforced chain data")
else:
_check_shop_item_visibility(failures, red_fire_chain_state, "imperial_seal", true, "030 reinforced chain")
_check_shop_item_visibility(failures, red_fire_chain_state, "war_drum", false, "030 reinforced chain")
var red_fire_raid_state = BattleStateScript.new()
if not red_fire_raid_state.load_battle("res://data/scenarios/030_red_cliffs_fire.json", {}, {}, {"ordered_night_raid": true}, ["zhang_he"]):
failures.append("could not load Red Cliffs Fire night raid data")
else:
_check_shop_item_visibility(failures, red_fire_raid_state, "war_drum", true, "030 ordered night raid")
_check_shop_item_visibility(failures, red_fire_raid_state, "imperial_seal", false, "030 ordered night raid")
var red_fire_old_flags_state = BattleStateScript.new()
if not red_fire_old_flags_state.load_battle("res://data/scenarios/030_red_cliffs_fire.json", {}, {}, {"pressed_red_cliffs_fleet": true, "secured_xiakou_harbor": true}, ["zhang_he"]):
failures.append("could not load Red Cliffs Fire old fleet setup flag data")
else:
_check_shop_items_unique(failures, red_fire_old_flags_state, "030 old Red Cliffs setup flags")
_check_shop_item_visibility(failures, red_fire_old_flags_state, "war_drum", false, "030 old Red Cliffs setup flags")
_check_shop_item_visibility(failures, red_fire_old_flags_state, "imperial_seal", false, "030 old Red Cliffs 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)