- 桥梁与静态物体高度采样修复: - 严格对齐 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 客户端对拍缺陷发现与修复工程指南
134 lines
5.2 KiB
GDScript
134 lines
5.2 KiB
GDScript
# test_wardrobe_transmog_parity.gd —— 40250 装备外观幻化与试衣间 1:1 回归测试套件
|
|
extends SceneTree
|
|
|
|
const WardrobeTransmogSystem = preload("res://wardrobe_transmog_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_wardrobe_transmog_parity (Direction 3: Wardrobe Transmog 1:1) ===")
|
|
_test_preview_mode()
|
|
_test_weapon_transmutation()
|
|
_test_type_mismatch_rejection()
|
|
_test_transmutation_revert()
|
|
_finish()
|
|
|
|
func _test_preview_mode() -> void:
|
|
print("\n--- Test 1: Wardrobe Preview Mode ---")
|
|
var sys := WardrobeTransmogSystem.new()
|
|
var sword := {"vnum": 189, "name": "毒剑+9", "type": WardrobeTransmogSystem.TYPE_WEAPON}
|
|
var skin := {"vnum": 199, "name": "圣天使之剑", "type": WardrobeTransmogSystem.TYPE_WEAPON}
|
|
|
|
var prev = sys.preview_transmog(sword, skin)
|
|
_assert(prev["ok"] == true, "Preview generated")
|
|
_assert(prev["preview_vnum"] == 199, "Preview skin vnum is 199")
|
|
_assert(prev["preview_name"] == "圣天使之剑", "Preview name matches")
|
|
|
|
func _test_weapon_transmutation() -> void:
|
|
print("\n--- Test 2: Weapon Transmutation & Full Stat Preservation ---")
|
|
var sys := WardrobeTransmogSystem.new()
|
|
var player := {"gold": 25000000}
|
|
var inv: Array = [
|
|
{"vnum": WardrobeTransmogSystem.VNUM_TRANSMOG_SCROLL, "name": "幻化秘籍", "count": 2},
|
|
{
|
|
"vnum": 189,
|
|
"name": "毒剑+9",
|
|
"type": WardrobeTransmogSystem.TYPE_WEAPON,
|
|
"refine_level": 9,
|
|
"sockets": [28430, 28435, 28436],
|
|
"attrs": [{"type": 1, "val": 2000}]
|
|
},
|
|
{"vnum": 199, "name": "圣天使之剑", "type": WardrobeTransmogSystem.TYPE_WEAPON, "count": 1}
|
|
]
|
|
|
|
var transmog_sig := {"fired": false, "slot": -1, "skin_vnum": 0}
|
|
sys.item_transmuted.connect(func(s: int, _tname: String, sk_vnum: int, _sk_name: String):
|
|
transmog_sig["fired"] = true
|
|
transmog_sig["slot"] = s
|
|
transmog_sig["skin_vnum"] = sk_vnum
|
|
)
|
|
|
|
# Apply transmutation
|
|
var res = sys.apply_transmutation(0, 1, 2, inv, player)
|
|
_assert(res["ok"] == true, "Transmutation succeeded")
|
|
_assert(player["gold"] == 15000000, "10M gold deducted (25M -> 15M)")
|
|
_assert(inv[0]["count"] == 1, "Scroll count decreased (2 -> 1)")
|
|
_assert(inv[2] == null, "Skin material item consumed")
|
|
|
|
# Check target item preservation
|
|
var target = inv[1]
|
|
_assert(target["vnum"] == 189, "Base vnum is still 189 (Poison Sword)")
|
|
_assert(target["refine_level"] == 9, "Refine level preserved as +9")
|
|
_assert(target["sockets"].size() == 3, "Sockets preserved")
|
|
_assert(target["attrs"].size() == 1, "Attrs preserved")
|
|
_assert(target["transmog_vnum"] == 199, "transmog_vnum set to 199")
|
|
_assert(target["transmog_name"] == "圣天使之剑", "transmog_name set to 圣天使之剑")
|
|
_assert(transmog_sig["fired"] == true and transmog_sig["skin_vnum"] == 199, "item_transmuted emitted")
|
|
|
|
func _test_type_mismatch_rejection() -> void:
|
|
print("\n--- Test 3: Type Mismatch Rejection (Weapon vs Armor) ---")
|
|
var sys := WardrobeTransmogSystem.new()
|
|
var player := {"gold": 50000000}
|
|
var inv: Array = [
|
|
{"vnum": WardrobeTransmogSystem.VNUM_TRANSMOG_SCROLL, "count": 1},
|
|
{"vnum": 189, "name": "毒剑+9", "type": WardrobeTransmogSystem.TYPE_WEAPON},
|
|
{"vnum": 11299, "name": "黑铁战甲+9", "type": WardrobeTransmogSystem.TYPE_ARMOR} # Armor into weapon
|
|
]
|
|
|
|
var fail_mismatch = sys.apply_transmutation(0, 1, 2, inv, player)
|
|
_assert(fail_mismatch["ok"] == false and fail_mismatch["reason"] == "TYPE_MISMATCH", "Rejected armor as skin for weapon")
|
|
_assert(player["gold"] == 50000000, "Gold untouched")
|
|
_assert(inv[0]["count"] == 1, "Scroll untouched")
|
|
|
|
func _test_transmutation_revert() -> void:
|
|
print("\n--- Test 4: Reverting Transmutation (72302) ---")
|
|
var sys := WardrobeTransmogSystem.new()
|
|
var inv: Array = [
|
|
{"vnum": WardrobeTransmogSystem.VNUM_REVERT_SCROLL, "name": "还原秘籍", "count": 1},
|
|
{
|
|
"vnum": 189,
|
|
"name": "毒剑+9",
|
|
"type": WardrobeTransmogSystem.TYPE_WEAPON,
|
|
"transmog_vnum": 199,
|
|
"transmog_name": "圣天使之剑"
|
|
}
|
|
]
|
|
|
|
var revert_sig := {"fired": false, "slot": -1}
|
|
sys.transmutation_reverted.connect(func(s: int, _n: String):
|
|
revert_sig["fired"] = true
|
|
revert_sig["slot"] = s
|
|
)
|
|
|
|
var res = sys.revert_transmutation(0, 1, inv)
|
|
_assert(res["ok"] == true, "Revert succeeded")
|
|
_assert(inv[0] == null, "Revert scroll consumed")
|
|
_assert(inv[1].has("transmog_vnum") == false, "transmog_vnum cleared")
|
|
_assert(revert_sig["fired"] == true and revert_sig["slot"] == 1, "transmutation_reverted emitted")
|
|
|
|
# Second revert on un-transmuted item must fail
|
|
inv[0] = {"vnum": WardrobeTransmogSystem.VNUM_REVERT_SCROLL, "count": 1}
|
|
var fail_again = sys.revert_transmutation(0, 1, inv)
|
|
_assert(fail_again["ok"] == false and fail_again["reason"] == "NOT_TRANSMUTED", "Cannot revert un-transmuted item")
|
|
|
|
func _finish() -> void:
|
|
print("\n==========================================")
|
|
print("Wardrobe Transmog Parity Tests Finished:")
|
|
print("Passed: %d, Failed: %d" % [_passed, _failed])
|
|
print("==========================================")
|
|
if _failed > 0:
|
|
printerr("FAILED: Some tests did not pass.")
|
|
quit(1)
|
|
else:
|
|
print("SUCCESS: All Wardrobe Transmog parity tests passed!")
|
|
quit(0)
|