- 桥梁与静态物体高度采样修复: - 严格对齐 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 客户端对拍缺陷发现与修复工程指南
163 lines
5.5 KiB
GDScript
163 lines
5.5 KiB
GDScript
# test_fishing_cooking_camp_parity.gd —— 40250 野外钓鱼烹饪与露营增益 1:1 回归测试套件
|
|
extends SceneTree
|
|
|
|
const FishingCookingCampSystem = preload("res://fishing_cooking_camp_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_cooking_camp_parity (Direction 2: Fishing Cooking Camp 1:1) ===")
|
|
_test_campfire_lighting()
|
|
_test_cooking_fish_recipes()
|
|
_test_eating_and_stat_buffs()
|
|
_test_buff_expiration_and_cleanup()
|
|
_finish()
|
|
|
|
func _test_campfire_lighting() -> void:
|
|
print("\n--- Test 1: Lighting & Extinguishing Campfire (27600) ---")
|
|
var camp := FishingCookingCampSystem.new()
|
|
var inv: Array = [
|
|
{"vnum": FishingCookingCampSystem.CAMPFIRE_KIT_VNUM, "name": "营火工具", "count": 2}
|
|
]
|
|
|
|
var light_sig := {"fired": false, "time": 0.0}
|
|
camp.campfire_lit.connect(func(_p: Vector3, d: float):
|
|
light_sig["fired"] = true
|
|
light_sig["time"] = d
|
|
)
|
|
|
|
var res = camp.light_campfire(Vector3(10, 0, 10), inv)
|
|
_assert(res["ok"] == true, "Campfire lit")
|
|
_assert(camp.is_campfire_active == true, "Campfire is active")
|
|
_assert(inv[0]["count"] == 1, "1 campfire kit consumed (2 -> 1)")
|
|
_assert(light_sig["fired"] == true and light_sig["time"] == 300.0, "campfire_lit emitted with 300s")
|
|
|
|
# Extinguish on timeout (advance 305 seconds)
|
|
var ext_sig := {"fired": false}
|
|
camp.campfire_extinguished.connect(func(): ext_sig["fired"] = true)
|
|
|
|
var dummy_p := {}
|
|
camp.update(305.0, dummy_p)
|
|
_assert(camp.is_campfire_active == false, "Campfire extinguished")
|
|
_assert(ext_sig["fired"] == true, "campfire_extinguished emitted")
|
|
|
|
func _test_cooking_fish_recipes() -> void:
|
|
print("\n--- Test 2: Cooking Fish Recipes on Campfire ---")
|
|
var camp := FishingCookingCampSystem.new()
|
|
var inv: Array = [
|
|
{"vnum": 27600, "count": 1},
|
|
{"vnum": 27802, "name": "生鲤鱼", "count": 1},
|
|
{"vnum": 27815, "name": "生红鳟鱼", "count": 2}
|
|
]
|
|
|
|
# Try cook without active fire
|
|
var fail_c = camp.cook_fish(1, inv)
|
|
_assert(fail_c["ok"] == false and fail_c["reason"] == "NO_ACTIVE_CAMPFIRE", "Cannot cook without campfire")
|
|
|
|
# Light fire
|
|
camp.light_campfire(Vector3.ZERO, inv)
|
|
|
|
var cook_sig := {"fired": false, "name": ""}
|
|
camp.fish_cooked.connect(func(_raw: int, _ckd: int, cname: String):
|
|
cook_sig["fired"] = true
|
|
cook_sig["name"] = cname
|
|
)
|
|
|
|
# Cook Carp (slot 1)
|
|
var res1 = camp.cook_fish(1, inv)
|
|
_assert(res1["ok"] == true, "Cooked Carp")
|
|
_assert(cook_sig["fired"] == true and cook_sig["name"] == "烤鲤鱼", "fish_cooked signal emitted")
|
|
|
|
var has_cooked_carp := false
|
|
for it in inv:
|
|
if it != null and it.get("vnum", 0) == 27832:
|
|
has_cooked_carp = true
|
|
break
|
|
_assert(has_cooked_carp, "Cooked carp found in inventory")
|
|
|
|
# Cook Trout (slot 2)
|
|
camp.cook_fish(2, inv)
|
|
_assert(inv[2]["count"] == 1, "Raw trout count decremented (2 -> 1)")
|
|
|
|
var has_cooked_trout := false
|
|
for it in inv:
|
|
if it != null and it.get("vnum", 0) == 27845:
|
|
has_cooked_trout = true
|
|
break
|
|
_assert(has_cooked_trout, "Cooked trout found in inventory")
|
|
|
|
func _test_eating_and_stat_buffs() -> void:
|
|
print("\n--- Test 3: Eating Cooked Fish & 30-Minute Buffs ---")
|
|
var camp := FishingCookingCampSystem.new()
|
|
var player := {
|
|
"max_hp": 8000,
|
|
"atk": 500,
|
|
"move_speed": 100
|
|
}
|
|
var inv: Array = [
|
|
{"vnum": 27832, "name": "烤鲤鱼", "count": 1},
|
|
{"vnum": 27845, "name": "烤红鳟鱼", "count": 1}
|
|
]
|
|
|
|
var buff_sig := {"fired": false, "id": "", "dur": 0.0}
|
|
camp.food_buff_applied.connect(func(bid: String, _n: String, d: float):
|
|
buff_sig["fired"] = true
|
|
buff_sig["id"] = bid
|
|
buff_sig["dur"] = d
|
|
)
|
|
|
|
# Eat Grilled Carp (max_hp +1000)
|
|
var eat1 = camp.eat_cooked_fish(0, inv, player)
|
|
_assert(eat1["ok"] == true, "Ate Grilled Carp")
|
|
_assert(player["max_hp"] == 9000, "Max HP increased 8000 -> 9000 (+1000)")
|
|
_assert(inv[0] == null, "Grilled carp consumed")
|
|
_assert(buff_sig["fired"] == true and buff_sig["id"] == "buff_grilled_carp", "food_buff_applied emitted")
|
|
|
|
# Eat Grilled Trout (atk +50)
|
|
var eat2 = camp.eat_cooked_fish(1, inv, player)
|
|
_assert(eat2["ok"] == true, "Ate Grilled Trout")
|
|
_assert(player["atk"] == 550, "Atk increased 500 -> 550 (+50)")
|
|
_assert(camp.active_buffs.size() == 2, "2 active food buffs running")
|
|
|
|
func _test_buff_expiration_and_cleanup() -> void:
|
|
print("\n--- Test 4: Buff Duration & Clean Expiration ---")
|
|
var camp := FishingCookingCampSystem.new()
|
|
var player := {"max_hp": 8000}
|
|
var inv: Array = [{"vnum": 27832, "name": "烤鲤鱼", "count": 1}]
|
|
|
|
camp.eat_cooked_fish(0, inv, player)
|
|
_assert(player["max_hp"] == 9000, "HP is 9000")
|
|
|
|
var expire_sig := {"fired": false, "id": ""}
|
|
camp.food_buff_expired.connect(func(bid: String):
|
|
expire_sig["fired"] = true
|
|
expire_sig["id"] = bid
|
|
)
|
|
|
|
# Simulate 1805 seconds (exceeding 1800s duration)
|
|
camp.update(1805.0, player)
|
|
_assert(expire_sig["fired"] == true and expire_sig["id"] == "buff_grilled_carp", "food_buff_expired emitted")
|
|
_assert(player["max_hp"] == 8000, "Max HP cleanly reverted back to baseline 8000")
|
|
_assert(camp.active_buffs.is_empty(), "active_buffs cleared")
|
|
|
|
func _finish() -> void:
|
|
print("\n==========================================")
|
|
print("Fishing Cooking Camp Parity Tests Finished:")
|
|
print("Passed: %d, Failed: %d" % [_passed, _failed])
|
|
print("==========================================")
|
|
if _failed > 0:
|
|
printerr("FAILED: Some tests did not pass.")
|
|
quit(1)
|
|
else:
|
|
print("SUCCESS: All Fishing Cooking Camp parity tests passed!")
|
|
quit(0)
|