- 桥梁与静态物体高度采样修复: - 严格对齐 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 客户端对拍缺陷发现与修复工程指南
150 lines
5.5 KiB
GDScript
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)
|