Files
DndGamePlayer/app/shared/effectEraserHitTest.test.ts
T
Ivan Fontosh 657e3c862e feat(effects): add Darkness action effect like freeze
Adds a fullscreen darkness vignette on click and a permanent shadow spot with a black radial gradient (40% edge, 100% center). Includes control panel UI, i18n, eraser support, and tests.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-02 16:37:06 +08:00

111 lines
3.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import assert from 'node:assert/strict';
import test from 'node:test';
import { minDistSqEffectToPoint, pickEraseTargetId } from './effectEraserHitTest';
import type { EffectInstance } from './types/effects';
const base = { seed: 1, createdAtMs: 0 };
void test('pickEraseTargetId: fire/rain по штриху как туман', () => {
const fire: EffectInstance = {
...base,
id: 'f1',
type: 'fire',
points: [{ x: 0.5, y: 0.5, tMs: 0 }],
radiusN: 0.05,
opacity: 1,
lifetimeMs: null,
};
const id = pickEraseTargetId([fire], { x: 0.51, y: 0.5 }, 0.05);
assert.equal(id, 'f1');
});
void test('pickEraseTargetId: вода по штриху как туман', () => {
const water: EffectInstance = {
...base,
id: 'w1',
type: 'water',
points: [{ x: 0.4, y: 0.55, tMs: 0 }],
radiusN: 0.06,
opacity: 0.5,
lifetimeMs: null,
};
const id = pickEraseTargetId([water], { x: 0.41, y: 0.55 }, 0.05);
assert.equal(id, 'w1');
});
void test('pickEraseTargetId: тьма как заморозка — точка удара', () => {
const darkness: EffectInstance = {
...base,
id: 'd1',
type: 'darkness',
at: { x: 0.4, y: 0.55 },
intensity: 1,
lifetimeMs: 820,
};
const id = pickEraseTargetId([darkness], { x: 0.41, y: 0.55 }, 0.05);
assert.equal(id, 'd1');
});
void test('pickEraseTargetId: shadow с учётом inst.radiusN', () => {
const shadow: EffectInstance = {
...base,
id: 's1',
type: 'shadow',
at: { x: 0.5, y: 0.5 },
radiusN: 0.08,
opacity: 1,
lifetimeMs: null,
};
const id = pickEraseTargetId([shadow], { x: 0.59, y: 0.5 }, 0.02);
assert.equal(id, 's1');
});
void test('minDistSqEffectToPoint: молния — расстояние до отрезка', () => {
const bolt: EffectInstance = {
...base,
id: 'L1',
type: 'lightning',
start: { x: 0, y: 0 },
end: { x: 1, y: 0 },
widthN: 0.02,
intensity: 1,
lifetimeMs: 500,
};
const mid = minDistSqEffectToPoint(bolt, { x: 0.5, y: 0.1 });
assert.ok(Math.abs(mid - 0.01) < 1e-9);
const end = minDistSqEffectToPoint(bolt, { x: 1, y: 0 });
assert.equal(end, 0);
});
void test('minDistSqEffectToPoint: луч света — как у молнии, отрезок', () => {
const beam: EffectInstance = {
...base,
id: 'S1',
type: 'sunbeam',
start: { x: 0.5, y: 0 },
end: { x: 0.5, y: 0.8 },
widthN: 0.04,
intensity: 1,
lifetimeMs: 220,
};
const onBeam = minDistSqEffectToPoint(beam, { x: 0.5, y: 0.4 });
assert.equal(onBeam, 0);
const aside = minDistSqEffectToPoint(beam, { x: 0.52, y: 0.4 });
assert.ok(aside > 0 && aside < 0.01);
});
void test('pickEraseTargetId: scorch с учётом inst.radiusN', () => {
const sc: EffectInstance = {
...base,
id: 's1',
type: 'scorch',
at: { x: 0.5, y: 0.5 },
radiusN: 0.08,
opacity: 1,
lifetimeMs: 1000,
};
const id = pickEraseTargetId([sc], { x: 0.59, y: 0.5 }, 0.02);
assert.equal(id, 's1');
});