Files
mtgodot-poc/project/test_mob_combat_reaction_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

98 lines
4.3 KiB
GDScript

# test_mob_combat_reaction_parity.gd —— 验证方向 2:怪物主动仇恨视野、追击脱战与连击击退硬直 40250 1:1 对齐
extends SceneTree
const MobCombatReactionSystem = preload("res://mob_combat_reaction_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_mob_combat_reaction_parity (Direction 2: Mob Aggro & Knockback 1:1) ===")
test_aggro_radius_detection()
test_leash_distance_and_reset()
test_combo_reaction_steps()
test_knockback_direction_vector()
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_aggro_radius_detection() -> void:
print("\n--- Test 1: Aggro Radius (18m) Detection ---")
var mob_pos := Vector3(0, 0, 0)
var player_in_range := Vector3(10, 0, 10) # distance = ~14.14m <= 18m
var player_out_range := Vector3(20, 0, 20) # distance = ~28.28m > 18m
# Active aggressive mob
_assert(MobCombatReactionSystem.check_aggro(mob_pos, player_in_range, true, 18.0),
"Aggressive mob detects player within 18m")
_assert(not MobCombatReactionSystem.check_aggro(mob_pos, player_out_range, true, 18.0),
"Aggressive mob ignores player outside 18m")
# Passive mob ignores player even close
_assert(not MobCombatReactionSystem.check_aggro(mob_pos, player_in_range, false, 18.0),
"Passive mob does not aggro even when close")
func test_leash_distance_and_reset() -> void:
print("\n--- Test 2: Leash Distance (40m) & Full HP Reset ---")
var spawn_pos := Vector3(100, 0, 100)
var mob_chasing := Vector3(120, 0, 120) # distance = 28.28m <= 40m
var mob_leashed := Vector3(150, 0, 150) # distance = 70.71m > 40m
_assert(not MobCombatReactionSystem.check_leash_exceeded(mob_chasing, spawn_pos, 40.0),
"Mob within 40m remains in chase")
_assert(MobCombatReactionSystem.check_leash_exceeded(mob_leashed, spawn_pos, 40.0),
"Mob exceeding 40m triggers leash exceeded")
# Leash reset
var damaged_mob := {"hp": 200, "max_hp": 2000, "target_vid": 1, "state": MobCombatReactionSystem.MobAIState.CHASE}
var reset_res := MobCombatReactionSystem.perform_leash_reset(damaged_mob, spawn_pos)
_assert(reset_res.leashed, "Leash reset executed")
_assert(damaged_mob.hp == 2000, "HP fully restored to 2000")
_assert(damaged_mob.target_vid == 0, "Target cleared")
_assert(damaged_mob.state == MobCombatReactionSystem.MobAIState.RETREAT, "State set to RETREAT")
func test_combo_reaction_steps() -> void:
print("\n--- Test 3: 40250 Combo Step Reactions (1-2 Damage vs 3-4 Knockdown) ---")
var mob_pos := Vector3(0, 0, 0)
# Step 1: Hit 1 -> normal damage stun
var hit1 := MobCombatReactionSystem.calculate_combo_reaction(1, mob_pos, 0.0)
_assert(hit1.reaction_type == "DAMAGE_STUN" and not hit1.is_knockback, "Combo 1 is DAMAGE_STUN (no knockback)")
_assert(hit1.anim == "damage", "Plays damage animation")
# Step 2: Hit 2 -> normal damage stun
var hit2 := MobCombatReactionSystem.calculate_combo_reaction(2, mob_pos, 0.0)
_assert(hit2.reaction_type == "DAMAGE_STUN" and not hit2.is_knockback, "Combo 2 is DAMAGE_STUN")
# Step 3: Hit 3 -> heavy knockback & knockdown
var hit3 := MobCombatReactionSystem.calculate_combo_reaction(3, mob_pos, 0.0)
_assert(hit3.reaction_type == "KNOCKBACK_FLYING" and hit3.is_knockback, "Combo 3 triggers KNOCKBACK_FLYING")
_assert(hit3.anim == "knockdown" and hit3.standup_anim == "standup", "Triggers knockdown and standup")
# Step 4: Hit 4 -> heavy knockback & knockdown
var hit4 := MobCombatReactionSystem.calculate_combo_reaction(4, mob_pos, 0.0)
_assert(hit4.reaction_type == "KNOCKBACK_FLYING" and hit4.is_knockback, "Combo 4 triggers KNOCKBACK_FLYING")
func test_knockback_direction_vector() -> void:
print("\n--- Test 4: Knockback Push Vector Along Attack Heading ---")
var mob_pos := Vector3(10, 0, 10)
# Attack heading = 0 radians (North / +Z)
var hit_north := MobCombatReactionSystem.calculate_combo_reaction(3, mob_pos, 0.0)
var offset_z: float = hit_north.push_offset.z
_assert(is_equal_approx(offset_z, 1.5), "Knockback pushed 1.5m along attack heading")
_assert(is_equal_approx(hit_north.target_pos.z, 11.5), "Target position updated to 11.5m")