- 桥梁与静态物体高度采样修复: - 严格对齐 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 客户端对拍缺陷发现与修复工程指南
141 lines
5.4 KiB
GDScript
141 lines
5.4 KiB
GDScript
# test_title_trophy_buff_parity.gd —— 40250 真实称号词条战力加成与奖杯成就图鉴 1:1 回归测试套件
|
|
extends SceneTree
|
|
|
|
const TitleTrophyBuffSystem = preload("res://title_trophy_buff_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_title_trophy_buff_parity (Direction 4: Title Trophy Buffs 1:1) ===")
|
|
_test_catalog_and_unlock()
|
|
_test_title_equip_and_stat_injection()
|
|
_test_title_switching_and_unequip()
|
|
_test_trophy_milestone_progression()
|
|
_finish()
|
|
|
|
func _test_catalog_and_unlock() -> void:
|
|
print("\n--- Test 1: Title Catalog & Unlocking ---")
|
|
var sys := TitleTrophyBuffSystem.new()
|
|
_assert(TitleTrophyBuffSystem.TITLES_CATALOG.size() == 7, "Catalog has 7 iconic titles")
|
|
|
|
var unk_res = sys.unlock_title("InvalidTitle")
|
|
_assert(unk_res["ok"] == false and unk_res["reason"] == "UNKNOWN_TITLE", "Unknown title rejected")
|
|
|
|
var u1 = sys.unlock_title("屠龙尊者", 100)
|
|
_assert(u1["ok"] == true, "屠龙尊者 unlocked")
|
|
_assert(sys.trophy_points == 100, "Trophy points = 100")
|
|
_assert("屠龙尊者" in sys.unlocked_titles, "Title in unlocked list")
|
|
|
|
func _test_title_equip_and_stat_injection() -> void:
|
|
print("\n--- Test 2: Equipping Title & Live Stat Injection ---")
|
|
var sys := TitleTrophyBuffSystem.new()
|
|
sys.unlock_title("屠龙尊者")
|
|
|
|
var player := {
|
|
"name": "战神",
|
|
"max_hp": 10000,
|
|
"atk": 500,
|
|
"def": 300,
|
|
"boss_dmg_pct": 0,
|
|
"crit_pct": 5
|
|
}
|
|
|
|
var equip_sig := {"fired": false, "title": ""}
|
|
sys.title_stat_buffs_applied.connect(func(t: String, _b: Dictionary):
|
|
equip_sig["fired"] = true
|
|
equip_sig["title"] = t
|
|
)
|
|
|
|
# Try equip locked title
|
|
var fail_lock = sys.equip_title("百战名将", player)
|
|
_assert(fail_lock["ok"] == false and fail_lock["reason"] == "TITLE_NOT_UNLOCKED", "Cannot equip locked title")
|
|
|
|
# Equip "屠龙尊者" (boss_dmg_pct: 15, max_hp: 2000, crit_pct: 5)
|
|
var res = sys.equip_title("屠龙尊者", player)
|
|
_assert(res["ok"] == true, "Title equipped")
|
|
_assert(equip_sig["fired"] == true and equip_sig["title"] == "屠龙尊者", "title_stat_buffs_applied emitted")
|
|
_assert(player["max_hp"] == 12000, "Max HP increased 10000 -> 12000 (+2000)")
|
|
_assert(player["boss_dmg_pct"] == 15, "Boss damage increased 0 -> 15%")
|
|
_assert(player["crit_pct"] == 10, "Crit rate increased 5 -> 10% (+5%)")
|
|
|
|
func _test_title_switching_and_unequip() -> void:
|
|
print("\n--- Test 3: Zero-Drift Switching & Unequipping ---")
|
|
var sys := TitleTrophyBuffSystem.new()
|
|
sys.unlock_title("屠龙尊者")
|
|
sys.unlock_title("百战名将")
|
|
|
|
var player := {
|
|
"max_hp": 10000,
|
|
"atk": 500,
|
|
"def": 300,
|
|
"boss_dmg_pct": 0,
|
|
"crit_pct": 5
|
|
}
|
|
|
|
# 1. Equip 屠龙尊者
|
|
sys.equip_title("屠龙尊者", player)
|
|
_assert(player["max_hp"] == 12000, "HP +2000")
|
|
|
|
# 2. Switch directly to 百战名将 (atk: 80, def: 50, max_hp: 1500)
|
|
# 屠龙尊者 stats (-2000 HP, -15% boss dmg, -5% crit) must be deducted first!
|
|
sys.equip_title("百战名将", player)
|
|
_assert(player["max_hp"] == 11500, "HP is 10000 + 1500 = 11500 (Clean subtraction of 2000, addition of 1500)")
|
|
_assert(player["atk"] == 580, "Atk is 500 + 80 = 580")
|
|
_assert(player["def"] == 350, "Def is 300 + 50 = 350")
|
|
_assert(player["boss_dmg_pct"] == 0, "Boss damage reverted back to 0")
|
|
_assert(player["crit_pct"] == 5, "Crit rate reverted back to baseline 5")
|
|
|
|
# 3. Unequip 百战名将
|
|
var unequip_sig := {"fired": false}
|
|
sys.title_stat_buffs_removed.connect(func(_t: String): unequip_sig["fired"] = true)
|
|
|
|
sys.unequip_title(player)
|
|
_assert(unequip_sig["fired"] == true, "title_stat_buffs_removed emitted")
|
|
_assert(player["max_hp"] == 10000, "HP returned to exact initial 10000")
|
|
_assert(player["atk"] == 500, "Atk returned to exact initial 500")
|
|
_assert(player["def"] == 300, "Def returned to exact initial 300")
|
|
|
|
func _test_trophy_milestone_progression() -> void:
|
|
print("\n--- Test 4: Trophy Milestones & Cumulative Passives ---")
|
|
var sys := TitleTrophyBuffSystem.new()
|
|
|
|
var milestone_events := []
|
|
sys.trophy_milestone_reached.connect(func(tier: int, tname: String, _desc: String):
|
|
milestone_events.append({"tier": tier, "name": tname})
|
|
)
|
|
|
|
# Unlock 1 title (50 pts) -> Reaches Tier 1 (50 pts)
|
|
sys.unlock_title("屠龙尊者", 50)
|
|
_assert(milestone_events.size() == 1 and milestone_events[0]["tier"] == 1, "Reached Tier 1 (青铜试炼奖杯)")
|
|
|
|
# Unlock 2 more titles (+100 pts -> 150 pts total) -> Reaches Tier 2 (150 pts)
|
|
sys.unlock_title("恶魔克星", 50)
|
|
sys.unlock_title("魔石终结者", 50)
|
|
_assert(milestone_events.size() == 2 and milestone_events[1]["tier"] == 2, "Reached Tier 2 (白银征服奖杯)")
|
|
|
|
var passives = sys.get_total_trophy_passive_bonuses()
|
|
_assert(passives.has("all_stats") and passives["all_stats"] == 3, "Has Tier 1 passive: all_stats +3")
|
|
_assert(passives.has("max_hp") and passives["max_hp"] == 1000, "Has Tier 2 passive: max_hp +1000")
|
|
_assert(passives.has("drop_rate_pct") and passives["drop_rate_pct"] == 5, "Has Tier 2 passive: drop_rate +5%")
|
|
|
|
func _finish() -> void:
|
|
print("\n==========================================")
|
|
print("Title Trophy Buff 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 Title Trophy Buff parity tests passed!")
|
|
quit(0)
|