Add Liaoxi camp and White Wolf bridge

This commit is contained in:
2026-06-19 02:55:26 +09:00
parent 9d31448573
commit 10c8fb5255
4 changed files with 330 additions and 2 deletions

View File

@@ -32,6 +32,59 @@
"Secured depots and guides now anchor the advance, letting Cao Cao's army cross the frontier roads with fewer blind corners." "Secured depots and guides now anchor the advance, letting Cao Cao's army cross the frontier roads with fewer blind corners."
] ]
} }
],
"camp_conversations": [
{
"id": "liaoxi_frontier_council",
"group": "topic",
"label": "Frontier Council",
"speaker": "Cao Cao",
"summary": "Decide how to read the frontier before the Yuan envoys reach Wuhuan tents.",
"lines": [
{ "speaker": "Cao Cao", "side": "left", "text": "Cities have gates. Frontiers have rumors, gifts, and riders who arrive before orders." },
{ "speaker": "Guo Jia", "side": "right", "text": "Then we do not chase only the envoys. We chase the rumor that says the Yuan brothers still have a road." },
{ "speaker": "Zhang He", "side": "right", "text": "Their scouts will mark the hills and ignore the dry road. That is where our column can move unseen." }
]
},
{
"id": "liaoxi_zhang_he_hill_roads",
"group": "officer",
"officer_id": "zhang_he",
"label": "Zhang He - Hill Roads",
"summary": "Read the road signs Zhang He learned while guarding Yuan retreats.",
"lines": [
{ "speaker": "Zhang He", "side": "right", "text": "The Yuan envoys trust old courier marks. Break those marks, and every rider behind them arrives late." },
{ "speaker": "Cao Cao", "side": "left", "text": "Good. Let their allies find dust where a road should be." }
]
},
{
"id": "liaoxi_fast_pursuit_drums",
"group": "topic",
"label": "Fast Pursuit Drums",
"summary": "The rushed Liaoxi march leaves spare signal drums for a harder opening blow.",
"campaign_flags": { "pressed_liaoxi_pursuit": true },
"effects": [
{ "type": "grant_item", "item_id": "war_drum", "count": 1, "text": "The fast pursuit drums add a War Drum to the field supplies." }
],
"lines": [
{ "speaker": "Xiahou Yuan", "side": "left", "text": "The men carried light and kept the drums dry. One sharp beat and the vanguard moves before the envoys breathe." },
{ "speaker": "Cao Cao", "side": "right", "text": "Keep that beat for the first ridge." }
]
},
{
"id": "liaoxi_approach_medicine",
"group": "topic",
"label": "Approach Medicine",
"summary": "The secured approach road brings frontier dressings into the field stores.",
"campaign_flags": { "secured_liaoxi_approaches": true },
"effects": [
{ "type": "grant_item", "item_id": "panacea", "count": 1, "text": "The Liaoxi approach medicine adds a Panacea to the field supplies." }
],
"lines": [
{ "speaker": "Cao Ren", "side": "left", "text": "The guide wagons reached us with dressings and bitter herbs. The road behind us is not empty." },
{ "speaker": "Cao Cao", "side": "right", "text": "A held road is another shield. Send the medicine forward." }
]
}
] ]
}, },
"shop": { "shop": {
@@ -55,7 +108,14 @@
"campaign_flags": { "secured_liaoxi_approaches": true }, "campaign_flags": { "secured_liaoxi_approaches": true },
"items": ["imperial_seal"] "items": ["imperial_seal"]
} }
] ],
"merchant": {
"name": "Liaoxi Frontier Sutler",
"lines": [
"Liaoxi coin spends quickly, my lord. Riders sell news first, then arrows.",
"Buy before the Wuhuan tents hear the Yuan brothers' names spoken with gifts."
]
}
}, },
"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

@@ -82,6 +82,10 @@ const BOHAI_FAST_COLUMN_CONVERSATION_ID := "bohai_remnants_fast_column_wine"
const BOHAI_COMMANDERY_CONVERSATION_ID := "bohai_remnants_commandery_medicine" const BOHAI_COMMANDERY_CONVERSATION_ID := "bohai_remnants_commandery_medicine"
const LIAOXI_SCENARIO_ID := "022_liaoxi_pursuit" const LIAOXI_SCENARIO_ID := "022_liaoxi_pursuit"
const LIAOXI_SCENARIO_PATH := "res://data/scenarios/022_liaoxi_pursuit.json" const LIAOXI_SCENARIO_PATH := "res://data/scenarios/022_liaoxi_pursuit.json"
const LIAOXI_FAST_DRUMS_CONVERSATION_ID := "liaoxi_fast_pursuit_drums"
const LIAOXI_APPROACH_MEDICINE_CONVERSATION_ID := "liaoxi_approach_medicine"
const WHITE_WOLF_SCENARIO_ID := "023_white_wolf_mountain"
const WHITE_WOLF_SCENARIO_PATH := "res://data/scenarios/023_white_wolf_mountain.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"
@@ -112,6 +116,7 @@ func _init() -> void:
_check_nanpi_post_battle_choice_bridges_to_surrender(failures) _check_nanpi_post_battle_choice_bridges_to_surrender(failures)
_check_nanpi_surrender_post_battle_choice_bridges_to_bohai(failures) _check_nanpi_surrender_post_battle_choice_bridges_to_bohai(failures)
_check_bohai_post_battle_choice_bridges_to_liaoxi(failures) _check_bohai_post_battle_choice_bridges_to_liaoxi(failures)
_check_liaoxi_post_battle_choice_bridges_to_white_wolf(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)
@@ -125,6 +130,7 @@ func _init() -> void:
_check_nanpi_branch_camp_conversations(failures) _check_nanpi_branch_camp_conversations(failures)
_check_nanpi_surrender_branch_camp_conversations(failures) _check_nanpi_surrender_branch_camp_conversations(failures)
_check_bohai_branch_camp_conversations(failures) _check_bohai_branch_camp_conversations(failures)
_check_liaoxi_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):
@@ -1174,6 +1180,25 @@ func _check_bohai_post_battle_choice_bridges_to_liaoxi(failures: Array[String])
) )
func _check_liaoxi_post_battle_choice_bridges_to_white_wolf(failures: Array[String]) -> void:
_check_liaoxi_choice_branch_to_white_wolf(
failures,
"strike_wuhuan_vanguard",
"struck_wuhuan_vanguard",
"fortified_white_wolf_route",
"war_drum",
"imperial_seal"
)
_check_liaoxi_choice_branch_to_white_wolf(
failures,
"fortify_white_wolf_route",
"fortified_white_wolf_route",
"struck_wuhuan_vanguard",
"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,
@@ -1831,6 +1856,79 @@ func _check_bohai_choice_branch_to_liaoxi(
scene.free() scene.free()
func _check_liaoxi_choice_branch_to_white_wolf(
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, "Liaoxi choice bridge %s" % choice_id, LIAOXI_SCENARIO_ID, LIAOXI_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(
LIAOXI_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("Liaoxi choice bridge %s could not reload Liaoxi 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("Liaoxi choice bridge %s should save 022 victory" % choice_id)
scene.free()
return
if not scene.campaign_state.get_joined_officers_snapshot().has("zhang_he"):
failures.append("Liaoxi choice bridge %s should keep Zhang He before White Wolf" % choice_id)
if bool(result.get("choice_applied", true)):
failures.append("Liaoxi choice bridge %s should wait for a selected post-battle choice" % choice_id)
if scene.campaign_state.pending_post_battle_choice_scenario_id != LIAOXI_SCENARIO_ID:
failures.append("Liaoxi choice bridge %s should mark Liaoxi choice pending" % choice_id)
var choice := _find_choice_by_id(result.get("post_battle_choices", []), choice_id)
if choice.is_empty():
failures.append("Liaoxi choice bridge missing choice: %s" % choice_id)
scene.free()
return
if not scene.campaign_state.try_apply_post_battle_choice(choice, LIAOXI_SCENARIO_ID):
failures.append("Liaoxi 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("Liaoxi choice bridge %s should set %s" % [choice_id, expected_flag])
if flags.get(cleared_flag, true) != false:
failures.append("Liaoxi choice bridge %s should clear %s" % [choice_id, cleared_flag])
if scene.campaign_state.current_scenario_id != WHITE_WOLF_SCENARIO_ID:
failures.append("Liaoxi choice bridge %s should advance to White Wolf, got %s" % [choice_id, scene.campaign_state.current_scenario_id])
if not scene.state.load_battle(
WHITE_WOLF_SCENARIO_PATH,
scene.campaign_state.get_roster_overrides(),
scene.campaign_state.get_inventory_snapshot(),
flags,
scene.campaign_state.get_joined_officers_snapshot()
):
failures.append("Liaoxi choice bridge %s could not load White Wolf" % choice_id)
scene.free()
return
if scene.state.get_unit("zhang_he_ch23").is_empty():
failures.append("Liaoxi choice bridge %s should deploy Zhang He in White Wolf" % choice_id)
elif not scene.state.is_required_deployment("zhang_he_ch23"):
failures.append("Liaoxi choice bridge %s should require Zhang He in White Wolf" % choice_id)
var shop_items: Array = scene.state.get_shop_item_ids()
if not shop_items.has(expected_shop_item_id):
failures.append("Liaoxi choice bridge %s should expose shop item %s" % [choice_id, expected_shop_item_id])
if shop_items.has(hidden_shop_item_id):
failures.append("Liaoxi 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 {}
@@ -2752,6 +2850,88 @@ func _check_bohai_branch_camp_conversations(failures: Array[String]) -> void:
secured_scene.free() secured_scene.free()
func _check_liaoxi_branch_camp_conversations(failures: Array[String]) -> void:
var base_scene = _new_prebattle_scene_for(failures, "Liaoxi base camp", LIAOXI_SCENARIO_ID, LIAOXI_SCENARIO_PATH)
if base_scene != null:
if base_scene._camp_conversation_by_id("liaoxi_frontier_council").is_empty():
failures.append("Liaoxi should expose the frontier council conversation")
if base_scene._camp_conversation_by_id("liaoxi_zhang_he_hill_roads").is_empty():
failures.append("Liaoxi should expose Zhang He's hill roads conversation")
if not base_scene._camp_conversation_by_id(LIAOXI_FAST_DRUMS_CONVERSATION_ID).is_empty():
failures.append("Liaoxi fast drums should be hidden without pressed Liaoxi flag")
if not base_scene._camp_conversation_by_id(LIAOXI_APPROACH_MEDICINE_CONVERSATION_ID).is_empty():
failures.append("Liaoxi approach medicine should be hidden without secured Liaoxi flag")
var merchant: Dictionary = base_scene.state.get_shop_merchant()
if str(merchant.get("name", "")) != "Liaoxi Frontier Sutler":
failures.append("Liaoxi shop merchant name should be present")
var merchant_lines: Array = merchant.get("lines", [])
if merchant_lines.size() < 2:
failures.append("Liaoxi shop merchant should expose flavor lines")
if base_scene._format_talk_status_text(base_scene._camp_conversation_entries()) != "Camp conversations | 2 topics":
failures.append("Liaoxi base talk status should summarize two non-supply topics")
base_scene.free()
var pressed_scene = _new_prebattle_scene_for(
failures,
"Liaoxi pressed camp",
LIAOXI_SCENARIO_ID,
LIAOXI_SCENARIO_PATH,
{"pressed_liaoxi_pursuit": true}
)
if pressed_scene != null:
var fast_drums: Dictionary = pressed_scene._camp_conversation_by_id(LIAOXI_FAST_DRUMS_CONVERSATION_ID)
if fast_drums.is_empty():
failures.append("pressed Liaoxi flag should expose Liaoxi fast drums")
if not pressed_scene._camp_conversation_by_id(LIAOXI_APPROACH_MEDICINE_CONVERSATION_ID).is_empty():
failures.append("pressed Liaoxi flag should not expose Liaoxi approach medicine")
if not fast_drums.is_empty():
if pressed_scene._format_talk_status_text(pressed_scene._camp_conversation_entries()) != "Camp conversations | 3 topics | 1 supplies ready":
failures.append("Liaoxi pressed talk status should show one ready supply")
if not pressed_scene._format_camp_conversation_button_text(fast_drums).contains("Supply War Drum"):
failures.append("Liaoxi fast drums button should show War Drum supply")
var before_drums := int(pressed_scene.campaign_state.get_inventory_snapshot().get("war_drum", 0))
pressed_scene._apply_camp_conversation_effects(fast_drums)
if int(pressed_scene.campaign_state.get_inventory_snapshot().get("war_drum", 0)) != before_drums + 1:
failures.append("Liaoxi fast drums should add War Drum to campaign inventory")
if int(pressed_scene.state.get_inventory_snapshot().get("war_drum", 0)) != before_drums + 1:
failures.append("Liaoxi fast drums should refresh battle War Drum inventory")
if not pressed_scene.campaign_state.has_claimed_camp_conversation_effects(LIAOXI_SCENARIO_ID, LIAOXI_FAST_DRUMS_CONVERSATION_ID):
failures.append("Liaoxi fast drums claim should be saved")
if pressed_scene._format_talk_status_text(pressed_scene._camp_conversation_entries()) != "Camp conversations | 3 topics | 1 claimed":
failures.append("Liaoxi pressed talk status should show claimed supply after claim")
pressed_scene.free()
var secured_scene = _new_prebattle_scene_for(
failures,
"Liaoxi secured camp",
LIAOXI_SCENARIO_ID,
LIAOXI_SCENARIO_PATH,
{"secured_liaoxi_approaches": true}
)
if secured_scene != null:
var approach_medicine: Dictionary = secured_scene._camp_conversation_by_id(LIAOXI_APPROACH_MEDICINE_CONVERSATION_ID)
if approach_medicine.is_empty():
failures.append("secured Liaoxi flag should expose Liaoxi approach medicine")
if not secured_scene._camp_conversation_by_id(LIAOXI_FAST_DRUMS_CONVERSATION_ID).is_empty():
failures.append("secured Liaoxi flag should not expose Liaoxi fast drums")
if not approach_medicine.is_empty():
if secured_scene._format_talk_status_text(secured_scene._camp_conversation_entries()) != "Camp conversations | 3 topics | 1 supplies ready":
failures.append("Liaoxi secured talk status should show one ready supply")
if not secured_scene._format_camp_conversation_button_text(approach_medicine).contains("Supply Panacea"):
failures.append("Liaoxi approach medicine button should show Panacea supply")
var before_panacea := int(secured_scene.campaign_state.get_inventory_snapshot().get("panacea", 0))
secured_scene._apply_camp_conversation_effects(approach_medicine)
if int(secured_scene.campaign_state.get_inventory_snapshot().get("panacea", 0)) != before_panacea + 1:
failures.append("Liaoxi approach medicine should add Panacea to campaign inventory")
if int(secured_scene.state.get_inventory_snapshot().get("panacea", 0)) != before_panacea + 1:
failures.append("Liaoxi approach medicine should refresh battle Panacea inventory")
if not secured_scene.campaign_state.has_claimed_camp_conversation_effects(LIAOXI_SCENARIO_ID, LIAOXI_APPROACH_MEDICINE_CONVERSATION_ID):
failures.append("Liaoxi approach medicine claim should be saved")
if secured_scene._format_talk_status_text(secured_scene._camp_conversation_entries()) != "Camp conversations | 3 topics | 1 claimed":
failures.append("Liaoxi secured talk status should show claimed supply after claim")
secured_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

@@ -1344,6 +1344,94 @@ func _check_battle_visual_data(failures: Array[String]) -> void:
).is_empty(): ).is_empty():
failures.append("021 old Nanpi Surrender flags should not expose commandery medicine") failures.append("021 old Nanpi Surrender flags should not expose commandery medicine")
var liaoxi_state = BattleStateScript.new()
if not liaoxi_state.load_battle("res://data/scenarios/022_liaoxi_pursuit.json", {}, {}, {}, ["zhang_he"]):
failures.append("could not load Liaoxi Pursuit camp data")
else:
_check_shop_items_unique(failures, liaoxi_state, "022 base")
var liaoxi_conversations: Array = liaoxi_state.get_briefing().get("camp_conversations", [])
if liaoxi_conversations.size() != 2:
failures.append("022 base briefing should expose exactly two camp conversations")
else:
_check_camp_conversation(failures, liaoxi_conversations[0], "liaoxi_frontier_council", "topic", "")
_check_camp_conversation(failures, liaoxi_conversations[1], "liaoxi_zhang_he_hill_roads", "officer", "zhang_he")
var liaoxi_merchant := liaoxi_state.get_shop_merchant()
if str(liaoxi_merchant.get("name", "")) != "Liaoxi Frontier Sutler":
failures.append("022 shop should expose Liaoxi Frontier merchant name")
if (liaoxi_merchant.get("lines", []) as Array).size() < 2:
failures.append("022 shop should expose merchant flavor lines")
if liaoxi_state.get_unit("zhang_he_ch22").is_empty() or not liaoxi_state.is_required_deployment("zhang_he_ch22"):
failures.append("022 should deploy Zhang He as a required officer")
_check_shop_item_visibility(failures, liaoxi_state, "war_drum", false, "022 base")
_check_shop_item_visibility(failures, liaoxi_state, "imperial_seal", false, "022 base")
_check_shop_item_visibility(failures, liaoxi_state, "iron_armor", true, "022 base")
var liaoxi_pressed_state = BattleStateScript.new()
if not liaoxi_pressed_state.load_battle("res://data/scenarios/022_liaoxi_pursuit.json", {}, {}, {"pressed_liaoxi_pursuit": true}, ["zhang_he"]):
failures.append("could not load Liaoxi pressed pursuit camp data")
else:
_check_shop_items_unique(failures, liaoxi_pressed_state, "022 pressed Liaoxi")
var fast_drums: Dictionary = _find_camp_conversation(
liaoxi_pressed_state.get_briefing().get("camp_conversations", []),
"liaoxi_fast_pursuit_drums"
)
if fast_drums.is_empty():
failures.append("022 pressed Liaoxi flag should expose fast pursuit drums")
else:
_check_camp_conversation_effect(failures, fast_drums, "war_drum", 1)
if not _find_camp_conversation(
liaoxi_pressed_state.get_briefing().get("camp_conversations", []),
"liaoxi_approach_medicine"
).is_empty():
failures.append("022 pressed Liaoxi flag should not expose approach medicine")
_check_shop_item_visibility(failures, liaoxi_pressed_state, "war_drum", true, "022 pressed Liaoxi")
_check_shop_item_visibility(failures, liaoxi_pressed_state, "imperial_seal", false, "022 pressed Liaoxi")
var liaoxi_secured_state = BattleStateScript.new()
if not liaoxi_secured_state.load_battle("res://data/scenarios/022_liaoxi_pursuit.json", {}, {}, {"secured_liaoxi_approaches": true}, ["zhang_he"]):
failures.append("could not load Liaoxi secured approaches camp data")
else:
_check_shop_items_unique(failures, liaoxi_secured_state, "022 secured Liaoxi")
var approach_medicine: Dictionary = _find_camp_conversation(
liaoxi_secured_state.get_briefing().get("camp_conversations", []),
"liaoxi_approach_medicine"
)
if approach_medicine.is_empty():
failures.append("022 secured Liaoxi flag should expose approach medicine")
else:
_check_camp_conversation_effect(failures, approach_medicine, "panacea", 1)
if not _find_camp_conversation(
liaoxi_secured_state.get_briefing().get("camp_conversations", []),
"liaoxi_fast_pursuit_drums"
).is_empty():
failures.append("022 secured Liaoxi flag should not expose fast pursuit drums")
_check_shop_item_visibility(failures, liaoxi_secured_state, "war_drum", false, "022 secured Liaoxi")
_check_shop_item_visibility(failures, liaoxi_secured_state, "imperial_seal", true, "022 secured Liaoxi")
var liaoxi_old_flags_state = BattleStateScript.new()
if not liaoxi_old_flags_state.load_battle("res://data/scenarios/022_liaoxi_pursuit.json", {}, {}, {"pursued_yuan_brothers": true, "secured_bohai_commandery": true}, ["zhang_he"]):
failures.append("could not load Liaoxi old Bohai flag camp data")
else:
_check_shop_item_visibility(failures, liaoxi_old_flags_state, "war_drum", false, "022 old Bohai flags")
_check_shop_item_visibility(failures, liaoxi_old_flags_state, "imperial_seal", false, "022 old Bohai flags")
if not _find_camp_conversation(
liaoxi_old_flags_state.get_briefing().get("camp_conversations", []),
"liaoxi_fast_pursuit_drums"
).is_empty():
failures.append("022 old Bohai flags should not expose fast pursuit drums")
if not _find_camp_conversation(
liaoxi_old_flags_state.get_briefing().get("camp_conversations", []),
"liaoxi_approach_medicine"
).is_empty():
failures.append("022 old Bohai flags should not expose approach medicine")
var white_wolf_state = BattleStateScript.new()
if not white_wolf_state.load_battle("res://data/scenarios/023_white_wolf_mountain.json", {}, {}, {}, ["zhang_he"]):
failures.append("could not load White Wolf Mountain data")
else:
if white_wolf_state.get_unit("zhang_he_ch23").is_empty() or not white_wolf_state.is_required_deployment("zhang_he_ch23"):
failures.append("023 should deploy Zhang He as a required officer")
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():