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

186 lines
6.7 KiB
GDScript

# test_dragon_lair_parity.gd —— 40250 冰龙贝兰-塞陶巢穴 1:1 纯净回归测试套件
extends SceneTree
const DragonLairSystem = preload("res://dragon_lair_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_dragon_lair_parity (Direction 1: Dragon Lair Beran-Setaou 1:1) ===")
_test_entry_and_key_consumption()
_test_metin_buffs_and_debuffs()
_test_metin_hp_regen()
_test_dragon_defeat_and_drops()
_test_dungeon_timeout()
_finish()
func _test_entry_and_key_consumption() -> void:
print("\n--- Test 1: Entry Requirements & Key Consumption (30179 x3) ---")
var dls := DragonLairSystem.new()
var inv: Array = [
{"vnum": 30179, "name": "扭曲钥匙", "count": 2},
{"vnum": 30179, "name": "扭曲钥匙", "count": 1},
null
]
# Level 70 rejected
var r1 = dls.enter_lair(70, inv)
_assert(r1["ok"] == false and r1["reason"] == "LEVEL_TOO_LOW", "Level < 75 rejected")
# Level 75 but lacking keys
var empty_inv: Array = [null]
var r2 = dls.enter_lair(75, empty_inv)
_assert(r2["ok"] == false and r2["reason"] == "MISSING_KEYS", "Missing keys rejected")
# Level 75 with 3 keys across 2 stacks succeeds
var r3 = dls.enter_lair(75, inv)
_assert(r3["ok"] == true, "Entry succeeds with Lv 75 and 3 keys")
_assert(inv[0] == null and inv[1] == null, "3 keys across both slots consumed")
_assert(dls.is_active == true, "Dungeon is active")
_assert(dls.remaining_time == 3600.0, "60-minute countdown initialized")
_assert(dls.get_alive_metin_count() == 4, "4 Metin stones initialized")
_assert(dls.dragon_hp == 800000, "Dragon HP initialized to 800,000")
func _test_metin_buffs_and_debuffs() -> void:
print("\n--- Test 2: Metin Stone Buffs & Debuff Removal (8031, 8033, 8034) ---")
var dls := DragonLairSystem.new()
dls.enter_lair(80, [{"vnum": 30179, "count": 3}])
# 1. 8034 (复仇之石) ATK buff (+40%): 1800 * 1.4 = 2520
_assert(dls.get_dragon_atk() == 2520, "Dragon ATK has +40% buff (2520) while 8034 alive")
var metin_signal := {"fired": false, "vnum": 0, "name": ""}
dls.metin_destroyed.connect(func(v: int, n: String):
metin_signal["fired"] = true
metin_signal["vnum"] = v
metin_signal["name"] = n
)
var minion_signal := {"fired": false, "count": 0}
dls.minions_spawned.connect(func(cnt: int, _mob: int):
minion_signal["fired"] = true
minion_signal["count"] = cnt
)
# Destroy 8034
var des_res = dls.destroy_metin(8034)
_assert(des_res["ok"] == true, "8034 destroyed")
_assert(metin_signal["fired"] == true and metin_signal["vnum"] == 8034, "metin_destroyed signal fired")
_assert(minion_signal["fired"] == true and minion_signal["count"] == 4, "minions_spawned signal fired with 4 minions")
_assert(dls.get_dragon_atk() == 1800, "Dragon ATK dropped to base 1800 after 8034 destroyed")
# 2. 8031 (傲慢之石) Physical Resistance (-30% damage taken)
# Raw dmg: 1650. DEF: 650. Net: 1000. With 30% reduction: 700.
var phys_res = dls.apply_damage(1650, false)
_assert(phys_res["net_dmg"] == 700, "Physical damage reduced by 30% (700 net) while 8031 alive")
# Destroy 8031
dls.destroy_metin(8031)
var phys_res2 = dls.apply_damage(1650, false)
_assert(phys_res2["net_dmg"] == 1000, "Physical damage unreduced (1000 net) after 8031 destroyed")
# 3. 8033 (平静之石) Magic Resistance (-30% magic damage taken)
var mag_res = dls.apply_damage(1650, true)
_assert(mag_res["net_dmg"] == 700, "Magic damage reduced by 30% (700 net) while 8033 alive")
# Destroy 8033
dls.destroy_metin(8033)
var mag_res2 = dls.apply_damage(1650, true)
_assert(mag_res2["net_dmg"] == 1000, "Magic damage unreduced (1000 net) after 8033 destroyed")
func _test_metin_hp_regen() -> void:
print("\n--- Test 3: 8032 Metin HP Regeneration ---")
var dls := DragonLairSystem.new()
dls.enter_lair(80, [{"vnum": 30179, "count": 3}])
# Deal 50,000 net damage (damage boss from 800,000 to 750,000)
dls.destroy_metin(8031) # remove physical reduction for easy calculation
dls.apply_damage(50650, false) # 50650 - 650 DEF = 50000 net dmg
_assert(dls.dragon_hp == 750000, "Dragon HP reduced to 750,000")
# Advance 5.0 seconds -> 8032 heals 2% (16,000 HP) -> HP 766,000
dls.update(5.0)
_assert(dls.dragon_hp == 766000, "8032 regenerated 16,000 HP (+2%) at 5s tick")
# Destroy 8032 -> advance 5.0s -> no healing occurs
dls.destroy_metin(8032)
dls.update(5.0)
_assert(dls.dragon_hp == 766000, "No regen occurs after 8032 destroyed")
func _test_dragon_defeat_and_drops() -> void:
print("\n--- Test 4: Dragon Defeat & Epic Drop Generation ---")
var dls := DragonLairSystem.new()
dls.enter_lair(80, [{"vnum": 30179, "count": 3}])
var kill_signal := {"fired": false, "drops": []}
dls.dragon_defeated.connect(func(drops: Array):
kill_signal["fired"] = true
kill_signal["drops"] = drops
)
# Deal lethal damage
dls.destroy_metin(8031)
var res = dls.apply_damage(1000000, false)
_assert(res["ok"] == true and res["killed"] == true, "Beran-Setaou killed")
_assert(dls.is_dragon_alive == false, "is_dragon_alive is false")
_assert(dls.is_active == false, "Dungeon completed")
_assert(kill_signal["fired"] == true, "dragon_defeated signal fired")
var drops: Array = res["drops"]
var has_scale := false
var has_claw := false
var has_chest := false
var has_soul_stone := false
var has_gold := false
for d in drops:
if d["vnum"] == 71123: # Dragon Scale
has_scale = true
elif d["vnum"] == 71129: # Dragon Claw
has_claw = true
elif d["vnum"] == 50186: # Beran-Setaou Chest
has_chest = true
elif d["vnum"] == 50513: # Soul Stone
has_soul_stone = true
elif d["vnum"] == 1:
has_gold = true
_assert(has_scale, "Guaranteed Dragon Scale (71123) dropped")
_assert(has_claw, "Guaranteed Dragon Claw (71129) dropped")
_assert(has_chest, "Guaranteed Beran-Setaou Chest (50186) dropped")
_assert(has_soul_stone, "Guaranteed Soul Stone (50513) dropped")
_assert(has_gold, "Yang dropped")
func _test_dungeon_timeout() -> void:
print("\n--- Test 5: Dungeon Timeout Failure ---")
var dls := DragonLairSystem.new()
dls.enter_lair(80, [{"vnum": 30179, "count": 3}])
var fail_signal := {"fired": false, "reason": ""}
dls.dungeon_failed.connect(func(reason: String):
fail_signal["fired"] = true
fail_signal["reason"] = reason
)
dls.update(3601.0)
_assert(fail_signal["fired"] == true and fail_signal["reason"] == "TIME_OUT", "Timeout signal emitted")
_assert(dls.is_active == false, "Dungeon closed on timeout")
func _finish() -> void:
print("\n==========================================")
print("Dragon Lair Parity Test Results: %d Passed, %d Failed" % [_passed, _failed])
print("==========================================")
if _failed > 0:
quit(1)
else:
quit(0)