装备校验链/快捷栏/公会/好友情侣/交易仓库五项差距修复(增量 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:
shenlei
2026-09-07 21:43:30 +09:00
co-authored by Claude Code
parent 61272b75e9
commit 8092ff44e2
25 changed files with 1067 additions and 134 deletions
+41 -2
View File
@@ -666,14 +666,47 @@ func can_equip_item(vnum: int, wear := -1) -> Dictionary:
return {"ok": false, "code": "NO_ITEM", "need": 0}
return EquipRules.can_equip(proto.item(vnum), wear, _equip_ctx())
# 组装 EquipRules.can_equip 需要的运行期上下文。属性点客户端未按名透出 → 传 -1(seam)。
# EPointTypes(服务器 char.h):ST=12 HT=13 DX=14 IQ=15MOUNT=109(骑乘中坐骑 vnum)。
const POINT_ST := 12
const POINT_HT := 13
const POINT_DX := 14
const POINT_IQ := 15
const POINT_MOUNT := 109
# 组装 EquipRules.can_equip 需要的运行期上下文(服务器真实链所需字段全集)。
# 属性四维从 get_points()["points"] 全量数组取;worn 是 {wear_cell: vnum} 穿戴表,
# 供 RING/UNIQUE 占用翻转与 UNIQUE 同组去重;polymorphed/riding 供 EquipItem 后置门。
func _equip_ctx() -> Dictionary:
var ctx := {"race": 0, "empire": 0, "level": 0, "st": -1, "dx": -1, "ht": -1, "iq": -1}
var ctx := {"race": 0, "empire": 0, "level": 0, "st": -1, "dx": -1, "ht": -1, "iq": -1,
"worn": {}, "polymorphed": false, "riding": false}
if client == null:
return ctx
if client.has_method("get_points"):
var p: Dictionary = client.get_points()
ctx["level"] = int(p.get("level", 0))
var vals: Array = p.get("points", [])
if vals.size() > POINT_MOUNT:
ctx["st"] = int(vals[POINT_ST])
ctx["ht"] = int(vals[POINT_HT])
ctx["dx"] = int(vals[POINT_DX])
ctx["iq"] = int(vals[POINT_IQ])
ctx["riding"] = int(vals[POINT_MOUNT]) > 0
# 穿戴表 {wear_cell: vnum}:旧 11 格来自 get_equipment()(下标即 wear cell);
# 新装备槽 19..23costume/ring/belt)留在 INVENTORY 全局 cell 90+wear(见上方常量)。
var worn := {}
if client.has_method("get_equipment"):
var eq: Array = client.get_equipment()
for i in eq.size():
var vnum := int(eq[i].get("vnum", 0)) if eq[i] is Dictionary else 0
if vnum != 0:
worn[i] = vnum
if client.has_method("get_inventory"):
for it in client.get_inventory():
if it is Dictionary:
var cell := int(it.get("cell", -1))
if cell >= EQUIP_BASE + WEAR_COSTUME_BODY and cell < EQUIP_BASE + WEAR_COUNT:
worn[cell - EQUIP_BASE] = int(it.get("vnum", 0))
ctx["worn"] = worn
if client.has_method("get_entities"):
for e in client.get_entities():
if bool(e.get("is_main", false)):
@@ -681,6 +714,8 @@ func _equip_ctx() -> Dictionary:
ctx["empire"] = int(e.get("empire", 0))
if int(e.get("level", 0)) > 0:
ctx["level"] = int(e.get("level", 0))
ctx["polymorphed"] = int(e.get("polymorph", 0)) != 0 \
or int(e.get("poly_vnum", 0)) != 0
break
return ctx
@@ -689,6 +724,10 @@ func _equip_reject_hint(verdict: Dictionary) -> String:
"ANTI_SEX": return "该装备不符合你的性别"
"ANTI_JOB": return "该装备不符合你的职业"
"ANTI_EMPIRE": return "该装备不符合你的帝国"
"UNIQUE_DUP": return "同类特殊装备只能佩戴一件"
"POLYMORPH": return "变身状态下无法更换装备"
"RIDE_TUXEDO": return "骑乘状态下无法穿礼服"
"RIDE_ITEM": return "已经在骑乘中了"
"NOT_WEARABLE_HERE": return "该装备不能穿在这个位置"
"LIMIT_LEVEL": return "需要等级 %d" % int(verdict.get("need", 0))
"LIMIT_STR": return "需要力量 %d" % int(verdict.get("need", 0))