- 桥梁与静态物体高度采样修复: - 严格对齐 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 客户端对拍缺陷发现与修复工程指南
98 lines
5.0 KiB
GDScript
98 lines
5.0 KiB
GDScript
# test_chest_keys_parity.gd —— 首领宝箱与钥匙系统 1:1 回归测试套件
|
|
# 运行方式:
|
|
# /opt/homebrew/bin/godot --headless --path metin2-client/project --script test_chest_keys_parity.gd
|
|
extends SceneTree
|
|
|
|
const ChestSystem = preload("res://chest_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_chest_keys_parity (Direction 4: Chests & Keys 1:1) ===")
|
|
_test_classification()
|
|
_test_key_matching()
|
|
_test_inventory_full_protection()
|
|
_test_direct_giftbox_opening()
|
|
_test_treasure_box_with_key()
|
|
_finish()
|
|
|
|
func _test_classification() -> void:
|
|
print("\n--- Test 1: Item Classification (GIFTBOX vs TREASURE_BOX vs KEY) ---")
|
|
_assert(ChestSystem.is_gift_box(ChestSystem.VNUM_MOONLIGHT_BOX), "Moonlight Box (50011) is Gift Box")
|
|
_assert(ChestSystem.is_gift_box(ChestSystem.VNUM_CHIEF_ORC_CHEST), "Chief Orc Chest (50070) is Gift Box")
|
|
_assert(not ChestSystem.is_gift_box(ChestSystem.VNUM_SILVER_BOX), "Silver Box is NOT a Gift Box")
|
|
|
|
_assert(ChestSystem.is_treasure_box(ChestSystem.VNUM_SILVER_BOX), "Silver Box is Treasure Box")
|
|
_assert(ChestSystem.is_treasure_box(ChestSystem.VNUM_GOLD_BOX), "Gold Box is Treasure Box")
|
|
_assert(not ChestSystem.is_treasure_box(ChestSystem.VNUM_MOONLIGHT_BOX), "Moonlight Box is NOT a Treasure Box")
|
|
|
|
_assert(ChestSystem.is_treasure_key(ChestSystem.VNUM_SILVER_KEY), "Silver Key (50002) is Treasure Key")
|
|
_assert(ChestSystem.is_treasure_key(ChestSystem.VNUM_GOLD_KEY), "Gold Key (50004) is Treasure Key")
|
|
|
|
func _test_key_matching() -> void:
|
|
print("\n--- Test 2: Key & Box Matching ---")
|
|
_assert(ChestSystem.is_matching_key(ChestSystem.VNUM_SILVER_KEY, ChestSystem.VNUM_SILVER_BOX), "Silver Key matches Silver Box")
|
|
_assert(not ChestSystem.is_matching_key(ChestSystem.VNUM_SILVER_KEY, ChestSystem.VNUM_GOLD_BOX), "Silver Key does NOT match Gold Box")
|
|
_assert(ChestSystem.is_matching_key(ChestSystem.VNUM_GOLD_KEY, ChestSystem.VNUM_GOLD_BOX), "Gold Key matches Gold Box")
|
|
_assert(not ChestSystem.is_matching_key(ChestSystem.VNUM_GOLD_KEY, ChestSystem.VNUM_SILVER_BOX), "Gold Key does NOT match Silver Box")
|
|
|
|
func _test_inventory_full_protection() -> void:
|
|
print("\n--- Test 3: Inventory Full Protection ---")
|
|
var r1 := ChestSystem.open_gift_box(ChestSystem.VNUM_MOONLIGHT_BOX, 0)
|
|
_assert(r1["success"] == false and r1["err"] == "inventory_full", "Giftbox opening blocked when inventory is full")
|
|
|
|
var r2 := ChestSystem.open_treasure_box_with_key(ChestSystem.VNUM_SILVER_KEY, ChestSystem.VNUM_SILVER_BOX, 0)
|
|
_assert(r2["success"] == false and r2["err"] == "inventory_full", "Treasure box opening blocked when inventory is full")
|
|
|
|
func _test_direct_giftbox_opening() -> void:
|
|
print("\n--- Test 4: Direct Giftbox Opening & Drop Rolling ---")
|
|
# Rejects non-giftbox
|
|
var r_err := ChestSystem.open_gift_box(ChestSystem.VNUM_SILVER_BOX, 5)
|
|
_assert(r_err["success"] == false and r_err["err"] == "not_gift_box", "Direct open fails on Silver Box (needs key)")
|
|
|
|
# Open Moonlight Box (roll 5 -> item 50300)
|
|
var r_moon := ChestSystem.open_gift_box(ChestSystem.VNUM_MOONLIGHT_BOX, 5, 5)
|
|
_assert(r_moon["success"] == true, "Moonlight box opened successfully")
|
|
_assert(r_moon["reward_name"] == "技能书", "Rolled Skill Book from Moonlight box")
|
|
|
|
# Open Chief Orc Chest (roll 58 -> trap)
|
|
var r_orc := ChestSystem.open_gift_box(ChestSystem.VNUM_CHIEF_ORC_CHEST, 5, 58)
|
|
_assert(r_orc["success"] == true, "Chief Orc chest opened")
|
|
_assert(r_orc["is_trap"] == true, "Triggered poison trap from Chief Orc chest")
|
|
|
|
func _test_treasure_box_with_key() -> void:
|
|
print("\n--- Test 5: Opening Treasure Box With Key (Drag & Drop) ---")
|
|
# Mismatched key
|
|
var r_mismatch := ChestSystem.open_treasure_box_with_key(ChestSystem.VNUM_GOLD_KEY, ChestSystem.VNUM_SILVER_BOX, 5)
|
|
_assert(r_mismatch["success"] == false and r_mismatch["err"] == "key_mismatch", "Rejects mismatched Gold Key on Silver Box")
|
|
|
|
# Matching Silver Key on Silver Box
|
|
var r_succ := ChestSystem.open_treasure_box_with_key(ChestSystem.VNUM_SILVER_KEY, ChestSystem.VNUM_SILVER_BOX, 5, 10)
|
|
_assert(r_succ["success"] == true, "Successfully unlocked Silver Box with Silver Key")
|
|
_assert(r_succ["consumed_key_vnum"] == ChestSystem.VNUM_SILVER_KEY, "Consumed Silver Key")
|
|
_assert(r_succ["consumed_box_vnum"] == ChestSystem.VNUM_SILVER_BOX, "Consumed Silver Box")
|
|
_assert(r_succ["reward_name"] == "祝福卷轴", "Obtained Blessing Scroll from Silver Box")
|
|
|
|
# Matching Gold Key on Gold Box
|
|
var r_gold := ChestSystem.open_treasure_box_with_key(ChestSystem.VNUM_GOLD_KEY, ChestSystem.VNUM_GOLD_BOX, 5, 30)
|
|
_assert(r_gold["success"] == true, "Successfully unlocked Gold Box with Gold Key")
|
|
_assert(r_gold["reward_name"] == "魂石", "Obtained Soul Stone from Gold Box")
|
|
|
|
func _finish() -> void:
|
|
print("\n=== SUMMARY: %d passed, %d failed ===" % [_passed, _failed])
|
|
if _failed == 0:
|
|
print("ALL TESTS PASSED!\n")
|
|
quit(0)
|
|
else:
|
|
printerr("SOME TESTS FAILED!\n")
|
|
quit(1)
|