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

201 lines
8.0 KiB
GDScript

# test_boss_summon_scroll_parity.gd —— Metin2 40250 首领与魔石召唤卷轴系统 1:1 校验套件
extends SceneTree
const BossSummonScrollSystem = preload("res://boss_summon_scroll_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
print(" [FAIL] %s" % msg)
func _init() -> void:
print("\n=== Running test_boss_summon_scroll_parity (Direction 4: Boss & Metin Summon Scrolls 1:1) ===")
test_boss_scrolls_spawning()
test_metin_scrolls_spawning()
test_ore_vein_scrolls_spawning()
test_safe_zone_restriction()
test_serialization_and_management()
print("\n=======================================================")
print("Boss & Metin Summon Scroll Tests: %d Passed, %d Failed" % [_passed, _failed])
print("=======================================================\n")
if _failed > 0:
quit(1)
else:
quit(0)
func test_boss_scrolls_spawning() -> void:
print("\n--- Test 1: Boss Summon Scrolls (40250 1:1) ---")
var system = BossSummonScrollSystem.new()
var boss_emitted := []
system.boss_summoned.connect(func(vnum, name, pos, aggressive):
boss_emitted.append({"vnum": vnum, "name": name, "pos": pos, "aggressive": aggressive})
)
# 背包中有 8 种 Boss 召唤卷
var inv: Array = [
{"vnum": 71036, "count": 2}, # 兽人首领
{"vnum": 71037, "count": 1}, # 密教首领
{"vnum": 71038, "count": 1}, # 蜘蛛女王
{"vnum": 71039, "count": 1}, # 沙漠巨龟
{"vnum": 71040, "count": 1}, # 烈焰魔王
{"vnum": 71041, "count": 1}, # 九尾狐
{"vnum": 71042, "count": 1}, # 恶魔之王
{"vnum": 71043, "count": 1} # 黄虎幽灵
]
var center = Vector2(1000.0, 2000.0)
# 测试 71036 堆叠为 2,消耗后余 1
var res = system.use_summon_scroll(inv, 0, center, false)
_assert(res["ok"] == true, "Summon Orc Chief succeeded")
_assert(inv[0] != null and inv[0]["count"] == 1, "Count decremented from 2 to 1")
_assert(res["entity"]["vnum"] == 691, "Spawned mob vnum is 691 (Orc Chief)")
_assert(res["entity"]["is_aggressive"] == true, "Boss is aggressive")
_assert(res["entity"]["level"] == 50, "Orc Chief level is 50")
_assert(boss_emitted.size() == 1, "boss_summoned signal emitted")
_assert(boss_emitted[0]["vnum"] == 691, "Signal reports mob vnum 691")
# 测试 71040 烈焰魔王 (2206, Lv 73)
res = system.use_summon_scroll(inv, 4, center, false)
_assert(res["ok"] == true, "Summon Flame King succeeded")
_assert(inv[4] == null, "Single count scroll consumed to null")
_assert(res["entity"]["vnum"] == 2206, "Spawned Flame King vnum 2206")
_assert(res["entity"]["level"] == 73, "Flame King level 73")
# 测试 71041 九尾狐 (1901, Lv 72)
res = system.use_summon_scroll(inv, 5, center, false)
_assert(res["ok"] == true, "Summon Nine Tails succeeded")
_assert(res["entity"]["vnum"] == 1901, "Spawned Nine Tails vnum 1901")
func test_metin_scrolls_spawning() -> void:
print("\n--- Test 2: Metin Stone Summon Scrolls (40250 1:1) ---")
var system = BossSummonScrollSystem.new()
var metin_emitted := []
system.metin_summoned.connect(func(vnum, name, pos, level):
metin_emitted.append({"vnum": vnum, "name": name, "pos": pos, "level": level})
)
var inv: Array = [
{"vnum": 71080, "count": 1}, # 初级魔石
{"vnum": 71081, "count": 1}, # 中级魔石
{"vnum": 71082, "count": 1} # 高级魔石
]
var center = Vector2(500.0, 500.0)
# 71080 初级魔石 (强制选取第4个 8004 贪婪之石 Lv 20)
var res = system.use_summon_scroll(inv, 0, center, false, 3)
_assert(res["ok"] == true, "Low Metin summon succeeded")
_assert(res["entity"]["vnum"] == 8004, "Metin of Greed spawned (vnum 8004)")
_assert(res["entity"]["level"] == 20, "Level is 20")
_assert(res["entity"]["rank"] == 5, "Rank is 5 (STONE)")
_assert(res["entity"]["is_aggressive"] == false, "Metin is stationary/non-aggressive")
# 71081 中级魔石 (强制选取第3个 8008 灵魂之石 Lv 40)
res = system.use_summon_scroll(inv, 1, center, false, 2)
_assert(res["ok"] == true, "Medium Metin summon succeeded")
_assert(res["entity"]["vnum"] == 8008, "Metin of Soul spawned (vnum 8008)")
_assert(res["entity"]["level"] == 40, "Level is 40")
# 71082 高级魔石 (强制选取第7个 8027 绝望之石 Lv 90)
res = system.use_summon_scroll(inv, 2, center, false, 7)
_assert(res["ok"] == true, "High Metin summon succeeded")
_assert(res["entity"]["vnum"] == 8027, "Metin of Jeon-Un spawned (vnum 8027)")
_assert(res["entity"]["level"] == 90, "Level is 90")
_assert(metin_emitted.size() == 3, "All 3 metin_summoned signals fired")
func test_ore_vein_scrolls_spawning() -> void:
print("\n--- Test 3: Ore Vein Summon Scrolls (40250 1:1) ---")
var system = BossSummonScrollSystem.new()
var vein_emitted := []
system.ore_vein_summoned.connect(func(vnum, name, pos):
vein_emitted.append({"vnum": vnum, "name": name, "pos": pos})
)
var inv: Array = [
{"vnum": 71057, "count": 1}, # 钻石矿脉 (20049)
{"vnum": 71064, "count": 1} # 黑檀木矿脉 (20056)
]
var center = Vector2(300.0, 300.0)
var res = system.use_summon_scroll(inv, 0, center, false)
_assert(res["ok"] == true, "Diamond vein summon succeeded")
_assert(res["entity"]["vnum"] == 20049, "Vein vnum 20049")
_assert(vein_emitted.size() == 1, "ore_vein_summoned emitted")
res = system.use_summon_scroll(inv, 1, center, false)
_assert(res["ok"] == true, "Ebony vein summon succeeded")
_assert(res["entity"]["vnum"] == 20056, "Vein vnum 20056")
func test_safe_zone_restriction() -> void:
print("\n--- Test 4: Safe Zone Summon Restrictions (40250 1:1) ---")
var system = BossSummonScrollSystem.new()
var inv: Array = [
{"vnum": 71036, "count": 1}, # 兽人首领
{"vnum": 71081, "count": 1}, # 中级魔石
{"vnum": 71060, "count": 1} # 铜矿脉
]
# 在安全区内尝试召唤首领
var res = system.use_summon_scroll(inv, 0, Vector2.ZERO, true)
_assert(res["ok"] == false, "Boss summon rejected in safe zone")
_assert(res["reason"] == "CANNOT_SPAWN_IN_SAFEZONE", "Reason is CANNOT_SPAWN_IN_SAFEZONE")
_assert(inv[0]["count"] == 1, "Item not consumed on rejection")
# 在安全区内尝试召唤魔石
res = system.use_summon_scroll(inv, 1, Vector2.ZERO, true)
_assert(res["ok"] == false, "Metin summon rejected in safe zone")
_assert(inv[1]["count"] == 1, "Metin scroll not consumed")
# 在安全区召唤矿脉是允许的 (矿脉无攻击性)
res = system.use_summon_scroll(inv, 2, Vector2.ZERO, true)
_assert(res["ok"] == true, "Ore vein allowed in safe zone")
_assert(inv[2] == null, "Ore vein scroll consumed")
func test_serialization_and_management() -> void:
print("\n--- Test 5: Registry Management & Serialization ---")
var system = BossSummonScrollSystem.new()
var inv: Array = [
{"vnum": 71038, "count": 1}, # 蜘蛛女王
{"vnum": 71082, "count": 1} # 高级魔石
]
system.use_summon_scroll(inv, 0, Vector2(100.0, 100.0), false)
system.use_summon_scroll(inv, 1, Vector2(200.0, 200.0), false, 0)
var list = system.get_active_summoned_entities()
_assert(list.size() == 2, "Active entities count is 2")
_assert(list[0]["vnum"] == 2091, "First entity is Spider Queen (2091)")
_assert(list[1]["vnum"] == 8011, "Second entity is Metin of Devil (8011)")
# 序列化
var data = system.serialize()
_assert(data.has("active_entities") and data["active_entities"].size() == 2, "Serialized 2 entities")
# 新系统反序列化
var restored_system = BossSummonScrollSystem.new()
restored_system.deserialize(data)
var restored_list = restored_system.get_active_summoned_entities()
_assert(restored_list.size() == 2, "Restored 2 entities")
_assert(restored_list[0]["vnum"] == 2091, "Restored Spider Queen vnum")
_assert(restored_list[1]["level"] == 55, "Restored Metin level 55")
# 移除与清空
var removed = system.remove_summoned_entity(0)
_assert(removed == true, "Removed first entity")
_assert(system.get_active_summoned_entities().size() == 1, "1 entity remaining")
system.clear_summoned_entities()
_assert(system.get_active_summoned_entities().is_empty(), "All entities cleared")