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

224 lines
8.1 KiB
GDScript

# test_devils_catacomb_parity.gd —— 40250 地下墓穴与冥王阿兹瑞尔 1:1 纯净回归测试套件
extends SceneTree
const DevilsCatacombSystem = preload("res://devils_catacomb_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_devils_catacomb_parity (Direction 1: Devil's Catacomb 1:1) ===")
_test_entry_requirements()
_test_floor_1_to_4_progression()
_test_floor_5_tartaros_and_obelisk()
_test_floor_6_charon()
_test_floor_7_azrael_battle_and_drops()
_test_catacomb_timeout()
_finish()
func _test_entry_requirements() -> void:
print("\n--- Test 1: Entry Requirements (Lv75 & Soul Key 30311) ---")
var dcs := DevilsCatacombSystem.new()
var inv: Array = [
{"vnum": 30311, "name": "灵魂水晶钥匙", "count": 1}
]
# Level < 75 rejected
var r1 = dcs.enter_catacomb(70, inv)
_assert(r1["ok"] == false and r1["reason"] == "LEVEL_TOO_LOW", "Level < 75 rejected")
# Missing key
var r2 = dcs.enter_catacomb(75, [null])
_assert(r2["ok"] == false and r2["reason"] == "MISSING_SOUL_KEY", "Missing soul crystal key rejected")
# Valid entry
var r3 = dcs.enter_catacomb(75, inv)
_assert(r3["ok"] == true, "Entry succeeds with Lv 75 and Soul Crystal Key")
_assert(dcs.is_active == true, "Catacomb is active")
_assert(dcs.current_floor == 1, "Starts on Floor 1")
_assert(dcs.remaining_time == 3600.0, "60-minute countdown initialized")
func _test_floor_1_to_4_progression() -> void:
print("\n--- Test 2: Floor 1 to 4 Progression (Key, Maze, Real Metin) ---")
var dcs := DevilsCatacombSystem.new()
var inv: Array = [
{"vnum": 30311, "name": "灵魂水晶钥匙", "count": 1}
]
dcs.enter_catacomb(75, inv)
var floor_signal := {"fired": false, "floor": 0}
dcs.floor_advanced.connect(func(f: int):
floor_signal["fired"] = true
floor_signal["floor"] = f
)
# 1. Floor 1: Unlock seal using 30311 key
var r1 = dcs.unlock_floor_1(inv)
_assert(r1["ok"] == true and r1["floor"] == 2, "Unlocked Floor 1 -> Advanced to Floor 2")
_assert(inv[0] == null, "Soul crystal key consumed")
_assert(floor_signal["fired"] == true and floor_signal["floor"] == 2, "floor_advanced signal fired for floor 2")
# 2. Floor 2: Complete maze
var r2 = dcs.complete_floor_2()
_assert(r2["ok"] == true and r2["floor"] == 3, "Maze completed -> Advanced to Floor 3")
# 3. Floor 3: Break fake vs real Metin (8035)
dcs.correct_metin_id = 4 # Force correct ID to 4 for deterministic test
var metin_signal := {"fired": false, "correct": false}
dcs.metin_destroyed.connect(func(corr: bool):
metin_signal["fired"] = true
metin_signal["correct"] = corr
)
# Break fake metin 1
var r_fake = dcs.break_floor_3_metin(1)
_assert(r_fake["ok"] == true and r_fake["correct"] == false, "Fake metin detected")
_assert(dcs.current_floor == 3, "Stays on floor 3 after fake metin")
_assert(metin_signal["fired"] == true and metin_signal["correct"] == false, "metin_destroyed signal fired false")
# Break real metin 4
var r_real = dcs.break_floor_3_metin(4)
_assert(r_real["ok"] == true and r_real["correct"] == true, "Real metin destroyed")
_assert(dcs.current_floor == 4, "Advanced to Floor 4")
_assert(metin_signal["correct"] == true, "metin_destroyed signal fired true")
# 4. Floor 4: Complete pillar maze
var r4 = dcs.complete_floor_4()
_assert(r4["ok"] == true and r4["floor"] == 5, "Floor 4 completed -> Advanced to Floor 5")
func _test_floor_5_tartaros_and_obelisk() -> void:
print("\n--- Test 3: Floor 5 Tartaros Defeat & Obelisk Activation ---")
var dcs := DevilsCatacombSystem.new()
dcs.enter_catacomb(75, [{"vnum": 30311}])
dcs.current_floor = 5 # Jump to floor 5
var inv: Array = [null]
var tartaros_signal := {"fired": false}
dcs.tartaros_killed.connect(func(_drop: Dictionary):
tartaros_signal["fired"] = true
)
# Defeat Tartaros
var r_tar = dcs.defeat_tartaros(inv)
_assert(r_tar["ok"] == true, "Tartaros defeated")
_assert(inv[0] != null and inv[0]["vnum"] == 30312, "Grim Soul Stone (30312) dropped into inventory")
_assert(tartaros_signal["fired"] == true, "tartaros_killed signal fired")
# Insert stone into obelisk
var obelisk_signal := {"fired": false}
dcs.obelisk_activated.connect(func():
obelisk_signal["fired"] = true
)
var r_ob = dcs.insert_grim_stone_to_obelisk(inv)
_assert(r_ob["ok"] == true and r_ob["floor"] == 6, "Obelisk activated -> Advanced to Floor 6")
_assert(inv[0] == null, "Grim Soul Stone consumed by obelisk")
_assert(obelisk_signal["fired"] == true, "obelisk_activated signal fired")
func _test_floor_6_charon() -> void:
print("\n--- Test 4: Floor 6 Charon Defeat ---")
var dcs := DevilsCatacombSystem.new()
dcs.enter_catacomb(75, [{"vnum": 30311}])
dcs.current_floor = 6
var charon_signal := {"fired": false}
dcs.charon_killed.connect(func(): charon_signal["fired"] = true)
var r = dcs.defeat_charon()
_assert(r["ok"] == true and r["floor"] == 7, "Charon defeated -> Advanced to Floor 7")
_assert(charon_signal["fired"] == true, "charon_killed signal fired")
_assert(dcs.is_azrael_alive == true, "Azrael is now active on floor 7")
_assert(dcs.azrael_hp == 900000, "Azrael initial HP is 900,000")
func _test_floor_7_azrael_battle_and_drops() -> void:
print("\n--- Test 5: Floor 7 Azrael Battle, Minion Summon & Drops ---")
var dcs := DevilsCatacombSystem.new()
dcs.enter_catacomb(75, [{"vnum": 30311}])
dcs.current_floor = 6
dcs.defeat_charon() # Transitions to floor 7
var azrael_hp_signal := {"fired": false, "hp": 0}
dcs.azrael_hp_changed.connect(func(hp: int, _max: int):
azrael_hp_signal["fired"] = true
azrael_hp_signal["hp"] = hp
)
# 1. Normal damage: Raw 1680 - DEF 680 = 1000 net dmg
var r1 = dcs.attack_azrael(1680)
_assert(r1["ok"] == true and r1["net_dmg"] == 1000, "Raw 1680 - 680 DEF = 1000 net dmg")
_assert(dcs.azrael_hp == 899000, "Azrael HP reduced to 899,000")
_assert(azrael_hp_signal["fired"] == true, "azrael_hp_changed signal fired")
# 2. Cross 50% HP threshold (450,000 HP) -> summons minions
# Current HP: 899,000. Deal 450,000 net dmg -> raw 450,680
var r2 = dcs.attack_azrael(450680)
_assert(dcs.azrael_hp == 449000, "Azrael HP below 50% (449,000)")
_assert(r2["summoned_minions"] == true, "Azrael summoned undead minions at <= 50% HP")
# 3. Lethal damage kills Azrael
var clear_signal := {"fired": false, "drops": []}
dcs.catacomb_cleared.connect(func(drops: Array):
clear_signal["fired"] = true
clear_signal["drops"] = drops
)
var r3 = dcs.attack_azrael(1000000)
_assert(r3["ok"] == true and r3["killed"] == true, "Azrael killed")
_assert(dcs.is_active == false, "Catacomb completed")
_assert(clear_signal["fired"] == true, "catacomb_cleared signal fired")
# Verify drops
var drops: Array = r3["drops"]
var has_chest := false
var has_soul_stone := false
var has_shield := false
var has_gold := false
for d in drops:
if d["vnum"] == 50187: # Azrael Chest
has_chest = true
elif d["vnum"] == 50513: # Soul Stone
has_soul_stone = true
elif d["vnum"] == 13149: # Titan Shield
has_shield = true
elif d["vnum"] == 1:
has_gold = true
_assert(has_chest, "Guaranteed Azrael Chest (50187) dropped")
_assert(has_soul_stone, "Guaranteed Soul Stone (50513) dropped")
_assert(has_shield, "Titan Shield (13149) dropped")
_assert(has_gold, "Yang dropped")
func _test_catacomb_timeout() -> void:
print("\n--- Test 6: Catacomb Timeout Failure ---")
var dcs := DevilsCatacombSystem.new()
dcs.enter_catacomb(75, [{"vnum": 30311}])
var fail_signal := {"fired": false, "reason": ""}
dcs.catacomb_failed.connect(func(r: String):
fail_signal["fired"] = true
fail_signal["reason"] = r
)
dcs.update(3601.0)
_assert(fail_signal["fired"] == true and fail_signal["reason"] == "TIME_OUT", "Timeout failure emitted")
_assert(dcs.is_active == false, "Catacomb deactivated on timeout")
func _finish() -> void:
print("\n==========================================")
print("Devil's Catacomb Parity Test Results: %d Passed, %d Failed" % [_passed, _failed])
print("==========================================")
if _failed > 0:
quit(1)
else:
quit(0)