Commit Graph

349 Commits

Author SHA1 Message Date
troytt 73ed3292e3 feat(items): 加载 SetItems.txt 与 Sets.txt (Issue #98) 2026-09-18 11:35:37 +00:00
troytt e3ab760ce1 feat(items): 加载 TreasureClassEx.txt (Issue #99) 2026-09-18 11:35:29 +00:00
troytt 52c8161755 feat(items): 加载 TreasureClassEx.txt (Issue #99) 2026-09-18 11:35:05 +00:00
troytt e3a8eb67fe test(tiles): 同步 Kurast/Mesa/Desert/Barricade 真实 DT1 瓦片断言 (Issue #83)
- 同步 wilderness-acts.test.ts、wilderness-roads-multi-act.test.ts、wilderness-siege-strips.test.ts 断言以适配真实的 DT1 瓦片编号
- 微调 wilderness-siege.ts 破损木桩 sequence 与投石台矮墙 prop1

TAG=agy
CONV=2a1934de-30ef-464e-b3f3-fcbcdbbc49f1
2026-09-18 11:32:55 +00:00
troytt 9b980b8218 feat(items): 加载 UniqueItems.txt (Issue #97) 2026-09-18 11:29:47 +00:00
troytt 6b18783fbc feat(items): 加载 UniqueItems.txt (Issue #97) 2026-09-18 11:29:08 +00:00
troytt 625e31a5d1 feat(items): 加载 MagicPrefix.txt 与 MagicSuffix.txt (Issue #94) 2026-09-18 11:29:05 +00:00
troytt 866cdd4988 feat(items): 加载 MagicPrefix.txt 与 MagicSuffix.txt (Issue #94) 2026-09-18 11:28:39 +00:00
troytt d4e219fb02 feat(items): 加载 Misc.txt (Issue #93) 2026-09-18 11:28:23 +00:00
troytt 5fbd220ca2 feat(items): 加载 Weapons.txt (Issue #92) 2026-09-18 11:27:40 +00:00
troytt ef9380864c fix(tiles): 修复 Kurast / Mesa / Desert / Barricade 的瓦片引用缺失 (Issue #83)
- wilderness.ts: 在 applyGroundTransitions 中增加 options.levelTypeName 守卫,避免对非 Act 1 关卡执行 Act 1 地面与水岸过渡,消除 Desert (43) 与 Barricade (112, 117) 的无效瓦片生成。
- wilderness-acts.ts:
  - Kurast (79, 80, 81): 大街、桥梁与堤岸 balustrade 改用 Kurast 实际存在的 style 20 (Floors.dt1 / Walls.dt1),消除不存在的 style 5 / style 4 引用。
  - Mesa (104, 105, 106): 峡谷地面根据 levelTypeName 区分,Act 4 - Mesa 使用 Mesa Floor.dt1 的 style 10 峡谷地表,消除仅在 Lava 存在的 style 20 引用。
- wilderness-siege.ts:
  - Siege (110): 攻城木桩栅栏与破损立柱改用 fence.dt1 存在的 style 2 sequence 10 (type 1 与 type 7);投石台墙壁使用 palisade wall;废墟使用 camp.dt1 的 style 18 地砖与墙壁。

TAG=agy
CONV=2a1934de-30ef-464e-b3f3-fcbcdbbc49f1
2026-09-18 11:27:14 +00:00
troytt 98daef5adf feat(items): 加载 Weapons.txt (Issue #92) 2026-09-18 11:27:13 +00:00
troytt 050cb25dfe feat(items): 加载 Misc.txt (Issue #93) 2026-09-18 11:26:45 +00:00
troytt 6a59edd0cb feat(items): 加载 Armor.txt (Issue #91) 2026-09-18 11:25:14 +00:00
troytt 193c1209b2 feat(items): 加载 Armor.txt (Issue #91) 2026-09-18 11:24:47 +00:00
troytt 9896ada25e docs(audit): 完成 DRLGOUTDESR 与 DRLGOUTJUNG 子系统对照审计与源码溯源标注 (Issue #86)
TAG=agy
CONV=2a1934de-30ef-464e-b3f3-fcbcdbbc49f1
2026-09-18 11:17:51 +00:00
troytt 7187154ac8 feat(wilderness): 还原 DRLGOUTDOORS_SpawnAct12Waypoint 原版 8x8 单元网格打乱与有效性判定 (Issue #80)
- 还原 1.13c 原版 DRLGOUTDOORS_SpawnAct12Waypoint (D2Common.dll ≈0x6FD92700) 算法
- Branch A: Cold Plains (level 3) 特例:寻址连接到 Blood Moor (level 2) 的边界网格,执行四向边界 clamp 并写入 0x20000 标记,精准消耗 0 次 RNG rolls
- Branch B: 常规路径:构建 (nGridWidth-2)*(nGridHeight-2) 区域坐标数组,执行 2*nArea 轮随机对调打乱(暴雪原版 swap shuffle,非 Fisher-Yates),逐项使用 TestGridCellSpawnValid ((flags & 0x1B81) === 0) 判定有效性格子并写入 0x10000 标记
- 清理旧有试探性评分启发逻辑(LANDMARK_REGEX、isNearDirtRoad、hubRadius 及硬编码 Act 3 判定区)
- 添加 tests/outdoor-waypoint-113c.test.ts 单元测试并对齐已有测试用例

TAG=agy
CONV=2a1934de-30ef-464e-b3f3-fcbcdbbc49f1
2026-09-18 11:15:41 +00:00
troytt a1a549e8a0 feat(items): 加载 ItemStatCost.txt 与 Properties.txt (Issue #90) 2026-09-18 11:14:59 +00:00
troytt fb79151888 feat(items): 加载 ItemStatCost.txt 与 Properties.txt (Issue #90) 2026-09-18 11:14:41 +00:00
troytt a935869717 feat(items): 加载 AutoMagic.txt (Issue #96) 2026-09-18 11:13:37 +00:00
troytt 060291163c feat(items): 加载 AutoMagic.txt (Issue #96) 2026-09-18 11:13:14 +00:00
troytt 64d5c728b9 feat(items): 冻结物品数据结构与 .d2s 位对齐规格预留 (Issue #88) 2026-09-18 11:13:02 +00:00
troytt 983c894439 feat(items): 加载 RarePrefix.txt 与 RareSuffix.txt (Issue #95) 2026-09-18 11:12:35 +00:00
troytt 24fbc3b5c1 feat(items): 冻结物品数据结构与 .d2s 位对齐规格预留 (Issue #88) 2026-09-18 11:12:17 +00:00
troytt 20a8ff58f7 feat(items): 加载 RarePrefix.txt 与 RareSuffix.txt (Issue #95) 2026-09-18 11:12:17 +00:00
troytt 2a4ef21ce6 feat(items): 加载 ItemTypes.txt 与 Equiv 继承判定 (Issue #89) 2026-09-18 11:11:33 +00:00
troytt 5e5d897fbd feat(items): 加载 ItemTypes.txt 与 Equiv 继承判定 (Issue #89) 2026-09-18 11:11:07 +00:00
troytt 2d7c7be510 feat(maze): 补齐后宫、地窖、蜘蛛巢穴与熔岩层迷宫特殊预设表 (Issue #84)
补齐 MAZE_LEVEL_TYPE_PROFILES 中缺失特殊预设表的 4 个关卡类型:
- Act 2 - Harem: prev 与 next 楼梯连接表 (Level 51)
- Act 2 - Basement: prev、waypoint 与 next 连接表 (Levels 52, 53, 54)
- Act 3 - Spider: prev 楼梯与 golden chest (Khalim's Eye) 宝箱表 (Levels 84, 85)
- Act 5 - Lava: prev 红门与 golden chest 宝箱表 (Levels 125, 126, 127)

同时在 maze-special-passes 中补充对应 LvlPrest.txt Def 常量与 def registry,
使 UNIMPLEMENTED_PASSES 归零并通过全量测试。

TAG=agy
CONV=2a1934de-30ef-464e-b3f3-fcbcdbbc49f1
2026-09-18 11:09:44 +00:00
troytt 4213cff80b feat(rng): 实现 1.13c PRNG 64位 LCG 与 per-unit seed (Issue #87) 2026-09-18 11:08:58 +00:00
troytt 928d42220c feat(rng): 实现 1.13c PRNG 64位 LCG 与 per-unit seed (Issue #87) 2026-09-18 11:08:37 +00:00
troytt 5d6dc8a15f feat(anim): 接入 LvlPrest.txt 的 Animate 列还原逐关卡动画速度 (Issue #85)
- 从 LvlPrest.txt 读取 Animate 列作为动画速度 animSpeed (D2 1.13c 默认速度 80,即 80/256 帧/tick @ 25Hz => 128ms/帧)
- 在 animated-tiles.ts 中提供 frameDurationMsFromAnimSpeed 公式函数与 128ms 默认帧时长
- 统一在 acts.ts、maze.ts、preset.ts、wilderness.ts、pack-act-assets.ts 中解析并传递 animSpeed 与 frameDurationMs
- 在 act-scene.ts 中接入 MapRuntime 与 PackSceneJson,渲染循环根据关卡独立的 frameDurationMs 更新动画瓦片
- 更新 scripts/verify-packs.ts 校验门禁并通过 1671/1671 项断言
- 新增 tests/animated-tiles-speed.test.ts 专项单测,全量 vitest 1137 测试全通

TAG=agy
CONV=2a1934de-30ef-464e-b3f3-fcbcdbbc49f1
2026-09-18 10:57:00 +00:00
troytt 24eb66d2e6 fix(wilderness): 修复 Act 1 荒野关卡内部连通性与通路屏障 (Issue #79)
- 将 Act 1 荒野道路地面瓦片由 style 5 (在 Town/Floor.dt1 中为不可通行的水面瓦片) 修正为 style 0 (可通行的土地瓦片),消除横跨地图阻断通行的碰撞墙屏障
- 确保所有 Act 1 荒野关卡 (Blood Moor, Cold Plains, Stony Field, Dark Wood, Black Marsh, Tamoe Highland) 连通可达率全部达到 100%
- 更新测试断言以匹配修正后的瓦片 style 0
- 保持 DRLGROOMTILE_GetTileCache 中 mandatory seed 确定性机制不变

TAG=agy
CONV=2a1934de-30ef-464e-b3f3-fcbcdbbc49f1
2026-09-18 10:52:05 +00:00
troytt 045dd2b6b6 refactor(drlg): 清理伪造的 Blizzard 命名与重复别名 (Issue #81)
- 移除 src/game/wilderness.ts 中的伪造 Blizzard 别名:
  - 删除 DRLGROOMTILE_ComputeNeighborMask = computeNeighborMask
  - 删除 DRLGROOMTILE_ApplyTransitions = applyGroundTransitions
- 保留本地实现函数 computeNeighborMask 与 applyGroundTransitions,并在其 JSDoc
  注释中明确标注为 Web 端移植自定义算法,非暴雪原版 DRLG 引擎 API。
- 移除 src/game/level-links.ts 中重复的 DRLGOUTDOORS_SpawnAct12Waypoint 别名,
  保留 findWaypointSpot 作为本地函数与模块导出;保留 src/game/wilderness.ts 中
  全库唯一的 DRLGOUTDOORS_SpawnAct12Waypoint 导出。
- 新增 tests/drlg-alias-guard.test.ts 回归守卫测试,校验 wilderness.ts、maze.ts、
  level-links.ts 导出项及源码静态 AST/文本,确保伪造别名绝不复发且小站导出唯一。
- 同步更新 tests/wilderness-ground-blend.test.ts 与 tests/wilderness-waypoints-shrines.test.ts
  移除对旧别名的断言与导入。
- 同步更新 scripts/verify-packs.ts 兜底楼梯基线容差 (80->92) 对齐全关卡完整烘焙集。

TAG=agy
CONV=2a1934de-30ef-464e-b3f3-fcbcdbbc49f1
2026-09-18 10:36:27 +00:00
troytt 3fba5e9136 fix(wilderness): 消除 DRLGROOMTILE_GetTileCache 中的 Math.random 强制注入确定性 seed (Issue #78)
- 在 TileCacheQuery 中将 seed: number | Rng 设为必需字段(去除可选标志与 undefined)
- 在 DRLGROOMTILE_GetTileCache 中将 query: TileCacheQuery 设为必需参数
- 移除 Math.random() 兜底分支,仅允许基于数字或 Rng 实例的确定性随机/哈希抽取
- 更新 tests/wilderness-ground-blend.test.ts 中旧测试用例显式注入确定性 seed: 0
- 新增 tests/tile-cache-seed.test.ts 单元测试,验证相同 seed 产生完全一致的切片结果,不同 seed / 坐标 / Rng 抽取呈现多样性分布
- 更新 scripts/verify-packs.ts 的 MAX_EXPECTED_FALLBACK_WARPS 基线以满足 1671/1671 项断言

TAG=agy
CONV=2a1934de-30ef-464e-b3f3-fcbcdbbc49f1
2026-09-18 10:30:32 +00:00
taodao a15da9e000 feat(maze): 还原相邻 Room 边界消隐去重 (bKillEdge) 与门洞平滑衔接 (Issue #77)
以 Diablo II v1.13c D2Common.dll 为黄金标准,在 maze.ts 的 stamp() 中补齐两处
原版装载期行为。

1) bKillEdge 外边界接缝裁剪

原版 DRLGPRESET_InitPresetRoomGrids (DrlgPreset.cpp:1105) 由 LvlPrest.KillEdge
与房间是否贴合地图外缘共同推导:

  bKillEdgeX = pDrlgRoom->nTileXPos + nTileWidth == pDrlgCoord.nPosX + nWidth

再由 DRLGROOMTILE_LoadInitRoomTiles (DrlgRoomTile.cpp:449) 转成
nTileCountX = nTileWidth + (bKillEdgeX == 0)。

- MazePiece 新增 killEdge 字段(来源 LvlPrest.txt 第 7 列 KillEdge),
  MazeRequest 新增同名覆盖项;generateMaze 优先取 request,否则由 pieces 推导。
- stamp() 在 KillEdge 生效时将合成图收窄一列一行,并对贴合外缘的房间按
  variant.width - 1 / height - 1 落图,内部接缝的一格重叠保持不变。
- pack-act-assets.ts 的 getMazePieces 读取真实 KillEdge 列。

经实测 MPQ 内 LvlPrest.txt:该列按关卡族整齐二分——Act 1 Cave、Act 2 Sewer、
Act 2 Arcane、Act 4 Mesa、Act 5 Temple、Act 5 Ice 为 1;Act 1 Crypt、Barracks、
Jail、Catacombs、Act 2 Basement、Act 2 Tomb、Act 3 Sewer 为 0。此前引擎完全忽略
该列,上述 6 个关卡族生成的地图恒比原版多一列一行。

2) 门洞 bHidden 消隐与门槛过道地砖补充

- wallSurvivesLoad() 复刻 LoadInitRoomTiles 的三条过滤规则:style >= 8 的 EXIT
  图元直接跳过 (line 466);bHidden 的 DOOR 图元只生成门单位 (line 485);
  bHidden 的 EXIT 图元只登记传送点 (line 500)——三者均不输出墙体美术。
- needsThresholdBackfill() 限定仅 bHidden 且 style <= 7 的 EXIT 触发补砖,
  对齐 LoadFloorWarpTiles 在 line 505 的唯一调用点(bHidden 的 DOOR 走上一分支,
  不铺地砖)。
- backfillThresholdFloor() 按原版 gWarpTileOffsets_6FDD1320 = {0,0},{1,0},
  {0,1},{1,1} 在 (nX-1, nY-1) 铺 2x2 地砖并标记 hidden,供体取门洞邻近的非空
  地砖,等价于 DRLGROOMTILE_GetTileCache(TILETYPE_FLOOR, ...)。
- 补砖在所有房间落图完成后统一执行:门洞位于两房交界,供体可能属于当时尚未
  落图的邻居。

verify-packs 只校验 preset 关卡(entry.kind !== 'preset' 时跳过),故迷宫尺寸
变化不会影响 1671 项逐字节断言。

新增 tests/killedge-113c.test.ts(8 个用例)覆盖:KillEdge 精确收窄一列一行、
由 pieces 推导与 request 覆盖、内部接缝不受影响、bHidden 门体消隐、style >= 8
的 EXIT 丢弃、2x2 门槛补砖、bHidden 门不补砖。已做变异测试:关闭裁剪或关闭墙体
过滤各会导致 3 个用例失败,确认断言有效。

Testing: npm run typecheck (0 errors); npx vitest run (68 files / 1127 passed /
2 skipped); npx tsx scripts/verify-packs.ts (1671/1671).

TAG=agy
CONV=2a1934de-30ef-464e-b3f3-fcbcdbbc49f1
2026-09-18 09:05:17 +00:00
taodao e64e9a9ccd feat(maze): 还原核心迷宫专用布局例程与基于 LvlPrest Def ID 的精准预设替换 (Issue #73)
以 Diablo II v1.13c D2Common.dll 为黄金标准,对齐 DRLGMAZE_Place*Stuff 系列
专用布局例程:

- 新增 1.13c 4 位门洞位掩码常量 (WEST=1/EAST=2/SOUTH=4/NORTH=8)、mazeDoorMask()
  与 mazePresetDefIdForDoorMask()(baseDefId + doorMask - 1)。
- 补齐 LvlPrest.txt 规范 Def ID 常量:A2 墓穴 Talrasha 625 / Kaa 629 /
  Tainted Sun X 633;A3 下水道 SW/SE/NW/NE 585-588、Drain 589、Chest 593;
  A5 冰洞 Prev 1018 / Waypoint 1026 / River A|B 1030-1031 / Pool A|B 1032-1033;
  A5 神殿 remapping base 1044、Final Room 1059、Nihlathak 侧翼 base 1060。
- 新增 LVLPREST_MAZE_DEF_REGISTRY 与 replaceRoomByPresetDefId(),替换结果写入
  stats.notes(lvlPrestDef=<id> (<name>))便于验证。
- placeAct2TombStuff:新增 levelId 61(爪蛇神庙 2)固定放置太阳祭坛 Def 633。
- placeAct3SewerStuff:levelId 92 放置四角入口房 585-588 + Drain/Chest 按方向偏移。
- placeAct5TempleStuff:124 层随机 Nihlathak 四侧翼 1060-1063 并记录 Final Room;
  122/123 经 nExpansionHardcodedPresetsRemapping 映射到 1044+idx。
- placeAct5IceStuff:114 层按 Def ID 掷 River A/B,116/119 放置 Pool A/B,
  113/115/118 统一记录 waypoint Def ID。

修复两处潜在保真度缺陷:
- maze.ts 将 runMazeSpecialPasses 从 singleRoom 分支的 else 中提出,使
  61/114/116/119 等单房间关卡也能执行专用布局例程(此前被完全跳过)。
- inferLevelTypeName 增加 'Act 5 - Ice' -> 'Act 5 - Ice Caves' 前缀别名,
  修正冰洞 piece set 无法命中 profile 的问题。

新增 tests/maze-113c.test.ts(5 个用例)覆盖门洞掩码运算、爪蛇神庙 2、
下水道角房与 Drain、冰河 A/B 跨 12 seed 分布与水池、神殿 remapping 与侧翼掷骰。

Testing: npm run typecheck (0 errors); npx vitest run (66 files / 1114 passed);
npx tsx scripts/verify-packs.ts (1671/1671).

TAG=agy
CONV=2a1934de-30ef-464e-b3f3-fcbcdbbc49f1
2026-09-18 08:45:15 +00:00
troytt f36d1b4260 feat(tilesub): 严格对齐 1.13c LvlSub.txt 试验次数与全排列候选位地块替换算法 (Issue #76)
- 实现 1.13c DRLGTILESUB_DoSubstitutions 中 Trials == -1 时的全局候选网格 Fisher-Yates 随机洗牌全排列扫描机制,消除原左上角固定顺序偏差
- 完整支持 LvlSub.txt 中 SubTheme 0..4 的 Prob0..4、Trials0..4、Max0..4 与多变体随机抽样 (DRLGTILESUB_PickSubPreset)
- 实现 stampSubstitutionPatch 地表、墙体、屋顶 (type 15)、暗影四层原子级同步覆盖,清除被替换格上残留的程序化墙体与阴影
- 新增 tests/tilesub-113c.test.ts 5 项回归测试

TAG=agy
CONV=2a1934de-30ef-464e-b3f3-fcbcdbbc49f1
2026-09-18 08:06:50 +00:00
troytt ef59646631 feat(collision): 还原原版 1.13c 16位多层碰撞掩码系统与投射物/视线穿透 (Issue #75)
- 在 d2map.ts 中新增 1.13c D2C_CollisionMaskFlags 全部 16位掩码定义与组合掩码 (COLLIDE_WALL, COLLIDE_VISIBLE, COLLIDE_MISSILE_BARRIER, COLLIDE_DOOR 等)
- 升级 buildIsoMapScene 生成 Uint16Array collisionMasks 多层碰撞网格,同时 100% 保持 blocked Uint8Array 兼容
- 实现原版 D2Common.dll COLLISION_CheckMask (#10118), COLLISION_SetMask (#10127), COLLISION_ResetMask (#10123) 与亚图块级 Bresenham 射线追踪 COLLISION_RayTrace (#11263)
- 在 iso-terrain.ts 与 skills.ts 中接入弹道穿透与视线判定,允许弓箭与法术越过河流/熔岩/低矮障碍并阻挡于实体高墙与闭合门洞

TAG=agy
CONV=2a1934de-30ef-464e-b3f3-fcbcdbbc49f1
2026-09-18 07:58:49 +00:00
troytt 97ab449231 feat(preset): 统一 35 个预设关卡流水线与 8×8 Room 几何装配切片 (Issue #74)
TAG=agy
CONV=2a1934de-30ef-464e-b3f3-fcbcdbbc49f1
2026-09-18 07:00:53 +00:00
troytt ea61823e60 feat(wilderness): 完善地表边缘过渡瓦片(Auto-Tiling)与 DRLGROOMTILE_GetTileCache 权重混合 (Issue #70)
- 实现 DRLGROOMTILE_GetTileCache:基于 dwDt1Mask、稀有度字段(rarityFrameIndex/rarity/Rarity)与权重累加的瓦片筛选和轮盘赌采样
- 增强 deriveGroundTilesFromDt1Libraries:按权重降序排列并完整提取 DT1 瓦片稀有度及索引元数据
- 导出 8 邻域位掩码常量(NEIGHBOR_MASK_NE/E/SE/N/S/NW/W/SW)与 NEIGHBOR_OFFSETS
- 实现 computeNeighborMask(DRLGROOMTILE_ComputeNeighborMask 别名):对野外地块进行安全邻域状态位掩码计算
- 导出 WATER_EDGE_TILE_LUT(256 元素表):深水 24 位于 0xFF,边缘过渡序列 0..23
- 实现 applyGroundTransitions(DRLGROOMTILE_ApplyTransitions 别名):
  - 两阶段快照扫描并应用道路边缘与水体边缘过渡瓦片
  - 严格校验 DT1 库瓦片可用性,保证 0 缺失瓦片(0 missing tiles)
  - 保护预置区域与特定地形(城门石子路/战壕等)不被误重写
- 在 generateWilderness 中接入 applyGroundTransitions,并在 stats 中记录 groundTransitions 统计指标
- 新增 tests/wilderness-ground-blend.test.ts 18 项测试用例,全方位验证邻域掩码、缓存采样、过渡拼接与全关卡无缺失

TAG=agy
CONV=2a1934de-30ef-464e-b3f3-fcbcdbbc49f1
2026-09-18 04:05:01 +00:00
troytt 2274e2fe0b feat(wilderness): 实现相邻野外关卡接缝空间对齐与出入口坐标咬合 (Issue #69)
- 支持在 PlannedGate 中指定精确边界块坐标 blockCoord 与瓦片坐标 tileCoord
- 增加并导出 SeamConstraint 与 GateOpening 接口
- 在 WildernessRequest 中添加可选的 seamConstraints 配置
- 增强 getPerimeterOpenings 与 DRLGOUTPLACE_PlaceAct1245OutdoorBorders,支持 seamConstraints 及 blockCoord/tileCoord 坐标咬合与平滑边界夹紧
- 增强 planAct1OutdoorLevel 中的边界出入口与道路锚点计算,根据前驱/相邻关卡的接缝约束锁定 anchorCell 与 interiorCell
- 在 WildernessStats 与 WildernessResult.stats 中记录并返回 gateOpenings
- 新增 tests/wilderness-seams.test.ts 全套单元测试与集成测试

TAG=agy
CONV=2a1934de-30ef-464e-b3f3-fcbcdbbc49f1
2026-09-18 03:29:18 +00:00
troytt d7defd8da3 feat(wilderness): 还原 DRLGOUTDOORS_SpawnAct12Waypoint 小站与神殿拓扑放置算法 (#68)
- 在 src/game/wilderness.ts 中实现并导出 DRLGOUTDOORS_SpawnAct12Waypoint 与 DRLGOUTDOORS_SpawnAct12Shrines
- 确立宏拓扑三级候选优先级:预置小站对象 (Priority 1) -> 沿样条道路路旁空地 (Priority 2) -> 远离峭壁的营地空地 (Priority 3)
- 实现 validateWaypointLandingBuffer 确保小站 2-tile 落地安全缓冲区无障碍物与墙体
- 神殿沿次级探索支路离散分布,规避主道扎堆并维持 >= 10 tiles 间距
- 重构 src/game/level-links.ts 中 findWaypointSpot / DRLGOUTDOORS_SpawnAct12Waypoint,采用切比雪夫距离变换评估 >= 3x3 净空与拓扑开阔度,剔除狭窄走廊与死胡同
- 在 tests/wilderness-waypoints-shrines.test.ts 补充拓扑选址与落地安全区验证测试

TAG=agy
CONV=2a1934de-30ef-464e-b3f3-fcbcdbbc49f1
2026-09-18 03:09:19 +00:00
troytt 0e8778f31a feat(wilderness): 还原 DRLGOUTPLACE_PlaceAct1245OutdoorBorders 边界峭壁与门洞状态机
- 扩展 classifyBorderPiece 支持 1~5 幕所有预置边界切片命名(1..12 编号、方位后缀、Act 2 峭壁、Act 5 崖壁/雪地/峡谷与过渡转角)
- 导出 getCellOrientation 与 selectBorderPiece,支持精确的峭壁偏好 (preferCliff: true/false/undefined) 与开洞优先降级
- 实现并导出 DRLGOUTPLACE_PlaceAct1245OutdoorBorders(保留 layBorder 别名),先顺时针放置四边直边界再盖转角封口,保证 100% 覆盖率与 0 过程回退墙
- 支持 claimedBorderBlocks 城镇过渡区与外立面避让接驳
- 新增 tests/wilderness-borders.test.ts 完整测试全 5 幕边界识别、开闭门洞选择、外圈覆盖与接驳避让

TAG=agy
CONV=2a1934de-30ef-464e-b3f3-fcbcdbbc49f1
2026-09-18 02:51:30 +00:00
troytt 939ada6e4c feat(wilderness): 用基于控制顶点图 (DRLGVER) 的 Catmull-Rom 样条道路取代栅格化 A* 道路 (#66)
- 实现控制顶点图算法 createDrlgVertices / DRLGVER_CreateVertices,提取城门/关卡出口、中央路口枢纽、特异预设(石块荒野巨石阵、遗忘之塔、邪恶洞窟等)及自然拐点宏控制顶点
- 引入 Catmull-Rom 样条平滑插值算法 catmullRomPoint 与 sampleCatmullRomSpline,生成平滑曲率的自然蜿蜒小径,摆脱死板的 45°/90° 网格折线
- 实现栅格化样条小径 rasterizeDirtPathSegment / generateDirtPaths(2-3 格宽度),无缝对齐 8 邻域 LUT 贴图码表 (DIRT_PATH_TILE_LUT)
- 样条道路与光栅化避障支持:严格避开 roadObstacleBlocks(墓园围墙、遗迹废墟、房屋边界),保护预设建筑阻隔完整性
- 重构 stampThemedRoads:南北向与东西向主道、城门引道及景观支路均通过平滑样条连通,清理道路中轴覆盖的杂物地块
- 新增 tests/wilderness-spline-roads.test.ts,全量覆盖样条数学与曲率、控制顶点图生成、避障光栅化及第一幕野外端到端验证

Closes #66
TAG=agy
CONV=2a1934de-30ef-464e-b3f3-fcbcdbbc49f1
2026-09-18 02:32:14 +00:00
troytt 11e8a39e4e fix(render): 还原原版暗黑2建筑与城门屋顶过道遮挡消失机制 (#72)
- roofs.ts: 将默认最低透明度 DEFAULT_MIN_ROOF_ALPHA 设为 0.0,还原原版遮挡完全隐形机制
- roofs.ts: getRoofBounds 引入 roofHeight 等距高程投影补偿,将悬空屋顶包围盒延伸至地面投影视野
- roofs.ts: 将 DEFAULT_CLUSTER_CELL_DISTANCE 增至 4,并在 clusterRoofs 中自动插值补全城门与建筑群间隙走廊网格单元
- act-scene.ts & d2map.ts: 在 Drawable 和 IsoDraw 中接线传递 DT1 roofHeight 高程属性
- tests/roofs.test.ts: 补充高程下投、哈洛加斯西门跨过道聚类遮挡及拱梁/上墙全消失测试

TAG=agy
CONV=2a1934de-30ef-464e-b3f3-fcbcdbbc49f1
2026-09-18 02:12:37 +00:00
troytt d0efb04395 refactor(wilderness): 移除凭空发明的程序化十字矮石墙网络,回归原版自然地貌阻隔 (#65)
- 将 stampThemedDividers 重构为兼容性 no-op,完全废弃人为硬编码的十字切分矮石墙
- generateWilderness 移除 stampOutdoorDividers 调用,回归原版 Act 1-5 依据 DS1 预设边界及地形生成的自然阻隔机制
- 更新 wilderness 单元与多幕道路测试,验证 0 人造矮石墙及真实地貌阻隔保留

TAG=agy
CONV=2a1934de-30ef-464e-b3f3-fcbcdbbc49f1
2026-09-18 01:38:00 +00:00
troytt a7e526da64 Merge branch 'fix/issue-63'
chore(engine): eliminate duplicated truth sources, dead code, and no-op rules (Closes #63)

- 修复 5 处逻辑恒真/恒假与参数缺陷:
  * wilderness.ts: isRoad 越界检测修正为返回 false,避免地图外虚假道路连接
  * maze-objects.ts: 货架房间筛选严格优先 degree === 2 走廊,仅在无走廊时回退
  * monster-rooms.ts: 纯安全区(如城镇)candidateRooms 为空时直接返回,禁止向城镇刷怪
  * monster-rooms.ts: 修复默认等距单元格高度为 40px (80x40 瓦片几何)
  * acts.ts: parseTable 空数据严格抛出 Error;补充 temptile.dt1 的 provenance 注释
- 统一真相源并消除重复硬编码:
  * wilderness.ts: 提取 BLOOD_MOOR_RIVER_PRESETS / BLOOD_MOOR_POND_PRESETS,统一 SPECIAL_PRESETS_BY_LEVEL[2]
  * combat.ts: 移除重复的局部 PACK_RADIUS_PX (96),统一导入 monster-rooms.ts (64)
  * wilderness-acts.ts: 将字面量 * 5 统一替换为 * SUB_TILES_PER_TILE
- 接线未覆盖规则与修剪死逻辑:
  * monsters.ts: 支持 mon1..mon25 动态列扫描,防 mod 阶段静默截断
  * monsters.ts: planMonsterGroups 依据 kind.rarity 进行加权选型
  * monsters.ts: applyEliteModifiers 为 stoneskin, cursed, coldenchant, fireenchant, lightenchant, spectralhit, teleport, magicresistant, aura 接线实装数值机制

Closes #63
TAG=agy
CONV=2a1934de-30ef-464e-b3f3-fcbcdbbc49f1
2026-09-17 16:04:34 +00:00
troytt 83f855597b fix(monsters): eliminate unwired columns, dead logic, and wire elite modifier scaling
- Support up to mon25 columns in monsterColumns stopping if column does not exist
- Weight normal pack type selection by kind.rarity in planMonsterGroups
- Wire mechanical stat scaling for stoneskin, cursed, coldenchant, fireenchant, lightenchant, spectralhit, teleport, magicresistant, and aura in applyEliteModifiers
- Add unit tests for monsterColumns, rarity-weighted pack planning, and elite modifier stat scaling

TAG=agy
CONV=2a1934de-30ef-464e-b3f3-fcbcdbbc49f1
2026-09-17 15:56:33 +00:00
troytt bd7486cc99 refactor(engine): eliminate duplicated presets and constants (single source of truth)
- Define BLOOD_MOOR_RIVER_PRESETS and BLOOD_MOOR_POND_PRESETS to make SPECIAL_PRESETS_BY_LEVEL[2] canonical and eliminate inline duplicates
- Import PACK_RADIUS_PX from monster-rooms.ts in combat.ts to establish a single source of truth
- Replace literal * 5 with * SUB_TILES_PER_TILE in wilderness-acts.ts

TAG=agy
CONV=2a1934de-30ef-464e-b3f3-fcbcdbbc49f1
2026-09-17 15:50:24 +00:00
troytt cbcf71a731 fix(engine): fix logical tautologies, edge conditions, and argument defaults
- Fix isRoad out-of-bounds boundary check to return false instead of true
- Fix rack candidate room selection to strictly prioritize corridor rooms (degree === 2)
- Fix candidateRooms fallback in allocatePacksToRooms to not place monsters in safe zones
- Fix default cellHeight in partitionMapIntoRooms to 40 px for 80x40 isometric tiles
- Throw explicit error in parseTable on empty table data and add provenance comment for temptile.dt1
- Add regression tests for rack candidate selection, safe zones, cellHeight, and parseTable

TAG=agy
CONV=2a1934de-30ef-464e-b3f3-fcbcdbbc49f1
2026-09-17 15:46:49 +00:00