# test_energy_system_parity.gd —— 40250 官方能量碎片与水晶熔炼系统 1:1 回归测试套件 extends SceneTree const EnergySystem = preload("res://energy_system.gd") var _passed := 0 var _failed := 0 func _assert(cond: bool, msg: String) -> void: if cond: _passed += 1 print(" [PASS] %s" % msg) else: _failed += 1 printerr(" [FAIL] %s" % msg) func _init() -> void: print("\n=== Running test_energy_system_parity (Direction 1: Energy System 1:1) ===") _test_fragment_extraction() _test_crystal_fusion() _test_crystal_usage_and_buff_lifecycle() _test_serialization() _finish() func _test_fragment_extraction() -> void: print("\n--- Test 1: Energy Fragment Extraction (40250 Quest Rules) ---") var sys := EnergySystem.new() var inv: Array = [ {"vnum": 10, "name": "长剑+0", "level_limit": 1}, {"vnum": 8000, "name": "木箭", "level_limit": 40, "type": 1, "subtype": 5}, {"vnum": 160, "name": "战斗剑+9", "level_limit": 65} ] # 1. Player level too low var res_low_player = sys.extract_energy_fragments(inv, 2, 30) _assert(res_low_player["ok"] == false, "Extraction rejected: player lv 30 < 35") _assert(res_low_player["reason"] == "PLAYER_LEVEL_TOO_LOW", "Reason is PLAYER_LEVEL_TOO_LOW") # 2. Equipment level too low (< 35) var res_low_equip = sys.extract_energy_fragments(inv, 0, 40) _assert(res_low_equip["ok"] == false, "Extraction rejected: equip lv 1 < 35") _assert(res_low_equip["reason"] == "EQUIP_LEVEL_TOO_LOW", "Reason is EQUIP_LEVEL_TOO_LOW") # 3. Arrow weapon prohibited var res_arrow = sys.extract_energy_fragments(inv, 1, 40) _assert(res_arrow["ok"] == false, "Extraction rejected: arrow weapon not allowed") _assert(res_arrow["reason"] == "ARROW_NOT_ALLOWED", "Reason is ARROW_NOT_ALLOWED") var extract_sig := {"fired": false, "cnt": 0} sys.fragments_extracted.connect(func(c: int, _n: String): extract_sig["fired"] = true extract_sig["cnt"] = c ) # 4. Valid extraction of Lv 65 sword var res_succ = sys.extract_energy_fragments(inv, 2, 70) _assert(res_succ["ok"] == true, "Lv 65 sword extracted successfully") _assert(inv[2] != null and inv[2]["vnum"] == EnergySystem.VNUM_ENERGY_STONE, "Slot 2 converted to Energy Stones") _assert(inv[2]["count"] >= 3 and inv[2]["count"] <= 8, "Yield is between 3 and 8 fragments") _assert(extract_sig["fired"] == true, "fragments_extracted signal emitted") func _test_crystal_fusion() -> void: print("\n--- Test 2: Energy Crystal (51002) Fusion (30 Stones + 1000 Gold) ---") var sys := EnergySystem.new() var player_gold := {"gold": 500} # Less than 1000 var inv: Array = [ {"vnum": EnergySystem.VNUM_ENERGY_STONE, "name": "能量碎片", "count": 25}, null ] # 1. Gold not enough var res_no_gold = sys.fuse_energy_crystal(inv, player_gold) _assert(res_no_gold["ok"] == false, "Fusion rejected: gold 500 < 1000") _assert(res_no_gold["reason"] == "NOT_ENOUGH_GOLD", "Reason is NOT_ENOUGH_GOLD") # 2. Stones not enough (25 < 30) player_gold["gold"] = 5000 var res_no_stone = sys.fuse_energy_crystal(inv, player_gold) _assert(res_no_stone["ok"] == false, "Fusion rejected: stones 25 < 30") _assert(res_no_stone["reason"] == "NOT_ENOUGH_STONES", "Reason is NOT_ENOUGH_STONES") # 3. Valid fusion with 35 stones inv[0]["count"] = 35 var fuse_sig := {"fired": false} sys.crystal_fused.connect(func(_c: Dictionary): fuse_sig["fired"] = true ) var res_succ = sys.fuse_energy_crystal(inv, player_gold) _assert(res_succ["ok"] == true, "Fusion succeeded") _assert(player_gold["gold"] == 4000, "1,000 gold deducted (5000 -> 4000)") _assert(inv[0]["count"] == 5, "Stones deducted (35 - 30 = 5 remaining)") _assert(inv[1] != null and inv[1]["vnum"] == EnergySystem.VNUM_CHARGING_STONE, "Energy Crystal generated in slot 1") _assert(fuse_sig["fired"] == true, "crystal_fused signal emitted") func _test_crystal_usage_and_buff_lifecycle() -> void: print("\n--- Test 3: Crystal Usage, 10% Attribute Buff & 2-Hour Lifecycle ---") var sys := EnergySystem.new() var inv: Array = [ {"vnum": EnergySystem.VNUM_CHARGING_STONE, "name": "能量水晶", "count": 1} ] var equipped: Array = [ {"attack_power": 200, "defense": 0, "max_hp": 0}, {"attack_power": 0, "defense": 150, "max_hp": 0}, {"attack_power": 0, "defense": 0, "max_hp": 1000} ] var player_stats := {"attack_power": 500, "defense": 300, "max_hp": 5000} var act_sig := {"fired": false, "dur": 0.0, "pct": 0} sys.energy_activated.connect(func(d: float, p: int): act_sig["fired"] = true act_sig["dur"] = d act_sig["pct"] = p ) var exp_sig := {"fired": false} sys.energy_expired.connect(func(): exp_sig["fired"] = true ) # Use crystal var use_res = sys.use_energy_crystal(inv, 0, equipped, player_stats) _assert(use_res["ok"] == true, "Crystal activated") _assert(sys.is_energy_active == true, "is_energy_active is true") _assert(inv[0] == null, "Energy crystal consumed from inventory") _assert(act_sig["fired"] == true, "energy_activated signal emitted") _assert(act_sig["dur"] == 7200.0, "Duration is 7200.0s (2 hours)") # Check 10% stats: # atk: 500 + 20 = 520 # def: 300 + 15 = 315 # hp: 5000 + 100 = 5100 _assert(player_stats["attack_power"] == 520, "Attack boosted by 10% of 200 = +20") _assert(player_stats["defense"] == 315, "Defense boosted by 10% of 150 = +15") _assert(player_stats["max_hp"] == 5100, "HP boosted by 10% of 1000 = +100") # Advance time 7200s -> timeout sys.update(7200.0, player_stats) _assert(sys.is_energy_active == false, "Energy expired after 2 hours") _assert(player_stats["attack_power"] == 500, "Attack cleanly reversed back to 500") _assert(player_stats["defense"] == 300, "Defense cleanly reversed back to 300") _assert(player_stats["max_hp"] == 5000, "HP cleanly reversed back to 5000") _assert(exp_sig["fired"] == true, "energy_expired signal emitted") func _test_serialization() -> void: print("\n--- Test 4: Serialization & Restoration ---") var sys1 := EnergySystem.new() sys1.is_energy_active = true sys1.energy_time_remaining = 3600.0 sys1.applied_bonuses = {"attack_power": 25, "defense": 18} var data = sys1.serialize() var sys2 := EnergySystem.new() sys2.deserialize(data) _assert(sys2.is_energy_active == true, "Restored is_energy_active") _assert(is_equal_approx(sys2.energy_time_remaining, 3600.0), "Restored time remaining") _assert(sys2.applied_bonuses["attack_power"] == 25, "Restored attack bonus") func _finish() -> void: print("\n=======================================================") print("Energy System Parity Tests: %d Passed, %d Failed" % [_passed, _failed]) print("=======================================================\n") if _failed > 0: quit(1) else: quit(0)