fix(wilderness): add seed diversity to Bloody Foothills obstacle placement
- Apply RNG jitter to obstacle placement coordinates and lengths across frontline zones - Preserve the unblocked central corridor along y=24 - Track procedural walls and roads in siege topography stats - Add unit test in tests/wilderness-siege-strips.test.ts verifying seed-based obstacle variance TAG=agy CONV=2a1934de-30ef-464e-b3f3-fcbcdbbc49f1
This commit is contained in:
parent
53d6cdd08c
commit
6de9fce610
|
|
@ -416,34 +416,34 @@ export function stampAct5SiegeStrips(
|
||||||
// Zone 1: West Frontline (x in [0, 80)) - High density (Shenk's stronghold)
|
// Zone 1: West Frontline (x in [0, 80)) - High density (Shenk's stronghold)
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
// Trenches (3 trenches)
|
// Trenches (3 trenches)
|
||||||
totalTrenchCells += stampTrench(canvas, 18, 8, 10, 'vertical', rng)
|
totalTrenchCells += stampTrench(canvas, 18 + rng.int(-2, 2), 8 + rng.int(-1, 1), 10 + rng.int(-1, 1), 'vertical', rng)
|
||||||
totalTrenchCells += stampTrench(canvas, 50, 28, 10, 'vertical', rng)
|
totalTrenchCells += stampTrench(canvas, 50 + rng.int(-2, 2), 28 + rng.int(-1, 1), 10 + rng.int(-1, 1), 'vertical', rng)
|
||||||
totalTrenchCells += stampTrench(canvas, 34, 12, 7, 'horizontal', rng)
|
totalTrenchCells += stampTrench(canvas, 34 + rng.int(-2, 2), 12 + rng.int(-1, 1), 7 + rng.int(-1, 1), 'horizontal', rng)
|
||||||
westObstacles += 3
|
westObstacles += 3
|
||||||
|
|
||||||
// Breached Barricades (3 barricades)
|
// Breached Barricades (3 barricades)
|
||||||
const b1 = stampBreachedBarricade(canvas, 26, 10, 24, 21, 5, rng)
|
const b1 = stampBreachedBarricade(canvas, 26 + rng.int(-2, 2), 10 + rng.int(-1, 1), 24, 21 + rng.int(0, 1), 5, rng)
|
||||||
totalBarricadeWalls += b1.wallCount
|
totalBarricadeWalls += b1.wallCount
|
||||||
totalTrenchCells += b1.breachFloorCount
|
totalTrenchCells += b1.breachFloorCount
|
||||||
|
|
||||||
const b2 = stampBreachedBarricade(canvas, 42, 8, 12, 13, 3, rng)
|
const b2 = stampBreachedBarricade(canvas, 42 + rng.int(-2, 2), 8 + rng.int(-1, 1), 12, 13, 3, rng)
|
||||||
totalBarricadeWalls += b2.wallCount
|
totalBarricadeWalls += b2.wallCount
|
||||||
totalTrenchCells += b2.breachFloorCount
|
totalTrenchCells += b2.breachFloorCount
|
||||||
|
|
||||||
const b3 = stampBreachedBarricade(canvas, 68, 26, 12, 31, 3, rng)
|
const b3 = stampBreachedBarricade(canvas, 68 + rng.int(-2, 2), 26 + rng.int(-1, 1), 12, 31, 3, rng)
|
||||||
totalBarricadeWalls += b3.wallCount
|
totalBarricadeWalls += b3.wallCount
|
||||||
totalTrenchCells += b3.breachFloorCount
|
totalTrenchCells += b3.breachFloorCount
|
||||||
westObstacles += 3
|
westObstacles += 3
|
||||||
|
|
||||||
// Catapult Platforms (2 platforms)
|
// Catapult Platforms (2 platforms)
|
||||||
stampCatapultPlatform(canvas, 12, 10, 4, 4, rng)
|
stampCatapultPlatform(canvas, 12 + rng.int(-2, 2), 10 + rng.int(-1, 1), 4, 4, rng)
|
||||||
stampCatapultPlatform(canvas, 58, 30, 4, 4, rng)
|
stampCatapultPlatform(canvas, 58 + rng.int(-2, 2), 30 + rng.int(-1, 1), 4, 4, rng)
|
||||||
catapultPlatformCount += 2
|
catapultPlatformCount += 2
|
||||||
westObstacles += 2
|
westObstacles += 2
|
||||||
|
|
||||||
// Fort Ruins (2 ruins)
|
// Fort Ruins (2 ruins)
|
||||||
stampFortRuin(canvas, 30, 30, 4, rng)
|
stampFortRuin(canvas, 30 + rng.int(-2, 2), 30 + rng.int(-1, 1), 4, rng)
|
||||||
stampFortRuin(canvas, 64, 10, 4, rng)
|
stampFortRuin(canvas, 64 + rng.int(-2, 2), 10 + rng.int(-1, 1), 4, rng)
|
||||||
fortRuinCount += 2
|
fortRuinCount += 2
|
||||||
westObstacles += 2
|
westObstacles += 2
|
||||||
|
|
||||||
|
|
@ -451,27 +451,27 @@ export function stampAct5SiegeStrips(
|
||||||
// Zone 2: Mid Field (x in [80, 160)) - Medium density (No-man's land)
|
// Zone 2: Mid Field (x in [80, 160)) - Medium density (No-man's land)
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
// Trenches (2 trenches)
|
// Trenches (2 trenches)
|
||||||
totalTrenchCells += stampTrench(canvas, 98, 10, 10, 'vertical', rng)
|
totalTrenchCells += stampTrench(canvas, 98 + rng.int(-2, 2), 10 + rng.int(-1, 1), 10 + rng.int(-1, 1), 'vertical', rng)
|
||||||
totalTrenchCells += stampTrench(canvas, 138, 28, 10, 'vertical', rng)
|
totalTrenchCells += stampTrench(canvas, 138 + rng.int(-2, 2), 28 + rng.int(-1, 1), 10 + rng.int(-1, 1), 'vertical', rng)
|
||||||
midObstacles += 2
|
midObstacles += 2
|
||||||
|
|
||||||
// Breached Barricades (2 barricades)
|
// Breached Barricades (2 barricades)
|
||||||
const b4 = stampBreachedBarricade(canvas, 114, 10, 24, 21, 5, rng)
|
const b4 = stampBreachedBarricade(canvas, 114 + rng.int(-2, 2), 10 + rng.int(-1, 1), 24, 21 + rng.int(0, 1), 5, rng)
|
||||||
totalBarricadeWalls += b4.wallCount
|
totalBarricadeWalls += b4.wallCount
|
||||||
totalTrenchCells += b4.breachFloorCount
|
totalTrenchCells += b4.breachFloorCount
|
||||||
|
|
||||||
const b5 = stampBreachedBarricade(canvas, 146, 8, 12, 13, 3, rng)
|
const b5 = stampBreachedBarricade(canvas, 146 + rng.int(-2, 2), 8 + rng.int(-1, 1), 12, 13, 3, rng)
|
||||||
totalBarricadeWalls += b5.wallCount
|
totalBarricadeWalls += b5.wallCount
|
||||||
totalTrenchCells += b5.breachFloorCount
|
totalTrenchCells += b5.breachFloorCount
|
||||||
midObstacles += 2
|
midObstacles += 2
|
||||||
|
|
||||||
// Catapult Platforms (1 platform)
|
// Catapult Platforms (1 platform)
|
||||||
stampCatapultPlatform(canvas, 86, 30, 4, 4, rng)
|
stampCatapultPlatform(canvas, 86 + rng.int(-2, 2), 30 + rng.int(-1, 1), 4, 4, rng)
|
||||||
catapultPlatformCount += 1
|
catapultPlatformCount += 1
|
||||||
midObstacles += 1
|
midObstacles += 1
|
||||||
|
|
||||||
// Fort Ruins (1 ruin)
|
// Fort Ruins (1 ruin)
|
||||||
stampFortRuin(canvas, 124, 10, 4, rng)
|
stampFortRuin(canvas, 124 + rng.int(-2, 2), 10 + rng.int(-1, 1), 4, rng)
|
||||||
fortRuinCount += 1
|
fortRuinCount += 1
|
||||||
midObstacles += 1
|
midObstacles += 1
|
||||||
|
|
||||||
|
|
@ -479,11 +479,11 @@ export function stampAct5SiegeStrips(
|
||||||
// Zone 3: East Rear (x in [160, 240)) - Low density (Harrogath outskirts)
|
// Zone 3: East Rear (x in [160, 240)) - Low density (Harrogath outskirts)
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
// Trenches (1 trench)
|
// Trenches (1 trench)
|
||||||
totalTrenchCells += stampTrench(canvas, 186, 12, 10, 'vertical', rng)
|
totalTrenchCells += stampTrench(canvas, 186 + rng.int(-2, 2), 12 + rng.int(-1, 1), 10 + rng.int(-1, 1), 'vertical', rng)
|
||||||
eastObstacles += 1
|
eastObstacles += 1
|
||||||
|
|
||||||
// Breached Barricades (1 barricade)
|
// Breached Barricades (1 barricade)
|
||||||
const b6 = stampBreachedBarricade(canvas, 202, 10, 24, 21, 5, rng)
|
const b6 = stampBreachedBarricade(canvas, 202 + rng.int(-2, 2), 10 + rng.int(-1, 1), 24, 21 + rng.int(0, 1), 5, rng)
|
||||||
totalBarricadeWalls += b6.wallCount
|
totalBarricadeWalls += b6.wallCount
|
||||||
totalTrenchCells += b6.breachFloorCount
|
totalTrenchCells += b6.breachFloorCount
|
||||||
eastObstacles += 1
|
eastObstacles += 1
|
||||||
|
|
@ -491,7 +491,7 @@ export function stampAct5SiegeStrips(
|
||||||
// Catapult Platforms (0 platforms in rear reserve)
|
// Catapult Platforms (0 platforms in rear reserve)
|
||||||
|
|
||||||
// Fort Ruins (1 ruin)
|
// Fort Ruins (1 ruin)
|
||||||
stampFortRuin(canvas, 170, 30, 4, rng)
|
stampFortRuin(canvas, 170 + rng.int(-2, 2), 30 + rng.int(-1, 1), 4, rng)
|
||||||
fortRuinCount += 1
|
fortRuinCount += 1
|
||||||
eastObstacles += 1
|
eastObstacles += 1
|
||||||
|
|
||||||
|
|
@ -510,6 +510,8 @@ export function stampAct5SiegeStrips(
|
||||||
}
|
}
|
||||||
|
|
||||||
stats.siegeTopography = siegeStats
|
stats.siegeTopography = siegeStats
|
||||||
|
stats.proceduralWallCells = (stats.proceduralWallCells ?? 0) + totalBarricadeWalls
|
||||||
|
stats.proceduralRoadCells = (stats.proceduralRoadCells ?? 0) + totalTrenchCells
|
||||||
stats.notes.push('generated dynamic siege trenches and fortifications')
|
stats.notes.push('generated dynamic siege trenches and fortifications')
|
||||||
|
|
||||||
return placed
|
return placed
|
||||||
|
|
|
||||||
|
|
@ -415,4 +415,59 @@ describe("Act 5 Bloody Foothills Dynamic Siege Generation (DRLGOUTSIEGE)", () =>
|
||||||
expect(notes).toContain("generated dynamic siege trenches and fortifications")
|
expect(notes).toContain("generated dynamic siege trenches and fortifications")
|
||||||
expect(result.stats.siegeTopography).toBeDefined()
|
expect(result.stats.siegeTopography).toBeDefined()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test("generates varied obstacle layouts with different seeds (seed diversity)", () => {
|
||||||
|
const pieces = createMockSiegePieces()
|
||||||
|
const result1 = generateWilderness({
|
||||||
|
levelId: 110,
|
||||||
|
levelName: "Bloody Foothills",
|
||||||
|
levelTypeName: "Act 5 - Siege",
|
||||||
|
sizeX: 240,
|
||||||
|
sizeY: 48,
|
||||||
|
subType: -1,
|
||||||
|
subTheme: -1,
|
||||||
|
seed: 11001,
|
||||||
|
pieces,
|
||||||
|
substitutions: [],
|
||||||
|
})
|
||||||
|
|
||||||
|
const result2 = generateWilderness({
|
||||||
|
levelId: 110,
|
||||||
|
levelName: "Bloody Foothills",
|
||||||
|
levelTypeName: "Act 5 - Siege",
|
||||||
|
sizeX: 240,
|
||||||
|
sizeY: 48,
|
||||||
|
subType: -1,
|
||||||
|
subTheme: -1,
|
||||||
|
seed: 11002,
|
||||||
|
pieces,
|
||||||
|
substitutions: [],
|
||||||
|
})
|
||||||
|
|
||||||
|
// Collect obstacle wall coordinates for both seeds
|
||||||
|
const walls1 = new Set<string>()
|
||||||
|
const walls2 = new Set<string>()
|
||||||
|
|
||||||
|
for (let y = 0; y < result1.level.height; y += 1) {
|
||||||
|
for (let x = 0; x < result1.level.width; x += 1) {
|
||||||
|
if (result1.level.cells[y]![x]!.walls.some(w => !w.hidden && w.prop1 !== 0)) {
|
||||||
|
walls1.add(`${x},${y}`)
|
||||||
|
}
|
||||||
|
if (result2.level.cells[y]![x]!.walls.some(w => !w.hidden && w.prop1 !== 0)) {
|
||||||
|
walls2.add(`${x},${y}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Both should have placed walls
|
||||||
|
expect(walls1.size).toBeGreaterThan(0)
|
||||||
|
expect(walls2.size).toBeGreaterThan(0)
|
||||||
|
|
||||||
|
// The obstacle coordinates must differ across different seeds
|
||||||
|
let diffCount = 0
|
||||||
|
for (const coord of walls1) {
|
||||||
|
if (!walls2.has(coord)) diffCount += 1
|
||||||
|
}
|
||||||
|
expect(diffCount).toBeGreaterThan(0)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue