- 桥梁与静态物体高度采样修复: - 严格对齐 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 客户端对拍缺陷发现与修复工程指南
138 lines
4.9 KiB
GDScript
138 lines
4.9 KiB
GDScript
# test_guild_war_parity.gd —— 40250 官方公会战备宣战与积分决斗 1:1 回归测试套件
|
|
extends SceneTree
|
|
|
|
const GuildWarSystem = preload("res://guild_war_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_guild_war_parity (Direction 3: Guild War 1:1) ===")
|
|
_test_war_declaration_and_start()
|
|
_test_score_tracking_and_target_win()
|
|
_test_war_timeout_resolution()
|
|
_test_serialization()
|
|
_finish()
|
|
|
|
func _test_war_declaration_and_start() -> void:
|
|
print("\n--- Test 1: War Declaration & State Machine ---")
|
|
var sys := GuildWarSystem.new()
|
|
_assert(sys.war_state == GuildWarSystem.STATE_NONE, "Initially not at war")
|
|
|
|
var dec_sig := {"fired": false, "opp": "", "score": 0}
|
|
sys.war_declared.connect(func(opp: String, _wt: int, s: int):
|
|
dec_sig["fired"] = true
|
|
dec_sig["opp"] = opp
|
|
dec_sig["score"] = s
|
|
)
|
|
|
|
# 1. Declare war against Shadow Assassins (101)
|
|
var dec_res = sys.declare_war(101, GuildWarSystem.WAR_TYPE_ARENA, 50, 1800.0)
|
|
_assert(dec_res["ok"] == true, "War declared")
|
|
_assert(sys.war_state == GuildWarSystem.STATE_DECLARED, "State is STATE_DECLARED")
|
|
_assert(dec_sig["fired"] == true, "war_declared signal emitted")
|
|
_assert(dec_sig["opp"] == "暗影刺客团", "Opponent is 暗影刺客团")
|
|
|
|
# Cannot declare war while already declared
|
|
var dec_again = sys.declare_war(102)
|
|
_assert(dec_again["ok"] == true, "Replaced declaration before start")
|
|
|
|
var start_sig := {"fired": false, "dur": 0.0}
|
|
sys.war_started.connect(func(_wt: int, d: float):
|
|
start_sig["fired"] = true
|
|
start_sig["dur"] = d
|
|
)
|
|
|
|
# 2. Start war
|
|
var start_res = sys.start_war()
|
|
_assert(start_res["ok"] == true, "War started")
|
|
_assert(sys.war_state == GuildWarSystem.STATE_FIGHTING, "State is STATE_FIGHTING")
|
|
_assert(start_sig["fired"] == true, "war_started signal emitted")
|
|
|
|
func _test_score_tracking_and_target_win() -> void:
|
|
print("\n--- Test 2: Score Tracking & Target Score (50 Points) Victory ---")
|
|
var sys := GuildWarSystem.new()
|
|
sys.declare_war(102, GuildWarSystem.WAR_TYPE_ARENA, 50, 1800.0)
|
|
sys.start_war()
|
|
|
|
var score_sig := {"fired": false, "sa": 0, "sb": 0}
|
|
sys.score_updated.connect(func(sa: int, sb: int):
|
|
score_sig["fired"] = true
|
|
score_sig["sa"] = sa
|
|
score_sig["sb"] = sb
|
|
)
|
|
|
|
var end_sig := {"fired": false, "winner": "", "reward": {}}
|
|
sys.war_ended.connect(func(w: String, _sa: int, _sb: int, rew: Dictionary):
|
|
end_sig["fired"] = true
|
|
end_sig["winner"] = w
|
|
end_sig["reward"] = rew
|
|
)
|
|
|
|
# Score increments
|
|
sys.record_score("A", 10)
|
|
sys.record_score("B", 5)
|
|
_assert(sys.score_a == 10 and sys.score_b == 5, "Score is 10 - 5")
|
|
_assert(score_sig["fired"] == true, "score_updated signal emitted")
|
|
|
|
# Side A scores 40 more to hit 50 points (target score)
|
|
var win_res = sys.record_score("A", 40)
|
|
_assert(win_res["winner"] == "A", "Side A declared winner")
|
|
_assert(sys.war_state == GuildWarSystem.STATE_FINISHED, "State is STATE_FINISHED")
|
|
_assert(sys.player_guild_ladder == 1030, "Ladder points +30 (1000 -> 1030)")
|
|
_assert(sys.total_wars_won == 1, "Total wars won is 1")
|
|
_assert(end_sig["fired"] == true, "war_ended signal emitted")
|
|
_assert(end_sig["reward"]["guild_gold"] == 1000000, "Received 1,000,000 guild gold")
|
|
|
|
func _test_war_timeout_resolution() -> void:
|
|
print("\n--- Test 3: War Timeout & Decisive Score Ruling ---")
|
|
var sys := GuildWarSystem.new()
|
|
sys.declare_war(103, GuildWarSystem.WAR_TYPE_FIELD, 100, 1800.0)
|
|
sys.start_war()
|
|
|
|
sys.record_score("A", 25)
|
|
sys.record_score("B", 18)
|
|
|
|
# Advance 1800s to timeout
|
|
sys.update(1800.0)
|
|
_assert(sys.war_state == GuildWarSystem.STATE_FINISHED, "War finished on timeout")
|
|
_assert(sys.score_a == 25 and sys.score_b == 18, "Final score is 25 - 18")
|
|
_assert(sys.player_guild_ladder == 1030, "Player won on higher score (+30 ladder)")
|
|
|
|
func _test_serialization() -> void:
|
|
print("\n--- Test 4: Serialization & Restoration ---")
|
|
var sys1 := GuildWarSystem.new()
|
|
sys1.player_guild_ladder = 1450
|
|
sys1.total_wars_won = 15
|
|
sys1.declare_war(101, GuildWarSystem.WAR_TYPE_FLAG, 50, 1500.0)
|
|
sys1.start_war()
|
|
sys1.record_score("A", 30)
|
|
sys1.record_score("B", 20)
|
|
|
|
var data = sys1.serialize()
|
|
var sys2 := GuildWarSystem.new()
|
|
sys2.deserialize(data)
|
|
|
|
_assert(sys2.war_state == GuildWarSystem.STATE_FIGHTING, "Restored state FIGHTING")
|
|
_assert(sys2.active_war_type == GuildWarSystem.WAR_TYPE_FLAG, "Restored war type FLAG")
|
|
_assert(sys2.score_a == 30 and sys2.score_b == 20, "Restored scores")
|
|
_assert(sys2.player_guild_ladder == 1450, "Restored ladder rating 1450")
|
|
_assert(sys2.total_wars_won == 15, "Restored total wars won 15")
|
|
|
|
func _finish() -> void:
|
|
print("\n=======================================================")
|
|
print("Guild War System Parity Tests: %d Passed, %d Failed" % [_passed, _failed])
|
|
print("=======================================================\n")
|
|
if _failed > 0:
|
|
quit(1)
|
|
else:
|
|
quit(0)
|