# test_metin_spawn_event_parity.gd —— 40250 野外 8 档魔石与怪潮暴动 1:1 回归测试套件 extends SceneTree const MetinSpawnEventSystem = preload("res://metin_spawn_event_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_metin_spawn_event_parity (Direction 3: Field Metin Spawn & Waves 1:1) ===") _test_table_configuration() _test_spawn_metin() _test_damage_and_phases() _test_destruction_and_drops() _test_invalid_inputs() _finish() func _test_table_configuration() -> void: print("\n--- Test 1: Metin Table Configuration (8008~8014, 8027) ---") var expected_vnums = [8008, 8009, 8010, 8011, 8012, 8013, 8014, 8027] _assert(MetinSpawnEventSystem.METIN_TABLE.size() == 8, "Table has exactly 8 Metin stone types") for vnum in expected_vnums: _assert(MetinSpawnEventSystem.METIN_TABLE.has(vnum), "Has Metin stone %d" % vnum) var entry = MetinSpawnEventSystem.METIN_TABLE[vnum] _assert(entry.has("name") and entry.has("level") and entry.has("max_hp") and entry.has("def") and entry.has("wave_mob") and entry.has("wave_count"), "Metin %d has all required fields" % vnum) _assert(entry["max_hp"] > 0 and entry["def"] > 0 and entry["wave_count"] > 0, "Metin %d has positive stats" % vnum) func _test_spawn_metin() -> void: print("\n--- Test 2: Spawning Metin Stones ---") var sys := MetinSpawnEventSystem.new() var spawn_sig := {"fired": false, "vnum": 0, "name": "", "pos": Vector3.ZERO} sys.metin_spawned.connect(func(v: int, n: String, p: Vector3): spawn_sig["fired"] = true spawn_sig["vnum"] = v spawn_sig["name"] = n spawn_sig["pos"] = p ) var spawn_pos := Vector3(100.5, 0.0, 200.5) var res = sys.spawn_metin(8008, spawn_pos) _assert(res["ok"] == true, "Spawned 8008 successfully") _assert(res["id"] == 1, "First instance ID is 1") _assert(sys.active_metins.has(1), "Instance 1 in active_metins") _assert(spawn_sig["fired"] == true and spawn_sig["vnum"] == 8008 and spawn_sig["pos"] == spawn_pos, "metin_spawned signal emitted correctly") var res2 = sys.spawn_metin(8027, Vector3(50.0, 0.0, 50.0)) _assert(res2["ok"] == true and res2["id"] == 2, "Second stone instance ID is 2") _assert(sys.active_metins.size() == 2, "2 stones active") func _test_damage_and_phases() -> void: print("\n--- Test 3: Damage Calculation & 75%, 50%, 25% Mob Waves ---") var sys := MetinSpawnEventSystem.new() var res = sys.spawn_metin(8008, Vector3.ZERO) # 8008: HP 70000, Def 120, Mob 391, count 4 var id: int = res["id"] var waves := [] sys.mob_wave_erupted.connect(func(vnum: int, count: int, minion_vnum: int): waves.append({"vnum": vnum, "count": count, "minion_vnum": minion_vnum}) ) # Raw damage 200 - 120 def = 80 net damage var atk1 = sys.attack_metin(id, 200) _assert(atk1["ok"] == true, "Attack successful") _assert(atk1["net_dmg"] == 80, "Net damage = 200 - 120 = 80") _assert(atk1["remaining_hp"] == 70000 - 80, "Remaining HP correct") _assert(atk1["wave_triggered"] == false, "No wave at > 75% HP") _assert(waves.size() == 0, "No wave signal fired") # Damage to trigger <= 75% HP: 70000 * 0.75 = 52500. We deal raw dmg to bring it below 52500. # Remaining is 69920. Need to deal at least 69920 - 52500 = 17420 net dmg. # Raw dmg = 17420 + 120 = 17540 var atk_phase_75 = sys.attack_metin(id, 17540) _assert(atk_phase_75["wave_triggered"] == true, "Phase 75% wave triggered") _assert(atk_phase_75["spawned_count"] == 4, "Spawned 4 minions") _assert(waves.size() == 1 and waves[0]["minion_vnum"] == 391, "Wave signal received for 391") # Another hit while still in 50%~75% bracket should NOT trigger wave again var atk_repeat = sys.attack_metin(id, 1000) _assert(atk_repeat["wave_triggered"] == false, "Subsequent hit doesn't retrigger 75% wave") _assert(waves.size() == 1, "Wave count still 1") # Damage to trigger <= 50% HP (35000) # Current HP is around 51620. Need 17000 net dmg. var atk_phase_50 = sys.attack_metin(id, 20000) _assert(atk_phase_50["wave_triggered"] == true, "Phase 50% wave triggered") _assert(waves.size() == 2, "Wave count now 2") # Damage to trigger <= 25% HP (17500) var atk_phase_25 = sys.attack_metin(id, 20000) _assert(atk_phase_25["wave_triggered"] == true, "Phase 25% wave triggered") _assert(waves.size() == 3, "Wave count now 3") func _test_destruction_and_drops() -> void: print("\n--- Test 4: Metin Destruction & Drops ---") var sys := MetinSpawnEventSystem.new() var res = sys.spawn_metin(8014, Vector3(10, 0, 10)) # 8014: 死亡之石, lvl 65, HP 260000 var id: int = res["id"] var destroy_sig := {"fired": false, "vnum": 0, "drops": []} sys.metin_destroyed.connect(func(vnum: int, pos: Vector3, drops: Array): destroy_sig["fired"] = true destroy_sig["vnum"] = vnum destroy_sig["drops"] = drops ) # Overkill blow var kill_atk = sys.attack_metin(id, 1000000) _assert(kill_atk["ok"] == true and kill_atk["destroyed"] == true, "Metin destroyed") _assert(sys.active_metins.has(id) == false, "Stone removed from active_metins") _assert(destroy_sig["fired"] == true and destroy_sig["vnum"] == 8014, "metin_destroyed signal emitted") var drops: Array = kill_atk["drops"] _assert(drops.size() == 4, "4 drops generated") var has_skill_book := false var has_soul_stone := false var has_spirit_stone := false var has_gold := false for d in drops: if d["vnum"] == 50300: has_skill_book = true elif d["vnum"] == 50513: has_soul_stone = true elif d["vnum"] == 28430: has_spirit_stone = true elif d["vnum"] == 1 and d["count"] >= 65 * 500: has_gold = true _assert(has_skill_book, "Dropped Skill Book 50300") _assert(has_soul_stone, "Dropped Soul Stone 50513") _assert(has_spirit_stone, "Dropped Spirit Stone 28430") _assert(has_gold, "Dropped Gold scaled with level 65") func _test_invalid_inputs() -> void: print("\n--- Test 5: Invalid Metin Inputs ---") var sys := MetinSpawnEventSystem.new() var spawn_fail = sys.spawn_metin(99999) _assert(spawn_fail["ok"] == false and spawn_fail["reason"] == "INVALID_METIN_VNUM", "Correctly rejected invalid vnum 99999") var atk_fail = sys.attack_metin(8888, 100) _assert(atk_fail["ok"] == false and atk_fail["reason"] == "METIN_NOT_FOUND", "Correctly rejected attack on missing instance 8888") func _finish() -> void: print("\n==========================================") print("Metin Spawn Event Parity Tests Finished:") print("Passed: %d, Failed: %d" % [_passed, _failed]) print("==========================================") if _failed > 0: printerr("FAILED: Some tests did not pass.") quit(1) else: print("SUCCESS: All Metin Spawn Event parity tests passed!") quit(0)