@almadar/ui 5.48.0 → 5.49.0
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/avl/index.cjs +2681 -148
- package/dist/avl/index.css +504 -0
- package/dist/avl/index.js +2681 -149
- package/dist/components/core/templates/index.d.ts +3 -0
- package/dist/components/game/atoms/ActionButton.d.ts +4 -1
- package/dist/components/game/atoms/ControlButton.d.ts +4 -2
- package/dist/components/game/atoms/DamageNumber.d.ts +4 -1
- package/dist/components/game/atoms/ScoreDisplay.d.ts +4 -1
- package/dist/components/game/atoms/TurnIndicator.d.ts +4 -1
- package/dist/components/game/molecules/EnemyPlate.d.ts +4 -1
- package/dist/components/game/molecules/StatBadge.d.ts +4 -1
- package/dist/components/game/molecules/three/index.cjs +1371 -283
- package/dist/components/game/molecules/three/index.js +1372 -284
- package/dist/components/game/organisms/GameBoard3D.d.ts +62 -0
- package/dist/components/game/organisms/PlatformerBoard.d.ts +51 -0
- package/dist/components/game/organisms/RoguelikeBoard.d.ts +59 -0
- package/dist/components/game/organisms/TowerDefenseBoard.d.ts +64 -0
- package/dist/components/game/organisms/index.d.ts +4 -0
- package/dist/components/game/templates/GameCanvas3DBattleTemplate.d.ts +22 -35
- package/dist/components/game/templates/GameCanvas3DCastleTemplate.d.ts +23 -23
- package/dist/components/game/templates/GameCanvas3DWorldMapTemplate.d.ts +27 -29
- package/dist/components/game/templates/PlatformerTemplate.d.ts +26 -0
- package/dist/components/game/templates/RoguelikeTemplate.d.ts +23 -0
- package/dist/components/game/templates/TowerDefenseTemplate.d.ts +43 -0
- package/dist/components/index.cjs +2674 -127
- package/dist/components/index.css +504 -0
- package/dist/components/index.js +2668 -129
- package/dist/docs/index.css +504 -0
- package/dist/providers/index.cjs +2664 -131
- package/dist/providers/index.css +504 -0
- package/dist/providers/index.js +2664 -132
- package/dist/runtime/index.cjs +2665 -132
- package/dist/runtime/index.css +504 -0
- package/dist/runtime/index.js +2665 -133
- package/package.json +1 -1
package/dist/providers/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React83 from 'react';
|
|
2
|
-
import React83__default, { createContext, useContext, useMemo, useRef, useEffect, useCallback, Suspense, useState, useLayoutEffect, lazy, useId, useSyncExternalStore } from 'react';
|
|
2
|
+
import React83__default, { createContext, useContext, useMemo, useRef, useEffect, useCallback, Suspense, useState, useLayoutEffect, lazy, useId, useSyncExternalStore, forwardRef, useImperativeHandle, Component } from 'react';
|
|
3
3
|
import { createLogger, isLogLevelEnabled } from '@almadar/logger';
|
|
4
4
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
5
5
|
import { EventBusContext, useTraitScope, TraitScopeProvider } from '@almadar/ui/providers';
|
|
@@ -41,6 +41,12 @@ import { DndContext, pointerWithin, rectIntersection, closestCorners, useSensors
|
|
|
41
41
|
import { useSortable, arrayMove, sortableKeyboardCoordinates, SortableContext, rectSortingStrategy, verticalListSortingStrategy } from '@dnd-kit/sortable';
|
|
42
42
|
import { CSS } from '@dnd-kit/utilities';
|
|
43
43
|
import { useNodeId, ReactFlowProvider, Handle, Position } from '@xyflow/react';
|
|
44
|
+
import * as THREE from 'three';
|
|
45
|
+
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
|
|
46
|
+
import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader.js';
|
|
47
|
+
import { GLTFLoader as GLTFLoader$1 } from 'three/examples/jsm/loaders/GLTFLoader';
|
|
48
|
+
import { Canvas, useThree } from '@react-three/fiber';
|
|
49
|
+
import { Grid as Grid$1, OrbitControls } from '@react-three/drei';
|
|
44
50
|
import { getPatternDefinition, getComponentForPattern as getComponentForPattern$1 } from '@almadar/patterns';
|
|
45
51
|
|
|
46
52
|
var __defProp = Object.defineProperty;
|
|
@@ -673,7 +679,7 @@ var init_Box = __esm({
|
|
|
673
679
|
position,
|
|
674
680
|
className,
|
|
675
681
|
children,
|
|
676
|
-
as:
|
|
682
|
+
as: Component2 = "div",
|
|
677
683
|
action,
|
|
678
684
|
actionPayload,
|
|
679
685
|
hoverEvent,
|
|
@@ -705,7 +711,7 @@ var init_Box = __esm({
|
|
|
705
711
|
}, [hoverEvent, eventBus, onMouseLeave]);
|
|
706
712
|
const isClickable = action || onClick;
|
|
707
713
|
return React83__default.createElement(
|
|
708
|
-
|
|
714
|
+
Component2,
|
|
709
715
|
{
|
|
710
716
|
ref,
|
|
711
717
|
className: cn(
|
|
@@ -843,9 +849,9 @@ function resolvePhosphor(name, weight, family) {
|
|
|
843
849
|
(lib) => {
|
|
844
850
|
const PhosphorComp = lib[target];
|
|
845
851
|
if (!PhosphorComp || typeof PhosphorComp !== "object") return null;
|
|
846
|
-
const
|
|
852
|
+
const Component2 = PhosphorComp;
|
|
847
853
|
const Adapter = (props) => /* @__PURE__ */ jsx(
|
|
848
|
-
|
|
854
|
+
Component2,
|
|
849
855
|
{
|
|
850
856
|
weight,
|
|
851
857
|
className: props.className,
|
|
@@ -869,9 +875,9 @@ function resolveTabler(name, family) {
|
|
|
869
875
|
(lib) => {
|
|
870
876
|
const TablerComp = lib[target];
|
|
871
877
|
if (!TablerComp || typeof TablerComp !== "object") return null;
|
|
872
|
-
const
|
|
878
|
+
const Component2 = TablerComp;
|
|
873
879
|
const Adapter = (props) => /* @__PURE__ */ jsx(
|
|
874
|
-
|
|
880
|
+
Component2,
|
|
875
881
|
{
|
|
876
882
|
stroke: props.strokeWidth ?? 1.5,
|
|
877
883
|
className: props.className,
|
|
@@ -895,9 +901,9 @@ function resolveFa(name, family) {
|
|
|
895
901
|
(lib) => {
|
|
896
902
|
const FaComp = lib[target];
|
|
897
903
|
if (!FaComp || typeof FaComp !== "function") return null;
|
|
898
|
-
const
|
|
904
|
+
const Component2 = FaComp;
|
|
899
905
|
const Adapter = (props) => /* @__PURE__ */ jsx(
|
|
900
|
-
|
|
906
|
+
Component2,
|
|
901
907
|
{
|
|
902
908
|
className: props.className,
|
|
903
909
|
style: props.style,
|
|
@@ -1852,8 +1858,8 @@ var init_Typography = __esm({
|
|
|
1852
1858
|
children
|
|
1853
1859
|
}) => {
|
|
1854
1860
|
const variant = variantProp ?? (level ? `h${level}` : "body1");
|
|
1855
|
-
const
|
|
1856
|
-
const Comp =
|
|
1861
|
+
const Component2 = as || defaultElements[variant];
|
|
1862
|
+
const Comp = Component2;
|
|
1857
1863
|
return /* @__PURE__ */ jsx(
|
|
1858
1864
|
Comp,
|
|
1859
1865
|
{
|
|
@@ -4408,10 +4414,10 @@ var init_Center = __esm({
|
|
|
4408
4414
|
className,
|
|
4409
4415
|
style,
|
|
4410
4416
|
children,
|
|
4411
|
-
as:
|
|
4417
|
+
as: Component2 = "div"
|
|
4412
4418
|
}) => {
|
|
4413
4419
|
const mergedStyle = minHeight ? { minHeight, ...style } : style;
|
|
4414
|
-
const Comp =
|
|
4420
|
+
const Comp = Component2;
|
|
4415
4421
|
return /* @__PURE__ */ jsx(
|
|
4416
4422
|
Comp,
|
|
4417
4423
|
{
|
|
@@ -5042,7 +5048,7 @@ var init_Stack = __esm({
|
|
|
5042
5048
|
className,
|
|
5043
5049
|
style,
|
|
5044
5050
|
children,
|
|
5045
|
-
as:
|
|
5051
|
+
as: Component2 = "div",
|
|
5046
5052
|
onClick,
|
|
5047
5053
|
onKeyDown,
|
|
5048
5054
|
role,
|
|
@@ -5060,7 +5066,7 @@ var init_Stack = __esm({
|
|
|
5060
5066
|
};
|
|
5061
5067
|
const isHorizontal = direction === "horizontal";
|
|
5062
5068
|
const directionClass = responsive && isHorizontal ? reverse ? "flex-col-reverse md:flex-row-reverse" : "flex-col md:flex-row" : isHorizontal ? reverse ? "flex-row-reverse" : "flex-row" : reverse ? "flex-col-reverse" : "flex-col";
|
|
5063
|
-
const Comp =
|
|
5069
|
+
const Comp = Component2;
|
|
5064
5070
|
return /* @__PURE__ */ jsx(
|
|
5065
5071
|
Comp,
|
|
5066
5072
|
{
|
|
@@ -7116,6 +7122,7 @@ var init_HealthBar = __esm({
|
|
|
7116
7122
|
}
|
|
7117
7123
|
});
|
|
7118
7124
|
function ScoreDisplay({
|
|
7125
|
+
assetUrl = DEFAULT_ASSET_URL,
|
|
7119
7126
|
value,
|
|
7120
7127
|
label,
|
|
7121
7128
|
icon,
|
|
@@ -7162,14 +7169,24 @@ function ScoreDisplay({
|
|
|
7162
7169
|
className
|
|
7163
7170
|
),
|
|
7164
7171
|
children: [
|
|
7165
|
-
|
|
7172
|
+
assetUrl ? /* @__PURE__ */ jsx(
|
|
7173
|
+
"img",
|
|
7174
|
+
{
|
|
7175
|
+
src: assetUrl,
|
|
7176
|
+
alt: "",
|
|
7177
|
+
width: 20,
|
|
7178
|
+
height: 20,
|
|
7179
|
+
style: { imageRendering: "pixelated", objectFit: "contain" },
|
|
7180
|
+
className: "flex-shrink-0"
|
|
7181
|
+
}
|
|
7182
|
+
) : icon ? /* @__PURE__ */ jsx("span", { className: "flex-shrink-0", children: typeof icon === "string" ? /* @__PURE__ */ jsx(Icon, { name: icon }) : /* @__PURE__ */ jsx(Icon, { icon }) }) : null,
|
|
7166
7183
|
label && /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: label }),
|
|
7167
7184
|
/* @__PURE__ */ jsx("span", { className: "tabular-nums", children: formattedValue })
|
|
7168
7185
|
]
|
|
7169
7186
|
}
|
|
7170
7187
|
);
|
|
7171
7188
|
}
|
|
7172
|
-
var sizeMap2;
|
|
7189
|
+
var sizeMap2, DEFAULT_ASSET_URL;
|
|
7173
7190
|
var init_ScoreDisplay = __esm({
|
|
7174
7191
|
"components/game/atoms/ScoreDisplay.tsx"() {
|
|
7175
7192
|
"use client";
|
|
@@ -7181,10 +7198,12 @@ var init_ScoreDisplay = __esm({
|
|
|
7181
7198
|
lg: "text-2xl",
|
|
7182
7199
|
xl: "text-4xl"
|
|
7183
7200
|
};
|
|
7201
|
+
DEFAULT_ASSET_URL = "https://almadar-kflow-assets.web.app/shared/effects/particles/star_01.png";
|
|
7184
7202
|
ScoreDisplay.displayName = "ScoreDisplay";
|
|
7185
7203
|
}
|
|
7186
7204
|
});
|
|
7187
7205
|
function ControlButton({
|
|
7206
|
+
assetUrl = DEFAULT_ASSET_URL2,
|
|
7188
7207
|
label,
|
|
7189
7208
|
icon,
|
|
7190
7209
|
size = "md",
|
|
@@ -7231,7 +7250,7 @@ function ControlButton({
|
|
|
7231
7250
|
},
|
|
7232
7251
|
[isPressed, releaseEvent, eventBus, onRelease]
|
|
7233
7252
|
);
|
|
7234
|
-
return /* @__PURE__ */
|
|
7253
|
+
return /* @__PURE__ */ jsx(
|
|
7235
7254
|
"button",
|
|
7236
7255
|
{
|
|
7237
7256
|
type: "button",
|
|
@@ -7252,20 +7271,27 @@ function ControlButton({
|
|
|
7252
7271
|
disabled && "opacity-50 cursor-not-allowed",
|
|
7253
7272
|
className
|
|
7254
7273
|
),
|
|
7255
|
-
children:
|
|
7256
|
-
|
|
7257
|
-
|
|
7258
|
-
|
|
7259
|
-
|
|
7260
|
-
|
|
7261
|
-
|
|
7262
|
-
|
|
7263
|
-
|
|
7264
|
-
|
|
7274
|
+
children: assetUrl ? /* @__PURE__ */ jsx(
|
|
7275
|
+
"img",
|
|
7276
|
+
{
|
|
7277
|
+
src: assetUrl,
|
|
7278
|
+
alt: "",
|
|
7279
|
+
width: 24,
|
|
7280
|
+
height: 24,
|
|
7281
|
+
style: { imageRendering: "pixelated", objectFit: "contain" },
|
|
7282
|
+
className: "flex-shrink-0"
|
|
7283
|
+
}
|
|
7284
|
+
) : icon ? /* @__PURE__ */ jsx("span", { className: "text-2xl", children: typeof icon === "string" ? /^[a-zA-Z0-9-]+$/.test(icon) ? (() => {
|
|
7285
|
+
const I = resolveIcon(icon);
|
|
7286
|
+
return I ? /* @__PURE__ */ jsx(I, { className: "w-6 h-6" }) : null;
|
|
7287
|
+
})() : icon : /* @__PURE__ */ (() => {
|
|
7288
|
+
const I = icon;
|
|
7289
|
+
return /* @__PURE__ */ jsx(I, { className: "w-6 h-6" });
|
|
7290
|
+
})() }) : label ? /* @__PURE__ */ jsx("span", { children: label }) : null
|
|
7265
7291
|
}
|
|
7266
7292
|
);
|
|
7267
7293
|
}
|
|
7268
|
-
var sizeMap3, shapeMap, variantMap;
|
|
7294
|
+
var sizeMap3, shapeMap, variantMap, DEFAULT_ASSET_URL2;
|
|
7269
7295
|
var init_ControlButton = __esm({
|
|
7270
7296
|
"components/game/atoms/ControlButton.tsx"() {
|
|
7271
7297
|
"use client";
|
|
@@ -7288,6 +7314,7 @@ var init_ControlButton = __esm({
|
|
|
7288
7314
|
secondary: "bg-secondary text-secondary-foreground border-border hover:bg-secondary-hover",
|
|
7289
7315
|
ghost: "bg-transparent text-foreground border-border hover:bg-muted"
|
|
7290
7316
|
};
|
|
7317
|
+
DEFAULT_ASSET_URL2 = "https://almadar-kflow-assets.web.app/shared/effects/particles/circle_01.png";
|
|
7291
7318
|
ControlButton.displayName = "ControlButton";
|
|
7292
7319
|
}
|
|
7293
7320
|
});
|
|
@@ -7367,7 +7394,7 @@ var init_Sprite = __esm({
|
|
|
7367
7394
|
}
|
|
7368
7395
|
});
|
|
7369
7396
|
function StateIndicator({
|
|
7370
|
-
assetUrl =
|
|
7397
|
+
assetUrl = DEFAULT_ASSET_URL3,
|
|
7371
7398
|
state = "idle",
|
|
7372
7399
|
label,
|
|
7373
7400
|
size = "md",
|
|
@@ -7406,13 +7433,13 @@ function StateIndicator({
|
|
|
7406
7433
|
}
|
|
7407
7434
|
);
|
|
7408
7435
|
}
|
|
7409
|
-
var
|
|
7436
|
+
var DEFAULT_ASSET_URL3, DEFAULT_STATE_STYLES, DEFAULT_STYLE, SIZE_CLASSES;
|
|
7410
7437
|
var init_StateIndicator = __esm({
|
|
7411
7438
|
"components/game/atoms/StateIndicator.tsx"() {
|
|
7412
7439
|
init_Box();
|
|
7413
7440
|
init_Icon();
|
|
7414
7441
|
init_cn();
|
|
7415
|
-
|
|
7442
|
+
DEFAULT_ASSET_URL3 = "https://almadar-kflow-assets.web.app/shared/isometric-dungeon/Isometric/chestClosed_E.png";
|
|
7416
7443
|
DEFAULT_STATE_STYLES = {
|
|
7417
7444
|
idle: { icon: "\u23F8", bgClass: "bg-muted" },
|
|
7418
7445
|
active: { icon: "\u25B6", bgClass: "bg-success" },
|
|
@@ -7487,7 +7514,7 @@ var init_TimerDisplay = __esm({
|
|
|
7487
7514
|
}
|
|
7488
7515
|
});
|
|
7489
7516
|
function ResourceCounter({
|
|
7490
|
-
assetUrl =
|
|
7517
|
+
assetUrl = DEFAULT_ASSET_URL4,
|
|
7491
7518
|
icon,
|
|
7492
7519
|
label = "Gold",
|
|
7493
7520
|
value = 250,
|
|
@@ -7530,7 +7557,7 @@ function ResourceCounter({
|
|
|
7530
7557
|
}
|
|
7531
7558
|
);
|
|
7532
7559
|
}
|
|
7533
|
-
var colorTokenClasses2,
|
|
7560
|
+
var colorTokenClasses2, DEFAULT_ASSET_URL4, sizeMap5;
|
|
7534
7561
|
var init_ResourceCounter = __esm({
|
|
7535
7562
|
"components/game/atoms/ResourceCounter.tsx"() {
|
|
7536
7563
|
init_cn();
|
|
@@ -7543,7 +7570,7 @@ var init_ResourceCounter = __esm({
|
|
|
7543
7570
|
error: "text-error",
|
|
7544
7571
|
muted: "text-muted-foreground"
|
|
7545
7572
|
};
|
|
7546
|
-
|
|
7573
|
+
DEFAULT_ASSET_URL4 = "https://almadar-kflow-assets.web.app/shared/world-map/gold_mine.png";
|
|
7547
7574
|
sizeMap5 = {
|
|
7548
7575
|
sm: { wrapper: "text-xs gap-1 px-1.5 py-0.5", icon: "text-sm", img: 16 },
|
|
7549
7576
|
md: { wrapper: "text-sm gap-1.5 px-2 py-1", icon: "text-base", img: 20 },
|
|
@@ -7553,7 +7580,7 @@ var init_ResourceCounter = __esm({
|
|
|
7553
7580
|
}
|
|
7554
7581
|
});
|
|
7555
7582
|
function ItemSlot({
|
|
7556
|
-
assetUrl =
|
|
7583
|
+
assetUrl = DEFAULT_ASSET_URL5,
|
|
7557
7584
|
icon = "sword",
|
|
7558
7585
|
label = "Iron Sword",
|
|
7559
7586
|
quantity,
|
|
@@ -7612,7 +7639,7 @@ function ItemSlot({
|
|
|
7612
7639
|
}
|
|
7613
7640
|
);
|
|
7614
7641
|
}
|
|
7615
|
-
var sizeMap6, rarityBorderMap, rarityGlowMap,
|
|
7642
|
+
var sizeMap6, rarityBorderMap, rarityGlowMap, DEFAULT_ASSET_URL5, assetSizeMap;
|
|
7616
7643
|
var init_ItemSlot = __esm({
|
|
7617
7644
|
"components/game/atoms/ItemSlot.tsx"() {
|
|
7618
7645
|
"use client";
|
|
@@ -7637,7 +7664,7 @@ var init_ItemSlot = __esm({
|
|
|
7637
7664
|
epic: "shadow-lg",
|
|
7638
7665
|
legendary: "shadow-lg"
|
|
7639
7666
|
};
|
|
7640
|
-
|
|
7667
|
+
DEFAULT_ASSET_URL5 = "https://almadar-kflow-assets.web.app/shared/isometric-dungeon/Isometric/chestClosed_E.png";
|
|
7641
7668
|
assetSizeMap = {
|
|
7642
7669
|
sm: 28,
|
|
7643
7670
|
md: 40,
|
|
@@ -7647,6 +7674,7 @@ var init_ItemSlot = __esm({
|
|
|
7647
7674
|
}
|
|
7648
7675
|
});
|
|
7649
7676
|
function TurnIndicator({
|
|
7677
|
+
assetUrl = DEFAULT_ASSET_URL6,
|
|
7650
7678
|
currentTurn = 1,
|
|
7651
7679
|
maxTurns,
|
|
7652
7680
|
activeTeam,
|
|
@@ -7679,14 +7707,24 @@ function TurnIndicator({
|
|
|
7679
7707
|
] }),
|
|
7680
7708
|
activeTeam && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
7681
7709
|
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "|" }),
|
|
7682
|
-
/* @__PURE__ */ jsx(
|
|
7710
|
+
assetUrl ? /* @__PURE__ */ jsx(
|
|
7711
|
+
"img",
|
|
7712
|
+
{
|
|
7713
|
+
src: assetUrl,
|
|
7714
|
+
alt: "",
|
|
7715
|
+
width: 12,
|
|
7716
|
+
height: 12,
|
|
7717
|
+
style: { imageRendering: "pixelated", objectFit: "contain" },
|
|
7718
|
+
className: "flex-shrink-0"
|
|
7719
|
+
}
|
|
7720
|
+
) : /* @__PURE__ */ jsx("span", { className: cn("rounded-full bg-success/20", sizes.dot) }),
|
|
7683
7721
|
/* @__PURE__ */ jsx("span", { className: "text-success", children: activeTeam })
|
|
7684
7722
|
] })
|
|
7685
7723
|
]
|
|
7686
7724
|
}
|
|
7687
7725
|
);
|
|
7688
7726
|
}
|
|
7689
|
-
var sizeMap7;
|
|
7727
|
+
var sizeMap7, DEFAULT_ASSET_URL6;
|
|
7690
7728
|
var init_TurnIndicator = __esm({
|
|
7691
7729
|
"components/game/atoms/TurnIndicator.tsx"() {
|
|
7692
7730
|
init_cn();
|
|
@@ -7695,6 +7733,7 @@ var init_TurnIndicator = __esm({
|
|
|
7695
7733
|
md: { wrapper: "text-sm gap-2 px-3 py-1", dot: "w-2 h-2" },
|
|
7696
7734
|
lg: { wrapper: "text-base gap-2.5 px-4 py-1.5", dot: "w-2.5 h-2.5" }
|
|
7697
7735
|
};
|
|
7736
|
+
DEFAULT_ASSET_URL6 = "https://almadar-kflow-assets.web.app/shared/effects/particles/symbol_01.png";
|
|
7698
7737
|
TurnIndicator.displayName = "TurnIndicator";
|
|
7699
7738
|
}
|
|
7700
7739
|
});
|
|
@@ -7710,7 +7749,7 @@ function getComboScale(combo) {
|
|
|
7710
7749
|
return "";
|
|
7711
7750
|
}
|
|
7712
7751
|
function ComboCounter({
|
|
7713
|
-
assetUrl =
|
|
7752
|
+
assetUrl = DEFAULT_ASSET_URL7,
|
|
7714
7753
|
combo = 5,
|
|
7715
7754
|
multiplier,
|
|
7716
7755
|
streak,
|
|
@@ -7755,11 +7794,11 @@ function ComboCounter({
|
|
|
7755
7794
|
}
|
|
7756
7795
|
);
|
|
7757
7796
|
}
|
|
7758
|
-
var
|
|
7797
|
+
var DEFAULT_ASSET_URL7, sizeMap8;
|
|
7759
7798
|
var init_ComboCounter = __esm({
|
|
7760
7799
|
"components/game/atoms/ComboCounter.tsx"() {
|
|
7761
7800
|
init_cn();
|
|
7762
|
-
|
|
7801
|
+
DEFAULT_ASSET_URL7 = "https://almadar-kflow-assets.web.app/shared/effects/flash/flash00.png";
|
|
7763
7802
|
sizeMap8 = {
|
|
7764
7803
|
sm: { combo: "text-lg", label: "text-xs", multiplier: "text-xs" },
|
|
7765
7804
|
md: { combo: "text-2xl", label: "text-xs", multiplier: "text-sm" },
|
|
@@ -7853,7 +7892,7 @@ var init_XPBar = __esm({
|
|
|
7853
7892
|
}
|
|
7854
7893
|
});
|
|
7855
7894
|
function WaypointMarker({
|
|
7856
|
-
assetUrl =
|
|
7895
|
+
assetUrl = DEFAULT_ASSET_URL8,
|
|
7857
7896
|
label,
|
|
7858
7897
|
icon,
|
|
7859
7898
|
active = true,
|
|
@@ -7919,12 +7958,12 @@ function WaypointMarker({
|
|
|
7919
7958
|
)
|
|
7920
7959
|
] });
|
|
7921
7960
|
}
|
|
7922
|
-
var
|
|
7961
|
+
var DEFAULT_ASSET_URL8, sizeMap10, checkIcon;
|
|
7923
7962
|
var init_WaypointMarker = __esm({
|
|
7924
7963
|
"components/game/atoms/WaypointMarker.tsx"() {
|
|
7925
7964
|
init_cn();
|
|
7926
7965
|
init_Icon();
|
|
7927
|
-
|
|
7966
|
+
DEFAULT_ASSET_URL8 = "https://almadar-kflow-assets.web.app/shared/world-map/battle_marker.png";
|
|
7928
7967
|
sizeMap10 = {
|
|
7929
7968
|
sm: { dot: "w-4 h-4", ring: "w-6 h-6", label: "text-xs mt-1", img: 12 },
|
|
7930
7969
|
md: { dot: "w-6 h-6", ring: "w-8 h-8", label: "text-sm mt-1.5", img: 18 },
|
|
@@ -7941,7 +7980,7 @@ function formatDuration(seconds) {
|
|
|
7941
7980
|
return `${Math.round(seconds)}s`;
|
|
7942
7981
|
}
|
|
7943
7982
|
function StatusEffect({
|
|
7944
|
-
assetUrl =
|
|
7983
|
+
assetUrl = DEFAULT_ASSET_URL9,
|
|
7945
7984
|
icon = "shield",
|
|
7946
7985
|
label = "Shield",
|
|
7947
7986
|
duration = 30,
|
|
@@ -7999,12 +8038,12 @@ function StatusEffect({
|
|
|
7999
8038
|
label && /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground mt-0.5 text-center whitespace-nowrap", children: label })
|
|
8000
8039
|
] });
|
|
8001
8040
|
}
|
|
8002
|
-
var
|
|
8041
|
+
var DEFAULT_ASSET_URL9, sizeMap11, variantStyles7;
|
|
8003
8042
|
var init_StatusEffect = __esm({
|
|
8004
8043
|
"components/game/atoms/StatusEffect.tsx"() {
|
|
8005
8044
|
init_cn();
|
|
8006
8045
|
init_Icon();
|
|
8007
|
-
|
|
8046
|
+
DEFAULT_ASSET_URL9 = "https://almadar-kflow-assets.web.app/shared/effects/particles/flame_01.png";
|
|
8008
8047
|
sizeMap11 = {
|
|
8009
8048
|
sm: { container: "w-8 h-8", icon: "text-sm", badge: "text-xs -top-1 -right-1 w-4 h-4", timer: "text-[9px]", img: 20 },
|
|
8010
8049
|
md: { container: "w-10 h-10", icon: "text-base", badge: "text-xs -top-1 -right-1 w-5 h-5", timer: "text-xs", img: 28 },
|
|
@@ -8019,6 +8058,7 @@ var init_StatusEffect = __esm({
|
|
|
8019
8058
|
}
|
|
8020
8059
|
});
|
|
8021
8060
|
function DamageNumber({
|
|
8061
|
+
assetUrl = DEFAULT_ASSET_URL10,
|
|
8022
8062
|
value = 42,
|
|
8023
8063
|
type = "damage",
|
|
8024
8064
|
size = "md",
|
|
@@ -8027,22 +8067,35 @@ function DamageNumber({
|
|
|
8027
8067
|
const displayText = type === "miss" ? "MISS" : type === "heal" ? `+${value}` : `${value}`;
|
|
8028
8068
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
8029
8069
|
/* @__PURE__ */ jsx("style", { children: floatKeyframes }),
|
|
8030
|
-
/* @__PURE__ */
|
|
8070
|
+
/* @__PURE__ */ jsxs(
|
|
8031
8071
|
"span",
|
|
8032
8072
|
{
|
|
8033
8073
|
className: cn(
|
|
8034
|
-
"inline-
|
|
8074
|
+
"inline-flex items-center gap-0.5 font-mono select-none pointer-events-none",
|
|
8035
8075
|
sizeMap12[size],
|
|
8036
8076
|
typeStyles[type],
|
|
8037
8077
|
className
|
|
8038
8078
|
),
|
|
8039
8079
|
style: { animation: "damageFloat 1s ease-out forwards" },
|
|
8040
|
-
children:
|
|
8080
|
+
children: [
|
|
8081
|
+
assetUrl && /* @__PURE__ */ jsx(
|
|
8082
|
+
"img",
|
|
8083
|
+
{
|
|
8084
|
+
src: assetUrl,
|
|
8085
|
+
alt: "",
|
|
8086
|
+
width: 14,
|
|
8087
|
+
height: 14,
|
|
8088
|
+
style: { imageRendering: "pixelated", objectFit: "contain" },
|
|
8089
|
+
className: "flex-shrink-0"
|
|
8090
|
+
}
|
|
8091
|
+
),
|
|
8092
|
+
displayText
|
|
8093
|
+
]
|
|
8041
8094
|
}
|
|
8042
8095
|
)
|
|
8043
8096
|
] });
|
|
8044
8097
|
}
|
|
8045
|
-
var sizeMap12, typeStyles, floatKeyframes;
|
|
8098
|
+
var sizeMap12, typeStyles, floatKeyframes, DEFAULT_ASSET_URL10;
|
|
8046
8099
|
var init_DamageNumber = __esm({
|
|
8047
8100
|
"components/game/atoms/DamageNumber.tsx"() {
|
|
8048
8101
|
init_cn();
|
|
@@ -8064,6 +8117,7 @@ var init_DamageNumber = __esm({
|
|
|
8064
8117
|
100% { opacity: 0; transform: translateY(-32px) scale(0.8); }
|
|
8065
8118
|
}
|
|
8066
8119
|
`;
|
|
8120
|
+
DEFAULT_ASSET_URL10 = "https://almadar-kflow-assets.web.app/shared/effects/particles/spark_01.png";
|
|
8067
8121
|
DamageNumber.displayName = "DamageNumber";
|
|
8068
8122
|
}
|
|
8069
8123
|
});
|
|
@@ -8152,6 +8206,7 @@ var init_ChoiceButton = __esm({
|
|
|
8152
8206
|
}
|
|
8153
8207
|
});
|
|
8154
8208
|
function ActionButton({
|
|
8209
|
+
assetUrl = DEFAULT_ASSET_URL11,
|
|
8155
8210
|
label = "Attack",
|
|
8156
8211
|
icon,
|
|
8157
8212
|
cooldown = 0,
|
|
@@ -8191,13 +8246,23 @@ function ActionButton({
|
|
|
8191
8246
|
}
|
|
8192
8247
|
}
|
|
8193
8248
|
),
|
|
8194
|
-
|
|
8249
|
+
assetUrl ? /* @__PURE__ */ jsx(
|
|
8250
|
+
"img",
|
|
8251
|
+
{
|
|
8252
|
+
src: assetUrl,
|
|
8253
|
+
alt: "",
|
|
8254
|
+
width: 16,
|
|
8255
|
+
height: 16,
|
|
8256
|
+
style: { imageRendering: "pixelated", objectFit: "contain" },
|
|
8257
|
+
className: cn("flex-shrink-0", sizes.icon)
|
|
8258
|
+
}
|
|
8259
|
+
) : icon ? /* @__PURE__ */ jsx("span", { className: cn("flex-shrink-0", sizes.icon), children: typeof icon === "string" ? (() => {
|
|
8195
8260
|
const I = resolveIcon(icon);
|
|
8196
8261
|
return I ? /* @__PURE__ */ jsx(I, { className: "w-4 h-4" }) : null;
|
|
8197
8262
|
})() : /* @__PURE__ */ (() => {
|
|
8198
8263
|
const I = icon;
|
|
8199
8264
|
return /* @__PURE__ */ jsx(I, { className: "w-4 h-4" });
|
|
8200
|
-
})() }),
|
|
8265
|
+
})() }) : null,
|
|
8201
8266
|
/* @__PURE__ */ jsx("span", { className: "relative z-10", children: label }),
|
|
8202
8267
|
hotkey && /* @__PURE__ */ jsx(
|
|
8203
8268
|
"span",
|
|
@@ -8213,7 +8278,7 @@ function ActionButton({
|
|
|
8213
8278
|
}
|
|
8214
8279
|
);
|
|
8215
8280
|
}
|
|
8216
|
-
var sizeMap13, variantStyles8;
|
|
8281
|
+
var sizeMap13, variantStyles8, DEFAULT_ASSET_URL11;
|
|
8217
8282
|
var init_ActionButton = __esm({
|
|
8218
8283
|
"components/game/atoms/ActionButton.tsx"() {
|
|
8219
8284
|
init_cn();
|
|
@@ -8228,6 +8293,7 @@ var init_ActionButton = __esm({
|
|
|
8228
8293
|
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary-hover border-border",
|
|
8229
8294
|
danger: "bg-error text-error-foreground hover:bg-error/90 border-error"
|
|
8230
8295
|
};
|
|
8296
|
+
DEFAULT_ASSET_URL11 = "https://almadar-kflow-assets.web.app/shared/effects/particles/slash_01.png";
|
|
8231
8297
|
ActionButton.displayName = "ActionButton";
|
|
8232
8298
|
}
|
|
8233
8299
|
});
|
|
@@ -9096,10 +9162,10 @@ var init_Container = __esm({
|
|
|
9096
9162
|
center = true,
|
|
9097
9163
|
className,
|
|
9098
9164
|
children,
|
|
9099
|
-
as:
|
|
9165
|
+
as: Component2 = "div"
|
|
9100
9166
|
}) => {
|
|
9101
9167
|
const resolvedSize = maxWidth ?? size ?? "lg";
|
|
9102
|
-
const Comp =
|
|
9168
|
+
const Comp = Component2;
|
|
9103
9169
|
return /* @__PURE__ */ jsx(
|
|
9104
9170
|
Comp,
|
|
9105
9171
|
{
|
|
@@ -25093,7 +25159,7 @@ var init_Flex = __esm({
|
|
|
25093
25159
|
basis,
|
|
25094
25160
|
className,
|
|
25095
25161
|
children,
|
|
25096
|
-
as:
|
|
25162
|
+
as: Component2 = "div"
|
|
25097
25163
|
}) => {
|
|
25098
25164
|
const flexStyle = {};
|
|
25099
25165
|
if (grow !== void 0 || shrink !== void 0 || basis !== void 0) {
|
|
@@ -25105,7 +25171,7 @@ var init_Flex = __esm({
|
|
|
25105
25171
|
flexStyle.flexBasis = typeof basis === "number" ? `${basis}px` : basis;
|
|
25106
25172
|
}
|
|
25107
25173
|
}
|
|
25108
|
-
const Comp =
|
|
25174
|
+
const Comp = Component2;
|
|
25109
25175
|
return /* @__PURE__ */ jsx(
|
|
25110
25176
|
Comp,
|
|
25111
25177
|
{
|
|
@@ -25225,11 +25291,11 @@ var init_Grid = __esm({
|
|
|
25225
25291
|
className,
|
|
25226
25292
|
style,
|
|
25227
25293
|
children,
|
|
25228
|
-
as:
|
|
25294
|
+
as: Component2 = "div"
|
|
25229
25295
|
}) => {
|
|
25230
25296
|
const mergedStyle = rows2 ? { gridTemplateRows: `repeat(${rows2}, minmax(0, 1fr))`, ...style } : style;
|
|
25231
25297
|
return React83__default.createElement(
|
|
25232
|
-
|
|
25298
|
+
Component2,
|
|
25233
25299
|
{
|
|
25234
25300
|
className: cn(
|
|
25235
25301
|
"grid",
|
|
@@ -27055,6 +27121,7 @@ var init_ProgressDots = __esm({
|
|
|
27055
27121
|
}
|
|
27056
27122
|
});
|
|
27057
27123
|
function StatBadge({
|
|
27124
|
+
assetUrl = DEFAULT_ASSET_URL12,
|
|
27058
27125
|
label,
|
|
27059
27126
|
value = 0,
|
|
27060
27127
|
max,
|
|
@@ -27078,7 +27145,17 @@ function StatBadge({
|
|
|
27078
27145
|
className
|
|
27079
27146
|
),
|
|
27080
27147
|
children: [
|
|
27081
|
-
|
|
27148
|
+
assetUrl ? /* @__PURE__ */ jsx(
|
|
27149
|
+
"img",
|
|
27150
|
+
{
|
|
27151
|
+
src: assetUrl,
|
|
27152
|
+
alt: "",
|
|
27153
|
+
width: 16,
|
|
27154
|
+
height: 16,
|
|
27155
|
+
style: { imageRendering: "pixelated", objectFit: "contain" },
|
|
27156
|
+
className: "flex-shrink-0"
|
|
27157
|
+
}
|
|
27158
|
+
) : icon ? /* @__PURE__ */ jsx("span", { className: "flex-shrink-0 text-lg", children: typeof icon === "string" ? /* @__PURE__ */ jsx(Icon, { name: icon, className: "w-4 h-4" }) : /* @__PURE__ */ jsx(Icon, { icon, className: "w-4 h-4" }) }) : null,
|
|
27082
27159
|
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground font-medium", children: label }),
|
|
27083
27160
|
format === "hearts" && max && /* @__PURE__ */ jsx(
|
|
27084
27161
|
HealthBar,
|
|
@@ -27111,7 +27188,7 @@ function StatBadge({
|
|
|
27111
27188
|
}
|
|
27112
27189
|
);
|
|
27113
27190
|
}
|
|
27114
|
-
var sizeMap17, variantMap2;
|
|
27191
|
+
var sizeMap17, variantMap2, DEFAULT_ASSET_URL12;
|
|
27115
27192
|
var init_StatBadge = __esm({
|
|
27116
27193
|
"components/game/molecules/StatBadge.tsx"() {
|
|
27117
27194
|
init_cn();
|
|
@@ -27130,6 +27207,7 @@ var init_StatBadge = __esm({
|
|
|
27130
27207
|
warning: "bg-warning/15 border-warning/40 text-foreground",
|
|
27131
27208
|
danger: "bg-error/15 border-error/40 text-foreground"
|
|
27132
27209
|
};
|
|
27210
|
+
DEFAULT_ASSET_URL12 = "https://almadar-kflow-assets.web.app/shared/effects/particles/light_01.png";
|
|
27133
27211
|
StatBadge.displayName = "StatBadge";
|
|
27134
27212
|
}
|
|
27135
27213
|
});
|
|
@@ -27786,6 +27864,7 @@ var init_TurnPanel = __esm({
|
|
|
27786
27864
|
}
|
|
27787
27865
|
});
|
|
27788
27866
|
function EnemyPlate({
|
|
27867
|
+
assetUrl = DEFAULT_ASSET_URL13,
|
|
27789
27868
|
name = "Shadow Guard",
|
|
27790
27869
|
health = 80,
|
|
27791
27870
|
maxHealth = 100,
|
|
@@ -27803,15 +27882,28 @@ function EnemyPlate({
|
|
|
27803
27882
|
),
|
|
27804
27883
|
children: [
|
|
27805
27884
|
/* @__PURE__ */ jsxs(Box, { className: "flex items-center justify-between gap-2", children: [
|
|
27806
|
-
/* @__PURE__ */
|
|
27807
|
-
|
|
27808
|
-
|
|
27809
|
-
|
|
27810
|
-
|
|
27811
|
-
|
|
27812
|
-
|
|
27813
|
-
|
|
27814
|
-
|
|
27885
|
+
/* @__PURE__ */ jsxs(Box, { className: "flex items-center gap-1.5 min-w-0", children: [
|
|
27886
|
+
assetUrl && /* @__PURE__ */ jsx(
|
|
27887
|
+
"img",
|
|
27888
|
+
{
|
|
27889
|
+
src: assetUrl,
|
|
27890
|
+
alt: name,
|
|
27891
|
+
width: 24,
|
|
27892
|
+
height: 24,
|
|
27893
|
+
style: { objectFit: "cover", borderRadius: "50%" },
|
|
27894
|
+
className: "flex-shrink-0"
|
|
27895
|
+
}
|
|
27896
|
+
),
|
|
27897
|
+
/* @__PURE__ */ jsx(
|
|
27898
|
+
Typography,
|
|
27899
|
+
{
|
|
27900
|
+
variant: "caption",
|
|
27901
|
+
weight: "bold",
|
|
27902
|
+
className: "text-[var(--color-foreground)] truncate",
|
|
27903
|
+
children: name
|
|
27904
|
+
}
|
|
27905
|
+
)
|
|
27906
|
+
] }),
|
|
27815
27907
|
level != null && /* @__PURE__ */ jsxs(Badge, { variant: "neutral", size: "sm", children: [
|
|
27816
27908
|
"Lv.",
|
|
27817
27909
|
level
|
|
@@ -27856,7 +27948,7 @@ function EnemyPlate({
|
|
|
27856
27948
|
}
|
|
27857
27949
|
);
|
|
27858
27950
|
}
|
|
27859
|
-
var effectVariantMap2, DEFAULT_ENEMY_EFFECTS;
|
|
27951
|
+
var effectVariantMap2, DEFAULT_ENEMY_EFFECTS, DEFAULT_ASSET_URL13;
|
|
27860
27952
|
var init_EnemyPlate = __esm({
|
|
27861
27953
|
"components/game/molecules/EnemyPlate.tsx"() {
|
|
27862
27954
|
"use client";
|
|
@@ -27873,6 +27965,7 @@ var init_EnemyPlate = __esm({
|
|
|
27873
27965
|
DEFAULT_ENEMY_EFFECTS = [
|
|
27874
27966
|
{ icon: "flame", label: "Burn", variant: "debuff" }
|
|
27875
27967
|
];
|
|
27968
|
+
DEFAULT_ASSET_URL13 = "https://almadar-kflow-assets.web.app/shared/portraits/shadow-legion.png";
|
|
27876
27969
|
EnemyPlate.displayName = "EnemyPlate";
|
|
27877
27970
|
}
|
|
27878
27971
|
});
|
|
@@ -29404,13 +29497,13 @@ var init_MapView = __esm({
|
|
|
29404
29497
|
shadowSize: [41, 41]
|
|
29405
29498
|
});
|
|
29406
29499
|
L.Marker.prototype.options.icon = defaultIcon;
|
|
29407
|
-
const { useEffect:
|
|
29500
|
+
const { useEffect: useEffect79, useRef: useRef74, useCallback: useCallback118, useState: useState109 } = React83__default;
|
|
29408
29501
|
const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
|
|
29409
|
-
const { useEventBus:
|
|
29502
|
+
const { useEventBus: useEventBus3 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
|
|
29410
29503
|
function MapUpdater({ centerLat, centerLng, zoom }) {
|
|
29411
29504
|
const map = useMap();
|
|
29412
|
-
const prevRef =
|
|
29413
|
-
|
|
29505
|
+
const prevRef = useRef74({ centerLat, centerLng, zoom });
|
|
29506
|
+
useEffect79(() => {
|
|
29414
29507
|
const prev = prevRef.current;
|
|
29415
29508
|
if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
|
|
29416
29509
|
map.setView([centerLat, centerLng], zoom);
|
|
@@ -29421,7 +29514,7 @@ var init_MapView = __esm({
|
|
|
29421
29514
|
}
|
|
29422
29515
|
function MapClickHandler({ onMapClick }) {
|
|
29423
29516
|
const map = useMap();
|
|
29424
|
-
|
|
29517
|
+
useEffect79(() => {
|
|
29425
29518
|
if (!onMapClick) return;
|
|
29426
29519
|
const handler = (e) => {
|
|
29427
29520
|
onMapClick(e.latlng.lat, e.latlng.lng);
|
|
@@ -29448,9 +29541,9 @@ var init_MapView = __esm({
|
|
|
29448
29541
|
className,
|
|
29449
29542
|
showAttribution = true
|
|
29450
29543
|
}) {
|
|
29451
|
-
const eventBus =
|
|
29452
|
-
const [clickedPosition, setClickedPosition] =
|
|
29453
|
-
const handleMapClick =
|
|
29544
|
+
const eventBus = useEventBus3();
|
|
29545
|
+
const [clickedPosition, setClickedPosition] = useState109(null);
|
|
29546
|
+
const handleMapClick = useCallback118((lat, lng) => {
|
|
29454
29547
|
if (showClickedPin) {
|
|
29455
29548
|
setClickedPosition({ lat, lng });
|
|
29456
29549
|
}
|
|
@@ -29459,7 +29552,7 @@ var init_MapView = __esm({
|
|
|
29459
29552
|
eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
|
|
29460
29553
|
}
|
|
29461
29554
|
}, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
|
|
29462
|
-
const handleMarkerClick =
|
|
29555
|
+
const handleMarkerClick = useCallback118((marker) => {
|
|
29463
29556
|
onMarkerClick?.(marker);
|
|
29464
29557
|
if (markerClickEvent) {
|
|
29465
29558
|
eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
|
|
@@ -36586,10 +36679,10 @@ var init_Section = __esm({
|
|
|
36586
36679
|
children,
|
|
36587
36680
|
headerClassName,
|
|
36588
36681
|
contentClassName,
|
|
36589
|
-
as:
|
|
36682
|
+
as: Component2 = "section"
|
|
36590
36683
|
}) => {
|
|
36591
36684
|
const hasHeader = title || description || action;
|
|
36592
|
-
const Comp =
|
|
36685
|
+
const Comp = Component2;
|
|
36593
36686
|
return /* @__PURE__ */ jsxs(
|
|
36594
36687
|
Comp,
|
|
36595
36688
|
{
|
|
@@ -41154,6 +41247,1568 @@ var init_GameAudioToggle = __esm({
|
|
|
41154
41247
|
GameAudioToggle.displayName = "GameAudioToggle";
|
|
41155
41248
|
}
|
|
41156
41249
|
});
|
|
41250
|
+
function detectAssetRoot(modelUrl) {
|
|
41251
|
+
const idx = modelUrl.indexOf("/3d/");
|
|
41252
|
+
if (idx !== -1) {
|
|
41253
|
+
return modelUrl.substring(0, idx + 4);
|
|
41254
|
+
}
|
|
41255
|
+
return modelUrl.substring(0, modelUrl.lastIndexOf("/") + 1);
|
|
41256
|
+
}
|
|
41257
|
+
function createGLTFLoaderForUrl(url) {
|
|
41258
|
+
const loader = new GLTFLoader();
|
|
41259
|
+
loader.setResourcePath(detectAssetRoot(url));
|
|
41260
|
+
return loader;
|
|
41261
|
+
}
|
|
41262
|
+
var AssetLoader;
|
|
41263
|
+
var init_AssetLoader = __esm({
|
|
41264
|
+
"components/game/molecules/three/loaders/AssetLoader.ts"() {
|
|
41265
|
+
AssetLoader = class {
|
|
41266
|
+
constructor() {
|
|
41267
|
+
__publicField(this, "objLoader");
|
|
41268
|
+
__publicField(this, "textureLoader");
|
|
41269
|
+
__publicField(this, "modelCache");
|
|
41270
|
+
__publicField(this, "textureCache");
|
|
41271
|
+
__publicField(this, "loadingPromises");
|
|
41272
|
+
this.objLoader = new OBJLoader();
|
|
41273
|
+
this.textureLoader = new THREE.TextureLoader();
|
|
41274
|
+
this.modelCache = /* @__PURE__ */ new Map();
|
|
41275
|
+
this.textureCache = /* @__PURE__ */ new Map();
|
|
41276
|
+
this.loadingPromises = /* @__PURE__ */ new Map();
|
|
41277
|
+
}
|
|
41278
|
+
/**
|
|
41279
|
+
* Load a GLB/GLTF model
|
|
41280
|
+
* @param url - URL to the .glb or .gltf file
|
|
41281
|
+
* @returns Promise with loaded model scene and animations
|
|
41282
|
+
*/
|
|
41283
|
+
async loadModel(url) {
|
|
41284
|
+
if (this.modelCache.has(url)) {
|
|
41285
|
+
return this.modelCache.get(url);
|
|
41286
|
+
}
|
|
41287
|
+
if (this.loadingPromises.has(url)) {
|
|
41288
|
+
return this.loadingPromises.get(url);
|
|
41289
|
+
}
|
|
41290
|
+
const loader = createGLTFLoaderForUrl(url);
|
|
41291
|
+
const loadPromise = loader.loadAsync(url).then((gltf) => {
|
|
41292
|
+
const result = {
|
|
41293
|
+
scene: gltf.scene,
|
|
41294
|
+
animations: gltf.animations || []
|
|
41295
|
+
};
|
|
41296
|
+
this.modelCache.set(url, result);
|
|
41297
|
+
this.loadingPromises.delete(url);
|
|
41298
|
+
return result;
|
|
41299
|
+
}).catch((error) => {
|
|
41300
|
+
this.loadingPromises.delete(url);
|
|
41301
|
+
throw new Error(`Failed to load model ${url}: ${error.message}`);
|
|
41302
|
+
});
|
|
41303
|
+
this.loadingPromises.set(url, loadPromise);
|
|
41304
|
+
return loadPromise;
|
|
41305
|
+
}
|
|
41306
|
+
/**
|
|
41307
|
+
* Load an OBJ model (fallback for non-GLB assets)
|
|
41308
|
+
* @param url - URL to the .obj file
|
|
41309
|
+
* @returns Promise with loaded object group
|
|
41310
|
+
*/
|
|
41311
|
+
async loadOBJ(url) {
|
|
41312
|
+
if (this.modelCache.has(url)) {
|
|
41313
|
+
return this.modelCache.get(url).scene;
|
|
41314
|
+
}
|
|
41315
|
+
if (this.loadingPromises.has(url)) {
|
|
41316
|
+
const result = await this.loadingPromises.get(url);
|
|
41317
|
+
return result.scene;
|
|
41318
|
+
}
|
|
41319
|
+
const loadPromise = this.objLoader.loadAsync(url).then((group) => {
|
|
41320
|
+
const result = {
|
|
41321
|
+
scene: group,
|
|
41322
|
+
animations: []
|
|
41323
|
+
};
|
|
41324
|
+
this.modelCache.set(url, result);
|
|
41325
|
+
this.loadingPromises.delete(url);
|
|
41326
|
+
return result;
|
|
41327
|
+
}).catch((error) => {
|
|
41328
|
+
this.loadingPromises.delete(url);
|
|
41329
|
+
throw new Error(`Failed to load OBJ ${url}: ${error.message}`);
|
|
41330
|
+
});
|
|
41331
|
+
this.loadingPromises.set(url, loadPromise);
|
|
41332
|
+
return (await loadPromise).scene;
|
|
41333
|
+
}
|
|
41334
|
+
/**
|
|
41335
|
+
* Load a texture
|
|
41336
|
+
* @param url - URL to the texture image
|
|
41337
|
+
* @returns Promise with loaded texture
|
|
41338
|
+
*/
|
|
41339
|
+
async loadTexture(url) {
|
|
41340
|
+
if (this.textureCache.has(url)) {
|
|
41341
|
+
return this.textureCache.get(url);
|
|
41342
|
+
}
|
|
41343
|
+
if (this.loadingPromises.has(`texture:${url}`)) {
|
|
41344
|
+
return this.loadingPromises.get(`texture:${url}`);
|
|
41345
|
+
}
|
|
41346
|
+
const loadPromise = this.textureLoader.loadAsync(url).then((texture) => {
|
|
41347
|
+
texture.colorSpace = THREE.SRGBColorSpace;
|
|
41348
|
+
this.textureCache.set(url, texture);
|
|
41349
|
+
this.loadingPromises.delete(`texture:${url}`);
|
|
41350
|
+
return texture;
|
|
41351
|
+
}).catch((error) => {
|
|
41352
|
+
this.loadingPromises.delete(`texture:${url}`);
|
|
41353
|
+
throw new Error(`Failed to load texture ${url}: ${error.message}`);
|
|
41354
|
+
});
|
|
41355
|
+
this.loadingPromises.set(`texture:${url}`, loadPromise);
|
|
41356
|
+
return loadPromise;
|
|
41357
|
+
}
|
|
41358
|
+
/**
|
|
41359
|
+
* Preload multiple assets
|
|
41360
|
+
* @param urls - Array of asset URLs to preload
|
|
41361
|
+
* @returns Promise that resolves when all assets are loaded
|
|
41362
|
+
*/
|
|
41363
|
+
async preload(urls) {
|
|
41364
|
+
const promises = urls.map((url) => {
|
|
41365
|
+
if (url.endsWith(".glb") || url.endsWith(".gltf")) {
|
|
41366
|
+
return this.loadModel(url).catch(() => null);
|
|
41367
|
+
} else if (url.endsWith(".obj")) {
|
|
41368
|
+
return this.loadOBJ(url).catch(() => null);
|
|
41369
|
+
} else if (/\.(png|jpg|jpeg|webp)$/i.test(url)) {
|
|
41370
|
+
return this.loadTexture(url).catch(() => null);
|
|
41371
|
+
}
|
|
41372
|
+
return Promise.resolve(null);
|
|
41373
|
+
});
|
|
41374
|
+
await Promise.all(promises);
|
|
41375
|
+
}
|
|
41376
|
+
/**
|
|
41377
|
+
* Check if a model is cached
|
|
41378
|
+
* @param url - Model URL
|
|
41379
|
+
*/
|
|
41380
|
+
hasModel(url) {
|
|
41381
|
+
return this.modelCache.has(url);
|
|
41382
|
+
}
|
|
41383
|
+
/**
|
|
41384
|
+
* Check if a texture is cached
|
|
41385
|
+
* @param url - Texture URL
|
|
41386
|
+
*/
|
|
41387
|
+
hasTexture(url) {
|
|
41388
|
+
return this.textureCache.has(url);
|
|
41389
|
+
}
|
|
41390
|
+
/**
|
|
41391
|
+
* Get cached model (throws if not cached)
|
|
41392
|
+
* @param url - Model URL
|
|
41393
|
+
*/
|
|
41394
|
+
getModel(url) {
|
|
41395
|
+
const model = this.modelCache.get(url);
|
|
41396
|
+
if (!model) {
|
|
41397
|
+
throw new Error(`Model ${url} not in cache`);
|
|
41398
|
+
}
|
|
41399
|
+
return model;
|
|
41400
|
+
}
|
|
41401
|
+
/**
|
|
41402
|
+
* Get cached texture (throws if not cached)
|
|
41403
|
+
* @param url - Texture URL
|
|
41404
|
+
*/
|
|
41405
|
+
getTexture(url) {
|
|
41406
|
+
const texture = this.textureCache.get(url);
|
|
41407
|
+
if (!texture) {
|
|
41408
|
+
throw new Error(`Texture ${url} not in cache`);
|
|
41409
|
+
}
|
|
41410
|
+
return texture;
|
|
41411
|
+
}
|
|
41412
|
+
/**
|
|
41413
|
+
* Clear all caches
|
|
41414
|
+
*/
|
|
41415
|
+
clearCache() {
|
|
41416
|
+
this.textureCache.forEach((texture) => {
|
|
41417
|
+
texture.dispose();
|
|
41418
|
+
});
|
|
41419
|
+
this.modelCache.forEach((model) => {
|
|
41420
|
+
model.scene.traverse((child) => {
|
|
41421
|
+
if (child instanceof THREE.Mesh) {
|
|
41422
|
+
child.geometry.dispose();
|
|
41423
|
+
if (Array.isArray(child.material)) {
|
|
41424
|
+
child.material.forEach((m) => m.dispose());
|
|
41425
|
+
} else {
|
|
41426
|
+
child.material.dispose();
|
|
41427
|
+
}
|
|
41428
|
+
}
|
|
41429
|
+
});
|
|
41430
|
+
});
|
|
41431
|
+
this.modelCache.clear();
|
|
41432
|
+
this.textureCache.clear();
|
|
41433
|
+
this.loadingPromises.clear();
|
|
41434
|
+
}
|
|
41435
|
+
/**
|
|
41436
|
+
* Get cache statistics
|
|
41437
|
+
*/
|
|
41438
|
+
getStats() {
|
|
41439
|
+
return {
|
|
41440
|
+
models: this.modelCache.size,
|
|
41441
|
+
textures: this.textureCache.size,
|
|
41442
|
+
loading: this.loadingPromises.size
|
|
41443
|
+
};
|
|
41444
|
+
}
|
|
41445
|
+
};
|
|
41446
|
+
new AssetLoader();
|
|
41447
|
+
}
|
|
41448
|
+
});
|
|
41449
|
+
function useAssetLoader(options = {}) {
|
|
41450
|
+
const { preloadUrls = [], loader: customLoader } = options;
|
|
41451
|
+
const loaderRef = useRef(customLoader || new AssetLoader());
|
|
41452
|
+
const [state, setState] = useState({
|
|
41453
|
+
isLoading: false,
|
|
41454
|
+
progress: 0,
|
|
41455
|
+
loaded: 0,
|
|
41456
|
+
total: 0,
|
|
41457
|
+
errors: []
|
|
41458
|
+
});
|
|
41459
|
+
useEffect(() => {
|
|
41460
|
+
if (preloadUrls.length > 0) {
|
|
41461
|
+
preload(preloadUrls);
|
|
41462
|
+
}
|
|
41463
|
+
}, []);
|
|
41464
|
+
const updateProgress = useCallback((loaded, total) => {
|
|
41465
|
+
setState((prev) => ({
|
|
41466
|
+
...prev,
|
|
41467
|
+
loaded,
|
|
41468
|
+
total,
|
|
41469
|
+
progress: total > 0 ? Math.round(loaded / total * 100) : 0
|
|
41470
|
+
}));
|
|
41471
|
+
}, []);
|
|
41472
|
+
const loadModel = useCallback(
|
|
41473
|
+
async (url) => {
|
|
41474
|
+
setState((prev) => ({ ...prev, isLoading: true }));
|
|
41475
|
+
try {
|
|
41476
|
+
const model = await loaderRef.current.loadModel(url);
|
|
41477
|
+
setState((prev) => ({
|
|
41478
|
+
...prev,
|
|
41479
|
+
isLoading: false,
|
|
41480
|
+
loaded: prev.loaded + 1
|
|
41481
|
+
}));
|
|
41482
|
+
return model;
|
|
41483
|
+
} catch (error) {
|
|
41484
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
41485
|
+
setState((prev) => ({
|
|
41486
|
+
...prev,
|
|
41487
|
+
isLoading: false,
|
|
41488
|
+
errors: [...prev.errors, errorMsg]
|
|
41489
|
+
}));
|
|
41490
|
+
throw error;
|
|
41491
|
+
}
|
|
41492
|
+
},
|
|
41493
|
+
[]
|
|
41494
|
+
);
|
|
41495
|
+
const loadOBJ = useCallback(
|
|
41496
|
+
async (url) => {
|
|
41497
|
+
setState((prev) => ({ ...prev, isLoading: true }));
|
|
41498
|
+
try {
|
|
41499
|
+
const model = await loaderRef.current.loadOBJ(url);
|
|
41500
|
+
setState((prev) => ({
|
|
41501
|
+
...prev,
|
|
41502
|
+
isLoading: false,
|
|
41503
|
+
loaded: prev.loaded + 1
|
|
41504
|
+
}));
|
|
41505
|
+
return model;
|
|
41506
|
+
} catch (error) {
|
|
41507
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
41508
|
+
setState((prev) => ({
|
|
41509
|
+
...prev,
|
|
41510
|
+
isLoading: false,
|
|
41511
|
+
errors: [...prev.errors, errorMsg]
|
|
41512
|
+
}));
|
|
41513
|
+
throw error;
|
|
41514
|
+
}
|
|
41515
|
+
},
|
|
41516
|
+
[]
|
|
41517
|
+
);
|
|
41518
|
+
const loadTexture = useCallback(
|
|
41519
|
+
async (url) => {
|
|
41520
|
+
setState((prev) => ({ ...prev, isLoading: true }));
|
|
41521
|
+
try {
|
|
41522
|
+
const texture = await loaderRef.current.loadTexture(url);
|
|
41523
|
+
setState((prev) => ({
|
|
41524
|
+
...prev,
|
|
41525
|
+
isLoading: false,
|
|
41526
|
+
loaded: prev.loaded + 1
|
|
41527
|
+
}));
|
|
41528
|
+
return texture;
|
|
41529
|
+
} catch (error) {
|
|
41530
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
41531
|
+
setState((prev) => ({
|
|
41532
|
+
...prev,
|
|
41533
|
+
isLoading: false,
|
|
41534
|
+
errors: [...prev.errors, errorMsg]
|
|
41535
|
+
}));
|
|
41536
|
+
throw error;
|
|
41537
|
+
}
|
|
41538
|
+
},
|
|
41539
|
+
[]
|
|
41540
|
+
);
|
|
41541
|
+
const preload = useCallback(
|
|
41542
|
+
async (urls) => {
|
|
41543
|
+
setState((prev) => ({
|
|
41544
|
+
...prev,
|
|
41545
|
+
isLoading: true,
|
|
41546
|
+
total: urls.length,
|
|
41547
|
+
loaded: 0,
|
|
41548
|
+
errors: []
|
|
41549
|
+
}));
|
|
41550
|
+
let completed = 0;
|
|
41551
|
+
const errors = [];
|
|
41552
|
+
await Promise.all(
|
|
41553
|
+
urls.map(async (url) => {
|
|
41554
|
+
try {
|
|
41555
|
+
if (url.endsWith(".glb") || url.endsWith(".gltf")) {
|
|
41556
|
+
await loaderRef.current.loadModel(url);
|
|
41557
|
+
} else if (url.endsWith(".obj")) {
|
|
41558
|
+
await loaderRef.current.loadOBJ(url);
|
|
41559
|
+
} else if (/\.(png|jpg|jpeg|webp)$/i.test(url)) {
|
|
41560
|
+
await loaderRef.current.loadTexture(url);
|
|
41561
|
+
}
|
|
41562
|
+
completed++;
|
|
41563
|
+
updateProgress(completed, urls.length);
|
|
41564
|
+
} catch (error) {
|
|
41565
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
41566
|
+
errors.push(`${url}: ${errorMsg}`);
|
|
41567
|
+
completed++;
|
|
41568
|
+
updateProgress(completed, urls.length);
|
|
41569
|
+
}
|
|
41570
|
+
})
|
|
41571
|
+
);
|
|
41572
|
+
setState((prev) => ({
|
|
41573
|
+
...prev,
|
|
41574
|
+
isLoading: false,
|
|
41575
|
+
errors
|
|
41576
|
+
}));
|
|
41577
|
+
},
|
|
41578
|
+
[updateProgress]
|
|
41579
|
+
);
|
|
41580
|
+
const hasModel = useCallback((url) => {
|
|
41581
|
+
return loaderRef.current.hasModel(url);
|
|
41582
|
+
}, []);
|
|
41583
|
+
const hasTexture = useCallback((url) => {
|
|
41584
|
+
return loaderRef.current.hasTexture(url);
|
|
41585
|
+
}, []);
|
|
41586
|
+
const getModel = useCallback((url) => {
|
|
41587
|
+
try {
|
|
41588
|
+
return loaderRef.current.getModel(url);
|
|
41589
|
+
} catch {
|
|
41590
|
+
return void 0;
|
|
41591
|
+
}
|
|
41592
|
+
}, []);
|
|
41593
|
+
const getTexture = useCallback((url) => {
|
|
41594
|
+
try {
|
|
41595
|
+
return loaderRef.current.getTexture(url);
|
|
41596
|
+
} catch {
|
|
41597
|
+
return void 0;
|
|
41598
|
+
}
|
|
41599
|
+
}, []);
|
|
41600
|
+
const clearCache = useCallback(() => {
|
|
41601
|
+
loaderRef.current.clearCache();
|
|
41602
|
+
setState({
|
|
41603
|
+
isLoading: false,
|
|
41604
|
+
progress: 0,
|
|
41605
|
+
loaded: 0,
|
|
41606
|
+
total: 0,
|
|
41607
|
+
errors: []
|
|
41608
|
+
});
|
|
41609
|
+
}, []);
|
|
41610
|
+
return {
|
|
41611
|
+
...state,
|
|
41612
|
+
loadModel,
|
|
41613
|
+
loadOBJ,
|
|
41614
|
+
loadTexture,
|
|
41615
|
+
preload,
|
|
41616
|
+
hasModel,
|
|
41617
|
+
hasTexture,
|
|
41618
|
+
getModel,
|
|
41619
|
+
getTexture,
|
|
41620
|
+
clearCache
|
|
41621
|
+
};
|
|
41622
|
+
}
|
|
41623
|
+
var init_useAssetLoader = __esm({
|
|
41624
|
+
"components/game/molecules/three/hooks/useAssetLoader.ts"() {
|
|
41625
|
+
"use client";
|
|
41626
|
+
init_AssetLoader();
|
|
41627
|
+
}
|
|
41628
|
+
});
|
|
41629
|
+
function useGameCanvas3DEvents(options) {
|
|
41630
|
+
const {
|
|
41631
|
+
tileClickEvent,
|
|
41632
|
+
unitClickEvent,
|
|
41633
|
+
featureClickEvent,
|
|
41634
|
+
canvasClickEvent,
|
|
41635
|
+
tileHoverEvent,
|
|
41636
|
+
tileLeaveEvent,
|
|
41637
|
+
unitAnimationEvent,
|
|
41638
|
+
cameraChangeEvent,
|
|
41639
|
+
onTileClick,
|
|
41640
|
+
onUnitClick,
|
|
41641
|
+
onFeatureClick,
|
|
41642
|
+
onCanvasClick,
|
|
41643
|
+
onTileHover,
|
|
41644
|
+
onUnitAnimation
|
|
41645
|
+
} = options;
|
|
41646
|
+
const emit = useEmitEvent();
|
|
41647
|
+
const optionsRef = useRef(options);
|
|
41648
|
+
optionsRef.current = options;
|
|
41649
|
+
const handleTileClick = useCallback(
|
|
41650
|
+
(tile, event) => {
|
|
41651
|
+
if (tileClickEvent) {
|
|
41652
|
+
emit(tileClickEvent, {
|
|
41653
|
+
tileId: tile.id,
|
|
41654
|
+
x: tile.x,
|
|
41655
|
+
z: tile.z ?? tile.y ?? 0,
|
|
41656
|
+
type: tile.type,
|
|
41657
|
+
terrain: tile.terrain,
|
|
41658
|
+
elevation: tile.elevation
|
|
41659
|
+
});
|
|
41660
|
+
}
|
|
41661
|
+
optionsRef.current.onTileClick?.(tile, event);
|
|
41662
|
+
},
|
|
41663
|
+
[tileClickEvent, emit]
|
|
41664
|
+
);
|
|
41665
|
+
const handleUnitClick = useCallback(
|
|
41666
|
+
(unit, event) => {
|
|
41667
|
+
if (unitClickEvent) {
|
|
41668
|
+
emit(unitClickEvent, {
|
|
41669
|
+
unitId: unit.id,
|
|
41670
|
+
x: unit.x,
|
|
41671
|
+
z: unit.z ?? unit.y ?? 0,
|
|
41672
|
+
unitType: unit.unitType,
|
|
41673
|
+
name: unit.name,
|
|
41674
|
+
team: unit.team,
|
|
41675
|
+
faction: unit.faction,
|
|
41676
|
+
health: unit.health,
|
|
41677
|
+
maxHealth: unit.maxHealth
|
|
41678
|
+
});
|
|
41679
|
+
}
|
|
41680
|
+
optionsRef.current.onUnitClick?.(unit, event);
|
|
41681
|
+
},
|
|
41682
|
+
[unitClickEvent, emit]
|
|
41683
|
+
);
|
|
41684
|
+
const handleFeatureClick = useCallback(
|
|
41685
|
+
(feature, event) => {
|
|
41686
|
+
if (featureClickEvent) {
|
|
41687
|
+
emit(featureClickEvent, {
|
|
41688
|
+
featureId: feature.id,
|
|
41689
|
+
x: feature.x,
|
|
41690
|
+
z: feature.z ?? feature.y ?? 0,
|
|
41691
|
+
type: feature.type,
|
|
41692
|
+
elevation: feature.elevation
|
|
41693
|
+
});
|
|
41694
|
+
}
|
|
41695
|
+
optionsRef.current.onFeatureClick?.(feature, event);
|
|
41696
|
+
},
|
|
41697
|
+
[featureClickEvent, emit]
|
|
41698
|
+
);
|
|
41699
|
+
const handleCanvasClick = useCallback(
|
|
41700
|
+
(event) => {
|
|
41701
|
+
if (canvasClickEvent) {
|
|
41702
|
+
emit(canvasClickEvent, {
|
|
41703
|
+
clientX: event.clientX,
|
|
41704
|
+
clientY: event.clientY,
|
|
41705
|
+
button: event.button
|
|
41706
|
+
});
|
|
41707
|
+
}
|
|
41708
|
+
optionsRef.current.onCanvasClick?.(event);
|
|
41709
|
+
},
|
|
41710
|
+
[canvasClickEvent, emit]
|
|
41711
|
+
);
|
|
41712
|
+
const handleTileHover = useCallback(
|
|
41713
|
+
(tile, event) => {
|
|
41714
|
+
if (tile) {
|
|
41715
|
+
if (tileHoverEvent) {
|
|
41716
|
+
emit(tileHoverEvent, {
|
|
41717
|
+
tileId: tile.id,
|
|
41718
|
+
x: tile.x,
|
|
41719
|
+
z: tile.z ?? tile.y ?? 0,
|
|
41720
|
+
type: tile.type
|
|
41721
|
+
});
|
|
41722
|
+
}
|
|
41723
|
+
} else {
|
|
41724
|
+
if (tileLeaveEvent) {
|
|
41725
|
+
emit(tileLeaveEvent, {});
|
|
41726
|
+
}
|
|
41727
|
+
}
|
|
41728
|
+
optionsRef.current.onTileHover?.(tile, event);
|
|
41729
|
+
},
|
|
41730
|
+
[tileHoverEvent, tileLeaveEvent, emit]
|
|
41731
|
+
);
|
|
41732
|
+
const handleUnitAnimation = useCallback(
|
|
41733
|
+
(unitId, state) => {
|
|
41734
|
+
if (unitAnimationEvent) {
|
|
41735
|
+
emit(unitAnimationEvent, {
|
|
41736
|
+
unitId,
|
|
41737
|
+
state,
|
|
41738
|
+
timestamp: Date.now()
|
|
41739
|
+
});
|
|
41740
|
+
}
|
|
41741
|
+
optionsRef.current.onUnitAnimation?.(unitId, state);
|
|
41742
|
+
},
|
|
41743
|
+
[unitAnimationEvent, emit]
|
|
41744
|
+
);
|
|
41745
|
+
const handleCameraChange = useCallback(
|
|
41746
|
+
(position) => {
|
|
41747
|
+
if (cameraChangeEvent) {
|
|
41748
|
+
emit(cameraChangeEvent, {
|
|
41749
|
+
position,
|
|
41750
|
+
timestamp: Date.now()
|
|
41751
|
+
});
|
|
41752
|
+
}
|
|
41753
|
+
},
|
|
41754
|
+
[cameraChangeEvent, emit]
|
|
41755
|
+
);
|
|
41756
|
+
return {
|
|
41757
|
+
handleTileClick,
|
|
41758
|
+
handleUnitClick,
|
|
41759
|
+
handleFeatureClick,
|
|
41760
|
+
handleCanvasClick,
|
|
41761
|
+
handleTileHover,
|
|
41762
|
+
handleUnitAnimation,
|
|
41763
|
+
handleCameraChange
|
|
41764
|
+
};
|
|
41765
|
+
}
|
|
41766
|
+
var init_useGameCanvas3DEvents = __esm({
|
|
41767
|
+
"components/game/molecules/three/hooks/useGameCanvas3DEvents.ts"() {
|
|
41768
|
+
"use client";
|
|
41769
|
+
init_useEventBus();
|
|
41770
|
+
}
|
|
41771
|
+
});
|
|
41772
|
+
|
|
41773
|
+
// components/game/molecules/three/components/Canvas3DLoadingState.css
|
|
41774
|
+
var init_Canvas3DLoadingState = __esm({
|
|
41775
|
+
"components/game/molecules/three/components/Canvas3DLoadingState.css"() {
|
|
41776
|
+
}
|
|
41777
|
+
});
|
|
41778
|
+
function Canvas3DLoadingState({
|
|
41779
|
+
progress = 0,
|
|
41780
|
+
loaded = 0,
|
|
41781
|
+
total = 0,
|
|
41782
|
+
message = "Loading 3D Scene...",
|
|
41783
|
+
details,
|
|
41784
|
+
showSpinner = true,
|
|
41785
|
+
className
|
|
41786
|
+
}) {
|
|
41787
|
+
const clampedProgress = Math.max(0, Math.min(100, progress));
|
|
41788
|
+
const hasProgress = total > 0;
|
|
41789
|
+
return /* @__PURE__ */ jsxs("div", { className: `canvas-3d-loading ${className || ""}`, children: [
|
|
41790
|
+
/* @__PURE__ */ jsxs("div", { className: "canvas-3d-loading__content", children: [
|
|
41791
|
+
showSpinner && /* @__PURE__ */ jsxs("div", { className: "canvas-3d-loading__spinner", children: [
|
|
41792
|
+
/* @__PURE__ */ jsx("div", { className: "spinner__ring" }),
|
|
41793
|
+
/* @__PURE__ */ jsx("div", { className: "spinner__ring spinner__ring--secondary" })
|
|
41794
|
+
] }),
|
|
41795
|
+
/* @__PURE__ */ jsx("div", { className: "canvas-3d-loading__message", children: message }),
|
|
41796
|
+
details && /* @__PURE__ */ jsx("div", { className: "canvas-3d-loading__details", children: details }),
|
|
41797
|
+
hasProgress && /* @__PURE__ */ jsxs("div", { className: "canvas-3d-loading__progress", children: [
|
|
41798
|
+
/* @__PURE__ */ jsx("div", { className: "progress__bar", children: /* @__PURE__ */ jsx(
|
|
41799
|
+
"div",
|
|
41800
|
+
{
|
|
41801
|
+
className: "progress__fill",
|
|
41802
|
+
style: { width: `${clampedProgress}%` }
|
|
41803
|
+
}
|
|
41804
|
+
) }),
|
|
41805
|
+
/* @__PURE__ */ jsxs("div", { className: "progress__text", children: [
|
|
41806
|
+
/* @__PURE__ */ jsxs("span", { className: "progress__percentage", children: [
|
|
41807
|
+
clampedProgress,
|
|
41808
|
+
"%"
|
|
41809
|
+
] }),
|
|
41810
|
+
/* @__PURE__ */ jsxs("span", { className: "progress__count", children: [
|
|
41811
|
+
"(",
|
|
41812
|
+
loaded,
|
|
41813
|
+
"/",
|
|
41814
|
+
total,
|
|
41815
|
+
")"
|
|
41816
|
+
] })
|
|
41817
|
+
] })
|
|
41818
|
+
] })
|
|
41819
|
+
] }),
|
|
41820
|
+
/* @__PURE__ */ jsx("div", { className: "canvas-3d-loading__background", children: /* @__PURE__ */ jsx("div", { className: "bg__grid" }) })
|
|
41821
|
+
] });
|
|
41822
|
+
}
|
|
41823
|
+
var init_Canvas3DLoadingState2 = __esm({
|
|
41824
|
+
"components/game/molecules/three/components/Canvas3DLoadingState.tsx"() {
|
|
41825
|
+
init_Canvas3DLoadingState();
|
|
41826
|
+
}
|
|
41827
|
+
});
|
|
41828
|
+
|
|
41829
|
+
// components/game/molecules/three/components/Canvas3DErrorBoundary.css
|
|
41830
|
+
var init_Canvas3DErrorBoundary = __esm({
|
|
41831
|
+
"components/game/molecules/three/components/Canvas3DErrorBoundary.css"() {
|
|
41832
|
+
}
|
|
41833
|
+
});
|
|
41834
|
+
var log11, Canvas3DErrorBoundary;
|
|
41835
|
+
var init_Canvas3DErrorBoundary2 = __esm({
|
|
41836
|
+
"components/game/molecules/three/components/Canvas3DErrorBoundary.tsx"() {
|
|
41837
|
+
init_Canvas3DErrorBoundary();
|
|
41838
|
+
log11 = createLogger("almadar:ui:game:canvas3d:error-boundary");
|
|
41839
|
+
Canvas3DErrorBoundary = class extends Component {
|
|
41840
|
+
constructor(props) {
|
|
41841
|
+
super(props);
|
|
41842
|
+
__publicField(this, "handleReset", () => {
|
|
41843
|
+
this.setState({
|
|
41844
|
+
hasError: false,
|
|
41845
|
+
error: null,
|
|
41846
|
+
errorInfo: null
|
|
41847
|
+
});
|
|
41848
|
+
this.props.onReset?.();
|
|
41849
|
+
});
|
|
41850
|
+
this.state = {
|
|
41851
|
+
hasError: false,
|
|
41852
|
+
error: null,
|
|
41853
|
+
errorInfo: null
|
|
41854
|
+
};
|
|
41855
|
+
}
|
|
41856
|
+
static getDerivedStateFromError(error) {
|
|
41857
|
+
return {
|
|
41858
|
+
hasError: true,
|
|
41859
|
+
error,
|
|
41860
|
+
errorInfo: null
|
|
41861
|
+
};
|
|
41862
|
+
}
|
|
41863
|
+
componentDidCatch(error, errorInfo) {
|
|
41864
|
+
this.setState({ errorInfo });
|
|
41865
|
+
this.props.onError?.(error, errorInfo);
|
|
41866
|
+
log11.error("Error caught", { error });
|
|
41867
|
+
log11.error("Component stack", { componentStack: errorInfo.componentStack ?? "<none>" });
|
|
41868
|
+
}
|
|
41869
|
+
render() {
|
|
41870
|
+
if (this.state.hasError) {
|
|
41871
|
+
if (this.props.fallback) {
|
|
41872
|
+
return this.props.fallback;
|
|
41873
|
+
}
|
|
41874
|
+
return /* @__PURE__ */ jsx("div", { className: "canvas-3d-error", children: /* @__PURE__ */ jsxs("div", { className: "canvas-3d-error__content", children: [
|
|
41875
|
+
/* @__PURE__ */ jsx("div", { className: "canvas-3d-error__icon", children: "\u26A0\uFE0F" }),
|
|
41876
|
+
/* @__PURE__ */ jsx("h2", { className: "canvas-3d-error__title", children: "3D Scene Error" }),
|
|
41877
|
+
/* @__PURE__ */ jsx("p", { className: "canvas-3d-error__message", children: "Something went wrong while rendering the 3D scene." }),
|
|
41878
|
+
this.state.error && /* @__PURE__ */ jsxs("details", { className: "canvas-3d-error__details", children: [
|
|
41879
|
+
/* @__PURE__ */ jsx("summary", { children: "Error Details" }),
|
|
41880
|
+
/* @__PURE__ */ jsxs("pre", { className: "error__stack", children: [
|
|
41881
|
+
this.state.error.message,
|
|
41882
|
+
"\n",
|
|
41883
|
+
this.state.error.stack
|
|
41884
|
+
] }),
|
|
41885
|
+
this.state.errorInfo && /* @__PURE__ */ jsx("pre", { className: "error__component-stack", children: this.state.errorInfo.componentStack })
|
|
41886
|
+
] }),
|
|
41887
|
+
/* @__PURE__ */ jsxs("div", { className: "canvas-3d-error__actions", children: [
|
|
41888
|
+
/* @__PURE__ */ jsx(
|
|
41889
|
+
"button",
|
|
41890
|
+
{
|
|
41891
|
+
className: "error__button error__button--primary",
|
|
41892
|
+
onClick: this.handleReset,
|
|
41893
|
+
children: "Try Again"
|
|
41894
|
+
}
|
|
41895
|
+
),
|
|
41896
|
+
/* @__PURE__ */ jsx(
|
|
41897
|
+
"button",
|
|
41898
|
+
{
|
|
41899
|
+
className: "error__button error__button--secondary",
|
|
41900
|
+
onClick: () => window.location.reload(),
|
|
41901
|
+
children: "Reload Page"
|
|
41902
|
+
}
|
|
41903
|
+
)
|
|
41904
|
+
] })
|
|
41905
|
+
] }) });
|
|
41906
|
+
}
|
|
41907
|
+
return this.props.children;
|
|
41908
|
+
}
|
|
41909
|
+
};
|
|
41910
|
+
}
|
|
41911
|
+
});
|
|
41912
|
+
function detectAssetRoot2(modelUrl) {
|
|
41913
|
+
const idx = modelUrl.indexOf("/3d/");
|
|
41914
|
+
if (idx !== -1) {
|
|
41915
|
+
return modelUrl.substring(0, idx + 4);
|
|
41916
|
+
}
|
|
41917
|
+
return modelUrl.substring(0, modelUrl.lastIndexOf("/") + 1);
|
|
41918
|
+
}
|
|
41919
|
+
function useGLTFModel(url, resourceBasePath) {
|
|
41920
|
+
const [state, setState] = useState({
|
|
41921
|
+
model: null,
|
|
41922
|
+
isLoading: false,
|
|
41923
|
+
error: null
|
|
41924
|
+
});
|
|
41925
|
+
useEffect(() => {
|
|
41926
|
+
if (!url) {
|
|
41927
|
+
setState({ model: null, isLoading: false, error: null });
|
|
41928
|
+
return;
|
|
41929
|
+
}
|
|
41930
|
+
log12.debug("Loading", { url });
|
|
41931
|
+
setState((prev) => ({ ...prev, isLoading: true, error: null }));
|
|
41932
|
+
const assetRoot = resourceBasePath || detectAssetRoot2(url);
|
|
41933
|
+
const loader = new GLTFLoader$1();
|
|
41934
|
+
loader.setResourcePath(assetRoot);
|
|
41935
|
+
loader.load(
|
|
41936
|
+
url,
|
|
41937
|
+
(gltf) => {
|
|
41938
|
+
log12.debug("Loaded", { url });
|
|
41939
|
+
setState({
|
|
41940
|
+
model: gltf.scene,
|
|
41941
|
+
isLoading: false,
|
|
41942
|
+
error: null
|
|
41943
|
+
});
|
|
41944
|
+
},
|
|
41945
|
+
void 0,
|
|
41946
|
+
(err) => {
|
|
41947
|
+
log12.warn("Failed", { url, error: err instanceof Error ? err : String(err) });
|
|
41948
|
+
setState({
|
|
41949
|
+
model: null,
|
|
41950
|
+
isLoading: false,
|
|
41951
|
+
error: err instanceof Error ? err : new Error(String(err))
|
|
41952
|
+
});
|
|
41953
|
+
}
|
|
41954
|
+
);
|
|
41955
|
+
}, [url, resourceBasePath]);
|
|
41956
|
+
return state;
|
|
41957
|
+
}
|
|
41958
|
+
function ModelLoader({
|
|
41959
|
+
url,
|
|
41960
|
+
position = [0, 0, 0],
|
|
41961
|
+
scale = 1,
|
|
41962
|
+
rotation = [0, 0, 0],
|
|
41963
|
+
isSelected = false,
|
|
41964
|
+
isHovered = false,
|
|
41965
|
+
onClick,
|
|
41966
|
+
onHover,
|
|
41967
|
+
fallbackGeometry = "box",
|
|
41968
|
+
castShadow = true,
|
|
41969
|
+
receiveShadow = true,
|
|
41970
|
+
resourceBasePath
|
|
41971
|
+
}) {
|
|
41972
|
+
const { model: loadedModel, isLoading, error } = useGLTFModel(url, resourceBasePath);
|
|
41973
|
+
const model = useMemo(() => {
|
|
41974
|
+
if (!loadedModel) return null;
|
|
41975
|
+
const cloned = loadedModel.clone();
|
|
41976
|
+
cloned.traverse((child) => {
|
|
41977
|
+
if (child instanceof THREE.Mesh) {
|
|
41978
|
+
child.castShadow = castShadow;
|
|
41979
|
+
child.receiveShadow = receiveShadow;
|
|
41980
|
+
}
|
|
41981
|
+
});
|
|
41982
|
+
return cloned;
|
|
41983
|
+
}, [loadedModel, castShadow, receiveShadow]);
|
|
41984
|
+
const scaleArray = useMemo(() => {
|
|
41985
|
+
if (typeof scale === "number") {
|
|
41986
|
+
return [scale, scale, scale];
|
|
41987
|
+
}
|
|
41988
|
+
return scale;
|
|
41989
|
+
}, [scale]);
|
|
41990
|
+
const rotationRad = useMemo(() => {
|
|
41991
|
+
return [
|
|
41992
|
+
rotation[0] * Math.PI / 180,
|
|
41993
|
+
rotation[1] * Math.PI / 180,
|
|
41994
|
+
rotation[2] * Math.PI / 180
|
|
41995
|
+
];
|
|
41996
|
+
}, [rotation]);
|
|
41997
|
+
if (isLoading) {
|
|
41998
|
+
return /* @__PURE__ */ jsx("group", { position, children: /* @__PURE__ */ jsxs("mesh", { rotation: [Math.PI / 2, 0, 0], children: [
|
|
41999
|
+
/* @__PURE__ */ jsx("ringGeometry", { args: [0.3, 0.35, 16] }),
|
|
42000
|
+
/* @__PURE__ */ jsx("meshBasicMaterial", { color: "#4a90d9", transparent: true, opacity: 0.8 })
|
|
42001
|
+
] }) });
|
|
42002
|
+
}
|
|
42003
|
+
if (error || !model) {
|
|
42004
|
+
if (fallbackGeometry === "none") {
|
|
42005
|
+
return /* @__PURE__ */ jsx("group", { position });
|
|
42006
|
+
}
|
|
42007
|
+
const fallbackProps = {
|
|
42008
|
+
onClick,
|
|
42009
|
+
onPointerOver: () => onHover?.(true),
|
|
42010
|
+
onPointerOut: () => onHover?.(false)
|
|
42011
|
+
};
|
|
42012
|
+
return /* @__PURE__ */ jsxs("group", { position, children: [
|
|
42013
|
+
(isSelected || isHovered) && /* @__PURE__ */ jsxs("mesh", { position: [0, 0.02, 0], rotation: [-Math.PI / 2, 0, 0], children: [
|
|
42014
|
+
/* @__PURE__ */ jsx("ringGeometry", { args: [0.6, 0.7, 32] }),
|
|
42015
|
+
/* @__PURE__ */ jsx(
|
|
42016
|
+
"meshBasicMaterial",
|
|
42017
|
+
{
|
|
42018
|
+
color: isSelected ? 16755200 : 16777215,
|
|
42019
|
+
transparent: true,
|
|
42020
|
+
opacity: 0.5
|
|
42021
|
+
}
|
|
42022
|
+
)
|
|
42023
|
+
] }),
|
|
42024
|
+
fallbackGeometry === "box" && /* @__PURE__ */ jsxs("mesh", { ...fallbackProps, position: [0, 0.5, 0], children: [
|
|
42025
|
+
/* @__PURE__ */ jsx("boxGeometry", { args: [0.8, 0.8, 0.8] }),
|
|
42026
|
+
/* @__PURE__ */ jsx("meshStandardMaterial", { color: error ? 16729156 : 8947848 })
|
|
42027
|
+
] }),
|
|
42028
|
+
fallbackGeometry === "sphere" && /* @__PURE__ */ jsxs("mesh", { ...fallbackProps, position: [0, 0.5, 0], children: [
|
|
42029
|
+
/* @__PURE__ */ jsx("sphereGeometry", { args: [0.4, 16, 16] }),
|
|
42030
|
+
/* @__PURE__ */ jsx("meshStandardMaterial", { color: error ? 16729156 : 8947848 })
|
|
42031
|
+
] }),
|
|
42032
|
+
fallbackGeometry === "cylinder" && /* @__PURE__ */ jsxs("mesh", { ...fallbackProps, position: [0, 0.5, 0], children: [
|
|
42033
|
+
/* @__PURE__ */ jsx("cylinderGeometry", { args: [0.3, 0.3, 0.8, 16] }),
|
|
42034
|
+
/* @__PURE__ */ jsx("meshStandardMaterial", { color: error ? 16729156 : 8947848 })
|
|
42035
|
+
] })
|
|
42036
|
+
] });
|
|
42037
|
+
}
|
|
42038
|
+
return /* @__PURE__ */ jsxs(
|
|
42039
|
+
"group",
|
|
42040
|
+
{
|
|
42041
|
+
position,
|
|
42042
|
+
rotation: rotationRad,
|
|
42043
|
+
onClick,
|
|
42044
|
+
onPointerOver: () => onHover?.(true),
|
|
42045
|
+
onPointerOut: () => onHover?.(false),
|
|
42046
|
+
children: [
|
|
42047
|
+
(isSelected || isHovered) && /* @__PURE__ */ jsxs("mesh", { position: [0, 0.02, 0], rotation: [-Math.PI / 2, 0, 0], children: [
|
|
42048
|
+
/* @__PURE__ */ jsx("ringGeometry", { args: [0.6, 0.7, 32] }),
|
|
42049
|
+
/* @__PURE__ */ jsx(
|
|
42050
|
+
"meshBasicMaterial",
|
|
42051
|
+
{
|
|
42052
|
+
color: isSelected ? 16755200 : 16777215,
|
|
42053
|
+
transparent: true,
|
|
42054
|
+
opacity: 0.5
|
|
42055
|
+
}
|
|
42056
|
+
)
|
|
42057
|
+
] }),
|
|
42058
|
+
/* @__PURE__ */ jsx("primitive", { object: model, scale: scaleArray })
|
|
42059
|
+
]
|
|
42060
|
+
}
|
|
42061
|
+
);
|
|
42062
|
+
}
|
|
42063
|
+
var log12;
|
|
42064
|
+
var init_ModelLoader = __esm({
|
|
42065
|
+
"components/game/molecules/three/components/ModelLoader.tsx"() {
|
|
42066
|
+
"use client";
|
|
42067
|
+
log12 = createLogger("almadar:ui:game:model-loader");
|
|
42068
|
+
}
|
|
42069
|
+
});
|
|
42070
|
+
|
|
42071
|
+
// components/game/molecules/GameCanvas3D.css
|
|
42072
|
+
var init_GameCanvas3D = __esm({
|
|
42073
|
+
"components/game/molecules/GameCanvas3D.css"() {
|
|
42074
|
+
}
|
|
42075
|
+
});
|
|
42076
|
+
function CameraController({
|
|
42077
|
+
onCameraChange
|
|
42078
|
+
}) {
|
|
42079
|
+
const { camera } = useThree();
|
|
42080
|
+
useEffect(() => {
|
|
42081
|
+
if (onCameraChange) {
|
|
42082
|
+
onCameraChange({
|
|
42083
|
+
x: camera.position.x,
|
|
42084
|
+
y: camera.position.y,
|
|
42085
|
+
z: camera.position.z
|
|
42086
|
+
});
|
|
42087
|
+
}
|
|
42088
|
+
}, [camera.position, onCameraChange]);
|
|
42089
|
+
return null;
|
|
42090
|
+
}
|
|
42091
|
+
var DEFAULT_GRID_CONFIG, GameCanvas3D;
|
|
42092
|
+
var init_GameCanvas3D2 = __esm({
|
|
42093
|
+
"components/game/molecules/GameCanvas3D.tsx"() {
|
|
42094
|
+
"use client";
|
|
42095
|
+
init_AssetLoader();
|
|
42096
|
+
init_useAssetLoader();
|
|
42097
|
+
init_useGameCanvas3DEvents();
|
|
42098
|
+
init_Canvas3DLoadingState2();
|
|
42099
|
+
init_Canvas3DErrorBoundary2();
|
|
42100
|
+
init_ModelLoader();
|
|
42101
|
+
init_cn();
|
|
42102
|
+
init_GameCanvas3D();
|
|
42103
|
+
DEFAULT_GRID_CONFIG = {
|
|
42104
|
+
cellSize: 1,
|
|
42105
|
+
offsetX: 0,
|
|
42106
|
+
offsetZ: 0
|
|
42107
|
+
};
|
|
42108
|
+
GameCanvas3D = forwardRef(
|
|
42109
|
+
({
|
|
42110
|
+
tiles = [],
|
|
42111
|
+
units = [],
|
|
42112
|
+
features = [],
|
|
42113
|
+
events: events2 = [],
|
|
42114
|
+
orientation = "standard",
|
|
42115
|
+
cameraMode = "isometric",
|
|
42116
|
+
showGrid = true,
|
|
42117
|
+
showCoordinates = false,
|
|
42118
|
+
showTileInfo = false,
|
|
42119
|
+
overlay = "default",
|
|
42120
|
+
shadows = true,
|
|
42121
|
+
backgroundColor = "#1a1a2e",
|
|
42122
|
+
onTileClick,
|
|
42123
|
+
onUnitClick,
|
|
42124
|
+
onFeatureClick,
|
|
42125
|
+
onCanvasClick,
|
|
42126
|
+
onTileHover,
|
|
42127
|
+
onUnitAnimation,
|
|
42128
|
+
assetLoader: customAssetLoader,
|
|
42129
|
+
tileRenderer: CustomTileRenderer,
|
|
42130
|
+
unitRenderer: CustomUnitRenderer,
|
|
42131
|
+
featureRenderer: CustomFeatureRenderer,
|
|
42132
|
+
className,
|
|
42133
|
+
isLoading: externalLoading,
|
|
42134
|
+
error: externalError,
|
|
42135
|
+
entity,
|
|
42136
|
+
preloadAssets = [],
|
|
42137
|
+
tileClickEvent,
|
|
42138
|
+
unitClickEvent,
|
|
42139
|
+
featureClickEvent,
|
|
42140
|
+
canvasClickEvent,
|
|
42141
|
+
tileHoverEvent,
|
|
42142
|
+
tileLeaveEvent,
|
|
42143
|
+
unitAnimationEvent,
|
|
42144
|
+
cameraChangeEvent,
|
|
42145
|
+
loadingMessage = "Loading 3D Scene...",
|
|
42146
|
+
useInstancing = true,
|
|
42147
|
+
validMoves = [],
|
|
42148
|
+
attackTargets = [],
|
|
42149
|
+
selectedTileIds = [],
|
|
42150
|
+
selectedUnitId = null,
|
|
42151
|
+
children
|
|
42152
|
+
}, ref) => {
|
|
42153
|
+
const containerRef = useRef(null);
|
|
42154
|
+
const controlsRef = useRef(null);
|
|
42155
|
+
const [hoveredTile, setHoveredTile] = useState(null);
|
|
42156
|
+
const [internalError, setInternalError] = useState(null);
|
|
42157
|
+
const { isLoading: assetsLoading, progress, loaded, total } = useAssetLoader({
|
|
42158
|
+
preloadUrls: preloadAssets,
|
|
42159
|
+
loader: customAssetLoader
|
|
42160
|
+
});
|
|
42161
|
+
const eventHandlers = useGameCanvas3DEvents({
|
|
42162
|
+
tileClickEvent,
|
|
42163
|
+
unitClickEvent,
|
|
42164
|
+
featureClickEvent,
|
|
42165
|
+
canvasClickEvent,
|
|
42166
|
+
tileHoverEvent,
|
|
42167
|
+
tileLeaveEvent,
|
|
42168
|
+
unitAnimationEvent,
|
|
42169
|
+
cameraChangeEvent,
|
|
42170
|
+
onTileClick,
|
|
42171
|
+
onUnitClick,
|
|
42172
|
+
onFeatureClick,
|
|
42173
|
+
onCanvasClick,
|
|
42174
|
+
onTileHover,
|
|
42175
|
+
onUnitAnimation
|
|
42176
|
+
});
|
|
42177
|
+
const gridBounds = useMemo(() => {
|
|
42178
|
+
if (tiles.length === 0) {
|
|
42179
|
+
return { minX: 0, maxX: 10, minZ: 0, maxZ: 10 };
|
|
42180
|
+
}
|
|
42181
|
+
const xs = tiles.map((t) => t.x);
|
|
42182
|
+
const zs = tiles.map((t) => t.z || t.y || 0);
|
|
42183
|
+
return {
|
|
42184
|
+
minX: Math.min(...xs),
|
|
42185
|
+
maxX: Math.max(...xs),
|
|
42186
|
+
minZ: Math.min(...zs),
|
|
42187
|
+
maxZ: Math.max(...zs)
|
|
42188
|
+
};
|
|
42189
|
+
}, [tiles]);
|
|
42190
|
+
const cameraTarget = useMemo(() => {
|
|
42191
|
+
return [
|
|
42192
|
+
(gridBounds.minX + gridBounds.maxX) / 2,
|
|
42193
|
+
0,
|
|
42194
|
+
(gridBounds.minZ + gridBounds.maxZ) / 2
|
|
42195
|
+
];
|
|
42196
|
+
}, [gridBounds]);
|
|
42197
|
+
const gridConfig = useMemo(
|
|
42198
|
+
() => ({
|
|
42199
|
+
...DEFAULT_GRID_CONFIG,
|
|
42200
|
+
offsetX: -(gridBounds.maxX - gridBounds.minX) / 2,
|
|
42201
|
+
offsetZ: -(gridBounds.maxZ - gridBounds.minZ) / 2
|
|
42202
|
+
}),
|
|
42203
|
+
[gridBounds]
|
|
42204
|
+
);
|
|
42205
|
+
const gridToWorld = useCallback(
|
|
42206
|
+
(x, z, y = 0) => {
|
|
42207
|
+
const worldX = (x - gridBounds.minX) * gridConfig.cellSize;
|
|
42208
|
+
const worldZ = (z - gridBounds.minZ) * gridConfig.cellSize;
|
|
42209
|
+
return [worldX, y * gridConfig.cellSize, worldZ];
|
|
42210
|
+
},
|
|
42211
|
+
[gridBounds, gridConfig]
|
|
42212
|
+
);
|
|
42213
|
+
useImperativeHandle(ref, () => ({
|
|
42214
|
+
getCameraPosition: () => {
|
|
42215
|
+
if (controlsRef.current) {
|
|
42216
|
+
const pos = controlsRef.current.object.position;
|
|
42217
|
+
return new THREE.Vector3(pos.x, pos.y, pos.z);
|
|
42218
|
+
}
|
|
42219
|
+
return null;
|
|
42220
|
+
},
|
|
42221
|
+
setCameraPosition: (x, y, z) => {
|
|
42222
|
+
if (controlsRef.current) {
|
|
42223
|
+
controlsRef.current.object.position.set(x, y, z);
|
|
42224
|
+
controlsRef.current.update();
|
|
42225
|
+
}
|
|
42226
|
+
},
|
|
42227
|
+
lookAt: (x, y, z) => {
|
|
42228
|
+
if (controlsRef.current) {
|
|
42229
|
+
controlsRef.current.target.set(x, y, z);
|
|
42230
|
+
controlsRef.current.update();
|
|
42231
|
+
}
|
|
42232
|
+
},
|
|
42233
|
+
resetCamera: () => {
|
|
42234
|
+
if (controlsRef.current) {
|
|
42235
|
+
controlsRef.current.reset();
|
|
42236
|
+
}
|
|
42237
|
+
},
|
|
42238
|
+
screenshot: () => {
|
|
42239
|
+
const canvas = containerRef.current?.querySelector("canvas");
|
|
42240
|
+
if (canvas) {
|
|
42241
|
+
return canvas.toDataURL("image/png");
|
|
42242
|
+
}
|
|
42243
|
+
return null;
|
|
42244
|
+
},
|
|
42245
|
+
export: () => ({
|
|
42246
|
+
tiles,
|
|
42247
|
+
units,
|
|
42248
|
+
features
|
|
42249
|
+
})
|
|
42250
|
+
}));
|
|
42251
|
+
const handleTileClick = useCallback(
|
|
42252
|
+
(tile, event) => {
|
|
42253
|
+
eventHandlers.handleTileClick(tile, event);
|
|
42254
|
+
},
|
|
42255
|
+
[eventHandlers]
|
|
42256
|
+
);
|
|
42257
|
+
const handleUnitClick = useCallback(
|
|
42258
|
+
(unit, event) => {
|
|
42259
|
+
eventHandlers.handleUnitClick(unit, event);
|
|
42260
|
+
},
|
|
42261
|
+
[eventHandlers]
|
|
42262
|
+
);
|
|
42263
|
+
const handleFeatureClick = useCallback(
|
|
42264
|
+
(feature, event) => {
|
|
42265
|
+
if (event) {
|
|
42266
|
+
eventHandlers.handleFeatureClick(feature, event);
|
|
42267
|
+
}
|
|
42268
|
+
},
|
|
42269
|
+
[eventHandlers]
|
|
42270
|
+
);
|
|
42271
|
+
const handleTileHover = useCallback(
|
|
42272
|
+
(tile, event) => {
|
|
42273
|
+
setHoveredTile(tile);
|
|
42274
|
+
if (event) {
|
|
42275
|
+
eventHandlers.handleTileHover(tile, event);
|
|
42276
|
+
}
|
|
42277
|
+
},
|
|
42278
|
+
[eventHandlers]
|
|
42279
|
+
);
|
|
42280
|
+
const cameraConfig = useMemo(() => {
|
|
42281
|
+
const size = Math.max(
|
|
42282
|
+
gridBounds.maxX - gridBounds.minX,
|
|
42283
|
+
gridBounds.maxZ - gridBounds.minZ
|
|
42284
|
+
);
|
|
42285
|
+
const distance = size * 1.5;
|
|
42286
|
+
switch (cameraMode) {
|
|
42287
|
+
case "isometric":
|
|
42288
|
+
return {
|
|
42289
|
+
position: [distance, distance * 0.8, distance],
|
|
42290
|
+
fov: 45
|
|
42291
|
+
};
|
|
42292
|
+
case "top-down":
|
|
42293
|
+
return {
|
|
42294
|
+
position: [0, distance * 2, 0],
|
|
42295
|
+
fov: 45
|
|
42296
|
+
};
|
|
42297
|
+
case "perspective":
|
|
42298
|
+
default:
|
|
42299
|
+
return {
|
|
42300
|
+
position: [distance, distance, distance],
|
|
42301
|
+
fov: 45
|
|
42302
|
+
};
|
|
42303
|
+
}
|
|
42304
|
+
}, [cameraMode, gridBounds]);
|
|
42305
|
+
const DefaultTileRenderer = useCallback(
|
|
42306
|
+
({ tile, position }) => {
|
|
42307
|
+
const isSelected = tile.id ? selectedTileIds.includes(tile.id) : false;
|
|
42308
|
+
const isHovered = hoveredTile?.id === tile.id;
|
|
42309
|
+
const isValidMove = validMoves.some(
|
|
42310
|
+
(m) => m.x === tile.x && m.z === (tile.z ?? tile.y ?? 0)
|
|
42311
|
+
);
|
|
42312
|
+
const isAttackTarget = attackTargets.some(
|
|
42313
|
+
(m) => m.x === tile.x && m.z === (tile.z ?? tile.y ?? 0)
|
|
42314
|
+
);
|
|
42315
|
+
let color = 8421504;
|
|
42316
|
+
if (tile.type === "water") color = 4491468;
|
|
42317
|
+
else if (tile.type === "grass") color = 4500036;
|
|
42318
|
+
else if (tile.type === "sand") color = 14535816;
|
|
42319
|
+
else if (tile.type === "rock") color = 8947848;
|
|
42320
|
+
else if (tile.type === "snow") color = 15658734;
|
|
42321
|
+
let emissive = 0;
|
|
42322
|
+
if (isSelected) emissive = 4473924;
|
|
42323
|
+
else if (isAttackTarget) emissive = 4456448;
|
|
42324
|
+
else if (isValidMove) emissive = 17408;
|
|
42325
|
+
else if (isHovered) emissive = 2236962;
|
|
42326
|
+
if (tile.modelUrl) {
|
|
42327
|
+
return /* @__PURE__ */ jsx(
|
|
42328
|
+
"group",
|
|
42329
|
+
{
|
|
42330
|
+
position,
|
|
42331
|
+
onClick: (e) => handleTileClick(tile, e),
|
|
42332
|
+
onPointerEnter: (e) => handleTileHover(tile, e),
|
|
42333
|
+
onPointerLeave: (e) => handleTileHover(null, e),
|
|
42334
|
+
userData: { type: "tile", tileId: tile.id, gridX: tile.x, gridZ: tile.z ?? tile.y },
|
|
42335
|
+
children: /* @__PURE__ */ jsx(
|
|
42336
|
+
ModelLoader,
|
|
42337
|
+
{
|
|
42338
|
+
url: tile.modelUrl,
|
|
42339
|
+
scale: 0.95,
|
|
42340
|
+
fallbackGeometry: "box",
|
|
42341
|
+
castShadow: true,
|
|
42342
|
+
receiveShadow: true
|
|
42343
|
+
}
|
|
42344
|
+
)
|
|
42345
|
+
}
|
|
42346
|
+
);
|
|
42347
|
+
}
|
|
42348
|
+
return /* @__PURE__ */ jsxs(
|
|
42349
|
+
"mesh",
|
|
42350
|
+
{
|
|
42351
|
+
position,
|
|
42352
|
+
onClick: (e) => handleTileClick(tile, e),
|
|
42353
|
+
onPointerEnter: (e) => handleTileHover(tile, e),
|
|
42354
|
+
onPointerLeave: (e) => handleTileHover(null, e),
|
|
42355
|
+
userData: { type: "tile", tileId: tile.id, gridX: tile.x, gridZ: tile.z ?? tile.y },
|
|
42356
|
+
children: [
|
|
42357
|
+
/* @__PURE__ */ jsx("boxGeometry", { args: [0.95, 0.2, 0.95] }),
|
|
42358
|
+
/* @__PURE__ */ jsx("meshStandardMaterial", { color, emissive })
|
|
42359
|
+
]
|
|
42360
|
+
}
|
|
42361
|
+
);
|
|
42362
|
+
},
|
|
42363
|
+
[selectedTileIds, hoveredTile, validMoves, attackTargets, handleTileClick, handleTileHover]
|
|
42364
|
+
);
|
|
42365
|
+
const DefaultUnitRenderer = useCallback(
|
|
42366
|
+
({ unit, position }) => {
|
|
42367
|
+
const isSelected = selectedUnitId === unit.id;
|
|
42368
|
+
const color = unit.faction === "player" ? 4491519 : unit.faction === "enemy" ? 16729156 : 16777028;
|
|
42369
|
+
return /* @__PURE__ */ jsxs(
|
|
42370
|
+
"group",
|
|
42371
|
+
{
|
|
42372
|
+
position,
|
|
42373
|
+
onClick: (e) => handleUnitClick(unit, e),
|
|
42374
|
+
userData: { type: "unit", unitId: unit.id },
|
|
42375
|
+
children: [
|
|
42376
|
+
isSelected && /* @__PURE__ */ jsxs("mesh", { position: [0, 0.05, 0], rotation: [-Math.PI / 2, 0, 0], children: [
|
|
42377
|
+
/* @__PURE__ */ jsx("ringGeometry", { args: [0.4, 0.5, 32] }),
|
|
42378
|
+
/* @__PURE__ */ jsx("meshBasicMaterial", { color: "#ffff00", transparent: true, opacity: 0.8 })
|
|
42379
|
+
] }),
|
|
42380
|
+
unit.modelUrl ? (
|
|
42381
|
+
/* GLB unit model (box fallback while loading / on error) */
|
|
42382
|
+
/* @__PURE__ */ jsx(
|
|
42383
|
+
ModelLoader,
|
|
42384
|
+
{
|
|
42385
|
+
url: unit.modelUrl,
|
|
42386
|
+
scale: 0.5,
|
|
42387
|
+
fallbackGeometry: "box",
|
|
42388
|
+
castShadow: true
|
|
42389
|
+
}
|
|
42390
|
+
)
|
|
42391
|
+
) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
42392
|
+
/* @__PURE__ */ jsxs("mesh", { position: [0, 0.3, 0], children: [
|
|
42393
|
+
/* @__PURE__ */ jsx("cylinderGeometry", { args: [0.3, 0.3, 0.1, 8] }),
|
|
42394
|
+
/* @__PURE__ */ jsx("meshStandardMaterial", { color })
|
|
42395
|
+
] }),
|
|
42396
|
+
/* @__PURE__ */ jsxs("mesh", { position: [0, 0.6, 0], children: [
|
|
42397
|
+
/* @__PURE__ */ jsx("capsuleGeometry", { args: [0.2, 0.4, 4, 8] }),
|
|
42398
|
+
/* @__PURE__ */ jsx("meshStandardMaterial", { color })
|
|
42399
|
+
] }),
|
|
42400
|
+
/* @__PURE__ */ jsxs("mesh", { position: [0, 0.9, 0], children: [
|
|
42401
|
+
/* @__PURE__ */ jsx("sphereGeometry", { args: [0.12, 8, 8] }),
|
|
42402
|
+
/* @__PURE__ */ jsx("meshStandardMaterial", { color })
|
|
42403
|
+
] })
|
|
42404
|
+
] }),
|
|
42405
|
+
unit.health !== void 0 && unit.maxHealth !== void 0 && /* @__PURE__ */ jsxs("group", { position: [0, 1.2, 0], children: [
|
|
42406
|
+
/* @__PURE__ */ jsxs("mesh", { position: [-0.25, 0, 0], children: [
|
|
42407
|
+
/* @__PURE__ */ jsx("planeGeometry", { args: [0.5, 0.05] }),
|
|
42408
|
+
/* @__PURE__ */ jsx("meshBasicMaterial", { color: 3355443 })
|
|
42409
|
+
] }),
|
|
42410
|
+
/* @__PURE__ */ jsxs(
|
|
42411
|
+
"mesh",
|
|
42412
|
+
{
|
|
42413
|
+
position: [
|
|
42414
|
+
-0.25 + 0.5 * (unit.health / unit.maxHealth) / 2,
|
|
42415
|
+
0,
|
|
42416
|
+
0.01
|
|
42417
|
+
],
|
|
42418
|
+
children: [
|
|
42419
|
+
/* @__PURE__ */ jsx("planeGeometry", { args: [0.5 * (unit.health / unit.maxHealth), 0.05] }),
|
|
42420
|
+
/* @__PURE__ */ jsx(
|
|
42421
|
+
"meshBasicMaterial",
|
|
42422
|
+
{
|
|
42423
|
+
color: unit.health / unit.maxHealth > 0.5 ? 4500036 : unit.health / unit.maxHealth > 0.25 ? 11184708 : 16729156
|
|
42424
|
+
}
|
|
42425
|
+
)
|
|
42426
|
+
]
|
|
42427
|
+
}
|
|
42428
|
+
)
|
|
42429
|
+
] })
|
|
42430
|
+
]
|
|
42431
|
+
}
|
|
42432
|
+
);
|
|
42433
|
+
},
|
|
42434
|
+
[selectedUnitId, handleUnitClick]
|
|
42435
|
+
);
|
|
42436
|
+
const DefaultFeatureRenderer = useCallback(
|
|
42437
|
+
({
|
|
42438
|
+
feature,
|
|
42439
|
+
position
|
|
42440
|
+
}) => {
|
|
42441
|
+
if (feature.assetUrl) {
|
|
42442
|
+
return /* @__PURE__ */ jsx(
|
|
42443
|
+
ModelLoader,
|
|
42444
|
+
{
|
|
42445
|
+
url: feature.assetUrl,
|
|
42446
|
+
position,
|
|
42447
|
+
scale: 0.5,
|
|
42448
|
+
rotation: [0, feature.rotation ?? 0, 0],
|
|
42449
|
+
onClick: () => handleFeatureClick(feature, null),
|
|
42450
|
+
fallbackGeometry: "box"
|
|
42451
|
+
},
|
|
42452
|
+
feature.id
|
|
42453
|
+
);
|
|
42454
|
+
}
|
|
42455
|
+
if (feature.type === "tree") {
|
|
42456
|
+
return /* @__PURE__ */ jsxs(
|
|
42457
|
+
"group",
|
|
42458
|
+
{
|
|
42459
|
+
position,
|
|
42460
|
+
onClick: (e) => handleFeatureClick(feature, e),
|
|
42461
|
+
userData: { type: "feature", featureId: feature.id },
|
|
42462
|
+
children: [
|
|
42463
|
+
/* @__PURE__ */ jsxs("mesh", { position: [0, 0.4, 0], children: [
|
|
42464
|
+
/* @__PURE__ */ jsx("cylinderGeometry", { args: [0.1, 0.15, 0.8, 6] }),
|
|
42465
|
+
/* @__PURE__ */ jsx("meshStandardMaterial", { color: 9127187 })
|
|
42466
|
+
] }),
|
|
42467
|
+
/* @__PURE__ */ jsxs("mesh", { position: [0, 0.9, 0], children: [
|
|
42468
|
+
/* @__PURE__ */ jsx("coneGeometry", { args: [0.5, 0.8, 8] }),
|
|
42469
|
+
/* @__PURE__ */ jsx("meshStandardMaterial", { color: 2263842 })
|
|
42470
|
+
] })
|
|
42471
|
+
]
|
|
42472
|
+
}
|
|
42473
|
+
);
|
|
42474
|
+
}
|
|
42475
|
+
if (feature.type === "rock") {
|
|
42476
|
+
return /* @__PURE__ */ jsxs(
|
|
42477
|
+
"mesh",
|
|
42478
|
+
{
|
|
42479
|
+
position: [position[0], position[1] + 0.3, position[2]],
|
|
42480
|
+
onClick: (e) => handleFeatureClick(feature, e),
|
|
42481
|
+
userData: { type: "feature", featureId: feature.id },
|
|
42482
|
+
children: [
|
|
42483
|
+
/* @__PURE__ */ jsx("dodecahedronGeometry", { args: [0.3, 0] }),
|
|
42484
|
+
/* @__PURE__ */ jsx("meshStandardMaterial", { color: 8421504 })
|
|
42485
|
+
]
|
|
42486
|
+
}
|
|
42487
|
+
);
|
|
42488
|
+
}
|
|
42489
|
+
return null;
|
|
42490
|
+
},
|
|
42491
|
+
[handleFeatureClick]
|
|
42492
|
+
);
|
|
42493
|
+
if (externalLoading || assetsLoading && preloadAssets.length > 0) {
|
|
42494
|
+
return /* @__PURE__ */ jsx(
|
|
42495
|
+
Canvas3DLoadingState,
|
|
42496
|
+
{
|
|
42497
|
+
progress,
|
|
42498
|
+
loaded,
|
|
42499
|
+
total,
|
|
42500
|
+
message: loadingMessage,
|
|
42501
|
+
className
|
|
42502
|
+
}
|
|
42503
|
+
);
|
|
42504
|
+
}
|
|
42505
|
+
const displayError = externalError || internalError;
|
|
42506
|
+
if (displayError) {
|
|
42507
|
+
return /* @__PURE__ */ jsx(Canvas3DErrorBoundary, { children: /* @__PURE__ */ jsx("div", { className: "game-canvas-3d game-canvas-3d--error", children: /* @__PURE__ */ jsxs("div", { className: "game-canvas-3d__error", children: [
|
|
42508
|
+
"Error: ",
|
|
42509
|
+
displayError
|
|
42510
|
+
] }) }) });
|
|
42511
|
+
}
|
|
42512
|
+
return /* @__PURE__ */ jsx(
|
|
42513
|
+
Canvas3DErrorBoundary,
|
|
42514
|
+
{
|
|
42515
|
+
onError: (err) => setInternalError(err.message),
|
|
42516
|
+
onReset: () => setInternalError(null),
|
|
42517
|
+
children: /* @__PURE__ */ jsxs(
|
|
42518
|
+
"div",
|
|
42519
|
+
{
|
|
42520
|
+
ref: containerRef,
|
|
42521
|
+
className: cn("game-canvas-3d relative w-full h-full min-h-[85vh] overflow-hidden", className),
|
|
42522
|
+
"data-orientation": orientation,
|
|
42523
|
+
"data-camera-mode": cameraMode,
|
|
42524
|
+
"data-overlay": overlay,
|
|
42525
|
+
children: [
|
|
42526
|
+
/* @__PURE__ */ jsxs(
|
|
42527
|
+
Canvas,
|
|
42528
|
+
{
|
|
42529
|
+
shadows,
|
|
42530
|
+
camera: {
|
|
42531
|
+
position: cameraConfig.position,
|
|
42532
|
+
fov: cameraConfig.fov,
|
|
42533
|
+
near: 0.1,
|
|
42534
|
+
far: 1e3
|
|
42535
|
+
},
|
|
42536
|
+
style: { background: backgroundColor },
|
|
42537
|
+
onClick: (e) => {
|
|
42538
|
+
if (e.target === e.currentTarget) {
|
|
42539
|
+
eventHandlers.handleCanvasClick(e);
|
|
42540
|
+
}
|
|
42541
|
+
},
|
|
42542
|
+
children: [
|
|
42543
|
+
/* @__PURE__ */ jsx(CameraController, { onCameraChange: eventHandlers.handleCameraChange }),
|
|
42544
|
+
/* @__PURE__ */ jsx("ambientLight", { intensity: 0.6 }),
|
|
42545
|
+
/* @__PURE__ */ jsx(
|
|
42546
|
+
"directionalLight",
|
|
42547
|
+
{
|
|
42548
|
+
position: [10, 20, 10],
|
|
42549
|
+
intensity: 0.8,
|
|
42550
|
+
castShadow: shadows,
|
|
42551
|
+
"shadow-mapSize": [2048, 2048]
|
|
42552
|
+
}
|
|
42553
|
+
),
|
|
42554
|
+
/* @__PURE__ */ jsx("hemisphereLight", { intensity: 0.3, color: "#87ceeb", groundColor: "#362d1d" }),
|
|
42555
|
+
showGrid && /* @__PURE__ */ jsx(
|
|
42556
|
+
Grid$1,
|
|
42557
|
+
{
|
|
42558
|
+
args: [
|
|
42559
|
+
Math.max(gridBounds.maxX - gridBounds.minX + 2, 10),
|
|
42560
|
+
Math.max(gridBounds.maxZ - gridBounds.minZ + 2, 10)
|
|
42561
|
+
],
|
|
42562
|
+
position: [
|
|
42563
|
+
(gridBounds.maxX - gridBounds.minX) / 2 - 0.5,
|
|
42564
|
+
0,
|
|
42565
|
+
(gridBounds.maxZ - gridBounds.minZ) / 2 - 0.5
|
|
42566
|
+
],
|
|
42567
|
+
cellSize: 1,
|
|
42568
|
+
cellThickness: 1,
|
|
42569
|
+
cellColor: "#444444",
|
|
42570
|
+
sectionSize: 5,
|
|
42571
|
+
sectionThickness: 1.5,
|
|
42572
|
+
sectionColor: "#666666",
|
|
42573
|
+
fadeDistance: 50,
|
|
42574
|
+
fadeStrength: 1
|
|
42575
|
+
}
|
|
42576
|
+
),
|
|
42577
|
+
tiles.map((tile, index) => {
|
|
42578
|
+
const position = gridToWorld(
|
|
42579
|
+
tile.x,
|
|
42580
|
+
tile.z ?? tile.y ?? 0,
|
|
42581
|
+
tile.elevation ?? 0
|
|
42582
|
+
);
|
|
42583
|
+
const Renderer = CustomTileRenderer || DefaultTileRenderer;
|
|
42584
|
+
return /* @__PURE__ */ jsx(Renderer, { tile, position }, tile.id ?? `tile-${index}`);
|
|
42585
|
+
}),
|
|
42586
|
+
features.map((feature, index) => {
|
|
42587
|
+
const position = gridToWorld(
|
|
42588
|
+
feature.x,
|
|
42589
|
+
feature.z ?? feature.y ?? 0,
|
|
42590
|
+
(feature.elevation ?? 0) + 0.5
|
|
42591
|
+
);
|
|
42592
|
+
const Renderer = CustomFeatureRenderer || DefaultFeatureRenderer;
|
|
42593
|
+
return /* @__PURE__ */ jsx(Renderer, { feature, position }, feature.id ?? `feature-${index}`);
|
|
42594
|
+
}),
|
|
42595
|
+
units.map((unit) => {
|
|
42596
|
+
const position = gridToWorld(
|
|
42597
|
+
unit.x ?? 0,
|
|
42598
|
+
unit.z ?? unit.y ?? 0,
|
|
42599
|
+
(unit.elevation ?? 0) + 0.5
|
|
42600
|
+
);
|
|
42601
|
+
const Renderer = CustomUnitRenderer || DefaultUnitRenderer;
|
|
42602
|
+
return /* @__PURE__ */ jsx(Renderer, { unit, position }, unit.id);
|
|
42603
|
+
}),
|
|
42604
|
+
children,
|
|
42605
|
+
/* @__PURE__ */ jsx(
|
|
42606
|
+
OrbitControls,
|
|
42607
|
+
{
|
|
42608
|
+
ref: controlsRef,
|
|
42609
|
+
target: cameraTarget,
|
|
42610
|
+
enableDamping: true,
|
|
42611
|
+
dampingFactor: 0.05,
|
|
42612
|
+
minDistance: 2,
|
|
42613
|
+
maxDistance: 100,
|
|
42614
|
+
maxPolarAngle: Math.PI / 2 - 0.1
|
|
42615
|
+
}
|
|
42616
|
+
)
|
|
42617
|
+
]
|
|
42618
|
+
}
|
|
42619
|
+
),
|
|
42620
|
+
showCoordinates && hoveredTile && /* @__PURE__ */ jsxs("div", { className: "game-canvas-3d__coordinates", children: [
|
|
42621
|
+
"X: ",
|
|
42622
|
+
hoveredTile.x,
|
|
42623
|
+
", Z: ",
|
|
42624
|
+
hoveredTile.z ?? hoveredTile.y ?? 0
|
|
42625
|
+
] }),
|
|
42626
|
+
showTileInfo && hoveredTile && /* @__PURE__ */ jsxs("div", { className: "game-canvas-3d__tile-info", children: [
|
|
42627
|
+
/* @__PURE__ */ jsx("div", { className: "tile-info__type", children: hoveredTile.type }),
|
|
42628
|
+
hoveredTile.terrain && /* @__PURE__ */ jsx("div", { className: "tile-info__terrain", children: hoveredTile.terrain })
|
|
42629
|
+
] })
|
|
42630
|
+
]
|
|
42631
|
+
}
|
|
42632
|
+
)
|
|
42633
|
+
}
|
|
42634
|
+
);
|
|
42635
|
+
}
|
|
42636
|
+
);
|
|
42637
|
+
GameCanvas3D.displayName = "GameCanvas3D";
|
|
42638
|
+
}
|
|
42639
|
+
});
|
|
42640
|
+
function GameBoard3D({
|
|
42641
|
+
entity,
|
|
42642
|
+
tiles = [],
|
|
42643
|
+
features = [],
|
|
42644
|
+
cameraMode = "perspective",
|
|
42645
|
+
backgroundColor = "#2a1a1a",
|
|
42646
|
+
tileClickEvent,
|
|
42647
|
+
unitClickEvent,
|
|
42648
|
+
attackEvent,
|
|
42649
|
+
endTurnEvent,
|
|
42650
|
+
cancelEvent,
|
|
42651
|
+
playAgainEvent,
|
|
42652
|
+
gameEndEvent,
|
|
42653
|
+
className
|
|
42654
|
+
}) {
|
|
42655
|
+
const row = boardEntity(entity);
|
|
42656
|
+
const eventBus = useEventBus();
|
|
42657
|
+
const entityUnits = row ? rows(row.units) : [];
|
|
42658
|
+
const units = entityUnits;
|
|
42659
|
+
const selectedUnitId = row ? str(row.selectedUnitId) || null : null;
|
|
42660
|
+
const phase = row ? str(row.phase) : "observation";
|
|
42661
|
+
const result = row ? str(row.result) : "none";
|
|
42662
|
+
const validMoves = row && Array.isArray(row.validMoves) ? row.validMoves : [];
|
|
42663
|
+
const attackTargets = row && Array.isArray(row.attackTargets) ? row.attackTargets : [];
|
|
42664
|
+
const turn = row ? num(row.turn) : 0;
|
|
42665
|
+
const currentTeam = row ? str(row.currentTeam) : "player";
|
|
42666
|
+
const isGameOver = result !== "none";
|
|
42667
|
+
const gameEndEmittedRef = useRef(false);
|
|
42668
|
+
useEffect(() => {
|
|
42669
|
+
if ((result === "victory" || result === "defeat") && gameEndEvent) {
|
|
42670
|
+
if (!gameEndEmittedRef.current) {
|
|
42671
|
+
gameEndEmittedRef.current = true;
|
|
42672
|
+
eventBus.emit(`UI:${gameEndEvent}`, { result });
|
|
42673
|
+
}
|
|
42674
|
+
} else {
|
|
42675
|
+
gameEndEmittedRef.current = false;
|
|
42676
|
+
}
|
|
42677
|
+
}, [result, gameEndEvent, eventBus]);
|
|
42678
|
+
const checkGameEnd = useCallback(() => {
|
|
42679
|
+
const alivePlayer = entityUnits.filter((u) => unitTeam(u) === "player" && unitHealth(u) > 0);
|
|
42680
|
+
const aliveEnemy = entityUnits.filter((u) => unitTeam(u) === "enemy" && unitHealth(u) > 0);
|
|
42681
|
+
if (alivePlayer.length === 0 && gameEndEvent) {
|
|
42682
|
+
eventBus.emit(`UI:${gameEndEvent}`, { result: "defeat" });
|
|
42683
|
+
} else if (aliveEnemy.length === 0 && gameEndEvent) {
|
|
42684
|
+
eventBus.emit(`UI:${gameEndEvent}`, { result: "victory" });
|
|
42685
|
+
}
|
|
42686
|
+
}, [entityUnits, gameEndEvent, eventBus]);
|
|
42687
|
+
const handleUnitClickCallback = useCallback((isoUnit) => {
|
|
42688
|
+
if (phase !== "action" || !selectedUnitId || !attackEvent) return;
|
|
42689
|
+
const attackerRow = entityUnits.find((u) => str(u.id) === selectedUnitId);
|
|
42690
|
+
const targetRow = entityUnits.find((u) => str(u.id) === isoUnit.id);
|
|
42691
|
+
if (!attackerRow || !targetRow) return;
|
|
42692
|
+
if (unitTeam(targetRow) !== "enemy" || unitHealth(targetRow) <= 0) return;
|
|
42693
|
+
const ap = unitPosition(attackerRow);
|
|
42694
|
+
const tp = unitPosition(targetRow);
|
|
42695
|
+
const dx = Math.abs(ap.x - tp.x);
|
|
42696
|
+
const dy = Math.abs(ap.y - tp.y);
|
|
42697
|
+
if (dx <= 1 && dy <= 1 && dx + dy > 0) {
|
|
42698
|
+
const damage = Math.max(1, num(attackerRow.attack) - num(targetRow.defense));
|
|
42699
|
+
eventBus.emit(`UI:${attackEvent}`, {
|
|
42700
|
+
attackerId: str(attackerRow.id),
|
|
42701
|
+
targetId: str(targetRow.id),
|
|
42702
|
+
damage
|
|
42703
|
+
});
|
|
42704
|
+
setTimeout(checkGameEnd, 100);
|
|
42705
|
+
}
|
|
42706
|
+
}, [phase, selectedUnitId, entityUnits, attackEvent, eventBus, checkGameEnd]);
|
|
42707
|
+
const handleEndTurn = useCallback(() => {
|
|
42708
|
+
if (endTurnEvent) eventBus.emit(`UI:${endTurnEvent}`, {});
|
|
42709
|
+
}, [endTurnEvent, eventBus]);
|
|
42710
|
+
const handleCancel = useCallback(() => {
|
|
42711
|
+
if (cancelEvent) eventBus.emit(`UI:${cancelEvent}`, {});
|
|
42712
|
+
}, [cancelEvent, eventBus]);
|
|
42713
|
+
const handlePlayAgain = useCallback(() => {
|
|
42714
|
+
if (playAgainEvent) eventBus.emit(`UI:${playAgainEvent}`, {});
|
|
42715
|
+
}, [playAgainEvent, eventBus]);
|
|
42716
|
+
return /* @__PURE__ */ jsxs(VStack, { className: cn("game-board-3d block w-full min-h-[85vh] relative", className), children: [
|
|
42717
|
+
/* @__PURE__ */ jsxs("div", { className: "game-board-3d__status absolute top-3 left-3 z-10 flex gap-2 items-center", children: [
|
|
42718
|
+
/* @__PURE__ */ jsx(Typography, { variant: "small", className: "status__phase capitalize", children: phase.replace("_", " ") }),
|
|
42719
|
+
currentTeam && !isGameOver && /* @__PURE__ */ jsxs(Typography, { variant: "small", color: "muted", className: "status__team", children: [
|
|
42720
|
+
"\u2014 ",
|
|
42721
|
+
currentTeam === "player" ? "Your Turn" : "Enemy's Turn"
|
|
42722
|
+
] }),
|
|
42723
|
+
/* @__PURE__ */ jsxs(Typography, { variant: "small", color: "muted", className: "status__turn", children: [
|
|
42724
|
+
"Turn ",
|
|
42725
|
+
turn
|
|
42726
|
+
] })
|
|
42727
|
+
] }),
|
|
42728
|
+
/* @__PURE__ */ jsx(
|
|
42729
|
+
GameCanvas3D,
|
|
42730
|
+
{
|
|
42731
|
+
tiles,
|
|
42732
|
+
units,
|
|
42733
|
+
features,
|
|
42734
|
+
cameraMode,
|
|
42735
|
+
showGrid: true,
|
|
42736
|
+
showCoordinates: false,
|
|
42737
|
+
showTileInfo: false,
|
|
42738
|
+
shadows: true,
|
|
42739
|
+
backgroundColor,
|
|
42740
|
+
tileClickEvent,
|
|
42741
|
+
unitClickEvent,
|
|
42742
|
+
onUnitClick: handleUnitClickCallback,
|
|
42743
|
+
selectedUnitId,
|
|
42744
|
+
validMoves,
|
|
42745
|
+
attackTargets,
|
|
42746
|
+
className: "game-board-3d__canvas w-full min-h-[85vh]"
|
|
42747
|
+
}
|
|
42748
|
+
),
|
|
42749
|
+
!isGameOver && /* @__PURE__ */ jsxs(HStack, { className: "fixed bottom-6 right-6 z-50", gap: "sm", children: [
|
|
42750
|
+
(phase === "selection" || phase === "movement" || phase === "action") && /* @__PURE__ */ jsx(
|
|
42751
|
+
Button,
|
|
42752
|
+
{
|
|
42753
|
+
variant: "secondary",
|
|
42754
|
+
className: "shadow-xl",
|
|
42755
|
+
onClick: handleCancel,
|
|
42756
|
+
children: "Cancel"
|
|
42757
|
+
}
|
|
42758
|
+
),
|
|
42759
|
+
phase !== "enemy_turn" && /* @__PURE__ */ jsx(
|
|
42760
|
+
Button,
|
|
42761
|
+
{
|
|
42762
|
+
variant: "primary",
|
|
42763
|
+
className: "shadow-xl",
|
|
42764
|
+
onClick: handleEndTurn,
|
|
42765
|
+
children: "End Turn"
|
|
42766
|
+
}
|
|
42767
|
+
)
|
|
42768
|
+
] }),
|
|
42769
|
+
isGameOver && /* @__PURE__ */ jsx("div", { className: "game-board-3d__overlay absolute inset-0 z-20 flex items-center justify-center bg-black/60", children: /* @__PURE__ */ jsxs(VStack, { align: "center", gap: "md", className: "overlay__card p-8 rounded-xl bg-gray-900/90 shadow-2xl", children: [
|
|
42770
|
+
/* @__PURE__ */ jsx(
|
|
42771
|
+
Typography,
|
|
42772
|
+
{
|
|
42773
|
+
variant: "h2",
|
|
42774
|
+
className: cn(
|
|
42775
|
+
"overlay__result",
|
|
42776
|
+
result === "victory" ? "text-yellow-400" : "text-red-500"
|
|
42777
|
+
),
|
|
42778
|
+
children: result === "victory" ? "Victory!" : "Defeat"
|
|
42779
|
+
}
|
|
42780
|
+
),
|
|
42781
|
+
/* @__PURE__ */ jsxs(Typography, { variant: "body", color: "muted", className: "overlay__turn-count", children: [
|
|
42782
|
+
"Completed in ",
|
|
42783
|
+
turn,
|
|
42784
|
+
" turn",
|
|
42785
|
+
turn !== 1 ? "s" : ""
|
|
42786
|
+
] }),
|
|
42787
|
+
/* @__PURE__ */ jsx(
|
|
42788
|
+
Button,
|
|
42789
|
+
{
|
|
42790
|
+
variant: "primary",
|
|
42791
|
+
className: "px-8 py-3 font-semibold",
|
|
42792
|
+
onClick: handlePlayAgain,
|
|
42793
|
+
children: "Play Again"
|
|
42794
|
+
}
|
|
42795
|
+
)
|
|
42796
|
+
] }) })
|
|
42797
|
+
] });
|
|
42798
|
+
}
|
|
42799
|
+
var init_GameBoard3D = __esm({
|
|
42800
|
+
"components/game/organisms/GameBoard3D.tsx"() {
|
|
42801
|
+
"use client";
|
|
42802
|
+
init_cn();
|
|
42803
|
+
init_Button();
|
|
42804
|
+
init_Typography();
|
|
42805
|
+
init_Stack();
|
|
42806
|
+
init_useEventBus();
|
|
42807
|
+
init_GameCanvas3D2();
|
|
42808
|
+
init_boardEntity();
|
|
42809
|
+
GameBoard3D.displayName = "GameBoard3D";
|
|
42810
|
+
}
|
|
42811
|
+
});
|
|
41157
42812
|
var GameShell;
|
|
41158
42813
|
var init_GameShell = __esm({
|
|
41159
42814
|
"components/game/templates/GameShell.tsx"() {
|
|
@@ -42696,6 +44351,236 @@ var init_NegotiatorBoard = __esm({
|
|
|
42696
44351
|
NegotiatorBoard.displayName = "NegotiatorBoard";
|
|
42697
44352
|
}
|
|
42698
44353
|
});
|
|
44354
|
+
function resolveEntity(entity) {
|
|
44355
|
+
if (!entity) return {};
|
|
44356
|
+
if (Array.isArray(entity)) return entity[0] ?? {};
|
|
44357
|
+
return entity;
|
|
44358
|
+
}
|
|
44359
|
+
function numField(row, key, fallback) {
|
|
44360
|
+
const v = row[key];
|
|
44361
|
+
return typeof v === "number" ? v : fallback;
|
|
44362
|
+
}
|
|
44363
|
+
function strField(row, key, fallback) {
|
|
44364
|
+
const v = row[key];
|
|
44365
|
+
return typeof v === "string" ? v : fallback;
|
|
44366
|
+
}
|
|
44367
|
+
function PlatformerBoard({
|
|
44368
|
+
entity,
|
|
44369
|
+
player: propPlayer,
|
|
44370
|
+
platforms: propPlatforms,
|
|
44371
|
+
result: propResult,
|
|
44372
|
+
lives: propLives,
|
|
44373
|
+
score: propScore,
|
|
44374
|
+
level: propLevel,
|
|
44375
|
+
worldWidth = 800,
|
|
44376
|
+
worldHeight = 400,
|
|
44377
|
+
canvasWidth = 800,
|
|
44378
|
+
canvasHeight = 400,
|
|
44379
|
+
playerSprite,
|
|
44380
|
+
tileSprites,
|
|
44381
|
+
bgColor,
|
|
44382
|
+
leftEvent = "LEFT",
|
|
44383
|
+
rightEvent = "RIGHT",
|
|
44384
|
+
jumpEvent = "JUMP",
|
|
44385
|
+
stopEvent = "STOP",
|
|
44386
|
+
playAgainEvent = "PLAY_AGAIN",
|
|
44387
|
+
gameEndEvent = "GAME_END",
|
|
44388
|
+
className
|
|
44389
|
+
}) {
|
|
44390
|
+
const row = resolveEntity(entity);
|
|
44391
|
+
const eventBus = useEventBus();
|
|
44392
|
+
const { t } = useTranslate();
|
|
44393
|
+
const result = propResult ?? strField(row, "result", "none");
|
|
44394
|
+
propLives ?? numField(row, "lives", 3);
|
|
44395
|
+
const score = propScore ?? numField(row, "score", 0);
|
|
44396
|
+
const level = propLevel ?? numField(row, "level", 1);
|
|
44397
|
+
const entityPlayer = row["player"];
|
|
44398
|
+
const player = propPlayer ?? entityPlayer ?? {
|
|
44399
|
+
x: 80,
|
|
44400
|
+
y: 320,
|
|
44401
|
+
width: 32,
|
|
44402
|
+
height: 48,
|
|
44403
|
+
vx: 0,
|
|
44404
|
+
vy: 0,
|
|
44405
|
+
grounded: false,
|
|
44406
|
+
facingRight: true
|
|
44407
|
+
};
|
|
44408
|
+
const entityPlatforms = Array.isArray(row["platforms"]) ? row["platforms"] : void 0;
|
|
44409
|
+
const platforms = propPlatforms ?? entityPlatforms ?? [
|
|
44410
|
+
{ x: 0, y: 368, width: 800, height: 32, type: "ground" },
|
|
44411
|
+
{ x: 150, y: 280, width: 160, height: 16, type: "platform" },
|
|
44412
|
+
{ x: 420, y: 220, width: 160, height: 16, type: "platform" },
|
|
44413
|
+
{ x: 580, y: 300, width: 80, height: 16, type: "hazard" },
|
|
44414
|
+
{ x: 700, y: 340, width: 64, height: 28, type: "goal" }
|
|
44415
|
+
];
|
|
44416
|
+
const handleRestart = useCallback(() => {
|
|
44417
|
+
if (playAgainEvent) {
|
|
44418
|
+
eventBus.emit(`UI:${playAgainEvent}`, {});
|
|
44419
|
+
}
|
|
44420
|
+
}, [playAgainEvent, eventBus]);
|
|
44421
|
+
const isGameOver = result === "won" || result === "lost";
|
|
44422
|
+
const gameEndEmittedRef = useRef(false);
|
|
44423
|
+
useEffect(() => {
|
|
44424
|
+
if ((result === "won" || result === "lost") && gameEndEvent) {
|
|
44425
|
+
if (!gameEndEmittedRef.current) {
|
|
44426
|
+
gameEndEmittedRef.current = true;
|
|
44427
|
+
eventBus.emit(`UI:${gameEndEvent}`, { result });
|
|
44428
|
+
}
|
|
44429
|
+
} else {
|
|
44430
|
+
gameEndEmittedRef.current = false;
|
|
44431
|
+
}
|
|
44432
|
+
}, [result, gameEndEvent, eventBus]);
|
|
44433
|
+
return /* @__PURE__ */ jsx(
|
|
44434
|
+
VStack,
|
|
44435
|
+
{
|
|
44436
|
+
className: cn("platformer-board relative bg-background", className),
|
|
44437
|
+
gap: "none",
|
|
44438
|
+
children: /* @__PURE__ */ jsxs(Box, { className: "relative", children: [
|
|
44439
|
+
/* @__PURE__ */ jsx(
|
|
44440
|
+
PlatformerCanvas,
|
|
44441
|
+
{
|
|
44442
|
+
player,
|
|
44443
|
+
platforms,
|
|
44444
|
+
worldWidth,
|
|
44445
|
+
worldHeight,
|
|
44446
|
+
canvasWidth,
|
|
44447
|
+
canvasHeight,
|
|
44448
|
+
followCamera: true,
|
|
44449
|
+
bgColor,
|
|
44450
|
+
playerSprite,
|
|
44451
|
+
tileSprites,
|
|
44452
|
+
leftEvent,
|
|
44453
|
+
rightEvent,
|
|
44454
|
+
jumpEvent,
|
|
44455
|
+
stopEvent
|
|
44456
|
+
}
|
|
44457
|
+
),
|
|
44458
|
+
isGameOver && /* @__PURE__ */ jsx(Box, { className: "absolute inset-0 z-50 flex items-center justify-center bg-background/70 backdrop-blur-sm rounded-container", children: /* @__PURE__ */ jsxs(VStack, { className: "text-center p-8", gap: "lg", children: [
|
|
44459
|
+
/* @__PURE__ */ jsx(
|
|
44460
|
+
Typography,
|
|
44461
|
+
{
|
|
44462
|
+
variant: "h2",
|
|
44463
|
+
className: cn(
|
|
44464
|
+
"text-4xl font-black tracking-widest uppercase",
|
|
44465
|
+
result === "won" ? "text-warning" : "text-error"
|
|
44466
|
+
),
|
|
44467
|
+
children: result === "won" ? t("platformer.won") : t("platformer.lost")
|
|
44468
|
+
}
|
|
44469
|
+
),
|
|
44470
|
+
result === "won" && /* @__PURE__ */ jsxs(Typography, { variant: "body1", className: "text-muted-foreground", children: [
|
|
44471
|
+
t("platformer.level"),
|
|
44472
|
+
" ",
|
|
44473
|
+
level,
|
|
44474
|
+
" \u2014 ",
|
|
44475
|
+
t("platformer.score"),
|
|
44476
|
+
": ",
|
|
44477
|
+
score
|
|
44478
|
+
] }),
|
|
44479
|
+
result === "lost" && /* @__PURE__ */ jsx(Typography, { variant: "body1", className: "text-muted-foreground", children: t("platformer.noLives") }),
|
|
44480
|
+
/* @__PURE__ */ jsx(
|
|
44481
|
+
Button,
|
|
44482
|
+
{
|
|
44483
|
+
variant: "primary",
|
|
44484
|
+
className: "px-8 py-3 font-semibold",
|
|
44485
|
+
onClick: handleRestart,
|
|
44486
|
+
children: result === "won" ? t("platformer.nextLevel") : t("platformer.playAgain")
|
|
44487
|
+
}
|
|
44488
|
+
)
|
|
44489
|
+
] }) })
|
|
44490
|
+
] })
|
|
44491
|
+
}
|
|
44492
|
+
);
|
|
44493
|
+
}
|
|
44494
|
+
var init_PlatformerBoard = __esm({
|
|
44495
|
+
"components/game/organisms/PlatformerBoard.tsx"() {
|
|
44496
|
+
"use client";
|
|
44497
|
+
init_cn();
|
|
44498
|
+
init_useEventBus();
|
|
44499
|
+
init_Box();
|
|
44500
|
+
init_Button();
|
|
44501
|
+
init_Typography();
|
|
44502
|
+
init_Stack();
|
|
44503
|
+
init_PlatformerCanvas();
|
|
44504
|
+
PlatformerBoard.displayName = "PlatformerBoard";
|
|
44505
|
+
}
|
|
44506
|
+
});
|
|
44507
|
+
function PlatformerTemplate({
|
|
44508
|
+
entity,
|
|
44509
|
+
platforms = DEFAULT_PLATFORMS,
|
|
44510
|
+
worldWidth = 800,
|
|
44511
|
+
worldHeight = 400,
|
|
44512
|
+
canvasWidth = 800,
|
|
44513
|
+
canvasHeight = 400,
|
|
44514
|
+
playerSprite = `${CDN3}/characters/platformChar_idle.png`,
|
|
44515
|
+
tileSprites = DEFAULT_TILE_SPRITES,
|
|
44516
|
+
bgColor = "#5c94fc",
|
|
44517
|
+
gameEndEvent = "GAME_END",
|
|
44518
|
+
className
|
|
44519
|
+
}) {
|
|
44520
|
+
const row = entity && !Array.isArray(entity) ? entity : void 0;
|
|
44521
|
+
const lives = typeof row?.["lives"] === "number" ? row["lives"] : 3;
|
|
44522
|
+
const score = typeof row?.["score"] === "number" ? row["score"] : 0;
|
|
44523
|
+
const level = typeof row?.["level"] === "number" ? row["level"] : 1;
|
|
44524
|
+
return /* @__PURE__ */ jsxs(VStack, { className: cn("platformer-template w-full", className), gap: "none", children: [
|
|
44525
|
+
/* @__PURE__ */ jsx(Box, { className: "relative", children: /* @__PURE__ */ jsx(
|
|
44526
|
+
GameHud,
|
|
44527
|
+
{
|
|
44528
|
+
position: "top",
|
|
44529
|
+
stats: [
|
|
44530
|
+
{ label: "Lives", value: lives, format: "number", variant: "danger" },
|
|
44531
|
+
{ label: "Level", value: level, format: "number", variant: "default" }
|
|
44532
|
+
]
|
|
44533
|
+
}
|
|
44534
|
+
) }),
|
|
44535
|
+
/* @__PURE__ */ jsx(
|
|
44536
|
+
PlatformerBoard,
|
|
44537
|
+
{
|
|
44538
|
+
entity,
|
|
44539
|
+
platforms,
|
|
44540
|
+
worldWidth,
|
|
44541
|
+
worldHeight,
|
|
44542
|
+
canvasWidth,
|
|
44543
|
+
canvasHeight,
|
|
44544
|
+
playerSprite,
|
|
44545
|
+
tileSprites,
|
|
44546
|
+
bgColor,
|
|
44547
|
+
leftEvent: "LEFT",
|
|
44548
|
+
rightEvent: "RIGHT",
|
|
44549
|
+
jumpEvent: "JUMP",
|
|
44550
|
+
stopEvent: "STOP",
|
|
44551
|
+
playAgainEvent: "PLAY_AGAIN",
|
|
44552
|
+
gameEndEvent
|
|
44553
|
+
}
|
|
44554
|
+
),
|
|
44555
|
+
/* @__PURE__ */ jsx(Box, { className: "px-4 py-2", children: /* @__PURE__ */ jsx(ScoreBoard, { score, level }) })
|
|
44556
|
+
] });
|
|
44557
|
+
}
|
|
44558
|
+
var CDN3, DEFAULT_TILE_SPRITES, DEFAULT_PLATFORMS;
|
|
44559
|
+
var init_PlatformerTemplate = __esm({
|
|
44560
|
+
"components/game/templates/PlatformerTemplate.tsx"() {
|
|
44561
|
+
init_cn();
|
|
44562
|
+
init_Box();
|
|
44563
|
+
init_Stack();
|
|
44564
|
+
init_PlatformerBoard();
|
|
44565
|
+
init_GameHud();
|
|
44566
|
+
init_ScoreBoard();
|
|
44567
|
+
CDN3 = "https://almadar-kflow-assets.web.app/shared/platformer";
|
|
44568
|
+
DEFAULT_TILE_SPRITES = {
|
|
44569
|
+
ground: `${CDN3}/tiles/platformPack_tile001.png`,
|
|
44570
|
+
platform: `${CDN3}/tiles/platformPack_tile004.png`,
|
|
44571
|
+
hazard: `${CDN3}/tiles/platformPack_tile017.png`,
|
|
44572
|
+
goal: `${CDN3}/tiles/platformPack_tile007.png`
|
|
44573
|
+
};
|
|
44574
|
+
DEFAULT_PLATFORMS = [
|
|
44575
|
+
{ x: 0, y: 368, width: 800, height: 32, type: "ground" },
|
|
44576
|
+
{ x: 150, y: 280, width: 160, height: 16, type: "platform" },
|
|
44577
|
+
{ x: 420, y: 220, width: 160, height: 16, type: "platform" },
|
|
44578
|
+
{ x: 580, y: 300, width: 80, height: 16, type: "hazard" },
|
|
44579
|
+
{ x: 700, y: 340, width: 64, height: 28, type: "goal" }
|
|
44580
|
+
];
|
|
44581
|
+
PlatformerTemplate.displayName = "PlatformerTemplate";
|
|
44582
|
+
}
|
|
44583
|
+
});
|
|
42699
44584
|
var PricingOrganism;
|
|
42700
44585
|
var init_PricingOrganism = __esm({
|
|
42701
44586
|
"components/marketing/organisms/PricingOrganism.tsx"() {
|
|
@@ -42818,6 +44703,356 @@ var init_PricingPageTemplate = __esm({
|
|
|
42818
44703
|
PricingPageTemplate.displayName = "PricingPageTemplate";
|
|
42819
44704
|
}
|
|
42820
44705
|
});
|
|
44706
|
+
function RoguelikeBoard({
|
|
44707
|
+
entity,
|
|
44708
|
+
tiles: propTiles,
|
|
44709
|
+
enemies: propEnemies,
|
|
44710
|
+
items: propItems,
|
|
44711
|
+
player: propPlayer,
|
|
44712
|
+
playerHp: propPlayerHp,
|
|
44713
|
+
playerMaxHp: propPlayerMaxHp,
|
|
44714
|
+
playerAttack: propPlayerAttack,
|
|
44715
|
+
depth: propDepth,
|
|
44716
|
+
result: propResult,
|
|
44717
|
+
phase: propPhase,
|
|
44718
|
+
stairsX: propStairsX,
|
|
44719
|
+
stairsY: propStairsY,
|
|
44720
|
+
assetManifest: propAssetManifest,
|
|
44721
|
+
scale = 0.45,
|
|
44722
|
+
unitScale = 1,
|
|
44723
|
+
moveEvent,
|
|
44724
|
+
playAgainEvent,
|
|
44725
|
+
gameEndEvent,
|
|
44726
|
+
className
|
|
44727
|
+
}) {
|
|
44728
|
+
const board = boardEntity(entity) ?? {};
|
|
44729
|
+
const tiles = propTiles ?? (Array.isArray(board.tiles) ? board.tiles : DEFAULT_TILES2);
|
|
44730
|
+
const enemies = propEnemies ?? (Array.isArray(board.enemies) ? board.enemies : DEFAULT_ENEMIES);
|
|
44731
|
+
const items = propItems ?? (Array.isArray(board.items) ? board.items : DEFAULT_ITEMS);
|
|
44732
|
+
const player = propPlayer ?? board.player ?? { x: 1, y: 1 };
|
|
44733
|
+
const playerHp = propPlayerHp ?? num(board.playerHp, 10);
|
|
44734
|
+
const playerMaxHp = propPlayerMaxHp ?? num(board.playerMaxHp, 10);
|
|
44735
|
+
const playerAttack = propPlayerAttack ?? num(board.playerAttack, 3);
|
|
44736
|
+
const depth = propDepth ?? num(board.depth, 1);
|
|
44737
|
+
const result = propResult ?? (str(board.result) || "none");
|
|
44738
|
+
const phase = propPhase ?? (str(board.phase) || "player_turn");
|
|
44739
|
+
propStairsX ?? num(board.stairsX, 3);
|
|
44740
|
+
propStairsY ?? num(board.stairsY, 3);
|
|
44741
|
+
const eventBus = useEventBus();
|
|
44742
|
+
const { t } = useTranslate();
|
|
44743
|
+
const [hoveredTile, setHoveredTile] = useState(null);
|
|
44744
|
+
const emitMove = useCallback((dx, dy) => {
|
|
44745
|
+
if (!moveEvent) return;
|
|
44746
|
+
eventBus.emit(`UI:${moveEvent}`, { dx, dy });
|
|
44747
|
+
}, [moveEvent, eventBus]);
|
|
44748
|
+
useEffect(() => {
|
|
44749
|
+
const handler = (e) => {
|
|
44750
|
+
if (result !== "none" || phase !== "player_turn") return;
|
|
44751
|
+
if (e.key === "ArrowUp" || e.key === "w") emitMove(0, -1);
|
|
44752
|
+
if (e.key === "ArrowDown" || e.key === "s") emitMove(0, 1);
|
|
44753
|
+
if (e.key === "ArrowLeft" || e.key === "a") emitMove(-1, 0);
|
|
44754
|
+
if (e.key === "ArrowRight" || e.key === "d") emitMove(1, 0);
|
|
44755
|
+
};
|
|
44756
|
+
window.addEventListener("keydown", handler);
|
|
44757
|
+
return () => window.removeEventListener("keydown", handler);
|
|
44758
|
+
}, [result, phase, emitMove]);
|
|
44759
|
+
useEffect(() => {
|
|
44760
|
+
if ((result === "won" || result === "lost") && gameEndEvent) {
|
|
44761
|
+
eventBus.emit(`UI:${gameEndEvent}`, { result });
|
|
44762
|
+
}
|
|
44763
|
+
}, [result, gameEndEvent, eventBus]);
|
|
44764
|
+
const handleTileClick = useCallback((x, y) => {
|
|
44765
|
+
if (result !== "none" || phase !== "player_turn") return;
|
|
44766
|
+
const dx = x - player.x;
|
|
44767
|
+
const dy = y - player.y;
|
|
44768
|
+
if (Math.abs(dx) + Math.abs(dy) === 1) {
|
|
44769
|
+
emitMove(dx, dy);
|
|
44770
|
+
}
|
|
44771
|
+
}, [result, phase, player, emitMove]);
|
|
44772
|
+
const handleReset = useCallback(() => {
|
|
44773
|
+
if (!playAgainEvent) return;
|
|
44774
|
+
eventBus.emit(`UI:${playAgainEvent}`, {});
|
|
44775
|
+
}, [playAgainEvent, eventBus]);
|
|
44776
|
+
const isoUnits = useMemo(() => {
|
|
44777
|
+
const liveEnemies = enemies.filter((e) => e.hp > 0);
|
|
44778
|
+
return [
|
|
44779
|
+
{
|
|
44780
|
+
id: "player",
|
|
44781
|
+
position: player,
|
|
44782
|
+
name: t("roguelike.player") || "Hero",
|
|
44783
|
+
team: "player",
|
|
44784
|
+
health: playerHp,
|
|
44785
|
+
maxHealth: playerMaxHp,
|
|
44786
|
+
unitType: "player",
|
|
44787
|
+
sprite: `${CDN4}/isometric-dungeon/Characters/Male/Male_0_Idle0.png`
|
|
44788
|
+
},
|
|
44789
|
+
...liveEnemies.map((e) => ({
|
|
44790
|
+
id: e.id,
|
|
44791
|
+
position: { x: e.x, y: e.y },
|
|
44792
|
+
name: t("roguelike.enemy") || "Enemy",
|
|
44793
|
+
team: "enemy",
|
|
44794
|
+
health: e.hp,
|
|
44795
|
+
maxHealth: 6,
|
|
44796
|
+
unitType: "enemy",
|
|
44797
|
+
sprite: `${CDN4}/sprite-sheets/shadow-legion-sprite-sheet-sw.png`
|
|
44798
|
+
}))
|
|
44799
|
+
];
|
|
44800
|
+
}, [player, enemies, playerHp, playerMaxHp, t]);
|
|
44801
|
+
const isoFeatures = useMemo(
|
|
44802
|
+
() => items.map((it) => ({
|
|
44803
|
+
id: it.id,
|
|
44804
|
+
x: it.x,
|
|
44805
|
+
y: it.y,
|
|
44806
|
+
type: it.kind,
|
|
44807
|
+
sprite: FEATURE_SPRITE[it.kind] ?? FEATURE_SPRITE.health_potion
|
|
44808
|
+
})),
|
|
44809
|
+
[items]
|
|
44810
|
+
);
|
|
44811
|
+
const validMoves = useMemo(() => {
|
|
44812
|
+
if (result !== "none" || phase !== "player_turn") return [];
|
|
44813
|
+
const dirs = [{ dx: 0, dy: -1 }, { dx: 0, dy: 1 }, { dx: -1, dy: 0 }, { dx: 1, dy: 0 }];
|
|
44814
|
+
return dirs.map(({ dx, dy }) => ({ x: player.x + dx, y: player.y + dy })).filter(({ x, y }) => {
|
|
44815
|
+
const tile = tiles.find((t2) => t2.x === x && t2.y === y);
|
|
44816
|
+
return tile?.passable ?? false;
|
|
44817
|
+
});
|
|
44818
|
+
}, [result, phase, player, tiles]);
|
|
44819
|
+
const isGameOver = result === "won" || result === "lost";
|
|
44820
|
+
return /* @__PURE__ */ jsxs(VStack, { className: cn("roguelike-board relative min-h-[600px] bg-background", className), gap: "none", children: [
|
|
44821
|
+
/* @__PURE__ */ jsxs(HStack, { className: "items-center justify-between px-4 py-2 border-b border-border", gap: "md", children: [
|
|
44822
|
+
/* @__PURE__ */ jsxs(HStack, { gap: "sm", className: "items-center", children: [
|
|
44823
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: t("roguelike.depth") || "Depth" }),
|
|
44824
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body1", className: "font-bold tabular-nums", children: depth })
|
|
44825
|
+
] }),
|
|
44826
|
+
/* @__PURE__ */ jsxs(HStack, { gap: "sm", className: "items-center", children: [
|
|
44827
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: t("roguelike.hp") || "HP" }),
|
|
44828
|
+
/* @__PURE__ */ jsxs(
|
|
44829
|
+
Typography,
|
|
44830
|
+
{
|
|
44831
|
+
variant: "body1",
|
|
44832
|
+
className: cn(
|
|
44833
|
+
"font-bold tabular-nums",
|
|
44834
|
+
playerHp <= Math.floor(playerMaxHp * 0.25) ? "text-error" : "text-success"
|
|
44835
|
+
),
|
|
44836
|
+
children: [
|
|
44837
|
+
playerHp,
|
|
44838
|
+
" / ",
|
|
44839
|
+
playerMaxHp
|
|
44840
|
+
]
|
|
44841
|
+
}
|
|
44842
|
+
)
|
|
44843
|
+
] }),
|
|
44844
|
+
/* @__PURE__ */ jsxs(HStack, { gap: "sm", className: "items-center", children: [
|
|
44845
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: t("roguelike.atk") || "ATK" }),
|
|
44846
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body1", className: "font-bold tabular-nums text-foreground", children: playerAttack })
|
|
44847
|
+
] }),
|
|
44848
|
+
/* @__PURE__ */ jsxs(HStack, { gap: "sm", className: "items-center", children: [
|
|
44849
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: t("roguelike.phase") || "Phase" }),
|
|
44850
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body2", className: "capitalize text-foreground", children: phase.replace("_", " ") })
|
|
44851
|
+
] })
|
|
44852
|
+
] }),
|
|
44853
|
+
/* @__PURE__ */ jsx(Box, { className: "relative flex-1", children: /* @__PURE__ */ jsx(
|
|
44854
|
+
IsometricCanvas_default,
|
|
44855
|
+
{
|
|
44856
|
+
tiles,
|
|
44857
|
+
units: isoUnits,
|
|
44858
|
+
features: isoFeatures,
|
|
44859
|
+
selectedUnitId: null,
|
|
44860
|
+
validMoves,
|
|
44861
|
+
attackTargets: [],
|
|
44862
|
+
hoveredTile,
|
|
44863
|
+
onTileClick: handleTileClick,
|
|
44864
|
+
onUnitClick: () => void 0,
|
|
44865
|
+
onTileHover: (x, y) => setHoveredTile({ x, y }),
|
|
44866
|
+
onTileLeave: () => setHoveredTile(null),
|
|
44867
|
+
scale,
|
|
44868
|
+
assetBaseUrl: propAssetManifest?.baseUrl ?? CDN4,
|
|
44869
|
+
assetManifest: propAssetManifest,
|
|
44870
|
+
unitScale
|
|
44871
|
+
}
|
|
44872
|
+
) }),
|
|
44873
|
+
!isGameOver && /* @__PURE__ */ jsx(HStack, { className: "justify-center gap-2 p-3", gap: "none", children: [
|
|
44874
|
+
{ label: "\u2191", dx: 0, dy: -1 },
|
|
44875
|
+
{ label: "\u2193", dx: 0, dy: 1 },
|
|
44876
|
+
{ label: "\u2190", dx: -1, dy: 0 },
|
|
44877
|
+
{ label: "\u2192", dx: 1, dy: 0 }
|
|
44878
|
+
].map(({ label, dx, dy }) => /* @__PURE__ */ jsx(
|
|
44879
|
+
Button,
|
|
44880
|
+
{
|
|
44881
|
+
variant: "secondary",
|
|
44882
|
+
className: "w-9 h-9 p-0 text-base font-mono",
|
|
44883
|
+
onClick: () => emitMove(dx, dy),
|
|
44884
|
+
disabled: phase !== "player_turn",
|
|
44885
|
+
children: label
|
|
44886
|
+
},
|
|
44887
|
+
label
|
|
44888
|
+
)) }),
|
|
44889
|
+
isGameOver && /* @__PURE__ */ jsx(Box, { className: "absolute inset-0 z-50 flex items-center justify-center bg-background/75 backdrop-blur-sm rounded-container", children: /* @__PURE__ */ jsxs(VStack, { className: "text-center p-8", gap: "lg", children: [
|
|
44890
|
+
/* @__PURE__ */ jsx(
|
|
44891
|
+
Typography,
|
|
44892
|
+
{
|
|
44893
|
+
variant: "h2",
|
|
44894
|
+
className: cn(
|
|
44895
|
+
"text-4xl font-black tracking-widest uppercase",
|
|
44896
|
+
result === "won" ? "text-warning" : "text-error"
|
|
44897
|
+
),
|
|
44898
|
+
children: result === "won" ? t("roguelike.victory") || "Victory!" : t("roguelike.defeat") || "Defeated!"
|
|
44899
|
+
}
|
|
44900
|
+
),
|
|
44901
|
+
result === "won" && /* @__PURE__ */ jsx(Typography, { variant: "body1", className: "text-muted-foreground", children: t("roguelike.cleared") || `Dungeon cleared! Depth reached: ${depth}` }),
|
|
44902
|
+
/* @__PURE__ */ jsx(
|
|
44903
|
+
Button,
|
|
44904
|
+
{
|
|
44905
|
+
variant: "primary",
|
|
44906
|
+
className: "px-8 py-3 font-semibold",
|
|
44907
|
+
onClick: handleReset,
|
|
44908
|
+
children: t("roguelike.playAgain") || "Play Again"
|
|
44909
|
+
}
|
|
44910
|
+
)
|
|
44911
|
+
] }) })
|
|
44912
|
+
] });
|
|
44913
|
+
}
|
|
44914
|
+
var CDN4, DEFAULT_TILES2, DEFAULT_ENEMIES, DEFAULT_ITEMS, FEATURE_SPRITE;
|
|
44915
|
+
var init_RoguelikeBoard = __esm({
|
|
44916
|
+
"components/game/organisms/RoguelikeBoard.tsx"() {
|
|
44917
|
+
"use client";
|
|
44918
|
+
init_cn();
|
|
44919
|
+
init_useEventBus();
|
|
44920
|
+
init_Box();
|
|
44921
|
+
init_Button();
|
|
44922
|
+
init_Typography();
|
|
44923
|
+
init_Stack();
|
|
44924
|
+
init_IsometricCanvas();
|
|
44925
|
+
init_boardEntity();
|
|
44926
|
+
CDN4 = "https://almadar-kflow-assets.web.app/shared";
|
|
44927
|
+
DEFAULT_TILES2 = [
|
|
44928
|
+
{ x: 0, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
44929
|
+
{ x: 1, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
44930
|
+
{ x: 2, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
44931
|
+
{ x: 3, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
44932
|
+
{ x: 4, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
44933
|
+
{ x: 0, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
44934
|
+
{ x: 1, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
|
|
44935
|
+
{ x: 2, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
|
|
44936
|
+
{ x: 3, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
|
|
44937
|
+
{ x: 4, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
44938
|
+
{ x: 0, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
44939
|
+
{ x: 1, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png` },
|
|
44940
|
+
{ x: 2, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png` },
|
|
44941
|
+
{ x: 3, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
|
|
44942
|
+
{ x: 4, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
44943
|
+
{ x: 0, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
44944
|
+
{ x: 1, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
|
|
44945
|
+
{ x: 2, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png` },
|
|
44946
|
+
{ x: 3, y: 3, terrain: "stairs", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stairs_E.png` },
|
|
44947
|
+
{ x: 4, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
44948
|
+
{ x: 0, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
44949
|
+
{ x: 1, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
44950
|
+
{ x: 2, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
44951
|
+
{ x: 3, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
44952
|
+
{ x: 4, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` }
|
|
44953
|
+
];
|
|
44954
|
+
DEFAULT_ENEMIES = [
|
|
44955
|
+
{ id: "e1", x: 3, y: 1, hp: 5, attack: 2 },
|
|
44956
|
+
{ id: "e2", x: 1, y: 3, hp: 4, attack: 1 }
|
|
44957
|
+
];
|
|
44958
|
+
DEFAULT_ITEMS = [
|
|
44959
|
+
{ id: "i1", x: 2, y: 2, kind: "health_potion" }
|
|
44960
|
+
];
|
|
44961
|
+
FEATURE_SPRITE = {
|
|
44962
|
+
health_potion: `${CDN4}/isometric-dungeon/Isometric/chestClosed_E.png`,
|
|
44963
|
+
sword: `${CDN4}/isometric-dungeon/Isometric/barrel_E.png`,
|
|
44964
|
+
shield: `${CDN4}/isometric-dungeon/Isometric/barrel_E.png`
|
|
44965
|
+
};
|
|
44966
|
+
RoguelikeBoard.displayName = "RoguelikeBoard";
|
|
44967
|
+
}
|
|
44968
|
+
});
|
|
44969
|
+
function RoguelikeTemplate({
|
|
44970
|
+
entity,
|
|
44971
|
+
scale = 0.45,
|
|
44972
|
+
unitScale = 1,
|
|
44973
|
+
tiles = DEFAULT_ROGUELIKE_TILES,
|
|
44974
|
+
enemies,
|
|
44975
|
+
items,
|
|
44976
|
+
stairsX,
|
|
44977
|
+
stairsY,
|
|
44978
|
+
assetManifest = DEFAULT_ROGUELIKE_MANIFEST,
|
|
44979
|
+
gameEndEvent,
|
|
44980
|
+
className
|
|
44981
|
+
}) {
|
|
44982
|
+
const resolved = entity && typeof entity === "object" && !Array.isArray(entity) ? entity : void 0;
|
|
44983
|
+
if (!resolved && !tiles && !assetManifest) return null;
|
|
44984
|
+
return /* @__PURE__ */ jsx(
|
|
44985
|
+
RoguelikeBoard,
|
|
44986
|
+
{
|
|
44987
|
+
entity: resolved,
|
|
44988
|
+
tiles,
|
|
44989
|
+
enemies,
|
|
44990
|
+
items,
|
|
44991
|
+
stairsX,
|
|
44992
|
+
stairsY,
|
|
44993
|
+
assetManifest,
|
|
44994
|
+
scale,
|
|
44995
|
+
unitScale,
|
|
44996
|
+
moveEvent: "MOVE",
|
|
44997
|
+
playAgainEvent: "PLAY_AGAIN",
|
|
44998
|
+
gameEndEvent: gameEndEvent ?? "GAME_END",
|
|
44999
|
+
className
|
|
45000
|
+
}
|
|
45001
|
+
);
|
|
45002
|
+
}
|
|
45003
|
+
var CDN5, DEFAULT_ROGUELIKE_TILES, DEFAULT_ROGUELIKE_MANIFEST;
|
|
45004
|
+
var init_RoguelikeTemplate = __esm({
|
|
45005
|
+
"components/game/templates/RoguelikeTemplate.tsx"() {
|
|
45006
|
+
init_RoguelikeBoard();
|
|
45007
|
+
CDN5 = "https://almadar-kflow-assets.web.app/shared";
|
|
45008
|
+
DEFAULT_ROGUELIKE_TILES = [
|
|
45009
|
+
{ x: 0, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45010
|
+
{ x: 1, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45011
|
+
{ x: 2, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45012
|
+
{ x: 3, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45013
|
+
{ x: 4, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45014
|
+
{ x: 0, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45015
|
+
{ x: 1, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirt_E.png` },
|
|
45016
|
+
{ x: 2, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirt_E.png` },
|
|
45017
|
+
{ x: 3, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirt_E.png` },
|
|
45018
|
+
{ x: 4, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45019
|
+
{ x: 0, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45020
|
+
{ x: 1, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirtTiles_E.png` },
|
|
45021
|
+
{ x: 2, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirtTiles_E.png` },
|
|
45022
|
+
{ x: 3, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirt_E.png` },
|
|
45023
|
+
{ x: 4, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45024
|
+
{ x: 0, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45025
|
+
{ x: 1, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirt_E.png` },
|
|
45026
|
+
{ x: 2, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirtTiles_E.png` },
|
|
45027
|
+
{ x: 3, y: 3, terrain: "stairs", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stairs_E.png` },
|
|
45028
|
+
{ x: 4, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45029
|
+
{ x: 0, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45030
|
+
{ x: 1, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45031
|
+
{ x: 2, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45032
|
+
{ x: 3, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45033
|
+
{ x: 4, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` }
|
|
45034
|
+
];
|
|
45035
|
+
DEFAULT_ROGUELIKE_MANIFEST = {
|
|
45036
|
+
baseUrl: CDN5,
|
|
45037
|
+
terrains: {
|
|
45038
|
+
floor: "/isometric-dungeon/Isometric/dirt_E.png",
|
|
45039
|
+
wall: "/isometric-dungeon/Isometric/stoneInset_E.png",
|
|
45040
|
+
stairs: "/isometric-dungeon/Isometric/stairs_E.png",
|
|
45041
|
+
planks: "/isometric-dungeon/Isometric/planks_E.png"
|
|
45042
|
+
},
|
|
45043
|
+
units: {
|
|
45044
|
+
player: "/isometric-dungeon/Characters/Male/Male_0_Idle0.png",
|
|
45045
|
+
enemy: "/sprite-sheets/shadow-legion-sprite-sheet-sw.png"
|
|
45046
|
+
},
|
|
45047
|
+
features: {
|
|
45048
|
+
health_potion: "/isometric-dungeon/Isometric/chestClosed_E.png",
|
|
45049
|
+
sword: "/isometric-dungeon/Isometric/barrel_E.png",
|
|
45050
|
+
shield: "/isometric-dungeon/Isometric/barrel_E.png"
|
|
45051
|
+
}
|
|
45052
|
+
};
|
|
45053
|
+
RoguelikeTemplate.displayName = "RoguelikeTemplate";
|
|
45054
|
+
}
|
|
45055
|
+
});
|
|
42821
45056
|
|
|
42822
45057
|
// lib/traitRegistry.ts
|
|
42823
45058
|
function getAllTraits() {
|
|
@@ -44052,7 +46287,7 @@ function getAllEvents(traits2) {
|
|
|
44052
46287
|
function EventDispatcherTab({ traits: traits2, schema }) {
|
|
44053
46288
|
const eventBus = useEventBus();
|
|
44054
46289
|
const { t } = useTranslate();
|
|
44055
|
-
const [
|
|
46290
|
+
const [log14, setLog] = React83.useState([]);
|
|
44056
46291
|
const prevStatesRef = React83.useRef(/* @__PURE__ */ new Map());
|
|
44057
46292
|
React83.useEffect(() => {
|
|
44058
46293
|
for (const trait of traits2) {
|
|
@@ -44116,9 +46351,9 @@ function EventDispatcherTab({ traits: traits2, schema }) {
|
|
|
44116
46351
|
/* @__PURE__ */ jsx(Typography, { variant: "small", weight: "medium", className: "text-gray-500 mb-1", children: t("debug.otherEvents") }),
|
|
44117
46352
|
/* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1", children: unavailableEvents.map((event) => /* @__PURE__ */ jsx(Badge, { variant: "default", size: "sm", className: "opacity-50", children: event }, event)) })
|
|
44118
46353
|
] }),
|
|
44119
|
-
|
|
46354
|
+
log14.length > 0 && /* @__PURE__ */ jsxs("div", { children: [
|
|
44120
46355
|
/* @__PURE__ */ jsx(Typography, { variant: "small", weight: "medium", className: "text-gray-500 mb-1", children: t("debug.recentTransitions") }),
|
|
44121
|
-
/* @__PURE__ */ jsx(Stack, { gap: "xs", children:
|
|
46356
|
+
/* @__PURE__ */ jsx(Stack, { gap: "xs", children: log14.map((entry, i) => /* @__PURE__ */ jsxs(Typography, { variant: "small", className: "font-mono text-xs", children: [
|
|
44122
46357
|
/* @__PURE__ */ jsx("span", { className: "text-purple-400", children: entry.traitName }),
|
|
44123
46358
|
" ",
|
|
44124
46359
|
/* @__PURE__ */ jsx("span", { className: "text-gray-500", children: entry.from }),
|
|
@@ -46039,9 +48274,9 @@ function VariablePanel({
|
|
|
46039
48274
|
/* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-muted-foreground font-medium", children: t("stateArchitect.variables", { name: entityName }) }),
|
|
46040
48275
|
variables.map((v) => {
|
|
46041
48276
|
const name = v.name == null ? "" : String(v.name);
|
|
46042
|
-
const value =
|
|
46043
|
-
const max =
|
|
46044
|
-
const min =
|
|
48277
|
+
const value = numField2(v.value);
|
|
48278
|
+
const max = numField2(v.max, 100);
|
|
48279
|
+
const min = numField2(v.min, 0);
|
|
46045
48280
|
const unit = v.unit == null ? "" : String(v.unit);
|
|
46046
48281
|
const pct = Math.round((value - min) / (max - min) * 100);
|
|
46047
48282
|
const isHigh = pct > 80;
|
|
@@ -46071,12 +48306,12 @@ function VariablePanel({
|
|
|
46071
48306
|
})
|
|
46072
48307
|
] });
|
|
46073
48308
|
}
|
|
46074
|
-
var
|
|
48309
|
+
var numField2;
|
|
46075
48310
|
var init_VariablePanel = __esm({
|
|
46076
48311
|
"components/game/organisms/puzzles/state-architect/VariablePanel.tsx"() {
|
|
46077
48312
|
init_atoms2();
|
|
46078
48313
|
init_cn();
|
|
46079
|
-
|
|
48314
|
+
numField2 = (v, fallback = 0) => {
|
|
46080
48315
|
const n = Number(v);
|
|
46081
48316
|
return Number.isFinite(n) ? n : fallback;
|
|
46082
48317
|
};
|
|
@@ -46929,6 +49164,289 @@ var init_ToastSlot = __esm({
|
|
|
46929
49164
|
ToastSlot.displayName = "ToastSlot";
|
|
46930
49165
|
}
|
|
46931
49166
|
});
|
|
49167
|
+
function tilesToIso(tiles) {
|
|
49168
|
+
return tiles.map((t) => ({
|
|
49169
|
+
x: t.x,
|
|
49170
|
+
y: t.y,
|
|
49171
|
+
terrain: t.terrain,
|
|
49172
|
+
terrainSprite: t.terrainSprite ?? TERRAIN_SPRITES[t.terrain ?? "ground"],
|
|
49173
|
+
passable: t.passable
|
|
49174
|
+
}));
|
|
49175
|
+
}
|
|
49176
|
+
function towersToUnits(towers) {
|
|
49177
|
+
return towers.map((t) => ({
|
|
49178
|
+
id: t.id,
|
|
49179
|
+
position: { x: t.x, y: t.y },
|
|
49180
|
+
name: "Tower",
|
|
49181
|
+
team: "player",
|
|
49182
|
+
sprite: TOWER_SPRITE,
|
|
49183
|
+
unitType: "guardian",
|
|
49184
|
+
health: 1,
|
|
49185
|
+
maxHealth: 1
|
|
49186
|
+
}));
|
|
49187
|
+
}
|
|
49188
|
+
function creepsToUnits(creeps) {
|
|
49189
|
+
return creeps.map((c) => ({
|
|
49190
|
+
id: c.id,
|
|
49191
|
+
position: { x: c.x, y: c.y },
|
|
49192
|
+
name: "Creep",
|
|
49193
|
+
team: "enemy",
|
|
49194
|
+
sprite: CREEP_SPRITE,
|
|
49195
|
+
unitType: "scrapper",
|
|
49196
|
+
health: c.hp,
|
|
49197
|
+
maxHealth: c.maxHp
|
|
49198
|
+
}));
|
|
49199
|
+
}
|
|
49200
|
+
function pathToFeatures(path) {
|
|
49201
|
+
return path.map((p2, i) => ({
|
|
49202
|
+
id: `path-${i}`,
|
|
49203
|
+
x: p2.x,
|
|
49204
|
+
y: p2.y,
|
|
49205
|
+
type: "path-marker",
|
|
49206
|
+
sprite: `${CDN6}world-map/road_straight.png`
|
|
49207
|
+
}));
|
|
49208
|
+
}
|
|
49209
|
+
function TowerDefenseBoard({
|
|
49210
|
+
entity,
|
|
49211
|
+
tiles: propTiles,
|
|
49212
|
+
path: propPath,
|
|
49213
|
+
towers: propTowers,
|
|
49214
|
+
creeps: propCreeps,
|
|
49215
|
+
gold: propGold,
|
|
49216
|
+
lives: propLives,
|
|
49217
|
+
wave: propWave,
|
|
49218
|
+
maxWaves: propMaxWaves,
|
|
49219
|
+
result: propResult,
|
|
49220
|
+
waveActive: propWaveActive,
|
|
49221
|
+
towerCost = 25,
|
|
49222
|
+
scale = 0.45,
|
|
49223
|
+
placeTowerEvent,
|
|
49224
|
+
startWaveEvent,
|
|
49225
|
+
playAgainEvent,
|
|
49226
|
+
gameEndEvent,
|
|
49227
|
+
className
|
|
49228
|
+
}) {
|
|
49229
|
+
const board = boardEntity(entity) ?? {};
|
|
49230
|
+
const eventBus = useEventBus();
|
|
49231
|
+
const { t } = useTranslate();
|
|
49232
|
+
const tiles = propTiles ?? rows(board.tiles);
|
|
49233
|
+
const path = propPath ?? rows(board.path);
|
|
49234
|
+
const towers = propTowers ?? rows(board.towers);
|
|
49235
|
+
const creeps = propCreeps ?? rows(board.creeps);
|
|
49236
|
+
const gold = propGold ?? num(board.gold, 100);
|
|
49237
|
+
const lives = propLives ?? num(board.lives, 20);
|
|
49238
|
+
const wave = propWave ?? num(board.wave, 1);
|
|
49239
|
+
const maxWaves = propMaxWaves ?? num(board.maxWaves, 5);
|
|
49240
|
+
const result = propResult ?? (str(board.result) || "none");
|
|
49241
|
+
const waveActive = propWaveActive ?? Boolean(board.waveActive);
|
|
49242
|
+
const [hoveredTile, setHoveredTile] = useState(null);
|
|
49243
|
+
const emittedGameEnd = useRef(false);
|
|
49244
|
+
if (result !== "none" && !emittedGameEnd.current) {
|
|
49245
|
+
emittedGameEnd.current = true;
|
|
49246
|
+
if (gameEndEvent) {
|
|
49247
|
+
eventBus.emit(`UI:${gameEndEvent}`, { result });
|
|
49248
|
+
}
|
|
49249
|
+
}
|
|
49250
|
+
if (result === "none") {
|
|
49251
|
+
emittedGameEnd.current = false;
|
|
49252
|
+
}
|
|
49253
|
+
const towerPositions = useMemo(() => new Set(towers.map((t2) => `${t2.x},${t2.y}`)), [towers]);
|
|
49254
|
+
const pathPositions = useMemo(() => new Set(path.map((p2) => `${p2.x},${p2.y}`)), [path]);
|
|
49255
|
+
const validMoves = useMemo(() => {
|
|
49256
|
+
if (result !== "none" || gold < towerCost) return [];
|
|
49257
|
+
return tiles.filter(
|
|
49258
|
+
(t2) => t2.passable !== false && !towerPositions.has(`${t2.x},${t2.y}`) && !pathPositions.has(`${t2.x},${t2.y}`)
|
|
49259
|
+
).map((t2) => ({ x: t2.x, y: t2.y }));
|
|
49260
|
+
}, [tiles, towerPositions, pathPositions, result, gold, towerCost]);
|
|
49261
|
+
const isoTiles = useMemo(() => tilesToIso(tiles), [tiles]);
|
|
49262
|
+
const towerUnits = useMemo(() => towersToUnits(towers), [towers]);
|
|
49263
|
+
const creepUnits = useMemo(() => creepsToUnits(creeps), [creeps]);
|
|
49264
|
+
const isoUnits = useMemo(() => [...towerUnits, ...creepUnits], [towerUnits, creepUnits]);
|
|
49265
|
+
const pathFeatures = useMemo(() => pathToFeatures(path), [path]);
|
|
49266
|
+
const handleTileClick = useCallback((x, y) => {
|
|
49267
|
+
if (result !== "none") return;
|
|
49268
|
+
if (pathPositions.has(`${x},${y}`)) return;
|
|
49269
|
+
if (towerPositions.has(`${x},${y}`)) return;
|
|
49270
|
+
if (gold < towerCost) return;
|
|
49271
|
+
if (placeTowerEvent) {
|
|
49272
|
+
eventBus.emit(`UI:${placeTowerEvent}`, { x, y });
|
|
49273
|
+
}
|
|
49274
|
+
}, [result, pathPositions, towerPositions, gold, towerCost, placeTowerEvent, eventBus]);
|
|
49275
|
+
const handleStartWave = useCallback(() => {
|
|
49276
|
+
if (startWaveEvent) {
|
|
49277
|
+
eventBus.emit(`UI:${startWaveEvent}`, { wave });
|
|
49278
|
+
}
|
|
49279
|
+
}, [startWaveEvent, wave, eventBus]);
|
|
49280
|
+
const handlePlayAgain = useCallback(() => {
|
|
49281
|
+
if (playAgainEvent) {
|
|
49282
|
+
eventBus.emit(`UI:${playAgainEvent}`, {});
|
|
49283
|
+
}
|
|
49284
|
+
}, [playAgainEvent, eventBus]);
|
|
49285
|
+
const canPlaceTower = gold >= towerCost && result === "none";
|
|
49286
|
+
const canStartWave = !waveActive && result === "none";
|
|
49287
|
+
return /* @__PURE__ */ jsxs(VStack, { className: cn("tower-defense-board relative min-h-[600px] bg-background", className), gap: "none", children: [
|
|
49288
|
+
/* @__PURE__ */ jsxs(
|
|
49289
|
+
HStack,
|
|
49290
|
+
{
|
|
49291
|
+
className: "px-4 py-2 border-b border-border bg-surface",
|
|
49292
|
+
gap: "lg",
|
|
49293
|
+
align: "center",
|
|
49294
|
+
children: [
|
|
49295
|
+
/* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
|
|
49296
|
+
/* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", children: t("td.gold") ?? "Gold" }),
|
|
49297
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body2", weight: "bold", className: "text-warning", children: gold })
|
|
49298
|
+
] }),
|
|
49299
|
+
/* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
|
|
49300
|
+
/* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", children: t("td.lives") ?? "Lives" }),
|
|
49301
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body2", weight: "bold", className: lives <= 5 ? "text-error" : "text-success", children: lives })
|
|
49302
|
+
] }),
|
|
49303
|
+
/* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
|
|
49304
|
+
/* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", children: t("td.wave") ?? "Wave" }),
|
|
49305
|
+
/* @__PURE__ */ jsxs(Typography, { variant: "body2", weight: "bold", children: [
|
|
49306
|
+
wave,
|
|
49307
|
+
" / ",
|
|
49308
|
+
maxWaves
|
|
49309
|
+
] })
|
|
49310
|
+
] }),
|
|
49311
|
+
/* @__PURE__ */ jsxs(Box, { className: "ml-auto", children: [
|
|
49312
|
+
canStartWave && /* @__PURE__ */ jsx(Button, { variant: "primary", size: "sm", onClick: handleStartWave, children: t("td.startWave") ?? "Start Wave" }),
|
|
49313
|
+
waveActive && /* @__PURE__ */ jsx(Typography, { variant: "small", className: "text-warning animate-pulse", children: t("td.waveInProgress") ?? "Wave in progress\u2026" })
|
|
49314
|
+
] })
|
|
49315
|
+
]
|
|
49316
|
+
}
|
|
49317
|
+
),
|
|
49318
|
+
/* @__PURE__ */ jsxs(Box, { className: "relative flex-1", children: [
|
|
49319
|
+
/* @__PURE__ */ jsx(
|
|
49320
|
+
IsometricCanvas_default,
|
|
49321
|
+
{
|
|
49322
|
+
tiles: isoTiles,
|
|
49323
|
+
units: isoUnits,
|
|
49324
|
+
features: pathFeatures,
|
|
49325
|
+
validMoves,
|
|
49326
|
+
hoveredTile,
|
|
49327
|
+
onTileClick: handleTileClick,
|
|
49328
|
+
onTileHover: (x, y) => setHoveredTile({ x, y }),
|
|
49329
|
+
onTileLeave: () => setHoveredTile(null),
|
|
49330
|
+
scale
|
|
49331
|
+
}
|
|
49332
|
+
),
|
|
49333
|
+
hoveredTile && canPlaceTower && validMoves.some((m) => m.x === hoveredTile.x && m.y === hoveredTile.y) && /* @__PURE__ */ jsx(Box, { className: "absolute bottom-4 left-1/2 -translate-x-1/2 z-10 bg-background/80 rounded px-3 py-1 backdrop-blur-sm pointer-events-none", children: /* @__PURE__ */ jsx(Typography, { variant: "small", children: t("td.placeTower") ?? `Place tower (${towerCost} gold)` }) })
|
|
49334
|
+
] }),
|
|
49335
|
+
result !== "none" && /* @__PURE__ */ jsx(Box, { className: "absolute inset-0 z-50 flex items-center justify-center bg-background/70 backdrop-blur-sm", children: /* @__PURE__ */ jsxs(VStack, { className: "text-center p-8", gap: "lg", children: [
|
|
49336
|
+
/* @__PURE__ */ jsx(
|
|
49337
|
+
Typography,
|
|
49338
|
+
{
|
|
49339
|
+
variant: "h2",
|
|
49340
|
+
className: cn(
|
|
49341
|
+
"text-4xl font-black tracking-widest uppercase",
|
|
49342
|
+
result === "won" ? "text-warning" : "text-error"
|
|
49343
|
+
),
|
|
49344
|
+
children: result === "won" ? t("td.victory") ?? "Victory!" : t("td.defeat") ?? "Defeat!"
|
|
49345
|
+
}
|
|
49346
|
+
),
|
|
49347
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body1", className: "text-muted-foreground", children: result === "won" ? t("td.survivedAllWaves") ?? `Survived all ${maxWaves} waves!` : t("td.livesReachedZero") ?? "Your base was overrun." }),
|
|
49348
|
+
/* @__PURE__ */ jsx(
|
|
49349
|
+
Button,
|
|
49350
|
+
{
|
|
49351
|
+
variant: "primary",
|
|
49352
|
+
className: "px-8 py-3 font-semibold",
|
|
49353
|
+
onClick: handlePlayAgain,
|
|
49354
|
+
children: t("td.playAgain") ?? "Play Again"
|
|
49355
|
+
}
|
|
49356
|
+
)
|
|
49357
|
+
] }) })
|
|
49358
|
+
] });
|
|
49359
|
+
}
|
|
49360
|
+
var CDN6, TERRAIN_SPRITES, TOWER_SPRITE, CREEP_SPRITE;
|
|
49361
|
+
var init_TowerDefenseBoard = __esm({
|
|
49362
|
+
"components/game/organisms/TowerDefenseBoard.tsx"() {
|
|
49363
|
+
"use client";
|
|
49364
|
+
init_cn();
|
|
49365
|
+
init_useEventBus();
|
|
49366
|
+
init_Box();
|
|
49367
|
+
init_Button();
|
|
49368
|
+
init_Typography();
|
|
49369
|
+
init_Stack();
|
|
49370
|
+
init_IsometricCanvas();
|
|
49371
|
+
init_boardEntity();
|
|
49372
|
+
CDN6 = "https://almadar-kflow-assets.web.app/shared/";
|
|
49373
|
+
TERRAIN_SPRITES = {
|
|
49374
|
+
ground: `${CDN6}isometric-blocks/PNG/Platformer tiles/platformerTile_01.png`,
|
|
49375
|
+
path: `${CDN6}isometric-blocks/PNG/Platformer tiles/platformerTile_09.png`,
|
|
49376
|
+
wall: `${CDN6}isometric-blocks/PNG/Platformer tiles/platformerTile_05.png`
|
|
49377
|
+
};
|
|
49378
|
+
TOWER_SPRITE = `${CDN6}units/guardian.png`;
|
|
49379
|
+
CREEP_SPRITE = `${CDN6}units/scrapper.png`;
|
|
49380
|
+
TowerDefenseBoard.displayName = "TowerDefenseBoard";
|
|
49381
|
+
}
|
|
49382
|
+
});
|
|
49383
|
+
function TowerDefenseTemplate({
|
|
49384
|
+
entity,
|
|
49385
|
+
title = "Tower Defense",
|
|
49386
|
+
tiles,
|
|
49387
|
+
path,
|
|
49388
|
+
towers,
|
|
49389
|
+
gold,
|
|
49390
|
+
lives,
|
|
49391
|
+
maxWaves,
|
|
49392
|
+
towerCost,
|
|
49393
|
+
scale,
|
|
49394
|
+
placeTowerEvent,
|
|
49395
|
+
startWaveEvent,
|
|
49396
|
+
playAgainEvent,
|
|
49397
|
+
gameEndEvent,
|
|
49398
|
+
className
|
|
49399
|
+
}) {
|
|
49400
|
+
const resolved = entity && typeof entity === "object" && !Array.isArray(entity) ? entity : void 0;
|
|
49401
|
+
return /* @__PURE__ */ jsxs(
|
|
49402
|
+
Box,
|
|
49403
|
+
{
|
|
49404
|
+
display: "flex",
|
|
49405
|
+
fullHeight: true,
|
|
49406
|
+
className: cn("tower-defense-template flex-col", className),
|
|
49407
|
+
children: [
|
|
49408
|
+
/* @__PURE__ */ jsx(
|
|
49409
|
+
HStack,
|
|
49410
|
+
{
|
|
49411
|
+
gap: "sm",
|
|
49412
|
+
align: "center",
|
|
49413
|
+
className: "px-4 py-3 border-b-2 border-border bg-surface shrink-0",
|
|
49414
|
+
children: /* @__PURE__ */ jsx(Typography, { variant: "h4", children: title })
|
|
49415
|
+
}
|
|
49416
|
+
),
|
|
49417
|
+
/* @__PURE__ */ jsx(Box, { className: "flex-1 relative overflow-hidden", children: /* @__PURE__ */ jsx(
|
|
49418
|
+
TowerDefenseBoard,
|
|
49419
|
+
{
|
|
49420
|
+
entity: resolved,
|
|
49421
|
+
tiles,
|
|
49422
|
+
path,
|
|
49423
|
+
towers,
|
|
49424
|
+
gold,
|
|
49425
|
+
lives,
|
|
49426
|
+
maxWaves,
|
|
49427
|
+
towerCost,
|
|
49428
|
+
scale,
|
|
49429
|
+
placeTowerEvent,
|
|
49430
|
+
startWaveEvent,
|
|
49431
|
+
playAgainEvent,
|
|
49432
|
+
gameEndEvent,
|
|
49433
|
+
className: "h-full"
|
|
49434
|
+
}
|
|
49435
|
+
) })
|
|
49436
|
+
]
|
|
49437
|
+
}
|
|
49438
|
+
);
|
|
49439
|
+
}
|
|
49440
|
+
var init_TowerDefenseTemplate = __esm({
|
|
49441
|
+
"components/game/templates/TowerDefenseTemplate.tsx"() {
|
|
49442
|
+
init_cn();
|
|
49443
|
+
init_Box();
|
|
49444
|
+
init_Stack();
|
|
49445
|
+
init_Typography();
|
|
49446
|
+
init_TowerDefenseBoard();
|
|
49447
|
+
TowerDefenseTemplate.displayName = "TowerDefenseTemplate";
|
|
49448
|
+
}
|
|
49449
|
+
});
|
|
46932
49450
|
function useBattleState(initialUnits, eventConfig = {}, callbacks = {}) {
|
|
46933
49451
|
const eventBus = useEventBus();
|
|
46934
49452
|
const {
|
|
@@ -47438,48 +49956,48 @@ function WorldMapTemplate({
|
|
|
47438
49956
|
}
|
|
47439
49957
|
);
|
|
47440
49958
|
}
|
|
47441
|
-
var
|
|
49959
|
+
var CDN7, DEFAULT_WORLDMAP_TILES, DEFAULT_WORLDMAP_UNITS, DEFAULT_WORLDMAP_FEATURES, DEFAULT_WORLDMAP_MANIFEST;
|
|
47442
49960
|
var init_WorldMapTemplate = __esm({
|
|
47443
49961
|
"components/game/templates/WorldMapTemplate.tsx"() {
|
|
47444
49962
|
init_WorldMapBoard();
|
|
47445
|
-
|
|
49963
|
+
CDN7 = "https://almadar-kflow-assets.web.app/shared";
|
|
47446
49964
|
DEFAULT_WORLDMAP_TILES = [
|
|
47447
|
-
{ x: 0, y: 0, terrain: "mountain", passable: false, terrainSprite: `${
|
|
47448
|
-
{ x: 1, y: 0, terrain: "mountain", passable: false, terrainSprite: `${
|
|
47449
|
-
{ x: 2, y: 0, terrain: "water", passable: false, terrainSprite: `${
|
|
47450
|
-
{ x: 3, y: 0, terrain: "mountain", passable: false, terrainSprite: `${
|
|
47451
|
-
{ x: 4, y: 0, terrain: "mountain", passable: false, terrainSprite: `${
|
|
47452
|
-
{ x: 0, y: 1, terrain: "mountain", passable: false, terrainSprite: `${
|
|
47453
|
-
{ x: 1, y: 1, terrain: "grass", passable: true, terrainSprite: `${
|
|
47454
|
-
{ x: 2, y: 1, terrain: "grass", passable: true, terrainSprite: `${
|
|
47455
|
-
{ x: 3, y: 1, terrain: "grass", passable: true, terrainSprite: `${
|
|
47456
|
-
{ x: 4, y: 1, terrain: "water", passable: false, terrainSprite: `${
|
|
47457
|
-
{ x: 0, y: 2, terrain: "water", passable: false, terrainSprite: `${
|
|
47458
|
-
{ x: 1, y: 2, terrain: "grass", passable: true, terrainSprite: `${
|
|
47459
|
-
{ x: 2, y: 2, terrain: "grass", passable: true, terrainSprite: `${
|
|
47460
|
-
{ x: 3, y: 2, terrain: "grass", passable: true, terrainSprite: `${
|
|
47461
|
-
{ x: 4, y: 2, terrain: "mountain", passable: false, terrainSprite: `${
|
|
47462
|
-
{ x: 0, y: 3, terrain: "mountain", passable: false, terrainSprite: `${
|
|
47463
|
-
{ x: 1, y: 3, terrain: "grass", passable: true, terrainSprite: `${
|
|
47464
|
-
{ x: 2, y: 3, terrain: "grass", passable: true, terrainSprite: `${
|
|
47465
|
-
{ x: 3, y: 3, terrain: "grass", passable: true, terrainSprite: `${
|
|
47466
|
-
{ x: 4, y: 3, terrain: "mountain", passable: false, terrainSprite: `${
|
|
47467
|
-
{ x: 0, y: 4, terrain: "mountain", passable: false, terrainSprite: `${
|
|
47468
|
-
{ x: 1, y: 4, terrain: "water", passable: false, terrainSprite: `${
|
|
47469
|
-
{ x: 2, y: 4, terrain: "grass", passable: true, terrainSprite: `${
|
|
47470
|
-
{ x: 3, y: 4, terrain: "mountain", passable: false, terrainSprite: `${
|
|
47471
|
-
{ x: 4, y: 4, terrain: "mountain", passable: false, terrainSprite: `${
|
|
49965
|
+
{ x: 0, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
|
|
49966
|
+
{ x: 1, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
|
|
49967
|
+
{ x: 2, y: 0, terrain: "water", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
|
|
49968
|
+
{ x: 3, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
|
|
49969
|
+
{ x: 4, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
|
|
49970
|
+
{ x: 0, y: 1, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
|
|
49971
|
+
{ x: 1, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
|
|
49972
|
+
{ x: 2, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
|
|
49973
|
+
{ x: 3, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
|
|
49974
|
+
{ x: 4, y: 1, terrain: "water", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
|
|
49975
|
+
{ x: 0, y: 2, terrain: "water", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
|
|
49976
|
+
{ x: 1, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
|
|
49977
|
+
{ x: 2, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_03.png` },
|
|
49978
|
+
{ x: 3, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
|
|
49979
|
+
{ x: 4, y: 2, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
|
|
49980
|
+
{ x: 0, y: 3, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
|
|
49981
|
+
{ x: 1, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
|
|
49982
|
+
{ x: 2, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
|
|
49983
|
+
{ x: 3, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_03.png` },
|
|
49984
|
+
{ x: 4, y: 3, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
|
|
49985
|
+
{ x: 0, y: 4, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
|
|
49986
|
+
{ x: 1, y: 4, terrain: "water", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
|
|
49987
|
+
{ x: 2, y: 4, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
|
|
49988
|
+
{ x: 3, y: 4, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
|
|
49989
|
+
{ x: 4, y: 4, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` }
|
|
47472
49990
|
];
|
|
47473
49991
|
DEFAULT_WORLDMAP_UNITS = [
|
|
47474
|
-
{ id: "h1", position: { x: 1, y: 1 }, unitType: "hero", name: "Amir", team: "player", health: 10, maxHealth: 10, sprite: `${
|
|
47475
|
-
{ id: "h2", position: { x: 3, y: 3 }, unitType: "scout", name: "Archivist", team: "player", health: 10, maxHealth: 10, sprite: `${
|
|
49992
|
+
{ id: "h1", position: { x: 1, y: 1 }, unitType: "hero", name: "Amir", team: "player", health: 10, maxHealth: 10, sprite: `${CDN7}/sprite-sheets/amir-sprite-sheet-se.png` },
|
|
49993
|
+
{ id: "h2", position: { x: 3, y: 3 }, unitType: "scout", name: "Archivist", team: "player", health: 10, maxHealth: 10, sprite: `${CDN7}/sprite-sheets/archivist-sprite-sheet-se.png` }
|
|
47476
49994
|
];
|
|
47477
49995
|
DEFAULT_WORLDMAP_FEATURES = [
|
|
47478
|
-
{ id: "f1", x: 2, y: 2, type: "capital", sprite: `${
|
|
47479
|
-
{ id: "f2", x: 4, y: 2, type: "power_node", sprite: `${
|
|
49996
|
+
{ id: "f1", x: 2, y: 2, type: "capital", sprite: `${CDN7}/scenes/world/capital.png` },
|
|
49997
|
+
{ id: "f2", x: 4, y: 2, type: "power_node", sprite: `${CDN7}/world-map/power_node.png` }
|
|
47480
49998
|
];
|
|
47481
49999
|
DEFAULT_WORLDMAP_MANIFEST = {
|
|
47482
|
-
baseUrl:
|
|
50000
|
+
baseUrl: CDN7,
|
|
47483
50001
|
terrains: {
|
|
47484
50002
|
grass: "/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png",
|
|
47485
50003
|
water: "/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png",
|
|
@@ -47524,7 +50042,7 @@ function lazyThree(name, loader) {
|
|
|
47524
50042
|
ThreeWrapper.displayName = `Lazy(${name})`;
|
|
47525
50043
|
return ThreeWrapper;
|
|
47526
50044
|
}
|
|
47527
|
-
var ThreeBoundary, FeatureRenderer,
|
|
50045
|
+
var ThreeBoundary, FeatureRenderer, GameCanvas3D2, GameCanvas3DBattleTemplate, GameCanvas3DCastleTemplate, GameCanvas3DWorldMapTemplate, COMPONENT_REGISTRY;
|
|
47528
50046
|
var init_component_registry_generated = __esm({
|
|
47529
50047
|
"components/core/organisms/component-registry.generated.ts"() {
|
|
47530
50048
|
init_AboutPageTemplate();
|
|
@@ -47634,6 +50152,7 @@ var init_component_registry_generated = __esm({
|
|
|
47634
50152
|
init_FormSectionHeader();
|
|
47635
50153
|
init_GameAudioProvider();
|
|
47636
50154
|
init_GameAudioToggle();
|
|
50155
|
+
init_GameBoard3D();
|
|
47637
50156
|
init_GameCanvas2D();
|
|
47638
50157
|
init_GameHud();
|
|
47639
50158
|
init_GameMenu();
|
|
@@ -47691,7 +50210,9 @@ var init_component_registry_generated = __esm({
|
|
|
47691
50210
|
init_PageHeader();
|
|
47692
50211
|
init_Pagination();
|
|
47693
50212
|
init_PatternTile();
|
|
50213
|
+
init_PlatformerBoard();
|
|
47694
50214
|
init_PlatformerCanvas();
|
|
50215
|
+
init_PlatformerTemplate();
|
|
47695
50216
|
init_Popover();
|
|
47696
50217
|
init_PositionedCanvas();
|
|
47697
50218
|
init_PowerupSlots();
|
|
@@ -47715,6 +50236,8 @@ var init_component_registry_generated = __esm({
|
|
|
47715
50236
|
init_ResourceBar();
|
|
47716
50237
|
init_ResourceCounter();
|
|
47717
50238
|
init_RichBlockEditor();
|
|
50239
|
+
init_RoguelikeBoard();
|
|
50240
|
+
init_RoguelikeTemplate();
|
|
47718
50241
|
init_RuntimeDebugger2();
|
|
47719
50242
|
init_ScaledDiagram();
|
|
47720
50243
|
init_ScoreBoard();
|
|
@@ -47787,6 +50310,8 @@ var init_component_registry_generated = __esm({
|
|
|
47787
50310
|
init_Toast();
|
|
47788
50311
|
init_ToastSlot();
|
|
47789
50312
|
init_Tooltip();
|
|
50313
|
+
init_TowerDefenseBoard();
|
|
50314
|
+
init_TowerDefenseTemplate();
|
|
47790
50315
|
init_TraitFrame();
|
|
47791
50316
|
init_TraitSlot();
|
|
47792
50317
|
init_TrendIndicator();
|
|
@@ -47831,7 +50356,7 @@ var init_component_registry_generated = __esm({
|
|
|
47831
50356
|
}
|
|
47832
50357
|
};
|
|
47833
50358
|
FeatureRenderer = lazyThree("FeatureRenderer", () => import('@almadar/ui/components/molecules/game/three'));
|
|
47834
|
-
|
|
50359
|
+
GameCanvas3D2 = lazyThree("GameCanvas3D", () => import('@almadar/ui/components/molecules/game/three'));
|
|
47835
50360
|
GameCanvas3DBattleTemplate = lazyThree("GameCanvas3DBattleTemplate", () => import('@almadar/ui/components/molecules/game/three'));
|
|
47836
50361
|
GameCanvas3DCastleTemplate = lazyThree("GameCanvas3DCastleTemplate", () => import('@almadar/ui/components/molecules/game/three'));
|
|
47837
50362
|
GameCanvas3DWorldMapTemplate = lazyThree("GameCanvas3DWorldMapTemplate", () => import('@almadar/ui/components/molecules/game/three'));
|
|
@@ -47950,8 +50475,9 @@ var init_component_registry_generated = __esm({
|
|
|
47950
50475
|
"FormSectionHeader": FormSectionHeader,
|
|
47951
50476
|
"GameAudioProvider": GameAudioProvider,
|
|
47952
50477
|
"GameAudioToggle": GameAudioToggle,
|
|
50478
|
+
"GameBoard3D": GameBoard3D,
|
|
47953
50479
|
"GameCanvas2D": GameCanvas2D,
|
|
47954
|
-
"GameCanvas3D":
|
|
50480
|
+
"GameCanvas3D": GameCanvas3D2,
|
|
47955
50481
|
"GameCanvas3DBattleTemplate": GameCanvas3DBattleTemplate,
|
|
47956
50482
|
"GameCanvas3DCastleTemplate": GameCanvas3DCastleTemplate,
|
|
47957
50483
|
"GameCanvas3DWorldMapTemplate": GameCanvas3DWorldMapTemplate,
|
|
@@ -48013,7 +50539,9 @@ var init_component_registry_generated = __esm({
|
|
|
48013
50539
|
"PageHeader": PageHeader,
|
|
48014
50540
|
"Pagination": Pagination,
|
|
48015
50541
|
"PatternTile": PatternTile,
|
|
50542
|
+
"PlatformerBoard": PlatformerBoard,
|
|
48016
50543
|
"PlatformerCanvas": PlatformerCanvas,
|
|
50544
|
+
"PlatformerTemplate": PlatformerTemplate,
|
|
48017
50545
|
"Popover": Popover,
|
|
48018
50546
|
"PositionedCanvas": PositionedCanvas,
|
|
48019
50547
|
"PowerupSlots": PowerupSlots,
|
|
@@ -48037,6 +50565,8 @@ var init_component_registry_generated = __esm({
|
|
|
48037
50565
|
"ResourceBar": ResourceBar,
|
|
48038
50566
|
"ResourceCounter": ResourceCounter,
|
|
48039
50567
|
"RichBlockEditor": RichBlockEditor,
|
|
50568
|
+
"RoguelikeBoard": RoguelikeBoard,
|
|
50569
|
+
"RoguelikeTemplate": RoguelikeTemplate,
|
|
48040
50570
|
"RuntimeDebugger": RuntimeDebugger,
|
|
48041
50571
|
"ScaledDiagram": ScaledDiagram,
|
|
48042
50572
|
"ScoreBoard": ScoreBoard,
|
|
@@ -48112,6 +50642,8 @@ var init_component_registry_generated = __esm({
|
|
|
48112
50642
|
"Toast": Toast,
|
|
48113
50643
|
"ToastSlot": ToastSlot,
|
|
48114
50644
|
"Tooltip": Tooltip,
|
|
50645
|
+
"TowerDefenseBoard": TowerDefenseBoard,
|
|
50646
|
+
"TowerDefenseTemplate": TowerDefenseTemplate,
|
|
48115
50647
|
"TraitFrame": TraitFrame,
|
|
48116
50648
|
"TraitSlot": TraitSlot,
|
|
48117
50649
|
"TrendIndicator": TrendIndicator,
|
|
@@ -49283,7 +51815,7 @@ init_UISlotRenderer();
|
|
|
49283
51815
|
// providers/VerificationProvider.tsx
|
|
49284
51816
|
init_useEventBus();
|
|
49285
51817
|
init_verificationRegistry();
|
|
49286
|
-
var
|
|
51818
|
+
var log13 = createLogger("almadar:verify");
|
|
49287
51819
|
var DISPATCH_SUFFIX = ":DISPATCH";
|
|
49288
51820
|
var SUCCESS_SUFFIX = ":SUCCESS";
|
|
49289
51821
|
var ERROR_SUFFIX = ":ERROR";
|
|
@@ -49330,7 +51862,7 @@ function VerificationProvider({
|
|
|
49330
51862
|
const verificationProviderLifecycleListener = (evt) => {
|
|
49331
51863
|
const parsed = parseLifecycleEvent(evt.type);
|
|
49332
51864
|
if (!parsed) return;
|
|
49333
|
-
|
|
51865
|
+
log13.debug("lifecycle:event", { kind: parsed.kind, traitName: parsed.traitName, event: parsed.event, type: evt.type });
|
|
49334
51866
|
const payload = evt.payload ?? {};
|
|
49335
51867
|
if (parsed.kind === "dispatch") {
|
|
49336
51868
|
const key = `${parsed.traitName}:${String(payload["event"] ?? "")}`;
|
|
@@ -49385,7 +51917,7 @@ function VerificationProvider({
|
|
|
49385
51917
|
},
|
|
49386
51918
|
timestamp: Date.now()
|
|
49387
51919
|
});
|
|
49388
|
-
|
|
51920
|
+
log13.debug("transition:success", { trait: parsed.traitName, event: parsed.event, from: pending?.from, to: newState, effectCount: effects.length });
|
|
49389
51921
|
} else if (parsed.kind === "error" && parsed.event) {
|
|
49390
51922
|
const key = `${parsed.traitName}:${parsed.event}`;
|
|
49391
51923
|
const pending = pendingRef.current.get(key);
|
|
@@ -49415,7 +51947,7 @@ function VerificationProvider({
|
|
|
49415
51947
|
},
|
|
49416
51948
|
timestamp: Date.now()
|
|
49417
51949
|
});
|
|
49418
|
-
|
|
51950
|
+
log13.warn("transition:error", { trait: parsed.traitName, event: parsed.event, from: fromState, error: errorMsg });
|
|
49419
51951
|
}
|
|
49420
51952
|
};
|
|
49421
51953
|
Object.defineProperty(verificationProviderLifecycleListener, "name", {
|