Commit Graph

1 Commits

Author SHA1 Message Date
troytt e180520ef5 fix(npc): 补齐城镇 NPC 解析的收尾问题并加上回归护栏 (refs #6)
承接前两个提交。上一版把 type-1 条目接了进来,但收尾有几处缺口,
逐项补齐:

1. 恢复被误删的注释
   `objectsTableTyped` 上方 `/** Same table, through the typed loader ... */`
   在重构中被删掉了,与改动无关,还原。

2. token 大小写统一
   `monstats.txt` 的 `Code` 列拼写不统一——同一批数据里既有 `K9` 又有
   `k9`,`ja` / `6z` / `7i` / `7j` 也是小写。而 `monsterMembers` 的索引
   键一律大写,于是 `map.get(token)` 直接落空,Jamella 和三个受伤的野蛮人
   被以「无美术」的形式烤进了 scene.json。上一版在查表处补了
   `.toUpperCase()`,这里进一步在**产出源头**归一化:同一个怪物不会再以
   两种拼写出现,调用方也不必猜大小写。

3. 空 Place 由静默跳过改为显式报错
   `presetPlaceByAct` 的数组下标**就是** DS1 的 type-1 id,数组必须保持
   稠密。原先的 `if (!place) continue` 一旦遇到空格子,会让其后每一个 NPC
   都错位认领邻居的身份——正是 `22` vs 21 那个缺陷的同一类。实测 1.13c
   五个 act 共 0 个空 Place,所以这条守卫永远不会触发;它的意义是万一数据
   变了要**响亮地失败**,而不是悄悄错号。

4. 补两层回归测试
   - `tests/resolve-type1.test.ts`:清掉两个未使用的 import、补回项目惯用的
     `.ts` 后缀、把边写边想的注释换成「这条用例为什么存在」,并新增一条
     覆盖小写 `Code` 归一化的用例。
   - `tests/packed-npc-art.test.ts`(新增):数据层不变式——凡是进入
     scene.json 的 NPC 必须同时具备 `member` 与 `frame`;同一 token 不得
     以两种拼写出现。这是之前唯一能抓住那 4 个哑火 NPC 的层次,单元测试
     抓不到,因为缺陷在打包脚本的查表里。
     守卫锚定在它真正读取的 `samples/d2-packs/index.json` 上,而不是
     `samples/d2` 目录。

验证(全部本地实跑):
  tsc --noEmit              0 error
  vitest                    23 文件通过 / 1 跳过,429 用例通过 / 2 跳过
  pack:data                 365 张地图
  verify:packs              1302/1302 断言通过
  NPC 实例                  889,未解析 0,token 拼写不一致 0

变异测试:
  - 把 `presets[objectId]` 改成 `presets[0]` → resolve-type1 2 条转红
  - 还原 `map.get(token.toUpperCase())` 为 `map.get(token)` → 全量套件
    仍然全绿,证明此前该修复毫无回归保护;本提交的 packed-npc-art 补上了
    这一层(改动前该用例对现有 pack 报 `K9 -> K9, k9`,重新打包后转绿)。
2026-09-14 15:58:51 +00:00