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

150 lines
5.5 KiB
GDScript

# test_battle_arena_duel_parity.gd —— 40250 官方武斗竞技场与裁判规则 1:1 回归测试套件
extends SceneTree
const BattleArenaDuelSystem = preload("res://battle_arena_duel_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_battle_arena_duel_parity (Direction 2: Battle Arena Duel 1:1) ===")
_test_duel_start_and_countdown()
_test_rules_interception()
_test_best_of_three_match_progression()
_test_straight_sweep_victory()
_finish()
func _test_duel_start_and_countdown() -> void:
print("\n--- Test 1: Arena Duel Initialization & Countdown ---")
var sys := BattleArenaDuelSystem.new()
var duel_sig := {"fired": false, "opp": "", "sets": 0}
sys.duel_started.connect(func(opp: String, s: int, _t: float):
duel_sig["fired"] = true
duel_sig["opp"] = opp
duel_sig["sets"] = s
)
var start_res = sys.start_duel("warrior", 3, 300.0)
_assert(start_res["ok"] == true, "Duel started successfully")
_assert(start_res["sets_to_win"] == 2, "Sets to win is 2 (Best of 3)")
_assert(sys.match_state == BattleArenaDuelSystem.STATE_COUNTDOWN, "Match in countdown state")
_assert(duel_sig["fired"] == true, "duel_started signal fired")
_assert(duel_sig["opp"] == "战神武者教头", "Opponent name matches warrior master")
var round_sig := {"fired": false, "round": 0}
sys.round_started.connect(func(r: int):
round_sig["fired"] = true
round_sig["round"] = r
)
# Update countdown by 3.0s
sys.update(3.0)
_assert(sys.match_state == BattleArenaDuelSystem.STATE_FIGHTING, "Match entered FIGHTING state after countdown")
_assert(round_sig["fired"] == true, "round_started signal fired")
_assert(round_sig["round"] == 1, "First round started")
func _test_rules_interception() -> void:
print("\n--- Test 2: Potion, Mount, & Boundary Rules Interception ---")
var sys := BattleArenaDuelSystem.new()
sys.start_duel("assassin", 3, 300.0)
sys.update(3.0) # In fighting state
var violation_sig := {"fired": false, "reason": ""}
sys.rule_violation_intercepted.connect(func(r: String):
violation_sig["fired"] = true
violation_sig["reason"] = r
)
# 1. Potion test (Red Potion 27001)
var potion_allowed = sys.use_potion_check(27001)
_assert(potion_allowed == false, "Red potion prohibited in arena")
_assert(violation_sig["reason"] == "POTION_FORBIDDEN_IN_ARENA", "Reported potion violation")
# 2. Mount test
violation_sig["fired"] = false
var mount_allowed = sys.mount_check()
_assert(mount_allowed == false, "Mount prohibited in arena")
_assert(violation_sig["reason"] == "MOUNT_FORBIDDEN_IN_ARENA", "Reported mount violation")
# 3. Arena Bounds test (Legal point inside (100, 100))
var inside_ok = sys.check_boundary(Vector2(100.0, 100.0))
_assert(inside_ok == true, "Position (100, 100) within arena bounds")
# Out of bounds point (500, 500)
violation_sig["fired"] = false
var out_ok = sys.check_boundary(Vector2(500.0, 500.0))
_assert(out_ok == false, "Position (500, 500) outside arena bounds")
_assert(violation_sig["reason"] == "OUT_OF_ARENA_BOUNDS", "Reported boundary violation")
func _test_best_of_three_match_progression() -> void:
print("\n--- Test 3: Best-of-3 Match Progression (1-0 -> 1-1 -> 2-1) ---")
var sys := BattleArenaDuelSystem.new()
sys.start_duel("sura", 3, 300.0)
sys.update(3.0) # Round 1 fighting
var duel_fin_sig := {"fired": false, "winner": "", "reward": {}}
sys.duel_finished.connect(func(w: String, _sa: int, _sb: int, rew: Dictionary):
duel_fin_sig["fired"] = true
duel_fin_sig["winner"] = w
duel_fin_sig["reward"] = rew
)
# Round 1: Player beats Sura
var r1 = sys.record_defeat("B")
_assert(r1["match_finished"] == false, "Match not finished after Round 1")
_assert(r1["score_a"] == 1 and r1["score_b"] == 0, "Score is 1 - 0")
_assert(r1["current_round"] == 2, "Round 2 is next")
# Advance countdown for Round 2
sys.update(3.0)
# Round 2: Sura beats Player
var r2 = sys.record_defeat("A")
_assert(r2["match_finished"] == false, "Match not finished after Round 2")
_assert(r2["score_a"] == 1 and r2["score_b"] == 1, "Score is 1 - 1 tied")
_assert(r2["current_round"] == 3, "Round 3 is decider")
# Advance countdown for Round 3
sys.update(3.0)
# Round 3: Player beats Sura
var r3 = sys.record_defeat("B")
_assert(r3["match_finished"] == true, "Match finished after Round 3")
_assert(r3["winner"] == "A", "Grand winner is Player (Side A)")
_assert(duel_fin_sig["fired"] == true, "duel_finished signal fired")
_assert(duel_fin_sig["reward"]["arena_points"] == 200, "Received 200 arena points")
_assert(sys.match_state == BattleArenaDuelSystem.STATE_FINISHED, "State is FINISHED")
func _test_straight_sweep_victory() -> void:
print("\n--- Test 4: Straight Sweep (2-0) Clean Finish ---")
var sys := BattleArenaDuelSystem.new()
sys.start_duel("shaman", 3, 300.0)
sys.update(3.0)
# Round 1 win
sys.record_defeat("B")
sys.update(3.0)
# Round 2 win -> reaches 2 sets_to_win
var r2 = sys.record_defeat("B")
_assert(r2["match_finished"] == true, "Match ends immediately on 2-0 sweep")
_assert(r2["winner"] == "A", "Player won 2-0")
_assert(sys.score_a == 2 and sys.score_b == 0, "Final score is 2 - 0")
func _finish() -> void:
print("\n=======================================================")
print("Battle Arena Duel Parity Tests: %d Passed, %d Failed" % [_passed, _failed])
print("=======================================================\n")
if _failed > 0:
quit(1)
else:
quit(0)