[P0][T12] 实现 auto-TC 运行时生成:armo3-87 / weap3-87 等 100 个虚拟节点 #100

Closed
opened 2026-09-18 10:50:49 +00:00 by troytt · 1 comment
Owner

问题

TreasureClassEx.txt 的 Item 列里有 100 个名字在表中根本不存在 —— weap3 armo3 bow6 mele39 这一类。它们是引擎在载入期动态生成的虚拟 TC。

举个最直接的例子,Act 1 Equip A 的全部内容是:

Act 1 Equip A  (group=1, level=0, Picks=1, NoDrop=空)
  · weap3   prob 7
  · armo3   prob 7

两个叶子都是 auto-TC。不实现这个 issue,Act 1 Equip A 直接断掉,而它是几乎所有装备掉落链的必经节点。 净效果是玩家一件装备都掉不出来。

金标准数据

种子:ItemTypes.TreasureClass = 1 的 5 行

ItemType Code Rarity Equiv
Bow bow 3 miss
Weapon weap 3 —
Melee Weapon mele 3 weap
Any Armor armo 3 —
Amazon Bow abow 1 bow / amaz

实测档位(被 852 行的 Item 列实际引用的)

前缀 档位 数量
weap 3, 6, 9, …, 87 29
armo 3, 6, 9, …, 87 29
bow 3, 6, 9, …, 87 29
mele 3, 6, 9, …, 39 13
abow — 0(未被引用)
合计 100

档位全是 3 的倍数。

基础物品侧的实测范围

表 rarity > 0 的数量 level 范围
Armor 202 / 202 1..85
Weapons 291 / 306 0..86

生成规则

对每个 <Code><N>(N = 3, 6, 9, …):
  桶内成员 = 所有满足下列条件的基础物品:
    · spawnable = 1
    · type 或 type2 沿 ItemTypes.Equiv 链属于 <Code>
    · rarity > 0
    · level <= N        (社区表述为 qlvl ∈ (N-3, N],见下方陷阱)
  权重 = 物品 rarity × ItemTypes.Rarity

实现要求

  1. 在 T-11 加载完成后、T-13 使用之前,扫描 ItemTypes 找出 TreasureClass=1 的 5 个种子。
  2. 对每个种子,按档位生成虚拟 TC 节点,注册进 T-11 的 name → TC 索引(这样 T-13 完全不需要知道它们是虚拟的)。
  3. 类型匹配必须沿 Equiv 链向上递归(复用 T-01 的 isA)—— 例如 mele 的桶要收所有 Equiv 链能走到 mele 的类型。
  4. 权重 = 物品.rarity × ItemTypes.Rarity。
  5. 生成后同样要预计算累计概率前缀和(与 T-11 的普通 TC 一致)。

陷阱

[!CAUTION]
档位的区间语义有两种说法:社区文档(KB #368)说 armoN 收 qlvl ∈ (N-3, N](半开区间,每个物品只进一个桶);另一种理解是 level <= N(累积,低级物品进所有更高的桶)。这两种会产生完全不同的掉落分布,必须用实测定夺 —— 建议构造一个只引用 armo3 的 TC,看能掉出哪些护甲。

[!WARNING]
abow 虽然是 5 个种子之一,但在 852 行里一次都没被引用。仍然要生成(防御未来数据变更),但不要因为它没被引用就以为逻辑错了。

[!WARNING]
Weapons 有 15 件 rarity = 0 的,必须排除在桶外。Armor 则全部 rarity > 0。

[!NOTE]
这 100 个虚拟节点只是 Item 列被引用到的。理论上可以生成更密的档位,但没必要 —— 按实际引用生成即可,多余的是死代码。

验收标准

  • 生成恰好 100 个 auto-TC 节点,名字与 T-11 标记的 100 个悬空引用完全一一对应
  • weap/armo/bow 各 29 档、mele 13 档
  • 每个桶非空(权重和 > 0)
  • 每个桶的成员都满足 spawnable=1 且 rarity>0 且类型沿 Equiv 链匹配
  • armo3 的成员逐个列出并人工核对(低级护甲,应含 cap 等)
  • 区间语义(半开 vs 累积)已实测定夺,结论写进代码注释
  • T-11 的悬空引用未知数降为 0
  • npm run typecheck 0 error
  • npx vitest run 全绿
  • npx tsx scripts/verify-items.ts 新增断言通过

溯源

金标准(数据) 1.13c MPQ data\global\excel\ 下的 ItemTypes.txt / Armor.txt / Weapons.txt / TreasureClassEx.txt(本机 /usr/local/google/home/taodao/d2-data,挂载序 d2data → d2exp → Patch_D2,Patch_D2 优先)
参考 D2Mods KB #368(docs/d2kb/)—— 区间语义的来源,需实测确认
本 issue 结论强度 种子与档位为本机 1.13c 实测确证;区间语义为社区推断,必须实测定夺

[!WARNING]
D2MOO 是 1.10f,不是本项目的金标准。 它只能作线索使用。任何涉及常量、列序、整数截断位置或 RNG 消耗次数的结论,都必须回到 1.13c 的表格或 DLL 复核后再落地。

## 问题 `TreasureClassEx.txt` 的 `Item` 列里有 **100 个名字在表中根本不存在** —— `weap3` `armo3` `bow6` `mele39` 这一类。它们是**引擎在载入期动态生成**的虚拟 TC。 举个最直接的例子,`Act 1 Equip A` 的全部内容是: ``` Act 1 Equip A (group=1, level=0, Picks=1, NoDrop=空) · weap3 prob 7 · armo3 prob 7 ``` 两个叶子都是 auto-TC。**不实现这个 issue,`Act 1 Equip A` 直接断掉,而它是几乎所有装备掉落链的必经节点。** 净效果是玩家一件装备都掉不出来。 ## 金标准数据 ### 种子:`ItemTypes.TreasureClass = 1` 的 5 行 | ItemType | Code | Rarity | Equiv | |---|---|---|---| | Bow | `bow` | 3 | miss | | Weapon | `weap` | 3 | — | | Melee Weapon | `mele` | 3 | weap | | Any Armor | `armo` | 3 | — | | Amazon Bow | `abow` | 1 | bow / amaz | ### 实测档位(被 852 行的 `Item` 列实际引用的) | 前缀 | 档位 | 数量 | |---|---|---:| | `weap` | 3, 6, 9, …, 87 | **29** | | `armo` | 3, 6, 9, …, 87 | **29** | | `bow` | 3, 6, 9, …, 87 | **29** | | `mele` | 3, 6, 9, …, 39 | **13** | | `abow` | — | **0**(未被引用) | | **合计** | | **100** | **档位全是 3 的倍数。** ### 基础物品侧的实测范围 | 表 | `rarity > 0` 的数量 | `level` 范围 | |---|---:|---| | Armor | 202 / 202 | 1..85 | | Weapons | 291 / 306 | 0..86 | ### 生成规则 ``` 对每个 <Code><N>(N = 3, 6, 9, …): 桶内成员 = 所有满足下列条件的基础物品: · spawnable = 1 · type 或 type2 沿 ItemTypes.Equiv 链属于 <Code> · rarity > 0 · level <= N (社区表述为 qlvl ∈ (N-3, N],见下方陷阱) 权重 = 物品 rarity × ItemTypes.Rarity ``` ## 实现要求 1. 在 T-11 加载完成后、T-13 使用之前,扫描 `ItemTypes` 找出 `TreasureClass=1` 的 5 个种子。 2. 对每个种子,按档位生成虚拟 TC 节点,注册进 T-11 的 name → TC 索引(这样 T-13 完全不需要知道它们是虚拟的)。 3. 类型匹配**必须沿 Equiv 链向上递归**(复用 T-01 的 `isA`)—— 例如 `mele` 的桶要收所有 Equiv 链能走到 `mele` 的类型。 4. 权重 = `物品.rarity × ItemTypes.Rarity`。 5. 生成后同样要预计算累计概率前缀和(与 T-11 的普通 TC 一致)。 ## 陷阱 > [!CAUTION] > **档位的区间语义有两种说法**:社区文档(KB #368)说 `armoN` 收 `qlvl ∈ (N-3, N]`(半开区间,每个物品只进一个桶);另一种理解是 `level <= N`(累积,低级物品进所有更高的桶)。**这两种会产生完全不同的掉落分布**,必须用实测定夺 —— 建议构造一个只引用 `armo3` 的 TC,看能掉出哪些护甲。 > [!WARNING] > `abow` 虽然是 5 个种子之一,但**在 852 行里一次都没被引用**。仍然要生成(防御未来数据变更),但不要因为它没被引用就以为逻辑错了。 > [!WARNING] > Weapons 有 **15 件 `rarity = 0`** 的,必须排除在桶外。Armor 则全部 `rarity > 0`。 > [!NOTE] > 这 100 个虚拟节点只是 `Item` 列被引用到的。理论上可以生成更密的档位,但没必要 —— 按实际引用生成即可,多余的是死代码。 ## 验收标准 - [ ] 生成**恰好 100 个** auto-TC 节点,名字与 T-11 标记的 100 个悬空引用**完全一一对应** - [ ] `weap`/`armo`/`bow` 各 29 档、`mele` 13 档 - [ ] 每个桶非空(权重和 > 0) - [ ] 每个桶的成员都满足 `spawnable=1` 且 `rarity>0` 且类型沿 Equiv 链匹配 - [ ] `armo3` 的成员逐个列出并人工核对(低级护甲,应含 `cap` 等) - [ ] 区间语义(半开 vs 累积)已实测定夺,结论写进代码注释 - [ ] T-11 的悬空引用未知数降为 **0** - [ ] `npm run typecheck` 0 error - [ ] `npx vitest run` 全绿 - [ ] `npx tsx scripts/verify-items.ts` 新增断言通过 --- ### 溯源 | | | |---|---| | 金标准(数据) | 1.13c MPQ `data\global\excel\` 下的 `ItemTypes.txt` / `Armor.txt` / `Weapons.txt` / `TreasureClassEx.txt`(本机 `/usr/local/google/home/taodao/d2-data`,挂载序 d2data → d2exp → Patch_D2,**Patch_D2 优先**) | | 参考 | D2Mods KB #368(`docs/d2kb/`)—— 区间语义的来源,**需实测确认** | | 本 issue 结论强度 | 种子与档位为**本机 1.13c 实测确证**;**区间语义为社区推断,必须实测定夺** | > [!WARNING] > **D2MOO 是 1.10f,不是本项目的金标准。** 它只能作线索使用。任何涉及常量、列序、整数截断位置或 RNG 消耗次数的结论,都必须回到 1.13c 的表格或 DLL 复核后再落地。
troytt added this to the [M10] 真实物品系统:500 基础物品、1000 词缀、TreasureClassEx 掉落树 milestone 2026-09-18 10:50:49 +00:00
Author
Owner

已完成 auto-TC 运行时生成(weap3..87/armo3..87/bow3..87/mele3..39 共 100 个虚拟节点生成,rarity 权重过滤与步长3区间划分),合并入 main (commit ce07af1)。

已完成 auto-TC 运行时生成(weap3..87/armo3..87/bow3..87/mele3..39 共 100 个虚拟节点生成,rarity 权重过滤与步长3区间划分),合并入 main (commit ce07af1)。
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#100
No description provided.