[P1][T03] 加载 Armor.txt → ItemBase(202 行 × 164 列) #91

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

问题

生产路径现在用的是 DEMO_BASES 里手写的 3 件物品。真实护甲有 202 件。

现有的 itemBaseFromRow 只映射了几列,需要按真实表逐列核对。

金标准数据

202 真实行(203 原始行 − 1 行 Expansion)× 164 列。

完整列头:

name | version | compactsave | rarity | spawnable | minac | maxac | absorbs | speed | reqstr |
block | durability | nodurability | level | levelreq | cost | gamble cost | code | namestr |
magic lvl | auto prefix | alternategfx | OpenBetaGfx | normcode | ubercode | ultracode |
spelloffset | component | invwidth | invheight | hasinv | gemsockets | gemapplytype | flippyfile |
invfile | uniqueinvfile | setinvfile | rArm | lArm | Torso | Legs | rSPad | lSPad | useable |
throwable | stackable | minstack | maxstack | type | type2 | dropsound | dropsfxframe | usesound |
unique | transparent | transtbl | quivered | lightradius | belt | quest | missiletype | durwarning |
qntwarning | mindam | maxdam | StrBonus | DexBonus | gemoffset | bitfield1 |
<商人库存 17 组 × 5 列> |
Source Art | Game Art | Transform | InvTrans | SkipName | NightmareUpgrade | HellUpgrade |
mindam | maxdam | nameable

真实样例:

row0   name=Cap/hat  code=cap namestr=cap rarity=1 spawnable=1 level=1 levelreq=0
       minac=3 maxac=5 reqstr=0 durability=12 cost=64 gamble cost=3016 type=helm
       invwidth=2 invheight=2 gemsockets=2 gemapplytype=1
       normcode=cap ubercode=xap ultracode=uap NightmareUpgrade=skp HellUpgrade=ghm
row1   name=Skull Cap code=skp namestr=skp rarity=4 level=5 minac=8 maxac=11 reqstr=15
       durability=18 cost=441 gamble cost=5551 type=helm ubercode=xkp ultracode=ukp
row100 name=Assault Helmet code=ba4 namestr=ba4 version=100 rarity=2 level=20 levelreq=15
       minac=30 maxac=35 reqstr=55 durability=50 cost=3420 type=phlm gemsockets=3
       NightmareUpgrade=xxx HellUpgrade=xxx

统计:spawnable=1 202/202;rarity 范围 1..4;level(qlvl)范围 1..85。

掉落相关的关键列:

列 用途
code 全局主键,TC 叶子引用的就是它
namestr string.tbl key(T-20),202/202 全可解析
version 0 = Classic,100 = LoD
spawnable 是否可自然生成
rarity auto-TC 桶内权重(T-12)
level qlvl,决定进哪个 armoN 桶,也是品质判定的减数基准(T-14)
levelreq 穿戴等级需求
type / type2 → ItemTypes.Code
minac / maxac / reqstr / durability / block 基础属性
gemsockets 最大插槽(再被 ItemTypes.MaxSock1/25/40 按 ilvl 截断)
magic lvl / auto prefix 影响 alvl(T-15)
normcode / ubercode / ultracode 普通 / 精华 / 精英三档(T-24 要用)
NightmareUpgrade / HellUpgrade xxx = 无
invwidth / invheight 背包格子
Transform / InvTrans 染色

实现要求

  1. 加载 data\global\excel\Armor.txt,剔除 Expansion 行。
  2. 按上表逐列映射到 ItemBase(结构以 T-17 冻结的为准)。
  3. 建 code → ItemBase 索引,与 Weapons / Misc 合并成一张全局物品码表。
  4. type / type2 解析成 ItemTypes 引用(T-01 的产物)。

陷阱

[!CAUTION]
mindam 和 maxdam 在本表出现了两次 —— 索引 63/64 和索引 161/162。header.indexOf('mindam') 只会拿到第一组,而第一组对护甲恒为 0。如果要读伤害(少数护甲如刺甲有),必须用索引而非列名,或显式取第二组。

[!WARNING]
中间夹着 17 组 × 5 列的商人库存(CharsiMin/Max/MagicMin/MagicMax/MagicLvl,然后 Gheed / Akara / Fara / Lysander / Drognan / Hralti / Alkor / Ormus / Elzix / Asheara / Cain / Halbu / Jamella / Larzuk / Malah / Drehya)。注意 HratliMagicLvl 的拼写与其它组不一致。本里程碑用不到,但解析时要正确跳过。

[!NOTE]
name 列是设计者内部备注,不是显示名。显示名一律走 namestr → string.tbl(T-20)。

验收标准

  • 202 行全部解析成 ItemBase,0 个失败
  • code 无重复
  • rarity 全部落在 [1,4]、level 全部落在 [1,85]
  • cap 的映射逐列核对:level=1 minac=3 maxac=5 reqstr=0 durability=12 gemsockets=2 ubercode=xap ultracode=uap
  • type / type2 全部能在 ItemTypes 里解析到
  • npm run typecheck 0 error
  • npx vitest run 全绿
  • npx tsx scripts/verify-items.ts 新增断言通过

溯源

金标准(数据) 1.13c MPQ data\global\excel\ 下的 Armor.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 复核后再落地。

## 问题 生产路径现在用的是 [`DEMO_BASES`](https://git.projectdiablo2.cn/troytt/diablo2-web/src/branch/main/src/game/demo-data.ts) 里手写的 **3 件**物品。真实护甲有 **202** 件。 现有的 `itemBaseFromRow` 只映射了几列,需要按真实表逐列核对。 ## 金标准数据 **202 真实行**(203 原始行 − 1 行 `Expansion`)× **164 列**。 完整列头: ``` name | version | compactsave | rarity | spawnable | minac | maxac | absorbs | speed | reqstr | block | durability | nodurability | level | levelreq | cost | gamble cost | code | namestr | magic lvl | auto prefix | alternategfx | OpenBetaGfx | normcode | ubercode | ultracode | spelloffset | component | invwidth | invheight | hasinv | gemsockets | gemapplytype | flippyfile | invfile | uniqueinvfile | setinvfile | rArm | lArm | Torso | Legs | rSPad | lSPad | useable | throwable | stackable | minstack | maxstack | type | type2 | dropsound | dropsfxframe | usesound | unique | transparent | transtbl | quivered | lightradius | belt | quest | missiletype | durwarning | qntwarning | mindam | maxdam | StrBonus | DexBonus | gemoffset | bitfield1 | <商人库存 17 组 × 5 列> | Source Art | Game Art | Transform | InvTrans | SkipName | NightmareUpgrade | HellUpgrade | mindam | maxdam | nameable ``` 真实样例: ``` row0 name=Cap/hat code=cap namestr=cap rarity=1 spawnable=1 level=1 levelreq=0 minac=3 maxac=5 reqstr=0 durability=12 cost=64 gamble cost=3016 type=helm invwidth=2 invheight=2 gemsockets=2 gemapplytype=1 normcode=cap ubercode=xap ultracode=uap NightmareUpgrade=skp HellUpgrade=ghm row1 name=Skull Cap code=skp namestr=skp rarity=4 level=5 minac=8 maxac=11 reqstr=15 durability=18 cost=441 gamble cost=5551 type=helm ubercode=xkp ultracode=ukp row100 name=Assault Helmet code=ba4 namestr=ba4 version=100 rarity=2 level=20 levelreq=15 minac=30 maxac=35 reqstr=55 durability=50 cost=3420 type=phlm gemsockets=3 NightmareUpgrade=xxx HellUpgrade=xxx ``` 统计:`spawnable=1` **202/202**;`rarity` 范围 **1..4**;`level`(qlvl)范围 **1..85**。 掉落相关的关键列: | 列 | 用途 | |---|---| | `code` | 全局主键,TC 叶子引用的就是它 | | `namestr` | **string.tbl key**(T-20),202/202 全可解析 | | `version` | 0 = Classic,100 = LoD | | `spawnable` | 是否可自然生成 | | `rarity` | **auto-TC 桶内权重**(T-12) | | `level` | **qlvl**,决定进哪个 `armoN` 桶,也是品质判定的减数基准(T-14) | | `levelreq` | 穿戴等级需求 | | `type` / `type2` | → `ItemTypes.Code` | | `minac` / `maxac` / `reqstr` / `durability` / `block` | 基础属性 | | `gemsockets` | 最大插槽(再被 `ItemTypes.MaxSock1/25/40` 按 ilvl 截断) | | `magic lvl` / `auto prefix` | 影响 alvl(T-15) | | `normcode` / `ubercode` / `ultracode` | 普通 / 精华 / 精英三档(T-24 要用) | | `NightmareUpgrade` / `HellUpgrade` | `xxx` = 无 | | `invwidth` / `invheight` | 背包格子 | | `Transform` / `InvTrans` | 染色 | ## 实现要求 1. 加载 `data\global\excel\Armor.txt`,剔除 `Expansion` 行。 2. 按上表逐列映射到 `ItemBase`(结构以 T-17 冻结的为准)。 3. 建 `code → ItemBase` 索引,与 Weapons / Misc 合并成一张全局物品码表。 4. `type` / `type2` 解析成 `ItemTypes` 引用(T-01 的产物)。 ## 陷阱 > [!CAUTION] > **`mindam` 和 `maxdam` 在本表出现了两次** —— 索引 63/64 和索引 161/162。`header.indexOf('mindam')` 只会拿到第一组,而第一组对护甲恒为 0。如果要读伤害(少数护甲如刺甲有),必须用索引而非列名,或显式取第二组。 > [!WARNING] > 中间夹着 **17 组 × 5 列的商人库存**(CharsiMin/Max/MagicMin/MagicMax/MagicLvl,然后 Gheed / Akara / Fara / Lysander / Drognan / Hralti / Alkor / Ormus / Elzix / Asheara / Cain / Halbu / Jamella / Larzuk / Malah / Drehya)。注意 `HratliMagicLvl` 的拼写与其它组不一致。本里程碑用不到,但解析时要正确跳过。 > [!NOTE] > `name` 列是**设计者内部备注,不是显示名**。显示名一律走 `namestr` → string.tbl(T-20)。 ## 验收标准 - [ ] 202 行全部解析成 `ItemBase`,0 个失败 - [ ] `code` 无重复 - [ ] `rarity` 全部落在 `[1,4]`、`level` 全部落在 `[1,85]` - [ ] `cap` 的映射逐列核对:`level=1 minac=3 maxac=5 reqstr=0 durability=12 gemsockets=2 ubercode=xap ultracode=uap` - [ ] `type` / `type2` 全部能在 ItemTypes 里解析到 - [ ] `npm run typecheck` 0 error - [ ] `npx vitest run` 全绿 - [ ] `npx tsx scripts/verify-items.ts` 新增断言通过 --- ### 溯源 | | | |---|---| | 金标准(数据) | 1.13c MPQ `data\global\excel\` 下的 `Armor.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:45 +00:00
Author
Owner

已完成并通过 1.13c MPQ 真实表验证(202 件真实护甲,全属性映射与三阶基底链接),合并入 main (commit 193c120)。

已完成并通过 1.13c MPQ 真实表验证(202 件真实护甲,全属性映射与三阶基底链接),合并入 main (commit 193c120)。
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#91
No description provided.