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

148 lines
5.9 KiB
GDScript

# test_inventory_expansion_parity.gd —— 40250 背包扩展凭证与阶梯解锁系统回归测试
extends SceneTree
const SystemClass = preload("res://inventory_expansion_system.gd")
var _passed: int = 0
var _failed: int = 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_inventory_expansion_parity (Batch 26 Direction 4) ===")
_test_default_unlocked_baseline()
_test_key_cost_curve()
_test_stage_by_stage_unlocking()
_test_locked_slot_item_placement_rejection()
_test_multislot_item_boundary_and_lock_check()
_test_full_180_slots_unlock_completion()
print("\n=== Result: %d Passed, %d Failed ===" % [_passed, _failed])
if _failed == 0:
print("ALL TESTS PASSED!\n")
else:
printerr("SOME TESTS FAILED!\n")
quit(0 if _failed == 0 else 1)
func _test_default_unlocked_baseline() -> void:
print("\n--- Test 1: Default Baseline (Pages 1 & 2 = 90 Slots Unlocked) ---")
var inv = SystemClass.new()
_assert(inv.get_unlocked_slot_count() == 90, "Baseline has 90 unlocked slots (2 pages)")
_assert(inv.is_slot_unlocked(0) == true, "Slot 0 (Page 1) is unlocked")
_assert(inv.is_slot_unlocked(44) == true, "Slot 44 (Page 1 end) is unlocked")
_assert(inv.is_slot_unlocked(45) == true, "Slot 45 (Page 2 start) is unlocked")
_assert(inv.is_slot_unlocked(89) == true, "Slot 89 (Page 2 end) is unlocked")
# Locked slots on Pages 3 & 4
_assert(inv.is_slot_unlocked(90) == false, "Slot 90 (Page 3 start) is locked")
_assert(inv.is_slot_unlocked(134) == false, "Slot 134 (Page 3 end) is locked")
_assert(inv.is_slot_unlocked(135) == false, "Slot 135 (Page 4 start) is locked")
_assert(inv.is_slot_unlocked(179) == false, "Slot 179 (Page 4 end) is locked")
func _test_key_cost_curve() -> void:
print("\n--- Test 2: 18-Stage Key Cost Curve (Official 40250) ---")
var inv = SystemClass.new()
_assert(inv.get_next_stage_key_cost() == 1, "Stage 1 costs 1 key")
inv.unlocked_stages = 5
_assert(inv.get_next_stage_key_cost() == 1, "Stage 6 costs 1 key")
inv.unlocked_stages = 6
_assert(inv.get_next_stage_key_cost() == 2, "Stage 7 costs 2 keys")
inv.unlocked_stages = 11
_assert(inv.get_next_stage_key_cost() == 2, "Stage 12 costs 2 keys")
inv.unlocked_stages = 12
_assert(inv.get_next_stage_key_cost() == 3, "Stage 13 costs 3 keys")
inv.unlocked_stages = 17
_assert(inv.get_next_stage_key_cost() == 4, "Stage 18 costs 4 keys")
# Sum of all stages
var total_keys := 0
for cost in SystemClass.STAGE_KEY_COSTS:
total_keys += cost
_assert(total_keys == 37, "Total keys for all 18 stages is exactly 37 keys")
func _test_stage_by_stage_unlocking() -> void:
print("\n--- Test 3: Stage-by-Stage Unlocking and Key Deduction ---")
var inv = SystemClass.new()
# Insufficient keys
var r_fail = inv.unlock_next_stage(0)
_assert(r_fail["error_code"] == "INSUFFICIENT_KEYS", "Reject unlock if keys < required")
# Unlock stage 1 (costs 1 key)
var r_stage1 = inv.unlock_next_stage(10)
_assert(r_stage1["success"] == true, "Stage 1 unlocked")
_assert(r_stage1["keys_deducted"] == 1, "1 key deducted")
_assert(r_stage1["remaining_keys"] == 9, "9 keys remain")
_assert(r_stage1["unlocked_slots"] == 95, "Unlocked slots increased to 95")
_assert(inv.is_slot_unlocked(90) == true, "Slot 90 now unlocked")
_assert(inv.is_slot_unlocked(94) == true, "Slot 94 now unlocked")
_assert(inv.is_slot_unlocked(95) == false, "Slot 95 still locked")
func _test_locked_slot_item_placement_rejection() -> void:
print("\n--- Test 4: Locked Slot Item Placement Rejection ---")
var inv = SystemClass.new()
var sword = { "vnum": 10, "name": "Sword+0" }
# Put into unlocked slot 0
var r_ok = inv.put_item(0, sword, 1)
_assert(r_ok["success"] == true, "Placed item into unlocked slot 0")
# Put into locked slot 90
var r_lock = inv.put_item(90, sword, 1)
_assert(r_lock["error_code"] == "SLOT_LOCKED", "Reject putting item into locked slot 90")
func _test_multislot_item_boundary_and_lock_check() -> void:
print("\n--- Test 5: Multi-Slot Item Boundary & Partial Lock Detection ---")
var inv = SystemClass.new()
var greatsword = { "vnum": 3000, "name": "Glaive+0" } # Height = 3
# Slot 80 is Page 2, row 7 (cells 80, 85, 90).
# But row 7 + 3 = 10 > 9 -> PAGE_OVERFLOW!
var r_overflow = inv.can_place_item_at(80, 3)
_assert(r_overflow["error_code"] == "PAGE_OVERFLOW", "Reject multi-slot item crossing page bottom")
# Slot 70 is Page 2, row 5 (cells 70, 75, 80). row 5 + 3 = 8 <= 9 -> OK!
var r_valid = inv.can_place_item_at(70, 3)
_assert(r_valid["can_place"] == true, "Can place 3-slot item safely inside page 2")
# Now unlock Stage 1 (slots 90..94 unlocked)
inv.unlock_next_stage(1)
# Try to place 2-slot item at slot 91 (needs 91 and 96; 91 is unlocked, but 96 is locked!)
var r_part_locked = inv.can_place_item_at(91, 2)
_assert(r_part_locked["error_code"] == "SLOT_LOCKED", "Reject multi-slot item when lower cell (96) is locked")
# But 1-slot item at 91 is fine
var r_single_ok = inv.can_place_item_at(91, 1)
_assert(r_single_ok["can_place"] == true, "Single slot item at 91 can be placed")
func _test_full_180_slots_unlock_completion() -> void:
print("\n--- Test 6: Full 180 Slots Unlocking (All 18 Stages) ---")
var inv = SystemClass.new()
var total_keys_available := 50
# Unlock all 18 stages
for s in range(18):
var res = inv.unlock_next_stage(total_keys_available)
_assert(res["success"] == true, "Stage %d unlocked successfully" % (s + 1))
total_keys_available = res["remaining_keys"]
_assert(inv.unlocked_stages == 18, "All 18 stages unlocked")
_assert(inv.get_unlocked_slot_count() == 180, "All 180 slots unlocked")
_assert(inv.is_slot_unlocked(179) == true, "Final slot 179 is unlocked")
_assert(total_keys_available == 50 - 37, "Remaining keys is 13 (50 - 37)")
# Attempting 19th stage
var r_max = inv.unlock_next_stage(total_keys_available)
_assert(r_max["error_code"] == "ALREADY_MAX_EXPANDED", "Reject unlocking beyond 18 stages")