213 lines
9.2 KiB
GDScript
213 lines
9.2 KiB
GDScript
extends SceneTree
|
|
|
|
const BattleStateScript := preload("res://scripts/core/battle_state.gd")
|
|
const BattleSceneScript := preload("res://scripts/scenes/battle_scene.gd")
|
|
|
|
|
|
func _init() -> void:
|
|
var failures: Array[String] = []
|
|
_check_core_unequip_contract(failures)
|
|
_check_unequip_guards(failures)
|
|
_check_armor_bonus_removal(failures)
|
|
_check_snapshot_reload_and_sell_stock(failures)
|
|
_check_unequip_ui_entries(failures)
|
|
|
|
if failures.is_empty():
|
|
print("equipment unequip smoke ok")
|
|
quit(0)
|
|
return
|
|
|
|
for failure in failures:
|
|
push_error(failure)
|
|
quit(1)
|
|
|
|
|
|
func _check_core_unequip_contract(failures: Array[String]) -> void:
|
|
var state = _loaded_state(failures, "core unequip")
|
|
if state == null:
|
|
return
|
|
|
|
var cao_cao: Dictionary = state.get_unit("cao_cao")
|
|
var before_atk := int(cao_cao.get("atk", 0))
|
|
var before_inventory: Dictionary = state.get_inventory_snapshot()
|
|
var weapon_item: Dictionary = state.get_item_def("bronze_sword")
|
|
var weapon_bonus := int(weapon_item.get("bonuses", {}).get("atk", 0))
|
|
|
|
if not state.get_equipped_equipment_slots("cao_cao").has("weapon"):
|
|
failures.append("Cao Cao should expose an equipped weapon slot")
|
|
if not state.try_unequip_item("cao_cao", "weapon"):
|
|
failures.append("Cao Cao should be able to unequip Bronze Sword before acting")
|
|
return
|
|
|
|
var after_unit: Dictionary = state.get_unit("cao_cao")
|
|
var after_equipment: Dictionary = state.get_equipment_snapshot("cao_cao")
|
|
var after_inventory: Dictionary = state.get_inventory_snapshot()
|
|
if after_equipment.has("weapon"):
|
|
failures.append("weapon slot should be removed after unequip: %s" % str(after_equipment))
|
|
if int(after_inventory.get("bronze_sword", 0)) != int(before_inventory.get("bronze_sword", 0)) + 1:
|
|
failures.append("unequip should return Bronze Sword to inventory")
|
|
if int(after_unit.get("atk", 0)) != before_atk - weapon_bonus:
|
|
failures.append("unequip should remove weapon ATK bonus: before %d after %d bonus %d" % [
|
|
before_atk,
|
|
int(after_unit.get("atk", 0)),
|
|
weapon_bonus
|
|
])
|
|
if int(after_unit.get("range", 0)) != 1 or int(after_unit.get("min_range", 0)) != 1:
|
|
failures.append("unequipped Cao Cao should return to class attack range 1-1")
|
|
|
|
var inventory_after_first: Dictionary = state.get_inventory_snapshot()
|
|
if state.try_unequip_item("cao_cao", "weapon"):
|
|
failures.append("unequipping an empty weapon slot should fail")
|
|
var inventory_after_repeat: Dictionary = state.get_inventory_snapshot()
|
|
if int(inventory_after_repeat.get("bronze_sword", 0)) != int(inventory_after_first.get("bronze_sword", 0)):
|
|
failures.append("failed repeat unequip should not duplicate inventory")
|
|
|
|
if not state.try_equip_item("cao_cao", "bronze_sword"):
|
|
failures.append("returned Bronze Sword should be equippable again")
|
|
var reequip_unit: Dictionary = state.get_unit("cao_cao")
|
|
var reequip_inventory: Dictionary = state.get_inventory_snapshot()
|
|
if int(reequip_unit.get("atk", 0)) != before_atk:
|
|
failures.append("re-equipping should restore weapon ATK")
|
|
if int(reequip_inventory.get("bronze_sword", 0)) != int(before_inventory.get("bronze_sword", 0)):
|
|
failures.append("re-equipping should consume the returned weapon stock")
|
|
|
|
|
|
func _check_unequip_guards(failures: Array[String]) -> void:
|
|
var state = _loaded_state(failures, "unequip guards")
|
|
if state == null:
|
|
return
|
|
|
|
var before_equipment: Dictionary = state.get_equipment_snapshot("cao_cao")
|
|
var before_inventory: Dictionary = state.get_inventory_snapshot()
|
|
|
|
var cao_cao: Dictionary = state.get_unit("cao_cao")
|
|
cao_cao["moved"] = true
|
|
if state.try_unequip_item("cao_cao", "weapon"):
|
|
failures.append("moved units should not be able to unequip")
|
|
cao_cao["moved"] = false
|
|
cao_cao["acted"] = true
|
|
if state.try_unequip_item("cao_cao", "weapon"):
|
|
failures.append("acted units should not be able to unequip")
|
|
cao_cao["acted"] = false
|
|
|
|
var enemy: Dictionary = state.get_unit("yellow_turban_1")
|
|
enemy["equipment"] = {"weapon": "bronze_sword"}
|
|
if state.try_unequip_item("yellow_turban_1", "weapon"):
|
|
failures.append("enemy units should not be able to unequip")
|
|
|
|
var protected_state = BattleStateScript.new()
|
|
if protected_state.load_battle("res://data/scenarios/007_xian_emperor_escort.json"):
|
|
var envoy: Dictionary = protected_state.get_unit("protected_envoy")
|
|
envoy["equipment"] = {"weapon": "bronze_sword"}
|
|
if protected_state.try_unequip_item("protected_envoy", "weapon"):
|
|
failures.append("non-controllable protected units should not be able to unequip")
|
|
else:
|
|
failures.append("could not load protected-unit scenario for unequip guard")
|
|
|
|
if state.get_equipment_snapshot("cao_cao") != before_equipment:
|
|
failures.append("failed guard unequips should not alter Cao Cao equipment")
|
|
if state.get_inventory_snapshot() != before_inventory:
|
|
failures.append("failed guard unequips should not alter inventory")
|
|
|
|
|
|
func _check_armor_bonus_removal(failures: Array[String]) -> void:
|
|
var state = _loaded_state(failures, "armor bonus removal")
|
|
if state == null:
|
|
return
|
|
var cao_cao: Dictionary = state.get_unit("cao_cao")
|
|
var base_max_mp := int(cao_cao.get("max_mp", 0))
|
|
var base_mp := int(cao_cao.get("mp", 0))
|
|
var base_def := int(cao_cao.get("def", 0))
|
|
var base_int := int(cao_cao.get("int", 0))
|
|
|
|
state.set_inventory_snapshot({"black_tortoise_robe": 1})
|
|
if not state.try_equip_item("cao_cao", "black_tortoise_robe"):
|
|
failures.append("Cao Cao should be able to equip Black Tortoise Robe for armor unequip test")
|
|
return
|
|
var equipped: Dictionary = state.get_unit("cao_cao")
|
|
if int(equipped.get("max_mp", 0)) != base_max_mp + 2:
|
|
failures.append("Black Tortoise Robe should add max MP")
|
|
if int(equipped.get("def", 0)) != base_def + 2:
|
|
failures.append("Black Tortoise Robe should replace Cloth Robe with net DEF +2")
|
|
if int(equipped.get("int", 0)) != base_int + 1:
|
|
failures.append("Black Tortoise Robe should add INT")
|
|
|
|
if not state.try_unequip_item("cao_cao", "armor"):
|
|
failures.append("Cao Cao should be able to unequip armor")
|
|
return
|
|
var unequipped: Dictionary = state.get_unit("cao_cao")
|
|
if int(unequipped.get("max_mp", 0)) != base_max_mp:
|
|
failures.append("armor unequip should remove max MP bonus")
|
|
if int(unequipped.get("mp", 0)) != mini(base_mp, base_max_mp):
|
|
failures.append("armor unequip should clamp current MP to restored max")
|
|
if int(unequipped.get("def", 0)) != base_def - 1:
|
|
failures.append("empty armor slot should remove all armor DEF bonus")
|
|
if int(unequipped.get("int", 0)) != base_int:
|
|
failures.append("armor unequip should remove INT bonus")
|
|
var inventory: Dictionary = state.get_inventory_snapshot()
|
|
if int(inventory.get("black_tortoise_robe", 0)) != 1:
|
|
failures.append("armor unequip should return Black Tortoise Robe to inventory")
|
|
|
|
|
|
func _check_snapshot_reload_and_sell_stock(failures: Array[String]) -> void:
|
|
var state = _loaded_state(failures, "snapshot reload")
|
|
if state == null:
|
|
return
|
|
if not state.try_unequip_item("cao_cao", "weapon"):
|
|
failures.append("could not unequip weapon before snapshot reload")
|
|
return
|
|
|
|
var roster_snapshot: Dictionary = state.get_player_roster_snapshot()
|
|
var inventory_snapshot: Dictionary = state.get_inventory_snapshot()
|
|
var reloaded = BattleStateScript.new()
|
|
if not reloaded.load_battle("res://data/scenarios/001_yellow_turbans.json", roster_snapshot, inventory_snapshot):
|
|
failures.append("could not reload battle from unequipped roster snapshot")
|
|
return
|
|
var reloaded_equipment: Dictionary = reloaded.get_equipment_snapshot("cao_cao")
|
|
if reloaded_equipment.has("weapon"):
|
|
failures.append("roster snapshot reload should keep weapon slot empty: %s" % str(reloaded_equipment))
|
|
if int(reloaded.get_inventory_snapshot().get("bronze_sword", 0)) != int(inventory_snapshot.get("bronze_sword", 0)):
|
|
failures.append("inventory snapshot reload should keep returned weapon stock")
|
|
|
|
var scene = BattleSceneScript.new()
|
|
scene._create_hud()
|
|
scene.state.load_battle("res://data/scenarios/001_yellow_turbans.json", roster_snapshot, inventory_snapshot)
|
|
scene.campaign_state.inventory = inventory_snapshot.duplicate(true)
|
|
var sellable: Array = scene._get_sellable_item_ids()
|
|
if not sellable.has("bronze_sword"):
|
|
failures.append("returned unequipped weapon should appear in shop sell stock")
|
|
scene.free()
|
|
|
|
|
|
func _check_unequip_ui_entries(failures: Array[String]) -> void:
|
|
var scene = BattleSceneScript.new()
|
|
scene._create_hud()
|
|
scene.state.load_battle("res://data/scenarios/001_yellow_turbans.json")
|
|
|
|
var selected: Dictionary = scene.state.get_unit("cao_cao")
|
|
scene._rebuild_equip_menu(selected)
|
|
if not _container_has_button_text(scene.equip_list, "병장 해제:"):
|
|
failures.append("battle equipment menu should include an Unequip Weapon button")
|
|
|
|
scene.armory_unit_id = "cao_cao"
|
|
scene._rebuild_armory_menu()
|
|
if not _container_has_button_text(scene.armory_list, "병장 해제:"):
|
|
failures.append("pre-battle Armory should include an Unequip Weapon button")
|
|
|
|
scene.free()
|
|
|
|
|
|
func _container_has_button_text(container: Node, fragment: String) -> bool:
|
|
for child in container.get_children():
|
|
if child is Button and str(child.text).contains(fragment):
|
|
return true
|
|
return false
|
|
|
|
|
|
func _loaded_state(failures: Array[String], label: String):
|
|
var state = BattleStateScript.new()
|
|
if not state.load_battle("res://data/scenarios/001_yellow_turbans.json"):
|
|
failures.append("%s could not load opening scenario" % label)
|
|
return null
|
|
return state
|