@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
|
@@ -40,6 +40,12 @@ var core = require('@dnd-kit/core');
|
|
|
40
40
|
var sortable = require('@dnd-kit/sortable');
|
|
41
41
|
var utilities = require('@dnd-kit/utilities');
|
|
42
42
|
var react = require('@xyflow/react');
|
|
43
|
+
var THREE = require('three');
|
|
44
|
+
var GLTFLoader_js = require('three/examples/jsm/loaders/GLTFLoader.js');
|
|
45
|
+
var OBJLoader_js = require('three/examples/jsm/loaders/OBJLoader.js');
|
|
46
|
+
var GLTFLoader = require('three/examples/jsm/loaders/GLTFLoader');
|
|
47
|
+
var fiber = require('@react-three/fiber');
|
|
48
|
+
var drei = require('@react-three/drei');
|
|
43
49
|
var context = require('@almadar/ui/context');
|
|
44
50
|
var patterns = require('@almadar/patterns');
|
|
45
51
|
|
|
@@ -88,6 +94,7 @@ var ReactMarkdown__default = /*#__PURE__*/_interopDefault(ReactMarkdown);
|
|
|
88
94
|
var remarkGfm__default = /*#__PURE__*/_interopDefault(remarkGfm);
|
|
89
95
|
var remarkMath__default = /*#__PURE__*/_interopDefault(remarkMath);
|
|
90
96
|
var rehypeKatex__default = /*#__PURE__*/_interopDefault(rehypeKatex);
|
|
97
|
+
var THREE__namespace = /*#__PURE__*/_interopNamespace(THREE);
|
|
91
98
|
|
|
92
99
|
var __defProp = Object.defineProperty;
|
|
93
100
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
@@ -1321,9 +1328,9 @@ function resolvePhosphor(name, weight, family) {
|
|
|
1321
1328
|
(lib) => {
|
|
1322
1329
|
const PhosphorComp = lib[target];
|
|
1323
1330
|
if (!PhosphorComp || typeof PhosphorComp !== "object") return null;
|
|
1324
|
-
const
|
|
1331
|
+
const Component2 = PhosphorComp;
|
|
1325
1332
|
const Adapter = (props) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1326
|
-
|
|
1333
|
+
Component2,
|
|
1327
1334
|
{
|
|
1328
1335
|
weight,
|
|
1329
1336
|
className: props.className,
|
|
@@ -1347,9 +1354,9 @@ function resolveTabler(name, family) {
|
|
|
1347
1354
|
(lib) => {
|
|
1348
1355
|
const TablerComp = lib[target];
|
|
1349
1356
|
if (!TablerComp || typeof TablerComp !== "object") return null;
|
|
1350
|
-
const
|
|
1357
|
+
const Component2 = TablerComp;
|
|
1351
1358
|
const Adapter = (props) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1352
|
-
|
|
1359
|
+
Component2,
|
|
1353
1360
|
{
|
|
1354
1361
|
stroke: props.strokeWidth ?? 1.5,
|
|
1355
1362
|
className: props.className,
|
|
@@ -1373,9 +1380,9 @@ function resolveFa(name, family) {
|
|
|
1373
1380
|
(lib) => {
|
|
1374
1381
|
const FaComp = lib[target];
|
|
1375
1382
|
if (!FaComp || typeof FaComp !== "function") return null;
|
|
1376
|
-
const
|
|
1383
|
+
const Component2 = FaComp;
|
|
1377
1384
|
const Adapter = (props) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1378
|
-
|
|
1385
|
+
Component2,
|
|
1379
1386
|
{
|
|
1380
1387
|
className: props.className,
|
|
1381
1388
|
style: props.style,
|
|
@@ -3368,7 +3375,7 @@ var init_Box = __esm({
|
|
|
3368
3375
|
position,
|
|
3369
3376
|
className,
|
|
3370
3377
|
children,
|
|
3371
|
-
as:
|
|
3378
|
+
as: Component2 = "div",
|
|
3372
3379
|
action,
|
|
3373
3380
|
actionPayload,
|
|
3374
3381
|
hoverEvent,
|
|
@@ -3400,7 +3407,7 @@ var init_Box = __esm({
|
|
|
3400
3407
|
}, [hoverEvent, eventBus, onMouseLeave]);
|
|
3401
3408
|
const isClickable = action || onClick;
|
|
3402
3409
|
return React77__namespace.default.createElement(
|
|
3403
|
-
|
|
3410
|
+
Component2,
|
|
3404
3411
|
{
|
|
3405
3412
|
ref,
|
|
3406
3413
|
className: cn(
|
|
@@ -3449,10 +3456,10 @@ var init_Center = __esm({
|
|
|
3449
3456
|
className,
|
|
3450
3457
|
style,
|
|
3451
3458
|
children,
|
|
3452
|
-
as:
|
|
3459
|
+
as: Component2 = "div"
|
|
3453
3460
|
}) => {
|
|
3454
3461
|
const mergedStyle = minHeight ? { minHeight, ...style } : style;
|
|
3455
|
-
const Comp =
|
|
3462
|
+
const Comp = Component2;
|
|
3456
3463
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3457
3464
|
Comp,
|
|
3458
3465
|
{
|
|
@@ -4083,7 +4090,7 @@ var init_Stack = __esm({
|
|
|
4083
4090
|
className,
|
|
4084
4091
|
style,
|
|
4085
4092
|
children,
|
|
4086
|
-
as:
|
|
4093
|
+
as: Component2 = "div",
|
|
4087
4094
|
onClick,
|
|
4088
4095
|
onKeyDown,
|
|
4089
4096
|
role,
|
|
@@ -4101,7 +4108,7 @@ var init_Stack = __esm({
|
|
|
4101
4108
|
};
|
|
4102
4109
|
const isHorizontal = direction === "horizontal";
|
|
4103
4110
|
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";
|
|
4104
|
-
const Comp =
|
|
4111
|
+
const Comp = Component2;
|
|
4105
4112
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
4106
4113
|
Comp,
|
|
4107
4114
|
{
|
|
@@ -4292,8 +4299,8 @@ var init_Typography = __esm({
|
|
|
4292
4299
|
children
|
|
4293
4300
|
}) => {
|
|
4294
4301
|
const variant = variantProp ?? (level ? `h${level}` : "body1");
|
|
4295
|
-
const
|
|
4296
|
-
const Comp =
|
|
4302
|
+
const Component2 = as || defaultElements[variant];
|
|
4303
|
+
const Comp = Component2;
|
|
4297
4304
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
4298
4305
|
Comp,
|
|
4299
4306
|
{
|
|
@@ -7506,10 +7513,10 @@ var init_Container = __esm({
|
|
|
7506
7513
|
center = true,
|
|
7507
7514
|
className,
|
|
7508
7515
|
children,
|
|
7509
|
-
as:
|
|
7516
|
+
as: Component2 = "div"
|
|
7510
7517
|
}) => {
|
|
7511
7518
|
const resolvedSize = maxWidth ?? size ?? "lg";
|
|
7512
|
-
const Comp =
|
|
7519
|
+
const Comp = Component2;
|
|
7513
7520
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
7514
7521
|
Comp,
|
|
7515
7522
|
{
|
|
@@ -8224,6 +8231,7 @@ var init_Accordion = __esm({
|
|
|
8224
8231
|
}
|
|
8225
8232
|
});
|
|
8226
8233
|
function ActionButton({
|
|
8234
|
+
assetUrl = DEFAULT_ASSET_URL,
|
|
8227
8235
|
label = "Attack",
|
|
8228
8236
|
icon,
|
|
8229
8237
|
cooldown = 0,
|
|
@@ -8263,13 +8271,23 @@ function ActionButton({
|
|
|
8263
8271
|
}
|
|
8264
8272
|
}
|
|
8265
8273
|
),
|
|
8266
|
-
|
|
8274
|
+
assetUrl ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
8275
|
+
"img",
|
|
8276
|
+
{
|
|
8277
|
+
src: assetUrl,
|
|
8278
|
+
alt: "",
|
|
8279
|
+
width: 16,
|
|
8280
|
+
height: 16,
|
|
8281
|
+
style: { imageRendering: "pixelated", objectFit: "contain" },
|
|
8282
|
+
className: cn("flex-shrink-0", sizes.icon)
|
|
8283
|
+
}
|
|
8284
|
+
) : icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("flex-shrink-0", sizes.icon), children: typeof icon === "string" ? (() => {
|
|
8267
8285
|
const I = resolveIcon(icon);
|
|
8268
8286
|
return I ? /* @__PURE__ */ jsxRuntime.jsx(I, { className: "w-4 h-4" }) : null;
|
|
8269
8287
|
})() : /* @__PURE__ */ (() => {
|
|
8270
8288
|
const I = icon;
|
|
8271
8289
|
return /* @__PURE__ */ jsxRuntime.jsx(I, { className: "w-4 h-4" });
|
|
8272
|
-
})() }),
|
|
8290
|
+
})() }) : null,
|
|
8273
8291
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "relative z-10", children: label }),
|
|
8274
8292
|
hotkey && /* @__PURE__ */ jsxRuntime.jsx(
|
|
8275
8293
|
"span",
|
|
@@ -8285,7 +8303,7 @@ function ActionButton({
|
|
|
8285
8303
|
}
|
|
8286
8304
|
);
|
|
8287
8305
|
}
|
|
8288
|
-
var sizeMap, variantStyles7;
|
|
8306
|
+
var sizeMap, variantStyles7, DEFAULT_ASSET_URL;
|
|
8289
8307
|
var init_ActionButton = __esm({
|
|
8290
8308
|
"components/game/atoms/ActionButton.tsx"() {
|
|
8291
8309
|
init_cn();
|
|
@@ -8300,10 +8318,12 @@ var init_ActionButton = __esm({
|
|
|
8300
8318
|
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary-hover border-border",
|
|
8301
8319
|
danger: "bg-error text-error-foreground hover:bg-error/90 border-error"
|
|
8302
8320
|
};
|
|
8321
|
+
DEFAULT_ASSET_URL = "https://almadar-kflow-assets.web.app/shared/effects/particles/slash_01.png";
|
|
8303
8322
|
ActionButton.displayName = "ActionButton";
|
|
8304
8323
|
}
|
|
8305
8324
|
});
|
|
8306
8325
|
function ControlButton({
|
|
8326
|
+
assetUrl = DEFAULT_ASSET_URL2,
|
|
8307
8327
|
label,
|
|
8308
8328
|
icon,
|
|
8309
8329
|
size = "md",
|
|
@@ -8350,7 +8370,7 @@ function ControlButton({
|
|
|
8350
8370
|
},
|
|
8351
8371
|
[isPressed, releaseEvent, eventBus, onRelease]
|
|
8352
8372
|
);
|
|
8353
|
-
return /* @__PURE__ */ jsxRuntime.
|
|
8373
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
8354
8374
|
"button",
|
|
8355
8375
|
{
|
|
8356
8376
|
type: "button",
|
|
@@ -8371,20 +8391,27 @@ function ControlButton({
|
|
|
8371
8391
|
disabled && "opacity-50 cursor-not-allowed",
|
|
8372
8392
|
className
|
|
8373
8393
|
),
|
|
8374
|
-
children:
|
|
8375
|
-
|
|
8376
|
-
|
|
8377
|
-
|
|
8378
|
-
|
|
8379
|
-
|
|
8380
|
-
|
|
8381
|
-
|
|
8382
|
-
|
|
8383
|
-
|
|
8394
|
+
children: assetUrl ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
8395
|
+
"img",
|
|
8396
|
+
{
|
|
8397
|
+
src: assetUrl,
|
|
8398
|
+
alt: "",
|
|
8399
|
+
width: 24,
|
|
8400
|
+
height: 24,
|
|
8401
|
+
style: { imageRendering: "pixelated", objectFit: "contain" },
|
|
8402
|
+
className: "flex-shrink-0"
|
|
8403
|
+
}
|
|
8404
|
+
) : icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-2xl", children: typeof icon === "string" ? /^[a-zA-Z0-9-]+$/.test(icon) ? (() => {
|
|
8405
|
+
const I = resolveIcon(icon);
|
|
8406
|
+
return I ? /* @__PURE__ */ jsxRuntime.jsx(I, { className: "w-6 h-6" }) : null;
|
|
8407
|
+
})() : icon : /* @__PURE__ */ (() => {
|
|
8408
|
+
const I = icon;
|
|
8409
|
+
return /* @__PURE__ */ jsxRuntime.jsx(I, { className: "w-6 h-6" });
|
|
8410
|
+
})() }) : label ? /* @__PURE__ */ jsxRuntime.jsx("span", { children: label }) : null
|
|
8384
8411
|
}
|
|
8385
8412
|
);
|
|
8386
8413
|
}
|
|
8387
|
-
var sizeMap2, shapeMap, variantMap;
|
|
8414
|
+
var sizeMap2, shapeMap, variantMap, DEFAULT_ASSET_URL2;
|
|
8388
8415
|
var init_ControlButton = __esm({
|
|
8389
8416
|
"components/game/atoms/ControlButton.tsx"() {
|
|
8390
8417
|
"use client";
|
|
@@ -8407,6 +8434,7 @@ var init_ControlButton = __esm({
|
|
|
8407
8434
|
secondary: "bg-secondary text-secondary-foreground border-border hover:bg-secondary-hover",
|
|
8408
8435
|
ghost: "bg-transparent text-foreground border-border hover:bg-muted"
|
|
8409
8436
|
};
|
|
8437
|
+
DEFAULT_ASSET_URL2 = "https://almadar-kflow-assets.web.app/shared/effects/particles/circle_01.png";
|
|
8410
8438
|
ControlButton.displayName = "ControlButton";
|
|
8411
8439
|
}
|
|
8412
8440
|
});
|
|
@@ -20216,7 +20244,7 @@ function getComboScale(combo) {
|
|
|
20216
20244
|
return "";
|
|
20217
20245
|
}
|
|
20218
20246
|
function ComboCounter({
|
|
20219
|
-
assetUrl =
|
|
20247
|
+
assetUrl = DEFAULT_ASSET_URL3,
|
|
20220
20248
|
combo = 5,
|
|
20221
20249
|
multiplier,
|
|
20222
20250
|
streak,
|
|
@@ -20261,11 +20289,11 @@ function ComboCounter({
|
|
|
20261
20289
|
}
|
|
20262
20290
|
);
|
|
20263
20291
|
}
|
|
20264
|
-
var
|
|
20292
|
+
var DEFAULT_ASSET_URL3, sizeMap4;
|
|
20265
20293
|
var init_ComboCounter = __esm({
|
|
20266
20294
|
"components/game/atoms/ComboCounter.tsx"() {
|
|
20267
20295
|
init_cn();
|
|
20268
|
-
|
|
20296
|
+
DEFAULT_ASSET_URL3 = "https://almadar-kflow-assets.web.app/shared/effects/flash/flash00.png";
|
|
20269
20297
|
sizeMap4 = {
|
|
20270
20298
|
sm: { combo: "text-lg", label: "text-xs", multiplier: "text-xs" },
|
|
20271
20299
|
md: { combo: "text-2xl", label: "text-xs", multiplier: "text-sm" },
|
|
@@ -20674,7 +20702,7 @@ var init_CounterTemplate = __esm({
|
|
|
20674
20702
|
}
|
|
20675
20703
|
});
|
|
20676
20704
|
function ItemSlot({
|
|
20677
|
-
assetUrl =
|
|
20705
|
+
assetUrl = DEFAULT_ASSET_URL4,
|
|
20678
20706
|
icon = "sword",
|
|
20679
20707
|
label = "Iron Sword",
|
|
20680
20708
|
quantity,
|
|
@@ -20733,7 +20761,7 @@ function ItemSlot({
|
|
|
20733
20761
|
}
|
|
20734
20762
|
);
|
|
20735
20763
|
}
|
|
20736
|
-
var sizeMap5, rarityBorderMap, rarityGlowMap,
|
|
20764
|
+
var sizeMap5, rarityBorderMap, rarityGlowMap, DEFAULT_ASSET_URL4, assetSizeMap;
|
|
20737
20765
|
var init_ItemSlot = __esm({
|
|
20738
20766
|
"components/game/atoms/ItemSlot.tsx"() {
|
|
20739
20767
|
"use client";
|
|
@@ -20758,7 +20786,7 @@ var init_ItemSlot = __esm({
|
|
|
20758
20786
|
epic: "shadow-lg",
|
|
20759
20787
|
legendary: "shadow-lg"
|
|
20760
20788
|
};
|
|
20761
|
-
|
|
20789
|
+
DEFAULT_ASSET_URL4 = "https://almadar-kflow-assets.web.app/shared/isometric-dungeon/Isometric/chestClosed_E.png";
|
|
20762
20790
|
assetSizeMap = {
|
|
20763
20791
|
sm: 28,
|
|
20764
20792
|
md: 40,
|
|
@@ -20937,6 +20965,7 @@ var init_DPad = __esm({
|
|
|
20937
20965
|
}
|
|
20938
20966
|
});
|
|
20939
20967
|
function DamageNumber({
|
|
20968
|
+
assetUrl = DEFAULT_ASSET_URL5,
|
|
20940
20969
|
value = 42,
|
|
20941
20970
|
type = "damage",
|
|
20942
20971
|
size = "md",
|
|
@@ -20945,22 +20974,35 @@ function DamageNumber({
|
|
|
20945
20974
|
const displayText = type === "miss" ? "MISS" : type === "heal" ? `+${value}` : `${value}`;
|
|
20946
20975
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
20947
20976
|
/* @__PURE__ */ jsxRuntime.jsx("style", { children: floatKeyframes }),
|
|
20948
|
-
/* @__PURE__ */ jsxRuntime.
|
|
20977
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
20949
20978
|
"span",
|
|
20950
20979
|
{
|
|
20951
20980
|
className: cn(
|
|
20952
|
-
"inline-
|
|
20981
|
+
"inline-flex items-center gap-0.5 font-mono select-none pointer-events-none",
|
|
20953
20982
|
sizeMap7[size],
|
|
20954
20983
|
typeStyles[type],
|
|
20955
20984
|
className
|
|
20956
20985
|
),
|
|
20957
20986
|
style: { animation: "damageFloat 1s ease-out forwards" },
|
|
20958
|
-
children:
|
|
20987
|
+
children: [
|
|
20988
|
+
assetUrl && /* @__PURE__ */ jsxRuntime.jsx(
|
|
20989
|
+
"img",
|
|
20990
|
+
{
|
|
20991
|
+
src: assetUrl,
|
|
20992
|
+
alt: "",
|
|
20993
|
+
width: 14,
|
|
20994
|
+
height: 14,
|
|
20995
|
+
style: { imageRendering: "pixelated", objectFit: "contain" },
|
|
20996
|
+
className: "flex-shrink-0"
|
|
20997
|
+
}
|
|
20998
|
+
),
|
|
20999
|
+
displayText
|
|
21000
|
+
]
|
|
20959
21001
|
}
|
|
20960
21002
|
)
|
|
20961
21003
|
] });
|
|
20962
21004
|
}
|
|
20963
|
-
var sizeMap7, typeStyles, floatKeyframes;
|
|
21005
|
+
var sizeMap7, typeStyles, floatKeyframes, DEFAULT_ASSET_URL5;
|
|
20964
21006
|
var init_DamageNumber = __esm({
|
|
20965
21007
|
"components/game/atoms/DamageNumber.tsx"() {
|
|
20966
21008
|
init_cn();
|
|
@@ -20982,6 +21024,7 @@ var init_DamageNumber = __esm({
|
|
|
20982
21024
|
100% { opacity: 0; transform: translateY(-32px) scale(0.8); }
|
|
20983
21025
|
}
|
|
20984
21026
|
`;
|
|
21027
|
+
DEFAULT_ASSET_URL5 = "https://almadar-kflow-assets.web.app/shared/effects/particles/spark_01.png";
|
|
20985
21028
|
DamageNumber.displayName = "DamageNumber";
|
|
20986
21029
|
}
|
|
20987
21030
|
});
|
|
@@ -24802,7 +24845,7 @@ var init_Flex = __esm({
|
|
|
24802
24845
|
basis,
|
|
24803
24846
|
className,
|
|
24804
24847
|
children,
|
|
24805
|
-
as:
|
|
24848
|
+
as: Component2 = "div"
|
|
24806
24849
|
}) => {
|
|
24807
24850
|
const flexStyle = {};
|
|
24808
24851
|
if (grow !== void 0 || shrink !== void 0 || basis !== void 0) {
|
|
@@ -24814,7 +24857,7 @@ var init_Flex = __esm({
|
|
|
24814
24857
|
flexStyle.flexBasis = typeof basis === "number" ? `${basis}px` : basis;
|
|
24815
24858
|
}
|
|
24816
24859
|
}
|
|
24817
|
-
const Comp =
|
|
24860
|
+
const Comp = Component2;
|
|
24818
24861
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
24819
24862
|
Comp,
|
|
24820
24863
|
{
|
|
@@ -24934,11 +24977,11 @@ var init_Grid = __esm({
|
|
|
24934
24977
|
className,
|
|
24935
24978
|
style,
|
|
24936
24979
|
children,
|
|
24937
|
-
as:
|
|
24980
|
+
as: Component2 = "div"
|
|
24938
24981
|
}) => {
|
|
24939
24982
|
const mergedStyle = rows2 ? { gridTemplateRows: `repeat(${rows2}, minmax(0, 1fr))`, ...style } : style;
|
|
24940
24983
|
return React77__namespace.default.createElement(
|
|
24941
|
-
|
|
24984
|
+
Component2,
|
|
24942
24985
|
{
|
|
24943
24986
|
className: cn(
|
|
24944
24987
|
"grid",
|
|
@@ -27087,6 +27130,7 @@ var init_HealthBar = __esm({
|
|
|
27087
27130
|
}
|
|
27088
27131
|
});
|
|
27089
27132
|
function ScoreDisplay({
|
|
27133
|
+
assetUrl = DEFAULT_ASSET_URL6,
|
|
27090
27134
|
value,
|
|
27091
27135
|
label,
|
|
27092
27136
|
icon,
|
|
@@ -27133,14 +27177,24 @@ function ScoreDisplay({
|
|
|
27133
27177
|
className
|
|
27134
27178
|
),
|
|
27135
27179
|
children: [
|
|
27136
|
-
|
|
27180
|
+
assetUrl ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
27181
|
+
"img",
|
|
27182
|
+
{
|
|
27183
|
+
src: assetUrl,
|
|
27184
|
+
alt: "",
|
|
27185
|
+
width: 20,
|
|
27186
|
+
height: 20,
|
|
27187
|
+
style: { imageRendering: "pixelated", objectFit: "contain" },
|
|
27188
|
+
className: "flex-shrink-0"
|
|
27189
|
+
}
|
|
27190
|
+
) : icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-shrink-0", children: typeof icon === "string" ? /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { name: icon }) : /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { icon }) }) : null,
|
|
27137
27191
|
label && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: label }),
|
|
27138
27192
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "tabular-nums", children: formattedValue })
|
|
27139
27193
|
]
|
|
27140
27194
|
}
|
|
27141
27195
|
);
|
|
27142
27196
|
}
|
|
27143
|
-
var sizeMap10;
|
|
27197
|
+
var sizeMap10, DEFAULT_ASSET_URL6;
|
|
27144
27198
|
var init_ScoreDisplay = __esm({
|
|
27145
27199
|
"components/game/atoms/ScoreDisplay.tsx"() {
|
|
27146
27200
|
"use client";
|
|
@@ -27152,10 +27206,12 @@ var init_ScoreDisplay = __esm({
|
|
|
27152
27206
|
lg: "text-2xl",
|
|
27153
27207
|
xl: "text-4xl"
|
|
27154
27208
|
};
|
|
27209
|
+
DEFAULT_ASSET_URL6 = "https://almadar-kflow-assets.web.app/shared/effects/particles/star_01.png";
|
|
27155
27210
|
ScoreDisplay.displayName = "ScoreDisplay";
|
|
27156
27211
|
}
|
|
27157
27212
|
});
|
|
27158
27213
|
function StatBadge({
|
|
27214
|
+
assetUrl = DEFAULT_ASSET_URL7,
|
|
27159
27215
|
label,
|
|
27160
27216
|
value = 0,
|
|
27161
27217
|
max,
|
|
@@ -27179,7 +27235,17 @@ function StatBadge({
|
|
|
27179
27235
|
className
|
|
27180
27236
|
),
|
|
27181
27237
|
children: [
|
|
27182
|
-
|
|
27238
|
+
assetUrl ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
27239
|
+
"img",
|
|
27240
|
+
{
|
|
27241
|
+
src: assetUrl,
|
|
27242
|
+
alt: "",
|
|
27243
|
+
width: 16,
|
|
27244
|
+
height: 16,
|
|
27245
|
+
style: { imageRendering: "pixelated", objectFit: "contain" },
|
|
27246
|
+
className: "flex-shrink-0"
|
|
27247
|
+
}
|
|
27248
|
+
) : icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-shrink-0 text-lg", children: typeof icon === "string" ? /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { name: icon, className: "w-4 h-4" }) : /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { icon, className: "w-4 h-4" }) }) : null,
|
|
27183
27249
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground font-medium", children: label }),
|
|
27184
27250
|
format === "hearts" && max && /* @__PURE__ */ jsxRuntime.jsx(
|
|
27185
27251
|
HealthBar,
|
|
@@ -27212,7 +27278,7 @@ function StatBadge({
|
|
|
27212
27278
|
}
|
|
27213
27279
|
);
|
|
27214
27280
|
}
|
|
27215
|
-
var sizeMap11, variantMap2;
|
|
27281
|
+
var sizeMap11, variantMap2, DEFAULT_ASSET_URL7;
|
|
27216
27282
|
var init_StatBadge = __esm({
|
|
27217
27283
|
"components/game/molecules/StatBadge.tsx"() {
|
|
27218
27284
|
init_cn();
|
|
@@ -27231,6 +27297,7 @@ var init_StatBadge = __esm({
|
|
|
27231
27297
|
warning: "bg-warning/15 border-warning/40 text-foreground",
|
|
27232
27298
|
danger: "bg-error/15 border-error/40 text-foreground"
|
|
27233
27299
|
};
|
|
27300
|
+
DEFAULT_ASSET_URL7 = "https://almadar-kflow-assets.web.app/shared/effects/particles/light_01.png";
|
|
27234
27301
|
StatBadge.displayName = "StatBadge";
|
|
27235
27302
|
}
|
|
27236
27303
|
});
|
|
@@ -27314,7 +27381,7 @@ var init_InventoryGrid = __esm({
|
|
|
27314
27381
|
}
|
|
27315
27382
|
});
|
|
27316
27383
|
function WaypointMarker({
|
|
27317
|
-
assetUrl =
|
|
27384
|
+
assetUrl = DEFAULT_ASSET_URL8,
|
|
27318
27385
|
label,
|
|
27319
27386
|
icon,
|
|
27320
27387
|
active = true,
|
|
@@ -27380,12 +27447,12 @@ function WaypointMarker({
|
|
|
27380
27447
|
)
|
|
27381
27448
|
] });
|
|
27382
27449
|
}
|
|
27383
|
-
var
|
|
27450
|
+
var DEFAULT_ASSET_URL8, sizeMap12, checkIcon;
|
|
27384
27451
|
var init_WaypointMarker = __esm({
|
|
27385
27452
|
"components/game/atoms/WaypointMarker.tsx"() {
|
|
27386
27453
|
init_cn();
|
|
27387
27454
|
init_Icon();
|
|
27388
|
-
|
|
27455
|
+
DEFAULT_ASSET_URL8 = "https://almadar-kflow-assets.web.app/shared/world-map/battle_marker.png";
|
|
27389
27456
|
sizeMap12 = {
|
|
27390
27457
|
sm: { dot: "w-4 h-4", ring: "w-6 h-6", label: "text-xs mt-1", img: 12 },
|
|
27391
27458
|
md: { dot: "w-6 h-6", ring: "w-8 h-8", label: "text-sm mt-1.5", img: 18 },
|
|
@@ -27903,6 +27970,7 @@ var init_ResourceBar = __esm({
|
|
|
27903
27970
|
}
|
|
27904
27971
|
});
|
|
27905
27972
|
function TurnIndicator({
|
|
27973
|
+
assetUrl = DEFAULT_ASSET_URL9,
|
|
27906
27974
|
currentTurn = 1,
|
|
27907
27975
|
maxTurns,
|
|
27908
27976
|
activeTeam,
|
|
@@ -27935,14 +28003,24 @@ function TurnIndicator({
|
|
|
27935
28003
|
] }),
|
|
27936
28004
|
activeTeam && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
27937
28005
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "|" }),
|
|
27938
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
28006
|
+
assetUrl ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
28007
|
+
"img",
|
|
28008
|
+
{
|
|
28009
|
+
src: assetUrl,
|
|
28010
|
+
alt: "",
|
|
28011
|
+
width: 12,
|
|
28012
|
+
height: 12,
|
|
28013
|
+
style: { imageRendering: "pixelated", objectFit: "contain" },
|
|
28014
|
+
className: "flex-shrink-0"
|
|
28015
|
+
}
|
|
28016
|
+
) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("rounded-full bg-success/20", sizes.dot) }),
|
|
27939
28017
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-success", children: activeTeam })
|
|
27940
28018
|
] })
|
|
27941
28019
|
]
|
|
27942
28020
|
}
|
|
27943
28021
|
);
|
|
27944
28022
|
}
|
|
27945
|
-
var sizeMap14;
|
|
28023
|
+
var sizeMap14, DEFAULT_ASSET_URL9;
|
|
27946
28024
|
var init_TurnIndicator = __esm({
|
|
27947
28025
|
"components/game/atoms/TurnIndicator.tsx"() {
|
|
27948
28026
|
init_cn();
|
|
@@ -27951,6 +28029,7 @@ var init_TurnIndicator = __esm({
|
|
|
27951
28029
|
md: { wrapper: "text-sm gap-2 px-3 py-1", dot: "w-2 h-2" },
|
|
27952
28030
|
lg: { wrapper: "text-base gap-2.5 px-4 py-1.5", dot: "w-2.5 h-2.5" }
|
|
27953
28031
|
};
|
|
28032
|
+
DEFAULT_ASSET_URL9 = "https://almadar-kflow-assets.web.app/shared/effects/particles/symbol_01.png";
|
|
27954
28033
|
TurnIndicator.displayName = "TurnIndicator";
|
|
27955
28034
|
}
|
|
27956
28035
|
});
|
|
@@ -28021,6 +28100,7 @@ var init_TurnPanel = __esm({
|
|
|
28021
28100
|
}
|
|
28022
28101
|
});
|
|
28023
28102
|
function EnemyPlate({
|
|
28103
|
+
assetUrl = DEFAULT_ASSET_URL10,
|
|
28024
28104
|
name = "Shadow Guard",
|
|
28025
28105
|
health = 80,
|
|
28026
28106
|
maxHealth = 100,
|
|
@@ -28038,15 +28118,28 @@ function EnemyPlate({
|
|
|
28038
28118
|
),
|
|
28039
28119
|
children: [
|
|
28040
28120
|
/* @__PURE__ */ jsxRuntime.jsxs(exports.Box, { className: "flex items-center justify-between gap-2", children: [
|
|
28041
|
-
/* @__PURE__ */ jsxRuntime.
|
|
28042
|
-
|
|
28043
|
-
|
|
28044
|
-
|
|
28045
|
-
|
|
28046
|
-
|
|
28047
|
-
|
|
28048
|
-
|
|
28049
|
-
|
|
28121
|
+
/* @__PURE__ */ jsxRuntime.jsxs(exports.Box, { className: "flex items-center gap-1.5 min-w-0", children: [
|
|
28122
|
+
assetUrl && /* @__PURE__ */ jsxRuntime.jsx(
|
|
28123
|
+
"img",
|
|
28124
|
+
{
|
|
28125
|
+
src: assetUrl,
|
|
28126
|
+
alt: name,
|
|
28127
|
+
width: 24,
|
|
28128
|
+
height: 24,
|
|
28129
|
+
style: { objectFit: "cover", borderRadius: "50%" },
|
|
28130
|
+
className: "flex-shrink-0"
|
|
28131
|
+
}
|
|
28132
|
+
),
|
|
28133
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
28134
|
+
exports.Typography,
|
|
28135
|
+
{
|
|
28136
|
+
variant: "caption",
|
|
28137
|
+
weight: "bold",
|
|
28138
|
+
className: "text-[var(--color-foreground)] truncate",
|
|
28139
|
+
children: name
|
|
28140
|
+
}
|
|
28141
|
+
)
|
|
28142
|
+
] }),
|
|
28050
28143
|
level != null && /* @__PURE__ */ jsxRuntime.jsxs(exports.Badge, { variant: "neutral", size: "sm", children: [
|
|
28051
28144
|
"Lv.",
|
|
28052
28145
|
level
|
|
@@ -28091,7 +28184,7 @@ function EnemyPlate({
|
|
|
28091
28184
|
}
|
|
28092
28185
|
);
|
|
28093
28186
|
}
|
|
28094
|
-
var effectVariantMap2, DEFAULT_ENEMY_EFFECTS;
|
|
28187
|
+
var effectVariantMap2, DEFAULT_ENEMY_EFFECTS, DEFAULT_ASSET_URL10;
|
|
28095
28188
|
var init_EnemyPlate = __esm({
|
|
28096
28189
|
"components/game/molecules/EnemyPlate.tsx"() {
|
|
28097
28190
|
"use client";
|
|
@@ -28108,6 +28201,7 @@ var init_EnemyPlate = __esm({
|
|
|
28108
28201
|
DEFAULT_ENEMY_EFFECTS = [
|
|
28109
28202
|
{ icon: "flame", label: "Burn", variant: "debuff" }
|
|
28110
28203
|
];
|
|
28204
|
+
DEFAULT_ASSET_URL10 = "https://almadar-kflow-assets.web.app/shared/portraits/shadow-legion.png";
|
|
28111
28205
|
EnemyPlate.displayName = "EnemyPlate";
|
|
28112
28206
|
}
|
|
28113
28207
|
});
|
|
@@ -29661,13 +29755,13 @@ var init_MapView = __esm({
|
|
|
29661
29755
|
shadowSize: [41, 41]
|
|
29662
29756
|
});
|
|
29663
29757
|
L.Marker.prototype.options.icon = defaultIcon;
|
|
29664
|
-
const { useEffect:
|
|
29758
|
+
const { useEffect: useEffect80, useRef: useRef77, useCallback: useCallback120, useState: useState110 } = React77__namespace.default;
|
|
29665
29759
|
const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
|
|
29666
|
-
const { useEventBus:
|
|
29760
|
+
const { useEventBus: useEventBus3 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
|
|
29667
29761
|
function MapUpdater({ centerLat, centerLng, zoom }) {
|
|
29668
29762
|
const map = useMap();
|
|
29669
|
-
const prevRef =
|
|
29670
|
-
|
|
29763
|
+
const prevRef = useRef77({ centerLat, centerLng, zoom });
|
|
29764
|
+
useEffect80(() => {
|
|
29671
29765
|
const prev = prevRef.current;
|
|
29672
29766
|
if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
|
|
29673
29767
|
map.setView([centerLat, centerLng], zoom);
|
|
@@ -29678,7 +29772,7 @@ var init_MapView = __esm({
|
|
|
29678
29772
|
}
|
|
29679
29773
|
function MapClickHandler({ onMapClick }) {
|
|
29680
29774
|
const map = useMap();
|
|
29681
|
-
|
|
29775
|
+
useEffect80(() => {
|
|
29682
29776
|
if (!onMapClick) return;
|
|
29683
29777
|
const handler = (e) => {
|
|
29684
29778
|
onMapClick(e.latlng.lat, e.latlng.lng);
|
|
@@ -29705,9 +29799,9 @@ var init_MapView = __esm({
|
|
|
29705
29799
|
className,
|
|
29706
29800
|
showAttribution = true
|
|
29707
29801
|
}) {
|
|
29708
|
-
const eventBus =
|
|
29709
|
-
const [clickedPosition, setClickedPosition] =
|
|
29710
|
-
const handleMapClick =
|
|
29802
|
+
const eventBus = useEventBus3();
|
|
29803
|
+
const [clickedPosition, setClickedPosition] = useState110(null);
|
|
29804
|
+
const handleMapClick = useCallback120((lat, lng) => {
|
|
29711
29805
|
if (showClickedPin) {
|
|
29712
29806
|
setClickedPosition({ lat, lng });
|
|
29713
29807
|
}
|
|
@@ -29716,7 +29810,7 @@ var init_MapView = __esm({
|
|
|
29716
29810
|
eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
|
|
29717
29811
|
}
|
|
29718
29812
|
}, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
|
|
29719
|
-
const handleMarkerClick =
|
|
29813
|
+
const handleMarkerClick = useCallback120((marker) => {
|
|
29720
29814
|
onMarkerClick?.(marker);
|
|
29721
29815
|
if (markerClickEvent) {
|
|
29722
29816
|
eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
|
|
@@ -36843,10 +36937,10 @@ var init_Section = __esm({
|
|
|
36843
36937
|
children,
|
|
36844
36938
|
headerClassName,
|
|
36845
36939
|
contentClassName,
|
|
36846
|
-
as:
|
|
36940
|
+
as: Component2 = "section"
|
|
36847
36941
|
}) => {
|
|
36848
36942
|
const hasHeader = title || description || action;
|
|
36849
|
-
const Comp =
|
|
36943
|
+
const Comp = Component2;
|
|
36850
36944
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
36851
36945
|
Comp,
|
|
36852
36946
|
{
|
|
@@ -39847,7 +39941,7 @@ var init_DrawerSlot = __esm({
|
|
|
39847
39941
|
}
|
|
39848
39942
|
});
|
|
39849
39943
|
function StateIndicator({
|
|
39850
|
-
assetUrl =
|
|
39944
|
+
assetUrl = DEFAULT_ASSET_URL11,
|
|
39851
39945
|
state = "idle",
|
|
39852
39946
|
label,
|
|
39853
39947
|
size = "md",
|
|
@@ -39886,13 +39980,13 @@ function StateIndicator({
|
|
|
39886
39980
|
}
|
|
39887
39981
|
);
|
|
39888
39982
|
}
|
|
39889
|
-
var
|
|
39983
|
+
var DEFAULT_ASSET_URL11, DEFAULT_STATE_STYLES, DEFAULT_STYLE, SIZE_CLASSES;
|
|
39890
39984
|
var init_StateIndicator = __esm({
|
|
39891
39985
|
"components/game/atoms/StateIndicator.tsx"() {
|
|
39892
39986
|
init_Box();
|
|
39893
39987
|
init_Icon();
|
|
39894
39988
|
init_cn();
|
|
39895
|
-
|
|
39989
|
+
DEFAULT_ASSET_URL11 = "https://almadar-kflow-assets.web.app/shared/isometric-dungeon/Isometric/chestClosed_E.png";
|
|
39896
39990
|
DEFAULT_STATE_STYLES = {
|
|
39897
39991
|
idle: { icon: "\u23F8", bgClass: "bg-muted" },
|
|
39898
39992
|
active: { icon: "\u25B6", bgClass: "bg-success" },
|
|
@@ -41738,6 +41832,1568 @@ var init_GameAudioToggle = __esm({
|
|
|
41738
41832
|
GameAudioToggle.displayName = "GameAudioToggle";
|
|
41739
41833
|
}
|
|
41740
41834
|
});
|
|
41835
|
+
function detectAssetRoot(modelUrl) {
|
|
41836
|
+
const idx = modelUrl.indexOf("/3d/");
|
|
41837
|
+
if (idx !== -1) {
|
|
41838
|
+
return modelUrl.substring(0, idx + 4);
|
|
41839
|
+
}
|
|
41840
|
+
return modelUrl.substring(0, modelUrl.lastIndexOf("/") + 1);
|
|
41841
|
+
}
|
|
41842
|
+
function createGLTFLoaderForUrl(url) {
|
|
41843
|
+
const loader = new GLTFLoader_js.GLTFLoader();
|
|
41844
|
+
loader.setResourcePath(detectAssetRoot(url));
|
|
41845
|
+
return loader;
|
|
41846
|
+
}
|
|
41847
|
+
var AssetLoader;
|
|
41848
|
+
var init_AssetLoader = __esm({
|
|
41849
|
+
"components/game/molecules/three/loaders/AssetLoader.ts"() {
|
|
41850
|
+
AssetLoader = class {
|
|
41851
|
+
constructor() {
|
|
41852
|
+
__publicField(this, "objLoader");
|
|
41853
|
+
__publicField(this, "textureLoader");
|
|
41854
|
+
__publicField(this, "modelCache");
|
|
41855
|
+
__publicField(this, "textureCache");
|
|
41856
|
+
__publicField(this, "loadingPromises");
|
|
41857
|
+
this.objLoader = new OBJLoader_js.OBJLoader();
|
|
41858
|
+
this.textureLoader = new THREE__namespace.TextureLoader();
|
|
41859
|
+
this.modelCache = /* @__PURE__ */ new Map();
|
|
41860
|
+
this.textureCache = /* @__PURE__ */ new Map();
|
|
41861
|
+
this.loadingPromises = /* @__PURE__ */ new Map();
|
|
41862
|
+
}
|
|
41863
|
+
/**
|
|
41864
|
+
* Load a GLB/GLTF model
|
|
41865
|
+
* @param url - URL to the .glb or .gltf file
|
|
41866
|
+
* @returns Promise with loaded model scene and animations
|
|
41867
|
+
*/
|
|
41868
|
+
async loadModel(url) {
|
|
41869
|
+
if (this.modelCache.has(url)) {
|
|
41870
|
+
return this.modelCache.get(url);
|
|
41871
|
+
}
|
|
41872
|
+
if (this.loadingPromises.has(url)) {
|
|
41873
|
+
return this.loadingPromises.get(url);
|
|
41874
|
+
}
|
|
41875
|
+
const loader = createGLTFLoaderForUrl(url);
|
|
41876
|
+
const loadPromise = loader.loadAsync(url).then((gltf) => {
|
|
41877
|
+
const result = {
|
|
41878
|
+
scene: gltf.scene,
|
|
41879
|
+
animations: gltf.animations || []
|
|
41880
|
+
};
|
|
41881
|
+
this.modelCache.set(url, result);
|
|
41882
|
+
this.loadingPromises.delete(url);
|
|
41883
|
+
return result;
|
|
41884
|
+
}).catch((error) => {
|
|
41885
|
+
this.loadingPromises.delete(url);
|
|
41886
|
+
throw new Error(`Failed to load model ${url}: ${error.message}`);
|
|
41887
|
+
});
|
|
41888
|
+
this.loadingPromises.set(url, loadPromise);
|
|
41889
|
+
return loadPromise;
|
|
41890
|
+
}
|
|
41891
|
+
/**
|
|
41892
|
+
* Load an OBJ model (fallback for non-GLB assets)
|
|
41893
|
+
* @param url - URL to the .obj file
|
|
41894
|
+
* @returns Promise with loaded object group
|
|
41895
|
+
*/
|
|
41896
|
+
async loadOBJ(url) {
|
|
41897
|
+
if (this.modelCache.has(url)) {
|
|
41898
|
+
return this.modelCache.get(url).scene;
|
|
41899
|
+
}
|
|
41900
|
+
if (this.loadingPromises.has(url)) {
|
|
41901
|
+
const result = await this.loadingPromises.get(url);
|
|
41902
|
+
return result.scene;
|
|
41903
|
+
}
|
|
41904
|
+
const loadPromise = this.objLoader.loadAsync(url).then((group) => {
|
|
41905
|
+
const result = {
|
|
41906
|
+
scene: group,
|
|
41907
|
+
animations: []
|
|
41908
|
+
};
|
|
41909
|
+
this.modelCache.set(url, result);
|
|
41910
|
+
this.loadingPromises.delete(url);
|
|
41911
|
+
return result;
|
|
41912
|
+
}).catch((error) => {
|
|
41913
|
+
this.loadingPromises.delete(url);
|
|
41914
|
+
throw new Error(`Failed to load OBJ ${url}: ${error.message}`);
|
|
41915
|
+
});
|
|
41916
|
+
this.loadingPromises.set(url, loadPromise);
|
|
41917
|
+
return (await loadPromise).scene;
|
|
41918
|
+
}
|
|
41919
|
+
/**
|
|
41920
|
+
* Load a texture
|
|
41921
|
+
* @param url - URL to the texture image
|
|
41922
|
+
* @returns Promise with loaded texture
|
|
41923
|
+
*/
|
|
41924
|
+
async loadTexture(url) {
|
|
41925
|
+
if (this.textureCache.has(url)) {
|
|
41926
|
+
return this.textureCache.get(url);
|
|
41927
|
+
}
|
|
41928
|
+
if (this.loadingPromises.has(`texture:${url}`)) {
|
|
41929
|
+
return this.loadingPromises.get(`texture:${url}`);
|
|
41930
|
+
}
|
|
41931
|
+
const loadPromise = this.textureLoader.loadAsync(url).then((texture) => {
|
|
41932
|
+
texture.colorSpace = THREE__namespace.SRGBColorSpace;
|
|
41933
|
+
this.textureCache.set(url, texture);
|
|
41934
|
+
this.loadingPromises.delete(`texture:${url}`);
|
|
41935
|
+
return texture;
|
|
41936
|
+
}).catch((error) => {
|
|
41937
|
+
this.loadingPromises.delete(`texture:${url}`);
|
|
41938
|
+
throw new Error(`Failed to load texture ${url}: ${error.message}`);
|
|
41939
|
+
});
|
|
41940
|
+
this.loadingPromises.set(`texture:${url}`, loadPromise);
|
|
41941
|
+
return loadPromise;
|
|
41942
|
+
}
|
|
41943
|
+
/**
|
|
41944
|
+
* Preload multiple assets
|
|
41945
|
+
* @param urls - Array of asset URLs to preload
|
|
41946
|
+
* @returns Promise that resolves when all assets are loaded
|
|
41947
|
+
*/
|
|
41948
|
+
async preload(urls) {
|
|
41949
|
+
const promises = urls.map((url) => {
|
|
41950
|
+
if (url.endsWith(".glb") || url.endsWith(".gltf")) {
|
|
41951
|
+
return this.loadModel(url).catch(() => null);
|
|
41952
|
+
} else if (url.endsWith(".obj")) {
|
|
41953
|
+
return this.loadOBJ(url).catch(() => null);
|
|
41954
|
+
} else if (/\.(png|jpg|jpeg|webp)$/i.test(url)) {
|
|
41955
|
+
return this.loadTexture(url).catch(() => null);
|
|
41956
|
+
}
|
|
41957
|
+
return Promise.resolve(null);
|
|
41958
|
+
});
|
|
41959
|
+
await Promise.all(promises);
|
|
41960
|
+
}
|
|
41961
|
+
/**
|
|
41962
|
+
* Check if a model is cached
|
|
41963
|
+
* @param url - Model URL
|
|
41964
|
+
*/
|
|
41965
|
+
hasModel(url) {
|
|
41966
|
+
return this.modelCache.has(url);
|
|
41967
|
+
}
|
|
41968
|
+
/**
|
|
41969
|
+
* Check if a texture is cached
|
|
41970
|
+
* @param url - Texture URL
|
|
41971
|
+
*/
|
|
41972
|
+
hasTexture(url) {
|
|
41973
|
+
return this.textureCache.has(url);
|
|
41974
|
+
}
|
|
41975
|
+
/**
|
|
41976
|
+
* Get cached model (throws if not cached)
|
|
41977
|
+
* @param url - Model URL
|
|
41978
|
+
*/
|
|
41979
|
+
getModel(url) {
|
|
41980
|
+
const model = this.modelCache.get(url);
|
|
41981
|
+
if (!model) {
|
|
41982
|
+
throw new Error(`Model ${url} not in cache`);
|
|
41983
|
+
}
|
|
41984
|
+
return model;
|
|
41985
|
+
}
|
|
41986
|
+
/**
|
|
41987
|
+
* Get cached texture (throws if not cached)
|
|
41988
|
+
* @param url - Texture URL
|
|
41989
|
+
*/
|
|
41990
|
+
getTexture(url) {
|
|
41991
|
+
const texture = this.textureCache.get(url);
|
|
41992
|
+
if (!texture) {
|
|
41993
|
+
throw new Error(`Texture ${url} not in cache`);
|
|
41994
|
+
}
|
|
41995
|
+
return texture;
|
|
41996
|
+
}
|
|
41997
|
+
/**
|
|
41998
|
+
* Clear all caches
|
|
41999
|
+
*/
|
|
42000
|
+
clearCache() {
|
|
42001
|
+
this.textureCache.forEach((texture) => {
|
|
42002
|
+
texture.dispose();
|
|
42003
|
+
});
|
|
42004
|
+
this.modelCache.forEach((model) => {
|
|
42005
|
+
model.scene.traverse((child) => {
|
|
42006
|
+
if (child instanceof THREE__namespace.Mesh) {
|
|
42007
|
+
child.geometry.dispose();
|
|
42008
|
+
if (Array.isArray(child.material)) {
|
|
42009
|
+
child.material.forEach((m) => m.dispose());
|
|
42010
|
+
} else {
|
|
42011
|
+
child.material.dispose();
|
|
42012
|
+
}
|
|
42013
|
+
}
|
|
42014
|
+
});
|
|
42015
|
+
});
|
|
42016
|
+
this.modelCache.clear();
|
|
42017
|
+
this.textureCache.clear();
|
|
42018
|
+
this.loadingPromises.clear();
|
|
42019
|
+
}
|
|
42020
|
+
/**
|
|
42021
|
+
* Get cache statistics
|
|
42022
|
+
*/
|
|
42023
|
+
getStats() {
|
|
42024
|
+
return {
|
|
42025
|
+
models: this.modelCache.size,
|
|
42026
|
+
textures: this.textureCache.size,
|
|
42027
|
+
loading: this.loadingPromises.size
|
|
42028
|
+
};
|
|
42029
|
+
}
|
|
42030
|
+
};
|
|
42031
|
+
new AssetLoader();
|
|
42032
|
+
}
|
|
42033
|
+
});
|
|
42034
|
+
function useAssetLoader(options = {}) {
|
|
42035
|
+
const { preloadUrls = [], loader: customLoader } = options;
|
|
42036
|
+
const loaderRef = React77.useRef(customLoader || new AssetLoader());
|
|
42037
|
+
const [state, setState] = React77.useState({
|
|
42038
|
+
isLoading: false,
|
|
42039
|
+
progress: 0,
|
|
42040
|
+
loaded: 0,
|
|
42041
|
+
total: 0,
|
|
42042
|
+
errors: []
|
|
42043
|
+
});
|
|
42044
|
+
React77.useEffect(() => {
|
|
42045
|
+
if (preloadUrls.length > 0) {
|
|
42046
|
+
preload(preloadUrls);
|
|
42047
|
+
}
|
|
42048
|
+
}, []);
|
|
42049
|
+
const updateProgress = React77.useCallback((loaded, total) => {
|
|
42050
|
+
setState((prev) => ({
|
|
42051
|
+
...prev,
|
|
42052
|
+
loaded,
|
|
42053
|
+
total,
|
|
42054
|
+
progress: total > 0 ? Math.round(loaded / total * 100) : 0
|
|
42055
|
+
}));
|
|
42056
|
+
}, []);
|
|
42057
|
+
const loadModel = React77.useCallback(
|
|
42058
|
+
async (url) => {
|
|
42059
|
+
setState((prev) => ({ ...prev, isLoading: true }));
|
|
42060
|
+
try {
|
|
42061
|
+
const model = await loaderRef.current.loadModel(url);
|
|
42062
|
+
setState((prev) => ({
|
|
42063
|
+
...prev,
|
|
42064
|
+
isLoading: false,
|
|
42065
|
+
loaded: prev.loaded + 1
|
|
42066
|
+
}));
|
|
42067
|
+
return model;
|
|
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 loadOBJ = React77.useCallback(
|
|
42081
|
+
async (url) => {
|
|
42082
|
+
setState((prev) => ({ ...prev, isLoading: true }));
|
|
42083
|
+
try {
|
|
42084
|
+
const model = await loaderRef.current.loadOBJ(url);
|
|
42085
|
+
setState((prev) => ({
|
|
42086
|
+
...prev,
|
|
42087
|
+
isLoading: false,
|
|
42088
|
+
loaded: prev.loaded + 1
|
|
42089
|
+
}));
|
|
42090
|
+
return model;
|
|
42091
|
+
} catch (error) {
|
|
42092
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
42093
|
+
setState((prev) => ({
|
|
42094
|
+
...prev,
|
|
42095
|
+
isLoading: false,
|
|
42096
|
+
errors: [...prev.errors, errorMsg]
|
|
42097
|
+
}));
|
|
42098
|
+
throw error;
|
|
42099
|
+
}
|
|
42100
|
+
},
|
|
42101
|
+
[]
|
|
42102
|
+
);
|
|
42103
|
+
const loadTexture = React77.useCallback(
|
|
42104
|
+
async (url) => {
|
|
42105
|
+
setState((prev) => ({ ...prev, isLoading: true }));
|
|
42106
|
+
try {
|
|
42107
|
+
const texture = await loaderRef.current.loadTexture(url);
|
|
42108
|
+
setState((prev) => ({
|
|
42109
|
+
...prev,
|
|
42110
|
+
isLoading: false,
|
|
42111
|
+
loaded: prev.loaded + 1
|
|
42112
|
+
}));
|
|
42113
|
+
return texture;
|
|
42114
|
+
} catch (error) {
|
|
42115
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
42116
|
+
setState((prev) => ({
|
|
42117
|
+
...prev,
|
|
42118
|
+
isLoading: false,
|
|
42119
|
+
errors: [...prev.errors, errorMsg]
|
|
42120
|
+
}));
|
|
42121
|
+
throw error;
|
|
42122
|
+
}
|
|
42123
|
+
},
|
|
42124
|
+
[]
|
|
42125
|
+
);
|
|
42126
|
+
const preload = React77.useCallback(
|
|
42127
|
+
async (urls) => {
|
|
42128
|
+
setState((prev) => ({
|
|
42129
|
+
...prev,
|
|
42130
|
+
isLoading: true,
|
|
42131
|
+
total: urls.length,
|
|
42132
|
+
loaded: 0,
|
|
42133
|
+
errors: []
|
|
42134
|
+
}));
|
|
42135
|
+
let completed = 0;
|
|
42136
|
+
const errors = [];
|
|
42137
|
+
await Promise.all(
|
|
42138
|
+
urls.map(async (url) => {
|
|
42139
|
+
try {
|
|
42140
|
+
if (url.endsWith(".glb") || url.endsWith(".gltf")) {
|
|
42141
|
+
await loaderRef.current.loadModel(url);
|
|
42142
|
+
} else if (url.endsWith(".obj")) {
|
|
42143
|
+
await loaderRef.current.loadOBJ(url);
|
|
42144
|
+
} else if (/\.(png|jpg|jpeg|webp)$/i.test(url)) {
|
|
42145
|
+
await loaderRef.current.loadTexture(url);
|
|
42146
|
+
}
|
|
42147
|
+
completed++;
|
|
42148
|
+
updateProgress(completed, urls.length);
|
|
42149
|
+
} catch (error) {
|
|
42150
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
42151
|
+
errors.push(`${url}: ${errorMsg}`);
|
|
42152
|
+
completed++;
|
|
42153
|
+
updateProgress(completed, urls.length);
|
|
42154
|
+
}
|
|
42155
|
+
})
|
|
42156
|
+
);
|
|
42157
|
+
setState((prev) => ({
|
|
42158
|
+
...prev,
|
|
42159
|
+
isLoading: false,
|
|
42160
|
+
errors
|
|
42161
|
+
}));
|
|
42162
|
+
},
|
|
42163
|
+
[updateProgress]
|
|
42164
|
+
);
|
|
42165
|
+
const hasModel = React77.useCallback((url) => {
|
|
42166
|
+
return loaderRef.current.hasModel(url);
|
|
42167
|
+
}, []);
|
|
42168
|
+
const hasTexture = React77.useCallback((url) => {
|
|
42169
|
+
return loaderRef.current.hasTexture(url);
|
|
42170
|
+
}, []);
|
|
42171
|
+
const getModel = React77.useCallback((url) => {
|
|
42172
|
+
try {
|
|
42173
|
+
return loaderRef.current.getModel(url);
|
|
42174
|
+
} catch {
|
|
42175
|
+
return void 0;
|
|
42176
|
+
}
|
|
42177
|
+
}, []);
|
|
42178
|
+
const getTexture = React77.useCallback((url) => {
|
|
42179
|
+
try {
|
|
42180
|
+
return loaderRef.current.getTexture(url);
|
|
42181
|
+
} catch {
|
|
42182
|
+
return void 0;
|
|
42183
|
+
}
|
|
42184
|
+
}, []);
|
|
42185
|
+
const clearCache = React77.useCallback(() => {
|
|
42186
|
+
loaderRef.current.clearCache();
|
|
42187
|
+
setState({
|
|
42188
|
+
isLoading: false,
|
|
42189
|
+
progress: 0,
|
|
42190
|
+
loaded: 0,
|
|
42191
|
+
total: 0,
|
|
42192
|
+
errors: []
|
|
42193
|
+
});
|
|
42194
|
+
}, []);
|
|
42195
|
+
return {
|
|
42196
|
+
...state,
|
|
42197
|
+
loadModel,
|
|
42198
|
+
loadOBJ,
|
|
42199
|
+
loadTexture,
|
|
42200
|
+
preload,
|
|
42201
|
+
hasModel,
|
|
42202
|
+
hasTexture,
|
|
42203
|
+
getModel,
|
|
42204
|
+
getTexture,
|
|
42205
|
+
clearCache
|
|
42206
|
+
};
|
|
42207
|
+
}
|
|
42208
|
+
var init_useAssetLoader = __esm({
|
|
42209
|
+
"components/game/molecules/three/hooks/useAssetLoader.ts"() {
|
|
42210
|
+
"use client";
|
|
42211
|
+
init_AssetLoader();
|
|
42212
|
+
}
|
|
42213
|
+
});
|
|
42214
|
+
function useGameCanvas3DEvents(options) {
|
|
42215
|
+
const {
|
|
42216
|
+
tileClickEvent,
|
|
42217
|
+
unitClickEvent,
|
|
42218
|
+
featureClickEvent,
|
|
42219
|
+
canvasClickEvent,
|
|
42220
|
+
tileHoverEvent,
|
|
42221
|
+
tileLeaveEvent,
|
|
42222
|
+
unitAnimationEvent,
|
|
42223
|
+
cameraChangeEvent,
|
|
42224
|
+
onTileClick,
|
|
42225
|
+
onUnitClick,
|
|
42226
|
+
onFeatureClick,
|
|
42227
|
+
onCanvasClick,
|
|
42228
|
+
onTileHover,
|
|
42229
|
+
onUnitAnimation
|
|
42230
|
+
} = options;
|
|
42231
|
+
const emit = useEmitEvent();
|
|
42232
|
+
const optionsRef = React77.useRef(options);
|
|
42233
|
+
optionsRef.current = options;
|
|
42234
|
+
const handleTileClick = React77.useCallback(
|
|
42235
|
+
(tile, event) => {
|
|
42236
|
+
if (tileClickEvent) {
|
|
42237
|
+
emit(tileClickEvent, {
|
|
42238
|
+
tileId: tile.id,
|
|
42239
|
+
x: tile.x,
|
|
42240
|
+
z: tile.z ?? tile.y ?? 0,
|
|
42241
|
+
type: tile.type,
|
|
42242
|
+
terrain: tile.terrain,
|
|
42243
|
+
elevation: tile.elevation
|
|
42244
|
+
});
|
|
42245
|
+
}
|
|
42246
|
+
optionsRef.current.onTileClick?.(tile, event);
|
|
42247
|
+
},
|
|
42248
|
+
[tileClickEvent, emit]
|
|
42249
|
+
);
|
|
42250
|
+
const handleUnitClick = React77.useCallback(
|
|
42251
|
+
(unit, event) => {
|
|
42252
|
+
if (unitClickEvent) {
|
|
42253
|
+
emit(unitClickEvent, {
|
|
42254
|
+
unitId: unit.id,
|
|
42255
|
+
x: unit.x,
|
|
42256
|
+
z: unit.z ?? unit.y ?? 0,
|
|
42257
|
+
unitType: unit.unitType,
|
|
42258
|
+
name: unit.name,
|
|
42259
|
+
team: unit.team,
|
|
42260
|
+
faction: unit.faction,
|
|
42261
|
+
health: unit.health,
|
|
42262
|
+
maxHealth: unit.maxHealth
|
|
42263
|
+
});
|
|
42264
|
+
}
|
|
42265
|
+
optionsRef.current.onUnitClick?.(unit, event);
|
|
42266
|
+
},
|
|
42267
|
+
[unitClickEvent, emit]
|
|
42268
|
+
);
|
|
42269
|
+
const handleFeatureClick = React77.useCallback(
|
|
42270
|
+
(feature, event) => {
|
|
42271
|
+
if (featureClickEvent) {
|
|
42272
|
+
emit(featureClickEvent, {
|
|
42273
|
+
featureId: feature.id,
|
|
42274
|
+
x: feature.x,
|
|
42275
|
+
z: feature.z ?? feature.y ?? 0,
|
|
42276
|
+
type: feature.type,
|
|
42277
|
+
elevation: feature.elevation
|
|
42278
|
+
});
|
|
42279
|
+
}
|
|
42280
|
+
optionsRef.current.onFeatureClick?.(feature, event);
|
|
42281
|
+
},
|
|
42282
|
+
[featureClickEvent, emit]
|
|
42283
|
+
);
|
|
42284
|
+
const handleCanvasClick = React77.useCallback(
|
|
42285
|
+
(event) => {
|
|
42286
|
+
if (canvasClickEvent) {
|
|
42287
|
+
emit(canvasClickEvent, {
|
|
42288
|
+
clientX: event.clientX,
|
|
42289
|
+
clientY: event.clientY,
|
|
42290
|
+
button: event.button
|
|
42291
|
+
});
|
|
42292
|
+
}
|
|
42293
|
+
optionsRef.current.onCanvasClick?.(event);
|
|
42294
|
+
},
|
|
42295
|
+
[canvasClickEvent, emit]
|
|
42296
|
+
);
|
|
42297
|
+
const handleTileHover = React77.useCallback(
|
|
42298
|
+
(tile, event) => {
|
|
42299
|
+
if (tile) {
|
|
42300
|
+
if (tileHoverEvent) {
|
|
42301
|
+
emit(tileHoverEvent, {
|
|
42302
|
+
tileId: tile.id,
|
|
42303
|
+
x: tile.x,
|
|
42304
|
+
z: tile.z ?? tile.y ?? 0,
|
|
42305
|
+
type: tile.type
|
|
42306
|
+
});
|
|
42307
|
+
}
|
|
42308
|
+
} else {
|
|
42309
|
+
if (tileLeaveEvent) {
|
|
42310
|
+
emit(tileLeaveEvent, {});
|
|
42311
|
+
}
|
|
42312
|
+
}
|
|
42313
|
+
optionsRef.current.onTileHover?.(tile, event);
|
|
42314
|
+
},
|
|
42315
|
+
[tileHoverEvent, tileLeaveEvent, emit]
|
|
42316
|
+
);
|
|
42317
|
+
const handleUnitAnimation = React77.useCallback(
|
|
42318
|
+
(unitId, state) => {
|
|
42319
|
+
if (unitAnimationEvent) {
|
|
42320
|
+
emit(unitAnimationEvent, {
|
|
42321
|
+
unitId,
|
|
42322
|
+
state,
|
|
42323
|
+
timestamp: Date.now()
|
|
42324
|
+
});
|
|
42325
|
+
}
|
|
42326
|
+
optionsRef.current.onUnitAnimation?.(unitId, state);
|
|
42327
|
+
},
|
|
42328
|
+
[unitAnimationEvent, emit]
|
|
42329
|
+
);
|
|
42330
|
+
const handleCameraChange = React77.useCallback(
|
|
42331
|
+
(position) => {
|
|
42332
|
+
if (cameraChangeEvent) {
|
|
42333
|
+
emit(cameraChangeEvent, {
|
|
42334
|
+
position,
|
|
42335
|
+
timestamp: Date.now()
|
|
42336
|
+
});
|
|
42337
|
+
}
|
|
42338
|
+
},
|
|
42339
|
+
[cameraChangeEvent, emit]
|
|
42340
|
+
);
|
|
42341
|
+
return {
|
|
42342
|
+
handleTileClick,
|
|
42343
|
+
handleUnitClick,
|
|
42344
|
+
handleFeatureClick,
|
|
42345
|
+
handleCanvasClick,
|
|
42346
|
+
handleTileHover,
|
|
42347
|
+
handleUnitAnimation,
|
|
42348
|
+
handleCameraChange
|
|
42349
|
+
};
|
|
42350
|
+
}
|
|
42351
|
+
var init_useGameCanvas3DEvents = __esm({
|
|
42352
|
+
"components/game/molecules/three/hooks/useGameCanvas3DEvents.ts"() {
|
|
42353
|
+
"use client";
|
|
42354
|
+
init_useEventBus();
|
|
42355
|
+
}
|
|
42356
|
+
});
|
|
42357
|
+
|
|
42358
|
+
// components/game/molecules/three/components/Canvas3DLoadingState.css
|
|
42359
|
+
var init_Canvas3DLoadingState = __esm({
|
|
42360
|
+
"components/game/molecules/three/components/Canvas3DLoadingState.css"() {
|
|
42361
|
+
}
|
|
42362
|
+
});
|
|
42363
|
+
function Canvas3DLoadingState({
|
|
42364
|
+
progress = 0,
|
|
42365
|
+
loaded = 0,
|
|
42366
|
+
total = 0,
|
|
42367
|
+
message = "Loading 3D Scene...",
|
|
42368
|
+
details,
|
|
42369
|
+
showSpinner = true,
|
|
42370
|
+
className
|
|
42371
|
+
}) {
|
|
42372
|
+
const clampedProgress = Math.max(0, Math.min(100, progress));
|
|
42373
|
+
const hasProgress = total > 0;
|
|
42374
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `canvas-3d-loading ${className || ""}`, children: [
|
|
42375
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "canvas-3d-loading__content", children: [
|
|
42376
|
+
showSpinner && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "canvas-3d-loading__spinner", children: [
|
|
42377
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "spinner__ring" }),
|
|
42378
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "spinner__ring spinner__ring--secondary" })
|
|
42379
|
+
] }),
|
|
42380
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "canvas-3d-loading__message", children: message }),
|
|
42381
|
+
details && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "canvas-3d-loading__details", children: details }),
|
|
42382
|
+
hasProgress && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "canvas-3d-loading__progress", children: [
|
|
42383
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "progress__bar", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
42384
|
+
"div",
|
|
42385
|
+
{
|
|
42386
|
+
className: "progress__fill",
|
|
42387
|
+
style: { width: `${clampedProgress}%` }
|
|
42388
|
+
}
|
|
42389
|
+
) }),
|
|
42390
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "progress__text", children: [
|
|
42391
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "progress__percentage", children: [
|
|
42392
|
+
clampedProgress,
|
|
42393
|
+
"%"
|
|
42394
|
+
] }),
|
|
42395
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "progress__count", children: [
|
|
42396
|
+
"(",
|
|
42397
|
+
loaded,
|
|
42398
|
+
"/",
|
|
42399
|
+
total,
|
|
42400
|
+
")"
|
|
42401
|
+
] })
|
|
42402
|
+
] })
|
|
42403
|
+
] })
|
|
42404
|
+
] }),
|
|
42405
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "canvas-3d-loading__background", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg__grid" }) })
|
|
42406
|
+
] });
|
|
42407
|
+
}
|
|
42408
|
+
var init_Canvas3DLoadingState2 = __esm({
|
|
42409
|
+
"components/game/molecules/three/components/Canvas3DLoadingState.tsx"() {
|
|
42410
|
+
init_Canvas3DLoadingState();
|
|
42411
|
+
}
|
|
42412
|
+
});
|
|
42413
|
+
|
|
42414
|
+
// components/game/molecules/three/components/Canvas3DErrorBoundary.css
|
|
42415
|
+
var init_Canvas3DErrorBoundary = __esm({
|
|
42416
|
+
"components/game/molecules/three/components/Canvas3DErrorBoundary.css"() {
|
|
42417
|
+
}
|
|
42418
|
+
});
|
|
42419
|
+
var log9, Canvas3DErrorBoundary;
|
|
42420
|
+
var init_Canvas3DErrorBoundary2 = __esm({
|
|
42421
|
+
"components/game/molecules/three/components/Canvas3DErrorBoundary.tsx"() {
|
|
42422
|
+
init_Canvas3DErrorBoundary();
|
|
42423
|
+
log9 = logger.createLogger("almadar:ui:game:canvas3d:error-boundary");
|
|
42424
|
+
Canvas3DErrorBoundary = class extends React77.Component {
|
|
42425
|
+
constructor(props) {
|
|
42426
|
+
super(props);
|
|
42427
|
+
__publicField(this, "handleReset", () => {
|
|
42428
|
+
this.setState({
|
|
42429
|
+
hasError: false,
|
|
42430
|
+
error: null,
|
|
42431
|
+
errorInfo: null
|
|
42432
|
+
});
|
|
42433
|
+
this.props.onReset?.();
|
|
42434
|
+
});
|
|
42435
|
+
this.state = {
|
|
42436
|
+
hasError: false,
|
|
42437
|
+
error: null,
|
|
42438
|
+
errorInfo: null
|
|
42439
|
+
};
|
|
42440
|
+
}
|
|
42441
|
+
static getDerivedStateFromError(error) {
|
|
42442
|
+
return {
|
|
42443
|
+
hasError: true,
|
|
42444
|
+
error,
|
|
42445
|
+
errorInfo: null
|
|
42446
|
+
};
|
|
42447
|
+
}
|
|
42448
|
+
componentDidCatch(error, errorInfo) {
|
|
42449
|
+
this.setState({ errorInfo });
|
|
42450
|
+
this.props.onError?.(error, errorInfo);
|
|
42451
|
+
log9.error("Error caught", { error });
|
|
42452
|
+
log9.error("Component stack", { componentStack: errorInfo.componentStack ?? "<none>" });
|
|
42453
|
+
}
|
|
42454
|
+
render() {
|
|
42455
|
+
if (this.state.hasError) {
|
|
42456
|
+
if (this.props.fallback) {
|
|
42457
|
+
return this.props.fallback;
|
|
42458
|
+
}
|
|
42459
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "canvas-3d-error", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "canvas-3d-error__content", children: [
|
|
42460
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "canvas-3d-error__icon", children: "\u26A0\uFE0F" }),
|
|
42461
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "canvas-3d-error__title", children: "3D Scene Error" }),
|
|
42462
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "canvas-3d-error__message", children: "Something went wrong while rendering the 3D scene." }),
|
|
42463
|
+
this.state.error && /* @__PURE__ */ jsxRuntime.jsxs("details", { className: "canvas-3d-error__details", children: [
|
|
42464
|
+
/* @__PURE__ */ jsxRuntime.jsx("summary", { children: "Error Details" }),
|
|
42465
|
+
/* @__PURE__ */ jsxRuntime.jsxs("pre", { className: "error__stack", children: [
|
|
42466
|
+
this.state.error.message,
|
|
42467
|
+
"\n",
|
|
42468
|
+
this.state.error.stack
|
|
42469
|
+
] }),
|
|
42470
|
+
this.state.errorInfo && /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "error__component-stack", children: this.state.errorInfo.componentStack })
|
|
42471
|
+
] }),
|
|
42472
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "canvas-3d-error__actions", children: [
|
|
42473
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
42474
|
+
"button",
|
|
42475
|
+
{
|
|
42476
|
+
className: "error__button error__button--primary",
|
|
42477
|
+
onClick: this.handleReset,
|
|
42478
|
+
children: "Try Again"
|
|
42479
|
+
}
|
|
42480
|
+
),
|
|
42481
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
42482
|
+
"button",
|
|
42483
|
+
{
|
|
42484
|
+
className: "error__button error__button--secondary",
|
|
42485
|
+
onClick: () => window.location.reload(),
|
|
42486
|
+
children: "Reload Page"
|
|
42487
|
+
}
|
|
42488
|
+
)
|
|
42489
|
+
] })
|
|
42490
|
+
] }) });
|
|
42491
|
+
}
|
|
42492
|
+
return this.props.children;
|
|
42493
|
+
}
|
|
42494
|
+
};
|
|
42495
|
+
}
|
|
42496
|
+
});
|
|
42497
|
+
function detectAssetRoot2(modelUrl) {
|
|
42498
|
+
const idx = modelUrl.indexOf("/3d/");
|
|
42499
|
+
if (idx !== -1) {
|
|
42500
|
+
return modelUrl.substring(0, idx + 4);
|
|
42501
|
+
}
|
|
42502
|
+
return modelUrl.substring(0, modelUrl.lastIndexOf("/") + 1);
|
|
42503
|
+
}
|
|
42504
|
+
function useGLTFModel(url, resourceBasePath) {
|
|
42505
|
+
const [state, setState] = React77.useState({
|
|
42506
|
+
model: null,
|
|
42507
|
+
isLoading: false,
|
|
42508
|
+
error: null
|
|
42509
|
+
});
|
|
42510
|
+
React77.useEffect(() => {
|
|
42511
|
+
if (!url) {
|
|
42512
|
+
setState({ model: null, isLoading: false, error: null });
|
|
42513
|
+
return;
|
|
42514
|
+
}
|
|
42515
|
+
log10.debug("Loading", { url });
|
|
42516
|
+
setState((prev) => ({ ...prev, isLoading: true, error: null }));
|
|
42517
|
+
const assetRoot = resourceBasePath || detectAssetRoot2(url);
|
|
42518
|
+
const loader = new GLTFLoader.GLTFLoader();
|
|
42519
|
+
loader.setResourcePath(assetRoot);
|
|
42520
|
+
loader.load(
|
|
42521
|
+
url,
|
|
42522
|
+
(gltf) => {
|
|
42523
|
+
log10.debug("Loaded", { url });
|
|
42524
|
+
setState({
|
|
42525
|
+
model: gltf.scene,
|
|
42526
|
+
isLoading: false,
|
|
42527
|
+
error: null
|
|
42528
|
+
});
|
|
42529
|
+
},
|
|
42530
|
+
void 0,
|
|
42531
|
+
(err) => {
|
|
42532
|
+
log10.warn("Failed", { url, error: err instanceof Error ? err : String(err) });
|
|
42533
|
+
setState({
|
|
42534
|
+
model: null,
|
|
42535
|
+
isLoading: false,
|
|
42536
|
+
error: err instanceof Error ? err : new Error(String(err))
|
|
42537
|
+
});
|
|
42538
|
+
}
|
|
42539
|
+
);
|
|
42540
|
+
}, [url, resourceBasePath]);
|
|
42541
|
+
return state;
|
|
42542
|
+
}
|
|
42543
|
+
function ModelLoader({
|
|
42544
|
+
url,
|
|
42545
|
+
position = [0, 0, 0],
|
|
42546
|
+
scale = 1,
|
|
42547
|
+
rotation = [0, 0, 0],
|
|
42548
|
+
isSelected = false,
|
|
42549
|
+
isHovered = false,
|
|
42550
|
+
onClick,
|
|
42551
|
+
onHover,
|
|
42552
|
+
fallbackGeometry = "box",
|
|
42553
|
+
castShadow = true,
|
|
42554
|
+
receiveShadow = true,
|
|
42555
|
+
resourceBasePath
|
|
42556
|
+
}) {
|
|
42557
|
+
const { model: loadedModel, isLoading, error } = useGLTFModel(url, resourceBasePath);
|
|
42558
|
+
const model = React77.useMemo(() => {
|
|
42559
|
+
if (!loadedModel) return null;
|
|
42560
|
+
const cloned = loadedModel.clone();
|
|
42561
|
+
cloned.traverse((child) => {
|
|
42562
|
+
if (child instanceof THREE__namespace.Mesh) {
|
|
42563
|
+
child.castShadow = castShadow;
|
|
42564
|
+
child.receiveShadow = receiveShadow;
|
|
42565
|
+
}
|
|
42566
|
+
});
|
|
42567
|
+
return cloned;
|
|
42568
|
+
}, [loadedModel, castShadow, receiveShadow]);
|
|
42569
|
+
const scaleArray = React77.useMemo(() => {
|
|
42570
|
+
if (typeof scale === "number") {
|
|
42571
|
+
return [scale, scale, scale];
|
|
42572
|
+
}
|
|
42573
|
+
return scale;
|
|
42574
|
+
}, [scale]);
|
|
42575
|
+
const rotationRad = React77.useMemo(() => {
|
|
42576
|
+
return [
|
|
42577
|
+
rotation[0] * Math.PI / 180,
|
|
42578
|
+
rotation[1] * Math.PI / 180,
|
|
42579
|
+
rotation[2] * Math.PI / 180
|
|
42580
|
+
];
|
|
42581
|
+
}, [rotation]);
|
|
42582
|
+
if (isLoading) {
|
|
42583
|
+
return /* @__PURE__ */ jsxRuntime.jsx("group", { position, children: /* @__PURE__ */ jsxRuntime.jsxs("mesh", { rotation: [Math.PI / 2, 0, 0], children: [
|
|
42584
|
+
/* @__PURE__ */ jsxRuntime.jsx("ringGeometry", { args: [0.3, 0.35, 16] }),
|
|
42585
|
+
/* @__PURE__ */ jsxRuntime.jsx("meshBasicMaterial", { color: "#4a90d9", transparent: true, opacity: 0.8 })
|
|
42586
|
+
] }) });
|
|
42587
|
+
}
|
|
42588
|
+
if (error || !model) {
|
|
42589
|
+
if (fallbackGeometry === "none") {
|
|
42590
|
+
return /* @__PURE__ */ jsxRuntime.jsx("group", { position });
|
|
42591
|
+
}
|
|
42592
|
+
const fallbackProps = {
|
|
42593
|
+
onClick,
|
|
42594
|
+
onPointerOver: () => onHover?.(true),
|
|
42595
|
+
onPointerOut: () => onHover?.(false)
|
|
42596
|
+
};
|
|
42597
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("group", { position, children: [
|
|
42598
|
+
(isSelected || isHovered) && /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.02, 0], rotation: [-Math.PI / 2, 0, 0], children: [
|
|
42599
|
+
/* @__PURE__ */ jsxRuntime.jsx("ringGeometry", { args: [0.6, 0.7, 32] }),
|
|
42600
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
42601
|
+
"meshBasicMaterial",
|
|
42602
|
+
{
|
|
42603
|
+
color: isSelected ? 16755200 : 16777215,
|
|
42604
|
+
transparent: true,
|
|
42605
|
+
opacity: 0.5
|
|
42606
|
+
}
|
|
42607
|
+
)
|
|
42608
|
+
] }),
|
|
42609
|
+
fallbackGeometry === "box" && /* @__PURE__ */ jsxRuntime.jsxs("mesh", { ...fallbackProps, position: [0, 0.5, 0], children: [
|
|
42610
|
+
/* @__PURE__ */ jsxRuntime.jsx("boxGeometry", { args: [0.8, 0.8, 0.8] }),
|
|
42611
|
+
/* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color: error ? 16729156 : 8947848 })
|
|
42612
|
+
] }),
|
|
42613
|
+
fallbackGeometry === "sphere" && /* @__PURE__ */ jsxRuntime.jsxs("mesh", { ...fallbackProps, position: [0, 0.5, 0], children: [
|
|
42614
|
+
/* @__PURE__ */ jsxRuntime.jsx("sphereGeometry", { args: [0.4, 16, 16] }),
|
|
42615
|
+
/* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color: error ? 16729156 : 8947848 })
|
|
42616
|
+
] }),
|
|
42617
|
+
fallbackGeometry === "cylinder" && /* @__PURE__ */ jsxRuntime.jsxs("mesh", { ...fallbackProps, position: [0, 0.5, 0], children: [
|
|
42618
|
+
/* @__PURE__ */ jsxRuntime.jsx("cylinderGeometry", { args: [0.3, 0.3, 0.8, 16] }),
|
|
42619
|
+
/* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color: error ? 16729156 : 8947848 })
|
|
42620
|
+
] })
|
|
42621
|
+
] });
|
|
42622
|
+
}
|
|
42623
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
42624
|
+
"group",
|
|
42625
|
+
{
|
|
42626
|
+
position,
|
|
42627
|
+
rotation: rotationRad,
|
|
42628
|
+
onClick,
|
|
42629
|
+
onPointerOver: () => onHover?.(true),
|
|
42630
|
+
onPointerOut: () => onHover?.(false),
|
|
42631
|
+
children: [
|
|
42632
|
+
(isSelected || isHovered) && /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.02, 0], rotation: [-Math.PI / 2, 0, 0], children: [
|
|
42633
|
+
/* @__PURE__ */ jsxRuntime.jsx("ringGeometry", { args: [0.6, 0.7, 32] }),
|
|
42634
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
42635
|
+
"meshBasicMaterial",
|
|
42636
|
+
{
|
|
42637
|
+
color: isSelected ? 16755200 : 16777215,
|
|
42638
|
+
transparent: true,
|
|
42639
|
+
opacity: 0.5
|
|
42640
|
+
}
|
|
42641
|
+
)
|
|
42642
|
+
] }),
|
|
42643
|
+
/* @__PURE__ */ jsxRuntime.jsx("primitive", { object: model, scale: scaleArray })
|
|
42644
|
+
]
|
|
42645
|
+
}
|
|
42646
|
+
);
|
|
42647
|
+
}
|
|
42648
|
+
var log10;
|
|
42649
|
+
var init_ModelLoader = __esm({
|
|
42650
|
+
"components/game/molecules/three/components/ModelLoader.tsx"() {
|
|
42651
|
+
"use client";
|
|
42652
|
+
log10 = logger.createLogger("almadar:ui:game:model-loader");
|
|
42653
|
+
}
|
|
42654
|
+
});
|
|
42655
|
+
|
|
42656
|
+
// components/game/molecules/GameCanvas3D.css
|
|
42657
|
+
var init_GameCanvas3D = __esm({
|
|
42658
|
+
"components/game/molecules/GameCanvas3D.css"() {
|
|
42659
|
+
}
|
|
42660
|
+
});
|
|
42661
|
+
function CameraController({
|
|
42662
|
+
onCameraChange
|
|
42663
|
+
}) {
|
|
42664
|
+
const { camera } = fiber.useThree();
|
|
42665
|
+
React77.useEffect(() => {
|
|
42666
|
+
if (onCameraChange) {
|
|
42667
|
+
onCameraChange({
|
|
42668
|
+
x: camera.position.x,
|
|
42669
|
+
y: camera.position.y,
|
|
42670
|
+
z: camera.position.z
|
|
42671
|
+
});
|
|
42672
|
+
}
|
|
42673
|
+
}, [camera.position, onCameraChange]);
|
|
42674
|
+
return null;
|
|
42675
|
+
}
|
|
42676
|
+
var DEFAULT_GRID_CONFIG, GameCanvas3D;
|
|
42677
|
+
var init_GameCanvas3D2 = __esm({
|
|
42678
|
+
"components/game/molecules/GameCanvas3D.tsx"() {
|
|
42679
|
+
"use client";
|
|
42680
|
+
init_AssetLoader();
|
|
42681
|
+
init_useAssetLoader();
|
|
42682
|
+
init_useGameCanvas3DEvents();
|
|
42683
|
+
init_Canvas3DLoadingState2();
|
|
42684
|
+
init_Canvas3DErrorBoundary2();
|
|
42685
|
+
init_ModelLoader();
|
|
42686
|
+
init_cn();
|
|
42687
|
+
init_GameCanvas3D();
|
|
42688
|
+
DEFAULT_GRID_CONFIG = {
|
|
42689
|
+
cellSize: 1,
|
|
42690
|
+
offsetX: 0,
|
|
42691
|
+
offsetZ: 0
|
|
42692
|
+
};
|
|
42693
|
+
GameCanvas3D = React77.forwardRef(
|
|
42694
|
+
({
|
|
42695
|
+
tiles = [],
|
|
42696
|
+
units = [],
|
|
42697
|
+
features = [],
|
|
42698
|
+
events: events2 = [],
|
|
42699
|
+
orientation = "standard",
|
|
42700
|
+
cameraMode = "isometric",
|
|
42701
|
+
showGrid = true,
|
|
42702
|
+
showCoordinates = false,
|
|
42703
|
+
showTileInfo = false,
|
|
42704
|
+
overlay = "default",
|
|
42705
|
+
shadows = true,
|
|
42706
|
+
backgroundColor = "#1a1a2e",
|
|
42707
|
+
onTileClick,
|
|
42708
|
+
onUnitClick,
|
|
42709
|
+
onFeatureClick,
|
|
42710
|
+
onCanvasClick,
|
|
42711
|
+
onTileHover,
|
|
42712
|
+
onUnitAnimation,
|
|
42713
|
+
assetLoader: customAssetLoader,
|
|
42714
|
+
tileRenderer: CustomTileRenderer,
|
|
42715
|
+
unitRenderer: CustomUnitRenderer,
|
|
42716
|
+
featureRenderer: CustomFeatureRenderer,
|
|
42717
|
+
className,
|
|
42718
|
+
isLoading: externalLoading,
|
|
42719
|
+
error: externalError,
|
|
42720
|
+
entity,
|
|
42721
|
+
preloadAssets = [],
|
|
42722
|
+
tileClickEvent,
|
|
42723
|
+
unitClickEvent,
|
|
42724
|
+
featureClickEvent,
|
|
42725
|
+
canvasClickEvent,
|
|
42726
|
+
tileHoverEvent,
|
|
42727
|
+
tileLeaveEvent,
|
|
42728
|
+
unitAnimationEvent,
|
|
42729
|
+
cameraChangeEvent,
|
|
42730
|
+
loadingMessage = "Loading 3D Scene...",
|
|
42731
|
+
useInstancing = true,
|
|
42732
|
+
validMoves = [],
|
|
42733
|
+
attackTargets = [],
|
|
42734
|
+
selectedTileIds = [],
|
|
42735
|
+
selectedUnitId = null,
|
|
42736
|
+
children
|
|
42737
|
+
}, ref) => {
|
|
42738
|
+
const containerRef = React77.useRef(null);
|
|
42739
|
+
const controlsRef = React77.useRef(null);
|
|
42740
|
+
const [hoveredTile, setHoveredTile] = React77.useState(null);
|
|
42741
|
+
const [internalError, setInternalError] = React77.useState(null);
|
|
42742
|
+
const { isLoading: assetsLoading, progress, loaded, total } = useAssetLoader({
|
|
42743
|
+
preloadUrls: preloadAssets,
|
|
42744
|
+
loader: customAssetLoader
|
|
42745
|
+
});
|
|
42746
|
+
const eventHandlers = useGameCanvas3DEvents({
|
|
42747
|
+
tileClickEvent,
|
|
42748
|
+
unitClickEvent,
|
|
42749
|
+
featureClickEvent,
|
|
42750
|
+
canvasClickEvent,
|
|
42751
|
+
tileHoverEvent,
|
|
42752
|
+
tileLeaveEvent,
|
|
42753
|
+
unitAnimationEvent,
|
|
42754
|
+
cameraChangeEvent,
|
|
42755
|
+
onTileClick,
|
|
42756
|
+
onUnitClick,
|
|
42757
|
+
onFeatureClick,
|
|
42758
|
+
onCanvasClick,
|
|
42759
|
+
onTileHover,
|
|
42760
|
+
onUnitAnimation
|
|
42761
|
+
});
|
|
42762
|
+
const gridBounds = React77.useMemo(() => {
|
|
42763
|
+
if (tiles.length === 0) {
|
|
42764
|
+
return { minX: 0, maxX: 10, minZ: 0, maxZ: 10 };
|
|
42765
|
+
}
|
|
42766
|
+
const xs = tiles.map((t) => t.x);
|
|
42767
|
+
const zs = tiles.map((t) => t.z || t.y || 0);
|
|
42768
|
+
return {
|
|
42769
|
+
minX: Math.min(...xs),
|
|
42770
|
+
maxX: Math.max(...xs),
|
|
42771
|
+
minZ: Math.min(...zs),
|
|
42772
|
+
maxZ: Math.max(...zs)
|
|
42773
|
+
};
|
|
42774
|
+
}, [tiles]);
|
|
42775
|
+
const cameraTarget = React77.useMemo(() => {
|
|
42776
|
+
return [
|
|
42777
|
+
(gridBounds.minX + gridBounds.maxX) / 2,
|
|
42778
|
+
0,
|
|
42779
|
+
(gridBounds.minZ + gridBounds.maxZ) / 2
|
|
42780
|
+
];
|
|
42781
|
+
}, [gridBounds]);
|
|
42782
|
+
const gridConfig = React77.useMemo(
|
|
42783
|
+
() => ({
|
|
42784
|
+
...DEFAULT_GRID_CONFIG,
|
|
42785
|
+
offsetX: -(gridBounds.maxX - gridBounds.minX) / 2,
|
|
42786
|
+
offsetZ: -(gridBounds.maxZ - gridBounds.minZ) / 2
|
|
42787
|
+
}),
|
|
42788
|
+
[gridBounds]
|
|
42789
|
+
);
|
|
42790
|
+
const gridToWorld = React77.useCallback(
|
|
42791
|
+
(x, z, y = 0) => {
|
|
42792
|
+
const worldX = (x - gridBounds.minX) * gridConfig.cellSize;
|
|
42793
|
+
const worldZ = (z - gridBounds.minZ) * gridConfig.cellSize;
|
|
42794
|
+
return [worldX, y * gridConfig.cellSize, worldZ];
|
|
42795
|
+
},
|
|
42796
|
+
[gridBounds, gridConfig]
|
|
42797
|
+
);
|
|
42798
|
+
React77.useImperativeHandle(ref, () => ({
|
|
42799
|
+
getCameraPosition: () => {
|
|
42800
|
+
if (controlsRef.current) {
|
|
42801
|
+
const pos = controlsRef.current.object.position;
|
|
42802
|
+
return new THREE__namespace.Vector3(pos.x, pos.y, pos.z);
|
|
42803
|
+
}
|
|
42804
|
+
return null;
|
|
42805
|
+
},
|
|
42806
|
+
setCameraPosition: (x, y, z) => {
|
|
42807
|
+
if (controlsRef.current) {
|
|
42808
|
+
controlsRef.current.object.position.set(x, y, z);
|
|
42809
|
+
controlsRef.current.update();
|
|
42810
|
+
}
|
|
42811
|
+
},
|
|
42812
|
+
lookAt: (x, y, z) => {
|
|
42813
|
+
if (controlsRef.current) {
|
|
42814
|
+
controlsRef.current.target.set(x, y, z);
|
|
42815
|
+
controlsRef.current.update();
|
|
42816
|
+
}
|
|
42817
|
+
},
|
|
42818
|
+
resetCamera: () => {
|
|
42819
|
+
if (controlsRef.current) {
|
|
42820
|
+
controlsRef.current.reset();
|
|
42821
|
+
}
|
|
42822
|
+
},
|
|
42823
|
+
screenshot: () => {
|
|
42824
|
+
const canvas = containerRef.current?.querySelector("canvas");
|
|
42825
|
+
if (canvas) {
|
|
42826
|
+
return canvas.toDataURL("image/png");
|
|
42827
|
+
}
|
|
42828
|
+
return null;
|
|
42829
|
+
},
|
|
42830
|
+
export: () => ({
|
|
42831
|
+
tiles,
|
|
42832
|
+
units,
|
|
42833
|
+
features
|
|
42834
|
+
})
|
|
42835
|
+
}));
|
|
42836
|
+
const handleTileClick = React77.useCallback(
|
|
42837
|
+
(tile, event) => {
|
|
42838
|
+
eventHandlers.handleTileClick(tile, event);
|
|
42839
|
+
},
|
|
42840
|
+
[eventHandlers]
|
|
42841
|
+
);
|
|
42842
|
+
const handleUnitClick = React77.useCallback(
|
|
42843
|
+
(unit, event) => {
|
|
42844
|
+
eventHandlers.handleUnitClick(unit, event);
|
|
42845
|
+
},
|
|
42846
|
+
[eventHandlers]
|
|
42847
|
+
);
|
|
42848
|
+
const handleFeatureClick = React77.useCallback(
|
|
42849
|
+
(feature, event) => {
|
|
42850
|
+
if (event) {
|
|
42851
|
+
eventHandlers.handleFeatureClick(feature, event);
|
|
42852
|
+
}
|
|
42853
|
+
},
|
|
42854
|
+
[eventHandlers]
|
|
42855
|
+
);
|
|
42856
|
+
const handleTileHover = React77.useCallback(
|
|
42857
|
+
(tile, event) => {
|
|
42858
|
+
setHoveredTile(tile);
|
|
42859
|
+
if (event) {
|
|
42860
|
+
eventHandlers.handleTileHover(tile, event);
|
|
42861
|
+
}
|
|
42862
|
+
},
|
|
42863
|
+
[eventHandlers]
|
|
42864
|
+
);
|
|
42865
|
+
const cameraConfig = React77.useMemo(() => {
|
|
42866
|
+
const size = Math.max(
|
|
42867
|
+
gridBounds.maxX - gridBounds.minX,
|
|
42868
|
+
gridBounds.maxZ - gridBounds.minZ
|
|
42869
|
+
);
|
|
42870
|
+
const distance = size * 1.5;
|
|
42871
|
+
switch (cameraMode) {
|
|
42872
|
+
case "isometric":
|
|
42873
|
+
return {
|
|
42874
|
+
position: [distance, distance * 0.8, distance],
|
|
42875
|
+
fov: 45
|
|
42876
|
+
};
|
|
42877
|
+
case "top-down":
|
|
42878
|
+
return {
|
|
42879
|
+
position: [0, distance * 2, 0],
|
|
42880
|
+
fov: 45
|
|
42881
|
+
};
|
|
42882
|
+
case "perspective":
|
|
42883
|
+
default:
|
|
42884
|
+
return {
|
|
42885
|
+
position: [distance, distance, distance],
|
|
42886
|
+
fov: 45
|
|
42887
|
+
};
|
|
42888
|
+
}
|
|
42889
|
+
}, [cameraMode, gridBounds]);
|
|
42890
|
+
const DefaultTileRenderer = React77.useCallback(
|
|
42891
|
+
({ tile, position }) => {
|
|
42892
|
+
const isSelected = tile.id ? selectedTileIds.includes(tile.id) : false;
|
|
42893
|
+
const isHovered = hoveredTile?.id === tile.id;
|
|
42894
|
+
const isValidMove = validMoves.some(
|
|
42895
|
+
(m) => m.x === tile.x && m.z === (tile.z ?? tile.y ?? 0)
|
|
42896
|
+
);
|
|
42897
|
+
const isAttackTarget = attackTargets.some(
|
|
42898
|
+
(m) => m.x === tile.x && m.z === (tile.z ?? tile.y ?? 0)
|
|
42899
|
+
);
|
|
42900
|
+
let color = 8421504;
|
|
42901
|
+
if (tile.type === "water") color = 4491468;
|
|
42902
|
+
else if (tile.type === "grass") color = 4500036;
|
|
42903
|
+
else if (tile.type === "sand") color = 14535816;
|
|
42904
|
+
else if (tile.type === "rock") color = 8947848;
|
|
42905
|
+
else if (tile.type === "snow") color = 15658734;
|
|
42906
|
+
let emissive = 0;
|
|
42907
|
+
if (isSelected) emissive = 4473924;
|
|
42908
|
+
else if (isAttackTarget) emissive = 4456448;
|
|
42909
|
+
else if (isValidMove) emissive = 17408;
|
|
42910
|
+
else if (isHovered) emissive = 2236962;
|
|
42911
|
+
if (tile.modelUrl) {
|
|
42912
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
42913
|
+
"group",
|
|
42914
|
+
{
|
|
42915
|
+
position,
|
|
42916
|
+
onClick: (e) => handleTileClick(tile, e),
|
|
42917
|
+
onPointerEnter: (e) => handleTileHover(tile, e),
|
|
42918
|
+
onPointerLeave: (e) => handleTileHover(null, e),
|
|
42919
|
+
userData: { type: "tile", tileId: tile.id, gridX: tile.x, gridZ: tile.z ?? tile.y },
|
|
42920
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
42921
|
+
ModelLoader,
|
|
42922
|
+
{
|
|
42923
|
+
url: tile.modelUrl,
|
|
42924
|
+
scale: 0.95,
|
|
42925
|
+
fallbackGeometry: "box",
|
|
42926
|
+
castShadow: true,
|
|
42927
|
+
receiveShadow: true
|
|
42928
|
+
}
|
|
42929
|
+
)
|
|
42930
|
+
}
|
|
42931
|
+
);
|
|
42932
|
+
}
|
|
42933
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
42934
|
+
"mesh",
|
|
42935
|
+
{
|
|
42936
|
+
position,
|
|
42937
|
+
onClick: (e) => handleTileClick(tile, e),
|
|
42938
|
+
onPointerEnter: (e) => handleTileHover(tile, e),
|
|
42939
|
+
onPointerLeave: (e) => handleTileHover(null, e),
|
|
42940
|
+
userData: { type: "tile", tileId: tile.id, gridX: tile.x, gridZ: tile.z ?? tile.y },
|
|
42941
|
+
children: [
|
|
42942
|
+
/* @__PURE__ */ jsxRuntime.jsx("boxGeometry", { args: [0.95, 0.2, 0.95] }),
|
|
42943
|
+
/* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color, emissive })
|
|
42944
|
+
]
|
|
42945
|
+
}
|
|
42946
|
+
);
|
|
42947
|
+
},
|
|
42948
|
+
[selectedTileIds, hoveredTile, validMoves, attackTargets, handleTileClick, handleTileHover]
|
|
42949
|
+
);
|
|
42950
|
+
const DefaultUnitRenderer = React77.useCallback(
|
|
42951
|
+
({ unit, position }) => {
|
|
42952
|
+
const isSelected = selectedUnitId === unit.id;
|
|
42953
|
+
const color = unit.faction === "player" ? 4491519 : unit.faction === "enemy" ? 16729156 : 16777028;
|
|
42954
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
42955
|
+
"group",
|
|
42956
|
+
{
|
|
42957
|
+
position,
|
|
42958
|
+
onClick: (e) => handleUnitClick(unit, e),
|
|
42959
|
+
userData: { type: "unit", unitId: unit.id },
|
|
42960
|
+
children: [
|
|
42961
|
+
isSelected && /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.05, 0], rotation: [-Math.PI / 2, 0, 0], children: [
|
|
42962
|
+
/* @__PURE__ */ jsxRuntime.jsx("ringGeometry", { args: [0.4, 0.5, 32] }),
|
|
42963
|
+
/* @__PURE__ */ jsxRuntime.jsx("meshBasicMaterial", { color: "#ffff00", transparent: true, opacity: 0.8 })
|
|
42964
|
+
] }),
|
|
42965
|
+
unit.modelUrl ? (
|
|
42966
|
+
/* GLB unit model (box fallback while loading / on error) */
|
|
42967
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
42968
|
+
ModelLoader,
|
|
42969
|
+
{
|
|
42970
|
+
url: unit.modelUrl,
|
|
42971
|
+
scale: 0.5,
|
|
42972
|
+
fallbackGeometry: "box",
|
|
42973
|
+
castShadow: true
|
|
42974
|
+
}
|
|
42975
|
+
)
|
|
42976
|
+
) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
42977
|
+
/* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.3, 0], children: [
|
|
42978
|
+
/* @__PURE__ */ jsxRuntime.jsx("cylinderGeometry", { args: [0.3, 0.3, 0.1, 8] }),
|
|
42979
|
+
/* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color })
|
|
42980
|
+
] }),
|
|
42981
|
+
/* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.6, 0], children: [
|
|
42982
|
+
/* @__PURE__ */ jsxRuntime.jsx("capsuleGeometry", { args: [0.2, 0.4, 4, 8] }),
|
|
42983
|
+
/* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color })
|
|
42984
|
+
] }),
|
|
42985
|
+
/* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.9, 0], children: [
|
|
42986
|
+
/* @__PURE__ */ jsxRuntime.jsx("sphereGeometry", { args: [0.12, 8, 8] }),
|
|
42987
|
+
/* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color })
|
|
42988
|
+
] })
|
|
42989
|
+
] }),
|
|
42990
|
+
unit.health !== void 0 && unit.maxHealth !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs("group", { position: [0, 1.2, 0], children: [
|
|
42991
|
+
/* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [-0.25, 0, 0], children: [
|
|
42992
|
+
/* @__PURE__ */ jsxRuntime.jsx("planeGeometry", { args: [0.5, 0.05] }),
|
|
42993
|
+
/* @__PURE__ */ jsxRuntime.jsx("meshBasicMaterial", { color: 3355443 })
|
|
42994
|
+
] }),
|
|
42995
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
42996
|
+
"mesh",
|
|
42997
|
+
{
|
|
42998
|
+
position: [
|
|
42999
|
+
-0.25 + 0.5 * (unit.health / unit.maxHealth) / 2,
|
|
43000
|
+
0,
|
|
43001
|
+
0.01
|
|
43002
|
+
],
|
|
43003
|
+
children: [
|
|
43004
|
+
/* @__PURE__ */ jsxRuntime.jsx("planeGeometry", { args: [0.5 * (unit.health / unit.maxHealth), 0.05] }),
|
|
43005
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
43006
|
+
"meshBasicMaterial",
|
|
43007
|
+
{
|
|
43008
|
+
color: unit.health / unit.maxHealth > 0.5 ? 4500036 : unit.health / unit.maxHealth > 0.25 ? 11184708 : 16729156
|
|
43009
|
+
}
|
|
43010
|
+
)
|
|
43011
|
+
]
|
|
43012
|
+
}
|
|
43013
|
+
)
|
|
43014
|
+
] })
|
|
43015
|
+
]
|
|
43016
|
+
}
|
|
43017
|
+
);
|
|
43018
|
+
},
|
|
43019
|
+
[selectedUnitId, handleUnitClick]
|
|
43020
|
+
);
|
|
43021
|
+
const DefaultFeatureRenderer = React77.useCallback(
|
|
43022
|
+
({
|
|
43023
|
+
feature,
|
|
43024
|
+
position
|
|
43025
|
+
}) => {
|
|
43026
|
+
if (feature.assetUrl) {
|
|
43027
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
43028
|
+
ModelLoader,
|
|
43029
|
+
{
|
|
43030
|
+
url: feature.assetUrl,
|
|
43031
|
+
position,
|
|
43032
|
+
scale: 0.5,
|
|
43033
|
+
rotation: [0, feature.rotation ?? 0, 0],
|
|
43034
|
+
onClick: () => handleFeatureClick(feature, null),
|
|
43035
|
+
fallbackGeometry: "box"
|
|
43036
|
+
},
|
|
43037
|
+
feature.id
|
|
43038
|
+
);
|
|
43039
|
+
}
|
|
43040
|
+
if (feature.type === "tree") {
|
|
43041
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
43042
|
+
"group",
|
|
43043
|
+
{
|
|
43044
|
+
position,
|
|
43045
|
+
onClick: (e) => handleFeatureClick(feature, e),
|
|
43046
|
+
userData: { type: "feature", featureId: feature.id },
|
|
43047
|
+
children: [
|
|
43048
|
+
/* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.4, 0], children: [
|
|
43049
|
+
/* @__PURE__ */ jsxRuntime.jsx("cylinderGeometry", { args: [0.1, 0.15, 0.8, 6] }),
|
|
43050
|
+
/* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color: 9127187 })
|
|
43051
|
+
] }),
|
|
43052
|
+
/* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.9, 0], children: [
|
|
43053
|
+
/* @__PURE__ */ jsxRuntime.jsx("coneGeometry", { args: [0.5, 0.8, 8] }),
|
|
43054
|
+
/* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color: 2263842 })
|
|
43055
|
+
] })
|
|
43056
|
+
]
|
|
43057
|
+
}
|
|
43058
|
+
);
|
|
43059
|
+
}
|
|
43060
|
+
if (feature.type === "rock") {
|
|
43061
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
43062
|
+
"mesh",
|
|
43063
|
+
{
|
|
43064
|
+
position: [position[0], position[1] + 0.3, position[2]],
|
|
43065
|
+
onClick: (e) => handleFeatureClick(feature, e),
|
|
43066
|
+
userData: { type: "feature", featureId: feature.id },
|
|
43067
|
+
children: [
|
|
43068
|
+
/* @__PURE__ */ jsxRuntime.jsx("dodecahedronGeometry", { args: [0.3, 0] }),
|
|
43069
|
+
/* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color: 8421504 })
|
|
43070
|
+
]
|
|
43071
|
+
}
|
|
43072
|
+
);
|
|
43073
|
+
}
|
|
43074
|
+
return null;
|
|
43075
|
+
},
|
|
43076
|
+
[handleFeatureClick]
|
|
43077
|
+
);
|
|
43078
|
+
if (externalLoading || assetsLoading && preloadAssets.length > 0) {
|
|
43079
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
43080
|
+
Canvas3DLoadingState,
|
|
43081
|
+
{
|
|
43082
|
+
progress,
|
|
43083
|
+
loaded,
|
|
43084
|
+
total,
|
|
43085
|
+
message: loadingMessage,
|
|
43086
|
+
className
|
|
43087
|
+
}
|
|
43088
|
+
);
|
|
43089
|
+
}
|
|
43090
|
+
const displayError = externalError || internalError;
|
|
43091
|
+
if (displayError) {
|
|
43092
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Canvas3DErrorBoundary, { children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "game-canvas-3d game-canvas-3d--error", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "game-canvas-3d__error", children: [
|
|
43093
|
+
"Error: ",
|
|
43094
|
+
displayError
|
|
43095
|
+
] }) }) });
|
|
43096
|
+
}
|
|
43097
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
43098
|
+
Canvas3DErrorBoundary,
|
|
43099
|
+
{
|
|
43100
|
+
onError: (err) => setInternalError(err.message),
|
|
43101
|
+
onReset: () => setInternalError(null),
|
|
43102
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
43103
|
+
"div",
|
|
43104
|
+
{
|
|
43105
|
+
ref: containerRef,
|
|
43106
|
+
className: cn("game-canvas-3d relative w-full h-full min-h-[85vh] overflow-hidden", className),
|
|
43107
|
+
"data-orientation": orientation,
|
|
43108
|
+
"data-camera-mode": cameraMode,
|
|
43109
|
+
"data-overlay": overlay,
|
|
43110
|
+
children: [
|
|
43111
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
43112
|
+
fiber.Canvas,
|
|
43113
|
+
{
|
|
43114
|
+
shadows,
|
|
43115
|
+
camera: {
|
|
43116
|
+
position: cameraConfig.position,
|
|
43117
|
+
fov: cameraConfig.fov,
|
|
43118
|
+
near: 0.1,
|
|
43119
|
+
far: 1e3
|
|
43120
|
+
},
|
|
43121
|
+
style: { background: backgroundColor },
|
|
43122
|
+
onClick: (e) => {
|
|
43123
|
+
if (e.target === e.currentTarget) {
|
|
43124
|
+
eventHandlers.handleCanvasClick(e);
|
|
43125
|
+
}
|
|
43126
|
+
},
|
|
43127
|
+
children: [
|
|
43128
|
+
/* @__PURE__ */ jsxRuntime.jsx(CameraController, { onCameraChange: eventHandlers.handleCameraChange }),
|
|
43129
|
+
/* @__PURE__ */ jsxRuntime.jsx("ambientLight", { intensity: 0.6 }),
|
|
43130
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
43131
|
+
"directionalLight",
|
|
43132
|
+
{
|
|
43133
|
+
position: [10, 20, 10],
|
|
43134
|
+
intensity: 0.8,
|
|
43135
|
+
castShadow: shadows,
|
|
43136
|
+
"shadow-mapSize": [2048, 2048]
|
|
43137
|
+
}
|
|
43138
|
+
),
|
|
43139
|
+
/* @__PURE__ */ jsxRuntime.jsx("hemisphereLight", { intensity: 0.3, color: "#87ceeb", groundColor: "#362d1d" }),
|
|
43140
|
+
showGrid && /* @__PURE__ */ jsxRuntime.jsx(
|
|
43141
|
+
drei.Grid,
|
|
43142
|
+
{
|
|
43143
|
+
args: [
|
|
43144
|
+
Math.max(gridBounds.maxX - gridBounds.minX + 2, 10),
|
|
43145
|
+
Math.max(gridBounds.maxZ - gridBounds.minZ + 2, 10)
|
|
43146
|
+
],
|
|
43147
|
+
position: [
|
|
43148
|
+
(gridBounds.maxX - gridBounds.minX) / 2 - 0.5,
|
|
43149
|
+
0,
|
|
43150
|
+
(gridBounds.maxZ - gridBounds.minZ) / 2 - 0.5
|
|
43151
|
+
],
|
|
43152
|
+
cellSize: 1,
|
|
43153
|
+
cellThickness: 1,
|
|
43154
|
+
cellColor: "#444444",
|
|
43155
|
+
sectionSize: 5,
|
|
43156
|
+
sectionThickness: 1.5,
|
|
43157
|
+
sectionColor: "#666666",
|
|
43158
|
+
fadeDistance: 50,
|
|
43159
|
+
fadeStrength: 1
|
|
43160
|
+
}
|
|
43161
|
+
),
|
|
43162
|
+
tiles.map((tile, index) => {
|
|
43163
|
+
const position = gridToWorld(
|
|
43164
|
+
tile.x,
|
|
43165
|
+
tile.z ?? tile.y ?? 0,
|
|
43166
|
+
tile.elevation ?? 0
|
|
43167
|
+
);
|
|
43168
|
+
const Renderer = CustomTileRenderer || DefaultTileRenderer;
|
|
43169
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Renderer, { tile, position }, tile.id ?? `tile-${index}`);
|
|
43170
|
+
}),
|
|
43171
|
+
features.map((feature, index) => {
|
|
43172
|
+
const position = gridToWorld(
|
|
43173
|
+
feature.x,
|
|
43174
|
+
feature.z ?? feature.y ?? 0,
|
|
43175
|
+
(feature.elevation ?? 0) + 0.5
|
|
43176
|
+
);
|
|
43177
|
+
const Renderer = CustomFeatureRenderer || DefaultFeatureRenderer;
|
|
43178
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Renderer, { feature, position }, feature.id ?? `feature-${index}`);
|
|
43179
|
+
}),
|
|
43180
|
+
units.map((unit) => {
|
|
43181
|
+
const position = gridToWorld(
|
|
43182
|
+
unit.x ?? 0,
|
|
43183
|
+
unit.z ?? unit.y ?? 0,
|
|
43184
|
+
(unit.elevation ?? 0) + 0.5
|
|
43185
|
+
);
|
|
43186
|
+
const Renderer = CustomUnitRenderer || DefaultUnitRenderer;
|
|
43187
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Renderer, { unit, position }, unit.id);
|
|
43188
|
+
}),
|
|
43189
|
+
children,
|
|
43190
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
43191
|
+
drei.OrbitControls,
|
|
43192
|
+
{
|
|
43193
|
+
ref: controlsRef,
|
|
43194
|
+
target: cameraTarget,
|
|
43195
|
+
enableDamping: true,
|
|
43196
|
+
dampingFactor: 0.05,
|
|
43197
|
+
minDistance: 2,
|
|
43198
|
+
maxDistance: 100,
|
|
43199
|
+
maxPolarAngle: Math.PI / 2 - 0.1
|
|
43200
|
+
}
|
|
43201
|
+
)
|
|
43202
|
+
]
|
|
43203
|
+
}
|
|
43204
|
+
),
|
|
43205
|
+
showCoordinates && hoveredTile && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "game-canvas-3d__coordinates", children: [
|
|
43206
|
+
"X: ",
|
|
43207
|
+
hoveredTile.x,
|
|
43208
|
+
", Z: ",
|
|
43209
|
+
hoveredTile.z ?? hoveredTile.y ?? 0
|
|
43210
|
+
] }),
|
|
43211
|
+
showTileInfo && hoveredTile && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "game-canvas-3d__tile-info", children: [
|
|
43212
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "tile-info__type", children: hoveredTile.type }),
|
|
43213
|
+
hoveredTile.terrain && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "tile-info__terrain", children: hoveredTile.terrain })
|
|
43214
|
+
] })
|
|
43215
|
+
]
|
|
43216
|
+
}
|
|
43217
|
+
)
|
|
43218
|
+
}
|
|
43219
|
+
);
|
|
43220
|
+
}
|
|
43221
|
+
);
|
|
43222
|
+
GameCanvas3D.displayName = "GameCanvas3D";
|
|
43223
|
+
}
|
|
43224
|
+
});
|
|
43225
|
+
function GameBoard3D({
|
|
43226
|
+
entity,
|
|
43227
|
+
tiles = [],
|
|
43228
|
+
features = [],
|
|
43229
|
+
cameraMode = "perspective",
|
|
43230
|
+
backgroundColor = "#2a1a1a",
|
|
43231
|
+
tileClickEvent,
|
|
43232
|
+
unitClickEvent,
|
|
43233
|
+
attackEvent,
|
|
43234
|
+
endTurnEvent,
|
|
43235
|
+
cancelEvent,
|
|
43236
|
+
playAgainEvent,
|
|
43237
|
+
gameEndEvent,
|
|
43238
|
+
className
|
|
43239
|
+
}) {
|
|
43240
|
+
const row = boardEntity(entity);
|
|
43241
|
+
const eventBus = useEventBus();
|
|
43242
|
+
const entityUnits = row ? rows(row.units) : [];
|
|
43243
|
+
const units = entityUnits;
|
|
43244
|
+
const selectedUnitId = row ? str(row.selectedUnitId) || null : null;
|
|
43245
|
+
const phase = row ? str(row.phase) : "observation";
|
|
43246
|
+
const result = row ? str(row.result) : "none";
|
|
43247
|
+
const validMoves = row && Array.isArray(row.validMoves) ? row.validMoves : [];
|
|
43248
|
+
const attackTargets = row && Array.isArray(row.attackTargets) ? row.attackTargets : [];
|
|
43249
|
+
const turn = row ? num(row.turn) : 0;
|
|
43250
|
+
const currentTeam = row ? str(row.currentTeam) : "player";
|
|
43251
|
+
const isGameOver = result !== "none";
|
|
43252
|
+
const gameEndEmittedRef = React77.useRef(false);
|
|
43253
|
+
React77.useEffect(() => {
|
|
43254
|
+
if ((result === "victory" || result === "defeat") && gameEndEvent) {
|
|
43255
|
+
if (!gameEndEmittedRef.current) {
|
|
43256
|
+
gameEndEmittedRef.current = true;
|
|
43257
|
+
eventBus.emit(`UI:${gameEndEvent}`, { result });
|
|
43258
|
+
}
|
|
43259
|
+
} else {
|
|
43260
|
+
gameEndEmittedRef.current = false;
|
|
43261
|
+
}
|
|
43262
|
+
}, [result, gameEndEvent, eventBus]);
|
|
43263
|
+
const checkGameEnd = React77.useCallback(() => {
|
|
43264
|
+
const alivePlayer = entityUnits.filter((u) => unitTeam(u) === "player" && unitHealth(u) > 0);
|
|
43265
|
+
const aliveEnemy = entityUnits.filter((u) => unitTeam(u) === "enemy" && unitHealth(u) > 0);
|
|
43266
|
+
if (alivePlayer.length === 0 && gameEndEvent) {
|
|
43267
|
+
eventBus.emit(`UI:${gameEndEvent}`, { result: "defeat" });
|
|
43268
|
+
} else if (aliveEnemy.length === 0 && gameEndEvent) {
|
|
43269
|
+
eventBus.emit(`UI:${gameEndEvent}`, { result: "victory" });
|
|
43270
|
+
}
|
|
43271
|
+
}, [entityUnits, gameEndEvent, eventBus]);
|
|
43272
|
+
const handleUnitClickCallback = React77.useCallback((isoUnit) => {
|
|
43273
|
+
if (phase !== "action" || !selectedUnitId || !attackEvent) return;
|
|
43274
|
+
const attackerRow = entityUnits.find((u) => str(u.id) === selectedUnitId);
|
|
43275
|
+
const targetRow = entityUnits.find((u) => str(u.id) === isoUnit.id);
|
|
43276
|
+
if (!attackerRow || !targetRow) return;
|
|
43277
|
+
if (unitTeam(targetRow) !== "enemy" || unitHealth(targetRow) <= 0) return;
|
|
43278
|
+
const ap = unitPosition(attackerRow);
|
|
43279
|
+
const tp = unitPosition(targetRow);
|
|
43280
|
+
const dx = Math.abs(ap.x - tp.x);
|
|
43281
|
+
const dy = Math.abs(ap.y - tp.y);
|
|
43282
|
+
if (dx <= 1 && dy <= 1 && dx + dy > 0) {
|
|
43283
|
+
const damage = Math.max(1, num(attackerRow.attack) - num(targetRow.defense));
|
|
43284
|
+
eventBus.emit(`UI:${attackEvent}`, {
|
|
43285
|
+
attackerId: str(attackerRow.id),
|
|
43286
|
+
targetId: str(targetRow.id),
|
|
43287
|
+
damage
|
|
43288
|
+
});
|
|
43289
|
+
setTimeout(checkGameEnd, 100);
|
|
43290
|
+
}
|
|
43291
|
+
}, [phase, selectedUnitId, entityUnits, attackEvent, eventBus, checkGameEnd]);
|
|
43292
|
+
const handleEndTurn = React77.useCallback(() => {
|
|
43293
|
+
if (endTurnEvent) eventBus.emit(`UI:${endTurnEvent}`, {});
|
|
43294
|
+
}, [endTurnEvent, eventBus]);
|
|
43295
|
+
const handleCancel = React77.useCallback(() => {
|
|
43296
|
+
if (cancelEvent) eventBus.emit(`UI:${cancelEvent}`, {});
|
|
43297
|
+
}, [cancelEvent, eventBus]);
|
|
43298
|
+
const handlePlayAgain = React77.useCallback(() => {
|
|
43299
|
+
if (playAgainEvent) eventBus.emit(`UI:${playAgainEvent}`, {});
|
|
43300
|
+
}, [playAgainEvent, eventBus]);
|
|
43301
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(exports.VStack, { className: cn("game-board-3d block w-full min-h-[85vh] relative", className), children: [
|
|
43302
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "game-board-3d__status absolute top-3 left-3 z-10 flex gap-2 items-center", children: [
|
|
43303
|
+
/* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "small", className: "status__phase capitalize", children: phase.replace("_", " ") }),
|
|
43304
|
+
currentTeam && !isGameOver && /* @__PURE__ */ jsxRuntime.jsxs(exports.Typography, { variant: "small", color: "muted", className: "status__team", children: [
|
|
43305
|
+
"\u2014 ",
|
|
43306
|
+
currentTeam === "player" ? "Your Turn" : "Enemy's Turn"
|
|
43307
|
+
] }),
|
|
43308
|
+
/* @__PURE__ */ jsxRuntime.jsxs(exports.Typography, { variant: "small", color: "muted", className: "status__turn", children: [
|
|
43309
|
+
"Turn ",
|
|
43310
|
+
turn
|
|
43311
|
+
] })
|
|
43312
|
+
] }),
|
|
43313
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
43314
|
+
GameCanvas3D,
|
|
43315
|
+
{
|
|
43316
|
+
tiles,
|
|
43317
|
+
units,
|
|
43318
|
+
features,
|
|
43319
|
+
cameraMode,
|
|
43320
|
+
showGrid: true,
|
|
43321
|
+
showCoordinates: false,
|
|
43322
|
+
showTileInfo: false,
|
|
43323
|
+
shadows: true,
|
|
43324
|
+
backgroundColor,
|
|
43325
|
+
tileClickEvent,
|
|
43326
|
+
unitClickEvent,
|
|
43327
|
+
onUnitClick: handleUnitClickCallback,
|
|
43328
|
+
selectedUnitId,
|
|
43329
|
+
validMoves,
|
|
43330
|
+
attackTargets,
|
|
43331
|
+
className: "game-board-3d__canvas w-full min-h-[85vh]"
|
|
43332
|
+
}
|
|
43333
|
+
),
|
|
43334
|
+
!isGameOver && /* @__PURE__ */ jsxRuntime.jsxs(exports.HStack, { className: "fixed bottom-6 right-6 z-50", gap: "sm", children: [
|
|
43335
|
+
(phase === "selection" || phase === "movement" || phase === "action") && /* @__PURE__ */ jsxRuntime.jsx(
|
|
43336
|
+
exports.Button,
|
|
43337
|
+
{
|
|
43338
|
+
variant: "secondary",
|
|
43339
|
+
className: "shadow-xl",
|
|
43340
|
+
onClick: handleCancel,
|
|
43341
|
+
children: "Cancel"
|
|
43342
|
+
}
|
|
43343
|
+
),
|
|
43344
|
+
phase !== "enemy_turn" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
43345
|
+
exports.Button,
|
|
43346
|
+
{
|
|
43347
|
+
variant: "primary",
|
|
43348
|
+
className: "shadow-xl",
|
|
43349
|
+
onClick: handleEndTurn,
|
|
43350
|
+
children: "End Turn"
|
|
43351
|
+
}
|
|
43352
|
+
)
|
|
43353
|
+
] }),
|
|
43354
|
+
isGameOver && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "game-board-3d__overlay absolute inset-0 z-20 flex items-center justify-center bg-black/60", children: /* @__PURE__ */ jsxRuntime.jsxs(exports.VStack, { align: "center", gap: "md", className: "overlay__card p-8 rounded-xl bg-gray-900/90 shadow-2xl", children: [
|
|
43355
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
43356
|
+
exports.Typography,
|
|
43357
|
+
{
|
|
43358
|
+
variant: "h2",
|
|
43359
|
+
className: cn(
|
|
43360
|
+
"overlay__result",
|
|
43361
|
+
result === "victory" ? "text-yellow-400" : "text-red-500"
|
|
43362
|
+
),
|
|
43363
|
+
children: result === "victory" ? "Victory!" : "Defeat"
|
|
43364
|
+
}
|
|
43365
|
+
),
|
|
43366
|
+
/* @__PURE__ */ jsxRuntime.jsxs(exports.Typography, { variant: "body", color: "muted", className: "overlay__turn-count", children: [
|
|
43367
|
+
"Completed in ",
|
|
43368
|
+
turn,
|
|
43369
|
+
" turn",
|
|
43370
|
+
turn !== 1 ? "s" : ""
|
|
43371
|
+
] }),
|
|
43372
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
43373
|
+
exports.Button,
|
|
43374
|
+
{
|
|
43375
|
+
variant: "primary",
|
|
43376
|
+
className: "px-8 py-3 font-semibold",
|
|
43377
|
+
onClick: handlePlayAgain,
|
|
43378
|
+
children: "Play Again"
|
|
43379
|
+
}
|
|
43380
|
+
)
|
|
43381
|
+
] }) })
|
|
43382
|
+
] });
|
|
43383
|
+
}
|
|
43384
|
+
var init_GameBoard3D = __esm({
|
|
43385
|
+
"components/game/organisms/GameBoard3D.tsx"() {
|
|
43386
|
+
"use client";
|
|
43387
|
+
init_cn();
|
|
43388
|
+
init_Button();
|
|
43389
|
+
init_Typography();
|
|
43390
|
+
init_Stack();
|
|
43391
|
+
init_useEventBus();
|
|
43392
|
+
init_GameCanvas3D2();
|
|
43393
|
+
init_boardEntity();
|
|
43394
|
+
GameBoard3D.displayName = "GameBoard3D";
|
|
43395
|
+
}
|
|
43396
|
+
});
|
|
41741
43397
|
exports.GameShell = void 0;
|
|
41742
43398
|
var init_GameShell = __esm({
|
|
41743
43399
|
"components/game/templates/GameShell.tsx"() {
|
|
@@ -43388,6 +45044,236 @@ var init_NegotiatorBoard = __esm({
|
|
|
43388
45044
|
NegotiatorBoard.displayName = "NegotiatorBoard";
|
|
43389
45045
|
}
|
|
43390
45046
|
});
|
|
45047
|
+
function resolveEntity(entity) {
|
|
45048
|
+
if (!entity) return {};
|
|
45049
|
+
if (Array.isArray(entity)) return entity[0] ?? {};
|
|
45050
|
+
return entity;
|
|
45051
|
+
}
|
|
45052
|
+
function numField(row, key, fallback) {
|
|
45053
|
+
const v = row[key];
|
|
45054
|
+
return typeof v === "number" ? v : fallback;
|
|
45055
|
+
}
|
|
45056
|
+
function strField(row, key, fallback) {
|
|
45057
|
+
const v = row[key];
|
|
45058
|
+
return typeof v === "string" ? v : fallback;
|
|
45059
|
+
}
|
|
45060
|
+
function PlatformerBoard({
|
|
45061
|
+
entity,
|
|
45062
|
+
player: propPlayer,
|
|
45063
|
+
platforms: propPlatforms,
|
|
45064
|
+
result: propResult,
|
|
45065
|
+
lives: propLives,
|
|
45066
|
+
score: propScore,
|
|
45067
|
+
level: propLevel,
|
|
45068
|
+
worldWidth = 800,
|
|
45069
|
+
worldHeight = 400,
|
|
45070
|
+
canvasWidth = 800,
|
|
45071
|
+
canvasHeight = 400,
|
|
45072
|
+
playerSprite,
|
|
45073
|
+
tileSprites,
|
|
45074
|
+
bgColor,
|
|
45075
|
+
leftEvent = "LEFT",
|
|
45076
|
+
rightEvent = "RIGHT",
|
|
45077
|
+
jumpEvent = "JUMP",
|
|
45078
|
+
stopEvent = "STOP",
|
|
45079
|
+
playAgainEvent = "PLAY_AGAIN",
|
|
45080
|
+
gameEndEvent = "GAME_END",
|
|
45081
|
+
className
|
|
45082
|
+
}) {
|
|
45083
|
+
const row = resolveEntity(entity);
|
|
45084
|
+
const eventBus = useEventBus();
|
|
45085
|
+
const { t } = hooks.useTranslate();
|
|
45086
|
+
const result = propResult ?? strField(row, "result", "none");
|
|
45087
|
+
propLives ?? numField(row, "lives", 3);
|
|
45088
|
+
const score = propScore ?? numField(row, "score", 0);
|
|
45089
|
+
const level = propLevel ?? numField(row, "level", 1);
|
|
45090
|
+
const entityPlayer = row["player"];
|
|
45091
|
+
const player = propPlayer ?? entityPlayer ?? {
|
|
45092
|
+
x: 80,
|
|
45093
|
+
y: 320,
|
|
45094
|
+
width: 32,
|
|
45095
|
+
height: 48,
|
|
45096
|
+
vx: 0,
|
|
45097
|
+
vy: 0,
|
|
45098
|
+
grounded: false,
|
|
45099
|
+
facingRight: true
|
|
45100
|
+
};
|
|
45101
|
+
const entityPlatforms = Array.isArray(row["platforms"]) ? row["platforms"] : void 0;
|
|
45102
|
+
const platforms = propPlatforms ?? entityPlatforms ?? [
|
|
45103
|
+
{ x: 0, y: 368, width: 800, height: 32, type: "ground" },
|
|
45104
|
+
{ x: 150, y: 280, width: 160, height: 16, type: "platform" },
|
|
45105
|
+
{ x: 420, y: 220, width: 160, height: 16, type: "platform" },
|
|
45106
|
+
{ x: 580, y: 300, width: 80, height: 16, type: "hazard" },
|
|
45107
|
+
{ x: 700, y: 340, width: 64, height: 28, type: "goal" }
|
|
45108
|
+
];
|
|
45109
|
+
const handleRestart = React77.useCallback(() => {
|
|
45110
|
+
if (playAgainEvent) {
|
|
45111
|
+
eventBus.emit(`UI:${playAgainEvent}`, {});
|
|
45112
|
+
}
|
|
45113
|
+
}, [playAgainEvent, eventBus]);
|
|
45114
|
+
const isGameOver = result === "won" || result === "lost";
|
|
45115
|
+
const gameEndEmittedRef = React77.useRef(false);
|
|
45116
|
+
React77.useEffect(() => {
|
|
45117
|
+
if ((result === "won" || result === "lost") && gameEndEvent) {
|
|
45118
|
+
if (!gameEndEmittedRef.current) {
|
|
45119
|
+
gameEndEmittedRef.current = true;
|
|
45120
|
+
eventBus.emit(`UI:${gameEndEvent}`, { result });
|
|
45121
|
+
}
|
|
45122
|
+
} else {
|
|
45123
|
+
gameEndEmittedRef.current = false;
|
|
45124
|
+
}
|
|
45125
|
+
}, [result, gameEndEvent, eventBus]);
|
|
45126
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
45127
|
+
exports.VStack,
|
|
45128
|
+
{
|
|
45129
|
+
className: cn("platformer-board relative bg-background", className),
|
|
45130
|
+
gap: "none",
|
|
45131
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(exports.Box, { className: "relative", children: [
|
|
45132
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
45133
|
+
PlatformerCanvas,
|
|
45134
|
+
{
|
|
45135
|
+
player,
|
|
45136
|
+
platforms,
|
|
45137
|
+
worldWidth,
|
|
45138
|
+
worldHeight,
|
|
45139
|
+
canvasWidth,
|
|
45140
|
+
canvasHeight,
|
|
45141
|
+
followCamera: true,
|
|
45142
|
+
bgColor,
|
|
45143
|
+
playerSprite,
|
|
45144
|
+
tileSprites,
|
|
45145
|
+
leftEvent,
|
|
45146
|
+
rightEvent,
|
|
45147
|
+
jumpEvent,
|
|
45148
|
+
stopEvent
|
|
45149
|
+
}
|
|
45150
|
+
),
|
|
45151
|
+
isGameOver && /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: "absolute inset-0 z-50 flex items-center justify-center bg-background/70 backdrop-blur-sm rounded-container", children: /* @__PURE__ */ jsxRuntime.jsxs(exports.VStack, { className: "text-center p-8", gap: "lg", children: [
|
|
45152
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
45153
|
+
exports.Typography,
|
|
45154
|
+
{
|
|
45155
|
+
variant: "h2",
|
|
45156
|
+
className: cn(
|
|
45157
|
+
"text-4xl font-black tracking-widest uppercase",
|
|
45158
|
+
result === "won" ? "text-warning" : "text-error"
|
|
45159
|
+
),
|
|
45160
|
+
children: result === "won" ? t("platformer.won") : t("platformer.lost")
|
|
45161
|
+
}
|
|
45162
|
+
),
|
|
45163
|
+
result === "won" && /* @__PURE__ */ jsxRuntime.jsxs(exports.Typography, { variant: "body1", className: "text-muted-foreground", children: [
|
|
45164
|
+
t("platformer.level"),
|
|
45165
|
+
" ",
|
|
45166
|
+
level,
|
|
45167
|
+
" \u2014 ",
|
|
45168
|
+
t("platformer.score"),
|
|
45169
|
+
": ",
|
|
45170
|
+
score
|
|
45171
|
+
] }),
|
|
45172
|
+
result === "lost" && /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "body1", className: "text-muted-foreground", children: t("platformer.noLives") }),
|
|
45173
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
45174
|
+
exports.Button,
|
|
45175
|
+
{
|
|
45176
|
+
variant: "primary",
|
|
45177
|
+
className: "px-8 py-3 font-semibold",
|
|
45178
|
+
onClick: handleRestart,
|
|
45179
|
+
children: result === "won" ? t("platformer.nextLevel") : t("platformer.playAgain")
|
|
45180
|
+
}
|
|
45181
|
+
)
|
|
45182
|
+
] }) })
|
|
45183
|
+
] })
|
|
45184
|
+
}
|
|
45185
|
+
);
|
|
45186
|
+
}
|
|
45187
|
+
var init_PlatformerBoard = __esm({
|
|
45188
|
+
"components/game/organisms/PlatformerBoard.tsx"() {
|
|
45189
|
+
"use client";
|
|
45190
|
+
init_cn();
|
|
45191
|
+
init_useEventBus();
|
|
45192
|
+
init_Box();
|
|
45193
|
+
init_Button();
|
|
45194
|
+
init_Typography();
|
|
45195
|
+
init_Stack();
|
|
45196
|
+
init_PlatformerCanvas();
|
|
45197
|
+
PlatformerBoard.displayName = "PlatformerBoard";
|
|
45198
|
+
}
|
|
45199
|
+
});
|
|
45200
|
+
function PlatformerTemplate({
|
|
45201
|
+
entity,
|
|
45202
|
+
platforms = DEFAULT_PLATFORMS,
|
|
45203
|
+
worldWidth = 800,
|
|
45204
|
+
worldHeight = 400,
|
|
45205
|
+
canvasWidth = 800,
|
|
45206
|
+
canvasHeight = 400,
|
|
45207
|
+
playerSprite = `${CDN3}/characters/platformChar_idle.png`,
|
|
45208
|
+
tileSprites = DEFAULT_TILE_SPRITES,
|
|
45209
|
+
bgColor = "#5c94fc",
|
|
45210
|
+
gameEndEvent = "GAME_END",
|
|
45211
|
+
className
|
|
45212
|
+
}) {
|
|
45213
|
+
const row = entity && !Array.isArray(entity) ? entity : void 0;
|
|
45214
|
+
const lives = typeof row?.["lives"] === "number" ? row["lives"] : 3;
|
|
45215
|
+
const score = typeof row?.["score"] === "number" ? row["score"] : 0;
|
|
45216
|
+
const level = typeof row?.["level"] === "number" ? row["level"] : 1;
|
|
45217
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(exports.VStack, { className: cn("platformer-template w-full", className), gap: "none", children: [
|
|
45218
|
+
/* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: "relative", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
45219
|
+
GameHud,
|
|
45220
|
+
{
|
|
45221
|
+
position: "top",
|
|
45222
|
+
stats: [
|
|
45223
|
+
{ label: "Lives", value: lives, format: "number", variant: "danger" },
|
|
45224
|
+
{ label: "Level", value: level, format: "number", variant: "default" }
|
|
45225
|
+
]
|
|
45226
|
+
}
|
|
45227
|
+
) }),
|
|
45228
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
45229
|
+
PlatformerBoard,
|
|
45230
|
+
{
|
|
45231
|
+
entity,
|
|
45232
|
+
platforms,
|
|
45233
|
+
worldWidth,
|
|
45234
|
+
worldHeight,
|
|
45235
|
+
canvasWidth,
|
|
45236
|
+
canvasHeight,
|
|
45237
|
+
playerSprite,
|
|
45238
|
+
tileSprites,
|
|
45239
|
+
bgColor,
|
|
45240
|
+
leftEvent: "LEFT",
|
|
45241
|
+
rightEvent: "RIGHT",
|
|
45242
|
+
jumpEvent: "JUMP",
|
|
45243
|
+
stopEvent: "STOP",
|
|
45244
|
+
playAgainEvent: "PLAY_AGAIN",
|
|
45245
|
+
gameEndEvent
|
|
45246
|
+
}
|
|
45247
|
+
),
|
|
45248
|
+
/* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: "px-4 py-2", children: /* @__PURE__ */ jsxRuntime.jsx(ScoreBoard, { score, level }) })
|
|
45249
|
+
] });
|
|
45250
|
+
}
|
|
45251
|
+
var CDN3, DEFAULT_TILE_SPRITES, DEFAULT_PLATFORMS;
|
|
45252
|
+
var init_PlatformerTemplate = __esm({
|
|
45253
|
+
"components/game/templates/PlatformerTemplate.tsx"() {
|
|
45254
|
+
init_cn();
|
|
45255
|
+
init_Box();
|
|
45256
|
+
init_Stack();
|
|
45257
|
+
init_PlatformerBoard();
|
|
45258
|
+
init_GameHud();
|
|
45259
|
+
init_ScoreBoard();
|
|
45260
|
+
CDN3 = "https://almadar-kflow-assets.web.app/shared/platformer";
|
|
45261
|
+
DEFAULT_TILE_SPRITES = {
|
|
45262
|
+
ground: `${CDN3}/tiles/platformPack_tile001.png`,
|
|
45263
|
+
platform: `${CDN3}/tiles/platformPack_tile004.png`,
|
|
45264
|
+
hazard: `${CDN3}/tiles/platformPack_tile017.png`,
|
|
45265
|
+
goal: `${CDN3}/tiles/platformPack_tile007.png`
|
|
45266
|
+
};
|
|
45267
|
+
DEFAULT_PLATFORMS = [
|
|
45268
|
+
{ x: 0, y: 368, width: 800, height: 32, type: "ground" },
|
|
45269
|
+
{ x: 150, y: 280, width: 160, height: 16, type: "platform" },
|
|
45270
|
+
{ x: 420, y: 220, width: 160, height: 16, type: "platform" },
|
|
45271
|
+
{ x: 580, y: 300, width: 80, height: 16, type: "hazard" },
|
|
45272
|
+
{ x: 700, y: 340, width: 64, height: 28, type: "goal" }
|
|
45273
|
+
];
|
|
45274
|
+
PlatformerTemplate.displayName = "PlatformerTemplate";
|
|
45275
|
+
}
|
|
45276
|
+
});
|
|
43391
45277
|
exports.PricingOrganism = void 0;
|
|
43392
45278
|
var init_PricingOrganism = __esm({
|
|
43393
45279
|
"components/marketing/organisms/PricingOrganism.tsx"() {
|
|
@@ -43511,7 +45397,7 @@ var init_PricingPageTemplate = __esm({
|
|
|
43511
45397
|
}
|
|
43512
45398
|
});
|
|
43513
45399
|
function ResourceCounter({
|
|
43514
|
-
assetUrl =
|
|
45400
|
+
assetUrl = DEFAULT_ASSET_URL12,
|
|
43515
45401
|
icon,
|
|
43516
45402
|
label = "Gold",
|
|
43517
45403
|
value = 250,
|
|
@@ -43554,7 +45440,7 @@ function ResourceCounter({
|
|
|
43554
45440
|
}
|
|
43555
45441
|
);
|
|
43556
45442
|
}
|
|
43557
|
-
var colorTokenClasses2,
|
|
45443
|
+
var colorTokenClasses2, DEFAULT_ASSET_URL12, sizeMap15;
|
|
43558
45444
|
var init_ResourceCounter = __esm({
|
|
43559
45445
|
"components/game/atoms/ResourceCounter.tsx"() {
|
|
43560
45446
|
init_cn();
|
|
@@ -43567,7 +45453,7 @@ var init_ResourceCounter = __esm({
|
|
|
43567
45453
|
error: "text-error",
|
|
43568
45454
|
muted: "text-muted-foreground"
|
|
43569
45455
|
};
|
|
43570
|
-
|
|
45456
|
+
DEFAULT_ASSET_URL12 = "https://almadar-kflow-assets.web.app/shared/world-map/gold_mine.png";
|
|
43571
45457
|
sizeMap15 = {
|
|
43572
45458
|
sm: { wrapper: "text-xs gap-1 px-1.5 py-0.5", icon: "text-sm", img: 16 },
|
|
43573
45459
|
md: { wrapper: "text-sm gap-1.5 px-2 py-1", icon: "text-base", img: 20 },
|
|
@@ -43576,6 +45462,356 @@ var init_ResourceCounter = __esm({
|
|
|
43576
45462
|
ResourceCounter.displayName = "ResourceCounter";
|
|
43577
45463
|
}
|
|
43578
45464
|
});
|
|
45465
|
+
function RoguelikeBoard({
|
|
45466
|
+
entity,
|
|
45467
|
+
tiles: propTiles,
|
|
45468
|
+
enemies: propEnemies,
|
|
45469
|
+
items: propItems,
|
|
45470
|
+
player: propPlayer,
|
|
45471
|
+
playerHp: propPlayerHp,
|
|
45472
|
+
playerMaxHp: propPlayerMaxHp,
|
|
45473
|
+
playerAttack: propPlayerAttack,
|
|
45474
|
+
depth: propDepth,
|
|
45475
|
+
result: propResult,
|
|
45476
|
+
phase: propPhase,
|
|
45477
|
+
stairsX: propStairsX,
|
|
45478
|
+
stairsY: propStairsY,
|
|
45479
|
+
assetManifest: propAssetManifest,
|
|
45480
|
+
scale = 0.45,
|
|
45481
|
+
unitScale = 1,
|
|
45482
|
+
moveEvent,
|
|
45483
|
+
playAgainEvent,
|
|
45484
|
+
gameEndEvent,
|
|
45485
|
+
className
|
|
45486
|
+
}) {
|
|
45487
|
+
const board = boardEntity(entity) ?? {};
|
|
45488
|
+
const tiles = propTiles ?? (Array.isArray(board.tiles) ? board.tiles : DEFAULT_TILES2);
|
|
45489
|
+
const enemies = propEnemies ?? (Array.isArray(board.enemies) ? board.enemies : DEFAULT_ENEMIES);
|
|
45490
|
+
const items = propItems ?? (Array.isArray(board.items) ? board.items : DEFAULT_ITEMS);
|
|
45491
|
+
const player = propPlayer ?? board.player ?? { x: 1, y: 1 };
|
|
45492
|
+
const playerHp = propPlayerHp ?? num(board.playerHp, 10);
|
|
45493
|
+
const playerMaxHp = propPlayerMaxHp ?? num(board.playerMaxHp, 10);
|
|
45494
|
+
const playerAttack = propPlayerAttack ?? num(board.playerAttack, 3);
|
|
45495
|
+
const depth = propDepth ?? num(board.depth, 1);
|
|
45496
|
+
const result = propResult ?? (str(board.result) || "none");
|
|
45497
|
+
const phase = propPhase ?? (str(board.phase) || "player_turn");
|
|
45498
|
+
propStairsX ?? num(board.stairsX, 3);
|
|
45499
|
+
propStairsY ?? num(board.stairsY, 3);
|
|
45500
|
+
const eventBus = useEventBus();
|
|
45501
|
+
const { t } = hooks.useTranslate();
|
|
45502
|
+
const [hoveredTile, setHoveredTile] = React77.useState(null);
|
|
45503
|
+
const emitMove = React77.useCallback((dx, dy) => {
|
|
45504
|
+
if (!moveEvent) return;
|
|
45505
|
+
eventBus.emit(`UI:${moveEvent}`, { dx, dy });
|
|
45506
|
+
}, [moveEvent, eventBus]);
|
|
45507
|
+
React77.useEffect(() => {
|
|
45508
|
+
const handler = (e) => {
|
|
45509
|
+
if (result !== "none" || phase !== "player_turn") return;
|
|
45510
|
+
if (e.key === "ArrowUp" || e.key === "w") emitMove(0, -1);
|
|
45511
|
+
if (e.key === "ArrowDown" || e.key === "s") emitMove(0, 1);
|
|
45512
|
+
if (e.key === "ArrowLeft" || e.key === "a") emitMove(-1, 0);
|
|
45513
|
+
if (e.key === "ArrowRight" || e.key === "d") emitMove(1, 0);
|
|
45514
|
+
};
|
|
45515
|
+
window.addEventListener("keydown", handler);
|
|
45516
|
+
return () => window.removeEventListener("keydown", handler);
|
|
45517
|
+
}, [result, phase, emitMove]);
|
|
45518
|
+
React77.useEffect(() => {
|
|
45519
|
+
if ((result === "won" || result === "lost") && gameEndEvent) {
|
|
45520
|
+
eventBus.emit(`UI:${gameEndEvent}`, { result });
|
|
45521
|
+
}
|
|
45522
|
+
}, [result, gameEndEvent, eventBus]);
|
|
45523
|
+
const handleTileClick = React77.useCallback((x, y) => {
|
|
45524
|
+
if (result !== "none" || phase !== "player_turn") return;
|
|
45525
|
+
const dx = x - player.x;
|
|
45526
|
+
const dy = y - player.y;
|
|
45527
|
+
if (Math.abs(dx) + Math.abs(dy) === 1) {
|
|
45528
|
+
emitMove(dx, dy);
|
|
45529
|
+
}
|
|
45530
|
+
}, [result, phase, player, emitMove]);
|
|
45531
|
+
const handleReset = React77.useCallback(() => {
|
|
45532
|
+
if (!playAgainEvent) return;
|
|
45533
|
+
eventBus.emit(`UI:${playAgainEvent}`, {});
|
|
45534
|
+
}, [playAgainEvent, eventBus]);
|
|
45535
|
+
const isoUnits = React77.useMemo(() => {
|
|
45536
|
+
const liveEnemies = enemies.filter((e) => e.hp > 0);
|
|
45537
|
+
return [
|
|
45538
|
+
{
|
|
45539
|
+
id: "player",
|
|
45540
|
+
position: player,
|
|
45541
|
+
name: t("roguelike.player") || "Hero",
|
|
45542
|
+
team: "player",
|
|
45543
|
+
health: playerHp,
|
|
45544
|
+
maxHealth: playerMaxHp,
|
|
45545
|
+
unitType: "player",
|
|
45546
|
+
sprite: `${CDN4}/isometric-dungeon/Characters/Male/Male_0_Idle0.png`
|
|
45547
|
+
},
|
|
45548
|
+
...liveEnemies.map((e) => ({
|
|
45549
|
+
id: e.id,
|
|
45550
|
+
position: { x: e.x, y: e.y },
|
|
45551
|
+
name: t("roguelike.enemy") || "Enemy",
|
|
45552
|
+
team: "enemy",
|
|
45553
|
+
health: e.hp,
|
|
45554
|
+
maxHealth: 6,
|
|
45555
|
+
unitType: "enemy",
|
|
45556
|
+
sprite: `${CDN4}/sprite-sheets/shadow-legion-sprite-sheet-sw.png`
|
|
45557
|
+
}))
|
|
45558
|
+
];
|
|
45559
|
+
}, [player, enemies, playerHp, playerMaxHp, t]);
|
|
45560
|
+
const isoFeatures = React77.useMemo(
|
|
45561
|
+
() => items.map((it) => ({
|
|
45562
|
+
id: it.id,
|
|
45563
|
+
x: it.x,
|
|
45564
|
+
y: it.y,
|
|
45565
|
+
type: it.kind,
|
|
45566
|
+
sprite: FEATURE_SPRITE[it.kind] ?? FEATURE_SPRITE.health_potion
|
|
45567
|
+
})),
|
|
45568
|
+
[items]
|
|
45569
|
+
);
|
|
45570
|
+
const validMoves = React77.useMemo(() => {
|
|
45571
|
+
if (result !== "none" || phase !== "player_turn") return [];
|
|
45572
|
+
const dirs = [{ dx: 0, dy: -1 }, { dx: 0, dy: 1 }, { dx: -1, dy: 0 }, { dx: 1, dy: 0 }];
|
|
45573
|
+
return dirs.map(({ dx, dy }) => ({ x: player.x + dx, y: player.y + dy })).filter(({ x, y }) => {
|
|
45574
|
+
const tile = tiles.find((t2) => t2.x === x && t2.y === y);
|
|
45575
|
+
return tile?.passable ?? false;
|
|
45576
|
+
});
|
|
45577
|
+
}, [result, phase, player, tiles]);
|
|
45578
|
+
const isGameOver = result === "won" || result === "lost";
|
|
45579
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(exports.VStack, { className: cn("roguelike-board relative min-h-[600px] bg-background", className), gap: "none", children: [
|
|
45580
|
+
/* @__PURE__ */ jsxRuntime.jsxs(exports.HStack, { className: "items-center justify-between px-4 py-2 border-b border-border", gap: "md", children: [
|
|
45581
|
+
/* @__PURE__ */ jsxRuntime.jsxs(exports.HStack, { gap: "sm", className: "items-center", children: [
|
|
45582
|
+
/* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "body2", className: "text-muted-foreground", children: t("roguelike.depth") || "Depth" }),
|
|
45583
|
+
/* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "body1", className: "font-bold tabular-nums", children: depth })
|
|
45584
|
+
] }),
|
|
45585
|
+
/* @__PURE__ */ jsxRuntime.jsxs(exports.HStack, { gap: "sm", className: "items-center", children: [
|
|
45586
|
+
/* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "body2", className: "text-muted-foreground", children: t("roguelike.hp") || "HP" }),
|
|
45587
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
45588
|
+
exports.Typography,
|
|
45589
|
+
{
|
|
45590
|
+
variant: "body1",
|
|
45591
|
+
className: cn(
|
|
45592
|
+
"font-bold tabular-nums",
|
|
45593
|
+
playerHp <= Math.floor(playerMaxHp * 0.25) ? "text-error" : "text-success"
|
|
45594
|
+
),
|
|
45595
|
+
children: [
|
|
45596
|
+
playerHp,
|
|
45597
|
+
" / ",
|
|
45598
|
+
playerMaxHp
|
|
45599
|
+
]
|
|
45600
|
+
}
|
|
45601
|
+
)
|
|
45602
|
+
] }),
|
|
45603
|
+
/* @__PURE__ */ jsxRuntime.jsxs(exports.HStack, { gap: "sm", className: "items-center", children: [
|
|
45604
|
+
/* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "body2", className: "text-muted-foreground", children: t("roguelike.atk") || "ATK" }),
|
|
45605
|
+
/* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "body1", className: "font-bold tabular-nums text-foreground", children: playerAttack })
|
|
45606
|
+
] }),
|
|
45607
|
+
/* @__PURE__ */ jsxRuntime.jsxs(exports.HStack, { gap: "sm", className: "items-center", children: [
|
|
45608
|
+
/* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "body2", className: "text-muted-foreground", children: t("roguelike.phase") || "Phase" }),
|
|
45609
|
+
/* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "body2", className: "capitalize text-foreground", children: phase.replace("_", " ") })
|
|
45610
|
+
] })
|
|
45611
|
+
] }),
|
|
45612
|
+
/* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: "relative flex-1", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
45613
|
+
IsometricCanvas_default,
|
|
45614
|
+
{
|
|
45615
|
+
tiles,
|
|
45616
|
+
units: isoUnits,
|
|
45617
|
+
features: isoFeatures,
|
|
45618
|
+
selectedUnitId: null,
|
|
45619
|
+
validMoves,
|
|
45620
|
+
attackTargets: [],
|
|
45621
|
+
hoveredTile,
|
|
45622
|
+
onTileClick: handleTileClick,
|
|
45623
|
+
onUnitClick: () => void 0,
|
|
45624
|
+
onTileHover: (x, y) => setHoveredTile({ x, y }),
|
|
45625
|
+
onTileLeave: () => setHoveredTile(null),
|
|
45626
|
+
scale,
|
|
45627
|
+
assetBaseUrl: propAssetManifest?.baseUrl ?? CDN4,
|
|
45628
|
+
assetManifest: propAssetManifest,
|
|
45629
|
+
unitScale
|
|
45630
|
+
}
|
|
45631
|
+
) }),
|
|
45632
|
+
!isGameOver && /* @__PURE__ */ jsxRuntime.jsx(exports.HStack, { className: "justify-center gap-2 p-3", gap: "none", children: [
|
|
45633
|
+
{ label: "\u2191", dx: 0, dy: -1 },
|
|
45634
|
+
{ label: "\u2193", dx: 0, dy: 1 },
|
|
45635
|
+
{ label: "\u2190", dx: -1, dy: 0 },
|
|
45636
|
+
{ label: "\u2192", dx: 1, dy: 0 }
|
|
45637
|
+
].map(({ label, dx, dy }) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
45638
|
+
exports.Button,
|
|
45639
|
+
{
|
|
45640
|
+
variant: "secondary",
|
|
45641
|
+
className: "w-9 h-9 p-0 text-base font-mono",
|
|
45642
|
+
onClick: () => emitMove(dx, dy),
|
|
45643
|
+
disabled: phase !== "player_turn",
|
|
45644
|
+
children: label
|
|
45645
|
+
},
|
|
45646
|
+
label
|
|
45647
|
+
)) }),
|
|
45648
|
+
isGameOver && /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: "absolute inset-0 z-50 flex items-center justify-center bg-background/75 backdrop-blur-sm rounded-container", children: /* @__PURE__ */ jsxRuntime.jsxs(exports.VStack, { className: "text-center p-8", gap: "lg", children: [
|
|
45649
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
45650
|
+
exports.Typography,
|
|
45651
|
+
{
|
|
45652
|
+
variant: "h2",
|
|
45653
|
+
className: cn(
|
|
45654
|
+
"text-4xl font-black tracking-widest uppercase",
|
|
45655
|
+
result === "won" ? "text-warning" : "text-error"
|
|
45656
|
+
),
|
|
45657
|
+
children: result === "won" ? t("roguelike.victory") || "Victory!" : t("roguelike.defeat") || "Defeated!"
|
|
45658
|
+
}
|
|
45659
|
+
),
|
|
45660
|
+
result === "won" && /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "body1", className: "text-muted-foreground", children: t("roguelike.cleared") || `Dungeon cleared! Depth reached: ${depth}` }),
|
|
45661
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
45662
|
+
exports.Button,
|
|
45663
|
+
{
|
|
45664
|
+
variant: "primary",
|
|
45665
|
+
className: "px-8 py-3 font-semibold",
|
|
45666
|
+
onClick: handleReset,
|
|
45667
|
+
children: t("roguelike.playAgain") || "Play Again"
|
|
45668
|
+
}
|
|
45669
|
+
)
|
|
45670
|
+
] }) })
|
|
45671
|
+
] });
|
|
45672
|
+
}
|
|
45673
|
+
var CDN4, DEFAULT_TILES2, DEFAULT_ENEMIES, DEFAULT_ITEMS, FEATURE_SPRITE;
|
|
45674
|
+
var init_RoguelikeBoard = __esm({
|
|
45675
|
+
"components/game/organisms/RoguelikeBoard.tsx"() {
|
|
45676
|
+
"use client";
|
|
45677
|
+
init_cn();
|
|
45678
|
+
init_useEventBus();
|
|
45679
|
+
init_Box();
|
|
45680
|
+
init_Button();
|
|
45681
|
+
init_Typography();
|
|
45682
|
+
init_Stack();
|
|
45683
|
+
init_IsometricCanvas();
|
|
45684
|
+
init_boardEntity();
|
|
45685
|
+
CDN4 = "https://almadar-kflow-assets.web.app/shared";
|
|
45686
|
+
DEFAULT_TILES2 = [
|
|
45687
|
+
{ x: 0, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45688
|
+
{ x: 1, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45689
|
+
{ x: 2, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45690
|
+
{ x: 3, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45691
|
+
{ x: 4, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45692
|
+
{ x: 0, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45693
|
+
{ x: 1, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
|
|
45694
|
+
{ x: 2, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
|
|
45695
|
+
{ x: 3, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
|
|
45696
|
+
{ x: 4, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45697
|
+
{ x: 0, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45698
|
+
{ x: 1, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png` },
|
|
45699
|
+
{ x: 2, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png` },
|
|
45700
|
+
{ x: 3, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
|
|
45701
|
+
{ x: 4, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45702
|
+
{ x: 0, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45703
|
+
{ x: 1, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
|
|
45704
|
+
{ x: 2, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png` },
|
|
45705
|
+
{ x: 3, y: 3, terrain: "stairs", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stairs_E.png` },
|
|
45706
|
+
{ x: 4, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45707
|
+
{ x: 0, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45708
|
+
{ x: 1, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45709
|
+
{ x: 2, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45710
|
+
{ x: 3, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45711
|
+
{ x: 4, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` }
|
|
45712
|
+
];
|
|
45713
|
+
DEFAULT_ENEMIES = [
|
|
45714
|
+
{ id: "e1", x: 3, y: 1, hp: 5, attack: 2 },
|
|
45715
|
+
{ id: "e2", x: 1, y: 3, hp: 4, attack: 1 }
|
|
45716
|
+
];
|
|
45717
|
+
DEFAULT_ITEMS = [
|
|
45718
|
+
{ id: "i1", x: 2, y: 2, kind: "health_potion" }
|
|
45719
|
+
];
|
|
45720
|
+
FEATURE_SPRITE = {
|
|
45721
|
+
health_potion: `${CDN4}/isometric-dungeon/Isometric/chestClosed_E.png`,
|
|
45722
|
+
sword: `${CDN4}/isometric-dungeon/Isometric/barrel_E.png`,
|
|
45723
|
+
shield: `${CDN4}/isometric-dungeon/Isometric/barrel_E.png`
|
|
45724
|
+
};
|
|
45725
|
+
RoguelikeBoard.displayName = "RoguelikeBoard";
|
|
45726
|
+
}
|
|
45727
|
+
});
|
|
45728
|
+
function RoguelikeTemplate({
|
|
45729
|
+
entity,
|
|
45730
|
+
scale = 0.45,
|
|
45731
|
+
unitScale = 1,
|
|
45732
|
+
tiles = DEFAULT_ROGUELIKE_TILES,
|
|
45733
|
+
enemies,
|
|
45734
|
+
items,
|
|
45735
|
+
stairsX,
|
|
45736
|
+
stairsY,
|
|
45737
|
+
assetManifest = DEFAULT_ROGUELIKE_MANIFEST,
|
|
45738
|
+
gameEndEvent,
|
|
45739
|
+
className
|
|
45740
|
+
}) {
|
|
45741
|
+
const resolved = entity && typeof entity === "object" && !Array.isArray(entity) ? entity : void 0;
|
|
45742
|
+
if (!resolved && !tiles && !assetManifest) return null;
|
|
45743
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
45744
|
+
RoguelikeBoard,
|
|
45745
|
+
{
|
|
45746
|
+
entity: resolved,
|
|
45747
|
+
tiles,
|
|
45748
|
+
enemies,
|
|
45749
|
+
items,
|
|
45750
|
+
stairsX,
|
|
45751
|
+
stairsY,
|
|
45752
|
+
assetManifest,
|
|
45753
|
+
scale,
|
|
45754
|
+
unitScale,
|
|
45755
|
+
moveEvent: "MOVE",
|
|
45756
|
+
playAgainEvent: "PLAY_AGAIN",
|
|
45757
|
+
gameEndEvent: gameEndEvent ?? "GAME_END",
|
|
45758
|
+
className
|
|
45759
|
+
}
|
|
45760
|
+
);
|
|
45761
|
+
}
|
|
45762
|
+
var CDN5, DEFAULT_ROGUELIKE_TILES, DEFAULT_ROGUELIKE_MANIFEST;
|
|
45763
|
+
var init_RoguelikeTemplate = __esm({
|
|
45764
|
+
"components/game/templates/RoguelikeTemplate.tsx"() {
|
|
45765
|
+
init_RoguelikeBoard();
|
|
45766
|
+
CDN5 = "https://almadar-kflow-assets.web.app/shared";
|
|
45767
|
+
DEFAULT_ROGUELIKE_TILES = [
|
|
45768
|
+
{ x: 0, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45769
|
+
{ x: 1, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45770
|
+
{ x: 2, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45771
|
+
{ x: 3, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45772
|
+
{ x: 4, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45773
|
+
{ x: 0, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45774
|
+
{ x: 1, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirt_E.png` },
|
|
45775
|
+
{ x: 2, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirt_E.png` },
|
|
45776
|
+
{ x: 3, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirt_E.png` },
|
|
45777
|
+
{ x: 4, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45778
|
+
{ x: 0, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45779
|
+
{ x: 1, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirtTiles_E.png` },
|
|
45780
|
+
{ x: 2, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirtTiles_E.png` },
|
|
45781
|
+
{ x: 3, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirt_E.png` },
|
|
45782
|
+
{ x: 4, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45783
|
+
{ x: 0, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45784
|
+
{ x: 1, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirt_E.png` },
|
|
45785
|
+
{ x: 2, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirtTiles_E.png` },
|
|
45786
|
+
{ x: 3, y: 3, terrain: "stairs", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stairs_E.png` },
|
|
45787
|
+
{ x: 4, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45788
|
+
{ x: 0, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45789
|
+
{ x: 1, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45790
|
+
{ x: 2, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45791
|
+
{ x: 3, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
45792
|
+
{ x: 4, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` }
|
|
45793
|
+
];
|
|
45794
|
+
DEFAULT_ROGUELIKE_MANIFEST = {
|
|
45795
|
+
baseUrl: CDN5,
|
|
45796
|
+
terrains: {
|
|
45797
|
+
floor: "/isometric-dungeon/Isometric/dirt_E.png",
|
|
45798
|
+
wall: "/isometric-dungeon/Isometric/stoneInset_E.png",
|
|
45799
|
+
stairs: "/isometric-dungeon/Isometric/stairs_E.png",
|
|
45800
|
+
planks: "/isometric-dungeon/Isometric/planks_E.png"
|
|
45801
|
+
},
|
|
45802
|
+
units: {
|
|
45803
|
+
player: "/isometric-dungeon/Characters/Male/Male_0_Idle0.png",
|
|
45804
|
+
enemy: "/sprite-sheets/shadow-legion-sprite-sheet-sw.png"
|
|
45805
|
+
},
|
|
45806
|
+
features: {
|
|
45807
|
+
health_potion: "/isometric-dungeon/Isometric/chestClosed_E.png",
|
|
45808
|
+
sword: "/isometric-dungeon/Isometric/barrel_E.png",
|
|
45809
|
+
shield: "/isometric-dungeon/Isometric/barrel_E.png"
|
|
45810
|
+
}
|
|
45811
|
+
};
|
|
45812
|
+
RoguelikeTemplate.displayName = "RoguelikeTemplate";
|
|
45813
|
+
}
|
|
45814
|
+
});
|
|
43579
45815
|
|
|
43580
45816
|
// lib/traitRegistry.ts
|
|
43581
45817
|
function getAllTraits() {
|
|
@@ -44810,7 +47046,7 @@ function getAllEvents(traits2) {
|
|
|
44810
47046
|
function EventDispatcherTab({ traits: traits2, schema }) {
|
|
44811
47047
|
const eventBus = useEventBus();
|
|
44812
47048
|
const { t } = hooks.useTranslate();
|
|
44813
|
-
const [
|
|
47049
|
+
const [log11, setLog] = React77__namespace.useState([]);
|
|
44814
47050
|
const prevStatesRef = React77__namespace.useRef(/* @__PURE__ */ new Map());
|
|
44815
47051
|
React77__namespace.useEffect(() => {
|
|
44816
47052
|
for (const trait of traits2) {
|
|
@@ -44874,9 +47110,9 @@ function EventDispatcherTab({ traits: traits2, schema }) {
|
|
|
44874
47110
|
/* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "small", weight: "medium", className: "text-gray-500 mb-1", children: t("debug.otherEvents") }),
|
|
44875
47111
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-1", children: unavailableEvents.map((event) => /* @__PURE__ */ jsxRuntime.jsx(exports.Badge, { variant: "default", size: "sm", className: "opacity-50", children: event }, event)) })
|
|
44876
47112
|
] }),
|
|
44877
|
-
|
|
47113
|
+
log11.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
44878
47114
|
/* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "small", weight: "medium", className: "text-gray-500 mb-1", children: t("debug.recentTransitions") }),
|
|
44879
|
-
/* @__PURE__ */ jsxRuntime.jsx(exports.Stack, { gap: "xs", children:
|
|
47115
|
+
/* @__PURE__ */ jsxRuntime.jsx(exports.Stack, { gap: "xs", children: log11.map((entry, i) => /* @__PURE__ */ jsxRuntime.jsxs(exports.Typography, { variant: "small", className: "font-mono text-xs", children: [
|
|
44880
47116
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-purple-400", children: entry.traitName }),
|
|
44881
47117
|
" ",
|
|
44882
47118
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-gray-500", children: entry.from }),
|
|
@@ -46908,9 +49144,9 @@ function VariablePanel({
|
|
|
46908
49144
|
/* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "body2", className: "text-muted-foreground font-medium", children: t("stateArchitect.variables", { name: entityName }) }),
|
|
46909
49145
|
variables.map((v) => {
|
|
46910
49146
|
const name = v.name == null ? "" : String(v.name);
|
|
46911
|
-
const value =
|
|
46912
|
-
const max =
|
|
46913
|
-
const min =
|
|
49147
|
+
const value = numField2(v.value);
|
|
49148
|
+
const max = numField2(v.max, 100);
|
|
49149
|
+
const min = numField2(v.min, 0);
|
|
46914
49150
|
const unit = v.unit == null ? "" : String(v.unit);
|
|
46915
49151
|
const pct = Math.round((value - min) / (max - min) * 100);
|
|
46916
49152
|
const isHigh = pct > 80;
|
|
@@ -46940,12 +49176,12 @@ function VariablePanel({
|
|
|
46940
49176
|
})
|
|
46941
49177
|
] });
|
|
46942
49178
|
}
|
|
46943
|
-
var
|
|
49179
|
+
var numField2;
|
|
46944
49180
|
var init_VariablePanel = __esm({
|
|
46945
49181
|
"components/game/organisms/puzzles/state-architect/VariablePanel.tsx"() {
|
|
46946
49182
|
init_atoms2();
|
|
46947
49183
|
init_cn();
|
|
46948
|
-
|
|
49184
|
+
numField2 = (v, fallback = 0) => {
|
|
46949
49185
|
const n = Number(v);
|
|
46950
49186
|
return Number.isFinite(n) ? n : fallback;
|
|
46951
49187
|
};
|
|
@@ -47372,7 +49608,7 @@ function formatDuration(seconds) {
|
|
|
47372
49608
|
return `${Math.round(seconds)}s`;
|
|
47373
49609
|
}
|
|
47374
49610
|
function StatusEffect({
|
|
47375
|
-
assetUrl =
|
|
49611
|
+
assetUrl = DEFAULT_ASSET_URL13,
|
|
47376
49612
|
icon = "shield",
|
|
47377
49613
|
label = "Shield",
|
|
47378
49614
|
duration = 30,
|
|
@@ -47430,12 +49666,12 @@ function StatusEffect({
|
|
|
47430
49666
|
label && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground mt-0.5 text-center whitespace-nowrap", children: label })
|
|
47431
49667
|
] });
|
|
47432
49668
|
}
|
|
47433
|
-
var
|
|
49669
|
+
var DEFAULT_ASSET_URL13, sizeMap16, variantStyles9;
|
|
47434
49670
|
var init_StatusEffect = __esm({
|
|
47435
49671
|
"components/game/atoms/StatusEffect.tsx"() {
|
|
47436
49672
|
init_cn();
|
|
47437
49673
|
init_Icon();
|
|
47438
|
-
|
|
49674
|
+
DEFAULT_ASSET_URL13 = "https://almadar-kflow-assets.web.app/shared/effects/particles/flame_01.png";
|
|
47439
49675
|
sizeMap16 = {
|
|
47440
49676
|
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 },
|
|
47441
49677
|
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 },
|
|
@@ -47932,6 +50168,289 @@ var init_ToastSlot = __esm({
|
|
|
47932
50168
|
exports.ToastSlot.displayName = "ToastSlot";
|
|
47933
50169
|
}
|
|
47934
50170
|
});
|
|
50171
|
+
function tilesToIso(tiles) {
|
|
50172
|
+
return tiles.map((t) => ({
|
|
50173
|
+
x: t.x,
|
|
50174
|
+
y: t.y,
|
|
50175
|
+
terrain: t.terrain,
|
|
50176
|
+
terrainSprite: t.terrainSprite ?? TERRAIN_SPRITES[t.terrain ?? "ground"],
|
|
50177
|
+
passable: t.passable
|
|
50178
|
+
}));
|
|
50179
|
+
}
|
|
50180
|
+
function towersToUnits(towers) {
|
|
50181
|
+
return towers.map((t) => ({
|
|
50182
|
+
id: t.id,
|
|
50183
|
+
position: { x: t.x, y: t.y },
|
|
50184
|
+
name: "Tower",
|
|
50185
|
+
team: "player",
|
|
50186
|
+
sprite: TOWER_SPRITE,
|
|
50187
|
+
unitType: "guardian",
|
|
50188
|
+
health: 1,
|
|
50189
|
+
maxHealth: 1
|
|
50190
|
+
}));
|
|
50191
|
+
}
|
|
50192
|
+
function creepsToUnits(creeps) {
|
|
50193
|
+
return creeps.map((c) => ({
|
|
50194
|
+
id: c.id,
|
|
50195
|
+
position: { x: c.x, y: c.y },
|
|
50196
|
+
name: "Creep",
|
|
50197
|
+
team: "enemy",
|
|
50198
|
+
sprite: CREEP_SPRITE,
|
|
50199
|
+
unitType: "scrapper",
|
|
50200
|
+
health: c.hp,
|
|
50201
|
+
maxHealth: c.maxHp
|
|
50202
|
+
}));
|
|
50203
|
+
}
|
|
50204
|
+
function pathToFeatures(path) {
|
|
50205
|
+
return path.map((p2, i) => ({
|
|
50206
|
+
id: `path-${i}`,
|
|
50207
|
+
x: p2.x,
|
|
50208
|
+
y: p2.y,
|
|
50209
|
+
type: "path-marker",
|
|
50210
|
+
sprite: `${CDN6}world-map/road_straight.png`
|
|
50211
|
+
}));
|
|
50212
|
+
}
|
|
50213
|
+
function TowerDefenseBoard({
|
|
50214
|
+
entity,
|
|
50215
|
+
tiles: propTiles,
|
|
50216
|
+
path: propPath,
|
|
50217
|
+
towers: propTowers,
|
|
50218
|
+
creeps: propCreeps,
|
|
50219
|
+
gold: propGold,
|
|
50220
|
+
lives: propLives,
|
|
50221
|
+
wave: propWave,
|
|
50222
|
+
maxWaves: propMaxWaves,
|
|
50223
|
+
result: propResult,
|
|
50224
|
+
waveActive: propWaveActive,
|
|
50225
|
+
towerCost = 25,
|
|
50226
|
+
scale = 0.45,
|
|
50227
|
+
placeTowerEvent,
|
|
50228
|
+
startWaveEvent,
|
|
50229
|
+
playAgainEvent,
|
|
50230
|
+
gameEndEvent,
|
|
50231
|
+
className
|
|
50232
|
+
}) {
|
|
50233
|
+
const board = boardEntity(entity) ?? {};
|
|
50234
|
+
const eventBus = useEventBus();
|
|
50235
|
+
const { t } = hooks.useTranslate();
|
|
50236
|
+
const tiles = propTiles ?? rows(board.tiles);
|
|
50237
|
+
const path = propPath ?? rows(board.path);
|
|
50238
|
+
const towers = propTowers ?? rows(board.towers);
|
|
50239
|
+
const creeps = propCreeps ?? rows(board.creeps);
|
|
50240
|
+
const gold = propGold ?? num(board.gold, 100);
|
|
50241
|
+
const lives = propLives ?? num(board.lives, 20);
|
|
50242
|
+
const wave = propWave ?? num(board.wave, 1);
|
|
50243
|
+
const maxWaves = propMaxWaves ?? num(board.maxWaves, 5);
|
|
50244
|
+
const result = propResult ?? (str(board.result) || "none");
|
|
50245
|
+
const waveActive = propWaveActive ?? Boolean(board.waveActive);
|
|
50246
|
+
const [hoveredTile, setHoveredTile] = React77.useState(null);
|
|
50247
|
+
const emittedGameEnd = React77.useRef(false);
|
|
50248
|
+
if (result !== "none" && !emittedGameEnd.current) {
|
|
50249
|
+
emittedGameEnd.current = true;
|
|
50250
|
+
if (gameEndEvent) {
|
|
50251
|
+
eventBus.emit(`UI:${gameEndEvent}`, { result });
|
|
50252
|
+
}
|
|
50253
|
+
}
|
|
50254
|
+
if (result === "none") {
|
|
50255
|
+
emittedGameEnd.current = false;
|
|
50256
|
+
}
|
|
50257
|
+
const towerPositions = React77.useMemo(() => new Set(towers.map((t2) => `${t2.x},${t2.y}`)), [towers]);
|
|
50258
|
+
const pathPositions = React77.useMemo(() => new Set(path.map((p2) => `${p2.x},${p2.y}`)), [path]);
|
|
50259
|
+
const validMoves = React77.useMemo(() => {
|
|
50260
|
+
if (result !== "none" || gold < towerCost) return [];
|
|
50261
|
+
return tiles.filter(
|
|
50262
|
+
(t2) => t2.passable !== false && !towerPositions.has(`${t2.x},${t2.y}`) && !pathPositions.has(`${t2.x},${t2.y}`)
|
|
50263
|
+
).map((t2) => ({ x: t2.x, y: t2.y }));
|
|
50264
|
+
}, [tiles, towerPositions, pathPositions, result, gold, towerCost]);
|
|
50265
|
+
const isoTiles = React77.useMemo(() => tilesToIso(tiles), [tiles]);
|
|
50266
|
+
const towerUnits = React77.useMemo(() => towersToUnits(towers), [towers]);
|
|
50267
|
+
const creepUnits = React77.useMemo(() => creepsToUnits(creeps), [creeps]);
|
|
50268
|
+
const isoUnits = React77.useMemo(() => [...towerUnits, ...creepUnits], [towerUnits, creepUnits]);
|
|
50269
|
+
const pathFeatures = React77.useMemo(() => pathToFeatures(path), [path]);
|
|
50270
|
+
const handleTileClick = React77.useCallback((x, y) => {
|
|
50271
|
+
if (result !== "none") return;
|
|
50272
|
+
if (pathPositions.has(`${x},${y}`)) return;
|
|
50273
|
+
if (towerPositions.has(`${x},${y}`)) return;
|
|
50274
|
+
if (gold < towerCost) return;
|
|
50275
|
+
if (placeTowerEvent) {
|
|
50276
|
+
eventBus.emit(`UI:${placeTowerEvent}`, { x, y });
|
|
50277
|
+
}
|
|
50278
|
+
}, [result, pathPositions, towerPositions, gold, towerCost, placeTowerEvent, eventBus]);
|
|
50279
|
+
const handleStartWave = React77.useCallback(() => {
|
|
50280
|
+
if (startWaveEvent) {
|
|
50281
|
+
eventBus.emit(`UI:${startWaveEvent}`, { wave });
|
|
50282
|
+
}
|
|
50283
|
+
}, [startWaveEvent, wave, eventBus]);
|
|
50284
|
+
const handlePlayAgain = React77.useCallback(() => {
|
|
50285
|
+
if (playAgainEvent) {
|
|
50286
|
+
eventBus.emit(`UI:${playAgainEvent}`, {});
|
|
50287
|
+
}
|
|
50288
|
+
}, [playAgainEvent, eventBus]);
|
|
50289
|
+
const canPlaceTower = gold >= towerCost && result === "none";
|
|
50290
|
+
const canStartWave = !waveActive && result === "none";
|
|
50291
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(exports.VStack, { className: cn("tower-defense-board relative min-h-[600px] bg-background", className), gap: "none", children: [
|
|
50292
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
50293
|
+
exports.HStack,
|
|
50294
|
+
{
|
|
50295
|
+
className: "px-4 py-2 border-b border-border bg-surface",
|
|
50296
|
+
gap: "lg",
|
|
50297
|
+
align: "center",
|
|
50298
|
+
children: [
|
|
50299
|
+
/* @__PURE__ */ jsxRuntime.jsxs(exports.HStack, { gap: "xs", align: "center", children: [
|
|
50300
|
+
/* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "small", color: "muted", children: t("td.gold") ?? "Gold" }),
|
|
50301
|
+
/* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "body2", weight: "bold", className: "text-warning", children: gold })
|
|
50302
|
+
] }),
|
|
50303
|
+
/* @__PURE__ */ jsxRuntime.jsxs(exports.HStack, { gap: "xs", align: "center", children: [
|
|
50304
|
+
/* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "small", color: "muted", children: t("td.lives") ?? "Lives" }),
|
|
50305
|
+
/* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "body2", weight: "bold", className: lives <= 5 ? "text-error" : "text-success", children: lives })
|
|
50306
|
+
] }),
|
|
50307
|
+
/* @__PURE__ */ jsxRuntime.jsxs(exports.HStack, { gap: "xs", align: "center", children: [
|
|
50308
|
+
/* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "small", color: "muted", children: t("td.wave") ?? "Wave" }),
|
|
50309
|
+
/* @__PURE__ */ jsxRuntime.jsxs(exports.Typography, { variant: "body2", weight: "bold", children: [
|
|
50310
|
+
wave,
|
|
50311
|
+
" / ",
|
|
50312
|
+
maxWaves
|
|
50313
|
+
] })
|
|
50314
|
+
] }),
|
|
50315
|
+
/* @__PURE__ */ jsxRuntime.jsxs(exports.Box, { className: "ml-auto", children: [
|
|
50316
|
+
canStartWave && /* @__PURE__ */ jsxRuntime.jsx(exports.Button, { variant: "primary", size: "sm", onClick: handleStartWave, children: t("td.startWave") ?? "Start Wave" }),
|
|
50317
|
+
waveActive && /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "small", className: "text-warning animate-pulse", children: t("td.waveInProgress") ?? "Wave in progress\u2026" })
|
|
50318
|
+
] })
|
|
50319
|
+
]
|
|
50320
|
+
}
|
|
50321
|
+
),
|
|
50322
|
+
/* @__PURE__ */ jsxRuntime.jsxs(exports.Box, { className: "relative flex-1", children: [
|
|
50323
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
50324
|
+
IsometricCanvas_default,
|
|
50325
|
+
{
|
|
50326
|
+
tiles: isoTiles,
|
|
50327
|
+
units: isoUnits,
|
|
50328
|
+
features: pathFeatures,
|
|
50329
|
+
validMoves,
|
|
50330
|
+
hoveredTile,
|
|
50331
|
+
onTileClick: handleTileClick,
|
|
50332
|
+
onTileHover: (x, y) => setHoveredTile({ x, y }),
|
|
50333
|
+
onTileLeave: () => setHoveredTile(null),
|
|
50334
|
+
scale
|
|
50335
|
+
}
|
|
50336
|
+
),
|
|
50337
|
+
hoveredTile && canPlaceTower && validMoves.some((m) => m.x === hoveredTile.x && m.y === hoveredTile.y) && /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: "absolute bottom-4 left-1/2 -translate-x-1/2 z-10 bg-background/80 rounded px-3 py-1 backdrop-blur-sm pointer-events-none", children: /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "small", children: t("td.placeTower") ?? `Place tower (${towerCost} gold)` }) })
|
|
50338
|
+
] }),
|
|
50339
|
+
result !== "none" && /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: "absolute inset-0 z-50 flex items-center justify-center bg-background/70 backdrop-blur-sm", children: /* @__PURE__ */ jsxRuntime.jsxs(exports.VStack, { className: "text-center p-8", gap: "lg", children: [
|
|
50340
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
50341
|
+
exports.Typography,
|
|
50342
|
+
{
|
|
50343
|
+
variant: "h2",
|
|
50344
|
+
className: cn(
|
|
50345
|
+
"text-4xl font-black tracking-widest uppercase",
|
|
50346
|
+
result === "won" ? "text-warning" : "text-error"
|
|
50347
|
+
),
|
|
50348
|
+
children: result === "won" ? t("td.victory") ?? "Victory!" : t("td.defeat") ?? "Defeat!"
|
|
50349
|
+
}
|
|
50350
|
+
),
|
|
50351
|
+
/* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "body1", className: "text-muted-foreground", children: result === "won" ? t("td.survivedAllWaves") ?? `Survived all ${maxWaves} waves!` : t("td.livesReachedZero") ?? "Your base was overrun." }),
|
|
50352
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
50353
|
+
exports.Button,
|
|
50354
|
+
{
|
|
50355
|
+
variant: "primary",
|
|
50356
|
+
className: "px-8 py-3 font-semibold",
|
|
50357
|
+
onClick: handlePlayAgain,
|
|
50358
|
+
children: t("td.playAgain") ?? "Play Again"
|
|
50359
|
+
}
|
|
50360
|
+
)
|
|
50361
|
+
] }) })
|
|
50362
|
+
] });
|
|
50363
|
+
}
|
|
50364
|
+
var CDN6, TERRAIN_SPRITES, TOWER_SPRITE, CREEP_SPRITE;
|
|
50365
|
+
var init_TowerDefenseBoard = __esm({
|
|
50366
|
+
"components/game/organisms/TowerDefenseBoard.tsx"() {
|
|
50367
|
+
"use client";
|
|
50368
|
+
init_cn();
|
|
50369
|
+
init_useEventBus();
|
|
50370
|
+
init_Box();
|
|
50371
|
+
init_Button();
|
|
50372
|
+
init_Typography();
|
|
50373
|
+
init_Stack();
|
|
50374
|
+
init_IsometricCanvas();
|
|
50375
|
+
init_boardEntity();
|
|
50376
|
+
CDN6 = "https://almadar-kflow-assets.web.app/shared/";
|
|
50377
|
+
TERRAIN_SPRITES = {
|
|
50378
|
+
ground: `${CDN6}isometric-blocks/PNG/Platformer tiles/platformerTile_01.png`,
|
|
50379
|
+
path: `${CDN6}isometric-blocks/PNG/Platformer tiles/platformerTile_09.png`,
|
|
50380
|
+
wall: `${CDN6}isometric-blocks/PNG/Platformer tiles/platformerTile_05.png`
|
|
50381
|
+
};
|
|
50382
|
+
TOWER_SPRITE = `${CDN6}units/guardian.png`;
|
|
50383
|
+
CREEP_SPRITE = `${CDN6}units/scrapper.png`;
|
|
50384
|
+
TowerDefenseBoard.displayName = "TowerDefenseBoard";
|
|
50385
|
+
}
|
|
50386
|
+
});
|
|
50387
|
+
function TowerDefenseTemplate({
|
|
50388
|
+
entity,
|
|
50389
|
+
title = "Tower Defense",
|
|
50390
|
+
tiles,
|
|
50391
|
+
path,
|
|
50392
|
+
towers,
|
|
50393
|
+
gold,
|
|
50394
|
+
lives,
|
|
50395
|
+
maxWaves,
|
|
50396
|
+
towerCost,
|
|
50397
|
+
scale,
|
|
50398
|
+
placeTowerEvent,
|
|
50399
|
+
startWaveEvent,
|
|
50400
|
+
playAgainEvent,
|
|
50401
|
+
gameEndEvent,
|
|
50402
|
+
className
|
|
50403
|
+
}) {
|
|
50404
|
+
const resolved = entity && typeof entity === "object" && !Array.isArray(entity) ? entity : void 0;
|
|
50405
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
50406
|
+
exports.Box,
|
|
50407
|
+
{
|
|
50408
|
+
display: "flex",
|
|
50409
|
+
fullHeight: true,
|
|
50410
|
+
className: cn("tower-defense-template flex-col", className),
|
|
50411
|
+
children: [
|
|
50412
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
50413
|
+
exports.HStack,
|
|
50414
|
+
{
|
|
50415
|
+
gap: "sm",
|
|
50416
|
+
align: "center",
|
|
50417
|
+
className: "px-4 py-3 border-b-2 border-border bg-surface shrink-0",
|
|
50418
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "h4", children: title })
|
|
50419
|
+
}
|
|
50420
|
+
),
|
|
50421
|
+
/* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: "flex-1 relative overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
50422
|
+
TowerDefenseBoard,
|
|
50423
|
+
{
|
|
50424
|
+
entity: resolved,
|
|
50425
|
+
tiles,
|
|
50426
|
+
path,
|
|
50427
|
+
towers,
|
|
50428
|
+
gold,
|
|
50429
|
+
lives,
|
|
50430
|
+
maxWaves,
|
|
50431
|
+
towerCost,
|
|
50432
|
+
scale,
|
|
50433
|
+
placeTowerEvent,
|
|
50434
|
+
startWaveEvent,
|
|
50435
|
+
playAgainEvent,
|
|
50436
|
+
gameEndEvent,
|
|
50437
|
+
className: "h-full"
|
|
50438
|
+
}
|
|
50439
|
+
) })
|
|
50440
|
+
]
|
|
50441
|
+
}
|
|
50442
|
+
);
|
|
50443
|
+
}
|
|
50444
|
+
var init_TowerDefenseTemplate = __esm({
|
|
50445
|
+
"components/game/templates/TowerDefenseTemplate.tsx"() {
|
|
50446
|
+
init_cn();
|
|
50447
|
+
init_Box();
|
|
50448
|
+
init_Stack();
|
|
50449
|
+
init_Typography();
|
|
50450
|
+
init_TowerDefenseBoard();
|
|
50451
|
+
TowerDefenseTemplate.displayName = "TowerDefenseTemplate";
|
|
50452
|
+
}
|
|
50453
|
+
});
|
|
47935
50454
|
function useBattleState(initialUnits, eventConfig = {}, callbacks = {}) {
|
|
47936
50455
|
const eventBus = useEventBus();
|
|
47937
50456
|
const {
|
|
@@ -48441,48 +50960,48 @@ function WorldMapTemplate({
|
|
|
48441
50960
|
}
|
|
48442
50961
|
);
|
|
48443
50962
|
}
|
|
48444
|
-
var
|
|
50963
|
+
var CDN7, DEFAULT_WORLDMAP_TILES, DEFAULT_WORLDMAP_UNITS, DEFAULT_WORLDMAP_FEATURES, DEFAULT_WORLDMAP_MANIFEST;
|
|
48445
50964
|
var init_WorldMapTemplate = __esm({
|
|
48446
50965
|
"components/game/templates/WorldMapTemplate.tsx"() {
|
|
48447
50966
|
init_WorldMapBoard();
|
|
48448
|
-
|
|
50967
|
+
CDN7 = "https://almadar-kflow-assets.web.app/shared";
|
|
48449
50968
|
DEFAULT_WORLDMAP_TILES = [
|
|
48450
|
-
{ x: 0, y: 0, terrain: "mountain", passable: false, terrainSprite: `${
|
|
48451
|
-
{ x: 1, y: 0, terrain: "mountain", passable: false, terrainSprite: `${
|
|
48452
|
-
{ x: 2, y: 0, terrain: "water", passable: false, terrainSprite: `${
|
|
48453
|
-
{ x: 3, y: 0, terrain: "mountain", passable: false, terrainSprite: `${
|
|
48454
|
-
{ x: 4, y: 0, terrain: "mountain", passable: false, terrainSprite: `${
|
|
48455
|
-
{ x: 0, y: 1, terrain: "mountain", passable: false, terrainSprite: `${
|
|
48456
|
-
{ x: 1, y: 1, terrain: "grass", passable: true, terrainSprite: `${
|
|
48457
|
-
{ x: 2, y: 1, terrain: "grass", passable: true, terrainSprite: `${
|
|
48458
|
-
{ x: 3, y: 1, terrain: "grass", passable: true, terrainSprite: `${
|
|
48459
|
-
{ x: 4, y: 1, terrain: "water", passable: false, terrainSprite: `${
|
|
48460
|
-
{ x: 0, y: 2, terrain: "water", passable: false, terrainSprite: `${
|
|
48461
|
-
{ x: 1, y: 2, terrain: "grass", passable: true, terrainSprite: `${
|
|
48462
|
-
{ x: 2, y: 2, terrain: "grass", passable: true, terrainSprite: `${
|
|
48463
|
-
{ x: 3, y: 2, terrain: "grass", passable: true, terrainSprite: `${
|
|
48464
|
-
{ x: 4, y: 2, terrain: "mountain", passable: false, terrainSprite: `${
|
|
48465
|
-
{ x: 0, y: 3, terrain: "mountain", passable: false, terrainSprite: `${
|
|
48466
|
-
{ x: 1, y: 3, terrain: "grass", passable: true, terrainSprite: `${
|
|
48467
|
-
{ x: 2, y: 3, terrain: "grass", passable: true, terrainSprite: `${
|
|
48468
|
-
{ x: 3, y: 3, terrain: "grass", passable: true, terrainSprite: `${
|
|
48469
|
-
{ x: 4, y: 3, terrain: "mountain", passable: false, terrainSprite: `${
|
|
48470
|
-
{ x: 0, y: 4, terrain: "mountain", passable: false, terrainSprite: `${
|
|
48471
|
-
{ x: 1, y: 4, terrain: "water", passable: false, terrainSprite: `${
|
|
48472
|
-
{ x: 2, y: 4, terrain: "grass", passable: true, terrainSprite: `${
|
|
48473
|
-
{ x: 3, y: 4, terrain: "mountain", passable: false, terrainSprite: `${
|
|
48474
|
-
{ x: 4, y: 4, terrain: "mountain", passable: false, terrainSprite: `${
|
|
50969
|
+
{ x: 0, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
|
|
50970
|
+
{ x: 1, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
|
|
50971
|
+
{ x: 2, y: 0, terrain: "water", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
|
|
50972
|
+
{ x: 3, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
|
|
50973
|
+
{ x: 4, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
|
|
50974
|
+
{ x: 0, y: 1, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
|
|
50975
|
+
{ x: 1, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
|
|
50976
|
+
{ x: 2, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
|
|
50977
|
+
{ x: 3, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
|
|
50978
|
+
{ x: 4, y: 1, terrain: "water", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
|
|
50979
|
+
{ x: 0, y: 2, terrain: "water", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
|
|
50980
|
+
{ x: 1, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
|
|
50981
|
+
{ x: 2, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_03.png` },
|
|
50982
|
+
{ x: 3, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
|
|
50983
|
+
{ x: 4, y: 2, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
|
|
50984
|
+
{ x: 0, y: 3, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
|
|
50985
|
+
{ x: 1, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
|
|
50986
|
+
{ x: 2, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
|
|
50987
|
+
{ x: 3, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_03.png` },
|
|
50988
|
+
{ x: 4, y: 3, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
|
|
50989
|
+
{ x: 0, y: 4, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
|
|
50990
|
+
{ x: 1, y: 4, terrain: "water", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
|
|
50991
|
+
{ x: 2, y: 4, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
|
|
50992
|
+
{ x: 3, y: 4, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
|
|
50993
|
+
{ x: 4, y: 4, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` }
|
|
48475
50994
|
];
|
|
48476
50995
|
DEFAULT_WORLDMAP_UNITS = [
|
|
48477
|
-
{ id: "h1", position: { x: 1, y: 1 }, unitType: "hero", name: "Amir", team: "player", health: 10, maxHealth: 10, sprite: `${
|
|
48478
|
-
{ id: "h2", position: { x: 3, y: 3 }, unitType: "scout", name: "Archivist", team: "player", health: 10, maxHealth: 10, sprite: `${
|
|
50996
|
+
{ 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` },
|
|
50997
|
+
{ 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` }
|
|
48479
50998
|
];
|
|
48480
50999
|
DEFAULT_WORLDMAP_FEATURES = [
|
|
48481
|
-
{ id: "f1", x: 2, y: 2, type: "capital", sprite: `${
|
|
48482
|
-
{ id: "f2", x: 4, y: 2, type: "power_node", sprite: `${
|
|
51000
|
+
{ id: "f1", x: 2, y: 2, type: "capital", sprite: `${CDN7}/scenes/world/capital.png` },
|
|
51001
|
+
{ id: "f2", x: 4, y: 2, type: "power_node", sprite: `${CDN7}/world-map/power_node.png` }
|
|
48483
51002
|
];
|
|
48484
51003
|
DEFAULT_WORLDMAP_MANIFEST = {
|
|
48485
|
-
baseUrl:
|
|
51004
|
+
baseUrl: CDN7,
|
|
48486
51005
|
terrains: {
|
|
48487
51006
|
grass: "/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png",
|
|
48488
51007
|
water: "/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png",
|
|
@@ -48611,7 +51130,7 @@ function lazyThree(name, loader) {
|
|
|
48611
51130
|
ThreeWrapper.displayName = `Lazy(${name})`;
|
|
48612
51131
|
return ThreeWrapper;
|
|
48613
51132
|
}
|
|
48614
|
-
var ThreeBoundary, FeatureRenderer,
|
|
51133
|
+
var ThreeBoundary, FeatureRenderer, GameCanvas3D2, GameCanvas3DBattleTemplate, GameCanvas3DCastleTemplate, GameCanvas3DWorldMapTemplate, COMPONENT_REGISTRY;
|
|
48615
51134
|
var init_component_registry_generated = __esm({
|
|
48616
51135
|
"components/core/organisms/component-registry.generated.ts"() {
|
|
48617
51136
|
init_AboutPageTemplate();
|
|
@@ -48721,6 +51240,7 @@ var init_component_registry_generated = __esm({
|
|
|
48721
51240
|
init_FormSectionHeader();
|
|
48722
51241
|
init_GameAudioProvider();
|
|
48723
51242
|
init_GameAudioToggle();
|
|
51243
|
+
init_GameBoard3D();
|
|
48724
51244
|
init_GameCanvas2D();
|
|
48725
51245
|
init_GameHud();
|
|
48726
51246
|
init_GameMenu();
|
|
@@ -48778,7 +51298,9 @@ var init_component_registry_generated = __esm({
|
|
|
48778
51298
|
init_PageHeader();
|
|
48779
51299
|
init_Pagination();
|
|
48780
51300
|
init_PatternTile();
|
|
51301
|
+
init_PlatformerBoard();
|
|
48781
51302
|
init_PlatformerCanvas();
|
|
51303
|
+
init_PlatformerTemplate();
|
|
48782
51304
|
init_Popover();
|
|
48783
51305
|
init_PositionedCanvas();
|
|
48784
51306
|
init_PowerupSlots();
|
|
@@ -48802,6 +51324,8 @@ var init_component_registry_generated = __esm({
|
|
|
48802
51324
|
init_ResourceBar();
|
|
48803
51325
|
init_ResourceCounter();
|
|
48804
51326
|
init_RichBlockEditor();
|
|
51327
|
+
init_RoguelikeBoard();
|
|
51328
|
+
init_RoguelikeTemplate();
|
|
48805
51329
|
init_RuntimeDebugger2();
|
|
48806
51330
|
init_ScaledDiagram();
|
|
48807
51331
|
init_ScoreBoard();
|
|
@@ -48874,6 +51398,8 @@ var init_component_registry_generated = __esm({
|
|
|
48874
51398
|
init_Toast();
|
|
48875
51399
|
init_ToastSlot();
|
|
48876
51400
|
init_Tooltip();
|
|
51401
|
+
init_TowerDefenseBoard();
|
|
51402
|
+
init_TowerDefenseTemplate();
|
|
48877
51403
|
init_TraitFrame();
|
|
48878
51404
|
init_TraitSlot();
|
|
48879
51405
|
init_TrendIndicator();
|
|
@@ -48918,7 +51444,7 @@ var init_component_registry_generated = __esm({
|
|
|
48918
51444
|
}
|
|
48919
51445
|
};
|
|
48920
51446
|
FeatureRenderer = lazyThree("FeatureRenderer", () => import('@almadar/ui/components/molecules/game/three'));
|
|
48921
|
-
|
|
51447
|
+
GameCanvas3D2 = lazyThree("GameCanvas3D", () => import('@almadar/ui/components/molecules/game/three'));
|
|
48922
51448
|
GameCanvas3DBattleTemplate = lazyThree("GameCanvas3DBattleTemplate", () => import('@almadar/ui/components/molecules/game/three'));
|
|
48923
51449
|
GameCanvas3DCastleTemplate = lazyThree("GameCanvas3DCastleTemplate", () => import('@almadar/ui/components/molecules/game/three'));
|
|
48924
51450
|
GameCanvas3DWorldMapTemplate = lazyThree("GameCanvas3DWorldMapTemplate", () => import('@almadar/ui/components/molecules/game/three'));
|
|
@@ -49037,8 +51563,9 @@ var init_component_registry_generated = __esm({
|
|
|
49037
51563
|
"FormSectionHeader": exports.FormSectionHeader,
|
|
49038
51564
|
"GameAudioProvider": GameAudioProvider,
|
|
49039
51565
|
"GameAudioToggle": GameAudioToggle,
|
|
51566
|
+
"GameBoard3D": GameBoard3D,
|
|
49040
51567
|
"GameCanvas2D": GameCanvas2D,
|
|
49041
|
-
"GameCanvas3D":
|
|
51568
|
+
"GameCanvas3D": GameCanvas3D2,
|
|
49042
51569
|
"GameCanvas3DBattleTemplate": GameCanvas3DBattleTemplate,
|
|
49043
51570
|
"GameCanvas3DCastleTemplate": GameCanvas3DCastleTemplate,
|
|
49044
51571
|
"GameCanvas3DWorldMapTemplate": GameCanvas3DWorldMapTemplate,
|
|
@@ -49100,7 +51627,9 @@ var init_component_registry_generated = __esm({
|
|
|
49100
51627
|
"PageHeader": exports.PageHeader,
|
|
49101
51628
|
"Pagination": exports.Pagination,
|
|
49102
51629
|
"PatternTile": exports.PatternTile,
|
|
51630
|
+
"PlatformerBoard": PlatformerBoard,
|
|
49103
51631
|
"PlatformerCanvas": PlatformerCanvas,
|
|
51632
|
+
"PlatformerTemplate": PlatformerTemplate,
|
|
49104
51633
|
"Popover": exports.Popover,
|
|
49105
51634
|
"PositionedCanvas": exports.PositionedCanvas,
|
|
49106
51635
|
"PowerupSlots": PowerupSlots,
|
|
@@ -49124,6 +51653,8 @@ var init_component_registry_generated = __esm({
|
|
|
49124
51653
|
"ResourceBar": ResourceBar,
|
|
49125
51654
|
"ResourceCounter": ResourceCounter,
|
|
49126
51655
|
"RichBlockEditor": exports.RichBlockEditor,
|
|
51656
|
+
"RoguelikeBoard": RoguelikeBoard,
|
|
51657
|
+
"RoguelikeTemplate": RoguelikeTemplate,
|
|
49127
51658
|
"RuntimeDebugger": RuntimeDebugger,
|
|
49128
51659
|
"ScaledDiagram": exports.ScaledDiagram,
|
|
49129
51660
|
"ScoreBoard": ScoreBoard,
|
|
@@ -49199,6 +51730,8 @@ var init_component_registry_generated = __esm({
|
|
|
49199
51730
|
"Toast": exports.Toast,
|
|
49200
51731
|
"ToastSlot": exports.ToastSlot,
|
|
49201
51732
|
"Tooltip": exports.Tooltip,
|
|
51733
|
+
"TowerDefenseBoard": TowerDefenseBoard,
|
|
51734
|
+
"TowerDefenseTemplate": TowerDefenseTemplate,
|
|
49202
51735
|
"TraitFrame": TraitFrame,
|
|
49203
51736
|
"TraitSlot": TraitSlot,
|
|
49204
51737
|
"TrendIndicator": exports.TrendIndicator,
|
|
@@ -50761,6 +53294,10 @@ init_UncontrolledBattleBoard();
|
|
|
50761
53294
|
init_useBattleState();
|
|
50762
53295
|
init_WorldMapBoard();
|
|
50763
53296
|
init_CastleBoard();
|
|
53297
|
+
init_PlatformerBoard();
|
|
53298
|
+
init_TowerDefenseBoard();
|
|
53299
|
+
init_RoguelikeBoard();
|
|
53300
|
+
init_GameBoard3D();
|
|
50764
53301
|
init_TraitStateViewer();
|
|
50765
53302
|
init_TraitSlot();
|
|
50766
53303
|
|
|
@@ -51333,6 +53870,9 @@ init_GameShell();
|
|
|
51333
53870
|
init_BattleTemplate();
|
|
51334
53871
|
init_CastleTemplate();
|
|
51335
53872
|
init_WorldMapTemplate();
|
|
53873
|
+
init_PlatformerTemplate();
|
|
53874
|
+
init_TowerDefenseTemplate();
|
|
53875
|
+
init_RoguelikeTemplate();
|
|
51336
53876
|
init_LandingPageTemplate();
|
|
51337
53877
|
init_PricingPageTemplate();
|
|
51338
53878
|
init_FeatureDetailPageTemplate();
|
|
@@ -51383,6 +53923,7 @@ exports.EventLog = EventLog;
|
|
|
51383
53923
|
exports.FEATURE_TYPES = FEATURE_TYPES;
|
|
51384
53924
|
exports.GameAudioProvider = GameAudioProvider;
|
|
51385
53925
|
exports.GameAudioToggle = GameAudioToggle;
|
|
53926
|
+
exports.GameBoard3D = GameBoard3D;
|
|
51386
53927
|
exports.GameCanvas2D = GameCanvas2D;
|
|
51387
53928
|
exports.GameHud = GameHud;
|
|
51388
53929
|
exports.GameMenu = GameMenu;
|
|
@@ -51401,11 +53942,15 @@ exports.NotifyListener = NotifyListener;
|
|
|
51401
53942
|
exports.ObjectRulePanel = ObjectRulePanel;
|
|
51402
53943
|
exports.OrbitalStateMachineView = exports.StateMachineView;
|
|
51403
53944
|
exports.PhysicsManager = PhysicsManager;
|
|
53945
|
+
exports.PlatformerBoard = PlatformerBoard;
|
|
51404
53946
|
exports.PlatformerCanvas = PlatformerCanvas;
|
|
53947
|
+
exports.PlatformerTemplate = PlatformerTemplate;
|
|
51405
53948
|
exports.PowerupSlots = PowerupSlots;
|
|
51406
53949
|
exports.QuestTracker = QuestTracker;
|
|
51407
53950
|
exports.ResourceBar = ResourceBar;
|
|
51408
53951
|
exports.ResourceCounter = ResourceCounter;
|
|
53952
|
+
exports.RoguelikeBoard = RoguelikeBoard;
|
|
53953
|
+
exports.RoguelikeTemplate = RoguelikeTemplate;
|
|
51409
53954
|
exports.RuleEditor = RuleEditor;
|
|
51410
53955
|
exports.RuntimeDebugger = RuntimeDebugger;
|
|
51411
53956
|
exports.SHEET_COLUMNS = SHEET_COLUMNS;
|
|
@@ -51433,6 +53978,8 @@ exports.TableView = TableView;
|
|
|
51433
53978
|
exports.TerrainPalette = TerrainPalette;
|
|
51434
53979
|
exports.TimeSlotCell = TimeSlotCell;
|
|
51435
53980
|
exports.TimerDisplay = TimerDisplay;
|
|
53981
|
+
exports.TowerDefenseBoard = TowerDefenseBoard;
|
|
53982
|
+
exports.TowerDefenseTemplate = TowerDefenseTemplate;
|
|
51436
53983
|
exports.TraitFrame = TraitFrame;
|
|
51437
53984
|
exports.TraitSlot = TraitSlot;
|
|
51438
53985
|
exports.TraitStateViewer = TraitStateViewer;
|