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

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)