fix(ui): 点击商人面板买/卖/修理按钮后鼠标样式应切换为原版 buysell.dc6 交易光标 #491

Closed
opened 2026-09-27 05:39:58 +00:00 by troytt · 0 comments
Owner

问题描述

在 NPC 交易/赌博面板(WorldPanels / HudManager)中,点击底部 买(Buy)、卖(Sell) 或 修理(Repair) 按钮后,按钮本身会切换为按下状态且 vendorTradeState 变为 'buy' | 'sell' | 'repair',但鼠标指针样式仍然保持普通手型(protate / ohand / orotate),未切换为暗黑破坏神 II v1.13c 原版交易/修理专属光标。


D2Client.dll v1.13c 逆向 Ground Truth

  1. 全局光标表 (0x6fba8558, 共 7 项, stride 0x1c):
    • CursorId = 6:'buysell' (data\global\ui\CURSOR\buysell.dc6, 共 10 帧, 32x40),帧索引回调 +0x14 = 0x6fac62c0(直接返回 g_nCursorFrame (0x6fbcb858) 整数帧号,而非手型动画的 8.8 定点数位移)。
  2. 商人按钮初始化表 (0x6fbbb238, 20 字节结构体, 0x6fb3f430):
    • 修理按钮 (0x6fb3ba70):nTradeMode = 4 (+0x0a),nButtonFrame = 6 (+0x0e),nCursorFrame = 1 (+0x10 -> buysell.dc6 Frame 1 铁砧修理锤光标)。
    • 购买按钮 (0x6fb3ba30):nTradeMode = 2 (+0x0a),nButtonFrame = 2 (+0x0e),nCursorFrame = 3 (+0x10 -> buysell.dc6 Frame 3 买入金币/手指光标)。
    • 出售按钮 (0x6fb3b9f0):nTradeMode = 3 (+0x0a),nButtonFrame = 4 (+0x0e),nCursorFrame = 4 (+0x10 -> buysell.dc6 Frame 4 卖出金币/手指光标)。
    • 鉴定卷轴/辨识模式 (0x6fb36fb7 / 0x6fac6070):g_nCursorId = 6,nCursorFrame = 0 (buysell.dc6 Frame 0 辨识卷轴光标)。
  3. 按钮激活与取消 (0x6fb475e1 / 0x6fb472d0 / 0x6fb3d300):
    • 点击买/卖/修理按钮释放时 (0x6fb475e1):设置 g_nCursorTradeMode (0x6fbcbc34) = button.nTradeMode,g_nCursorId (0x6fbcb854) = 6 (buysell.dc6),g_nCursorFrame (0x6fbcb858) = button.nCursorFrame (3 / 4 / 1),g_nCursorState (0x6fbcb864) = 7。
    • 右键点击、再次点击同一按钮取消、点击全部修理或关闭面板时:重置为 idle 并恢复默认手型光标 (CursorId = 5 protate)。

修复方案

  1. 离线烘焙 (scripts/pack-cursor.ts):从 d2data.mpq 提取 data/global/ui/CURSOR/buysell.dc6 全部 10 帧(32x40)烘焙进 public/ui/cursor.png 图集及 src/ui/cursor-meta.ts。
  2. 光标控制器与 HUD 渲染 (src/ui/cursor.ts, src/ui/hud-manager.ts, src/ui/world-panels.ts):
    • 支持交易光标模式 ('buy' | 'sell' | 'repair') 及辨识光标模式 ('identify'),精确渲染 buysell.dc6 对应帧(Buy=Frame 3, Sell=Frame 4, Repair=Frame 1, Identify=Frame 0)。
    • 支持右键取消交易光标模式,关闭面板或切换状态时自动归位。
  3. 测试验证:新增单元测试与 Headless 浏览器端到端验证。
### 问题描述 在 NPC 交易/赌博面板(`WorldPanels` / `HudManager`)中,点击底部 **买(Buy)**、**卖(Sell)** 或 **修理(Repair)** 按钮后,按钮本身会切换为按下状态且 `vendorTradeState` 变为 `'buy' | 'sell' | 'repair'`,但鼠标指针样式仍然保持普通手型(`protate` / `ohand` / `orotate`),未切换为暗黑破坏神 II v1.13c 原版交易/修理专属光标。 --- ### D2Client.dll v1.13c 逆向 Ground Truth 1. **全局光标表 (`0x6fba8558`, 共 7 项, stride `0x1c`)**: - `CursorId = 6`:`'buysell'` (`data\global\ui\CURSOR\buysell.dc6`, 共 10 帧, `32x40`),帧索引回调 `+0x14 = 0x6fac62c0`(直接返回 `g_nCursorFrame (0x6fbcb858)` 整数帧号,而非手型动画的 8.8 定点数位移)。 2. **商人按钮初始化表 (`0x6fbbb238`, 20 字节结构体, `0x6fb3f430`)**: - **修理按钮 (`0x6fb3ba70`)**:`nTradeMode = 4` (`+0x0a`),`nButtonFrame = 6` (`+0x0e`),`nCursorFrame = 1` (`+0x10` -> `buysell.dc6` **Frame 1** 铁砧修理锤光标)。 - **购买按钮 (`0x6fb3ba30`)**:`nTradeMode = 2` (`+0x0a`),`nButtonFrame = 2` (`+0x0e`),`nCursorFrame = 3` (`+0x10` -> `buysell.dc6` **Frame 3** 买入金币/手指光标)。 - **出售按钮 (`0x6fb3b9f0`)**:`nTradeMode = 3` (`+0x0a`),`nButtonFrame = 4` (`+0x0e`),`nCursorFrame = 4` (`+0x10` -> `buysell.dc6` **Frame 4** 卖出金币/手指光标)。 - **鉴定卷轴/辨识模式 (`0x6fb36fb7` / `0x6fac6070`)**:`g_nCursorId = 6`,`nCursorFrame = 0` (`buysell.dc6` **Frame 0** 辨识卷轴光标)。 3. **按钮激活与取消 (`0x6fb475e1` / `0x6fb472d0` / `0x6fb3d300`)**: - 点击买/卖/修理按钮释放时 (`0x6fb475e1`):设置 `g_nCursorTradeMode (0x6fbcbc34) = button.nTradeMode`,`g_nCursorId (0x6fbcb854) = 6` (`buysell.dc6`),`g_nCursorFrame (0x6fbcb858) = button.nCursorFrame` (`3` / `4` / `1`),`g_nCursorState (0x6fbcb864) = 7`。 - 右键点击、再次点击同一按钮取消、点击全部修理或关闭面板时:重置为 `idle` 并恢复默认手型光标 (`CursorId = 5` `protate`)。 --- ### 修复方案 1. **离线烘焙 (`scripts/pack-cursor.ts`)**:从 `d2data.mpq` 提取 `data/global/ui/CURSOR/buysell.dc6` 全部 10 帧(`32x40`)烘焙进 `public/ui/cursor.png` 图集及 `src/ui/cursor-meta.ts`。 2. **光标控制器与 HUD 渲染 (`src/ui/cursor.ts`, `src/ui/hud-manager.ts`, `src/ui/world-panels.ts`)**: - 支持交易光标模式 (`'buy' | 'sell' | 'repair'`) 及辨识光标模式 (`'identify'`),精确渲染 `buysell.dc6` 对应帧(Buy=Frame 3, Sell=Frame 4, Repair=Frame 1, Identify=Frame 0)。 - 支持右键取消交易光标模式,关闭面板或切换状态时自动归位。 3. **测试验证**:新增单元测试与 Headless 浏览器端到端验证。
Sign in to join this conversation.
No Label
No Milestone
No project
No Assignees
1 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: troytt/diablo2-web#491
No description provided.