[P0][T02] 加载 ItemStatCost.txt + Properties.txt:属性层与属性函数 #90

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

问题

词缀、暗金、套装、符文之语、宝石全部通过 Properties.code 引用属性,再由 Properties.statN 落到 ItemStatCost.Stat。不先把这两张表做出来,T-06 / T-09 / T-10 / T-16 / T-18 全都没有落点。

同时 ItemStatCost 的 Save Bits / Save Add 是 .d2s 序列化的必需品(见 T-17)。

金标准数据

ItemStatCost.txt —— 359 行 × 53 列(无分隔行)

Stat | ID | Send Other | Signed | Send Bits | Send Param Bits | UpdateAnimRate | Saved | CSvSigned |
CSvBits | CSvParam | fCallback | fMin | MinAccr | Encode | Add | Multiply | Divide | ValShift |
1.09-Save Bits | 1.09-Save Add | Save Bits | Save Add | Save Param Bits | keepzero | op | op param |
op base | op stat1 | op stat2 | op stat3 | direct | maxstat | itemspecific | damagerelated |
itemevent1 | itemeventfunc1 | itemevent2 | itemeventfunc2 | descpriority | descfunc | descval |
descstrpos | descstrneg | descstr2 | dgrp | dgrpfunc | dgrpval | dgrpstrpos | dgrpstrneg | dgrpstr2 |
stuff | *eol

真实样例:

strength  ID=0 Send Other=1 Send Bits=11 Saved=1 CSvBits=10 fMin=1 MinAccr=1
          Add=125 Multiply=55 Divide=1024 Save Bits=8 Save Add=32
          descpriority=67 descfunc=1 descval=1 descstrpos=ModStr1a descstrneg=ModStr1a
          dgrp=1 dgrpfunc=1 dgrpval=1 dgrpstrpos=Moditem2allattrib stuff=6
energy    ID=1 Send Bits=11 Saved=1 Add=100 Multiply=55 Divide=1024 op=8 op stat1=maxmana
dexterity ID=2 Send Other=1 Send Bits=11 Saved=1 Add=125 Multiply=55 Divide=1024
nextexp   ID=30 Send Bits=32 Divide=1024

关键列:

列 用途
Stat 被 Properties.statN 引用的主键
ID 数值 id,.d2s 属性列表里存的就是它(9 bit)
Save Bits + Save Add 存档位宽与偏移 —— 负数属性靠 Add 平移成无符号
Save Param Bits 带参属性(技能 id 等)的额外位宽
op / op param / op base / op stat1..3 派生运算(如 energy → maxmana)
descpriority / descfunc / descval tooltip 排序与模板
descstrpos / descstrneg / descstr2 string.tbl key(如 ModStr1a),供 T-20
dgrp* 属性分组显示(三围凑齐显示「全属性 +N」)
maxstat / Encode / keepzero / itemspecific / damagerelated 其它语义

Properties.txt —— 268 行 × 36 列(1 行 Expansion)

code | *done | set1|val1|func1|stat1 | set2|…|stat2 | … | set7|…|stat7 |
*desc | *param | *min | *max | *notes | *eol
ac       *done=1 func1=1 stat1=armorclass              *notes=none
ac-miss  *done=1 func1=1 stat1=armorclass_vs_missile   *notes=none
ac-hth   *done=1 func1=1 stat1=armorclass_vs_hth       *notes=none
abs-cold *done=1 func1=1 stat1=item_absorbcold         *notes=none

code 是整个词缀系统的中枢,被这些地方引用:

  • MagicPrefix / MagicSuffix / AutoMagic 的 mod1-3code
  • UniqueItems 的 prop1-12
  • SetItems 的 prop1-9 / aprop1a-5b
  • Sets 的 PCode* / FCode*
  • Runes 的 T1Code1-7
  • Gems 的 *Mod1-3Code

funcN 是赋值函数号:1 = 直接赋 min..max 随机值,14 = 插槽数,15/16/17 = 技能触发,19 = charged 等。

实现要求

  1. 加载两张表,各建主键索引(Stat → row、code → row)。
  2. 实现 resolveProperty(code) → { stats: [{ stat, func, val, set }] },一个 property 最多展开 7 个 stat。
  3. * 开头的列是注释列(*done *desc *param *min *max *notes *eol),游戏不读,解析时跳过。
  4. 把 Save Bits / Save Add / Save Param Bits 暴露给 T-17 的序列化层。
  5. descstrpos 等 tbl key 先存字符串,T-20 再解析。

陷阱

[!CAUTION]
ItemStatCost 的 Save Bits 和 1.09-Save Bits 是两列不同的东西。1.13c 用的是前者。

[!WARNING]
Properties.txt 里有 1 行 Expansion 分隔行要剔除(268 真实行 / 269 原始行)。ItemStatCost.txt 则没有分隔行,359 行全是真实数据。

验收标准

  • ItemStatCost 359 行全部解析,Stat → ID 映射建立
  • Properties 268 行全部解析(剔除 Expansion)
  • 每个 Properties.statN 都能在 ItemStatCost.Stat 里找到(悬空引用数为 0,若非 0 需列出并说明)
  • Save Bits / Save Add 可被 T-17 的序列化层读取
  • npm run typecheck 0 error
  • npx vitest run 全绿
  • npx tsx scripts/verify-items.ts 新增断言通过

溯源

金标准(数据) 1.13c MPQ data\global\excel\ 下的 ItemStatCost.txt / Properties.txt(本机 /usr/local/google/home/taodao/d2-data,挂载序 d2data → d2exp → Patch_D2,Patch_D2 优先)
本 issue 结论强度 本机 1.13c 实测确证(行数、列头、样例均为实跑结果)

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

## 问题 词缀、暗金、套装、符文之语、宝石**全部**通过 `Properties.code` 引用属性,再由 `Properties.statN` 落到 `ItemStatCost.Stat`。不先把这两张表做出来,T-06 / T-09 / T-10 / T-16 / T-18 全都没有落点。 同时 `ItemStatCost` 的 `Save Bits` / `Save Add` 是 `.d2s` 序列化的必需品(见 T-17)。 ## 金标准数据 ### ItemStatCost.txt —— 359 行 × 53 列(**无分隔行**) ``` Stat | ID | Send Other | Signed | Send Bits | Send Param Bits | UpdateAnimRate | Saved | CSvSigned | CSvBits | CSvParam | fCallback | fMin | MinAccr | Encode | Add | Multiply | Divide | ValShift | 1.09-Save Bits | 1.09-Save Add | Save Bits | Save Add | Save Param Bits | keepzero | op | op param | op base | op stat1 | op stat2 | op stat3 | direct | maxstat | itemspecific | damagerelated | itemevent1 | itemeventfunc1 | itemevent2 | itemeventfunc2 | descpriority | descfunc | descval | descstrpos | descstrneg | descstr2 | dgrp | dgrpfunc | dgrpval | dgrpstrpos | dgrpstrneg | dgrpstr2 | stuff | *eol ``` 真实样例: ``` strength ID=0 Send Other=1 Send Bits=11 Saved=1 CSvBits=10 fMin=1 MinAccr=1 Add=125 Multiply=55 Divide=1024 Save Bits=8 Save Add=32 descpriority=67 descfunc=1 descval=1 descstrpos=ModStr1a descstrneg=ModStr1a dgrp=1 dgrpfunc=1 dgrpval=1 dgrpstrpos=Moditem2allattrib stuff=6 energy ID=1 Send Bits=11 Saved=1 Add=100 Multiply=55 Divide=1024 op=8 op stat1=maxmana dexterity ID=2 Send Other=1 Send Bits=11 Saved=1 Add=125 Multiply=55 Divide=1024 nextexp ID=30 Send Bits=32 Divide=1024 ``` 关键列: | 列 | 用途 | |---|---| | `Stat` | 被 `Properties.statN` 引用的主键 | | `ID` | 数值 id,**`.d2s` 属性列表里存的就是它**(9 bit) | | `Save Bits` + `Save Add` | **存档位宽与偏移** —— 负数属性靠 `Add` 平移成无符号 | | `Save Param Bits` | 带参属性(技能 id 等)的额外位宽 | | `op` / `op param` / `op base` / `op stat1..3` | 派生运算(如 energy → maxmana) | | `descpriority` / `descfunc` / `descval` | tooltip 排序与模板 | | `descstrpos` / `descstrneg` / `descstr2` | **string.tbl key**(如 `ModStr1a`),供 T-20 | | `dgrp*` | 属性分组显示(三围凑齐显示「全属性 +N」) | | `maxstat` / `Encode` / `keepzero` / `itemspecific` / `damagerelated` | 其它语义 | ### Properties.txt —— 268 行 × 36 列(1 行 `Expansion`) ``` code | *done | set1|val1|func1|stat1 | set2|…|stat2 | … | set7|…|stat7 | *desc | *param | *min | *max | *notes | *eol ``` ``` ac *done=1 func1=1 stat1=armorclass *notes=none ac-miss *done=1 func1=1 stat1=armorclass_vs_missile *notes=none ac-hth *done=1 func1=1 stat1=armorclass_vs_hth *notes=none abs-cold *done=1 func1=1 stat1=item_absorbcold *notes=none ``` `code` 是**整个词缀系统的中枢**,被这些地方引用: - `MagicPrefix` / `MagicSuffix` / `AutoMagic` 的 `mod1-3code` - `UniqueItems` 的 `prop1-12` - `SetItems` 的 `prop1-9` / `aprop1a-5b` - `Sets` 的 `PCode*` / `FCode*` - `Runes` 的 `T1Code1-7` - `Gems` 的 `*Mod1-3Code` `funcN` 是赋值函数号:1 = 直接赋 `min..max` 随机值,14 = 插槽数,15/16/17 = 技能触发,19 = charged 等。 ## 实现要求 1. 加载两张表,各建主键索引(`Stat → row`、`code → row`)。 2. 实现 `resolveProperty(code) → { stats: [{ stat, func, val, set }] }`,一个 property 最多展开 7 个 stat。 3. **`*` 开头的列是注释列**(`*done` `*desc` `*param` `*min` `*max` `*notes` `*eol`),游戏不读,解析时跳过。 4. 把 `Save Bits` / `Save Add` / `Save Param Bits` 暴露给 T-17 的序列化层。 5. `descstrpos` 等 tbl key 先存字符串,T-20 再解析。 ## 陷阱 > [!CAUTION] > `ItemStatCost` 的 `Save Bits` 和 `1.09-Save Bits` 是**两列不同的东西**。1.13c 用的是前者。 > [!WARNING] > `Properties.txt` 里有 1 行 `Expansion` 分隔行要剔除(268 真实行 / 269 原始行)。`ItemStatCost.txt` 则**没有**分隔行,359 行全是真实数据。 ## 验收标准 - [ ] ItemStatCost 359 行全部解析,`Stat → ID` 映射建立 - [ ] Properties 268 行全部解析(剔除 `Expansion`) - [ ] 每个 `Properties.statN` 都能在 `ItemStatCost.Stat` 里找到(悬空引用数为 0,若非 0 需列出并说明) - [ ] `Save Bits` / `Save Add` 可被 T-17 的序列化层读取 - [ ] `npm run typecheck` 0 error - [ ] `npx vitest run` 全绿 - [ ] `npx tsx scripts/verify-items.ts` 新增断言通过 --- ### 溯源 | | | |---|---| | 金标准(数据) | 1.13c MPQ `data\global\excel\` 下的 `ItemStatCost.txt` / `Properties.txt`(本机 `/usr/local/google/home/taodao/d2-data`,挂载序 d2data → d2exp → Patch_D2,**Patch_D2 优先**) | | 本 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:44 +00:00
Author
Owner

已完成并通过 1.13c MPQ 真实表验证(ItemStatCost 359 行 / Properties 268 行,属性函数与序列化位宽),合并入 main (commit fb79151)。

已完成并通过 1.13c MPQ 真实表验证(ItemStatCost 359 行 / Properties 268 行,属性函数与序列化位宽),合并入 main (commit fb79151)。
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#90
No description provided.