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

133 lines
6.0 KiB
GDScript

# test_polymorph_marble_parity.gd —— 40250 官方变身宝珠与怪物精魂附体系统 1:1 回归测试套件
extends SceneTree
const PolymorphMarbleSystem = preload("res://polymorph_marble_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_polymorph_marble_parity (Direction 1: Polymorph Marble 1:1) ===")
_test_marble_transformation_and_bonuses()
_test_skill_mastery_durations()
_test_mount_and_skill_restrictions()
_test_expiration_and_stat_reversion()
_test_serialization()
_finish()
func _test_marble_transformation_and_bonuses() -> void:
print("\n--- Test 1: Transformation & Bonus Stat Injection ---")
var sys := PolymorphMarbleSystem.new()
var player := {"attack_power": 500, "defense": 300, "move_speed": 100}
var start_sig := {"fired": false, "mob": 0, "name": "", "bonus_type": 0}
sys.polymorph_started.connect(func(m: int, n: String, _d: float, bt: int, _bv: int):
start_sig["fired"] = true
start_sig["mob"] = m
start_sig["name"] = n
start_sig["bonus_type"] = bt
)
# 1. Barbarian Infantry (501) - Attack Bonus +40
var marble_barbarian := {"vnum": PolymorphMarbleSystem.VNUM_POLYMORPH_MARBLE, "mob_vnum": 501}
var res1 = sys.polymorph_character(marble_barbarian, PolymorphMarbleSystem.SKILL_NORMAL, player)
_assert(res1["ok"] == true, "Polymorphed into Barbarian Infantry")
_assert(sys.is_polymorphed == true, "is_polymorphed is true")
_assert(player["attack_power"] == 540, "Attack power increased 500 -> 540 (+40)")
_assert(start_sig["fired"] == true, "polymorph_started signal emitted")
_assert(start_sig["mob"] == 501, "Mob vnum is 501")
# 2. Directly switch to White Hair Spider (492) - Def Bonus +50
var marble_spider := {"vnum": PolymorphMarbleSystem.VNUM_POLYMORPH_MARBLE, "mob_vnum": 492}
var res2 = sys.polymorph_character(marble_spider, PolymorphMarbleSystem.SKILL_NORMAL, player)
_assert(res2["ok"] == true, "Switched into White Hair Spider")
_assert(player["attack_power"] == 500, "Previous attack bonus (+40) cleared cleanly")
_assert(player["defense"] == 350, "Defense increased 300 -> 350 (+50)")
func _test_skill_mastery_durations() -> void:
print("\n--- Test 2: 40250 Mastery Skill Durations ---")
_assert(PolymorphMarbleSystem.get_duration_by_mastery(PolymorphMarbleSystem.SKILL_NORMAL) == 600.0, "Normal: 600s (10 min)")
_assert(PolymorphMarbleSystem.get_duration_by_mastery(PolymorphMarbleSystem.SKILL_MASTER) == 900.0, "Master: 900s (15 min)")
_assert(PolymorphMarbleSystem.get_duration_by_mastery(PolymorphMarbleSystem.SKILL_GRAND_MASTER) == 1200.0, "Grand Master: 1200s (20 min)")
_assert(PolymorphMarbleSystem.get_duration_by_mastery(PolymorphMarbleSystem.SKILL_PERFECT_MASTER) == 1500.0, "Perfect Master: 1500s (25 min)")
func _test_mount_and_skill_restrictions() -> void:
print("\n--- Test 3: Mount & Character Skill Restrictions ---")
var sys := PolymorphMarbleSystem.new()
var player := {"attack_power": 100}
_assert(sys.can_mount_horse() == true, "Normal character can mount horse")
_assert(sys.can_cast_player_skills() == true, "Normal character can cast skills")
# Transform
sys.polymorph_character({"vnum": PolymorphMarbleSystem.VNUM_POLYMORPH_MARBLE, "mob_vnum": 101}, PolymorphMarbleSystem.SKILL_NORMAL, player)
_assert(sys.can_mount_horse() == false, "Polymorphed character CANNOT mount horse")
_assert(sys.can_cast_player_skills() == false, "Polymorphed character CANNOT cast player skills")
# Revert
sys.revert_polymorph(player)
_assert(sys.can_mount_horse() == true, "Reverted character can mount horse again")
_assert(sys.can_cast_player_skills() == true, "Reverted character can cast skills again")
func _test_expiration_and_stat_reversion() -> void:
print("\n--- Test 4: Expiration Heartbeat & Stat Reversion ---")
var sys := PolymorphMarbleSystem.new()
var player := {"move_speed": 100}
var marble_fox := {"vnum": PolymorphMarbleSystem.VNUM_POLYMORPH_MARBLE, "mob_vnum": 1901} # 九尾妖狐 (+30 ms)
var end_sig := {"fired": false, "mob": 0}
sys.polymorph_ended.connect(func(m: int, _n: String):
end_sig["fired"] = true
end_sig["mob"] = m
)
sys.polymorph_character(marble_fox, PolymorphMarbleSystem.SKILL_NORMAL, player) # 600s
_assert(player["move_speed"] == 130, "Move speed boosted to 130")
# Advance 500s (100s left)
sys.update(500.0, player)
_assert(sys.is_polymorphed == true, "Still polymorphed at 500s")
_assert(player["move_speed"] == 130, "Speed boost still active")
# Advance remaining 100s -> timeout
sys.update(100.0, player)
_assert(sys.is_polymorphed == false, "Polymorph expired after 600s")
_assert(player["move_speed"] == 100, "Move speed reversed cleanly to 100")
_assert(end_sig["fired"] == true, "polymorph_ended signal emitted")
_assert(end_sig["mob"] == 1901, "Reported Nine Tails mob vnum")
func _test_serialization() -> void:
print("\n--- Test 5: Serialization & Restoration ---")
var sys1 := PolymorphMarbleSystem.new()
var player := {"defense": 200}
sys1.polymorph_character({"vnum": PolymorphMarbleSystem.VNUM_POLYMORPH_MARBLE, "mob_vnum": 492}, PolymorphMarbleSystem.SKILL_MASTER, player)
sys1.update(300.0, player) # 600s remaining
var data = sys1.serialize()
_assert(data["is_polymorphed"] == true, "Serialized is_polymorphed")
_assert(data["active_mob_vnum"] == 492, "Serialized mob vnum")
_assert(data["active_stat_key"] == "defense", "Serialized stat key")
var sys2 := PolymorphMarbleSystem.new()
sys2.deserialize(data)
_assert(sys2.is_polymorphed == true, "Restored is_polymorphed")
_assert(sys2.active_mob_vnum == 492, "Restored mob vnum 492")
_assert(sys2.active_mob_name == "白发蜘蛛", "Restored name")
_assert(is_equal_approx(sys2.time_remaining, 600.0), "Restored time remaining")
func _finish() -> void:
print("\n=======================================================")
print("Polymorph Marble Parity Tests: %d Passed, %d Failed" % [_passed, _failed])
print("=======================================================\n")
if _failed > 0:
quit(1)
else:
quit(0)