- 桥梁与静态物体高度采样修复: - 严格对齐 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 客户端对拍缺陷发现与修复工程指南
101 lines
4.4 KiB
GDScript
101 lines
4.4 KiB
GDScript
# test_fishing_mining_parity.gd —— 验证方向 4:钓鱼、开蚌壳出珍珠与采矿生活系统 40250 1:1 对齐
|
|
extends SceneTree
|
|
|
|
const FishingMiningSystem = preload("res://fishing_mining_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_fishing_mining_parity (Direction 4: Fishing & Mining 1:1) ===")
|
|
test_fishing_equipment_detection()
|
|
test_fishing_flow_and_bait_consumption()
|
|
test_open_live_fish_drops()
|
|
test_open_clam_pearl_rates()
|
|
test_mining_veins_and_ores()
|
|
|
|
print("\n=== SUMMARY: %d passed, %d failed ===" % [_passed, _failed])
|
|
if _failed > 0:
|
|
printerr("TEST FAILED!")
|
|
quit(1)
|
|
else:
|
|
print("ALL TESTS PASSED!")
|
|
quit(0)
|
|
|
|
func test_fishing_equipment_detection() -> void:
|
|
print("\n--- Test 1: Fishing Equipment Identification ---")
|
|
_assert(FishingMiningSystem.is_fishing_rod(27400), "27400 is Fishing Rod +0")
|
|
_assert(FishingMiningSystem.is_fishing_rod(27490), "27490 is Fishing Rod +9")
|
|
_assert(not FishingMiningSystem.is_fishing_rod(10), "Sword is not a fishing rod")
|
|
|
|
_assert(FishingMiningSystem.is_bait(27800), "27800 (Earthworm) is valid bait")
|
|
_assert(FishingMiningSystem.is_bait(27801), "27801 (Fish Paste) is valid bait")
|
|
_assert(not FishingMiningSystem.is_bait(27001), "Potion is not bait")
|
|
|
|
func test_fishing_flow_and_bait_consumption() -> void:
|
|
print("\n--- Test 2: Fishing Flow & Bait Requirements (fishing.cpp:210) ---")
|
|
# 1. Fishing without bait is rejected
|
|
var res_no_bait := FishingMiningSystem.perform_fishing(false, 0)
|
|
_assert(not res_no_bait.ok and res_no_bait.code == "NO_BAIT", "Fishing without bait is rejected")
|
|
|
|
# 2. Fishing with bait and force success
|
|
var res_success := FishingMiningSystem.perform_fishing(true, 5, true)
|
|
_assert(res_success.ok and res_success.code == "SUCCESS", "Fishing succeeded with bait")
|
|
_assert(res_success.consumed_bait, "Bait consumed on fish attempt")
|
|
_assert(FishingMiningSystem.is_live_fish(res_success.fish_vnum), "Caught item is a live fish")
|
|
|
|
func test_open_live_fish_drops() -> void:
|
|
print("\n--- Test 3: Opening Live Fish (Fishbone, Dead Fish, Clam) ---")
|
|
# Live fish 27802 (Golden Carp)
|
|
var drops := {}
|
|
for _i in 100:
|
|
var res := FishingMiningSystem.open_live_fish(27802)
|
|
if res.ok:
|
|
drops[res.code] = true
|
|
|
|
_assert(drops.has("DEAD_FISH"), "Opening fish can yield dead fish")
|
|
_assert(drops.has("FISHBONE"), "Opening fish can yield Fishbone (27990)")
|
|
_assert(drops.has("CLAM"), "Opening fish can yield Clam (27987)")
|
|
|
|
func test_open_clam_pearl_rates() -> void:
|
|
print("\n--- Test 4: Opening Clam for Pearls (White, Blue, Blood Pearls) ---")
|
|
# Force opening White Pearl (27992)
|
|
var res_white := FishingMiningSystem.open_clam(FishingMiningSystem.VNUM_WHITE_PEARL)
|
|
_assert(res_white.ok and res_white.result_vnum == 27992, "Yields White Pearl (27992)")
|
|
|
|
# Force opening Blue Pearl (27993)
|
|
var res_blue := FishingMiningSystem.open_clam(FishingMiningSystem.VNUM_BLUE_PEARL)
|
|
_assert(res_blue.ok and res_blue.result_vnum == 27993, "Yields Blue Pearl (27993)")
|
|
|
|
# Force opening Blood Pearl (27994)
|
|
var res_blood := FishingMiningSystem.open_clam(FishingMiningSystem.VNUM_BLOOD_PEARL)
|
|
_assert(res_blood.ok and res_blood.result_vnum == 27994, "Yields Blood Pearl (27994)")
|
|
|
|
func test_mining_veins_and_ores() -> void:
|
|
print("\n--- Test 5: Mining Pickaxe, Veins & Rough Ore Yield (mining.cpp) ---")
|
|
_assert(FishingMiningSystem.is_pickaxe(29101), "29101 is Pickaxe +0")
|
|
_assert(FishingMiningSystem.is_pickaxe(29110), "29110 is Pickaxe +9")
|
|
_assert(not FishingMiningSystem.is_pickaxe(10), "Sword is not a pickaxe")
|
|
|
|
_assert(FishingMiningSystem.is_vein(20047), "20047 is Diamond Vein")
|
|
_assert(FishingMiningSystem.is_vein(20059), "20059 is Heaven's Tear Vein")
|
|
_assert(not FishingMiningSystem.is_vein(101), "Wild dog is not a vein")
|
|
|
|
# Mining Diamond Vein (20047 -> 50601)
|
|
var mine_res := FishingMiningSystem.perform_mining(20047, 5, true)
|
|
_assert(mine_res.ok and mine_res.code == "SUCCESS", "Mining succeeded")
|
|
_assert(mine_res.ore_vnum == 50601, "Yields Diamond Ore (50601)")
|
|
_assert(mine_res.count >= 1 and mine_res.count <= 3, "Yields 1..3 rough ores")
|
|
|
|
# Mining invalid target rejected
|
|
var mine_bad := FishingMiningSystem.perform_mining(99999, 0)
|
|
_assert(not mine_bad.ok and mine_bad.code == "NOT_A_VEIN", "Mining invalid target rejected")
|