[P1][T24] 实现 exceptional / elite 基底升级:qf[4] / qf[5] 的两个 1024 判定 #103

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

问题

D2 的装备有三档基底:普通(normcode)/ 精华 exceptional(ubercode)/ 精英 elite(ultracode)。同一个 Cap 在地狱难度可能掉成 xap(War Hat)或 uap(Shako)。

这个机制原计划完全没有覆盖 —— 是反汇编时发现的。不实现的话,高难度永远掉不出精英基底,暗金里那些绑在 ultracode 上的顶级装备(Shako 等)就永远出不来。

金标准数据

T-13 沿 TC 链传播的 6 个品质因子里,[0..3] 是 Magic/Rare/Set/Unique(给 T-14 用),而 [4] 和 [5] 各做一次独立的 1024 判定:

genFlags = 0
if (qf[4] && (Rand(monster.seed) & 0x3FF) < qf[4]) genFlags  = 0x04   // → 升 exceptional
if (qf[5] && (Rand(monster.seed) & 0x3FF) < qf[5]) genFlags |= 0x10   // → 升 elite

注意是 Rand(seed) & 0x3FF(取低 10 位,即 0..1023),不是 Rand(seed, 1024) —— 虽然对 1024 这个 2 的幂来说两者等价,但写法要一致。

genFlags 随后传给物品创建函数 D2Game!6FC31880(pGame, nItemId, nQuality, pMonster, dwGenFlags)。

数值来源:Difficultylevels.txt

难度 UberCodeOddsNormal UberCodeOddsGood UltraCodeOddsNormal UltraCodeOddsGood
Normal 0 0 0 0
Nightmare 10 20 0 0
Hell 20 40 30 40

数值尺度与 1024 判定吻合(40/1024 ≈ 3.9%)。Normal 全 0 → 普通难度永不升级,符合游戏常识。

基底三档的列(Armor.txt / Weapons.txt)

normcode | ubercode | ultracode
cap: normcode=cap ubercode=xap ultracode=uap
skp: ubercode=xkp ultracode=ukp
ba4: NightmareUpgrade=xxx HellUpgrade=xxx    ← xxx 表示无

实现要求

  1. 新加载 data\global\excel\Difficultylevels.txt,取 UberCodeOdds* / UltraCodeOdds* 四列。
  2. 在 T-13 的展开过程中,对 qf[4] / qf[5] 各做一次判定,产出 genFlags。
  3. 物品创建时按 genFlags:0x04 → 用 ubercode 替换基底,0x10 → 用 ultracode 替换。
  4. ubercode/ultracode 为空或为 xxx 时不升级(保持原基底)。
  5. 升级后的基底有自己的 level(qlvl)、rarity、需求等,T-14 的品质判定要用升级后的 qlvl。
  6. ItemRatio 的 Uber 列(=1)就是给这些升级后的基底用的 —— T-14 选行时要据此判断。

陷阱

[!CAUTION]
两个判定各消耗一次 RNG,且无条件按顺序执行(只要 qf[N] 非 0)。如果为了「优化」跳过其中一个,后续所有掷骰的序列都会错位,对拍直接失败。

[!WARNING]
genFlags 的 exceptional 用 =(赋值)而 elite 用 |=(或等)—— 这是反汇编里的实际写法。两个标志可以同时置位,此时以 elite 为准(需实测确认优先级)。

[!WARNING]
升级后要用新基底的 qlvl 去做 T-14 的品质判定,不是原基底的。同时 ItemRatio 要切到 Uber=1 那一行。这两处很容易漏。

[!NOTE]
NightmareUpgrade / HellUpgrade 列是另一套机制(商店 / 赌博用),与本 issue 的 ubercode/ultracode 不是一回事,不要混用。

验收标准

  • Difficultylevels.txt 的四列加载正确,三个难度的值与上表一致
  • Normal 难度下 genFlags 恒为 0(因为 odds 全 0)
  • Hell 难度下大样本统计,exceptional / elite 的出现率与 odds/1024 吻合
  • ubercode 为空或 xxx 时不升级,不报错
  • 升级后 T-14 切换到 ItemRatio 的 Uber=1 行,且用新 qlvl
  • RNG 消耗次数:两个判定各消耗一次,与原版对拍时序列不错位
  • 【实测项】Normal 难度把 UberCodeOdds* 改成 1024,验证普通基底 100% 变成 exceptional

待实测确认

[!IMPORTANT]
genFlags 的 0x04 / 0x10 对应 exceptional / elite 升级这一点是高可信推断,不是确证 —— 依据是 Difficultylevels.txt 里 UberCodeOdds/UltraCodeOdds 的命名与数值尺度吻合。

收敛方法:Normal 难度把 UberCodeOddsNormal/Good 改成 1024,跑原版看普通基底是否 100% 变成异常品。请在实现时一并做掉,并把结论回填到本 issue。


溯源

金标准(数据) 1.13c MPQ data\global\excel\ 下的 Difficultylevels.txt / Armor.txt / Weapons.txt / ItemRatio.txt(本机 /usr/local/google/home/taodao/d2-data,挂载序 d2data → d2exp → Patch_D2,Patch_D2 优先)
金标准(算法) 1.13c 反汇编:D2Game!6FC32380 / D2Game!6FC31880(objdump -d,D2Common 基址 0x6FD50000、D2Game 0x6FC10000)
本 issue 结论强度 1024 判定本身逐指令确证;「0x04/0x10 = exceptional/elite」为高可信推断,需按上方方法实测

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

## 问题 D2 的装备有三档基底:普通(`normcode`)/ 精华 exceptional(`ubercode`)/ 精英 elite(`ultracode`)。同一个 `Cap` 在地狱难度可能掉成 `xap`(War Hat)或 `uap`(Shako)。 这个机制**原计划完全没有覆盖** —— 是反汇编时发现的。不实现的话,高难度永远掉不出精英基底,暗金里那些绑在 `ultracode` 上的顶级装备(Shako 等)就永远出不来。 ## 金标准数据 T-13 沿 TC 链传播的 6 个品质因子里,`[0..3]` 是 Magic/Rare/Set/Unique(给 T-14 用),而 **`[4]` 和 `[5]` 各做一次独立的 1024 判定**: ``` genFlags = 0 if (qf[4] && (Rand(monster.seed) & 0x3FF) < qf[4]) genFlags = 0x04 // → 升 exceptional if (qf[5] && (Rand(monster.seed) & 0x3FF) < qf[5]) genFlags |= 0x10 // → 升 elite ``` 注意是 `Rand(seed) & 0x3FF`(取低 10 位,即 0..1023),不是 `Rand(seed, 1024)` —— 虽然对 1024 这个 2 的幂来说两者等价,但写法要一致。 `genFlags` 随后传给物品创建函数 `D2Game!6FC31880(pGame, nItemId, nQuality, pMonster, dwGenFlags)`。 ### 数值来源:Difficultylevels.txt | 难度 | UberCodeOddsNormal | UberCodeOddsGood | UltraCodeOddsNormal | UltraCodeOddsGood | |---|---:|---:|---:|---:| | Normal | 0 | 0 | 0 | 0 | | Nightmare | 10 | 20 | 0 | 0 | | Hell | 20 | 40 | 30 | 40 | 数值尺度与 1024 判定吻合(`40/1024 ≈ 3.9%`)。Normal 全 0 → 普通难度永不升级,符合游戏常识。 ### 基底三档的列(Armor.txt / Weapons.txt) ``` normcode | ubercode | ultracode ``` ``` cap: normcode=cap ubercode=xap ultracode=uap skp: ubercode=xkp ultracode=ukp ba4: NightmareUpgrade=xxx HellUpgrade=xxx ← xxx 表示无 ``` ## 实现要求 1. 新加载 `data\global\excel\Difficultylevels.txt`,取 `UberCodeOdds*` / `UltraCodeOdds*` 四列。 2. 在 T-13 的展开过程中,对 `qf[4]` / `qf[5]` 各做一次判定,产出 `genFlags`。 3. 物品创建时按 `genFlags`:`0x04` → 用 `ubercode` 替换基底,`0x10` → 用 `ultracode` 替换。 4. `ubercode`/`ultracode` 为空或为 `xxx` 时**不升级**(保持原基底)。 5. 升级后的基底有自己的 `level`(qlvl)、`rarity`、需求等,T-14 的品质判定要用**升级后**的 qlvl。 6. `ItemRatio` 的 `Uber` 列(=1)就是给这些升级后的基底用的 —— T-14 选行时要据此判断。 ## 陷阱 > [!CAUTION] > **两个判定各消耗一次 RNG,且无条件按顺序执行**(只要 `qf[N]` 非 0)。如果为了「优化」跳过其中一个,后续所有掷骰的序列都会错位,对拍直接失败。 > [!WARNING] > `genFlags` 的 exceptional 用 **`=`**(赋值)而 elite 用 **`|=`**(或等)—— 这是反汇编里的实际写法。两个标志可以同时置位,此时以 elite 为准(需实测确认优先级)。 > [!WARNING] > **升级后要用新基底的 qlvl 去做 T-14 的品质判定**,不是原基底的。同时 `ItemRatio` 要切到 `Uber=1` 那一行。这两处很容易漏。 > [!NOTE] > `NightmareUpgrade` / `HellUpgrade` 列是另一套机制(商店 / 赌博用),**与本 issue 的 `ubercode`/`ultracode` 不是一回事**,不要混用。 ## 验收标准 - [ ] `Difficultylevels.txt` 的四列加载正确,三个难度的值与上表一致 - [ ] Normal 难度下 `genFlags` 恒为 0(因为 odds 全 0) - [ ] Hell 难度下大样本统计,exceptional / elite 的出现率与 `odds/1024` 吻合 - [ ] `ubercode` 为空或 `xxx` 时不升级,不报错 - [ ] 升级后 T-14 切换到 `ItemRatio` 的 `Uber=1` 行,且用新 qlvl - [ ] **RNG 消耗次数**:两个判定各消耗一次,与原版对拍时序列不错位 - [ ] 【实测项】Normal 难度把 `UberCodeOdds*` 改成 1024,验证普通基底 100% 变成 exceptional ## 待实测确认 > [!IMPORTANT] > `genFlags` 的 `0x04` / `0x10` **对应 exceptional / elite 升级**这一点是**高可信推断**,不是确证 —— 依据是 `Difficultylevels.txt` 里 `UberCodeOdds`/`UltraCodeOdds` 的命名与数值尺度吻合。 > > 收敛方法:Normal 难度把 `UberCodeOddsNormal`/`Good` 改成 1024,跑原版看普通基底是否 100% 变成异常品。请在实现时一并做掉,并把结论回填到本 issue。 --- ### 溯源 | | | |---|---| | 金标准(数据) | 1.13c MPQ `data\global\excel\` 下的 `Difficultylevels.txt` / `Armor.txt` / `Weapons.txt` / `ItemRatio.txt`(本机 `/usr/local/google/home/taodao/d2-data`,挂载序 d2data → d2exp → Patch_D2,**Patch_D2 优先**) | | 金标准(算法) | 1.13c 反汇编:`D2Game!6FC32380` / `D2Game!6FC31880`(`objdump -d`,D2Common 基址 `0x6FD50000`、D2Game `0x6FC10000`) | | 本 issue 结论强度 | 1024 判定本身**逐指令确证**;**「0x04/0x10 = exceptional/elite」为高可信推断,需按上方方法实测** | > [!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

已完成并通过 1.13c Difficultylevels.txt 与 qf[4]/qf[5] 1024 判定实测验证(ubercode/ultracode 基底升级,isUber 标记与新 qlvl 继承),合并入 main (commit 94be8ce)。

已完成并通过 1.13c Difficultylevels.txt 与 qf[4]/qf[5] 1024 判定实测验证(ubercode/ultracode 基底升级,isUber 标记与新 qlvl 继承),合并入 main (commit 94be8ce)。
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#103
No description provided.