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

184 lines
7.6 KiB
GDScript

# test_epic_refine_parity.gd —— 40250 修元平史诗级装备升阶转换 1:1 纯净回归测试套件
extends SceneTree
const EpicRefineSystem = preload("res://epic_refine_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_epic_refine_parity (Direction 2: Seon-Pyeong Epic Refine 1:1) ===")
_test_recipe_definitions()
_test_material_and_gold_validation()
_test_weapon_epic_refine_and_inheritance()
_test_armor_epic_refine_and_inheritance()
_finish()
func _test_recipe_definitions() -> void:
print("\n--- Test 1: Recipe Table & Eligibility Validation ---")
var ers := EpicRefineSystem.new()
# Valid Lv65 +9 weapons
_assert(ers.can_epic_refine({"vnum": 169}), "Battle Sword +9 (169) is eligible")
_assert(ers.can_epic_refine({"vnum": 3159}), "Ghost Fang Blade +9 (3159) is eligible")
_assert(ers.can_epic_refine({"vnum": 1109}), "Partisan +9 (1109) is eligible")
_assert(ers.can_epic_refine({"vnum": 1119}), "Dragon Knife +9 (1119) is eligible")
_assert(ers.can_epic_refine({"vnum": 2149}), "Yellow Dragon Bow +9 (2149) is eligible")
_assert(ers.can_epic_refine({"vnum": 5109}), "Salvation Bell +9 (5109) is eligible")
# Valid Lv66 +9 armors
_assert(ers.can_epic_refine({"vnum": 11299}), "Black Steel Armor +9 (11299) is eligible")
_assert(ers.can_epic_refine({"vnum": 11499}), "Black Wind Suit +9 (11499) is eligible")
_assert(ers.can_epic_refine({"vnum": 11699}), "Black Magic Armor +9 (11699) is eligible")
_assert(ers.can_epic_refine({"vnum": 11899}), "Black Clothing +9 (11899) is eligible")
# Ineligible items
_assert(not ers.can_epic_refine({"vnum": 10}), "Wooden Sword (10) ineligible")
_assert(not ers.can_epic_refine({"vnum": 168}), "Battle Sword +8 (168) ineligible")
_assert(not ers.can_epic_refine({}), "Empty dict ineligible")
# Check target vnums
_assert(ers.get_recipe(169)["target_vnum"] == 279, "Battle Sword +9 -> Triton Sword +0 (279)")
_assert(ers.get_recipe(11299)["target_vnum"] == 12019, "Black Steel +9 -> Blue Steel +0 (12019)")
func _test_material_and_gold_validation() -> void:
print("\n--- Test 2: Material & Yang Requirement Validation ---")
var ers := EpicRefineSystem.new()
var player_data := {"gold": 100000} # Less than 200,000
var inv: Array = [
{"vnum": 169, "name": "战神之剑+9", "count": 1},
{"vnum": 71123, "name": "龙鳞", "count": 2}, # need 3
{"vnum": 71129, "name": "龙爪", "count": 3} # need 4
]
# Insufficient Yang
var r1 = ers.do_epic_refine(0, inv, player_data)
_assert(r1["ok"] == false and r1["reason"] == "INSUFFICIENT_YANG", "Blocked when Yang < 200,000")
player_data["gold"] = 500000 # Give enough Yang
# Missing Dragon Scales (has 2, needs 3)
var r2 = ers.do_epic_refine(0, inv, player_data)
_assert(r2["ok"] == false and r2["reason"] == "MISSING_DRAGON_SCALES", "Blocked when Dragon Scales < 3")
inv[1]["count"] = 3 # Now have 3 scales
# Missing Dragon Claws (has 3, needs 4)
var r3 = ers.do_epic_refine(0, inv, player_data)
_assert(r3["ok"] == false and r3["reason"] == "MISSING_DRAGON_CLAWS", "Blocked when Dragon Claws < 4")
# Locked item blocked
inv[0]["is_locked"] = true
inv[2]["count"] = 4
var r4 = ers.do_epic_refine(0, inv, player_data)
_assert(r4["ok"] == false and r4["reason"] == "ITEM_LOCKED", "Blocked when item is locked")
func _test_weapon_epic_refine_and_inheritance() -> void:
print("\n--- Test 3: Weapon Refine (169 -> 279) with 100% 5-Attr & Sockets Preserved ---")
var ers := EpicRefineSystem.new()
var signal_data := {"fired": false, "old": 0, "new": 0}
ers.epic_refine_succeeded.connect(func(o: int, n: int, _item: Dictionary):
signal_data["fired"] = true
signal_data["old"] = o
signal_data["new"] = n
)
var base_weapon: Dictionary = {
"vnum": 169,
"name": "战神之剑+9",
"count": 1,
"attributes": [
{"type": 17, "value": 10}, # 半人增伤 +10%
{"type": 15, "value": 10}, # 致命一击 +10%
{"type": 5, "value": 12}, # 力量 +12
{"type": 16, "value": 10}, # 穿透一击 +10%
{"type": 9, "value": 20} # 施法加速 +20%
],
"sockets": [28430, 28431, 28432], # 战士灵石+4, 刺客灵石+4, 修罗灵石+4
"socket_count": 3
}
var player_data := {"gold": 500000}
var inv: Array = [
base_weapon,
{"vnum": 71123, "name": "龙鳞", "count": 5}, # 5 scales (consume 3, leave 2)
{"vnum": 71129, "name": "龙爪", "count": 4} # 4 claws (consume all 4)
]
var res = ers.do_epic_refine(0, inv, player_data)
_assert(res["ok"] == true, "Epic refine succeeded")
_assert(signal_data["fired"] == true, "epic_refine_succeeded signal fired")
_assert(signal_data["old"] == 169 and signal_data["new"] == 279, "Signal values match 169 -> 279")
# Check costs
_assert(player_data["gold"] == 300000, "200,000 Yang deducted (500k -> 300k)")
_assert(inv[1]["count"] == 2, "3 Dragon Scales consumed (5 -> 2)")
_assert(inv[2] == null, "4 Dragon Claws fully consumed (slot becomes null)")
# Check upgraded item in slot 0
var new_item = inv[0]
_assert(new_item["vnum"] == 279, "New item vnum is 279 (Triton Sword +0)")
_assert(new_item["name"] == "崔顿之剑+0", "New item name is 崔顿之剑+0")
# Check 5 Attributes preserved exactly
_assert(new_item["attributes"].size() == 5, "All 5 attributes preserved")
_assert(new_item["attributes"][0]["type"] == 17 and new_item["attributes"][0]["value"] == 10, "Attr 1: Semi-Human +10% preserved")
_assert(new_item["attributes"][1]["type"] == 15 and new_item["attributes"][1]["value"] == 10, "Attr 2: Critical +10% preserved")
_assert(new_item["attributes"][2]["type"] == 5 and new_item["attributes"][2]["value"] == 12, "Attr 3: STR +12 preserved")
_assert(new_item["attributes"][3]["type"] == 16 and new_item["attributes"][3]["value"] == 10, "Attr 4: Piercing +10% preserved")
_assert(new_item["attributes"][4]["type"] == 9 and new_item["attributes"][4]["value"] == 20, "Attr 5: Casting Speed +20% preserved")
# Check 3 Sockets preserved exactly
_assert(new_item["sockets"].size() == 3, "All 3 sockets preserved")
_assert(new_item["sockets"][0] == 28430, "Socket 1 preserved (28430)")
_assert(new_item["sockets"][1] == 28431, "Socket 2 preserved (28431)")
_assert(new_item["sockets"][2] == 28432, "Socket 3 preserved (28432)")
func _test_armor_epic_refine_and_inheritance() -> void:
print("\n--- Test 4: Armor Refine (11299 -> 12019) with Attributes & Sockets ---")
var ers := EpicRefineSystem.new()
var base_armor: Dictionary = {
"vnum": 11299,
"name": "黑钢甲+9",
"count": 1,
"attributes": [
{"type": 1, "value": 2000}, # 最大生命 +2000
{"type": 29, "value": 15}, # 剑防御 +15%
{"type": 30, "value": 15} # 双手防御 +15%
],
"sockets": [28438, 28439, 28440] # 防御灵石+4, 闪避灵石+4, 生命灵石+4
}
var player_data := {"gold": 300000}
var inv: Array = [
base_armor,
{"vnum": 71123, "name": "龙鳞", "count": 3},
{"vnum": 71129, "name": "龙爪", "count": 4}
]
var res = ers.do_epic_refine(0, inv, player_data)
_assert(res["ok"] == true, "Armor epic refine succeeded")
_assert(inv[0]["vnum"] == 12019, "Armor converted to Blue Steel Armor +0 (12019)")
_assert(inv[0]["attributes"].size() == 3, "All 3 armor bonus attributes preserved")
_assert(inv[0]["attributes"][0]["value"] == 2000, "Max HP +2000 preserved")
_assert(inv[0]["sockets"].size() == 3, "All 3 armor sockets preserved")
func _finish() -> void:
print("\n==========================================")
print("Epic Refine Parity Test Results: %d Passed, %d Failed" % [_passed, _failed])
print("==========================================")
if _failed > 0:
quit(1)
else:
quit(0)