Files
mtgodot-poc/project/test_alignment_parity.gd
T
shenandshen 66d217b313 feat(client): 完成40250客户端核心功能1:1对齐与桥梁高度采样修复
- 桥梁与静态物体高度采样修复:
  - 严格对齐 40250 CMapOutdoor::GetHeight 与 CAttributeInstance::GetHeight
  - 解析 .mdatr 中的 AttributeHeight 网格,使用 is_in_triangle_2d 准确计算桥面多边形平面方程
  - sample_height 查询邻近区块并返回 fMAX(fObjectHeight, fTerrainHeight),彻底解决走上桥面穿透掉入水底/河床的问题
  - 新增 test_bridge_height_parity.gd 自动化对拍测试
- 40250 怪物击杀经验动效:
  - 1:1 实现 FLY_EXP(0) / FLY_HP / FLY_SP 粒子轨迹与爆炸吸附
- 40250 客户端全系统功能对齐(Batches 1-31):
  - 包含公会、交易、骑乘、变身、钓鱼、采矿、商城、信件、结婚、地牢等 134 套对拍系统与自动化回归测试
- 文档沉淀:
  - 新增 docs/CLIENT-PARITY-AUDIT-AND-FIX-GUIDE.md 客户端对拍缺陷发现与修复工程指南
2026-09-19 08:51:25 -07:00

103 lines
5.2 KiB
GDScript

# test_alignment_parity.gd —— 验证方向 2:人物善恶道德与红名系统 40250 1:1 对齐
extends SceneTree
const AlignmentSystem = preload("res://alignment_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_parity (Direction 2: Karma & Alignment 1:1) ===")
test_alignment_grades_and_thresholds()
test_title_colors_and_names()
test_natural_time_recovery()
test_kill_monster_karma()
test_zen_bean_karma_clearing()
print("\n=== SUMMARY: %d passed, %d failed ===" % [_passed, _failed])
if _failed > 0:
printerr("TEST FAILED!")
quit(1)
else:
print("ALL TESTS PASSED!")
quit(0)
func test_alignment_grades_and_thresholds() -> void:
print("\n--- Test 1: 9 Alignment Grades & Numerical Thresholds ---")
_assert(AlignmentSystem.get_alignment_grade(15000) == AlignmentSystem.TITLE_HEROIC, "15000 is Heroic (>= 12000)")
_assert(AlignmentSystem.get_alignment_grade(12000) == AlignmentSystem.TITLE_HEROIC, "12000 is Heroic (boundary)")
_assert(AlignmentSystem.get_alignment_grade(9500) == AlignmentSystem.TITLE_NOBLE, "9500 is Noble (8000..11999)")
_assert(AlignmentSystem.get_alignment_grade(5000) == AlignmentSystem.TITLE_GOOD, "5000 is Good (4000..7999)")
_assert(AlignmentSystem.get_alignment_grade(2000) == AlignmentSystem.TITLE_FRIENDLY, "2000 is Friendly (1000..3999)")
_assert(AlignmentSystem.get_alignment_grade(500) == AlignmentSystem.TITLE_NEUTRAL, "500 is Neutral (0..999)")
_assert(AlignmentSystem.get_alignment_grade(0) == AlignmentSystem.TITLE_NEUTRAL, "0 is Neutral (boundary)")
_assert(AlignmentSystem.get_alignment_grade(-2000) == AlignmentSystem.TITLE_AGGRESSIVE, "-2000 is Aggressive (-1..-3999)")
_assert(AlignmentSystem.get_alignment_grade(-5000) == AlignmentSystem.TITLE_FRAUDULENT, "-5000 is Fraudulent (-4000..-7999)")
_assert(AlignmentSystem.get_alignment_grade(-10000) == AlignmentSystem.TITLE_MALICIOUS, "-10000 is Malicious (-8000..-11999)")
_assert(AlignmentSystem.get_alignment_grade(-15000) == AlignmentSystem.TITLE_CRUEL, "-15000 is Cruel (<= -12000)")
func test_title_colors_and_names() -> void:
print("\n--- Test 2: Title Names and 40250 RGB Colors ---")
_assert(AlignmentSystem.get_title_name(AlignmentSystem.TITLE_HEROIC) == "英雄", "Grade 0 is 英雄")
_assert(AlignmentSystem.get_title_name(AlignmentSystem.TITLE_CRUEL) == "魔头", "Grade 8 is 魔头")
var c_heroic := AlignmentSystem.get_title_color(AlignmentSystem.TITLE_HEROIC)
_assert(c_heroic == Color8(0, 204, 255), "Heroic color matches 40250 Color8(0, 204, 255) cyan")
var c_cruel := AlignmentSystem.get_title_color(AlignmentSystem.TITLE_CRUEL)
_assert(c_cruel == Color8(255, 0, 0), "Cruel color matches 40250 Color8(255, 0, 0) red")
_assert(AlignmentSystem.is_red_name(-100), "-100 is red name (evil)")
_assert(not AlignmentSystem.is_red_name(0), "0 is not red name")
_assert(AlignmentSystem.is_blue_name(1500), "1500 is blue name (just)")
func test_natural_time_recovery() -> void:
print("\n--- Test 3: 40250 Online Natural Time Recovery (char.cpp:1197) ---")
# 1. Evil player (-1000) after 10 minutes -> +60 * 10 = +600 -> -400
var evil_rec := AlignmentSystem.calculate_time_recovery(-1000, 10, false)
_assert(evil_rec == -400, "Evil karma recovered from -1000 to -400 (+60/min)")
# 2. Evil player with fast item (120/min) after 5 minutes -> +120 * 5 = +600 -> -400
var fast_rec := AlignmentSystem.calculate_time_recovery(-1000, 5, true)
_assert(fast_rec == -400, "Evil karma with fast item recovered +120/min")
# 3. Evil natural recovery clamps at 0 (does not automatically become positive just by AFK)
var clamp_rec := AlignmentSystem.calculate_time_recovery(-100, 10, false)
_assert(clamp_rec == 0, "Evil time recovery clamps at 0")
# 4. Good player (1000) after 10 minutes -> +5 * 10 = +50 -> 1050
var good_rec := AlignmentSystem.calculate_time_recovery(1000, 10, false)
_assert(good_rec == 1050, "Good karma increases +5/min")
func test_kill_monster_karma() -> void:
print("\n--- Test 4: Monster Kill Karma Growth ---")
var normal_kill := AlignmentSystem.on_kill_monster(500, 30, 20) # 30 - 10 = 20
_assert(normal_kill == 520, "Monster kill added 20 alignment")
# Evil players get double recovery rate when killing monsters
var evil_kill := AlignmentSystem.on_kill_monster(-1000, 30, 20) # 20 * 2 = 40
_assert(evil_kill == -960, "Evil player gets 2x karma on monster kill")
func test_zen_bean_karma_clearing() -> void:
print("\n--- Test 5: Zen Bean (70102) Karma Clearing ---")
# Zen bean on evil player (-800) clears 500 karma -> -300
var res_bean := AlignmentSystem.use_zen_bean(-800)
_assert(res_bean.ok and res_bean.new_alignment == -300, "Zen bean reduced evil karma from -800 to -300")
# Zen bean on slightly evil player (-200) clamps at 0
var res_bean_clamp := AlignmentSystem.use_zen_bean(-200)
_assert(res_bean_clamp.ok and res_bean_clamp.new_alignment == 0, "Zen bean clamps at 0")
# Zen bean on neutral or good player is rejected
var res_bean_good := AlignmentSystem.use_zen_bean(500)
_assert(not res_bean_good.ok and res_bean_good.code == "CANNOT_USE_NOT_EVIL",
"Zen bean rejected when player is not evil")