- 桥梁与静态物体高度采样修复: - 严格对齐 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 客户端对拍缺陷发现与修复工程指南
170 lines
5.9 KiB
GDScript
170 lines
5.9 KiB
GDScript
# test_flame_dungeon_razador_parity.gd —— 40250 红龙烈焰神殿与拉扎多尔试炼 1:1 回归测试套件
|
|
extends SceneTree
|
|
|
|
const FlameDungeonRazadorSystem = preload("res://flame_dungeon_razador_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_flame_dungeon_razador_parity (Direction 2: Flame Dungeon Razador 1:1) ===")
|
|
_test_entry_and_ticket_consumption()
|
|
_test_stage_advancement_and_altars()
|
|
_test_razador_boss_slay_and_rewards()
|
|
_test_timeout_failure()
|
|
_test_serialization()
|
|
_finish()
|
|
|
|
func _test_entry_and_ticket_consumption() -> void:
|
|
print("\n--- Test 1: Flame Dungeon Entry & Ticket Consumption ---")
|
|
var sys := FlameDungeonRazadorSystem.new()
|
|
var inv: Array = [
|
|
{"vnum": FlameDungeonRazadorSystem.VNUM_TICKET_71095, "name": "通行证", "count": 2}
|
|
]
|
|
|
|
# 1. Level too low (< 100)
|
|
var res_low = sys.enter_dungeon(95, inv)
|
|
_assert(res_low["ok"] == false, "Entry rejected: level 95 < 100")
|
|
_assert(res_low["reason"] == "LEVEL_TOO_LOW", "Reason is LEVEL_TOO_LOW")
|
|
|
|
var enter_sig := {"fired": false, "dur": 0.0}
|
|
sys.dungeon_entered.connect(func(d: float):
|
|
enter_sig["fired"] = true
|
|
enter_sig["dur"] = d
|
|
)
|
|
|
|
# 2. Valid entry at Lv 100
|
|
var res_succ = sys.enter_dungeon(100, inv)
|
|
_assert(res_succ["ok"] == true, "Entered Flame Dungeon successfully")
|
|
_assert(sys.is_active == true, "Dungeon is active")
|
|
_assert(sys.current_stage == 1, "Initial stage is 1")
|
|
_assert(inv[0]["count"] == 1, "Ticket count decremented 2 -> 1")
|
|
_assert(enter_sig["fired"] == true, "dungeon_entered signal emitted")
|
|
_assert(enter_sig["dur"] == 2700.0, "Time limit is 2700.0s (45 minutes)")
|
|
|
|
func _test_stage_advancement_and_altars() -> void:
|
|
print("\n--- Test 2: Stage Advancement & Altar Lighting ---")
|
|
var sys := FlameDungeonRazadorSystem.new()
|
|
var inv: Array = [{"vnum": FlameDungeonRazadorSystem.VNUM_TICKET_71130, "name": "烈焰通行证", "count": 1}]
|
|
sys.enter_dungeon(105, inv)
|
|
|
|
# Advance stages 1 -> 2 -> 3 -> 4 -> 5
|
|
for i in range(4):
|
|
sys.advance_stage()
|
|
|
|
_assert(sys.current_stage == 5, "Reached Stage 5 (Fire Altars)")
|
|
|
|
var altar_sig := {"fired": false, "lit": 0}
|
|
sys.altar_lit.connect(func(l: int, _t: int):
|
|
altar_sig["fired"] = true
|
|
altar_sig["lit"] = l
|
|
)
|
|
|
|
# Light 4 altars
|
|
for i in range(4):
|
|
var res_altar = sys.light_fire_altar()
|
|
_assert(res_altar["stage_cleared"] == false, "Stage not yet cleared with < 5 altars")
|
|
|
|
_assert(sys.altars_lit_count == 4, "4 altars lit")
|
|
|
|
# Light 5th altar -> auto clears stage 5 and enters stage 6
|
|
var res_5th = sys.light_fire_altar()
|
|
_assert(res_5th["stage_cleared"] == true, "5th altar lit: stage cleared")
|
|
_assert(sys.current_stage == 6, "Automatically advanced to Stage 6")
|
|
|
|
var boss_sig := {"fired": false, "vnum": 0}
|
|
sys.razador_spawned.connect(func(v: int):
|
|
boss_sig["fired"] = true
|
|
boss_sig["vnum"] = v
|
|
)
|
|
|
|
# Advance stage 6 -> 7 (Boss Chamber)
|
|
var res_boss_room = sys.advance_stage()
|
|
_assert(res_boss_room["current_stage"] == 7, "Entered Stage 7 (Razador)")
|
|
_assert(sys.razador_alive == true, "Razador is alive")
|
|
_assert(boss_sig["fired"] == true, "razador_spawned signal emitted")
|
|
_assert(boss_sig["vnum"] == 6091, "Razador mob vnum is 6091")
|
|
|
|
func _test_razador_boss_slay_and_rewards() -> void:
|
|
print("\n--- Test 3: Razador Boss Slay & Rewards ---")
|
|
var sys := FlameDungeonRazadorSystem.new()
|
|
var inv: Array = [
|
|
{"vnum": FlameDungeonRazadorSystem.VNUM_TICKET_71095, "name": "通行证", "count": 1},
|
|
null, null, null
|
|
]
|
|
sys.enter_dungeon(105, inv)
|
|
sys.current_stage = 7
|
|
sys.razador_alive = true
|
|
|
|
var comp_sig := {"fired": false}
|
|
sys.dungeon_completed.connect(func():
|
|
comp_sig["fired"] = true
|
|
)
|
|
|
|
# Slay Razador
|
|
var res_slay = sys.slay_razador(inv)
|
|
_assert(res_slay["ok"] == true, "Razador slain")
|
|
_assert(sys.is_active == false, "Dungeon completed and inactive")
|
|
_assert(comp_sig["fired"] == true, "dungeon_completed signal emitted")
|
|
|
|
# Verify Razador's Chest received
|
|
var chest_found := false
|
|
for it in inv:
|
|
if it != null and int(it.get("vnum", 0)) == FlameDungeonRazadorSystem.VNUM_RAZADOR_CHEST:
|
|
chest_found = true
|
|
break
|
|
_assert(chest_found == true, "Razador's Chest (50186) found in inventory")
|
|
|
|
func _test_timeout_failure() -> void:
|
|
print("\n--- Test 4: Dungeon Timeout Failure ---")
|
|
var sys := FlameDungeonRazadorSystem.new()
|
|
var inv: Array = [{"vnum": FlameDungeonRazadorSystem.VNUM_TICKET_71095, "name": "通行证", "count": 1}]
|
|
sys.enter_dungeon(100, inv)
|
|
|
|
var fail_sig := {"fired": false, "reason": ""}
|
|
sys.dungeon_failed.connect(func(r: String):
|
|
fail_sig["fired"] = true
|
|
fail_sig["reason"] = r
|
|
)
|
|
|
|
# Advance 2700s
|
|
sys.update(2700.0)
|
|
_assert(sys.is_active == false, "Dungeon inactive on timeout")
|
|
_assert(fail_sig["fired"] == true, "dungeon_failed signal emitted")
|
|
_assert(fail_sig["reason"] == "TIMEOUT", "Reported TIMEOUT")
|
|
|
|
func _test_serialization() -> void:
|
|
print("\n--- Test 5: Serialization & Restoration ---")
|
|
var sys1 := FlameDungeonRazadorSystem.new()
|
|
var inv: Array = [{"vnum": FlameDungeonRazadorSystem.VNUM_TICKET_71095, "name": "通行证", "count": 1}]
|
|
sys1.enter_dungeon(100, inv)
|
|
sys1.current_stage = 5
|
|
sys1.altars_lit_count = 3
|
|
sys1.update(600.0) # 2100s left
|
|
|
|
var data = sys1.serialize()
|
|
var sys2 := FlameDungeonRazadorSystem.new()
|
|
sys2.deserialize(data)
|
|
|
|
_assert(sys2.is_active == true, "Restored is_active")
|
|
_assert(sys2.current_stage == 5, "Restored current stage 5")
|
|
_assert(sys2.altars_lit_count == 3, "Restored altars lit count 3")
|
|
_assert(is_equal_approx(sys2.time_remaining, 2100.0), "Restored time remaining 2100s")
|
|
|
|
func _finish() -> void:
|
|
print("\n=======================================================")
|
|
print("Flame Dungeon Razador Parity Tests: %d Passed, %d Failed" % [_passed, _failed])
|
|
print("=======================================================\n")
|
|
if _failed > 0:
|
|
quit(1)
|
|
else:
|
|
quit(0)
|