[P1][T15] 实现词缀抽取:alvl 计算、group 冲突排除、rare 3~6 词缀 #104

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

问题

品质判定(T-14)判出 magic / rare 之后,要从 1162 条可生成词缀里选出具体的前后缀。

[!WARNING]
本 issue 是整个 M10 里证据最弱的一块。 反汇编子代理在 D2Common 的 ITEMS 区段里一次 LCG 都没找到(所有 0x6AC690C5 命中都在别的区段),说明词缀 roll 在 D2Game 侧,但本轮预算内没能钉死那个函数。

表列语义是确证的,算法是高可信推断。 实现时必须按下方「待实测确认」一节收敛,不能当成和 T-13 / T-14 同等可信。

金标准数据(确证部分)

候选池筛选

spawnable == 1
version <= 游戏版本
alvl >= level  且(maxlevel != 0 时)alvl <= maxlevel
基底 ItemType ∈ itype1..7(沿 Equiv 链向上)且 ∉ etype1..5(前缀)/ etype1..3(后缀)
rare / crafted 额外要求 rare == 1
权重 = frequency(0 不参与)
classspecific / class / classlevelreq 用于职业专属

列语义见 T-06。

.d2s 格式给出的硬约束(确证)

品质 槽位 位宽
magic 1 前缀 + 1 后缀 各 11 bit
rare / crafted 3 前缀 + 3 后缀(6 组交替) 每组 1 bit 有无 + 11 bit id
rare / crafted 名字 RarePrefix + RareSuffix 各 1 各 8 bit

所以 magic 只可能是 {前缀} / {后缀} / {前缀+后缀} 三种形态 —— 这是格式层面的铁约束,不是推断。

词缀属性取值

每条词缀最多 3 个 mod(modNcode/param/min/max):

value = Rand(item.seed, min, max)     // 闭区间,用 T-23 的 min/max 变体

用物品自己的 seed(不是怪物的)—— 这是 .d2s 只存 32 位 id 就能复原词缀数值的原因。

实现要求

  1. 实现候选池筛选(上面的确证规则)。
  2. 实现 group 互斥:选中一条后,把同 group 的从候选池剔除再选下一条。前后缀各自判重。
  3. magic:按 {前缀}/{后缀}/{两者} 三种形态之一生成。
  4. rare:3 前缀 + 3 后缀上限,实际条数 3~6。
  5. 名字:rare 走 T-07 的 RarePrefix + RareSuffix;magic 走 T-06 的 Name 列(直接是显示文本,不查 tbl)。
  6. 属性值用物品 seed roll。

待实测确认

以下三项没有二进制背书,必须实测收敛后再定稿。建议在实现时就把实测脚本一起写了。

1. alvl 公式【高可信推断】

if (magic_lvl > 0)          alvl = ilvl + magic_lvl     // Misc/Weapons/Armor 的 "magic lvl" 列
else if (qlvl > ilvl / 2)   alvl = ilvl - qlvl / 2
else                        alvl = ilvl
alvl = min(alvl, 99)

这是社区所有词缀计算器在用的式子(戒指 / 护身符 / 珠宝靠 magic lvl 抬高 alvl)。未在 1.13c 二进制定位到。

收敛方法:固定基底 + 固定 ilvl 刷大量 magic,统计出现过的最高级词缀反解 alvl;或改表把某词缀的 level 调到临界点做二分。

2. magic 前后缀数量分布【存疑】

社区共识是「前缀、后缀各掷 50%,都没中则重掷」。未核实。

收敛方法:同 seed 大样本统计三种形态的比例。

3. rare 的词缀条数分布【存疑】

社区说法是「起手若干条 + 逐条概率追加,最终 3~6」,具体分布未证实。

收敛方法:大样本形态统计。

4. group 冲突【高可信推断】

「同 group ���两条词缀不能共存」与表结构自洽,但未在二进制确认。

陷阱

[!CAUTION]
用物品 seed,不是怪物 seed。 掉落链(T-13/T-14/T-24)用怪物 seed,物品创建后的词缀 roll 切到物品自己的 seed。写错会导致同一只怪掉的所有物品词缀相关。

[!WARNING]
itype/etype 匹配必须沿 Equiv 链向上递归。itype1=armo 要能匹配到 tors/helm/shie 等所有子类型。

[!WARNING]
前缀有 etype1..5,后缀只有 etype1..3。

[!NOTE]
crafted(quality 8)走 CubeMain.txt 配方 + 固定词缀数 —— 本里程碑不做(Q2 已决定 CubeMain 留给后续里程碑)。

验收标准

  • 候选池筛选的每个条件都有单测
  • group 互斥生效:构造两条同 group 的词缀,验证不会同时出现
  • magic 只产出 {前缀}/{后缀}/{两者} 三种形态
  • rare 产出 3~6 条,前后缀各不超过 3
  • 属性值用物品 seed,同 seed 可完整复现
  • alvl 公式已实测定夺,结论与实测方法写进代码注释
  • magic 前后缀分布已实测,比例写进注释
  • rare 条数分布已实测,分布写进注释
  • npm run typecheck 0 error
  • npx vitest run 全绿
  • npx tsx scripts/verify-items.ts 新增断言通过

溯源

金标准(数据) 1.13c MPQ data\global\excel\ 下的 MagicPrefix.txt / MagicSuffix.txt / RarePrefix.txt / RareSuffix.txt / Properties.txt / ItemStatCost.txt(本机 /usr/local/google/home/taodao/d2-data,挂载序 d2data → d2exp → Patch_D2,Patch_D2 优先)
参考 .d2s 格式约束来自 D2Common!6FD77180 反汇编(确证)
本 issue 结论强度 ⚠ 表列语义确证,算法为高可信推断 / 存疑 —— D2Game 侧的 roll 函数本轮未定位。必须按「待实测确认」一节收敛

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

## 问题 品质判定(T-14)判出 magic / rare 之后,要从 1162 条可生成词缀里选出具体的前后缀。 > [!WARNING] > **本 issue 是整个 M10 里证据最弱的一块。** 反汇编子代理在 `D2Common` 的 ITEMS 区段里**一次 LCG 都没找到**(所有 `0x6AC690C5` 命中都在别的区段),说明词缀 roll 在 D2Game 侧,但本轮预算内没能钉死那个函数。 > > **表列语义是确证的,算法是高可信推断。** 实现时必须按下方「待实测确认」一节收敛,不能当成和 T-13 / T-14 同等可信。 ## 金标准数据(确证部分) ### 候选池筛选 ``` spawnable == 1 version <= 游戏版本 alvl >= level 且(maxlevel != 0 时)alvl <= maxlevel 基底 ItemType ∈ itype1..7(沿 Equiv 链向上)且 ∉ etype1..5(前缀)/ etype1..3(后缀) rare / crafted 额外要求 rare == 1 权重 = frequency(0 不参与) classspecific / class / classlevelreq 用于职业专属 ``` 列语义见 T-06。 ### `.d2s` 格式给出的硬约束(确证) | 品质 | 槽位 | 位宽 | |---|---|---| | magic | **1 前缀 + 1 后缀** | 各 11 bit | | rare / crafted | **3 前缀 + 3 后缀**(6 组交替) | 每组 1 bit 有无 + 11 bit id | | rare / crafted 名字 | RarePrefix + RareSuffix 各 1 | 各 8 bit | 所以 **magic 只可能是 {前缀} / {后缀} / {前缀+后缀}** 三种形态 —— 这是格式层面的铁约束,不是推断。 ### 词缀属性取值 每条词缀最多 3 个 mod(`modNcode/param/min/max`): ``` value = Rand(item.seed, min, max) // 闭区间,用 T-23 的 min/max 变体 ``` 用**物品自己的 seed**(不是怪物的)—— 这是 `.d2s` 只存 32 位 id 就能复原词缀数值的原因。 ## 实现要求 1. 实现候选池筛选(上面的确证规则)。 2. 实现 `group` 互斥:选中一条后,把**同 group** 的从候选池剔除再选下一条。前后缀各自判重。 3. magic:按 {前缀}/{后缀}/{两者} 三种形态之一生成。 4. rare:3 前缀 + 3 后缀上限,实际条数 3~6。 5. 名字:rare 走 T-07 的 RarePrefix + RareSuffix;magic 走 T-06 的 `Name` 列(直接是显示文本,不查 tbl)。 6. 属性值用**物品 seed** roll。 ## 待实测确认 以下三项**没有二进制背书**,必须实测收敛后再定稿。建议在实现时就把实测脚本一起写了。 ### 1. alvl 公式【高可信推断】 ``` if (magic_lvl > 0) alvl = ilvl + magic_lvl // Misc/Weapons/Armor 的 "magic lvl" 列 else if (qlvl > ilvl / 2) alvl = ilvl - qlvl / 2 else alvl = ilvl alvl = min(alvl, 99) ``` 这是社区所有词缀计算器在用的式子(戒指 / 护身符 / 珠宝靠 `magic lvl` 抬高 alvl)。**未在 1.13c 二进制定位到。** **收敛方法**:固定基底 + 固定 ilvl 刷大量 magic,统计出现过的最高级词缀反解 alvl;或改表把某词缀的 `level` 调到临界点做二分。 ### 2. magic 前后缀数量分布【存疑】 社区共识是「前缀、后缀各掷 50%,都没中则重掷」。**未核实。** **收敛方法**:同 seed 大样本统计三种形态的比例。 ### 3. rare 的词缀条数分布【存疑】 社区说法是「起手若干条 + 逐条概率追加,最终 3~6」,具体分布未证实。 **收敛方法**:大样本形态统计。 ### 4. group 冲突【高可信推断】 「同 group ���两条词缀不能共存」与表结构自洽,但未在二进制确认。 ## 陷阱 > [!CAUTION] > **用物品 seed,不是怪物 seed。** 掉落链(T-13/T-14/T-24)用怪物 seed,物品创建后的词缀 roll 切到物品自己的 seed。写错会导致同一只怪掉的所有物品词缀相关。 > [!WARNING] > `itype`/`etype` 匹配**必须沿 Equiv 链向上递归**。`itype1=armo` 要能匹配到 `tors`/`helm`/`shie` 等所有子类型。 > [!WARNING] > 前缀有 `etype1..5`,后缀只有 `etype1..3`。 > [!NOTE] > crafted(quality 8)走 `CubeMain.txt` 配方 + 固定词缀数 —— **本里程碑不做**(Q2 已决定 CubeMain 留给后续里程碑)。 ## 验收标准 - [ ] 候选池筛选的每个条件都有单测 - [ ] group 互斥生效:构造两条同 group 的词缀,验证不会同时出现 - [ ] magic 只产出 {前缀}/{后缀}/{两者} 三种形态 - [ ] rare 产出 3~6 条,前后缀各不超过 3 - [ ] 属性值用物品 seed,同 seed 可完整复现 - [ ] **alvl 公式已实测定夺**,结论与实测方法写进代码注释 - [ ] **magic 前后缀分布已实测**,比例写进注释 - [ ] **rare 条数分布已实测**,分布写进注释 - [ ] `npm run typecheck` 0 error - [ ] `npx vitest run` 全绿 - [ ] `npx tsx scripts/verify-items.ts` 新增断言通过 --- ### 溯源 | | | |---|---| | 金标准(数据) | 1.13c MPQ `data\global\excel\` 下的 `MagicPrefix.txt` / `MagicSuffix.txt` / `RarePrefix.txt` / `RareSuffix.txt` / `Properties.txt` / `ItemStatCost.txt`(本机 `/usr/local/google/home/taodao/d2-data`,挂载序 d2data → d2exp → Patch_D2,**Patch_D2 优先**) | | 参考 | `.d2s` 格式约束来自 `D2Common!6FD77180` 反汇编(确证) | | 本 issue 结论强度 | ⚠ **表列语义确证,算法为高可信推断 / 存疑** —— D2Game 侧的 roll 函数本轮未定位。必须按「待实测确认」一节收敛 | > [!WARNING] > **D2MOO 是 1.10f,不是本项目的金标准。** 它只能作线索使用。任何涉及常量、列序、整数截断位置或 RNG 消耗次数的结论,都必须回到 1.13c 的表格或 DLL 复核后再落地。
troytt added this to the [M10] 真实物品系统:500 基础物品、1000 词缀、TreasureClassEx 掉落树 milestone 2026-09-18 10:50:51 +00:00
Author
Owner

已完成 alvl 公式、group 互斥、前缀/后缀槽位抽取与稀有名称生成(1.13c D2Game!6FC30580 与 RarePrefix/RareSuffix 配对),合并入 main (commit 390816c)。

已完成 alvl 公式、group 互斥、前缀/后缀槽位抽取与稀有名称生成(1.13c D2Game!6FC30580 与 RarePrefix/RareSuffix 配对),合并入 main (commit 390816c)。
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#104
No description provided.