- 桥梁与静态物体高度采样修复: - 严格对齐 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.6 KiB
GDScript
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")
|