- 桥梁与静态物体高度采样修复: - 严格对齐 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 客户端对拍缺陷发现与修复工程指南
100 lines
3.5 KiB
GDScript
100 lines
3.5 KiB
GDScript
# test_point_reset_parity.gd
|
|
# 检验 40250 属性点/技能重置老妪洗点与两阶段确认系统
|
|
extends SceneTree
|
|
|
|
const PointResetSystem = preload("res://point_reset_system.gd")
|
|
|
|
func _init() -> void:
|
|
print("--- 开始测试 40250 洗点老妪属性与技能重置系统 (test_point_reset_parity) ---")
|
|
var sys = PointResetSystem.new()
|
|
var fails: int = 0
|
|
|
|
# 1. 初始化战士数据 (Lv 25, 2000 金币, CON 20, INT 3, STR 50, DEX 10, 剩余属性点 2)
|
|
# 战士初始: CON 4, INT 3, STR 6, DEX 3
|
|
# 投入点数: CON +16, STR +44, DEX +7 = 67 点
|
|
sys.init_player_data(
|
|
0, # WARRIOR
|
|
25, # Lv 25
|
|
2000, # 2000 Yang
|
|
{"CON": 20, "INT": 3, "STR": 50, "DEX": 10},
|
|
2, # 2 unallocated stat points
|
|
1, # 分支 1 (体战)
|
|
0,
|
|
{1: 17, 2: 5} # 17级剑气, 5级狂暴
|
|
)
|
|
|
|
# 2. 两阶段弹窗生命周期测试
|
|
sys.open_dialog()
|
|
if sys.state != PointResetSystem.DialogState.INITIAL_PROMPT:
|
|
printerr("FAIL: 打开后未进入 INITIAL_PROMPT 状态: ", sys.state)
|
|
fails += 1
|
|
|
|
var opened_confirm = sys.open_confirm_dialog()
|
|
if not opened_confirm or sys.state != PointResetSystem.DialogState.CONFIRMATION:
|
|
printerr("FAIL: 未成功转入 CONFIRMATION 阶段: ", sys.state)
|
|
fails += 1
|
|
|
|
# 3. 接受洗点并核对扣款与属性全额回退
|
|
var reset_ok = sys.accept_reset()
|
|
if not reset_ok:
|
|
printerr("FAIL: 确认洗点失败!")
|
|
fails += 1
|
|
if sys.player_gold != 1500: # 2000 - 500 = 1500
|
|
printerr("FAIL: 500 金币扣除错误,剩余金币: ", sys.player_gold)
|
|
fails += 1
|
|
if sys.last_packet_sent != "/pointreset":
|
|
printerr("FAIL: 发送协议指令不符: ", sys.last_packet_sent)
|
|
fails += 1
|
|
|
|
# 属性应重置为战士初始值 [CON:4, INT:3, STR:6, DEX:3]
|
|
if sys.current_stats["CON"] != 4 or sys.current_stats["STR"] != 6 or sys.current_stats["DEX"] != 3 or sys.current_stats["INT"] != 3:
|
|
printerr("FAIL: 四维属性未恢复初始基准: ", sys.current_stats)
|
|
fails += 1
|
|
|
|
# 未分配属性点应为: 2(原未分配) + 67(洗回) = 69 点
|
|
if sys.unallocated_stat_points != 69:
|
|
printerr("FAIL: 属性点回退总额不符,期望 69,实际: ", sys.unallocated_stat_points)
|
|
fails += 1
|
|
|
|
if sys.state != PointResetSystem.DialogState.CLOSED:
|
|
printerr("FAIL: 洗点完成后弹窗未关闭: ", sys.state)
|
|
fails += 1
|
|
|
|
# 4. 金币不足时拦截测试
|
|
sys.player_gold = 200
|
|
sys.open_dialog()
|
|
var confirm_when_broke = sys.open_confirm_dialog()
|
|
if confirm_when_broke or sys.state != PointResetSystem.DialogState.CLOSED:
|
|
printerr("FAIL: 金币不足时未能正确阻断!")
|
|
fails += 1
|
|
|
|
# 5. 老妇人 30 级以下技能重洗测试
|
|
sys.player_gold = 50000
|
|
var skill_reset_ok = sys.reset_skills_at_old_woman()
|
|
if not skill_reset_ok:
|
|
printerr("FAIL: 25 级角色老妇人洗技能失败!")
|
|
fails += 1
|
|
if sys.current_skill_tree != 0:
|
|
printerr("FAIL: 洗技能后技能树分支应重置为 0: ", sys.current_skill_tree)
|
|
fails += 1
|
|
if sys.active_skills.size() != 0:
|
|
printerr("FAIL: 洗技能后技能字典应清空: ", sys.active_skills)
|
|
fails += 1
|
|
if sys.unallocated_skill_points != 22: # 17 + 5 = 22
|
|
printerr("FAIL: 技能点退回不符,期望 22,实际: ", sys.unallocated_skill_points)
|
|
fails += 1
|
|
|
|
# 6. 超出 30 级老妇人洗技能拒绝测试
|
|
sys.player_level = 31
|
|
var high_lv_reset = sys.reset_skills_at_old_woman()
|
|
if high_lv_reset:
|
|
printerr("FAIL: 超过 30 级老妇人洗技能未被拒绝!")
|
|
fails += 1
|
|
|
|
if fails == 0:
|
|
print("PASS: test_point_reset_parity (8/8 全部通过)")
|
|
quit(0)
|
|
else:
|
|
printerr("FAILED: test_point_reset_parity (", fails, " 项失败)")
|
|
quit(1)
|