@almadar/ui 2.8.1 → 2.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-A5J5CNCU.js → chunk-6D5QMEUS.js} +1 -1
- package/dist/chunk-7AKZ7SRV.js +375 -0
- package/dist/{chunk-NES4SBB7.js → chunk-P6NZVIE5.js} +1355 -103
- package/dist/components/index.d.ts +5 -5
- package/dist/components/index.js +42 -1282
- package/dist/hooks/index.js +2 -2
- package/dist/lib/index.js +1 -1
- package/dist/providers/index.js +5 -375
- package/dist/runtime/index.css +1156 -0
- package/dist/runtime/index.d.ts +280 -0
- package/dist/runtime/index.js +471 -0
- package/package.json +6 -1
- package/dist/{chunk-2QM732NQ.js → chunk-GTIAVPI5.js} +1 -1
package/dist/components/index.js
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
import { useAuthContext } from '../chunk-2QM732NQ.js';
|
|
2
|
-
export { ENTITY_EVENTS, useAgentChat, useAuthContext, useCompile, useConnectGitHub, useCreateEntity, useDeepAgentGeneration, useDeleteEntity, useDisconnectGitHub, useEntities, useEntitiesByType, useEntity as useEntityById, useEntityMutations, useExtensions, useFileEditor, useFileSystem, useGitHubBranches, useGitHubRepo, useGitHubRepos, useGitHubStatus, useInput, useOrbitalHistory, useOrbitalMutations, usePhysics, usePinchZoom, usePlayer, usePreview, useResolvedEntity, useSelectedEntity, useSendOrbitalEvent, useSingletonEntity, useUIEvents, useUpdateEntity, useValidation } from '../chunk-2QM732NQ.js';
|
|
3
1
|
import { DEFAULT_CONFIG, renderStateMachineToDomData, parseContentSegments } from '../chunk-N6DJVKZ6.js';
|
|
2
|
+
import { useAuthContext } from '../chunk-GTIAVPI5.js';
|
|
3
|
+
export { ENTITY_EVENTS, useAgentChat, useAuthContext, useCompile, useConnectGitHub, useCreateEntity, useDeepAgentGeneration, useDeleteEntity, useDisconnectGitHub, useEntities, useEntitiesByType, useEntity as useEntityById, useEntityMutations, useExtensions, useFileEditor, useFileSystem, useGitHubBranches, useGitHubRepo, useGitHubRepos, useGitHubStatus, useInput, useOrbitalHistory, useOrbitalMutations, usePhysics, usePinchZoom, usePlayer, usePreview, useResolvedEntity, useSelectedEntity, useSendOrbitalEvent, useSingletonEntity, useUIEvents, useUpdateEntity, useValidation } from '../chunk-GTIAVPI5.js';
|
|
4
|
+
export { clearEntities, getAllEntities, getByType, getEntity, getSingleton, removeEntity, spawnEntity, updateEntity, updateSingleton } from '../chunk-N7MVUW4R.js';
|
|
4
5
|
import '../chunk-3HJHHULT.js';
|
|
5
|
-
import { VStack, HStack, Typography, Button, Icon, Box, Card, Avatar, Badge, SearchInput, Checkbox, Menu as Menu$1, Pagination, LoadingState, EmptyState, Modal, ErrorState, QuizBlock, CodeBlock, ScaledDiagram, MarkdownContent, Divider, ProgressBar, isoToScreen, IsometricCanvas_default, Stack, Select, Drawer, Toast, Tabs, Input, ThemeToggle, TILE_WIDTH, EntityDisplayEvents, StateIndicator, Container } from '../chunk-
|
|
6
|
-
export { Accordion, ActionButton, ActionButtons, Card2 as ActionCard, Alert, AnimatedCounter, Avatar, Badge, Box, Breadcrumb, Button, ButtonGroup, CalendarGrid, Card, CardBody, CardContent, CardFooter, CardGrid, CardHeader, CardTitle, Carousel, Center, ChartLegend, Checkbox, ChoiceButton, CodeBlock, CombatLog, ComboCounter, ConditionalWrapper, ConfettiEffect, Container, ControlButton, CraftingRecipe, DIAMOND_TOP_Y, DPad, DamageNumber, DataGrid, DataList, DataTable, DateRangeSelector, DayCell, DetailPanel, DialogueBox, DialogueBubble, Divider, Drawer, EmptyState, EnemyPlate, EntityDisplayEvents, ErrorBoundary, ErrorState, FEATURE_COLORS, FLOOR_HEIGHT, FilterGroup, Flex, FlipCard, FlipContainer, FloatingActionButton, Form, FormField, FormSectionHeader, GameCanvas2D, GameHud, GameMenu, GameOverScreen, GraphView, Grid, HStack, Heading, HealthBar, HealthPanel, Icon, InfiniteScrollSentinel, Input, InputGroup, InventoryGrid, InventoryPanel, IsometricCanvas, ItemSlot, Label, LawReferenceTooltip, Lightbox, LineChart, LoadingState, MapView, MarkdownContent, MasterDetail, Menu, Meter, MiniMap, Modal, NumberStepper, Overlay, PageHeader, Pagination, PlatformerCanvas, Popover, PowerupSlots, ProgressBar, ProgressDots, PullToRefresh, QuestTracker, QuizBlock, Radio, RangeSlider, RelationSelect, RepeatableFormSection, ResourceBar, ResourceCounter, ScaledDiagram, ScoreBoard, ScoreDisplay, SearchInput, Select, SidePanel, SimpleGrid, Skeleton, SlotContentRenderer, SortableList, Spacer, Spinner, Sprite, Stack, StarRating, StatBadge, StatCard, StatDisplay, StateIndicator, StatusDot, StatusEffect, SwipeableRow, Switch, TILE_HEIGHT, TILE_WIDTH, Tabs, Text, TextHighlight, Textarea, ThemeSelector, ThemeToggle, TimeSlotCell, TimerDisplay, Toast, Tooltip, TrendIndicator, TurnIndicator, TurnPanel, TypewriterText, Typography, UISlotComponent, UISlotRenderer, UnitCommandBar, UploadDropZone, VStack, ViolationAlert, WaypointMarker, WizardNavigation, WizardProgress, XPBar, drawSprite, isoToScreen, screenToIso, useCamera, useImageCache } from '../chunk-
|
|
6
|
+
import { VStack, HStack, Typography, Button, Icon, Box, Card, Avatar, Badge, SearchInput, Checkbox, Menu as Menu$1, Pagination, LoadingState, EmptyState, Modal, ErrorState, QuizBlock, CodeBlock, ScaledDiagram, MarkdownContent, Divider, ProgressBar, isoToScreen, IsometricCanvas_default, Stack, Select, Drawer, Toast, Tabs, Input, ThemeToggle, TILE_WIDTH, EntityDisplayEvents, StateIndicator, Container } from '../chunk-P6NZVIE5.js';
|
|
7
|
+
export { Accordion, ActionButton, ActionButtons, Card2 as ActionCard, Alert, AnimatedCounter, Avatar, Badge, Box, Breadcrumb, Button, ButtonGroup, CalendarGrid, CanvasEffect, Card, CardBody, CardContent, CardFooter, CardGrid, CardHeader, CardTitle, Carousel, Center, ChartLegend, Checkbox, ChoiceButton, CodeBlock, CombatLog, ComboCounter, ConditionalWrapper, ConfettiEffect, Container, ControlButton, CraftingRecipe, DIAMOND_TOP_Y, DPad, DamageNumber, DataGrid, DataList, DataTable, DateRangeSelector, DayCell, DetailPanel, DialogueBox, DialogueBubble, Divider, Drawer, EmptyState, EnemyPlate, EntityDisplayEvents, ErrorBoundary, ErrorState, FEATURE_COLORS, FLOOR_HEIGHT, FilterGroup, Flex, FlipCard, FlipContainer, FloatingActionButton, Form, FormField, FormSectionHeader, GameCanvas2D, GameHud, GameMenu, GameOverScreen, GraphView, Grid, HStack, Heading, HealthBar, HealthPanel, Icon, InfiniteScrollSentinel, Input, InputGroup, InventoryGrid, InventoryPanel, IsometricCanvas, ItemSlot, Label, LawReferenceTooltip, Lightbox, LineChart, LoadingState, MapView, MarkdownContent, MasterDetail, Menu, Meter, MiniMap, Modal, NumberStepper, Overlay, PageHeader, Pagination, PlatformerCanvas, Popover, PowerupSlots, ProgressBar, ProgressDots, PullToRefresh, QuestTracker, QuizBlock, Radio, RangeSlider, RelationSelect, RepeatableFormSection, ResourceBar, ResourceCounter, ScaledDiagram, ScoreBoard, ScoreDisplay, SearchInput, Select, SidePanel, SimpleGrid, Skeleton, SlotContentRenderer, SortableList, Spacer, Spinner, Sprite, Stack, StarRating, StatBadge, StatCard, StatDisplay, StateIndicator, StatusDot, StatusEffect, SwipeableRow, Switch, TILE_HEIGHT, TILE_WIDTH, Tabs, Text, TextHighlight, Textarea, ThemeSelector, ThemeToggle, TimeSlotCell, TimerDisplay, Toast, Tooltip, TrendIndicator, TurnIndicator, TurnPanel, TypewriterText, Typography, UISlotComponent, UISlotRenderer, UnitCommandBar, UploadDropZone, VStack, ViolationAlert, WaypointMarker, WizardNavigation, WizardProgress, XPBar, drawSprite, isoToScreen, screenToIso, useCamera, useImageCache } from '../chunk-P6NZVIE5.js';
|
|
7
8
|
import '../chunk-DKQN5FVU.js';
|
|
8
9
|
import { useTranslate } from '../chunk-WGJIL4YR.js';
|
|
9
10
|
export { EntityDataProvider, I18nProvider, createTranslate, entityDataKeys, parseQueryBinding, useDragReorder, useEntity, useEntityDataAdapter, useEntityDetail, useEntityList, useEntityListSuspense, useEntitySuspense, useInfiniteScroll, useLongPress, usePullToRefresh, useQuerySingleton, useSwipeGesture, useTranslate } from '../chunk-WGJIL4YR.js';
|
|
10
11
|
import { useEventBus, useEventListener } from '../chunk-YXZM3WCF.js';
|
|
11
12
|
export { useEmitEvent, useEventBus, useEventListener } from '../chunk-YXZM3WCF.js';
|
|
12
13
|
export { DEFAULT_SLOTS, useUISlotManager } from '../chunk-3JGAROCW.js';
|
|
13
|
-
import { cn, getNestedValue, bindCanvasCapture } from '../chunk-
|
|
14
|
-
export { cn } from '../chunk-
|
|
14
|
+
import { cn, getNestedValue, bindCanvasCapture } from '../chunk-6D5QMEUS.js';
|
|
15
|
+
export { cn } from '../chunk-6D5QMEUS.js';
|
|
15
16
|
import '../chunk-TSETXL2E.js';
|
|
16
17
|
import '../chunk-K2D5D3WK.js';
|
|
17
|
-
export { clearEntities, getAllEntities, getByType, getEntity, getSingleton, removeEntity, spawnEntity, updateEntity, updateSingleton } from '../chunk-N7MVUW4R.js';
|
|
18
18
|
import { __publicField } from '../chunk-PKBMQBKP.js';
|
|
19
19
|
import React, { createContext, useState, useCallback, useMemo, useEffect, useRef, useContext } from 'react';
|
|
20
20
|
import { ChevronDown, X, Menu, ChevronRight, ChevronLeft, ArrowUp, ArrowDown, MoreVertical, Package, Check, AlertTriangle, Trash2, List as List$1, Printer, CheckCircle, XCircle, Play, RotateCcw, Send, Wrench, Bug, ArrowRight, Pause, SkipForward, AlertCircle, Circle, Clock, CheckCircle2, Image as Image$1, Upload, ZoomIn, Eraser, FileText, ZoomOut, Download, Code, WrapText, Copy, Settings, Search, Bell, LogOut, Calendar, Pencil, Eye, MoreHorizontal, Minus, Plus } from 'lucide-react';
|
|
@@ -3745,1246 +3745,6 @@ var TabbedContainer = ({
|
|
|
3745
3745
|
);
|
|
3746
3746
|
};
|
|
3747
3747
|
TabbedContainer.displayName = "TabbedContainer";
|
|
3748
|
-
|
|
3749
|
-
// components/organisms/game/types/effects.ts
|
|
3750
|
-
var EMPTY_EFFECT_STATE = {
|
|
3751
|
-
particles: [],
|
|
3752
|
-
sequences: [],
|
|
3753
|
-
overlays: []
|
|
3754
|
-
};
|
|
3755
|
-
|
|
3756
|
-
// components/organisms/game/utils/canvasEffects.ts
|
|
3757
|
-
var _offscreen = null;
|
|
3758
|
-
var _offCtx = null;
|
|
3759
|
-
function getOffscreenCtx(w, h) {
|
|
3760
|
-
if (!_offscreen) {
|
|
3761
|
-
if (typeof OffscreenCanvas !== "undefined") {
|
|
3762
|
-
_offscreen = new OffscreenCanvas(w, h);
|
|
3763
|
-
} else {
|
|
3764
|
-
_offscreen = document.createElement("canvas");
|
|
3765
|
-
}
|
|
3766
|
-
}
|
|
3767
|
-
if (_offscreen.width < w) _offscreen.width = w;
|
|
3768
|
-
if (_offscreen.height < h) _offscreen.height = h;
|
|
3769
|
-
if (!_offCtx) {
|
|
3770
|
-
_offCtx = _offscreen.getContext("2d");
|
|
3771
|
-
}
|
|
3772
|
-
return _offCtx;
|
|
3773
|
-
}
|
|
3774
|
-
function drawTintedImage(ctx, img, x, y, w, h, tint, alpha, blendMode = "source-over") {
|
|
3775
|
-
if (w <= 0 || h <= 0) return;
|
|
3776
|
-
const oc = getOffscreenCtx(w, h);
|
|
3777
|
-
oc.clearRect(0, 0, w, h);
|
|
3778
|
-
oc.globalCompositeOperation = "source-over";
|
|
3779
|
-
oc.drawImage(img, 0, 0, w, h);
|
|
3780
|
-
oc.globalCompositeOperation = "source-atop";
|
|
3781
|
-
oc.fillStyle = `rgb(${tint.r}, ${tint.g}, ${tint.b})`;
|
|
3782
|
-
oc.fillRect(0, 0, w, h);
|
|
3783
|
-
const prevAlpha = ctx.globalAlpha;
|
|
3784
|
-
const prevBlend = ctx.globalCompositeOperation;
|
|
3785
|
-
ctx.globalAlpha = alpha;
|
|
3786
|
-
ctx.globalCompositeOperation = blendMode;
|
|
3787
|
-
ctx.drawImage(_offscreen, 0, 0, w, h, x, y, w, h);
|
|
3788
|
-
ctx.globalAlpha = prevAlpha;
|
|
3789
|
-
ctx.globalCompositeOperation = prevBlend;
|
|
3790
|
-
}
|
|
3791
|
-
function randRange(min, max) {
|
|
3792
|
-
return min + Math.random() * (max - min);
|
|
3793
|
-
}
|
|
3794
|
-
function spawnParticles(config, animTime) {
|
|
3795
|
-
const particles = [];
|
|
3796
|
-
for (let i = 0; i < config.count; i++) {
|
|
3797
|
-
const angle = randRange(config.angleMin, config.angleMax);
|
|
3798
|
-
const speed = randRange(config.velocityMin, config.velocityMax);
|
|
3799
|
-
const spriteUrl = config.spriteUrls[Math.floor(Math.random() * config.spriteUrls.length)];
|
|
3800
|
-
particles.push({
|
|
3801
|
-
spriteUrl,
|
|
3802
|
-
x: config.originX + randRange(-config.spread, config.spread),
|
|
3803
|
-
y: config.originY + randRange(-config.spread, config.spread),
|
|
3804
|
-
vx: Math.cos(angle) * speed,
|
|
3805
|
-
vy: Math.sin(angle) * speed,
|
|
3806
|
-
gravity: config.gravity,
|
|
3807
|
-
rotation: Math.random() * Math.PI * 2,
|
|
3808
|
-
rotationSpeed: randRange(config.rotationSpeedMin ?? -2, config.rotationSpeedMax ?? 2),
|
|
3809
|
-
scale: randRange(config.scaleMin, config.scaleMax),
|
|
3810
|
-
scaleSpeed: config.scaleSpeed ?? 0,
|
|
3811
|
-
alpha: config.alpha ?? 1,
|
|
3812
|
-
fadeRate: config.fadeRate ?? -1.5,
|
|
3813
|
-
tint: { ...config.tint },
|
|
3814
|
-
blendMode: config.blendMode ?? "source-over",
|
|
3815
|
-
spawnTime: animTime,
|
|
3816
|
-
lifetime: randRange(config.lifetimeMin, config.lifetimeMax)
|
|
3817
|
-
});
|
|
3818
|
-
}
|
|
3819
|
-
return particles;
|
|
3820
|
-
}
|
|
3821
|
-
function spawnSequence(config, animTime) {
|
|
3822
|
-
return {
|
|
3823
|
-
frameUrls: config.frameUrls,
|
|
3824
|
-
x: config.originX,
|
|
3825
|
-
y: config.originY,
|
|
3826
|
-
frameDuration: config.frameDuration,
|
|
3827
|
-
startTime: animTime,
|
|
3828
|
-
loop: config.loop ?? false,
|
|
3829
|
-
scale: config.scale ?? 1,
|
|
3830
|
-
tint: config.tint ?? null,
|
|
3831
|
-
alpha: config.alpha ?? 1,
|
|
3832
|
-
blendMode: config.blendMode ?? "source-over"
|
|
3833
|
-
};
|
|
3834
|
-
}
|
|
3835
|
-
function spawnOverlay(config, animTime) {
|
|
3836
|
-
return {
|
|
3837
|
-
spriteUrl: config.spriteUrl,
|
|
3838
|
-
x: config.originX,
|
|
3839
|
-
y: config.originY,
|
|
3840
|
-
alpha: config.alpha ?? 0.8,
|
|
3841
|
-
fadeRate: config.fadeRate ?? -0.5,
|
|
3842
|
-
pulseAmplitude: config.pulseAmplitude ?? 0,
|
|
3843
|
-
pulseFrequency: config.pulseFrequency ?? 2,
|
|
3844
|
-
scale: config.scale ?? 1,
|
|
3845
|
-
blendMode: config.blendMode ?? "source-over",
|
|
3846
|
-
spawnTime: animTime,
|
|
3847
|
-
lifetime: config.lifetime ?? 2e3
|
|
3848
|
-
};
|
|
3849
|
-
}
|
|
3850
|
-
function updateEffectState(state, animTime, deltaMs) {
|
|
3851
|
-
const dt = deltaMs / 1e3;
|
|
3852
|
-
const particles = state.particles.map((p2) => ({
|
|
3853
|
-
...p2,
|
|
3854
|
-
x: p2.x + p2.vx * dt,
|
|
3855
|
-
y: p2.y + p2.vy * dt,
|
|
3856
|
-
vy: p2.vy + p2.gravity * dt,
|
|
3857
|
-
rotation: p2.rotation + p2.rotationSpeed * dt,
|
|
3858
|
-
scale: Math.max(0, p2.scale + p2.scaleSpeed * dt),
|
|
3859
|
-
alpha: Math.max(0, p2.alpha + p2.fadeRate * dt)
|
|
3860
|
-
})).filter((p2) => p2.alpha > 0.01 && animTime - p2.spawnTime < p2.lifetime);
|
|
3861
|
-
const sequences = state.sequences.filter((s) => {
|
|
3862
|
-
const elapsed = animTime - s.startTime;
|
|
3863
|
-
const totalDuration = s.frameUrls.length * s.frameDuration;
|
|
3864
|
-
return s.loop || elapsed < totalDuration;
|
|
3865
|
-
});
|
|
3866
|
-
const overlays = state.overlays.map((o) => ({
|
|
3867
|
-
...o,
|
|
3868
|
-
alpha: Math.max(0, o.alpha + o.fadeRate * dt)
|
|
3869
|
-
})).filter((o) => o.alpha > 0.01 && animTime - o.spawnTime < o.lifetime);
|
|
3870
|
-
return { particles, sequences, overlays };
|
|
3871
|
-
}
|
|
3872
|
-
function drawEffectState(ctx, state, animTime, getImage) {
|
|
3873
|
-
for (const o of state.overlays) {
|
|
3874
|
-
const img = getImage(o.spriteUrl);
|
|
3875
|
-
if (!img) continue;
|
|
3876
|
-
let alpha = o.alpha;
|
|
3877
|
-
if (o.pulseAmplitude > 0) {
|
|
3878
|
-
const elapsed = (animTime - o.spawnTime) / 1e3;
|
|
3879
|
-
alpha += Math.sin(elapsed * o.pulseFrequency * Math.PI * 2) * o.pulseAmplitude;
|
|
3880
|
-
alpha = Math.max(0, Math.min(1, alpha));
|
|
3881
|
-
}
|
|
3882
|
-
const w = img.naturalWidth * o.scale;
|
|
3883
|
-
const h = img.naturalHeight * o.scale;
|
|
3884
|
-
const prevAlpha = ctx.globalAlpha;
|
|
3885
|
-
const prevBlend = ctx.globalCompositeOperation;
|
|
3886
|
-
ctx.globalAlpha = alpha;
|
|
3887
|
-
ctx.globalCompositeOperation = o.blendMode;
|
|
3888
|
-
ctx.drawImage(img, o.x - w / 2, o.y - h / 2, w, h);
|
|
3889
|
-
ctx.globalAlpha = prevAlpha;
|
|
3890
|
-
ctx.globalCompositeOperation = prevBlend;
|
|
3891
|
-
}
|
|
3892
|
-
for (const s of state.sequences) {
|
|
3893
|
-
const elapsed = animTime - s.startTime;
|
|
3894
|
-
let frameIndex = Math.floor(elapsed / s.frameDuration);
|
|
3895
|
-
if (s.loop) {
|
|
3896
|
-
frameIndex = frameIndex % s.frameUrls.length;
|
|
3897
|
-
} else if (frameIndex >= s.frameUrls.length) {
|
|
3898
|
-
continue;
|
|
3899
|
-
}
|
|
3900
|
-
const img = getImage(s.frameUrls[frameIndex]);
|
|
3901
|
-
if (!img) continue;
|
|
3902
|
-
const w = img.naturalWidth * s.scale;
|
|
3903
|
-
const h = img.naturalHeight * s.scale;
|
|
3904
|
-
if (s.tint) {
|
|
3905
|
-
drawTintedImage(ctx, img, s.x - w / 2, s.y - h / 2, w, h, s.tint, s.alpha, s.blendMode);
|
|
3906
|
-
} else {
|
|
3907
|
-
const prevAlpha = ctx.globalAlpha;
|
|
3908
|
-
const prevBlend = ctx.globalCompositeOperation;
|
|
3909
|
-
ctx.globalAlpha = s.alpha;
|
|
3910
|
-
ctx.globalCompositeOperation = s.blendMode;
|
|
3911
|
-
ctx.drawImage(img, s.x - w / 2, s.y - h / 2, w, h);
|
|
3912
|
-
ctx.globalAlpha = prevAlpha;
|
|
3913
|
-
ctx.globalCompositeOperation = prevBlend;
|
|
3914
|
-
}
|
|
3915
|
-
}
|
|
3916
|
-
for (const p2 of state.particles) {
|
|
3917
|
-
const img = getImage(p2.spriteUrl);
|
|
3918
|
-
if (!img) continue;
|
|
3919
|
-
const w = img.naturalWidth * p2.scale;
|
|
3920
|
-
const h = img.naturalHeight * p2.scale;
|
|
3921
|
-
ctx.save();
|
|
3922
|
-
ctx.translate(p2.x, p2.y);
|
|
3923
|
-
ctx.rotate(p2.rotation);
|
|
3924
|
-
drawTintedImage(ctx, img, -w / 2, -h / 2, w, h, p2.tint, p2.alpha, p2.blendMode);
|
|
3925
|
-
ctx.restore();
|
|
3926
|
-
}
|
|
3927
|
-
}
|
|
3928
|
-
function hasActiveEffects(state) {
|
|
3929
|
-
return state.particles.length > 0 || state.sequences.length > 0 || state.overlays.length > 0;
|
|
3930
|
-
}
|
|
3931
|
-
function getAllEffectSpriteUrls(manifest) {
|
|
3932
|
-
const urls = [];
|
|
3933
|
-
const base = manifest.baseUrl;
|
|
3934
|
-
if (manifest.particles) {
|
|
3935
|
-
for (const value of Object.values(manifest.particles)) {
|
|
3936
|
-
if (Array.isArray(value)) {
|
|
3937
|
-
value.forEach((v) => urls.push(`${base}/${v}`));
|
|
3938
|
-
} else if (typeof value === "string") {
|
|
3939
|
-
urls.push(`${base}/${value}`);
|
|
3940
|
-
}
|
|
3941
|
-
}
|
|
3942
|
-
}
|
|
3943
|
-
if (manifest.animations) {
|
|
3944
|
-
for (const frames of Object.values(manifest.animations)) {
|
|
3945
|
-
if (Array.isArray(frames)) {
|
|
3946
|
-
frames.forEach((f) => urls.push(`${base}/${f}`));
|
|
3947
|
-
}
|
|
3948
|
-
}
|
|
3949
|
-
}
|
|
3950
|
-
return urls;
|
|
3951
|
-
}
|
|
3952
|
-
|
|
3953
|
-
// components/organisms/game/utils/combatPresets.ts
|
|
3954
|
-
var PI = Math.PI;
|
|
3955
|
-
function p(manifest, key) {
|
|
3956
|
-
const particles = manifest.particles;
|
|
3957
|
-
if (!particles) return [];
|
|
3958
|
-
const val = particles[key];
|
|
3959
|
-
if (Array.isArray(val)) return val.map((v) => `${manifest.baseUrl}/${v}`);
|
|
3960
|
-
if (typeof val === "string") return [`${manifest.baseUrl}/${val}`];
|
|
3961
|
-
return [];
|
|
3962
|
-
}
|
|
3963
|
-
function anim(manifest, key) {
|
|
3964
|
-
const animations = manifest.animations;
|
|
3965
|
-
if (!animations) return [];
|
|
3966
|
-
const val = animations[key];
|
|
3967
|
-
if (Array.isArray(val)) return val.map((v) => `${manifest.baseUrl}/${v}`);
|
|
3968
|
-
return [];
|
|
3969
|
-
}
|
|
3970
|
-
function createCombatPresets(manifest) {
|
|
3971
|
-
return {
|
|
3972
|
-
// =====================================================================
|
|
3973
|
-
// MELEE — slash (red) + dirt + scratch + flash sequence
|
|
3974
|
-
// =====================================================================
|
|
3975
|
-
melee: (originX, originY) => {
|
|
3976
|
-
const particles = [
|
|
3977
|
-
{
|
|
3978
|
-
spriteUrls: p(manifest, "slash"),
|
|
3979
|
-
count: 6,
|
|
3980
|
-
originX,
|
|
3981
|
-
originY,
|
|
3982
|
-
spread: 8,
|
|
3983
|
-
velocityMin: 40,
|
|
3984
|
-
velocityMax: 120,
|
|
3985
|
-
angleMin: -PI * 0.8,
|
|
3986
|
-
angleMax: -PI * 0.2,
|
|
3987
|
-
gravity: 0,
|
|
3988
|
-
tint: { r: 255, g: 60, b: 40 },
|
|
3989
|
-
scaleMin: 0.3,
|
|
3990
|
-
scaleMax: 0.6,
|
|
3991
|
-
lifetimeMin: 300,
|
|
3992
|
-
lifetimeMax: 500,
|
|
3993
|
-
fadeRate: -2.5
|
|
3994
|
-
},
|
|
3995
|
-
{
|
|
3996
|
-
spriteUrls: p(manifest, "dirt"),
|
|
3997
|
-
count: 4,
|
|
3998
|
-
originX,
|
|
3999
|
-
originY: originY + 10,
|
|
4000
|
-
spread: 12,
|
|
4001
|
-
velocityMin: 20,
|
|
4002
|
-
velocityMax: 60,
|
|
4003
|
-
angleMin: -PI * 0.9,
|
|
4004
|
-
angleMax: -PI * 0.1,
|
|
4005
|
-
gravity: 120,
|
|
4006
|
-
tint: { r: 180, g: 140, b: 90 },
|
|
4007
|
-
scaleMin: 0.15,
|
|
4008
|
-
scaleMax: 0.3,
|
|
4009
|
-
lifetimeMin: 400,
|
|
4010
|
-
lifetimeMax: 700,
|
|
4011
|
-
fadeRate: -1.8
|
|
4012
|
-
},
|
|
4013
|
-
{
|
|
4014
|
-
spriteUrls: p(manifest, "scratch"),
|
|
4015
|
-
count: 2,
|
|
4016
|
-
originX,
|
|
4017
|
-
originY,
|
|
4018
|
-
spread: 5,
|
|
4019
|
-
velocityMin: 10,
|
|
4020
|
-
velocityMax: 30,
|
|
4021
|
-
angleMin: -PI * 0.7,
|
|
4022
|
-
angleMax: -PI * 0.3,
|
|
4023
|
-
gravity: 0,
|
|
4024
|
-
tint: { r: 255, g: 200, b: 150 },
|
|
4025
|
-
scaleMin: 0.25,
|
|
4026
|
-
scaleMax: 0.4,
|
|
4027
|
-
lifetimeMin: 200,
|
|
4028
|
-
lifetimeMax: 400,
|
|
4029
|
-
fadeRate: -3
|
|
4030
|
-
}
|
|
4031
|
-
];
|
|
4032
|
-
const sequences = [];
|
|
4033
|
-
const flashFrames = anim(manifest, "flash");
|
|
4034
|
-
if (flashFrames.length > 0) {
|
|
4035
|
-
sequences.push({
|
|
4036
|
-
frameUrls: flashFrames,
|
|
4037
|
-
originX,
|
|
4038
|
-
originY,
|
|
4039
|
-
frameDuration: 35,
|
|
4040
|
-
scale: 0.4
|
|
4041
|
-
});
|
|
4042
|
-
}
|
|
4043
|
-
return {
|
|
4044
|
-
particles: particles.filter((pc) => pc.spriteUrls.length > 0),
|
|
4045
|
-
sequences,
|
|
4046
|
-
overlays: [],
|
|
4047
|
-
screenShake: 4,
|
|
4048
|
-
screenFlash: null
|
|
4049
|
-
};
|
|
4050
|
-
},
|
|
4051
|
-
// =====================================================================
|
|
4052
|
-
// RANGED — muzzle + trace + smoke + explosion sequence
|
|
4053
|
-
// =====================================================================
|
|
4054
|
-
ranged: (originX, originY) => {
|
|
4055
|
-
const particles = [
|
|
4056
|
-
{
|
|
4057
|
-
spriteUrls: p(manifest, "muzzle"),
|
|
4058
|
-
count: 3,
|
|
4059
|
-
originX,
|
|
4060
|
-
originY,
|
|
4061
|
-
spread: 4,
|
|
4062
|
-
velocityMin: 60,
|
|
4063
|
-
velocityMax: 150,
|
|
4064
|
-
angleMin: -PI * 0.6,
|
|
4065
|
-
angleMax: -PI * 0.4,
|
|
4066
|
-
gravity: 0,
|
|
4067
|
-
tint: { r: 255, g: 220, b: 100 },
|
|
4068
|
-
scaleMin: 0.2,
|
|
4069
|
-
scaleMax: 0.4,
|
|
4070
|
-
lifetimeMin: 200,
|
|
4071
|
-
lifetimeMax: 400,
|
|
4072
|
-
fadeRate: -3
|
|
4073
|
-
},
|
|
4074
|
-
{
|
|
4075
|
-
spriteUrls: p(manifest, "trace"),
|
|
4076
|
-
count: 5,
|
|
4077
|
-
originX,
|
|
4078
|
-
originY,
|
|
4079
|
-
spread: 3,
|
|
4080
|
-
velocityMin: 100,
|
|
4081
|
-
velocityMax: 200,
|
|
4082
|
-
angleMin: -PI * 0.55,
|
|
4083
|
-
angleMax: -PI * 0.45,
|
|
4084
|
-
gravity: 0,
|
|
4085
|
-
tint: { r: 255, g: 200, b: 80 },
|
|
4086
|
-
scaleMin: 0.15,
|
|
4087
|
-
scaleMax: 0.3,
|
|
4088
|
-
lifetimeMin: 150,
|
|
4089
|
-
lifetimeMax: 300,
|
|
4090
|
-
fadeRate: -4
|
|
4091
|
-
},
|
|
4092
|
-
{
|
|
4093
|
-
spriteUrls: p(manifest, "smoke").slice(0, 3),
|
|
4094
|
-
count: 3,
|
|
4095
|
-
originX,
|
|
4096
|
-
originY: originY + 5,
|
|
4097
|
-
spread: 6,
|
|
4098
|
-
velocityMin: 10,
|
|
4099
|
-
velocityMax: 30,
|
|
4100
|
-
angleMin: -PI * 0.8,
|
|
4101
|
-
angleMax: -PI * 0.2,
|
|
4102
|
-
gravity: -20,
|
|
4103
|
-
tint: { r: 200, g: 200, b: 200 },
|
|
4104
|
-
scaleMin: 0.2,
|
|
4105
|
-
scaleMax: 0.35,
|
|
4106
|
-
lifetimeMin: 500,
|
|
4107
|
-
lifetimeMax: 800,
|
|
4108
|
-
fadeRate: -1.5
|
|
4109
|
-
}
|
|
4110
|
-
];
|
|
4111
|
-
const sequences = [];
|
|
4112
|
-
const explosionFrames = anim(manifest, "smokeExplosion");
|
|
4113
|
-
if (explosionFrames.length > 0) {
|
|
4114
|
-
sequences.push({
|
|
4115
|
-
frameUrls: explosionFrames,
|
|
4116
|
-
originX,
|
|
4117
|
-
originY,
|
|
4118
|
-
frameDuration: 50,
|
|
4119
|
-
scale: 0.35
|
|
4120
|
-
});
|
|
4121
|
-
}
|
|
4122
|
-
return {
|
|
4123
|
-
particles: particles.filter((pc) => pc.spriteUrls.length > 0),
|
|
4124
|
-
sequences,
|
|
4125
|
-
overlays: [],
|
|
4126
|
-
screenShake: 2,
|
|
4127
|
-
screenFlash: null
|
|
4128
|
-
};
|
|
4129
|
-
},
|
|
4130
|
-
// =====================================================================
|
|
4131
|
-
// MAGIC — twirl (purple) + spark (purple) + star
|
|
4132
|
-
// =====================================================================
|
|
4133
|
-
magic: (originX, originY) => {
|
|
4134
|
-
const particles = [
|
|
4135
|
-
{
|
|
4136
|
-
spriteUrls: p(manifest, "twirl"),
|
|
4137
|
-
count: 5,
|
|
4138
|
-
originX,
|
|
4139
|
-
originY,
|
|
4140
|
-
spread: 15,
|
|
4141
|
-
velocityMin: 20,
|
|
4142
|
-
velocityMax: 80,
|
|
4143
|
-
angleMin: 0,
|
|
4144
|
-
angleMax: PI * 2,
|
|
4145
|
-
gravity: -30,
|
|
4146
|
-
tint: { r: 180, g: 80, b: 255 },
|
|
4147
|
-
scaleMin: 0.2,
|
|
4148
|
-
scaleMax: 0.5,
|
|
4149
|
-
lifetimeMin: 500,
|
|
4150
|
-
lifetimeMax: 900,
|
|
4151
|
-
fadeRate: -1.2,
|
|
4152
|
-
blendMode: "lighter",
|
|
4153
|
-
rotationSpeedMin: -4,
|
|
4154
|
-
rotationSpeedMax: 4
|
|
4155
|
-
},
|
|
4156
|
-
{
|
|
4157
|
-
spriteUrls: p(manifest, "spark"),
|
|
4158
|
-
count: 8,
|
|
4159
|
-
originX,
|
|
4160
|
-
originY,
|
|
4161
|
-
spread: 20,
|
|
4162
|
-
velocityMin: 30,
|
|
4163
|
-
velocityMax: 100,
|
|
4164
|
-
angleMin: 0,
|
|
4165
|
-
angleMax: PI * 2,
|
|
4166
|
-
gravity: -15,
|
|
4167
|
-
tint: { r: 200, g: 120, b: 255 },
|
|
4168
|
-
scaleMin: 0.1,
|
|
4169
|
-
scaleMax: 0.25,
|
|
4170
|
-
lifetimeMin: 300,
|
|
4171
|
-
lifetimeMax: 600,
|
|
4172
|
-
fadeRate: -2,
|
|
4173
|
-
blendMode: "lighter"
|
|
4174
|
-
},
|
|
4175
|
-
{
|
|
4176
|
-
spriteUrls: p(manifest, "star"),
|
|
4177
|
-
count: 4,
|
|
4178
|
-
originX,
|
|
4179
|
-
originY,
|
|
4180
|
-
spread: 10,
|
|
4181
|
-
velocityMin: 15,
|
|
4182
|
-
velocityMax: 50,
|
|
4183
|
-
angleMin: -PI,
|
|
4184
|
-
angleMax: 0,
|
|
4185
|
-
gravity: -40,
|
|
4186
|
-
tint: { r: 220, g: 180, b: 255 },
|
|
4187
|
-
scaleMin: 0.15,
|
|
4188
|
-
scaleMax: 0.3,
|
|
4189
|
-
lifetimeMin: 600,
|
|
4190
|
-
lifetimeMax: 1e3,
|
|
4191
|
-
fadeRate: -1,
|
|
4192
|
-
blendMode: "lighter"
|
|
4193
|
-
}
|
|
4194
|
-
];
|
|
4195
|
-
const overlays = [];
|
|
4196
|
-
const circleUrls = p(manifest, "circle");
|
|
4197
|
-
if (circleUrls.length > 0) {
|
|
4198
|
-
overlays.push({
|
|
4199
|
-
spriteUrl: circleUrls[0],
|
|
4200
|
-
originX,
|
|
4201
|
-
originY,
|
|
4202
|
-
alpha: 0.5,
|
|
4203
|
-
fadeRate: -0.6,
|
|
4204
|
-
pulseAmplitude: 0.2,
|
|
4205
|
-
pulseFrequency: 3,
|
|
4206
|
-
scale: 0.5,
|
|
4207
|
-
blendMode: "lighter",
|
|
4208
|
-
lifetime: 1200
|
|
4209
|
-
});
|
|
4210
|
-
}
|
|
4211
|
-
return {
|
|
4212
|
-
particles: particles.filter((pc) => pc.spriteUrls.length > 0),
|
|
4213
|
-
sequences: [],
|
|
4214
|
-
overlays,
|
|
4215
|
-
screenShake: 0,
|
|
4216
|
-
screenFlash: null
|
|
4217
|
-
};
|
|
4218
|
-
},
|
|
4219
|
-
// =====================================================================
|
|
4220
|
-
// HEAL — circle (green) + star (green) + light (green, pulse)
|
|
4221
|
-
// =====================================================================
|
|
4222
|
-
heal: (originX, originY) => {
|
|
4223
|
-
const particles = [
|
|
4224
|
-
{
|
|
4225
|
-
spriteUrls: p(manifest, "circle"),
|
|
4226
|
-
count: 6,
|
|
4227
|
-
originX,
|
|
4228
|
-
originY,
|
|
4229
|
-
spread: 15,
|
|
4230
|
-
velocityMin: 10,
|
|
4231
|
-
velocityMax: 40,
|
|
4232
|
-
angleMin: -PI,
|
|
4233
|
-
angleMax: -PI * 0.3,
|
|
4234
|
-
gravity: -50,
|
|
4235
|
-
tint: { r: 80, g: 255, b: 120 },
|
|
4236
|
-
scaleMin: 0.15,
|
|
4237
|
-
scaleMax: 0.35,
|
|
4238
|
-
lifetimeMin: 600,
|
|
4239
|
-
lifetimeMax: 1e3,
|
|
4240
|
-
fadeRate: -0.8,
|
|
4241
|
-
blendMode: "lighter"
|
|
4242
|
-
},
|
|
4243
|
-
{
|
|
4244
|
-
spriteUrls: p(manifest, "star"),
|
|
4245
|
-
count: 5,
|
|
4246
|
-
originX,
|
|
4247
|
-
originY,
|
|
4248
|
-
spread: 12,
|
|
4249
|
-
velocityMin: 15,
|
|
4250
|
-
velocityMax: 50,
|
|
4251
|
-
angleMin: -PI * 0.9,
|
|
4252
|
-
angleMax: -PI * 0.1,
|
|
4253
|
-
gravity: -60,
|
|
4254
|
-
tint: { r: 100, g: 255, b: 140 },
|
|
4255
|
-
scaleMin: 0.1,
|
|
4256
|
-
scaleMax: 0.2,
|
|
4257
|
-
lifetimeMin: 500,
|
|
4258
|
-
lifetimeMax: 800,
|
|
4259
|
-
fadeRate: -1.2,
|
|
4260
|
-
blendMode: "lighter"
|
|
4261
|
-
}
|
|
4262
|
-
];
|
|
4263
|
-
const overlays = [];
|
|
4264
|
-
const lightUrls = p(manifest, "light");
|
|
4265
|
-
if (lightUrls.length > 0) {
|
|
4266
|
-
overlays.push({
|
|
4267
|
-
spriteUrl: lightUrls[0],
|
|
4268
|
-
originX,
|
|
4269
|
-
originY,
|
|
4270
|
-
alpha: 0.6,
|
|
4271
|
-
fadeRate: -0.4,
|
|
4272
|
-
pulseAmplitude: 0.25,
|
|
4273
|
-
pulseFrequency: 2.5,
|
|
4274
|
-
scale: 0.6,
|
|
4275
|
-
blendMode: "lighter",
|
|
4276
|
-
lifetime: 1500
|
|
4277
|
-
});
|
|
4278
|
-
}
|
|
4279
|
-
return {
|
|
4280
|
-
particles: particles.filter((pc) => pc.spriteUrls.length > 0),
|
|
4281
|
-
sequences: [],
|
|
4282
|
-
overlays,
|
|
4283
|
-
screenShake: 0,
|
|
4284
|
-
screenFlash: null
|
|
4285
|
-
};
|
|
4286
|
-
},
|
|
4287
|
-
// =====================================================================
|
|
4288
|
-
// DEFEND / SHIELD — star (blue) + circle (blue, pulse)
|
|
4289
|
-
// =====================================================================
|
|
4290
|
-
defend: (originX, originY) => {
|
|
4291
|
-
const particles = [
|
|
4292
|
-
{
|
|
4293
|
-
spriteUrls: p(manifest, "star"),
|
|
4294
|
-
count: 8,
|
|
4295
|
-
originX,
|
|
4296
|
-
originY,
|
|
4297
|
-
spread: 18,
|
|
4298
|
-
velocityMin: 10,
|
|
4299
|
-
velocityMax: 35,
|
|
4300
|
-
angleMin: 0,
|
|
4301
|
-
angleMax: PI * 2,
|
|
4302
|
-
gravity: 0,
|
|
4303
|
-
tint: { r: 80, g: 160, b: 255 },
|
|
4304
|
-
scaleMin: 0.12,
|
|
4305
|
-
scaleMax: 0.25,
|
|
4306
|
-
lifetimeMin: 600,
|
|
4307
|
-
lifetimeMax: 1e3,
|
|
4308
|
-
fadeRate: -0.8,
|
|
4309
|
-
blendMode: "lighter",
|
|
4310
|
-
rotationSpeedMin: -1,
|
|
4311
|
-
rotationSpeedMax: 1
|
|
4312
|
-
}
|
|
4313
|
-
];
|
|
4314
|
-
const overlays = [];
|
|
4315
|
-
const circleUrls = p(manifest, "circle");
|
|
4316
|
-
if (circleUrls.length > 0) {
|
|
4317
|
-
overlays.push({
|
|
4318
|
-
spriteUrl: circleUrls[0],
|
|
4319
|
-
originX,
|
|
4320
|
-
originY,
|
|
4321
|
-
alpha: 0.6,
|
|
4322
|
-
fadeRate: -0.3,
|
|
4323
|
-
pulseAmplitude: 0.2,
|
|
4324
|
-
pulseFrequency: 2,
|
|
4325
|
-
scale: 0.6,
|
|
4326
|
-
blendMode: "lighter",
|
|
4327
|
-
lifetime: 1500
|
|
4328
|
-
});
|
|
4329
|
-
}
|
|
4330
|
-
return {
|
|
4331
|
-
particles: particles.filter((pc) => pc.spriteUrls.length > 0),
|
|
4332
|
-
sequences: [],
|
|
4333
|
-
overlays,
|
|
4334
|
-
screenShake: 0,
|
|
4335
|
-
screenFlash: null
|
|
4336
|
-
};
|
|
4337
|
-
},
|
|
4338
|
-
// shield aliases to defend
|
|
4339
|
-
shield: (originX, originY) => {
|
|
4340
|
-
const particles = [
|
|
4341
|
-
{
|
|
4342
|
-
spriteUrls: p(manifest, "star"),
|
|
4343
|
-
count: 10,
|
|
4344
|
-
originX,
|
|
4345
|
-
originY,
|
|
4346
|
-
spread: 20,
|
|
4347
|
-
velocityMin: 8,
|
|
4348
|
-
velocityMax: 30,
|
|
4349
|
-
angleMin: 0,
|
|
4350
|
-
angleMax: PI * 2,
|
|
4351
|
-
gravity: 0,
|
|
4352
|
-
tint: { r: 60, g: 180, b: 255 },
|
|
4353
|
-
scaleMin: 0.1,
|
|
4354
|
-
scaleMax: 0.22,
|
|
4355
|
-
lifetimeMin: 700,
|
|
4356
|
-
lifetimeMax: 1200,
|
|
4357
|
-
fadeRate: -0.7,
|
|
4358
|
-
blendMode: "lighter",
|
|
4359
|
-
rotationSpeedMin: -0.8,
|
|
4360
|
-
rotationSpeedMax: 0.8
|
|
4361
|
-
}
|
|
4362
|
-
];
|
|
4363
|
-
const overlays = [];
|
|
4364
|
-
const circleUrls = p(manifest, "circle");
|
|
4365
|
-
if (circleUrls.length > 0) {
|
|
4366
|
-
overlays.push({
|
|
4367
|
-
spriteUrl: circleUrls[0],
|
|
4368
|
-
originX,
|
|
4369
|
-
originY,
|
|
4370
|
-
alpha: 0.7,
|
|
4371
|
-
fadeRate: -0.25,
|
|
4372
|
-
pulseAmplitude: 0.25,
|
|
4373
|
-
pulseFrequency: 1.8,
|
|
4374
|
-
scale: 0.7,
|
|
4375
|
-
blendMode: "lighter",
|
|
4376
|
-
lifetime: 1800
|
|
4377
|
-
});
|
|
4378
|
-
}
|
|
4379
|
-
return {
|
|
4380
|
-
particles: particles.filter((pc) => pc.spriteUrls.length > 0),
|
|
4381
|
-
sequences: [],
|
|
4382
|
-
overlays,
|
|
4383
|
-
screenShake: 0,
|
|
4384
|
-
screenFlash: null
|
|
4385
|
-
};
|
|
4386
|
-
},
|
|
4387
|
-
// =====================================================================
|
|
4388
|
-
// HIT — spark (orange) + flash (5 frames) + screen shake/flash
|
|
4389
|
-
// =====================================================================
|
|
4390
|
-
hit: (originX, originY) => {
|
|
4391
|
-
const particles = [
|
|
4392
|
-
{
|
|
4393
|
-
spriteUrls: p(manifest, "spark"),
|
|
4394
|
-
count: 10,
|
|
4395
|
-
originX,
|
|
4396
|
-
originY,
|
|
4397
|
-
spread: 8,
|
|
4398
|
-
velocityMin: 50,
|
|
4399
|
-
velocityMax: 150,
|
|
4400
|
-
angleMin: 0,
|
|
4401
|
-
angleMax: PI * 2,
|
|
4402
|
-
gravity: 80,
|
|
4403
|
-
tint: { r: 255, g: 180, b: 50 },
|
|
4404
|
-
scaleMin: 0.08,
|
|
4405
|
-
scaleMax: 0.2,
|
|
4406
|
-
lifetimeMin: 200,
|
|
4407
|
-
lifetimeMax: 500,
|
|
4408
|
-
fadeRate: -2.5
|
|
4409
|
-
}
|
|
4410
|
-
];
|
|
4411
|
-
const sequences = [];
|
|
4412
|
-
const flashFrames = anim(manifest, "flash");
|
|
4413
|
-
if (flashFrames.length > 0) {
|
|
4414
|
-
sequences.push({
|
|
4415
|
-
frameUrls: flashFrames.slice(0, 5),
|
|
4416
|
-
originX,
|
|
4417
|
-
originY,
|
|
4418
|
-
frameDuration: 40,
|
|
4419
|
-
scale: 0.3
|
|
4420
|
-
});
|
|
4421
|
-
}
|
|
4422
|
-
return {
|
|
4423
|
-
particles: particles.filter((pc) => pc.spriteUrls.length > 0),
|
|
4424
|
-
sequences,
|
|
4425
|
-
overlays: [],
|
|
4426
|
-
screenShake: 3,
|
|
4427
|
-
screenFlash: { r: 255, g: 50, b: 50, duration: 150 }
|
|
4428
|
-
};
|
|
4429
|
-
},
|
|
4430
|
-
// critical aliases to hit with bigger shake
|
|
4431
|
-
critical: (originX, originY) => {
|
|
4432
|
-
const particles = [
|
|
4433
|
-
{
|
|
4434
|
-
spriteUrls: p(manifest, "flame"),
|
|
4435
|
-
count: 8,
|
|
4436
|
-
originX,
|
|
4437
|
-
originY,
|
|
4438
|
-
spread: 12,
|
|
4439
|
-
velocityMin: 60,
|
|
4440
|
-
velocityMax: 180,
|
|
4441
|
-
angleMin: 0,
|
|
4442
|
-
angleMax: PI * 2,
|
|
4443
|
-
gravity: 60,
|
|
4444
|
-
tint: { r: 255, g: 120, b: 30 },
|
|
4445
|
-
scaleMin: 0.15,
|
|
4446
|
-
scaleMax: 0.4,
|
|
4447
|
-
lifetimeMin: 300,
|
|
4448
|
-
lifetimeMax: 600,
|
|
4449
|
-
fadeRate: -2
|
|
4450
|
-
},
|
|
4451
|
-
{
|
|
4452
|
-
spriteUrls: p(manifest, "spark"),
|
|
4453
|
-
count: 12,
|
|
4454
|
-
originX,
|
|
4455
|
-
originY,
|
|
4456
|
-
spread: 10,
|
|
4457
|
-
velocityMin: 80,
|
|
4458
|
-
velocityMax: 200,
|
|
4459
|
-
angleMin: 0,
|
|
4460
|
-
angleMax: PI * 2,
|
|
4461
|
-
gravity: 100,
|
|
4462
|
-
tint: { r: 255, g: 200, b: 60 },
|
|
4463
|
-
scaleMin: 0.06,
|
|
4464
|
-
scaleMax: 0.18,
|
|
4465
|
-
lifetimeMin: 200,
|
|
4466
|
-
lifetimeMax: 400,
|
|
4467
|
-
fadeRate: -3
|
|
4468
|
-
}
|
|
4469
|
-
];
|
|
4470
|
-
const sequences = [];
|
|
4471
|
-
const flashFrames = anim(manifest, "flash");
|
|
4472
|
-
if (flashFrames.length > 0) {
|
|
4473
|
-
sequences.push({
|
|
4474
|
-
frameUrls: flashFrames,
|
|
4475
|
-
originX,
|
|
4476
|
-
originY,
|
|
4477
|
-
frameDuration: 30,
|
|
4478
|
-
scale: 0.5
|
|
4479
|
-
});
|
|
4480
|
-
}
|
|
4481
|
-
return {
|
|
4482
|
-
particles: particles.filter((pc) => pc.spriteUrls.length > 0),
|
|
4483
|
-
sequences,
|
|
4484
|
-
overlays: [],
|
|
4485
|
-
screenShake: 6,
|
|
4486
|
-
screenFlash: { r: 255, g: 80, b: 0, duration: 200 }
|
|
4487
|
-
};
|
|
4488
|
-
},
|
|
4489
|
-
// =====================================================================
|
|
4490
|
-
// DEATH — dirt (gray) + explosion + black smoke + scorch (ground)
|
|
4491
|
-
// =====================================================================
|
|
4492
|
-
death: (originX, originY) => {
|
|
4493
|
-
const particles = [
|
|
4494
|
-
{
|
|
4495
|
-
spriteUrls: p(manifest, "dirt"),
|
|
4496
|
-
count: 8,
|
|
4497
|
-
originX,
|
|
4498
|
-
originY,
|
|
4499
|
-
spread: 10,
|
|
4500
|
-
velocityMin: 30,
|
|
4501
|
-
velocityMax: 100,
|
|
4502
|
-
angleMin: 0,
|
|
4503
|
-
angleMax: PI * 2,
|
|
4504
|
-
gravity: 100,
|
|
4505
|
-
tint: { r: 140, g: 140, b: 140 },
|
|
4506
|
-
scaleMin: 0.15,
|
|
4507
|
-
scaleMax: 0.35,
|
|
4508
|
-
lifetimeMin: 500,
|
|
4509
|
-
lifetimeMax: 900,
|
|
4510
|
-
fadeRate: -1.2
|
|
4511
|
-
}
|
|
4512
|
-
];
|
|
4513
|
-
const sequences = [];
|
|
4514
|
-
const explosionFrames = anim(manifest, "explosion");
|
|
4515
|
-
if (explosionFrames.length > 0) {
|
|
4516
|
-
sequences.push({
|
|
4517
|
-
frameUrls: explosionFrames,
|
|
4518
|
-
originX,
|
|
4519
|
-
originY,
|
|
4520
|
-
frameDuration: 60,
|
|
4521
|
-
scale: 0.5
|
|
4522
|
-
});
|
|
4523
|
-
}
|
|
4524
|
-
const blackSmokeFrames = anim(manifest, "blackSmoke");
|
|
4525
|
-
if (blackSmokeFrames.length > 0) {
|
|
4526
|
-
sequences.push({
|
|
4527
|
-
frameUrls: blackSmokeFrames,
|
|
4528
|
-
originX,
|
|
4529
|
-
originY: originY - 10,
|
|
4530
|
-
frameDuration: 50,
|
|
4531
|
-
scale: 0.4,
|
|
4532
|
-
alpha: 0.7
|
|
4533
|
-
});
|
|
4534
|
-
}
|
|
4535
|
-
const overlays = [];
|
|
4536
|
-
const scorchUrls = p(manifest, "scorch");
|
|
4537
|
-
if (scorchUrls.length > 0) {
|
|
4538
|
-
overlays.push({
|
|
4539
|
-
spriteUrl: scorchUrls[0],
|
|
4540
|
-
originX,
|
|
4541
|
-
originY: originY + 10,
|
|
4542
|
-
alpha: 0.6,
|
|
4543
|
-
fadeRate: -0.15,
|
|
4544
|
-
scale: 0.4,
|
|
4545
|
-
lifetime: 4e3
|
|
4546
|
-
});
|
|
4547
|
-
}
|
|
4548
|
-
return {
|
|
4549
|
-
particles: particles.filter((pc) => pc.spriteUrls.length > 0),
|
|
4550
|
-
sequences,
|
|
4551
|
-
overlays,
|
|
4552
|
-
screenShake: 0,
|
|
4553
|
-
screenFlash: null
|
|
4554
|
-
};
|
|
4555
|
-
},
|
|
4556
|
-
// =====================================================================
|
|
4557
|
-
// BUFF — star (gold) + symbol + flare (gold, pulse)
|
|
4558
|
-
// =====================================================================
|
|
4559
|
-
buff: (originX, originY) => {
|
|
4560
|
-
const particles = [
|
|
4561
|
-
{
|
|
4562
|
-
spriteUrls: p(manifest, "star"),
|
|
4563
|
-
count: 6,
|
|
4564
|
-
originX,
|
|
4565
|
-
originY,
|
|
4566
|
-
spread: 15,
|
|
4567
|
-
velocityMin: 15,
|
|
4568
|
-
velocityMax: 50,
|
|
4569
|
-
angleMin: -PI,
|
|
4570
|
-
angleMax: 0,
|
|
4571
|
-
gravity: -30,
|
|
4572
|
-
tint: { r: 255, g: 215, b: 50 },
|
|
4573
|
-
scaleMin: 0.12,
|
|
4574
|
-
scaleMax: 0.25,
|
|
4575
|
-
lifetimeMin: 600,
|
|
4576
|
-
lifetimeMax: 1e3,
|
|
4577
|
-
fadeRate: -0.8,
|
|
4578
|
-
blendMode: "lighter"
|
|
4579
|
-
},
|
|
4580
|
-
{
|
|
4581
|
-
spriteUrls: p(manifest, "symbol"),
|
|
4582
|
-
count: 2,
|
|
4583
|
-
originX,
|
|
4584
|
-
originY: originY - 10,
|
|
4585
|
-
spread: 8,
|
|
4586
|
-
velocityMin: 5,
|
|
4587
|
-
velocityMax: 20,
|
|
4588
|
-
angleMin: -PI * 0.7,
|
|
4589
|
-
angleMax: -PI * 0.3,
|
|
4590
|
-
gravity: -20,
|
|
4591
|
-
tint: { r: 255, g: 230, b: 100 },
|
|
4592
|
-
scaleMin: 0.2,
|
|
4593
|
-
scaleMax: 0.35,
|
|
4594
|
-
lifetimeMin: 800,
|
|
4595
|
-
lifetimeMax: 1200,
|
|
4596
|
-
fadeRate: -0.6,
|
|
4597
|
-
blendMode: "lighter"
|
|
4598
|
-
}
|
|
4599
|
-
];
|
|
4600
|
-
const overlays = [];
|
|
4601
|
-
const flareUrls = p(manifest, "flare");
|
|
4602
|
-
if (flareUrls.length > 0) {
|
|
4603
|
-
overlays.push({
|
|
4604
|
-
spriteUrl: flareUrls[0],
|
|
4605
|
-
originX,
|
|
4606
|
-
originY,
|
|
4607
|
-
alpha: 0.5,
|
|
4608
|
-
fadeRate: -0.3,
|
|
4609
|
-
pulseAmplitude: 0.3,
|
|
4610
|
-
pulseFrequency: 2,
|
|
4611
|
-
scale: 0.5,
|
|
4612
|
-
blendMode: "lighter",
|
|
4613
|
-
lifetime: 1500
|
|
4614
|
-
});
|
|
4615
|
-
}
|
|
4616
|
-
return {
|
|
4617
|
-
particles: particles.filter((pc) => pc.spriteUrls.length > 0),
|
|
4618
|
-
sequences: [],
|
|
4619
|
-
overlays,
|
|
4620
|
-
screenShake: 0,
|
|
4621
|
-
screenFlash: null
|
|
4622
|
-
};
|
|
4623
|
-
},
|
|
4624
|
-
// =====================================================================
|
|
4625
|
-
// DEBUFF — scorch (dark) + smoke (purple tint)
|
|
4626
|
-
// =====================================================================
|
|
4627
|
-
debuff: (originX, originY) => {
|
|
4628
|
-
const particles = [
|
|
4629
|
-
{
|
|
4630
|
-
spriteUrls: p(manifest, "scorch"),
|
|
4631
|
-
count: 4,
|
|
4632
|
-
originX,
|
|
4633
|
-
originY,
|
|
4634
|
-
spread: 12,
|
|
4635
|
-
velocityMin: 15,
|
|
4636
|
-
velocityMax: 40,
|
|
4637
|
-
angleMin: -PI,
|
|
4638
|
-
angleMax: 0,
|
|
4639
|
-
gravity: -20,
|
|
4640
|
-
tint: { r: 120, g: 40, b: 160 },
|
|
4641
|
-
scaleMin: 0.15,
|
|
4642
|
-
scaleMax: 0.3,
|
|
4643
|
-
lifetimeMin: 500,
|
|
4644
|
-
lifetimeMax: 800,
|
|
4645
|
-
fadeRate: -1
|
|
4646
|
-
},
|
|
4647
|
-
{
|
|
4648
|
-
spriteUrls: p(manifest, "smoke").slice(0, 3),
|
|
4649
|
-
count: 3,
|
|
4650
|
-
originX,
|
|
4651
|
-
originY,
|
|
4652
|
-
spread: 10,
|
|
4653
|
-
velocityMin: 8,
|
|
4654
|
-
velocityMax: 25,
|
|
4655
|
-
angleMin: -PI * 0.8,
|
|
4656
|
-
angleMax: -PI * 0.2,
|
|
4657
|
-
gravity: -15,
|
|
4658
|
-
tint: { r: 100, g: 50, b: 140 },
|
|
4659
|
-
scaleMin: 0.2,
|
|
4660
|
-
scaleMax: 0.35,
|
|
4661
|
-
lifetimeMin: 600,
|
|
4662
|
-
lifetimeMax: 1e3,
|
|
4663
|
-
fadeRate: -0.8
|
|
4664
|
-
}
|
|
4665
|
-
];
|
|
4666
|
-
const overlays = [];
|
|
4667
|
-
const circleUrls = p(manifest, "circle");
|
|
4668
|
-
if (circleUrls.length > 0) {
|
|
4669
|
-
overlays.push({
|
|
4670
|
-
spriteUrl: circleUrls[0],
|
|
4671
|
-
originX,
|
|
4672
|
-
originY,
|
|
4673
|
-
alpha: 0.4,
|
|
4674
|
-
fadeRate: -0.4,
|
|
4675
|
-
pulseAmplitude: 0.15,
|
|
4676
|
-
pulseFrequency: 2,
|
|
4677
|
-
scale: 0.45,
|
|
4678
|
-
lifetime: 1200
|
|
4679
|
-
});
|
|
4680
|
-
}
|
|
4681
|
-
return {
|
|
4682
|
-
particles: particles.filter((pc) => pc.spriteUrls.length > 0),
|
|
4683
|
-
sequences: [],
|
|
4684
|
-
overlays,
|
|
4685
|
-
screenShake: 0,
|
|
4686
|
-
screenFlash: null
|
|
4687
|
-
};
|
|
4688
|
-
},
|
|
4689
|
-
// =====================================================================
|
|
4690
|
-
// AOE — explosion (large) + flame + spark (radial) + screen shake
|
|
4691
|
-
// =====================================================================
|
|
4692
|
-
aoe: (originX, originY) => {
|
|
4693
|
-
const particles = [
|
|
4694
|
-
{
|
|
4695
|
-
spriteUrls: p(manifest, "flame"),
|
|
4696
|
-
count: 10,
|
|
4697
|
-
originX,
|
|
4698
|
-
originY,
|
|
4699
|
-
spread: 20,
|
|
4700
|
-
velocityMin: 40,
|
|
4701
|
-
velocityMax: 140,
|
|
4702
|
-
angleMin: 0,
|
|
4703
|
-
angleMax: PI * 2,
|
|
4704
|
-
gravity: 40,
|
|
4705
|
-
tint: { r: 255, g: 140, b: 30 },
|
|
4706
|
-
scaleMin: 0.2,
|
|
4707
|
-
scaleMax: 0.5,
|
|
4708
|
-
lifetimeMin: 400,
|
|
4709
|
-
lifetimeMax: 800,
|
|
4710
|
-
fadeRate: -1.5
|
|
4711
|
-
},
|
|
4712
|
-
{
|
|
4713
|
-
spriteUrls: p(manifest, "spark"),
|
|
4714
|
-
count: 15,
|
|
4715
|
-
originX,
|
|
4716
|
-
originY,
|
|
4717
|
-
spread: 15,
|
|
4718
|
-
velocityMin: 60,
|
|
4719
|
-
velocityMax: 200,
|
|
4720
|
-
angleMin: 0,
|
|
4721
|
-
angleMax: PI * 2,
|
|
4722
|
-
gravity: 60,
|
|
4723
|
-
tint: { r: 255, g: 180, b: 60 },
|
|
4724
|
-
scaleMin: 0.06,
|
|
4725
|
-
scaleMax: 0.15,
|
|
4726
|
-
lifetimeMin: 200,
|
|
4727
|
-
lifetimeMax: 500,
|
|
4728
|
-
fadeRate: -2.5
|
|
4729
|
-
}
|
|
4730
|
-
];
|
|
4731
|
-
const sequences = [];
|
|
4732
|
-
const explosionFrames = anim(manifest, "explosion");
|
|
4733
|
-
if (explosionFrames.length > 0) {
|
|
4734
|
-
sequences.push({
|
|
4735
|
-
frameUrls: explosionFrames,
|
|
4736
|
-
originX,
|
|
4737
|
-
originY,
|
|
4738
|
-
frameDuration: 50,
|
|
4739
|
-
scale: 0.6
|
|
4740
|
-
});
|
|
4741
|
-
}
|
|
4742
|
-
return {
|
|
4743
|
-
particles: particles.filter((pc) => pc.spriteUrls.length > 0),
|
|
4744
|
-
sequences,
|
|
4745
|
-
overlays: [],
|
|
4746
|
-
screenShake: 5,
|
|
4747
|
-
screenFlash: { r: 255, g: 160, b: 0, duration: 180 }
|
|
4748
|
-
};
|
|
4749
|
-
}
|
|
4750
|
-
};
|
|
4751
|
-
}
|
|
4752
|
-
var ACTION_EMOJI = {
|
|
4753
|
-
melee: { emoji: "\u2694\uFE0F", color: "var(--color-error)", label: "Slash" },
|
|
4754
|
-
ranged: { emoji: "\u{1F3F9}", color: "var(--color-warning)", label: "Arrow" },
|
|
4755
|
-
magic: { emoji: "\u2728", color: "var(--color-primary)", label: "Spell" },
|
|
4756
|
-
heal: { emoji: "\u{1F49A}", color: "var(--color-success)", label: "Heal" },
|
|
4757
|
-
buff: { emoji: "\u2B06\uFE0F", color: "var(--color-info)", label: "Buff" },
|
|
4758
|
-
debuff: { emoji: "\u2B07\uFE0F", color: "var(--color-warning)", label: "Debuff" },
|
|
4759
|
-
shield: { emoji: "\u{1F6E1}\uFE0F", color: "var(--color-info)", label: "Shield" },
|
|
4760
|
-
aoe: { emoji: "\u{1F4A5}", color: "var(--color-error)", label: "Explosion" },
|
|
4761
|
-
critical: { emoji: "\u{1F525}", color: "var(--color-error)", label: "Critical" },
|
|
4762
|
-
defend: { emoji: "\u{1F6E1}\uFE0F", color: "var(--color-info)", label: "Defend" },
|
|
4763
|
-
hit: { emoji: "\u{1F4A5}", color: "var(--color-error)", label: "Hit" },
|
|
4764
|
-
death: { emoji: "\u{1F480}", color: "var(--color-error)", label: "Death" }
|
|
4765
|
-
};
|
|
4766
|
-
function CanvasEffectEngine({
|
|
4767
|
-
actionType,
|
|
4768
|
-
x,
|
|
4769
|
-
y,
|
|
4770
|
-
duration = 2e3,
|
|
4771
|
-
intensity = 1,
|
|
4772
|
-
onComplete,
|
|
4773
|
-
className,
|
|
4774
|
-
assetManifest,
|
|
4775
|
-
width = 400,
|
|
4776
|
-
height = 300
|
|
4777
|
-
}) {
|
|
4778
|
-
const canvasRef = useRef(null);
|
|
4779
|
-
const stateRef = useRef({ ...EMPTY_EFFECT_STATE });
|
|
4780
|
-
const lastTimeRef = useRef(0);
|
|
4781
|
-
const rafRef = useRef(0);
|
|
4782
|
-
const imageCacheRef = useRef(/* @__PURE__ */ new Map());
|
|
4783
|
-
const [shakeOffset, setShakeOffset] = useState({ x: 0, y: 0 });
|
|
4784
|
-
const [flash, setFlash] = useState(null);
|
|
4785
|
-
const shakeRef = useRef({ x: 0, y: 0, intensity: 0 });
|
|
4786
|
-
const presets = useMemo(() => createCombatPresets(assetManifest), [assetManifest]);
|
|
4787
|
-
const spriteUrls = useMemo(() => getAllEffectSpriteUrls(assetManifest), [assetManifest]);
|
|
4788
|
-
useEffect(() => {
|
|
4789
|
-
const cache = imageCacheRef.current;
|
|
4790
|
-
for (const url of spriteUrls) {
|
|
4791
|
-
if (!cache.has(url)) {
|
|
4792
|
-
const img = new Image();
|
|
4793
|
-
img.crossOrigin = "anonymous";
|
|
4794
|
-
img.src = url;
|
|
4795
|
-
cache.set(url, img);
|
|
4796
|
-
}
|
|
4797
|
-
}
|
|
4798
|
-
}, [spriteUrls]);
|
|
4799
|
-
const getImage = useCallback((url) => {
|
|
4800
|
-
const img = imageCacheRef.current.get(url);
|
|
4801
|
-
return img?.complete ? img : void 0;
|
|
4802
|
-
}, []);
|
|
4803
|
-
useEffect(() => {
|
|
4804
|
-
const now = performance.now();
|
|
4805
|
-
const effectX = x || width / 2;
|
|
4806
|
-
const effectY = y || height / 2;
|
|
4807
|
-
const preset = presets[actionType](effectX, effectY);
|
|
4808
|
-
const state = stateRef.current;
|
|
4809
|
-
for (const emitter of preset.particles) {
|
|
4810
|
-
const scaledEmitter = { ...emitter, count: Math.round(emitter.count * intensity) };
|
|
4811
|
-
state.particles.push(...spawnParticles(scaledEmitter, now));
|
|
4812
|
-
}
|
|
4813
|
-
for (const seqConfig of preset.sequences) {
|
|
4814
|
-
state.sequences.push(spawnSequence(seqConfig, now));
|
|
4815
|
-
}
|
|
4816
|
-
for (const ovConfig of preset.overlays) {
|
|
4817
|
-
state.overlays.push(spawnOverlay(ovConfig, now));
|
|
4818
|
-
}
|
|
4819
|
-
if (preset.screenShake > 0) {
|
|
4820
|
-
shakeRef.current.intensity = preset.screenShake * intensity;
|
|
4821
|
-
}
|
|
4822
|
-
if (preset.screenFlash) {
|
|
4823
|
-
const { r, g, b, duration: flashDur } = preset.screenFlash;
|
|
4824
|
-
setFlash({ color: `rgb(${r}, ${g}, ${b})`, alpha: 0.3 });
|
|
4825
|
-
setTimeout(() => setFlash(null), flashDur);
|
|
4826
|
-
}
|
|
4827
|
-
const timer = setTimeout(() => {
|
|
4828
|
-
onComplete?.();
|
|
4829
|
-
}, duration);
|
|
4830
|
-
return () => clearTimeout(timer);
|
|
4831
|
-
}, []);
|
|
4832
|
-
useEffect(() => {
|
|
4833
|
-
const canvas = canvasRef.current;
|
|
4834
|
-
if (!canvas) return;
|
|
4835
|
-
const ctx = canvas.getContext("2d");
|
|
4836
|
-
if (!ctx) return;
|
|
4837
|
-
function loop(animTime) {
|
|
4838
|
-
const delta = lastTimeRef.current > 0 ? animTime - lastTimeRef.current : 16;
|
|
4839
|
-
lastTimeRef.current = animTime;
|
|
4840
|
-
stateRef.current = updateEffectState(stateRef.current, animTime, delta);
|
|
4841
|
-
if (shakeRef.current.intensity > 0.2) {
|
|
4842
|
-
const i = shakeRef.current.intensity;
|
|
4843
|
-
shakeRef.current.x = (Math.random() - 0.5) * i * 2;
|
|
4844
|
-
shakeRef.current.y = (Math.random() - 0.5) * i * 2;
|
|
4845
|
-
shakeRef.current.intensity *= 0.85;
|
|
4846
|
-
setShakeOffset({ x: shakeRef.current.x, y: shakeRef.current.y });
|
|
4847
|
-
} else if (shakeRef.current.intensity > 0) {
|
|
4848
|
-
shakeRef.current = { x: 0, y: 0, intensity: 0 };
|
|
4849
|
-
setShakeOffset({ x: 0, y: 0 });
|
|
4850
|
-
}
|
|
4851
|
-
ctx.clearRect(0, 0, width, height);
|
|
4852
|
-
drawEffectState(ctx, stateRef.current, animTime, getImage);
|
|
4853
|
-
if (hasActiveEffects(stateRef.current)) {
|
|
4854
|
-
rafRef.current = requestAnimationFrame(loop);
|
|
4855
|
-
}
|
|
4856
|
-
}
|
|
4857
|
-
rafRef.current = requestAnimationFrame(loop);
|
|
4858
|
-
return () => cancelAnimationFrame(rafRef.current);
|
|
4859
|
-
}, [width, height, getImage]);
|
|
4860
|
-
const shakeStyle = shakeOffset.x !== 0 || shakeOffset.y !== 0 ? { transform: `translate(${shakeOffset.x}px, ${shakeOffset.y}px)` } : {};
|
|
4861
|
-
return /* @__PURE__ */ jsxs(
|
|
4862
|
-
Box,
|
|
4863
|
-
{
|
|
4864
|
-
className: cn("absolute inset-0 pointer-events-none z-10", className),
|
|
4865
|
-
style: shakeStyle,
|
|
4866
|
-
children: [
|
|
4867
|
-
flash && /* @__PURE__ */ jsx(
|
|
4868
|
-
Box,
|
|
4869
|
-
{
|
|
4870
|
-
className: "absolute inset-0 z-20 pointer-events-none rounded-lg",
|
|
4871
|
-
style: { backgroundColor: flash.color, opacity: flash.alpha }
|
|
4872
|
-
}
|
|
4873
|
-
),
|
|
4874
|
-
/* @__PURE__ */ jsx(
|
|
4875
|
-
"canvas",
|
|
4876
|
-
{
|
|
4877
|
-
ref: canvasRef,
|
|
4878
|
-
width,
|
|
4879
|
-
height,
|
|
4880
|
-
className: "absolute inset-0 w-full h-full",
|
|
4881
|
-
style: { imageRendering: "pixelated" }
|
|
4882
|
-
}
|
|
4883
|
-
)
|
|
4884
|
-
]
|
|
4885
|
-
}
|
|
4886
|
-
);
|
|
4887
|
-
}
|
|
4888
|
-
function EmojiEffect({
|
|
4889
|
-
actionType,
|
|
4890
|
-
x,
|
|
4891
|
-
y,
|
|
4892
|
-
duration = 800,
|
|
4893
|
-
intensity = 1,
|
|
4894
|
-
onComplete,
|
|
4895
|
-
className,
|
|
4896
|
-
effectSpriteUrl,
|
|
4897
|
-
assetBaseUrl
|
|
4898
|
-
}) {
|
|
4899
|
-
const [visible, setVisible] = useState(true);
|
|
4900
|
-
const [phase, setPhase] = useState("enter");
|
|
4901
|
-
useEffect(() => {
|
|
4902
|
-
const enterTimer = setTimeout(() => setPhase("active"), 100);
|
|
4903
|
-
const exitTimer = setTimeout(() => setPhase("exit"), duration * 0.7);
|
|
4904
|
-
const doneTimer = setTimeout(() => {
|
|
4905
|
-
setVisible(false);
|
|
4906
|
-
onComplete?.();
|
|
4907
|
-
}, duration);
|
|
4908
|
-
return () => {
|
|
4909
|
-
clearTimeout(enterTimer);
|
|
4910
|
-
clearTimeout(exitTimer);
|
|
4911
|
-
clearTimeout(doneTimer);
|
|
4912
|
-
};
|
|
4913
|
-
}, [duration, onComplete]);
|
|
4914
|
-
if (!visible) return null;
|
|
4915
|
-
const config = ACTION_EMOJI[actionType] ?? ACTION_EMOJI.melee;
|
|
4916
|
-
const scaleVal = phase === "enter" ? 0.3 : phase === "active" ? intensity : 0.5;
|
|
4917
|
-
const opacity = phase === "exit" ? 0 : 1;
|
|
4918
|
-
const resolvedSpriteUrl = effectSpriteUrl ? effectSpriteUrl.startsWith("http") || effectSpriteUrl.startsWith("/") ? effectSpriteUrl : assetBaseUrl ? `${assetBaseUrl.replace(/\/$/, "")}/${effectSpriteUrl}` : effectSpriteUrl : void 0;
|
|
4919
|
-
return /* @__PURE__ */ jsxs(
|
|
4920
|
-
Box,
|
|
4921
|
-
{
|
|
4922
|
-
className: cn(
|
|
4923
|
-
"fixed pointer-events-none z-50 flex items-center justify-center",
|
|
4924
|
-
"transition-all ease-out",
|
|
4925
|
-
className
|
|
4926
|
-
),
|
|
4927
|
-
style: {
|
|
4928
|
-
left: x,
|
|
4929
|
-
top: y,
|
|
4930
|
-
transform: `translate(-50%, -50%) scale(${scaleVal})`,
|
|
4931
|
-
opacity,
|
|
4932
|
-
transitionDuration: phase === "enter" ? "100ms" : "300ms"
|
|
4933
|
-
},
|
|
4934
|
-
children: [
|
|
4935
|
-
/* @__PURE__ */ jsx(
|
|
4936
|
-
Box,
|
|
4937
|
-
{
|
|
4938
|
-
className: "absolute rounded-full animate-ping",
|
|
4939
|
-
style: {
|
|
4940
|
-
width: 48 * intensity,
|
|
4941
|
-
height: 48 * intensity,
|
|
4942
|
-
backgroundColor: config.color,
|
|
4943
|
-
opacity: 0.25
|
|
4944
|
-
}
|
|
4945
|
-
}
|
|
4946
|
-
),
|
|
4947
|
-
resolvedSpriteUrl ? /* @__PURE__ */ jsx(
|
|
4948
|
-
"img",
|
|
4949
|
-
{
|
|
4950
|
-
src: resolvedSpriteUrl,
|
|
4951
|
-
alt: config.label,
|
|
4952
|
-
className: "relative drop-shadow-lg",
|
|
4953
|
-
style: {
|
|
4954
|
-
width: `${3 * intensity}rem`,
|
|
4955
|
-
height: `${3 * intensity}rem`,
|
|
4956
|
-
objectFit: "contain",
|
|
4957
|
-
imageRendering: "pixelated"
|
|
4958
|
-
}
|
|
4959
|
-
}
|
|
4960
|
-
) : /* @__PURE__ */ jsx(
|
|
4961
|
-
"span",
|
|
4962
|
-
{
|
|
4963
|
-
className: "relative text-3xl drop-shadow-lg",
|
|
4964
|
-
style: { fontSize: `${2 * intensity}rem` },
|
|
4965
|
-
role: "img",
|
|
4966
|
-
"aria-label": config.label,
|
|
4967
|
-
children: config.emoji
|
|
4968
|
-
}
|
|
4969
|
-
)
|
|
4970
|
-
]
|
|
4971
|
-
}
|
|
4972
|
-
);
|
|
4973
|
-
}
|
|
4974
|
-
function CanvasEffect(props) {
|
|
4975
|
-
const eventBus = useEventBus();
|
|
4976
|
-
const { completeEvent, onComplete, ...rest } = props;
|
|
4977
|
-
const handleComplete = useCallback(() => {
|
|
4978
|
-
if (completeEvent) eventBus.emit(`UI:${completeEvent}`, {});
|
|
4979
|
-
onComplete?.();
|
|
4980
|
-
}, [completeEvent, eventBus, onComplete]);
|
|
4981
|
-
const enhancedProps = { ...rest, onComplete: handleComplete };
|
|
4982
|
-
if (props.assetManifest) {
|
|
4983
|
-
return /* @__PURE__ */ jsx(CanvasEffectEngine, { ...enhancedProps, assetManifest: props.assetManifest });
|
|
4984
|
-
}
|
|
4985
|
-
return /* @__PURE__ */ jsx(EmojiEffect, { ...enhancedProps });
|
|
4986
|
-
}
|
|
4987
|
-
CanvasEffect.displayName = "CanvasEffect";
|
|
4988
3748
|
function pickPath(entry) {
|
|
4989
3749
|
if (Array.isArray(entry.path)) {
|
|
4990
3750
|
return entry.path[Math.floor(Math.random() * entry.path.length)];
|
|
@@ -5805,7 +4565,7 @@ function BattleBoard({
|
|
|
5805
4565
|
onUnitMove,
|
|
5806
4566
|
calculateDamage: calculateDamage2,
|
|
5807
4567
|
onDrawEffects,
|
|
5808
|
-
hasActiveEffects
|
|
4568
|
+
hasActiveEffects = false,
|
|
5809
4569
|
effectSpriteUrls = [],
|
|
5810
4570
|
resolveUnitFrame,
|
|
5811
4571
|
tileClickEvent,
|
|
@@ -5880,25 +4640,25 @@ function BattleBoard({
|
|
|
5880
4640
|
}, []);
|
|
5881
4641
|
useEffect(() => {
|
|
5882
4642
|
const interval = setInterval(() => {
|
|
5883
|
-
const
|
|
5884
|
-
if (!
|
|
5885
|
-
|
|
5886
|
-
const t2 = Math.min(
|
|
4643
|
+
const anim = movementAnimRef.current;
|
|
4644
|
+
if (!anim) return;
|
|
4645
|
+
anim.elapsed += 16;
|
|
4646
|
+
const t2 = Math.min(anim.elapsed / anim.duration, 1);
|
|
5887
4647
|
const eased = 1 - (1 - t2) * (1 - t2);
|
|
5888
|
-
const cx =
|
|
5889
|
-
const cy =
|
|
4648
|
+
const cx = anim.from.x + (anim.to.x - anim.from.x) * eased;
|
|
4649
|
+
const cy = anim.from.y + (anim.to.y - anim.from.y) * eased;
|
|
5890
4650
|
if (t2 >= 1) {
|
|
5891
4651
|
movementAnimRef.current = null;
|
|
5892
4652
|
setMovingPositions((prev) => {
|
|
5893
4653
|
const next = new Map(prev);
|
|
5894
|
-
next.delete(
|
|
4654
|
+
next.delete(anim.unitId);
|
|
5895
4655
|
return next;
|
|
5896
4656
|
});
|
|
5897
|
-
|
|
4657
|
+
anim.onComplete();
|
|
5898
4658
|
} else {
|
|
5899
4659
|
setMovingPositions((prev) => {
|
|
5900
4660
|
const next = new Map(prev);
|
|
5901
|
-
next.set(
|
|
4661
|
+
next.set(anim.unitId, { x: cx, y: cy });
|
|
5902
4662
|
return next;
|
|
5903
4663
|
});
|
|
5904
4664
|
}
|
|
@@ -6069,7 +4829,7 @@ function BattleBoard({
|
|
|
6069
4829
|
assetManifest,
|
|
6070
4830
|
backgroundImage,
|
|
6071
4831
|
onDrawEffects,
|
|
6072
|
-
hasActiveEffects
|
|
4832
|
+
hasActiveEffects,
|
|
6073
4833
|
effectSpriteUrls,
|
|
6074
4834
|
resolveUnitFrame,
|
|
6075
4835
|
unitScale
|
|
@@ -6365,25 +5125,25 @@ function WorldMapBoard({
|
|
|
6365
5125
|
}, []);
|
|
6366
5126
|
useEffect(() => {
|
|
6367
5127
|
const interval = setInterval(() => {
|
|
6368
|
-
const
|
|
6369
|
-
if (!
|
|
6370
|
-
|
|
6371
|
-
const t = Math.min(
|
|
5128
|
+
const anim = movementAnimRef.current;
|
|
5129
|
+
if (!anim) return;
|
|
5130
|
+
anim.elapsed += 16;
|
|
5131
|
+
const t = Math.min(anim.elapsed / anim.duration, 1);
|
|
6372
5132
|
const eased = 1 - (1 - t) * (1 - t);
|
|
6373
|
-
const cx =
|
|
6374
|
-
const cy =
|
|
5133
|
+
const cx = anim.from.x + (anim.to.x - anim.from.x) * eased;
|
|
5134
|
+
const cy = anim.from.y + (anim.to.y - anim.from.y) * eased;
|
|
6375
5135
|
if (t >= 1) {
|
|
6376
5136
|
movementAnimRef.current = null;
|
|
6377
5137
|
setMovingPositions((prev) => {
|
|
6378
5138
|
const n = new Map(prev);
|
|
6379
|
-
n.delete(
|
|
5139
|
+
n.delete(anim.heroId);
|
|
6380
5140
|
return n;
|
|
6381
5141
|
});
|
|
6382
|
-
|
|
5142
|
+
anim.onComplete();
|
|
6383
5143
|
} else {
|
|
6384
5144
|
setMovingPositions((prev) => {
|
|
6385
5145
|
const n = new Map(prev);
|
|
6386
|
-
n.set(
|
|
5146
|
+
n.set(anim.heroId, { x: cx, y: cy });
|
|
6387
5147
|
return n;
|
|
6388
5148
|
});
|
|
6389
5149
|
}
|
|
@@ -8398,8 +7158,8 @@ function SimulatorBoard({
|
|
|
8398
7158
|
const { t } = useTranslate();
|
|
8399
7159
|
const [values, setValues] = useState(() => {
|
|
8400
7160
|
const init = {};
|
|
8401
|
-
for (const
|
|
8402
|
-
init[
|
|
7161
|
+
for (const p of entity.parameters) {
|
|
7162
|
+
init[p.id] = p.initial;
|
|
8403
7163
|
}
|
|
8404
7164
|
return init;
|
|
8405
7165
|
});
|
|
@@ -8436,8 +7196,8 @@ function SimulatorBoard({
|
|
|
8436
7196
|
};
|
|
8437
7197
|
const handleFullReset = () => {
|
|
8438
7198
|
const init = {};
|
|
8439
|
-
for (const
|
|
8440
|
-
init[
|
|
7199
|
+
for (const p of entity.parameters) {
|
|
7200
|
+
init[p.id] = p.initial;
|
|
8441
7201
|
}
|
|
8442
7202
|
setValues(init);
|
|
8443
7203
|
setSubmitted(false);
|
|
@@ -8983,7 +7743,7 @@ function NegotiatorBoard({
|
|
|
8983
7743
|
if (isComplete) return;
|
|
8984
7744
|
const opponentAction = getOpponentAction(entity.opponentStrategy, entity.actions, history);
|
|
8985
7745
|
const payoff = entity.payoffMatrix.find(
|
|
8986
|
-
(
|
|
7746
|
+
(p) => p.playerAction === actionId && p.opponentAction === opponentAction
|
|
8987
7747
|
);
|
|
8988
7748
|
const result = {
|
|
8989
7749
|
round: currentRound + 1,
|
|
@@ -9157,7 +7917,7 @@ function resolvePreset(preset) {
|
|
|
9157
7917
|
if (typeof preset !== "string") return preset;
|
|
9158
7918
|
const needle = preset.toLowerCase();
|
|
9159
7919
|
return ALL_PRESETS.find(
|
|
9160
|
-
(
|
|
7920
|
+
(p) => p.id === preset || p.id.includes(needle) || p.name.toLowerCase().includes(needle)
|
|
9161
7921
|
) ?? projectileMotion;
|
|
9162
7922
|
}
|
|
9163
7923
|
function SimulationCanvas({
|
|
@@ -9857,7 +8617,7 @@ var LineChart2 = ({ data, height, showValues, fill = false }) => {
|
|
|
9857
8617
|
...point
|
|
9858
8618
|
}));
|
|
9859
8619
|
}, [data, maxValue, chartWidth, chartHeight, padding]);
|
|
9860
|
-
const linePath = points.map((
|
|
8620
|
+
const linePath = points.map((p, i) => `${i === 0 ? "M" : "L"} ${p.x} ${p.y}`).join(" ");
|
|
9861
8621
|
const areaPath = `${linePath} L ${points[points.length - 1]?.x ?? 0} ${padding.top + chartHeight} L ${padding.left} ${padding.top + chartHeight} Z`;
|
|
9862
8622
|
return /* @__PURE__ */ jsxs("svg", { width: "100%", height, viewBox: `0 0 ${width} ${height}`, preserveAspectRatio: "xMidYMid meet", children: [
|
|
9863
8623
|
[0, 0.25, 0.5, 0.75, 1].map((frac) => {
|
|
@@ -9878,18 +8638,18 @@ var LineChart2 = ({ data, height, showValues, fill = false }) => {
|
|
|
9878
8638
|
}),
|
|
9879
8639
|
fill && /* @__PURE__ */ jsx("path", { d: areaPath, fill: "var(--color-primary)", opacity: 0.1 }),
|
|
9880
8640
|
/* @__PURE__ */ jsx("path", { d: linePath, fill: "none", stroke: "var(--color-primary)", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }),
|
|
9881
|
-
points.map((
|
|
9882
|
-
/* @__PURE__ */ jsx("circle", { cx:
|
|
9883
|
-
showValues && /* @__PURE__ */ jsx("text", { x:
|
|
8641
|
+
points.map((p, idx) => /* @__PURE__ */ jsxs("g", { children: [
|
|
8642
|
+
/* @__PURE__ */ jsx("circle", { cx: p.x, cy: p.y, r: "4", fill: "var(--color-card)", stroke: "var(--color-primary)", strokeWidth: "2" }),
|
|
8643
|
+
showValues && /* @__PURE__ */ jsx("text", { x: p.x, y: p.y - 10, textAnchor: "middle", fill: "var(--color-foreground)", fontSize: "10", fontWeight: "500", children: p.value }),
|
|
9884
8644
|
/* @__PURE__ */ jsx(
|
|
9885
8645
|
"text",
|
|
9886
8646
|
{
|
|
9887
|
-
x:
|
|
8647
|
+
x: p.x,
|
|
9888
8648
|
y: height - 8,
|
|
9889
8649
|
textAnchor: "middle",
|
|
9890
8650
|
fill: "var(--color-muted-foreground)",
|
|
9891
8651
|
fontSize: "9",
|
|
9892
|
-
children:
|
|
8652
|
+
children: p.label
|
|
9893
8653
|
}
|
|
9894
8654
|
)
|
|
9895
8655
|
] }, idx))
|
|
@@ -10534,12 +9294,12 @@ var DocumentViewer = ({
|
|
|
10534
9294
|
const handleZoomIn = useCallback(() => setZoom((z) => Math.min(z + 25, 200)), []);
|
|
10535
9295
|
const handleZoomOut = useCallback(() => setZoom((z) => Math.max(z - 25, 50)), []);
|
|
10536
9296
|
const handlePagePrev = useCallback(() => {
|
|
10537
|
-
setCurrentPage((
|
|
9297
|
+
setCurrentPage((p) => Math.max(p - 1, 1));
|
|
10538
9298
|
eventBus.emit("UI:DOCUMENT_PAGE_CHANGE", { page: currentPage - 1 });
|
|
10539
9299
|
}, [eventBus, currentPage]);
|
|
10540
9300
|
const handlePageNext = useCallback(() => {
|
|
10541
9301
|
if (totalPages) {
|
|
10542
|
-
setCurrentPage((
|
|
9302
|
+
setCurrentPage((p) => Math.min(p + 1, totalPages));
|
|
10543
9303
|
eventBus.emit("UI:DOCUMENT_PAGE_CHANGE", { page: currentPage + 1 });
|
|
10544
9304
|
}
|
|
10545
9305
|
}, [totalPages, eventBus, currentPage]);
|
|
@@ -12141,4 +10901,4 @@ function WorldMapTemplate({
|
|
|
12141
10901
|
}
|
|
12142
10902
|
WorldMapTemplate.displayName = "WorldMapTemplate";
|
|
12143
10903
|
|
|
12144
|
-
export { ALL_PRESETS, AR_BOOK_FIELDS, ActionPalette, ActionTile, AuthLayout, BattleBoard, BattleTemplate, BookChapterView, BookCoverPage, BookNavBar, BookTableOfContents, BookViewer, BuilderBoard,
|
|
10904
|
+
export { ALL_PRESETS, AR_BOOK_FIELDS, ActionPalette, ActionTile, AuthLayout, BattleBoard, BattleTemplate, BookChapterView, BookCoverPage, BookNavBar, BookTableOfContents, BookViewer, BuilderBoard, CastleBoard, CastleTemplate, Chart, ClassifierBoard, CodeView, CodeViewer, CollapsibleSection, ConfirmDialog, ContentRenderer, CounterTemplate, DashboardGrid, DashboardLayout, DebuggerBoard, DocumentViewer, StateMachineView as DomStateMachineVisualizer, DrawerSlot, EditorCheckbox, EditorSelect, EditorSlider, EditorTextInput, EditorToolbar, EventHandlerBoard, EventLog, FEATURE_TYPES, FormActions, FormLayout, FormSection, GameAudioContext, GameAudioProvider, GameAudioToggle, GameShell, GameTemplate, GenericAppTemplate, GraphCanvas, Header, IDENTITY_BOOK_FIELDS, JazariStateMachine, List, MediaGallery, ModalSlot, Navigation, NegotiatorBoard, NotifyListener, ObjectRulePanel, StateMachineView as OrbitalStateMachineView, OrbitalVisualization, PhysicsManager, RuleEditor, SHEET_COLUMNS, SPRITE_SHEET_LAYOUT, Section, SequenceBar, SequencerBoard, Sidebar, SignaturePad, SimulationCanvas, SimulationControls, SimulationGraph, SimulatorBoard, Split, SplitPane, StateArchitectBoard, StateMachineView, StateNode2 as StateNode, StatusBar, TERRAIN_COLORS, TabbedContainer, Table, TerrainPalette, Timeline, ToastSlot, TraitSlot, TraitStateViewer, TransitionArrow, UncontrolledBattleBoard, VariablePanel, WizardContainer, WorldMapBoard, WorldMapTemplate, applyTemporaryEffect, calculateAttackTargets, calculateDamage, calculateValidMoves, combatAnimations, combatClasses, combatEffects, createInitialGameState, createUnitAnimationState, generateCombatMessage, getCurrentFrame, inferDirection, mapBookData, pendulum, projectileMotion, resolveFieldMap, resolveFrame, resolveSheetDirection, springOscillator, tickAnimationState, transitionAnimation, useBattleState, useGameAudio, useGameAudioContext, usePhysics2D, useSpriteAnimations };
|