feat(map-gen/maze): 补齐迷宫楼梯表 MAZE_LEVEL_TYPE_PROFILES,消除 215 处兜底楼梯 #37

Closed
opened 2026-09-16 10:40:15 +00:00 by troytt · 0 comments
Owner

背景说明

M8「世界连通」(#23)已经把 Levels.txt 的 Vis0..7 / Warp0..7 提炼成了一张全局世界图,并且发现 DS1 的 type = 10 / 11 特殊瓦片的 style 字段就是 Warp0..7 的槽位编号——也就是说,原版美术资源自己就标注了每一处楼梯口的精确坐标。烘焙管线(scripts/pack-act-assets.ts 的 buildSceneLinks)因此按五遍优先级定位每一条出入口:

  1. findWarpTiles(ds1) —— 美术瓦片标注,标记为 source: 'tile',这是真实坐标;
  2. 户外生成器切出的接缝与预设洞口,同样是 'tile';
  3. 迷宫生成器盖出的楼梯间房间,标记为 source: 'room',房间对、房间内位置近似;
  4. findBorderOpening 从碰撞图反推无缝接缝;
  5. 兜底:在空地上凭空放一个楼梯,标记为 source: 'fallback'。

第 5 遍存在的唯一理由是「进得去出不来的关卡比一个位置不准的楼梯更糟」。但它是一个谎言,verify-packs 每次都会把它的数量打印出来:

楼梯来源:美术瓦片 N,迷宫楼梯间 N,兜底 215(涉及 47 个关卡)

本 issue 追踪消除这 215 处兜底楼梯。


根因

src/game/maze.ts 中的 MAZE_LEVEL_TYPE_PROFILES(约 L486-601)逐条转写了 DRLGMAZE_GenerateLevel 内联的 ReplaceRoomPreset 调用序列——也就是「把布局里的哪个房间换成 Prev / Next / Down / Quest 楼梯间」这张表。目前只转写了一部分关卡类型,其余全部是 specials: [],于是生成器根本不盖楼梯间,第 3 遍无料可用;而这些关卡类型所用的拼图碎片恰好又不带 type = 10 / 11 标记,第 1 遍也落空,只能落到兜底。

specials: [] 的关卡类型清单

关卡类型 备注
Act 1 - Barracks 通往庭院与监狱
Act 2 - Sewer 三层下水道
Act 2 - Tomb 七座假墓 + 真墓,另有 prevChain: 'tomb'
Act 2 - Lair
Act 2 - Harem
Act 2 - Basement
Act 3 - Spider
Act 3 - Kurast
Act 3 - Dungeon
Act 4 - Lava 火焰之河 → 混沌避难所
Act 5 - Ice Caves
Act 5 - Temple
Act 5 - Baal 另有 prevChain: 'baal'
Act 5 - Lava 另有 lavaPairs: true

Act 3 - Sewer 属于部分转写:只有 levelIds: [92] 的一条 prev,其余楼梯仍然缺失。


待实现内容 (TODOs)

  1. 补齐 MAZE_LEVEL_TYPE_PROFILES

    • 对上表每一个关卡类型,照抄 D2MOO DRLGMAZE_GenerateLevel 里对应分支的 ReplaceRoomPreset 调用序列,填出 specials 数组:kind(prev / next / down / quest / treasure)、候选 entries()(plainSides / sides / direction)、以及 levelIds / exceptLevelIds / inPlaceOnly 限定。
    • 注意已有的特例字段仍需保留:prevChain、singleRoom、lavaPairs、ring、grow、theme、opening。
  2. 核对第 1 遍与第 3 遍的一致性

    • 若补齐后某个关卡同时拿到了美术瓦片标记与楼梯间房间,第 1 遍应当继续获胜('tile' 优于 'room'),现有 placedWarps 去重逻辑已经保证了这一点,但需要补一条回归断言。
  3. 收紧验收阈值

    • scripts/verify-packs.ts 目前只统计并打印兜底数量。补齐之后应把它改成断言:fallback === 0,让这个数字再也涨不回来。
  4. 顺带处理的关联缺口

    • UNIMPLEMENTED_PASSES 里的 DRLGMAZE_PlaceAct2TombStuff、DRLGMAZE_PlaceAct2LairStuff、DRLGMAZE_PlaceAct3DungeonStuff、DRLGMAZE_PlaceAct3SewerStuff、DRLGMAZE_PlaceAct3MephistoStuff、DRLGMAZE_PlaceAct5TempleStuff、DRLGMAZE_PlaceAct5BaalStuff、DRLGMAZE_PlaceAct5IceStuff 与本 issue 是同一批分支上的代码,转写楼梯表时顺手一起看比分两次看便宜。

验收标准

  • MAZE_LEVEL_TYPE_PROFILES 中不再有 specials: [](除非确实核对过原版该类型就是没有 ReplaceRoomPreset,并在注释里写明)。
  • 完整烘焙后 npm run verify:packs 报告 兜底 0。
  • npx tsx scripts/verify-generators.ts 全绿,迷宫连通性检查不回退。
  • 每个涉及的关卡都能从生成的楼梯间走到下一层(人工抽查 Act 2 下水道 1→2→3、Act 2 七墓、Act 5 冰窟)。

关联代码位置

  • 楼梯表:src/game/maze.ts 的 MAZE_LEVEL_TYPE_PROFILES(约 L486-601)、SpecialStep / entries()(约 L387-475)、findSpecial(约 L1099)、stamp()(约 L1592-1690)
  • 出入口定位:scripts/pack-act-assets.ts 的 buildSceneLinks(第 3 遍与第 5 遍)
  • 美术瓦片标记:src/game/warp-tiles.ts
  • 计数与断言:scripts/verify-packs.ts

关联 issue:#23(M8 世界连通)

## 背景说明 M8「世界连通」(#23)已经把 `Levels.txt` 的 `Vis0..7` / `Warp0..7` 提炼成了一张全局世界图,并且发现 **DS1 的 `type = 10 / 11` 特殊瓦片的 `style` 字段就是 `Warp0..7` 的槽位编号**——也就是说,原版美术资源自己就标注了每一处楼梯口的精确坐标。烘焙管线(`scripts/pack-act-assets.ts` 的 `buildSceneLinks`)因此按五遍优先级定位每一条出入口: 1. `findWarpTiles(ds1)` —— 美术瓦片标注,标记为 `source: 'tile'`,**这是真实坐标**; 2. 户外生成器切出的接缝与预设洞口,同样是 `'tile'`; 3. 迷宫生成器盖出的楼梯间房间,标记为 `source: 'room'`,房间对、房间内位置近似; 4. `findBorderOpening` 从碰撞图反推无缝接缝; 5. **兜底**:在空地上凭空放一个楼梯,标记为 `source: 'fallback'`。 第 5 遍存在的唯一理由是「进得去出不来的关卡比一个位置不准的楼梯更糟」。但它是一个谎言,`verify-packs` 每次都会把它的数量打印出来: > 楼梯来源:美术瓦片 N,迷宫楼梯间 N,**兜底 215(涉及 47 个关卡)** 本 issue 追踪消除这 215 处兜底楼梯。 --- ## 根因 `src/game/maze.ts` 中的 `MAZE_LEVEL_TYPE_PROFILES`(约 L486-601)逐条转写了 `DRLGMAZE_GenerateLevel` 内联的 `ReplaceRoomPreset` 调用序列——也就是「把布局里的哪个房间换成 `Prev` / `Next` / `Down` / `Quest` 楼梯间」这张表。目前只转写了一部分关卡类型,其余全部是 `specials: []`,于是生成器根本不盖楼梯间,第 3 遍无料可用;而这些关卡类型所用的拼图碎片恰好又不带 `type = 10 / 11` 标记,第 1 遍也落空,只能落到兜底。 ### `specials: []` 的关卡类型清单 | 关卡类型 | 备注 | | --- | --- | | `Act 1 - Barracks` | 通往庭院与监狱 | | `Act 2 - Sewer` | 三层下水道 | | `Act 2 - Tomb` | 七座假墓 + 真墓,另有 `prevChain: 'tomb'` | | `Act 2 - Lair` | | | `Act 2 - Harem` | | | `Act 2 - Basement` | | | `Act 3 - Spider` | | | `Act 3 - Kurast` | | | `Act 3 - Dungeon` | | | `Act 4 - Lava` | 火焰之河 → 混沌避难所 | | `Act 5 - Ice Caves` | | | `Act 5 - Temple` | | | `Act 5 - Baal` | 另有 `prevChain: 'baal'` | | `Act 5 - Lava` | 另有 `lavaPairs: true` | `Act 3 - Sewer` 属于**部分转写**:只有 `levelIds: [92]` 的一条 `prev`,其余楼梯仍然缺失。 --- ## 待实现内容 (TODOs) 1. **补齐 `MAZE_LEVEL_TYPE_PROFILES`** - 对上表每一个关卡类型,照抄 D2MOO `DRLGMAZE_GenerateLevel` 里对应分支的 `ReplaceRoomPreset` 调用序列,填出 `specials` 数组:`kind`(`prev` / `next` / `down` / `quest` / `treasure`)、候选 `entries()`(`plainSides` / `sides` / `direction`)、以及 `levelIds` / `exceptLevelIds` / `inPlaceOnly` 限定。 - 注意已有的特例字段仍需保留:`prevChain`、`singleRoom`、`lavaPairs`、`ring`、`grow`、`theme`、`opening`。 2. **核对第 1 遍与第 3 遍的一致性** - 若补齐后某个关卡同时拿到了美术瓦片标记与楼梯间房间,第 1 遍应当继续获胜(`'tile'` 优于 `'room'`),现有 `placedWarps` 去重逻辑已经保证了这一点,但需要补一条回归断言。 3. **收紧验收阈值** - `scripts/verify-packs.ts` 目前只统计并打印兜底数量。补齐之后应把它改成断言:`fallback === 0`,让这个数字再也涨不回来。 4. **顺带处理的关联缺口** - `UNIMPLEMENTED_PASSES` 里的 `DRLGMAZE_PlaceAct2TombStuff`、`DRLGMAZE_PlaceAct2LairStuff`、`DRLGMAZE_PlaceAct3DungeonStuff`、`DRLGMAZE_PlaceAct3SewerStuff`、`DRLGMAZE_PlaceAct3MephistoStuff`、`DRLGMAZE_PlaceAct5TempleStuff`、`DRLGMAZE_PlaceAct5BaalStuff`、`DRLGMAZE_PlaceAct5IceStuff` 与本 issue 是同一批分支上的代码,转写楼梯表时顺手一起看比分两次看便宜。 --- ## 验收标准 - [ ] `MAZE_LEVEL_TYPE_PROFILES` 中不再有 `specials: []`(除非确实核对过原版该类型就是没有 `ReplaceRoomPreset`,并在注释里写明)。 - [ ] 完整烘焙后 `npm run verify:packs` 报告 **兜底 0**。 - [ ] `npx tsx scripts/verify-generators.ts` 全绿,迷宫连通性检查不回退。 - [ ] 每个涉及的关卡都能从生成的楼梯间走到下一层(人工抽查 Act 2 下水道 1→2→3、Act 2 七墓、Act 5 冰窟)。 --- ## 关联代码位置 - 楼梯表:`src/game/maze.ts` 的 `MAZE_LEVEL_TYPE_PROFILES`(约 L486-601)、`SpecialStep` / `entries()`(约 L387-475)、`findSpecial`(约 L1099)、`stamp()`(约 L1592-1690) - 出入口定位:`scripts/pack-act-assets.ts` 的 `buildSceneLinks`(第 3 遍与第 5 遍) - 美术瓦片标记:`src/game/warp-tiles.ts` - 计数与断言:`scripts/verify-packs.ts` 关联 issue:#23(M8 世界连通)
Sign in to join this conversation.
No Label
No Milestone
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#37
No description provided.