- 桥梁与静态物体高度采样修复: - 严格对齐 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 客户端对拍缺陷发现与修复工程指南
124 lines
5.3 KiB
GDScript
124 lines
5.3 KiB
GDScript
# test_soul_stone_grandmaster_parity.gd —— Metin2 40250 灵魂石领悟宗师绝技 1:1 测试套件
|
|
extends SceneTree
|
|
|
|
const SoulStoneGrandmasterSystem = preload("res://soul_stone_grandmaster_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_soul_stone_grandmaster_parity (Direction 1: Soul Stone Grandmaster 1:1) ===")
|
|
|
|
test_eligibility_and_alignment_cost()
|
|
test_successful_training_and_p_tier()
|
|
test_failure_alignment_penalty()
|
|
test_cooldown_and_exorcism()
|
|
test_serialization()
|
|
|
|
print("\n=======================================================")
|
|
print("Soul Stone Grandmaster Tests: %d Passed, %d Failed" % [_passed, _failed])
|
|
print("=======================================================")
|
|
|
|
if _failed > 0:
|
|
quit(1)
|
|
else:
|
|
quit(0)
|
|
|
|
func test_eligibility_and_alignment_cost() -> void:
|
|
print("\n--- Test 1: Eligibility & Alignment Calculations (40250 1:1) ---")
|
|
var system = SoulStoneGrandmasterSystem.new()
|
|
|
|
# 检查 G 阶资格: 30(G1) ~ 39(G10) 允许,其他拒绝
|
|
_assert(system.can_train_skill(20) == false, "M-tier skill (Lv 20) not eligible for soul stone")
|
|
_assert(system.can_train_skill(30) == true, "G1 (Lv 30) eligible")
|
|
_assert(system.can_train_skill(39) == true, "G10 (Lv 39) eligible")
|
|
_assert(system.can_train_skill(40) == false, "P-tier (Lv 40) already maxed")
|
|
|
|
# 善恶值消耗计算: need_alignment = 1000 + 500 * (level - 30)
|
|
# 正善恶值玩家
|
|
_assert(system.get_required_alignment(30, 5000) == 1000, "G1 costs 1000 alignment")
|
|
_assert(system.get_required_alignment(31, 5000) == 1500, "G2 costs 1500 alignment")
|
|
_assert(system.get_required_alignment(39, 5000) == 5500, "G10 costs 5500 alignment")
|
|
|
|
# 负善恶值 (邪恶阵营) 翻倍惩罚 (40250 quest: need_alignment = need_alignment * 2)
|
|
_assert(system.get_required_alignment(30, -2000) == 2000, "G1 costs 2000 alignment for evil player")
|
|
_assert(system.get_required_alignment(39, -500) == 11000, "G10 costs 11000 alignment for evil player")
|
|
|
|
func test_successful_training_and_p_tier() -> void:
|
|
print("\n--- Test 2: Successful Training & Reaching P (40250 1:1) ---")
|
|
var system = SoulStoneGrandmasterSystem.new()
|
|
|
|
var inv: Array = [
|
|
{"vnum": 50513, "count": 2} # 灵魂石 x2
|
|
]
|
|
|
|
# 1. 成功从 G1 (30) 升到 G2 (31)
|
|
var res = system.train_grandmaster_skill(inv, 0, 1, "三重斩", 30, 8000, false, true)
|
|
_assert(res["ok"] == true and res["success"] == true, "Training succeeded")
|
|
_assert(res["new_level"] == 31, "Skill level promoted to 31 (G2)")
|
|
_assert(res["alignment_cost"] == 1000, "Deducted 1000 alignment")
|
|
_assert(res["new_alignment"] == 7000, "New alignment is 7000 (8000 - 1000)")
|
|
_assert(inv[0]["count"] == 1, "Consumed 1 Soul Stone")
|
|
|
|
# 清除冷却用于测试
|
|
system.use_exorcism_scroll()
|
|
|
|
# 2. 成功从 G10 (39) 登峰造极突破至 P 阶 (40)
|
|
res = system.train_grandmaster_skill(inv, 0, 1, "三重斩", 39, 10000, false, true)
|
|
_assert(res["ok"] == true and res["success"] == true, "Promoted to P tier")
|
|
_assert(res["new_level"] == 40, "Level reached 40")
|
|
_assert(res["is_perfect_master"] == true, "Reached Perfect Master!")
|
|
_assert(res["tier_text"] == "P 阶 (Perfect Master)", "Tier text is Perfect Master")
|
|
|
|
func test_failure_alignment_penalty() -> void:
|
|
print("\n--- Test 3: Failure & Alignment Penalty (40250 1:1) ---")
|
|
var system = SoulStoneGrandmasterSystem.new()
|
|
|
|
var inv: Array = [{"vnum": 50513, "count": 1}]
|
|
# 强制失败 (roll = 90 > 30)
|
|
var res = system.train_grandmaster_skill(inv, 0, 2, "旋风斩", 30, 5000, false, false, 90)
|
|
_assert(res["ok"] == true and res["success"] == false, "Training failed")
|
|
_assert(res["new_level"] == 30, "Skill level unchanged at 30")
|
|
_assert(res["alignment_cost"] >= 330 and res["alignment_cost"] <= 500, "Deducted 1/3 to 1/2 penalty")
|
|
_assert(res["new_alignment"] < 5000, "Alignment penalised")
|
|
_assert(inv[0] == null, "Soul stone shattered and removed")
|
|
|
|
func test_cooldown_and_exorcism() -> void:
|
|
print("\n--- Test 4: Cooldown & Exorcism Scroll (40250 1:1) ---")
|
|
var system = SoulStoneGrandmasterSystem.new()
|
|
var inv: Array = [{"vnum": 50513, "count": 2}]
|
|
|
|
system.train_grandmaster_skill(inv, 0, 1, "三重斩", 30, 8000, false, true)
|
|
_assert(system.training_cooldown_left > 0.0, "Cooldown active after training")
|
|
|
|
# 冷却期间再次参悟 -> 拦截
|
|
var res = system.train_grandmaster_skill(inv, 0, 1, "三重斩", 31, 7000, false, true)
|
|
_assert(res["ok"] == false, "Rejected during cooldown")
|
|
_assert(res["reason"] == "COOLDOWN_ACTIVE", "Reason is COOLDOWN_ACTIVE")
|
|
|
|
# 使用驱魔卷轴 (71001) 清除心境冷却
|
|
system.use_exorcism_scroll()
|
|
_assert(system.training_cooldown_left == 0.0, "Cooldown cleared by exorcism scroll")
|
|
|
|
# 再次参悟 -> 成功
|
|
res = system.train_grandmaster_skill(inv, 0, 1, "三重斩", 31, 7000, false, true)
|
|
_assert(res["ok"] == true, "Trained successfully after exorcism")
|
|
|
|
func test_serialization() -> void:
|
|
print("\n--- Test 5: Serialization & Restoration ---")
|
|
var system = SoulStoneGrandmasterSystem.new()
|
|
system.training_cooldown_left = 15000.0
|
|
var data = system.serialize()
|
|
|
|
var restored = SoulStoneGrandmasterSystem.new()
|
|
restored.deserialize(data)
|
|
_assert(restored.training_cooldown_left == 15000.0, "Restored cooldown")
|