import assert from 'node:assert/strict'; import test from 'node:test'; import { applyFieldEffectEraserStroke } from './fieldEffectEraser'; import type { EffectInstance } from './types/effects'; const base = { seed: 1, createdAtMs: 0 }; const makeId = (prefix: string) => `${prefix}_new`; void test('applyFieldEffectEraserStroke: удаляет точки в радиусе кисти', () => { const fog: EffectInstance = { ...base, id: 'f1', type: 'fog', points: [ { x: 0.2, y: 0.5, tMs: 0 }, { x: 0.5, y: 0.5, tMs: 100 }, { x: 0.8, y: 0.5, tMs: 200 }, ], radiusN: 0.02, opacity: 0.5, lifetimeMs: null, }; const next = applyFieldEffectEraserStroke([fog], [{ x: 0.5, y: 0.5, tMs: 0 }], 0.05, makeId); assert.equal(next.length, 2); const left = next[0]; const right = next[1]; assert.ok(left); assert.ok(right); assert.equal(left.type, 'fog'); assert.equal(right.type, 'fog'); assert.equal(left.points.length, 1); assert.equal(left.points[0]?.x, 0.2); assert.equal(right.points.length, 1); assert.equal(right.points[0]?.x, 0.8); }); void test('applyFieldEffectEraserStroke: стирает вдоль сегмента штриха', () => { const rain: EffectInstance = { ...base, id: 'r1', type: 'rain', points: [ { x: 0.1, y: 0.5, tMs: 0 }, { x: 0.3, y: 0.5, tMs: 50 }, { x: 0.5, y: 0.5, tMs: 100 }, { x: 0.7, y: 0.5, tMs: 150 }, { x: 0.9, y: 0.5, tMs: 200 }, ], radiusN: 0.01, opacity: 0.6, lifetimeMs: null, }; const next = applyFieldEffectEraserStroke( [rain], [ { x: 0.25, y: 0.5, tMs: 0 }, { x: 0.75, y: 0.5, tMs: 50 }, ], 0.04, makeId, ); assert.equal(next.length, 2); const xs = next.flatMap((i) => (i.type === 'rain' ? i.points.map((p) => p.x) : [])); assert.deepEqual(xs, [0.1, 0.9]); }); void test('applyFieldEffectEraserStroke: VFX-огонь стирается как полевой эффект', () => { const fire: EffectInstance = { ...base, id: 'fire_vfx', type: 'fire', points: [ { x: 0.2, y: 0.5, tMs: 0 }, { x: 0.5, y: 0.5, tMs: 100 }, ], radiusN: 0.02, opacity: 0.8, lifetimeMs: null, }; const next = applyFieldEffectEraserStroke([fire], [{ x: 0.5, y: 0.5, tMs: 0 }], 0.05, makeId); assert.equal(next.length, 1); const kept = next[0]; assert.equal(kept?.type === 'fire' && kept.points[0]?.x, 0.2); }); void test('applyFieldEffectEraserStroke: не трогает эффекты действия', () => { const fog: EffectInstance = { ...base, id: 'f1', type: 'fog', points: [{ x: 0.5, y: 0.5, tMs: 0 }], radiusN: 0.05, opacity: 1, lifetimeMs: null, }; const bolt: EffectInstance = { ...base, id: 'L1', type: 'lightning', start: { x: 0.5, y: 0 }, end: { x: 0.5, y: 0.8 }, widthN: 0.02, intensity: 1, lifetimeMs: 500, }; const next = applyFieldEffectEraserStroke([fog, bolt], [{ x: 0.5, y: 0.5, tMs: 0 }], 0.1, makeId); assert.equal(next.length, 1); assert.equal(next[0]?.id, 'L1'); }); void test('applyFieldEffectEraserStroke: пустой штрих — без изменений', () => { const water: EffectInstance = { ...base, id: 'w1', type: 'water', points: [{ x: 0.4, y: 0.4, tMs: 0 }], radiusN: 0.05, opacity: 0.5, lifetimeMs: null, }; const next = applyFieldEffectEraserStroke([water], [], 0.05, makeId); assert.equal(next.length, 1); assert.equal(next[0]?.id, 'w1'); }); void test('applyFieldEffectEraserStroke: types=["fire"] гасит только огонь', () => { const fire: EffectInstance = { ...base, id: 'fire1', type: 'fire', points: [ { x: 0.5, y: 0.5, tMs: 0 }, { x: 0.55, y: 0.5, tMs: 50 }, ], radiusN: 0.03, opacity: 1, lifetimeMs: null, }; const fog: EffectInstance = { ...base, id: 'fog1', type: 'fog', points: [{ x: 0.5, y: 0.5, tMs: 0 }], radiusN: 0.03, opacity: 0.5, lifetimeMs: null, }; const next = applyFieldEffectEraserStroke( [fire, fog], [{ x: 0.5, y: 0.5, tMs: 0 }], 0.08, makeId, ['fire'], ); assert.equal(next.length, 1); assert.equal(next[0]?.id, 'fog1'); }); void test('applyFieldEffectEraserStroke: hitMode=brush не гасит издалека', () => { const fire: EffectInstance = { ...base, id: 'fire1', type: 'fire', points: [{ x: 0.5, y: 0.5, tMs: 0 }], radiusN: 0.08, opacity: 1, lifetimeMs: null, }; // brush ≈ 0.38 * 0.08 ≈ 0.030; dist 0.06 — мимо, dist 0.02 — попадание. const far = applyFieldEffectEraserStroke( [fire], [{ x: 0.5, y: 0.56, tMs: 0 }], 0.08, makeId, ['fire'], 'brush', ); assert.equal(far.length, 1); assert.equal(far[0]?.id, 'fire1'); const near = applyFieldEffectEraserStroke( [fire], [{ x: 0.5, y: 0.52, tMs: 0 }], 0.08, makeId, ['fire'], 'brush', ); assert.equal(near.length, 0); });