Files
DndGamePlayer/app/main/effects/effectsStore.test.ts
T
Ivan Fontosh 089da3cae0 feat(effects): migrate battle effects to VFX
- add WebP frame-sequence assets for lightning, electric accent, fire, sunbeam, poison, rain, water, and rounded fog effects
- replace procedural lightning rendering with VFX frame playback
- align lightning impact to the click point
- remove the full-screen lightning blur/flash overlay
- add electric accent playback for lightning impact dispersion
- keep lightning scorch marks as the persistent ground trace after the action effect
- consolidate the lightning tool into a single public `Молния` action
- replace procedural fire with the VFX fire implementation
- remove the separate `Огонь 2` tool and keep the VFX fire under `Огонь`
- keep VFX fire brightness fixed at full intensity
- preserve fire as a field effect with brush placement and eraser support
- replace procedural sunbeam with the Pulse Discharge VFX implementation
- remove the separate `Луч света 2` tool and keep the VFX sunbeam under `Луч света`
- align sunbeam impact to the click point instead of the raw frame center
- remove the full-screen sunbeam flash overlay
- add Dust Burst VFX playback for poison cloud
- tint poison smoke green
- keep the skull glyph rendered above the poison smoke
- align poison smoke bottom to the click point
- remove the old procedural poison cloud implementation
- remove the separate `Яд 2` tool and keep the VFX poison under `Яд`
- replace procedural rain strokes with medium-rain VFX frame playback
- recolor rain frames to gray/light-gray so rain no longer renders black
- preserve rain as a field effect with brush placement and eraser support
- replace static water fill with generated animated water VFX frames
- render water VFX through the existing stroke mask so water keeps the painted brush shape
- preserve water as a field effect with brush placement and eraser support
- replace procedural fog texture generation with Smokey Atmosphere VFX frames
- generate rounded fog VFX frames with soft alpha falloff at the edges
- size each fog VFX stamp to the brush diameter
- remove per-stamp fog drift and rotation so fog elements stay fixed in place
- keep fog animation limited to internal frame playback
- preload VFX frame textures for smoother first use
- cache VFX textures per Pixi instance to avoid duplicate decoding
- filter expired action instances before node synchronization to stop old effects from flashing back during rapid casts
- add brush-stroke erasing for field effects using the same model as scene darkness reveal
- keep whole-instance erasing for action effects
- update effect hit tests for the consolidated VFX action effects
- update effect store pruning for renamed and consolidated action effects
- update control-panel buttons for consolidated fire, sunbeam, poison, and VFX-backed field effects
- update editor localization for removed and renamed effect tools
- add tests for field-effect brush erasing
- update eraser hit-test coverage for VFX-backed effects
- update effects store lifetime pruning tests for consolidated poison
- update control-panel tests for consolidated effect buttons
- include the field-effect eraser test in the default test script

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-03 21:20:43 +08:00

85 lines
2.2 KiB
TypeScript

import assert from 'node:assert/strict';
import test from 'node:test';
import { EffectsStore } from './effectsStore';
void test('pruneExpired: лёд не удаляется по времени', () => {
const store = new EffectsStore();
const createdAtMs = Date.now() - 365 * 24 * 60 * 60 * 1000;
store.dispatch({
kind: 'instance.add',
instance: {
id: 'ice_test',
type: 'ice',
seed: 1,
createdAtMs,
at: { x: 0.5, y: 0.5 },
radiusN: 0.1,
opacity: 0.85,
lifetimeMs: null,
},
});
assert.equal(store.getState().instances.length, 1);
assert.equal(store.pruneExpired(), false);
assert.equal(store.getState().instances.length, 1);
});
void test('pruneExpired: молния удаляется после lifetime', () => {
const store = new EffectsStore();
store.dispatch({
kind: 'instance.add',
instance: {
id: 'lt_test',
type: 'lightning',
seed: 1,
createdAtMs: Date.now() - 10_000,
start: { x: 0, y: 0 },
end: { x: 0.5, y: 0.5 },
widthN: 0.05,
intensity: 1,
lifetimeMs: 1000,
},
});
assert.equal(store.pruneExpired(), true);
assert.equal(store.getState().instances.length, 0);
});
void test('pruneExpired: луч света удаляется после lifetime', () => {
const store = new EffectsStore();
store.dispatch({
kind: 'instance.add',
instance: {
id: 'sb_test',
type: 'sunbeam',
seed: 1,
createdAtMs: Date.now() - 10_000,
start: { x: 0.5, y: 0 },
end: { x: 0.5, y: 0.6 },
widthN: 0.04,
intensity: 1,
lifetimeMs: 800,
},
});
assert.equal(store.pruneExpired(), true);
assert.equal(store.getState().instances.length, 0);
});
void test('pruneExpired: яд удаляется после lifetime', () => {
const store = new EffectsStore();
store.dispatch({
kind: 'instance.add',
instance: {
id: 'pc_test',
type: 'poisonCloud',
seed: 1,
createdAtMs: Date.now() - 20_000,
at: { x: 0.5, y: 0.5 },
radiusN: 0.08,
intensity: 1,
lifetimeMs: 3000,
},
});
assert.equal(store.pruneExpired(), true);
assert.equal(store.getState().instances.length, 0);
});