# test_alignment_pk_parity.gd —— 40250 善恶值与名望头衔奖惩系统 1:1 回归测试套件 extends SceneTree const AlignmentPkSystem = preload("res://alignment_pk_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_alignment_pk_parity (Direction 3: Alignment PK & Titles 1:1) ===") _test_title_tiers_and_thresholds() _test_zen_bean_clearing() _test_safe_zone_time_recovery() _test_red_name_death_drop_penalty() _test_serialization() _finish() func _test_title_tiers_and_thresholds() -> void: print("\n--- Test 1: Title Tiers & Alignment Thresholds (40250 1:1) ---") var sys := AlignmentPkSystem.new() _assert(AlignmentPkSystem.get_title_name(15000) == "崇高骑士", ">= 12000 is Chivalric (崇高骑士)") _assert(AlignmentPkSystem.get_title_name(9000) == "尊贵贵族", ">= 8000 is Noble (尊贵贵族)") _assert(AlignmentPkSystem.get_title_name(5000) == "正义良民", ">= 4000 is Good (正义良民)") _assert(AlignmentPkSystem.get_title_name(1500) == "友好伙伴", ">= 1000 is Friendly (友好伙伴)") _assert(AlignmentPkSystem.get_title_name(500) == "中立行者", "0 ~ 999 is Neutral (中立行者)") _assert(AlignmentPkSystem.get_title_name(-1000) == "好斗狂徒", "-1 ~ -3999 is Aggressive (好斗狂徒)") _assert(AlignmentPkSystem.get_title_name(-5000) == "狡诈恶徒", "-4000 ~ -7999 is Fraudulent (狡诈恶徒)") _assert(AlignmentPkSystem.get_title_name(-9000) == "险恶凶手", "-8000 ~ -11999 is Malicious (险恶凶手)") _assert(AlignmentPkSystem.get_title_name(-15000)== "残忍魔头", "<= -12000 is Cruel (残忍魔头)") # Test clamping bounds (-200000 to +200000 real alignment) sys.update_real_alignment(500000) _assert(sys.real_alignment == 200000, "Clamped at MAX_REAL_ALIGNMENT (+200000)") _assert(sys.get_alignment() == 20000, "Display alignment clamped at +20000") sys.update_real_alignment(-900000) _assert(sys.real_alignment == -200000, "Clamped at MIN_REAL_ALIGNMENT (-200000)") _assert(sys.get_alignment() == -20000, "Display alignment clamped at -20000") func _test_zen_bean_clearing() -> void: print("\n--- Test 2: Zen Bean (70102) Sin Clearing ---") var sys := AlignmentPkSystem.new() var inv: Array = [ {"vnum": AlignmentPkSystem.VNUM_ZEN_BEAN, "name": "禅豆", "count": 3} ] # Set alignment to positive sys.real_alignment = 5000 # +500 var res_pos = sys.use_zen_bean(inv, 0) _assert(res_pos["ok"] == false, "Zen bean rejected when alignment is positive") _assert(res_pos["reason"] == "ALIGNMENT_ALREADY_GOOD", "Reason is ALREADY_GOOD") _assert(inv[0]["count"] == 3, "Zen bean not consumed") # Set alignment to -1200 (-12000 real) sys.real_alignment = -12000 var bean_sig := {"fired": false, "cleared": 0, "align": 0} sys.zen_bean_consumed.connect(func(c: int, a: int): bean_sig["fired"] = true bean_sig["cleared"] = c bean_sig["align"] = a ) var res_neg = sys.use_zen_bean(inv, 0) _assert(res_neg["ok"] == true, "Zen bean successfully used") _assert(res_neg["cleared"] == 500, "Cleared 500 display points") _assert(sys.get_alignment() == -700, "New alignment is -700 (-1200 + 500)") _assert(inv[0]["count"] == 2, "Zen bean count decremented to 2") _assert(bean_sig["fired"] == true, "zen_bean_consumed signal emitted") # Test capping clear to 0 when remaining evil < 500 (e.g. -200) sys.real_alignment = -2000 # -200 display inv[0]["count"] = 1 var res_cap = sys.use_zen_bean(inv, 0) _assert(res_cap["ok"] == true, "Zen bean used") _assert(res_cap["cleared"] == 200, "Only cleared remaining 200 points") _assert(sys.get_alignment() == 0, "Alignment restored to 0 (Neutral)") _assert(inv[0] == null, "Last Zen bean consumed completely") func _test_safe_zone_time_recovery() -> void: print("\n--- Test 3: Safe Zone Time-Based Recovery (40250 char.cpp) ---") var sys := AlignmentPkSystem.new() # Evil player: recovers 60 pts/min without item sys.real_alignment = -10000 # -1000 display sys.recover_alignment_by_time(5, false) # +300 pts _assert(sys.get_alignment() == -700, "Recovered 300 points over 5 minutes (60/min)") # Evil player: recovers 120 pts/min with item sys.recover_alignment_by_time(5, true) # +600 pts _assert(sys.get_alignment() == -100, "Recovered 600 points over 5 minutes with item (120/min)") # Good player: recovers 5 pts/min sys.real_alignment = 10000 # +1000 display sys.recover_alignment_by_time(10, false) # +50 pts _assert(sys.get_alignment() == 1050, "Recovered 50 points over 10 minutes (5/min)") func _test_red_name_death_drop_penalty() -> void: print("\n--- Test 4: Red Name Death Drop Penalty & Soulbound Exemption ---") var sys := AlignmentPkSystem.new() var inv: Array = [ {"vnum": 189, "name": "毒剑+9", "is_soulbound": false}, {"vnum": 11299, "name": "黑铁甲+9", "is_soulbound": true}, # Soulbound protected! {"vnum": 50300, "name": "技能书", "is_soulbound": false} ] # 1. White name (Alignment >= 0): 0 drops sys.real_alignment = 50000 var drops_good = sys.handle_death_drop_penalty(inv) _assert(drops_good.is_empty(), "Good player never drops items on death") _assert(inv[0] != null and inv[1] != null and inv[2] != null, "Inventory remains intact") # 2. Cruel Red name (Alignment <= -12000): guaranteed drop with 80% chance sys.real_alignment = -150000 # -15000 (Cruel) # Seed random for deterministic test seed(42) var drops_evil = sys.handle_death_drop_penalty(inv) _assert(not drops_evil.is_empty(), "Cruel red name dropped items on death") _assert(inv[1] != null, "Soulbound Black Steel Armor was NOT dropped (immune)") func _test_serialization() -> void: print("\n--- Test 5: Serialization & Restoration ---") var sys1 := AlignmentPkSystem.new() sys1.real_alignment = -85400 # -8540 display (Malicious) var data = sys1.serialize() var sys2 := AlignmentPkSystem.new() sys2.deserialize(data) _assert(sys2.real_alignment == -85400, "Restored real alignment") _assert(sys2.get_alignment() == -8540, "Restored display alignment") _assert(sys2.get_title_name(sys2.get_alignment()) == "险恶凶手", "Restored Malicious title") func _finish() -> void: print("\n=======================================================") print("Alignment PK System Parity Tests: %d Passed, %d Failed" % [_passed, _failed]) print("=======================================================\n") if _failed > 0: quit(1) else: quit(0)