- 桥梁与静态物体高度采样修复: - 严格对齐 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 客户端对拍缺陷发现与修复工程指南
146 lines
5.5 KiB
GDScript
146 lines
5.5 KiB
GDScript
# test_compass_treasure_hunt_parity.gd —— 40250 魔石地脉探测罗盘与寻宝系统 1:1 回归测试套件
|
|
extends SceneTree
|
|
|
|
const CompassTreasureHuntSystem = preload("res://compass_treasure_hunt_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_compass_treasure_hunt_parity (Direction 4: Compass Treasure Hunt 1:1) ===")
|
|
_test_compass_scanning_and_charges()
|
|
_test_excavation_at_dowsing_node()
|
|
_test_key_opening()
|
|
_finish()
|
|
|
|
func _test_compass_scanning_and_charges() -> void:
|
|
print("\n--- Test 1: Compass Scanning & 6-Charge Depletion ---")
|
|
var sys := CompassTreasureHuntSystem.new()
|
|
var inv: Array = [
|
|
{"vnum": CompassTreasureHuntSystem.VNUM_COMPASS_OF_METIN, "name": "魔石探测罗盘", "charges": 6}
|
|
]
|
|
var player_pos := Vector2(0, 0)
|
|
var metins: Array = [
|
|
{"name": "战斗魔石", "pos": Vector2(300, 300)},
|
|
{"name": "嫉妒魔石", "pos": Vector2(10, 10)}, # dist ~14.14m (VERY_CLOSE)
|
|
{"name": "阴影魔石", "pos": Vector2(150, 20)}
|
|
]
|
|
|
|
var scan_sig := {"fired": false, "target": "", "dist": 0.0, "prox": "", "charges": 0}
|
|
sys.compass_scanned.connect(func(t: String, d: float, _a: float, p: String, c: int):
|
|
scan_sig["fired"] = true
|
|
scan_sig["target"] = t
|
|
scan_sig["dist"] = d
|
|
scan_sig["prox"] = p
|
|
scan_sig["charges"] = c
|
|
)
|
|
|
|
# Scan 1
|
|
var res1 = sys.scan_nearest_metin(player_pos, metins, inv, 0)
|
|
_assert(res1["ok"] == true, "Compass scan 1 succeeded")
|
|
_assert(res1["target_name"] == "嫉妒魔石", "Nearest metin is 嫉妒魔石")
|
|
_assert(res1["proximity"] == CompassTreasureHuntSystem.PROXIMITY_VERY_CLOSE, "Proximity is VERY_CLOSE (< 20m)")
|
|
_assert(res1["charges_left"] == 5, "Charges left is 5")
|
|
_assert(scan_sig["fired"] == true, "compass_scanned signal emitted")
|
|
|
|
# Deplete remaining 5 charges
|
|
for i in range(4):
|
|
sys.scan_nearest_metin(player_pos, metins, inv, 0)
|
|
|
|
_assert(inv[0]["charges"] == 1, "1 charge remaining before last use")
|
|
|
|
# 6th scan consumes the compass completely
|
|
var res6 = sys.scan_nearest_metin(player_pos, metins, inv, 0)
|
|
_assert(res6["ok"] == true, "6th scan succeeded")
|
|
_assert(res6["charges_left"] == 0, "0 charges left")
|
|
_assert(inv[0] == null, "Compass destroyed after 6 charges (slot 0 is null)")
|
|
|
|
func _test_excavation_at_dowsing_node() -> void:
|
|
print("\n--- Test 2: Treasure Excavation Nearby (< 5m) ---")
|
|
var sys := CompassTreasureHuntSystem.new()
|
|
var inv: Array = [null, null, null]
|
|
var nodes: Array = [
|
|
{"pos": Vector2(50, 50), "is_gold": true},
|
|
{"pos": Vector2(200, 200), "is_gold": false}
|
|
]
|
|
|
|
# 1. Player is far away at (0, 0)
|
|
var res_far = sys.excavate_treasure(Vector2(0, 0), nodes, inv)
|
|
_assert(res_far["ok"] == false, "Excavation rejected when > 5m")
|
|
_assert(res_far["reason"] == "NO_TREASURE_NEARBY", "Reason is NO_TREASURE_NEARBY")
|
|
|
|
var exc_sig := {"fired": false, "vnum": 0, "name": ""}
|
|
sys.treasure_excavated.connect(func(v: int, n: String):
|
|
exc_sig["fired"] = true
|
|
exc_sig["vnum"] = v
|
|
exc_sig["name"] = n
|
|
)
|
|
|
|
# 2. Player approaches to (51, 50) -> dist is 1m <= 5m
|
|
var res_succ = sys.excavate_treasure(Vector2(51, 50), nodes, inv)
|
|
_assert(res_succ["ok"] == true, "Excavation succeeded")
|
|
_assert(inv[0] != null and inv[0]["vnum"] == CompassTreasureHuntSystem.VNUM_GOLD_CHEST, "Golden Chest placed into slot 0")
|
|
_assert(exc_sig["fired"] == true, "treasure_excavated signal emitted")
|
|
_assert(nodes.size() == 1, "Excavated node removed from map")
|
|
|
|
func _test_key_opening() -> void:
|
|
print("\n--- Test 3: Golden/Silver Key Chest Opening ---")
|
|
var sys := CompassTreasureHuntSystem.new()
|
|
var inv: Array = [
|
|
{"vnum": CompassTreasureHuntSystem.VNUM_GOLD_CHEST, "name": "黄金宝箱"},
|
|
{"vnum": CompassTreasureHuntSystem.VNUM_SILVER_KEY, "name": "白银钥匙", "count": 1},
|
|
{"vnum": CompassTreasureHuntSystem.VNUM_GOLD_KEY, "name": "黄金钥匙", "count": 1},
|
|
null, null, null
|
|
]
|
|
|
|
# 1. Open Golden Chest with Silver Key -> mismatch
|
|
var res_mismatch = sys.open_treasure_chest(0, 1, inv)
|
|
_assert(res_mismatch["ok"] == false, "Key mismatch rejected")
|
|
_assert(res_mismatch["reason"] == "KEY_MISMATCH", "Reason is KEY_MISMATCH")
|
|
|
|
var open_sig := {"fired": false, "rewards": []}
|
|
sys.treasure_opened.connect(func(_n: String, rew: Array):
|
|
open_sig["fired"] = true
|
|
open_sig["rewards"] = rew
|
|
)
|
|
|
|
# 2. Open Golden Chest with Golden Key (slot 0 & slot 2)
|
|
var res_succ = sys.open_treasure_chest(0, 2, inv)
|
|
var chest_remains = false
|
|
var key_remains = false
|
|
for it in inv:
|
|
if it != null:
|
|
if int(it.get("vnum", 0)) == CompassTreasureHuntSystem.VNUM_GOLD_CHEST:
|
|
chest_remains = true
|
|
elif int(it.get("vnum", 0)) == CompassTreasureHuntSystem.VNUM_GOLD_KEY:
|
|
key_remains = true
|
|
_assert(not chest_remains, "Chest consumed")
|
|
_assert(not key_remains, "Key consumed")
|
|
_assert(open_sig["fired"] == true, "treasure_opened signal emitted")
|
|
_assert(open_sig["rewards"].size() == 3, "Received 3 rare rewards")
|
|
|
|
# Check blessing scroll in inventory
|
|
var scroll_found := false
|
|
for it in inv:
|
|
if it != null and int(it.get("vnum", 0)) == 25040:
|
|
scroll_found = true
|
|
break
|
|
_assert(scroll_found == true, "Blessing Scroll found in rewards")
|
|
|
|
func _finish() -> void:
|
|
print("\n=======================================================")
|
|
print("Compass & Treasure Hunt Parity Tests: %d Passed, %d Failed" % [_passed, _failed])
|
|
print("=======================================================\n")
|
|
if _failed > 0:
|
|
quit(1)
|
|
else:
|
|
quit(0)
|