@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.cjs
CHANGED
|
@@ -41,6 +41,12 @@ var core$1 = require('@dnd-kit/core');
|
|
|
41
41
|
var sortable = require('@dnd-kit/sortable');
|
|
42
42
|
var utilities = require('@dnd-kit/utilities');
|
|
43
43
|
var react = require('@xyflow/react');
|
|
44
|
+
var THREE = require('three');
|
|
45
|
+
var GLTFLoader_js = require('three/examples/jsm/loaders/GLTFLoader.js');
|
|
46
|
+
var OBJLoader_js = require('three/examples/jsm/loaders/OBJLoader.js');
|
|
47
|
+
var GLTFLoader = require('three/examples/jsm/loaders/GLTFLoader');
|
|
48
|
+
var fiber = require('@react-three/fiber');
|
|
49
|
+
var drei = require('@react-three/drei');
|
|
44
50
|
var patterns = require('@almadar/patterns');
|
|
45
51
|
|
|
46
52
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
@@ -88,6 +94,7 @@ var ReactMarkdown__default = /*#__PURE__*/_interopDefault(ReactMarkdown);
|
|
|
88
94
|
var remarkGfm__default = /*#__PURE__*/_interopDefault(remarkGfm);
|
|
89
95
|
var remarkMath__default = /*#__PURE__*/_interopDefault(remarkMath);
|
|
90
96
|
var rehypeKatex__default = /*#__PURE__*/_interopDefault(rehypeKatex);
|
|
97
|
+
var THREE__namespace = /*#__PURE__*/_interopNamespace(THREE);
|
|
91
98
|
|
|
92
99
|
var __defProp = Object.defineProperty;
|
|
93
100
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
@@ -719,7 +726,7 @@ var init_Box = __esm({
|
|
|
719
726
|
position,
|
|
720
727
|
className,
|
|
721
728
|
children,
|
|
722
|
-
as:
|
|
729
|
+
as: Component2 = "div",
|
|
723
730
|
action,
|
|
724
731
|
actionPayload,
|
|
725
732
|
hoverEvent,
|
|
@@ -751,7 +758,7 @@ var init_Box = __esm({
|
|
|
751
758
|
}, [hoverEvent, eventBus, onMouseLeave]);
|
|
752
759
|
const isClickable = action || onClick;
|
|
753
760
|
return React83__namespace.default.createElement(
|
|
754
|
-
|
|
761
|
+
Component2,
|
|
755
762
|
{
|
|
756
763
|
ref,
|
|
757
764
|
className: cn(
|
|
@@ -889,9 +896,9 @@ function resolvePhosphor(name, weight, family) {
|
|
|
889
896
|
(lib) => {
|
|
890
897
|
const PhosphorComp = lib[target];
|
|
891
898
|
if (!PhosphorComp || typeof PhosphorComp !== "object") return null;
|
|
892
|
-
const
|
|
899
|
+
const Component2 = PhosphorComp;
|
|
893
900
|
const Adapter = (props) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
894
|
-
|
|
901
|
+
Component2,
|
|
895
902
|
{
|
|
896
903
|
weight,
|
|
897
904
|
className: props.className,
|
|
@@ -915,9 +922,9 @@ function resolveTabler(name, family) {
|
|
|
915
922
|
(lib) => {
|
|
916
923
|
const TablerComp = lib[target];
|
|
917
924
|
if (!TablerComp || typeof TablerComp !== "object") return null;
|
|
918
|
-
const
|
|
925
|
+
const Component2 = TablerComp;
|
|
919
926
|
const Adapter = (props) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
920
|
-
|
|
927
|
+
Component2,
|
|
921
928
|
{
|
|
922
929
|
stroke: props.strokeWidth ?? 1.5,
|
|
923
930
|
className: props.className,
|
|
@@ -941,9 +948,9 @@ function resolveFa(name, family) {
|
|
|
941
948
|
(lib) => {
|
|
942
949
|
const FaComp = lib[target];
|
|
943
950
|
if (!FaComp || typeof FaComp !== "function") return null;
|
|
944
|
-
const
|
|
951
|
+
const Component2 = FaComp;
|
|
945
952
|
const Adapter = (props) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
946
|
-
|
|
953
|
+
Component2,
|
|
947
954
|
{
|
|
948
955
|
className: props.className,
|
|
949
956
|
style: props.style,
|
|
@@ -1898,8 +1905,8 @@ var init_Typography = __esm({
|
|
|
1898
1905
|
children
|
|
1899
1906
|
}) => {
|
|
1900
1907
|
const variant = variantProp ?? (level ? `h${level}` : "body1");
|
|
1901
|
-
const
|
|
1902
|
-
const Comp =
|
|
1908
|
+
const Component2 = as || defaultElements[variant];
|
|
1909
|
+
const Comp = Component2;
|
|
1903
1910
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1904
1911
|
Comp,
|
|
1905
1912
|
{
|
|
@@ -4454,10 +4461,10 @@ var init_Center = __esm({
|
|
|
4454
4461
|
className,
|
|
4455
4462
|
style,
|
|
4456
4463
|
children,
|
|
4457
|
-
as:
|
|
4464
|
+
as: Component2 = "div"
|
|
4458
4465
|
}) => {
|
|
4459
4466
|
const mergedStyle = minHeight ? { minHeight, ...style } : style;
|
|
4460
|
-
const Comp =
|
|
4467
|
+
const Comp = Component2;
|
|
4461
4468
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
4462
4469
|
Comp,
|
|
4463
4470
|
{
|
|
@@ -5088,7 +5095,7 @@ var init_Stack = __esm({
|
|
|
5088
5095
|
className,
|
|
5089
5096
|
style,
|
|
5090
5097
|
children,
|
|
5091
|
-
as:
|
|
5098
|
+
as: Component2 = "div",
|
|
5092
5099
|
onClick,
|
|
5093
5100
|
onKeyDown,
|
|
5094
5101
|
role,
|
|
@@ -5106,7 +5113,7 @@ var init_Stack = __esm({
|
|
|
5106
5113
|
};
|
|
5107
5114
|
const isHorizontal = direction === "horizontal";
|
|
5108
5115
|
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";
|
|
5109
|
-
const Comp =
|
|
5116
|
+
const Comp = Component2;
|
|
5110
5117
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
5111
5118
|
Comp,
|
|
5112
5119
|
{
|
|
@@ -7162,6 +7169,7 @@ var init_HealthBar = __esm({
|
|
|
7162
7169
|
}
|
|
7163
7170
|
});
|
|
7164
7171
|
function ScoreDisplay({
|
|
7172
|
+
assetUrl = DEFAULT_ASSET_URL,
|
|
7165
7173
|
value,
|
|
7166
7174
|
label,
|
|
7167
7175
|
icon,
|
|
@@ -7208,14 +7216,24 @@ function ScoreDisplay({
|
|
|
7208
7216
|
className
|
|
7209
7217
|
),
|
|
7210
7218
|
children: [
|
|
7211
|
-
|
|
7219
|
+
assetUrl ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
7220
|
+
"img",
|
|
7221
|
+
{
|
|
7222
|
+
src: assetUrl,
|
|
7223
|
+
alt: "",
|
|
7224
|
+
width: 20,
|
|
7225
|
+
height: 20,
|
|
7226
|
+
style: { imageRendering: "pixelated", objectFit: "contain" },
|
|
7227
|
+
className: "flex-shrink-0"
|
|
7228
|
+
}
|
|
7229
|
+
) : icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-shrink-0", children: typeof icon === "string" ? /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: icon }) : /* @__PURE__ */ jsxRuntime.jsx(Icon, { icon }) }) : null,
|
|
7212
7230
|
label && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: label }),
|
|
7213
7231
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "tabular-nums", children: formattedValue })
|
|
7214
7232
|
]
|
|
7215
7233
|
}
|
|
7216
7234
|
);
|
|
7217
7235
|
}
|
|
7218
|
-
var sizeMap2;
|
|
7236
|
+
var sizeMap2, DEFAULT_ASSET_URL;
|
|
7219
7237
|
var init_ScoreDisplay = __esm({
|
|
7220
7238
|
"components/game/atoms/ScoreDisplay.tsx"() {
|
|
7221
7239
|
"use client";
|
|
@@ -7227,10 +7245,12 @@ var init_ScoreDisplay = __esm({
|
|
|
7227
7245
|
lg: "text-2xl",
|
|
7228
7246
|
xl: "text-4xl"
|
|
7229
7247
|
};
|
|
7248
|
+
DEFAULT_ASSET_URL = "https://almadar-kflow-assets.web.app/shared/effects/particles/star_01.png";
|
|
7230
7249
|
ScoreDisplay.displayName = "ScoreDisplay";
|
|
7231
7250
|
}
|
|
7232
7251
|
});
|
|
7233
7252
|
function ControlButton({
|
|
7253
|
+
assetUrl = DEFAULT_ASSET_URL2,
|
|
7234
7254
|
label,
|
|
7235
7255
|
icon,
|
|
7236
7256
|
size = "md",
|
|
@@ -7277,7 +7297,7 @@ function ControlButton({
|
|
|
7277
7297
|
},
|
|
7278
7298
|
[isPressed, releaseEvent, eventBus, onRelease]
|
|
7279
7299
|
);
|
|
7280
|
-
return /* @__PURE__ */ jsxRuntime.
|
|
7300
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
7281
7301
|
"button",
|
|
7282
7302
|
{
|
|
7283
7303
|
type: "button",
|
|
@@ -7298,20 +7318,27 @@ function ControlButton({
|
|
|
7298
7318
|
disabled && "opacity-50 cursor-not-allowed",
|
|
7299
7319
|
className
|
|
7300
7320
|
),
|
|
7301
|
-
children:
|
|
7302
|
-
|
|
7303
|
-
|
|
7304
|
-
|
|
7305
|
-
|
|
7306
|
-
|
|
7307
|
-
|
|
7308
|
-
|
|
7309
|
-
|
|
7310
|
-
|
|
7321
|
+
children: assetUrl ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
7322
|
+
"img",
|
|
7323
|
+
{
|
|
7324
|
+
src: assetUrl,
|
|
7325
|
+
alt: "",
|
|
7326
|
+
width: 24,
|
|
7327
|
+
height: 24,
|
|
7328
|
+
style: { imageRendering: "pixelated", objectFit: "contain" },
|
|
7329
|
+
className: "flex-shrink-0"
|
|
7330
|
+
}
|
|
7331
|
+
) : icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-2xl", children: typeof icon === "string" ? /^[a-zA-Z0-9-]+$/.test(icon) ? (() => {
|
|
7332
|
+
const I = resolveIcon(icon);
|
|
7333
|
+
return I ? /* @__PURE__ */ jsxRuntime.jsx(I, { className: "w-6 h-6" }) : null;
|
|
7334
|
+
})() : icon : /* @__PURE__ */ (() => {
|
|
7335
|
+
const I = icon;
|
|
7336
|
+
return /* @__PURE__ */ jsxRuntime.jsx(I, { className: "w-6 h-6" });
|
|
7337
|
+
})() }) : label ? /* @__PURE__ */ jsxRuntime.jsx("span", { children: label }) : null
|
|
7311
7338
|
}
|
|
7312
7339
|
);
|
|
7313
7340
|
}
|
|
7314
|
-
var sizeMap3, shapeMap, variantMap;
|
|
7341
|
+
var sizeMap3, shapeMap, variantMap, DEFAULT_ASSET_URL2;
|
|
7315
7342
|
var init_ControlButton = __esm({
|
|
7316
7343
|
"components/game/atoms/ControlButton.tsx"() {
|
|
7317
7344
|
"use client";
|
|
@@ -7334,6 +7361,7 @@ var init_ControlButton = __esm({
|
|
|
7334
7361
|
secondary: "bg-secondary text-secondary-foreground border-border hover:bg-secondary-hover",
|
|
7335
7362
|
ghost: "bg-transparent text-foreground border-border hover:bg-muted"
|
|
7336
7363
|
};
|
|
7364
|
+
DEFAULT_ASSET_URL2 = "https://almadar-kflow-assets.web.app/shared/effects/particles/circle_01.png";
|
|
7337
7365
|
ControlButton.displayName = "ControlButton";
|
|
7338
7366
|
}
|
|
7339
7367
|
});
|
|
@@ -7413,7 +7441,7 @@ var init_Sprite = __esm({
|
|
|
7413
7441
|
}
|
|
7414
7442
|
});
|
|
7415
7443
|
function StateIndicator({
|
|
7416
|
-
assetUrl =
|
|
7444
|
+
assetUrl = DEFAULT_ASSET_URL3,
|
|
7417
7445
|
state = "idle",
|
|
7418
7446
|
label,
|
|
7419
7447
|
size = "md",
|
|
@@ -7452,13 +7480,13 @@ function StateIndicator({
|
|
|
7452
7480
|
}
|
|
7453
7481
|
);
|
|
7454
7482
|
}
|
|
7455
|
-
var
|
|
7483
|
+
var DEFAULT_ASSET_URL3, DEFAULT_STATE_STYLES, DEFAULT_STYLE, SIZE_CLASSES;
|
|
7456
7484
|
var init_StateIndicator = __esm({
|
|
7457
7485
|
"components/game/atoms/StateIndicator.tsx"() {
|
|
7458
7486
|
init_Box();
|
|
7459
7487
|
init_Icon();
|
|
7460
7488
|
init_cn();
|
|
7461
|
-
|
|
7489
|
+
DEFAULT_ASSET_URL3 = "https://almadar-kflow-assets.web.app/shared/isometric-dungeon/Isometric/chestClosed_E.png";
|
|
7462
7490
|
DEFAULT_STATE_STYLES = {
|
|
7463
7491
|
idle: { icon: "\u23F8", bgClass: "bg-muted" },
|
|
7464
7492
|
active: { icon: "\u25B6", bgClass: "bg-success" },
|
|
@@ -7533,7 +7561,7 @@ var init_TimerDisplay = __esm({
|
|
|
7533
7561
|
}
|
|
7534
7562
|
});
|
|
7535
7563
|
function ResourceCounter({
|
|
7536
|
-
assetUrl =
|
|
7564
|
+
assetUrl = DEFAULT_ASSET_URL4,
|
|
7537
7565
|
icon,
|
|
7538
7566
|
label = "Gold",
|
|
7539
7567
|
value = 250,
|
|
@@ -7576,7 +7604,7 @@ function ResourceCounter({
|
|
|
7576
7604
|
}
|
|
7577
7605
|
);
|
|
7578
7606
|
}
|
|
7579
|
-
var colorTokenClasses2,
|
|
7607
|
+
var colorTokenClasses2, DEFAULT_ASSET_URL4, sizeMap5;
|
|
7580
7608
|
var init_ResourceCounter = __esm({
|
|
7581
7609
|
"components/game/atoms/ResourceCounter.tsx"() {
|
|
7582
7610
|
init_cn();
|
|
@@ -7589,7 +7617,7 @@ var init_ResourceCounter = __esm({
|
|
|
7589
7617
|
error: "text-error",
|
|
7590
7618
|
muted: "text-muted-foreground"
|
|
7591
7619
|
};
|
|
7592
|
-
|
|
7620
|
+
DEFAULT_ASSET_URL4 = "https://almadar-kflow-assets.web.app/shared/world-map/gold_mine.png";
|
|
7593
7621
|
sizeMap5 = {
|
|
7594
7622
|
sm: { wrapper: "text-xs gap-1 px-1.5 py-0.5", icon: "text-sm", img: 16 },
|
|
7595
7623
|
md: { wrapper: "text-sm gap-1.5 px-2 py-1", icon: "text-base", img: 20 },
|
|
@@ -7599,7 +7627,7 @@ var init_ResourceCounter = __esm({
|
|
|
7599
7627
|
}
|
|
7600
7628
|
});
|
|
7601
7629
|
function ItemSlot({
|
|
7602
|
-
assetUrl =
|
|
7630
|
+
assetUrl = DEFAULT_ASSET_URL5,
|
|
7603
7631
|
icon = "sword",
|
|
7604
7632
|
label = "Iron Sword",
|
|
7605
7633
|
quantity,
|
|
@@ -7658,7 +7686,7 @@ function ItemSlot({
|
|
|
7658
7686
|
}
|
|
7659
7687
|
);
|
|
7660
7688
|
}
|
|
7661
|
-
var sizeMap6, rarityBorderMap, rarityGlowMap,
|
|
7689
|
+
var sizeMap6, rarityBorderMap, rarityGlowMap, DEFAULT_ASSET_URL5, assetSizeMap;
|
|
7662
7690
|
var init_ItemSlot = __esm({
|
|
7663
7691
|
"components/game/atoms/ItemSlot.tsx"() {
|
|
7664
7692
|
"use client";
|
|
@@ -7683,7 +7711,7 @@ var init_ItemSlot = __esm({
|
|
|
7683
7711
|
epic: "shadow-lg",
|
|
7684
7712
|
legendary: "shadow-lg"
|
|
7685
7713
|
};
|
|
7686
|
-
|
|
7714
|
+
DEFAULT_ASSET_URL5 = "https://almadar-kflow-assets.web.app/shared/isometric-dungeon/Isometric/chestClosed_E.png";
|
|
7687
7715
|
assetSizeMap = {
|
|
7688
7716
|
sm: 28,
|
|
7689
7717
|
md: 40,
|
|
@@ -7693,6 +7721,7 @@ var init_ItemSlot = __esm({
|
|
|
7693
7721
|
}
|
|
7694
7722
|
});
|
|
7695
7723
|
function TurnIndicator({
|
|
7724
|
+
assetUrl = DEFAULT_ASSET_URL6,
|
|
7696
7725
|
currentTurn = 1,
|
|
7697
7726
|
maxTurns,
|
|
7698
7727
|
activeTeam,
|
|
@@ -7725,14 +7754,24 @@ function TurnIndicator({
|
|
|
7725
7754
|
] }),
|
|
7726
7755
|
activeTeam && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
7727
7756
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "|" }),
|
|
7728
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7757
|
+
assetUrl ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
7758
|
+
"img",
|
|
7759
|
+
{
|
|
7760
|
+
src: assetUrl,
|
|
7761
|
+
alt: "",
|
|
7762
|
+
width: 12,
|
|
7763
|
+
height: 12,
|
|
7764
|
+
style: { imageRendering: "pixelated", objectFit: "contain" },
|
|
7765
|
+
className: "flex-shrink-0"
|
|
7766
|
+
}
|
|
7767
|
+
) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("rounded-full bg-success/20", sizes.dot) }),
|
|
7729
7768
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-success", children: activeTeam })
|
|
7730
7769
|
] })
|
|
7731
7770
|
]
|
|
7732
7771
|
}
|
|
7733
7772
|
);
|
|
7734
7773
|
}
|
|
7735
|
-
var sizeMap7;
|
|
7774
|
+
var sizeMap7, DEFAULT_ASSET_URL6;
|
|
7736
7775
|
var init_TurnIndicator = __esm({
|
|
7737
7776
|
"components/game/atoms/TurnIndicator.tsx"() {
|
|
7738
7777
|
init_cn();
|
|
@@ -7741,6 +7780,7 @@ var init_TurnIndicator = __esm({
|
|
|
7741
7780
|
md: { wrapper: "text-sm gap-2 px-3 py-1", dot: "w-2 h-2" },
|
|
7742
7781
|
lg: { wrapper: "text-base gap-2.5 px-4 py-1.5", dot: "w-2.5 h-2.5" }
|
|
7743
7782
|
};
|
|
7783
|
+
DEFAULT_ASSET_URL6 = "https://almadar-kflow-assets.web.app/shared/effects/particles/symbol_01.png";
|
|
7744
7784
|
TurnIndicator.displayName = "TurnIndicator";
|
|
7745
7785
|
}
|
|
7746
7786
|
});
|
|
@@ -7756,7 +7796,7 @@ function getComboScale(combo) {
|
|
|
7756
7796
|
return "";
|
|
7757
7797
|
}
|
|
7758
7798
|
function ComboCounter({
|
|
7759
|
-
assetUrl =
|
|
7799
|
+
assetUrl = DEFAULT_ASSET_URL7,
|
|
7760
7800
|
combo = 5,
|
|
7761
7801
|
multiplier,
|
|
7762
7802
|
streak,
|
|
@@ -7801,11 +7841,11 @@ function ComboCounter({
|
|
|
7801
7841
|
}
|
|
7802
7842
|
);
|
|
7803
7843
|
}
|
|
7804
|
-
var
|
|
7844
|
+
var DEFAULT_ASSET_URL7, sizeMap8;
|
|
7805
7845
|
var init_ComboCounter = __esm({
|
|
7806
7846
|
"components/game/atoms/ComboCounter.tsx"() {
|
|
7807
7847
|
init_cn();
|
|
7808
|
-
|
|
7848
|
+
DEFAULT_ASSET_URL7 = "https://almadar-kflow-assets.web.app/shared/effects/flash/flash00.png";
|
|
7809
7849
|
sizeMap8 = {
|
|
7810
7850
|
sm: { combo: "text-lg", label: "text-xs", multiplier: "text-xs" },
|
|
7811
7851
|
md: { combo: "text-2xl", label: "text-xs", multiplier: "text-sm" },
|
|
@@ -7899,7 +7939,7 @@ var init_XPBar = __esm({
|
|
|
7899
7939
|
}
|
|
7900
7940
|
});
|
|
7901
7941
|
function WaypointMarker({
|
|
7902
|
-
assetUrl =
|
|
7942
|
+
assetUrl = DEFAULT_ASSET_URL8,
|
|
7903
7943
|
label,
|
|
7904
7944
|
icon,
|
|
7905
7945
|
active = true,
|
|
@@ -7965,12 +8005,12 @@ function WaypointMarker({
|
|
|
7965
8005
|
)
|
|
7966
8006
|
] });
|
|
7967
8007
|
}
|
|
7968
|
-
var
|
|
8008
|
+
var DEFAULT_ASSET_URL8, sizeMap10, checkIcon;
|
|
7969
8009
|
var init_WaypointMarker = __esm({
|
|
7970
8010
|
"components/game/atoms/WaypointMarker.tsx"() {
|
|
7971
8011
|
init_cn();
|
|
7972
8012
|
init_Icon();
|
|
7973
|
-
|
|
8013
|
+
DEFAULT_ASSET_URL8 = "https://almadar-kflow-assets.web.app/shared/world-map/battle_marker.png";
|
|
7974
8014
|
sizeMap10 = {
|
|
7975
8015
|
sm: { dot: "w-4 h-4", ring: "w-6 h-6", label: "text-xs mt-1", img: 12 },
|
|
7976
8016
|
md: { dot: "w-6 h-6", ring: "w-8 h-8", label: "text-sm mt-1.5", img: 18 },
|
|
@@ -7987,7 +8027,7 @@ function formatDuration(seconds) {
|
|
|
7987
8027
|
return `${Math.round(seconds)}s`;
|
|
7988
8028
|
}
|
|
7989
8029
|
function StatusEffect({
|
|
7990
|
-
assetUrl =
|
|
8030
|
+
assetUrl = DEFAULT_ASSET_URL9,
|
|
7991
8031
|
icon = "shield",
|
|
7992
8032
|
label = "Shield",
|
|
7993
8033
|
duration = 30,
|
|
@@ -8045,12 +8085,12 @@ function StatusEffect({
|
|
|
8045
8085
|
label && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground mt-0.5 text-center whitespace-nowrap", children: label })
|
|
8046
8086
|
] });
|
|
8047
8087
|
}
|
|
8048
|
-
var
|
|
8088
|
+
var DEFAULT_ASSET_URL9, sizeMap11, variantStyles7;
|
|
8049
8089
|
var init_StatusEffect = __esm({
|
|
8050
8090
|
"components/game/atoms/StatusEffect.tsx"() {
|
|
8051
8091
|
init_cn();
|
|
8052
8092
|
init_Icon();
|
|
8053
|
-
|
|
8093
|
+
DEFAULT_ASSET_URL9 = "https://almadar-kflow-assets.web.app/shared/effects/particles/flame_01.png";
|
|
8054
8094
|
sizeMap11 = {
|
|
8055
8095
|
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 },
|
|
8056
8096
|
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 },
|
|
@@ -8065,6 +8105,7 @@ var init_StatusEffect = __esm({
|
|
|
8065
8105
|
}
|
|
8066
8106
|
});
|
|
8067
8107
|
function DamageNumber({
|
|
8108
|
+
assetUrl = DEFAULT_ASSET_URL10,
|
|
8068
8109
|
value = 42,
|
|
8069
8110
|
type = "damage",
|
|
8070
8111
|
size = "md",
|
|
@@ -8073,22 +8114,35 @@ function DamageNumber({
|
|
|
8073
8114
|
const displayText = type === "miss" ? "MISS" : type === "heal" ? `+${value}` : `${value}`;
|
|
8074
8115
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
8075
8116
|
/* @__PURE__ */ jsxRuntime.jsx("style", { children: floatKeyframes }),
|
|
8076
|
-
/* @__PURE__ */ jsxRuntime.
|
|
8117
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
8077
8118
|
"span",
|
|
8078
8119
|
{
|
|
8079
8120
|
className: cn(
|
|
8080
|
-
"inline-
|
|
8121
|
+
"inline-flex items-center gap-0.5 font-mono select-none pointer-events-none",
|
|
8081
8122
|
sizeMap12[size],
|
|
8082
8123
|
typeStyles[type],
|
|
8083
8124
|
className
|
|
8084
8125
|
),
|
|
8085
8126
|
style: { animation: "damageFloat 1s ease-out forwards" },
|
|
8086
|
-
children:
|
|
8127
|
+
children: [
|
|
8128
|
+
assetUrl && /* @__PURE__ */ jsxRuntime.jsx(
|
|
8129
|
+
"img",
|
|
8130
|
+
{
|
|
8131
|
+
src: assetUrl,
|
|
8132
|
+
alt: "",
|
|
8133
|
+
width: 14,
|
|
8134
|
+
height: 14,
|
|
8135
|
+
style: { imageRendering: "pixelated", objectFit: "contain" },
|
|
8136
|
+
className: "flex-shrink-0"
|
|
8137
|
+
}
|
|
8138
|
+
),
|
|
8139
|
+
displayText
|
|
8140
|
+
]
|
|
8087
8141
|
}
|
|
8088
8142
|
)
|
|
8089
8143
|
] });
|
|
8090
8144
|
}
|
|
8091
|
-
var sizeMap12, typeStyles, floatKeyframes;
|
|
8145
|
+
var sizeMap12, typeStyles, floatKeyframes, DEFAULT_ASSET_URL10;
|
|
8092
8146
|
var init_DamageNumber = __esm({
|
|
8093
8147
|
"components/game/atoms/DamageNumber.tsx"() {
|
|
8094
8148
|
init_cn();
|
|
@@ -8110,6 +8164,7 @@ var init_DamageNumber = __esm({
|
|
|
8110
8164
|
100% { opacity: 0; transform: translateY(-32px) scale(0.8); }
|
|
8111
8165
|
}
|
|
8112
8166
|
`;
|
|
8167
|
+
DEFAULT_ASSET_URL10 = "https://almadar-kflow-assets.web.app/shared/effects/particles/spark_01.png";
|
|
8113
8168
|
DamageNumber.displayName = "DamageNumber";
|
|
8114
8169
|
}
|
|
8115
8170
|
});
|
|
@@ -8198,6 +8253,7 @@ var init_ChoiceButton = __esm({
|
|
|
8198
8253
|
}
|
|
8199
8254
|
});
|
|
8200
8255
|
function ActionButton({
|
|
8256
|
+
assetUrl = DEFAULT_ASSET_URL11,
|
|
8201
8257
|
label = "Attack",
|
|
8202
8258
|
icon,
|
|
8203
8259
|
cooldown = 0,
|
|
@@ -8237,13 +8293,23 @@ function ActionButton({
|
|
|
8237
8293
|
}
|
|
8238
8294
|
}
|
|
8239
8295
|
),
|
|
8240
|
-
|
|
8296
|
+
assetUrl ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
8297
|
+
"img",
|
|
8298
|
+
{
|
|
8299
|
+
src: assetUrl,
|
|
8300
|
+
alt: "",
|
|
8301
|
+
width: 16,
|
|
8302
|
+
height: 16,
|
|
8303
|
+
style: { imageRendering: "pixelated", objectFit: "contain" },
|
|
8304
|
+
className: cn("flex-shrink-0", sizes.icon)
|
|
8305
|
+
}
|
|
8306
|
+
) : icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("flex-shrink-0", sizes.icon), children: typeof icon === "string" ? (() => {
|
|
8241
8307
|
const I = resolveIcon(icon);
|
|
8242
8308
|
return I ? /* @__PURE__ */ jsxRuntime.jsx(I, { className: "w-4 h-4" }) : null;
|
|
8243
8309
|
})() : /* @__PURE__ */ (() => {
|
|
8244
8310
|
const I = icon;
|
|
8245
8311
|
return /* @__PURE__ */ jsxRuntime.jsx(I, { className: "w-4 h-4" });
|
|
8246
|
-
})() }),
|
|
8312
|
+
})() }) : null,
|
|
8247
8313
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "relative z-10", children: label }),
|
|
8248
8314
|
hotkey && /* @__PURE__ */ jsxRuntime.jsx(
|
|
8249
8315
|
"span",
|
|
@@ -8259,7 +8325,7 @@ function ActionButton({
|
|
|
8259
8325
|
}
|
|
8260
8326
|
);
|
|
8261
8327
|
}
|
|
8262
|
-
var sizeMap13, variantStyles8;
|
|
8328
|
+
var sizeMap13, variantStyles8, DEFAULT_ASSET_URL11;
|
|
8263
8329
|
var init_ActionButton = __esm({
|
|
8264
8330
|
"components/game/atoms/ActionButton.tsx"() {
|
|
8265
8331
|
init_cn();
|
|
@@ -8274,6 +8340,7 @@ var init_ActionButton = __esm({
|
|
|
8274
8340
|
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary-hover border-border",
|
|
8275
8341
|
danger: "bg-error text-error-foreground hover:bg-error/90 border-error"
|
|
8276
8342
|
};
|
|
8343
|
+
DEFAULT_ASSET_URL11 = "https://almadar-kflow-assets.web.app/shared/effects/particles/slash_01.png";
|
|
8277
8344
|
ActionButton.displayName = "ActionButton";
|
|
8278
8345
|
}
|
|
8279
8346
|
});
|
|
@@ -9142,10 +9209,10 @@ var init_Container = __esm({
|
|
|
9142
9209
|
center = true,
|
|
9143
9210
|
className,
|
|
9144
9211
|
children,
|
|
9145
|
-
as:
|
|
9212
|
+
as: Component2 = "div"
|
|
9146
9213
|
}) => {
|
|
9147
9214
|
const resolvedSize = maxWidth ?? size ?? "lg";
|
|
9148
|
-
const Comp =
|
|
9215
|
+
const Comp = Component2;
|
|
9149
9216
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
9150
9217
|
Comp,
|
|
9151
9218
|
{
|
|
@@ -25139,7 +25206,7 @@ var init_Flex = __esm({
|
|
|
25139
25206
|
basis,
|
|
25140
25207
|
className,
|
|
25141
25208
|
children,
|
|
25142
|
-
as:
|
|
25209
|
+
as: Component2 = "div"
|
|
25143
25210
|
}) => {
|
|
25144
25211
|
const flexStyle = {};
|
|
25145
25212
|
if (grow !== void 0 || shrink !== void 0 || basis !== void 0) {
|
|
@@ -25151,7 +25218,7 @@ var init_Flex = __esm({
|
|
|
25151
25218
|
flexStyle.flexBasis = typeof basis === "number" ? `${basis}px` : basis;
|
|
25152
25219
|
}
|
|
25153
25220
|
}
|
|
25154
|
-
const Comp =
|
|
25221
|
+
const Comp = Component2;
|
|
25155
25222
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
25156
25223
|
Comp,
|
|
25157
25224
|
{
|
|
@@ -25271,11 +25338,11 @@ var init_Grid = __esm({
|
|
|
25271
25338
|
className,
|
|
25272
25339
|
style,
|
|
25273
25340
|
children,
|
|
25274
|
-
as:
|
|
25341
|
+
as: Component2 = "div"
|
|
25275
25342
|
}) => {
|
|
25276
25343
|
const mergedStyle = rows2 ? { gridTemplateRows: `repeat(${rows2}, minmax(0, 1fr))`, ...style } : style;
|
|
25277
25344
|
return React83__namespace.default.createElement(
|
|
25278
|
-
|
|
25345
|
+
Component2,
|
|
25279
25346
|
{
|
|
25280
25347
|
className: cn(
|
|
25281
25348
|
"grid",
|
|
@@ -27101,6 +27168,7 @@ var init_ProgressDots = __esm({
|
|
|
27101
27168
|
}
|
|
27102
27169
|
});
|
|
27103
27170
|
function StatBadge({
|
|
27171
|
+
assetUrl = DEFAULT_ASSET_URL12,
|
|
27104
27172
|
label,
|
|
27105
27173
|
value = 0,
|
|
27106
27174
|
max,
|
|
@@ -27124,7 +27192,17 @@ function StatBadge({
|
|
|
27124
27192
|
className
|
|
27125
27193
|
),
|
|
27126
27194
|
children: [
|
|
27127
|
-
|
|
27195
|
+
assetUrl ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
27196
|
+
"img",
|
|
27197
|
+
{
|
|
27198
|
+
src: assetUrl,
|
|
27199
|
+
alt: "",
|
|
27200
|
+
width: 16,
|
|
27201
|
+
height: 16,
|
|
27202
|
+
style: { imageRendering: "pixelated", objectFit: "contain" },
|
|
27203
|
+
className: "flex-shrink-0"
|
|
27204
|
+
}
|
|
27205
|
+
) : icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-shrink-0 text-lg", children: typeof icon === "string" ? /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: icon, className: "w-4 h-4" }) : /* @__PURE__ */ jsxRuntime.jsx(Icon, { icon, className: "w-4 h-4" }) }) : null,
|
|
27128
27206
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground font-medium", children: label }),
|
|
27129
27207
|
format === "hearts" && max && /* @__PURE__ */ jsxRuntime.jsx(
|
|
27130
27208
|
HealthBar,
|
|
@@ -27157,7 +27235,7 @@ function StatBadge({
|
|
|
27157
27235
|
}
|
|
27158
27236
|
);
|
|
27159
27237
|
}
|
|
27160
|
-
var sizeMap17, variantMap2;
|
|
27238
|
+
var sizeMap17, variantMap2, DEFAULT_ASSET_URL12;
|
|
27161
27239
|
var init_StatBadge = __esm({
|
|
27162
27240
|
"components/game/molecules/StatBadge.tsx"() {
|
|
27163
27241
|
init_cn();
|
|
@@ -27176,6 +27254,7 @@ var init_StatBadge = __esm({
|
|
|
27176
27254
|
warning: "bg-warning/15 border-warning/40 text-foreground",
|
|
27177
27255
|
danger: "bg-error/15 border-error/40 text-foreground"
|
|
27178
27256
|
};
|
|
27257
|
+
DEFAULT_ASSET_URL12 = "https://almadar-kflow-assets.web.app/shared/effects/particles/light_01.png";
|
|
27179
27258
|
StatBadge.displayName = "StatBadge";
|
|
27180
27259
|
}
|
|
27181
27260
|
});
|
|
@@ -27832,6 +27911,7 @@ var init_TurnPanel = __esm({
|
|
|
27832
27911
|
}
|
|
27833
27912
|
});
|
|
27834
27913
|
function EnemyPlate({
|
|
27914
|
+
assetUrl = DEFAULT_ASSET_URL13,
|
|
27835
27915
|
name = "Shadow Guard",
|
|
27836
27916
|
health = 80,
|
|
27837
27917
|
maxHealth = 100,
|
|
@@ -27849,15 +27929,28 @@ function EnemyPlate({
|
|
|
27849
27929
|
),
|
|
27850
27930
|
children: [
|
|
27851
27931
|
/* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex items-center justify-between gap-2", children: [
|
|
27852
|
-
/* @__PURE__ */ jsxRuntime.
|
|
27853
|
-
|
|
27854
|
-
|
|
27855
|
-
|
|
27856
|
-
|
|
27857
|
-
|
|
27858
|
-
|
|
27859
|
-
|
|
27860
|
-
|
|
27932
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex items-center gap-1.5 min-w-0", children: [
|
|
27933
|
+
assetUrl && /* @__PURE__ */ jsxRuntime.jsx(
|
|
27934
|
+
"img",
|
|
27935
|
+
{
|
|
27936
|
+
src: assetUrl,
|
|
27937
|
+
alt: name,
|
|
27938
|
+
width: 24,
|
|
27939
|
+
height: 24,
|
|
27940
|
+
style: { objectFit: "cover", borderRadius: "50%" },
|
|
27941
|
+
className: "flex-shrink-0"
|
|
27942
|
+
}
|
|
27943
|
+
),
|
|
27944
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
27945
|
+
Typography,
|
|
27946
|
+
{
|
|
27947
|
+
variant: "caption",
|
|
27948
|
+
weight: "bold",
|
|
27949
|
+
className: "text-[var(--color-foreground)] truncate",
|
|
27950
|
+
children: name
|
|
27951
|
+
}
|
|
27952
|
+
)
|
|
27953
|
+
] }),
|
|
27861
27954
|
level != null && /* @__PURE__ */ jsxRuntime.jsxs(Badge, { variant: "neutral", size: "sm", children: [
|
|
27862
27955
|
"Lv.",
|
|
27863
27956
|
level
|
|
@@ -27902,7 +27995,7 @@ function EnemyPlate({
|
|
|
27902
27995
|
}
|
|
27903
27996
|
);
|
|
27904
27997
|
}
|
|
27905
|
-
var effectVariantMap2, DEFAULT_ENEMY_EFFECTS;
|
|
27998
|
+
var effectVariantMap2, DEFAULT_ENEMY_EFFECTS, DEFAULT_ASSET_URL13;
|
|
27906
27999
|
var init_EnemyPlate = __esm({
|
|
27907
28000
|
"components/game/molecules/EnemyPlate.tsx"() {
|
|
27908
28001
|
"use client";
|
|
@@ -27919,6 +28012,7 @@ var init_EnemyPlate = __esm({
|
|
|
27919
28012
|
DEFAULT_ENEMY_EFFECTS = [
|
|
27920
28013
|
{ icon: "flame", label: "Burn", variant: "debuff" }
|
|
27921
28014
|
];
|
|
28015
|
+
DEFAULT_ASSET_URL13 = "https://almadar-kflow-assets.web.app/shared/portraits/shadow-legion.png";
|
|
27922
28016
|
EnemyPlate.displayName = "EnemyPlate";
|
|
27923
28017
|
}
|
|
27924
28018
|
});
|
|
@@ -29450,13 +29544,13 @@ var init_MapView = __esm({
|
|
|
29450
29544
|
shadowSize: [41, 41]
|
|
29451
29545
|
});
|
|
29452
29546
|
L.Marker.prototype.options.icon = defaultIcon;
|
|
29453
|
-
const { useEffect:
|
|
29547
|
+
const { useEffect: useEffect79, useRef: useRef74, useCallback: useCallback118, useState: useState109 } = React83__namespace.default;
|
|
29454
29548
|
const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
|
|
29455
|
-
const { useEventBus:
|
|
29549
|
+
const { useEventBus: useEventBus3 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
|
|
29456
29550
|
function MapUpdater({ centerLat, centerLng, zoom }) {
|
|
29457
29551
|
const map = useMap();
|
|
29458
|
-
const prevRef =
|
|
29459
|
-
|
|
29552
|
+
const prevRef = useRef74({ centerLat, centerLng, zoom });
|
|
29553
|
+
useEffect79(() => {
|
|
29460
29554
|
const prev = prevRef.current;
|
|
29461
29555
|
if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
|
|
29462
29556
|
map.setView([centerLat, centerLng], zoom);
|
|
@@ -29467,7 +29561,7 @@ var init_MapView = __esm({
|
|
|
29467
29561
|
}
|
|
29468
29562
|
function MapClickHandler({ onMapClick }) {
|
|
29469
29563
|
const map = useMap();
|
|
29470
|
-
|
|
29564
|
+
useEffect79(() => {
|
|
29471
29565
|
if (!onMapClick) return;
|
|
29472
29566
|
const handler = (e) => {
|
|
29473
29567
|
onMapClick(e.latlng.lat, e.latlng.lng);
|
|
@@ -29494,9 +29588,9 @@ var init_MapView = __esm({
|
|
|
29494
29588
|
className,
|
|
29495
29589
|
showAttribution = true
|
|
29496
29590
|
}) {
|
|
29497
|
-
const eventBus =
|
|
29498
|
-
const [clickedPosition, setClickedPosition] =
|
|
29499
|
-
const handleMapClick =
|
|
29591
|
+
const eventBus = useEventBus3();
|
|
29592
|
+
const [clickedPosition, setClickedPosition] = useState109(null);
|
|
29593
|
+
const handleMapClick = useCallback118((lat, lng) => {
|
|
29500
29594
|
if (showClickedPin) {
|
|
29501
29595
|
setClickedPosition({ lat, lng });
|
|
29502
29596
|
}
|
|
@@ -29505,7 +29599,7 @@ var init_MapView = __esm({
|
|
|
29505
29599
|
eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
|
|
29506
29600
|
}
|
|
29507
29601
|
}, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
|
|
29508
|
-
const handleMarkerClick =
|
|
29602
|
+
const handleMarkerClick = useCallback118((marker) => {
|
|
29509
29603
|
onMarkerClick?.(marker);
|
|
29510
29604
|
if (markerClickEvent) {
|
|
29511
29605
|
eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
|
|
@@ -36632,10 +36726,10 @@ var init_Section = __esm({
|
|
|
36632
36726
|
children,
|
|
36633
36727
|
headerClassName,
|
|
36634
36728
|
contentClassName,
|
|
36635
|
-
as:
|
|
36729
|
+
as: Component2 = "section"
|
|
36636
36730
|
}) => {
|
|
36637
36731
|
const hasHeader = title || description || action;
|
|
36638
|
-
const Comp =
|
|
36732
|
+
const Comp = Component2;
|
|
36639
36733
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
36640
36734
|
Comp,
|
|
36641
36735
|
{
|
|
@@ -41200,6 +41294,1568 @@ var init_GameAudioToggle = __esm({
|
|
|
41200
41294
|
GameAudioToggle.displayName = "GameAudioToggle";
|
|
41201
41295
|
}
|
|
41202
41296
|
});
|
|
41297
|
+
function detectAssetRoot(modelUrl) {
|
|
41298
|
+
const idx = modelUrl.indexOf("/3d/");
|
|
41299
|
+
if (idx !== -1) {
|
|
41300
|
+
return modelUrl.substring(0, idx + 4);
|
|
41301
|
+
}
|
|
41302
|
+
return modelUrl.substring(0, modelUrl.lastIndexOf("/") + 1);
|
|
41303
|
+
}
|
|
41304
|
+
function createGLTFLoaderForUrl(url) {
|
|
41305
|
+
const loader = new GLTFLoader_js.GLTFLoader();
|
|
41306
|
+
loader.setResourcePath(detectAssetRoot(url));
|
|
41307
|
+
return loader;
|
|
41308
|
+
}
|
|
41309
|
+
var AssetLoader;
|
|
41310
|
+
var init_AssetLoader = __esm({
|
|
41311
|
+
"components/game/molecules/three/loaders/AssetLoader.ts"() {
|
|
41312
|
+
AssetLoader = class {
|
|
41313
|
+
constructor() {
|
|
41314
|
+
__publicField(this, "objLoader");
|
|
41315
|
+
__publicField(this, "textureLoader");
|
|
41316
|
+
__publicField(this, "modelCache");
|
|
41317
|
+
__publicField(this, "textureCache");
|
|
41318
|
+
__publicField(this, "loadingPromises");
|
|
41319
|
+
this.objLoader = new OBJLoader_js.OBJLoader();
|
|
41320
|
+
this.textureLoader = new THREE__namespace.TextureLoader();
|
|
41321
|
+
this.modelCache = /* @__PURE__ */ new Map();
|
|
41322
|
+
this.textureCache = /* @__PURE__ */ new Map();
|
|
41323
|
+
this.loadingPromises = /* @__PURE__ */ new Map();
|
|
41324
|
+
}
|
|
41325
|
+
/**
|
|
41326
|
+
* Load a GLB/GLTF model
|
|
41327
|
+
* @param url - URL to the .glb or .gltf file
|
|
41328
|
+
* @returns Promise with loaded model scene and animations
|
|
41329
|
+
*/
|
|
41330
|
+
async loadModel(url) {
|
|
41331
|
+
if (this.modelCache.has(url)) {
|
|
41332
|
+
return this.modelCache.get(url);
|
|
41333
|
+
}
|
|
41334
|
+
if (this.loadingPromises.has(url)) {
|
|
41335
|
+
return this.loadingPromises.get(url);
|
|
41336
|
+
}
|
|
41337
|
+
const loader = createGLTFLoaderForUrl(url);
|
|
41338
|
+
const loadPromise = loader.loadAsync(url).then((gltf) => {
|
|
41339
|
+
const result = {
|
|
41340
|
+
scene: gltf.scene,
|
|
41341
|
+
animations: gltf.animations || []
|
|
41342
|
+
};
|
|
41343
|
+
this.modelCache.set(url, result);
|
|
41344
|
+
this.loadingPromises.delete(url);
|
|
41345
|
+
return result;
|
|
41346
|
+
}).catch((error) => {
|
|
41347
|
+
this.loadingPromises.delete(url);
|
|
41348
|
+
throw new Error(`Failed to load model ${url}: ${error.message}`);
|
|
41349
|
+
});
|
|
41350
|
+
this.loadingPromises.set(url, loadPromise);
|
|
41351
|
+
return loadPromise;
|
|
41352
|
+
}
|
|
41353
|
+
/**
|
|
41354
|
+
* Load an OBJ model (fallback for non-GLB assets)
|
|
41355
|
+
* @param url - URL to the .obj file
|
|
41356
|
+
* @returns Promise with loaded object group
|
|
41357
|
+
*/
|
|
41358
|
+
async loadOBJ(url) {
|
|
41359
|
+
if (this.modelCache.has(url)) {
|
|
41360
|
+
return this.modelCache.get(url).scene;
|
|
41361
|
+
}
|
|
41362
|
+
if (this.loadingPromises.has(url)) {
|
|
41363
|
+
const result = await this.loadingPromises.get(url);
|
|
41364
|
+
return result.scene;
|
|
41365
|
+
}
|
|
41366
|
+
const loadPromise = this.objLoader.loadAsync(url).then((group) => {
|
|
41367
|
+
const result = {
|
|
41368
|
+
scene: group,
|
|
41369
|
+
animations: []
|
|
41370
|
+
};
|
|
41371
|
+
this.modelCache.set(url, result);
|
|
41372
|
+
this.loadingPromises.delete(url);
|
|
41373
|
+
return result;
|
|
41374
|
+
}).catch((error) => {
|
|
41375
|
+
this.loadingPromises.delete(url);
|
|
41376
|
+
throw new Error(`Failed to load OBJ ${url}: ${error.message}`);
|
|
41377
|
+
});
|
|
41378
|
+
this.loadingPromises.set(url, loadPromise);
|
|
41379
|
+
return (await loadPromise).scene;
|
|
41380
|
+
}
|
|
41381
|
+
/**
|
|
41382
|
+
* Load a texture
|
|
41383
|
+
* @param url - URL to the texture image
|
|
41384
|
+
* @returns Promise with loaded texture
|
|
41385
|
+
*/
|
|
41386
|
+
async loadTexture(url) {
|
|
41387
|
+
if (this.textureCache.has(url)) {
|
|
41388
|
+
return this.textureCache.get(url);
|
|
41389
|
+
}
|
|
41390
|
+
if (this.loadingPromises.has(`texture:${url}`)) {
|
|
41391
|
+
return this.loadingPromises.get(`texture:${url}`);
|
|
41392
|
+
}
|
|
41393
|
+
const loadPromise = this.textureLoader.loadAsync(url).then((texture) => {
|
|
41394
|
+
texture.colorSpace = THREE__namespace.SRGBColorSpace;
|
|
41395
|
+
this.textureCache.set(url, texture);
|
|
41396
|
+
this.loadingPromises.delete(`texture:${url}`);
|
|
41397
|
+
return texture;
|
|
41398
|
+
}).catch((error) => {
|
|
41399
|
+
this.loadingPromises.delete(`texture:${url}`);
|
|
41400
|
+
throw new Error(`Failed to load texture ${url}: ${error.message}`);
|
|
41401
|
+
});
|
|
41402
|
+
this.loadingPromises.set(`texture:${url}`, loadPromise);
|
|
41403
|
+
return loadPromise;
|
|
41404
|
+
}
|
|
41405
|
+
/**
|
|
41406
|
+
* Preload multiple assets
|
|
41407
|
+
* @param urls - Array of asset URLs to preload
|
|
41408
|
+
* @returns Promise that resolves when all assets are loaded
|
|
41409
|
+
*/
|
|
41410
|
+
async preload(urls) {
|
|
41411
|
+
const promises = urls.map((url) => {
|
|
41412
|
+
if (url.endsWith(".glb") || url.endsWith(".gltf")) {
|
|
41413
|
+
return this.loadModel(url).catch(() => null);
|
|
41414
|
+
} else if (url.endsWith(".obj")) {
|
|
41415
|
+
return this.loadOBJ(url).catch(() => null);
|
|
41416
|
+
} else if (/\.(png|jpg|jpeg|webp)$/i.test(url)) {
|
|
41417
|
+
return this.loadTexture(url).catch(() => null);
|
|
41418
|
+
}
|
|
41419
|
+
return Promise.resolve(null);
|
|
41420
|
+
});
|
|
41421
|
+
await Promise.all(promises);
|
|
41422
|
+
}
|
|
41423
|
+
/**
|
|
41424
|
+
* Check if a model is cached
|
|
41425
|
+
* @param url - Model URL
|
|
41426
|
+
*/
|
|
41427
|
+
hasModel(url) {
|
|
41428
|
+
return this.modelCache.has(url);
|
|
41429
|
+
}
|
|
41430
|
+
/**
|
|
41431
|
+
* Check if a texture is cached
|
|
41432
|
+
* @param url - Texture URL
|
|
41433
|
+
*/
|
|
41434
|
+
hasTexture(url) {
|
|
41435
|
+
return this.textureCache.has(url);
|
|
41436
|
+
}
|
|
41437
|
+
/**
|
|
41438
|
+
* Get cached model (throws if not cached)
|
|
41439
|
+
* @param url - Model URL
|
|
41440
|
+
*/
|
|
41441
|
+
getModel(url) {
|
|
41442
|
+
const model = this.modelCache.get(url);
|
|
41443
|
+
if (!model) {
|
|
41444
|
+
throw new Error(`Model ${url} not in cache`);
|
|
41445
|
+
}
|
|
41446
|
+
return model;
|
|
41447
|
+
}
|
|
41448
|
+
/**
|
|
41449
|
+
* Get cached texture (throws if not cached)
|
|
41450
|
+
* @param url - Texture URL
|
|
41451
|
+
*/
|
|
41452
|
+
getTexture(url) {
|
|
41453
|
+
const texture = this.textureCache.get(url);
|
|
41454
|
+
if (!texture) {
|
|
41455
|
+
throw new Error(`Texture ${url} not in cache`);
|
|
41456
|
+
}
|
|
41457
|
+
return texture;
|
|
41458
|
+
}
|
|
41459
|
+
/**
|
|
41460
|
+
* Clear all caches
|
|
41461
|
+
*/
|
|
41462
|
+
clearCache() {
|
|
41463
|
+
this.textureCache.forEach((texture) => {
|
|
41464
|
+
texture.dispose();
|
|
41465
|
+
});
|
|
41466
|
+
this.modelCache.forEach((model) => {
|
|
41467
|
+
model.scene.traverse((child) => {
|
|
41468
|
+
if (child instanceof THREE__namespace.Mesh) {
|
|
41469
|
+
child.geometry.dispose();
|
|
41470
|
+
if (Array.isArray(child.material)) {
|
|
41471
|
+
child.material.forEach((m) => m.dispose());
|
|
41472
|
+
} else {
|
|
41473
|
+
child.material.dispose();
|
|
41474
|
+
}
|
|
41475
|
+
}
|
|
41476
|
+
});
|
|
41477
|
+
});
|
|
41478
|
+
this.modelCache.clear();
|
|
41479
|
+
this.textureCache.clear();
|
|
41480
|
+
this.loadingPromises.clear();
|
|
41481
|
+
}
|
|
41482
|
+
/**
|
|
41483
|
+
* Get cache statistics
|
|
41484
|
+
*/
|
|
41485
|
+
getStats() {
|
|
41486
|
+
return {
|
|
41487
|
+
models: this.modelCache.size,
|
|
41488
|
+
textures: this.textureCache.size,
|
|
41489
|
+
loading: this.loadingPromises.size
|
|
41490
|
+
};
|
|
41491
|
+
}
|
|
41492
|
+
};
|
|
41493
|
+
new AssetLoader();
|
|
41494
|
+
}
|
|
41495
|
+
});
|
|
41496
|
+
function useAssetLoader(options = {}) {
|
|
41497
|
+
const { preloadUrls = [], loader: customLoader } = options;
|
|
41498
|
+
const loaderRef = React83.useRef(customLoader || new AssetLoader());
|
|
41499
|
+
const [state, setState] = React83.useState({
|
|
41500
|
+
isLoading: false,
|
|
41501
|
+
progress: 0,
|
|
41502
|
+
loaded: 0,
|
|
41503
|
+
total: 0,
|
|
41504
|
+
errors: []
|
|
41505
|
+
});
|
|
41506
|
+
React83.useEffect(() => {
|
|
41507
|
+
if (preloadUrls.length > 0) {
|
|
41508
|
+
preload(preloadUrls);
|
|
41509
|
+
}
|
|
41510
|
+
}, []);
|
|
41511
|
+
const updateProgress = React83.useCallback((loaded, total) => {
|
|
41512
|
+
setState((prev) => ({
|
|
41513
|
+
...prev,
|
|
41514
|
+
loaded,
|
|
41515
|
+
total,
|
|
41516
|
+
progress: total > 0 ? Math.round(loaded / total * 100) : 0
|
|
41517
|
+
}));
|
|
41518
|
+
}, []);
|
|
41519
|
+
const loadModel = React83.useCallback(
|
|
41520
|
+
async (url) => {
|
|
41521
|
+
setState((prev) => ({ ...prev, isLoading: true }));
|
|
41522
|
+
try {
|
|
41523
|
+
const model = await loaderRef.current.loadModel(url);
|
|
41524
|
+
setState((prev) => ({
|
|
41525
|
+
...prev,
|
|
41526
|
+
isLoading: false,
|
|
41527
|
+
loaded: prev.loaded + 1
|
|
41528
|
+
}));
|
|
41529
|
+
return model;
|
|
41530
|
+
} catch (error) {
|
|
41531
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
41532
|
+
setState((prev) => ({
|
|
41533
|
+
...prev,
|
|
41534
|
+
isLoading: false,
|
|
41535
|
+
errors: [...prev.errors, errorMsg]
|
|
41536
|
+
}));
|
|
41537
|
+
throw error;
|
|
41538
|
+
}
|
|
41539
|
+
},
|
|
41540
|
+
[]
|
|
41541
|
+
);
|
|
41542
|
+
const loadOBJ = React83.useCallback(
|
|
41543
|
+
async (url) => {
|
|
41544
|
+
setState((prev) => ({ ...prev, isLoading: true }));
|
|
41545
|
+
try {
|
|
41546
|
+
const model = await loaderRef.current.loadOBJ(url);
|
|
41547
|
+
setState((prev) => ({
|
|
41548
|
+
...prev,
|
|
41549
|
+
isLoading: false,
|
|
41550
|
+
loaded: prev.loaded + 1
|
|
41551
|
+
}));
|
|
41552
|
+
return model;
|
|
41553
|
+
} catch (error) {
|
|
41554
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
41555
|
+
setState((prev) => ({
|
|
41556
|
+
...prev,
|
|
41557
|
+
isLoading: false,
|
|
41558
|
+
errors: [...prev.errors, errorMsg]
|
|
41559
|
+
}));
|
|
41560
|
+
throw error;
|
|
41561
|
+
}
|
|
41562
|
+
},
|
|
41563
|
+
[]
|
|
41564
|
+
);
|
|
41565
|
+
const loadTexture = React83.useCallback(
|
|
41566
|
+
async (url) => {
|
|
41567
|
+
setState((prev) => ({ ...prev, isLoading: true }));
|
|
41568
|
+
try {
|
|
41569
|
+
const texture = await loaderRef.current.loadTexture(url);
|
|
41570
|
+
setState((prev) => ({
|
|
41571
|
+
...prev,
|
|
41572
|
+
isLoading: false,
|
|
41573
|
+
loaded: prev.loaded + 1
|
|
41574
|
+
}));
|
|
41575
|
+
return texture;
|
|
41576
|
+
} catch (error) {
|
|
41577
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
41578
|
+
setState((prev) => ({
|
|
41579
|
+
...prev,
|
|
41580
|
+
isLoading: false,
|
|
41581
|
+
errors: [...prev.errors, errorMsg]
|
|
41582
|
+
}));
|
|
41583
|
+
throw error;
|
|
41584
|
+
}
|
|
41585
|
+
},
|
|
41586
|
+
[]
|
|
41587
|
+
);
|
|
41588
|
+
const preload = React83.useCallback(
|
|
41589
|
+
async (urls) => {
|
|
41590
|
+
setState((prev) => ({
|
|
41591
|
+
...prev,
|
|
41592
|
+
isLoading: true,
|
|
41593
|
+
total: urls.length,
|
|
41594
|
+
loaded: 0,
|
|
41595
|
+
errors: []
|
|
41596
|
+
}));
|
|
41597
|
+
let completed = 0;
|
|
41598
|
+
const errors = [];
|
|
41599
|
+
await Promise.all(
|
|
41600
|
+
urls.map(async (url) => {
|
|
41601
|
+
try {
|
|
41602
|
+
if (url.endsWith(".glb") || url.endsWith(".gltf")) {
|
|
41603
|
+
await loaderRef.current.loadModel(url);
|
|
41604
|
+
} else if (url.endsWith(".obj")) {
|
|
41605
|
+
await loaderRef.current.loadOBJ(url);
|
|
41606
|
+
} else if (/\.(png|jpg|jpeg|webp)$/i.test(url)) {
|
|
41607
|
+
await loaderRef.current.loadTexture(url);
|
|
41608
|
+
}
|
|
41609
|
+
completed++;
|
|
41610
|
+
updateProgress(completed, urls.length);
|
|
41611
|
+
} catch (error) {
|
|
41612
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
41613
|
+
errors.push(`${url}: ${errorMsg}`);
|
|
41614
|
+
completed++;
|
|
41615
|
+
updateProgress(completed, urls.length);
|
|
41616
|
+
}
|
|
41617
|
+
})
|
|
41618
|
+
);
|
|
41619
|
+
setState((prev) => ({
|
|
41620
|
+
...prev,
|
|
41621
|
+
isLoading: false,
|
|
41622
|
+
errors
|
|
41623
|
+
}));
|
|
41624
|
+
},
|
|
41625
|
+
[updateProgress]
|
|
41626
|
+
);
|
|
41627
|
+
const hasModel = React83.useCallback((url) => {
|
|
41628
|
+
return loaderRef.current.hasModel(url);
|
|
41629
|
+
}, []);
|
|
41630
|
+
const hasTexture = React83.useCallback((url) => {
|
|
41631
|
+
return loaderRef.current.hasTexture(url);
|
|
41632
|
+
}, []);
|
|
41633
|
+
const getModel = React83.useCallback((url) => {
|
|
41634
|
+
try {
|
|
41635
|
+
return loaderRef.current.getModel(url);
|
|
41636
|
+
} catch {
|
|
41637
|
+
return void 0;
|
|
41638
|
+
}
|
|
41639
|
+
}, []);
|
|
41640
|
+
const getTexture = React83.useCallback((url) => {
|
|
41641
|
+
try {
|
|
41642
|
+
return loaderRef.current.getTexture(url);
|
|
41643
|
+
} catch {
|
|
41644
|
+
return void 0;
|
|
41645
|
+
}
|
|
41646
|
+
}, []);
|
|
41647
|
+
const clearCache = React83.useCallback(() => {
|
|
41648
|
+
loaderRef.current.clearCache();
|
|
41649
|
+
setState({
|
|
41650
|
+
isLoading: false,
|
|
41651
|
+
progress: 0,
|
|
41652
|
+
loaded: 0,
|
|
41653
|
+
total: 0,
|
|
41654
|
+
errors: []
|
|
41655
|
+
});
|
|
41656
|
+
}, []);
|
|
41657
|
+
return {
|
|
41658
|
+
...state,
|
|
41659
|
+
loadModel,
|
|
41660
|
+
loadOBJ,
|
|
41661
|
+
loadTexture,
|
|
41662
|
+
preload,
|
|
41663
|
+
hasModel,
|
|
41664
|
+
hasTexture,
|
|
41665
|
+
getModel,
|
|
41666
|
+
getTexture,
|
|
41667
|
+
clearCache
|
|
41668
|
+
};
|
|
41669
|
+
}
|
|
41670
|
+
var init_useAssetLoader = __esm({
|
|
41671
|
+
"components/game/molecules/three/hooks/useAssetLoader.ts"() {
|
|
41672
|
+
"use client";
|
|
41673
|
+
init_AssetLoader();
|
|
41674
|
+
}
|
|
41675
|
+
});
|
|
41676
|
+
function useGameCanvas3DEvents(options) {
|
|
41677
|
+
const {
|
|
41678
|
+
tileClickEvent,
|
|
41679
|
+
unitClickEvent,
|
|
41680
|
+
featureClickEvent,
|
|
41681
|
+
canvasClickEvent,
|
|
41682
|
+
tileHoverEvent,
|
|
41683
|
+
tileLeaveEvent,
|
|
41684
|
+
unitAnimationEvent,
|
|
41685
|
+
cameraChangeEvent,
|
|
41686
|
+
onTileClick,
|
|
41687
|
+
onUnitClick,
|
|
41688
|
+
onFeatureClick,
|
|
41689
|
+
onCanvasClick,
|
|
41690
|
+
onTileHover,
|
|
41691
|
+
onUnitAnimation
|
|
41692
|
+
} = options;
|
|
41693
|
+
const emit = useEmitEvent();
|
|
41694
|
+
const optionsRef = React83.useRef(options);
|
|
41695
|
+
optionsRef.current = options;
|
|
41696
|
+
const handleTileClick = React83.useCallback(
|
|
41697
|
+
(tile, event) => {
|
|
41698
|
+
if (tileClickEvent) {
|
|
41699
|
+
emit(tileClickEvent, {
|
|
41700
|
+
tileId: tile.id,
|
|
41701
|
+
x: tile.x,
|
|
41702
|
+
z: tile.z ?? tile.y ?? 0,
|
|
41703
|
+
type: tile.type,
|
|
41704
|
+
terrain: tile.terrain,
|
|
41705
|
+
elevation: tile.elevation
|
|
41706
|
+
});
|
|
41707
|
+
}
|
|
41708
|
+
optionsRef.current.onTileClick?.(tile, event);
|
|
41709
|
+
},
|
|
41710
|
+
[tileClickEvent, emit]
|
|
41711
|
+
);
|
|
41712
|
+
const handleUnitClick = React83.useCallback(
|
|
41713
|
+
(unit, event) => {
|
|
41714
|
+
if (unitClickEvent) {
|
|
41715
|
+
emit(unitClickEvent, {
|
|
41716
|
+
unitId: unit.id,
|
|
41717
|
+
x: unit.x,
|
|
41718
|
+
z: unit.z ?? unit.y ?? 0,
|
|
41719
|
+
unitType: unit.unitType,
|
|
41720
|
+
name: unit.name,
|
|
41721
|
+
team: unit.team,
|
|
41722
|
+
faction: unit.faction,
|
|
41723
|
+
health: unit.health,
|
|
41724
|
+
maxHealth: unit.maxHealth
|
|
41725
|
+
});
|
|
41726
|
+
}
|
|
41727
|
+
optionsRef.current.onUnitClick?.(unit, event);
|
|
41728
|
+
},
|
|
41729
|
+
[unitClickEvent, emit]
|
|
41730
|
+
);
|
|
41731
|
+
const handleFeatureClick = React83.useCallback(
|
|
41732
|
+
(feature, event) => {
|
|
41733
|
+
if (featureClickEvent) {
|
|
41734
|
+
emit(featureClickEvent, {
|
|
41735
|
+
featureId: feature.id,
|
|
41736
|
+
x: feature.x,
|
|
41737
|
+
z: feature.z ?? feature.y ?? 0,
|
|
41738
|
+
type: feature.type,
|
|
41739
|
+
elevation: feature.elevation
|
|
41740
|
+
});
|
|
41741
|
+
}
|
|
41742
|
+
optionsRef.current.onFeatureClick?.(feature, event);
|
|
41743
|
+
},
|
|
41744
|
+
[featureClickEvent, emit]
|
|
41745
|
+
);
|
|
41746
|
+
const handleCanvasClick = React83.useCallback(
|
|
41747
|
+
(event) => {
|
|
41748
|
+
if (canvasClickEvent) {
|
|
41749
|
+
emit(canvasClickEvent, {
|
|
41750
|
+
clientX: event.clientX,
|
|
41751
|
+
clientY: event.clientY,
|
|
41752
|
+
button: event.button
|
|
41753
|
+
});
|
|
41754
|
+
}
|
|
41755
|
+
optionsRef.current.onCanvasClick?.(event);
|
|
41756
|
+
},
|
|
41757
|
+
[canvasClickEvent, emit]
|
|
41758
|
+
);
|
|
41759
|
+
const handleTileHover = React83.useCallback(
|
|
41760
|
+
(tile, event) => {
|
|
41761
|
+
if (tile) {
|
|
41762
|
+
if (tileHoverEvent) {
|
|
41763
|
+
emit(tileHoverEvent, {
|
|
41764
|
+
tileId: tile.id,
|
|
41765
|
+
x: tile.x,
|
|
41766
|
+
z: tile.z ?? tile.y ?? 0,
|
|
41767
|
+
type: tile.type
|
|
41768
|
+
});
|
|
41769
|
+
}
|
|
41770
|
+
} else {
|
|
41771
|
+
if (tileLeaveEvent) {
|
|
41772
|
+
emit(tileLeaveEvent, {});
|
|
41773
|
+
}
|
|
41774
|
+
}
|
|
41775
|
+
optionsRef.current.onTileHover?.(tile, event);
|
|
41776
|
+
},
|
|
41777
|
+
[tileHoverEvent, tileLeaveEvent, emit]
|
|
41778
|
+
);
|
|
41779
|
+
const handleUnitAnimation = React83.useCallback(
|
|
41780
|
+
(unitId, state) => {
|
|
41781
|
+
if (unitAnimationEvent) {
|
|
41782
|
+
emit(unitAnimationEvent, {
|
|
41783
|
+
unitId,
|
|
41784
|
+
state,
|
|
41785
|
+
timestamp: Date.now()
|
|
41786
|
+
});
|
|
41787
|
+
}
|
|
41788
|
+
optionsRef.current.onUnitAnimation?.(unitId, state);
|
|
41789
|
+
},
|
|
41790
|
+
[unitAnimationEvent, emit]
|
|
41791
|
+
);
|
|
41792
|
+
const handleCameraChange = React83.useCallback(
|
|
41793
|
+
(position) => {
|
|
41794
|
+
if (cameraChangeEvent) {
|
|
41795
|
+
emit(cameraChangeEvent, {
|
|
41796
|
+
position,
|
|
41797
|
+
timestamp: Date.now()
|
|
41798
|
+
});
|
|
41799
|
+
}
|
|
41800
|
+
},
|
|
41801
|
+
[cameraChangeEvent, emit]
|
|
41802
|
+
);
|
|
41803
|
+
return {
|
|
41804
|
+
handleTileClick,
|
|
41805
|
+
handleUnitClick,
|
|
41806
|
+
handleFeatureClick,
|
|
41807
|
+
handleCanvasClick,
|
|
41808
|
+
handleTileHover,
|
|
41809
|
+
handleUnitAnimation,
|
|
41810
|
+
handleCameraChange
|
|
41811
|
+
};
|
|
41812
|
+
}
|
|
41813
|
+
var init_useGameCanvas3DEvents = __esm({
|
|
41814
|
+
"components/game/molecules/three/hooks/useGameCanvas3DEvents.ts"() {
|
|
41815
|
+
"use client";
|
|
41816
|
+
init_useEventBus();
|
|
41817
|
+
}
|
|
41818
|
+
});
|
|
41819
|
+
|
|
41820
|
+
// components/game/molecules/three/components/Canvas3DLoadingState.css
|
|
41821
|
+
var init_Canvas3DLoadingState = __esm({
|
|
41822
|
+
"components/game/molecules/three/components/Canvas3DLoadingState.css"() {
|
|
41823
|
+
}
|
|
41824
|
+
});
|
|
41825
|
+
function Canvas3DLoadingState({
|
|
41826
|
+
progress = 0,
|
|
41827
|
+
loaded = 0,
|
|
41828
|
+
total = 0,
|
|
41829
|
+
message = "Loading 3D Scene...",
|
|
41830
|
+
details,
|
|
41831
|
+
showSpinner = true,
|
|
41832
|
+
className
|
|
41833
|
+
}) {
|
|
41834
|
+
const clampedProgress = Math.max(0, Math.min(100, progress));
|
|
41835
|
+
const hasProgress = total > 0;
|
|
41836
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `canvas-3d-loading ${className || ""}`, children: [
|
|
41837
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "canvas-3d-loading__content", children: [
|
|
41838
|
+
showSpinner && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "canvas-3d-loading__spinner", children: [
|
|
41839
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "spinner__ring" }),
|
|
41840
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "spinner__ring spinner__ring--secondary" })
|
|
41841
|
+
] }),
|
|
41842
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "canvas-3d-loading__message", children: message }),
|
|
41843
|
+
details && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "canvas-3d-loading__details", children: details }),
|
|
41844
|
+
hasProgress && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "canvas-3d-loading__progress", children: [
|
|
41845
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "progress__bar", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
41846
|
+
"div",
|
|
41847
|
+
{
|
|
41848
|
+
className: "progress__fill",
|
|
41849
|
+
style: { width: `${clampedProgress}%` }
|
|
41850
|
+
}
|
|
41851
|
+
) }),
|
|
41852
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "progress__text", children: [
|
|
41853
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "progress__percentage", children: [
|
|
41854
|
+
clampedProgress,
|
|
41855
|
+
"%"
|
|
41856
|
+
] }),
|
|
41857
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "progress__count", children: [
|
|
41858
|
+
"(",
|
|
41859
|
+
loaded,
|
|
41860
|
+
"/",
|
|
41861
|
+
total,
|
|
41862
|
+
")"
|
|
41863
|
+
] })
|
|
41864
|
+
] })
|
|
41865
|
+
] })
|
|
41866
|
+
] }),
|
|
41867
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "canvas-3d-loading__background", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg__grid" }) })
|
|
41868
|
+
] });
|
|
41869
|
+
}
|
|
41870
|
+
var init_Canvas3DLoadingState2 = __esm({
|
|
41871
|
+
"components/game/molecules/three/components/Canvas3DLoadingState.tsx"() {
|
|
41872
|
+
init_Canvas3DLoadingState();
|
|
41873
|
+
}
|
|
41874
|
+
});
|
|
41875
|
+
|
|
41876
|
+
// components/game/molecules/three/components/Canvas3DErrorBoundary.css
|
|
41877
|
+
var init_Canvas3DErrorBoundary = __esm({
|
|
41878
|
+
"components/game/molecules/three/components/Canvas3DErrorBoundary.css"() {
|
|
41879
|
+
}
|
|
41880
|
+
});
|
|
41881
|
+
var log11, Canvas3DErrorBoundary;
|
|
41882
|
+
var init_Canvas3DErrorBoundary2 = __esm({
|
|
41883
|
+
"components/game/molecules/three/components/Canvas3DErrorBoundary.tsx"() {
|
|
41884
|
+
init_Canvas3DErrorBoundary();
|
|
41885
|
+
log11 = logger.createLogger("almadar:ui:game:canvas3d:error-boundary");
|
|
41886
|
+
Canvas3DErrorBoundary = class extends React83.Component {
|
|
41887
|
+
constructor(props) {
|
|
41888
|
+
super(props);
|
|
41889
|
+
__publicField(this, "handleReset", () => {
|
|
41890
|
+
this.setState({
|
|
41891
|
+
hasError: false,
|
|
41892
|
+
error: null,
|
|
41893
|
+
errorInfo: null
|
|
41894
|
+
});
|
|
41895
|
+
this.props.onReset?.();
|
|
41896
|
+
});
|
|
41897
|
+
this.state = {
|
|
41898
|
+
hasError: false,
|
|
41899
|
+
error: null,
|
|
41900
|
+
errorInfo: null
|
|
41901
|
+
};
|
|
41902
|
+
}
|
|
41903
|
+
static getDerivedStateFromError(error) {
|
|
41904
|
+
return {
|
|
41905
|
+
hasError: true,
|
|
41906
|
+
error,
|
|
41907
|
+
errorInfo: null
|
|
41908
|
+
};
|
|
41909
|
+
}
|
|
41910
|
+
componentDidCatch(error, errorInfo) {
|
|
41911
|
+
this.setState({ errorInfo });
|
|
41912
|
+
this.props.onError?.(error, errorInfo);
|
|
41913
|
+
log11.error("Error caught", { error });
|
|
41914
|
+
log11.error("Component stack", { componentStack: errorInfo.componentStack ?? "<none>" });
|
|
41915
|
+
}
|
|
41916
|
+
render() {
|
|
41917
|
+
if (this.state.hasError) {
|
|
41918
|
+
if (this.props.fallback) {
|
|
41919
|
+
return this.props.fallback;
|
|
41920
|
+
}
|
|
41921
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "canvas-3d-error", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "canvas-3d-error__content", children: [
|
|
41922
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "canvas-3d-error__icon", children: "\u26A0\uFE0F" }),
|
|
41923
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "canvas-3d-error__title", children: "3D Scene Error" }),
|
|
41924
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "canvas-3d-error__message", children: "Something went wrong while rendering the 3D scene." }),
|
|
41925
|
+
this.state.error && /* @__PURE__ */ jsxRuntime.jsxs("details", { className: "canvas-3d-error__details", children: [
|
|
41926
|
+
/* @__PURE__ */ jsxRuntime.jsx("summary", { children: "Error Details" }),
|
|
41927
|
+
/* @__PURE__ */ jsxRuntime.jsxs("pre", { className: "error__stack", children: [
|
|
41928
|
+
this.state.error.message,
|
|
41929
|
+
"\n",
|
|
41930
|
+
this.state.error.stack
|
|
41931
|
+
] }),
|
|
41932
|
+
this.state.errorInfo && /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "error__component-stack", children: this.state.errorInfo.componentStack })
|
|
41933
|
+
] }),
|
|
41934
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "canvas-3d-error__actions", children: [
|
|
41935
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
41936
|
+
"button",
|
|
41937
|
+
{
|
|
41938
|
+
className: "error__button error__button--primary",
|
|
41939
|
+
onClick: this.handleReset,
|
|
41940
|
+
children: "Try Again"
|
|
41941
|
+
}
|
|
41942
|
+
),
|
|
41943
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
41944
|
+
"button",
|
|
41945
|
+
{
|
|
41946
|
+
className: "error__button error__button--secondary",
|
|
41947
|
+
onClick: () => window.location.reload(),
|
|
41948
|
+
children: "Reload Page"
|
|
41949
|
+
}
|
|
41950
|
+
)
|
|
41951
|
+
] })
|
|
41952
|
+
] }) });
|
|
41953
|
+
}
|
|
41954
|
+
return this.props.children;
|
|
41955
|
+
}
|
|
41956
|
+
};
|
|
41957
|
+
}
|
|
41958
|
+
});
|
|
41959
|
+
function detectAssetRoot2(modelUrl) {
|
|
41960
|
+
const idx = modelUrl.indexOf("/3d/");
|
|
41961
|
+
if (idx !== -1) {
|
|
41962
|
+
return modelUrl.substring(0, idx + 4);
|
|
41963
|
+
}
|
|
41964
|
+
return modelUrl.substring(0, modelUrl.lastIndexOf("/") + 1);
|
|
41965
|
+
}
|
|
41966
|
+
function useGLTFModel(url, resourceBasePath) {
|
|
41967
|
+
const [state, setState] = React83.useState({
|
|
41968
|
+
model: null,
|
|
41969
|
+
isLoading: false,
|
|
41970
|
+
error: null
|
|
41971
|
+
});
|
|
41972
|
+
React83.useEffect(() => {
|
|
41973
|
+
if (!url) {
|
|
41974
|
+
setState({ model: null, isLoading: false, error: null });
|
|
41975
|
+
return;
|
|
41976
|
+
}
|
|
41977
|
+
log12.debug("Loading", { url });
|
|
41978
|
+
setState((prev) => ({ ...prev, isLoading: true, error: null }));
|
|
41979
|
+
const assetRoot = resourceBasePath || detectAssetRoot2(url);
|
|
41980
|
+
const loader = new GLTFLoader.GLTFLoader();
|
|
41981
|
+
loader.setResourcePath(assetRoot);
|
|
41982
|
+
loader.load(
|
|
41983
|
+
url,
|
|
41984
|
+
(gltf) => {
|
|
41985
|
+
log12.debug("Loaded", { url });
|
|
41986
|
+
setState({
|
|
41987
|
+
model: gltf.scene,
|
|
41988
|
+
isLoading: false,
|
|
41989
|
+
error: null
|
|
41990
|
+
});
|
|
41991
|
+
},
|
|
41992
|
+
void 0,
|
|
41993
|
+
(err) => {
|
|
41994
|
+
log12.warn("Failed", { url, error: err instanceof Error ? err : String(err) });
|
|
41995
|
+
setState({
|
|
41996
|
+
model: null,
|
|
41997
|
+
isLoading: false,
|
|
41998
|
+
error: err instanceof Error ? err : new Error(String(err))
|
|
41999
|
+
});
|
|
42000
|
+
}
|
|
42001
|
+
);
|
|
42002
|
+
}, [url, resourceBasePath]);
|
|
42003
|
+
return state;
|
|
42004
|
+
}
|
|
42005
|
+
function ModelLoader({
|
|
42006
|
+
url,
|
|
42007
|
+
position = [0, 0, 0],
|
|
42008
|
+
scale = 1,
|
|
42009
|
+
rotation = [0, 0, 0],
|
|
42010
|
+
isSelected = false,
|
|
42011
|
+
isHovered = false,
|
|
42012
|
+
onClick,
|
|
42013
|
+
onHover,
|
|
42014
|
+
fallbackGeometry = "box",
|
|
42015
|
+
castShadow = true,
|
|
42016
|
+
receiveShadow = true,
|
|
42017
|
+
resourceBasePath
|
|
42018
|
+
}) {
|
|
42019
|
+
const { model: loadedModel, isLoading, error } = useGLTFModel(url, resourceBasePath);
|
|
42020
|
+
const model = React83.useMemo(() => {
|
|
42021
|
+
if (!loadedModel) return null;
|
|
42022
|
+
const cloned = loadedModel.clone();
|
|
42023
|
+
cloned.traverse((child) => {
|
|
42024
|
+
if (child instanceof THREE__namespace.Mesh) {
|
|
42025
|
+
child.castShadow = castShadow;
|
|
42026
|
+
child.receiveShadow = receiveShadow;
|
|
42027
|
+
}
|
|
42028
|
+
});
|
|
42029
|
+
return cloned;
|
|
42030
|
+
}, [loadedModel, castShadow, receiveShadow]);
|
|
42031
|
+
const scaleArray = React83.useMemo(() => {
|
|
42032
|
+
if (typeof scale === "number") {
|
|
42033
|
+
return [scale, scale, scale];
|
|
42034
|
+
}
|
|
42035
|
+
return scale;
|
|
42036
|
+
}, [scale]);
|
|
42037
|
+
const rotationRad = React83.useMemo(() => {
|
|
42038
|
+
return [
|
|
42039
|
+
rotation[0] * Math.PI / 180,
|
|
42040
|
+
rotation[1] * Math.PI / 180,
|
|
42041
|
+
rotation[2] * Math.PI / 180
|
|
42042
|
+
];
|
|
42043
|
+
}, [rotation]);
|
|
42044
|
+
if (isLoading) {
|
|
42045
|
+
return /* @__PURE__ */ jsxRuntime.jsx("group", { position, children: /* @__PURE__ */ jsxRuntime.jsxs("mesh", { rotation: [Math.PI / 2, 0, 0], children: [
|
|
42046
|
+
/* @__PURE__ */ jsxRuntime.jsx("ringGeometry", { args: [0.3, 0.35, 16] }),
|
|
42047
|
+
/* @__PURE__ */ jsxRuntime.jsx("meshBasicMaterial", { color: "#4a90d9", transparent: true, opacity: 0.8 })
|
|
42048
|
+
] }) });
|
|
42049
|
+
}
|
|
42050
|
+
if (error || !model) {
|
|
42051
|
+
if (fallbackGeometry === "none") {
|
|
42052
|
+
return /* @__PURE__ */ jsxRuntime.jsx("group", { position });
|
|
42053
|
+
}
|
|
42054
|
+
const fallbackProps = {
|
|
42055
|
+
onClick,
|
|
42056
|
+
onPointerOver: () => onHover?.(true),
|
|
42057
|
+
onPointerOut: () => onHover?.(false)
|
|
42058
|
+
};
|
|
42059
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("group", { position, children: [
|
|
42060
|
+
(isSelected || isHovered) && /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.02, 0], rotation: [-Math.PI / 2, 0, 0], children: [
|
|
42061
|
+
/* @__PURE__ */ jsxRuntime.jsx("ringGeometry", { args: [0.6, 0.7, 32] }),
|
|
42062
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
42063
|
+
"meshBasicMaterial",
|
|
42064
|
+
{
|
|
42065
|
+
color: isSelected ? 16755200 : 16777215,
|
|
42066
|
+
transparent: true,
|
|
42067
|
+
opacity: 0.5
|
|
42068
|
+
}
|
|
42069
|
+
)
|
|
42070
|
+
] }),
|
|
42071
|
+
fallbackGeometry === "box" && /* @__PURE__ */ jsxRuntime.jsxs("mesh", { ...fallbackProps, position: [0, 0.5, 0], children: [
|
|
42072
|
+
/* @__PURE__ */ jsxRuntime.jsx("boxGeometry", { args: [0.8, 0.8, 0.8] }),
|
|
42073
|
+
/* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color: error ? 16729156 : 8947848 })
|
|
42074
|
+
] }),
|
|
42075
|
+
fallbackGeometry === "sphere" && /* @__PURE__ */ jsxRuntime.jsxs("mesh", { ...fallbackProps, position: [0, 0.5, 0], children: [
|
|
42076
|
+
/* @__PURE__ */ jsxRuntime.jsx("sphereGeometry", { args: [0.4, 16, 16] }),
|
|
42077
|
+
/* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color: error ? 16729156 : 8947848 })
|
|
42078
|
+
] }),
|
|
42079
|
+
fallbackGeometry === "cylinder" && /* @__PURE__ */ jsxRuntime.jsxs("mesh", { ...fallbackProps, position: [0, 0.5, 0], children: [
|
|
42080
|
+
/* @__PURE__ */ jsxRuntime.jsx("cylinderGeometry", { args: [0.3, 0.3, 0.8, 16] }),
|
|
42081
|
+
/* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color: error ? 16729156 : 8947848 })
|
|
42082
|
+
] })
|
|
42083
|
+
] });
|
|
42084
|
+
}
|
|
42085
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
42086
|
+
"group",
|
|
42087
|
+
{
|
|
42088
|
+
position,
|
|
42089
|
+
rotation: rotationRad,
|
|
42090
|
+
onClick,
|
|
42091
|
+
onPointerOver: () => onHover?.(true),
|
|
42092
|
+
onPointerOut: () => onHover?.(false),
|
|
42093
|
+
children: [
|
|
42094
|
+
(isSelected || isHovered) && /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.02, 0], rotation: [-Math.PI / 2, 0, 0], children: [
|
|
42095
|
+
/* @__PURE__ */ jsxRuntime.jsx("ringGeometry", { args: [0.6, 0.7, 32] }),
|
|
42096
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
42097
|
+
"meshBasicMaterial",
|
|
42098
|
+
{
|
|
42099
|
+
color: isSelected ? 16755200 : 16777215,
|
|
42100
|
+
transparent: true,
|
|
42101
|
+
opacity: 0.5
|
|
42102
|
+
}
|
|
42103
|
+
)
|
|
42104
|
+
] }),
|
|
42105
|
+
/* @__PURE__ */ jsxRuntime.jsx("primitive", { object: model, scale: scaleArray })
|
|
42106
|
+
]
|
|
42107
|
+
}
|
|
42108
|
+
);
|
|
42109
|
+
}
|
|
42110
|
+
var log12;
|
|
42111
|
+
var init_ModelLoader = __esm({
|
|
42112
|
+
"components/game/molecules/three/components/ModelLoader.tsx"() {
|
|
42113
|
+
"use client";
|
|
42114
|
+
log12 = logger.createLogger("almadar:ui:game:model-loader");
|
|
42115
|
+
}
|
|
42116
|
+
});
|
|
42117
|
+
|
|
42118
|
+
// components/game/molecules/GameCanvas3D.css
|
|
42119
|
+
var init_GameCanvas3D = __esm({
|
|
42120
|
+
"components/game/molecules/GameCanvas3D.css"() {
|
|
42121
|
+
}
|
|
42122
|
+
});
|
|
42123
|
+
function CameraController({
|
|
42124
|
+
onCameraChange
|
|
42125
|
+
}) {
|
|
42126
|
+
const { camera } = fiber.useThree();
|
|
42127
|
+
React83.useEffect(() => {
|
|
42128
|
+
if (onCameraChange) {
|
|
42129
|
+
onCameraChange({
|
|
42130
|
+
x: camera.position.x,
|
|
42131
|
+
y: camera.position.y,
|
|
42132
|
+
z: camera.position.z
|
|
42133
|
+
});
|
|
42134
|
+
}
|
|
42135
|
+
}, [camera.position, onCameraChange]);
|
|
42136
|
+
return null;
|
|
42137
|
+
}
|
|
42138
|
+
var DEFAULT_GRID_CONFIG, GameCanvas3D;
|
|
42139
|
+
var init_GameCanvas3D2 = __esm({
|
|
42140
|
+
"components/game/molecules/GameCanvas3D.tsx"() {
|
|
42141
|
+
"use client";
|
|
42142
|
+
init_AssetLoader();
|
|
42143
|
+
init_useAssetLoader();
|
|
42144
|
+
init_useGameCanvas3DEvents();
|
|
42145
|
+
init_Canvas3DLoadingState2();
|
|
42146
|
+
init_Canvas3DErrorBoundary2();
|
|
42147
|
+
init_ModelLoader();
|
|
42148
|
+
init_cn();
|
|
42149
|
+
init_GameCanvas3D();
|
|
42150
|
+
DEFAULT_GRID_CONFIG = {
|
|
42151
|
+
cellSize: 1,
|
|
42152
|
+
offsetX: 0,
|
|
42153
|
+
offsetZ: 0
|
|
42154
|
+
};
|
|
42155
|
+
GameCanvas3D = React83.forwardRef(
|
|
42156
|
+
({
|
|
42157
|
+
tiles = [],
|
|
42158
|
+
units = [],
|
|
42159
|
+
features = [],
|
|
42160
|
+
events: events2 = [],
|
|
42161
|
+
orientation = "standard",
|
|
42162
|
+
cameraMode = "isometric",
|
|
42163
|
+
showGrid = true,
|
|
42164
|
+
showCoordinates = false,
|
|
42165
|
+
showTileInfo = false,
|
|
42166
|
+
overlay = "default",
|
|
42167
|
+
shadows = true,
|
|
42168
|
+
backgroundColor = "#1a1a2e",
|
|
42169
|
+
onTileClick,
|
|
42170
|
+
onUnitClick,
|
|
42171
|
+
onFeatureClick,
|
|
42172
|
+
onCanvasClick,
|
|
42173
|
+
onTileHover,
|
|
42174
|
+
onUnitAnimation,
|
|
42175
|
+
assetLoader: customAssetLoader,
|
|
42176
|
+
tileRenderer: CustomTileRenderer,
|
|
42177
|
+
unitRenderer: CustomUnitRenderer,
|
|
42178
|
+
featureRenderer: CustomFeatureRenderer,
|
|
42179
|
+
className,
|
|
42180
|
+
isLoading: externalLoading,
|
|
42181
|
+
error: externalError,
|
|
42182
|
+
entity,
|
|
42183
|
+
preloadAssets = [],
|
|
42184
|
+
tileClickEvent,
|
|
42185
|
+
unitClickEvent,
|
|
42186
|
+
featureClickEvent,
|
|
42187
|
+
canvasClickEvent,
|
|
42188
|
+
tileHoverEvent,
|
|
42189
|
+
tileLeaveEvent,
|
|
42190
|
+
unitAnimationEvent,
|
|
42191
|
+
cameraChangeEvent,
|
|
42192
|
+
loadingMessage = "Loading 3D Scene...",
|
|
42193
|
+
useInstancing = true,
|
|
42194
|
+
validMoves = [],
|
|
42195
|
+
attackTargets = [],
|
|
42196
|
+
selectedTileIds = [],
|
|
42197
|
+
selectedUnitId = null,
|
|
42198
|
+
children
|
|
42199
|
+
}, ref) => {
|
|
42200
|
+
const containerRef = React83.useRef(null);
|
|
42201
|
+
const controlsRef = React83.useRef(null);
|
|
42202
|
+
const [hoveredTile, setHoveredTile] = React83.useState(null);
|
|
42203
|
+
const [internalError, setInternalError] = React83.useState(null);
|
|
42204
|
+
const { isLoading: assetsLoading, progress, loaded, total } = useAssetLoader({
|
|
42205
|
+
preloadUrls: preloadAssets,
|
|
42206
|
+
loader: customAssetLoader
|
|
42207
|
+
});
|
|
42208
|
+
const eventHandlers = useGameCanvas3DEvents({
|
|
42209
|
+
tileClickEvent,
|
|
42210
|
+
unitClickEvent,
|
|
42211
|
+
featureClickEvent,
|
|
42212
|
+
canvasClickEvent,
|
|
42213
|
+
tileHoverEvent,
|
|
42214
|
+
tileLeaveEvent,
|
|
42215
|
+
unitAnimationEvent,
|
|
42216
|
+
cameraChangeEvent,
|
|
42217
|
+
onTileClick,
|
|
42218
|
+
onUnitClick,
|
|
42219
|
+
onFeatureClick,
|
|
42220
|
+
onCanvasClick,
|
|
42221
|
+
onTileHover,
|
|
42222
|
+
onUnitAnimation
|
|
42223
|
+
});
|
|
42224
|
+
const gridBounds = React83.useMemo(() => {
|
|
42225
|
+
if (tiles.length === 0) {
|
|
42226
|
+
return { minX: 0, maxX: 10, minZ: 0, maxZ: 10 };
|
|
42227
|
+
}
|
|
42228
|
+
const xs = tiles.map((t) => t.x);
|
|
42229
|
+
const zs = tiles.map((t) => t.z || t.y || 0);
|
|
42230
|
+
return {
|
|
42231
|
+
minX: Math.min(...xs),
|
|
42232
|
+
maxX: Math.max(...xs),
|
|
42233
|
+
minZ: Math.min(...zs),
|
|
42234
|
+
maxZ: Math.max(...zs)
|
|
42235
|
+
};
|
|
42236
|
+
}, [tiles]);
|
|
42237
|
+
const cameraTarget = React83.useMemo(() => {
|
|
42238
|
+
return [
|
|
42239
|
+
(gridBounds.minX + gridBounds.maxX) / 2,
|
|
42240
|
+
0,
|
|
42241
|
+
(gridBounds.minZ + gridBounds.maxZ) / 2
|
|
42242
|
+
];
|
|
42243
|
+
}, [gridBounds]);
|
|
42244
|
+
const gridConfig = React83.useMemo(
|
|
42245
|
+
() => ({
|
|
42246
|
+
...DEFAULT_GRID_CONFIG,
|
|
42247
|
+
offsetX: -(gridBounds.maxX - gridBounds.minX) / 2,
|
|
42248
|
+
offsetZ: -(gridBounds.maxZ - gridBounds.minZ) / 2
|
|
42249
|
+
}),
|
|
42250
|
+
[gridBounds]
|
|
42251
|
+
);
|
|
42252
|
+
const gridToWorld = React83.useCallback(
|
|
42253
|
+
(x, z, y = 0) => {
|
|
42254
|
+
const worldX = (x - gridBounds.minX) * gridConfig.cellSize;
|
|
42255
|
+
const worldZ = (z - gridBounds.minZ) * gridConfig.cellSize;
|
|
42256
|
+
return [worldX, y * gridConfig.cellSize, worldZ];
|
|
42257
|
+
},
|
|
42258
|
+
[gridBounds, gridConfig]
|
|
42259
|
+
);
|
|
42260
|
+
React83.useImperativeHandle(ref, () => ({
|
|
42261
|
+
getCameraPosition: () => {
|
|
42262
|
+
if (controlsRef.current) {
|
|
42263
|
+
const pos = controlsRef.current.object.position;
|
|
42264
|
+
return new THREE__namespace.Vector3(pos.x, pos.y, pos.z);
|
|
42265
|
+
}
|
|
42266
|
+
return null;
|
|
42267
|
+
},
|
|
42268
|
+
setCameraPosition: (x, y, z) => {
|
|
42269
|
+
if (controlsRef.current) {
|
|
42270
|
+
controlsRef.current.object.position.set(x, y, z);
|
|
42271
|
+
controlsRef.current.update();
|
|
42272
|
+
}
|
|
42273
|
+
},
|
|
42274
|
+
lookAt: (x, y, z) => {
|
|
42275
|
+
if (controlsRef.current) {
|
|
42276
|
+
controlsRef.current.target.set(x, y, z);
|
|
42277
|
+
controlsRef.current.update();
|
|
42278
|
+
}
|
|
42279
|
+
},
|
|
42280
|
+
resetCamera: () => {
|
|
42281
|
+
if (controlsRef.current) {
|
|
42282
|
+
controlsRef.current.reset();
|
|
42283
|
+
}
|
|
42284
|
+
},
|
|
42285
|
+
screenshot: () => {
|
|
42286
|
+
const canvas = containerRef.current?.querySelector("canvas");
|
|
42287
|
+
if (canvas) {
|
|
42288
|
+
return canvas.toDataURL("image/png");
|
|
42289
|
+
}
|
|
42290
|
+
return null;
|
|
42291
|
+
},
|
|
42292
|
+
export: () => ({
|
|
42293
|
+
tiles,
|
|
42294
|
+
units,
|
|
42295
|
+
features
|
|
42296
|
+
})
|
|
42297
|
+
}));
|
|
42298
|
+
const handleTileClick = React83.useCallback(
|
|
42299
|
+
(tile, event) => {
|
|
42300
|
+
eventHandlers.handleTileClick(tile, event);
|
|
42301
|
+
},
|
|
42302
|
+
[eventHandlers]
|
|
42303
|
+
);
|
|
42304
|
+
const handleUnitClick = React83.useCallback(
|
|
42305
|
+
(unit, event) => {
|
|
42306
|
+
eventHandlers.handleUnitClick(unit, event);
|
|
42307
|
+
},
|
|
42308
|
+
[eventHandlers]
|
|
42309
|
+
);
|
|
42310
|
+
const handleFeatureClick = React83.useCallback(
|
|
42311
|
+
(feature, event) => {
|
|
42312
|
+
if (event) {
|
|
42313
|
+
eventHandlers.handleFeatureClick(feature, event);
|
|
42314
|
+
}
|
|
42315
|
+
},
|
|
42316
|
+
[eventHandlers]
|
|
42317
|
+
);
|
|
42318
|
+
const handleTileHover = React83.useCallback(
|
|
42319
|
+
(tile, event) => {
|
|
42320
|
+
setHoveredTile(tile);
|
|
42321
|
+
if (event) {
|
|
42322
|
+
eventHandlers.handleTileHover(tile, event);
|
|
42323
|
+
}
|
|
42324
|
+
},
|
|
42325
|
+
[eventHandlers]
|
|
42326
|
+
);
|
|
42327
|
+
const cameraConfig = React83.useMemo(() => {
|
|
42328
|
+
const size = Math.max(
|
|
42329
|
+
gridBounds.maxX - gridBounds.minX,
|
|
42330
|
+
gridBounds.maxZ - gridBounds.minZ
|
|
42331
|
+
);
|
|
42332
|
+
const distance = size * 1.5;
|
|
42333
|
+
switch (cameraMode) {
|
|
42334
|
+
case "isometric":
|
|
42335
|
+
return {
|
|
42336
|
+
position: [distance, distance * 0.8, distance],
|
|
42337
|
+
fov: 45
|
|
42338
|
+
};
|
|
42339
|
+
case "top-down":
|
|
42340
|
+
return {
|
|
42341
|
+
position: [0, distance * 2, 0],
|
|
42342
|
+
fov: 45
|
|
42343
|
+
};
|
|
42344
|
+
case "perspective":
|
|
42345
|
+
default:
|
|
42346
|
+
return {
|
|
42347
|
+
position: [distance, distance, distance],
|
|
42348
|
+
fov: 45
|
|
42349
|
+
};
|
|
42350
|
+
}
|
|
42351
|
+
}, [cameraMode, gridBounds]);
|
|
42352
|
+
const DefaultTileRenderer = React83.useCallback(
|
|
42353
|
+
({ tile, position }) => {
|
|
42354
|
+
const isSelected = tile.id ? selectedTileIds.includes(tile.id) : false;
|
|
42355
|
+
const isHovered = hoveredTile?.id === tile.id;
|
|
42356
|
+
const isValidMove = validMoves.some(
|
|
42357
|
+
(m) => m.x === tile.x && m.z === (tile.z ?? tile.y ?? 0)
|
|
42358
|
+
);
|
|
42359
|
+
const isAttackTarget = attackTargets.some(
|
|
42360
|
+
(m) => m.x === tile.x && m.z === (tile.z ?? tile.y ?? 0)
|
|
42361
|
+
);
|
|
42362
|
+
let color = 8421504;
|
|
42363
|
+
if (tile.type === "water") color = 4491468;
|
|
42364
|
+
else if (tile.type === "grass") color = 4500036;
|
|
42365
|
+
else if (tile.type === "sand") color = 14535816;
|
|
42366
|
+
else if (tile.type === "rock") color = 8947848;
|
|
42367
|
+
else if (tile.type === "snow") color = 15658734;
|
|
42368
|
+
let emissive = 0;
|
|
42369
|
+
if (isSelected) emissive = 4473924;
|
|
42370
|
+
else if (isAttackTarget) emissive = 4456448;
|
|
42371
|
+
else if (isValidMove) emissive = 17408;
|
|
42372
|
+
else if (isHovered) emissive = 2236962;
|
|
42373
|
+
if (tile.modelUrl) {
|
|
42374
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
42375
|
+
"group",
|
|
42376
|
+
{
|
|
42377
|
+
position,
|
|
42378
|
+
onClick: (e) => handleTileClick(tile, e),
|
|
42379
|
+
onPointerEnter: (e) => handleTileHover(tile, e),
|
|
42380
|
+
onPointerLeave: (e) => handleTileHover(null, e),
|
|
42381
|
+
userData: { type: "tile", tileId: tile.id, gridX: tile.x, gridZ: tile.z ?? tile.y },
|
|
42382
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
42383
|
+
ModelLoader,
|
|
42384
|
+
{
|
|
42385
|
+
url: tile.modelUrl,
|
|
42386
|
+
scale: 0.95,
|
|
42387
|
+
fallbackGeometry: "box",
|
|
42388
|
+
castShadow: true,
|
|
42389
|
+
receiveShadow: true
|
|
42390
|
+
}
|
|
42391
|
+
)
|
|
42392
|
+
}
|
|
42393
|
+
);
|
|
42394
|
+
}
|
|
42395
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
42396
|
+
"mesh",
|
|
42397
|
+
{
|
|
42398
|
+
position,
|
|
42399
|
+
onClick: (e) => handleTileClick(tile, e),
|
|
42400
|
+
onPointerEnter: (e) => handleTileHover(tile, e),
|
|
42401
|
+
onPointerLeave: (e) => handleTileHover(null, e),
|
|
42402
|
+
userData: { type: "tile", tileId: tile.id, gridX: tile.x, gridZ: tile.z ?? tile.y },
|
|
42403
|
+
children: [
|
|
42404
|
+
/* @__PURE__ */ jsxRuntime.jsx("boxGeometry", { args: [0.95, 0.2, 0.95] }),
|
|
42405
|
+
/* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color, emissive })
|
|
42406
|
+
]
|
|
42407
|
+
}
|
|
42408
|
+
);
|
|
42409
|
+
},
|
|
42410
|
+
[selectedTileIds, hoveredTile, validMoves, attackTargets, handleTileClick, handleTileHover]
|
|
42411
|
+
);
|
|
42412
|
+
const DefaultUnitRenderer = React83.useCallback(
|
|
42413
|
+
({ unit, position }) => {
|
|
42414
|
+
const isSelected = selectedUnitId === unit.id;
|
|
42415
|
+
const color = unit.faction === "player" ? 4491519 : unit.faction === "enemy" ? 16729156 : 16777028;
|
|
42416
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
42417
|
+
"group",
|
|
42418
|
+
{
|
|
42419
|
+
position,
|
|
42420
|
+
onClick: (e) => handleUnitClick(unit, e),
|
|
42421
|
+
userData: { type: "unit", unitId: unit.id },
|
|
42422
|
+
children: [
|
|
42423
|
+
isSelected && /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.05, 0], rotation: [-Math.PI / 2, 0, 0], children: [
|
|
42424
|
+
/* @__PURE__ */ jsxRuntime.jsx("ringGeometry", { args: [0.4, 0.5, 32] }),
|
|
42425
|
+
/* @__PURE__ */ jsxRuntime.jsx("meshBasicMaterial", { color: "#ffff00", transparent: true, opacity: 0.8 })
|
|
42426
|
+
] }),
|
|
42427
|
+
unit.modelUrl ? (
|
|
42428
|
+
/* GLB unit model (box fallback while loading / on error) */
|
|
42429
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
42430
|
+
ModelLoader,
|
|
42431
|
+
{
|
|
42432
|
+
url: unit.modelUrl,
|
|
42433
|
+
scale: 0.5,
|
|
42434
|
+
fallbackGeometry: "box",
|
|
42435
|
+
castShadow: true
|
|
42436
|
+
}
|
|
42437
|
+
)
|
|
42438
|
+
) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
42439
|
+
/* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.3, 0], children: [
|
|
42440
|
+
/* @__PURE__ */ jsxRuntime.jsx("cylinderGeometry", { args: [0.3, 0.3, 0.1, 8] }),
|
|
42441
|
+
/* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color })
|
|
42442
|
+
] }),
|
|
42443
|
+
/* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.6, 0], children: [
|
|
42444
|
+
/* @__PURE__ */ jsxRuntime.jsx("capsuleGeometry", { args: [0.2, 0.4, 4, 8] }),
|
|
42445
|
+
/* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color })
|
|
42446
|
+
] }),
|
|
42447
|
+
/* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.9, 0], children: [
|
|
42448
|
+
/* @__PURE__ */ jsxRuntime.jsx("sphereGeometry", { args: [0.12, 8, 8] }),
|
|
42449
|
+
/* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color })
|
|
42450
|
+
] })
|
|
42451
|
+
] }),
|
|
42452
|
+
unit.health !== void 0 && unit.maxHealth !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs("group", { position: [0, 1.2, 0], children: [
|
|
42453
|
+
/* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [-0.25, 0, 0], children: [
|
|
42454
|
+
/* @__PURE__ */ jsxRuntime.jsx("planeGeometry", { args: [0.5, 0.05] }),
|
|
42455
|
+
/* @__PURE__ */ jsxRuntime.jsx("meshBasicMaterial", { color: 3355443 })
|
|
42456
|
+
] }),
|
|
42457
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
42458
|
+
"mesh",
|
|
42459
|
+
{
|
|
42460
|
+
position: [
|
|
42461
|
+
-0.25 + 0.5 * (unit.health / unit.maxHealth) / 2,
|
|
42462
|
+
0,
|
|
42463
|
+
0.01
|
|
42464
|
+
],
|
|
42465
|
+
children: [
|
|
42466
|
+
/* @__PURE__ */ jsxRuntime.jsx("planeGeometry", { args: [0.5 * (unit.health / unit.maxHealth), 0.05] }),
|
|
42467
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
42468
|
+
"meshBasicMaterial",
|
|
42469
|
+
{
|
|
42470
|
+
color: unit.health / unit.maxHealth > 0.5 ? 4500036 : unit.health / unit.maxHealth > 0.25 ? 11184708 : 16729156
|
|
42471
|
+
}
|
|
42472
|
+
)
|
|
42473
|
+
]
|
|
42474
|
+
}
|
|
42475
|
+
)
|
|
42476
|
+
] })
|
|
42477
|
+
]
|
|
42478
|
+
}
|
|
42479
|
+
);
|
|
42480
|
+
},
|
|
42481
|
+
[selectedUnitId, handleUnitClick]
|
|
42482
|
+
);
|
|
42483
|
+
const DefaultFeatureRenderer = React83.useCallback(
|
|
42484
|
+
({
|
|
42485
|
+
feature,
|
|
42486
|
+
position
|
|
42487
|
+
}) => {
|
|
42488
|
+
if (feature.assetUrl) {
|
|
42489
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
42490
|
+
ModelLoader,
|
|
42491
|
+
{
|
|
42492
|
+
url: feature.assetUrl,
|
|
42493
|
+
position,
|
|
42494
|
+
scale: 0.5,
|
|
42495
|
+
rotation: [0, feature.rotation ?? 0, 0],
|
|
42496
|
+
onClick: () => handleFeatureClick(feature, null),
|
|
42497
|
+
fallbackGeometry: "box"
|
|
42498
|
+
},
|
|
42499
|
+
feature.id
|
|
42500
|
+
);
|
|
42501
|
+
}
|
|
42502
|
+
if (feature.type === "tree") {
|
|
42503
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
42504
|
+
"group",
|
|
42505
|
+
{
|
|
42506
|
+
position,
|
|
42507
|
+
onClick: (e) => handleFeatureClick(feature, e),
|
|
42508
|
+
userData: { type: "feature", featureId: feature.id },
|
|
42509
|
+
children: [
|
|
42510
|
+
/* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.4, 0], children: [
|
|
42511
|
+
/* @__PURE__ */ jsxRuntime.jsx("cylinderGeometry", { args: [0.1, 0.15, 0.8, 6] }),
|
|
42512
|
+
/* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color: 9127187 })
|
|
42513
|
+
] }),
|
|
42514
|
+
/* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.9, 0], children: [
|
|
42515
|
+
/* @__PURE__ */ jsxRuntime.jsx("coneGeometry", { args: [0.5, 0.8, 8] }),
|
|
42516
|
+
/* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color: 2263842 })
|
|
42517
|
+
] })
|
|
42518
|
+
]
|
|
42519
|
+
}
|
|
42520
|
+
);
|
|
42521
|
+
}
|
|
42522
|
+
if (feature.type === "rock") {
|
|
42523
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
42524
|
+
"mesh",
|
|
42525
|
+
{
|
|
42526
|
+
position: [position[0], position[1] + 0.3, position[2]],
|
|
42527
|
+
onClick: (e) => handleFeatureClick(feature, e),
|
|
42528
|
+
userData: { type: "feature", featureId: feature.id },
|
|
42529
|
+
children: [
|
|
42530
|
+
/* @__PURE__ */ jsxRuntime.jsx("dodecahedronGeometry", { args: [0.3, 0] }),
|
|
42531
|
+
/* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color: 8421504 })
|
|
42532
|
+
]
|
|
42533
|
+
}
|
|
42534
|
+
);
|
|
42535
|
+
}
|
|
42536
|
+
return null;
|
|
42537
|
+
},
|
|
42538
|
+
[handleFeatureClick]
|
|
42539
|
+
);
|
|
42540
|
+
if (externalLoading || assetsLoading && preloadAssets.length > 0) {
|
|
42541
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
42542
|
+
Canvas3DLoadingState,
|
|
42543
|
+
{
|
|
42544
|
+
progress,
|
|
42545
|
+
loaded,
|
|
42546
|
+
total,
|
|
42547
|
+
message: loadingMessage,
|
|
42548
|
+
className
|
|
42549
|
+
}
|
|
42550
|
+
);
|
|
42551
|
+
}
|
|
42552
|
+
const displayError = externalError || internalError;
|
|
42553
|
+
if (displayError) {
|
|
42554
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Canvas3DErrorBoundary, { children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "game-canvas-3d game-canvas-3d--error", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "game-canvas-3d__error", children: [
|
|
42555
|
+
"Error: ",
|
|
42556
|
+
displayError
|
|
42557
|
+
] }) }) });
|
|
42558
|
+
}
|
|
42559
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
42560
|
+
Canvas3DErrorBoundary,
|
|
42561
|
+
{
|
|
42562
|
+
onError: (err) => setInternalError(err.message),
|
|
42563
|
+
onReset: () => setInternalError(null),
|
|
42564
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
42565
|
+
"div",
|
|
42566
|
+
{
|
|
42567
|
+
ref: containerRef,
|
|
42568
|
+
className: cn("game-canvas-3d relative w-full h-full min-h-[85vh] overflow-hidden", className),
|
|
42569
|
+
"data-orientation": orientation,
|
|
42570
|
+
"data-camera-mode": cameraMode,
|
|
42571
|
+
"data-overlay": overlay,
|
|
42572
|
+
children: [
|
|
42573
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
42574
|
+
fiber.Canvas,
|
|
42575
|
+
{
|
|
42576
|
+
shadows,
|
|
42577
|
+
camera: {
|
|
42578
|
+
position: cameraConfig.position,
|
|
42579
|
+
fov: cameraConfig.fov,
|
|
42580
|
+
near: 0.1,
|
|
42581
|
+
far: 1e3
|
|
42582
|
+
},
|
|
42583
|
+
style: { background: backgroundColor },
|
|
42584
|
+
onClick: (e) => {
|
|
42585
|
+
if (e.target === e.currentTarget) {
|
|
42586
|
+
eventHandlers.handleCanvasClick(e);
|
|
42587
|
+
}
|
|
42588
|
+
},
|
|
42589
|
+
children: [
|
|
42590
|
+
/* @__PURE__ */ jsxRuntime.jsx(CameraController, { onCameraChange: eventHandlers.handleCameraChange }),
|
|
42591
|
+
/* @__PURE__ */ jsxRuntime.jsx("ambientLight", { intensity: 0.6 }),
|
|
42592
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
42593
|
+
"directionalLight",
|
|
42594
|
+
{
|
|
42595
|
+
position: [10, 20, 10],
|
|
42596
|
+
intensity: 0.8,
|
|
42597
|
+
castShadow: shadows,
|
|
42598
|
+
"shadow-mapSize": [2048, 2048]
|
|
42599
|
+
}
|
|
42600
|
+
),
|
|
42601
|
+
/* @__PURE__ */ jsxRuntime.jsx("hemisphereLight", { intensity: 0.3, color: "#87ceeb", groundColor: "#362d1d" }),
|
|
42602
|
+
showGrid && /* @__PURE__ */ jsxRuntime.jsx(
|
|
42603
|
+
drei.Grid,
|
|
42604
|
+
{
|
|
42605
|
+
args: [
|
|
42606
|
+
Math.max(gridBounds.maxX - gridBounds.minX + 2, 10),
|
|
42607
|
+
Math.max(gridBounds.maxZ - gridBounds.minZ + 2, 10)
|
|
42608
|
+
],
|
|
42609
|
+
position: [
|
|
42610
|
+
(gridBounds.maxX - gridBounds.minX) / 2 - 0.5,
|
|
42611
|
+
0,
|
|
42612
|
+
(gridBounds.maxZ - gridBounds.minZ) / 2 - 0.5
|
|
42613
|
+
],
|
|
42614
|
+
cellSize: 1,
|
|
42615
|
+
cellThickness: 1,
|
|
42616
|
+
cellColor: "#444444",
|
|
42617
|
+
sectionSize: 5,
|
|
42618
|
+
sectionThickness: 1.5,
|
|
42619
|
+
sectionColor: "#666666",
|
|
42620
|
+
fadeDistance: 50,
|
|
42621
|
+
fadeStrength: 1
|
|
42622
|
+
}
|
|
42623
|
+
),
|
|
42624
|
+
tiles.map((tile, index) => {
|
|
42625
|
+
const position = gridToWorld(
|
|
42626
|
+
tile.x,
|
|
42627
|
+
tile.z ?? tile.y ?? 0,
|
|
42628
|
+
tile.elevation ?? 0
|
|
42629
|
+
);
|
|
42630
|
+
const Renderer = CustomTileRenderer || DefaultTileRenderer;
|
|
42631
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Renderer, { tile, position }, tile.id ?? `tile-${index}`);
|
|
42632
|
+
}),
|
|
42633
|
+
features.map((feature, index) => {
|
|
42634
|
+
const position = gridToWorld(
|
|
42635
|
+
feature.x,
|
|
42636
|
+
feature.z ?? feature.y ?? 0,
|
|
42637
|
+
(feature.elevation ?? 0) + 0.5
|
|
42638
|
+
);
|
|
42639
|
+
const Renderer = CustomFeatureRenderer || DefaultFeatureRenderer;
|
|
42640
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Renderer, { feature, position }, feature.id ?? `feature-${index}`);
|
|
42641
|
+
}),
|
|
42642
|
+
units.map((unit) => {
|
|
42643
|
+
const position = gridToWorld(
|
|
42644
|
+
unit.x ?? 0,
|
|
42645
|
+
unit.z ?? unit.y ?? 0,
|
|
42646
|
+
(unit.elevation ?? 0) + 0.5
|
|
42647
|
+
);
|
|
42648
|
+
const Renderer = CustomUnitRenderer || DefaultUnitRenderer;
|
|
42649
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Renderer, { unit, position }, unit.id);
|
|
42650
|
+
}),
|
|
42651
|
+
children,
|
|
42652
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
42653
|
+
drei.OrbitControls,
|
|
42654
|
+
{
|
|
42655
|
+
ref: controlsRef,
|
|
42656
|
+
target: cameraTarget,
|
|
42657
|
+
enableDamping: true,
|
|
42658
|
+
dampingFactor: 0.05,
|
|
42659
|
+
minDistance: 2,
|
|
42660
|
+
maxDistance: 100,
|
|
42661
|
+
maxPolarAngle: Math.PI / 2 - 0.1
|
|
42662
|
+
}
|
|
42663
|
+
)
|
|
42664
|
+
]
|
|
42665
|
+
}
|
|
42666
|
+
),
|
|
42667
|
+
showCoordinates && hoveredTile && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "game-canvas-3d__coordinates", children: [
|
|
42668
|
+
"X: ",
|
|
42669
|
+
hoveredTile.x,
|
|
42670
|
+
", Z: ",
|
|
42671
|
+
hoveredTile.z ?? hoveredTile.y ?? 0
|
|
42672
|
+
] }),
|
|
42673
|
+
showTileInfo && hoveredTile && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "game-canvas-3d__tile-info", children: [
|
|
42674
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "tile-info__type", children: hoveredTile.type }),
|
|
42675
|
+
hoveredTile.terrain && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "tile-info__terrain", children: hoveredTile.terrain })
|
|
42676
|
+
] })
|
|
42677
|
+
]
|
|
42678
|
+
}
|
|
42679
|
+
)
|
|
42680
|
+
}
|
|
42681
|
+
);
|
|
42682
|
+
}
|
|
42683
|
+
);
|
|
42684
|
+
GameCanvas3D.displayName = "GameCanvas3D";
|
|
42685
|
+
}
|
|
42686
|
+
});
|
|
42687
|
+
function GameBoard3D({
|
|
42688
|
+
entity,
|
|
42689
|
+
tiles = [],
|
|
42690
|
+
features = [],
|
|
42691
|
+
cameraMode = "perspective",
|
|
42692
|
+
backgroundColor = "#2a1a1a",
|
|
42693
|
+
tileClickEvent,
|
|
42694
|
+
unitClickEvent,
|
|
42695
|
+
attackEvent,
|
|
42696
|
+
endTurnEvent,
|
|
42697
|
+
cancelEvent,
|
|
42698
|
+
playAgainEvent,
|
|
42699
|
+
gameEndEvent,
|
|
42700
|
+
className
|
|
42701
|
+
}) {
|
|
42702
|
+
const row = boardEntity(entity);
|
|
42703
|
+
const eventBus = useEventBus();
|
|
42704
|
+
const entityUnits = row ? rows(row.units) : [];
|
|
42705
|
+
const units = entityUnits;
|
|
42706
|
+
const selectedUnitId = row ? str(row.selectedUnitId) || null : null;
|
|
42707
|
+
const phase = row ? str(row.phase) : "observation";
|
|
42708
|
+
const result = row ? str(row.result) : "none";
|
|
42709
|
+
const validMoves = row && Array.isArray(row.validMoves) ? row.validMoves : [];
|
|
42710
|
+
const attackTargets = row && Array.isArray(row.attackTargets) ? row.attackTargets : [];
|
|
42711
|
+
const turn = row ? num(row.turn) : 0;
|
|
42712
|
+
const currentTeam = row ? str(row.currentTeam) : "player";
|
|
42713
|
+
const isGameOver = result !== "none";
|
|
42714
|
+
const gameEndEmittedRef = React83.useRef(false);
|
|
42715
|
+
React83.useEffect(() => {
|
|
42716
|
+
if ((result === "victory" || result === "defeat") && gameEndEvent) {
|
|
42717
|
+
if (!gameEndEmittedRef.current) {
|
|
42718
|
+
gameEndEmittedRef.current = true;
|
|
42719
|
+
eventBus.emit(`UI:${gameEndEvent}`, { result });
|
|
42720
|
+
}
|
|
42721
|
+
} else {
|
|
42722
|
+
gameEndEmittedRef.current = false;
|
|
42723
|
+
}
|
|
42724
|
+
}, [result, gameEndEvent, eventBus]);
|
|
42725
|
+
const checkGameEnd = React83.useCallback(() => {
|
|
42726
|
+
const alivePlayer = entityUnits.filter((u) => unitTeam(u) === "player" && unitHealth(u) > 0);
|
|
42727
|
+
const aliveEnemy = entityUnits.filter((u) => unitTeam(u) === "enemy" && unitHealth(u) > 0);
|
|
42728
|
+
if (alivePlayer.length === 0 && gameEndEvent) {
|
|
42729
|
+
eventBus.emit(`UI:${gameEndEvent}`, { result: "defeat" });
|
|
42730
|
+
} else if (aliveEnemy.length === 0 && gameEndEvent) {
|
|
42731
|
+
eventBus.emit(`UI:${gameEndEvent}`, { result: "victory" });
|
|
42732
|
+
}
|
|
42733
|
+
}, [entityUnits, gameEndEvent, eventBus]);
|
|
42734
|
+
const handleUnitClickCallback = React83.useCallback((isoUnit) => {
|
|
42735
|
+
if (phase !== "action" || !selectedUnitId || !attackEvent) return;
|
|
42736
|
+
const attackerRow = entityUnits.find((u) => str(u.id) === selectedUnitId);
|
|
42737
|
+
const targetRow = entityUnits.find((u) => str(u.id) === isoUnit.id);
|
|
42738
|
+
if (!attackerRow || !targetRow) return;
|
|
42739
|
+
if (unitTeam(targetRow) !== "enemy" || unitHealth(targetRow) <= 0) return;
|
|
42740
|
+
const ap = unitPosition(attackerRow);
|
|
42741
|
+
const tp = unitPosition(targetRow);
|
|
42742
|
+
const dx = Math.abs(ap.x - tp.x);
|
|
42743
|
+
const dy = Math.abs(ap.y - tp.y);
|
|
42744
|
+
if (dx <= 1 && dy <= 1 && dx + dy > 0) {
|
|
42745
|
+
const damage = Math.max(1, num(attackerRow.attack) - num(targetRow.defense));
|
|
42746
|
+
eventBus.emit(`UI:${attackEvent}`, {
|
|
42747
|
+
attackerId: str(attackerRow.id),
|
|
42748
|
+
targetId: str(targetRow.id),
|
|
42749
|
+
damage
|
|
42750
|
+
});
|
|
42751
|
+
setTimeout(checkGameEnd, 100);
|
|
42752
|
+
}
|
|
42753
|
+
}, [phase, selectedUnitId, entityUnits, attackEvent, eventBus, checkGameEnd]);
|
|
42754
|
+
const handleEndTurn = React83.useCallback(() => {
|
|
42755
|
+
if (endTurnEvent) eventBus.emit(`UI:${endTurnEvent}`, {});
|
|
42756
|
+
}, [endTurnEvent, eventBus]);
|
|
42757
|
+
const handleCancel = React83.useCallback(() => {
|
|
42758
|
+
if (cancelEvent) eventBus.emit(`UI:${cancelEvent}`, {});
|
|
42759
|
+
}, [cancelEvent, eventBus]);
|
|
42760
|
+
const handlePlayAgain = React83.useCallback(() => {
|
|
42761
|
+
if (playAgainEvent) eventBus.emit(`UI:${playAgainEvent}`, {});
|
|
42762
|
+
}, [playAgainEvent, eventBus]);
|
|
42763
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(VStack, { className: cn("game-board-3d block w-full min-h-[85vh] relative", className), children: [
|
|
42764
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "game-board-3d__status absolute top-3 left-3 z-10 flex gap-2 items-center", children: [
|
|
42765
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", className: "status__phase capitalize", children: phase.replace("_", " ") }),
|
|
42766
|
+
currentTeam && !isGameOver && /* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "small", color: "muted", className: "status__team", children: [
|
|
42767
|
+
"\u2014 ",
|
|
42768
|
+
currentTeam === "player" ? "Your Turn" : "Enemy's Turn"
|
|
42769
|
+
] }),
|
|
42770
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "small", color: "muted", className: "status__turn", children: [
|
|
42771
|
+
"Turn ",
|
|
42772
|
+
turn
|
|
42773
|
+
] })
|
|
42774
|
+
] }),
|
|
42775
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
42776
|
+
GameCanvas3D,
|
|
42777
|
+
{
|
|
42778
|
+
tiles,
|
|
42779
|
+
units,
|
|
42780
|
+
features,
|
|
42781
|
+
cameraMode,
|
|
42782
|
+
showGrid: true,
|
|
42783
|
+
showCoordinates: false,
|
|
42784
|
+
showTileInfo: false,
|
|
42785
|
+
shadows: true,
|
|
42786
|
+
backgroundColor,
|
|
42787
|
+
tileClickEvent,
|
|
42788
|
+
unitClickEvent,
|
|
42789
|
+
onUnitClick: handleUnitClickCallback,
|
|
42790
|
+
selectedUnitId,
|
|
42791
|
+
validMoves,
|
|
42792
|
+
attackTargets,
|
|
42793
|
+
className: "game-board-3d__canvas w-full min-h-[85vh]"
|
|
42794
|
+
}
|
|
42795
|
+
),
|
|
42796
|
+
!isGameOver && /* @__PURE__ */ jsxRuntime.jsxs(HStack, { className: "fixed bottom-6 right-6 z-50", gap: "sm", children: [
|
|
42797
|
+
(phase === "selection" || phase === "movement" || phase === "action") && /* @__PURE__ */ jsxRuntime.jsx(
|
|
42798
|
+
Button,
|
|
42799
|
+
{
|
|
42800
|
+
variant: "secondary",
|
|
42801
|
+
className: "shadow-xl",
|
|
42802
|
+
onClick: handleCancel,
|
|
42803
|
+
children: "Cancel"
|
|
42804
|
+
}
|
|
42805
|
+
),
|
|
42806
|
+
phase !== "enemy_turn" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
42807
|
+
Button,
|
|
42808
|
+
{
|
|
42809
|
+
variant: "primary",
|
|
42810
|
+
className: "shadow-xl",
|
|
42811
|
+
onClick: handleEndTurn,
|
|
42812
|
+
children: "End Turn"
|
|
42813
|
+
}
|
|
42814
|
+
)
|
|
42815
|
+
] }),
|
|
42816
|
+
isGameOver && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "game-board-3d__overlay absolute inset-0 z-20 flex items-center justify-center bg-black/60", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { align: "center", gap: "md", className: "overlay__card p-8 rounded-xl bg-gray-900/90 shadow-2xl", children: [
|
|
42817
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
42818
|
+
Typography,
|
|
42819
|
+
{
|
|
42820
|
+
variant: "h2",
|
|
42821
|
+
className: cn(
|
|
42822
|
+
"overlay__result",
|
|
42823
|
+
result === "victory" ? "text-yellow-400" : "text-red-500"
|
|
42824
|
+
),
|
|
42825
|
+
children: result === "victory" ? "Victory!" : "Defeat"
|
|
42826
|
+
}
|
|
42827
|
+
),
|
|
42828
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "body", color: "muted", className: "overlay__turn-count", children: [
|
|
42829
|
+
"Completed in ",
|
|
42830
|
+
turn,
|
|
42831
|
+
" turn",
|
|
42832
|
+
turn !== 1 ? "s" : ""
|
|
42833
|
+
] }),
|
|
42834
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
42835
|
+
Button,
|
|
42836
|
+
{
|
|
42837
|
+
variant: "primary",
|
|
42838
|
+
className: "px-8 py-3 font-semibold",
|
|
42839
|
+
onClick: handlePlayAgain,
|
|
42840
|
+
children: "Play Again"
|
|
42841
|
+
}
|
|
42842
|
+
)
|
|
42843
|
+
] }) })
|
|
42844
|
+
] });
|
|
42845
|
+
}
|
|
42846
|
+
var init_GameBoard3D = __esm({
|
|
42847
|
+
"components/game/organisms/GameBoard3D.tsx"() {
|
|
42848
|
+
"use client";
|
|
42849
|
+
init_cn();
|
|
42850
|
+
init_Button();
|
|
42851
|
+
init_Typography();
|
|
42852
|
+
init_Stack();
|
|
42853
|
+
init_useEventBus();
|
|
42854
|
+
init_GameCanvas3D2();
|
|
42855
|
+
init_boardEntity();
|
|
42856
|
+
GameBoard3D.displayName = "GameBoard3D";
|
|
42857
|
+
}
|
|
42858
|
+
});
|
|
41203
42859
|
var GameShell;
|
|
41204
42860
|
var init_GameShell = __esm({
|
|
41205
42861
|
"components/game/templates/GameShell.tsx"() {
|
|
@@ -42742,6 +44398,236 @@ var init_NegotiatorBoard = __esm({
|
|
|
42742
44398
|
NegotiatorBoard.displayName = "NegotiatorBoard";
|
|
42743
44399
|
}
|
|
42744
44400
|
});
|
|
44401
|
+
function resolveEntity(entity) {
|
|
44402
|
+
if (!entity) return {};
|
|
44403
|
+
if (Array.isArray(entity)) return entity[0] ?? {};
|
|
44404
|
+
return entity;
|
|
44405
|
+
}
|
|
44406
|
+
function numField(row, key, fallback) {
|
|
44407
|
+
const v = row[key];
|
|
44408
|
+
return typeof v === "number" ? v : fallback;
|
|
44409
|
+
}
|
|
44410
|
+
function strField(row, key, fallback) {
|
|
44411
|
+
const v = row[key];
|
|
44412
|
+
return typeof v === "string" ? v : fallback;
|
|
44413
|
+
}
|
|
44414
|
+
function PlatformerBoard({
|
|
44415
|
+
entity,
|
|
44416
|
+
player: propPlayer,
|
|
44417
|
+
platforms: propPlatforms,
|
|
44418
|
+
result: propResult,
|
|
44419
|
+
lives: propLives,
|
|
44420
|
+
score: propScore,
|
|
44421
|
+
level: propLevel,
|
|
44422
|
+
worldWidth = 800,
|
|
44423
|
+
worldHeight = 400,
|
|
44424
|
+
canvasWidth = 800,
|
|
44425
|
+
canvasHeight = 400,
|
|
44426
|
+
playerSprite,
|
|
44427
|
+
tileSprites,
|
|
44428
|
+
bgColor,
|
|
44429
|
+
leftEvent = "LEFT",
|
|
44430
|
+
rightEvent = "RIGHT",
|
|
44431
|
+
jumpEvent = "JUMP",
|
|
44432
|
+
stopEvent = "STOP",
|
|
44433
|
+
playAgainEvent = "PLAY_AGAIN",
|
|
44434
|
+
gameEndEvent = "GAME_END",
|
|
44435
|
+
className
|
|
44436
|
+
}) {
|
|
44437
|
+
const row = resolveEntity(entity);
|
|
44438
|
+
const eventBus = useEventBus();
|
|
44439
|
+
const { t } = hooks.useTranslate();
|
|
44440
|
+
const result = propResult ?? strField(row, "result", "none");
|
|
44441
|
+
propLives ?? numField(row, "lives", 3);
|
|
44442
|
+
const score = propScore ?? numField(row, "score", 0);
|
|
44443
|
+
const level = propLevel ?? numField(row, "level", 1);
|
|
44444
|
+
const entityPlayer = row["player"];
|
|
44445
|
+
const player = propPlayer ?? entityPlayer ?? {
|
|
44446
|
+
x: 80,
|
|
44447
|
+
y: 320,
|
|
44448
|
+
width: 32,
|
|
44449
|
+
height: 48,
|
|
44450
|
+
vx: 0,
|
|
44451
|
+
vy: 0,
|
|
44452
|
+
grounded: false,
|
|
44453
|
+
facingRight: true
|
|
44454
|
+
};
|
|
44455
|
+
const entityPlatforms = Array.isArray(row["platforms"]) ? row["platforms"] : void 0;
|
|
44456
|
+
const platforms = propPlatforms ?? entityPlatforms ?? [
|
|
44457
|
+
{ x: 0, y: 368, width: 800, height: 32, type: "ground" },
|
|
44458
|
+
{ x: 150, y: 280, width: 160, height: 16, type: "platform" },
|
|
44459
|
+
{ x: 420, y: 220, width: 160, height: 16, type: "platform" },
|
|
44460
|
+
{ x: 580, y: 300, width: 80, height: 16, type: "hazard" },
|
|
44461
|
+
{ x: 700, y: 340, width: 64, height: 28, type: "goal" }
|
|
44462
|
+
];
|
|
44463
|
+
const handleRestart = React83.useCallback(() => {
|
|
44464
|
+
if (playAgainEvent) {
|
|
44465
|
+
eventBus.emit(`UI:${playAgainEvent}`, {});
|
|
44466
|
+
}
|
|
44467
|
+
}, [playAgainEvent, eventBus]);
|
|
44468
|
+
const isGameOver = result === "won" || result === "lost";
|
|
44469
|
+
const gameEndEmittedRef = React83.useRef(false);
|
|
44470
|
+
React83.useEffect(() => {
|
|
44471
|
+
if ((result === "won" || result === "lost") && gameEndEvent) {
|
|
44472
|
+
if (!gameEndEmittedRef.current) {
|
|
44473
|
+
gameEndEmittedRef.current = true;
|
|
44474
|
+
eventBus.emit(`UI:${gameEndEvent}`, { result });
|
|
44475
|
+
}
|
|
44476
|
+
} else {
|
|
44477
|
+
gameEndEmittedRef.current = false;
|
|
44478
|
+
}
|
|
44479
|
+
}, [result, gameEndEvent, eventBus]);
|
|
44480
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
44481
|
+
VStack,
|
|
44482
|
+
{
|
|
44483
|
+
className: cn("platformer-board relative bg-background", className),
|
|
44484
|
+
gap: "none",
|
|
44485
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "relative", children: [
|
|
44486
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
44487
|
+
PlatformerCanvas,
|
|
44488
|
+
{
|
|
44489
|
+
player,
|
|
44490
|
+
platforms,
|
|
44491
|
+
worldWidth,
|
|
44492
|
+
worldHeight,
|
|
44493
|
+
canvasWidth,
|
|
44494
|
+
canvasHeight,
|
|
44495
|
+
followCamera: true,
|
|
44496
|
+
bgColor,
|
|
44497
|
+
playerSprite,
|
|
44498
|
+
tileSprites,
|
|
44499
|
+
leftEvent,
|
|
44500
|
+
rightEvent,
|
|
44501
|
+
jumpEvent,
|
|
44502
|
+
stopEvent
|
|
44503
|
+
}
|
|
44504
|
+
),
|
|
44505
|
+
isGameOver && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "absolute inset-0 z-50 flex items-center justify-center bg-background/70 backdrop-blur-sm rounded-container", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { className: "text-center p-8", gap: "lg", children: [
|
|
44506
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
44507
|
+
Typography,
|
|
44508
|
+
{
|
|
44509
|
+
variant: "h2",
|
|
44510
|
+
className: cn(
|
|
44511
|
+
"text-4xl font-black tracking-widest uppercase",
|
|
44512
|
+
result === "won" ? "text-warning" : "text-error"
|
|
44513
|
+
),
|
|
44514
|
+
children: result === "won" ? t("platformer.won") : t("platformer.lost")
|
|
44515
|
+
}
|
|
44516
|
+
),
|
|
44517
|
+
result === "won" && /* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "body1", className: "text-muted-foreground", children: [
|
|
44518
|
+
t("platformer.level"),
|
|
44519
|
+
" ",
|
|
44520
|
+
level,
|
|
44521
|
+
" \u2014 ",
|
|
44522
|
+
t("platformer.score"),
|
|
44523
|
+
": ",
|
|
44524
|
+
score
|
|
44525
|
+
] }),
|
|
44526
|
+
result === "lost" && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body1", className: "text-muted-foreground", children: t("platformer.noLives") }),
|
|
44527
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
44528
|
+
Button,
|
|
44529
|
+
{
|
|
44530
|
+
variant: "primary",
|
|
44531
|
+
className: "px-8 py-3 font-semibold",
|
|
44532
|
+
onClick: handleRestart,
|
|
44533
|
+
children: result === "won" ? t("platformer.nextLevel") : t("platformer.playAgain")
|
|
44534
|
+
}
|
|
44535
|
+
)
|
|
44536
|
+
] }) })
|
|
44537
|
+
] })
|
|
44538
|
+
}
|
|
44539
|
+
);
|
|
44540
|
+
}
|
|
44541
|
+
var init_PlatformerBoard = __esm({
|
|
44542
|
+
"components/game/organisms/PlatformerBoard.tsx"() {
|
|
44543
|
+
"use client";
|
|
44544
|
+
init_cn();
|
|
44545
|
+
init_useEventBus();
|
|
44546
|
+
init_Box();
|
|
44547
|
+
init_Button();
|
|
44548
|
+
init_Typography();
|
|
44549
|
+
init_Stack();
|
|
44550
|
+
init_PlatformerCanvas();
|
|
44551
|
+
PlatformerBoard.displayName = "PlatformerBoard";
|
|
44552
|
+
}
|
|
44553
|
+
});
|
|
44554
|
+
function PlatformerTemplate({
|
|
44555
|
+
entity,
|
|
44556
|
+
platforms = DEFAULT_PLATFORMS,
|
|
44557
|
+
worldWidth = 800,
|
|
44558
|
+
worldHeight = 400,
|
|
44559
|
+
canvasWidth = 800,
|
|
44560
|
+
canvasHeight = 400,
|
|
44561
|
+
playerSprite = `${CDN3}/characters/platformChar_idle.png`,
|
|
44562
|
+
tileSprites = DEFAULT_TILE_SPRITES,
|
|
44563
|
+
bgColor = "#5c94fc",
|
|
44564
|
+
gameEndEvent = "GAME_END",
|
|
44565
|
+
className
|
|
44566
|
+
}) {
|
|
44567
|
+
const row = entity && !Array.isArray(entity) ? entity : void 0;
|
|
44568
|
+
const lives = typeof row?.["lives"] === "number" ? row["lives"] : 3;
|
|
44569
|
+
const score = typeof row?.["score"] === "number" ? row["score"] : 0;
|
|
44570
|
+
const level = typeof row?.["level"] === "number" ? row["level"] : 1;
|
|
44571
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(VStack, { className: cn("platformer-template w-full", className), gap: "none", children: [
|
|
44572
|
+
/* @__PURE__ */ jsxRuntime.jsx(Box, { className: "relative", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
44573
|
+
GameHud,
|
|
44574
|
+
{
|
|
44575
|
+
position: "top",
|
|
44576
|
+
stats: [
|
|
44577
|
+
{ label: "Lives", value: lives, format: "number", variant: "danger" },
|
|
44578
|
+
{ label: "Level", value: level, format: "number", variant: "default" }
|
|
44579
|
+
]
|
|
44580
|
+
}
|
|
44581
|
+
) }),
|
|
44582
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
44583
|
+
PlatformerBoard,
|
|
44584
|
+
{
|
|
44585
|
+
entity,
|
|
44586
|
+
platforms,
|
|
44587
|
+
worldWidth,
|
|
44588
|
+
worldHeight,
|
|
44589
|
+
canvasWidth,
|
|
44590
|
+
canvasHeight,
|
|
44591
|
+
playerSprite,
|
|
44592
|
+
tileSprites,
|
|
44593
|
+
bgColor,
|
|
44594
|
+
leftEvent: "LEFT",
|
|
44595
|
+
rightEvent: "RIGHT",
|
|
44596
|
+
jumpEvent: "JUMP",
|
|
44597
|
+
stopEvent: "STOP",
|
|
44598
|
+
playAgainEvent: "PLAY_AGAIN",
|
|
44599
|
+
gameEndEvent
|
|
44600
|
+
}
|
|
44601
|
+
),
|
|
44602
|
+
/* @__PURE__ */ jsxRuntime.jsx(Box, { className: "px-4 py-2", children: /* @__PURE__ */ jsxRuntime.jsx(ScoreBoard, { score, level }) })
|
|
44603
|
+
] });
|
|
44604
|
+
}
|
|
44605
|
+
var CDN3, DEFAULT_TILE_SPRITES, DEFAULT_PLATFORMS;
|
|
44606
|
+
var init_PlatformerTemplate = __esm({
|
|
44607
|
+
"components/game/templates/PlatformerTemplate.tsx"() {
|
|
44608
|
+
init_cn();
|
|
44609
|
+
init_Box();
|
|
44610
|
+
init_Stack();
|
|
44611
|
+
init_PlatformerBoard();
|
|
44612
|
+
init_GameHud();
|
|
44613
|
+
init_ScoreBoard();
|
|
44614
|
+
CDN3 = "https://almadar-kflow-assets.web.app/shared/platformer";
|
|
44615
|
+
DEFAULT_TILE_SPRITES = {
|
|
44616
|
+
ground: `${CDN3}/tiles/platformPack_tile001.png`,
|
|
44617
|
+
platform: `${CDN3}/tiles/platformPack_tile004.png`,
|
|
44618
|
+
hazard: `${CDN3}/tiles/platformPack_tile017.png`,
|
|
44619
|
+
goal: `${CDN3}/tiles/platformPack_tile007.png`
|
|
44620
|
+
};
|
|
44621
|
+
DEFAULT_PLATFORMS = [
|
|
44622
|
+
{ x: 0, y: 368, width: 800, height: 32, type: "ground" },
|
|
44623
|
+
{ x: 150, y: 280, width: 160, height: 16, type: "platform" },
|
|
44624
|
+
{ x: 420, y: 220, width: 160, height: 16, type: "platform" },
|
|
44625
|
+
{ x: 580, y: 300, width: 80, height: 16, type: "hazard" },
|
|
44626
|
+
{ x: 700, y: 340, width: 64, height: 28, type: "goal" }
|
|
44627
|
+
];
|
|
44628
|
+
PlatformerTemplate.displayName = "PlatformerTemplate";
|
|
44629
|
+
}
|
|
44630
|
+
});
|
|
42745
44631
|
var PricingOrganism;
|
|
42746
44632
|
var init_PricingOrganism = __esm({
|
|
42747
44633
|
"components/marketing/organisms/PricingOrganism.tsx"() {
|
|
@@ -42864,6 +44750,356 @@ var init_PricingPageTemplate = __esm({
|
|
|
42864
44750
|
PricingPageTemplate.displayName = "PricingPageTemplate";
|
|
42865
44751
|
}
|
|
42866
44752
|
});
|
|
44753
|
+
function RoguelikeBoard({
|
|
44754
|
+
entity,
|
|
44755
|
+
tiles: propTiles,
|
|
44756
|
+
enemies: propEnemies,
|
|
44757
|
+
items: propItems,
|
|
44758
|
+
player: propPlayer,
|
|
44759
|
+
playerHp: propPlayerHp,
|
|
44760
|
+
playerMaxHp: propPlayerMaxHp,
|
|
44761
|
+
playerAttack: propPlayerAttack,
|
|
44762
|
+
depth: propDepth,
|
|
44763
|
+
result: propResult,
|
|
44764
|
+
phase: propPhase,
|
|
44765
|
+
stairsX: propStairsX,
|
|
44766
|
+
stairsY: propStairsY,
|
|
44767
|
+
assetManifest: propAssetManifest,
|
|
44768
|
+
scale = 0.45,
|
|
44769
|
+
unitScale = 1,
|
|
44770
|
+
moveEvent,
|
|
44771
|
+
playAgainEvent,
|
|
44772
|
+
gameEndEvent,
|
|
44773
|
+
className
|
|
44774
|
+
}) {
|
|
44775
|
+
const board = boardEntity(entity) ?? {};
|
|
44776
|
+
const tiles = propTiles ?? (Array.isArray(board.tiles) ? board.tiles : DEFAULT_TILES2);
|
|
44777
|
+
const enemies = propEnemies ?? (Array.isArray(board.enemies) ? board.enemies : DEFAULT_ENEMIES);
|
|
44778
|
+
const items = propItems ?? (Array.isArray(board.items) ? board.items : DEFAULT_ITEMS);
|
|
44779
|
+
const player = propPlayer ?? board.player ?? { x: 1, y: 1 };
|
|
44780
|
+
const playerHp = propPlayerHp ?? num(board.playerHp, 10);
|
|
44781
|
+
const playerMaxHp = propPlayerMaxHp ?? num(board.playerMaxHp, 10);
|
|
44782
|
+
const playerAttack = propPlayerAttack ?? num(board.playerAttack, 3);
|
|
44783
|
+
const depth = propDepth ?? num(board.depth, 1);
|
|
44784
|
+
const result = propResult ?? (str(board.result) || "none");
|
|
44785
|
+
const phase = propPhase ?? (str(board.phase) || "player_turn");
|
|
44786
|
+
propStairsX ?? num(board.stairsX, 3);
|
|
44787
|
+
propStairsY ?? num(board.stairsY, 3);
|
|
44788
|
+
const eventBus = useEventBus();
|
|
44789
|
+
const { t } = hooks.useTranslate();
|
|
44790
|
+
const [hoveredTile, setHoveredTile] = React83.useState(null);
|
|
44791
|
+
const emitMove = React83.useCallback((dx, dy) => {
|
|
44792
|
+
if (!moveEvent) return;
|
|
44793
|
+
eventBus.emit(`UI:${moveEvent}`, { dx, dy });
|
|
44794
|
+
}, [moveEvent, eventBus]);
|
|
44795
|
+
React83.useEffect(() => {
|
|
44796
|
+
const handler = (e) => {
|
|
44797
|
+
if (result !== "none" || phase !== "player_turn") return;
|
|
44798
|
+
if (e.key === "ArrowUp" || e.key === "w") emitMove(0, -1);
|
|
44799
|
+
if (e.key === "ArrowDown" || e.key === "s") emitMove(0, 1);
|
|
44800
|
+
if (e.key === "ArrowLeft" || e.key === "a") emitMove(-1, 0);
|
|
44801
|
+
if (e.key === "ArrowRight" || e.key === "d") emitMove(1, 0);
|
|
44802
|
+
};
|
|
44803
|
+
window.addEventListener("keydown", handler);
|
|
44804
|
+
return () => window.removeEventListener("keydown", handler);
|
|
44805
|
+
}, [result, phase, emitMove]);
|
|
44806
|
+
React83.useEffect(() => {
|
|
44807
|
+
if ((result === "won" || result === "lost") && gameEndEvent) {
|
|
44808
|
+
eventBus.emit(`UI:${gameEndEvent}`, { result });
|
|
44809
|
+
}
|
|
44810
|
+
}, [result, gameEndEvent, eventBus]);
|
|
44811
|
+
const handleTileClick = React83.useCallback((x, y) => {
|
|
44812
|
+
if (result !== "none" || phase !== "player_turn") return;
|
|
44813
|
+
const dx = x - player.x;
|
|
44814
|
+
const dy = y - player.y;
|
|
44815
|
+
if (Math.abs(dx) + Math.abs(dy) === 1) {
|
|
44816
|
+
emitMove(dx, dy);
|
|
44817
|
+
}
|
|
44818
|
+
}, [result, phase, player, emitMove]);
|
|
44819
|
+
const handleReset = React83.useCallback(() => {
|
|
44820
|
+
if (!playAgainEvent) return;
|
|
44821
|
+
eventBus.emit(`UI:${playAgainEvent}`, {});
|
|
44822
|
+
}, [playAgainEvent, eventBus]);
|
|
44823
|
+
const isoUnits = React83.useMemo(() => {
|
|
44824
|
+
const liveEnemies = enemies.filter((e) => e.hp > 0);
|
|
44825
|
+
return [
|
|
44826
|
+
{
|
|
44827
|
+
id: "player",
|
|
44828
|
+
position: player,
|
|
44829
|
+
name: t("roguelike.player") || "Hero",
|
|
44830
|
+
team: "player",
|
|
44831
|
+
health: playerHp,
|
|
44832
|
+
maxHealth: playerMaxHp,
|
|
44833
|
+
unitType: "player",
|
|
44834
|
+
sprite: `${CDN4}/isometric-dungeon/Characters/Male/Male_0_Idle0.png`
|
|
44835
|
+
},
|
|
44836
|
+
...liveEnemies.map((e) => ({
|
|
44837
|
+
id: e.id,
|
|
44838
|
+
position: { x: e.x, y: e.y },
|
|
44839
|
+
name: t("roguelike.enemy") || "Enemy",
|
|
44840
|
+
team: "enemy",
|
|
44841
|
+
health: e.hp,
|
|
44842
|
+
maxHealth: 6,
|
|
44843
|
+
unitType: "enemy",
|
|
44844
|
+
sprite: `${CDN4}/sprite-sheets/shadow-legion-sprite-sheet-sw.png`
|
|
44845
|
+
}))
|
|
44846
|
+
];
|
|
44847
|
+
}, [player, enemies, playerHp, playerMaxHp, t]);
|
|
44848
|
+
const isoFeatures = React83.useMemo(
|
|
44849
|
+
() => items.map((it) => ({
|
|
44850
|
+
id: it.id,
|
|
44851
|
+
x: it.x,
|
|
44852
|
+
y: it.y,
|
|
44853
|
+
type: it.kind,
|
|
44854
|
+
sprite: FEATURE_SPRITE[it.kind] ?? FEATURE_SPRITE.health_potion
|
|
44855
|
+
})),
|
|
44856
|
+
[items]
|
|
44857
|
+
);
|
|
44858
|
+
const validMoves = React83.useMemo(() => {
|
|
44859
|
+
if (result !== "none" || phase !== "player_turn") return [];
|
|
44860
|
+
const dirs = [{ dx: 0, dy: -1 }, { dx: 0, dy: 1 }, { dx: -1, dy: 0 }, { dx: 1, dy: 0 }];
|
|
44861
|
+
return dirs.map(({ dx, dy }) => ({ x: player.x + dx, y: player.y + dy })).filter(({ x, y }) => {
|
|
44862
|
+
const tile = tiles.find((t2) => t2.x === x && t2.y === y);
|
|
44863
|
+
return tile?.passable ?? false;
|
|
44864
|
+
});
|
|
44865
|
+
}, [result, phase, player, tiles]);
|
|
44866
|
+
const isGameOver = result === "won" || result === "lost";
|
|
44867
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(VStack, { className: cn("roguelike-board relative min-h-[600px] bg-background", className), gap: "none", children: [
|
|
44868
|
+
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { className: "items-center justify-between px-4 py-2 border-b border-border", gap: "md", children: [
|
|
44869
|
+
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", className: "items-center", children: [
|
|
44870
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: t("roguelike.depth") || "Depth" }),
|
|
44871
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body1", className: "font-bold tabular-nums", children: depth })
|
|
44872
|
+
] }),
|
|
44873
|
+
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", className: "items-center", children: [
|
|
44874
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: t("roguelike.hp") || "HP" }),
|
|
44875
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
44876
|
+
Typography,
|
|
44877
|
+
{
|
|
44878
|
+
variant: "body1",
|
|
44879
|
+
className: cn(
|
|
44880
|
+
"font-bold tabular-nums",
|
|
44881
|
+
playerHp <= Math.floor(playerMaxHp * 0.25) ? "text-error" : "text-success"
|
|
44882
|
+
),
|
|
44883
|
+
children: [
|
|
44884
|
+
playerHp,
|
|
44885
|
+
" / ",
|
|
44886
|
+
playerMaxHp
|
|
44887
|
+
]
|
|
44888
|
+
}
|
|
44889
|
+
)
|
|
44890
|
+
] }),
|
|
44891
|
+
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", className: "items-center", children: [
|
|
44892
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: t("roguelike.atk") || "ATK" }),
|
|
44893
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body1", className: "font-bold tabular-nums text-foreground", children: playerAttack })
|
|
44894
|
+
] }),
|
|
44895
|
+
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", className: "items-center", children: [
|
|
44896
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: t("roguelike.phase") || "Phase" }),
|
|
44897
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "capitalize text-foreground", children: phase.replace("_", " ") })
|
|
44898
|
+
] })
|
|
44899
|
+
] }),
|
|
44900
|
+
/* @__PURE__ */ jsxRuntime.jsx(Box, { className: "relative flex-1", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
44901
|
+
IsometricCanvas_default,
|
|
44902
|
+
{
|
|
44903
|
+
tiles,
|
|
44904
|
+
units: isoUnits,
|
|
44905
|
+
features: isoFeatures,
|
|
44906
|
+
selectedUnitId: null,
|
|
44907
|
+
validMoves,
|
|
44908
|
+
attackTargets: [],
|
|
44909
|
+
hoveredTile,
|
|
44910
|
+
onTileClick: handleTileClick,
|
|
44911
|
+
onUnitClick: () => void 0,
|
|
44912
|
+
onTileHover: (x, y) => setHoveredTile({ x, y }),
|
|
44913
|
+
onTileLeave: () => setHoveredTile(null),
|
|
44914
|
+
scale,
|
|
44915
|
+
assetBaseUrl: propAssetManifest?.baseUrl ?? CDN4,
|
|
44916
|
+
assetManifest: propAssetManifest,
|
|
44917
|
+
unitScale
|
|
44918
|
+
}
|
|
44919
|
+
) }),
|
|
44920
|
+
!isGameOver && /* @__PURE__ */ jsxRuntime.jsx(HStack, { className: "justify-center gap-2 p-3", gap: "none", children: [
|
|
44921
|
+
{ label: "\u2191", dx: 0, dy: -1 },
|
|
44922
|
+
{ label: "\u2193", dx: 0, dy: 1 },
|
|
44923
|
+
{ label: "\u2190", dx: -1, dy: 0 },
|
|
44924
|
+
{ label: "\u2192", dx: 1, dy: 0 }
|
|
44925
|
+
].map(({ label, dx, dy }) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
44926
|
+
Button,
|
|
44927
|
+
{
|
|
44928
|
+
variant: "secondary",
|
|
44929
|
+
className: "w-9 h-9 p-0 text-base font-mono",
|
|
44930
|
+
onClick: () => emitMove(dx, dy),
|
|
44931
|
+
disabled: phase !== "player_turn",
|
|
44932
|
+
children: label
|
|
44933
|
+
},
|
|
44934
|
+
label
|
|
44935
|
+
)) }),
|
|
44936
|
+
isGameOver && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "absolute inset-0 z-50 flex items-center justify-center bg-background/75 backdrop-blur-sm rounded-container", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { className: "text-center p-8", gap: "lg", children: [
|
|
44937
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
44938
|
+
Typography,
|
|
44939
|
+
{
|
|
44940
|
+
variant: "h2",
|
|
44941
|
+
className: cn(
|
|
44942
|
+
"text-4xl font-black tracking-widest uppercase",
|
|
44943
|
+
result === "won" ? "text-warning" : "text-error"
|
|
44944
|
+
),
|
|
44945
|
+
children: result === "won" ? t("roguelike.victory") || "Victory!" : t("roguelike.defeat") || "Defeated!"
|
|
44946
|
+
}
|
|
44947
|
+
),
|
|
44948
|
+
result === "won" && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body1", className: "text-muted-foreground", children: t("roguelike.cleared") || `Dungeon cleared! Depth reached: ${depth}` }),
|
|
44949
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
44950
|
+
Button,
|
|
44951
|
+
{
|
|
44952
|
+
variant: "primary",
|
|
44953
|
+
className: "px-8 py-3 font-semibold",
|
|
44954
|
+
onClick: handleReset,
|
|
44955
|
+
children: t("roguelike.playAgain") || "Play Again"
|
|
44956
|
+
}
|
|
44957
|
+
)
|
|
44958
|
+
] }) })
|
|
44959
|
+
] });
|
|
44960
|
+
}
|
|
44961
|
+
var CDN4, DEFAULT_TILES2, DEFAULT_ENEMIES, DEFAULT_ITEMS, FEATURE_SPRITE;
|
|
44962
|
+
var init_RoguelikeBoard = __esm({
|
|
44963
|
+
"components/game/organisms/RoguelikeBoard.tsx"() {
|
|
44964
|
+
"use client";
|
|
44965
|
+
init_cn();
|
|
44966
|
+
init_useEventBus();
|
|
44967
|
+
init_Box();
|
|
44968
|
+
init_Button();
|
|
44969
|
+
init_Typography();
|
|
44970
|
+
init_Stack();
|
|
44971
|
+
init_IsometricCanvas();
|
|
44972
|
+
init_boardEntity();
|
|
44973
|
+
CDN4 = "https://almadar-kflow-assets.web.app/shared";
|
|
44974
|
+
DEFAULT_TILES2 = [
|
|
44975
|
+
{ x: 0, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
44976
|
+
{ x: 1, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
44977
|
+
{ x: 2, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
44978
|
+
{ x: 3, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
44979
|
+
{ x: 4, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
44980
|
+
{ x: 0, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
44981
|
+
{ x: 1, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
|
|
44982
|
+
{ x: 2, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
|
|
44983
|
+
{ x: 3, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
|
|
44984
|
+
{ x: 4, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
44985
|
+
{ x: 0, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
44986
|
+
{ x: 1, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png` },
|
|
44987
|
+
{ x: 2, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png` },
|
|
44988
|
+
{ x: 3, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
|
|
44989
|
+
{ x: 4, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
44990
|
+
{ x: 0, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
44991
|
+
{ x: 1, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
|
|
44992
|
+
{ x: 2, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png` },
|
|
44993
|
+
{ x: 3, y: 3, terrain: "stairs", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stairs_E.png` },
|
|
44994
|
+
{ x: 4, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
44995
|
+
{ x: 0, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
44996
|
+
{ x: 1, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
44997
|
+
{ x: 2, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
44998
|
+
{ x: 3, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
44999
|
+
{ x: 4, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` }
|
|
45000
|
+
];
|
|
45001
|
+
DEFAULT_ENEMIES = [
|
|
45002
|
+
{ id: "e1", x: 3, y: 1, hp: 5, attack: 2 },
|
|
45003
|
+
{ id: "e2", x: 1, y: 3, hp: 4, attack: 1 }
|
|
45004
|
+
];
|
|
45005
|
+
DEFAULT_ITEMS = [
|
|
45006
|
+
{ id: "i1", x: 2, y: 2, kind: "health_potion" }
|
|
45007
|
+
];
|
|
45008
|
+
FEATURE_SPRITE = {
|
|
45009
|
+
health_potion: `${CDN4}/isometric-dungeon/Isometric/chestClosed_E.png`,
|
|
45010
|
+
sword: `${CDN4}/isometric-dungeon/Isometric/barrel_E.png`,
|
|
45011
|
+
shield: `${CDN4}/isometric-dungeon/Isometric/barrel_E.png`
|
|
45012
|
+
};
|
|
45013
|
+
RoguelikeBoard.displayName = "RoguelikeBoard";
|
|
45014
|
+
}
|
|
45015
|
+
});
|
|
45016
|
+
function RoguelikeTemplate({
|
|
45017
|
+
entity,
|
|
45018
|
+
scale = 0.45,
|
|
45019
|
+
unitScale = 1,
|
|
45020
|
+
tiles = DEFAULT_ROGUELIKE_TILES,
|
|
45021
|
+
enemies,
|
|
45022
|
+
items,
|
|
45023
|
+
stairsX,
|
|
45024
|
+
stairsY,
|
|
45025
|
+
assetManifest = DEFAULT_ROGUELIKE_MANIFEST,
|
|
45026
|
+
gameEndEvent,
|
|
45027
|
+
className
|
|
45028
|
+
}) {
|
|
45029
|
+
const resolved = entity && typeof entity === "object" && !Array.isArray(entity) ? entity : void 0;
|
|
45030
|
+
if (!resolved && !tiles && !assetManifest) return null;
|
|
45031
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
45032
|
+
RoguelikeBoard,
|
|
45033
|
+
{
|
|
45034
|
+
entity: resolved,
|
|
45035
|
+
tiles,
|
|
45036
|
+
enemies,
|
|
45037
|
+
items,
|
|
45038
|
+
stairsX,
|
|
45039
|
+
stairsY,
|
|
45040
|
+
assetManifest,
|
|
45041
|
+
scale,
|
|
45042
|
+
unitScale,
|
|
45043
|
+
moveEvent: "MOVE",
|
|
45044
|
+
playAgainEvent: "PLAY_AGAIN",
|
|
45045
|
+
gameEndEvent: gameEndEvent ?? "GAME_END",
|
|
45046
|
+
className
|
|
45047
|
+
}
|
|
45048
|
+
);
|
|
45049
|
+
}
|
|
45050
|
+
var CDN5, DEFAULT_ROGUELIKE_TILES, DEFAULT_ROGUELIKE_MANIFEST;
|
|
45051
|
+
var init_RoguelikeTemplate = __esm({
|
|
45052
|
+
"components/game/templates/RoguelikeTemplate.tsx"() {
|
|
45053
|
+
init_RoguelikeBoard();
|
|
45054
|
+
CDN5 = "https://almadar-kflow-assets.web.app/shared";
|
|
45055
|
+
DEFAULT_ROGUELIKE_TILES = [
|
|
45056
|
+
{ x: 0, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45057
|
+
{ x: 1, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45058
|
+
{ x: 2, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45059
|
+
{ x: 3, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45060
|
+
{ x: 4, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45061
|
+
{ x: 0, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45062
|
+
{ x: 1, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirt_E.png` },
|
|
45063
|
+
{ x: 2, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirt_E.png` },
|
|
45064
|
+
{ x: 3, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirt_E.png` },
|
|
45065
|
+
{ x: 4, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45066
|
+
{ x: 0, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45067
|
+
{ x: 1, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirtTiles_E.png` },
|
|
45068
|
+
{ x: 2, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirtTiles_E.png` },
|
|
45069
|
+
{ x: 3, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirt_E.png` },
|
|
45070
|
+
{ x: 4, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45071
|
+
{ x: 0, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45072
|
+
{ x: 1, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirt_E.png` },
|
|
45073
|
+
{ x: 2, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirtTiles_E.png` },
|
|
45074
|
+
{ x: 3, y: 3, terrain: "stairs", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stairs_E.png` },
|
|
45075
|
+
{ x: 4, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45076
|
+
{ x: 0, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45077
|
+
{ x: 1, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45078
|
+
{ x: 2, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45079
|
+
{ x: 3, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45080
|
+
{ x: 4, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` }
|
|
45081
|
+
];
|
|
45082
|
+
DEFAULT_ROGUELIKE_MANIFEST = {
|
|
45083
|
+
baseUrl: CDN5,
|
|
45084
|
+
terrains: {
|
|
45085
|
+
floor: "/isometric-dungeon/Isometric/dirt_E.png",
|
|
45086
|
+
wall: "/isometric-dungeon/Isometric/stoneInset_E.png",
|
|
45087
|
+
stairs: "/isometric-dungeon/Isometric/stairs_E.png",
|
|
45088
|
+
planks: "/isometric-dungeon/Isometric/planks_E.png"
|
|
45089
|
+
},
|
|
45090
|
+
units: {
|
|
45091
|
+
player: "/isometric-dungeon/Characters/Male/Male_0_Idle0.png",
|
|
45092
|
+
enemy: "/sprite-sheets/shadow-legion-sprite-sheet-sw.png"
|
|
45093
|
+
},
|
|
45094
|
+
features: {
|
|
45095
|
+
health_potion: "/isometric-dungeon/Isometric/chestClosed_E.png",
|
|
45096
|
+
sword: "/isometric-dungeon/Isometric/barrel_E.png",
|
|
45097
|
+
shield: "/isometric-dungeon/Isometric/barrel_E.png"
|
|
45098
|
+
}
|
|
45099
|
+
};
|
|
45100
|
+
RoguelikeTemplate.displayName = "RoguelikeTemplate";
|
|
45101
|
+
}
|
|
45102
|
+
});
|
|
42867
45103
|
|
|
42868
45104
|
// lib/traitRegistry.ts
|
|
42869
45105
|
function getAllTraits() {
|
|
@@ -44098,7 +46334,7 @@ function getAllEvents(traits2) {
|
|
|
44098
46334
|
function EventDispatcherTab({ traits: traits2, schema }) {
|
|
44099
46335
|
const eventBus = useEventBus();
|
|
44100
46336
|
const { t } = hooks.useTranslate();
|
|
44101
|
-
const [
|
|
46337
|
+
const [log14, setLog] = React83__namespace.useState([]);
|
|
44102
46338
|
const prevStatesRef = React83__namespace.useRef(/* @__PURE__ */ new Map());
|
|
44103
46339
|
React83__namespace.useEffect(() => {
|
|
44104
46340
|
for (const trait of traits2) {
|
|
@@ -44162,9 +46398,9 @@ function EventDispatcherTab({ traits: traits2, schema }) {
|
|
|
44162
46398
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", weight: "medium", className: "text-gray-500 mb-1", children: t("debug.otherEvents") }),
|
|
44163
46399
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-1", children: unavailableEvents.map((event) => /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: "default", size: "sm", className: "opacity-50", children: event }, event)) })
|
|
44164
46400
|
] }),
|
|
44165
|
-
|
|
46401
|
+
log14.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
44166
46402
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", weight: "medium", className: "text-gray-500 mb-1", children: t("debug.recentTransitions") }),
|
|
44167
|
-
/* @__PURE__ */ jsxRuntime.jsx(Stack, { gap: "xs", children:
|
|
46403
|
+
/* @__PURE__ */ jsxRuntime.jsx(Stack, { gap: "xs", children: log14.map((entry, i) => /* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "small", className: "font-mono text-xs", children: [
|
|
44168
46404
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-purple-400", children: entry.traitName }),
|
|
44169
46405
|
" ",
|
|
44170
46406
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-gray-500", children: entry.from }),
|
|
@@ -46085,9 +48321,9 @@ function VariablePanel({
|
|
|
46085
48321
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-muted-foreground font-medium", children: t("stateArchitect.variables", { name: entityName }) }),
|
|
46086
48322
|
variables.map((v) => {
|
|
46087
48323
|
const name = v.name == null ? "" : String(v.name);
|
|
46088
|
-
const value =
|
|
46089
|
-
const max =
|
|
46090
|
-
const min =
|
|
48324
|
+
const value = numField2(v.value);
|
|
48325
|
+
const max = numField2(v.max, 100);
|
|
48326
|
+
const min = numField2(v.min, 0);
|
|
46091
48327
|
const unit = v.unit == null ? "" : String(v.unit);
|
|
46092
48328
|
const pct = Math.round((value - min) / (max - min) * 100);
|
|
46093
48329
|
const isHigh = pct > 80;
|
|
@@ -46117,12 +48353,12 @@ function VariablePanel({
|
|
|
46117
48353
|
})
|
|
46118
48354
|
] });
|
|
46119
48355
|
}
|
|
46120
|
-
var
|
|
48356
|
+
var numField2;
|
|
46121
48357
|
var init_VariablePanel = __esm({
|
|
46122
48358
|
"components/game/organisms/puzzles/state-architect/VariablePanel.tsx"() {
|
|
46123
48359
|
init_atoms2();
|
|
46124
48360
|
init_cn();
|
|
46125
|
-
|
|
48361
|
+
numField2 = (v, fallback = 0) => {
|
|
46126
48362
|
const n = Number(v);
|
|
46127
48363
|
return Number.isFinite(n) ? n : fallback;
|
|
46128
48364
|
};
|
|
@@ -46975,6 +49211,289 @@ var init_ToastSlot = __esm({
|
|
|
46975
49211
|
ToastSlot.displayName = "ToastSlot";
|
|
46976
49212
|
}
|
|
46977
49213
|
});
|
|
49214
|
+
function tilesToIso(tiles) {
|
|
49215
|
+
return tiles.map((t) => ({
|
|
49216
|
+
x: t.x,
|
|
49217
|
+
y: t.y,
|
|
49218
|
+
terrain: t.terrain,
|
|
49219
|
+
terrainSprite: t.terrainSprite ?? TERRAIN_SPRITES[t.terrain ?? "ground"],
|
|
49220
|
+
passable: t.passable
|
|
49221
|
+
}));
|
|
49222
|
+
}
|
|
49223
|
+
function towersToUnits(towers) {
|
|
49224
|
+
return towers.map((t) => ({
|
|
49225
|
+
id: t.id,
|
|
49226
|
+
position: { x: t.x, y: t.y },
|
|
49227
|
+
name: "Tower",
|
|
49228
|
+
team: "player",
|
|
49229
|
+
sprite: TOWER_SPRITE,
|
|
49230
|
+
unitType: "guardian",
|
|
49231
|
+
health: 1,
|
|
49232
|
+
maxHealth: 1
|
|
49233
|
+
}));
|
|
49234
|
+
}
|
|
49235
|
+
function creepsToUnits(creeps) {
|
|
49236
|
+
return creeps.map((c) => ({
|
|
49237
|
+
id: c.id,
|
|
49238
|
+
position: { x: c.x, y: c.y },
|
|
49239
|
+
name: "Creep",
|
|
49240
|
+
team: "enemy",
|
|
49241
|
+
sprite: CREEP_SPRITE,
|
|
49242
|
+
unitType: "scrapper",
|
|
49243
|
+
health: c.hp,
|
|
49244
|
+
maxHealth: c.maxHp
|
|
49245
|
+
}));
|
|
49246
|
+
}
|
|
49247
|
+
function pathToFeatures(path) {
|
|
49248
|
+
return path.map((p2, i) => ({
|
|
49249
|
+
id: `path-${i}`,
|
|
49250
|
+
x: p2.x,
|
|
49251
|
+
y: p2.y,
|
|
49252
|
+
type: "path-marker",
|
|
49253
|
+
sprite: `${CDN6}world-map/road_straight.png`
|
|
49254
|
+
}));
|
|
49255
|
+
}
|
|
49256
|
+
function TowerDefenseBoard({
|
|
49257
|
+
entity,
|
|
49258
|
+
tiles: propTiles,
|
|
49259
|
+
path: propPath,
|
|
49260
|
+
towers: propTowers,
|
|
49261
|
+
creeps: propCreeps,
|
|
49262
|
+
gold: propGold,
|
|
49263
|
+
lives: propLives,
|
|
49264
|
+
wave: propWave,
|
|
49265
|
+
maxWaves: propMaxWaves,
|
|
49266
|
+
result: propResult,
|
|
49267
|
+
waveActive: propWaveActive,
|
|
49268
|
+
towerCost = 25,
|
|
49269
|
+
scale = 0.45,
|
|
49270
|
+
placeTowerEvent,
|
|
49271
|
+
startWaveEvent,
|
|
49272
|
+
playAgainEvent,
|
|
49273
|
+
gameEndEvent,
|
|
49274
|
+
className
|
|
49275
|
+
}) {
|
|
49276
|
+
const board = boardEntity(entity) ?? {};
|
|
49277
|
+
const eventBus = useEventBus();
|
|
49278
|
+
const { t } = hooks.useTranslate();
|
|
49279
|
+
const tiles = propTiles ?? rows(board.tiles);
|
|
49280
|
+
const path = propPath ?? rows(board.path);
|
|
49281
|
+
const towers = propTowers ?? rows(board.towers);
|
|
49282
|
+
const creeps = propCreeps ?? rows(board.creeps);
|
|
49283
|
+
const gold = propGold ?? num(board.gold, 100);
|
|
49284
|
+
const lives = propLives ?? num(board.lives, 20);
|
|
49285
|
+
const wave = propWave ?? num(board.wave, 1);
|
|
49286
|
+
const maxWaves = propMaxWaves ?? num(board.maxWaves, 5);
|
|
49287
|
+
const result = propResult ?? (str(board.result) || "none");
|
|
49288
|
+
const waveActive = propWaveActive ?? Boolean(board.waveActive);
|
|
49289
|
+
const [hoveredTile, setHoveredTile] = React83.useState(null);
|
|
49290
|
+
const emittedGameEnd = React83.useRef(false);
|
|
49291
|
+
if (result !== "none" && !emittedGameEnd.current) {
|
|
49292
|
+
emittedGameEnd.current = true;
|
|
49293
|
+
if (gameEndEvent) {
|
|
49294
|
+
eventBus.emit(`UI:${gameEndEvent}`, { result });
|
|
49295
|
+
}
|
|
49296
|
+
}
|
|
49297
|
+
if (result === "none") {
|
|
49298
|
+
emittedGameEnd.current = false;
|
|
49299
|
+
}
|
|
49300
|
+
const towerPositions = React83.useMemo(() => new Set(towers.map((t2) => `${t2.x},${t2.y}`)), [towers]);
|
|
49301
|
+
const pathPositions = React83.useMemo(() => new Set(path.map((p2) => `${p2.x},${p2.y}`)), [path]);
|
|
49302
|
+
const validMoves = React83.useMemo(() => {
|
|
49303
|
+
if (result !== "none" || gold < towerCost) return [];
|
|
49304
|
+
return tiles.filter(
|
|
49305
|
+
(t2) => t2.passable !== false && !towerPositions.has(`${t2.x},${t2.y}`) && !pathPositions.has(`${t2.x},${t2.y}`)
|
|
49306
|
+
).map((t2) => ({ x: t2.x, y: t2.y }));
|
|
49307
|
+
}, [tiles, towerPositions, pathPositions, result, gold, towerCost]);
|
|
49308
|
+
const isoTiles = React83.useMemo(() => tilesToIso(tiles), [tiles]);
|
|
49309
|
+
const towerUnits = React83.useMemo(() => towersToUnits(towers), [towers]);
|
|
49310
|
+
const creepUnits = React83.useMemo(() => creepsToUnits(creeps), [creeps]);
|
|
49311
|
+
const isoUnits = React83.useMemo(() => [...towerUnits, ...creepUnits], [towerUnits, creepUnits]);
|
|
49312
|
+
const pathFeatures = React83.useMemo(() => pathToFeatures(path), [path]);
|
|
49313
|
+
const handleTileClick = React83.useCallback((x, y) => {
|
|
49314
|
+
if (result !== "none") return;
|
|
49315
|
+
if (pathPositions.has(`${x},${y}`)) return;
|
|
49316
|
+
if (towerPositions.has(`${x},${y}`)) return;
|
|
49317
|
+
if (gold < towerCost) return;
|
|
49318
|
+
if (placeTowerEvent) {
|
|
49319
|
+
eventBus.emit(`UI:${placeTowerEvent}`, { x, y });
|
|
49320
|
+
}
|
|
49321
|
+
}, [result, pathPositions, towerPositions, gold, towerCost, placeTowerEvent, eventBus]);
|
|
49322
|
+
const handleStartWave = React83.useCallback(() => {
|
|
49323
|
+
if (startWaveEvent) {
|
|
49324
|
+
eventBus.emit(`UI:${startWaveEvent}`, { wave });
|
|
49325
|
+
}
|
|
49326
|
+
}, [startWaveEvent, wave, eventBus]);
|
|
49327
|
+
const handlePlayAgain = React83.useCallback(() => {
|
|
49328
|
+
if (playAgainEvent) {
|
|
49329
|
+
eventBus.emit(`UI:${playAgainEvent}`, {});
|
|
49330
|
+
}
|
|
49331
|
+
}, [playAgainEvent, eventBus]);
|
|
49332
|
+
const canPlaceTower = gold >= towerCost && result === "none";
|
|
49333
|
+
const canStartWave = !waveActive && result === "none";
|
|
49334
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(VStack, { className: cn("tower-defense-board relative min-h-[600px] bg-background", className), gap: "none", children: [
|
|
49335
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
49336
|
+
HStack,
|
|
49337
|
+
{
|
|
49338
|
+
className: "px-4 py-2 border-b border-border bg-surface",
|
|
49339
|
+
gap: "lg",
|
|
49340
|
+
align: "center",
|
|
49341
|
+
children: [
|
|
49342
|
+
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", align: "center", children: [
|
|
49343
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", color: "muted", children: t("td.gold") ?? "Gold" }),
|
|
49344
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", weight: "bold", className: "text-warning", children: gold })
|
|
49345
|
+
] }),
|
|
49346
|
+
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", align: "center", children: [
|
|
49347
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", color: "muted", children: t("td.lives") ?? "Lives" }),
|
|
49348
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", weight: "bold", className: lives <= 5 ? "text-error" : "text-success", children: lives })
|
|
49349
|
+
] }),
|
|
49350
|
+
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", align: "center", children: [
|
|
49351
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", color: "muted", children: t("td.wave") ?? "Wave" }),
|
|
49352
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "body2", weight: "bold", children: [
|
|
49353
|
+
wave,
|
|
49354
|
+
" / ",
|
|
49355
|
+
maxWaves
|
|
49356
|
+
] })
|
|
49357
|
+
] }),
|
|
49358
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "ml-auto", children: [
|
|
49359
|
+
canStartWave && /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "primary", size: "sm", onClick: handleStartWave, children: t("td.startWave") ?? "Start Wave" }),
|
|
49360
|
+
waveActive && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", className: "text-warning animate-pulse", children: t("td.waveInProgress") ?? "Wave in progress\u2026" })
|
|
49361
|
+
] })
|
|
49362
|
+
]
|
|
49363
|
+
}
|
|
49364
|
+
),
|
|
49365
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "relative flex-1", children: [
|
|
49366
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
49367
|
+
IsometricCanvas_default,
|
|
49368
|
+
{
|
|
49369
|
+
tiles: isoTiles,
|
|
49370
|
+
units: isoUnits,
|
|
49371
|
+
features: pathFeatures,
|
|
49372
|
+
validMoves,
|
|
49373
|
+
hoveredTile,
|
|
49374
|
+
onTileClick: handleTileClick,
|
|
49375
|
+
onTileHover: (x, y) => setHoveredTile({ x, y }),
|
|
49376
|
+
onTileLeave: () => setHoveredTile(null),
|
|
49377
|
+
scale
|
|
49378
|
+
}
|
|
49379
|
+
),
|
|
49380
|
+
hoveredTile && canPlaceTower && validMoves.some((m) => m.x === hoveredTile.x && m.y === hoveredTile.y) && /* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.jsx(Typography, { variant: "small", children: t("td.placeTower") ?? `Place tower (${towerCost} gold)` }) })
|
|
49381
|
+
] }),
|
|
49382
|
+
result !== "none" && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "absolute inset-0 z-50 flex items-center justify-center bg-background/70 backdrop-blur-sm", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { className: "text-center p-8", gap: "lg", children: [
|
|
49383
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
49384
|
+
Typography,
|
|
49385
|
+
{
|
|
49386
|
+
variant: "h2",
|
|
49387
|
+
className: cn(
|
|
49388
|
+
"text-4xl font-black tracking-widest uppercase",
|
|
49389
|
+
result === "won" ? "text-warning" : "text-error"
|
|
49390
|
+
),
|
|
49391
|
+
children: result === "won" ? t("td.victory") ?? "Victory!" : t("td.defeat") ?? "Defeat!"
|
|
49392
|
+
}
|
|
49393
|
+
),
|
|
49394
|
+
/* @__PURE__ */ jsxRuntime.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." }),
|
|
49395
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
49396
|
+
Button,
|
|
49397
|
+
{
|
|
49398
|
+
variant: "primary",
|
|
49399
|
+
className: "px-8 py-3 font-semibold",
|
|
49400
|
+
onClick: handlePlayAgain,
|
|
49401
|
+
children: t("td.playAgain") ?? "Play Again"
|
|
49402
|
+
}
|
|
49403
|
+
)
|
|
49404
|
+
] }) })
|
|
49405
|
+
] });
|
|
49406
|
+
}
|
|
49407
|
+
var CDN6, TERRAIN_SPRITES, TOWER_SPRITE, CREEP_SPRITE;
|
|
49408
|
+
var init_TowerDefenseBoard = __esm({
|
|
49409
|
+
"components/game/organisms/TowerDefenseBoard.tsx"() {
|
|
49410
|
+
"use client";
|
|
49411
|
+
init_cn();
|
|
49412
|
+
init_useEventBus();
|
|
49413
|
+
init_Box();
|
|
49414
|
+
init_Button();
|
|
49415
|
+
init_Typography();
|
|
49416
|
+
init_Stack();
|
|
49417
|
+
init_IsometricCanvas();
|
|
49418
|
+
init_boardEntity();
|
|
49419
|
+
CDN6 = "https://almadar-kflow-assets.web.app/shared/";
|
|
49420
|
+
TERRAIN_SPRITES = {
|
|
49421
|
+
ground: `${CDN6}isometric-blocks/PNG/Platformer tiles/platformerTile_01.png`,
|
|
49422
|
+
path: `${CDN6}isometric-blocks/PNG/Platformer tiles/platformerTile_09.png`,
|
|
49423
|
+
wall: `${CDN6}isometric-blocks/PNG/Platformer tiles/platformerTile_05.png`
|
|
49424
|
+
};
|
|
49425
|
+
TOWER_SPRITE = `${CDN6}units/guardian.png`;
|
|
49426
|
+
CREEP_SPRITE = `${CDN6}units/scrapper.png`;
|
|
49427
|
+
TowerDefenseBoard.displayName = "TowerDefenseBoard";
|
|
49428
|
+
}
|
|
49429
|
+
});
|
|
49430
|
+
function TowerDefenseTemplate({
|
|
49431
|
+
entity,
|
|
49432
|
+
title = "Tower Defense",
|
|
49433
|
+
tiles,
|
|
49434
|
+
path,
|
|
49435
|
+
towers,
|
|
49436
|
+
gold,
|
|
49437
|
+
lives,
|
|
49438
|
+
maxWaves,
|
|
49439
|
+
towerCost,
|
|
49440
|
+
scale,
|
|
49441
|
+
placeTowerEvent,
|
|
49442
|
+
startWaveEvent,
|
|
49443
|
+
playAgainEvent,
|
|
49444
|
+
gameEndEvent,
|
|
49445
|
+
className
|
|
49446
|
+
}) {
|
|
49447
|
+
const resolved = entity && typeof entity === "object" && !Array.isArray(entity) ? entity : void 0;
|
|
49448
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
49449
|
+
Box,
|
|
49450
|
+
{
|
|
49451
|
+
display: "flex",
|
|
49452
|
+
fullHeight: true,
|
|
49453
|
+
className: cn("tower-defense-template flex-col", className),
|
|
49454
|
+
children: [
|
|
49455
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
49456
|
+
HStack,
|
|
49457
|
+
{
|
|
49458
|
+
gap: "sm",
|
|
49459
|
+
align: "center",
|
|
49460
|
+
className: "px-4 py-3 border-b-2 border-border bg-surface shrink-0",
|
|
49461
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", children: title })
|
|
49462
|
+
}
|
|
49463
|
+
),
|
|
49464
|
+
/* @__PURE__ */ jsxRuntime.jsx(Box, { className: "flex-1 relative overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
49465
|
+
TowerDefenseBoard,
|
|
49466
|
+
{
|
|
49467
|
+
entity: resolved,
|
|
49468
|
+
tiles,
|
|
49469
|
+
path,
|
|
49470
|
+
towers,
|
|
49471
|
+
gold,
|
|
49472
|
+
lives,
|
|
49473
|
+
maxWaves,
|
|
49474
|
+
towerCost,
|
|
49475
|
+
scale,
|
|
49476
|
+
placeTowerEvent,
|
|
49477
|
+
startWaveEvent,
|
|
49478
|
+
playAgainEvent,
|
|
49479
|
+
gameEndEvent,
|
|
49480
|
+
className: "h-full"
|
|
49481
|
+
}
|
|
49482
|
+
) })
|
|
49483
|
+
]
|
|
49484
|
+
}
|
|
49485
|
+
);
|
|
49486
|
+
}
|
|
49487
|
+
var init_TowerDefenseTemplate = __esm({
|
|
49488
|
+
"components/game/templates/TowerDefenseTemplate.tsx"() {
|
|
49489
|
+
init_cn();
|
|
49490
|
+
init_Box();
|
|
49491
|
+
init_Stack();
|
|
49492
|
+
init_Typography();
|
|
49493
|
+
init_TowerDefenseBoard();
|
|
49494
|
+
TowerDefenseTemplate.displayName = "TowerDefenseTemplate";
|
|
49495
|
+
}
|
|
49496
|
+
});
|
|
46978
49497
|
function useBattleState(initialUnits, eventConfig = {}, callbacks = {}) {
|
|
46979
49498
|
const eventBus = useEventBus();
|
|
46980
49499
|
const {
|
|
@@ -47484,48 +50003,48 @@ function WorldMapTemplate({
|
|
|
47484
50003
|
}
|
|
47485
50004
|
);
|
|
47486
50005
|
}
|
|
47487
|
-
var
|
|
50006
|
+
var CDN7, DEFAULT_WORLDMAP_TILES, DEFAULT_WORLDMAP_UNITS, DEFAULT_WORLDMAP_FEATURES, DEFAULT_WORLDMAP_MANIFEST;
|
|
47488
50007
|
var init_WorldMapTemplate = __esm({
|
|
47489
50008
|
"components/game/templates/WorldMapTemplate.tsx"() {
|
|
47490
50009
|
init_WorldMapBoard();
|
|
47491
|
-
|
|
50010
|
+
CDN7 = "https://almadar-kflow-assets.web.app/shared";
|
|
47492
50011
|
DEFAULT_WORLDMAP_TILES = [
|
|
47493
|
-
{ x: 0, y: 0, terrain: "mountain", passable: false, terrainSprite: `${
|
|
47494
|
-
{ x: 1, y: 0, terrain: "mountain", passable: false, terrainSprite: `${
|
|
47495
|
-
{ x: 2, y: 0, terrain: "water", passable: false, terrainSprite: `${
|
|
47496
|
-
{ x: 3, y: 0, terrain: "mountain", passable: false, terrainSprite: `${
|
|
47497
|
-
{ x: 4, y: 0, terrain: "mountain", passable: false, terrainSprite: `${
|
|
47498
|
-
{ x: 0, y: 1, terrain: "mountain", passable: false, terrainSprite: `${
|
|
47499
|
-
{ x: 1, y: 1, terrain: "grass", passable: true, terrainSprite: `${
|
|
47500
|
-
{ x: 2, y: 1, terrain: "grass", passable: true, terrainSprite: `${
|
|
47501
|
-
{ x: 3, y: 1, terrain: "grass", passable: true, terrainSprite: `${
|
|
47502
|
-
{ x: 4, y: 1, terrain: "water", passable: false, terrainSprite: `${
|
|
47503
|
-
{ x: 0, y: 2, terrain: "water", passable: false, terrainSprite: `${
|
|
47504
|
-
{ x: 1, y: 2, terrain: "grass", passable: true, terrainSprite: `${
|
|
47505
|
-
{ x: 2, y: 2, terrain: "grass", passable: true, terrainSprite: `${
|
|
47506
|
-
{ x: 3, y: 2, terrain: "grass", passable: true, terrainSprite: `${
|
|
47507
|
-
{ x: 4, y: 2, terrain: "mountain", passable: false, terrainSprite: `${
|
|
47508
|
-
{ x: 0, y: 3, terrain: "mountain", passable: false, terrainSprite: `${
|
|
47509
|
-
{ x: 1, y: 3, terrain: "grass", passable: true, terrainSprite: `${
|
|
47510
|
-
{ x: 2, y: 3, terrain: "grass", passable: true, terrainSprite: `${
|
|
47511
|
-
{ x: 3, y: 3, terrain: "grass", passable: true, terrainSprite: `${
|
|
47512
|
-
{ x: 4, y: 3, terrain: "mountain", passable: false, terrainSprite: `${
|
|
47513
|
-
{ x: 0, y: 4, terrain: "mountain", passable: false, terrainSprite: `${
|
|
47514
|
-
{ x: 1, y: 4, terrain: "water", passable: false, terrainSprite: `${
|
|
47515
|
-
{ x: 2, y: 4, terrain: "grass", passable: true, terrainSprite: `${
|
|
47516
|
-
{ x: 3, y: 4, terrain: "mountain", passable: false, terrainSprite: `${
|
|
47517
|
-
{ x: 4, y: 4, terrain: "mountain", passable: false, terrainSprite: `${
|
|
50012
|
+
{ x: 0, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
|
|
50013
|
+
{ x: 1, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
|
|
50014
|
+
{ x: 2, y: 0, terrain: "water", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
|
|
50015
|
+
{ x: 3, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
|
|
50016
|
+
{ x: 4, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
|
|
50017
|
+
{ x: 0, y: 1, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
|
|
50018
|
+
{ x: 1, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
|
|
50019
|
+
{ x: 2, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
|
|
50020
|
+
{ x: 3, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
|
|
50021
|
+
{ x: 4, y: 1, terrain: "water", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
|
|
50022
|
+
{ x: 0, y: 2, terrain: "water", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
|
|
50023
|
+
{ x: 1, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
|
|
50024
|
+
{ x: 2, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_03.png` },
|
|
50025
|
+
{ x: 3, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
|
|
50026
|
+
{ x: 4, y: 2, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
|
|
50027
|
+
{ x: 0, y: 3, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
|
|
50028
|
+
{ x: 1, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
|
|
50029
|
+
{ x: 2, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
|
|
50030
|
+
{ x: 3, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_03.png` },
|
|
50031
|
+
{ x: 4, y: 3, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
|
|
50032
|
+
{ x: 0, y: 4, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
|
|
50033
|
+
{ x: 1, y: 4, terrain: "water", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
|
|
50034
|
+
{ x: 2, y: 4, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
|
|
50035
|
+
{ x: 3, y: 4, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
|
|
50036
|
+
{ x: 4, y: 4, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` }
|
|
47518
50037
|
];
|
|
47519
50038
|
DEFAULT_WORLDMAP_UNITS = [
|
|
47520
|
-
{ id: "h1", position: { x: 1, y: 1 }, unitType: "hero", name: "Amir", team: "player", health: 10, maxHealth: 10, sprite: `${
|
|
47521
|
-
{ id: "h2", position: { x: 3, y: 3 }, unitType: "scout", name: "Archivist", team: "player", health: 10, maxHealth: 10, sprite: `${
|
|
50039
|
+
{ 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` },
|
|
50040
|
+
{ 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` }
|
|
47522
50041
|
];
|
|
47523
50042
|
DEFAULT_WORLDMAP_FEATURES = [
|
|
47524
|
-
{ id: "f1", x: 2, y: 2, type: "capital", sprite: `${
|
|
47525
|
-
{ id: "f2", x: 4, y: 2, type: "power_node", sprite: `${
|
|
50043
|
+
{ id: "f1", x: 2, y: 2, type: "capital", sprite: `${CDN7}/scenes/world/capital.png` },
|
|
50044
|
+
{ id: "f2", x: 4, y: 2, type: "power_node", sprite: `${CDN7}/world-map/power_node.png` }
|
|
47526
50045
|
];
|
|
47527
50046
|
DEFAULT_WORLDMAP_MANIFEST = {
|
|
47528
|
-
baseUrl:
|
|
50047
|
+
baseUrl: CDN7,
|
|
47529
50048
|
terrains: {
|
|
47530
50049
|
grass: "/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png",
|
|
47531
50050
|
water: "/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png",
|
|
@@ -47570,7 +50089,7 @@ function lazyThree(name, loader) {
|
|
|
47570
50089
|
ThreeWrapper.displayName = `Lazy(${name})`;
|
|
47571
50090
|
return ThreeWrapper;
|
|
47572
50091
|
}
|
|
47573
|
-
var ThreeBoundary, FeatureRenderer,
|
|
50092
|
+
var ThreeBoundary, FeatureRenderer, GameCanvas3D2, GameCanvas3DBattleTemplate, GameCanvas3DCastleTemplate, GameCanvas3DWorldMapTemplate, COMPONENT_REGISTRY;
|
|
47574
50093
|
var init_component_registry_generated = __esm({
|
|
47575
50094
|
"components/core/organisms/component-registry.generated.ts"() {
|
|
47576
50095
|
init_AboutPageTemplate();
|
|
@@ -47680,6 +50199,7 @@ var init_component_registry_generated = __esm({
|
|
|
47680
50199
|
init_FormSectionHeader();
|
|
47681
50200
|
init_GameAudioProvider();
|
|
47682
50201
|
init_GameAudioToggle();
|
|
50202
|
+
init_GameBoard3D();
|
|
47683
50203
|
init_GameCanvas2D();
|
|
47684
50204
|
init_GameHud();
|
|
47685
50205
|
init_GameMenu();
|
|
@@ -47737,7 +50257,9 @@ var init_component_registry_generated = __esm({
|
|
|
47737
50257
|
init_PageHeader();
|
|
47738
50258
|
init_Pagination();
|
|
47739
50259
|
init_PatternTile();
|
|
50260
|
+
init_PlatformerBoard();
|
|
47740
50261
|
init_PlatformerCanvas();
|
|
50262
|
+
init_PlatformerTemplate();
|
|
47741
50263
|
init_Popover();
|
|
47742
50264
|
init_PositionedCanvas();
|
|
47743
50265
|
init_PowerupSlots();
|
|
@@ -47761,6 +50283,8 @@ var init_component_registry_generated = __esm({
|
|
|
47761
50283
|
init_ResourceBar();
|
|
47762
50284
|
init_ResourceCounter();
|
|
47763
50285
|
init_RichBlockEditor();
|
|
50286
|
+
init_RoguelikeBoard();
|
|
50287
|
+
init_RoguelikeTemplate();
|
|
47764
50288
|
init_RuntimeDebugger2();
|
|
47765
50289
|
init_ScaledDiagram();
|
|
47766
50290
|
init_ScoreBoard();
|
|
@@ -47833,6 +50357,8 @@ var init_component_registry_generated = __esm({
|
|
|
47833
50357
|
init_Toast();
|
|
47834
50358
|
init_ToastSlot();
|
|
47835
50359
|
init_Tooltip();
|
|
50360
|
+
init_TowerDefenseBoard();
|
|
50361
|
+
init_TowerDefenseTemplate();
|
|
47836
50362
|
init_TraitFrame();
|
|
47837
50363
|
init_TraitSlot();
|
|
47838
50364
|
init_TrendIndicator();
|
|
@@ -47877,7 +50403,7 @@ var init_component_registry_generated = __esm({
|
|
|
47877
50403
|
}
|
|
47878
50404
|
};
|
|
47879
50405
|
FeatureRenderer = lazyThree("FeatureRenderer", () => import('@almadar/ui/components/molecules/game/three'));
|
|
47880
|
-
|
|
50406
|
+
GameCanvas3D2 = lazyThree("GameCanvas3D", () => import('@almadar/ui/components/molecules/game/three'));
|
|
47881
50407
|
GameCanvas3DBattleTemplate = lazyThree("GameCanvas3DBattleTemplate", () => import('@almadar/ui/components/molecules/game/three'));
|
|
47882
50408
|
GameCanvas3DCastleTemplate = lazyThree("GameCanvas3DCastleTemplate", () => import('@almadar/ui/components/molecules/game/three'));
|
|
47883
50409
|
GameCanvas3DWorldMapTemplate = lazyThree("GameCanvas3DWorldMapTemplate", () => import('@almadar/ui/components/molecules/game/three'));
|
|
@@ -47996,8 +50522,9 @@ var init_component_registry_generated = __esm({
|
|
|
47996
50522
|
"FormSectionHeader": FormSectionHeader,
|
|
47997
50523
|
"GameAudioProvider": GameAudioProvider,
|
|
47998
50524
|
"GameAudioToggle": GameAudioToggle,
|
|
50525
|
+
"GameBoard3D": GameBoard3D,
|
|
47999
50526
|
"GameCanvas2D": GameCanvas2D,
|
|
48000
|
-
"GameCanvas3D":
|
|
50527
|
+
"GameCanvas3D": GameCanvas3D2,
|
|
48001
50528
|
"GameCanvas3DBattleTemplate": GameCanvas3DBattleTemplate,
|
|
48002
50529
|
"GameCanvas3DCastleTemplate": GameCanvas3DCastleTemplate,
|
|
48003
50530
|
"GameCanvas3DWorldMapTemplate": GameCanvas3DWorldMapTemplate,
|
|
@@ -48059,7 +50586,9 @@ var init_component_registry_generated = __esm({
|
|
|
48059
50586
|
"PageHeader": PageHeader,
|
|
48060
50587
|
"Pagination": Pagination,
|
|
48061
50588
|
"PatternTile": PatternTile,
|
|
50589
|
+
"PlatformerBoard": PlatformerBoard,
|
|
48062
50590
|
"PlatformerCanvas": PlatformerCanvas,
|
|
50591
|
+
"PlatformerTemplate": PlatformerTemplate,
|
|
48063
50592
|
"Popover": Popover,
|
|
48064
50593
|
"PositionedCanvas": PositionedCanvas,
|
|
48065
50594
|
"PowerupSlots": PowerupSlots,
|
|
@@ -48083,6 +50612,8 @@ var init_component_registry_generated = __esm({
|
|
|
48083
50612
|
"ResourceBar": ResourceBar,
|
|
48084
50613
|
"ResourceCounter": ResourceCounter,
|
|
48085
50614
|
"RichBlockEditor": RichBlockEditor,
|
|
50615
|
+
"RoguelikeBoard": RoguelikeBoard,
|
|
50616
|
+
"RoguelikeTemplate": RoguelikeTemplate,
|
|
48086
50617
|
"RuntimeDebugger": RuntimeDebugger,
|
|
48087
50618
|
"ScaledDiagram": ScaledDiagram,
|
|
48088
50619
|
"ScoreBoard": ScoreBoard,
|
|
@@ -48158,6 +50689,8 @@ var init_component_registry_generated = __esm({
|
|
|
48158
50689
|
"Toast": Toast,
|
|
48159
50690
|
"ToastSlot": ToastSlot,
|
|
48160
50691
|
"Tooltip": Tooltip,
|
|
50692
|
+
"TowerDefenseBoard": TowerDefenseBoard,
|
|
50693
|
+
"TowerDefenseTemplate": TowerDefenseTemplate,
|
|
48161
50694
|
"TraitFrame": TraitFrame,
|
|
48162
50695
|
"TraitSlot": TraitSlot,
|
|
48163
50696
|
"TrendIndicator": TrendIndicator,
|
|
@@ -49329,7 +51862,7 @@ init_UISlotRenderer();
|
|
|
49329
51862
|
// providers/VerificationProvider.tsx
|
|
49330
51863
|
init_useEventBus();
|
|
49331
51864
|
init_verificationRegistry();
|
|
49332
|
-
var
|
|
51865
|
+
var log13 = logger.createLogger("almadar:verify");
|
|
49333
51866
|
var DISPATCH_SUFFIX = ":DISPATCH";
|
|
49334
51867
|
var SUCCESS_SUFFIX = ":SUCCESS";
|
|
49335
51868
|
var ERROR_SUFFIX = ":ERROR";
|
|
@@ -49376,7 +51909,7 @@ function VerificationProvider({
|
|
|
49376
51909
|
const verificationProviderLifecycleListener = (evt) => {
|
|
49377
51910
|
const parsed = parseLifecycleEvent(evt.type);
|
|
49378
51911
|
if (!parsed) return;
|
|
49379
|
-
|
|
51912
|
+
log13.debug("lifecycle:event", { kind: parsed.kind, traitName: parsed.traitName, event: parsed.event, type: evt.type });
|
|
49380
51913
|
const payload = evt.payload ?? {};
|
|
49381
51914
|
if (parsed.kind === "dispatch") {
|
|
49382
51915
|
const key = `${parsed.traitName}:${String(payload["event"] ?? "")}`;
|
|
@@ -49431,7 +51964,7 @@ function VerificationProvider({
|
|
|
49431
51964
|
},
|
|
49432
51965
|
timestamp: Date.now()
|
|
49433
51966
|
});
|
|
49434
|
-
|
|
51967
|
+
log13.debug("transition:success", { trait: parsed.traitName, event: parsed.event, from: pending?.from, to: newState, effectCount: effects.length });
|
|
49435
51968
|
} else if (parsed.kind === "error" && parsed.event) {
|
|
49436
51969
|
const key = `${parsed.traitName}:${parsed.event}`;
|
|
49437
51970
|
const pending = pendingRef.current.get(key);
|
|
@@ -49461,7 +51994,7 @@ function VerificationProvider({
|
|
|
49461
51994
|
},
|
|
49462
51995
|
timestamp: Date.now()
|
|
49463
51996
|
});
|
|
49464
|
-
|
|
51997
|
+
log13.warn("transition:error", { trait: parsed.traitName, event: parsed.event, from: fromState, error: errorMsg });
|
|
49465
51998
|
}
|
|
49466
51999
|
};
|
|
49467
52000
|
Object.defineProperty(verificationProviderLifecycleListener, "name", {
|