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

114 lines
5.1 KiB
GDScript

# test_belt_system_parity.gd —— 40250 腰带系统与专属药水背包 1:1 纯净回归测试套件
extends SceneTree
const BeltSystem = preload("res://belt_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_belt_system_parity (Direction 2: Belt System 1:1) ===")
_test_slot_unlock_by_refine_level()
_test_potion_only_restriction()
_test_capacity_boundary()
_test_unequip_and_inventory_transfer()
_finish()
func _test_slot_unlock_by_refine_level() -> void:
print("\n--- Test 1: Refine-Level Based Slot Unlocking (4 ~ 16 Slots) ---")
_assert(BeltSystem.calculate_unlocked_slots(0) == 4, "+0 belt unlocks 4 slots")
_assert(BeltSystem.calculate_unlocked_slots(3) == 8, "+3 belt unlocks 8 slots")
_assert(BeltSystem.calculate_unlocked_slots(7) == 12, "+7 belt unlocks 12 slots")
_assert(BeltSystem.calculate_unlocked_slots(9) == 16, "+9 belt unlocks 16 slots (4x4)")
var bs := BeltSystem.new()
_assert(bs.get_unlocked_slot_count() == 0, "0 slots when no belt equipped")
bs.equip_belt({"vnum": 18000, "name": "亚麻腰带+0", "refine_level": 0})
_assert(bs.get_unlocked_slot_count() == 4, "+0 Linen Belt unlocks 4 slots")
bs.equip_belt({"vnum": 18039, "name": "王者腰带+9", "refine_level": 9})
_assert(bs.get_unlocked_slot_count() == 16, "+9 King Belt unlocks 16 slots")
func _test_potion_only_restriction() -> void:
print("\n--- Test 2: Potion-Only Storage Restriction ---")
var bs := BeltSystem.new()
bs.equip_belt({"vnum": 18000, "name": "皮腰带+3", "refine_level": 3}) # 8 slots
# 1. Weapon rejected
var r_sword = bs.store_item_in_belt(0, {"vnum": 10, "name": "木剑+0", "item_type": "weapon"})
_assert(r_sword["ok"] == false and r_sword["reason"] == "NOT_A_POTION", "Weapon rejected from belt")
# 2. Armor rejected
var r_armor = bs.store_item_in_belt(0, {"vnum": 11299, "name": "黑钢甲+9", "item_type": "armor"})
_assert(r_armor["ok"] == false and r_armor["reason"] == "NOT_A_POTION", "Armor rejected from belt")
# 3. Red Potion accepted
var r_pot = bs.store_item_in_belt(0, {"vnum": 27003, "name": "红药水(大)", "item_type": "potion", "count": 200})
_assert(r_pot["ok"] == true, "Red Potion accepted in belt")
_assert(bs.belt_inventory[0]["vnum"] == 27003, "Red potion stored at belt slot 0")
# 4. Sacred Dew accepted
var r_dew = bs.store_item_in_belt(1, {"vnum": 50821, "name": "绿露水", "item_type": "dew", "count": 10})
_assert(r_dew["ok"] == true, "Dew accepted in belt")
# 5. Sun Elixir accepted
var r_elixir = bs.store_item_in_belt(2, {"vnum": 72723, "name": "太阳之灵药", "item_type": "elixir", "count": 1})
_assert(r_elixir["ok"] == true, "Elixir accepted in belt")
func _test_capacity_boundary() -> void:
print("\n--- Test 3: Capacity Boundaries on Locked Slots ---")
var bs := BeltSystem.new()
bs.equip_belt({"vnum": 18000, "name": "亚麻腰带+0", "refine_level": 0}) # only slots 0..3 open
var potion := {"vnum": 27003, "name": "红药水", "item_type": "potion", "count": 10}
# Slot 3 (4th slot) is allowed
var r_ok = bs.store_item_in_belt(3, potion)
_assert(r_ok["ok"] == true, "Slot 3 allowed on +0 belt")
# Slot 4 (5th slot) is locked
var r_locked = bs.store_item_in_belt(4, potion)
_assert(r_locked["ok"] == false and r_locked["reason"] == "SLOT_LOCKED_OR_INVALID", "Slot 4 locked on +0 belt")
func _test_unequip_and_inventory_transfer() -> void:
print("\n--- Test 4: Belt Unequip & Potion Eviction to Main Inventory ---")
var bs := BeltSystem.new()
bs.equip_belt({"vnum": 18000, "name": "腰带+0", "refine_level": 0})
# Store 2 potions in belt
bs.store_item_in_belt(0, {"vnum": 27003, "name": "红药水", "item_type": "potion", "count": 50})
bs.store_item_in_belt(1, {"vnum": 27006, "name": "蓝药水", "item_type": "potion", "count": 50})
# 1. Main inventory completely full -> unequip blocked
var full_inv: Array = [{"vnum": 1}, {"vnum": 2}] # no nulls
var r_block = bs.unequip_belt(full_inv)
_assert(r_block["ok"] == false and r_block["reason"] == "BELT_NOT_EMPTY", "Unequip blocked when main inventory full")
_assert(not bs.equipped_belt.is_empty(), "Belt remains equipped")
# 2. Main inventory has space -> potions transferred and belt unequipped
var open_inv: Array = [null, null, null]
var r_ok = bs.unequip_belt(open_inv)
_assert(r_ok["ok"] == true, "Unequip succeeds with open inventory")
_assert(bs.equipped_belt.is_empty(), "Belt unequipped")
_assert(open_inv[0] != null and open_inv[0]["vnum"] == 27003, "Red potion transferred to main inventory slot 0")
_assert(open_inv[1] != null and open_inv[1]["vnum"] == 27006, "Blue potion transferred to main inventory slot 1")
_assert(bs.belt_inventory[0] == null and bs.belt_inventory[1] == null, "Belt inventory cleared")
func _finish() -> void:
print("\n==========================================")
print("Belt System Parity Test Results: %d Passed, %d Failed" % [_passed, _failed])
print("==========================================")
if _failed > 0:
quit(1)
else:
quit(0)