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

141 lines
5.6 KiB
GDScript

# test_demon_tower_parity.gd —— 验证方向 1:恶魔之塔 1~9 层单机爬塔循环与塔顶免费铁匠 40250 1:1 对齐
extends SceneTree
const DemonTowerSystem = preload("res://demon_tower_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_demon_tower_parity (Direction 1: Demon Tower 1~9 Parity 1:1) ===")
test_floors_1_to_3()
test_floor_4_puzzle()
test_floor_5_seals()
test_floor_6_blacksmith_and_free_refine()
test_floors_7_to_9_reaper()
print("\n=== SUMMARY: %d passed, %d failed ===" % [_passed, _failed])
if _failed > 0:
printerr("TEST FAILED!")
quit(1)
else:
print("ALL TESTS PASSED!")
quit(0)
func test_floors_1_to_3() -> void:
print("\n--- Test 1: Floors 1 to 3 Progression ---")
var tower := DemonTowerSystem.new()
tower.start_tower()
_assert(tower.get_floor() == 1, "Tower started on Floor 1")
_assert("恶魔入口" in tower.get_floor_name(), "Floor 1 name matches")
# Floor 1: Metin 8015
_assert(not tower.on_floor1_metin_destroyed(9999), "Wrong metin does not advance")
_assert(tower.on_floor1_metin_destroyed(DemonTowerSystem.VNUM_METIN_FLOOR1), "Destroying Metin 8015 advances to Floor 2")
_assert(tower.get_floor() == 2, "Now on Floor 2")
# Floor 2: Clear mobs
_assert(not tower.on_floor2_mobs_cleared(10), "Floor 2 remains while mobs remain")
_assert(tower.on_floor2_mobs_cleared(0), "Clearing mobs advances to Floor 3")
_assert(tower.get_floor() == 3, "Now on Floor 3")
# Floor 3: Demon King 1091
_assert(tower.on_floor3_boss_killed(DemonTowerSystem.VNUM_DEMON_KING), "Killing Demon King 1091 advances to Floor 4")
_assert(tower.get_floor() == 4, "Now on Floor 4")
func test_floor_4_puzzle() -> void:
print("\n--- Test 2: Floor 4 7-Metin Puzzle ---")
var tower := DemonTowerSystem.new()
tower.current_floor = 4
tower.is_active = true
tower.setup_floor4_metins()
var real_idx := tower.floor4_real_metin_idx
_assert(real_idx >= 0 and real_idx < 7, "Real metin index is between 0 and 6")
var fake_idx := (real_idx + 1) % 7
var res_fake := tower.on_floor4_metin_hit(fake_idx)
_assert(res_fake.ok and not res_fake.is_real, "Hitting fake metin gives clue, does not advance")
_assert(tower.get_floor() == 4, "Still on Floor 4")
var res_real := tower.on_floor4_metin_hit(real_idx)
_assert(res_real.ok and res_real.is_real, "Hitting real metin advances to Floor 5")
_assert(tower.get_floor() == 5, "Now on Floor 5")
func test_floor_5_seals() -> void:
print("\n--- Test 3: Floor 5 5-Stone Pillar Seals ---")
var tower := DemonTowerSystem.new()
tower.current_floor = 5
tower.is_active = true
# Unlocking with wrong key fails
var res_bad := tower.on_floor5_unlock_pillar(12345)
_assert(not res_bad.ok, "Wrong key fails")
# Unlocking pillars 1..4
for i in 4:
var res := tower.on_floor5_unlock_pillar(DemonTowerSystem.VNUM_ZIN_KEY_FLOOR5)
_assert(res.ok and not res.completed, "Pillar %d unlocked" % (i + 1))
# Unlocking 5th pillar completes floor 5
var res5 := tower.on_floor5_unlock_pillar(DemonTowerSystem.VNUM_ZIN_KEY_FLOOR5)
_assert(res5.ok and res5.completed, "5th pillar unlocked, floor completed")
_assert(tower.get_floor() == 6, "Now on Floor 6")
func test_floor_6_blacksmith_and_free_refine() -> void:
print("\n--- Test 4: Floor 6 Elite Demon King & Free Blacksmith ---")
var tower := DemonTowerSystem.new()
tower.current_floor = 6
tower.is_active = true
# Kill Elite Demon King 1092
var res_boss := tower.on_floor6_boss_killed(DemonTowerSystem.VNUM_ELITE_DEMON_KING)
_assert(res_boss.ok, "Elite Demon King killed")
_assert(tower.floor6_blacksmith_vnum in [20074, 20075, 20076], "Tower Blacksmith spawned")
# Free Refine with Blacksmith
tower.floor6_blacksmith_vnum = DemonTowerSystem.NPC_TOWER_WEAPON_SMITH
var sword := {"vnum": 18} # Sword +8
var res_refine := tower.perform_tower_free_refine(sword, 1)
_assert(res_refine.ok and res_refine.new_vnum == 19, "Sword+8 free refined to Sword+9 without materials")
# Second attempt rejected (only 1 free refine permitted per run)
var res_refine2 := tower.perform_tower_free_refine(sword, 1)
_assert(not res_refine2.ok and res_refine2.code == "ALREADY_USED", "Second free refine attempt rejected")
# Advance to floor 7 level gate (requires level 75)
var res_adv_low := tower.advance_to_floor7(70)
_assert(not res_adv_low.ok and res_adv_low.code == "LEVEL_TOO_LOW", "Level < 75 rejected from Floor 7")
var res_adv_ok := tower.advance_to_floor7(75)
_assert(res_adv_ok.ok, "Level 75 advances to Floor 7")
_assert(tower.get_floor() == 7, "Now on Floor 7")
func test_floors_7_to_9_reaper() -> void:
print("\n--- Test 5: Floors 7 to 9 & Death Reaper Defeat ---")
var tower := DemonTowerSystem.new()
tower.current_floor = 7
tower.is_active = true
# Floor 7 Map 30302
_assert(tower.on_floor7_map_used(DemonTowerSystem.VNUM_ZIN_MAP_FLOOR7), "Using Zin Map 30302 advances to Floor 8")
_assert(tower.get_floor() == 8, "Now on Floor 8")
# Floor 8 Key 30304
_assert(tower.on_floor8_key_used(DemonTowerSystem.VNUM_ZIN_KEY_FLOOR8), "Using Zin Key 30304 advances to Floor 9")
_assert(tower.get_floor() == 9, "Now on Floor 9")
# Floor 9 Final Boss: Death Reaper 1093
var res_reaper := tower.on_floor9_boss_killed(DemonTowerSystem.VNUM_DEATH_REAPER)
_assert(res_reaper.ok and res_reaper.code == "TOWER_CLEAR", "Death Reaper defeated, tower cleared")
_assert(res_reaper.drop_vnum == DemonTowerSystem.VNUM_DEATH_REAPER_CHEST, "Rewards Death Reaper Chest (50082)")
_assert(not tower.is_active, "Tower challenge marked completed")