- 桥梁与静态物体高度采样修复: - 严格对齐 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 客户端对拍缺陷发现与修复工程指南
184 lines
7.6 KiB
GDScript
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)
|