- 桥梁与静态物体高度采样修复: - 严格对齐 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 客户端对拍缺陷发现与修复工程指南
166 lines
6.5 KiB
GDScript
166 lines
6.5 KiB
GDScript
# test_safebox_storage_keeper_parity.gd —— 40250 仓库保管员金条熔铸与密码保险箱系统回归测试
|
|
extends SceneTree
|
|
|
|
const SystemClass = preload("res://safebox_storage_keeper_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_safebox_storage_keeper_parity (Batch 26 Direction 2) ===")
|
|
_test_password_and_open_checks()
|
|
_test_password_change()
|
|
_test_safebox_storage_operations()
|
|
_test_gold_bar_smelting_and_encashment()
|
|
_test_safebox_edge_cases()
|
|
|
|
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_password_and_open_checks() -> void:
|
|
print("\n--- Test 1: Safebox Password Authentication & Cooldown/Distance ---")
|
|
var box = SystemClass.new()
|
|
|
|
# 1. Distance > 1000 fails
|
|
var r_dist = box.open_safebox("000000", 1500.0)
|
|
_assert(r_dist["error_code"] == "TOO_FAR", "Reject opening safebox if distance > 1000")
|
|
|
|
# 2. Wrong password fails
|
|
var r_wrong = box.open_safebox("123456", 200.0)
|
|
_assert(r_wrong["error_code"] == "WRONG_PASSWORD", "Reject opening safebox with wrong password")
|
|
_assert(box.is_open == false, "Safebox remains closed on wrong password")
|
|
|
|
# 3. Default password "000000" succeeds
|
|
var r_ok = box.open_safebox("000000", 200.0)
|
|
_assert(r_ok["success"] == true, "Default password 000000 opens safebox")
|
|
_assert(box.is_open == true, "Safebox is open")
|
|
|
|
# 4. Opening within 10s fails with COOLDOWN_ACTIVE
|
|
box.close_safebox()
|
|
box.current_time = 1005 # only 5 seconds later
|
|
var r_cd = box.open_safebox("000000", 200.0)
|
|
_assert(r_cd["error_code"] == "COOLDOWN_ACTIVE", "Reject opening safebox within 10 seconds")
|
|
|
|
# 5. Opening after 10s succeeds
|
|
box.current_time = 1015
|
|
var r_cd_ok = box.open_safebox("000000", 200.0)
|
|
_assert(r_cd_ok["success"] == true, "Open safebox succeeds after cooldown expires")
|
|
|
|
func _test_password_change() -> void:
|
|
print("\n--- Test 2: Password Change Verification ---")
|
|
var box = SystemClass.new()
|
|
box.open_safebox("000000", 200.0)
|
|
|
|
# Old password mismatch
|
|
var r_fail = box.change_password("999999", "654321")
|
|
_assert(r_fail["error_code"] == "OLD_PASSWORD_MISMATCH", "Reject password change if old password mismatches")
|
|
|
|
# Change password successfully
|
|
var r_succ = box.change_password("000000", "888888")
|
|
_assert(r_succ["success"] == true, "Password successfully changed to 888888")
|
|
_assert(box.password == "888888", "Internal password updated")
|
|
|
|
# Re-open with new password
|
|
box.close_safebox()
|
|
box.current_time += 20
|
|
var r_new_open = box.open_safebox("888888", 200.0)
|
|
_assert(r_new_open["success"] == true, "Can open safebox with new password")
|
|
|
|
func _test_safebox_storage_operations() -> void:
|
|
print("\n--- Test 3: Storage Deposit, Withdraw & Stacking (45 Slots) ---")
|
|
var box = SystemClass.new()
|
|
box.open_safebox("000000", 200.0)
|
|
|
|
var sword = { "vnum": 10, "name": "Sword+0", "count": 1, "stackable": false }
|
|
var potion1 = { "vnum": 27001, "name": "Red Potion (S)", "count": 50, "stackable": true }
|
|
var potion2 = { "vnum": 27001, "name": "Red Potion (S)", "count": 25, "stackable": true }
|
|
|
|
# Deposit sword into slot 0
|
|
var dep1 = box.deposit_item(0, sword)
|
|
_assert(dep1["success"] == true, "Sword deposited into slot 0")
|
|
_assert(box.safebox_grid[0]["vnum"] == 10, "Slot 0 holds Sword+0")
|
|
|
|
# Deposit potion into slot 1
|
|
var dep2 = box.deposit_item(1, potion1)
|
|
_assert(dep2["success"] == true, "Potion deposited into slot 1")
|
|
|
|
# Stacking into slot 1
|
|
var dep3 = box.deposit_item(1, potion2)
|
|
_assert(dep3["success"] == true, "Potion stacked into slot 1")
|
|
_assert(box.safebox_grid[1]["count"] == 75, "Slot 1 potion count updated to 75")
|
|
|
|
# Moving item from slot 0 to slot 5
|
|
var move_ok = box.move_safebox_item(0, 5)
|
|
_assert(move_ok == true, "Moved item from slot 0 to slot 5")
|
|
_assert(box.safebox_grid[0] == null, "Slot 0 is now empty")
|
|
_assert(box.safebox_grid[5]["vnum"] == 10, "Slot 5 now holds Sword+0")
|
|
|
|
# Withdraw item from slot 5
|
|
var wd = box.withdraw_item(5)
|
|
_assert(wd["success"] == true, "Withdrew item from slot 5")
|
|
_assert(wd["item"]["vnum"] == 10, "Withdrawn item is Sword+0")
|
|
_assert(box.safebox_grid[5] == null, "Slot 5 is now empty")
|
|
|
|
func _test_gold_bar_smelting_and_encashment() -> void:
|
|
print("\n--- Test 4: Official 1% Smelting Tax & Encashment (80003~80007) ---")
|
|
var box = SystemClass.new()
|
|
|
|
# 1. Smelt 50k bar (80003): cost = 50500 (1% tax)
|
|
var player_gold := 100000
|
|
var s1 = box.smelt_gold_bar(player_gold, 80003)
|
|
_assert(s1["success"] == true, "Smelted 50k silver bar")
|
|
_assert(s1["cost"] == 50500, "Cost is exactly 50,500 (1% fee)")
|
|
_assert(s1["new_gold"] == 49500, "Player gold reduced to 49,500")
|
|
_assert(s1["bar_item"]["face_value"] == 50000, "Bar face value is 50,000")
|
|
|
|
# 2. Smelt 2M bar (80007): cost = 2,020,000 (1% tax)
|
|
player_gold = 3000000
|
|
var s2 = box.smelt_gold_bar(player_gold, 80007)
|
|
_assert(s2["success"] == true, "Smelted 2M gold bar")
|
|
_assert(s2["cost"] == 2020000, "Cost is exactly 2,020,000")
|
|
_assert(s2["new_gold"] == 980000, "Player gold reduced to 980,000")
|
|
|
|
# 3. Insufficient gold rejected
|
|
var s_fail = box.smelt_gold_bar(1000, 80003)
|
|
_assert(s_fail["error_code"] == "INSUFFICIENT_GOLD", "Reject smelting when gold < cost")
|
|
|
|
# 4. Encash 2M bar (80007) back to cash: grants 2,000,000 face value
|
|
var c1 = box.encash_gold_bar(500000, 80007)
|
|
_assert(c1["success"] == true, "Encash 2M gold bar")
|
|
_assert(c1["cash_value"] == 2000000, "Cash value is 2,000,000")
|
|
_assert(c1["new_gold"] == 2500000, "Player gold increased to 2,500,000")
|
|
|
|
func _test_safebox_edge_cases() -> void:
|
|
print("\n--- Test 5: Closed Safebox Operations & Invalid Slots ---")
|
|
var box = SystemClass.new()
|
|
|
|
# Deposit while closed
|
|
var dep_closed = box.deposit_item(0, { "vnum": 1, "count": 1 })
|
|
_assert(dep_closed["error_code"] == "NOT_OPEN", "Reject deposit when safebox is closed")
|
|
|
|
# Withdraw while closed
|
|
var wd_closed = box.withdraw_item(0)
|
|
_assert(wd_closed["error_code"] == "NOT_OPEN", "Reject withdraw when safebox is closed")
|
|
|
|
# Open safebox
|
|
box.open_safebox("000000", 200.0)
|
|
|
|
# Invalid slots (< 0 or >= 45)
|
|
var dep_inv = box.deposit_item(45, { "vnum": 1, "count": 1 })
|
|
_assert(dep_inv["error_code"] == "INVALID_SLOT", "Reject deposit into slot 45 (max 44)")
|
|
|
|
var wd_inv = box.withdraw_item(-1)
|
|
_assert(wd_inv["error_code"] == "INVALID_SLOT", "Reject withdraw from slot -1")
|