@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/components/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
2
2
|
import * as React77 from 'react';
|
|
3
|
-
import React77__default, { useContext, useMemo, useRef, useEffect, useCallback, useState, Suspense, lazy, createContext, useLayoutEffect, useId, useSyncExternalStore } from 'react';
|
|
3
|
+
import React77__default, { useContext, useMemo, useRef, useEffect, useCallback, useState, Suspense, lazy, createContext, useLayoutEffect, useId, forwardRef, useImperativeHandle, useSyncExternalStore, Component } from 'react';
|
|
4
4
|
import { clsx } from 'clsx';
|
|
5
5
|
import { twMerge } from 'tailwind-merge';
|
|
6
6
|
import { EventBusContext, useTraitScope, TraitScopeProvider } from '@almadar/ui/providers';
|
|
@@ -41,6 +41,12 @@ import { DndContext, useSensors, useSensor, PointerSensor, KeyboardSensor, useDr
|
|
|
41
41
|
import { useSortable, arrayMove, sortableKeyboardCoordinates, SortableContext, rectSortingStrategy, verticalListSortingStrategy } from '@dnd-kit/sortable';
|
|
42
42
|
import { CSS } from '@dnd-kit/utilities';
|
|
43
43
|
import { useNodeId, ReactFlowProvider, Handle, Position } from '@xyflow/react';
|
|
44
|
+
import * as THREE from 'three';
|
|
45
|
+
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
|
|
46
|
+
import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader.js';
|
|
47
|
+
import { GLTFLoader as GLTFLoader$1 } from 'three/examples/jsm/loaders/GLTFLoader';
|
|
48
|
+
import { Canvas, useThree } from '@react-three/fiber';
|
|
49
|
+
import { Grid as Grid$1, OrbitControls } from '@react-three/drei';
|
|
44
50
|
import { useUISlots } from '@almadar/ui/context';
|
|
45
51
|
import { getPatternDefinition as getPatternDefinition$1, getComponentForPattern as getComponentForPattern$1 } from '@almadar/patterns';
|
|
46
52
|
|
|
@@ -1276,9 +1282,9 @@ function resolvePhosphor(name, weight, family) {
|
|
|
1276
1282
|
(lib) => {
|
|
1277
1283
|
const PhosphorComp = lib[target];
|
|
1278
1284
|
if (!PhosphorComp || typeof PhosphorComp !== "object") return null;
|
|
1279
|
-
const
|
|
1285
|
+
const Component2 = PhosphorComp;
|
|
1280
1286
|
const Adapter = (props) => /* @__PURE__ */ jsx(
|
|
1281
|
-
|
|
1287
|
+
Component2,
|
|
1282
1288
|
{
|
|
1283
1289
|
weight,
|
|
1284
1290
|
className: props.className,
|
|
@@ -1302,9 +1308,9 @@ function resolveTabler(name, family) {
|
|
|
1302
1308
|
(lib) => {
|
|
1303
1309
|
const TablerComp = lib[target];
|
|
1304
1310
|
if (!TablerComp || typeof TablerComp !== "object") return null;
|
|
1305
|
-
const
|
|
1311
|
+
const Component2 = TablerComp;
|
|
1306
1312
|
const Adapter = (props) => /* @__PURE__ */ jsx(
|
|
1307
|
-
|
|
1313
|
+
Component2,
|
|
1308
1314
|
{
|
|
1309
1315
|
stroke: props.strokeWidth ?? 1.5,
|
|
1310
1316
|
className: props.className,
|
|
@@ -1328,9 +1334,9 @@ function resolveFa(name, family) {
|
|
|
1328
1334
|
(lib) => {
|
|
1329
1335
|
const FaComp = lib[target];
|
|
1330
1336
|
if (!FaComp || typeof FaComp !== "function") return null;
|
|
1331
|
-
const
|
|
1337
|
+
const Component2 = FaComp;
|
|
1332
1338
|
const Adapter = (props) => /* @__PURE__ */ jsx(
|
|
1333
|
-
|
|
1339
|
+
Component2,
|
|
1334
1340
|
{
|
|
1335
1341
|
className: props.className,
|
|
1336
1342
|
style: props.style,
|
|
@@ -3323,7 +3329,7 @@ var init_Box = __esm({
|
|
|
3323
3329
|
position,
|
|
3324
3330
|
className,
|
|
3325
3331
|
children,
|
|
3326
|
-
as:
|
|
3332
|
+
as: Component2 = "div",
|
|
3327
3333
|
action,
|
|
3328
3334
|
actionPayload,
|
|
3329
3335
|
hoverEvent,
|
|
@@ -3355,7 +3361,7 @@ var init_Box = __esm({
|
|
|
3355
3361
|
}, [hoverEvent, eventBus, onMouseLeave]);
|
|
3356
3362
|
const isClickable = action || onClick;
|
|
3357
3363
|
return React77__default.createElement(
|
|
3358
|
-
|
|
3364
|
+
Component2,
|
|
3359
3365
|
{
|
|
3360
3366
|
ref,
|
|
3361
3367
|
className: cn(
|
|
@@ -3404,10 +3410,10 @@ var init_Center = __esm({
|
|
|
3404
3410
|
className,
|
|
3405
3411
|
style,
|
|
3406
3412
|
children,
|
|
3407
|
-
as:
|
|
3413
|
+
as: Component2 = "div"
|
|
3408
3414
|
}) => {
|
|
3409
3415
|
const mergedStyle = minHeight ? { minHeight, ...style } : style;
|
|
3410
|
-
const Comp =
|
|
3416
|
+
const Comp = Component2;
|
|
3411
3417
|
return /* @__PURE__ */ jsx(
|
|
3412
3418
|
Comp,
|
|
3413
3419
|
{
|
|
@@ -4038,7 +4044,7 @@ var init_Stack = __esm({
|
|
|
4038
4044
|
className,
|
|
4039
4045
|
style,
|
|
4040
4046
|
children,
|
|
4041
|
-
as:
|
|
4047
|
+
as: Component2 = "div",
|
|
4042
4048
|
onClick,
|
|
4043
4049
|
onKeyDown,
|
|
4044
4050
|
role,
|
|
@@ -4056,7 +4062,7 @@ var init_Stack = __esm({
|
|
|
4056
4062
|
};
|
|
4057
4063
|
const isHorizontal = direction === "horizontal";
|
|
4058
4064
|
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";
|
|
4059
|
-
const Comp =
|
|
4065
|
+
const Comp = Component2;
|
|
4060
4066
|
return /* @__PURE__ */ jsx(
|
|
4061
4067
|
Comp,
|
|
4062
4068
|
{
|
|
@@ -4247,8 +4253,8 @@ var init_Typography = __esm({
|
|
|
4247
4253
|
children
|
|
4248
4254
|
}) => {
|
|
4249
4255
|
const variant = variantProp ?? (level ? `h${level}` : "body1");
|
|
4250
|
-
const
|
|
4251
|
-
const Comp =
|
|
4256
|
+
const Component2 = as || defaultElements[variant];
|
|
4257
|
+
const Comp = Component2;
|
|
4252
4258
|
return /* @__PURE__ */ jsx(
|
|
4253
4259
|
Comp,
|
|
4254
4260
|
{
|
|
@@ -7461,10 +7467,10 @@ var init_Container = __esm({
|
|
|
7461
7467
|
center = true,
|
|
7462
7468
|
className,
|
|
7463
7469
|
children,
|
|
7464
|
-
as:
|
|
7470
|
+
as: Component2 = "div"
|
|
7465
7471
|
}) => {
|
|
7466
7472
|
const resolvedSize = maxWidth ?? size ?? "lg";
|
|
7467
|
-
const Comp =
|
|
7473
|
+
const Comp = Component2;
|
|
7468
7474
|
return /* @__PURE__ */ jsx(
|
|
7469
7475
|
Comp,
|
|
7470
7476
|
{
|
|
@@ -8179,6 +8185,7 @@ var init_Accordion = __esm({
|
|
|
8179
8185
|
}
|
|
8180
8186
|
});
|
|
8181
8187
|
function ActionButton({
|
|
8188
|
+
assetUrl = DEFAULT_ASSET_URL,
|
|
8182
8189
|
label = "Attack",
|
|
8183
8190
|
icon,
|
|
8184
8191
|
cooldown = 0,
|
|
@@ -8218,13 +8225,23 @@ function ActionButton({
|
|
|
8218
8225
|
}
|
|
8219
8226
|
}
|
|
8220
8227
|
),
|
|
8221
|
-
|
|
8228
|
+
assetUrl ? /* @__PURE__ */ jsx(
|
|
8229
|
+
"img",
|
|
8230
|
+
{
|
|
8231
|
+
src: assetUrl,
|
|
8232
|
+
alt: "",
|
|
8233
|
+
width: 16,
|
|
8234
|
+
height: 16,
|
|
8235
|
+
style: { imageRendering: "pixelated", objectFit: "contain" },
|
|
8236
|
+
className: cn("flex-shrink-0", sizes.icon)
|
|
8237
|
+
}
|
|
8238
|
+
) : icon ? /* @__PURE__ */ jsx("span", { className: cn("flex-shrink-0", sizes.icon), children: typeof icon === "string" ? (() => {
|
|
8222
8239
|
const I = resolveIcon(icon);
|
|
8223
8240
|
return I ? /* @__PURE__ */ jsx(I, { className: "w-4 h-4" }) : null;
|
|
8224
8241
|
})() : /* @__PURE__ */ (() => {
|
|
8225
8242
|
const I = icon;
|
|
8226
8243
|
return /* @__PURE__ */ jsx(I, { className: "w-4 h-4" });
|
|
8227
|
-
})() }),
|
|
8244
|
+
})() }) : null,
|
|
8228
8245
|
/* @__PURE__ */ jsx("span", { className: "relative z-10", children: label }),
|
|
8229
8246
|
hotkey && /* @__PURE__ */ jsx(
|
|
8230
8247
|
"span",
|
|
@@ -8240,7 +8257,7 @@ function ActionButton({
|
|
|
8240
8257
|
}
|
|
8241
8258
|
);
|
|
8242
8259
|
}
|
|
8243
|
-
var sizeMap, variantStyles7;
|
|
8260
|
+
var sizeMap, variantStyles7, DEFAULT_ASSET_URL;
|
|
8244
8261
|
var init_ActionButton = __esm({
|
|
8245
8262
|
"components/game/atoms/ActionButton.tsx"() {
|
|
8246
8263
|
init_cn();
|
|
@@ -8255,10 +8272,12 @@ var init_ActionButton = __esm({
|
|
|
8255
8272
|
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary-hover border-border",
|
|
8256
8273
|
danger: "bg-error text-error-foreground hover:bg-error/90 border-error"
|
|
8257
8274
|
};
|
|
8275
|
+
DEFAULT_ASSET_URL = "https://almadar-kflow-assets.web.app/shared/effects/particles/slash_01.png";
|
|
8258
8276
|
ActionButton.displayName = "ActionButton";
|
|
8259
8277
|
}
|
|
8260
8278
|
});
|
|
8261
8279
|
function ControlButton({
|
|
8280
|
+
assetUrl = DEFAULT_ASSET_URL2,
|
|
8262
8281
|
label,
|
|
8263
8282
|
icon,
|
|
8264
8283
|
size = "md",
|
|
@@ -8305,7 +8324,7 @@ function ControlButton({
|
|
|
8305
8324
|
},
|
|
8306
8325
|
[isPressed, releaseEvent, eventBus, onRelease]
|
|
8307
8326
|
);
|
|
8308
|
-
return /* @__PURE__ */
|
|
8327
|
+
return /* @__PURE__ */ jsx(
|
|
8309
8328
|
"button",
|
|
8310
8329
|
{
|
|
8311
8330
|
type: "button",
|
|
@@ -8326,20 +8345,27 @@ function ControlButton({
|
|
|
8326
8345
|
disabled && "opacity-50 cursor-not-allowed",
|
|
8327
8346
|
className
|
|
8328
8347
|
),
|
|
8329
|
-
children:
|
|
8330
|
-
|
|
8331
|
-
|
|
8332
|
-
|
|
8333
|
-
|
|
8334
|
-
|
|
8335
|
-
|
|
8336
|
-
|
|
8337
|
-
|
|
8338
|
-
|
|
8348
|
+
children: assetUrl ? /* @__PURE__ */ jsx(
|
|
8349
|
+
"img",
|
|
8350
|
+
{
|
|
8351
|
+
src: assetUrl,
|
|
8352
|
+
alt: "",
|
|
8353
|
+
width: 24,
|
|
8354
|
+
height: 24,
|
|
8355
|
+
style: { imageRendering: "pixelated", objectFit: "contain" },
|
|
8356
|
+
className: "flex-shrink-0"
|
|
8357
|
+
}
|
|
8358
|
+
) : icon ? /* @__PURE__ */ jsx("span", { className: "text-2xl", children: typeof icon === "string" ? /^[a-zA-Z0-9-]+$/.test(icon) ? (() => {
|
|
8359
|
+
const I = resolveIcon(icon);
|
|
8360
|
+
return I ? /* @__PURE__ */ jsx(I, { className: "w-6 h-6" }) : null;
|
|
8361
|
+
})() : icon : /* @__PURE__ */ (() => {
|
|
8362
|
+
const I = icon;
|
|
8363
|
+
return /* @__PURE__ */ jsx(I, { className: "w-6 h-6" });
|
|
8364
|
+
})() }) : label ? /* @__PURE__ */ jsx("span", { children: label }) : null
|
|
8339
8365
|
}
|
|
8340
8366
|
);
|
|
8341
8367
|
}
|
|
8342
|
-
var sizeMap2, shapeMap, variantMap;
|
|
8368
|
+
var sizeMap2, shapeMap, variantMap, DEFAULT_ASSET_URL2;
|
|
8343
8369
|
var init_ControlButton = __esm({
|
|
8344
8370
|
"components/game/atoms/ControlButton.tsx"() {
|
|
8345
8371
|
"use client";
|
|
@@ -8362,6 +8388,7 @@ var init_ControlButton = __esm({
|
|
|
8362
8388
|
secondary: "bg-secondary text-secondary-foreground border-border hover:bg-secondary-hover",
|
|
8363
8389
|
ghost: "bg-transparent text-foreground border-border hover:bg-muted"
|
|
8364
8390
|
};
|
|
8391
|
+
DEFAULT_ASSET_URL2 = "https://almadar-kflow-assets.web.app/shared/effects/particles/circle_01.png";
|
|
8365
8392
|
ControlButton.displayName = "ControlButton";
|
|
8366
8393
|
}
|
|
8367
8394
|
});
|
|
@@ -20171,7 +20198,7 @@ function getComboScale(combo) {
|
|
|
20171
20198
|
return "";
|
|
20172
20199
|
}
|
|
20173
20200
|
function ComboCounter({
|
|
20174
|
-
assetUrl =
|
|
20201
|
+
assetUrl = DEFAULT_ASSET_URL3,
|
|
20175
20202
|
combo = 5,
|
|
20176
20203
|
multiplier,
|
|
20177
20204
|
streak,
|
|
@@ -20216,11 +20243,11 @@ function ComboCounter({
|
|
|
20216
20243
|
}
|
|
20217
20244
|
);
|
|
20218
20245
|
}
|
|
20219
|
-
var
|
|
20246
|
+
var DEFAULT_ASSET_URL3, sizeMap4;
|
|
20220
20247
|
var init_ComboCounter = __esm({
|
|
20221
20248
|
"components/game/atoms/ComboCounter.tsx"() {
|
|
20222
20249
|
init_cn();
|
|
20223
|
-
|
|
20250
|
+
DEFAULT_ASSET_URL3 = "https://almadar-kflow-assets.web.app/shared/effects/flash/flash00.png";
|
|
20224
20251
|
sizeMap4 = {
|
|
20225
20252
|
sm: { combo: "text-lg", label: "text-xs", multiplier: "text-xs" },
|
|
20226
20253
|
md: { combo: "text-2xl", label: "text-xs", multiplier: "text-sm" },
|
|
@@ -20629,7 +20656,7 @@ var init_CounterTemplate = __esm({
|
|
|
20629
20656
|
}
|
|
20630
20657
|
});
|
|
20631
20658
|
function ItemSlot({
|
|
20632
|
-
assetUrl =
|
|
20659
|
+
assetUrl = DEFAULT_ASSET_URL4,
|
|
20633
20660
|
icon = "sword",
|
|
20634
20661
|
label = "Iron Sword",
|
|
20635
20662
|
quantity,
|
|
@@ -20688,7 +20715,7 @@ function ItemSlot({
|
|
|
20688
20715
|
}
|
|
20689
20716
|
);
|
|
20690
20717
|
}
|
|
20691
|
-
var sizeMap5, rarityBorderMap, rarityGlowMap,
|
|
20718
|
+
var sizeMap5, rarityBorderMap, rarityGlowMap, DEFAULT_ASSET_URL4, assetSizeMap;
|
|
20692
20719
|
var init_ItemSlot = __esm({
|
|
20693
20720
|
"components/game/atoms/ItemSlot.tsx"() {
|
|
20694
20721
|
"use client";
|
|
@@ -20713,7 +20740,7 @@ var init_ItemSlot = __esm({
|
|
|
20713
20740
|
epic: "shadow-lg",
|
|
20714
20741
|
legendary: "shadow-lg"
|
|
20715
20742
|
};
|
|
20716
|
-
|
|
20743
|
+
DEFAULT_ASSET_URL4 = "https://almadar-kflow-assets.web.app/shared/isometric-dungeon/Isometric/chestClosed_E.png";
|
|
20717
20744
|
assetSizeMap = {
|
|
20718
20745
|
sm: 28,
|
|
20719
20746
|
md: 40,
|
|
@@ -20892,6 +20919,7 @@ var init_DPad = __esm({
|
|
|
20892
20919
|
}
|
|
20893
20920
|
});
|
|
20894
20921
|
function DamageNumber({
|
|
20922
|
+
assetUrl = DEFAULT_ASSET_URL5,
|
|
20895
20923
|
value = 42,
|
|
20896
20924
|
type = "damage",
|
|
20897
20925
|
size = "md",
|
|
@@ -20900,22 +20928,35 @@ function DamageNumber({
|
|
|
20900
20928
|
const displayText = type === "miss" ? "MISS" : type === "heal" ? `+${value}` : `${value}`;
|
|
20901
20929
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
20902
20930
|
/* @__PURE__ */ jsx("style", { children: floatKeyframes }),
|
|
20903
|
-
/* @__PURE__ */
|
|
20931
|
+
/* @__PURE__ */ jsxs(
|
|
20904
20932
|
"span",
|
|
20905
20933
|
{
|
|
20906
20934
|
className: cn(
|
|
20907
|
-
"inline-
|
|
20935
|
+
"inline-flex items-center gap-0.5 font-mono select-none pointer-events-none",
|
|
20908
20936
|
sizeMap7[size],
|
|
20909
20937
|
typeStyles[type],
|
|
20910
20938
|
className
|
|
20911
20939
|
),
|
|
20912
20940
|
style: { animation: "damageFloat 1s ease-out forwards" },
|
|
20913
|
-
children:
|
|
20941
|
+
children: [
|
|
20942
|
+
assetUrl && /* @__PURE__ */ jsx(
|
|
20943
|
+
"img",
|
|
20944
|
+
{
|
|
20945
|
+
src: assetUrl,
|
|
20946
|
+
alt: "",
|
|
20947
|
+
width: 14,
|
|
20948
|
+
height: 14,
|
|
20949
|
+
style: { imageRendering: "pixelated", objectFit: "contain" },
|
|
20950
|
+
className: "flex-shrink-0"
|
|
20951
|
+
}
|
|
20952
|
+
),
|
|
20953
|
+
displayText
|
|
20954
|
+
]
|
|
20914
20955
|
}
|
|
20915
20956
|
)
|
|
20916
20957
|
] });
|
|
20917
20958
|
}
|
|
20918
|
-
var sizeMap7, typeStyles, floatKeyframes;
|
|
20959
|
+
var sizeMap7, typeStyles, floatKeyframes, DEFAULT_ASSET_URL5;
|
|
20919
20960
|
var init_DamageNumber = __esm({
|
|
20920
20961
|
"components/game/atoms/DamageNumber.tsx"() {
|
|
20921
20962
|
init_cn();
|
|
@@ -20937,6 +20978,7 @@ var init_DamageNumber = __esm({
|
|
|
20937
20978
|
100% { opacity: 0; transform: translateY(-32px) scale(0.8); }
|
|
20938
20979
|
}
|
|
20939
20980
|
`;
|
|
20981
|
+
DEFAULT_ASSET_URL5 = "https://almadar-kflow-assets.web.app/shared/effects/particles/spark_01.png";
|
|
20940
20982
|
DamageNumber.displayName = "DamageNumber";
|
|
20941
20983
|
}
|
|
20942
20984
|
});
|
|
@@ -24757,7 +24799,7 @@ var init_Flex = __esm({
|
|
|
24757
24799
|
basis,
|
|
24758
24800
|
className,
|
|
24759
24801
|
children,
|
|
24760
|
-
as:
|
|
24802
|
+
as: Component2 = "div"
|
|
24761
24803
|
}) => {
|
|
24762
24804
|
const flexStyle = {};
|
|
24763
24805
|
if (grow !== void 0 || shrink !== void 0 || basis !== void 0) {
|
|
@@ -24769,7 +24811,7 @@ var init_Flex = __esm({
|
|
|
24769
24811
|
flexStyle.flexBasis = typeof basis === "number" ? `${basis}px` : basis;
|
|
24770
24812
|
}
|
|
24771
24813
|
}
|
|
24772
|
-
const Comp =
|
|
24814
|
+
const Comp = Component2;
|
|
24773
24815
|
return /* @__PURE__ */ jsx(
|
|
24774
24816
|
Comp,
|
|
24775
24817
|
{
|
|
@@ -24889,11 +24931,11 @@ var init_Grid = __esm({
|
|
|
24889
24931
|
className,
|
|
24890
24932
|
style,
|
|
24891
24933
|
children,
|
|
24892
|
-
as:
|
|
24934
|
+
as: Component2 = "div"
|
|
24893
24935
|
}) => {
|
|
24894
24936
|
const mergedStyle = rows2 ? { gridTemplateRows: `repeat(${rows2}, minmax(0, 1fr))`, ...style } : style;
|
|
24895
24937
|
return React77__default.createElement(
|
|
24896
|
-
|
|
24938
|
+
Component2,
|
|
24897
24939
|
{
|
|
24898
24940
|
className: cn(
|
|
24899
24941
|
"grid",
|
|
@@ -27042,6 +27084,7 @@ var init_HealthBar = __esm({
|
|
|
27042
27084
|
}
|
|
27043
27085
|
});
|
|
27044
27086
|
function ScoreDisplay({
|
|
27087
|
+
assetUrl = DEFAULT_ASSET_URL6,
|
|
27045
27088
|
value,
|
|
27046
27089
|
label,
|
|
27047
27090
|
icon,
|
|
@@ -27088,14 +27131,24 @@ function ScoreDisplay({
|
|
|
27088
27131
|
className
|
|
27089
27132
|
),
|
|
27090
27133
|
children: [
|
|
27091
|
-
|
|
27134
|
+
assetUrl ? /* @__PURE__ */ jsx(
|
|
27135
|
+
"img",
|
|
27136
|
+
{
|
|
27137
|
+
src: assetUrl,
|
|
27138
|
+
alt: "",
|
|
27139
|
+
width: 20,
|
|
27140
|
+
height: 20,
|
|
27141
|
+
style: { imageRendering: "pixelated", objectFit: "contain" },
|
|
27142
|
+
className: "flex-shrink-0"
|
|
27143
|
+
}
|
|
27144
|
+
) : icon ? /* @__PURE__ */ jsx("span", { className: "flex-shrink-0", children: typeof icon === "string" ? /* @__PURE__ */ jsx(Icon, { name: icon }) : /* @__PURE__ */ jsx(Icon, { icon }) }) : null,
|
|
27092
27145
|
label && /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: label }),
|
|
27093
27146
|
/* @__PURE__ */ jsx("span", { className: "tabular-nums", children: formattedValue })
|
|
27094
27147
|
]
|
|
27095
27148
|
}
|
|
27096
27149
|
);
|
|
27097
27150
|
}
|
|
27098
|
-
var sizeMap10;
|
|
27151
|
+
var sizeMap10, DEFAULT_ASSET_URL6;
|
|
27099
27152
|
var init_ScoreDisplay = __esm({
|
|
27100
27153
|
"components/game/atoms/ScoreDisplay.tsx"() {
|
|
27101
27154
|
"use client";
|
|
@@ -27107,10 +27160,12 @@ var init_ScoreDisplay = __esm({
|
|
|
27107
27160
|
lg: "text-2xl",
|
|
27108
27161
|
xl: "text-4xl"
|
|
27109
27162
|
};
|
|
27163
|
+
DEFAULT_ASSET_URL6 = "https://almadar-kflow-assets.web.app/shared/effects/particles/star_01.png";
|
|
27110
27164
|
ScoreDisplay.displayName = "ScoreDisplay";
|
|
27111
27165
|
}
|
|
27112
27166
|
});
|
|
27113
27167
|
function StatBadge({
|
|
27168
|
+
assetUrl = DEFAULT_ASSET_URL7,
|
|
27114
27169
|
label,
|
|
27115
27170
|
value = 0,
|
|
27116
27171
|
max,
|
|
@@ -27134,7 +27189,17 @@ function StatBadge({
|
|
|
27134
27189
|
className
|
|
27135
27190
|
),
|
|
27136
27191
|
children: [
|
|
27137
|
-
|
|
27192
|
+
assetUrl ? /* @__PURE__ */ jsx(
|
|
27193
|
+
"img",
|
|
27194
|
+
{
|
|
27195
|
+
src: assetUrl,
|
|
27196
|
+
alt: "",
|
|
27197
|
+
width: 16,
|
|
27198
|
+
height: 16,
|
|
27199
|
+
style: { imageRendering: "pixelated", objectFit: "contain" },
|
|
27200
|
+
className: "flex-shrink-0"
|
|
27201
|
+
}
|
|
27202
|
+
) : icon ? /* @__PURE__ */ jsx("span", { className: "flex-shrink-0 text-lg", children: typeof icon === "string" ? /* @__PURE__ */ jsx(Icon, { name: icon, className: "w-4 h-4" }) : /* @__PURE__ */ jsx(Icon, { icon, className: "w-4 h-4" }) }) : null,
|
|
27138
27203
|
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground font-medium", children: label }),
|
|
27139
27204
|
format === "hearts" && max && /* @__PURE__ */ jsx(
|
|
27140
27205
|
HealthBar,
|
|
@@ -27167,7 +27232,7 @@ function StatBadge({
|
|
|
27167
27232
|
}
|
|
27168
27233
|
);
|
|
27169
27234
|
}
|
|
27170
|
-
var sizeMap11, variantMap2;
|
|
27235
|
+
var sizeMap11, variantMap2, DEFAULT_ASSET_URL7;
|
|
27171
27236
|
var init_StatBadge = __esm({
|
|
27172
27237
|
"components/game/molecules/StatBadge.tsx"() {
|
|
27173
27238
|
init_cn();
|
|
@@ -27186,6 +27251,7 @@ var init_StatBadge = __esm({
|
|
|
27186
27251
|
warning: "bg-warning/15 border-warning/40 text-foreground",
|
|
27187
27252
|
danger: "bg-error/15 border-error/40 text-foreground"
|
|
27188
27253
|
};
|
|
27254
|
+
DEFAULT_ASSET_URL7 = "https://almadar-kflow-assets.web.app/shared/effects/particles/light_01.png";
|
|
27189
27255
|
StatBadge.displayName = "StatBadge";
|
|
27190
27256
|
}
|
|
27191
27257
|
});
|
|
@@ -27269,7 +27335,7 @@ var init_InventoryGrid = __esm({
|
|
|
27269
27335
|
}
|
|
27270
27336
|
});
|
|
27271
27337
|
function WaypointMarker({
|
|
27272
|
-
assetUrl =
|
|
27338
|
+
assetUrl = DEFAULT_ASSET_URL8,
|
|
27273
27339
|
label,
|
|
27274
27340
|
icon,
|
|
27275
27341
|
active = true,
|
|
@@ -27335,12 +27401,12 @@ function WaypointMarker({
|
|
|
27335
27401
|
)
|
|
27336
27402
|
] });
|
|
27337
27403
|
}
|
|
27338
|
-
var
|
|
27404
|
+
var DEFAULT_ASSET_URL8, sizeMap12, checkIcon;
|
|
27339
27405
|
var init_WaypointMarker = __esm({
|
|
27340
27406
|
"components/game/atoms/WaypointMarker.tsx"() {
|
|
27341
27407
|
init_cn();
|
|
27342
27408
|
init_Icon();
|
|
27343
|
-
|
|
27409
|
+
DEFAULT_ASSET_URL8 = "https://almadar-kflow-assets.web.app/shared/world-map/battle_marker.png";
|
|
27344
27410
|
sizeMap12 = {
|
|
27345
27411
|
sm: { dot: "w-4 h-4", ring: "w-6 h-6", label: "text-xs mt-1", img: 12 },
|
|
27346
27412
|
md: { dot: "w-6 h-6", ring: "w-8 h-8", label: "text-sm mt-1.5", img: 18 },
|
|
@@ -27858,6 +27924,7 @@ var init_ResourceBar = __esm({
|
|
|
27858
27924
|
}
|
|
27859
27925
|
});
|
|
27860
27926
|
function TurnIndicator({
|
|
27927
|
+
assetUrl = DEFAULT_ASSET_URL9,
|
|
27861
27928
|
currentTurn = 1,
|
|
27862
27929
|
maxTurns,
|
|
27863
27930
|
activeTeam,
|
|
@@ -27890,14 +27957,24 @@ function TurnIndicator({
|
|
|
27890
27957
|
] }),
|
|
27891
27958
|
activeTeam && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
27892
27959
|
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "|" }),
|
|
27893
|
-
/* @__PURE__ */ jsx(
|
|
27960
|
+
assetUrl ? /* @__PURE__ */ jsx(
|
|
27961
|
+
"img",
|
|
27962
|
+
{
|
|
27963
|
+
src: assetUrl,
|
|
27964
|
+
alt: "",
|
|
27965
|
+
width: 12,
|
|
27966
|
+
height: 12,
|
|
27967
|
+
style: { imageRendering: "pixelated", objectFit: "contain" },
|
|
27968
|
+
className: "flex-shrink-0"
|
|
27969
|
+
}
|
|
27970
|
+
) : /* @__PURE__ */ jsx("span", { className: cn("rounded-full bg-success/20", sizes.dot) }),
|
|
27894
27971
|
/* @__PURE__ */ jsx("span", { className: "text-success", children: activeTeam })
|
|
27895
27972
|
] })
|
|
27896
27973
|
]
|
|
27897
27974
|
}
|
|
27898
27975
|
);
|
|
27899
27976
|
}
|
|
27900
|
-
var sizeMap14;
|
|
27977
|
+
var sizeMap14, DEFAULT_ASSET_URL9;
|
|
27901
27978
|
var init_TurnIndicator = __esm({
|
|
27902
27979
|
"components/game/atoms/TurnIndicator.tsx"() {
|
|
27903
27980
|
init_cn();
|
|
@@ -27906,6 +27983,7 @@ var init_TurnIndicator = __esm({
|
|
|
27906
27983
|
md: { wrapper: "text-sm gap-2 px-3 py-1", dot: "w-2 h-2" },
|
|
27907
27984
|
lg: { wrapper: "text-base gap-2.5 px-4 py-1.5", dot: "w-2.5 h-2.5" }
|
|
27908
27985
|
};
|
|
27986
|
+
DEFAULT_ASSET_URL9 = "https://almadar-kflow-assets.web.app/shared/effects/particles/symbol_01.png";
|
|
27909
27987
|
TurnIndicator.displayName = "TurnIndicator";
|
|
27910
27988
|
}
|
|
27911
27989
|
});
|
|
@@ -27976,6 +28054,7 @@ var init_TurnPanel = __esm({
|
|
|
27976
28054
|
}
|
|
27977
28055
|
});
|
|
27978
28056
|
function EnemyPlate({
|
|
28057
|
+
assetUrl = DEFAULT_ASSET_URL10,
|
|
27979
28058
|
name = "Shadow Guard",
|
|
27980
28059
|
health = 80,
|
|
27981
28060
|
maxHealth = 100,
|
|
@@ -27993,15 +28072,28 @@ function EnemyPlate({
|
|
|
27993
28072
|
),
|
|
27994
28073
|
children: [
|
|
27995
28074
|
/* @__PURE__ */ jsxs(Box, { className: "flex items-center justify-between gap-2", children: [
|
|
27996
|
-
/* @__PURE__ */
|
|
27997
|
-
|
|
27998
|
-
|
|
27999
|
-
|
|
28000
|
-
|
|
28001
|
-
|
|
28002
|
-
|
|
28003
|
-
|
|
28004
|
-
|
|
28075
|
+
/* @__PURE__ */ jsxs(Box, { className: "flex items-center gap-1.5 min-w-0", children: [
|
|
28076
|
+
assetUrl && /* @__PURE__ */ jsx(
|
|
28077
|
+
"img",
|
|
28078
|
+
{
|
|
28079
|
+
src: assetUrl,
|
|
28080
|
+
alt: name,
|
|
28081
|
+
width: 24,
|
|
28082
|
+
height: 24,
|
|
28083
|
+
style: { objectFit: "cover", borderRadius: "50%" },
|
|
28084
|
+
className: "flex-shrink-0"
|
|
28085
|
+
}
|
|
28086
|
+
),
|
|
28087
|
+
/* @__PURE__ */ jsx(
|
|
28088
|
+
Typography,
|
|
28089
|
+
{
|
|
28090
|
+
variant: "caption",
|
|
28091
|
+
weight: "bold",
|
|
28092
|
+
className: "text-[var(--color-foreground)] truncate",
|
|
28093
|
+
children: name
|
|
28094
|
+
}
|
|
28095
|
+
)
|
|
28096
|
+
] }),
|
|
28005
28097
|
level != null && /* @__PURE__ */ jsxs(Badge, { variant: "neutral", size: "sm", children: [
|
|
28006
28098
|
"Lv.",
|
|
28007
28099
|
level
|
|
@@ -28046,7 +28138,7 @@ function EnemyPlate({
|
|
|
28046
28138
|
}
|
|
28047
28139
|
);
|
|
28048
28140
|
}
|
|
28049
|
-
var effectVariantMap2, DEFAULT_ENEMY_EFFECTS;
|
|
28141
|
+
var effectVariantMap2, DEFAULT_ENEMY_EFFECTS, DEFAULT_ASSET_URL10;
|
|
28050
28142
|
var init_EnemyPlate = __esm({
|
|
28051
28143
|
"components/game/molecules/EnemyPlate.tsx"() {
|
|
28052
28144
|
"use client";
|
|
@@ -28063,6 +28155,7 @@ var init_EnemyPlate = __esm({
|
|
|
28063
28155
|
DEFAULT_ENEMY_EFFECTS = [
|
|
28064
28156
|
{ icon: "flame", label: "Burn", variant: "debuff" }
|
|
28065
28157
|
];
|
|
28158
|
+
DEFAULT_ASSET_URL10 = "https://almadar-kflow-assets.web.app/shared/portraits/shadow-legion.png";
|
|
28066
28159
|
EnemyPlate.displayName = "EnemyPlate";
|
|
28067
28160
|
}
|
|
28068
28161
|
});
|
|
@@ -29616,13 +29709,13 @@ var init_MapView = __esm({
|
|
|
29616
29709
|
shadowSize: [41, 41]
|
|
29617
29710
|
});
|
|
29618
29711
|
L.Marker.prototype.options.icon = defaultIcon;
|
|
29619
|
-
const { useEffect:
|
|
29712
|
+
const { useEffect: useEffect80, useRef: useRef77, useCallback: useCallback120, useState: useState110 } = React77__default;
|
|
29620
29713
|
const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
|
|
29621
|
-
const { useEventBus:
|
|
29714
|
+
const { useEventBus: useEventBus3 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
|
|
29622
29715
|
function MapUpdater({ centerLat, centerLng, zoom }) {
|
|
29623
29716
|
const map = useMap();
|
|
29624
|
-
const prevRef =
|
|
29625
|
-
|
|
29717
|
+
const prevRef = useRef77({ centerLat, centerLng, zoom });
|
|
29718
|
+
useEffect80(() => {
|
|
29626
29719
|
const prev = prevRef.current;
|
|
29627
29720
|
if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
|
|
29628
29721
|
map.setView([centerLat, centerLng], zoom);
|
|
@@ -29633,7 +29726,7 @@ var init_MapView = __esm({
|
|
|
29633
29726
|
}
|
|
29634
29727
|
function MapClickHandler({ onMapClick }) {
|
|
29635
29728
|
const map = useMap();
|
|
29636
|
-
|
|
29729
|
+
useEffect80(() => {
|
|
29637
29730
|
if (!onMapClick) return;
|
|
29638
29731
|
const handler = (e) => {
|
|
29639
29732
|
onMapClick(e.latlng.lat, e.latlng.lng);
|
|
@@ -29660,9 +29753,9 @@ var init_MapView = __esm({
|
|
|
29660
29753
|
className,
|
|
29661
29754
|
showAttribution = true
|
|
29662
29755
|
}) {
|
|
29663
|
-
const eventBus =
|
|
29664
|
-
const [clickedPosition, setClickedPosition] =
|
|
29665
|
-
const handleMapClick =
|
|
29756
|
+
const eventBus = useEventBus3();
|
|
29757
|
+
const [clickedPosition, setClickedPosition] = useState110(null);
|
|
29758
|
+
const handleMapClick = useCallback120((lat, lng) => {
|
|
29666
29759
|
if (showClickedPin) {
|
|
29667
29760
|
setClickedPosition({ lat, lng });
|
|
29668
29761
|
}
|
|
@@ -29671,7 +29764,7 @@ var init_MapView = __esm({
|
|
|
29671
29764
|
eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
|
|
29672
29765
|
}
|
|
29673
29766
|
}, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
|
|
29674
|
-
const handleMarkerClick =
|
|
29767
|
+
const handleMarkerClick = useCallback120((marker) => {
|
|
29675
29768
|
onMarkerClick?.(marker);
|
|
29676
29769
|
if (markerClickEvent) {
|
|
29677
29770
|
eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
|
|
@@ -36798,10 +36891,10 @@ var init_Section = __esm({
|
|
|
36798
36891
|
children,
|
|
36799
36892
|
headerClassName,
|
|
36800
36893
|
contentClassName,
|
|
36801
|
-
as:
|
|
36894
|
+
as: Component2 = "section"
|
|
36802
36895
|
}) => {
|
|
36803
36896
|
const hasHeader = title || description || action;
|
|
36804
|
-
const Comp =
|
|
36897
|
+
const Comp = Component2;
|
|
36805
36898
|
return /* @__PURE__ */ jsxs(
|
|
36806
36899
|
Comp,
|
|
36807
36900
|
{
|
|
@@ -39802,7 +39895,7 @@ var init_DrawerSlot = __esm({
|
|
|
39802
39895
|
}
|
|
39803
39896
|
});
|
|
39804
39897
|
function StateIndicator({
|
|
39805
|
-
assetUrl =
|
|
39898
|
+
assetUrl = DEFAULT_ASSET_URL11,
|
|
39806
39899
|
state = "idle",
|
|
39807
39900
|
label,
|
|
39808
39901
|
size = "md",
|
|
@@ -39841,13 +39934,13 @@ function StateIndicator({
|
|
|
39841
39934
|
}
|
|
39842
39935
|
);
|
|
39843
39936
|
}
|
|
39844
|
-
var
|
|
39937
|
+
var DEFAULT_ASSET_URL11, DEFAULT_STATE_STYLES, DEFAULT_STYLE, SIZE_CLASSES;
|
|
39845
39938
|
var init_StateIndicator = __esm({
|
|
39846
39939
|
"components/game/atoms/StateIndicator.tsx"() {
|
|
39847
39940
|
init_Box();
|
|
39848
39941
|
init_Icon();
|
|
39849
39942
|
init_cn();
|
|
39850
|
-
|
|
39943
|
+
DEFAULT_ASSET_URL11 = "https://almadar-kflow-assets.web.app/shared/isometric-dungeon/Isometric/chestClosed_E.png";
|
|
39851
39944
|
DEFAULT_STATE_STYLES = {
|
|
39852
39945
|
idle: { icon: "\u23F8", bgClass: "bg-muted" },
|
|
39853
39946
|
active: { icon: "\u25B6", bgClass: "bg-success" },
|
|
@@ -41693,6 +41786,1568 @@ var init_GameAudioToggle = __esm({
|
|
|
41693
41786
|
GameAudioToggle.displayName = "GameAudioToggle";
|
|
41694
41787
|
}
|
|
41695
41788
|
});
|
|
41789
|
+
function detectAssetRoot(modelUrl) {
|
|
41790
|
+
const idx = modelUrl.indexOf("/3d/");
|
|
41791
|
+
if (idx !== -1) {
|
|
41792
|
+
return modelUrl.substring(0, idx + 4);
|
|
41793
|
+
}
|
|
41794
|
+
return modelUrl.substring(0, modelUrl.lastIndexOf("/") + 1);
|
|
41795
|
+
}
|
|
41796
|
+
function createGLTFLoaderForUrl(url) {
|
|
41797
|
+
const loader = new GLTFLoader();
|
|
41798
|
+
loader.setResourcePath(detectAssetRoot(url));
|
|
41799
|
+
return loader;
|
|
41800
|
+
}
|
|
41801
|
+
var AssetLoader;
|
|
41802
|
+
var init_AssetLoader = __esm({
|
|
41803
|
+
"components/game/molecules/three/loaders/AssetLoader.ts"() {
|
|
41804
|
+
AssetLoader = class {
|
|
41805
|
+
constructor() {
|
|
41806
|
+
__publicField(this, "objLoader");
|
|
41807
|
+
__publicField(this, "textureLoader");
|
|
41808
|
+
__publicField(this, "modelCache");
|
|
41809
|
+
__publicField(this, "textureCache");
|
|
41810
|
+
__publicField(this, "loadingPromises");
|
|
41811
|
+
this.objLoader = new OBJLoader();
|
|
41812
|
+
this.textureLoader = new THREE.TextureLoader();
|
|
41813
|
+
this.modelCache = /* @__PURE__ */ new Map();
|
|
41814
|
+
this.textureCache = /* @__PURE__ */ new Map();
|
|
41815
|
+
this.loadingPromises = /* @__PURE__ */ new Map();
|
|
41816
|
+
}
|
|
41817
|
+
/**
|
|
41818
|
+
* Load a GLB/GLTF model
|
|
41819
|
+
* @param url - URL to the .glb or .gltf file
|
|
41820
|
+
* @returns Promise with loaded model scene and animations
|
|
41821
|
+
*/
|
|
41822
|
+
async loadModel(url) {
|
|
41823
|
+
if (this.modelCache.has(url)) {
|
|
41824
|
+
return this.modelCache.get(url);
|
|
41825
|
+
}
|
|
41826
|
+
if (this.loadingPromises.has(url)) {
|
|
41827
|
+
return this.loadingPromises.get(url);
|
|
41828
|
+
}
|
|
41829
|
+
const loader = createGLTFLoaderForUrl(url);
|
|
41830
|
+
const loadPromise = loader.loadAsync(url).then((gltf) => {
|
|
41831
|
+
const result = {
|
|
41832
|
+
scene: gltf.scene,
|
|
41833
|
+
animations: gltf.animations || []
|
|
41834
|
+
};
|
|
41835
|
+
this.modelCache.set(url, result);
|
|
41836
|
+
this.loadingPromises.delete(url);
|
|
41837
|
+
return result;
|
|
41838
|
+
}).catch((error) => {
|
|
41839
|
+
this.loadingPromises.delete(url);
|
|
41840
|
+
throw new Error(`Failed to load model ${url}: ${error.message}`);
|
|
41841
|
+
});
|
|
41842
|
+
this.loadingPromises.set(url, loadPromise);
|
|
41843
|
+
return loadPromise;
|
|
41844
|
+
}
|
|
41845
|
+
/**
|
|
41846
|
+
* Load an OBJ model (fallback for non-GLB assets)
|
|
41847
|
+
* @param url - URL to the .obj file
|
|
41848
|
+
* @returns Promise with loaded object group
|
|
41849
|
+
*/
|
|
41850
|
+
async loadOBJ(url) {
|
|
41851
|
+
if (this.modelCache.has(url)) {
|
|
41852
|
+
return this.modelCache.get(url).scene;
|
|
41853
|
+
}
|
|
41854
|
+
if (this.loadingPromises.has(url)) {
|
|
41855
|
+
const result = await this.loadingPromises.get(url);
|
|
41856
|
+
return result.scene;
|
|
41857
|
+
}
|
|
41858
|
+
const loadPromise = this.objLoader.loadAsync(url).then((group) => {
|
|
41859
|
+
const result = {
|
|
41860
|
+
scene: group,
|
|
41861
|
+
animations: []
|
|
41862
|
+
};
|
|
41863
|
+
this.modelCache.set(url, result);
|
|
41864
|
+
this.loadingPromises.delete(url);
|
|
41865
|
+
return result;
|
|
41866
|
+
}).catch((error) => {
|
|
41867
|
+
this.loadingPromises.delete(url);
|
|
41868
|
+
throw new Error(`Failed to load OBJ ${url}: ${error.message}`);
|
|
41869
|
+
});
|
|
41870
|
+
this.loadingPromises.set(url, loadPromise);
|
|
41871
|
+
return (await loadPromise).scene;
|
|
41872
|
+
}
|
|
41873
|
+
/**
|
|
41874
|
+
* Load a texture
|
|
41875
|
+
* @param url - URL to the texture image
|
|
41876
|
+
* @returns Promise with loaded texture
|
|
41877
|
+
*/
|
|
41878
|
+
async loadTexture(url) {
|
|
41879
|
+
if (this.textureCache.has(url)) {
|
|
41880
|
+
return this.textureCache.get(url);
|
|
41881
|
+
}
|
|
41882
|
+
if (this.loadingPromises.has(`texture:${url}`)) {
|
|
41883
|
+
return this.loadingPromises.get(`texture:${url}`);
|
|
41884
|
+
}
|
|
41885
|
+
const loadPromise = this.textureLoader.loadAsync(url).then((texture) => {
|
|
41886
|
+
texture.colorSpace = THREE.SRGBColorSpace;
|
|
41887
|
+
this.textureCache.set(url, texture);
|
|
41888
|
+
this.loadingPromises.delete(`texture:${url}`);
|
|
41889
|
+
return texture;
|
|
41890
|
+
}).catch((error) => {
|
|
41891
|
+
this.loadingPromises.delete(`texture:${url}`);
|
|
41892
|
+
throw new Error(`Failed to load texture ${url}: ${error.message}`);
|
|
41893
|
+
});
|
|
41894
|
+
this.loadingPromises.set(`texture:${url}`, loadPromise);
|
|
41895
|
+
return loadPromise;
|
|
41896
|
+
}
|
|
41897
|
+
/**
|
|
41898
|
+
* Preload multiple assets
|
|
41899
|
+
* @param urls - Array of asset URLs to preload
|
|
41900
|
+
* @returns Promise that resolves when all assets are loaded
|
|
41901
|
+
*/
|
|
41902
|
+
async preload(urls) {
|
|
41903
|
+
const promises = urls.map((url) => {
|
|
41904
|
+
if (url.endsWith(".glb") || url.endsWith(".gltf")) {
|
|
41905
|
+
return this.loadModel(url).catch(() => null);
|
|
41906
|
+
} else if (url.endsWith(".obj")) {
|
|
41907
|
+
return this.loadOBJ(url).catch(() => null);
|
|
41908
|
+
} else if (/\.(png|jpg|jpeg|webp)$/i.test(url)) {
|
|
41909
|
+
return this.loadTexture(url).catch(() => null);
|
|
41910
|
+
}
|
|
41911
|
+
return Promise.resolve(null);
|
|
41912
|
+
});
|
|
41913
|
+
await Promise.all(promises);
|
|
41914
|
+
}
|
|
41915
|
+
/**
|
|
41916
|
+
* Check if a model is cached
|
|
41917
|
+
* @param url - Model URL
|
|
41918
|
+
*/
|
|
41919
|
+
hasModel(url) {
|
|
41920
|
+
return this.modelCache.has(url);
|
|
41921
|
+
}
|
|
41922
|
+
/**
|
|
41923
|
+
* Check if a texture is cached
|
|
41924
|
+
* @param url - Texture URL
|
|
41925
|
+
*/
|
|
41926
|
+
hasTexture(url) {
|
|
41927
|
+
return this.textureCache.has(url);
|
|
41928
|
+
}
|
|
41929
|
+
/**
|
|
41930
|
+
* Get cached model (throws if not cached)
|
|
41931
|
+
* @param url - Model URL
|
|
41932
|
+
*/
|
|
41933
|
+
getModel(url) {
|
|
41934
|
+
const model = this.modelCache.get(url);
|
|
41935
|
+
if (!model) {
|
|
41936
|
+
throw new Error(`Model ${url} not in cache`);
|
|
41937
|
+
}
|
|
41938
|
+
return model;
|
|
41939
|
+
}
|
|
41940
|
+
/**
|
|
41941
|
+
* Get cached texture (throws if not cached)
|
|
41942
|
+
* @param url - Texture URL
|
|
41943
|
+
*/
|
|
41944
|
+
getTexture(url) {
|
|
41945
|
+
const texture = this.textureCache.get(url);
|
|
41946
|
+
if (!texture) {
|
|
41947
|
+
throw new Error(`Texture ${url} not in cache`);
|
|
41948
|
+
}
|
|
41949
|
+
return texture;
|
|
41950
|
+
}
|
|
41951
|
+
/**
|
|
41952
|
+
* Clear all caches
|
|
41953
|
+
*/
|
|
41954
|
+
clearCache() {
|
|
41955
|
+
this.textureCache.forEach((texture) => {
|
|
41956
|
+
texture.dispose();
|
|
41957
|
+
});
|
|
41958
|
+
this.modelCache.forEach((model) => {
|
|
41959
|
+
model.scene.traverse((child) => {
|
|
41960
|
+
if (child instanceof THREE.Mesh) {
|
|
41961
|
+
child.geometry.dispose();
|
|
41962
|
+
if (Array.isArray(child.material)) {
|
|
41963
|
+
child.material.forEach((m) => m.dispose());
|
|
41964
|
+
} else {
|
|
41965
|
+
child.material.dispose();
|
|
41966
|
+
}
|
|
41967
|
+
}
|
|
41968
|
+
});
|
|
41969
|
+
});
|
|
41970
|
+
this.modelCache.clear();
|
|
41971
|
+
this.textureCache.clear();
|
|
41972
|
+
this.loadingPromises.clear();
|
|
41973
|
+
}
|
|
41974
|
+
/**
|
|
41975
|
+
* Get cache statistics
|
|
41976
|
+
*/
|
|
41977
|
+
getStats() {
|
|
41978
|
+
return {
|
|
41979
|
+
models: this.modelCache.size,
|
|
41980
|
+
textures: this.textureCache.size,
|
|
41981
|
+
loading: this.loadingPromises.size
|
|
41982
|
+
};
|
|
41983
|
+
}
|
|
41984
|
+
};
|
|
41985
|
+
new AssetLoader();
|
|
41986
|
+
}
|
|
41987
|
+
});
|
|
41988
|
+
function useAssetLoader(options = {}) {
|
|
41989
|
+
const { preloadUrls = [], loader: customLoader } = options;
|
|
41990
|
+
const loaderRef = useRef(customLoader || new AssetLoader());
|
|
41991
|
+
const [state, setState] = useState({
|
|
41992
|
+
isLoading: false,
|
|
41993
|
+
progress: 0,
|
|
41994
|
+
loaded: 0,
|
|
41995
|
+
total: 0,
|
|
41996
|
+
errors: []
|
|
41997
|
+
});
|
|
41998
|
+
useEffect(() => {
|
|
41999
|
+
if (preloadUrls.length > 0) {
|
|
42000
|
+
preload(preloadUrls);
|
|
42001
|
+
}
|
|
42002
|
+
}, []);
|
|
42003
|
+
const updateProgress = useCallback((loaded, total) => {
|
|
42004
|
+
setState((prev) => ({
|
|
42005
|
+
...prev,
|
|
42006
|
+
loaded,
|
|
42007
|
+
total,
|
|
42008
|
+
progress: total > 0 ? Math.round(loaded / total * 100) : 0
|
|
42009
|
+
}));
|
|
42010
|
+
}, []);
|
|
42011
|
+
const loadModel = useCallback(
|
|
42012
|
+
async (url) => {
|
|
42013
|
+
setState((prev) => ({ ...prev, isLoading: true }));
|
|
42014
|
+
try {
|
|
42015
|
+
const model = await loaderRef.current.loadModel(url);
|
|
42016
|
+
setState((prev) => ({
|
|
42017
|
+
...prev,
|
|
42018
|
+
isLoading: false,
|
|
42019
|
+
loaded: prev.loaded + 1
|
|
42020
|
+
}));
|
|
42021
|
+
return model;
|
|
42022
|
+
} catch (error) {
|
|
42023
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
42024
|
+
setState((prev) => ({
|
|
42025
|
+
...prev,
|
|
42026
|
+
isLoading: false,
|
|
42027
|
+
errors: [...prev.errors, errorMsg]
|
|
42028
|
+
}));
|
|
42029
|
+
throw error;
|
|
42030
|
+
}
|
|
42031
|
+
},
|
|
42032
|
+
[]
|
|
42033
|
+
);
|
|
42034
|
+
const loadOBJ = useCallback(
|
|
42035
|
+
async (url) => {
|
|
42036
|
+
setState((prev) => ({ ...prev, isLoading: true }));
|
|
42037
|
+
try {
|
|
42038
|
+
const model = await loaderRef.current.loadOBJ(url);
|
|
42039
|
+
setState((prev) => ({
|
|
42040
|
+
...prev,
|
|
42041
|
+
isLoading: false,
|
|
42042
|
+
loaded: prev.loaded + 1
|
|
42043
|
+
}));
|
|
42044
|
+
return model;
|
|
42045
|
+
} catch (error) {
|
|
42046
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
42047
|
+
setState((prev) => ({
|
|
42048
|
+
...prev,
|
|
42049
|
+
isLoading: false,
|
|
42050
|
+
errors: [...prev.errors, errorMsg]
|
|
42051
|
+
}));
|
|
42052
|
+
throw error;
|
|
42053
|
+
}
|
|
42054
|
+
},
|
|
42055
|
+
[]
|
|
42056
|
+
);
|
|
42057
|
+
const loadTexture = useCallback(
|
|
42058
|
+
async (url) => {
|
|
42059
|
+
setState((prev) => ({ ...prev, isLoading: true }));
|
|
42060
|
+
try {
|
|
42061
|
+
const texture = await loaderRef.current.loadTexture(url);
|
|
42062
|
+
setState((prev) => ({
|
|
42063
|
+
...prev,
|
|
42064
|
+
isLoading: false,
|
|
42065
|
+
loaded: prev.loaded + 1
|
|
42066
|
+
}));
|
|
42067
|
+
return texture;
|
|
42068
|
+
} catch (error) {
|
|
42069
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
42070
|
+
setState((prev) => ({
|
|
42071
|
+
...prev,
|
|
42072
|
+
isLoading: false,
|
|
42073
|
+
errors: [...prev.errors, errorMsg]
|
|
42074
|
+
}));
|
|
42075
|
+
throw error;
|
|
42076
|
+
}
|
|
42077
|
+
},
|
|
42078
|
+
[]
|
|
42079
|
+
);
|
|
42080
|
+
const preload = useCallback(
|
|
42081
|
+
async (urls) => {
|
|
42082
|
+
setState((prev) => ({
|
|
42083
|
+
...prev,
|
|
42084
|
+
isLoading: true,
|
|
42085
|
+
total: urls.length,
|
|
42086
|
+
loaded: 0,
|
|
42087
|
+
errors: []
|
|
42088
|
+
}));
|
|
42089
|
+
let completed = 0;
|
|
42090
|
+
const errors = [];
|
|
42091
|
+
await Promise.all(
|
|
42092
|
+
urls.map(async (url) => {
|
|
42093
|
+
try {
|
|
42094
|
+
if (url.endsWith(".glb") || url.endsWith(".gltf")) {
|
|
42095
|
+
await loaderRef.current.loadModel(url);
|
|
42096
|
+
} else if (url.endsWith(".obj")) {
|
|
42097
|
+
await loaderRef.current.loadOBJ(url);
|
|
42098
|
+
} else if (/\.(png|jpg|jpeg|webp)$/i.test(url)) {
|
|
42099
|
+
await loaderRef.current.loadTexture(url);
|
|
42100
|
+
}
|
|
42101
|
+
completed++;
|
|
42102
|
+
updateProgress(completed, urls.length);
|
|
42103
|
+
} catch (error) {
|
|
42104
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
42105
|
+
errors.push(`${url}: ${errorMsg}`);
|
|
42106
|
+
completed++;
|
|
42107
|
+
updateProgress(completed, urls.length);
|
|
42108
|
+
}
|
|
42109
|
+
})
|
|
42110
|
+
);
|
|
42111
|
+
setState((prev) => ({
|
|
42112
|
+
...prev,
|
|
42113
|
+
isLoading: false,
|
|
42114
|
+
errors
|
|
42115
|
+
}));
|
|
42116
|
+
},
|
|
42117
|
+
[updateProgress]
|
|
42118
|
+
);
|
|
42119
|
+
const hasModel = useCallback((url) => {
|
|
42120
|
+
return loaderRef.current.hasModel(url);
|
|
42121
|
+
}, []);
|
|
42122
|
+
const hasTexture = useCallback((url) => {
|
|
42123
|
+
return loaderRef.current.hasTexture(url);
|
|
42124
|
+
}, []);
|
|
42125
|
+
const getModel = useCallback((url) => {
|
|
42126
|
+
try {
|
|
42127
|
+
return loaderRef.current.getModel(url);
|
|
42128
|
+
} catch {
|
|
42129
|
+
return void 0;
|
|
42130
|
+
}
|
|
42131
|
+
}, []);
|
|
42132
|
+
const getTexture = useCallback((url) => {
|
|
42133
|
+
try {
|
|
42134
|
+
return loaderRef.current.getTexture(url);
|
|
42135
|
+
} catch {
|
|
42136
|
+
return void 0;
|
|
42137
|
+
}
|
|
42138
|
+
}, []);
|
|
42139
|
+
const clearCache = useCallback(() => {
|
|
42140
|
+
loaderRef.current.clearCache();
|
|
42141
|
+
setState({
|
|
42142
|
+
isLoading: false,
|
|
42143
|
+
progress: 0,
|
|
42144
|
+
loaded: 0,
|
|
42145
|
+
total: 0,
|
|
42146
|
+
errors: []
|
|
42147
|
+
});
|
|
42148
|
+
}, []);
|
|
42149
|
+
return {
|
|
42150
|
+
...state,
|
|
42151
|
+
loadModel,
|
|
42152
|
+
loadOBJ,
|
|
42153
|
+
loadTexture,
|
|
42154
|
+
preload,
|
|
42155
|
+
hasModel,
|
|
42156
|
+
hasTexture,
|
|
42157
|
+
getModel,
|
|
42158
|
+
getTexture,
|
|
42159
|
+
clearCache
|
|
42160
|
+
};
|
|
42161
|
+
}
|
|
42162
|
+
var init_useAssetLoader = __esm({
|
|
42163
|
+
"components/game/molecules/three/hooks/useAssetLoader.ts"() {
|
|
42164
|
+
"use client";
|
|
42165
|
+
init_AssetLoader();
|
|
42166
|
+
}
|
|
42167
|
+
});
|
|
42168
|
+
function useGameCanvas3DEvents(options) {
|
|
42169
|
+
const {
|
|
42170
|
+
tileClickEvent,
|
|
42171
|
+
unitClickEvent,
|
|
42172
|
+
featureClickEvent,
|
|
42173
|
+
canvasClickEvent,
|
|
42174
|
+
tileHoverEvent,
|
|
42175
|
+
tileLeaveEvent,
|
|
42176
|
+
unitAnimationEvent,
|
|
42177
|
+
cameraChangeEvent,
|
|
42178
|
+
onTileClick,
|
|
42179
|
+
onUnitClick,
|
|
42180
|
+
onFeatureClick,
|
|
42181
|
+
onCanvasClick,
|
|
42182
|
+
onTileHover,
|
|
42183
|
+
onUnitAnimation
|
|
42184
|
+
} = options;
|
|
42185
|
+
const emit = useEmitEvent();
|
|
42186
|
+
const optionsRef = useRef(options);
|
|
42187
|
+
optionsRef.current = options;
|
|
42188
|
+
const handleTileClick = useCallback(
|
|
42189
|
+
(tile, event) => {
|
|
42190
|
+
if (tileClickEvent) {
|
|
42191
|
+
emit(tileClickEvent, {
|
|
42192
|
+
tileId: tile.id,
|
|
42193
|
+
x: tile.x,
|
|
42194
|
+
z: tile.z ?? tile.y ?? 0,
|
|
42195
|
+
type: tile.type,
|
|
42196
|
+
terrain: tile.terrain,
|
|
42197
|
+
elevation: tile.elevation
|
|
42198
|
+
});
|
|
42199
|
+
}
|
|
42200
|
+
optionsRef.current.onTileClick?.(tile, event);
|
|
42201
|
+
},
|
|
42202
|
+
[tileClickEvent, emit]
|
|
42203
|
+
);
|
|
42204
|
+
const handleUnitClick = useCallback(
|
|
42205
|
+
(unit, event) => {
|
|
42206
|
+
if (unitClickEvent) {
|
|
42207
|
+
emit(unitClickEvent, {
|
|
42208
|
+
unitId: unit.id,
|
|
42209
|
+
x: unit.x,
|
|
42210
|
+
z: unit.z ?? unit.y ?? 0,
|
|
42211
|
+
unitType: unit.unitType,
|
|
42212
|
+
name: unit.name,
|
|
42213
|
+
team: unit.team,
|
|
42214
|
+
faction: unit.faction,
|
|
42215
|
+
health: unit.health,
|
|
42216
|
+
maxHealth: unit.maxHealth
|
|
42217
|
+
});
|
|
42218
|
+
}
|
|
42219
|
+
optionsRef.current.onUnitClick?.(unit, event);
|
|
42220
|
+
},
|
|
42221
|
+
[unitClickEvent, emit]
|
|
42222
|
+
);
|
|
42223
|
+
const handleFeatureClick = useCallback(
|
|
42224
|
+
(feature, event) => {
|
|
42225
|
+
if (featureClickEvent) {
|
|
42226
|
+
emit(featureClickEvent, {
|
|
42227
|
+
featureId: feature.id,
|
|
42228
|
+
x: feature.x,
|
|
42229
|
+
z: feature.z ?? feature.y ?? 0,
|
|
42230
|
+
type: feature.type,
|
|
42231
|
+
elevation: feature.elevation
|
|
42232
|
+
});
|
|
42233
|
+
}
|
|
42234
|
+
optionsRef.current.onFeatureClick?.(feature, event);
|
|
42235
|
+
},
|
|
42236
|
+
[featureClickEvent, emit]
|
|
42237
|
+
);
|
|
42238
|
+
const handleCanvasClick = useCallback(
|
|
42239
|
+
(event) => {
|
|
42240
|
+
if (canvasClickEvent) {
|
|
42241
|
+
emit(canvasClickEvent, {
|
|
42242
|
+
clientX: event.clientX,
|
|
42243
|
+
clientY: event.clientY,
|
|
42244
|
+
button: event.button
|
|
42245
|
+
});
|
|
42246
|
+
}
|
|
42247
|
+
optionsRef.current.onCanvasClick?.(event);
|
|
42248
|
+
},
|
|
42249
|
+
[canvasClickEvent, emit]
|
|
42250
|
+
);
|
|
42251
|
+
const handleTileHover = useCallback(
|
|
42252
|
+
(tile, event) => {
|
|
42253
|
+
if (tile) {
|
|
42254
|
+
if (tileHoverEvent) {
|
|
42255
|
+
emit(tileHoverEvent, {
|
|
42256
|
+
tileId: tile.id,
|
|
42257
|
+
x: tile.x,
|
|
42258
|
+
z: tile.z ?? tile.y ?? 0,
|
|
42259
|
+
type: tile.type
|
|
42260
|
+
});
|
|
42261
|
+
}
|
|
42262
|
+
} else {
|
|
42263
|
+
if (tileLeaveEvent) {
|
|
42264
|
+
emit(tileLeaveEvent, {});
|
|
42265
|
+
}
|
|
42266
|
+
}
|
|
42267
|
+
optionsRef.current.onTileHover?.(tile, event);
|
|
42268
|
+
},
|
|
42269
|
+
[tileHoverEvent, tileLeaveEvent, emit]
|
|
42270
|
+
);
|
|
42271
|
+
const handleUnitAnimation = useCallback(
|
|
42272
|
+
(unitId, state) => {
|
|
42273
|
+
if (unitAnimationEvent) {
|
|
42274
|
+
emit(unitAnimationEvent, {
|
|
42275
|
+
unitId,
|
|
42276
|
+
state,
|
|
42277
|
+
timestamp: Date.now()
|
|
42278
|
+
});
|
|
42279
|
+
}
|
|
42280
|
+
optionsRef.current.onUnitAnimation?.(unitId, state);
|
|
42281
|
+
},
|
|
42282
|
+
[unitAnimationEvent, emit]
|
|
42283
|
+
);
|
|
42284
|
+
const handleCameraChange = useCallback(
|
|
42285
|
+
(position) => {
|
|
42286
|
+
if (cameraChangeEvent) {
|
|
42287
|
+
emit(cameraChangeEvent, {
|
|
42288
|
+
position,
|
|
42289
|
+
timestamp: Date.now()
|
|
42290
|
+
});
|
|
42291
|
+
}
|
|
42292
|
+
},
|
|
42293
|
+
[cameraChangeEvent, emit]
|
|
42294
|
+
);
|
|
42295
|
+
return {
|
|
42296
|
+
handleTileClick,
|
|
42297
|
+
handleUnitClick,
|
|
42298
|
+
handleFeatureClick,
|
|
42299
|
+
handleCanvasClick,
|
|
42300
|
+
handleTileHover,
|
|
42301
|
+
handleUnitAnimation,
|
|
42302
|
+
handleCameraChange
|
|
42303
|
+
};
|
|
42304
|
+
}
|
|
42305
|
+
var init_useGameCanvas3DEvents = __esm({
|
|
42306
|
+
"components/game/molecules/three/hooks/useGameCanvas3DEvents.ts"() {
|
|
42307
|
+
"use client";
|
|
42308
|
+
init_useEventBus();
|
|
42309
|
+
}
|
|
42310
|
+
});
|
|
42311
|
+
|
|
42312
|
+
// components/game/molecules/three/components/Canvas3DLoadingState.css
|
|
42313
|
+
var init_Canvas3DLoadingState = __esm({
|
|
42314
|
+
"components/game/molecules/three/components/Canvas3DLoadingState.css"() {
|
|
42315
|
+
}
|
|
42316
|
+
});
|
|
42317
|
+
function Canvas3DLoadingState({
|
|
42318
|
+
progress = 0,
|
|
42319
|
+
loaded = 0,
|
|
42320
|
+
total = 0,
|
|
42321
|
+
message = "Loading 3D Scene...",
|
|
42322
|
+
details,
|
|
42323
|
+
showSpinner = true,
|
|
42324
|
+
className
|
|
42325
|
+
}) {
|
|
42326
|
+
const clampedProgress = Math.max(0, Math.min(100, progress));
|
|
42327
|
+
const hasProgress = total > 0;
|
|
42328
|
+
return /* @__PURE__ */ jsxs("div", { className: `canvas-3d-loading ${className || ""}`, children: [
|
|
42329
|
+
/* @__PURE__ */ jsxs("div", { className: "canvas-3d-loading__content", children: [
|
|
42330
|
+
showSpinner && /* @__PURE__ */ jsxs("div", { className: "canvas-3d-loading__spinner", children: [
|
|
42331
|
+
/* @__PURE__ */ jsx("div", { className: "spinner__ring" }),
|
|
42332
|
+
/* @__PURE__ */ jsx("div", { className: "spinner__ring spinner__ring--secondary" })
|
|
42333
|
+
] }),
|
|
42334
|
+
/* @__PURE__ */ jsx("div", { className: "canvas-3d-loading__message", children: message }),
|
|
42335
|
+
details && /* @__PURE__ */ jsx("div", { className: "canvas-3d-loading__details", children: details }),
|
|
42336
|
+
hasProgress && /* @__PURE__ */ jsxs("div", { className: "canvas-3d-loading__progress", children: [
|
|
42337
|
+
/* @__PURE__ */ jsx("div", { className: "progress__bar", children: /* @__PURE__ */ jsx(
|
|
42338
|
+
"div",
|
|
42339
|
+
{
|
|
42340
|
+
className: "progress__fill",
|
|
42341
|
+
style: { width: `${clampedProgress}%` }
|
|
42342
|
+
}
|
|
42343
|
+
) }),
|
|
42344
|
+
/* @__PURE__ */ jsxs("div", { className: "progress__text", children: [
|
|
42345
|
+
/* @__PURE__ */ jsxs("span", { className: "progress__percentage", children: [
|
|
42346
|
+
clampedProgress,
|
|
42347
|
+
"%"
|
|
42348
|
+
] }),
|
|
42349
|
+
/* @__PURE__ */ jsxs("span", { className: "progress__count", children: [
|
|
42350
|
+
"(",
|
|
42351
|
+
loaded,
|
|
42352
|
+
"/",
|
|
42353
|
+
total,
|
|
42354
|
+
")"
|
|
42355
|
+
] })
|
|
42356
|
+
] })
|
|
42357
|
+
] })
|
|
42358
|
+
] }),
|
|
42359
|
+
/* @__PURE__ */ jsx("div", { className: "canvas-3d-loading__background", children: /* @__PURE__ */ jsx("div", { className: "bg__grid" }) })
|
|
42360
|
+
] });
|
|
42361
|
+
}
|
|
42362
|
+
var init_Canvas3DLoadingState2 = __esm({
|
|
42363
|
+
"components/game/molecules/three/components/Canvas3DLoadingState.tsx"() {
|
|
42364
|
+
init_Canvas3DLoadingState();
|
|
42365
|
+
}
|
|
42366
|
+
});
|
|
42367
|
+
|
|
42368
|
+
// components/game/molecules/three/components/Canvas3DErrorBoundary.css
|
|
42369
|
+
var init_Canvas3DErrorBoundary = __esm({
|
|
42370
|
+
"components/game/molecules/three/components/Canvas3DErrorBoundary.css"() {
|
|
42371
|
+
}
|
|
42372
|
+
});
|
|
42373
|
+
var log9, Canvas3DErrorBoundary;
|
|
42374
|
+
var init_Canvas3DErrorBoundary2 = __esm({
|
|
42375
|
+
"components/game/molecules/three/components/Canvas3DErrorBoundary.tsx"() {
|
|
42376
|
+
init_Canvas3DErrorBoundary();
|
|
42377
|
+
log9 = createLogger("almadar:ui:game:canvas3d:error-boundary");
|
|
42378
|
+
Canvas3DErrorBoundary = class extends Component {
|
|
42379
|
+
constructor(props) {
|
|
42380
|
+
super(props);
|
|
42381
|
+
__publicField(this, "handleReset", () => {
|
|
42382
|
+
this.setState({
|
|
42383
|
+
hasError: false,
|
|
42384
|
+
error: null,
|
|
42385
|
+
errorInfo: null
|
|
42386
|
+
});
|
|
42387
|
+
this.props.onReset?.();
|
|
42388
|
+
});
|
|
42389
|
+
this.state = {
|
|
42390
|
+
hasError: false,
|
|
42391
|
+
error: null,
|
|
42392
|
+
errorInfo: null
|
|
42393
|
+
};
|
|
42394
|
+
}
|
|
42395
|
+
static getDerivedStateFromError(error) {
|
|
42396
|
+
return {
|
|
42397
|
+
hasError: true,
|
|
42398
|
+
error,
|
|
42399
|
+
errorInfo: null
|
|
42400
|
+
};
|
|
42401
|
+
}
|
|
42402
|
+
componentDidCatch(error, errorInfo) {
|
|
42403
|
+
this.setState({ errorInfo });
|
|
42404
|
+
this.props.onError?.(error, errorInfo);
|
|
42405
|
+
log9.error("Error caught", { error });
|
|
42406
|
+
log9.error("Component stack", { componentStack: errorInfo.componentStack ?? "<none>" });
|
|
42407
|
+
}
|
|
42408
|
+
render() {
|
|
42409
|
+
if (this.state.hasError) {
|
|
42410
|
+
if (this.props.fallback) {
|
|
42411
|
+
return this.props.fallback;
|
|
42412
|
+
}
|
|
42413
|
+
return /* @__PURE__ */ jsx("div", { className: "canvas-3d-error", children: /* @__PURE__ */ jsxs("div", { className: "canvas-3d-error__content", children: [
|
|
42414
|
+
/* @__PURE__ */ jsx("div", { className: "canvas-3d-error__icon", children: "\u26A0\uFE0F" }),
|
|
42415
|
+
/* @__PURE__ */ jsx("h2", { className: "canvas-3d-error__title", children: "3D Scene Error" }),
|
|
42416
|
+
/* @__PURE__ */ jsx("p", { className: "canvas-3d-error__message", children: "Something went wrong while rendering the 3D scene." }),
|
|
42417
|
+
this.state.error && /* @__PURE__ */ jsxs("details", { className: "canvas-3d-error__details", children: [
|
|
42418
|
+
/* @__PURE__ */ jsx("summary", { children: "Error Details" }),
|
|
42419
|
+
/* @__PURE__ */ jsxs("pre", { className: "error__stack", children: [
|
|
42420
|
+
this.state.error.message,
|
|
42421
|
+
"\n",
|
|
42422
|
+
this.state.error.stack
|
|
42423
|
+
] }),
|
|
42424
|
+
this.state.errorInfo && /* @__PURE__ */ jsx("pre", { className: "error__component-stack", children: this.state.errorInfo.componentStack })
|
|
42425
|
+
] }),
|
|
42426
|
+
/* @__PURE__ */ jsxs("div", { className: "canvas-3d-error__actions", children: [
|
|
42427
|
+
/* @__PURE__ */ jsx(
|
|
42428
|
+
"button",
|
|
42429
|
+
{
|
|
42430
|
+
className: "error__button error__button--primary",
|
|
42431
|
+
onClick: this.handleReset,
|
|
42432
|
+
children: "Try Again"
|
|
42433
|
+
}
|
|
42434
|
+
),
|
|
42435
|
+
/* @__PURE__ */ jsx(
|
|
42436
|
+
"button",
|
|
42437
|
+
{
|
|
42438
|
+
className: "error__button error__button--secondary",
|
|
42439
|
+
onClick: () => window.location.reload(),
|
|
42440
|
+
children: "Reload Page"
|
|
42441
|
+
}
|
|
42442
|
+
)
|
|
42443
|
+
] })
|
|
42444
|
+
] }) });
|
|
42445
|
+
}
|
|
42446
|
+
return this.props.children;
|
|
42447
|
+
}
|
|
42448
|
+
};
|
|
42449
|
+
}
|
|
42450
|
+
});
|
|
42451
|
+
function detectAssetRoot2(modelUrl) {
|
|
42452
|
+
const idx = modelUrl.indexOf("/3d/");
|
|
42453
|
+
if (idx !== -1) {
|
|
42454
|
+
return modelUrl.substring(0, idx + 4);
|
|
42455
|
+
}
|
|
42456
|
+
return modelUrl.substring(0, modelUrl.lastIndexOf("/") + 1);
|
|
42457
|
+
}
|
|
42458
|
+
function useGLTFModel(url, resourceBasePath) {
|
|
42459
|
+
const [state, setState] = useState({
|
|
42460
|
+
model: null,
|
|
42461
|
+
isLoading: false,
|
|
42462
|
+
error: null
|
|
42463
|
+
});
|
|
42464
|
+
useEffect(() => {
|
|
42465
|
+
if (!url) {
|
|
42466
|
+
setState({ model: null, isLoading: false, error: null });
|
|
42467
|
+
return;
|
|
42468
|
+
}
|
|
42469
|
+
log10.debug("Loading", { url });
|
|
42470
|
+
setState((prev) => ({ ...prev, isLoading: true, error: null }));
|
|
42471
|
+
const assetRoot = resourceBasePath || detectAssetRoot2(url);
|
|
42472
|
+
const loader = new GLTFLoader$1();
|
|
42473
|
+
loader.setResourcePath(assetRoot);
|
|
42474
|
+
loader.load(
|
|
42475
|
+
url,
|
|
42476
|
+
(gltf) => {
|
|
42477
|
+
log10.debug("Loaded", { url });
|
|
42478
|
+
setState({
|
|
42479
|
+
model: gltf.scene,
|
|
42480
|
+
isLoading: false,
|
|
42481
|
+
error: null
|
|
42482
|
+
});
|
|
42483
|
+
},
|
|
42484
|
+
void 0,
|
|
42485
|
+
(err) => {
|
|
42486
|
+
log10.warn("Failed", { url, error: err instanceof Error ? err : String(err) });
|
|
42487
|
+
setState({
|
|
42488
|
+
model: null,
|
|
42489
|
+
isLoading: false,
|
|
42490
|
+
error: err instanceof Error ? err : new Error(String(err))
|
|
42491
|
+
});
|
|
42492
|
+
}
|
|
42493
|
+
);
|
|
42494
|
+
}, [url, resourceBasePath]);
|
|
42495
|
+
return state;
|
|
42496
|
+
}
|
|
42497
|
+
function ModelLoader({
|
|
42498
|
+
url,
|
|
42499
|
+
position = [0, 0, 0],
|
|
42500
|
+
scale = 1,
|
|
42501
|
+
rotation = [0, 0, 0],
|
|
42502
|
+
isSelected = false,
|
|
42503
|
+
isHovered = false,
|
|
42504
|
+
onClick,
|
|
42505
|
+
onHover,
|
|
42506
|
+
fallbackGeometry = "box",
|
|
42507
|
+
castShadow = true,
|
|
42508
|
+
receiveShadow = true,
|
|
42509
|
+
resourceBasePath
|
|
42510
|
+
}) {
|
|
42511
|
+
const { model: loadedModel, isLoading, error } = useGLTFModel(url, resourceBasePath);
|
|
42512
|
+
const model = useMemo(() => {
|
|
42513
|
+
if (!loadedModel) return null;
|
|
42514
|
+
const cloned = loadedModel.clone();
|
|
42515
|
+
cloned.traverse((child) => {
|
|
42516
|
+
if (child instanceof THREE.Mesh) {
|
|
42517
|
+
child.castShadow = castShadow;
|
|
42518
|
+
child.receiveShadow = receiveShadow;
|
|
42519
|
+
}
|
|
42520
|
+
});
|
|
42521
|
+
return cloned;
|
|
42522
|
+
}, [loadedModel, castShadow, receiveShadow]);
|
|
42523
|
+
const scaleArray = useMemo(() => {
|
|
42524
|
+
if (typeof scale === "number") {
|
|
42525
|
+
return [scale, scale, scale];
|
|
42526
|
+
}
|
|
42527
|
+
return scale;
|
|
42528
|
+
}, [scale]);
|
|
42529
|
+
const rotationRad = useMemo(() => {
|
|
42530
|
+
return [
|
|
42531
|
+
rotation[0] * Math.PI / 180,
|
|
42532
|
+
rotation[1] * Math.PI / 180,
|
|
42533
|
+
rotation[2] * Math.PI / 180
|
|
42534
|
+
];
|
|
42535
|
+
}, [rotation]);
|
|
42536
|
+
if (isLoading) {
|
|
42537
|
+
return /* @__PURE__ */ jsx("group", { position, children: /* @__PURE__ */ jsxs("mesh", { rotation: [Math.PI / 2, 0, 0], children: [
|
|
42538
|
+
/* @__PURE__ */ jsx("ringGeometry", { args: [0.3, 0.35, 16] }),
|
|
42539
|
+
/* @__PURE__ */ jsx("meshBasicMaterial", { color: "#4a90d9", transparent: true, opacity: 0.8 })
|
|
42540
|
+
] }) });
|
|
42541
|
+
}
|
|
42542
|
+
if (error || !model) {
|
|
42543
|
+
if (fallbackGeometry === "none") {
|
|
42544
|
+
return /* @__PURE__ */ jsx("group", { position });
|
|
42545
|
+
}
|
|
42546
|
+
const fallbackProps = {
|
|
42547
|
+
onClick,
|
|
42548
|
+
onPointerOver: () => onHover?.(true),
|
|
42549
|
+
onPointerOut: () => onHover?.(false)
|
|
42550
|
+
};
|
|
42551
|
+
return /* @__PURE__ */ jsxs("group", { position, children: [
|
|
42552
|
+
(isSelected || isHovered) && /* @__PURE__ */ jsxs("mesh", { position: [0, 0.02, 0], rotation: [-Math.PI / 2, 0, 0], children: [
|
|
42553
|
+
/* @__PURE__ */ jsx("ringGeometry", { args: [0.6, 0.7, 32] }),
|
|
42554
|
+
/* @__PURE__ */ jsx(
|
|
42555
|
+
"meshBasicMaterial",
|
|
42556
|
+
{
|
|
42557
|
+
color: isSelected ? 16755200 : 16777215,
|
|
42558
|
+
transparent: true,
|
|
42559
|
+
opacity: 0.5
|
|
42560
|
+
}
|
|
42561
|
+
)
|
|
42562
|
+
] }),
|
|
42563
|
+
fallbackGeometry === "box" && /* @__PURE__ */ jsxs("mesh", { ...fallbackProps, position: [0, 0.5, 0], children: [
|
|
42564
|
+
/* @__PURE__ */ jsx("boxGeometry", { args: [0.8, 0.8, 0.8] }),
|
|
42565
|
+
/* @__PURE__ */ jsx("meshStandardMaterial", { color: error ? 16729156 : 8947848 })
|
|
42566
|
+
] }),
|
|
42567
|
+
fallbackGeometry === "sphere" && /* @__PURE__ */ jsxs("mesh", { ...fallbackProps, position: [0, 0.5, 0], children: [
|
|
42568
|
+
/* @__PURE__ */ jsx("sphereGeometry", { args: [0.4, 16, 16] }),
|
|
42569
|
+
/* @__PURE__ */ jsx("meshStandardMaterial", { color: error ? 16729156 : 8947848 })
|
|
42570
|
+
] }),
|
|
42571
|
+
fallbackGeometry === "cylinder" && /* @__PURE__ */ jsxs("mesh", { ...fallbackProps, position: [0, 0.5, 0], children: [
|
|
42572
|
+
/* @__PURE__ */ jsx("cylinderGeometry", { args: [0.3, 0.3, 0.8, 16] }),
|
|
42573
|
+
/* @__PURE__ */ jsx("meshStandardMaterial", { color: error ? 16729156 : 8947848 })
|
|
42574
|
+
] })
|
|
42575
|
+
] });
|
|
42576
|
+
}
|
|
42577
|
+
return /* @__PURE__ */ jsxs(
|
|
42578
|
+
"group",
|
|
42579
|
+
{
|
|
42580
|
+
position,
|
|
42581
|
+
rotation: rotationRad,
|
|
42582
|
+
onClick,
|
|
42583
|
+
onPointerOver: () => onHover?.(true),
|
|
42584
|
+
onPointerOut: () => onHover?.(false),
|
|
42585
|
+
children: [
|
|
42586
|
+
(isSelected || isHovered) && /* @__PURE__ */ jsxs("mesh", { position: [0, 0.02, 0], rotation: [-Math.PI / 2, 0, 0], children: [
|
|
42587
|
+
/* @__PURE__ */ jsx("ringGeometry", { args: [0.6, 0.7, 32] }),
|
|
42588
|
+
/* @__PURE__ */ jsx(
|
|
42589
|
+
"meshBasicMaterial",
|
|
42590
|
+
{
|
|
42591
|
+
color: isSelected ? 16755200 : 16777215,
|
|
42592
|
+
transparent: true,
|
|
42593
|
+
opacity: 0.5
|
|
42594
|
+
}
|
|
42595
|
+
)
|
|
42596
|
+
] }),
|
|
42597
|
+
/* @__PURE__ */ jsx("primitive", { object: model, scale: scaleArray })
|
|
42598
|
+
]
|
|
42599
|
+
}
|
|
42600
|
+
);
|
|
42601
|
+
}
|
|
42602
|
+
var log10;
|
|
42603
|
+
var init_ModelLoader = __esm({
|
|
42604
|
+
"components/game/molecules/three/components/ModelLoader.tsx"() {
|
|
42605
|
+
"use client";
|
|
42606
|
+
log10 = createLogger("almadar:ui:game:model-loader");
|
|
42607
|
+
}
|
|
42608
|
+
});
|
|
42609
|
+
|
|
42610
|
+
// components/game/molecules/GameCanvas3D.css
|
|
42611
|
+
var init_GameCanvas3D = __esm({
|
|
42612
|
+
"components/game/molecules/GameCanvas3D.css"() {
|
|
42613
|
+
}
|
|
42614
|
+
});
|
|
42615
|
+
function CameraController({
|
|
42616
|
+
onCameraChange
|
|
42617
|
+
}) {
|
|
42618
|
+
const { camera } = useThree();
|
|
42619
|
+
useEffect(() => {
|
|
42620
|
+
if (onCameraChange) {
|
|
42621
|
+
onCameraChange({
|
|
42622
|
+
x: camera.position.x,
|
|
42623
|
+
y: camera.position.y,
|
|
42624
|
+
z: camera.position.z
|
|
42625
|
+
});
|
|
42626
|
+
}
|
|
42627
|
+
}, [camera.position, onCameraChange]);
|
|
42628
|
+
return null;
|
|
42629
|
+
}
|
|
42630
|
+
var DEFAULT_GRID_CONFIG, GameCanvas3D;
|
|
42631
|
+
var init_GameCanvas3D2 = __esm({
|
|
42632
|
+
"components/game/molecules/GameCanvas3D.tsx"() {
|
|
42633
|
+
"use client";
|
|
42634
|
+
init_AssetLoader();
|
|
42635
|
+
init_useAssetLoader();
|
|
42636
|
+
init_useGameCanvas3DEvents();
|
|
42637
|
+
init_Canvas3DLoadingState2();
|
|
42638
|
+
init_Canvas3DErrorBoundary2();
|
|
42639
|
+
init_ModelLoader();
|
|
42640
|
+
init_cn();
|
|
42641
|
+
init_GameCanvas3D();
|
|
42642
|
+
DEFAULT_GRID_CONFIG = {
|
|
42643
|
+
cellSize: 1,
|
|
42644
|
+
offsetX: 0,
|
|
42645
|
+
offsetZ: 0
|
|
42646
|
+
};
|
|
42647
|
+
GameCanvas3D = forwardRef(
|
|
42648
|
+
({
|
|
42649
|
+
tiles = [],
|
|
42650
|
+
units = [],
|
|
42651
|
+
features = [],
|
|
42652
|
+
events: events2 = [],
|
|
42653
|
+
orientation = "standard",
|
|
42654
|
+
cameraMode = "isometric",
|
|
42655
|
+
showGrid = true,
|
|
42656
|
+
showCoordinates = false,
|
|
42657
|
+
showTileInfo = false,
|
|
42658
|
+
overlay = "default",
|
|
42659
|
+
shadows = true,
|
|
42660
|
+
backgroundColor = "#1a1a2e",
|
|
42661
|
+
onTileClick,
|
|
42662
|
+
onUnitClick,
|
|
42663
|
+
onFeatureClick,
|
|
42664
|
+
onCanvasClick,
|
|
42665
|
+
onTileHover,
|
|
42666
|
+
onUnitAnimation,
|
|
42667
|
+
assetLoader: customAssetLoader,
|
|
42668
|
+
tileRenderer: CustomTileRenderer,
|
|
42669
|
+
unitRenderer: CustomUnitRenderer,
|
|
42670
|
+
featureRenderer: CustomFeatureRenderer,
|
|
42671
|
+
className,
|
|
42672
|
+
isLoading: externalLoading,
|
|
42673
|
+
error: externalError,
|
|
42674
|
+
entity,
|
|
42675
|
+
preloadAssets = [],
|
|
42676
|
+
tileClickEvent,
|
|
42677
|
+
unitClickEvent,
|
|
42678
|
+
featureClickEvent,
|
|
42679
|
+
canvasClickEvent,
|
|
42680
|
+
tileHoverEvent,
|
|
42681
|
+
tileLeaveEvent,
|
|
42682
|
+
unitAnimationEvent,
|
|
42683
|
+
cameraChangeEvent,
|
|
42684
|
+
loadingMessage = "Loading 3D Scene...",
|
|
42685
|
+
useInstancing = true,
|
|
42686
|
+
validMoves = [],
|
|
42687
|
+
attackTargets = [],
|
|
42688
|
+
selectedTileIds = [],
|
|
42689
|
+
selectedUnitId = null,
|
|
42690
|
+
children
|
|
42691
|
+
}, ref) => {
|
|
42692
|
+
const containerRef = useRef(null);
|
|
42693
|
+
const controlsRef = useRef(null);
|
|
42694
|
+
const [hoveredTile, setHoveredTile] = useState(null);
|
|
42695
|
+
const [internalError, setInternalError] = useState(null);
|
|
42696
|
+
const { isLoading: assetsLoading, progress, loaded, total } = useAssetLoader({
|
|
42697
|
+
preloadUrls: preloadAssets,
|
|
42698
|
+
loader: customAssetLoader
|
|
42699
|
+
});
|
|
42700
|
+
const eventHandlers = useGameCanvas3DEvents({
|
|
42701
|
+
tileClickEvent,
|
|
42702
|
+
unitClickEvent,
|
|
42703
|
+
featureClickEvent,
|
|
42704
|
+
canvasClickEvent,
|
|
42705
|
+
tileHoverEvent,
|
|
42706
|
+
tileLeaveEvent,
|
|
42707
|
+
unitAnimationEvent,
|
|
42708
|
+
cameraChangeEvent,
|
|
42709
|
+
onTileClick,
|
|
42710
|
+
onUnitClick,
|
|
42711
|
+
onFeatureClick,
|
|
42712
|
+
onCanvasClick,
|
|
42713
|
+
onTileHover,
|
|
42714
|
+
onUnitAnimation
|
|
42715
|
+
});
|
|
42716
|
+
const gridBounds = useMemo(() => {
|
|
42717
|
+
if (tiles.length === 0) {
|
|
42718
|
+
return { minX: 0, maxX: 10, minZ: 0, maxZ: 10 };
|
|
42719
|
+
}
|
|
42720
|
+
const xs = tiles.map((t) => t.x);
|
|
42721
|
+
const zs = tiles.map((t) => t.z || t.y || 0);
|
|
42722
|
+
return {
|
|
42723
|
+
minX: Math.min(...xs),
|
|
42724
|
+
maxX: Math.max(...xs),
|
|
42725
|
+
minZ: Math.min(...zs),
|
|
42726
|
+
maxZ: Math.max(...zs)
|
|
42727
|
+
};
|
|
42728
|
+
}, [tiles]);
|
|
42729
|
+
const cameraTarget = useMemo(() => {
|
|
42730
|
+
return [
|
|
42731
|
+
(gridBounds.minX + gridBounds.maxX) / 2,
|
|
42732
|
+
0,
|
|
42733
|
+
(gridBounds.minZ + gridBounds.maxZ) / 2
|
|
42734
|
+
];
|
|
42735
|
+
}, [gridBounds]);
|
|
42736
|
+
const gridConfig = useMemo(
|
|
42737
|
+
() => ({
|
|
42738
|
+
...DEFAULT_GRID_CONFIG,
|
|
42739
|
+
offsetX: -(gridBounds.maxX - gridBounds.minX) / 2,
|
|
42740
|
+
offsetZ: -(gridBounds.maxZ - gridBounds.minZ) / 2
|
|
42741
|
+
}),
|
|
42742
|
+
[gridBounds]
|
|
42743
|
+
);
|
|
42744
|
+
const gridToWorld = useCallback(
|
|
42745
|
+
(x, z, y = 0) => {
|
|
42746
|
+
const worldX = (x - gridBounds.minX) * gridConfig.cellSize;
|
|
42747
|
+
const worldZ = (z - gridBounds.minZ) * gridConfig.cellSize;
|
|
42748
|
+
return [worldX, y * gridConfig.cellSize, worldZ];
|
|
42749
|
+
},
|
|
42750
|
+
[gridBounds, gridConfig]
|
|
42751
|
+
);
|
|
42752
|
+
useImperativeHandle(ref, () => ({
|
|
42753
|
+
getCameraPosition: () => {
|
|
42754
|
+
if (controlsRef.current) {
|
|
42755
|
+
const pos = controlsRef.current.object.position;
|
|
42756
|
+
return new THREE.Vector3(pos.x, pos.y, pos.z);
|
|
42757
|
+
}
|
|
42758
|
+
return null;
|
|
42759
|
+
},
|
|
42760
|
+
setCameraPosition: (x, y, z) => {
|
|
42761
|
+
if (controlsRef.current) {
|
|
42762
|
+
controlsRef.current.object.position.set(x, y, z);
|
|
42763
|
+
controlsRef.current.update();
|
|
42764
|
+
}
|
|
42765
|
+
},
|
|
42766
|
+
lookAt: (x, y, z) => {
|
|
42767
|
+
if (controlsRef.current) {
|
|
42768
|
+
controlsRef.current.target.set(x, y, z);
|
|
42769
|
+
controlsRef.current.update();
|
|
42770
|
+
}
|
|
42771
|
+
},
|
|
42772
|
+
resetCamera: () => {
|
|
42773
|
+
if (controlsRef.current) {
|
|
42774
|
+
controlsRef.current.reset();
|
|
42775
|
+
}
|
|
42776
|
+
},
|
|
42777
|
+
screenshot: () => {
|
|
42778
|
+
const canvas = containerRef.current?.querySelector("canvas");
|
|
42779
|
+
if (canvas) {
|
|
42780
|
+
return canvas.toDataURL("image/png");
|
|
42781
|
+
}
|
|
42782
|
+
return null;
|
|
42783
|
+
},
|
|
42784
|
+
export: () => ({
|
|
42785
|
+
tiles,
|
|
42786
|
+
units,
|
|
42787
|
+
features
|
|
42788
|
+
})
|
|
42789
|
+
}));
|
|
42790
|
+
const handleTileClick = useCallback(
|
|
42791
|
+
(tile, event) => {
|
|
42792
|
+
eventHandlers.handleTileClick(tile, event);
|
|
42793
|
+
},
|
|
42794
|
+
[eventHandlers]
|
|
42795
|
+
);
|
|
42796
|
+
const handleUnitClick = useCallback(
|
|
42797
|
+
(unit, event) => {
|
|
42798
|
+
eventHandlers.handleUnitClick(unit, event);
|
|
42799
|
+
},
|
|
42800
|
+
[eventHandlers]
|
|
42801
|
+
);
|
|
42802
|
+
const handleFeatureClick = useCallback(
|
|
42803
|
+
(feature, event) => {
|
|
42804
|
+
if (event) {
|
|
42805
|
+
eventHandlers.handleFeatureClick(feature, event);
|
|
42806
|
+
}
|
|
42807
|
+
},
|
|
42808
|
+
[eventHandlers]
|
|
42809
|
+
);
|
|
42810
|
+
const handleTileHover = useCallback(
|
|
42811
|
+
(tile, event) => {
|
|
42812
|
+
setHoveredTile(tile);
|
|
42813
|
+
if (event) {
|
|
42814
|
+
eventHandlers.handleTileHover(tile, event);
|
|
42815
|
+
}
|
|
42816
|
+
},
|
|
42817
|
+
[eventHandlers]
|
|
42818
|
+
);
|
|
42819
|
+
const cameraConfig = useMemo(() => {
|
|
42820
|
+
const size = Math.max(
|
|
42821
|
+
gridBounds.maxX - gridBounds.minX,
|
|
42822
|
+
gridBounds.maxZ - gridBounds.minZ
|
|
42823
|
+
);
|
|
42824
|
+
const distance = size * 1.5;
|
|
42825
|
+
switch (cameraMode) {
|
|
42826
|
+
case "isometric":
|
|
42827
|
+
return {
|
|
42828
|
+
position: [distance, distance * 0.8, distance],
|
|
42829
|
+
fov: 45
|
|
42830
|
+
};
|
|
42831
|
+
case "top-down":
|
|
42832
|
+
return {
|
|
42833
|
+
position: [0, distance * 2, 0],
|
|
42834
|
+
fov: 45
|
|
42835
|
+
};
|
|
42836
|
+
case "perspective":
|
|
42837
|
+
default:
|
|
42838
|
+
return {
|
|
42839
|
+
position: [distance, distance, distance],
|
|
42840
|
+
fov: 45
|
|
42841
|
+
};
|
|
42842
|
+
}
|
|
42843
|
+
}, [cameraMode, gridBounds]);
|
|
42844
|
+
const DefaultTileRenderer = useCallback(
|
|
42845
|
+
({ tile, position }) => {
|
|
42846
|
+
const isSelected = tile.id ? selectedTileIds.includes(tile.id) : false;
|
|
42847
|
+
const isHovered = hoveredTile?.id === tile.id;
|
|
42848
|
+
const isValidMove = validMoves.some(
|
|
42849
|
+
(m) => m.x === tile.x && m.z === (tile.z ?? tile.y ?? 0)
|
|
42850
|
+
);
|
|
42851
|
+
const isAttackTarget = attackTargets.some(
|
|
42852
|
+
(m) => m.x === tile.x && m.z === (tile.z ?? tile.y ?? 0)
|
|
42853
|
+
);
|
|
42854
|
+
let color = 8421504;
|
|
42855
|
+
if (tile.type === "water") color = 4491468;
|
|
42856
|
+
else if (tile.type === "grass") color = 4500036;
|
|
42857
|
+
else if (tile.type === "sand") color = 14535816;
|
|
42858
|
+
else if (tile.type === "rock") color = 8947848;
|
|
42859
|
+
else if (tile.type === "snow") color = 15658734;
|
|
42860
|
+
let emissive = 0;
|
|
42861
|
+
if (isSelected) emissive = 4473924;
|
|
42862
|
+
else if (isAttackTarget) emissive = 4456448;
|
|
42863
|
+
else if (isValidMove) emissive = 17408;
|
|
42864
|
+
else if (isHovered) emissive = 2236962;
|
|
42865
|
+
if (tile.modelUrl) {
|
|
42866
|
+
return /* @__PURE__ */ jsx(
|
|
42867
|
+
"group",
|
|
42868
|
+
{
|
|
42869
|
+
position,
|
|
42870
|
+
onClick: (e) => handleTileClick(tile, e),
|
|
42871
|
+
onPointerEnter: (e) => handleTileHover(tile, e),
|
|
42872
|
+
onPointerLeave: (e) => handleTileHover(null, e),
|
|
42873
|
+
userData: { type: "tile", tileId: tile.id, gridX: tile.x, gridZ: tile.z ?? tile.y },
|
|
42874
|
+
children: /* @__PURE__ */ jsx(
|
|
42875
|
+
ModelLoader,
|
|
42876
|
+
{
|
|
42877
|
+
url: tile.modelUrl,
|
|
42878
|
+
scale: 0.95,
|
|
42879
|
+
fallbackGeometry: "box",
|
|
42880
|
+
castShadow: true,
|
|
42881
|
+
receiveShadow: true
|
|
42882
|
+
}
|
|
42883
|
+
)
|
|
42884
|
+
}
|
|
42885
|
+
);
|
|
42886
|
+
}
|
|
42887
|
+
return /* @__PURE__ */ jsxs(
|
|
42888
|
+
"mesh",
|
|
42889
|
+
{
|
|
42890
|
+
position,
|
|
42891
|
+
onClick: (e) => handleTileClick(tile, e),
|
|
42892
|
+
onPointerEnter: (e) => handleTileHover(tile, e),
|
|
42893
|
+
onPointerLeave: (e) => handleTileHover(null, e),
|
|
42894
|
+
userData: { type: "tile", tileId: tile.id, gridX: tile.x, gridZ: tile.z ?? tile.y },
|
|
42895
|
+
children: [
|
|
42896
|
+
/* @__PURE__ */ jsx("boxGeometry", { args: [0.95, 0.2, 0.95] }),
|
|
42897
|
+
/* @__PURE__ */ jsx("meshStandardMaterial", { color, emissive })
|
|
42898
|
+
]
|
|
42899
|
+
}
|
|
42900
|
+
);
|
|
42901
|
+
},
|
|
42902
|
+
[selectedTileIds, hoveredTile, validMoves, attackTargets, handleTileClick, handleTileHover]
|
|
42903
|
+
);
|
|
42904
|
+
const DefaultUnitRenderer = useCallback(
|
|
42905
|
+
({ unit, position }) => {
|
|
42906
|
+
const isSelected = selectedUnitId === unit.id;
|
|
42907
|
+
const color = unit.faction === "player" ? 4491519 : unit.faction === "enemy" ? 16729156 : 16777028;
|
|
42908
|
+
return /* @__PURE__ */ jsxs(
|
|
42909
|
+
"group",
|
|
42910
|
+
{
|
|
42911
|
+
position,
|
|
42912
|
+
onClick: (e) => handleUnitClick(unit, e),
|
|
42913
|
+
userData: { type: "unit", unitId: unit.id },
|
|
42914
|
+
children: [
|
|
42915
|
+
isSelected && /* @__PURE__ */ jsxs("mesh", { position: [0, 0.05, 0], rotation: [-Math.PI / 2, 0, 0], children: [
|
|
42916
|
+
/* @__PURE__ */ jsx("ringGeometry", { args: [0.4, 0.5, 32] }),
|
|
42917
|
+
/* @__PURE__ */ jsx("meshBasicMaterial", { color: "#ffff00", transparent: true, opacity: 0.8 })
|
|
42918
|
+
] }),
|
|
42919
|
+
unit.modelUrl ? (
|
|
42920
|
+
/* GLB unit model (box fallback while loading / on error) */
|
|
42921
|
+
/* @__PURE__ */ jsx(
|
|
42922
|
+
ModelLoader,
|
|
42923
|
+
{
|
|
42924
|
+
url: unit.modelUrl,
|
|
42925
|
+
scale: 0.5,
|
|
42926
|
+
fallbackGeometry: "box",
|
|
42927
|
+
castShadow: true
|
|
42928
|
+
}
|
|
42929
|
+
)
|
|
42930
|
+
) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
42931
|
+
/* @__PURE__ */ jsxs("mesh", { position: [0, 0.3, 0], children: [
|
|
42932
|
+
/* @__PURE__ */ jsx("cylinderGeometry", { args: [0.3, 0.3, 0.1, 8] }),
|
|
42933
|
+
/* @__PURE__ */ jsx("meshStandardMaterial", { color })
|
|
42934
|
+
] }),
|
|
42935
|
+
/* @__PURE__ */ jsxs("mesh", { position: [0, 0.6, 0], children: [
|
|
42936
|
+
/* @__PURE__ */ jsx("capsuleGeometry", { args: [0.2, 0.4, 4, 8] }),
|
|
42937
|
+
/* @__PURE__ */ jsx("meshStandardMaterial", { color })
|
|
42938
|
+
] }),
|
|
42939
|
+
/* @__PURE__ */ jsxs("mesh", { position: [0, 0.9, 0], children: [
|
|
42940
|
+
/* @__PURE__ */ jsx("sphereGeometry", { args: [0.12, 8, 8] }),
|
|
42941
|
+
/* @__PURE__ */ jsx("meshStandardMaterial", { color })
|
|
42942
|
+
] })
|
|
42943
|
+
] }),
|
|
42944
|
+
unit.health !== void 0 && unit.maxHealth !== void 0 && /* @__PURE__ */ jsxs("group", { position: [0, 1.2, 0], children: [
|
|
42945
|
+
/* @__PURE__ */ jsxs("mesh", { position: [-0.25, 0, 0], children: [
|
|
42946
|
+
/* @__PURE__ */ jsx("planeGeometry", { args: [0.5, 0.05] }),
|
|
42947
|
+
/* @__PURE__ */ jsx("meshBasicMaterial", { color: 3355443 })
|
|
42948
|
+
] }),
|
|
42949
|
+
/* @__PURE__ */ jsxs(
|
|
42950
|
+
"mesh",
|
|
42951
|
+
{
|
|
42952
|
+
position: [
|
|
42953
|
+
-0.25 + 0.5 * (unit.health / unit.maxHealth) / 2,
|
|
42954
|
+
0,
|
|
42955
|
+
0.01
|
|
42956
|
+
],
|
|
42957
|
+
children: [
|
|
42958
|
+
/* @__PURE__ */ jsx("planeGeometry", { args: [0.5 * (unit.health / unit.maxHealth), 0.05] }),
|
|
42959
|
+
/* @__PURE__ */ jsx(
|
|
42960
|
+
"meshBasicMaterial",
|
|
42961
|
+
{
|
|
42962
|
+
color: unit.health / unit.maxHealth > 0.5 ? 4500036 : unit.health / unit.maxHealth > 0.25 ? 11184708 : 16729156
|
|
42963
|
+
}
|
|
42964
|
+
)
|
|
42965
|
+
]
|
|
42966
|
+
}
|
|
42967
|
+
)
|
|
42968
|
+
] })
|
|
42969
|
+
]
|
|
42970
|
+
}
|
|
42971
|
+
);
|
|
42972
|
+
},
|
|
42973
|
+
[selectedUnitId, handleUnitClick]
|
|
42974
|
+
);
|
|
42975
|
+
const DefaultFeatureRenderer = useCallback(
|
|
42976
|
+
({
|
|
42977
|
+
feature,
|
|
42978
|
+
position
|
|
42979
|
+
}) => {
|
|
42980
|
+
if (feature.assetUrl) {
|
|
42981
|
+
return /* @__PURE__ */ jsx(
|
|
42982
|
+
ModelLoader,
|
|
42983
|
+
{
|
|
42984
|
+
url: feature.assetUrl,
|
|
42985
|
+
position,
|
|
42986
|
+
scale: 0.5,
|
|
42987
|
+
rotation: [0, feature.rotation ?? 0, 0],
|
|
42988
|
+
onClick: () => handleFeatureClick(feature, null),
|
|
42989
|
+
fallbackGeometry: "box"
|
|
42990
|
+
},
|
|
42991
|
+
feature.id
|
|
42992
|
+
);
|
|
42993
|
+
}
|
|
42994
|
+
if (feature.type === "tree") {
|
|
42995
|
+
return /* @__PURE__ */ jsxs(
|
|
42996
|
+
"group",
|
|
42997
|
+
{
|
|
42998
|
+
position,
|
|
42999
|
+
onClick: (e) => handleFeatureClick(feature, e),
|
|
43000
|
+
userData: { type: "feature", featureId: feature.id },
|
|
43001
|
+
children: [
|
|
43002
|
+
/* @__PURE__ */ jsxs("mesh", { position: [0, 0.4, 0], children: [
|
|
43003
|
+
/* @__PURE__ */ jsx("cylinderGeometry", { args: [0.1, 0.15, 0.8, 6] }),
|
|
43004
|
+
/* @__PURE__ */ jsx("meshStandardMaterial", { color: 9127187 })
|
|
43005
|
+
] }),
|
|
43006
|
+
/* @__PURE__ */ jsxs("mesh", { position: [0, 0.9, 0], children: [
|
|
43007
|
+
/* @__PURE__ */ jsx("coneGeometry", { args: [0.5, 0.8, 8] }),
|
|
43008
|
+
/* @__PURE__ */ jsx("meshStandardMaterial", { color: 2263842 })
|
|
43009
|
+
] })
|
|
43010
|
+
]
|
|
43011
|
+
}
|
|
43012
|
+
);
|
|
43013
|
+
}
|
|
43014
|
+
if (feature.type === "rock") {
|
|
43015
|
+
return /* @__PURE__ */ jsxs(
|
|
43016
|
+
"mesh",
|
|
43017
|
+
{
|
|
43018
|
+
position: [position[0], position[1] + 0.3, position[2]],
|
|
43019
|
+
onClick: (e) => handleFeatureClick(feature, e),
|
|
43020
|
+
userData: { type: "feature", featureId: feature.id },
|
|
43021
|
+
children: [
|
|
43022
|
+
/* @__PURE__ */ jsx("dodecahedronGeometry", { args: [0.3, 0] }),
|
|
43023
|
+
/* @__PURE__ */ jsx("meshStandardMaterial", { color: 8421504 })
|
|
43024
|
+
]
|
|
43025
|
+
}
|
|
43026
|
+
);
|
|
43027
|
+
}
|
|
43028
|
+
return null;
|
|
43029
|
+
},
|
|
43030
|
+
[handleFeatureClick]
|
|
43031
|
+
);
|
|
43032
|
+
if (externalLoading || assetsLoading && preloadAssets.length > 0) {
|
|
43033
|
+
return /* @__PURE__ */ jsx(
|
|
43034
|
+
Canvas3DLoadingState,
|
|
43035
|
+
{
|
|
43036
|
+
progress,
|
|
43037
|
+
loaded,
|
|
43038
|
+
total,
|
|
43039
|
+
message: loadingMessage,
|
|
43040
|
+
className
|
|
43041
|
+
}
|
|
43042
|
+
);
|
|
43043
|
+
}
|
|
43044
|
+
const displayError = externalError || internalError;
|
|
43045
|
+
if (displayError) {
|
|
43046
|
+
return /* @__PURE__ */ jsx(Canvas3DErrorBoundary, { children: /* @__PURE__ */ jsx("div", { className: "game-canvas-3d game-canvas-3d--error", children: /* @__PURE__ */ jsxs("div", { className: "game-canvas-3d__error", children: [
|
|
43047
|
+
"Error: ",
|
|
43048
|
+
displayError
|
|
43049
|
+
] }) }) });
|
|
43050
|
+
}
|
|
43051
|
+
return /* @__PURE__ */ jsx(
|
|
43052
|
+
Canvas3DErrorBoundary,
|
|
43053
|
+
{
|
|
43054
|
+
onError: (err) => setInternalError(err.message),
|
|
43055
|
+
onReset: () => setInternalError(null),
|
|
43056
|
+
children: /* @__PURE__ */ jsxs(
|
|
43057
|
+
"div",
|
|
43058
|
+
{
|
|
43059
|
+
ref: containerRef,
|
|
43060
|
+
className: cn("game-canvas-3d relative w-full h-full min-h-[85vh] overflow-hidden", className),
|
|
43061
|
+
"data-orientation": orientation,
|
|
43062
|
+
"data-camera-mode": cameraMode,
|
|
43063
|
+
"data-overlay": overlay,
|
|
43064
|
+
children: [
|
|
43065
|
+
/* @__PURE__ */ jsxs(
|
|
43066
|
+
Canvas,
|
|
43067
|
+
{
|
|
43068
|
+
shadows,
|
|
43069
|
+
camera: {
|
|
43070
|
+
position: cameraConfig.position,
|
|
43071
|
+
fov: cameraConfig.fov,
|
|
43072
|
+
near: 0.1,
|
|
43073
|
+
far: 1e3
|
|
43074
|
+
},
|
|
43075
|
+
style: { background: backgroundColor },
|
|
43076
|
+
onClick: (e) => {
|
|
43077
|
+
if (e.target === e.currentTarget) {
|
|
43078
|
+
eventHandlers.handleCanvasClick(e);
|
|
43079
|
+
}
|
|
43080
|
+
},
|
|
43081
|
+
children: [
|
|
43082
|
+
/* @__PURE__ */ jsx(CameraController, { onCameraChange: eventHandlers.handleCameraChange }),
|
|
43083
|
+
/* @__PURE__ */ jsx("ambientLight", { intensity: 0.6 }),
|
|
43084
|
+
/* @__PURE__ */ jsx(
|
|
43085
|
+
"directionalLight",
|
|
43086
|
+
{
|
|
43087
|
+
position: [10, 20, 10],
|
|
43088
|
+
intensity: 0.8,
|
|
43089
|
+
castShadow: shadows,
|
|
43090
|
+
"shadow-mapSize": [2048, 2048]
|
|
43091
|
+
}
|
|
43092
|
+
),
|
|
43093
|
+
/* @__PURE__ */ jsx("hemisphereLight", { intensity: 0.3, color: "#87ceeb", groundColor: "#362d1d" }),
|
|
43094
|
+
showGrid && /* @__PURE__ */ jsx(
|
|
43095
|
+
Grid$1,
|
|
43096
|
+
{
|
|
43097
|
+
args: [
|
|
43098
|
+
Math.max(gridBounds.maxX - gridBounds.minX + 2, 10),
|
|
43099
|
+
Math.max(gridBounds.maxZ - gridBounds.minZ + 2, 10)
|
|
43100
|
+
],
|
|
43101
|
+
position: [
|
|
43102
|
+
(gridBounds.maxX - gridBounds.minX) / 2 - 0.5,
|
|
43103
|
+
0,
|
|
43104
|
+
(gridBounds.maxZ - gridBounds.minZ) / 2 - 0.5
|
|
43105
|
+
],
|
|
43106
|
+
cellSize: 1,
|
|
43107
|
+
cellThickness: 1,
|
|
43108
|
+
cellColor: "#444444",
|
|
43109
|
+
sectionSize: 5,
|
|
43110
|
+
sectionThickness: 1.5,
|
|
43111
|
+
sectionColor: "#666666",
|
|
43112
|
+
fadeDistance: 50,
|
|
43113
|
+
fadeStrength: 1
|
|
43114
|
+
}
|
|
43115
|
+
),
|
|
43116
|
+
tiles.map((tile, index) => {
|
|
43117
|
+
const position = gridToWorld(
|
|
43118
|
+
tile.x,
|
|
43119
|
+
tile.z ?? tile.y ?? 0,
|
|
43120
|
+
tile.elevation ?? 0
|
|
43121
|
+
);
|
|
43122
|
+
const Renderer = CustomTileRenderer || DefaultTileRenderer;
|
|
43123
|
+
return /* @__PURE__ */ jsx(Renderer, { tile, position }, tile.id ?? `tile-${index}`);
|
|
43124
|
+
}),
|
|
43125
|
+
features.map((feature, index) => {
|
|
43126
|
+
const position = gridToWorld(
|
|
43127
|
+
feature.x,
|
|
43128
|
+
feature.z ?? feature.y ?? 0,
|
|
43129
|
+
(feature.elevation ?? 0) + 0.5
|
|
43130
|
+
);
|
|
43131
|
+
const Renderer = CustomFeatureRenderer || DefaultFeatureRenderer;
|
|
43132
|
+
return /* @__PURE__ */ jsx(Renderer, { feature, position }, feature.id ?? `feature-${index}`);
|
|
43133
|
+
}),
|
|
43134
|
+
units.map((unit) => {
|
|
43135
|
+
const position = gridToWorld(
|
|
43136
|
+
unit.x ?? 0,
|
|
43137
|
+
unit.z ?? unit.y ?? 0,
|
|
43138
|
+
(unit.elevation ?? 0) + 0.5
|
|
43139
|
+
);
|
|
43140
|
+
const Renderer = CustomUnitRenderer || DefaultUnitRenderer;
|
|
43141
|
+
return /* @__PURE__ */ jsx(Renderer, { unit, position }, unit.id);
|
|
43142
|
+
}),
|
|
43143
|
+
children,
|
|
43144
|
+
/* @__PURE__ */ jsx(
|
|
43145
|
+
OrbitControls,
|
|
43146
|
+
{
|
|
43147
|
+
ref: controlsRef,
|
|
43148
|
+
target: cameraTarget,
|
|
43149
|
+
enableDamping: true,
|
|
43150
|
+
dampingFactor: 0.05,
|
|
43151
|
+
minDistance: 2,
|
|
43152
|
+
maxDistance: 100,
|
|
43153
|
+
maxPolarAngle: Math.PI / 2 - 0.1
|
|
43154
|
+
}
|
|
43155
|
+
)
|
|
43156
|
+
]
|
|
43157
|
+
}
|
|
43158
|
+
),
|
|
43159
|
+
showCoordinates && hoveredTile && /* @__PURE__ */ jsxs("div", { className: "game-canvas-3d__coordinates", children: [
|
|
43160
|
+
"X: ",
|
|
43161
|
+
hoveredTile.x,
|
|
43162
|
+
", Z: ",
|
|
43163
|
+
hoveredTile.z ?? hoveredTile.y ?? 0
|
|
43164
|
+
] }),
|
|
43165
|
+
showTileInfo && hoveredTile && /* @__PURE__ */ jsxs("div", { className: "game-canvas-3d__tile-info", children: [
|
|
43166
|
+
/* @__PURE__ */ jsx("div", { className: "tile-info__type", children: hoveredTile.type }),
|
|
43167
|
+
hoveredTile.terrain && /* @__PURE__ */ jsx("div", { className: "tile-info__terrain", children: hoveredTile.terrain })
|
|
43168
|
+
] })
|
|
43169
|
+
]
|
|
43170
|
+
}
|
|
43171
|
+
)
|
|
43172
|
+
}
|
|
43173
|
+
);
|
|
43174
|
+
}
|
|
43175
|
+
);
|
|
43176
|
+
GameCanvas3D.displayName = "GameCanvas3D";
|
|
43177
|
+
}
|
|
43178
|
+
});
|
|
43179
|
+
function GameBoard3D({
|
|
43180
|
+
entity,
|
|
43181
|
+
tiles = [],
|
|
43182
|
+
features = [],
|
|
43183
|
+
cameraMode = "perspective",
|
|
43184
|
+
backgroundColor = "#2a1a1a",
|
|
43185
|
+
tileClickEvent,
|
|
43186
|
+
unitClickEvent,
|
|
43187
|
+
attackEvent,
|
|
43188
|
+
endTurnEvent,
|
|
43189
|
+
cancelEvent,
|
|
43190
|
+
playAgainEvent,
|
|
43191
|
+
gameEndEvent,
|
|
43192
|
+
className
|
|
43193
|
+
}) {
|
|
43194
|
+
const row = boardEntity(entity);
|
|
43195
|
+
const eventBus = useEventBus();
|
|
43196
|
+
const entityUnits = row ? rows(row.units) : [];
|
|
43197
|
+
const units = entityUnits;
|
|
43198
|
+
const selectedUnitId = row ? str(row.selectedUnitId) || null : null;
|
|
43199
|
+
const phase = row ? str(row.phase) : "observation";
|
|
43200
|
+
const result = row ? str(row.result) : "none";
|
|
43201
|
+
const validMoves = row && Array.isArray(row.validMoves) ? row.validMoves : [];
|
|
43202
|
+
const attackTargets = row && Array.isArray(row.attackTargets) ? row.attackTargets : [];
|
|
43203
|
+
const turn = row ? num(row.turn) : 0;
|
|
43204
|
+
const currentTeam = row ? str(row.currentTeam) : "player";
|
|
43205
|
+
const isGameOver = result !== "none";
|
|
43206
|
+
const gameEndEmittedRef = useRef(false);
|
|
43207
|
+
useEffect(() => {
|
|
43208
|
+
if ((result === "victory" || result === "defeat") && gameEndEvent) {
|
|
43209
|
+
if (!gameEndEmittedRef.current) {
|
|
43210
|
+
gameEndEmittedRef.current = true;
|
|
43211
|
+
eventBus.emit(`UI:${gameEndEvent}`, { result });
|
|
43212
|
+
}
|
|
43213
|
+
} else {
|
|
43214
|
+
gameEndEmittedRef.current = false;
|
|
43215
|
+
}
|
|
43216
|
+
}, [result, gameEndEvent, eventBus]);
|
|
43217
|
+
const checkGameEnd = useCallback(() => {
|
|
43218
|
+
const alivePlayer = entityUnits.filter((u) => unitTeam(u) === "player" && unitHealth(u) > 0);
|
|
43219
|
+
const aliveEnemy = entityUnits.filter((u) => unitTeam(u) === "enemy" && unitHealth(u) > 0);
|
|
43220
|
+
if (alivePlayer.length === 0 && gameEndEvent) {
|
|
43221
|
+
eventBus.emit(`UI:${gameEndEvent}`, { result: "defeat" });
|
|
43222
|
+
} else if (aliveEnemy.length === 0 && gameEndEvent) {
|
|
43223
|
+
eventBus.emit(`UI:${gameEndEvent}`, { result: "victory" });
|
|
43224
|
+
}
|
|
43225
|
+
}, [entityUnits, gameEndEvent, eventBus]);
|
|
43226
|
+
const handleUnitClickCallback = useCallback((isoUnit) => {
|
|
43227
|
+
if (phase !== "action" || !selectedUnitId || !attackEvent) return;
|
|
43228
|
+
const attackerRow = entityUnits.find((u) => str(u.id) === selectedUnitId);
|
|
43229
|
+
const targetRow = entityUnits.find((u) => str(u.id) === isoUnit.id);
|
|
43230
|
+
if (!attackerRow || !targetRow) return;
|
|
43231
|
+
if (unitTeam(targetRow) !== "enemy" || unitHealth(targetRow) <= 0) return;
|
|
43232
|
+
const ap = unitPosition(attackerRow);
|
|
43233
|
+
const tp = unitPosition(targetRow);
|
|
43234
|
+
const dx = Math.abs(ap.x - tp.x);
|
|
43235
|
+
const dy = Math.abs(ap.y - tp.y);
|
|
43236
|
+
if (dx <= 1 && dy <= 1 && dx + dy > 0) {
|
|
43237
|
+
const damage = Math.max(1, num(attackerRow.attack) - num(targetRow.defense));
|
|
43238
|
+
eventBus.emit(`UI:${attackEvent}`, {
|
|
43239
|
+
attackerId: str(attackerRow.id),
|
|
43240
|
+
targetId: str(targetRow.id),
|
|
43241
|
+
damage
|
|
43242
|
+
});
|
|
43243
|
+
setTimeout(checkGameEnd, 100);
|
|
43244
|
+
}
|
|
43245
|
+
}, [phase, selectedUnitId, entityUnits, attackEvent, eventBus, checkGameEnd]);
|
|
43246
|
+
const handleEndTurn = useCallback(() => {
|
|
43247
|
+
if (endTurnEvent) eventBus.emit(`UI:${endTurnEvent}`, {});
|
|
43248
|
+
}, [endTurnEvent, eventBus]);
|
|
43249
|
+
const handleCancel = useCallback(() => {
|
|
43250
|
+
if (cancelEvent) eventBus.emit(`UI:${cancelEvent}`, {});
|
|
43251
|
+
}, [cancelEvent, eventBus]);
|
|
43252
|
+
const handlePlayAgain = useCallback(() => {
|
|
43253
|
+
if (playAgainEvent) eventBus.emit(`UI:${playAgainEvent}`, {});
|
|
43254
|
+
}, [playAgainEvent, eventBus]);
|
|
43255
|
+
return /* @__PURE__ */ jsxs(VStack, { className: cn("game-board-3d block w-full min-h-[85vh] relative", className), children: [
|
|
43256
|
+
/* @__PURE__ */ jsxs("div", { className: "game-board-3d__status absolute top-3 left-3 z-10 flex gap-2 items-center", children: [
|
|
43257
|
+
/* @__PURE__ */ jsx(Typography, { variant: "small", className: "status__phase capitalize", children: phase.replace("_", " ") }),
|
|
43258
|
+
currentTeam && !isGameOver && /* @__PURE__ */ jsxs(Typography, { variant: "small", color: "muted", className: "status__team", children: [
|
|
43259
|
+
"\u2014 ",
|
|
43260
|
+
currentTeam === "player" ? "Your Turn" : "Enemy's Turn"
|
|
43261
|
+
] }),
|
|
43262
|
+
/* @__PURE__ */ jsxs(Typography, { variant: "small", color: "muted", className: "status__turn", children: [
|
|
43263
|
+
"Turn ",
|
|
43264
|
+
turn
|
|
43265
|
+
] })
|
|
43266
|
+
] }),
|
|
43267
|
+
/* @__PURE__ */ jsx(
|
|
43268
|
+
GameCanvas3D,
|
|
43269
|
+
{
|
|
43270
|
+
tiles,
|
|
43271
|
+
units,
|
|
43272
|
+
features,
|
|
43273
|
+
cameraMode,
|
|
43274
|
+
showGrid: true,
|
|
43275
|
+
showCoordinates: false,
|
|
43276
|
+
showTileInfo: false,
|
|
43277
|
+
shadows: true,
|
|
43278
|
+
backgroundColor,
|
|
43279
|
+
tileClickEvent,
|
|
43280
|
+
unitClickEvent,
|
|
43281
|
+
onUnitClick: handleUnitClickCallback,
|
|
43282
|
+
selectedUnitId,
|
|
43283
|
+
validMoves,
|
|
43284
|
+
attackTargets,
|
|
43285
|
+
className: "game-board-3d__canvas w-full min-h-[85vh]"
|
|
43286
|
+
}
|
|
43287
|
+
),
|
|
43288
|
+
!isGameOver && /* @__PURE__ */ jsxs(HStack, { className: "fixed bottom-6 right-6 z-50", gap: "sm", children: [
|
|
43289
|
+
(phase === "selection" || phase === "movement" || phase === "action") && /* @__PURE__ */ jsx(
|
|
43290
|
+
Button,
|
|
43291
|
+
{
|
|
43292
|
+
variant: "secondary",
|
|
43293
|
+
className: "shadow-xl",
|
|
43294
|
+
onClick: handleCancel,
|
|
43295
|
+
children: "Cancel"
|
|
43296
|
+
}
|
|
43297
|
+
),
|
|
43298
|
+
phase !== "enemy_turn" && /* @__PURE__ */ jsx(
|
|
43299
|
+
Button,
|
|
43300
|
+
{
|
|
43301
|
+
variant: "primary",
|
|
43302
|
+
className: "shadow-xl",
|
|
43303
|
+
onClick: handleEndTurn,
|
|
43304
|
+
children: "End Turn"
|
|
43305
|
+
}
|
|
43306
|
+
)
|
|
43307
|
+
] }),
|
|
43308
|
+
isGameOver && /* @__PURE__ */ jsx("div", { className: "game-board-3d__overlay absolute inset-0 z-20 flex items-center justify-center bg-black/60", children: /* @__PURE__ */ jsxs(VStack, { align: "center", gap: "md", className: "overlay__card p-8 rounded-xl bg-gray-900/90 shadow-2xl", children: [
|
|
43309
|
+
/* @__PURE__ */ jsx(
|
|
43310
|
+
Typography,
|
|
43311
|
+
{
|
|
43312
|
+
variant: "h2",
|
|
43313
|
+
className: cn(
|
|
43314
|
+
"overlay__result",
|
|
43315
|
+
result === "victory" ? "text-yellow-400" : "text-red-500"
|
|
43316
|
+
),
|
|
43317
|
+
children: result === "victory" ? "Victory!" : "Defeat"
|
|
43318
|
+
}
|
|
43319
|
+
),
|
|
43320
|
+
/* @__PURE__ */ jsxs(Typography, { variant: "body", color: "muted", className: "overlay__turn-count", children: [
|
|
43321
|
+
"Completed in ",
|
|
43322
|
+
turn,
|
|
43323
|
+
" turn",
|
|
43324
|
+
turn !== 1 ? "s" : ""
|
|
43325
|
+
] }),
|
|
43326
|
+
/* @__PURE__ */ jsx(
|
|
43327
|
+
Button,
|
|
43328
|
+
{
|
|
43329
|
+
variant: "primary",
|
|
43330
|
+
className: "px-8 py-3 font-semibold",
|
|
43331
|
+
onClick: handlePlayAgain,
|
|
43332
|
+
children: "Play Again"
|
|
43333
|
+
}
|
|
43334
|
+
)
|
|
43335
|
+
] }) })
|
|
43336
|
+
] });
|
|
43337
|
+
}
|
|
43338
|
+
var init_GameBoard3D = __esm({
|
|
43339
|
+
"components/game/organisms/GameBoard3D.tsx"() {
|
|
43340
|
+
"use client";
|
|
43341
|
+
init_cn();
|
|
43342
|
+
init_Button();
|
|
43343
|
+
init_Typography();
|
|
43344
|
+
init_Stack();
|
|
43345
|
+
init_useEventBus();
|
|
43346
|
+
init_GameCanvas3D2();
|
|
43347
|
+
init_boardEntity();
|
|
43348
|
+
GameBoard3D.displayName = "GameBoard3D";
|
|
43349
|
+
}
|
|
43350
|
+
});
|
|
41696
43351
|
var GameShell;
|
|
41697
43352
|
var init_GameShell = __esm({
|
|
41698
43353
|
"components/game/templates/GameShell.tsx"() {
|
|
@@ -43343,6 +44998,236 @@ var init_NegotiatorBoard = __esm({
|
|
|
43343
44998
|
NegotiatorBoard.displayName = "NegotiatorBoard";
|
|
43344
44999
|
}
|
|
43345
45000
|
});
|
|
45001
|
+
function resolveEntity(entity) {
|
|
45002
|
+
if (!entity) return {};
|
|
45003
|
+
if (Array.isArray(entity)) return entity[0] ?? {};
|
|
45004
|
+
return entity;
|
|
45005
|
+
}
|
|
45006
|
+
function numField(row, key, fallback) {
|
|
45007
|
+
const v = row[key];
|
|
45008
|
+
return typeof v === "number" ? v : fallback;
|
|
45009
|
+
}
|
|
45010
|
+
function strField(row, key, fallback) {
|
|
45011
|
+
const v = row[key];
|
|
45012
|
+
return typeof v === "string" ? v : fallback;
|
|
45013
|
+
}
|
|
45014
|
+
function PlatformerBoard({
|
|
45015
|
+
entity,
|
|
45016
|
+
player: propPlayer,
|
|
45017
|
+
platforms: propPlatforms,
|
|
45018
|
+
result: propResult,
|
|
45019
|
+
lives: propLives,
|
|
45020
|
+
score: propScore,
|
|
45021
|
+
level: propLevel,
|
|
45022
|
+
worldWidth = 800,
|
|
45023
|
+
worldHeight = 400,
|
|
45024
|
+
canvasWidth = 800,
|
|
45025
|
+
canvasHeight = 400,
|
|
45026
|
+
playerSprite,
|
|
45027
|
+
tileSprites,
|
|
45028
|
+
bgColor,
|
|
45029
|
+
leftEvent = "LEFT",
|
|
45030
|
+
rightEvent = "RIGHT",
|
|
45031
|
+
jumpEvent = "JUMP",
|
|
45032
|
+
stopEvent = "STOP",
|
|
45033
|
+
playAgainEvent = "PLAY_AGAIN",
|
|
45034
|
+
gameEndEvent = "GAME_END",
|
|
45035
|
+
className
|
|
45036
|
+
}) {
|
|
45037
|
+
const row = resolveEntity(entity);
|
|
45038
|
+
const eventBus = useEventBus();
|
|
45039
|
+
const { t } = useTranslate();
|
|
45040
|
+
const result = propResult ?? strField(row, "result", "none");
|
|
45041
|
+
propLives ?? numField(row, "lives", 3);
|
|
45042
|
+
const score = propScore ?? numField(row, "score", 0);
|
|
45043
|
+
const level = propLevel ?? numField(row, "level", 1);
|
|
45044
|
+
const entityPlayer = row["player"];
|
|
45045
|
+
const player = propPlayer ?? entityPlayer ?? {
|
|
45046
|
+
x: 80,
|
|
45047
|
+
y: 320,
|
|
45048
|
+
width: 32,
|
|
45049
|
+
height: 48,
|
|
45050
|
+
vx: 0,
|
|
45051
|
+
vy: 0,
|
|
45052
|
+
grounded: false,
|
|
45053
|
+
facingRight: true
|
|
45054
|
+
};
|
|
45055
|
+
const entityPlatforms = Array.isArray(row["platforms"]) ? row["platforms"] : void 0;
|
|
45056
|
+
const platforms = propPlatforms ?? entityPlatforms ?? [
|
|
45057
|
+
{ x: 0, y: 368, width: 800, height: 32, type: "ground" },
|
|
45058
|
+
{ x: 150, y: 280, width: 160, height: 16, type: "platform" },
|
|
45059
|
+
{ x: 420, y: 220, width: 160, height: 16, type: "platform" },
|
|
45060
|
+
{ x: 580, y: 300, width: 80, height: 16, type: "hazard" },
|
|
45061
|
+
{ x: 700, y: 340, width: 64, height: 28, type: "goal" }
|
|
45062
|
+
];
|
|
45063
|
+
const handleRestart = useCallback(() => {
|
|
45064
|
+
if (playAgainEvent) {
|
|
45065
|
+
eventBus.emit(`UI:${playAgainEvent}`, {});
|
|
45066
|
+
}
|
|
45067
|
+
}, [playAgainEvent, eventBus]);
|
|
45068
|
+
const isGameOver = result === "won" || result === "lost";
|
|
45069
|
+
const gameEndEmittedRef = useRef(false);
|
|
45070
|
+
useEffect(() => {
|
|
45071
|
+
if ((result === "won" || result === "lost") && gameEndEvent) {
|
|
45072
|
+
if (!gameEndEmittedRef.current) {
|
|
45073
|
+
gameEndEmittedRef.current = true;
|
|
45074
|
+
eventBus.emit(`UI:${gameEndEvent}`, { result });
|
|
45075
|
+
}
|
|
45076
|
+
} else {
|
|
45077
|
+
gameEndEmittedRef.current = false;
|
|
45078
|
+
}
|
|
45079
|
+
}, [result, gameEndEvent, eventBus]);
|
|
45080
|
+
return /* @__PURE__ */ jsx(
|
|
45081
|
+
VStack,
|
|
45082
|
+
{
|
|
45083
|
+
className: cn("platformer-board relative bg-background", className),
|
|
45084
|
+
gap: "none",
|
|
45085
|
+
children: /* @__PURE__ */ jsxs(Box, { className: "relative", children: [
|
|
45086
|
+
/* @__PURE__ */ jsx(
|
|
45087
|
+
PlatformerCanvas,
|
|
45088
|
+
{
|
|
45089
|
+
player,
|
|
45090
|
+
platforms,
|
|
45091
|
+
worldWidth,
|
|
45092
|
+
worldHeight,
|
|
45093
|
+
canvasWidth,
|
|
45094
|
+
canvasHeight,
|
|
45095
|
+
followCamera: true,
|
|
45096
|
+
bgColor,
|
|
45097
|
+
playerSprite,
|
|
45098
|
+
tileSprites,
|
|
45099
|
+
leftEvent,
|
|
45100
|
+
rightEvent,
|
|
45101
|
+
jumpEvent,
|
|
45102
|
+
stopEvent
|
|
45103
|
+
}
|
|
45104
|
+
),
|
|
45105
|
+
isGameOver && /* @__PURE__ */ jsx(Box, { className: "absolute inset-0 z-50 flex items-center justify-center bg-background/70 backdrop-blur-sm rounded-container", children: /* @__PURE__ */ jsxs(VStack, { className: "text-center p-8", gap: "lg", children: [
|
|
45106
|
+
/* @__PURE__ */ jsx(
|
|
45107
|
+
Typography,
|
|
45108
|
+
{
|
|
45109
|
+
variant: "h2",
|
|
45110
|
+
className: cn(
|
|
45111
|
+
"text-4xl font-black tracking-widest uppercase",
|
|
45112
|
+
result === "won" ? "text-warning" : "text-error"
|
|
45113
|
+
),
|
|
45114
|
+
children: result === "won" ? t("platformer.won") : t("platformer.lost")
|
|
45115
|
+
}
|
|
45116
|
+
),
|
|
45117
|
+
result === "won" && /* @__PURE__ */ jsxs(Typography, { variant: "body1", className: "text-muted-foreground", children: [
|
|
45118
|
+
t("platformer.level"),
|
|
45119
|
+
" ",
|
|
45120
|
+
level,
|
|
45121
|
+
" \u2014 ",
|
|
45122
|
+
t("platformer.score"),
|
|
45123
|
+
": ",
|
|
45124
|
+
score
|
|
45125
|
+
] }),
|
|
45126
|
+
result === "lost" && /* @__PURE__ */ jsx(Typography, { variant: "body1", className: "text-muted-foreground", children: t("platformer.noLives") }),
|
|
45127
|
+
/* @__PURE__ */ jsx(
|
|
45128
|
+
Button,
|
|
45129
|
+
{
|
|
45130
|
+
variant: "primary",
|
|
45131
|
+
className: "px-8 py-3 font-semibold",
|
|
45132
|
+
onClick: handleRestart,
|
|
45133
|
+
children: result === "won" ? t("platformer.nextLevel") : t("platformer.playAgain")
|
|
45134
|
+
}
|
|
45135
|
+
)
|
|
45136
|
+
] }) })
|
|
45137
|
+
] })
|
|
45138
|
+
}
|
|
45139
|
+
);
|
|
45140
|
+
}
|
|
45141
|
+
var init_PlatformerBoard = __esm({
|
|
45142
|
+
"components/game/organisms/PlatformerBoard.tsx"() {
|
|
45143
|
+
"use client";
|
|
45144
|
+
init_cn();
|
|
45145
|
+
init_useEventBus();
|
|
45146
|
+
init_Box();
|
|
45147
|
+
init_Button();
|
|
45148
|
+
init_Typography();
|
|
45149
|
+
init_Stack();
|
|
45150
|
+
init_PlatformerCanvas();
|
|
45151
|
+
PlatformerBoard.displayName = "PlatformerBoard";
|
|
45152
|
+
}
|
|
45153
|
+
});
|
|
45154
|
+
function PlatformerTemplate({
|
|
45155
|
+
entity,
|
|
45156
|
+
platforms = DEFAULT_PLATFORMS,
|
|
45157
|
+
worldWidth = 800,
|
|
45158
|
+
worldHeight = 400,
|
|
45159
|
+
canvasWidth = 800,
|
|
45160
|
+
canvasHeight = 400,
|
|
45161
|
+
playerSprite = `${CDN3}/characters/platformChar_idle.png`,
|
|
45162
|
+
tileSprites = DEFAULT_TILE_SPRITES,
|
|
45163
|
+
bgColor = "#5c94fc",
|
|
45164
|
+
gameEndEvent = "GAME_END",
|
|
45165
|
+
className
|
|
45166
|
+
}) {
|
|
45167
|
+
const row = entity && !Array.isArray(entity) ? entity : void 0;
|
|
45168
|
+
const lives = typeof row?.["lives"] === "number" ? row["lives"] : 3;
|
|
45169
|
+
const score = typeof row?.["score"] === "number" ? row["score"] : 0;
|
|
45170
|
+
const level = typeof row?.["level"] === "number" ? row["level"] : 1;
|
|
45171
|
+
return /* @__PURE__ */ jsxs(VStack, { className: cn("platformer-template w-full", className), gap: "none", children: [
|
|
45172
|
+
/* @__PURE__ */ jsx(Box, { className: "relative", children: /* @__PURE__ */ jsx(
|
|
45173
|
+
GameHud,
|
|
45174
|
+
{
|
|
45175
|
+
position: "top",
|
|
45176
|
+
stats: [
|
|
45177
|
+
{ label: "Lives", value: lives, format: "number", variant: "danger" },
|
|
45178
|
+
{ label: "Level", value: level, format: "number", variant: "default" }
|
|
45179
|
+
]
|
|
45180
|
+
}
|
|
45181
|
+
) }),
|
|
45182
|
+
/* @__PURE__ */ jsx(
|
|
45183
|
+
PlatformerBoard,
|
|
45184
|
+
{
|
|
45185
|
+
entity,
|
|
45186
|
+
platforms,
|
|
45187
|
+
worldWidth,
|
|
45188
|
+
worldHeight,
|
|
45189
|
+
canvasWidth,
|
|
45190
|
+
canvasHeight,
|
|
45191
|
+
playerSprite,
|
|
45192
|
+
tileSprites,
|
|
45193
|
+
bgColor,
|
|
45194
|
+
leftEvent: "LEFT",
|
|
45195
|
+
rightEvent: "RIGHT",
|
|
45196
|
+
jumpEvent: "JUMP",
|
|
45197
|
+
stopEvent: "STOP",
|
|
45198
|
+
playAgainEvent: "PLAY_AGAIN",
|
|
45199
|
+
gameEndEvent
|
|
45200
|
+
}
|
|
45201
|
+
),
|
|
45202
|
+
/* @__PURE__ */ jsx(Box, { className: "px-4 py-2", children: /* @__PURE__ */ jsx(ScoreBoard, { score, level }) })
|
|
45203
|
+
] });
|
|
45204
|
+
}
|
|
45205
|
+
var CDN3, DEFAULT_TILE_SPRITES, DEFAULT_PLATFORMS;
|
|
45206
|
+
var init_PlatformerTemplate = __esm({
|
|
45207
|
+
"components/game/templates/PlatformerTemplate.tsx"() {
|
|
45208
|
+
init_cn();
|
|
45209
|
+
init_Box();
|
|
45210
|
+
init_Stack();
|
|
45211
|
+
init_PlatformerBoard();
|
|
45212
|
+
init_GameHud();
|
|
45213
|
+
init_ScoreBoard();
|
|
45214
|
+
CDN3 = "https://almadar-kflow-assets.web.app/shared/platformer";
|
|
45215
|
+
DEFAULT_TILE_SPRITES = {
|
|
45216
|
+
ground: `${CDN3}/tiles/platformPack_tile001.png`,
|
|
45217
|
+
platform: `${CDN3}/tiles/platformPack_tile004.png`,
|
|
45218
|
+
hazard: `${CDN3}/tiles/platformPack_tile017.png`,
|
|
45219
|
+
goal: `${CDN3}/tiles/platformPack_tile007.png`
|
|
45220
|
+
};
|
|
45221
|
+
DEFAULT_PLATFORMS = [
|
|
45222
|
+
{ x: 0, y: 368, width: 800, height: 32, type: "ground" },
|
|
45223
|
+
{ x: 150, y: 280, width: 160, height: 16, type: "platform" },
|
|
45224
|
+
{ x: 420, y: 220, width: 160, height: 16, type: "platform" },
|
|
45225
|
+
{ x: 580, y: 300, width: 80, height: 16, type: "hazard" },
|
|
45226
|
+
{ x: 700, y: 340, width: 64, height: 28, type: "goal" }
|
|
45227
|
+
];
|
|
45228
|
+
PlatformerTemplate.displayName = "PlatformerTemplate";
|
|
45229
|
+
}
|
|
45230
|
+
});
|
|
43346
45231
|
var PricingOrganism;
|
|
43347
45232
|
var init_PricingOrganism = __esm({
|
|
43348
45233
|
"components/marketing/organisms/PricingOrganism.tsx"() {
|
|
@@ -43466,7 +45351,7 @@ var init_PricingPageTemplate = __esm({
|
|
|
43466
45351
|
}
|
|
43467
45352
|
});
|
|
43468
45353
|
function ResourceCounter({
|
|
43469
|
-
assetUrl =
|
|
45354
|
+
assetUrl = DEFAULT_ASSET_URL12,
|
|
43470
45355
|
icon,
|
|
43471
45356
|
label = "Gold",
|
|
43472
45357
|
value = 250,
|
|
@@ -43509,7 +45394,7 @@ function ResourceCounter({
|
|
|
43509
45394
|
}
|
|
43510
45395
|
);
|
|
43511
45396
|
}
|
|
43512
|
-
var colorTokenClasses2,
|
|
45397
|
+
var colorTokenClasses2, DEFAULT_ASSET_URL12, sizeMap15;
|
|
43513
45398
|
var init_ResourceCounter = __esm({
|
|
43514
45399
|
"components/game/atoms/ResourceCounter.tsx"() {
|
|
43515
45400
|
init_cn();
|
|
@@ -43522,7 +45407,7 @@ var init_ResourceCounter = __esm({
|
|
|
43522
45407
|
error: "text-error",
|
|
43523
45408
|
muted: "text-muted-foreground"
|
|
43524
45409
|
};
|
|
43525
|
-
|
|
45410
|
+
DEFAULT_ASSET_URL12 = "https://almadar-kflow-assets.web.app/shared/world-map/gold_mine.png";
|
|
43526
45411
|
sizeMap15 = {
|
|
43527
45412
|
sm: { wrapper: "text-xs gap-1 px-1.5 py-0.5", icon: "text-sm", img: 16 },
|
|
43528
45413
|
md: { wrapper: "text-sm gap-1.5 px-2 py-1", icon: "text-base", img: 20 },
|
|
@@ -43531,6 +45416,356 @@ var init_ResourceCounter = __esm({
|
|
|
43531
45416
|
ResourceCounter.displayName = "ResourceCounter";
|
|
43532
45417
|
}
|
|
43533
45418
|
});
|
|
45419
|
+
function RoguelikeBoard({
|
|
45420
|
+
entity,
|
|
45421
|
+
tiles: propTiles,
|
|
45422
|
+
enemies: propEnemies,
|
|
45423
|
+
items: propItems,
|
|
45424
|
+
player: propPlayer,
|
|
45425
|
+
playerHp: propPlayerHp,
|
|
45426
|
+
playerMaxHp: propPlayerMaxHp,
|
|
45427
|
+
playerAttack: propPlayerAttack,
|
|
45428
|
+
depth: propDepth,
|
|
45429
|
+
result: propResult,
|
|
45430
|
+
phase: propPhase,
|
|
45431
|
+
stairsX: propStairsX,
|
|
45432
|
+
stairsY: propStairsY,
|
|
45433
|
+
assetManifest: propAssetManifest,
|
|
45434
|
+
scale = 0.45,
|
|
45435
|
+
unitScale = 1,
|
|
45436
|
+
moveEvent,
|
|
45437
|
+
playAgainEvent,
|
|
45438
|
+
gameEndEvent,
|
|
45439
|
+
className
|
|
45440
|
+
}) {
|
|
45441
|
+
const board = boardEntity(entity) ?? {};
|
|
45442
|
+
const tiles = propTiles ?? (Array.isArray(board.tiles) ? board.tiles : DEFAULT_TILES2);
|
|
45443
|
+
const enemies = propEnemies ?? (Array.isArray(board.enemies) ? board.enemies : DEFAULT_ENEMIES);
|
|
45444
|
+
const items = propItems ?? (Array.isArray(board.items) ? board.items : DEFAULT_ITEMS);
|
|
45445
|
+
const player = propPlayer ?? board.player ?? { x: 1, y: 1 };
|
|
45446
|
+
const playerHp = propPlayerHp ?? num(board.playerHp, 10);
|
|
45447
|
+
const playerMaxHp = propPlayerMaxHp ?? num(board.playerMaxHp, 10);
|
|
45448
|
+
const playerAttack = propPlayerAttack ?? num(board.playerAttack, 3);
|
|
45449
|
+
const depth = propDepth ?? num(board.depth, 1);
|
|
45450
|
+
const result = propResult ?? (str(board.result) || "none");
|
|
45451
|
+
const phase = propPhase ?? (str(board.phase) || "player_turn");
|
|
45452
|
+
propStairsX ?? num(board.stairsX, 3);
|
|
45453
|
+
propStairsY ?? num(board.stairsY, 3);
|
|
45454
|
+
const eventBus = useEventBus();
|
|
45455
|
+
const { t } = useTranslate();
|
|
45456
|
+
const [hoveredTile, setHoveredTile] = useState(null);
|
|
45457
|
+
const emitMove = useCallback((dx, dy) => {
|
|
45458
|
+
if (!moveEvent) return;
|
|
45459
|
+
eventBus.emit(`UI:${moveEvent}`, { dx, dy });
|
|
45460
|
+
}, [moveEvent, eventBus]);
|
|
45461
|
+
useEffect(() => {
|
|
45462
|
+
const handler = (e) => {
|
|
45463
|
+
if (result !== "none" || phase !== "player_turn") return;
|
|
45464
|
+
if (e.key === "ArrowUp" || e.key === "w") emitMove(0, -1);
|
|
45465
|
+
if (e.key === "ArrowDown" || e.key === "s") emitMove(0, 1);
|
|
45466
|
+
if (e.key === "ArrowLeft" || e.key === "a") emitMove(-1, 0);
|
|
45467
|
+
if (e.key === "ArrowRight" || e.key === "d") emitMove(1, 0);
|
|
45468
|
+
};
|
|
45469
|
+
window.addEventListener("keydown", handler);
|
|
45470
|
+
return () => window.removeEventListener("keydown", handler);
|
|
45471
|
+
}, [result, phase, emitMove]);
|
|
45472
|
+
useEffect(() => {
|
|
45473
|
+
if ((result === "won" || result === "lost") && gameEndEvent) {
|
|
45474
|
+
eventBus.emit(`UI:${gameEndEvent}`, { result });
|
|
45475
|
+
}
|
|
45476
|
+
}, [result, gameEndEvent, eventBus]);
|
|
45477
|
+
const handleTileClick = useCallback((x, y) => {
|
|
45478
|
+
if (result !== "none" || phase !== "player_turn") return;
|
|
45479
|
+
const dx = x - player.x;
|
|
45480
|
+
const dy = y - player.y;
|
|
45481
|
+
if (Math.abs(dx) + Math.abs(dy) === 1) {
|
|
45482
|
+
emitMove(dx, dy);
|
|
45483
|
+
}
|
|
45484
|
+
}, [result, phase, player, emitMove]);
|
|
45485
|
+
const handleReset = useCallback(() => {
|
|
45486
|
+
if (!playAgainEvent) return;
|
|
45487
|
+
eventBus.emit(`UI:${playAgainEvent}`, {});
|
|
45488
|
+
}, [playAgainEvent, eventBus]);
|
|
45489
|
+
const isoUnits = useMemo(() => {
|
|
45490
|
+
const liveEnemies = enemies.filter((e) => e.hp > 0);
|
|
45491
|
+
return [
|
|
45492
|
+
{
|
|
45493
|
+
id: "player",
|
|
45494
|
+
position: player,
|
|
45495
|
+
name: t("roguelike.player") || "Hero",
|
|
45496
|
+
team: "player",
|
|
45497
|
+
health: playerHp,
|
|
45498
|
+
maxHealth: playerMaxHp,
|
|
45499
|
+
unitType: "player",
|
|
45500
|
+
sprite: `${CDN4}/isometric-dungeon/Characters/Male/Male_0_Idle0.png`
|
|
45501
|
+
},
|
|
45502
|
+
...liveEnemies.map((e) => ({
|
|
45503
|
+
id: e.id,
|
|
45504
|
+
position: { x: e.x, y: e.y },
|
|
45505
|
+
name: t("roguelike.enemy") || "Enemy",
|
|
45506
|
+
team: "enemy",
|
|
45507
|
+
health: e.hp,
|
|
45508
|
+
maxHealth: 6,
|
|
45509
|
+
unitType: "enemy",
|
|
45510
|
+
sprite: `${CDN4}/sprite-sheets/shadow-legion-sprite-sheet-sw.png`
|
|
45511
|
+
}))
|
|
45512
|
+
];
|
|
45513
|
+
}, [player, enemies, playerHp, playerMaxHp, t]);
|
|
45514
|
+
const isoFeatures = useMemo(
|
|
45515
|
+
() => items.map((it) => ({
|
|
45516
|
+
id: it.id,
|
|
45517
|
+
x: it.x,
|
|
45518
|
+
y: it.y,
|
|
45519
|
+
type: it.kind,
|
|
45520
|
+
sprite: FEATURE_SPRITE[it.kind] ?? FEATURE_SPRITE.health_potion
|
|
45521
|
+
})),
|
|
45522
|
+
[items]
|
|
45523
|
+
);
|
|
45524
|
+
const validMoves = useMemo(() => {
|
|
45525
|
+
if (result !== "none" || phase !== "player_turn") return [];
|
|
45526
|
+
const dirs = [{ dx: 0, dy: -1 }, { dx: 0, dy: 1 }, { dx: -1, dy: 0 }, { dx: 1, dy: 0 }];
|
|
45527
|
+
return dirs.map(({ dx, dy }) => ({ x: player.x + dx, y: player.y + dy })).filter(({ x, y }) => {
|
|
45528
|
+
const tile = tiles.find((t2) => t2.x === x && t2.y === y);
|
|
45529
|
+
return tile?.passable ?? false;
|
|
45530
|
+
});
|
|
45531
|
+
}, [result, phase, player, tiles]);
|
|
45532
|
+
const isGameOver = result === "won" || result === "lost";
|
|
45533
|
+
return /* @__PURE__ */ jsxs(VStack, { className: cn("roguelike-board relative min-h-[600px] bg-background", className), gap: "none", children: [
|
|
45534
|
+
/* @__PURE__ */ jsxs(HStack, { className: "items-center justify-between px-4 py-2 border-b border-border", gap: "md", children: [
|
|
45535
|
+
/* @__PURE__ */ jsxs(HStack, { gap: "sm", className: "items-center", children: [
|
|
45536
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: t("roguelike.depth") || "Depth" }),
|
|
45537
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body1", className: "font-bold tabular-nums", children: depth })
|
|
45538
|
+
] }),
|
|
45539
|
+
/* @__PURE__ */ jsxs(HStack, { gap: "sm", className: "items-center", children: [
|
|
45540
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: t("roguelike.hp") || "HP" }),
|
|
45541
|
+
/* @__PURE__ */ jsxs(
|
|
45542
|
+
Typography,
|
|
45543
|
+
{
|
|
45544
|
+
variant: "body1",
|
|
45545
|
+
className: cn(
|
|
45546
|
+
"font-bold tabular-nums",
|
|
45547
|
+
playerHp <= Math.floor(playerMaxHp * 0.25) ? "text-error" : "text-success"
|
|
45548
|
+
),
|
|
45549
|
+
children: [
|
|
45550
|
+
playerHp,
|
|
45551
|
+
" / ",
|
|
45552
|
+
playerMaxHp
|
|
45553
|
+
]
|
|
45554
|
+
}
|
|
45555
|
+
)
|
|
45556
|
+
] }),
|
|
45557
|
+
/* @__PURE__ */ jsxs(HStack, { gap: "sm", className: "items-center", children: [
|
|
45558
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: t("roguelike.atk") || "ATK" }),
|
|
45559
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body1", className: "font-bold tabular-nums text-foreground", children: playerAttack })
|
|
45560
|
+
] }),
|
|
45561
|
+
/* @__PURE__ */ jsxs(HStack, { gap: "sm", className: "items-center", children: [
|
|
45562
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: t("roguelike.phase") || "Phase" }),
|
|
45563
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body2", className: "capitalize text-foreground", children: phase.replace("_", " ") })
|
|
45564
|
+
] })
|
|
45565
|
+
] }),
|
|
45566
|
+
/* @__PURE__ */ jsx(Box, { className: "relative flex-1", children: /* @__PURE__ */ jsx(
|
|
45567
|
+
IsometricCanvas_default,
|
|
45568
|
+
{
|
|
45569
|
+
tiles,
|
|
45570
|
+
units: isoUnits,
|
|
45571
|
+
features: isoFeatures,
|
|
45572
|
+
selectedUnitId: null,
|
|
45573
|
+
validMoves,
|
|
45574
|
+
attackTargets: [],
|
|
45575
|
+
hoveredTile,
|
|
45576
|
+
onTileClick: handleTileClick,
|
|
45577
|
+
onUnitClick: () => void 0,
|
|
45578
|
+
onTileHover: (x, y) => setHoveredTile({ x, y }),
|
|
45579
|
+
onTileLeave: () => setHoveredTile(null),
|
|
45580
|
+
scale,
|
|
45581
|
+
assetBaseUrl: propAssetManifest?.baseUrl ?? CDN4,
|
|
45582
|
+
assetManifest: propAssetManifest,
|
|
45583
|
+
unitScale
|
|
45584
|
+
}
|
|
45585
|
+
) }),
|
|
45586
|
+
!isGameOver && /* @__PURE__ */ jsx(HStack, { className: "justify-center gap-2 p-3", gap: "none", children: [
|
|
45587
|
+
{ label: "\u2191", dx: 0, dy: -1 },
|
|
45588
|
+
{ label: "\u2193", dx: 0, dy: 1 },
|
|
45589
|
+
{ label: "\u2190", dx: -1, dy: 0 },
|
|
45590
|
+
{ label: "\u2192", dx: 1, dy: 0 }
|
|
45591
|
+
].map(({ label, dx, dy }) => /* @__PURE__ */ jsx(
|
|
45592
|
+
Button,
|
|
45593
|
+
{
|
|
45594
|
+
variant: "secondary",
|
|
45595
|
+
className: "w-9 h-9 p-0 text-base font-mono",
|
|
45596
|
+
onClick: () => emitMove(dx, dy),
|
|
45597
|
+
disabled: phase !== "player_turn",
|
|
45598
|
+
children: label
|
|
45599
|
+
},
|
|
45600
|
+
label
|
|
45601
|
+
)) }),
|
|
45602
|
+
isGameOver && /* @__PURE__ */ jsx(Box, { className: "absolute inset-0 z-50 flex items-center justify-center bg-background/75 backdrop-blur-sm rounded-container", children: /* @__PURE__ */ jsxs(VStack, { className: "text-center p-8", gap: "lg", children: [
|
|
45603
|
+
/* @__PURE__ */ jsx(
|
|
45604
|
+
Typography,
|
|
45605
|
+
{
|
|
45606
|
+
variant: "h2",
|
|
45607
|
+
className: cn(
|
|
45608
|
+
"text-4xl font-black tracking-widest uppercase",
|
|
45609
|
+
result === "won" ? "text-warning" : "text-error"
|
|
45610
|
+
),
|
|
45611
|
+
children: result === "won" ? t("roguelike.victory") || "Victory!" : t("roguelike.defeat") || "Defeated!"
|
|
45612
|
+
}
|
|
45613
|
+
),
|
|
45614
|
+
result === "won" && /* @__PURE__ */ jsx(Typography, { variant: "body1", className: "text-muted-foreground", children: t("roguelike.cleared") || `Dungeon cleared! Depth reached: ${depth}` }),
|
|
45615
|
+
/* @__PURE__ */ jsx(
|
|
45616
|
+
Button,
|
|
45617
|
+
{
|
|
45618
|
+
variant: "primary",
|
|
45619
|
+
className: "px-8 py-3 font-semibold",
|
|
45620
|
+
onClick: handleReset,
|
|
45621
|
+
children: t("roguelike.playAgain") || "Play Again"
|
|
45622
|
+
}
|
|
45623
|
+
)
|
|
45624
|
+
] }) })
|
|
45625
|
+
] });
|
|
45626
|
+
}
|
|
45627
|
+
var CDN4, DEFAULT_TILES2, DEFAULT_ENEMIES, DEFAULT_ITEMS, FEATURE_SPRITE;
|
|
45628
|
+
var init_RoguelikeBoard = __esm({
|
|
45629
|
+
"components/game/organisms/RoguelikeBoard.tsx"() {
|
|
45630
|
+
"use client";
|
|
45631
|
+
init_cn();
|
|
45632
|
+
init_useEventBus();
|
|
45633
|
+
init_Box();
|
|
45634
|
+
init_Button();
|
|
45635
|
+
init_Typography();
|
|
45636
|
+
init_Stack();
|
|
45637
|
+
init_IsometricCanvas();
|
|
45638
|
+
init_boardEntity();
|
|
45639
|
+
CDN4 = "https://almadar-kflow-assets.web.app/shared";
|
|
45640
|
+
DEFAULT_TILES2 = [
|
|
45641
|
+
{ x: 0, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45642
|
+
{ x: 1, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45643
|
+
{ x: 2, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45644
|
+
{ x: 3, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45645
|
+
{ x: 4, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45646
|
+
{ x: 0, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45647
|
+
{ x: 1, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
|
|
45648
|
+
{ x: 2, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
|
|
45649
|
+
{ x: 3, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
|
|
45650
|
+
{ x: 4, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45651
|
+
{ x: 0, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45652
|
+
{ x: 1, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png` },
|
|
45653
|
+
{ x: 2, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png` },
|
|
45654
|
+
{ x: 3, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
|
|
45655
|
+
{ x: 4, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45656
|
+
{ x: 0, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45657
|
+
{ x: 1, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
|
|
45658
|
+
{ x: 2, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png` },
|
|
45659
|
+
{ x: 3, y: 3, terrain: "stairs", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stairs_E.png` },
|
|
45660
|
+
{ x: 4, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45661
|
+
{ x: 0, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45662
|
+
{ x: 1, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45663
|
+
{ x: 2, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45664
|
+
{ x: 3, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45665
|
+
{ x: 4, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` }
|
|
45666
|
+
];
|
|
45667
|
+
DEFAULT_ENEMIES = [
|
|
45668
|
+
{ id: "e1", x: 3, y: 1, hp: 5, attack: 2 },
|
|
45669
|
+
{ id: "e2", x: 1, y: 3, hp: 4, attack: 1 }
|
|
45670
|
+
];
|
|
45671
|
+
DEFAULT_ITEMS = [
|
|
45672
|
+
{ id: "i1", x: 2, y: 2, kind: "health_potion" }
|
|
45673
|
+
];
|
|
45674
|
+
FEATURE_SPRITE = {
|
|
45675
|
+
health_potion: `${CDN4}/isometric-dungeon/Isometric/chestClosed_E.png`,
|
|
45676
|
+
sword: `${CDN4}/isometric-dungeon/Isometric/barrel_E.png`,
|
|
45677
|
+
shield: `${CDN4}/isometric-dungeon/Isometric/barrel_E.png`
|
|
45678
|
+
};
|
|
45679
|
+
RoguelikeBoard.displayName = "RoguelikeBoard";
|
|
45680
|
+
}
|
|
45681
|
+
});
|
|
45682
|
+
function RoguelikeTemplate({
|
|
45683
|
+
entity,
|
|
45684
|
+
scale = 0.45,
|
|
45685
|
+
unitScale = 1,
|
|
45686
|
+
tiles = DEFAULT_ROGUELIKE_TILES,
|
|
45687
|
+
enemies,
|
|
45688
|
+
items,
|
|
45689
|
+
stairsX,
|
|
45690
|
+
stairsY,
|
|
45691
|
+
assetManifest = DEFAULT_ROGUELIKE_MANIFEST,
|
|
45692
|
+
gameEndEvent,
|
|
45693
|
+
className
|
|
45694
|
+
}) {
|
|
45695
|
+
const resolved = entity && typeof entity === "object" && !Array.isArray(entity) ? entity : void 0;
|
|
45696
|
+
if (!resolved && !tiles && !assetManifest) return null;
|
|
45697
|
+
return /* @__PURE__ */ jsx(
|
|
45698
|
+
RoguelikeBoard,
|
|
45699
|
+
{
|
|
45700
|
+
entity: resolved,
|
|
45701
|
+
tiles,
|
|
45702
|
+
enemies,
|
|
45703
|
+
items,
|
|
45704
|
+
stairsX,
|
|
45705
|
+
stairsY,
|
|
45706
|
+
assetManifest,
|
|
45707
|
+
scale,
|
|
45708
|
+
unitScale,
|
|
45709
|
+
moveEvent: "MOVE",
|
|
45710
|
+
playAgainEvent: "PLAY_AGAIN",
|
|
45711
|
+
gameEndEvent: gameEndEvent ?? "GAME_END",
|
|
45712
|
+
className
|
|
45713
|
+
}
|
|
45714
|
+
);
|
|
45715
|
+
}
|
|
45716
|
+
var CDN5, DEFAULT_ROGUELIKE_TILES, DEFAULT_ROGUELIKE_MANIFEST;
|
|
45717
|
+
var init_RoguelikeTemplate = __esm({
|
|
45718
|
+
"components/game/templates/RoguelikeTemplate.tsx"() {
|
|
45719
|
+
init_RoguelikeBoard();
|
|
45720
|
+
CDN5 = "https://almadar-kflow-assets.web.app/shared";
|
|
45721
|
+
DEFAULT_ROGUELIKE_TILES = [
|
|
45722
|
+
{ x: 0, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45723
|
+
{ x: 1, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45724
|
+
{ x: 2, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45725
|
+
{ x: 3, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45726
|
+
{ x: 4, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45727
|
+
{ x: 0, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45728
|
+
{ x: 1, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirt_E.png` },
|
|
45729
|
+
{ x: 2, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirt_E.png` },
|
|
45730
|
+
{ x: 3, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirt_E.png` },
|
|
45731
|
+
{ x: 4, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45732
|
+
{ x: 0, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45733
|
+
{ x: 1, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirtTiles_E.png` },
|
|
45734
|
+
{ x: 2, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirtTiles_E.png` },
|
|
45735
|
+
{ x: 3, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirt_E.png` },
|
|
45736
|
+
{ x: 4, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45737
|
+
{ x: 0, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45738
|
+
{ x: 1, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirt_E.png` },
|
|
45739
|
+
{ x: 2, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirtTiles_E.png` },
|
|
45740
|
+
{ x: 3, y: 3, terrain: "stairs", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stairs_E.png` },
|
|
45741
|
+
{ x: 4, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45742
|
+
{ x: 0, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45743
|
+
{ x: 1, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45744
|
+
{ x: 2, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45745
|
+
{ x: 3, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45746
|
+
{ x: 4, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` }
|
|
45747
|
+
];
|
|
45748
|
+
DEFAULT_ROGUELIKE_MANIFEST = {
|
|
45749
|
+
baseUrl: CDN5,
|
|
45750
|
+
terrains: {
|
|
45751
|
+
floor: "/isometric-dungeon/Isometric/dirt_E.png",
|
|
45752
|
+
wall: "/isometric-dungeon/Isometric/stoneInset_E.png",
|
|
45753
|
+
stairs: "/isometric-dungeon/Isometric/stairs_E.png",
|
|
45754
|
+
planks: "/isometric-dungeon/Isometric/planks_E.png"
|
|
45755
|
+
},
|
|
45756
|
+
units: {
|
|
45757
|
+
player: "/isometric-dungeon/Characters/Male/Male_0_Idle0.png",
|
|
45758
|
+
enemy: "/sprite-sheets/shadow-legion-sprite-sheet-sw.png"
|
|
45759
|
+
},
|
|
45760
|
+
features: {
|
|
45761
|
+
health_potion: "/isometric-dungeon/Isometric/chestClosed_E.png",
|
|
45762
|
+
sword: "/isometric-dungeon/Isometric/barrel_E.png",
|
|
45763
|
+
shield: "/isometric-dungeon/Isometric/barrel_E.png"
|
|
45764
|
+
}
|
|
45765
|
+
};
|
|
45766
|
+
RoguelikeTemplate.displayName = "RoguelikeTemplate";
|
|
45767
|
+
}
|
|
45768
|
+
});
|
|
43534
45769
|
|
|
43535
45770
|
// lib/traitRegistry.ts
|
|
43536
45771
|
function getAllTraits() {
|
|
@@ -44765,7 +47000,7 @@ function getAllEvents(traits2) {
|
|
|
44765
47000
|
function EventDispatcherTab({ traits: traits2, schema }) {
|
|
44766
47001
|
const eventBus = useEventBus();
|
|
44767
47002
|
const { t } = useTranslate();
|
|
44768
|
-
const [
|
|
47003
|
+
const [log11, setLog] = React77.useState([]);
|
|
44769
47004
|
const prevStatesRef = React77.useRef(/* @__PURE__ */ new Map());
|
|
44770
47005
|
React77.useEffect(() => {
|
|
44771
47006
|
for (const trait of traits2) {
|
|
@@ -44829,9 +47064,9 @@ function EventDispatcherTab({ traits: traits2, schema }) {
|
|
|
44829
47064
|
/* @__PURE__ */ jsx(Typography, { variant: "small", weight: "medium", className: "text-gray-500 mb-1", children: t("debug.otherEvents") }),
|
|
44830
47065
|
/* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1", children: unavailableEvents.map((event) => /* @__PURE__ */ jsx(Badge, { variant: "default", size: "sm", className: "opacity-50", children: event }, event)) })
|
|
44831
47066
|
] }),
|
|
44832
|
-
|
|
47067
|
+
log11.length > 0 && /* @__PURE__ */ jsxs("div", { children: [
|
|
44833
47068
|
/* @__PURE__ */ jsx(Typography, { variant: "small", weight: "medium", className: "text-gray-500 mb-1", children: t("debug.recentTransitions") }),
|
|
44834
|
-
/* @__PURE__ */ jsx(Stack, { gap: "xs", children:
|
|
47069
|
+
/* @__PURE__ */ jsx(Stack, { gap: "xs", children: log11.map((entry, i) => /* @__PURE__ */ jsxs(Typography, { variant: "small", className: "font-mono text-xs", children: [
|
|
44835
47070
|
/* @__PURE__ */ jsx("span", { className: "text-purple-400", children: entry.traitName }),
|
|
44836
47071
|
" ",
|
|
44837
47072
|
/* @__PURE__ */ jsx("span", { className: "text-gray-500", children: entry.from }),
|
|
@@ -46863,9 +49098,9 @@ function VariablePanel({
|
|
|
46863
49098
|
/* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-muted-foreground font-medium", children: t("stateArchitect.variables", { name: entityName }) }),
|
|
46864
49099
|
variables.map((v) => {
|
|
46865
49100
|
const name = v.name == null ? "" : String(v.name);
|
|
46866
|
-
const value =
|
|
46867
|
-
const max =
|
|
46868
|
-
const min =
|
|
49101
|
+
const value = numField2(v.value);
|
|
49102
|
+
const max = numField2(v.max, 100);
|
|
49103
|
+
const min = numField2(v.min, 0);
|
|
46869
49104
|
const unit = v.unit == null ? "" : String(v.unit);
|
|
46870
49105
|
const pct = Math.round((value - min) / (max - min) * 100);
|
|
46871
49106
|
const isHigh = pct > 80;
|
|
@@ -46895,12 +49130,12 @@ function VariablePanel({
|
|
|
46895
49130
|
})
|
|
46896
49131
|
] });
|
|
46897
49132
|
}
|
|
46898
|
-
var
|
|
49133
|
+
var numField2;
|
|
46899
49134
|
var init_VariablePanel = __esm({
|
|
46900
49135
|
"components/game/organisms/puzzles/state-architect/VariablePanel.tsx"() {
|
|
46901
49136
|
init_atoms2();
|
|
46902
49137
|
init_cn();
|
|
46903
|
-
|
|
49138
|
+
numField2 = (v, fallback = 0) => {
|
|
46904
49139
|
const n = Number(v);
|
|
46905
49140
|
return Number.isFinite(n) ? n : fallback;
|
|
46906
49141
|
};
|
|
@@ -47327,7 +49562,7 @@ function formatDuration(seconds) {
|
|
|
47327
49562
|
return `${Math.round(seconds)}s`;
|
|
47328
49563
|
}
|
|
47329
49564
|
function StatusEffect({
|
|
47330
|
-
assetUrl =
|
|
49565
|
+
assetUrl = DEFAULT_ASSET_URL13,
|
|
47331
49566
|
icon = "shield",
|
|
47332
49567
|
label = "Shield",
|
|
47333
49568
|
duration = 30,
|
|
@@ -47385,12 +49620,12 @@ function StatusEffect({
|
|
|
47385
49620
|
label && /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground mt-0.5 text-center whitespace-nowrap", children: label })
|
|
47386
49621
|
] });
|
|
47387
49622
|
}
|
|
47388
|
-
var
|
|
49623
|
+
var DEFAULT_ASSET_URL13, sizeMap16, variantStyles9;
|
|
47389
49624
|
var init_StatusEffect = __esm({
|
|
47390
49625
|
"components/game/atoms/StatusEffect.tsx"() {
|
|
47391
49626
|
init_cn();
|
|
47392
49627
|
init_Icon();
|
|
47393
|
-
|
|
49628
|
+
DEFAULT_ASSET_URL13 = "https://almadar-kflow-assets.web.app/shared/effects/particles/flame_01.png";
|
|
47394
49629
|
sizeMap16 = {
|
|
47395
49630
|
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 },
|
|
47396
49631
|
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 },
|
|
@@ -47887,6 +50122,289 @@ var init_ToastSlot = __esm({
|
|
|
47887
50122
|
ToastSlot.displayName = "ToastSlot";
|
|
47888
50123
|
}
|
|
47889
50124
|
});
|
|
50125
|
+
function tilesToIso(tiles) {
|
|
50126
|
+
return tiles.map((t) => ({
|
|
50127
|
+
x: t.x,
|
|
50128
|
+
y: t.y,
|
|
50129
|
+
terrain: t.terrain,
|
|
50130
|
+
terrainSprite: t.terrainSprite ?? TERRAIN_SPRITES[t.terrain ?? "ground"],
|
|
50131
|
+
passable: t.passable
|
|
50132
|
+
}));
|
|
50133
|
+
}
|
|
50134
|
+
function towersToUnits(towers) {
|
|
50135
|
+
return towers.map((t) => ({
|
|
50136
|
+
id: t.id,
|
|
50137
|
+
position: { x: t.x, y: t.y },
|
|
50138
|
+
name: "Tower",
|
|
50139
|
+
team: "player",
|
|
50140
|
+
sprite: TOWER_SPRITE,
|
|
50141
|
+
unitType: "guardian",
|
|
50142
|
+
health: 1,
|
|
50143
|
+
maxHealth: 1
|
|
50144
|
+
}));
|
|
50145
|
+
}
|
|
50146
|
+
function creepsToUnits(creeps) {
|
|
50147
|
+
return creeps.map((c) => ({
|
|
50148
|
+
id: c.id,
|
|
50149
|
+
position: { x: c.x, y: c.y },
|
|
50150
|
+
name: "Creep",
|
|
50151
|
+
team: "enemy",
|
|
50152
|
+
sprite: CREEP_SPRITE,
|
|
50153
|
+
unitType: "scrapper",
|
|
50154
|
+
health: c.hp,
|
|
50155
|
+
maxHealth: c.maxHp
|
|
50156
|
+
}));
|
|
50157
|
+
}
|
|
50158
|
+
function pathToFeatures(path) {
|
|
50159
|
+
return path.map((p2, i) => ({
|
|
50160
|
+
id: `path-${i}`,
|
|
50161
|
+
x: p2.x,
|
|
50162
|
+
y: p2.y,
|
|
50163
|
+
type: "path-marker",
|
|
50164
|
+
sprite: `${CDN6}world-map/road_straight.png`
|
|
50165
|
+
}));
|
|
50166
|
+
}
|
|
50167
|
+
function TowerDefenseBoard({
|
|
50168
|
+
entity,
|
|
50169
|
+
tiles: propTiles,
|
|
50170
|
+
path: propPath,
|
|
50171
|
+
towers: propTowers,
|
|
50172
|
+
creeps: propCreeps,
|
|
50173
|
+
gold: propGold,
|
|
50174
|
+
lives: propLives,
|
|
50175
|
+
wave: propWave,
|
|
50176
|
+
maxWaves: propMaxWaves,
|
|
50177
|
+
result: propResult,
|
|
50178
|
+
waveActive: propWaveActive,
|
|
50179
|
+
towerCost = 25,
|
|
50180
|
+
scale = 0.45,
|
|
50181
|
+
placeTowerEvent,
|
|
50182
|
+
startWaveEvent,
|
|
50183
|
+
playAgainEvent,
|
|
50184
|
+
gameEndEvent,
|
|
50185
|
+
className
|
|
50186
|
+
}) {
|
|
50187
|
+
const board = boardEntity(entity) ?? {};
|
|
50188
|
+
const eventBus = useEventBus();
|
|
50189
|
+
const { t } = useTranslate();
|
|
50190
|
+
const tiles = propTiles ?? rows(board.tiles);
|
|
50191
|
+
const path = propPath ?? rows(board.path);
|
|
50192
|
+
const towers = propTowers ?? rows(board.towers);
|
|
50193
|
+
const creeps = propCreeps ?? rows(board.creeps);
|
|
50194
|
+
const gold = propGold ?? num(board.gold, 100);
|
|
50195
|
+
const lives = propLives ?? num(board.lives, 20);
|
|
50196
|
+
const wave = propWave ?? num(board.wave, 1);
|
|
50197
|
+
const maxWaves = propMaxWaves ?? num(board.maxWaves, 5);
|
|
50198
|
+
const result = propResult ?? (str(board.result) || "none");
|
|
50199
|
+
const waveActive = propWaveActive ?? Boolean(board.waveActive);
|
|
50200
|
+
const [hoveredTile, setHoveredTile] = useState(null);
|
|
50201
|
+
const emittedGameEnd = useRef(false);
|
|
50202
|
+
if (result !== "none" && !emittedGameEnd.current) {
|
|
50203
|
+
emittedGameEnd.current = true;
|
|
50204
|
+
if (gameEndEvent) {
|
|
50205
|
+
eventBus.emit(`UI:${gameEndEvent}`, { result });
|
|
50206
|
+
}
|
|
50207
|
+
}
|
|
50208
|
+
if (result === "none") {
|
|
50209
|
+
emittedGameEnd.current = false;
|
|
50210
|
+
}
|
|
50211
|
+
const towerPositions = useMemo(() => new Set(towers.map((t2) => `${t2.x},${t2.y}`)), [towers]);
|
|
50212
|
+
const pathPositions = useMemo(() => new Set(path.map((p2) => `${p2.x},${p2.y}`)), [path]);
|
|
50213
|
+
const validMoves = useMemo(() => {
|
|
50214
|
+
if (result !== "none" || gold < towerCost) return [];
|
|
50215
|
+
return tiles.filter(
|
|
50216
|
+
(t2) => t2.passable !== false && !towerPositions.has(`${t2.x},${t2.y}`) && !pathPositions.has(`${t2.x},${t2.y}`)
|
|
50217
|
+
).map((t2) => ({ x: t2.x, y: t2.y }));
|
|
50218
|
+
}, [tiles, towerPositions, pathPositions, result, gold, towerCost]);
|
|
50219
|
+
const isoTiles = useMemo(() => tilesToIso(tiles), [tiles]);
|
|
50220
|
+
const towerUnits = useMemo(() => towersToUnits(towers), [towers]);
|
|
50221
|
+
const creepUnits = useMemo(() => creepsToUnits(creeps), [creeps]);
|
|
50222
|
+
const isoUnits = useMemo(() => [...towerUnits, ...creepUnits], [towerUnits, creepUnits]);
|
|
50223
|
+
const pathFeatures = useMemo(() => pathToFeatures(path), [path]);
|
|
50224
|
+
const handleTileClick = useCallback((x, y) => {
|
|
50225
|
+
if (result !== "none") return;
|
|
50226
|
+
if (pathPositions.has(`${x},${y}`)) return;
|
|
50227
|
+
if (towerPositions.has(`${x},${y}`)) return;
|
|
50228
|
+
if (gold < towerCost) return;
|
|
50229
|
+
if (placeTowerEvent) {
|
|
50230
|
+
eventBus.emit(`UI:${placeTowerEvent}`, { x, y });
|
|
50231
|
+
}
|
|
50232
|
+
}, [result, pathPositions, towerPositions, gold, towerCost, placeTowerEvent, eventBus]);
|
|
50233
|
+
const handleStartWave = useCallback(() => {
|
|
50234
|
+
if (startWaveEvent) {
|
|
50235
|
+
eventBus.emit(`UI:${startWaveEvent}`, { wave });
|
|
50236
|
+
}
|
|
50237
|
+
}, [startWaveEvent, wave, eventBus]);
|
|
50238
|
+
const handlePlayAgain = useCallback(() => {
|
|
50239
|
+
if (playAgainEvent) {
|
|
50240
|
+
eventBus.emit(`UI:${playAgainEvent}`, {});
|
|
50241
|
+
}
|
|
50242
|
+
}, [playAgainEvent, eventBus]);
|
|
50243
|
+
const canPlaceTower = gold >= towerCost && result === "none";
|
|
50244
|
+
const canStartWave = !waveActive && result === "none";
|
|
50245
|
+
return /* @__PURE__ */ jsxs(VStack, { className: cn("tower-defense-board relative min-h-[600px] bg-background", className), gap: "none", children: [
|
|
50246
|
+
/* @__PURE__ */ jsxs(
|
|
50247
|
+
HStack,
|
|
50248
|
+
{
|
|
50249
|
+
className: "px-4 py-2 border-b border-border bg-surface",
|
|
50250
|
+
gap: "lg",
|
|
50251
|
+
align: "center",
|
|
50252
|
+
children: [
|
|
50253
|
+
/* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
|
|
50254
|
+
/* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", children: t("td.gold") ?? "Gold" }),
|
|
50255
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body2", weight: "bold", className: "text-warning", children: gold })
|
|
50256
|
+
] }),
|
|
50257
|
+
/* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
|
|
50258
|
+
/* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", children: t("td.lives") ?? "Lives" }),
|
|
50259
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body2", weight: "bold", className: lives <= 5 ? "text-error" : "text-success", children: lives })
|
|
50260
|
+
] }),
|
|
50261
|
+
/* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
|
|
50262
|
+
/* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", children: t("td.wave") ?? "Wave" }),
|
|
50263
|
+
/* @__PURE__ */ jsxs(Typography, { variant: "body2", weight: "bold", children: [
|
|
50264
|
+
wave,
|
|
50265
|
+
" / ",
|
|
50266
|
+
maxWaves
|
|
50267
|
+
] })
|
|
50268
|
+
] }),
|
|
50269
|
+
/* @__PURE__ */ jsxs(Box, { className: "ml-auto", children: [
|
|
50270
|
+
canStartWave && /* @__PURE__ */ jsx(Button, { variant: "primary", size: "sm", onClick: handleStartWave, children: t("td.startWave") ?? "Start Wave" }),
|
|
50271
|
+
waveActive && /* @__PURE__ */ jsx(Typography, { variant: "small", className: "text-warning animate-pulse", children: t("td.waveInProgress") ?? "Wave in progress\u2026" })
|
|
50272
|
+
] })
|
|
50273
|
+
]
|
|
50274
|
+
}
|
|
50275
|
+
),
|
|
50276
|
+
/* @__PURE__ */ jsxs(Box, { className: "relative flex-1", children: [
|
|
50277
|
+
/* @__PURE__ */ jsx(
|
|
50278
|
+
IsometricCanvas_default,
|
|
50279
|
+
{
|
|
50280
|
+
tiles: isoTiles,
|
|
50281
|
+
units: isoUnits,
|
|
50282
|
+
features: pathFeatures,
|
|
50283
|
+
validMoves,
|
|
50284
|
+
hoveredTile,
|
|
50285
|
+
onTileClick: handleTileClick,
|
|
50286
|
+
onTileHover: (x, y) => setHoveredTile({ x, y }),
|
|
50287
|
+
onTileLeave: () => setHoveredTile(null),
|
|
50288
|
+
scale
|
|
50289
|
+
}
|
|
50290
|
+
),
|
|
50291
|
+
hoveredTile && canPlaceTower && validMoves.some((m) => m.x === hoveredTile.x && m.y === hoveredTile.y) && /* @__PURE__ */ jsx(Box, { className: "absolute bottom-4 left-1/2 -translate-x-1/2 z-10 bg-background/80 rounded px-3 py-1 backdrop-blur-sm pointer-events-none", children: /* @__PURE__ */ jsx(Typography, { variant: "small", children: t("td.placeTower") ?? `Place tower (${towerCost} gold)` }) })
|
|
50292
|
+
] }),
|
|
50293
|
+
result !== "none" && /* @__PURE__ */ jsx(Box, { className: "absolute inset-0 z-50 flex items-center justify-center bg-background/70 backdrop-blur-sm", children: /* @__PURE__ */ jsxs(VStack, { className: "text-center p-8", gap: "lg", children: [
|
|
50294
|
+
/* @__PURE__ */ jsx(
|
|
50295
|
+
Typography,
|
|
50296
|
+
{
|
|
50297
|
+
variant: "h2",
|
|
50298
|
+
className: cn(
|
|
50299
|
+
"text-4xl font-black tracking-widest uppercase",
|
|
50300
|
+
result === "won" ? "text-warning" : "text-error"
|
|
50301
|
+
),
|
|
50302
|
+
children: result === "won" ? t("td.victory") ?? "Victory!" : t("td.defeat") ?? "Defeat!"
|
|
50303
|
+
}
|
|
50304
|
+
),
|
|
50305
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body1", className: "text-muted-foreground", children: result === "won" ? t("td.survivedAllWaves") ?? `Survived all ${maxWaves} waves!` : t("td.livesReachedZero") ?? "Your base was overrun." }),
|
|
50306
|
+
/* @__PURE__ */ jsx(
|
|
50307
|
+
Button,
|
|
50308
|
+
{
|
|
50309
|
+
variant: "primary",
|
|
50310
|
+
className: "px-8 py-3 font-semibold",
|
|
50311
|
+
onClick: handlePlayAgain,
|
|
50312
|
+
children: t("td.playAgain") ?? "Play Again"
|
|
50313
|
+
}
|
|
50314
|
+
)
|
|
50315
|
+
] }) })
|
|
50316
|
+
] });
|
|
50317
|
+
}
|
|
50318
|
+
var CDN6, TERRAIN_SPRITES, TOWER_SPRITE, CREEP_SPRITE;
|
|
50319
|
+
var init_TowerDefenseBoard = __esm({
|
|
50320
|
+
"components/game/organisms/TowerDefenseBoard.tsx"() {
|
|
50321
|
+
"use client";
|
|
50322
|
+
init_cn();
|
|
50323
|
+
init_useEventBus();
|
|
50324
|
+
init_Box();
|
|
50325
|
+
init_Button();
|
|
50326
|
+
init_Typography();
|
|
50327
|
+
init_Stack();
|
|
50328
|
+
init_IsometricCanvas();
|
|
50329
|
+
init_boardEntity();
|
|
50330
|
+
CDN6 = "https://almadar-kflow-assets.web.app/shared/";
|
|
50331
|
+
TERRAIN_SPRITES = {
|
|
50332
|
+
ground: `${CDN6}isometric-blocks/PNG/Platformer tiles/platformerTile_01.png`,
|
|
50333
|
+
path: `${CDN6}isometric-blocks/PNG/Platformer tiles/platformerTile_09.png`,
|
|
50334
|
+
wall: `${CDN6}isometric-blocks/PNG/Platformer tiles/platformerTile_05.png`
|
|
50335
|
+
};
|
|
50336
|
+
TOWER_SPRITE = `${CDN6}units/guardian.png`;
|
|
50337
|
+
CREEP_SPRITE = `${CDN6}units/scrapper.png`;
|
|
50338
|
+
TowerDefenseBoard.displayName = "TowerDefenseBoard";
|
|
50339
|
+
}
|
|
50340
|
+
});
|
|
50341
|
+
function TowerDefenseTemplate({
|
|
50342
|
+
entity,
|
|
50343
|
+
title = "Tower Defense",
|
|
50344
|
+
tiles,
|
|
50345
|
+
path,
|
|
50346
|
+
towers,
|
|
50347
|
+
gold,
|
|
50348
|
+
lives,
|
|
50349
|
+
maxWaves,
|
|
50350
|
+
towerCost,
|
|
50351
|
+
scale,
|
|
50352
|
+
placeTowerEvent,
|
|
50353
|
+
startWaveEvent,
|
|
50354
|
+
playAgainEvent,
|
|
50355
|
+
gameEndEvent,
|
|
50356
|
+
className
|
|
50357
|
+
}) {
|
|
50358
|
+
const resolved = entity && typeof entity === "object" && !Array.isArray(entity) ? entity : void 0;
|
|
50359
|
+
return /* @__PURE__ */ jsxs(
|
|
50360
|
+
Box,
|
|
50361
|
+
{
|
|
50362
|
+
display: "flex",
|
|
50363
|
+
fullHeight: true,
|
|
50364
|
+
className: cn("tower-defense-template flex-col", className),
|
|
50365
|
+
children: [
|
|
50366
|
+
/* @__PURE__ */ jsx(
|
|
50367
|
+
HStack,
|
|
50368
|
+
{
|
|
50369
|
+
gap: "sm",
|
|
50370
|
+
align: "center",
|
|
50371
|
+
className: "px-4 py-3 border-b-2 border-border bg-surface shrink-0",
|
|
50372
|
+
children: /* @__PURE__ */ jsx(Typography, { variant: "h4", children: title })
|
|
50373
|
+
}
|
|
50374
|
+
),
|
|
50375
|
+
/* @__PURE__ */ jsx(Box, { className: "flex-1 relative overflow-hidden", children: /* @__PURE__ */ jsx(
|
|
50376
|
+
TowerDefenseBoard,
|
|
50377
|
+
{
|
|
50378
|
+
entity: resolved,
|
|
50379
|
+
tiles,
|
|
50380
|
+
path,
|
|
50381
|
+
towers,
|
|
50382
|
+
gold,
|
|
50383
|
+
lives,
|
|
50384
|
+
maxWaves,
|
|
50385
|
+
towerCost,
|
|
50386
|
+
scale,
|
|
50387
|
+
placeTowerEvent,
|
|
50388
|
+
startWaveEvent,
|
|
50389
|
+
playAgainEvent,
|
|
50390
|
+
gameEndEvent,
|
|
50391
|
+
className: "h-full"
|
|
50392
|
+
}
|
|
50393
|
+
) })
|
|
50394
|
+
]
|
|
50395
|
+
}
|
|
50396
|
+
);
|
|
50397
|
+
}
|
|
50398
|
+
var init_TowerDefenseTemplate = __esm({
|
|
50399
|
+
"components/game/templates/TowerDefenseTemplate.tsx"() {
|
|
50400
|
+
init_cn();
|
|
50401
|
+
init_Box();
|
|
50402
|
+
init_Stack();
|
|
50403
|
+
init_Typography();
|
|
50404
|
+
init_TowerDefenseBoard();
|
|
50405
|
+
TowerDefenseTemplate.displayName = "TowerDefenseTemplate";
|
|
50406
|
+
}
|
|
50407
|
+
});
|
|
47890
50408
|
function useBattleState(initialUnits, eventConfig = {}, callbacks = {}) {
|
|
47891
50409
|
const eventBus = useEventBus();
|
|
47892
50410
|
const {
|
|
@@ -48396,48 +50914,48 @@ function WorldMapTemplate({
|
|
|
48396
50914
|
}
|
|
48397
50915
|
);
|
|
48398
50916
|
}
|
|
48399
|
-
var
|
|
50917
|
+
var CDN7, DEFAULT_WORLDMAP_TILES, DEFAULT_WORLDMAP_UNITS, DEFAULT_WORLDMAP_FEATURES, DEFAULT_WORLDMAP_MANIFEST;
|
|
48400
50918
|
var init_WorldMapTemplate = __esm({
|
|
48401
50919
|
"components/game/templates/WorldMapTemplate.tsx"() {
|
|
48402
50920
|
init_WorldMapBoard();
|
|
48403
|
-
|
|
50921
|
+
CDN7 = "https://almadar-kflow-assets.web.app/shared";
|
|
48404
50922
|
DEFAULT_WORLDMAP_TILES = [
|
|
48405
|
-
{ x: 0, y: 0, terrain: "mountain", passable: false, terrainSprite: `${
|
|
48406
|
-
{ x: 1, y: 0, terrain: "mountain", passable: false, terrainSprite: `${
|
|
48407
|
-
{ x: 2, y: 0, terrain: "water", passable: false, terrainSprite: `${
|
|
48408
|
-
{ x: 3, y: 0, terrain: "mountain", passable: false, terrainSprite: `${
|
|
48409
|
-
{ x: 4, y: 0, terrain: "mountain", passable: false, terrainSprite: `${
|
|
48410
|
-
{ x: 0, y: 1, terrain: "mountain", passable: false, terrainSprite: `${
|
|
48411
|
-
{ x: 1, y: 1, terrain: "grass", passable: true, terrainSprite: `${
|
|
48412
|
-
{ x: 2, y: 1, terrain: "grass", passable: true, terrainSprite: `${
|
|
48413
|
-
{ x: 3, y: 1, terrain: "grass", passable: true, terrainSprite: `${
|
|
48414
|
-
{ x: 4, y: 1, terrain: "water", passable: false, terrainSprite: `${
|
|
48415
|
-
{ x: 0, y: 2, terrain: "water", passable: false, terrainSprite: `${
|
|
48416
|
-
{ x: 1, y: 2, terrain: "grass", passable: true, terrainSprite: `${
|
|
48417
|
-
{ x: 2, y: 2, terrain: "grass", passable: true, terrainSprite: `${
|
|
48418
|
-
{ x: 3, y: 2, terrain: "grass", passable: true, terrainSprite: `${
|
|
48419
|
-
{ x: 4, y: 2, terrain: "mountain", passable: false, terrainSprite: `${
|
|
48420
|
-
{ x: 0, y: 3, terrain: "mountain", passable: false, terrainSprite: `${
|
|
48421
|
-
{ x: 1, y: 3, terrain: "grass", passable: true, terrainSprite: `${
|
|
48422
|
-
{ x: 2, y: 3, terrain: "grass", passable: true, terrainSprite: `${
|
|
48423
|
-
{ x: 3, y: 3, terrain: "grass", passable: true, terrainSprite: `${
|
|
48424
|
-
{ x: 4, y: 3, terrain: "mountain", passable: false, terrainSprite: `${
|
|
48425
|
-
{ x: 0, y: 4, terrain: "mountain", passable: false, terrainSprite: `${
|
|
48426
|
-
{ x: 1, y: 4, terrain: "water", passable: false, terrainSprite: `${
|
|
48427
|
-
{ x: 2, y: 4, terrain: "grass", passable: true, terrainSprite: `${
|
|
48428
|
-
{ x: 3, y: 4, terrain: "mountain", passable: false, terrainSprite: `${
|
|
48429
|
-
{ x: 4, y: 4, terrain: "mountain", passable: false, terrainSprite: `${
|
|
50923
|
+
{ x: 0, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
|
|
50924
|
+
{ x: 1, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
|
|
50925
|
+
{ x: 2, y: 0, terrain: "water", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
|
|
50926
|
+
{ x: 3, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
|
|
50927
|
+
{ x: 4, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
|
|
50928
|
+
{ x: 0, y: 1, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
|
|
50929
|
+
{ x: 1, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
|
|
50930
|
+
{ x: 2, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
|
|
50931
|
+
{ x: 3, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
|
|
50932
|
+
{ x: 4, y: 1, terrain: "water", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
|
|
50933
|
+
{ x: 0, y: 2, terrain: "water", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
|
|
50934
|
+
{ x: 1, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
|
|
50935
|
+
{ x: 2, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_03.png` },
|
|
50936
|
+
{ x: 3, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
|
|
50937
|
+
{ x: 4, y: 2, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
|
|
50938
|
+
{ x: 0, y: 3, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
|
|
50939
|
+
{ x: 1, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
|
|
50940
|
+
{ x: 2, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
|
|
50941
|
+
{ x: 3, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_03.png` },
|
|
50942
|
+
{ x: 4, y: 3, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
|
|
50943
|
+
{ x: 0, y: 4, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
|
|
50944
|
+
{ x: 1, y: 4, terrain: "water", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
|
|
50945
|
+
{ x: 2, y: 4, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
|
|
50946
|
+
{ x: 3, y: 4, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
|
|
50947
|
+
{ x: 4, y: 4, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` }
|
|
48430
50948
|
];
|
|
48431
50949
|
DEFAULT_WORLDMAP_UNITS = [
|
|
48432
|
-
{ id: "h1", position: { x: 1, y: 1 }, unitType: "hero", name: "Amir", team: "player", health: 10, maxHealth: 10, sprite: `${
|
|
48433
|
-
{ id: "h2", position: { x: 3, y: 3 }, unitType: "scout", name: "Archivist", team: "player", health: 10, maxHealth: 10, sprite: `${
|
|
50950
|
+
{ 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` },
|
|
50951
|
+
{ 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` }
|
|
48434
50952
|
];
|
|
48435
50953
|
DEFAULT_WORLDMAP_FEATURES = [
|
|
48436
|
-
{ id: "f1", x: 2, y: 2, type: "capital", sprite: `${
|
|
48437
|
-
{ id: "f2", x: 4, y: 2, type: "power_node", sprite: `${
|
|
50954
|
+
{ id: "f1", x: 2, y: 2, type: "capital", sprite: `${CDN7}/scenes/world/capital.png` },
|
|
50955
|
+
{ id: "f2", x: 4, y: 2, type: "power_node", sprite: `${CDN7}/world-map/power_node.png` }
|
|
48438
50956
|
];
|
|
48439
50957
|
DEFAULT_WORLDMAP_MANIFEST = {
|
|
48440
|
-
baseUrl:
|
|
50958
|
+
baseUrl: CDN7,
|
|
48441
50959
|
terrains: {
|
|
48442
50960
|
grass: "/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png",
|
|
48443
50961
|
water: "/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png",
|
|
@@ -48566,7 +51084,7 @@ function lazyThree(name, loader) {
|
|
|
48566
51084
|
ThreeWrapper.displayName = `Lazy(${name})`;
|
|
48567
51085
|
return ThreeWrapper;
|
|
48568
51086
|
}
|
|
48569
|
-
var ThreeBoundary, FeatureRenderer,
|
|
51087
|
+
var ThreeBoundary, FeatureRenderer, GameCanvas3D2, GameCanvas3DBattleTemplate, GameCanvas3DCastleTemplate, GameCanvas3DWorldMapTemplate, COMPONENT_REGISTRY;
|
|
48570
51088
|
var init_component_registry_generated = __esm({
|
|
48571
51089
|
"components/core/organisms/component-registry.generated.ts"() {
|
|
48572
51090
|
init_AboutPageTemplate();
|
|
@@ -48676,6 +51194,7 @@ var init_component_registry_generated = __esm({
|
|
|
48676
51194
|
init_FormSectionHeader();
|
|
48677
51195
|
init_GameAudioProvider();
|
|
48678
51196
|
init_GameAudioToggle();
|
|
51197
|
+
init_GameBoard3D();
|
|
48679
51198
|
init_GameCanvas2D();
|
|
48680
51199
|
init_GameHud();
|
|
48681
51200
|
init_GameMenu();
|
|
@@ -48733,7 +51252,9 @@ var init_component_registry_generated = __esm({
|
|
|
48733
51252
|
init_PageHeader();
|
|
48734
51253
|
init_Pagination();
|
|
48735
51254
|
init_PatternTile();
|
|
51255
|
+
init_PlatformerBoard();
|
|
48736
51256
|
init_PlatformerCanvas();
|
|
51257
|
+
init_PlatformerTemplate();
|
|
48737
51258
|
init_Popover();
|
|
48738
51259
|
init_PositionedCanvas();
|
|
48739
51260
|
init_PowerupSlots();
|
|
@@ -48757,6 +51278,8 @@ var init_component_registry_generated = __esm({
|
|
|
48757
51278
|
init_ResourceBar();
|
|
48758
51279
|
init_ResourceCounter();
|
|
48759
51280
|
init_RichBlockEditor();
|
|
51281
|
+
init_RoguelikeBoard();
|
|
51282
|
+
init_RoguelikeTemplate();
|
|
48760
51283
|
init_RuntimeDebugger2();
|
|
48761
51284
|
init_ScaledDiagram();
|
|
48762
51285
|
init_ScoreBoard();
|
|
@@ -48829,6 +51352,8 @@ var init_component_registry_generated = __esm({
|
|
|
48829
51352
|
init_Toast();
|
|
48830
51353
|
init_ToastSlot();
|
|
48831
51354
|
init_Tooltip();
|
|
51355
|
+
init_TowerDefenseBoard();
|
|
51356
|
+
init_TowerDefenseTemplate();
|
|
48832
51357
|
init_TraitFrame();
|
|
48833
51358
|
init_TraitSlot();
|
|
48834
51359
|
init_TrendIndicator();
|
|
@@ -48873,7 +51398,7 @@ var init_component_registry_generated = __esm({
|
|
|
48873
51398
|
}
|
|
48874
51399
|
};
|
|
48875
51400
|
FeatureRenderer = lazyThree("FeatureRenderer", () => import('@almadar/ui/components/molecules/game/three'));
|
|
48876
|
-
|
|
51401
|
+
GameCanvas3D2 = lazyThree("GameCanvas3D", () => import('@almadar/ui/components/molecules/game/three'));
|
|
48877
51402
|
GameCanvas3DBattleTemplate = lazyThree("GameCanvas3DBattleTemplate", () => import('@almadar/ui/components/molecules/game/three'));
|
|
48878
51403
|
GameCanvas3DCastleTemplate = lazyThree("GameCanvas3DCastleTemplate", () => import('@almadar/ui/components/molecules/game/three'));
|
|
48879
51404
|
GameCanvas3DWorldMapTemplate = lazyThree("GameCanvas3DWorldMapTemplate", () => import('@almadar/ui/components/molecules/game/three'));
|
|
@@ -48992,8 +51517,9 @@ var init_component_registry_generated = __esm({
|
|
|
48992
51517
|
"FormSectionHeader": FormSectionHeader,
|
|
48993
51518
|
"GameAudioProvider": GameAudioProvider,
|
|
48994
51519
|
"GameAudioToggle": GameAudioToggle,
|
|
51520
|
+
"GameBoard3D": GameBoard3D,
|
|
48995
51521
|
"GameCanvas2D": GameCanvas2D,
|
|
48996
|
-
"GameCanvas3D":
|
|
51522
|
+
"GameCanvas3D": GameCanvas3D2,
|
|
48997
51523
|
"GameCanvas3DBattleTemplate": GameCanvas3DBattleTemplate,
|
|
48998
51524
|
"GameCanvas3DCastleTemplate": GameCanvas3DCastleTemplate,
|
|
48999
51525
|
"GameCanvas3DWorldMapTemplate": GameCanvas3DWorldMapTemplate,
|
|
@@ -49055,7 +51581,9 @@ var init_component_registry_generated = __esm({
|
|
|
49055
51581
|
"PageHeader": PageHeader,
|
|
49056
51582
|
"Pagination": Pagination,
|
|
49057
51583
|
"PatternTile": PatternTile,
|
|
51584
|
+
"PlatformerBoard": PlatformerBoard,
|
|
49058
51585
|
"PlatformerCanvas": PlatformerCanvas,
|
|
51586
|
+
"PlatformerTemplate": PlatformerTemplate,
|
|
49059
51587
|
"Popover": Popover,
|
|
49060
51588
|
"PositionedCanvas": PositionedCanvas,
|
|
49061
51589
|
"PowerupSlots": PowerupSlots,
|
|
@@ -49079,6 +51607,8 @@ var init_component_registry_generated = __esm({
|
|
|
49079
51607
|
"ResourceBar": ResourceBar,
|
|
49080
51608
|
"ResourceCounter": ResourceCounter,
|
|
49081
51609
|
"RichBlockEditor": RichBlockEditor,
|
|
51610
|
+
"RoguelikeBoard": RoguelikeBoard,
|
|
51611
|
+
"RoguelikeTemplate": RoguelikeTemplate,
|
|
49082
51612
|
"RuntimeDebugger": RuntimeDebugger,
|
|
49083
51613
|
"ScaledDiagram": ScaledDiagram,
|
|
49084
51614
|
"ScoreBoard": ScoreBoard,
|
|
@@ -49154,6 +51684,8 @@ var init_component_registry_generated = __esm({
|
|
|
49154
51684
|
"Toast": Toast,
|
|
49155
51685
|
"ToastSlot": ToastSlot,
|
|
49156
51686
|
"Tooltip": Tooltip,
|
|
51687
|
+
"TowerDefenseBoard": TowerDefenseBoard,
|
|
51688
|
+
"TowerDefenseTemplate": TowerDefenseTemplate,
|
|
49157
51689
|
"TraitFrame": TraitFrame,
|
|
49158
51690
|
"TraitSlot": TraitSlot,
|
|
49159
51691
|
"TrendIndicator": TrendIndicator,
|
|
@@ -50716,6 +53248,10 @@ init_UncontrolledBattleBoard();
|
|
|
50716
53248
|
init_useBattleState();
|
|
50717
53249
|
init_WorldMapBoard();
|
|
50718
53250
|
init_CastleBoard();
|
|
53251
|
+
init_PlatformerBoard();
|
|
53252
|
+
init_TowerDefenseBoard();
|
|
53253
|
+
init_RoguelikeBoard();
|
|
53254
|
+
init_GameBoard3D();
|
|
50719
53255
|
init_TraitStateViewer();
|
|
50720
53256
|
init_TraitSlot();
|
|
50721
53257
|
|
|
@@ -51288,6 +53824,9 @@ init_GameShell();
|
|
|
51288
53824
|
init_BattleTemplate();
|
|
51289
53825
|
init_CastleTemplate();
|
|
51290
53826
|
init_WorldMapTemplate();
|
|
53827
|
+
init_PlatformerTemplate();
|
|
53828
|
+
init_TowerDefenseTemplate();
|
|
53829
|
+
init_RoguelikeTemplate();
|
|
51291
53830
|
init_LandingPageTemplate();
|
|
51292
53831
|
init_PricingPageTemplate();
|
|
51293
53832
|
init_FeatureDetailPageTemplate();
|
|
@@ -51296,4 +53835,4 @@ init_AboutPageTemplate();
|
|
|
51296
53835
|
// components/index.ts
|
|
51297
53836
|
init_cn();
|
|
51298
53837
|
|
|
51299
|
-
export { ALL_PRESETS, AR_BOOK_FIELDS, AboutPageTemplate, Accordion, ActionButton, ActionButtons, Card2 as ActionCard, ActionPalette, ActionTile, ActivationBlock, Alert, AnimatedCounter, AnimatedGraphic, AnimatedReveal, ArticleSection, Aside, AssetPicker, AuthLayout, Avatar, Badge, BattleBoard, BattleTemplate, BehaviorView, BloomQuizBlock, BookChapterView, BookCoverPage, BookNavBar, BookTableOfContents, BookViewer, Box, BranchingLogicBuilder, Breadcrumb, BuilderBoard, Button, ButtonGroup, CTABanner, CalendarGrid, CanvasEffect, Card, CardBody, CardContent, CardFooter, CardGrid, CardHeader, CardTitle, Carousel, CaseStudyCard, CaseStudyOrganism, CastleBoard, CastleTemplate, Center, Chart, ChartLegend, Checkbox, ChoiceButton, ClassifierBoard, Coachmark, CodeBlock, CodeRunnerPanel, CollapsibleSection, CombatLog, ComboCounter, CommunityLinks, ConditionalWrapper, ConfettiEffect, ConfirmDialog, ConnectionBlock, Container, ContentRenderer, ContentSection, ControlButton, CounterTemplate, CraftingRecipe, DEFAULT_LIKERT_OPTIONS, DEFAULT_MATRIX_COLUMNS, DIAMOND_TOP_Y, DPad, DamageNumber, DashboardGrid, DashboardLayout, DataGrid, DataList, DataTable, DateRangePicker, DateRangeSelector, DayCell, DebuggerBoard, DetailPanel, Dialog, DialogueBox, DialogueBubble, Divider, DocBreadcrumb, DocPagination, DocSearch, DocSidebar, DocTOC, DocumentViewer, StateMachineView as DomStateMachineVisualizer, Drawer, DrawerSlot, EdgeDecoration, EditorCheckbox, EditorSelect, EditorSlider, EditorTextInput, EditorToolbar, EmptyState, EnemyPlate, EntityDisplayEvents, ErrorBoundary, ErrorState, EventHandlerBoard, EventLog, FEATURE_COLORS, FEATURE_TYPES, FLOOR_HEIGHT, FeatureCard, FeatureDetailPageTemplate, FeatureGrid, FeatureGridOrganism, FileTree, FilterGroup, FilterPill, Flex, FlipCard, FlipContainer, FloatingActionButton, Form, FormActions, FormField, FormLayout, FormSection, FormSectionHeader, GameAudioContext, GameAudioProvider, GameAudioToggle, GameCanvas2D, GameHud, GameMenu, GameOverScreen, GameShell, GameTemplate, GenericAppTemplate, GeometricPattern, GradientDivider, GraphCanvas, GraphView, Grid, GridPicker, HStack, Header, HealthBar, HealthPanel, HeroOrganism, HeroSection, IDENTITY_BOOK_FIELDS, Icon, IconPicker, InfiniteScrollSentinel, Input, InputGroup, InstallBox, InventoryGrid, InventoryPanel, IsometricCanvas, ItemSlot, JazariStateMachine, JsonTreeEditor, Label, LandingPageTemplate, LawReferenceTooltip, Lightbox, LikertScale, LineChart2 as LineChart, List3 as List, LoadingState, MapView, MarkdownContent, MarketingFooter, MarketingStatCard, MasterDetail, MasterDetailLayout, MatrixQuestion, MediaGallery, Menu, Meter, MiniMap, Modal, ModalSlot, ModuleCard, Navigation, NegotiatorBoard, NodeSlotEditor, NotifyListener, NumberStepper, ObjectRulePanel, OnboardingSpotlight, OptionConstraintGroup, StateMachineView as OrbitalStateMachineView, OrbitalVisualization, Overlay, PageHeader, Pagination, PatternTile, PhysicsManager, PlatformerCanvas, Popover, PositionedCanvas, PowerupSlots, PricingCard, PricingGrid, PricingOrganism, PricingPageTemplate, ProgressBar, ProgressDots, PropertyInspector, PullQuote, PullToRefresh, QrScanner, QuestTracker, QuizBlock, Radio, RangeSlider, ReflectionBlock, RelationSelect, RepeatableFormSection, ReplyTree, ResourceBar, ResourceCounter, RichBlockEditor, RuleEditor, RuntimeDebugger, SHEET_COLUMNS, SPRITE_SHEET_LAYOUT, ScaledDiagram, ScoreBoard, ScoreDisplay, SearchInput, Section, SectionHeader, SegmentRenderer, Select, SequenceBar, SequencerBoard, ServiceCatalog, ShowcaseCard, ShowcaseOrganism, SidePanel, Sidebar, SignaturePad, SimpleGrid, SimulationCanvas, SimulationControls, SimulationGraph, SimulatorBoard, Skeleton, SlotContentRenderer, SocialProof, SortableList, Spacer, Sparkline, Spinner, Split, SplitPane, SplitSection, Sprite, Stack, StarRating, StatBadge, StatCard, StatDisplay, StateArchitectBoard, StateIndicator, StateJsonView, StateMachineView, StateNode2 as StateNode, StatsGrid, StatsOrganism, StatusBar, StatusDot, StatusEffect, StepFlow, StepFlowOrganism, SvgBranch, SvgConnection, SvgFlow, SvgGrid, SvgLobe, SvgMesh, SvgMorph, SvgNode, SvgPulse, SvgRing, SvgShield, SvgStack, SwipeableRow, Switch, TERRAIN_COLORS, TILE_HEIGHT, TILE_WIDTH, TabbedContainer, TableView, Tabs, TagCloud, TagInput, TeamCard, TeamOrganism, TerrainPalette, TextHighlight, Textarea, ThemeSelector, ThemeToggle, TimeSlotCell, Timeline, TimerDisplay, Toast, ToastSlot, Tooltip, TraitFrame, TraitSlot, TraitStateViewer, TransitionArrow, TrendIndicator, TurnIndicator, TurnPanel, TypewriterText, Typography, UISlotComponent, UISlotRenderer, UncontrolledBattleBoard, UnitCommandBar, UploadDropZone, VStack, VariablePanel, VersionDiff, ViolationAlert, VoteStack, WaypointMarker, WizardContainer, WizardNavigation, WizardProgress, WorldMapBoard, WorldMapTemplate, XPBar, applyTemporaryEffect, calculateAttackTargets, calculateDamage, calculateValidMoves, cn, combatAnimations, combatClasses, combatEffects, createInitialGameState, createUnitAnimationState, drawSprite, generateCombatMessage, getCurrentFrame, getTileDimensions, inferDirection, isoToScreen, mapBookData, parseLessonSegments, parseMarkdownWithCodeBlocks, pendulum, projectileMotion, resolveFieldMap, resolveFrame, resolveSheetDirection, screenToIso, springOscillator, tickAnimationState, toCodeLanguage, transitionAnimation, useAnchorRect, useBattleState, useCamera, useGameAudio, useGameAudioContext, useImageCache, usePhysics2D, useSpriteAnimations };
|
|
53838
|
+
export { ALL_PRESETS, AR_BOOK_FIELDS, AboutPageTemplate, Accordion, ActionButton, ActionButtons, Card2 as ActionCard, ActionPalette, ActionTile, ActivationBlock, Alert, AnimatedCounter, AnimatedGraphic, AnimatedReveal, ArticleSection, Aside, AssetPicker, AuthLayout, Avatar, Badge, BattleBoard, BattleTemplate, BehaviorView, BloomQuizBlock, BookChapterView, BookCoverPage, BookNavBar, BookTableOfContents, BookViewer, Box, BranchingLogicBuilder, Breadcrumb, BuilderBoard, Button, ButtonGroup, CTABanner, CalendarGrid, CanvasEffect, Card, CardBody, CardContent, CardFooter, CardGrid, CardHeader, CardTitle, Carousel, CaseStudyCard, CaseStudyOrganism, CastleBoard, CastleTemplate, Center, Chart, ChartLegend, Checkbox, ChoiceButton, ClassifierBoard, Coachmark, CodeBlock, CodeRunnerPanel, CollapsibleSection, CombatLog, ComboCounter, CommunityLinks, ConditionalWrapper, ConfettiEffect, ConfirmDialog, ConnectionBlock, Container, ContentRenderer, ContentSection, ControlButton, CounterTemplate, CraftingRecipe, DEFAULT_LIKERT_OPTIONS, DEFAULT_MATRIX_COLUMNS, DIAMOND_TOP_Y, DPad, DamageNumber, DashboardGrid, DashboardLayout, DataGrid, DataList, DataTable, DateRangePicker, DateRangeSelector, DayCell, DebuggerBoard, DetailPanel, Dialog, DialogueBox, DialogueBubble, Divider, DocBreadcrumb, DocPagination, DocSearch, DocSidebar, DocTOC, DocumentViewer, StateMachineView as DomStateMachineVisualizer, Drawer, DrawerSlot, EdgeDecoration, EditorCheckbox, EditorSelect, EditorSlider, EditorTextInput, EditorToolbar, EmptyState, EnemyPlate, EntityDisplayEvents, ErrorBoundary, ErrorState, EventHandlerBoard, EventLog, FEATURE_COLORS, FEATURE_TYPES, FLOOR_HEIGHT, FeatureCard, FeatureDetailPageTemplate, FeatureGrid, FeatureGridOrganism, FileTree, FilterGroup, FilterPill, Flex, FlipCard, FlipContainer, FloatingActionButton, Form, FormActions, FormField, FormLayout, FormSection, FormSectionHeader, GameAudioContext, GameAudioProvider, GameAudioToggle, GameBoard3D, GameCanvas2D, GameHud, GameMenu, GameOverScreen, GameShell, GameTemplate, GenericAppTemplate, GeometricPattern, GradientDivider, GraphCanvas, GraphView, Grid, GridPicker, HStack, Header, HealthBar, HealthPanel, HeroOrganism, HeroSection, IDENTITY_BOOK_FIELDS, Icon, IconPicker, InfiniteScrollSentinel, Input, InputGroup, InstallBox, InventoryGrid, InventoryPanel, IsometricCanvas, ItemSlot, JazariStateMachine, JsonTreeEditor, Label, LandingPageTemplate, LawReferenceTooltip, Lightbox, LikertScale, LineChart2 as LineChart, List3 as List, LoadingState, MapView, MarkdownContent, MarketingFooter, MarketingStatCard, MasterDetail, MasterDetailLayout, MatrixQuestion, MediaGallery, Menu, Meter, MiniMap, Modal, ModalSlot, ModuleCard, Navigation, NegotiatorBoard, NodeSlotEditor, NotifyListener, NumberStepper, ObjectRulePanel, OnboardingSpotlight, OptionConstraintGroup, StateMachineView as OrbitalStateMachineView, OrbitalVisualization, Overlay, PageHeader, Pagination, PatternTile, PhysicsManager, PlatformerBoard, PlatformerCanvas, PlatformerTemplate, Popover, PositionedCanvas, PowerupSlots, PricingCard, PricingGrid, PricingOrganism, PricingPageTemplate, ProgressBar, ProgressDots, PropertyInspector, PullQuote, PullToRefresh, QrScanner, QuestTracker, QuizBlock, Radio, RangeSlider, ReflectionBlock, RelationSelect, RepeatableFormSection, ReplyTree, ResourceBar, ResourceCounter, RichBlockEditor, RoguelikeBoard, RoguelikeTemplate, RuleEditor, RuntimeDebugger, SHEET_COLUMNS, SPRITE_SHEET_LAYOUT, ScaledDiagram, ScoreBoard, ScoreDisplay, SearchInput, Section, SectionHeader, SegmentRenderer, Select, SequenceBar, SequencerBoard, ServiceCatalog, ShowcaseCard, ShowcaseOrganism, SidePanel, Sidebar, SignaturePad, SimpleGrid, SimulationCanvas, SimulationControls, SimulationGraph, SimulatorBoard, Skeleton, SlotContentRenderer, SocialProof, SortableList, Spacer, Sparkline, Spinner, Split, SplitPane, SplitSection, Sprite, Stack, StarRating, StatBadge, StatCard, StatDisplay, StateArchitectBoard, StateIndicator, StateJsonView, StateMachineView, StateNode2 as StateNode, StatsGrid, StatsOrganism, StatusBar, StatusDot, StatusEffect, StepFlow, StepFlowOrganism, SvgBranch, SvgConnection, SvgFlow, SvgGrid, SvgLobe, SvgMesh, SvgMorph, SvgNode, SvgPulse, SvgRing, SvgShield, SvgStack, SwipeableRow, Switch, TERRAIN_COLORS, TILE_HEIGHT, TILE_WIDTH, TabbedContainer, TableView, Tabs, TagCloud, TagInput, TeamCard, TeamOrganism, TerrainPalette, TextHighlight, Textarea, ThemeSelector, ThemeToggle, TimeSlotCell, Timeline, TimerDisplay, Toast, ToastSlot, Tooltip, TowerDefenseBoard, TowerDefenseTemplate, TraitFrame, TraitSlot, TraitStateViewer, TransitionArrow, TrendIndicator, TurnIndicator, TurnPanel, TypewriterText, Typography, UISlotComponent, UISlotRenderer, UncontrolledBattleBoard, UnitCommandBar, UploadDropZone, VStack, VariablePanel, VersionDiff, ViolationAlert, VoteStack, WaypointMarker, WizardContainer, WizardNavigation, WizardProgress, WorldMapBoard, WorldMapTemplate, XPBar, applyTemporaryEffect, calculateAttackTargets, calculateDamage, calculateValidMoves, cn, combatAnimations, combatClasses, combatEffects, createInitialGameState, createUnitAnimationState, drawSprite, generateCombatMessage, getCurrentFrame, getTileDimensions, inferDirection, isoToScreen, mapBookData, parseLessonSegments, parseMarkdownWithCodeBlocks, pendulum, projectileMotion, resolveFieldMap, resolveFrame, resolveSheetDirection, screenToIso, springOscillator, tickAnimationState, toCodeLanguage, transitionAnimation, useAnchorRect, useBattleState, useCamera, useGameAudio, useGameAudioContext, useImageCache, usePhysics2D, useSpriteAnimations };
|