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

113 lines
4.8 KiB
GDScript

# test_guild_war_observer_arena_parity.gd —— Metin2 40250 公会战备观战与武斗擂台传送 1:1 测试套件
extends SceneTree
const GuildWarObserverArenaSystem = preload("res://guild_war_observer_arena_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_observer_arena_parity (Direction 4: Guild War Observer 1:1) ===")
test_active_wars_and_display()
test_observer_entry_and_ghost_mode()
test_manual_leave_observer_mode()
test_war_ending_auto_evacuation()
test_serialization()
print("\n=======================================================")
print("Guild War Observer Tests: %d Passed, %d Failed" % [_passed, _failed])
print("=======================================================\n")
if _failed > 0:
quit(1)
else:
quit(0)
func test_active_wars_and_display() -> void:
print("\n--- Test 1: Active Wars Registration & Town Guard List (40250 1:1) ---")
var system = GuildWarObserverArenaSystem.new()
var wid = system.register_active_war(101, "王者之师", 202, "龙城铁骑", 1, 50)
_assert(wid > 0, "Registered active war")
var list = system.get_active_wars_for_display()
_assert(list.size() == 1, "Listed 1 active war for guard display")
_assert(list[0]["guild1_name"] == "王者之师", "Guild 1 name correct")
_assert(list[0]["guild2_name"] == "龙城铁骑", "Guild 2 name correct")
_assert(list[0]["map_index"] == GuildWarObserverArenaSystem.MAP_GUILD_ARENA, "Map index is 110 (Arena)")
func test_observer_entry_and_ghost_mode() -> void:
print("\n--- Test 2: Observer Entry & Ghost Mode (40250 1:1) ---")
var system = GuildWarObserverArenaSystem.new()
var wid = system.register_active_war(101, "王者之师", 202, "龙城铁骑", 1, 50)
var orig_pos = Vector2(800.0, 900.0)
var res = system.enter_as_observer(999, wid, "主城辛秀", orig_pos)
_assert(res["ok"] == true, "Entered observer mode")
_assert(res["observer_pos"] == GuildWarObserverArenaSystem.OBSERVER_PLATFORM_POS, "Warps to high platform")
_assert(system.is_player_observing(999) == true, "Player 999 is in observer state")
# 幽灵模式免疫战斗与禁止出招
_assert(system.can_player_attack_or_be_attacked(999) == false, "Player cannot attack or be attacked in observer mode")
func test_manual_leave_observer_mode() -> void:
print("\n--- Test 3: Manual Leave Observer Mode (40250 1:1) ---")
var system = GuildWarObserverArenaSystem.new()
var wid = system.register_active_war(101, "王者之师", 202, "龙城铁骑", 1, 50)
var orig_pos = Vector2(1200.0, 1500.0)
system.enter_as_observer(999, wid, "主城辛秀", orig_pos)
# 主动离开
var leave_res = system.leave_observer_mode(999)
_assert(leave_res["ok"] == true, "Left observer mode")
_assert(leave_res["return_map"] == "主城辛秀", "Returned to previous map")
_assert(leave_res["return_pos"] == orig_pos, "Returned to previous coordinates")
_assert(system.is_player_observing(999) == false, "No longer observer")
_assert(system.can_player_attack_or_be_attacked(999) == true, "Combat privileges restored")
func test_war_ending_auto_evacuation() -> void:
print("\n--- Test 4: War Ending Auto Evacuation (40250 1:1) ---")
var system = GuildWarObserverArenaSystem.new()
var wid = system.register_active_war(101, "王者之师", 202, "龙城铁骑", 1, 50)
var left_signals := []
system.observer_left.connect(func(pid, map, pos):
left_signals.append({"pid": pid, "map": map, "pos": pos})
)
# 2 位观战者入场
system.enter_as_observer(801, wid, "主城辛秀", Vector2(100.0, 100.0))
system.enter_as_observer(802, wid, "主城镇奴", Vector2(200.0, 200.0))
# 公会 1 战胜达成 50 分,终局自动结算
system.update_war_score(wid, 50, 30)
# 检查全部观战者被安全自动遣散
_assert(left_signals.size() == 2, "Both observers evacuated")
_assert(system.is_player_observing(801) == false, "Observer 801 cleared")
_assert(system.is_player_observing(802) == false, "Observer 802 cleared")
_assert(system.get_active_wars_for_display().is_empty(), "War is marked ended and cleared from active list")
func test_serialization() -> void:
print("\n--- Test 5: Serialization & Restoration ---")
var system = GuildWarObserverArenaSystem.new()
var wid = system.register_active_war(101, "公会A", 202, "公会B")
system.enter_as_observer(555, wid, "主城", Vector2(300.0, 400.0))
var data = system.serialize()
_assert(data.has("observers") and data["observers"].has(555), "Serialized observer state")
var restored = GuildWarObserverArenaSystem.new()
restored.deserialize(data)
_assert(restored.is_player_observing(555) == true, "Restored observer state")
_assert(restored.can_player_attack_or_be_attacked(555) == false, "Restored combat immunity")