装备校验链/快捷栏/公会/好友情侣/交易仓库五项差距修复(增量 129)
- 装备校验:can_equip 按 CanEquipNow→FindEquipCell→EquipItem 精确重排, 新增 find_equip_cell() 1:1 复刻(RING/UNIQUE 占用翻转、COSTUME/BELT/DS), 帝国 antiflag 降级为 tooltip 提示,LIMIT_PCBANG/REAL_TIME* 语义与倒计时文案 - 快捷栏:死亡全槽禁用+激活守卫、变身(affect 220)技能置灰、 物品槽失配置灰(服务器回收/换武器后刷新) - 公会:GUILD_AUTH_* 权限位门控踢人/公告/技能升级,/gskillup、 被宣战应答弹窗(/war·/nowar)、资金存取行(40250 服务端已禁用仍保留 1:1) - 好友/情侣:messenger 三固定组(好友/公会/情侣),lover_login/logout/ near/far/divorce 命令事件→在线/在身边状态与离婚隐藏 - 交易/仓库:ExchangeState.last_notice(ALREADY/LESS_GOLD)结束浮层提示; 仓库改密 /safebox_change_password 三段输入;关窗补 /safebox_close·/mall_close; 仓库金钱经核实 40250 无 wire 协议,UI 定界只读 - app_flow:重连时 guild_marks_ready 重复连接加 is_connected 守卫 - 相机 look_at 零向量守卫(首帧/传送落点) - 测试:equip/love/guild 断言更新,79 项中 78 绿(game_camera_test 为 HEAD 既有失败);真服冒烟 LIVE_SMOKE PASS(192.168.21.203 全链路) - docs/CLIENT-GAP.md 同步增量 129 Co-Authored-By: Claude Code <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018kUFvQGYusuY3dkfGitmAe
This commit is contained in:
+67
-11
@@ -1,4 +1,6 @@
|
||||
# equip_rules_test —— §4.1 修改 2:装备穿戴合法性校验(EquipRules)1:1 自检。
|
||||
# equip_rules_test —— 装备穿戴合法性校验(EquipRules)1:1 自检。
|
||||
# 顺序对齐服务器真实链:CanEquipNow(JOB→limit→UNIQUE 去重) → FindEquipCell →
|
||||
# EquipItem 后置(燕尾服/变身/性别/骑乘)。
|
||||
# canonical #17。 godot --headless --path project --script equip_rules_test.gd
|
||||
extends SceneTree
|
||||
|
||||
@@ -24,8 +26,10 @@ func _init() -> void:
|
||||
_test_wearable()
|
||||
_test_limits()
|
||||
_test_order_and_newslots()
|
||||
_test_find_equip_cell()
|
||||
_test_post_checks()
|
||||
if failed == 0:
|
||||
print("PASS: equip_rules_test (§4.1 CanEquipNow antiflag→wearable→limit 1:1)")
|
||||
print("PASS: equip_rules_test (CanEquipNow→FindEquipCell→EquipItem 后置 1:1)")
|
||||
quit(0)
|
||||
else:
|
||||
quit(1)
|
||||
@@ -78,10 +82,13 @@ func _test_antiflag() -> void:
|
||||
_ck(EquipRules.can_equip(no_warrior, -1, {"race": 0})["code"] == "ANTI_JOB", "ANTI_WARRIOR blocks warrior (race 0)")
|
||||
_ck(EquipRules.can_equip(no_warrior, -1, {"race": 1})["ok"], "ANTI_WARRIOR ok for assassin (race 1)")
|
||||
|
||||
# 帝国 antiflag 不是装备门(服务器装备路径从不检查)——can_equip 放行,
|
||||
# 冲突位只由 empire_warning() 给 tooltip。
|
||||
var no_emp_a := _weapon({"anti_flags": EquipRules.ANTIFLAG_EMPIRE_A})
|
||||
_ck(EquipRules.can_equip(no_emp_a, -1, {"empire": 1})["code"] == "ANTI_EMPIRE", "ANTI_EMPIRE_A blocks empire 1")
|
||||
_ck(EquipRules.can_equip(no_emp_a, -1, {"empire": 2})["ok"], "ANTI_EMPIRE_A ok for empire 2")
|
||||
_ck(EquipRules.can_equip(no_emp_a, -1, {"empire": 0})["ok"], "no empire -> anti empire skipped")
|
||||
_ck(EquipRules.can_equip(no_emp_a, -1, {"empire": 1})["ok"], "ANTI_EMPIRE no longer blocks equip")
|
||||
_ck(EquipRules.empire_warning(no_emp_a, 1) == EquipRules.ANTIFLAG_EMPIRE_A, "empire_warning reports conflict")
|
||||
_ck(EquipRules.empire_warning(no_emp_a, 2) == 0, "empire_warning clean for empire 2")
|
||||
_ck(EquipRules.empire_warning(no_emp_a, 0) == 0, "empire_warning clean without empire")
|
||||
|
||||
func _test_wearable() -> void:
|
||||
var res := EquipRules.can_equip(_weapon(), EquipRules.WEAR_BODY, {"race": 0})
|
||||
@@ -109,16 +116,22 @@ func _test_limits() -> void:
|
||||
_ck(EquipRules.can_equip(zero, -1, {"race": 0, "level": 1})["ok"], "limit value 0 ignored")
|
||||
|
||||
func _test_order_and_newslots() -> void:
|
||||
# anti-flag 先于 limit:两个都失败 → 返回 ANTI_SEX
|
||||
# limit 先于性别(服务器顺序:CanEquipNow 的 limit 在 EquipItem 的
|
||||
# FN_check_item_sex 之前):两个都失败 → 返回 LIMIT_LEVEL
|
||||
var both := _weapon({"anti_flags": EquipRules.ANTIFLAG_FEMALE,
|
||||
"limits": [{"type": EquipRules.LIMIT_LEVEL, "value": 99}]})
|
||||
_ck(EquipRules.can_equip(both, -1, {"race": 1, "level": 1})["code"] == "ANTI_SEX",
|
||||
"antiflag checked before limit")
|
||||
_ck(EquipRules.can_equip(both, -1, {"race": 1, "level": 1})["code"] == "LIMIT_LEVEL",
|
||||
"limit checked before sex antiflag (server order)")
|
||||
# JOB 仍是最先的 antiflag 检查
|
||||
var job_first := _weapon({"anti_flags": EquipRules.ANTIFLAG_WARRIOR,
|
||||
"limits": [{"type": EquipRules.LIMIT_LEVEL, "value": 99}]})
|
||||
_ck(EquipRules.can_equip(job_first, -1, {"race": 0, "level": 1})["code"] == "ANTI_JOB",
|
||||
"job antiflag checked before limit")
|
||||
|
||||
# wearable 先于 limit
|
||||
# 显式槽不匹配(客户端防御层)在 limit 之后
|
||||
var wl := _weapon({"limits": [{"type": EquipRules.LIMIT_LEVEL, "value": 99}]})
|
||||
_ck(EquipRules.can_equip(wl, EquipRules.WEAR_BODY, {"race": 0, "level": 1})["code"] == "NOT_WEARABLE_HERE",
|
||||
"wearable checked before limit")
|
||||
_ck(EquipRules.can_equip(wl, EquipRules.WEAR_BODY, {"race": 0, "level": 99})["code"] == "NOT_WEARABLE_HERE",
|
||||
"explicit slot mismatch -> NOT_WEARABLE_HERE")
|
||||
|
||||
# 新装备槽:ring / belt / costume 按 type 判定,无 wear_flags 也能穿
|
||||
_ck(EquipRules.can_equip({"type": 33}, EquipRules.WEAR_RING1, {"race": 0})["ok"], "ring at RING1 ok")
|
||||
@@ -129,3 +142,46 @@ func _test_order_and_newslots() -> void:
|
||||
|
||||
# 空物品
|
||||
_ck(EquipRules.can_equip({}, -1, {})["code"] == "NO_ITEM", "empty item -> NO_ITEM")
|
||||
|
||||
func _test_find_equip_cell() -> void:
|
||||
# item.cpp:472 的 else-if 优先级与 RING/UNIQUE 占用翻转。
|
||||
_ck(EquipRules.find_equip_cell(_weapon()) == EquipRules.WEAR_WEAPON, "weapon cell")
|
||||
_ck(EquipRules.find_equip_cell(_weapon({"wear_flags": (1 << 0) | (1 << 4)})) == EquipRules.WEAR_BODY,
|
||||
"BODY wins over WEAPON in else-if chain")
|
||||
_ck(EquipRules.find_equip_cell({"type": 33}) == EquipRules.WEAR_RING1, "ring -> RING1 when free")
|
||||
_ck(EquipRules.find_equip_cell({"type": 33}, {EquipRules.WEAR_RING1: 1234}) == EquipRules.WEAR_RING2,
|
||||
"ring -> RING2 when RING1 occupied")
|
||||
var uniq := {"type": 2, "wear_flags": 1 << 7, "vnum": 70001}
|
||||
_ck(EquipRules.find_equip_cell(uniq) == EquipRules.WEAR_UNIQUE1, "unique -> UNIQUE1 when free")
|
||||
_ck(EquipRules.find_equip_cell(uniq, {EquipRules.WEAR_UNIQUE1: 70002}) == EquipRules.WEAR_UNIQUE2,
|
||||
"unique -> UNIQUE2 when UNIQUE1 occupied")
|
||||
# 无 wear_flag 且非 COSTUME/DS/RING/BELT → -1(TOTEM 同)
|
||||
_ck(EquipRules.find_equip_cell({"type": 3}) == -1, "no wear flag -> -1")
|
||||
_ck(EquipRules.find_equip_cell({"type": 26, "wear_flags": 1 << 0}) == -1, "totem -> -1")
|
||||
# 龙魂石走客户端专用路径
|
||||
_ck(EquipRules.find_equip_cell({"type": 29, "sub_type": 3}) == -1, "DS -> -1 (dedicated path)")
|
||||
|
||||
func _test_post_checks() -> void:
|
||||
# EquipItem 后置门(char_item.cpp:6122+)。
|
||||
# 变身中除 ARROW 外一律拒绝
|
||||
var bow := _weapon({"wear_flags": 1 << 9})
|
||||
_ck(EquipRules.can_equip(_weapon(), -1, {"race": 0, "polymorphed": true})["code"] == "POLYMORPH",
|
||||
"polymorphed blocks weapon")
|
||||
_ck(EquipRules.can_equip(bow, -1, {"race": 0, "polymorphed": true})["ok"],
|
||||
"polymorphed allows ARROW")
|
||||
# 燕尾服骑乘禁止(vnum 11901..11904)
|
||||
var tux := {"type": 2, "sub_type": 0, "wear_flags": 1 << 0, "vnum": 11901}
|
||||
_ck(EquipRules.can_equip(tux, -1, {"race": 0, "riding": true})["code"] == "RIDE_TUXEDO",
|
||||
"tuxedo blocked while riding")
|
||||
_ck(EquipRules.can_equip(tux, -1, {"race": 0, "riding": false})["ok"], "tuxedo ok on foot")
|
||||
# 骑乘物品已骑乘禁止(UNIQUE + RIDE/MOUNT_RIDE 子类)
|
||||
var horse := {"type": 16, "sub_type": 2, "wear_flags": 1 << 7, "vnum": 50051}
|
||||
_ck(EquipRules.can_equip(horse, -1, {"race": 0, "riding": true})["code"] == "RIDE_ITEM",
|
||||
"ride item blocked while riding")
|
||||
_ck(EquipRules.can_equip(horse, -1, {"race": 0, "riding": false})["ok"], "ride item ok on foot")
|
||||
# UNIQUE 同 vnum 去重
|
||||
var u := {"type": 2, "wear_flags": 1 << 7, "vnum": 70001}
|
||||
_ck(EquipRules.can_equip(u, -1, {"race": 0, "worn": {EquipRules.WEAR_UNIQUE1: 70001}})["code"] == "UNIQUE_DUP",
|
||||
"same vnum in UNIQUE1 -> UNIQUE_DUP")
|
||||
_ck(EquipRules.can_equip(u, -1, {"race": 0, "worn": {EquipRules.WEAR_UNIQUE1: 70002}})["ok"],
|
||||
"different vnum in UNIQUE1 ok")
|
||||
|
||||
Reference in New Issue
Block a user