- 桥梁与静态物体高度采样修复: - 严格对齐 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 客户端对拍缺陷发现与修复工程指南
119 lines
4.6 KiB
GDScript
119 lines
4.6 KiB
GDScript
# test_mall_affect_parity.gd —— 40250 商城常驻 Affect 增益与双倍特权 1:1 纯净回归测试套件
|
|
extends SceneTree
|
|
|
|
const MallAffectSystem = preload("res://mall_affect_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_mall_affect_parity (Direction 4: Mall Affects 1:1) ===")
|
|
_test_mall_item_activation()
|
|
_test_multipliers_and_privileges()
|
|
_test_hud_icon_formatting()
|
|
_test_decay_and_expiration()
|
|
_finish()
|
|
|
|
func _test_mall_item_activation() -> void:
|
|
print("\n--- Test 1: Mall Item Activation & Affect Table ---")
|
|
var mas := MallAffectSystem.new()
|
|
|
|
var non_mall := {"vnum": 10}
|
|
var res = mas.use_mall_item(non_mall)
|
|
_assert(res["ok"] == false and res["reason"] == "NOT_MALL_ITEM", "Non-mall item rejected")
|
|
|
|
# EXP Ring 1 hour (70005)
|
|
var exp_ring_1h := {"vnum": 70005}
|
|
res = mas.use_mall_item(exp_ring_1h)
|
|
_assert(res["ok"] == true, "EXP Ring 70005 activated")
|
|
_assert(mas.has_affect(MallAffectSystem.AFFECT_EXP_BONUS), "AFFECT_EXP_BONUS is active")
|
|
_assert(mas.active_affects[MallAffectSystem.AFFECT_EXP_BONUS]["duration"] == 3600.0, "Duration is 3600s (1h)")
|
|
|
|
# Thief Glove (70043)
|
|
var thief_glove := {"vnum": 70043}
|
|
res = mas.use_mall_item(thief_glove)
|
|
_assert(res["ok"] == true, "Thief Glove 70043 activated")
|
|
_assert(mas.has_affect(MallAffectSystem.AFFECT_ITEM_BONUS), "AFFECT_ITEM_BONUS is active")
|
|
|
|
# Lucky Gold Coin (70044)
|
|
var gold_coin := {"vnum": 70044}
|
|
res = mas.use_mall_item(gold_coin)
|
|
_assert(res["ok"] == true, "Lucky Gold Coin 70044 activated")
|
|
_assert(mas.has_affect(MallAffectSystem.AFFECT_GOLD_BONUS), "AFFECT_GOLD_BONUS is active")
|
|
|
|
# Safebox expansion ticket (72006)
|
|
var safebox_ticket := {"vnum": 72006}
|
|
res = mas.use_mall_item(safebox_ticket)
|
|
_assert(res["ok"] == true, "Safebox ticket 72006 activated")
|
|
_assert(mas.has_safebox_expansion() == true, "Safebox expansion granted")
|
|
|
|
func _test_multipliers_and_privileges() -> void:
|
|
print("\n--- Test 2: Game Multipliers (EXP, Drop, Gold) ---")
|
|
var mas := MallAffectSystem.new()
|
|
|
|
# Defaults
|
|
_assert(is_equal_approx(mas.get_exp_multiplier(), 1.0), "Default EXP multiplier is 1.0x")
|
|
_assert(is_equal_approx(mas.get_drop_multiplier(), 1.0), "Default Drop multiplier is 1.0x")
|
|
_assert(is_equal_approx(mas.get_gold_multiplier(), 1.0), "Default Gold multiplier is 1.0x")
|
|
|
|
# Activate 50% EXP ring
|
|
mas.use_mall_item({"vnum": 70005}) # value = 50
|
|
_assert(is_equal_approx(mas.get_exp_multiplier(), 1.5), "50% EXP Ring gives 1.5x EXP")
|
|
|
|
# Activate 100% EXP ring (72001)
|
|
mas.use_mall_item({"vnum": 72001}) # value = 100
|
|
_assert(is_equal_approx(mas.get_exp_multiplier(), 2.0), "100% EXP Ring gives 2.0x EXP")
|
|
|
|
# Activate Thief Glove (70043)
|
|
mas.use_mall_item({"vnum": 70043})
|
|
_assert(is_equal_approx(mas.get_drop_multiplier(), 2.0), "Thief Glove gives 2.0x Drop Rate")
|
|
|
|
# Activate Gold Coin (70044)
|
|
mas.use_mall_item({"vnum": 70044})
|
|
_assert(is_equal_approx(mas.get_gold_multiplier(), 2.0), "Lucky Gold Coin gives 2.0x Gold Amount")
|
|
|
|
func _test_hud_icon_formatting() -> void:
|
|
print("\n--- Test 3: HUD Icon & Official Sub Path Formatting ---")
|
|
var mas := MallAffectSystem.new()
|
|
mas.use_mall_item({"vnum": 70005}) # 1 hour = 3600s -> "01:00:00"
|
|
|
|
var icons: Array[Dictionary] = mas.get_hud_icons()
|
|
_assert(icons.size() == 1, "1 icon in HUD list")
|
|
var ic: Dictionary = icons[0]
|
|
_assert(ic["affect_type"] == MallAffectSystem.AFFECT_EXP_BONUS, "Affect type is EXP_BONUS")
|
|
_assert(ic["icon_sub"] == "d:/ymir work/ui/skill/common/affect/exp_bonus.sub", "Official 40250 sub texture matched")
|
|
_assert(ic["time_remaining_str"] == "01:00:00", "Remaining time formatted as 01:00:00")
|
|
|
|
func _test_decay_and_expiration() -> void:
|
|
print("\n--- Test 4: Duration Decay & Expiration ---")
|
|
var mas := MallAffectSystem.new()
|
|
mas.add_affect(MallAffectSystem.AFFECT_AUTOLOOT, 10.0) # 10 seconds
|
|
_assert(mas.has_affect(MallAffectSystem.AFFECT_AUTOLOOT), "Autoloot active")
|
|
|
|
# Decay 5s
|
|
var expired = mas.update(5.0)
|
|
_assert(expired.is_empty(), "No expiration after 5s")
|
|
_assert(mas.has_affect(MallAffectSystem.AFFECT_AUTOLOOT), "Still active")
|
|
|
|
# Decay 6s -> expire
|
|
expired = mas.update(6.0)
|
|
_assert(expired == [MallAffectSystem.AFFECT_AUTOLOOT], "Autoloot expired")
|
|
_assert(mas.has_affect(MallAffectSystem.AFFECT_AUTOLOOT) == false, "Autoloot no longer active")
|
|
|
|
func _finish() -> void:
|
|
print("\n=== SUMMARY: %d passed, %d failed ===" % [_passed, _failed])
|
|
if _failed == 0:
|
|
print("ALL TESTS PASSED!\n")
|
|
quit(0)
|
|
else:
|
|
printerr("SOME TESTS FAILED!\n")
|
|
quit(1)
|