diablo2-web/tests/act-scene-object-dispatch.t...

145 lines
5.1 KiB
TypeScript

import { describe, it, expect } from 'vitest'
import {
ADDITIVE_OBJECT_TOKENS,
type ObjectDrawable,
} from '../src/scene/act-scene.ts'
import {
buildObjectDrawables,
executeDepthDrawDispatch,
MockRenderer,
type PackObjectInput,
type SimulatedWall,
} from '../scripts/verify-scene-object-dispatch.ts'
describe('Scene Object Rendering Dispatch (Milestone 1 / R1)', () => {
it('correctly maps all 1.13c additive tokens to blendMode: "additive"', () => {
const tokens = ['11', '12', 'R1', 'R2', 'R3', 'R4', 'R5', '1R', '2R', '3R', '4R', 'HA']
for (const token of tokens) {
expect(ADDITIVE_OBJECT_TOKENS.has(token)).toBe(true)
const drawables = buildObjectDrawables([
{
x: 100,
y: 200,
token,
frame: { x: 0, y: 0, width: 32, height: 32, offsetX: 0, offsetY: 0, page: 0 },
},
])
expect(drawables).toHaveLength(1)
expect(drawables[0]!.blendMode).toBe('additive')
}
})
it('correctly identifies trans=7 and trans=1 objects as additive', () => {
const drawables = buildObjectDrawables([
{
x: 10,
y: 20,
token: 'UNKNOWN',
trans: 7,
frame: { x: 0, y: 0, width: 32, height: 32, offsetX: 0, offsetY: 0, page: 0 },
},
{
x: 30,
y: 40,
token: 'OTHER',
trans: 1,
frame: { x: 0, y: 0, width: 32, height: 32, offsetX: 0, offsetY: 0, page: 0 },
},
])
expect(drawables).toHaveLength(2)
expect(drawables[0]!.blendMode).toBe('additive')
expect(drawables[1]!.blendMode).toBe('additive')
})
it('preserves blendMode: "normal" for regular objects and torches', () => {
const drawables = buildObjectDrawables([
{
x: 10,
y: 20,
token: 'CHEST',
trans: 0,
frame: { x: 0, y: 0, width: 32, height: 32, offsetX: 0, offsetY: 0, page: 0 },
},
{
x: 30,
y: 40,
token: 'TO',
trans: 0,
frame: { x: 0, y: 0, width: 32, height: 32, offsetX: 0, offsetY: 0, page: 0 },
},
])
expect(drawables).toHaveLength(2)
expect(drawables[0]!.blendMode).toBe('normal')
expect(drawables[1]!.blendMode).toBe('normal')
})
it('dispatches additive objects with blendMode: "additive" and regular objects with "normal"', () => {
const rawObjects: PackObjectInput[] = [
{ id: 1, token: '11', depth: 2, frame: { x: 0, y: 0, width: 10, height: 10, offsetX: 0, offsetY: 0, page: 0 }, x: 10, y: 0 },
{ id: 2, token: 'BOX', depth: 6, frame: { x: 0, y: 0, width: 10, height: 10, offsetX: 0, offsetY: 0, page: 0 }, x: 30, y: 0 },
]
const objs = buildObjectDrawables(rawObjects)
const walls: SimulatedWall[] = [
{ frame: { x: 0, y: 0, width: 32, height: 32, _depth: 4 } as any, x: 0, y: 0, cellX: 2, cellY: 2, page: 0 },
]
const renderer = new MockRenderer()
executeDepthDrawDispatch(renderer, {
walls,
objs,
maxDepthSteps: [Infinity],
})
expect(renderer.draws).toHaveLength(3)
// Draw 0: Object 1 (Token 11, depth 2) -> additive
expect(renderer.draws[0]!.target).toBe('object')
expect(renderer.draws[0]!.depth).toBe(2)
expect(renderer.draws[0]!.blendMode).toBe('additive')
// Draw 1: Wall (depth 4) -> blendMode undefined (options has { atlas })
expect(renderer.draws[1]!.target).toBe('wall')
expect(renderer.draws[1]!.depth).toBe(4)
expect(renderer.draws[1]!.blendMode).toBeUndefined()
// Draw 2: Object 2 (BOX, depth 6) -> normal
expect(renderer.draws[2]!.target).toBe('object')
expect(renderer.draws[2]!.depth).toBe(6)
expect(renderer.draws[2]!.blendMode).toBe('normal')
})
it('strictly preserves depth ordering across mixed walls, objects, and incremental depth steps', () => {
const rawObjects: PackObjectInput[] = [
{ id: 1, depth: 3, token: '11', frame: { x: 0, y: 0, width: 10, height: 10, offsetX: 0, offsetY: 0, page: 0 }, x: 15, y: 0 },
{ id: 2, depth: 8, token: '12', frame: { x: 0, y: 0, width: 10, height: 10, offsetX: 0, offsetY: 0, page: 0 }, x: 40, y: 0 },
{ id: 3, depth: 15, token: 'CHEST', frame: { x: 0, y: 0, width: 10, height: 10, offsetX: 0, offsetY: 0, page: 0 }, x: 75, y: 0 },
]
const objs = buildObjectDrawables(rawObjects)
const walls: SimulatedWall[] = [
{ frame: { x: 0, y: 0, width: 32, height: 32, _depth: 1 } as any, x: 0, y: 0, cellX: 0, cellY: 1, page: 0 },
{ frame: { x: 0, y: 0, width: 32, height: 32, _depth: 5 } as any, x: 0, y: 0, cellX: 2, cellY: 3, page: 0 },
{ frame: { x: 0, y: 0, width: 32, height: 32, _depth: 10 } as any, x: 0, y: 0, cellX: 5, cellY: 5, page: 0 },
]
const renderer = new MockRenderer()
executeDepthDrawDispatch(renderer, {
walls,
objs,
maxDepthSteps: [4, 9, Infinity],
})
expect(renderer.draws).toHaveLength(6)
// Verify non-decreasing order
for (let i = 1; i < renderer.draws.length; i++) {
expect(renderer.draws[i]!.depth).toBeGreaterThanOrEqual(renderer.draws[i - 1]!.depth)
}
const depths = renderer.draws.map(d => d.depth)
expect(depths).toEqual([1, 3, 5, 8, 10, 15])
})
})