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

139 lines
6.3 KiB
GDScript

# test_item_attr_parity.gd —— 验证方向 1:装备附魔、洗炼与祝福宝珠 40250 1:1 对齐
extends SceneTree
const ItemAttrSystem = preload("res://item_attr_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_item_attr_parity (Direction 1: Item Add/Change Bonus 1:1) ===")
test_scroll_detection()
test_can_have_attributes()
test_add_attribute_parity()
test_change_attribute_parity()
test_blessing_marble_parity()
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_scroll_detection() -> void:
print("\n--- Test 1: Scroll Vnum Detection (71084, 71085, 70024) ---")
_assert(ItemAttrSystem.is_attr_scroll(71085), "71085 is detected as Add Attribute Scroll")
_assert(ItemAttrSystem.is_attr_scroll(71084), "71084 is detected as Change Attribute Scroll")
_assert(ItemAttrSystem.is_attr_scroll(70024), "70024 is detected as Blessing Marble")
_assert(not ItemAttrSystem.is_attr_scroll(27001), "Normal potion is not an attr scroll")
_assert(not ItemAttrSystem.is_attr_scroll(10), "Sword is not an attr scroll")
func test_can_have_attributes() -> void:
print("\n--- Test 2: Target Equipment Compatibility (Weapon/Armor vs Arrow) ---")
var weapon := {"type": ItemAttrSystem.ITEM_TYPE_WEAPON, "sub_type": 0} # 剑
var armor := {"type": ItemAttrSystem.ITEM_TYPE_ARMOR, "sub_type": 0} # 衣服
var arrow := {"type": ItemAttrSystem.ITEM_TYPE_WEAPON, "sub_type": 5} # 箭矢
var potion := {"type": 3, "sub_type": 0} # 消耗品
_assert(ItemAttrSystem.can_have_attributes(weapon), "Weapon can have attributes")
_assert(ItemAttrSystem.can_have_attributes(armor), "Armor can have attributes")
_assert(not ItemAttrSystem.can_have_attributes(arrow), "Arrow (WEAPON_ARROW) cannot have attributes")
_assert(not ItemAttrSystem.can_have_attributes(potion), "Potion cannot have attributes")
func test_add_attribute_parity() -> void:
print("\n--- Test 3: 40250 Add Attribute Progression (1..4 Attrs & Cap) ---")
var weapon_proto := {"type": ItemAttrSystem.ITEM_TYPE_WEAPON, "sub_type": 0}
var sword_item := {"vnum": 10, "attrs": []}
# 1st attribute
var res1 := ItemAttrSystem.apply_add_attribute(sword_item, weapon_proto, true)
_assert(res1.ok and res1.code == "SUCCESS", "1st attribute added successfully")
_assert(sword_item.attrs.size() == 1, "Sword has 1 attribute now")
# 2nd attribute
var res2 := ItemAttrSystem.apply_add_attribute(sword_item, weapon_proto, true)
_assert(res2.ok and res2.code == "SUCCESS", "2nd attribute added successfully")
_assert(sword_item.attrs.size() == 2, "Sword has 2 attributes now")
_assert(sword_item.attrs[0].type != sword_item.attrs[1].type, "1st and 2nd attribute types are distinct (no duplicate)")
# 3rd attribute
var res3 := ItemAttrSystem.apply_add_attribute(sword_item, weapon_proto, true)
_assert(res3.ok and res3.code == "SUCCESS", "3rd attribute added successfully")
_assert(sword_item.attrs.size() == 3, "Sword has 3 attributes now")
# 4th attribute
var res4 := ItemAttrSystem.apply_add_attribute(sword_item, weapon_proto, true)
_assert(res4.ok and res4.code == "SUCCESS", "4th attribute added successfully")
_assert(sword_item.attrs.size() == 4, "Sword has 4 attributes now")
# 5th attempt with normal scroll 71085 MUST fail (40250 char_item.cpp:4665 item2->GetAttributeCount() < 4)
var res5 := ItemAttrSystem.apply_add_attribute(sword_item, weapon_proto, true)
_assert(not res5.ok and res5.code == "MAX_ATTR_REACHED", "Normal scroll cannot add 5th attribute (MAX_ATTR_REACHED)")
_assert(sword_item.attrs.size() == 4, "Sword remains at 4 attributes")
func test_change_attribute_parity() -> void:
print("\n--- Test 4: 40250 Change Attribute (Reroll All Attributes) ---")
var weapon_proto := {"type": ItemAttrSystem.ITEM_TYPE_WEAPON, "sub_type": 0}
var empty_item := {"vnum": 10, "attrs": []}
# Fails on item with 0 attributes (40250 char_item.cpp:4560 item2->GetAttributeCount() == 0)
var res_empty := ItemAttrSystem.apply_change_attribute(empty_item, weapon_proto)
_assert(not res_empty.ok and res_empty.code == "NO_ATTRIBUTES", "Change attribute fails when item has 0 attributes")
var geared_item := {
"vnum": 10,
"attrs": [
{"type": 1, "value": 500},
{"type": 15, "value": 10},
{"type": 16, "value": 10}
]
}
var res_reroll := ItemAttrSystem.apply_change_attribute(geared_item, weapon_proto)
_assert(res_reroll.ok and res_reroll.code == "SUCCESS", "Change attribute rerolls successfully")
_assert(geared_item.attrs.size() == 3, "Item still has exactly 3 attributes after reroll")
# Verify all rerolled attribute types are unique
var types := {}
var has_duplicate := false
for a in geared_item.attrs:
if types.has(a.type):
has_duplicate = true
types[a.type] = true
_assert(not has_duplicate, "All rerolled attribute types are distinct")
func test_blessing_marble_parity() -> void:
print("\n--- Test 5: 40250 Blessing Marble 70024 (5th Attribute Lock) ---")
var weapon_proto := {"type": ItemAttrSystem.ITEM_TYPE_WEAPON, "sub_type": 0}
# Item with 3 attributes -> marble fails (40250 char_item.cpp:4738 item2->GetAttributeCount() == 4)
var item_3_attrs := {
"vnum": 10,
"attrs": [
{"type": 1, "value": 500},
{"type": 2, "value": 200},
{"type": 3, "value": 4}
]
}
var res_marble_fail := ItemAttrSystem.apply_blessing_marble(item_3_attrs, weapon_proto, true)
_assert(not res_marble_fail.ok and res_marble_fail.code == "NEED_FOUR_ATTRS", "Blessing marble fails on item with less than 4 attributes")
# Item with 4 attributes -> marble succeeds and adds 5th
item_3_attrs.attrs.append({"type": 4, "value": 4})
var res_marble_ok := ItemAttrSystem.apply_blessing_marble(item_3_attrs, weapon_proto, true)
_assert(res_marble_ok.ok and res_marble_ok.code == "SUCCESS", "Blessing marble successfully unlocks 5th attribute")
_assert(item_3_attrs.attrs.size() == 5, "Item now has 5 attributes")
# Marble fails on item that already has 5 attributes
var res_marble_cap := ItemAttrSystem.apply_blessing_marble(item_3_attrs, weapon_proto, true)
_assert(not res_marble_cap.ok and res_marble_cap.code == "ALREADY_FIVE_ATTRS", "Blessing marble cannot exceed 5 attributes")