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
This commit is contained in:
parent
4213cff80b
commit
2d7c7be510
|
|
@ -121,6 +121,27 @@ export const LVLPREST_ACT5_TEMPLE_REMAPPING_BASE = 1044
|
|||
export const LVLPREST_ACT5_TEMPLE_FINAL_ROOM = 1059
|
||||
export const LVLPREST_ACT5_TEMPLE_NIHLATHAK_WING_BASE = 1060
|
||||
|
||||
export const LVLPREST_ACT2_CORRUPT_HAREM_NE = 354
|
||||
export const LVLPREST_ACT2_CORRUPT_HAREM_SE = 355
|
||||
export const LVLPREST_ACT2_CORRUPT_HAREM_SW = 356
|
||||
export const LVLPREST_ACT2_CORRUPT_HAREM_NW = 357
|
||||
export const LVLPREST_ACT2_BASEMENT_NE = 358
|
||||
export const LVLPREST_ACT2_BASEMENT_SE = 359
|
||||
export const LVLPREST_ACT2_BASEMENT_SW = 360
|
||||
export const LVLPREST_ACT2_BASEMENT_NW = 361
|
||||
export const LVLPREST_ACT3_SPIDER_SW = 659
|
||||
export const LVLPREST_ACT3_SPIDER_SE = 660
|
||||
export const LVLPREST_ACT3_SPIDER_NW = 661
|
||||
export const LVLPREST_ACT3_SPIDER_NE = 662
|
||||
export const LVLPREST_ACT3_SPIDER_CHEST_NW = 663
|
||||
export const LVLPREST_ACT3_SPIDER_CHEST_NE = 664
|
||||
export const LVLPREST_ACT5_LAVA_N = 1053
|
||||
export const LVLPREST_ACT5_LAVA_S = 1054
|
||||
export const LVLPREST_ACT5_LAVA_E = 1055
|
||||
export const LVLPREST_ACT5_LAVA_W = 1056
|
||||
export const LVLPREST_ACT5_LAVA_EW = 1057
|
||||
export const LVLPREST_ACT5_LAVA_NS = 1058
|
||||
|
||||
/**
|
||||
* 1.13c `nExpansionHardcodedPresetsRemapping` orientations for Act 5 Temple levels (`DrlgMaze.cpp`).
|
||||
*/
|
||||
|
|
@ -141,6 +162,8 @@ export const LVLPREST_MAZE_DEF_REGISTRY: Readonly<Record<number, { readonly name
|
|||
[LVLPREST_ACT5_ICE_POOL_A]: { name: 'Act 5 - Ice Pool A', kind: 'quest' },
|
||||
[LVLPREST_ACT5_ICE_POOL_B]: { name: 'Act 5 - Ice Pool B', kind: 'quest' },
|
||||
[LVLPREST_ACT5_TEMPLE_FINAL_ROOM]: { name: 'Act 5 - Temple Final Room', kind: 'quest' },
|
||||
[LVLPREST_ACT3_SPIDER_CHEST_NW]: { name: 'Act 3 - Spider Chest NW', kind: 'treasure', sides: 'NW' },
|
||||
[LVLPREST_ACT3_SPIDER_CHEST_NE]: { name: 'Act 3 - Spider Chest NE', kind: 'treasure', sides: 'NE' },
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -846,9 +846,37 @@ export const MAZE_LEVEL_TYPE_PROFILES: readonly MazeLevelProfile[] = [
|
|||
arcane: true,
|
||||
specials: [{ kind: 'quest', entries: entries() }],
|
||||
},
|
||||
{ levelTypeName: 'Act 2 - Harem', ring: 2, grow: false, theme: false, specials: [] },
|
||||
{ levelTypeName: 'Act 2 - Basement', ring: 2, grow: false, theme: false, specials: [] },
|
||||
{ levelTypeName: 'Act 3 - Spider', ring: 2, grow: false, theme: false, specials: [] },
|
||||
{
|
||||
levelTypeName: 'Act 2 - Harem',
|
||||
ring: 2,
|
||||
grow: false,
|
||||
theme: false,
|
||||
specials: [
|
||||
{ kind: 'prev', entries: entries(), levelIds: [51] },
|
||||
{ kind: 'next', entries: entries(), levelIds: [51] },
|
||||
],
|
||||
},
|
||||
{
|
||||
levelTypeName: 'Act 2 - Basement',
|
||||
ring: 2,
|
||||
grow: false,
|
||||
theme: false,
|
||||
specials: [
|
||||
{ kind: 'prev', entries: entries(), levelIds: [52, 53, 54] },
|
||||
{ kind: 'waypoint', entries: entries(), levelIds: [52] },
|
||||
{ kind: 'next', entries: entries(), levelIds: [52, 53] },
|
||||
],
|
||||
},
|
||||
{
|
||||
levelTypeName: 'Act 3 - Spider',
|
||||
ring: 2,
|
||||
grow: false,
|
||||
theme: false,
|
||||
specials: [
|
||||
{ kind: 'prev', entries: entries(), levelIds: [84, 85] },
|
||||
{ kind: 'treasure', entries: entries(), levelIds: [84, 85] },
|
||||
],
|
||||
},
|
||||
{
|
||||
levelTypeName: 'Act 3 - Kurast',
|
||||
ring: 2,
|
||||
|
|
@ -987,7 +1015,16 @@ export const MAZE_LEVEL_TYPE_PROFILES: readonly MazeLevelProfile[] = [
|
|||
],
|
||||
specialPass: 'DRLGMAZE_PlaceAct5BaalStuff',
|
||||
},
|
||||
{ levelTypeName: 'Act 5 - Lava', grow: false, theme: false, lavaPairs: true, specials: [] },
|
||||
{
|
||||
levelTypeName: 'Act 5 - Lava',
|
||||
grow: false,
|
||||
theme: false,
|
||||
lavaPairs: true,
|
||||
specials: [
|
||||
{ kind: 'prev', entries: entries(), levelIds: [125, 126, 127] },
|
||||
{ kind: 'treasure', entries: entries(), levelIds: [125, 126, 127] },
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -109,28 +109,21 @@ function createStandardPieceSet(levelTypeName: string, extraPieces: MazePiece[]
|
|||
}
|
||||
|
||||
describe('Diablo II DRLG Maze Special Passes', () => {
|
||||
// Was `expect(UNIMPLEMENTED_PASSES).toEqual([])`: the constant was hardcoded
|
||||
// to `[]`, so it asserted a claim the profile table contradicts. The gap list
|
||||
// is now derived, so the honest assertion is "it names exactly the level types
|
||||
// whose `specials` table is still empty".
|
||||
test('UNIMPLEMENTED_PASSES names every level type with no transcribed specials table', () => {
|
||||
test('UNIMPLEMENTED_PASSES is empty when all maze profiles define specials', () => {
|
||||
const emptySpecials = MAZE_LEVEL_TYPE_PROFILES
|
||||
.filter(profile => profile.specials.length === 0 && profile.singleRoom === undefined)
|
||||
.map(profile => profile.levelTypeName)
|
||||
expect(emptySpecials.length).toBeGreaterThan(0)
|
||||
expect(UNIMPLEMENTED_PASSES).toEqual(
|
||||
emptySpecials.map(name => `DRLGMAZE_GenerateLevel specials table (${name})`),
|
||||
)
|
||||
expect(emptySpecials).toEqual([])
|
||||
expect(UNIMPLEMENTED_PASSES).toEqual([])
|
||||
})
|
||||
|
||||
test('unimplementedPassesFor is empty for a fully transcribed level type', () => {
|
||||
expect(unimplementedPassesFor('Act 1 - Cave')).toEqual([])
|
||||
expect(unimplementedPassesFor('Act 2 - Tomb')).toEqual([])
|
||||
})
|
||||
|
||||
test('unimplementedPassesFor reports the gap for a level type with no specials', () => {
|
||||
expect(unimplementedPassesFor('Act 3 - Spider'))
|
||||
.toEqual(['DRLGMAZE_GenerateLevel specials table (Act 3 - Spider)'])
|
||||
expect(unimplementedPassesFor('Act 2 - Harem')).toEqual([])
|
||||
expect(unimplementedPassesFor('Act 2 - Basement')).toEqual([])
|
||||
expect(unimplementedPassesFor('Act 3 - Spider')).toEqual([])
|
||||
expect(unimplementedPassesFor('Act 5 - Lava')).toEqual([])
|
||||
})
|
||||
|
||||
test('unimplementedPassesFor reports a level type that has no profile at all', () => {
|
||||
|
|
@ -138,7 +131,7 @@ describe('Diablo II DRLG Maze Special Passes', () => {
|
|||
.toEqual(['DRLGMAZE_GenerateLevel profile (Act 9 - Nowhere)'])
|
||||
})
|
||||
|
||||
test('generateMaze reports the level type gap, not a global constant', () => {
|
||||
test('generateMaze reports empty unimplementedPasses for transcribed levels', () => {
|
||||
const spider = generateMaze({
|
||||
levelId: 84,
|
||||
levelName: 'Spider Cavern',
|
||||
|
|
@ -148,8 +141,7 @@ describe('Diablo II DRLG Maze Special Passes', () => {
|
|||
seed: 8484,
|
||||
pieces: createStandardPieceSet('Act 3 - Spider'),
|
||||
})
|
||||
expect(spider.stats.unimplementedPasses)
|
||||
.toEqual(['DRLGMAZE_GenerateLevel specials table (Act 3 - Spider)'])
|
||||
expect(spider.stats.unimplementedPasses).toEqual([])
|
||||
// The other two diagnostic channels must travel with it.
|
||||
expect(Array.isArray(spider.stats.unresolvedRoles)).toBe(true)
|
||||
expect(Array.isArray(spider.stats.notes)).toBe(true)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,348 @@
|
|||
import { describe, test, expect } from 'vitest'
|
||||
import {
|
||||
generateMaze,
|
||||
unimplementedPassesFor,
|
||||
UNIMPLEMENTED_PASSES,
|
||||
MAZE_LEVEL_TYPE_PROFILES,
|
||||
type MazePiece,
|
||||
type MazePieceKind,
|
||||
type MazeWarp,
|
||||
type MazeWaypoint,
|
||||
} from '../src/game/maze.ts'
|
||||
import {
|
||||
LVLPREST_ACT2_CORRUPT_HAREM_NE,
|
||||
LVLPREST_ACT2_CORRUPT_HAREM_SE,
|
||||
LVLPREST_ACT2_CORRUPT_HAREM_SW,
|
||||
LVLPREST_ACT2_CORRUPT_HAREM_NW,
|
||||
LVLPREST_ACT2_BASEMENT_NE,
|
||||
LVLPREST_ACT2_BASEMENT_SE,
|
||||
LVLPREST_ACT2_BASEMENT_SW,
|
||||
LVLPREST_ACT2_BASEMENT_NW,
|
||||
LVLPREST_ACT3_SPIDER_SW,
|
||||
LVLPREST_ACT3_SPIDER_SE,
|
||||
LVLPREST_ACT3_SPIDER_NW,
|
||||
LVLPREST_ACT3_SPIDER_NE,
|
||||
LVLPREST_ACT3_SPIDER_CHEST_NW,
|
||||
LVLPREST_ACT3_SPIDER_CHEST_NE,
|
||||
LVLPREST_ACT5_LAVA_N,
|
||||
LVLPREST_ACT5_LAVA_S,
|
||||
LVLPREST_ACT5_LAVA_E,
|
||||
LVLPREST_ACT5_LAVA_W,
|
||||
LVLPREST_ACT5_LAVA_EW,
|
||||
LVLPREST_ACT5_LAVA_NS,
|
||||
LVLPREST_MAZE_DEF_REGISTRY,
|
||||
} from '../src/game/maze-special-passes.ts'
|
||||
import type { Ds1, Ds1Cell, Ds1Object } from '../src/formats/ds1.ts'
|
||||
|
||||
function mockDs1(width = 10, height = 10, objects: Ds1Object[] = []): Ds1 {
|
||||
const cells: Ds1Cell[][] = []
|
||||
for (let y = 0; y < height; y++) {
|
||||
const row: Ds1Cell[] = []
|
||||
for (let x = 0; x < width; x++) {
|
||||
row.push({
|
||||
walls: [{ prop1: 1, sequence: 0, style: 0, type: 0, unknown1: 0, unknown2: 0, hidden: false }],
|
||||
floors: [{ prop1: 1, sequence: 0, style: 0, unknown1: 0, unknown2: 0, hidden: false }],
|
||||
shadows: [{ prop1: 0, sequence: 0, style: 0, unknown1: 0, unknown2: 0, hidden: false }],
|
||||
substitutions: [],
|
||||
})
|
||||
}
|
||||
cells.push(row)
|
||||
}
|
||||
return {
|
||||
version: 18,
|
||||
width,
|
||||
height,
|
||||
act: 1,
|
||||
substitutionType: 0,
|
||||
wallLayers: 1,
|
||||
floorLayers: 1,
|
||||
cells,
|
||||
objects,
|
||||
npcPathOffset: null,
|
||||
}
|
||||
}
|
||||
|
||||
function mockPiece(
|
||||
name: string,
|
||||
kind: MazePieceKind,
|
||||
sides = '',
|
||||
objects: Ds1Object[] = [],
|
||||
width = 10,
|
||||
height = 10,
|
||||
): MazePiece {
|
||||
return {
|
||||
name,
|
||||
kind,
|
||||
sides,
|
||||
levels: [mockDs1(width, height, objects)],
|
||||
}
|
||||
}
|
||||
|
||||
const SIDES = ['W', 'E', 'EW', 'S', 'SW', 'SE', 'SEW', 'N', 'NW', 'NE', 'NEW', 'NS', 'NSW', 'NSE', 'NSEW']
|
||||
|
||||
function createPieceSetForType(
|
||||
levelTypeName: string,
|
||||
extraKinds: { kind: MazePieceKind; nameToken: string; objects?: Ds1Object[] }[] = [],
|
||||
): MazePiece[] {
|
||||
const pieces: MazePiece[] = [
|
||||
mockPiece(`${levelTypeName} Entrance`, 'entrance', ''),
|
||||
...SIDES.map(s => mockPiece(`${levelTypeName} ${s}`, 'room', s)),
|
||||
...['N', 'S', 'E', 'W'].map(s =>
|
||||
mockPiece(`${levelTypeName} Prev ${s}`, 'prev', s, [{ type: 2, id: 1, x: 25, y: 25, flags: 0 }]),
|
||||
),
|
||||
...['N', 'S', 'E', 'W'].map(s =>
|
||||
mockPiece(`${levelTypeName} Next ${s}`, 'next', s, [{ type: 2, id: 2, x: 25, y: 25, flags: 0 }]),
|
||||
),
|
||||
...['N', 'S', 'E', 'W'].map(s =>
|
||||
mockPiece(`${levelTypeName} Waypoint ${s}`, 'waypoint', s, [{ type: 2, id: 156, x: 25, y: 25, flags: 0 }]),
|
||||
),
|
||||
...['N', 'S', 'E', 'W'].map(s =>
|
||||
mockPiece(`${levelTypeName} Treasure ${s}`, 'treasure', s, [{ type: 2, id: 397, x: 25, y: 25, flags: 0 }]),
|
||||
),
|
||||
]
|
||||
for (const extra of extraKinds) {
|
||||
for (const s of ['N', 'S', 'E', 'W', 'NW', 'NE', 'SW', 'SE']) {
|
||||
pieces.push(mockPiece(`${levelTypeName} ${extra.nameToken} ${s}`, extra.kind, s, extra.objects ?? []))
|
||||
}
|
||||
}
|
||||
return pieces
|
||||
}
|
||||
|
||||
describe('Maze Specials Profiles (Issue #84)', () => {
|
||||
describe('Profile completeness and unimplementedPasses check', () => {
|
||||
test('all 4 target level types report 0 unimplemented passes', () => {
|
||||
expect(unimplementedPassesFor('Act 2 - Harem')).toEqual([])
|
||||
expect(unimplementedPassesFor('Act 2 - Basement')).toEqual([])
|
||||
expect(unimplementedPassesFor('Act 3 - Spider')).toEqual([])
|
||||
expect(unimplementedPassesFor('Act 5 - Lava')).toEqual([])
|
||||
})
|
||||
|
||||
test('UNIMPLEMENTED_PASSES global array is completely empty', () => {
|
||||
expect(UNIMPLEMENTED_PASSES).toEqual([])
|
||||
})
|
||||
|
||||
test('profile table contains correctly configured special tables for all four types', () => {
|
||||
const harem = MAZE_LEVEL_TYPE_PROFILES.find(p => p.levelTypeName === 'Act 2 - Harem')!
|
||||
expect(harem).toBeDefined()
|
||||
expect(harem.ring).toBe(2)
|
||||
expect(harem.grow).toBe(false)
|
||||
expect(harem.specials.map(s => ({ kind: s.kind, levelIds: s.levelIds }))).toEqual([
|
||||
{ kind: 'prev', levelIds: [51] },
|
||||
{ kind: 'next', levelIds: [51] },
|
||||
])
|
||||
|
||||
const basement = MAZE_LEVEL_TYPE_PROFILES.find(p => p.levelTypeName === 'Act 2 - Basement')!
|
||||
expect(basement).toBeDefined()
|
||||
expect(basement.ring).toBe(2)
|
||||
expect(basement.grow).toBe(false)
|
||||
expect(basement.specials.map(s => ({ kind: s.kind, levelIds: s.levelIds }))).toEqual([
|
||||
{ kind: 'prev', levelIds: [52, 53, 54] },
|
||||
{ kind: 'waypoint', levelIds: [52] },
|
||||
{ kind: 'next', levelIds: [52, 53] },
|
||||
])
|
||||
|
||||
const spider = MAZE_LEVEL_TYPE_PROFILES.find(p => p.levelTypeName === 'Act 3 - Spider')!
|
||||
expect(spider).toBeDefined()
|
||||
expect(spider.ring).toBe(2)
|
||||
expect(spider.grow).toBe(false)
|
||||
expect(spider.specials.map(s => ({ kind: s.kind, levelIds: s.levelIds }))).toEqual([
|
||||
{ kind: 'prev', levelIds: [84, 85] },
|
||||
{ kind: 'treasure', levelIds: [84, 85] },
|
||||
])
|
||||
|
||||
const lava = MAZE_LEVEL_TYPE_PROFILES.find(p => p.levelTypeName === 'Act 5 - Lava')!
|
||||
expect(lava).toBeDefined()
|
||||
expect(lava.grow).toBe(false)
|
||||
expect(lava.lavaPairs).toBe(true)
|
||||
expect(lava.specials.map(s => ({ kind: s.kind, levelIds: s.levelIds }))).toEqual([
|
||||
{ kind: 'prev', levelIds: [125, 126, 127] },
|
||||
{ kind: 'treasure', levelIds: [125, 126, 127] },
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
describe('LvlPrest constants & def registry', () => {
|
||||
test('defines canonical LvlPrest Def IDs', () => {
|
||||
expect(LVLPREST_ACT2_CORRUPT_HAREM_NE).toBe(354)
|
||||
expect(LVLPREST_ACT2_CORRUPT_HAREM_SE).toBe(355)
|
||||
expect(LVLPREST_ACT2_CORRUPT_HAREM_SW).toBe(356)
|
||||
expect(LVLPREST_ACT2_CORRUPT_HAREM_NW).toBe(357)
|
||||
|
||||
expect(LVLPREST_ACT2_BASEMENT_NE).toBe(358)
|
||||
expect(LVLPREST_ACT2_BASEMENT_SE).toBe(359)
|
||||
expect(LVLPREST_ACT2_BASEMENT_SW).toBe(360)
|
||||
expect(LVLPREST_ACT2_BASEMENT_NW).toBe(361)
|
||||
|
||||
expect(LVLPREST_ACT3_SPIDER_SW).toBe(659)
|
||||
expect(LVLPREST_ACT3_SPIDER_SE).toBe(660)
|
||||
expect(LVLPREST_ACT3_SPIDER_NW).toBe(661)
|
||||
expect(LVLPREST_ACT3_SPIDER_NE).toBe(662)
|
||||
expect(LVLPREST_ACT3_SPIDER_CHEST_NW).toBe(663)
|
||||
expect(LVLPREST_ACT3_SPIDER_CHEST_NE).toBe(664)
|
||||
|
||||
expect(LVLPREST_ACT5_LAVA_N).toBe(1053)
|
||||
expect(LVLPREST_ACT5_LAVA_S).toBe(1054)
|
||||
expect(LVLPREST_ACT5_LAVA_E).toBe(1055)
|
||||
expect(LVLPREST_ACT5_LAVA_W).toBe(1056)
|
||||
expect(LVLPREST_ACT5_LAVA_EW).toBe(1057)
|
||||
expect(LVLPREST_ACT5_LAVA_NS).toBe(1058)
|
||||
})
|
||||
|
||||
test('registers Spider chests in LVLPREST_MAZE_DEF_REGISTRY', () => {
|
||||
expect(LVLPREST_MAZE_DEF_REGISTRY[LVLPREST_ACT3_SPIDER_CHEST_NW]).toEqual({
|
||||
name: 'Act 3 - Spider Chest NW',
|
||||
kind: 'treasure',
|
||||
sides: 'NW',
|
||||
})
|
||||
expect(LVLPREST_MAZE_DEF_REGISTRY[LVLPREST_ACT3_SPIDER_CHEST_NE]).toEqual({
|
||||
name: 'Act 3 - Spider Chest NE',
|
||||
kind: 'treasure',
|
||||
sides: 'NE',
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('generateMaze execution with specials', () => {
|
||||
test('Act 2 - Harem (Level 51) places prev and next specials', () => {
|
||||
const pieces = createPieceSetForType('Act 2 - Harem')
|
||||
const result = generateMaze({
|
||||
levelId: 51,
|
||||
levelName: 'Harem Level 2',
|
||||
levelTypeName: 'Act 2 - Harem',
|
||||
sectionSize: 10,
|
||||
minRooms: 4,
|
||||
merge: 0,
|
||||
seed: 51001,
|
||||
pieces,
|
||||
})
|
||||
|
||||
expect(result.stats.unimplementedPasses).toEqual([])
|
||||
const specials = result.stats.specialsApplied as { room: number; kind: string; sides: string }[]
|
||||
const kinds = specials.map(s => s.kind)
|
||||
expect(kinds).toContain('prev')
|
||||
expect(kinds).toContain('next')
|
||||
const warps = result.stats.warps as MazeWarp[]
|
||||
expect(warps.length).toBeGreaterThanOrEqual(2)
|
||||
expect(warps.some(w => w.direction === 'up')).toBe(true)
|
||||
expect(warps.some(w => w.direction === 'down')).toBe(true)
|
||||
})
|
||||
|
||||
test('Act 2 - Basement (Level 52) places prev, waypoint, and next specials', () => {
|
||||
const pieces = createPieceSetForType('Act 2 - Basement')
|
||||
const result = generateMaze({
|
||||
levelId: 52,
|
||||
levelName: 'Palace Cellar Level 1',
|
||||
levelTypeName: 'Act 2 - Basement',
|
||||
sectionSize: 10,
|
||||
minRooms: 4,
|
||||
merge: 0,
|
||||
seed: 52001,
|
||||
pieces,
|
||||
hasWaypoint: true,
|
||||
})
|
||||
|
||||
expect(result.stats.unimplementedPasses).toEqual([])
|
||||
const specials = result.stats.specialsApplied as { room: number; kind: string; sides: string }[]
|
||||
const kinds = specials.map(s => s.kind)
|
||||
expect(kinds).toContain('prev')
|
||||
expect(kinds).toContain('waypoint')
|
||||
expect(kinds).toContain('next')
|
||||
const waypoints = result.stats.waypoints as MazeWaypoint[]
|
||||
expect(waypoints.length).toBe(1)
|
||||
const warps = result.stats.warps as MazeWarp[]
|
||||
expect(warps.length).toBeGreaterThanOrEqual(2)
|
||||
})
|
||||
|
||||
test('Act 2 - Basement (Level 53) places prev and next without waypoint', () => {
|
||||
const pieces = createPieceSetForType('Act 2 - Basement')
|
||||
const result = generateMaze({
|
||||
levelId: 53,
|
||||
levelName: 'Palace Cellar Level 2',
|
||||
levelTypeName: 'Act 2 - Basement',
|
||||
sectionSize: 10,
|
||||
minRooms: 4,
|
||||
merge: 0,
|
||||
seed: 53001,
|
||||
pieces,
|
||||
})
|
||||
|
||||
expect(result.stats.unimplementedPasses).toEqual([])
|
||||
const specials = result.stats.specialsApplied as { room: number; kind: string; sides: string }[]
|
||||
const kinds = specials.map(s => s.kind)
|
||||
expect(kinds).toContain('prev')
|
||||
expect(kinds).toContain('next')
|
||||
expect(kinds).not.toContain('waypoint')
|
||||
const waypoints = result.stats.waypoints as MazeWaypoint[]
|
||||
expect(waypoints.length).toBe(0)
|
||||
})
|
||||
|
||||
test('Act 2 - Basement (Level 54) places prev only', () => {
|
||||
const pieces = createPieceSetForType('Act 2 - Basement')
|
||||
const result = generateMaze({
|
||||
levelId: 54,
|
||||
levelName: 'Palace Cellar Level 3',
|
||||
levelTypeName: 'Act 2 - Basement',
|
||||
sectionSize: 10,
|
||||
minRooms: 4,
|
||||
merge: 0,
|
||||
seed: 54001,
|
||||
pieces,
|
||||
})
|
||||
|
||||
expect(result.stats.unimplementedPasses).toEqual([])
|
||||
const specials = result.stats.specialsApplied as { room: number; kind: string; sides: string }[]
|
||||
const kinds = specials.map(s => s.kind)
|
||||
expect(kinds).toContain('prev')
|
||||
expect(kinds).not.toContain('next')
|
||||
expect(kinds).not.toContain('waypoint')
|
||||
})
|
||||
|
||||
test('Act 3 - Spider (Level 84 & 85) places prev and treasure', () => {
|
||||
for (const levelId of [84, 85]) {
|
||||
const pieces = createPieceSetForType('Act 3 - Spider')
|
||||
const result = generateMaze({
|
||||
levelId,
|
||||
levelName: levelId === 84 ? 'Spider Cave' : 'Spider Cavern',
|
||||
levelTypeName: 'Act 3 - Spider',
|
||||
sectionSize: 10,
|
||||
minRooms: 4,
|
||||
merge: 0,
|
||||
seed: levelId * 1000 + 7,
|
||||
pieces,
|
||||
})
|
||||
|
||||
expect(result.stats.unimplementedPasses).toEqual([])
|
||||
const specials = result.stats.specialsApplied as { room: number; kind: string; sides: string }[]
|
||||
const kinds = specials.map(s => s.kind)
|
||||
expect(kinds).toContain('prev')
|
||||
expect(kinds).toContain('treasure')
|
||||
const warps = result.stats.warps as MazeWarp[]
|
||||
expect(warps.some(w => w.direction === 'up')).toBe(true)
|
||||
}
|
||||
})
|
||||
|
||||
test('Act 5 - Lava (Levels 125, 126, 127) places prev and treasure', () => {
|
||||
for (const levelId of [125, 126, 127]) {
|
||||
const pieces = createPieceSetForType('Act 5 - Lava')
|
||||
const result = generateMaze({
|
||||
levelId,
|
||||
levelName: `Lava Pit ${levelId}`,
|
||||
levelTypeName: 'Act 5 - Lava',
|
||||
sectionSize: 10,
|
||||
minRooms: 4,
|
||||
merge: 0,
|
||||
seed: levelId * 1000 + 9,
|
||||
pieces,
|
||||
})
|
||||
|
||||
expect(result.stats.unimplementedPasses).toEqual([])
|
||||
const specials = result.stats.specialsApplied as { room: number; kind: string; sides: string }[]
|
||||
const kinds = specials.map(s => s.kind)
|
||||
expect(kinds).toContain('prev')
|
||||
expect(kinds).toContain('treasure')
|
||||
const warps = result.stats.warps as MazeWarp[]
|
||||
expect(warps.some(w => w.direction === 'up')).toBe(true)
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
Loading…
Reference in New Issue