71 lines
2.9 KiB
TypeScript
71 lines
2.9 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
import { existsSync, readFileSync } from 'node:fs'
|
|
import { join } from 'node:path'
|
|
import { MONSTER_ART_MAP } from '../src/game/monster-mapping.ts'
|
|
|
|
describe('offline pre-baked entity atlases (Issue #30)', () => {
|
|
const packRoot = join(process.cwd(), 'samples', 'd2-packs')
|
|
const hasPacks = existsSync(join(packRoot, 'act1', 'entities', 'char-so.json'))
|
|
|
|
it.skipIf(!hasPacks)('bakes Sorceress char-so PNG + JSON for Acts 1..5', () => {
|
|
for (let act = 1; act <= 5; act += 1) {
|
|
const dir = join(packRoot, `act${act}`, 'entities')
|
|
const jsonPath = join(dir, 'char-so.json')
|
|
const pngPath = join(dir, 'char-so.png')
|
|
expect(existsSync(jsonPath)).toBe(true)
|
|
expect(existsSync(pngPath)).toBe(true)
|
|
|
|
const meta = JSON.parse(readFileSync(jsonPath, 'utf8'))
|
|
expect(meta.file).toBe('char-so.png')
|
|
expect(meta.directions).toBe(16)
|
|
expect(meta.walk).toBe(0)
|
|
expect(meta.stand).toBe(16)
|
|
expect(meta.members).toBeGreaterThanOrEqual(16)
|
|
expect(meta.groups.length).toBe(32) // 16 walk + 16 stand
|
|
|
|
const png = readFileSync(pngPath)
|
|
// Check PNG magic header
|
|
expect(png[0]).toBe(137)
|
|
expect(png[1]).toBe(80) // P
|
|
expect(png[2]).toBe(78) // N
|
|
expect(png[3]).toBe(71) // G
|
|
// Read IHDR width and height
|
|
const view = new DataView(png.buffer, png.byteOffset, png.byteLength)
|
|
expect(view.getUint32(16)).toBe(meta.width)
|
|
expect(view.getUint32(20)).toBe(meta.height)
|
|
}
|
|
})
|
|
|
|
it.skipIf(!hasPacks)('bakes monster PNG + JSON atlases for all mapped monster specs across Acts 1..5', () => {
|
|
const uniqueSpecs = new Map<string, { token: string; weapon: string }>()
|
|
for (const spec of Object.values(MONSTER_ART_MAP)) {
|
|
const key = `${spec.token}-${spec.weapon}`
|
|
if (!uniqueSpecs.has(key)) uniqueSpecs.set(key, spec)
|
|
}
|
|
|
|
for (let act = 1; act <= 5; act += 1) {
|
|
const dir = join(packRoot, `act${act}`, 'entities')
|
|
for (const spec of uniqueSpecs.values()) {
|
|
const slug = `monster-${spec.token.toLowerCase()}-${spec.weapon.toLowerCase()}`
|
|
const jsonPath = join(dir, `${slug}.json`)
|
|
const pngPath = join(dir, `${slug}.png`)
|
|
expect(existsSync(jsonPath), `missing ${jsonPath}`).toBe(true)
|
|
expect(existsSync(pngPath), `missing ${pngPath}`).toBe(true)
|
|
|
|
const meta = JSON.parse(readFileSync(jsonPath, 'utf8'))
|
|
expect(meta.token).toBe(spec.token)
|
|
expect(meta.weapon).toBe(spec.weapon)
|
|
expect(meta.directions).toBe(8)
|
|
expect(meta.walkOffset).toBe(0)
|
|
expect(meta.standOffset).toBe(8)
|
|
expect(meta.groups.length).toBe(16) // 8 walk + 8 stand
|
|
|
|
const png = readFileSync(pngPath)
|
|
const view = new DataView(png.buffer, png.byteOffset, png.byteLength)
|
|
expect(view.getUint32(16)).toBe(meta.width)
|
|
expect(view.getUint32(20)).toBe(meta.height)
|
|
}
|
|
}
|
|
})
|
|
})
|