feat(ui): 掉落物转 UI 背包/装备模型桥接、中文化词缀 Tooltip 与拾取闭环 (Drop Item to UiInventoryItem Bridge, Bilingual Tooltip & Pickup Loop) #407

Closed
opened 2026-09-24 03:22:49 +00:00 by troytt · 1 comment
Owner

问题背景与现状分析

目前在 src/game/drop-pipeline.ts 与 src/ui/inventory.ts 之间存在核心数据契约断层:

  1. executeDropPipeline 产出的对象是底层 Item(来自 src/game/items.ts):其 quality 是数字枚举 1..9(如 ItemQuality.MAGIC = 4),stats 是 Record<string, number> 字典,且不包含 invFile、nameZh、baseNameZh、allowedSlots 等 UI 字段。
  2. 而场景拾取逻辑(act-scene.ts:2334 this.hudManager.inventory.autoPlaceInGrid(item.item))直接把地面物品内部的 item 塞进了 UI 背包 InventoryPanel!
  3. InventoryPanel 渲染背包图标依赖 item.invFile 查找 BAKED_UI_MANIFEST.itemRects,渲染悬浮窗 Tooltip 依赖 item.stats 为 { text, color }[] 数组,装备穿戴依赖 item.allowedSlots。若直接塞入原始 Item,会导致捡起打怪掉落的装备后背包内无贴图显示、鼠标悬停崩溃或无词缀显示、且无法穿戴到角色装备栏!

原版 Diablo II v1.13c 核心机制规范(Ground Truth)

1. Item → UiInventoryItem 全属性无损转换器

  • 贴图解析 (invFile):根据物品 code 从 Weapons.txt / Armor.txt / Misc.txt 解析 invfile(暗金/套装优先匹配 uniqueinvfile / setinvfile 并回退基础 invfile),确保在 BAKED_UI_MANIFEST.itemRects 中 100% 命中原版 DC6 背包图标;地面翻转图标同步命中 flippyfile。
  • 可穿戴槽位 (allowedSlots):根据 ItemTypes.txt 的 BodyLoc1 / BodyLoc2 及类型继承树(weap, shld, tors, helm, glov, boot, belt, ring, amul)精确映射至 EquipSlotId[](helm, amulet, weapon1, weapon2, armor, gloves, ring1, belt, ring2, boots)。
  • 中文化名称与词缀 Tooltip (formatItemTooltip & tooltip-i18n.ts):
    • 完整转换普通/超强/低劣底材名、魔法前后缀名(如「锋利的 短剑 之 急速」)、稀有双词缀名、绿色套装名、暗金专属名至 nameZh 与 baseNameZh。
    • 将武器伤害(mindam~maxdam / 双手伤害)、防具防御(defense)、耐久度(durability)、需求属性(reqStr, reqLevel)以及 rolledProps 魔法/稀有/暗金/套装词条完整格式化为带颜色码的 UiInventoryItem.stats 数组。

2. 拾取分流与背包/腰带/金币闭环

  • 金币拾取:点击地面金币堆走近拾取后,直接累加至 hudManager.inventory.gold 并移除地面实体。
  • 装备与道具拾取:点击地面装备/药水/卷轴/符文/宝石(或按住 Alt 点击浮动标签),角色自动寻路走近(<= 48px)并将其转换为 UiInventoryItem 放入背包 10×4 网格;若背包空间不足,严格触发原版 triggerFlippyBounce 抛起弹跳动画与「包裹已满」反馈。

改造与验收标准

  1. 实现并导出 itemToUiInventoryItem(item: Item, dropTables?: DropTables): UiInventoryItem 桥接转换器。
  2. 打怪掉落的任意品质物品(白装、蓝装、黄装、绿装、暗金、药水、卷轴、符文、宝石)在地面显示正确的 flippy 图标与中文 Alt 标签。
  3. 点击拾取进入背包后,背包网格内 100% 渲染正确的原版 inv*.dc6 物品贴图,鼠标悬停展示完整的暗黑 2 原版中文属性/词缀悬浮窗(Tooltip),且支持拖拽或右键穿戴到对应装备栏。
  4. 自动化构建与单测 100% 通过。
## 问题背景与现状分析 目前在 [`src/game/drop-pipeline.ts`](https://git.projectdiablo2.cn/troytt/diablo2-web/src/branch/main/src/game/drop-pipeline.ts) 与 [`src/ui/inventory.ts`](https://git.projectdiablo2.cn/troytt/diablo2-web/src/branch/main/src/ui/inventory.ts) 之间存在核心数据契约断层: 1. `executeDropPipeline` 产出的对象是底层 `Item`(来自 `src/game/items.ts`):其 `quality` 是数字枚举 `1..9`(如 `ItemQuality.MAGIC = 4`),`stats` 是 `Record<string, number>` 字典,且不包含 `invFile`、`nameZh`、`baseNameZh`、`allowedSlots` 等 UI 字段。 2. 而场景拾取逻辑(`act-scene.ts:2334` `this.hudManager.inventory.autoPlaceInGrid(item.item)`)直接把地面物品内部的 `item` 塞进了 UI 背包 `InventoryPanel`! 3. `InventoryPanel` 渲染背包图标依赖 `item.invFile` 查找 `BAKED_UI_MANIFEST.itemRects`,渲染悬浮窗 Tooltip 依赖 `item.stats` 为 `{ text, color }[]` 数组,装备穿戴依赖 `item.allowedSlots`。若直接塞入原始 `Item`,会导致捡起打怪掉落的装备后**背包内无贴图显示、鼠标悬停崩溃或无词缀显示、且无法穿戴到角色装备栏**! --- ## 原版 Diablo II v1.13c 核心机制规范(Ground Truth) ### 1. `Item` → `UiInventoryItem` 全属性无损转换器 - **贴图解析 (`invFile`)**:根据物品 `code` 从 `Weapons.txt` / `Armor.txt` / `Misc.txt` 解析 `invfile`(暗金/套装优先匹配 `uniqueinvfile` / `setinvfile` 并回退基础 `invfile`),确保在 `BAKED_UI_MANIFEST.itemRects` 中 100% 命中原版 DC6 背包图标;地面翻转图标同步命中 `flippyfile`。 - **可穿戴槽位 (`allowedSlots`)**:根据 `ItemTypes.txt` 的 `BodyLoc1` / `BodyLoc2` 及类型继承树(`weap`, `shld`, `tors`, `helm`, `glov`, `boot`, `belt`, `ring`, `amul`)精确映射至 `EquipSlotId[]`(`helm`, `amulet`, `weapon1`, `weapon2`, `armor`, `gloves`, `ring1`, `belt`, `ring2`, `boots`)。 - **中文化名称与词缀 Tooltip (`formatItemTooltip` & `tooltip-i18n.ts`)**: - 完整转换普通/超强/低劣底材名、魔法前后缀名(如「锋利的 短剑 之 急速」)、稀有双词缀名、绿色套装名、暗金专属名至 `nameZh` 与 `baseNameZh`。 - 将武器伤害(`mindam`~`maxdam` / 双手伤害)、防具防御(`defense`)、耐久度(`durability`)、需求属性(`reqStr`, `reqLevel`)以及 `rolledProps` 魔法/稀有/暗金/套装词条完整格式化为带颜色码的 `UiInventoryItem.stats` 数组。 ### 2. 拾取分流与背包/腰带/金币闭环 - **金币拾取**:点击地面金币堆走近拾取后,直接累加至 `hudManager.inventory.gold` 并移除地面实体。 - **装备与道具拾取**:点击地面装备/药水/卷轴/符文/宝石(或按住 Alt 点击浮动标签),角色自动寻路走近(`<= 48px`)并将其转换为 `UiInventoryItem` 放入背包 `10×4` 网格;若背包空间不足,严格触发原版 `triggerFlippyBounce` 抛起弹跳动画与「包裹已满」反馈。 --- ## 改造与验收标准 1. 实现并导出 `itemToUiInventoryItem(item: Item, dropTables?: DropTables): UiInventoryItem` 桥接转换器。 2. 打怪掉落的任意品质物品(白装、蓝装、黄装、绿装、暗金、药水、卷轴、符文、宝石)在地面显示正确的 `flippy` 图标与中文 Alt 标签。 3. 点击拾取进入背包后,背包网格内 100% 渲染正确的原版 `inv*.dc6` 物品贴图,鼠标悬停展示完整的暗黑 2 原版中文属性/词缀悬浮窗(Tooltip),且支持拖拽或右键穿戴到对应装备栏。 4. 自动化构建与单测 100% 通过。
troytt added this to the 实现打怪掉落物品 milestone 2026-09-24 03:22:49 +00:00
Author
Owner

Milestone M11.4 (Issue #407) Gate 1 Verification: 100% PASS

All 5 Gate subagents voted unanimously APPROVE / CLEAN:

  • Reviewer 1: APPROVE (itemToUiInventoryItem bridge, 100% invFile resolution against baked manifest, allowedSlots mapping via BodyLoc1/2, bilingual localized tooltips)
  • Reviewer 2: APPROVE (Normal & Telekinesis pickup loop integration in act-scene.ts, gold clamping to PLAYER_GOLD_CAP, inventory full refusal feedback)
  • Challenger 1: APPROVE (31/31 adversarial assertions passed across all 7 item qualities, non-wearables, paperdoll slot equipping with zero TypeError, full 10x4 inventory refusal bounce)
  • Challenger 2: APPROVE (28/28 new tests, 143/143 related tests passed, clean typecheck, clean production build)
  • Forensic Auditor: CLEAN (Strict worktree isolation, main repository 100% clean, zero leaks)

Merged to main at commit b5754c0 and pushed to origin/main.
Worktree .worktrees/issue-407 pruned cleanly.

### Milestone M11.4 (Issue #407) Gate 1 Verification: 100% PASS All 5 Gate subagents voted unanimously **APPROVE** / **CLEAN**: - **Reviewer 1**: APPROVE (`itemToUiInventoryItem` bridge, 100% `invFile` resolution against baked manifest, `allowedSlots` mapping via BodyLoc1/2, bilingual localized tooltips) - **Reviewer 2**: APPROVE (Normal & Telekinesis pickup loop integration in `act-scene.ts`, gold clamping to `PLAYER_GOLD_CAP`, inventory full refusal feedback) - **Challenger 1**: APPROVE (31/31 adversarial assertions passed across all 7 item qualities, non-wearables, paperdoll slot equipping with zero `TypeError`, full 10x4 inventory refusal bounce) - **Challenger 2**: APPROVE (28/28 new tests, 143/143 related tests passed, clean typecheck, clean production build) - **Forensic Auditor**: CLEAN (Strict worktree isolation, main repository 100% clean, zero leaks) Merged to `main` at commit `b5754c0` and pushed to `origin/main`. Worktree `.worktrees/issue-407` pruned cleanly.
Sign in to join this conversation.
No Label
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#407
No description provided.