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

149 lines
5.1 KiB
GDScript

# test_endless_spire_dungeon_parity.gd —— 40250 无尽天关爬塔挑战 1:1 回归测试套件
extends SceneTree
const EndlessSpireDungeonSystem = preload("res://endless_spire_dungeon_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_endless_spire_dungeon_parity (Direction 1: Endless Spire Dungeon 1:1) ===")
_test_start_and_normal_floors()
_test_milestone_boss_and_checkpoint()
_test_resume_from_checkpoint()
_test_full_clear_floor_50()
_test_timeout_defeat()
_finish()
func _test_start_and_normal_floors() -> void:
print("\n--- Test 1: Starting Floor 1 & Clearing Mobs ---")
var spire := EndlessSpireDungeonSystem.new()
var start_sig := {"fired": false, "floor": 0, "is_boss": true}
spire.floor_started.connect(func(f: int, is_b: bool, _c: int):
start_sig["fired"] = true
start_sig["floor"] = f
start_sig["is_boss"] = is_b
)
var res = spire.start_trial(false)
_assert(res["ok"] == true and spire.current_floor == 1, "Trial started at Floor 1")
_assert(start_sig["fired"] == true and start_sig["floor"] == 1 and start_sig["is_boss"] == false, "floor_started signal emitted for regular floor")
_assert(spire.active_mobs.size() == 6, "Floor 1 has 6 mobs (4 + (1%5)*2 = 6)")
# Kill all mobs on floor 1
var m_ids = spire.active_mobs.keys().duplicate()
for mid in m_ids:
spire.kill_mob(mid)
# Transitioned to floor 2
_assert(spire.current_floor == 2, "Transitioned to Floor 2")
_assert(spire.total_points == 10, "Points earned 10 (1 * 10)")
func _test_milestone_boss_and_checkpoint() -> void:
print("\n--- Test 2: Floor 5 Milestone Boss & Checkpoint Save ---")
var spire := EndlessSpireDungeonSystem.new()
spire.start_trial(false)
var cp_sig := {"fired": false, "cp": 0}
spire.checkpoint_saved.connect(func(cp: int):
cp_sig["fired"] = true
cp_sig["cp"] = cp
)
# Advance to floor 5
while spire.current_floor < 5:
var ids = spire.active_mobs.keys().duplicate()
for mid in ids:
spire.kill_mob(mid)
_assert(spire.current_floor == 5, "Reached Floor 5 (Milestone Boss)")
_assert(spire.active_mobs.size() == 1, "Floor 5 has 1 boss")
var boss_id = spire.active_mobs.keys()[0]
_assert(spire.active_mobs[boss_id]["vnum"] == 691, "Boss is Orc Chief (691)")
# Kill Floor 5 Boss
spire.kill_mob(boss_id)
_assert(spire.current_floor == 6, "Advanced to Floor 6")
_assert(cp_sig["fired"] == true and cp_sig["cp"] == 6, "checkpoint_saved signal fired with Floor 6")
_assert(spire.highest_checkpoint == 6, "highest_checkpoint is 6")
func _test_resume_from_checkpoint() -> void:
print("\n--- Test 3: Exit & Resume from Checkpoint ---")
var spire := EndlessSpireDungeonSystem.new()
spire.start_trial(false)
# Progress to checkpoint 6
while spire.current_floor < 6:
var ids = spire.active_mobs.keys().duplicate()
for mid in ids:
spire.kill_mob(mid)
# Exit trial
spire.exit_trial()
_assert(spire.is_in_trial == false, "Exited trial")
# Resume from checkpoint
var resume_res = spire.start_trial(true)
_assert(resume_res["ok"] == true, "Resumed trial")
_assert(spire.current_floor == 6, "Resumed directly at Floor 6")
func _test_full_clear_floor_50() -> void:
print("\n--- Test 4: Floor 50 Final Boss & Spire Mastery ---")
var spire := EndlessSpireDungeonSystem.new()
spire.highest_checkpoint = 50
spire.start_trial(true)
var mastery_sig := {"fired": false, "floor": 0}
spire.spire_trial_completed.connect(func(f: int, _p: int):
mastery_sig["fired"] = true
mastery_sig["floor"] = f
)
_assert(spire.current_floor == 50, "At final Floor 50")
var boss_id = spire.active_mobs.keys()[0]
_assert(spire.active_mobs[boss_id]["vnum"] == 8027, "Final boss is Chaos Overlord (8027)")
# Kill final boss
var finish_res = spire.kill_mob(boss_id)
_assert(finish_res["ok"] == true and finish_res["trial_completed"] == true, "Trial fully completed")
_assert(spire.is_in_trial == false, "Trial marked as finished")
_assert(mastery_sig["fired"] == true and mastery_sig["floor"] == 50, "spire_trial_completed emitted")
func _test_timeout_defeat() -> void:
print("\n--- Test 5: Timeout Defeat ---")
var spire := EndlessSpireDungeonSystem.new()
spire.start_trial(false)
var fail_sig := {"fired": false, "floor": 0}
spire.spire_trial_failed.connect(func(f: int, _r: String):
fail_sig["fired"] = true
fail_sig["floor"] = f
)
# Advance time past 120s limit
var tick = spire.update(125.0)
_assert(tick["status"] == "failed" and tick["reason"] == "TIME_EXPIRED", "Failed on timeout")
_assert(fail_sig["fired"] == true and fail_sig["floor"] == 1, "spire_trial_failed emitted")
_assert(spire.is_in_trial == false, "Trial ended")
func _finish() -> void:
print("\n==========================================")
print("Endless Spire Dungeon 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 Endless Spire Dungeon parity tests passed!")
quit(0)