@almadar/ui 5.48.0 → 5.49.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/avl/index.cjs +2681 -148
- package/dist/avl/index.css +504 -0
- package/dist/avl/index.js +2681 -149
- package/dist/components/core/templates/index.d.ts +3 -0
- package/dist/components/game/atoms/ActionButton.d.ts +4 -1
- package/dist/components/game/atoms/ControlButton.d.ts +4 -2
- package/dist/components/game/atoms/DamageNumber.d.ts +4 -1
- package/dist/components/game/atoms/ScoreDisplay.d.ts +4 -1
- package/dist/components/game/atoms/TurnIndicator.d.ts +4 -1
- package/dist/components/game/molecules/EnemyPlate.d.ts +4 -1
- package/dist/components/game/molecules/StatBadge.d.ts +4 -1
- package/dist/components/game/molecules/three/index.cjs +1371 -283
- package/dist/components/game/molecules/three/index.js +1372 -284
- package/dist/components/game/organisms/GameBoard3D.d.ts +62 -0
- package/dist/components/game/organisms/PlatformerBoard.d.ts +51 -0
- package/dist/components/game/organisms/RoguelikeBoard.d.ts +59 -0
- package/dist/components/game/organisms/TowerDefenseBoard.d.ts +64 -0
- package/dist/components/game/organisms/index.d.ts +4 -0
- package/dist/components/game/templates/GameCanvas3DBattleTemplate.d.ts +22 -35
- package/dist/components/game/templates/GameCanvas3DCastleTemplate.d.ts +23 -23
- package/dist/components/game/templates/GameCanvas3DWorldMapTemplate.d.ts +27 -29
- package/dist/components/game/templates/PlatformerTemplate.d.ts +26 -0
- package/dist/components/game/templates/RoguelikeTemplate.d.ts +23 -0
- package/dist/components/game/templates/TowerDefenseTemplate.d.ts +43 -0
- package/dist/components/index.cjs +2674 -127
- package/dist/components/index.css +504 -0
- package/dist/components/index.js +2668 -129
- package/dist/docs/index.css +504 -0
- package/dist/providers/index.cjs +2664 -131
- package/dist/providers/index.css +504 -0
- package/dist/providers/index.js +2664 -132
- package/dist/runtime/index.cjs +2665 -132
- package/dist/runtime/index.css +504 -0
- package/dist/runtime/index.js +2665 -133
- package/package.json +1 -1
package/dist/runtime/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React82 from 'react';
|
|
2
|
-
import React82__default, { createContext, useMemo, useContext, useRef, useEffect, useCallback, Suspense, useState, useSyncExternalStore, useLayoutEffect, lazy, useId } from 'react';
|
|
2
|
+
import React82__default, { createContext, useMemo, useContext, useRef, useEffect, useCallback, Suspense, useState, useSyncExternalStore, useLayoutEffect, lazy, useId, forwardRef, useImperativeHandle, Component } from 'react';
|
|
3
3
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
4
4
|
import { clsx } from 'clsx';
|
|
5
5
|
import { twMerge } from 'tailwind-merge';
|
|
@@ -41,6 +41,12 @@ import { DndContext, pointerWithin, rectIntersection, closestCorners, useSensors
|
|
|
41
41
|
import { useSortable, arrayMove, sortableKeyboardCoordinates, SortableContext, rectSortingStrategy, verticalListSortingStrategy } from '@dnd-kit/sortable';
|
|
42
42
|
import { CSS } from '@dnd-kit/utilities';
|
|
43
43
|
import { useNodeId, ReactFlowProvider, Handle, Position } from '@xyflow/react';
|
|
44
|
+
import * as THREE from 'three';
|
|
45
|
+
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
|
|
46
|
+
import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader.js';
|
|
47
|
+
import { GLTFLoader as GLTFLoader$1 } from 'three/examples/jsm/loaders/GLTFLoader';
|
|
48
|
+
import { Canvas, useThree } from '@react-three/fiber';
|
|
49
|
+
import { Grid as Grid$1, OrbitControls } from '@react-three/drei';
|
|
44
50
|
import { getPatternDefinition, getComponentForPattern as getComponentForPattern$1 } from '@almadar/patterns';
|
|
45
51
|
import { StateMachineManager, createContextFromBindings, interpolateValue, collectDeclaredConfigDefaults, createServerEffectHandlers, EffectExecutor, InMemoryPersistence } from '@almadar/runtime';
|
|
46
52
|
import { OrbitalServerRuntime } from '@almadar/runtime/OrbitalServerRuntime';
|
|
@@ -409,7 +415,7 @@ var init_Box = __esm({
|
|
|
409
415
|
position,
|
|
410
416
|
className,
|
|
411
417
|
children,
|
|
412
|
-
as:
|
|
418
|
+
as: Component2 = "div",
|
|
413
419
|
action,
|
|
414
420
|
actionPayload,
|
|
415
421
|
hoverEvent,
|
|
@@ -441,7 +447,7 @@ var init_Box = __esm({
|
|
|
441
447
|
}, [hoverEvent, eventBus, onMouseLeave]);
|
|
442
448
|
const isClickable = action || onClick;
|
|
443
449
|
return React82__default.createElement(
|
|
444
|
-
|
|
450
|
+
Component2,
|
|
445
451
|
{
|
|
446
452
|
ref,
|
|
447
453
|
className: cn(
|
|
@@ -579,9 +585,9 @@ function resolvePhosphor(name, weight, family) {
|
|
|
579
585
|
(lib) => {
|
|
580
586
|
const PhosphorComp = lib[target];
|
|
581
587
|
if (!PhosphorComp || typeof PhosphorComp !== "object") return null;
|
|
582
|
-
const
|
|
588
|
+
const Component2 = PhosphorComp;
|
|
583
589
|
const Adapter = (props) => /* @__PURE__ */ jsx(
|
|
584
|
-
|
|
590
|
+
Component2,
|
|
585
591
|
{
|
|
586
592
|
weight,
|
|
587
593
|
className: props.className,
|
|
@@ -605,9 +611,9 @@ function resolveTabler(name, family) {
|
|
|
605
611
|
(lib) => {
|
|
606
612
|
const TablerComp = lib[target];
|
|
607
613
|
if (!TablerComp || typeof TablerComp !== "object") return null;
|
|
608
|
-
const
|
|
614
|
+
const Component2 = TablerComp;
|
|
609
615
|
const Adapter = (props) => /* @__PURE__ */ jsx(
|
|
610
|
-
|
|
616
|
+
Component2,
|
|
611
617
|
{
|
|
612
618
|
stroke: props.strokeWidth ?? 1.5,
|
|
613
619
|
className: props.className,
|
|
@@ -631,9 +637,9 @@ function resolveFa(name, family) {
|
|
|
631
637
|
(lib) => {
|
|
632
638
|
const FaComp = lib[target];
|
|
633
639
|
if (!FaComp || typeof FaComp !== "function") return null;
|
|
634
|
-
const
|
|
640
|
+
const Component2 = FaComp;
|
|
635
641
|
const Adapter = (props) => /* @__PURE__ */ jsx(
|
|
636
|
-
|
|
642
|
+
Component2,
|
|
637
643
|
{
|
|
638
644
|
className: props.className,
|
|
639
645
|
style: props.style,
|
|
@@ -1588,8 +1594,8 @@ var init_Typography = __esm({
|
|
|
1588
1594
|
children
|
|
1589
1595
|
}) => {
|
|
1590
1596
|
const variant = variantProp ?? (level ? `h${level}` : "body1");
|
|
1591
|
-
const
|
|
1592
|
-
const Comp =
|
|
1597
|
+
const Component2 = as || defaultElements[variant];
|
|
1598
|
+
const Comp = Component2;
|
|
1593
1599
|
return /* @__PURE__ */ jsx(
|
|
1594
1600
|
Comp,
|
|
1595
1601
|
{
|
|
@@ -4144,10 +4150,10 @@ var init_Center = __esm({
|
|
|
4144
4150
|
className,
|
|
4145
4151
|
style,
|
|
4146
4152
|
children,
|
|
4147
|
-
as:
|
|
4153
|
+
as: Component2 = "div"
|
|
4148
4154
|
}) => {
|
|
4149
4155
|
const mergedStyle = minHeight ? { minHeight, ...style } : style;
|
|
4150
|
-
const Comp =
|
|
4156
|
+
const Comp = Component2;
|
|
4151
4157
|
return /* @__PURE__ */ jsx(
|
|
4152
4158
|
Comp,
|
|
4153
4159
|
{
|
|
@@ -4778,7 +4784,7 @@ var init_Stack = __esm({
|
|
|
4778
4784
|
className,
|
|
4779
4785
|
style,
|
|
4780
4786
|
children,
|
|
4781
|
-
as:
|
|
4787
|
+
as: Component2 = "div",
|
|
4782
4788
|
onClick,
|
|
4783
4789
|
onKeyDown,
|
|
4784
4790
|
role,
|
|
@@ -4796,7 +4802,7 @@ var init_Stack = __esm({
|
|
|
4796
4802
|
};
|
|
4797
4803
|
const isHorizontal = direction === "horizontal";
|
|
4798
4804
|
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";
|
|
4799
|
-
const Comp =
|
|
4805
|
+
const Comp = Component2;
|
|
4800
4806
|
return /* @__PURE__ */ jsx(
|
|
4801
4807
|
Comp,
|
|
4802
4808
|
{
|
|
@@ -7027,6 +7033,7 @@ var init_HealthBar = __esm({
|
|
|
7027
7033
|
}
|
|
7028
7034
|
});
|
|
7029
7035
|
function ScoreDisplay({
|
|
7036
|
+
assetUrl = DEFAULT_ASSET_URL,
|
|
7030
7037
|
value,
|
|
7031
7038
|
label,
|
|
7032
7039
|
icon,
|
|
@@ -7073,14 +7080,24 @@ function ScoreDisplay({
|
|
|
7073
7080
|
className
|
|
7074
7081
|
),
|
|
7075
7082
|
children: [
|
|
7076
|
-
|
|
7083
|
+
assetUrl ? /* @__PURE__ */ jsx(
|
|
7084
|
+
"img",
|
|
7085
|
+
{
|
|
7086
|
+
src: assetUrl,
|
|
7087
|
+
alt: "",
|
|
7088
|
+
width: 20,
|
|
7089
|
+
height: 20,
|
|
7090
|
+
style: { imageRendering: "pixelated", objectFit: "contain" },
|
|
7091
|
+
className: "flex-shrink-0"
|
|
7092
|
+
}
|
|
7093
|
+
) : icon ? /* @__PURE__ */ jsx("span", { className: "flex-shrink-0", children: typeof icon === "string" ? /* @__PURE__ */ jsx(Icon, { name: icon }) : /* @__PURE__ */ jsx(Icon, { icon }) }) : null,
|
|
7077
7094
|
label && /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: label }),
|
|
7078
7095
|
/* @__PURE__ */ jsx("span", { className: "tabular-nums", children: formattedValue })
|
|
7079
7096
|
]
|
|
7080
7097
|
}
|
|
7081
7098
|
);
|
|
7082
7099
|
}
|
|
7083
|
-
var sizeMap2;
|
|
7100
|
+
var sizeMap2, DEFAULT_ASSET_URL;
|
|
7084
7101
|
var init_ScoreDisplay = __esm({
|
|
7085
7102
|
"components/game/atoms/ScoreDisplay.tsx"() {
|
|
7086
7103
|
"use client";
|
|
@@ -7092,10 +7109,12 @@ var init_ScoreDisplay = __esm({
|
|
|
7092
7109
|
lg: "text-2xl",
|
|
7093
7110
|
xl: "text-4xl"
|
|
7094
7111
|
};
|
|
7112
|
+
DEFAULT_ASSET_URL = "https://almadar-kflow-assets.web.app/shared/effects/particles/star_01.png";
|
|
7095
7113
|
ScoreDisplay.displayName = "ScoreDisplay";
|
|
7096
7114
|
}
|
|
7097
7115
|
});
|
|
7098
7116
|
function ControlButton({
|
|
7117
|
+
assetUrl = DEFAULT_ASSET_URL2,
|
|
7099
7118
|
label,
|
|
7100
7119
|
icon,
|
|
7101
7120
|
size = "md",
|
|
@@ -7142,7 +7161,7 @@ function ControlButton({
|
|
|
7142
7161
|
},
|
|
7143
7162
|
[isPressed, releaseEvent, eventBus, onRelease]
|
|
7144
7163
|
);
|
|
7145
|
-
return /* @__PURE__ */
|
|
7164
|
+
return /* @__PURE__ */ jsx(
|
|
7146
7165
|
"button",
|
|
7147
7166
|
{
|
|
7148
7167
|
type: "button",
|
|
@@ -7163,20 +7182,27 @@ function ControlButton({
|
|
|
7163
7182
|
disabled && "opacity-50 cursor-not-allowed",
|
|
7164
7183
|
className
|
|
7165
7184
|
),
|
|
7166
|
-
children:
|
|
7167
|
-
|
|
7168
|
-
|
|
7169
|
-
|
|
7170
|
-
|
|
7171
|
-
|
|
7172
|
-
|
|
7173
|
-
|
|
7174
|
-
|
|
7175
|
-
|
|
7185
|
+
children: assetUrl ? /* @__PURE__ */ jsx(
|
|
7186
|
+
"img",
|
|
7187
|
+
{
|
|
7188
|
+
src: assetUrl,
|
|
7189
|
+
alt: "",
|
|
7190
|
+
width: 24,
|
|
7191
|
+
height: 24,
|
|
7192
|
+
style: { imageRendering: "pixelated", objectFit: "contain" },
|
|
7193
|
+
className: "flex-shrink-0"
|
|
7194
|
+
}
|
|
7195
|
+
) : icon ? /* @__PURE__ */ jsx("span", { className: "text-2xl", children: typeof icon === "string" ? /^[a-zA-Z0-9-]+$/.test(icon) ? (() => {
|
|
7196
|
+
const I = resolveIcon(icon);
|
|
7197
|
+
return I ? /* @__PURE__ */ jsx(I, { className: "w-6 h-6" }) : null;
|
|
7198
|
+
})() : icon : /* @__PURE__ */ (() => {
|
|
7199
|
+
const I = icon;
|
|
7200
|
+
return /* @__PURE__ */ jsx(I, { className: "w-6 h-6" });
|
|
7201
|
+
})() }) : label ? /* @__PURE__ */ jsx("span", { children: label }) : null
|
|
7176
7202
|
}
|
|
7177
7203
|
);
|
|
7178
7204
|
}
|
|
7179
|
-
var sizeMap3, shapeMap, variantMap;
|
|
7205
|
+
var sizeMap3, shapeMap, variantMap, DEFAULT_ASSET_URL2;
|
|
7180
7206
|
var init_ControlButton = __esm({
|
|
7181
7207
|
"components/game/atoms/ControlButton.tsx"() {
|
|
7182
7208
|
"use client";
|
|
@@ -7199,6 +7225,7 @@ var init_ControlButton = __esm({
|
|
|
7199
7225
|
secondary: "bg-secondary text-secondary-foreground border-border hover:bg-secondary-hover",
|
|
7200
7226
|
ghost: "bg-transparent text-foreground border-border hover:bg-muted"
|
|
7201
7227
|
};
|
|
7228
|
+
DEFAULT_ASSET_URL2 = "https://almadar-kflow-assets.web.app/shared/effects/particles/circle_01.png";
|
|
7202
7229
|
ControlButton.displayName = "ControlButton";
|
|
7203
7230
|
}
|
|
7204
7231
|
});
|
|
@@ -7278,7 +7305,7 @@ var init_Sprite = __esm({
|
|
|
7278
7305
|
}
|
|
7279
7306
|
});
|
|
7280
7307
|
function StateIndicator({
|
|
7281
|
-
assetUrl =
|
|
7308
|
+
assetUrl = DEFAULT_ASSET_URL3,
|
|
7282
7309
|
state = "idle",
|
|
7283
7310
|
label,
|
|
7284
7311
|
size = "md",
|
|
@@ -7317,13 +7344,13 @@ function StateIndicator({
|
|
|
7317
7344
|
}
|
|
7318
7345
|
);
|
|
7319
7346
|
}
|
|
7320
|
-
var
|
|
7347
|
+
var DEFAULT_ASSET_URL3, DEFAULT_STATE_STYLES, DEFAULT_STYLE, SIZE_CLASSES;
|
|
7321
7348
|
var init_StateIndicator = __esm({
|
|
7322
7349
|
"components/game/atoms/StateIndicator.tsx"() {
|
|
7323
7350
|
init_Box();
|
|
7324
7351
|
init_Icon();
|
|
7325
7352
|
init_cn();
|
|
7326
|
-
|
|
7353
|
+
DEFAULT_ASSET_URL3 = "https://almadar-kflow-assets.web.app/shared/isometric-dungeon/Isometric/chestClosed_E.png";
|
|
7327
7354
|
DEFAULT_STATE_STYLES = {
|
|
7328
7355
|
idle: { icon: "\u23F8", bgClass: "bg-muted" },
|
|
7329
7356
|
active: { icon: "\u25B6", bgClass: "bg-success" },
|
|
@@ -7398,7 +7425,7 @@ var init_TimerDisplay = __esm({
|
|
|
7398
7425
|
}
|
|
7399
7426
|
});
|
|
7400
7427
|
function ResourceCounter({
|
|
7401
|
-
assetUrl =
|
|
7428
|
+
assetUrl = DEFAULT_ASSET_URL4,
|
|
7402
7429
|
icon,
|
|
7403
7430
|
label = "Gold",
|
|
7404
7431
|
value = 250,
|
|
@@ -7441,7 +7468,7 @@ function ResourceCounter({
|
|
|
7441
7468
|
}
|
|
7442
7469
|
);
|
|
7443
7470
|
}
|
|
7444
|
-
var colorTokenClasses2,
|
|
7471
|
+
var colorTokenClasses2, DEFAULT_ASSET_URL4, sizeMap5;
|
|
7445
7472
|
var init_ResourceCounter = __esm({
|
|
7446
7473
|
"components/game/atoms/ResourceCounter.tsx"() {
|
|
7447
7474
|
init_cn();
|
|
@@ -7454,7 +7481,7 @@ var init_ResourceCounter = __esm({
|
|
|
7454
7481
|
error: "text-error",
|
|
7455
7482
|
muted: "text-muted-foreground"
|
|
7456
7483
|
};
|
|
7457
|
-
|
|
7484
|
+
DEFAULT_ASSET_URL4 = "https://almadar-kflow-assets.web.app/shared/world-map/gold_mine.png";
|
|
7458
7485
|
sizeMap5 = {
|
|
7459
7486
|
sm: { wrapper: "text-xs gap-1 px-1.5 py-0.5", icon: "text-sm", img: 16 },
|
|
7460
7487
|
md: { wrapper: "text-sm gap-1.5 px-2 py-1", icon: "text-base", img: 20 },
|
|
@@ -7464,7 +7491,7 @@ var init_ResourceCounter = __esm({
|
|
|
7464
7491
|
}
|
|
7465
7492
|
});
|
|
7466
7493
|
function ItemSlot({
|
|
7467
|
-
assetUrl =
|
|
7494
|
+
assetUrl = DEFAULT_ASSET_URL5,
|
|
7468
7495
|
icon = "sword",
|
|
7469
7496
|
label = "Iron Sword",
|
|
7470
7497
|
quantity,
|
|
@@ -7523,7 +7550,7 @@ function ItemSlot({
|
|
|
7523
7550
|
}
|
|
7524
7551
|
);
|
|
7525
7552
|
}
|
|
7526
|
-
var sizeMap6, rarityBorderMap, rarityGlowMap,
|
|
7553
|
+
var sizeMap6, rarityBorderMap, rarityGlowMap, DEFAULT_ASSET_URL5, assetSizeMap;
|
|
7527
7554
|
var init_ItemSlot = __esm({
|
|
7528
7555
|
"components/game/atoms/ItemSlot.tsx"() {
|
|
7529
7556
|
"use client";
|
|
@@ -7548,7 +7575,7 @@ var init_ItemSlot = __esm({
|
|
|
7548
7575
|
epic: "shadow-lg",
|
|
7549
7576
|
legendary: "shadow-lg"
|
|
7550
7577
|
};
|
|
7551
|
-
|
|
7578
|
+
DEFAULT_ASSET_URL5 = "https://almadar-kflow-assets.web.app/shared/isometric-dungeon/Isometric/chestClosed_E.png";
|
|
7552
7579
|
assetSizeMap = {
|
|
7553
7580
|
sm: 28,
|
|
7554
7581
|
md: 40,
|
|
@@ -7558,6 +7585,7 @@ var init_ItemSlot = __esm({
|
|
|
7558
7585
|
}
|
|
7559
7586
|
});
|
|
7560
7587
|
function TurnIndicator({
|
|
7588
|
+
assetUrl = DEFAULT_ASSET_URL6,
|
|
7561
7589
|
currentTurn = 1,
|
|
7562
7590
|
maxTurns,
|
|
7563
7591
|
activeTeam,
|
|
@@ -7590,14 +7618,24 @@ function TurnIndicator({
|
|
|
7590
7618
|
] }),
|
|
7591
7619
|
activeTeam && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
7592
7620
|
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "|" }),
|
|
7593
|
-
/* @__PURE__ */ jsx(
|
|
7621
|
+
assetUrl ? /* @__PURE__ */ jsx(
|
|
7622
|
+
"img",
|
|
7623
|
+
{
|
|
7624
|
+
src: assetUrl,
|
|
7625
|
+
alt: "",
|
|
7626
|
+
width: 12,
|
|
7627
|
+
height: 12,
|
|
7628
|
+
style: { imageRendering: "pixelated", objectFit: "contain" },
|
|
7629
|
+
className: "flex-shrink-0"
|
|
7630
|
+
}
|
|
7631
|
+
) : /* @__PURE__ */ jsx("span", { className: cn("rounded-full bg-success/20", sizes.dot) }),
|
|
7594
7632
|
/* @__PURE__ */ jsx("span", { className: "text-success", children: activeTeam })
|
|
7595
7633
|
] })
|
|
7596
7634
|
]
|
|
7597
7635
|
}
|
|
7598
7636
|
);
|
|
7599
7637
|
}
|
|
7600
|
-
var sizeMap7;
|
|
7638
|
+
var sizeMap7, DEFAULT_ASSET_URL6;
|
|
7601
7639
|
var init_TurnIndicator = __esm({
|
|
7602
7640
|
"components/game/atoms/TurnIndicator.tsx"() {
|
|
7603
7641
|
init_cn();
|
|
@@ -7606,6 +7644,7 @@ var init_TurnIndicator = __esm({
|
|
|
7606
7644
|
md: { wrapper: "text-sm gap-2 px-3 py-1", dot: "w-2 h-2" },
|
|
7607
7645
|
lg: { wrapper: "text-base gap-2.5 px-4 py-1.5", dot: "w-2.5 h-2.5" }
|
|
7608
7646
|
};
|
|
7647
|
+
DEFAULT_ASSET_URL6 = "https://almadar-kflow-assets.web.app/shared/effects/particles/symbol_01.png";
|
|
7609
7648
|
TurnIndicator.displayName = "TurnIndicator";
|
|
7610
7649
|
}
|
|
7611
7650
|
});
|
|
@@ -7621,7 +7660,7 @@ function getComboScale(combo) {
|
|
|
7621
7660
|
return "";
|
|
7622
7661
|
}
|
|
7623
7662
|
function ComboCounter({
|
|
7624
|
-
assetUrl =
|
|
7663
|
+
assetUrl = DEFAULT_ASSET_URL7,
|
|
7625
7664
|
combo = 5,
|
|
7626
7665
|
multiplier,
|
|
7627
7666
|
streak,
|
|
@@ -7666,11 +7705,11 @@ function ComboCounter({
|
|
|
7666
7705
|
}
|
|
7667
7706
|
);
|
|
7668
7707
|
}
|
|
7669
|
-
var
|
|
7708
|
+
var DEFAULT_ASSET_URL7, sizeMap8;
|
|
7670
7709
|
var init_ComboCounter = __esm({
|
|
7671
7710
|
"components/game/atoms/ComboCounter.tsx"() {
|
|
7672
7711
|
init_cn();
|
|
7673
|
-
|
|
7712
|
+
DEFAULT_ASSET_URL7 = "https://almadar-kflow-assets.web.app/shared/effects/flash/flash00.png";
|
|
7674
7713
|
sizeMap8 = {
|
|
7675
7714
|
sm: { combo: "text-lg", label: "text-xs", multiplier: "text-xs" },
|
|
7676
7715
|
md: { combo: "text-2xl", label: "text-xs", multiplier: "text-sm" },
|
|
@@ -7764,7 +7803,7 @@ var init_XPBar = __esm({
|
|
|
7764
7803
|
}
|
|
7765
7804
|
});
|
|
7766
7805
|
function WaypointMarker({
|
|
7767
|
-
assetUrl =
|
|
7806
|
+
assetUrl = DEFAULT_ASSET_URL8,
|
|
7768
7807
|
label,
|
|
7769
7808
|
icon,
|
|
7770
7809
|
active = true,
|
|
@@ -7830,12 +7869,12 @@ function WaypointMarker({
|
|
|
7830
7869
|
)
|
|
7831
7870
|
] });
|
|
7832
7871
|
}
|
|
7833
|
-
var
|
|
7872
|
+
var DEFAULT_ASSET_URL8, sizeMap10, checkIcon;
|
|
7834
7873
|
var init_WaypointMarker = __esm({
|
|
7835
7874
|
"components/game/atoms/WaypointMarker.tsx"() {
|
|
7836
7875
|
init_cn();
|
|
7837
7876
|
init_Icon();
|
|
7838
|
-
|
|
7877
|
+
DEFAULT_ASSET_URL8 = "https://almadar-kflow-assets.web.app/shared/world-map/battle_marker.png";
|
|
7839
7878
|
sizeMap10 = {
|
|
7840
7879
|
sm: { dot: "w-4 h-4", ring: "w-6 h-6", label: "text-xs mt-1", img: 12 },
|
|
7841
7880
|
md: { dot: "w-6 h-6", ring: "w-8 h-8", label: "text-sm mt-1.5", img: 18 },
|
|
@@ -7852,7 +7891,7 @@ function formatDuration(seconds) {
|
|
|
7852
7891
|
return `${Math.round(seconds)}s`;
|
|
7853
7892
|
}
|
|
7854
7893
|
function StatusEffect({
|
|
7855
|
-
assetUrl =
|
|
7894
|
+
assetUrl = DEFAULT_ASSET_URL9,
|
|
7856
7895
|
icon = "shield",
|
|
7857
7896
|
label = "Shield",
|
|
7858
7897
|
duration = 30,
|
|
@@ -7910,12 +7949,12 @@ function StatusEffect({
|
|
|
7910
7949
|
label && /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground mt-0.5 text-center whitespace-nowrap", children: label })
|
|
7911
7950
|
] });
|
|
7912
7951
|
}
|
|
7913
|
-
var
|
|
7952
|
+
var DEFAULT_ASSET_URL9, sizeMap11, variantStyles7;
|
|
7914
7953
|
var init_StatusEffect = __esm({
|
|
7915
7954
|
"components/game/atoms/StatusEffect.tsx"() {
|
|
7916
7955
|
init_cn();
|
|
7917
7956
|
init_Icon();
|
|
7918
|
-
|
|
7957
|
+
DEFAULT_ASSET_URL9 = "https://almadar-kflow-assets.web.app/shared/effects/particles/flame_01.png";
|
|
7919
7958
|
sizeMap11 = {
|
|
7920
7959
|
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 },
|
|
7921
7960
|
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 },
|
|
@@ -7930,6 +7969,7 @@ var init_StatusEffect = __esm({
|
|
|
7930
7969
|
}
|
|
7931
7970
|
});
|
|
7932
7971
|
function DamageNumber({
|
|
7972
|
+
assetUrl = DEFAULT_ASSET_URL10,
|
|
7933
7973
|
value = 42,
|
|
7934
7974
|
type = "damage",
|
|
7935
7975
|
size = "md",
|
|
@@ -7938,22 +7978,35 @@ function DamageNumber({
|
|
|
7938
7978
|
const displayText = type === "miss" ? "MISS" : type === "heal" ? `+${value}` : `${value}`;
|
|
7939
7979
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
7940
7980
|
/* @__PURE__ */ jsx("style", { children: floatKeyframes }),
|
|
7941
|
-
/* @__PURE__ */
|
|
7981
|
+
/* @__PURE__ */ jsxs(
|
|
7942
7982
|
"span",
|
|
7943
7983
|
{
|
|
7944
7984
|
className: cn(
|
|
7945
|
-
"inline-
|
|
7985
|
+
"inline-flex items-center gap-0.5 font-mono select-none pointer-events-none",
|
|
7946
7986
|
sizeMap12[size],
|
|
7947
7987
|
typeStyles[type],
|
|
7948
7988
|
className
|
|
7949
7989
|
),
|
|
7950
7990
|
style: { animation: "damageFloat 1s ease-out forwards" },
|
|
7951
|
-
children:
|
|
7991
|
+
children: [
|
|
7992
|
+
assetUrl && /* @__PURE__ */ jsx(
|
|
7993
|
+
"img",
|
|
7994
|
+
{
|
|
7995
|
+
src: assetUrl,
|
|
7996
|
+
alt: "",
|
|
7997
|
+
width: 14,
|
|
7998
|
+
height: 14,
|
|
7999
|
+
style: { imageRendering: "pixelated", objectFit: "contain" },
|
|
8000
|
+
className: "flex-shrink-0"
|
|
8001
|
+
}
|
|
8002
|
+
),
|
|
8003
|
+
displayText
|
|
8004
|
+
]
|
|
7952
8005
|
}
|
|
7953
8006
|
)
|
|
7954
8007
|
] });
|
|
7955
8008
|
}
|
|
7956
|
-
var sizeMap12, typeStyles, floatKeyframes;
|
|
8009
|
+
var sizeMap12, typeStyles, floatKeyframes, DEFAULT_ASSET_URL10;
|
|
7957
8010
|
var init_DamageNumber = __esm({
|
|
7958
8011
|
"components/game/atoms/DamageNumber.tsx"() {
|
|
7959
8012
|
init_cn();
|
|
@@ -7975,6 +8028,7 @@ var init_DamageNumber = __esm({
|
|
|
7975
8028
|
100% { opacity: 0; transform: translateY(-32px) scale(0.8); }
|
|
7976
8029
|
}
|
|
7977
8030
|
`;
|
|
8031
|
+
DEFAULT_ASSET_URL10 = "https://almadar-kflow-assets.web.app/shared/effects/particles/spark_01.png";
|
|
7978
8032
|
DamageNumber.displayName = "DamageNumber";
|
|
7979
8033
|
}
|
|
7980
8034
|
});
|
|
@@ -8063,6 +8117,7 @@ var init_ChoiceButton = __esm({
|
|
|
8063
8117
|
}
|
|
8064
8118
|
});
|
|
8065
8119
|
function ActionButton({
|
|
8120
|
+
assetUrl = DEFAULT_ASSET_URL11,
|
|
8066
8121
|
label = "Attack",
|
|
8067
8122
|
icon,
|
|
8068
8123
|
cooldown = 0,
|
|
@@ -8102,13 +8157,23 @@ function ActionButton({
|
|
|
8102
8157
|
}
|
|
8103
8158
|
}
|
|
8104
8159
|
),
|
|
8105
|
-
|
|
8160
|
+
assetUrl ? /* @__PURE__ */ jsx(
|
|
8161
|
+
"img",
|
|
8162
|
+
{
|
|
8163
|
+
src: assetUrl,
|
|
8164
|
+
alt: "",
|
|
8165
|
+
width: 16,
|
|
8166
|
+
height: 16,
|
|
8167
|
+
style: { imageRendering: "pixelated", objectFit: "contain" },
|
|
8168
|
+
className: cn("flex-shrink-0", sizes.icon)
|
|
8169
|
+
}
|
|
8170
|
+
) : icon ? /* @__PURE__ */ jsx("span", { className: cn("flex-shrink-0", sizes.icon), children: typeof icon === "string" ? (() => {
|
|
8106
8171
|
const I = resolveIcon(icon);
|
|
8107
8172
|
return I ? /* @__PURE__ */ jsx(I, { className: "w-4 h-4" }) : null;
|
|
8108
8173
|
})() : /* @__PURE__ */ (() => {
|
|
8109
8174
|
const I = icon;
|
|
8110
8175
|
return /* @__PURE__ */ jsx(I, { className: "w-4 h-4" });
|
|
8111
|
-
})() }),
|
|
8176
|
+
})() }) : null,
|
|
8112
8177
|
/* @__PURE__ */ jsx("span", { className: "relative z-10", children: label }),
|
|
8113
8178
|
hotkey && /* @__PURE__ */ jsx(
|
|
8114
8179
|
"span",
|
|
@@ -8124,7 +8189,7 @@ function ActionButton({
|
|
|
8124
8189
|
}
|
|
8125
8190
|
);
|
|
8126
8191
|
}
|
|
8127
|
-
var sizeMap13, variantStyles8;
|
|
8192
|
+
var sizeMap13, variantStyles8, DEFAULT_ASSET_URL11;
|
|
8128
8193
|
var init_ActionButton = __esm({
|
|
8129
8194
|
"components/game/atoms/ActionButton.tsx"() {
|
|
8130
8195
|
init_cn();
|
|
@@ -8139,6 +8204,7 @@ var init_ActionButton = __esm({
|
|
|
8139
8204
|
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary-hover border-border",
|
|
8140
8205
|
danger: "bg-error text-error-foreground hover:bg-error/90 border-error"
|
|
8141
8206
|
};
|
|
8207
|
+
DEFAULT_ASSET_URL11 = "https://almadar-kflow-assets.web.app/shared/effects/particles/slash_01.png";
|
|
8142
8208
|
ActionButton.displayName = "ActionButton";
|
|
8143
8209
|
}
|
|
8144
8210
|
});
|
|
@@ -8651,10 +8717,10 @@ var init_Container = __esm({
|
|
|
8651
8717
|
center = true,
|
|
8652
8718
|
className,
|
|
8653
8719
|
children,
|
|
8654
|
-
as:
|
|
8720
|
+
as: Component2 = "div"
|
|
8655
8721
|
}) => {
|
|
8656
8722
|
const resolvedSize = maxWidth ?? size ?? "lg";
|
|
8657
|
-
const Comp =
|
|
8723
|
+
const Comp = Component2;
|
|
8658
8724
|
return /* @__PURE__ */ jsx(
|
|
8659
8725
|
Comp,
|
|
8660
8726
|
{
|
|
@@ -24660,7 +24726,7 @@ var init_Flex = __esm({
|
|
|
24660
24726
|
basis,
|
|
24661
24727
|
className,
|
|
24662
24728
|
children,
|
|
24663
|
-
as:
|
|
24729
|
+
as: Component2 = "div"
|
|
24664
24730
|
}) => {
|
|
24665
24731
|
const flexStyle = {};
|
|
24666
24732
|
if (grow !== void 0 || shrink !== void 0 || basis !== void 0) {
|
|
@@ -24672,7 +24738,7 @@ var init_Flex = __esm({
|
|
|
24672
24738
|
flexStyle.flexBasis = typeof basis === "number" ? `${basis}px` : basis;
|
|
24673
24739
|
}
|
|
24674
24740
|
}
|
|
24675
|
-
const Comp =
|
|
24741
|
+
const Comp = Component2;
|
|
24676
24742
|
return /* @__PURE__ */ jsx(
|
|
24677
24743
|
Comp,
|
|
24678
24744
|
{
|
|
@@ -24792,11 +24858,11 @@ var init_Grid = __esm({
|
|
|
24792
24858
|
className,
|
|
24793
24859
|
style,
|
|
24794
24860
|
children,
|
|
24795
|
-
as:
|
|
24861
|
+
as: Component2 = "div"
|
|
24796
24862
|
}) => {
|
|
24797
24863
|
const mergedStyle = rows2 ? { gridTemplateRows: `repeat(${rows2}, minmax(0, 1fr))`, ...style } : style;
|
|
24798
24864
|
return React82__default.createElement(
|
|
24799
|
-
|
|
24865
|
+
Component2,
|
|
24800
24866
|
{
|
|
24801
24867
|
className: cn(
|
|
24802
24868
|
"grid",
|
|
@@ -26622,6 +26688,7 @@ var init_ProgressDots = __esm({
|
|
|
26622
26688
|
}
|
|
26623
26689
|
});
|
|
26624
26690
|
function StatBadge({
|
|
26691
|
+
assetUrl = DEFAULT_ASSET_URL12,
|
|
26625
26692
|
label,
|
|
26626
26693
|
value = 0,
|
|
26627
26694
|
max,
|
|
@@ -26645,7 +26712,17 @@ function StatBadge({
|
|
|
26645
26712
|
className
|
|
26646
26713
|
),
|
|
26647
26714
|
children: [
|
|
26648
|
-
|
|
26715
|
+
assetUrl ? /* @__PURE__ */ jsx(
|
|
26716
|
+
"img",
|
|
26717
|
+
{
|
|
26718
|
+
src: assetUrl,
|
|
26719
|
+
alt: "",
|
|
26720
|
+
width: 16,
|
|
26721
|
+
height: 16,
|
|
26722
|
+
style: { imageRendering: "pixelated", objectFit: "contain" },
|
|
26723
|
+
className: "flex-shrink-0"
|
|
26724
|
+
}
|
|
26725
|
+
) : icon ? /* @__PURE__ */ jsx("span", { className: "flex-shrink-0 text-lg", children: typeof icon === "string" ? /* @__PURE__ */ jsx(Icon, { name: icon, className: "w-4 h-4" }) : /* @__PURE__ */ jsx(Icon, { icon, className: "w-4 h-4" }) }) : null,
|
|
26649
26726
|
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground font-medium", children: label }),
|
|
26650
26727
|
format === "hearts" && max && /* @__PURE__ */ jsx(
|
|
26651
26728
|
HealthBar,
|
|
@@ -26678,7 +26755,7 @@ function StatBadge({
|
|
|
26678
26755
|
}
|
|
26679
26756
|
);
|
|
26680
26757
|
}
|
|
26681
|
-
var sizeMap17, variantMap2;
|
|
26758
|
+
var sizeMap17, variantMap2, DEFAULT_ASSET_URL12;
|
|
26682
26759
|
var init_StatBadge = __esm({
|
|
26683
26760
|
"components/game/molecules/StatBadge.tsx"() {
|
|
26684
26761
|
init_cn();
|
|
@@ -26697,6 +26774,7 @@ var init_StatBadge = __esm({
|
|
|
26697
26774
|
warning: "bg-warning/15 border-warning/40 text-foreground",
|
|
26698
26775
|
danger: "bg-error/15 border-error/40 text-foreground"
|
|
26699
26776
|
};
|
|
26777
|
+
DEFAULT_ASSET_URL12 = "https://almadar-kflow-assets.web.app/shared/effects/particles/light_01.png";
|
|
26700
26778
|
StatBadge.displayName = "StatBadge";
|
|
26701
26779
|
}
|
|
26702
26780
|
});
|
|
@@ -27353,6 +27431,7 @@ var init_TurnPanel = __esm({
|
|
|
27353
27431
|
}
|
|
27354
27432
|
});
|
|
27355
27433
|
function EnemyPlate({
|
|
27434
|
+
assetUrl = DEFAULT_ASSET_URL13,
|
|
27356
27435
|
name = "Shadow Guard",
|
|
27357
27436
|
health = 80,
|
|
27358
27437
|
maxHealth = 100,
|
|
@@ -27370,15 +27449,28 @@ function EnemyPlate({
|
|
|
27370
27449
|
),
|
|
27371
27450
|
children: [
|
|
27372
27451
|
/* @__PURE__ */ jsxs(Box, { className: "flex items-center justify-between gap-2", children: [
|
|
27373
|
-
/* @__PURE__ */
|
|
27374
|
-
|
|
27375
|
-
|
|
27376
|
-
|
|
27377
|
-
|
|
27378
|
-
|
|
27379
|
-
|
|
27380
|
-
|
|
27381
|
-
|
|
27452
|
+
/* @__PURE__ */ jsxs(Box, { className: "flex items-center gap-1.5 min-w-0", children: [
|
|
27453
|
+
assetUrl && /* @__PURE__ */ jsx(
|
|
27454
|
+
"img",
|
|
27455
|
+
{
|
|
27456
|
+
src: assetUrl,
|
|
27457
|
+
alt: name,
|
|
27458
|
+
width: 24,
|
|
27459
|
+
height: 24,
|
|
27460
|
+
style: { objectFit: "cover", borderRadius: "50%" },
|
|
27461
|
+
className: "flex-shrink-0"
|
|
27462
|
+
}
|
|
27463
|
+
),
|
|
27464
|
+
/* @__PURE__ */ jsx(
|
|
27465
|
+
Typography,
|
|
27466
|
+
{
|
|
27467
|
+
variant: "caption",
|
|
27468
|
+
weight: "bold",
|
|
27469
|
+
className: "text-[var(--color-foreground)] truncate",
|
|
27470
|
+
children: name
|
|
27471
|
+
}
|
|
27472
|
+
)
|
|
27473
|
+
] }),
|
|
27382
27474
|
level != null && /* @__PURE__ */ jsxs(Badge, { variant: "neutral", size: "sm", children: [
|
|
27383
27475
|
"Lv.",
|
|
27384
27476
|
level
|
|
@@ -27423,7 +27515,7 @@ function EnemyPlate({
|
|
|
27423
27515
|
}
|
|
27424
27516
|
);
|
|
27425
27517
|
}
|
|
27426
|
-
var effectVariantMap2, DEFAULT_ENEMY_EFFECTS;
|
|
27518
|
+
var effectVariantMap2, DEFAULT_ENEMY_EFFECTS, DEFAULT_ASSET_URL13;
|
|
27427
27519
|
var init_EnemyPlate = __esm({
|
|
27428
27520
|
"components/game/molecules/EnemyPlate.tsx"() {
|
|
27429
27521
|
"use client";
|
|
@@ -27440,6 +27532,7 @@ var init_EnemyPlate = __esm({
|
|
|
27440
27532
|
DEFAULT_ENEMY_EFFECTS = [
|
|
27441
27533
|
{ icon: "flame", label: "Burn", variant: "debuff" }
|
|
27442
27534
|
];
|
|
27535
|
+
DEFAULT_ASSET_URL13 = "https://almadar-kflow-assets.web.app/shared/portraits/shadow-legion.png";
|
|
27443
27536
|
EnemyPlate.displayName = "EnemyPlate";
|
|
27444
27537
|
}
|
|
27445
27538
|
});
|
|
@@ -28971,13 +29064,13 @@ var init_MapView = __esm({
|
|
|
28971
29064
|
shadowSize: [41, 41]
|
|
28972
29065
|
});
|
|
28973
29066
|
L.Marker.prototype.options.icon = defaultIcon;
|
|
28974
|
-
const { useEffect:
|
|
29067
|
+
const { useEffect: useEffect80, useRef: useRef74, useCallback: useCallback118, useState: useState112 } = React82__default;
|
|
28975
29068
|
const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
|
|
28976
|
-
const { useEventBus:
|
|
29069
|
+
const { useEventBus: useEventBus4 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
|
|
28977
29070
|
function MapUpdater({ centerLat, centerLng, zoom }) {
|
|
28978
29071
|
const map = useMap();
|
|
28979
|
-
const prevRef =
|
|
28980
|
-
|
|
29072
|
+
const prevRef = useRef74({ centerLat, centerLng, zoom });
|
|
29073
|
+
useEffect80(() => {
|
|
28981
29074
|
const prev = prevRef.current;
|
|
28982
29075
|
if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
|
|
28983
29076
|
map.setView([centerLat, centerLng], zoom);
|
|
@@ -28988,7 +29081,7 @@ var init_MapView = __esm({
|
|
|
28988
29081
|
}
|
|
28989
29082
|
function MapClickHandler({ onMapClick }) {
|
|
28990
29083
|
const map = useMap();
|
|
28991
|
-
|
|
29084
|
+
useEffect80(() => {
|
|
28992
29085
|
if (!onMapClick) return;
|
|
28993
29086
|
const handler = (e) => {
|
|
28994
29087
|
onMapClick(e.latlng.lat, e.latlng.lng);
|
|
@@ -29015,9 +29108,9 @@ var init_MapView = __esm({
|
|
|
29015
29108
|
className,
|
|
29016
29109
|
showAttribution = true
|
|
29017
29110
|
}) {
|
|
29018
|
-
const eventBus =
|
|
29019
|
-
const [clickedPosition, setClickedPosition] =
|
|
29020
|
-
const handleMapClick =
|
|
29111
|
+
const eventBus = useEventBus4();
|
|
29112
|
+
const [clickedPosition, setClickedPosition] = useState112(null);
|
|
29113
|
+
const handleMapClick = useCallback118((lat, lng) => {
|
|
29021
29114
|
if (showClickedPin) {
|
|
29022
29115
|
setClickedPosition({ lat, lng });
|
|
29023
29116
|
}
|
|
@@ -29026,7 +29119,7 @@ var init_MapView = __esm({
|
|
|
29026
29119
|
eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
|
|
29027
29120
|
}
|
|
29028
29121
|
}, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
|
|
29029
|
-
const handleMarkerClick =
|
|
29122
|
+
const handleMarkerClick = useCallback118((marker) => {
|
|
29030
29123
|
onMarkerClick?.(marker);
|
|
29031
29124
|
if (markerClickEvent) {
|
|
29032
29125
|
eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
|
|
@@ -36153,10 +36246,10 @@ var init_Section = __esm({
|
|
|
36153
36246
|
children,
|
|
36154
36247
|
headerClassName,
|
|
36155
36248
|
contentClassName,
|
|
36156
|
-
as:
|
|
36249
|
+
as: Component2 = "section"
|
|
36157
36250
|
}) => {
|
|
36158
36251
|
const hasHeader = title || description || action;
|
|
36159
|
-
const Comp =
|
|
36252
|
+
const Comp = Component2;
|
|
36160
36253
|
return /* @__PURE__ */ jsxs(
|
|
36161
36254
|
Comp,
|
|
36162
36255
|
{
|
|
@@ -40721,6 +40814,1568 @@ var init_GameAudioToggle = __esm({
|
|
|
40721
40814
|
GameAudioToggle.displayName = "GameAudioToggle";
|
|
40722
40815
|
}
|
|
40723
40816
|
});
|
|
40817
|
+
function detectAssetRoot(modelUrl) {
|
|
40818
|
+
const idx = modelUrl.indexOf("/3d/");
|
|
40819
|
+
if (idx !== -1) {
|
|
40820
|
+
return modelUrl.substring(0, idx + 4);
|
|
40821
|
+
}
|
|
40822
|
+
return modelUrl.substring(0, modelUrl.lastIndexOf("/") + 1);
|
|
40823
|
+
}
|
|
40824
|
+
function createGLTFLoaderForUrl(url) {
|
|
40825
|
+
const loader = new GLTFLoader();
|
|
40826
|
+
loader.setResourcePath(detectAssetRoot(url));
|
|
40827
|
+
return loader;
|
|
40828
|
+
}
|
|
40829
|
+
var AssetLoader;
|
|
40830
|
+
var init_AssetLoader = __esm({
|
|
40831
|
+
"components/game/molecules/three/loaders/AssetLoader.ts"() {
|
|
40832
|
+
AssetLoader = class {
|
|
40833
|
+
constructor() {
|
|
40834
|
+
__publicField(this, "objLoader");
|
|
40835
|
+
__publicField(this, "textureLoader");
|
|
40836
|
+
__publicField(this, "modelCache");
|
|
40837
|
+
__publicField(this, "textureCache");
|
|
40838
|
+
__publicField(this, "loadingPromises");
|
|
40839
|
+
this.objLoader = new OBJLoader();
|
|
40840
|
+
this.textureLoader = new THREE.TextureLoader();
|
|
40841
|
+
this.modelCache = /* @__PURE__ */ new Map();
|
|
40842
|
+
this.textureCache = /* @__PURE__ */ new Map();
|
|
40843
|
+
this.loadingPromises = /* @__PURE__ */ new Map();
|
|
40844
|
+
}
|
|
40845
|
+
/**
|
|
40846
|
+
* Load a GLB/GLTF model
|
|
40847
|
+
* @param url - URL to the .glb or .gltf file
|
|
40848
|
+
* @returns Promise with loaded model scene and animations
|
|
40849
|
+
*/
|
|
40850
|
+
async loadModel(url) {
|
|
40851
|
+
if (this.modelCache.has(url)) {
|
|
40852
|
+
return this.modelCache.get(url);
|
|
40853
|
+
}
|
|
40854
|
+
if (this.loadingPromises.has(url)) {
|
|
40855
|
+
return this.loadingPromises.get(url);
|
|
40856
|
+
}
|
|
40857
|
+
const loader = createGLTFLoaderForUrl(url);
|
|
40858
|
+
const loadPromise = loader.loadAsync(url).then((gltf) => {
|
|
40859
|
+
const result = {
|
|
40860
|
+
scene: gltf.scene,
|
|
40861
|
+
animations: gltf.animations || []
|
|
40862
|
+
};
|
|
40863
|
+
this.modelCache.set(url, result);
|
|
40864
|
+
this.loadingPromises.delete(url);
|
|
40865
|
+
return result;
|
|
40866
|
+
}).catch((error) => {
|
|
40867
|
+
this.loadingPromises.delete(url);
|
|
40868
|
+
throw new Error(`Failed to load model ${url}: ${error.message}`);
|
|
40869
|
+
});
|
|
40870
|
+
this.loadingPromises.set(url, loadPromise);
|
|
40871
|
+
return loadPromise;
|
|
40872
|
+
}
|
|
40873
|
+
/**
|
|
40874
|
+
* Load an OBJ model (fallback for non-GLB assets)
|
|
40875
|
+
* @param url - URL to the .obj file
|
|
40876
|
+
* @returns Promise with loaded object group
|
|
40877
|
+
*/
|
|
40878
|
+
async loadOBJ(url) {
|
|
40879
|
+
if (this.modelCache.has(url)) {
|
|
40880
|
+
return this.modelCache.get(url).scene;
|
|
40881
|
+
}
|
|
40882
|
+
if (this.loadingPromises.has(url)) {
|
|
40883
|
+
const result = await this.loadingPromises.get(url);
|
|
40884
|
+
return result.scene;
|
|
40885
|
+
}
|
|
40886
|
+
const loadPromise = this.objLoader.loadAsync(url).then((group) => {
|
|
40887
|
+
const result = {
|
|
40888
|
+
scene: group,
|
|
40889
|
+
animations: []
|
|
40890
|
+
};
|
|
40891
|
+
this.modelCache.set(url, result);
|
|
40892
|
+
this.loadingPromises.delete(url);
|
|
40893
|
+
return result;
|
|
40894
|
+
}).catch((error) => {
|
|
40895
|
+
this.loadingPromises.delete(url);
|
|
40896
|
+
throw new Error(`Failed to load OBJ ${url}: ${error.message}`);
|
|
40897
|
+
});
|
|
40898
|
+
this.loadingPromises.set(url, loadPromise);
|
|
40899
|
+
return (await loadPromise).scene;
|
|
40900
|
+
}
|
|
40901
|
+
/**
|
|
40902
|
+
* Load a texture
|
|
40903
|
+
* @param url - URL to the texture image
|
|
40904
|
+
* @returns Promise with loaded texture
|
|
40905
|
+
*/
|
|
40906
|
+
async loadTexture(url) {
|
|
40907
|
+
if (this.textureCache.has(url)) {
|
|
40908
|
+
return this.textureCache.get(url);
|
|
40909
|
+
}
|
|
40910
|
+
if (this.loadingPromises.has(`texture:${url}`)) {
|
|
40911
|
+
return this.loadingPromises.get(`texture:${url}`);
|
|
40912
|
+
}
|
|
40913
|
+
const loadPromise = this.textureLoader.loadAsync(url).then((texture) => {
|
|
40914
|
+
texture.colorSpace = THREE.SRGBColorSpace;
|
|
40915
|
+
this.textureCache.set(url, texture);
|
|
40916
|
+
this.loadingPromises.delete(`texture:${url}`);
|
|
40917
|
+
return texture;
|
|
40918
|
+
}).catch((error) => {
|
|
40919
|
+
this.loadingPromises.delete(`texture:${url}`);
|
|
40920
|
+
throw new Error(`Failed to load texture ${url}: ${error.message}`);
|
|
40921
|
+
});
|
|
40922
|
+
this.loadingPromises.set(`texture:${url}`, loadPromise);
|
|
40923
|
+
return loadPromise;
|
|
40924
|
+
}
|
|
40925
|
+
/**
|
|
40926
|
+
* Preload multiple assets
|
|
40927
|
+
* @param urls - Array of asset URLs to preload
|
|
40928
|
+
* @returns Promise that resolves when all assets are loaded
|
|
40929
|
+
*/
|
|
40930
|
+
async preload(urls) {
|
|
40931
|
+
const promises = urls.map((url) => {
|
|
40932
|
+
if (url.endsWith(".glb") || url.endsWith(".gltf")) {
|
|
40933
|
+
return this.loadModel(url).catch(() => null);
|
|
40934
|
+
} else if (url.endsWith(".obj")) {
|
|
40935
|
+
return this.loadOBJ(url).catch(() => null);
|
|
40936
|
+
} else if (/\.(png|jpg|jpeg|webp)$/i.test(url)) {
|
|
40937
|
+
return this.loadTexture(url).catch(() => null);
|
|
40938
|
+
}
|
|
40939
|
+
return Promise.resolve(null);
|
|
40940
|
+
});
|
|
40941
|
+
await Promise.all(promises);
|
|
40942
|
+
}
|
|
40943
|
+
/**
|
|
40944
|
+
* Check if a model is cached
|
|
40945
|
+
* @param url - Model URL
|
|
40946
|
+
*/
|
|
40947
|
+
hasModel(url) {
|
|
40948
|
+
return this.modelCache.has(url);
|
|
40949
|
+
}
|
|
40950
|
+
/**
|
|
40951
|
+
* Check if a texture is cached
|
|
40952
|
+
* @param url - Texture URL
|
|
40953
|
+
*/
|
|
40954
|
+
hasTexture(url) {
|
|
40955
|
+
return this.textureCache.has(url);
|
|
40956
|
+
}
|
|
40957
|
+
/**
|
|
40958
|
+
* Get cached model (throws if not cached)
|
|
40959
|
+
* @param url - Model URL
|
|
40960
|
+
*/
|
|
40961
|
+
getModel(url) {
|
|
40962
|
+
const model = this.modelCache.get(url);
|
|
40963
|
+
if (!model) {
|
|
40964
|
+
throw new Error(`Model ${url} not in cache`);
|
|
40965
|
+
}
|
|
40966
|
+
return model;
|
|
40967
|
+
}
|
|
40968
|
+
/**
|
|
40969
|
+
* Get cached texture (throws if not cached)
|
|
40970
|
+
* @param url - Texture URL
|
|
40971
|
+
*/
|
|
40972
|
+
getTexture(url) {
|
|
40973
|
+
const texture = this.textureCache.get(url);
|
|
40974
|
+
if (!texture) {
|
|
40975
|
+
throw new Error(`Texture ${url} not in cache`);
|
|
40976
|
+
}
|
|
40977
|
+
return texture;
|
|
40978
|
+
}
|
|
40979
|
+
/**
|
|
40980
|
+
* Clear all caches
|
|
40981
|
+
*/
|
|
40982
|
+
clearCache() {
|
|
40983
|
+
this.textureCache.forEach((texture) => {
|
|
40984
|
+
texture.dispose();
|
|
40985
|
+
});
|
|
40986
|
+
this.modelCache.forEach((model) => {
|
|
40987
|
+
model.scene.traverse((child) => {
|
|
40988
|
+
if (child instanceof THREE.Mesh) {
|
|
40989
|
+
child.geometry.dispose();
|
|
40990
|
+
if (Array.isArray(child.material)) {
|
|
40991
|
+
child.material.forEach((m) => m.dispose());
|
|
40992
|
+
} else {
|
|
40993
|
+
child.material.dispose();
|
|
40994
|
+
}
|
|
40995
|
+
}
|
|
40996
|
+
});
|
|
40997
|
+
});
|
|
40998
|
+
this.modelCache.clear();
|
|
40999
|
+
this.textureCache.clear();
|
|
41000
|
+
this.loadingPromises.clear();
|
|
41001
|
+
}
|
|
41002
|
+
/**
|
|
41003
|
+
* Get cache statistics
|
|
41004
|
+
*/
|
|
41005
|
+
getStats() {
|
|
41006
|
+
return {
|
|
41007
|
+
models: this.modelCache.size,
|
|
41008
|
+
textures: this.textureCache.size,
|
|
41009
|
+
loading: this.loadingPromises.size
|
|
41010
|
+
};
|
|
41011
|
+
}
|
|
41012
|
+
};
|
|
41013
|
+
new AssetLoader();
|
|
41014
|
+
}
|
|
41015
|
+
});
|
|
41016
|
+
function useAssetLoader(options = {}) {
|
|
41017
|
+
const { preloadUrls = [], loader: customLoader } = options;
|
|
41018
|
+
const loaderRef = useRef(customLoader || new AssetLoader());
|
|
41019
|
+
const [state, setState] = useState({
|
|
41020
|
+
isLoading: false,
|
|
41021
|
+
progress: 0,
|
|
41022
|
+
loaded: 0,
|
|
41023
|
+
total: 0,
|
|
41024
|
+
errors: []
|
|
41025
|
+
});
|
|
41026
|
+
useEffect(() => {
|
|
41027
|
+
if (preloadUrls.length > 0) {
|
|
41028
|
+
preload(preloadUrls);
|
|
41029
|
+
}
|
|
41030
|
+
}, []);
|
|
41031
|
+
const updateProgress = useCallback((loaded, total) => {
|
|
41032
|
+
setState((prev) => ({
|
|
41033
|
+
...prev,
|
|
41034
|
+
loaded,
|
|
41035
|
+
total,
|
|
41036
|
+
progress: total > 0 ? Math.round(loaded / total * 100) : 0
|
|
41037
|
+
}));
|
|
41038
|
+
}, []);
|
|
41039
|
+
const loadModel = useCallback(
|
|
41040
|
+
async (url) => {
|
|
41041
|
+
setState((prev) => ({ ...prev, isLoading: true }));
|
|
41042
|
+
try {
|
|
41043
|
+
const model = await loaderRef.current.loadModel(url);
|
|
41044
|
+
setState((prev) => ({
|
|
41045
|
+
...prev,
|
|
41046
|
+
isLoading: false,
|
|
41047
|
+
loaded: prev.loaded + 1
|
|
41048
|
+
}));
|
|
41049
|
+
return model;
|
|
41050
|
+
} catch (error) {
|
|
41051
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
41052
|
+
setState((prev) => ({
|
|
41053
|
+
...prev,
|
|
41054
|
+
isLoading: false,
|
|
41055
|
+
errors: [...prev.errors, errorMsg]
|
|
41056
|
+
}));
|
|
41057
|
+
throw error;
|
|
41058
|
+
}
|
|
41059
|
+
},
|
|
41060
|
+
[]
|
|
41061
|
+
);
|
|
41062
|
+
const loadOBJ = useCallback(
|
|
41063
|
+
async (url) => {
|
|
41064
|
+
setState((prev) => ({ ...prev, isLoading: true }));
|
|
41065
|
+
try {
|
|
41066
|
+
const model = await loaderRef.current.loadOBJ(url);
|
|
41067
|
+
setState((prev) => ({
|
|
41068
|
+
...prev,
|
|
41069
|
+
isLoading: false,
|
|
41070
|
+
loaded: prev.loaded + 1
|
|
41071
|
+
}));
|
|
41072
|
+
return model;
|
|
41073
|
+
} catch (error) {
|
|
41074
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
41075
|
+
setState((prev) => ({
|
|
41076
|
+
...prev,
|
|
41077
|
+
isLoading: false,
|
|
41078
|
+
errors: [...prev.errors, errorMsg]
|
|
41079
|
+
}));
|
|
41080
|
+
throw error;
|
|
41081
|
+
}
|
|
41082
|
+
},
|
|
41083
|
+
[]
|
|
41084
|
+
);
|
|
41085
|
+
const loadTexture = useCallback(
|
|
41086
|
+
async (url) => {
|
|
41087
|
+
setState((prev) => ({ ...prev, isLoading: true }));
|
|
41088
|
+
try {
|
|
41089
|
+
const texture = await loaderRef.current.loadTexture(url);
|
|
41090
|
+
setState((prev) => ({
|
|
41091
|
+
...prev,
|
|
41092
|
+
isLoading: false,
|
|
41093
|
+
loaded: prev.loaded + 1
|
|
41094
|
+
}));
|
|
41095
|
+
return texture;
|
|
41096
|
+
} catch (error) {
|
|
41097
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
41098
|
+
setState((prev) => ({
|
|
41099
|
+
...prev,
|
|
41100
|
+
isLoading: false,
|
|
41101
|
+
errors: [...prev.errors, errorMsg]
|
|
41102
|
+
}));
|
|
41103
|
+
throw error;
|
|
41104
|
+
}
|
|
41105
|
+
},
|
|
41106
|
+
[]
|
|
41107
|
+
);
|
|
41108
|
+
const preload = useCallback(
|
|
41109
|
+
async (urls) => {
|
|
41110
|
+
setState((prev) => ({
|
|
41111
|
+
...prev,
|
|
41112
|
+
isLoading: true,
|
|
41113
|
+
total: urls.length,
|
|
41114
|
+
loaded: 0,
|
|
41115
|
+
errors: []
|
|
41116
|
+
}));
|
|
41117
|
+
let completed = 0;
|
|
41118
|
+
const errors = [];
|
|
41119
|
+
await Promise.all(
|
|
41120
|
+
urls.map(async (url) => {
|
|
41121
|
+
try {
|
|
41122
|
+
if (url.endsWith(".glb") || url.endsWith(".gltf")) {
|
|
41123
|
+
await loaderRef.current.loadModel(url);
|
|
41124
|
+
} else if (url.endsWith(".obj")) {
|
|
41125
|
+
await loaderRef.current.loadOBJ(url);
|
|
41126
|
+
} else if (/\.(png|jpg|jpeg|webp)$/i.test(url)) {
|
|
41127
|
+
await loaderRef.current.loadTexture(url);
|
|
41128
|
+
}
|
|
41129
|
+
completed++;
|
|
41130
|
+
updateProgress(completed, urls.length);
|
|
41131
|
+
} catch (error) {
|
|
41132
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
41133
|
+
errors.push(`${url}: ${errorMsg}`);
|
|
41134
|
+
completed++;
|
|
41135
|
+
updateProgress(completed, urls.length);
|
|
41136
|
+
}
|
|
41137
|
+
})
|
|
41138
|
+
);
|
|
41139
|
+
setState((prev) => ({
|
|
41140
|
+
...prev,
|
|
41141
|
+
isLoading: false,
|
|
41142
|
+
errors
|
|
41143
|
+
}));
|
|
41144
|
+
},
|
|
41145
|
+
[updateProgress]
|
|
41146
|
+
);
|
|
41147
|
+
const hasModel = useCallback((url) => {
|
|
41148
|
+
return loaderRef.current.hasModel(url);
|
|
41149
|
+
}, []);
|
|
41150
|
+
const hasTexture = useCallback((url) => {
|
|
41151
|
+
return loaderRef.current.hasTexture(url);
|
|
41152
|
+
}, []);
|
|
41153
|
+
const getModel = useCallback((url) => {
|
|
41154
|
+
try {
|
|
41155
|
+
return loaderRef.current.getModel(url);
|
|
41156
|
+
} catch {
|
|
41157
|
+
return void 0;
|
|
41158
|
+
}
|
|
41159
|
+
}, []);
|
|
41160
|
+
const getTexture = useCallback((url) => {
|
|
41161
|
+
try {
|
|
41162
|
+
return loaderRef.current.getTexture(url);
|
|
41163
|
+
} catch {
|
|
41164
|
+
return void 0;
|
|
41165
|
+
}
|
|
41166
|
+
}, []);
|
|
41167
|
+
const clearCache = useCallback(() => {
|
|
41168
|
+
loaderRef.current.clearCache();
|
|
41169
|
+
setState({
|
|
41170
|
+
isLoading: false,
|
|
41171
|
+
progress: 0,
|
|
41172
|
+
loaded: 0,
|
|
41173
|
+
total: 0,
|
|
41174
|
+
errors: []
|
|
41175
|
+
});
|
|
41176
|
+
}, []);
|
|
41177
|
+
return {
|
|
41178
|
+
...state,
|
|
41179
|
+
loadModel,
|
|
41180
|
+
loadOBJ,
|
|
41181
|
+
loadTexture,
|
|
41182
|
+
preload,
|
|
41183
|
+
hasModel,
|
|
41184
|
+
hasTexture,
|
|
41185
|
+
getModel,
|
|
41186
|
+
getTexture,
|
|
41187
|
+
clearCache
|
|
41188
|
+
};
|
|
41189
|
+
}
|
|
41190
|
+
var init_useAssetLoader = __esm({
|
|
41191
|
+
"components/game/molecules/three/hooks/useAssetLoader.ts"() {
|
|
41192
|
+
"use client";
|
|
41193
|
+
init_AssetLoader();
|
|
41194
|
+
}
|
|
41195
|
+
});
|
|
41196
|
+
function useGameCanvas3DEvents(options) {
|
|
41197
|
+
const {
|
|
41198
|
+
tileClickEvent,
|
|
41199
|
+
unitClickEvent,
|
|
41200
|
+
featureClickEvent,
|
|
41201
|
+
canvasClickEvent,
|
|
41202
|
+
tileHoverEvent,
|
|
41203
|
+
tileLeaveEvent,
|
|
41204
|
+
unitAnimationEvent,
|
|
41205
|
+
cameraChangeEvent,
|
|
41206
|
+
onTileClick,
|
|
41207
|
+
onUnitClick,
|
|
41208
|
+
onFeatureClick,
|
|
41209
|
+
onCanvasClick,
|
|
41210
|
+
onTileHover,
|
|
41211
|
+
onUnitAnimation
|
|
41212
|
+
} = options;
|
|
41213
|
+
const emit = useEmitEvent();
|
|
41214
|
+
const optionsRef = useRef(options);
|
|
41215
|
+
optionsRef.current = options;
|
|
41216
|
+
const handleTileClick = useCallback(
|
|
41217
|
+
(tile, event) => {
|
|
41218
|
+
if (tileClickEvent) {
|
|
41219
|
+
emit(tileClickEvent, {
|
|
41220
|
+
tileId: tile.id,
|
|
41221
|
+
x: tile.x,
|
|
41222
|
+
z: tile.z ?? tile.y ?? 0,
|
|
41223
|
+
type: tile.type,
|
|
41224
|
+
terrain: tile.terrain,
|
|
41225
|
+
elevation: tile.elevation
|
|
41226
|
+
});
|
|
41227
|
+
}
|
|
41228
|
+
optionsRef.current.onTileClick?.(tile, event);
|
|
41229
|
+
},
|
|
41230
|
+
[tileClickEvent, emit]
|
|
41231
|
+
);
|
|
41232
|
+
const handleUnitClick = useCallback(
|
|
41233
|
+
(unit, event) => {
|
|
41234
|
+
if (unitClickEvent) {
|
|
41235
|
+
emit(unitClickEvent, {
|
|
41236
|
+
unitId: unit.id,
|
|
41237
|
+
x: unit.x,
|
|
41238
|
+
z: unit.z ?? unit.y ?? 0,
|
|
41239
|
+
unitType: unit.unitType,
|
|
41240
|
+
name: unit.name,
|
|
41241
|
+
team: unit.team,
|
|
41242
|
+
faction: unit.faction,
|
|
41243
|
+
health: unit.health,
|
|
41244
|
+
maxHealth: unit.maxHealth
|
|
41245
|
+
});
|
|
41246
|
+
}
|
|
41247
|
+
optionsRef.current.onUnitClick?.(unit, event);
|
|
41248
|
+
},
|
|
41249
|
+
[unitClickEvent, emit]
|
|
41250
|
+
);
|
|
41251
|
+
const handleFeatureClick = useCallback(
|
|
41252
|
+
(feature, event) => {
|
|
41253
|
+
if (featureClickEvent) {
|
|
41254
|
+
emit(featureClickEvent, {
|
|
41255
|
+
featureId: feature.id,
|
|
41256
|
+
x: feature.x,
|
|
41257
|
+
z: feature.z ?? feature.y ?? 0,
|
|
41258
|
+
type: feature.type,
|
|
41259
|
+
elevation: feature.elevation
|
|
41260
|
+
});
|
|
41261
|
+
}
|
|
41262
|
+
optionsRef.current.onFeatureClick?.(feature, event);
|
|
41263
|
+
},
|
|
41264
|
+
[featureClickEvent, emit]
|
|
41265
|
+
);
|
|
41266
|
+
const handleCanvasClick = useCallback(
|
|
41267
|
+
(event) => {
|
|
41268
|
+
if (canvasClickEvent) {
|
|
41269
|
+
emit(canvasClickEvent, {
|
|
41270
|
+
clientX: event.clientX,
|
|
41271
|
+
clientY: event.clientY,
|
|
41272
|
+
button: event.button
|
|
41273
|
+
});
|
|
41274
|
+
}
|
|
41275
|
+
optionsRef.current.onCanvasClick?.(event);
|
|
41276
|
+
},
|
|
41277
|
+
[canvasClickEvent, emit]
|
|
41278
|
+
);
|
|
41279
|
+
const handleTileHover = useCallback(
|
|
41280
|
+
(tile, event) => {
|
|
41281
|
+
if (tile) {
|
|
41282
|
+
if (tileHoverEvent) {
|
|
41283
|
+
emit(tileHoverEvent, {
|
|
41284
|
+
tileId: tile.id,
|
|
41285
|
+
x: tile.x,
|
|
41286
|
+
z: tile.z ?? tile.y ?? 0,
|
|
41287
|
+
type: tile.type
|
|
41288
|
+
});
|
|
41289
|
+
}
|
|
41290
|
+
} else {
|
|
41291
|
+
if (tileLeaveEvent) {
|
|
41292
|
+
emit(tileLeaveEvent, {});
|
|
41293
|
+
}
|
|
41294
|
+
}
|
|
41295
|
+
optionsRef.current.onTileHover?.(tile, event);
|
|
41296
|
+
},
|
|
41297
|
+
[tileHoverEvent, tileLeaveEvent, emit]
|
|
41298
|
+
);
|
|
41299
|
+
const handleUnitAnimation = useCallback(
|
|
41300
|
+
(unitId, state) => {
|
|
41301
|
+
if (unitAnimationEvent) {
|
|
41302
|
+
emit(unitAnimationEvent, {
|
|
41303
|
+
unitId,
|
|
41304
|
+
state,
|
|
41305
|
+
timestamp: Date.now()
|
|
41306
|
+
});
|
|
41307
|
+
}
|
|
41308
|
+
optionsRef.current.onUnitAnimation?.(unitId, state);
|
|
41309
|
+
},
|
|
41310
|
+
[unitAnimationEvent, emit]
|
|
41311
|
+
);
|
|
41312
|
+
const handleCameraChange = useCallback(
|
|
41313
|
+
(position) => {
|
|
41314
|
+
if (cameraChangeEvent) {
|
|
41315
|
+
emit(cameraChangeEvent, {
|
|
41316
|
+
position,
|
|
41317
|
+
timestamp: Date.now()
|
|
41318
|
+
});
|
|
41319
|
+
}
|
|
41320
|
+
},
|
|
41321
|
+
[cameraChangeEvent, emit]
|
|
41322
|
+
);
|
|
41323
|
+
return {
|
|
41324
|
+
handleTileClick,
|
|
41325
|
+
handleUnitClick,
|
|
41326
|
+
handleFeatureClick,
|
|
41327
|
+
handleCanvasClick,
|
|
41328
|
+
handleTileHover,
|
|
41329
|
+
handleUnitAnimation,
|
|
41330
|
+
handleCameraChange
|
|
41331
|
+
};
|
|
41332
|
+
}
|
|
41333
|
+
var init_useGameCanvas3DEvents = __esm({
|
|
41334
|
+
"components/game/molecules/three/hooks/useGameCanvas3DEvents.ts"() {
|
|
41335
|
+
"use client";
|
|
41336
|
+
init_useEventBus();
|
|
41337
|
+
}
|
|
41338
|
+
});
|
|
41339
|
+
|
|
41340
|
+
// components/game/molecules/three/components/Canvas3DLoadingState.css
|
|
41341
|
+
var init_Canvas3DLoadingState = __esm({
|
|
41342
|
+
"components/game/molecules/three/components/Canvas3DLoadingState.css"() {
|
|
41343
|
+
}
|
|
41344
|
+
});
|
|
41345
|
+
function Canvas3DLoadingState({
|
|
41346
|
+
progress = 0,
|
|
41347
|
+
loaded = 0,
|
|
41348
|
+
total = 0,
|
|
41349
|
+
message = "Loading 3D Scene...",
|
|
41350
|
+
details,
|
|
41351
|
+
showSpinner = true,
|
|
41352
|
+
className
|
|
41353
|
+
}) {
|
|
41354
|
+
const clampedProgress = Math.max(0, Math.min(100, progress));
|
|
41355
|
+
const hasProgress = total > 0;
|
|
41356
|
+
return /* @__PURE__ */ jsxs("div", { className: `canvas-3d-loading ${className || ""}`, children: [
|
|
41357
|
+
/* @__PURE__ */ jsxs("div", { className: "canvas-3d-loading__content", children: [
|
|
41358
|
+
showSpinner && /* @__PURE__ */ jsxs("div", { className: "canvas-3d-loading__spinner", children: [
|
|
41359
|
+
/* @__PURE__ */ jsx("div", { className: "spinner__ring" }),
|
|
41360
|
+
/* @__PURE__ */ jsx("div", { className: "spinner__ring spinner__ring--secondary" })
|
|
41361
|
+
] }),
|
|
41362
|
+
/* @__PURE__ */ jsx("div", { className: "canvas-3d-loading__message", children: message }),
|
|
41363
|
+
details && /* @__PURE__ */ jsx("div", { className: "canvas-3d-loading__details", children: details }),
|
|
41364
|
+
hasProgress && /* @__PURE__ */ jsxs("div", { className: "canvas-3d-loading__progress", children: [
|
|
41365
|
+
/* @__PURE__ */ jsx("div", { className: "progress__bar", children: /* @__PURE__ */ jsx(
|
|
41366
|
+
"div",
|
|
41367
|
+
{
|
|
41368
|
+
className: "progress__fill",
|
|
41369
|
+
style: { width: `${clampedProgress}%` }
|
|
41370
|
+
}
|
|
41371
|
+
) }),
|
|
41372
|
+
/* @__PURE__ */ jsxs("div", { className: "progress__text", children: [
|
|
41373
|
+
/* @__PURE__ */ jsxs("span", { className: "progress__percentage", children: [
|
|
41374
|
+
clampedProgress,
|
|
41375
|
+
"%"
|
|
41376
|
+
] }),
|
|
41377
|
+
/* @__PURE__ */ jsxs("span", { className: "progress__count", children: [
|
|
41378
|
+
"(",
|
|
41379
|
+
loaded,
|
|
41380
|
+
"/",
|
|
41381
|
+
total,
|
|
41382
|
+
")"
|
|
41383
|
+
] })
|
|
41384
|
+
] })
|
|
41385
|
+
] })
|
|
41386
|
+
] }),
|
|
41387
|
+
/* @__PURE__ */ jsx("div", { className: "canvas-3d-loading__background", children: /* @__PURE__ */ jsx("div", { className: "bg__grid" }) })
|
|
41388
|
+
] });
|
|
41389
|
+
}
|
|
41390
|
+
var init_Canvas3DLoadingState2 = __esm({
|
|
41391
|
+
"components/game/molecules/three/components/Canvas3DLoadingState.tsx"() {
|
|
41392
|
+
init_Canvas3DLoadingState();
|
|
41393
|
+
}
|
|
41394
|
+
});
|
|
41395
|
+
|
|
41396
|
+
// components/game/molecules/three/components/Canvas3DErrorBoundary.css
|
|
41397
|
+
var init_Canvas3DErrorBoundary = __esm({
|
|
41398
|
+
"components/game/molecules/three/components/Canvas3DErrorBoundary.css"() {
|
|
41399
|
+
}
|
|
41400
|
+
});
|
|
41401
|
+
var log10, Canvas3DErrorBoundary;
|
|
41402
|
+
var init_Canvas3DErrorBoundary2 = __esm({
|
|
41403
|
+
"components/game/molecules/three/components/Canvas3DErrorBoundary.tsx"() {
|
|
41404
|
+
init_Canvas3DErrorBoundary();
|
|
41405
|
+
log10 = createLogger("almadar:ui:game:canvas3d:error-boundary");
|
|
41406
|
+
Canvas3DErrorBoundary = class extends Component {
|
|
41407
|
+
constructor(props) {
|
|
41408
|
+
super(props);
|
|
41409
|
+
__publicField(this, "handleReset", () => {
|
|
41410
|
+
this.setState({
|
|
41411
|
+
hasError: false,
|
|
41412
|
+
error: null,
|
|
41413
|
+
errorInfo: null
|
|
41414
|
+
});
|
|
41415
|
+
this.props.onReset?.();
|
|
41416
|
+
});
|
|
41417
|
+
this.state = {
|
|
41418
|
+
hasError: false,
|
|
41419
|
+
error: null,
|
|
41420
|
+
errorInfo: null
|
|
41421
|
+
};
|
|
41422
|
+
}
|
|
41423
|
+
static getDerivedStateFromError(error) {
|
|
41424
|
+
return {
|
|
41425
|
+
hasError: true,
|
|
41426
|
+
error,
|
|
41427
|
+
errorInfo: null
|
|
41428
|
+
};
|
|
41429
|
+
}
|
|
41430
|
+
componentDidCatch(error, errorInfo) {
|
|
41431
|
+
this.setState({ errorInfo });
|
|
41432
|
+
this.props.onError?.(error, errorInfo);
|
|
41433
|
+
log10.error("Error caught", { error });
|
|
41434
|
+
log10.error("Component stack", { componentStack: errorInfo.componentStack ?? "<none>" });
|
|
41435
|
+
}
|
|
41436
|
+
render() {
|
|
41437
|
+
if (this.state.hasError) {
|
|
41438
|
+
if (this.props.fallback) {
|
|
41439
|
+
return this.props.fallback;
|
|
41440
|
+
}
|
|
41441
|
+
return /* @__PURE__ */ jsx("div", { className: "canvas-3d-error", children: /* @__PURE__ */ jsxs("div", { className: "canvas-3d-error__content", children: [
|
|
41442
|
+
/* @__PURE__ */ jsx("div", { className: "canvas-3d-error__icon", children: "\u26A0\uFE0F" }),
|
|
41443
|
+
/* @__PURE__ */ jsx("h2", { className: "canvas-3d-error__title", children: "3D Scene Error" }),
|
|
41444
|
+
/* @__PURE__ */ jsx("p", { className: "canvas-3d-error__message", children: "Something went wrong while rendering the 3D scene." }),
|
|
41445
|
+
this.state.error && /* @__PURE__ */ jsxs("details", { className: "canvas-3d-error__details", children: [
|
|
41446
|
+
/* @__PURE__ */ jsx("summary", { children: "Error Details" }),
|
|
41447
|
+
/* @__PURE__ */ jsxs("pre", { className: "error__stack", children: [
|
|
41448
|
+
this.state.error.message,
|
|
41449
|
+
"\n",
|
|
41450
|
+
this.state.error.stack
|
|
41451
|
+
] }),
|
|
41452
|
+
this.state.errorInfo && /* @__PURE__ */ jsx("pre", { className: "error__component-stack", children: this.state.errorInfo.componentStack })
|
|
41453
|
+
] }),
|
|
41454
|
+
/* @__PURE__ */ jsxs("div", { className: "canvas-3d-error__actions", children: [
|
|
41455
|
+
/* @__PURE__ */ jsx(
|
|
41456
|
+
"button",
|
|
41457
|
+
{
|
|
41458
|
+
className: "error__button error__button--primary",
|
|
41459
|
+
onClick: this.handleReset,
|
|
41460
|
+
children: "Try Again"
|
|
41461
|
+
}
|
|
41462
|
+
),
|
|
41463
|
+
/* @__PURE__ */ jsx(
|
|
41464
|
+
"button",
|
|
41465
|
+
{
|
|
41466
|
+
className: "error__button error__button--secondary",
|
|
41467
|
+
onClick: () => window.location.reload(),
|
|
41468
|
+
children: "Reload Page"
|
|
41469
|
+
}
|
|
41470
|
+
)
|
|
41471
|
+
] })
|
|
41472
|
+
] }) });
|
|
41473
|
+
}
|
|
41474
|
+
return this.props.children;
|
|
41475
|
+
}
|
|
41476
|
+
};
|
|
41477
|
+
}
|
|
41478
|
+
});
|
|
41479
|
+
function detectAssetRoot2(modelUrl) {
|
|
41480
|
+
const idx = modelUrl.indexOf("/3d/");
|
|
41481
|
+
if (idx !== -1) {
|
|
41482
|
+
return modelUrl.substring(0, idx + 4);
|
|
41483
|
+
}
|
|
41484
|
+
return modelUrl.substring(0, modelUrl.lastIndexOf("/") + 1);
|
|
41485
|
+
}
|
|
41486
|
+
function useGLTFModel(url, resourceBasePath) {
|
|
41487
|
+
const [state, setState] = useState({
|
|
41488
|
+
model: null,
|
|
41489
|
+
isLoading: false,
|
|
41490
|
+
error: null
|
|
41491
|
+
});
|
|
41492
|
+
useEffect(() => {
|
|
41493
|
+
if (!url) {
|
|
41494
|
+
setState({ model: null, isLoading: false, error: null });
|
|
41495
|
+
return;
|
|
41496
|
+
}
|
|
41497
|
+
log11.debug("Loading", { url });
|
|
41498
|
+
setState((prev) => ({ ...prev, isLoading: true, error: null }));
|
|
41499
|
+
const assetRoot = resourceBasePath || detectAssetRoot2(url);
|
|
41500
|
+
const loader = new GLTFLoader$1();
|
|
41501
|
+
loader.setResourcePath(assetRoot);
|
|
41502
|
+
loader.load(
|
|
41503
|
+
url,
|
|
41504
|
+
(gltf) => {
|
|
41505
|
+
log11.debug("Loaded", { url });
|
|
41506
|
+
setState({
|
|
41507
|
+
model: gltf.scene,
|
|
41508
|
+
isLoading: false,
|
|
41509
|
+
error: null
|
|
41510
|
+
});
|
|
41511
|
+
},
|
|
41512
|
+
void 0,
|
|
41513
|
+
(err) => {
|
|
41514
|
+
log11.warn("Failed", { url, error: err instanceof Error ? err : String(err) });
|
|
41515
|
+
setState({
|
|
41516
|
+
model: null,
|
|
41517
|
+
isLoading: false,
|
|
41518
|
+
error: err instanceof Error ? err : new Error(String(err))
|
|
41519
|
+
});
|
|
41520
|
+
}
|
|
41521
|
+
);
|
|
41522
|
+
}, [url, resourceBasePath]);
|
|
41523
|
+
return state;
|
|
41524
|
+
}
|
|
41525
|
+
function ModelLoader({
|
|
41526
|
+
url,
|
|
41527
|
+
position = [0, 0, 0],
|
|
41528
|
+
scale = 1,
|
|
41529
|
+
rotation = [0, 0, 0],
|
|
41530
|
+
isSelected = false,
|
|
41531
|
+
isHovered = false,
|
|
41532
|
+
onClick,
|
|
41533
|
+
onHover,
|
|
41534
|
+
fallbackGeometry = "box",
|
|
41535
|
+
castShadow = true,
|
|
41536
|
+
receiveShadow = true,
|
|
41537
|
+
resourceBasePath
|
|
41538
|
+
}) {
|
|
41539
|
+
const { model: loadedModel, isLoading, error } = useGLTFModel(url, resourceBasePath);
|
|
41540
|
+
const model = useMemo(() => {
|
|
41541
|
+
if (!loadedModel) return null;
|
|
41542
|
+
const cloned = loadedModel.clone();
|
|
41543
|
+
cloned.traverse((child) => {
|
|
41544
|
+
if (child instanceof THREE.Mesh) {
|
|
41545
|
+
child.castShadow = castShadow;
|
|
41546
|
+
child.receiveShadow = receiveShadow;
|
|
41547
|
+
}
|
|
41548
|
+
});
|
|
41549
|
+
return cloned;
|
|
41550
|
+
}, [loadedModel, castShadow, receiveShadow]);
|
|
41551
|
+
const scaleArray = useMemo(() => {
|
|
41552
|
+
if (typeof scale === "number") {
|
|
41553
|
+
return [scale, scale, scale];
|
|
41554
|
+
}
|
|
41555
|
+
return scale;
|
|
41556
|
+
}, [scale]);
|
|
41557
|
+
const rotationRad = useMemo(() => {
|
|
41558
|
+
return [
|
|
41559
|
+
rotation[0] * Math.PI / 180,
|
|
41560
|
+
rotation[1] * Math.PI / 180,
|
|
41561
|
+
rotation[2] * Math.PI / 180
|
|
41562
|
+
];
|
|
41563
|
+
}, [rotation]);
|
|
41564
|
+
if (isLoading) {
|
|
41565
|
+
return /* @__PURE__ */ jsx("group", { position, children: /* @__PURE__ */ jsxs("mesh", { rotation: [Math.PI / 2, 0, 0], children: [
|
|
41566
|
+
/* @__PURE__ */ jsx("ringGeometry", { args: [0.3, 0.35, 16] }),
|
|
41567
|
+
/* @__PURE__ */ jsx("meshBasicMaterial", { color: "#4a90d9", transparent: true, opacity: 0.8 })
|
|
41568
|
+
] }) });
|
|
41569
|
+
}
|
|
41570
|
+
if (error || !model) {
|
|
41571
|
+
if (fallbackGeometry === "none") {
|
|
41572
|
+
return /* @__PURE__ */ jsx("group", { position });
|
|
41573
|
+
}
|
|
41574
|
+
const fallbackProps = {
|
|
41575
|
+
onClick,
|
|
41576
|
+
onPointerOver: () => onHover?.(true),
|
|
41577
|
+
onPointerOut: () => onHover?.(false)
|
|
41578
|
+
};
|
|
41579
|
+
return /* @__PURE__ */ jsxs("group", { position, children: [
|
|
41580
|
+
(isSelected || isHovered) && /* @__PURE__ */ jsxs("mesh", { position: [0, 0.02, 0], rotation: [-Math.PI / 2, 0, 0], children: [
|
|
41581
|
+
/* @__PURE__ */ jsx("ringGeometry", { args: [0.6, 0.7, 32] }),
|
|
41582
|
+
/* @__PURE__ */ jsx(
|
|
41583
|
+
"meshBasicMaterial",
|
|
41584
|
+
{
|
|
41585
|
+
color: isSelected ? 16755200 : 16777215,
|
|
41586
|
+
transparent: true,
|
|
41587
|
+
opacity: 0.5
|
|
41588
|
+
}
|
|
41589
|
+
)
|
|
41590
|
+
] }),
|
|
41591
|
+
fallbackGeometry === "box" && /* @__PURE__ */ jsxs("mesh", { ...fallbackProps, position: [0, 0.5, 0], children: [
|
|
41592
|
+
/* @__PURE__ */ jsx("boxGeometry", { args: [0.8, 0.8, 0.8] }),
|
|
41593
|
+
/* @__PURE__ */ jsx("meshStandardMaterial", { color: error ? 16729156 : 8947848 })
|
|
41594
|
+
] }),
|
|
41595
|
+
fallbackGeometry === "sphere" && /* @__PURE__ */ jsxs("mesh", { ...fallbackProps, position: [0, 0.5, 0], children: [
|
|
41596
|
+
/* @__PURE__ */ jsx("sphereGeometry", { args: [0.4, 16, 16] }),
|
|
41597
|
+
/* @__PURE__ */ jsx("meshStandardMaterial", { color: error ? 16729156 : 8947848 })
|
|
41598
|
+
] }),
|
|
41599
|
+
fallbackGeometry === "cylinder" && /* @__PURE__ */ jsxs("mesh", { ...fallbackProps, position: [0, 0.5, 0], children: [
|
|
41600
|
+
/* @__PURE__ */ jsx("cylinderGeometry", { args: [0.3, 0.3, 0.8, 16] }),
|
|
41601
|
+
/* @__PURE__ */ jsx("meshStandardMaterial", { color: error ? 16729156 : 8947848 })
|
|
41602
|
+
] })
|
|
41603
|
+
] });
|
|
41604
|
+
}
|
|
41605
|
+
return /* @__PURE__ */ jsxs(
|
|
41606
|
+
"group",
|
|
41607
|
+
{
|
|
41608
|
+
position,
|
|
41609
|
+
rotation: rotationRad,
|
|
41610
|
+
onClick,
|
|
41611
|
+
onPointerOver: () => onHover?.(true),
|
|
41612
|
+
onPointerOut: () => onHover?.(false),
|
|
41613
|
+
children: [
|
|
41614
|
+
(isSelected || isHovered) && /* @__PURE__ */ jsxs("mesh", { position: [0, 0.02, 0], rotation: [-Math.PI / 2, 0, 0], children: [
|
|
41615
|
+
/* @__PURE__ */ jsx("ringGeometry", { args: [0.6, 0.7, 32] }),
|
|
41616
|
+
/* @__PURE__ */ jsx(
|
|
41617
|
+
"meshBasicMaterial",
|
|
41618
|
+
{
|
|
41619
|
+
color: isSelected ? 16755200 : 16777215,
|
|
41620
|
+
transparent: true,
|
|
41621
|
+
opacity: 0.5
|
|
41622
|
+
}
|
|
41623
|
+
)
|
|
41624
|
+
] }),
|
|
41625
|
+
/* @__PURE__ */ jsx("primitive", { object: model, scale: scaleArray })
|
|
41626
|
+
]
|
|
41627
|
+
}
|
|
41628
|
+
);
|
|
41629
|
+
}
|
|
41630
|
+
var log11;
|
|
41631
|
+
var init_ModelLoader = __esm({
|
|
41632
|
+
"components/game/molecules/three/components/ModelLoader.tsx"() {
|
|
41633
|
+
"use client";
|
|
41634
|
+
log11 = createLogger("almadar:ui:game:model-loader");
|
|
41635
|
+
}
|
|
41636
|
+
});
|
|
41637
|
+
|
|
41638
|
+
// components/game/molecules/GameCanvas3D.css
|
|
41639
|
+
var init_GameCanvas3D = __esm({
|
|
41640
|
+
"components/game/molecules/GameCanvas3D.css"() {
|
|
41641
|
+
}
|
|
41642
|
+
});
|
|
41643
|
+
function CameraController({
|
|
41644
|
+
onCameraChange
|
|
41645
|
+
}) {
|
|
41646
|
+
const { camera } = useThree();
|
|
41647
|
+
useEffect(() => {
|
|
41648
|
+
if (onCameraChange) {
|
|
41649
|
+
onCameraChange({
|
|
41650
|
+
x: camera.position.x,
|
|
41651
|
+
y: camera.position.y,
|
|
41652
|
+
z: camera.position.z
|
|
41653
|
+
});
|
|
41654
|
+
}
|
|
41655
|
+
}, [camera.position, onCameraChange]);
|
|
41656
|
+
return null;
|
|
41657
|
+
}
|
|
41658
|
+
var DEFAULT_GRID_CONFIG, GameCanvas3D;
|
|
41659
|
+
var init_GameCanvas3D2 = __esm({
|
|
41660
|
+
"components/game/molecules/GameCanvas3D.tsx"() {
|
|
41661
|
+
"use client";
|
|
41662
|
+
init_AssetLoader();
|
|
41663
|
+
init_useAssetLoader();
|
|
41664
|
+
init_useGameCanvas3DEvents();
|
|
41665
|
+
init_Canvas3DLoadingState2();
|
|
41666
|
+
init_Canvas3DErrorBoundary2();
|
|
41667
|
+
init_ModelLoader();
|
|
41668
|
+
init_cn();
|
|
41669
|
+
init_GameCanvas3D();
|
|
41670
|
+
DEFAULT_GRID_CONFIG = {
|
|
41671
|
+
cellSize: 1,
|
|
41672
|
+
offsetX: 0,
|
|
41673
|
+
offsetZ: 0
|
|
41674
|
+
};
|
|
41675
|
+
GameCanvas3D = forwardRef(
|
|
41676
|
+
({
|
|
41677
|
+
tiles = [],
|
|
41678
|
+
units = [],
|
|
41679
|
+
features = [],
|
|
41680
|
+
events: events2 = [],
|
|
41681
|
+
orientation = "standard",
|
|
41682
|
+
cameraMode = "isometric",
|
|
41683
|
+
showGrid = true,
|
|
41684
|
+
showCoordinates = false,
|
|
41685
|
+
showTileInfo = false,
|
|
41686
|
+
overlay = "default",
|
|
41687
|
+
shadows = true,
|
|
41688
|
+
backgroundColor = "#1a1a2e",
|
|
41689
|
+
onTileClick,
|
|
41690
|
+
onUnitClick,
|
|
41691
|
+
onFeatureClick,
|
|
41692
|
+
onCanvasClick,
|
|
41693
|
+
onTileHover,
|
|
41694
|
+
onUnitAnimation,
|
|
41695
|
+
assetLoader: customAssetLoader,
|
|
41696
|
+
tileRenderer: CustomTileRenderer,
|
|
41697
|
+
unitRenderer: CustomUnitRenderer,
|
|
41698
|
+
featureRenderer: CustomFeatureRenderer,
|
|
41699
|
+
className,
|
|
41700
|
+
isLoading: externalLoading,
|
|
41701
|
+
error: externalError,
|
|
41702
|
+
entity,
|
|
41703
|
+
preloadAssets = [],
|
|
41704
|
+
tileClickEvent,
|
|
41705
|
+
unitClickEvent,
|
|
41706
|
+
featureClickEvent,
|
|
41707
|
+
canvasClickEvent,
|
|
41708
|
+
tileHoverEvent,
|
|
41709
|
+
tileLeaveEvent,
|
|
41710
|
+
unitAnimationEvent,
|
|
41711
|
+
cameraChangeEvent,
|
|
41712
|
+
loadingMessage = "Loading 3D Scene...",
|
|
41713
|
+
useInstancing = true,
|
|
41714
|
+
validMoves = [],
|
|
41715
|
+
attackTargets = [],
|
|
41716
|
+
selectedTileIds = [],
|
|
41717
|
+
selectedUnitId = null,
|
|
41718
|
+
children
|
|
41719
|
+
}, ref) => {
|
|
41720
|
+
const containerRef = useRef(null);
|
|
41721
|
+
const controlsRef = useRef(null);
|
|
41722
|
+
const [hoveredTile, setHoveredTile] = useState(null);
|
|
41723
|
+
const [internalError, setInternalError] = useState(null);
|
|
41724
|
+
const { isLoading: assetsLoading, progress, loaded, total } = useAssetLoader({
|
|
41725
|
+
preloadUrls: preloadAssets,
|
|
41726
|
+
loader: customAssetLoader
|
|
41727
|
+
});
|
|
41728
|
+
const eventHandlers = useGameCanvas3DEvents({
|
|
41729
|
+
tileClickEvent,
|
|
41730
|
+
unitClickEvent,
|
|
41731
|
+
featureClickEvent,
|
|
41732
|
+
canvasClickEvent,
|
|
41733
|
+
tileHoverEvent,
|
|
41734
|
+
tileLeaveEvent,
|
|
41735
|
+
unitAnimationEvent,
|
|
41736
|
+
cameraChangeEvent,
|
|
41737
|
+
onTileClick,
|
|
41738
|
+
onUnitClick,
|
|
41739
|
+
onFeatureClick,
|
|
41740
|
+
onCanvasClick,
|
|
41741
|
+
onTileHover,
|
|
41742
|
+
onUnitAnimation
|
|
41743
|
+
});
|
|
41744
|
+
const gridBounds = useMemo(() => {
|
|
41745
|
+
if (tiles.length === 0) {
|
|
41746
|
+
return { minX: 0, maxX: 10, minZ: 0, maxZ: 10 };
|
|
41747
|
+
}
|
|
41748
|
+
const xs = tiles.map((t) => t.x);
|
|
41749
|
+
const zs = tiles.map((t) => t.z || t.y || 0);
|
|
41750
|
+
return {
|
|
41751
|
+
minX: Math.min(...xs),
|
|
41752
|
+
maxX: Math.max(...xs),
|
|
41753
|
+
minZ: Math.min(...zs),
|
|
41754
|
+
maxZ: Math.max(...zs)
|
|
41755
|
+
};
|
|
41756
|
+
}, [tiles]);
|
|
41757
|
+
const cameraTarget = useMemo(() => {
|
|
41758
|
+
return [
|
|
41759
|
+
(gridBounds.minX + gridBounds.maxX) / 2,
|
|
41760
|
+
0,
|
|
41761
|
+
(gridBounds.minZ + gridBounds.maxZ) / 2
|
|
41762
|
+
];
|
|
41763
|
+
}, [gridBounds]);
|
|
41764
|
+
const gridConfig = useMemo(
|
|
41765
|
+
() => ({
|
|
41766
|
+
...DEFAULT_GRID_CONFIG,
|
|
41767
|
+
offsetX: -(gridBounds.maxX - gridBounds.minX) / 2,
|
|
41768
|
+
offsetZ: -(gridBounds.maxZ - gridBounds.minZ) / 2
|
|
41769
|
+
}),
|
|
41770
|
+
[gridBounds]
|
|
41771
|
+
);
|
|
41772
|
+
const gridToWorld = useCallback(
|
|
41773
|
+
(x, z, y = 0) => {
|
|
41774
|
+
const worldX = (x - gridBounds.minX) * gridConfig.cellSize;
|
|
41775
|
+
const worldZ = (z - gridBounds.minZ) * gridConfig.cellSize;
|
|
41776
|
+
return [worldX, y * gridConfig.cellSize, worldZ];
|
|
41777
|
+
},
|
|
41778
|
+
[gridBounds, gridConfig]
|
|
41779
|
+
);
|
|
41780
|
+
useImperativeHandle(ref, () => ({
|
|
41781
|
+
getCameraPosition: () => {
|
|
41782
|
+
if (controlsRef.current) {
|
|
41783
|
+
const pos = controlsRef.current.object.position;
|
|
41784
|
+
return new THREE.Vector3(pos.x, pos.y, pos.z);
|
|
41785
|
+
}
|
|
41786
|
+
return null;
|
|
41787
|
+
},
|
|
41788
|
+
setCameraPosition: (x, y, z) => {
|
|
41789
|
+
if (controlsRef.current) {
|
|
41790
|
+
controlsRef.current.object.position.set(x, y, z);
|
|
41791
|
+
controlsRef.current.update();
|
|
41792
|
+
}
|
|
41793
|
+
},
|
|
41794
|
+
lookAt: (x, y, z) => {
|
|
41795
|
+
if (controlsRef.current) {
|
|
41796
|
+
controlsRef.current.target.set(x, y, z);
|
|
41797
|
+
controlsRef.current.update();
|
|
41798
|
+
}
|
|
41799
|
+
},
|
|
41800
|
+
resetCamera: () => {
|
|
41801
|
+
if (controlsRef.current) {
|
|
41802
|
+
controlsRef.current.reset();
|
|
41803
|
+
}
|
|
41804
|
+
},
|
|
41805
|
+
screenshot: () => {
|
|
41806
|
+
const canvas = containerRef.current?.querySelector("canvas");
|
|
41807
|
+
if (canvas) {
|
|
41808
|
+
return canvas.toDataURL("image/png");
|
|
41809
|
+
}
|
|
41810
|
+
return null;
|
|
41811
|
+
},
|
|
41812
|
+
export: () => ({
|
|
41813
|
+
tiles,
|
|
41814
|
+
units,
|
|
41815
|
+
features
|
|
41816
|
+
})
|
|
41817
|
+
}));
|
|
41818
|
+
const handleTileClick = useCallback(
|
|
41819
|
+
(tile, event) => {
|
|
41820
|
+
eventHandlers.handleTileClick(tile, event);
|
|
41821
|
+
},
|
|
41822
|
+
[eventHandlers]
|
|
41823
|
+
);
|
|
41824
|
+
const handleUnitClick = useCallback(
|
|
41825
|
+
(unit, event) => {
|
|
41826
|
+
eventHandlers.handleUnitClick(unit, event);
|
|
41827
|
+
},
|
|
41828
|
+
[eventHandlers]
|
|
41829
|
+
);
|
|
41830
|
+
const handleFeatureClick = useCallback(
|
|
41831
|
+
(feature, event) => {
|
|
41832
|
+
if (event) {
|
|
41833
|
+
eventHandlers.handleFeatureClick(feature, event);
|
|
41834
|
+
}
|
|
41835
|
+
},
|
|
41836
|
+
[eventHandlers]
|
|
41837
|
+
);
|
|
41838
|
+
const handleTileHover = useCallback(
|
|
41839
|
+
(tile, event) => {
|
|
41840
|
+
setHoveredTile(tile);
|
|
41841
|
+
if (event) {
|
|
41842
|
+
eventHandlers.handleTileHover(tile, event);
|
|
41843
|
+
}
|
|
41844
|
+
},
|
|
41845
|
+
[eventHandlers]
|
|
41846
|
+
);
|
|
41847
|
+
const cameraConfig = useMemo(() => {
|
|
41848
|
+
const size = Math.max(
|
|
41849
|
+
gridBounds.maxX - gridBounds.minX,
|
|
41850
|
+
gridBounds.maxZ - gridBounds.minZ
|
|
41851
|
+
);
|
|
41852
|
+
const distance = size * 1.5;
|
|
41853
|
+
switch (cameraMode) {
|
|
41854
|
+
case "isometric":
|
|
41855
|
+
return {
|
|
41856
|
+
position: [distance, distance * 0.8, distance],
|
|
41857
|
+
fov: 45
|
|
41858
|
+
};
|
|
41859
|
+
case "top-down":
|
|
41860
|
+
return {
|
|
41861
|
+
position: [0, distance * 2, 0],
|
|
41862
|
+
fov: 45
|
|
41863
|
+
};
|
|
41864
|
+
case "perspective":
|
|
41865
|
+
default:
|
|
41866
|
+
return {
|
|
41867
|
+
position: [distance, distance, distance],
|
|
41868
|
+
fov: 45
|
|
41869
|
+
};
|
|
41870
|
+
}
|
|
41871
|
+
}, [cameraMode, gridBounds]);
|
|
41872
|
+
const DefaultTileRenderer = useCallback(
|
|
41873
|
+
({ tile, position }) => {
|
|
41874
|
+
const isSelected = tile.id ? selectedTileIds.includes(tile.id) : false;
|
|
41875
|
+
const isHovered = hoveredTile?.id === tile.id;
|
|
41876
|
+
const isValidMove = validMoves.some(
|
|
41877
|
+
(m) => m.x === tile.x && m.z === (tile.z ?? tile.y ?? 0)
|
|
41878
|
+
);
|
|
41879
|
+
const isAttackTarget = attackTargets.some(
|
|
41880
|
+
(m) => m.x === tile.x && m.z === (tile.z ?? tile.y ?? 0)
|
|
41881
|
+
);
|
|
41882
|
+
let color = 8421504;
|
|
41883
|
+
if (tile.type === "water") color = 4491468;
|
|
41884
|
+
else if (tile.type === "grass") color = 4500036;
|
|
41885
|
+
else if (tile.type === "sand") color = 14535816;
|
|
41886
|
+
else if (tile.type === "rock") color = 8947848;
|
|
41887
|
+
else if (tile.type === "snow") color = 15658734;
|
|
41888
|
+
let emissive = 0;
|
|
41889
|
+
if (isSelected) emissive = 4473924;
|
|
41890
|
+
else if (isAttackTarget) emissive = 4456448;
|
|
41891
|
+
else if (isValidMove) emissive = 17408;
|
|
41892
|
+
else if (isHovered) emissive = 2236962;
|
|
41893
|
+
if (tile.modelUrl) {
|
|
41894
|
+
return /* @__PURE__ */ jsx(
|
|
41895
|
+
"group",
|
|
41896
|
+
{
|
|
41897
|
+
position,
|
|
41898
|
+
onClick: (e) => handleTileClick(tile, e),
|
|
41899
|
+
onPointerEnter: (e) => handleTileHover(tile, e),
|
|
41900
|
+
onPointerLeave: (e) => handleTileHover(null, e),
|
|
41901
|
+
userData: { type: "tile", tileId: tile.id, gridX: tile.x, gridZ: tile.z ?? tile.y },
|
|
41902
|
+
children: /* @__PURE__ */ jsx(
|
|
41903
|
+
ModelLoader,
|
|
41904
|
+
{
|
|
41905
|
+
url: tile.modelUrl,
|
|
41906
|
+
scale: 0.95,
|
|
41907
|
+
fallbackGeometry: "box",
|
|
41908
|
+
castShadow: true,
|
|
41909
|
+
receiveShadow: true
|
|
41910
|
+
}
|
|
41911
|
+
)
|
|
41912
|
+
}
|
|
41913
|
+
);
|
|
41914
|
+
}
|
|
41915
|
+
return /* @__PURE__ */ jsxs(
|
|
41916
|
+
"mesh",
|
|
41917
|
+
{
|
|
41918
|
+
position,
|
|
41919
|
+
onClick: (e) => handleTileClick(tile, e),
|
|
41920
|
+
onPointerEnter: (e) => handleTileHover(tile, e),
|
|
41921
|
+
onPointerLeave: (e) => handleTileHover(null, e),
|
|
41922
|
+
userData: { type: "tile", tileId: tile.id, gridX: tile.x, gridZ: tile.z ?? tile.y },
|
|
41923
|
+
children: [
|
|
41924
|
+
/* @__PURE__ */ jsx("boxGeometry", { args: [0.95, 0.2, 0.95] }),
|
|
41925
|
+
/* @__PURE__ */ jsx("meshStandardMaterial", { color, emissive })
|
|
41926
|
+
]
|
|
41927
|
+
}
|
|
41928
|
+
);
|
|
41929
|
+
},
|
|
41930
|
+
[selectedTileIds, hoveredTile, validMoves, attackTargets, handleTileClick, handleTileHover]
|
|
41931
|
+
);
|
|
41932
|
+
const DefaultUnitRenderer = useCallback(
|
|
41933
|
+
({ unit, position }) => {
|
|
41934
|
+
const isSelected = selectedUnitId === unit.id;
|
|
41935
|
+
const color = unit.faction === "player" ? 4491519 : unit.faction === "enemy" ? 16729156 : 16777028;
|
|
41936
|
+
return /* @__PURE__ */ jsxs(
|
|
41937
|
+
"group",
|
|
41938
|
+
{
|
|
41939
|
+
position,
|
|
41940
|
+
onClick: (e) => handleUnitClick(unit, e),
|
|
41941
|
+
userData: { type: "unit", unitId: unit.id },
|
|
41942
|
+
children: [
|
|
41943
|
+
isSelected && /* @__PURE__ */ jsxs("mesh", { position: [0, 0.05, 0], rotation: [-Math.PI / 2, 0, 0], children: [
|
|
41944
|
+
/* @__PURE__ */ jsx("ringGeometry", { args: [0.4, 0.5, 32] }),
|
|
41945
|
+
/* @__PURE__ */ jsx("meshBasicMaterial", { color: "#ffff00", transparent: true, opacity: 0.8 })
|
|
41946
|
+
] }),
|
|
41947
|
+
unit.modelUrl ? (
|
|
41948
|
+
/* GLB unit model (box fallback while loading / on error) */
|
|
41949
|
+
/* @__PURE__ */ jsx(
|
|
41950
|
+
ModelLoader,
|
|
41951
|
+
{
|
|
41952
|
+
url: unit.modelUrl,
|
|
41953
|
+
scale: 0.5,
|
|
41954
|
+
fallbackGeometry: "box",
|
|
41955
|
+
castShadow: true
|
|
41956
|
+
}
|
|
41957
|
+
)
|
|
41958
|
+
) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
41959
|
+
/* @__PURE__ */ jsxs("mesh", { position: [0, 0.3, 0], children: [
|
|
41960
|
+
/* @__PURE__ */ jsx("cylinderGeometry", { args: [0.3, 0.3, 0.1, 8] }),
|
|
41961
|
+
/* @__PURE__ */ jsx("meshStandardMaterial", { color })
|
|
41962
|
+
] }),
|
|
41963
|
+
/* @__PURE__ */ jsxs("mesh", { position: [0, 0.6, 0], children: [
|
|
41964
|
+
/* @__PURE__ */ jsx("capsuleGeometry", { args: [0.2, 0.4, 4, 8] }),
|
|
41965
|
+
/* @__PURE__ */ jsx("meshStandardMaterial", { color })
|
|
41966
|
+
] }),
|
|
41967
|
+
/* @__PURE__ */ jsxs("mesh", { position: [0, 0.9, 0], children: [
|
|
41968
|
+
/* @__PURE__ */ jsx("sphereGeometry", { args: [0.12, 8, 8] }),
|
|
41969
|
+
/* @__PURE__ */ jsx("meshStandardMaterial", { color })
|
|
41970
|
+
] })
|
|
41971
|
+
] }),
|
|
41972
|
+
unit.health !== void 0 && unit.maxHealth !== void 0 && /* @__PURE__ */ jsxs("group", { position: [0, 1.2, 0], children: [
|
|
41973
|
+
/* @__PURE__ */ jsxs("mesh", { position: [-0.25, 0, 0], children: [
|
|
41974
|
+
/* @__PURE__ */ jsx("planeGeometry", { args: [0.5, 0.05] }),
|
|
41975
|
+
/* @__PURE__ */ jsx("meshBasicMaterial", { color: 3355443 })
|
|
41976
|
+
] }),
|
|
41977
|
+
/* @__PURE__ */ jsxs(
|
|
41978
|
+
"mesh",
|
|
41979
|
+
{
|
|
41980
|
+
position: [
|
|
41981
|
+
-0.25 + 0.5 * (unit.health / unit.maxHealth) / 2,
|
|
41982
|
+
0,
|
|
41983
|
+
0.01
|
|
41984
|
+
],
|
|
41985
|
+
children: [
|
|
41986
|
+
/* @__PURE__ */ jsx("planeGeometry", { args: [0.5 * (unit.health / unit.maxHealth), 0.05] }),
|
|
41987
|
+
/* @__PURE__ */ jsx(
|
|
41988
|
+
"meshBasicMaterial",
|
|
41989
|
+
{
|
|
41990
|
+
color: unit.health / unit.maxHealth > 0.5 ? 4500036 : unit.health / unit.maxHealth > 0.25 ? 11184708 : 16729156
|
|
41991
|
+
}
|
|
41992
|
+
)
|
|
41993
|
+
]
|
|
41994
|
+
}
|
|
41995
|
+
)
|
|
41996
|
+
] })
|
|
41997
|
+
]
|
|
41998
|
+
}
|
|
41999
|
+
);
|
|
42000
|
+
},
|
|
42001
|
+
[selectedUnitId, handleUnitClick]
|
|
42002
|
+
);
|
|
42003
|
+
const DefaultFeatureRenderer = useCallback(
|
|
42004
|
+
({
|
|
42005
|
+
feature,
|
|
42006
|
+
position
|
|
42007
|
+
}) => {
|
|
42008
|
+
if (feature.assetUrl) {
|
|
42009
|
+
return /* @__PURE__ */ jsx(
|
|
42010
|
+
ModelLoader,
|
|
42011
|
+
{
|
|
42012
|
+
url: feature.assetUrl,
|
|
42013
|
+
position,
|
|
42014
|
+
scale: 0.5,
|
|
42015
|
+
rotation: [0, feature.rotation ?? 0, 0],
|
|
42016
|
+
onClick: () => handleFeatureClick(feature, null),
|
|
42017
|
+
fallbackGeometry: "box"
|
|
42018
|
+
},
|
|
42019
|
+
feature.id
|
|
42020
|
+
);
|
|
42021
|
+
}
|
|
42022
|
+
if (feature.type === "tree") {
|
|
42023
|
+
return /* @__PURE__ */ jsxs(
|
|
42024
|
+
"group",
|
|
42025
|
+
{
|
|
42026
|
+
position,
|
|
42027
|
+
onClick: (e) => handleFeatureClick(feature, e),
|
|
42028
|
+
userData: { type: "feature", featureId: feature.id },
|
|
42029
|
+
children: [
|
|
42030
|
+
/* @__PURE__ */ jsxs("mesh", { position: [0, 0.4, 0], children: [
|
|
42031
|
+
/* @__PURE__ */ jsx("cylinderGeometry", { args: [0.1, 0.15, 0.8, 6] }),
|
|
42032
|
+
/* @__PURE__ */ jsx("meshStandardMaterial", { color: 9127187 })
|
|
42033
|
+
] }),
|
|
42034
|
+
/* @__PURE__ */ jsxs("mesh", { position: [0, 0.9, 0], children: [
|
|
42035
|
+
/* @__PURE__ */ jsx("coneGeometry", { args: [0.5, 0.8, 8] }),
|
|
42036
|
+
/* @__PURE__ */ jsx("meshStandardMaterial", { color: 2263842 })
|
|
42037
|
+
] })
|
|
42038
|
+
]
|
|
42039
|
+
}
|
|
42040
|
+
);
|
|
42041
|
+
}
|
|
42042
|
+
if (feature.type === "rock") {
|
|
42043
|
+
return /* @__PURE__ */ jsxs(
|
|
42044
|
+
"mesh",
|
|
42045
|
+
{
|
|
42046
|
+
position: [position[0], position[1] + 0.3, position[2]],
|
|
42047
|
+
onClick: (e) => handleFeatureClick(feature, e),
|
|
42048
|
+
userData: { type: "feature", featureId: feature.id },
|
|
42049
|
+
children: [
|
|
42050
|
+
/* @__PURE__ */ jsx("dodecahedronGeometry", { args: [0.3, 0] }),
|
|
42051
|
+
/* @__PURE__ */ jsx("meshStandardMaterial", { color: 8421504 })
|
|
42052
|
+
]
|
|
42053
|
+
}
|
|
42054
|
+
);
|
|
42055
|
+
}
|
|
42056
|
+
return null;
|
|
42057
|
+
},
|
|
42058
|
+
[handleFeatureClick]
|
|
42059
|
+
);
|
|
42060
|
+
if (externalLoading || assetsLoading && preloadAssets.length > 0) {
|
|
42061
|
+
return /* @__PURE__ */ jsx(
|
|
42062
|
+
Canvas3DLoadingState,
|
|
42063
|
+
{
|
|
42064
|
+
progress,
|
|
42065
|
+
loaded,
|
|
42066
|
+
total,
|
|
42067
|
+
message: loadingMessage,
|
|
42068
|
+
className
|
|
42069
|
+
}
|
|
42070
|
+
);
|
|
42071
|
+
}
|
|
42072
|
+
const displayError = externalError || internalError;
|
|
42073
|
+
if (displayError) {
|
|
42074
|
+
return /* @__PURE__ */ jsx(Canvas3DErrorBoundary, { children: /* @__PURE__ */ jsx("div", { className: "game-canvas-3d game-canvas-3d--error", children: /* @__PURE__ */ jsxs("div", { className: "game-canvas-3d__error", children: [
|
|
42075
|
+
"Error: ",
|
|
42076
|
+
displayError
|
|
42077
|
+
] }) }) });
|
|
42078
|
+
}
|
|
42079
|
+
return /* @__PURE__ */ jsx(
|
|
42080
|
+
Canvas3DErrorBoundary,
|
|
42081
|
+
{
|
|
42082
|
+
onError: (err) => setInternalError(err.message),
|
|
42083
|
+
onReset: () => setInternalError(null),
|
|
42084
|
+
children: /* @__PURE__ */ jsxs(
|
|
42085
|
+
"div",
|
|
42086
|
+
{
|
|
42087
|
+
ref: containerRef,
|
|
42088
|
+
className: cn("game-canvas-3d relative w-full h-full min-h-[85vh] overflow-hidden", className),
|
|
42089
|
+
"data-orientation": orientation,
|
|
42090
|
+
"data-camera-mode": cameraMode,
|
|
42091
|
+
"data-overlay": overlay,
|
|
42092
|
+
children: [
|
|
42093
|
+
/* @__PURE__ */ jsxs(
|
|
42094
|
+
Canvas,
|
|
42095
|
+
{
|
|
42096
|
+
shadows,
|
|
42097
|
+
camera: {
|
|
42098
|
+
position: cameraConfig.position,
|
|
42099
|
+
fov: cameraConfig.fov,
|
|
42100
|
+
near: 0.1,
|
|
42101
|
+
far: 1e3
|
|
42102
|
+
},
|
|
42103
|
+
style: { background: backgroundColor },
|
|
42104
|
+
onClick: (e) => {
|
|
42105
|
+
if (e.target === e.currentTarget) {
|
|
42106
|
+
eventHandlers.handleCanvasClick(e);
|
|
42107
|
+
}
|
|
42108
|
+
},
|
|
42109
|
+
children: [
|
|
42110
|
+
/* @__PURE__ */ jsx(CameraController, { onCameraChange: eventHandlers.handleCameraChange }),
|
|
42111
|
+
/* @__PURE__ */ jsx("ambientLight", { intensity: 0.6 }),
|
|
42112
|
+
/* @__PURE__ */ jsx(
|
|
42113
|
+
"directionalLight",
|
|
42114
|
+
{
|
|
42115
|
+
position: [10, 20, 10],
|
|
42116
|
+
intensity: 0.8,
|
|
42117
|
+
castShadow: shadows,
|
|
42118
|
+
"shadow-mapSize": [2048, 2048]
|
|
42119
|
+
}
|
|
42120
|
+
),
|
|
42121
|
+
/* @__PURE__ */ jsx("hemisphereLight", { intensity: 0.3, color: "#87ceeb", groundColor: "#362d1d" }),
|
|
42122
|
+
showGrid && /* @__PURE__ */ jsx(
|
|
42123
|
+
Grid$1,
|
|
42124
|
+
{
|
|
42125
|
+
args: [
|
|
42126
|
+
Math.max(gridBounds.maxX - gridBounds.minX + 2, 10),
|
|
42127
|
+
Math.max(gridBounds.maxZ - gridBounds.minZ + 2, 10)
|
|
42128
|
+
],
|
|
42129
|
+
position: [
|
|
42130
|
+
(gridBounds.maxX - gridBounds.minX) / 2 - 0.5,
|
|
42131
|
+
0,
|
|
42132
|
+
(gridBounds.maxZ - gridBounds.minZ) / 2 - 0.5
|
|
42133
|
+
],
|
|
42134
|
+
cellSize: 1,
|
|
42135
|
+
cellThickness: 1,
|
|
42136
|
+
cellColor: "#444444",
|
|
42137
|
+
sectionSize: 5,
|
|
42138
|
+
sectionThickness: 1.5,
|
|
42139
|
+
sectionColor: "#666666",
|
|
42140
|
+
fadeDistance: 50,
|
|
42141
|
+
fadeStrength: 1
|
|
42142
|
+
}
|
|
42143
|
+
),
|
|
42144
|
+
tiles.map((tile, index) => {
|
|
42145
|
+
const position = gridToWorld(
|
|
42146
|
+
tile.x,
|
|
42147
|
+
tile.z ?? tile.y ?? 0,
|
|
42148
|
+
tile.elevation ?? 0
|
|
42149
|
+
);
|
|
42150
|
+
const Renderer = CustomTileRenderer || DefaultTileRenderer;
|
|
42151
|
+
return /* @__PURE__ */ jsx(Renderer, { tile, position }, tile.id ?? `tile-${index}`);
|
|
42152
|
+
}),
|
|
42153
|
+
features.map((feature, index) => {
|
|
42154
|
+
const position = gridToWorld(
|
|
42155
|
+
feature.x,
|
|
42156
|
+
feature.z ?? feature.y ?? 0,
|
|
42157
|
+
(feature.elevation ?? 0) + 0.5
|
|
42158
|
+
);
|
|
42159
|
+
const Renderer = CustomFeatureRenderer || DefaultFeatureRenderer;
|
|
42160
|
+
return /* @__PURE__ */ jsx(Renderer, { feature, position }, feature.id ?? `feature-${index}`);
|
|
42161
|
+
}),
|
|
42162
|
+
units.map((unit) => {
|
|
42163
|
+
const position = gridToWorld(
|
|
42164
|
+
unit.x ?? 0,
|
|
42165
|
+
unit.z ?? unit.y ?? 0,
|
|
42166
|
+
(unit.elevation ?? 0) + 0.5
|
|
42167
|
+
);
|
|
42168
|
+
const Renderer = CustomUnitRenderer || DefaultUnitRenderer;
|
|
42169
|
+
return /* @__PURE__ */ jsx(Renderer, { unit, position }, unit.id);
|
|
42170
|
+
}),
|
|
42171
|
+
children,
|
|
42172
|
+
/* @__PURE__ */ jsx(
|
|
42173
|
+
OrbitControls,
|
|
42174
|
+
{
|
|
42175
|
+
ref: controlsRef,
|
|
42176
|
+
target: cameraTarget,
|
|
42177
|
+
enableDamping: true,
|
|
42178
|
+
dampingFactor: 0.05,
|
|
42179
|
+
minDistance: 2,
|
|
42180
|
+
maxDistance: 100,
|
|
42181
|
+
maxPolarAngle: Math.PI / 2 - 0.1
|
|
42182
|
+
}
|
|
42183
|
+
)
|
|
42184
|
+
]
|
|
42185
|
+
}
|
|
42186
|
+
),
|
|
42187
|
+
showCoordinates && hoveredTile && /* @__PURE__ */ jsxs("div", { className: "game-canvas-3d__coordinates", children: [
|
|
42188
|
+
"X: ",
|
|
42189
|
+
hoveredTile.x,
|
|
42190
|
+
", Z: ",
|
|
42191
|
+
hoveredTile.z ?? hoveredTile.y ?? 0
|
|
42192
|
+
] }),
|
|
42193
|
+
showTileInfo && hoveredTile && /* @__PURE__ */ jsxs("div", { className: "game-canvas-3d__tile-info", children: [
|
|
42194
|
+
/* @__PURE__ */ jsx("div", { className: "tile-info__type", children: hoveredTile.type }),
|
|
42195
|
+
hoveredTile.terrain && /* @__PURE__ */ jsx("div", { className: "tile-info__terrain", children: hoveredTile.terrain })
|
|
42196
|
+
] })
|
|
42197
|
+
]
|
|
42198
|
+
}
|
|
42199
|
+
)
|
|
42200
|
+
}
|
|
42201
|
+
);
|
|
42202
|
+
}
|
|
42203
|
+
);
|
|
42204
|
+
GameCanvas3D.displayName = "GameCanvas3D";
|
|
42205
|
+
}
|
|
42206
|
+
});
|
|
42207
|
+
function GameBoard3D({
|
|
42208
|
+
entity,
|
|
42209
|
+
tiles = [],
|
|
42210
|
+
features = [],
|
|
42211
|
+
cameraMode = "perspective",
|
|
42212
|
+
backgroundColor = "#2a1a1a",
|
|
42213
|
+
tileClickEvent,
|
|
42214
|
+
unitClickEvent,
|
|
42215
|
+
attackEvent,
|
|
42216
|
+
endTurnEvent,
|
|
42217
|
+
cancelEvent,
|
|
42218
|
+
playAgainEvent,
|
|
42219
|
+
gameEndEvent,
|
|
42220
|
+
className
|
|
42221
|
+
}) {
|
|
42222
|
+
const row = boardEntity(entity);
|
|
42223
|
+
const eventBus = useEventBus();
|
|
42224
|
+
const entityUnits = row ? rows(row.units) : [];
|
|
42225
|
+
const units = entityUnits;
|
|
42226
|
+
const selectedUnitId = row ? str(row.selectedUnitId) || null : null;
|
|
42227
|
+
const phase = row ? str(row.phase) : "observation";
|
|
42228
|
+
const result = row ? str(row.result) : "none";
|
|
42229
|
+
const validMoves = row && Array.isArray(row.validMoves) ? row.validMoves : [];
|
|
42230
|
+
const attackTargets = row && Array.isArray(row.attackTargets) ? row.attackTargets : [];
|
|
42231
|
+
const turn = row ? num(row.turn) : 0;
|
|
42232
|
+
const currentTeam = row ? str(row.currentTeam) : "player";
|
|
42233
|
+
const isGameOver = result !== "none";
|
|
42234
|
+
const gameEndEmittedRef = useRef(false);
|
|
42235
|
+
useEffect(() => {
|
|
42236
|
+
if ((result === "victory" || result === "defeat") && gameEndEvent) {
|
|
42237
|
+
if (!gameEndEmittedRef.current) {
|
|
42238
|
+
gameEndEmittedRef.current = true;
|
|
42239
|
+
eventBus.emit(`UI:${gameEndEvent}`, { result });
|
|
42240
|
+
}
|
|
42241
|
+
} else {
|
|
42242
|
+
gameEndEmittedRef.current = false;
|
|
42243
|
+
}
|
|
42244
|
+
}, [result, gameEndEvent, eventBus]);
|
|
42245
|
+
const checkGameEnd = useCallback(() => {
|
|
42246
|
+
const alivePlayer = entityUnits.filter((u) => unitTeam(u) === "player" && unitHealth(u) > 0);
|
|
42247
|
+
const aliveEnemy = entityUnits.filter((u) => unitTeam(u) === "enemy" && unitHealth(u) > 0);
|
|
42248
|
+
if (alivePlayer.length === 0 && gameEndEvent) {
|
|
42249
|
+
eventBus.emit(`UI:${gameEndEvent}`, { result: "defeat" });
|
|
42250
|
+
} else if (aliveEnemy.length === 0 && gameEndEvent) {
|
|
42251
|
+
eventBus.emit(`UI:${gameEndEvent}`, { result: "victory" });
|
|
42252
|
+
}
|
|
42253
|
+
}, [entityUnits, gameEndEvent, eventBus]);
|
|
42254
|
+
const handleUnitClickCallback = useCallback((isoUnit) => {
|
|
42255
|
+
if (phase !== "action" || !selectedUnitId || !attackEvent) return;
|
|
42256
|
+
const attackerRow = entityUnits.find((u) => str(u.id) === selectedUnitId);
|
|
42257
|
+
const targetRow = entityUnits.find((u) => str(u.id) === isoUnit.id);
|
|
42258
|
+
if (!attackerRow || !targetRow) return;
|
|
42259
|
+
if (unitTeam(targetRow) !== "enemy" || unitHealth(targetRow) <= 0) return;
|
|
42260
|
+
const ap = unitPosition(attackerRow);
|
|
42261
|
+
const tp = unitPosition(targetRow);
|
|
42262
|
+
const dx = Math.abs(ap.x - tp.x);
|
|
42263
|
+
const dy = Math.abs(ap.y - tp.y);
|
|
42264
|
+
if (dx <= 1 && dy <= 1 && dx + dy > 0) {
|
|
42265
|
+
const damage = Math.max(1, num(attackerRow.attack) - num(targetRow.defense));
|
|
42266
|
+
eventBus.emit(`UI:${attackEvent}`, {
|
|
42267
|
+
attackerId: str(attackerRow.id),
|
|
42268
|
+
targetId: str(targetRow.id),
|
|
42269
|
+
damage
|
|
42270
|
+
});
|
|
42271
|
+
setTimeout(checkGameEnd, 100);
|
|
42272
|
+
}
|
|
42273
|
+
}, [phase, selectedUnitId, entityUnits, attackEvent, eventBus, checkGameEnd]);
|
|
42274
|
+
const handleEndTurn = useCallback(() => {
|
|
42275
|
+
if (endTurnEvent) eventBus.emit(`UI:${endTurnEvent}`, {});
|
|
42276
|
+
}, [endTurnEvent, eventBus]);
|
|
42277
|
+
const handleCancel = useCallback(() => {
|
|
42278
|
+
if (cancelEvent) eventBus.emit(`UI:${cancelEvent}`, {});
|
|
42279
|
+
}, [cancelEvent, eventBus]);
|
|
42280
|
+
const handlePlayAgain = useCallback(() => {
|
|
42281
|
+
if (playAgainEvent) eventBus.emit(`UI:${playAgainEvent}`, {});
|
|
42282
|
+
}, [playAgainEvent, eventBus]);
|
|
42283
|
+
return /* @__PURE__ */ jsxs(VStack, { className: cn("game-board-3d block w-full min-h-[85vh] relative", className), children: [
|
|
42284
|
+
/* @__PURE__ */ jsxs("div", { className: "game-board-3d__status absolute top-3 left-3 z-10 flex gap-2 items-center", children: [
|
|
42285
|
+
/* @__PURE__ */ jsx(Typography, { variant: "small", className: "status__phase capitalize", children: phase.replace("_", " ") }),
|
|
42286
|
+
currentTeam && !isGameOver && /* @__PURE__ */ jsxs(Typography, { variant: "small", color: "muted", className: "status__team", children: [
|
|
42287
|
+
"\u2014 ",
|
|
42288
|
+
currentTeam === "player" ? "Your Turn" : "Enemy's Turn"
|
|
42289
|
+
] }),
|
|
42290
|
+
/* @__PURE__ */ jsxs(Typography, { variant: "small", color: "muted", className: "status__turn", children: [
|
|
42291
|
+
"Turn ",
|
|
42292
|
+
turn
|
|
42293
|
+
] })
|
|
42294
|
+
] }),
|
|
42295
|
+
/* @__PURE__ */ jsx(
|
|
42296
|
+
GameCanvas3D,
|
|
42297
|
+
{
|
|
42298
|
+
tiles,
|
|
42299
|
+
units,
|
|
42300
|
+
features,
|
|
42301
|
+
cameraMode,
|
|
42302
|
+
showGrid: true,
|
|
42303
|
+
showCoordinates: false,
|
|
42304
|
+
showTileInfo: false,
|
|
42305
|
+
shadows: true,
|
|
42306
|
+
backgroundColor,
|
|
42307
|
+
tileClickEvent,
|
|
42308
|
+
unitClickEvent,
|
|
42309
|
+
onUnitClick: handleUnitClickCallback,
|
|
42310
|
+
selectedUnitId,
|
|
42311
|
+
validMoves,
|
|
42312
|
+
attackTargets,
|
|
42313
|
+
className: "game-board-3d__canvas w-full min-h-[85vh]"
|
|
42314
|
+
}
|
|
42315
|
+
),
|
|
42316
|
+
!isGameOver && /* @__PURE__ */ jsxs(HStack, { className: "fixed bottom-6 right-6 z-50", gap: "sm", children: [
|
|
42317
|
+
(phase === "selection" || phase === "movement" || phase === "action") && /* @__PURE__ */ jsx(
|
|
42318
|
+
Button,
|
|
42319
|
+
{
|
|
42320
|
+
variant: "secondary",
|
|
42321
|
+
className: "shadow-xl",
|
|
42322
|
+
onClick: handleCancel,
|
|
42323
|
+
children: "Cancel"
|
|
42324
|
+
}
|
|
42325
|
+
),
|
|
42326
|
+
phase !== "enemy_turn" && /* @__PURE__ */ jsx(
|
|
42327
|
+
Button,
|
|
42328
|
+
{
|
|
42329
|
+
variant: "primary",
|
|
42330
|
+
className: "shadow-xl",
|
|
42331
|
+
onClick: handleEndTurn,
|
|
42332
|
+
children: "End Turn"
|
|
42333
|
+
}
|
|
42334
|
+
)
|
|
42335
|
+
] }),
|
|
42336
|
+
isGameOver && /* @__PURE__ */ jsx("div", { className: "game-board-3d__overlay absolute inset-0 z-20 flex items-center justify-center bg-black/60", children: /* @__PURE__ */ jsxs(VStack, { align: "center", gap: "md", className: "overlay__card p-8 rounded-xl bg-gray-900/90 shadow-2xl", children: [
|
|
42337
|
+
/* @__PURE__ */ jsx(
|
|
42338
|
+
Typography,
|
|
42339
|
+
{
|
|
42340
|
+
variant: "h2",
|
|
42341
|
+
className: cn(
|
|
42342
|
+
"overlay__result",
|
|
42343
|
+
result === "victory" ? "text-yellow-400" : "text-red-500"
|
|
42344
|
+
),
|
|
42345
|
+
children: result === "victory" ? "Victory!" : "Defeat"
|
|
42346
|
+
}
|
|
42347
|
+
),
|
|
42348
|
+
/* @__PURE__ */ jsxs(Typography, { variant: "body", color: "muted", className: "overlay__turn-count", children: [
|
|
42349
|
+
"Completed in ",
|
|
42350
|
+
turn,
|
|
42351
|
+
" turn",
|
|
42352
|
+
turn !== 1 ? "s" : ""
|
|
42353
|
+
] }),
|
|
42354
|
+
/* @__PURE__ */ jsx(
|
|
42355
|
+
Button,
|
|
42356
|
+
{
|
|
42357
|
+
variant: "primary",
|
|
42358
|
+
className: "px-8 py-3 font-semibold",
|
|
42359
|
+
onClick: handlePlayAgain,
|
|
42360
|
+
children: "Play Again"
|
|
42361
|
+
}
|
|
42362
|
+
)
|
|
42363
|
+
] }) })
|
|
42364
|
+
] });
|
|
42365
|
+
}
|
|
42366
|
+
var init_GameBoard3D = __esm({
|
|
42367
|
+
"components/game/organisms/GameBoard3D.tsx"() {
|
|
42368
|
+
"use client";
|
|
42369
|
+
init_cn();
|
|
42370
|
+
init_Button();
|
|
42371
|
+
init_Typography();
|
|
42372
|
+
init_Stack();
|
|
42373
|
+
init_useEventBus();
|
|
42374
|
+
init_GameCanvas3D2();
|
|
42375
|
+
init_boardEntity();
|
|
42376
|
+
GameBoard3D.displayName = "GameBoard3D";
|
|
42377
|
+
}
|
|
42378
|
+
});
|
|
40724
42379
|
var GameShell;
|
|
40725
42380
|
var init_GameShell = __esm({
|
|
40726
42381
|
"components/game/templates/GameShell.tsx"() {
|
|
@@ -42263,6 +43918,236 @@ var init_NegotiatorBoard = __esm({
|
|
|
42263
43918
|
NegotiatorBoard.displayName = "NegotiatorBoard";
|
|
42264
43919
|
}
|
|
42265
43920
|
});
|
|
43921
|
+
function resolveEntity(entity) {
|
|
43922
|
+
if (!entity) return {};
|
|
43923
|
+
if (Array.isArray(entity)) return entity[0] ?? {};
|
|
43924
|
+
return entity;
|
|
43925
|
+
}
|
|
43926
|
+
function numField(row, key, fallback) {
|
|
43927
|
+
const v = row[key];
|
|
43928
|
+
return typeof v === "number" ? v : fallback;
|
|
43929
|
+
}
|
|
43930
|
+
function strField(row, key, fallback) {
|
|
43931
|
+
const v = row[key];
|
|
43932
|
+
return typeof v === "string" ? v : fallback;
|
|
43933
|
+
}
|
|
43934
|
+
function PlatformerBoard({
|
|
43935
|
+
entity,
|
|
43936
|
+
player: propPlayer,
|
|
43937
|
+
platforms: propPlatforms,
|
|
43938
|
+
result: propResult,
|
|
43939
|
+
lives: propLives,
|
|
43940
|
+
score: propScore,
|
|
43941
|
+
level: propLevel,
|
|
43942
|
+
worldWidth = 800,
|
|
43943
|
+
worldHeight = 400,
|
|
43944
|
+
canvasWidth = 800,
|
|
43945
|
+
canvasHeight = 400,
|
|
43946
|
+
playerSprite,
|
|
43947
|
+
tileSprites,
|
|
43948
|
+
bgColor,
|
|
43949
|
+
leftEvent = "LEFT",
|
|
43950
|
+
rightEvent = "RIGHT",
|
|
43951
|
+
jumpEvent = "JUMP",
|
|
43952
|
+
stopEvent = "STOP",
|
|
43953
|
+
playAgainEvent = "PLAY_AGAIN",
|
|
43954
|
+
gameEndEvent = "GAME_END",
|
|
43955
|
+
className
|
|
43956
|
+
}) {
|
|
43957
|
+
const row = resolveEntity(entity);
|
|
43958
|
+
const eventBus = useEventBus();
|
|
43959
|
+
const { t } = useTranslate();
|
|
43960
|
+
const result = propResult ?? strField(row, "result", "none");
|
|
43961
|
+
propLives ?? numField(row, "lives", 3);
|
|
43962
|
+
const score = propScore ?? numField(row, "score", 0);
|
|
43963
|
+
const level = propLevel ?? numField(row, "level", 1);
|
|
43964
|
+
const entityPlayer = row["player"];
|
|
43965
|
+
const player = propPlayer ?? entityPlayer ?? {
|
|
43966
|
+
x: 80,
|
|
43967
|
+
y: 320,
|
|
43968
|
+
width: 32,
|
|
43969
|
+
height: 48,
|
|
43970
|
+
vx: 0,
|
|
43971
|
+
vy: 0,
|
|
43972
|
+
grounded: false,
|
|
43973
|
+
facingRight: true
|
|
43974
|
+
};
|
|
43975
|
+
const entityPlatforms = Array.isArray(row["platforms"]) ? row["platforms"] : void 0;
|
|
43976
|
+
const platforms = propPlatforms ?? entityPlatforms ?? [
|
|
43977
|
+
{ x: 0, y: 368, width: 800, height: 32, type: "ground" },
|
|
43978
|
+
{ x: 150, y: 280, width: 160, height: 16, type: "platform" },
|
|
43979
|
+
{ x: 420, y: 220, width: 160, height: 16, type: "platform" },
|
|
43980
|
+
{ x: 580, y: 300, width: 80, height: 16, type: "hazard" },
|
|
43981
|
+
{ x: 700, y: 340, width: 64, height: 28, type: "goal" }
|
|
43982
|
+
];
|
|
43983
|
+
const handleRestart = useCallback(() => {
|
|
43984
|
+
if (playAgainEvent) {
|
|
43985
|
+
eventBus.emit(`UI:${playAgainEvent}`, {});
|
|
43986
|
+
}
|
|
43987
|
+
}, [playAgainEvent, eventBus]);
|
|
43988
|
+
const isGameOver = result === "won" || result === "lost";
|
|
43989
|
+
const gameEndEmittedRef = useRef(false);
|
|
43990
|
+
useEffect(() => {
|
|
43991
|
+
if ((result === "won" || result === "lost") && gameEndEvent) {
|
|
43992
|
+
if (!gameEndEmittedRef.current) {
|
|
43993
|
+
gameEndEmittedRef.current = true;
|
|
43994
|
+
eventBus.emit(`UI:${gameEndEvent}`, { result });
|
|
43995
|
+
}
|
|
43996
|
+
} else {
|
|
43997
|
+
gameEndEmittedRef.current = false;
|
|
43998
|
+
}
|
|
43999
|
+
}, [result, gameEndEvent, eventBus]);
|
|
44000
|
+
return /* @__PURE__ */ jsx(
|
|
44001
|
+
VStack,
|
|
44002
|
+
{
|
|
44003
|
+
className: cn("platformer-board relative bg-background", className),
|
|
44004
|
+
gap: "none",
|
|
44005
|
+
children: /* @__PURE__ */ jsxs(Box, { className: "relative", children: [
|
|
44006
|
+
/* @__PURE__ */ jsx(
|
|
44007
|
+
PlatformerCanvas,
|
|
44008
|
+
{
|
|
44009
|
+
player,
|
|
44010
|
+
platforms,
|
|
44011
|
+
worldWidth,
|
|
44012
|
+
worldHeight,
|
|
44013
|
+
canvasWidth,
|
|
44014
|
+
canvasHeight,
|
|
44015
|
+
followCamera: true,
|
|
44016
|
+
bgColor,
|
|
44017
|
+
playerSprite,
|
|
44018
|
+
tileSprites,
|
|
44019
|
+
leftEvent,
|
|
44020
|
+
rightEvent,
|
|
44021
|
+
jumpEvent,
|
|
44022
|
+
stopEvent
|
|
44023
|
+
}
|
|
44024
|
+
),
|
|
44025
|
+
isGameOver && /* @__PURE__ */ jsx(Box, { className: "absolute inset-0 z-50 flex items-center justify-center bg-background/70 backdrop-blur-sm rounded-container", children: /* @__PURE__ */ jsxs(VStack, { className: "text-center p-8", gap: "lg", children: [
|
|
44026
|
+
/* @__PURE__ */ jsx(
|
|
44027
|
+
Typography,
|
|
44028
|
+
{
|
|
44029
|
+
variant: "h2",
|
|
44030
|
+
className: cn(
|
|
44031
|
+
"text-4xl font-black tracking-widest uppercase",
|
|
44032
|
+
result === "won" ? "text-warning" : "text-error"
|
|
44033
|
+
),
|
|
44034
|
+
children: result === "won" ? t("platformer.won") : t("platformer.lost")
|
|
44035
|
+
}
|
|
44036
|
+
),
|
|
44037
|
+
result === "won" && /* @__PURE__ */ jsxs(Typography, { variant: "body1", className: "text-muted-foreground", children: [
|
|
44038
|
+
t("platformer.level"),
|
|
44039
|
+
" ",
|
|
44040
|
+
level,
|
|
44041
|
+
" \u2014 ",
|
|
44042
|
+
t("platformer.score"),
|
|
44043
|
+
": ",
|
|
44044
|
+
score
|
|
44045
|
+
] }),
|
|
44046
|
+
result === "lost" && /* @__PURE__ */ jsx(Typography, { variant: "body1", className: "text-muted-foreground", children: t("platformer.noLives") }),
|
|
44047
|
+
/* @__PURE__ */ jsx(
|
|
44048
|
+
Button,
|
|
44049
|
+
{
|
|
44050
|
+
variant: "primary",
|
|
44051
|
+
className: "px-8 py-3 font-semibold",
|
|
44052
|
+
onClick: handleRestart,
|
|
44053
|
+
children: result === "won" ? t("platformer.nextLevel") : t("platformer.playAgain")
|
|
44054
|
+
}
|
|
44055
|
+
)
|
|
44056
|
+
] }) })
|
|
44057
|
+
] })
|
|
44058
|
+
}
|
|
44059
|
+
);
|
|
44060
|
+
}
|
|
44061
|
+
var init_PlatformerBoard = __esm({
|
|
44062
|
+
"components/game/organisms/PlatformerBoard.tsx"() {
|
|
44063
|
+
"use client";
|
|
44064
|
+
init_cn();
|
|
44065
|
+
init_useEventBus();
|
|
44066
|
+
init_Box();
|
|
44067
|
+
init_Button();
|
|
44068
|
+
init_Typography();
|
|
44069
|
+
init_Stack();
|
|
44070
|
+
init_PlatformerCanvas();
|
|
44071
|
+
PlatformerBoard.displayName = "PlatformerBoard";
|
|
44072
|
+
}
|
|
44073
|
+
});
|
|
44074
|
+
function PlatformerTemplate({
|
|
44075
|
+
entity,
|
|
44076
|
+
platforms = DEFAULT_PLATFORMS,
|
|
44077
|
+
worldWidth = 800,
|
|
44078
|
+
worldHeight = 400,
|
|
44079
|
+
canvasWidth = 800,
|
|
44080
|
+
canvasHeight = 400,
|
|
44081
|
+
playerSprite = `${CDN3}/characters/platformChar_idle.png`,
|
|
44082
|
+
tileSprites = DEFAULT_TILE_SPRITES,
|
|
44083
|
+
bgColor = "#5c94fc",
|
|
44084
|
+
gameEndEvent = "GAME_END",
|
|
44085
|
+
className
|
|
44086
|
+
}) {
|
|
44087
|
+
const row = entity && !Array.isArray(entity) ? entity : void 0;
|
|
44088
|
+
const lives = typeof row?.["lives"] === "number" ? row["lives"] : 3;
|
|
44089
|
+
const score = typeof row?.["score"] === "number" ? row["score"] : 0;
|
|
44090
|
+
const level = typeof row?.["level"] === "number" ? row["level"] : 1;
|
|
44091
|
+
return /* @__PURE__ */ jsxs(VStack, { className: cn("platformer-template w-full", className), gap: "none", children: [
|
|
44092
|
+
/* @__PURE__ */ jsx(Box, { className: "relative", children: /* @__PURE__ */ jsx(
|
|
44093
|
+
GameHud,
|
|
44094
|
+
{
|
|
44095
|
+
position: "top",
|
|
44096
|
+
stats: [
|
|
44097
|
+
{ label: "Lives", value: lives, format: "number", variant: "danger" },
|
|
44098
|
+
{ label: "Level", value: level, format: "number", variant: "default" }
|
|
44099
|
+
]
|
|
44100
|
+
}
|
|
44101
|
+
) }),
|
|
44102
|
+
/* @__PURE__ */ jsx(
|
|
44103
|
+
PlatformerBoard,
|
|
44104
|
+
{
|
|
44105
|
+
entity,
|
|
44106
|
+
platforms,
|
|
44107
|
+
worldWidth,
|
|
44108
|
+
worldHeight,
|
|
44109
|
+
canvasWidth,
|
|
44110
|
+
canvasHeight,
|
|
44111
|
+
playerSprite,
|
|
44112
|
+
tileSprites,
|
|
44113
|
+
bgColor,
|
|
44114
|
+
leftEvent: "LEFT",
|
|
44115
|
+
rightEvent: "RIGHT",
|
|
44116
|
+
jumpEvent: "JUMP",
|
|
44117
|
+
stopEvent: "STOP",
|
|
44118
|
+
playAgainEvent: "PLAY_AGAIN",
|
|
44119
|
+
gameEndEvent
|
|
44120
|
+
}
|
|
44121
|
+
),
|
|
44122
|
+
/* @__PURE__ */ jsx(Box, { className: "px-4 py-2", children: /* @__PURE__ */ jsx(ScoreBoard, { score, level }) })
|
|
44123
|
+
] });
|
|
44124
|
+
}
|
|
44125
|
+
var CDN3, DEFAULT_TILE_SPRITES, DEFAULT_PLATFORMS;
|
|
44126
|
+
var init_PlatformerTemplate = __esm({
|
|
44127
|
+
"components/game/templates/PlatformerTemplate.tsx"() {
|
|
44128
|
+
init_cn();
|
|
44129
|
+
init_Box();
|
|
44130
|
+
init_Stack();
|
|
44131
|
+
init_PlatformerBoard();
|
|
44132
|
+
init_GameHud();
|
|
44133
|
+
init_ScoreBoard();
|
|
44134
|
+
CDN3 = "https://almadar-kflow-assets.web.app/shared/platformer";
|
|
44135
|
+
DEFAULT_TILE_SPRITES = {
|
|
44136
|
+
ground: `${CDN3}/tiles/platformPack_tile001.png`,
|
|
44137
|
+
platform: `${CDN3}/tiles/platformPack_tile004.png`,
|
|
44138
|
+
hazard: `${CDN3}/tiles/platformPack_tile017.png`,
|
|
44139
|
+
goal: `${CDN3}/tiles/platformPack_tile007.png`
|
|
44140
|
+
};
|
|
44141
|
+
DEFAULT_PLATFORMS = [
|
|
44142
|
+
{ x: 0, y: 368, width: 800, height: 32, type: "ground" },
|
|
44143
|
+
{ x: 150, y: 280, width: 160, height: 16, type: "platform" },
|
|
44144
|
+
{ x: 420, y: 220, width: 160, height: 16, type: "platform" },
|
|
44145
|
+
{ x: 580, y: 300, width: 80, height: 16, type: "hazard" },
|
|
44146
|
+
{ x: 700, y: 340, width: 64, height: 28, type: "goal" }
|
|
44147
|
+
];
|
|
44148
|
+
PlatformerTemplate.displayName = "PlatformerTemplate";
|
|
44149
|
+
}
|
|
44150
|
+
});
|
|
42266
44151
|
var PricingOrganism;
|
|
42267
44152
|
var init_PricingOrganism = __esm({
|
|
42268
44153
|
"components/marketing/organisms/PricingOrganism.tsx"() {
|
|
@@ -42385,6 +44270,356 @@ var init_PricingPageTemplate = __esm({
|
|
|
42385
44270
|
PricingPageTemplate.displayName = "PricingPageTemplate";
|
|
42386
44271
|
}
|
|
42387
44272
|
});
|
|
44273
|
+
function RoguelikeBoard({
|
|
44274
|
+
entity,
|
|
44275
|
+
tiles: propTiles,
|
|
44276
|
+
enemies: propEnemies,
|
|
44277
|
+
items: propItems,
|
|
44278
|
+
player: propPlayer,
|
|
44279
|
+
playerHp: propPlayerHp,
|
|
44280
|
+
playerMaxHp: propPlayerMaxHp,
|
|
44281
|
+
playerAttack: propPlayerAttack,
|
|
44282
|
+
depth: propDepth,
|
|
44283
|
+
result: propResult,
|
|
44284
|
+
phase: propPhase,
|
|
44285
|
+
stairsX: propStairsX,
|
|
44286
|
+
stairsY: propStairsY,
|
|
44287
|
+
assetManifest: propAssetManifest,
|
|
44288
|
+
scale = 0.45,
|
|
44289
|
+
unitScale = 1,
|
|
44290
|
+
moveEvent,
|
|
44291
|
+
playAgainEvent,
|
|
44292
|
+
gameEndEvent,
|
|
44293
|
+
className
|
|
44294
|
+
}) {
|
|
44295
|
+
const board = boardEntity(entity) ?? {};
|
|
44296
|
+
const tiles = propTiles ?? (Array.isArray(board.tiles) ? board.tiles : DEFAULT_TILES2);
|
|
44297
|
+
const enemies = propEnemies ?? (Array.isArray(board.enemies) ? board.enemies : DEFAULT_ENEMIES);
|
|
44298
|
+
const items = propItems ?? (Array.isArray(board.items) ? board.items : DEFAULT_ITEMS);
|
|
44299
|
+
const player = propPlayer ?? board.player ?? { x: 1, y: 1 };
|
|
44300
|
+
const playerHp = propPlayerHp ?? num(board.playerHp, 10);
|
|
44301
|
+
const playerMaxHp = propPlayerMaxHp ?? num(board.playerMaxHp, 10);
|
|
44302
|
+
const playerAttack = propPlayerAttack ?? num(board.playerAttack, 3);
|
|
44303
|
+
const depth = propDepth ?? num(board.depth, 1);
|
|
44304
|
+
const result = propResult ?? (str(board.result) || "none");
|
|
44305
|
+
const phase = propPhase ?? (str(board.phase) || "player_turn");
|
|
44306
|
+
propStairsX ?? num(board.stairsX, 3);
|
|
44307
|
+
propStairsY ?? num(board.stairsY, 3);
|
|
44308
|
+
const eventBus = useEventBus();
|
|
44309
|
+
const { t } = useTranslate();
|
|
44310
|
+
const [hoveredTile, setHoveredTile] = useState(null);
|
|
44311
|
+
const emitMove = useCallback((dx, dy) => {
|
|
44312
|
+
if (!moveEvent) return;
|
|
44313
|
+
eventBus.emit(`UI:${moveEvent}`, { dx, dy });
|
|
44314
|
+
}, [moveEvent, eventBus]);
|
|
44315
|
+
useEffect(() => {
|
|
44316
|
+
const handler = (e) => {
|
|
44317
|
+
if (result !== "none" || phase !== "player_turn") return;
|
|
44318
|
+
if (e.key === "ArrowUp" || e.key === "w") emitMove(0, -1);
|
|
44319
|
+
if (e.key === "ArrowDown" || e.key === "s") emitMove(0, 1);
|
|
44320
|
+
if (e.key === "ArrowLeft" || e.key === "a") emitMove(-1, 0);
|
|
44321
|
+
if (e.key === "ArrowRight" || e.key === "d") emitMove(1, 0);
|
|
44322
|
+
};
|
|
44323
|
+
window.addEventListener("keydown", handler);
|
|
44324
|
+
return () => window.removeEventListener("keydown", handler);
|
|
44325
|
+
}, [result, phase, emitMove]);
|
|
44326
|
+
useEffect(() => {
|
|
44327
|
+
if ((result === "won" || result === "lost") && gameEndEvent) {
|
|
44328
|
+
eventBus.emit(`UI:${gameEndEvent}`, { result });
|
|
44329
|
+
}
|
|
44330
|
+
}, [result, gameEndEvent, eventBus]);
|
|
44331
|
+
const handleTileClick = useCallback((x, y) => {
|
|
44332
|
+
if (result !== "none" || phase !== "player_turn") return;
|
|
44333
|
+
const dx = x - player.x;
|
|
44334
|
+
const dy = y - player.y;
|
|
44335
|
+
if (Math.abs(dx) + Math.abs(dy) === 1) {
|
|
44336
|
+
emitMove(dx, dy);
|
|
44337
|
+
}
|
|
44338
|
+
}, [result, phase, player, emitMove]);
|
|
44339
|
+
const handleReset = useCallback(() => {
|
|
44340
|
+
if (!playAgainEvent) return;
|
|
44341
|
+
eventBus.emit(`UI:${playAgainEvent}`, {});
|
|
44342
|
+
}, [playAgainEvent, eventBus]);
|
|
44343
|
+
const isoUnits = useMemo(() => {
|
|
44344
|
+
const liveEnemies = enemies.filter((e) => e.hp > 0);
|
|
44345
|
+
return [
|
|
44346
|
+
{
|
|
44347
|
+
id: "player",
|
|
44348
|
+
position: player,
|
|
44349
|
+
name: t("roguelike.player") || "Hero",
|
|
44350
|
+
team: "player",
|
|
44351
|
+
health: playerHp,
|
|
44352
|
+
maxHealth: playerMaxHp,
|
|
44353
|
+
unitType: "player",
|
|
44354
|
+
sprite: `${CDN4}/isometric-dungeon/Characters/Male/Male_0_Idle0.png`
|
|
44355
|
+
},
|
|
44356
|
+
...liveEnemies.map((e) => ({
|
|
44357
|
+
id: e.id,
|
|
44358
|
+
position: { x: e.x, y: e.y },
|
|
44359
|
+
name: t("roguelike.enemy") || "Enemy",
|
|
44360
|
+
team: "enemy",
|
|
44361
|
+
health: e.hp,
|
|
44362
|
+
maxHealth: 6,
|
|
44363
|
+
unitType: "enemy",
|
|
44364
|
+
sprite: `${CDN4}/sprite-sheets/shadow-legion-sprite-sheet-sw.png`
|
|
44365
|
+
}))
|
|
44366
|
+
];
|
|
44367
|
+
}, [player, enemies, playerHp, playerMaxHp, t]);
|
|
44368
|
+
const isoFeatures = useMemo(
|
|
44369
|
+
() => items.map((it) => ({
|
|
44370
|
+
id: it.id,
|
|
44371
|
+
x: it.x,
|
|
44372
|
+
y: it.y,
|
|
44373
|
+
type: it.kind,
|
|
44374
|
+
sprite: FEATURE_SPRITE[it.kind] ?? FEATURE_SPRITE.health_potion
|
|
44375
|
+
})),
|
|
44376
|
+
[items]
|
|
44377
|
+
);
|
|
44378
|
+
const validMoves = useMemo(() => {
|
|
44379
|
+
if (result !== "none" || phase !== "player_turn") return [];
|
|
44380
|
+
const dirs = [{ dx: 0, dy: -1 }, { dx: 0, dy: 1 }, { dx: -1, dy: 0 }, { dx: 1, dy: 0 }];
|
|
44381
|
+
return dirs.map(({ dx, dy }) => ({ x: player.x + dx, y: player.y + dy })).filter(({ x, y }) => {
|
|
44382
|
+
const tile = tiles.find((t2) => t2.x === x && t2.y === y);
|
|
44383
|
+
return tile?.passable ?? false;
|
|
44384
|
+
});
|
|
44385
|
+
}, [result, phase, player, tiles]);
|
|
44386
|
+
const isGameOver = result === "won" || result === "lost";
|
|
44387
|
+
return /* @__PURE__ */ jsxs(VStack, { className: cn("roguelike-board relative min-h-[600px] bg-background", className), gap: "none", children: [
|
|
44388
|
+
/* @__PURE__ */ jsxs(HStack, { className: "items-center justify-between px-4 py-2 border-b border-border", gap: "md", children: [
|
|
44389
|
+
/* @__PURE__ */ jsxs(HStack, { gap: "sm", className: "items-center", children: [
|
|
44390
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: t("roguelike.depth") || "Depth" }),
|
|
44391
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body1", className: "font-bold tabular-nums", children: depth })
|
|
44392
|
+
] }),
|
|
44393
|
+
/* @__PURE__ */ jsxs(HStack, { gap: "sm", className: "items-center", children: [
|
|
44394
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: t("roguelike.hp") || "HP" }),
|
|
44395
|
+
/* @__PURE__ */ jsxs(
|
|
44396
|
+
Typography,
|
|
44397
|
+
{
|
|
44398
|
+
variant: "body1",
|
|
44399
|
+
className: cn(
|
|
44400
|
+
"font-bold tabular-nums",
|
|
44401
|
+
playerHp <= Math.floor(playerMaxHp * 0.25) ? "text-error" : "text-success"
|
|
44402
|
+
),
|
|
44403
|
+
children: [
|
|
44404
|
+
playerHp,
|
|
44405
|
+
" / ",
|
|
44406
|
+
playerMaxHp
|
|
44407
|
+
]
|
|
44408
|
+
}
|
|
44409
|
+
)
|
|
44410
|
+
] }),
|
|
44411
|
+
/* @__PURE__ */ jsxs(HStack, { gap: "sm", className: "items-center", children: [
|
|
44412
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: t("roguelike.atk") || "ATK" }),
|
|
44413
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body1", className: "font-bold tabular-nums text-foreground", children: playerAttack })
|
|
44414
|
+
] }),
|
|
44415
|
+
/* @__PURE__ */ jsxs(HStack, { gap: "sm", className: "items-center", children: [
|
|
44416
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: t("roguelike.phase") || "Phase" }),
|
|
44417
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body2", className: "capitalize text-foreground", children: phase.replace("_", " ") })
|
|
44418
|
+
] })
|
|
44419
|
+
] }),
|
|
44420
|
+
/* @__PURE__ */ jsx(Box, { className: "relative flex-1", children: /* @__PURE__ */ jsx(
|
|
44421
|
+
IsometricCanvas_default,
|
|
44422
|
+
{
|
|
44423
|
+
tiles,
|
|
44424
|
+
units: isoUnits,
|
|
44425
|
+
features: isoFeatures,
|
|
44426
|
+
selectedUnitId: null,
|
|
44427
|
+
validMoves,
|
|
44428
|
+
attackTargets: [],
|
|
44429
|
+
hoveredTile,
|
|
44430
|
+
onTileClick: handleTileClick,
|
|
44431
|
+
onUnitClick: () => void 0,
|
|
44432
|
+
onTileHover: (x, y) => setHoveredTile({ x, y }),
|
|
44433
|
+
onTileLeave: () => setHoveredTile(null),
|
|
44434
|
+
scale,
|
|
44435
|
+
assetBaseUrl: propAssetManifest?.baseUrl ?? CDN4,
|
|
44436
|
+
assetManifest: propAssetManifest,
|
|
44437
|
+
unitScale
|
|
44438
|
+
}
|
|
44439
|
+
) }),
|
|
44440
|
+
!isGameOver && /* @__PURE__ */ jsx(HStack, { className: "justify-center gap-2 p-3", gap: "none", children: [
|
|
44441
|
+
{ label: "\u2191", dx: 0, dy: -1 },
|
|
44442
|
+
{ label: "\u2193", dx: 0, dy: 1 },
|
|
44443
|
+
{ label: "\u2190", dx: -1, dy: 0 },
|
|
44444
|
+
{ label: "\u2192", dx: 1, dy: 0 }
|
|
44445
|
+
].map(({ label, dx, dy }) => /* @__PURE__ */ jsx(
|
|
44446
|
+
Button,
|
|
44447
|
+
{
|
|
44448
|
+
variant: "secondary",
|
|
44449
|
+
className: "w-9 h-9 p-0 text-base font-mono",
|
|
44450
|
+
onClick: () => emitMove(dx, dy),
|
|
44451
|
+
disabled: phase !== "player_turn",
|
|
44452
|
+
children: label
|
|
44453
|
+
},
|
|
44454
|
+
label
|
|
44455
|
+
)) }),
|
|
44456
|
+
isGameOver && /* @__PURE__ */ jsx(Box, { className: "absolute inset-0 z-50 flex items-center justify-center bg-background/75 backdrop-blur-sm rounded-container", children: /* @__PURE__ */ jsxs(VStack, { className: "text-center p-8", gap: "lg", children: [
|
|
44457
|
+
/* @__PURE__ */ jsx(
|
|
44458
|
+
Typography,
|
|
44459
|
+
{
|
|
44460
|
+
variant: "h2",
|
|
44461
|
+
className: cn(
|
|
44462
|
+
"text-4xl font-black tracking-widest uppercase",
|
|
44463
|
+
result === "won" ? "text-warning" : "text-error"
|
|
44464
|
+
),
|
|
44465
|
+
children: result === "won" ? t("roguelike.victory") || "Victory!" : t("roguelike.defeat") || "Defeated!"
|
|
44466
|
+
}
|
|
44467
|
+
),
|
|
44468
|
+
result === "won" && /* @__PURE__ */ jsx(Typography, { variant: "body1", className: "text-muted-foreground", children: t("roguelike.cleared") || `Dungeon cleared! Depth reached: ${depth}` }),
|
|
44469
|
+
/* @__PURE__ */ jsx(
|
|
44470
|
+
Button,
|
|
44471
|
+
{
|
|
44472
|
+
variant: "primary",
|
|
44473
|
+
className: "px-8 py-3 font-semibold",
|
|
44474
|
+
onClick: handleReset,
|
|
44475
|
+
children: t("roguelike.playAgain") || "Play Again"
|
|
44476
|
+
}
|
|
44477
|
+
)
|
|
44478
|
+
] }) })
|
|
44479
|
+
] });
|
|
44480
|
+
}
|
|
44481
|
+
var CDN4, DEFAULT_TILES2, DEFAULT_ENEMIES, DEFAULT_ITEMS, FEATURE_SPRITE;
|
|
44482
|
+
var init_RoguelikeBoard = __esm({
|
|
44483
|
+
"components/game/organisms/RoguelikeBoard.tsx"() {
|
|
44484
|
+
"use client";
|
|
44485
|
+
init_cn();
|
|
44486
|
+
init_useEventBus();
|
|
44487
|
+
init_Box();
|
|
44488
|
+
init_Button();
|
|
44489
|
+
init_Typography();
|
|
44490
|
+
init_Stack();
|
|
44491
|
+
init_IsometricCanvas();
|
|
44492
|
+
init_boardEntity();
|
|
44493
|
+
CDN4 = "https://almadar-kflow-assets.web.app/shared";
|
|
44494
|
+
DEFAULT_TILES2 = [
|
|
44495
|
+
{ x: 0, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
44496
|
+
{ x: 1, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
44497
|
+
{ x: 2, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
44498
|
+
{ x: 3, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
44499
|
+
{ x: 4, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
44500
|
+
{ x: 0, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
44501
|
+
{ x: 1, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
|
|
44502
|
+
{ x: 2, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
|
|
44503
|
+
{ x: 3, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
|
|
44504
|
+
{ x: 4, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
44505
|
+
{ x: 0, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
44506
|
+
{ x: 1, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png` },
|
|
44507
|
+
{ x: 2, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png` },
|
|
44508
|
+
{ x: 3, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
|
|
44509
|
+
{ x: 4, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
44510
|
+
{ x: 0, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
44511
|
+
{ x: 1, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
|
|
44512
|
+
{ x: 2, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png` },
|
|
44513
|
+
{ x: 3, y: 3, terrain: "stairs", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stairs_E.png` },
|
|
44514
|
+
{ x: 4, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
44515
|
+
{ x: 0, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
44516
|
+
{ x: 1, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
44517
|
+
{ x: 2, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
44518
|
+
{ x: 3, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
44519
|
+
{ x: 4, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` }
|
|
44520
|
+
];
|
|
44521
|
+
DEFAULT_ENEMIES = [
|
|
44522
|
+
{ id: "e1", x: 3, y: 1, hp: 5, attack: 2 },
|
|
44523
|
+
{ id: "e2", x: 1, y: 3, hp: 4, attack: 1 }
|
|
44524
|
+
];
|
|
44525
|
+
DEFAULT_ITEMS = [
|
|
44526
|
+
{ id: "i1", x: 2, y: 2, kind: "health_potion" }
|
|
44527
|
+
];
|
|
44528
|
+
FEATURE_SPRITE = {
|
|
44529
|
+
health_potion: `${CDN4}/isometric-dungeon/Isometric/chestClosed_E.png`,
|
|
44530
|
+
sword: `${CDN4}/isometric-dungeon/Isometric/barrel_E.png`,
|
|
44531
|
+
shield: `${CDN4}/isometric-dungeon/Isometric/barrel_E.png`
|
|
44532
|
+
};
|
|
44533
|
+
RoguelikeBoard.displayName = "RoguelikeBoard";
|
|
44534
|
+
}
|
|
44535
|
+
});
|
|
44536
|
+
function RoguelikeTemplate({
|
|
44537
|
+
entity,
|
|
44538
|
+
scale = 0.45,
|
|
44539
|
+
unitScale = 1,
|
|
44540
|
+
tiles = DEFAULT_ROGUELIKE_TILES,
|
|
44541
|
+
enemies,
|
|
44542
|
+
items,
|
|
44543
|
+
stairsX,
|
|
44544
|
+
stairsY,
|
|
44545
|
+
assetManifest = DEFAULT_ROGUELIKE_MANIFEST,
|
|
44546
|
+
gameEndEvent,
|
|
44547
|
+
className
|
|
44548
|
+
}) {
|
|
44549
|
+
const resolved = entity && typeof entity === "object" && !Array.isArray(entity) ? entity : void 0;
|
|
44550
|
+
if (!resolved && !tiles && !assetManifest) return null;
|
|
44551
|
+
return /* @__PURE__ */ jsx(
|
|
44552
|
+
RoguelikeBoard,
|
|
44553
|
+
{
|
|
44554
|
+
entity: resolved,
|
|
44555
|
+
tiles,
|
|
44556
|
+
enemies,
|
|
44557
|
+
items,
|
|
44558
|
+
stairsX,
|
|
44559
|
+
stairsY,
|
|
44560
|
+
assetManifest,
|
|
44561
|
+
scale,
|
|
44562
|
+
unitScale,
|
|
44563
|
+
moveEvent: "MOVE",
|
|
44564
|
+
playAgainEvent: "PLAY_AGAIN",
|
|
44565
|
+
gameEndEvent: gameEndEvent ?? "GAME_END",
|
|
44566
|
+
className
|
|
44567
|
+
}
|
|
44568
|
+
);
|
|
44569
|
+
}
|
|
44570
|
+
var CDN5, DEFAULT_ROGUELIKE_TILES, DEFAULT_ROGUELIKE_MANIFEST;
|
|
44571
|
+
var init_RoguelikeTemplate = __esm({
|
|
44572
|
+
"components/game/templates/RoguelikeTemplate.tsx"() {
|
|
44573
|
+
init_RoguelikeBoard();
|
|
44574
|
+
CDN5 = "https://almadar-kflow-assets.web.app/shared";
|
|
44575
|
+
DEFAULT_ROGUELIKE_TILES = [
|
|
44576
|
+
{ x: 0, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
44577
|
+
{ x: 1, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
44578
|
+
{ x: 2, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
44579
|
+
{ x: 3, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
44580
|
+
{ x: 4, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
44581
|
+
{ x: 0, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
44582
|
+
{ x: 1, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirt_E.png` },
|
|
44583
|
+
{ x: 2, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirt_E.png` },
|
|
44584
|
+
{ x: 3, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirt_E.png` },
|
|
44585
|
+
{ x: 4, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
44586
|
+
{ x: 0, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
44587
|
+
{ x: 1, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirtTiles_E.png` },
|
|
44588
|
+
{ x: 2, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirtTiles_E.png` },
|
|
44589
|
+
{ x: 3, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirt_E.png` },
|
|
44590
|
+
{ x: 4, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
44591
|
+
{ x: 0, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
44592
|
+
{ x: 1, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirt_E.png` },
|
|
44593
|
+
{ x: 2, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirtTiles_E.png` },
|
|
44594
|
+
{ x: 3, y: 3, terrain: "stairs", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stairs_E.png` },
|
|
44595
|
+
{ x: 4, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
44596
|
+
{ x: 0, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
44597
|
+
{ x: 1, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
44598
|
+
{ x: 2, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
44599
|
+
{ x: 3, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
44600
|
+
{ x: 4, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` }
|
|
44601
|
+
];
|
|
44602
|
+
DEFAULT_ROGUELIKE_MANIFEST = {
|
|
44603
|
+
baseUrl: CDN5,
|
|
44604
|
+
terrains: {
|
|
44605
|
+
floor: "/isometric-dungeon/Isometric/dirt_E.png",
|
|
44606
|
+
wall: "/isometric-dungeon/Isometric/stoneInset_E.png",
|
|
44607
|
+
stairs: "/isometric-dungeon/Isometric/stairs_E.png",
|
|
44608
|
+
planks: "/isometric-dungeon/Isometric/planks_E.png"
|
|
44609
|
+
},
|
|
44610
|
+
units: {
|
|
44611
|
+
player: "/isometric-dungeon/Characters/Male/Male_0_Idle0.png",
|
|
44612
|
+
enemy: "/sprite-sheets/shadow-legion-sprite-sheet-sw.png"
|
|
44613
|
+
},
|
|
44614
|
+
features: {
|
|
44615
|
+
health_potion: "/isometric-dungeon/Isometric/chestClosed_E.png",
|
|
44616
|
+
sword: "/isometric-dungeon/Isometric/barrel_E.png",
|
|
44617
|
+
shield: "/isometric-dungeon/Isometric/barrel_E.png"
|
|
44618
|
+
}
|
|
44619
|
+
};
|
|
44620
|
+
RoguelikeTemplate.displayName = "RoguelikeTemplate";
|
|
44621
|
+
}
|
|
44622
|
+
});
|
|
42388
44623
|
|
|
42389
44624
|
// lib/traitRegistry.ts
|
|
42390
44625
|
function notifyListeners2() {
|
|
@@ -43638,7 +45873,7 @@ function getAllEvents(traits2) {
|
|
|
43638
45873
|
function EventDispatcherTab({ traits: traits2, schema }) {
|
|
43639
45874
|
const eventBus = useEventBus();
|
|
43640
45875
|
const { t } = useTranslate();
|
|
43641
|
-
const [
|
|
45876
|
+
const [log14, setLog] = React82.useState([]);
|
|
43642
45877
|
const prevStatesRef = React82.useRef(/* @__PURE__ */ new Map());
|
|
43643
45878
|
React82.useEffect(() => {
|
|
43644
45879
|
for (const trait of traits2) {
|
|
@@ -43702,9 +45937,9 @@ function EventDispatcherTab({ traits: traits2, schema }) {
|
|
|
43702
45937
|
/* @__PURE__ */ jsx(Typography, { variant: "small", weight: "medium", className: "text-gray-500 mb-1", children: t("debug.otherEvents") }),
|
|
43703
45938
|
/* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1", children: unavailableEvents.map((event) => /* @__PURE__ */ jsx(Badge, { variant: "default", size: "sm", className: "opacity-50", children: event }, event)) })
|
|
43704
45939
|
] }),
|
|
43705
|
-
|
|
45940
|
+
log14.length > 0 && /* @__PURE__ */ jsxs("div", { children: [
|
|
43706
45941
|
/* @__PURE__ */ jsx(Typography, { variant: "small", weight: "medium", className: "text-gray-500 mb-1", children: t("debug.recentTransitions") }),
|
|
43707
|
-
/* @__PURE__ */ jsx(Stack, { gap: "xs", children:
|
|
45942
|
+
/* @__PURE__ */ jsx(Stack, { gap: "xs", children: log14.map((entry, i) => /* @__PURE__ */ jsxs(Typography, { variant: "small", className: "font-mono text-xs", children: [
|
|
43708
45943
|
/* @__PURE__ */ jsx("span", { className: "text-purple-400", children: entry.traitName }),
|
|
43709
45944
|
" ",
|
|
43710
45945
|
/* @__PURE__ */ jsx("span", { className: "text-gray-500", children: entry.from }),
|
|
@@ -45625,9 +47860,9 @@ function VariablePanel({
|
|
|
45625
47860
|
/* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-muted-foreground font-medium", children: t("stateArchitect.variables", { name: entityName }) }),
|
|
45626
47861
|
variables.map((v) => {
|
|
45627
47862
|
const name = v.name == null ? "" : String(v.name);
|
|
45628
|
-
const value =
|
|
45629
|
-
const max =
|
|
45630
|
-
const min =
|
|
47863
|
+
const value = numField2(v.value);
|
|
47864
|
+
const max = numField2(v.max, 100);
|
|
47865
|
+
const min = numField2(v.min, 0);
|
|
45631
47866
|
const unit = v.unit == null ? "" : String(v.unit);
|
|
45632
47867
|
const pct = Math.round((value - min) / (max - min) * 100);
|
|
45633
47868
|
const isHigh = pct > 80;
|
|
@@ -45657,12 +47892,12 @@ function VariablePanel({
|
|
|
45657
47892
|
})
|
|
45658
47893
|
] });
|
|
45659
47894
|
}
|
|
45660
|
-
var
|
|
47895
|
+
var numField2;
|
|
45661
47896
|
var init_VariablePanel = __esm({
|
|
45662
47897
|
"components/game/organisms/puzzles/state-architect/VariablePanel.tsx"() {
|
|
45663
47898
|
init_atoms2();
|
|
45664
47899
|
init_cn();
|
|
45665
|
-
|
|
47900
|
+
numField2 = (v, fallback = 0) => {
|
|
45666
47901
|
const n = Number(v);
|
|
45667
47902
|
return Number.isFinite(n) ? n : fallback;
|
|
45668
47903
|
};
|
|
@@ -46515,6 +48750,289 @@ var init_ToastSlot = __esm({
|
|
|
46515
48750
|
ToastSlot.displayName = "ToastSlot";
|
|
46516
48751
|
}
|
|
46517
48752
|
});
|
|
48753
|
+
function tilesToIso(tiles) {
|
|
48754
|
+
return tiles.map((t) => ({
|
|
48755
|
+
x: t.x,
|
|
48756
|
+
y: t.y,
|
|
48757
|
+
terrain: t.terrain,
|
|
48758
|
+
terrainSprite: t.terrainSprite ?? TERRAIN_SPRITES[t.terrain ?? "ground"],
|
|
48759
|
+
passable: t.passable
|
|
48760
|
+
}));
|
|
48761
|
+
}
|
|
48762
|
+
function towersToUnits(towers) {
|
|
48763
|
+
return towers.map((t) => ({
|
|
48764
|
+
id: t.id,
|
|
48765
|
+
position: { x: t.x, y: t.y },
|
|
48766
|
+
name: "Tower",
|
|
48767
|
+
team: "player",
|
|
48768
|
+
sprite: TOWER_SPRITE,
|
|
48769
|
+
unitType: "guardian",
|
|
48770
|
+
health: 1,
|
|
48771
|
+
maxHealth: 1
|
|
48772
|
+
}));
|
|
48773
|
+
}
|
|
48774
|
+
function creepsToUnits(creeps) {
|
|
48775
|
+
return creeps.map((c) => ({
|
|
48776
|
+
id: c.id,
|
|
48777
|
+
position: { x: c.x, y: c.y },
|
|
48778
|
+
name: "Creep",
|
|
48779
|
+
team: "enemy",
|
|
48780
|
+
sprite: CREEP_SPRITE,
|
|
48781
|
+
unitType: "scrapper",
|
|
48782
|
+
health: c.hp,
|
|
48783
|
+
maxHealth: c.maxHp
|
|
48784
|
+
}));
|
|
48785
|
+
}
|
|
48786
|
+
function pathToFeatures(path) {
|
|
48787
|
+
return path.map((p2, i) => ({
|
|
48788
|
+
id: `path-${i}`,
|
|
48789
|
+
x: p2.x,
|
|
48790
|
+
y: p2.y,
|
|
48791
|
+
type: "path-marker",
|
|
48792
|
+
sprite: `${CDN6}world-map/road_straight.png`
|
|
48793
|
+
}));
|
|
48794
|
+
}
|
|
48795
|
+
function TowerDefenseBoard({
|
|
48796
|
+
entity,
|
|
48797
|
+
tiles: propTiles,
|
|
48798
|
+
path: propPath,
|
|
48799
|
+
towers: propTowers,
|
|
48800
|
+
creeps: propCreeps,
|
|
48801
|
+
gold: propGold,
|
|
48802
|
+
lives: propLives,
|
|
48803
|
+
wave: propWave,
|
|
48804
|
+
maxWaves: propMaxWaves,
|
|
48805
|
+
result: propResult,
|
|
48806
|
+
waveActive: propWaveActive,
|
|
48807
|
+
towerCost = 25,
|
|
48808
|
+
scale = 0.45,
|
|
48809
|
+
placeTowerEvent,
|
|
48810
|
+
startWaveEvent,
|
|
48811
|
+
playAgainEvent,
|
|
48812
|
+
gameEndEvent,
|
|
48813
|
+
className
|
|
48814
|
+
}) {
|
|
48815
|
+
const board = boardEntity(entity) ?? {};
|
|
48816
|
+
const eventBus = useEventBus();
|
|
48817
|
+
const { t } = useTranslate();
|
|
48818
|
+
const tiles = propTiles ?? rows(board.tiles);
|
|
48819
|
+
const path = propPath ?? rows(board.path);
|
|
48820
|
+
const towers = propTowers ?? rows(board.towers);
|
|
48821
|
+
const creeps = propCreeps ?? rows(board.creeps);
|
|
48822
|
+
const gold = propGold ?? num(board.gold, 100);
|
|
48823
|
+
const lives = propLives ?? num(board.lives, 20);
|
|
48824
|
+
const wave = propWave ?? num(board.wave, 1);
|
|
48825
|
+
const maxWaves = propMaxWaves ?? num(board.maxWaves, 5);
|
|
48826
|
+
const result = propResult ?? (str(board.result) || "none");
|
|
48827
|
+
const waveActive = propWaveActive ?? Boolean(board.waveActive);
|
|
48828
|
+
const [hoveredTile, setHoveredTile] = useState(null);
|
|
48829
|
+
const emittedGameEnd = useRef(false);
|
|
48830
|
+
if (result !== "none" && !emittedGameEnd.current) {
|
|
48831
|
+
emittedGameEnd.current = true;
|
|
48832
|
+
if (gameEndEvent) {
|
|
48833
|
+
eventBus.emit(`UI:${gameEndEvent}`, { result });
|
|
48834
|
+
}
|
|
48835
|
+
}
|
|
48836
|
+
if (result === "none") {
|
|
48837
|
+
emittedGameEnd.current = false;
|
|
48838
|
+
}
|
|
48839
|
+
const towerPositions = useMemo(() => new Set(towers.map((t2) => `${t2.x},${t2.y}`)), [towers]);
|
|
48840
|
+
const pathPositions = useMemo(() => new Set(path.map((p2) => `${p2.x},${p2.y}`)), [path]);
|
|
48841
|
+
const validMoves = useMemo(() => {
|
|
48842
|
+
if (result !== "none" || gold < towerCost) return [];
|
|
48843
|
+
return tiles.filter(
|
|
48844
|
+
(t2) => t2.passable !== false && !towerPositions.has(`${t2.x},${t2.y}`) && !pathPositions.has(`${t2.x},${t2.y}`)
|
|
48845
|
+
).map((t2) => ({ x: t2.x, y: t2.y }));
|
|
48846
|
+
}, [tiles, towerPositions, pathPositions, result, gold, towerCost]);
|
|
48847
|
+
const isoTiles = useMemo(() => tilesToIso(tiles), [tiles]);
|
|
48848
|
+
const towerUnits = useMemo(() => towersToUnits(towers), [towers]);
|
|
48849
|
+
const creepUnits = useMemo(() => creepsToUnits(creeps), [creeps]);
|
|
48850
|
+
const isoUnits = useMemo(() => [...towerUnits, ...creepUnits], [towerUnits, creepUnits]);
|
|
48851
|
+
const pathFeatures = useMemo(() => pathToFeatures(path), [path]);
|
|
48852
|
+
const handleTileClick = useCallback((x, y) => {
|
|
48853
|
+
if (result !== "none") return;
|
|
48854
|
+
if (pathPositions.has(`${x},${y}`)) return;
|
|
48855
|
+
if (towerPositions.has(`${x},${y}`)) return;
|
|
48856
|
+
if (gold < towerCost) return;
|
|
48857
|
+
if (placeTowerEvent) {
|
|
48858
|
+
eventBus.emit(`UI:${placeTowerEvent}`, { x, y });
|
|
48859
|
+
}
|
|
48860
|
+
}, [result, pathPositions, towerPositions, gold, towerCost, placeTowerEvent, eventBus]);
|
|
48861
|
+
const handleStartWave = useCallback(() => {
|
|
48862
|
+
if (startWaveEvent) {
|
|
48863
|
+
eventBus.emit(`UI:${startWaveEvent}`, { wave });
|
|
48864
|
+
}
|
|
48865
|
+
}, [startWaveEvent, wave, eventBus]);
|
|
48866
|
+
const handlePlayAgain = useCallback(() => {
|
|
48867
|
+
if (playAgainEvent) {
|
|
48868
|
+
eventBus.emit(`UI:${playAgainEvent}`, {});
|
|
48869
|
+
}
|
|
48870
|
+
}, [playAgainEvent, eventBus]);
|
|
48871
|
+
const canPlaceTower = gold >= towerCost && result === "none";
|
|
48872
|
+
const canStartWave = !waveActive && result === "none";
|
|
48873
|
+
return /* @__PURE__ */ jsxs(VStack, { className: cn("tower-defense-board relative min-h-[600px] bg-background", className), gap: "none", children: [
|
|
48874
|
+
/* @__PURE__ */ jsxs(
|
|
48875
|
+
HStack,
|
|
48876
|
+
{
|
|
48877
|
+
className: "px-4 py-2 border-b border-border bg-surface",
|
|
48878
|
+
gap: "lg",
|
|
48879
|
+
align: "center",
|
|
48880
|
+
children: [
|
|
48881
|
+
/* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
|
|
48882
|
+
/* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", children: t("td.gold") ?? "Gold" }),
|
|
48883
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body2", weight: "bold", className: "text-warning", children: gold })
|
|
48884
|
+
] }),
|
|
48885
|
+
/* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
|
|
48886
|
+
/* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", children: t("td.lives") ?? "Lives" }),
|
|
48887
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body2", weight: "bold", className: lives <= 5 ? "text-error" : "text-success", children: lives })
|
|
48888
|
+
] }),
|
|
48889
|
+
/* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
|
|
48890
|
+
/* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", children: t("td.wave") ?? "Wave" }),
|
|
48891
|
+
/* @__PURE__ */ jsxs(Typography, { variant: "body2", weight: "bold", children: [
|
|
48892
|
+
wave,
|
|
48893
|
+
" / ",
|
|
48894
|
+
maxWaves
|
|
48895
|
+
] })
|
|
48896
|
+
] }),
|
|
48897
|
+
/* @__PURE__ */ jsxs(Box, { className: "ml-auto", children: [
|
|
48898
|
+
canStartWave && /* @__PURE__ */ jsx(Button, { variant: "primary", size: "sm", onClick: handleStartWave, children: t("td.startWave") ?? "Start Wave" }),
|
|
48899
|
+
waveActive && /* @__PURE__ */ jsx(Typography, { variant: "small", className: "text-warning animate-pulse", children: t("td.waveInProgress") ?? "Wave in progress\u2026" })
|
|
48900
|
+
] })
|
|
48901
|
+
]
|
|
48902
|
+
}
|
|
48903
|
+
),
|
|
48904
|
+
/* @__PURE__ */ jsxs(Box, { className: "relative flex-1", children: [
|
|
48905
|
+
/* @__PURE__ */ jsx(
|
|
48906
|
+
IsometricCanvas_default,
|
|
48907
|
+
{
|
|
48908
|
+
tiles: isoTiles,
|
|
48909
|
+
units: isoUnits,
|
|
48910
|
+
features: pathFeatures,
|
|
48911
|
+
validMoves,
|
|
48912
|
+
hoveredTile,
|
|
48913
|
+
onTileClick: handleTileClick,
|
|
48914
|
+
onTileHover: (x, y) => setHoveredTile({ x, y }),
|
|
48915
|
+
onTileLeave: () => setHoveredTile(null),
|
|
48916
|
+
scale
|
|
48917
|
+
}
|
|
48918
|
+
),
|
|
48919
|
+
hoveredTile && canPlaceTower && validMoves.some((m) => m.x === hoveredTile.x && m.y === hoveredTile.y) && /* @__PURE__ */ jsx(Box, { className: "absolute bottom-4 left-1/2 -translate-x-1/2 z-10 bg-background/80 rounded px-3 py-1 backdrop-blur-sm pointer-events-none", children: /* @__PURE__ */ jsx(Typography, { variant: "small", children: t("td.placeTower") ?? `Place tower (${towerCost} gold)` }) })
|
|
48920
|
+
] }),
|
|
48921
|
+
result !== "none" && /* @__PURE__ */ jsx(Box, { className: "absolute inset-0 z-50 flex items-center justify-center bg-background/70 backdrop-blur-sm", children: /* @__PURE__ */ jsxs(VStack, { className: "text-center p-8", gap: "lg", children: [
|
|
48922
|
+
/* @__PURE__ */ jsx(
|
|
48923
|
+
Typography,
|
|
48924
|
+
{
|
|
48925
|
+
variant: "h2",
|
|
48926
|
+
className: cn(
|
|
48927
|
+
"text-4xl font-black tracking-widest uppercase",
|
|
48928
|
+
result === "won" ? "text-warning" : "text-error"
|
|
48929
|
+
),
|
|
48930
|
+
children: result === "won" ? t("td.victory") ?? "Victory!" : t("td.defeat") ?? "Defeat!"
|
|
48931
|
+
}
|
|
48932
|
+
),
|
|
48933
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body1", className: "text-muted-foreground", children: result === "won" ? t("td.survivedAllWaves") ?? `Survived all ${maxWaves} waves!` : t("td.livesReachedZero") ?? "Your base was overrun." }),
|
|
48934
|
+
/* @__PURE__ */ jsx(
|
|
48935
|
+
Button,
|
|
48936
|
+
{
|
|
48937
|
+
variant: "primary",
|
|
48938
|
+
className: "px-8 py-3 font-semibold",
|
|
48939
|
+
onClick: handlePlayAgain,
|
|
48940
|
+
children: t("td.playAgain") ?? "Play Again"
|
|
48941
|
+
}
|
|
48942
|
+
)
|
|
48943
|
+
] }) })
|
|
48944
|
+
] });
|
|
48945
|
+
}
|
|
48946
|
+
var CDN6, TERRAIN_SPRITES, TOWER_SPRITE, CREEP_SPRITE;
|
|
48947
|
+
var init_TowerDefenseBoard = __esm({
|
|
48948
|
+
"components/game/organisms/TowerDefenseBoard.tsx"() {
|
|
48949
|
+
"use client";
|
|
48950
|
+
init_cn();
|
|
48951
|
+
init_useEventBus();
|
|
48952
|
+
init_Box();
|
|
48953
|
+
init_Button();
|
|
48954
|
+
init_Typography();
|
|
48955
|
+
init_Stack();
|
|
48956
|
+
init_IsometricCanvas();
|
|
48957
|
+
init_boardEntity();
|
|
48958
|
+
CDN6 = "https://almadar-kflow-assets.web.app/shared/";
|
|
48959
|
+
TERRAIN_SPRITES = {
|
|
48960
|
+
ground: `${CDN6}isometric-blocks/PNG/Platformer tiles/platformerTile_01.png`,
|
|
48961
|
+
path: `${CDN6}isometric-blocks/PNG/Platformer tiles/platformerTile_09.png`,
|
|
48962
|
+
wall: `${CDN6}isometric-blocks/PNG/Platformer tiles/platformerTile_05.png`
|
|
48963
|
+
};
|
|
48964
|
+
TOWER_SPRITE = `${CDN6}units/guardian.png`;
|
|
48965
|
+
CREEP_SPRITE = `${CDN6}units/scrapper.png`;
|
|
48966
|
+
TowerDefenseBoard.displayName = "TowerDefenseBoard";
|
|
48967
|
+
}
|
|
48968
|
+
});
|
|
48969
|
+
function TowerDefenseTemplate({
|
|
48970
|
+
entity,
|
|
48971
|
+
title = "Tower Defense",
|
|
48972
|
+
tiles,
|
|
48973
|
+
path,
|
|
48974
|
+
towers,
|
|
48975
|
+
gold,
|
|
48976
|
+
lives,
|
|
48977
|
+
maxWaves,
|
|
48978
|
+
towerCost,
|
|
48979
|
+
scale,
|
|
48980
|
+
placeTowerEvent,
|
|
48981
|
+
startWaveEvent,
|
|
48982
|
+
playAgainEvent,
|
|
48983
|
+
gameEndEvent,
|
|
48984
|
+
className
|
|
48985
|
+
}) {
|
|
48986
|
+
const resolved = entity && typeof entity === "object" && !Array.isArray(entity) ? entity : void 0;
|
|
48987
|
+
return /* @__PURE__ */ jsxs(
|
|
48988
|
+
Box,
|
|
48989
|
+
{
|
|
48990
|
+
display: "flex",
|
|
48991
|
+
fullHeight: true,
|
|
48992
|
+
className: cn("tower-defense-template flex-col", className),
|
|
48993
|
+
children: [
|
|
48994
|
+
/* @__PURE__ */ jsx(
|
|
48995
|
+
HStack,
|
|
48996
|
+
{
|
|
48997
|
+
gap: "sm",
|
|
48998
|
+
align: "center",
|
|
48999
|
+
className: "px-4 py-3 border-b-2 border-border bg-surface shrink-0",
|
|
49000
|
+
children: /* @__PURE__ */ jsx(Typography, { variant: "h4", children: title })
|
|
49001
|
+
}
|
|
49002
|
+
),
|
|
49003
|
+
/* @__PURE__ */ jsx(Box, { className: "flex-1 relative overflow-hidden", children: /* @__PURE__ */ jsx(
|
|
49004
|
+
TowerDefenseBoard,
|
|
49005
|
+
{
|
|
49006
|
+
entity: resolved,
|
|
49007
|
+
tiles,
|
|
49008
|
+
path,
|
|
49009
|
+
towers,
|
|
49010
|
+
gold,
|
|
49011
|
+
lives,
|
|
49012
|
+
maxWaves,
|
|
49013
|
+
towerCost,
|
|
49014
|
+
scale,
|
|
49015
|
+
placeTowerEvent,
|
|
49016
|
+
startWaveEvent,
|
|
49017
|
+
playAgainEvent,
|
|
49018
|
+
gameEndEvent,
|
|
49019
|
+
className: "h-full"
|
|
49020
|
+
}
|
|
49021
|
+
) })
|
|
49022
|
+
]
|
|
49023
|
+
}
|
|
49024
|
+
);
|
|
49025
|
+
}
|
|
49026
|
+
var init_TowerDefenseTemplate = __esm({
|
|
49027
|
+
"components/game/templates/TowerDefenseTemplate.tsx"() {
|
|
49028
|
+
init_cn();
|
|
49029
|
+
init_Box();
|
|
49030
|
+
init_Stack();
|
|
49031
|
+
init_Typography();
|
|
49032
|
+
init_TowerDefenseBoard();
|
|
49033
|
+
TowerDefenseTemplate.displayName = "TowerDefenseTemplate";
|
|
49034
|
+
}
|
|
49035
|
+
});
|
|
46518
49036
|
function useBattleState(initialUnits, eventConfig = {}, callbacks = {}) {
|
|
46519
49037
|
const eventBus = useEventBus();
|
|
46520
49038
|
const {
|
|
@@ -47024,48 +49542,48 @@ function WorldMapTemplate({
|
|
|
47024
49542
|
}
|
|
47025
49543
|
);
|
|
47026
49544
|
}
|
|
47027
|
-
var
|
|
49545
|
+
var CDN7, DEFAULT_WORLDMAP_TILES, DEFAULT_WORLDMAP_UNITS, DEFAULT_WORLDMAP_FEATURES, DEFAULT_WORLDMAP_MANIFEST;
|
|
47028
49546
|
var init_WorldMapTemplate = __esm({
|
|
47029
49547
|
"components/game/templates/WorldMapTemplate.tsx"() {
|
|
47030
49548
|
init_WorldMapBoard();
|
|
47031
|
-
|
|
49549
|
+
CDN7 = "https://almadar-kflow-assets.web.app/shared";
|
|
47032
49550
|
DEFAULT_WORLDMAP_TILES = [
|
|
47033
|
-
{ x: 0, y: 0, terrain: "mountain", passable: false, terrainSprite: `${
|
|
47034
|
-
{ x: 1, y: 0, terrain: "mountain", passable: false, terrainSprite: `${
|
|
47035
|
-
{ x: 2, y: 0, terrain: "water", passable: false, terrainSprite: `${
|
|
47036
|
-
{ x: 3, y: 0, terrain: "mountain", passable: false, terrainSprite: `${
|
|
47037
|
-
{ x: 4, y: 0, terrain: "mountain", passable: false, terrainSprite: `${
|
|
47038
|
-
{ x: 0, y: 1, terrain: "mountain", passable: false, terrainSprite: `${
|
|
47039
|
-
{ x: 1, y: 1, terrain: "grass", passable: true, terrainSprite: `${
|
|
47040
|
-
{ x: 2, y: 1, terrain: "grass", passable: true, terrainSprite: `${
|
|
47041
|
-
{ x: 3, y: 1, terrain: "grass", passable: true, terrainSprite: `${
|
|
47042
|
-
{ x: 4, y: 1, terrain: "water", passable: false, terrainSprite: `${
|
|
47043
|
-
{ x: 0, y: 2, terrain: "water", passable: false, terrainSprite: `${
|
|
47044
|
-
{ x: 1, y: 2, terrain: "grass", passable: true, terrainSprite: `${
|
|
47045
|
-
{ x: 2, y: 2, terrain: "grass", passable: true, terrainSprite: `${
|
|
47046
|
-
{ x: 3, y: 2, terrain: "grass", passable: true, terrainSprite: `${
|
|
47047
|
-
{ x: 4, y: 2, terrain: "mountain", passable: false, terrainSprite: `${
|
|
47048
|
-
{ x: 0, y: 3, terrain: "mountain", passable: false, terrainSprite: `${
|
|
47049
|
-
{ x: 1, y: 3, terrain: "grass", passable: true, terrainSprite: `${
|
|
47050
|
-
{ x: 2, y: 3, terrain: "grass", passable: true, terrainSprite: `${
|
|
47051
|
-
{ x: 3, y: 3, terrain: "grass", passable: true, terrainSprite: `${
|
|
47052
|
-
{ x: 4, y: 3, terrain: "mountain", passable: false, terrainSprite: `${
|
|
47053
|
-
{ x: 0, y: 4, terrain: "mountain", passable: false, terrainSprite: `${
|
|
47054
|
-
{ x: 1, y: 4, terrain: "water", passable: false, terrainSprite: `${
|
|
47055
|
-
{ x: 2, y: 4, terrain: "grass", passable: true, terrainSprite: `${
|
|
47056
|
-
{ x: 3, y: 4, terrain: "mountain", passable: false, terrainSprite: `${
|
|
47057
|
-
{ x: 4, y: 4, terrain: "mountain", passable: false, terrainSprite: `${
|
|
49551
|
+
{ x: 0, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
|
|
49552
|
+
{ x: 1, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
|
|
49553
|
+
{ x: 2, y: 0, terrain: "water", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
|
|
49554
|
+
{ x: 3, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
|
|
49555
|
+
{ x: 4, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
|
|
49556
|
+
{ x: 0, y: 1, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
|
|
49557
|
+
{ x: 1, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
|
|
49558
|
+
{ x: 2, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
|
|
49559
|
+
{ x: 3, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
|
|
49560
|
+
{ x: 4, y: 1, terrain: "water", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
|
|
49561
|
+
{ x: 0, y: 2, terrain: "water", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
|
|
49562
|
+
{ x: 1, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
|
|
49563
|
+
{ x: 2, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_03.png` },
|
|
49564
|
+
{ x: 3, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
|
|
49565
|
+
{ x: 4, y: 2, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
|
|
49566
|
+
{ x: 0, y: 3, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
|
|
49567
|
+
{ x: 1, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
|
|
49568
|
+
{ x: 2, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
|
|
49569
|
+
{ x: 3, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_03.png` },
|
|
49570
|
+
{ x: 4, y: 3, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
|
|
49571
|
+
{ x: 0, y: 4, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
|
|
49572
|
+
{ x: 1, y: 4, terrain: "water", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
|
|
49573
|
+
{ x: 2, y: 4, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
|
|
49574
|
+
{ x: 3, y: 4, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
|
|
49575
|
+
{ x: 4, y: 4, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` }
|
|
47058
49576
|
];
|
|
47059
49577
|
DEFAULT_WORLDMAP_UNITS = [
|
|
47060
|
-
{ id: "h1", position: { x: 1, y: 1 }, unitType: "hero", name: "Amir", team: "player", health: 10, maxHealth: 10, sprite: `${
|
|
47061
|
-
{ id: "h2", position: { x: 3, y: 3 }, unitType: "scout", name: "Archivist", team: "player", health: 10, maxHealth: 10, sprite: `${
|
|
49578
|
+
{ 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` },
|
|
49579
|
+
{ 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` }
|
|
47062
49580
|
];
|
|
47063
49581
|
DEFAULT_WORLDMAP_FEATURES = [
|
|
47064
|
-
{ id: "f1", x: 2, y: 2, type: "capital", sprite: `${
|
|
47065
|
-
{ id: "f2", x: 4, y: 2, type: "power_node", sprite: `${
|
|
49582
|
+
{ id: "f1", x: 2, y: 2, type: "capital", sprite: `${CDN7}/scenes/world/capital.png` },
|
|
49583
|
+
{ id: "f2", x: 4, y: 2, type: "power_node", sprite: `${CDN7}/world-map/power_node.png` }
|
|
47066
49584
|
];
|
|
47067
49585
|
DEFAULT_WORLDMAP_MANIFEST = {
|
|
47068
|
-
baseUrl:
|
|
49586
|
+
baseUrl: CDN7,
|
|
47069
49587
|
terrains: {
|
|
47070
49588
|
grass: "/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png",
|
|
47071
49589
|
water: "/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png",
|
|
@@ -47110,7 +49628,7 @@ function lazyThree(name, loader) {
|
|
|
47110
49628
|
ThreeWrapper.displayName = `Lazy(${name})`;
|
|
47111
49629
|
return ThreeWrapper;
|
|
47112
49630
|
}
|
|
47113
|
-
var ThreeBoundary, FeatureRenderer,
|
|
49631
|
+
var ThreeBoundary, FeatureRenderer, GameCanvas3D2, GameCanvas3DBattleTemplate, GameCanvas3DCastleTemplate, GameCanvas3DWorldMapTemplate, COMPONENT_REGISTRY;
|
|
47114
49632
|
var init_component_registry_generated = __esm({
|
|
47115
49633
|
"components/core/organisms/component-registry.generated.ts"() {
|
|
47116
49634
|
init_AboutPageTemplate();
|
|
@@ -47220,6 +49738,7 @@ var init_component_registry_generated = __esm({
|
|
|
47220
49738
|
init_FormSectionHeader();
|
|
47221
49739
|
init_GameAudioProvider();
|
|
47222
49740
|
init_GameAudioToggle();
|
|
49741
|
+
init_GameBoard3D();
|
|
47223
49742
|
init_GameCanvas2D();
|
|
47224
49743
|
init_GameHud();
|
|
47225
49744
|
init_GameMenu();
|
|
@@ -47277,7 +49796,9 @@ var init_component_registry_generated = __esm({
|
|
|
47277
49796
|
init_PageHeader();
|
|
47278
49797
|
init_Pagination();
|
|
47279
49798
|
init_PatternTile();
|
|
49799
|
+
init_PlatformerBoard();
|
|
47280
49800
|
init_PlatformerCanvas();
|
|
49801
|
+
init_PlatformerTemplate();
|
|
47281
49802
|
init_Popover();
|
|
47282
49803
|
init_PositionedCanvas();
|
|
47283
49804
|
init_PowerupSlots();
|
|
@@ -47301,6 +49822,8 @@ var init_component_registry_generated = __esm({
|
|
|
47301
49822
|
init_ResourceBar();
|
|
47302
49823
|
init_ResourceCounter();
|
|
47303
49824
|
init_RichBlockEditor();
|
|
49825
|
+
init_RoguelikeBoard();
|
|
49826
|
+
init_RoguelikeTemplate();
|
|
47304
49827
|
init_RuntimeDebugger2();
|
|
47305
49828
|
init_ScaledDiagram();
|
|
47306
49829
|
init_ScoreBoard();
|
|
@@ -47373,6 +49896,8 @@ var init_component_registry_generated = __esm({
|
|
|
47373
49896
|
init_Toast();
|
|
47374
49897
|
init_ToastSlot();
|
|
47375
49898
|
init_Tooltip();
|
|
49899
|
+
init_TowerDefenseBoard();
|
|
49900
|
+
init_TowerDefenseTemplate();
|
|
47376
49901
|
init_TraitFrame();
|
|
47377
49902
|
init_TraitSlot();
|
|
47378
49903
|
init_TrendIndicator();
|
|
@@ -47417,7 +49942,7 @@ var init_component_registry_generated = __esm({
|
|
|
47417
49942
|
}
|
|
47418
49943
|
};
|
|
47419
49944
|
FeatureRenderer = lazyThree("FeatureRenderer", () => import('@almadar/ui/components/molecules/game/three'));
|
|
47420
|
-
|
|
49945
|
+
GameCanvas3D2 = lazyThree("GameCanvas3D", () => import('@almadar/ui/components/molecules/game/three'));
|
|
47421
49946
|
GameCanvas3DBattleTemplate = lazyThree("GameCanvas3DBattleTemplate", () => import('@almadar/ui/components/molecules/game/three'));
|
|
47422
49947
|
GameCanvas3DCastleTemplate = lazyThree("GameCanvas3DCastleTemplate", () => import('@almadar/ui/components/molecules/game/three'));
|
|
47423
49948
|
GameCanvas3DWorldMapTemplate = lazyThree("GameCanvas3DWorldMapTemplate", () => import('@almadar/ui/components/molecules/game/three'));
|
|
@@ -47536,8 +50061,9 @@ var init_component_registry_generated = __esm({
|
|
|
47536
50061
|
"FormSectionHeader": FormSectionHeader,
|
|
47537
50062
|
"GameAudioProvider": GameAudioProvider,
|
|
47538
50063
|
"GameAudioToggle": GameAudioToggle,
|
|
50064
|
+
"GameBoard3D": GameBoard3D,
|
|
47539
50065
|
"GameCanvas2D": GameCanvas2D,
|
|
47540
|
-
"GameCanvas3D":
|
|
50066
|
+
"GameCanvas3D": GameCanvas3D2,
|
|
47541
50067
|
"GameCanvas3DBattleTemplate": GameCanvas3DBattleTemplate,
|
|
47542
50068
|
"GameCanvas3DCastleTemplate": GameCanvas3DCastleTemplate,
|
|
47543
50069
|
"GameCanvas3DWorldMapTemplate": GameCanvas3DWorldMapTemplate,
|
|
@@ -47599,7 +50125,9 @@ var init_component_registry_generated = __esm({
|
|
|
47599
50125
|
"PageHeader": PageHeader,
|
|
47600
50126
|
"Pagination": Pagination,
|
|
47601
50127
|
"PatternTile": PatternTile,
|
|
50128
|
+
"PlatformerBoard": PlatformerBoard,
|
|
47602
50129
|
"PlatformerCanvas": PlatformerCanvas,
|
|
50130
|
+
"PlatformerTemplate": PlatformerTemplate,
|
|
47603
50131
|
"Popover": Popover,
|
|
47604
50132
|
"PositionedCanvas": PositionedCanvas,
|
|
47605
50133
|
"PowerupSlots": PowerupSlots,
|
|
@@ -47623,6 +50151,8 @@ var init_component_registry_generated = __esm({
|
|
|
47623
50151
|
"ResourceBar": ResourceBar,
|
|
47624
50152
|
"ResourceCounter": ResourceCounter,
|
|
47625
50153
|
"RichBlockEditor": RichBlockEditor,
|
|
50154
|
+
"RoguelikeBoard": RoguelikeBoard,
|
|
50155
|
+
"RoguelikeTemplate": RoguelikeTemplate,
|
|
47626
50156
|
"RuntimeDebugger": RuntimeDebugger,
|
|
47627
50157
|
"ScaledDiagram": ScaledDiagram,
|
|
47628
50158
|
"ScoreBoard": ScoreBoard,
|
|
@@ -47698,6 +50228,8 @@ var init_component_registry_generated = __esm({
|
|
|
47698
50228
|
"Toast": Toast,
|
|
47699
50229
|
"ToastSlot": ToastSlot,
|
|
47700
50230
|
"Tooltip": Tooltip,
|
|
50231
|
+
"TowerDefenseBoard": TowerDefenseBoard,
|
|
50232
|
+
"TowerDefenseTemplate": TowerDefenseTemplate,
|
|
47701
50233
|
"TraitFrame": TraitFrame,
|
|
47702
50234
|
"TraitSlot": TraitSlot,
|
|
47703
50235
|
"TrendIndicator": TrendIndicator,
|
|
@@ -49594,7 +52126,7 @@ function clearSchemaCache() {
|
|
|
49594
52126
|
|
|
49595
52127
|
// runtime/index.ts
|
|
49596
52128
|
init_EntitySchemaContext();
|
|
49597
|
-
var
|
|
52129
|
+
var log12 = createLogger("almadar:ui:trait-provider");
|
|
49598
52130
|
var TraitContext = createContext(null);
|
|
49599
52131
|
function TraitProvider({
|
|
49600
52132
|
traits: traitBindings,
|
|
@@ -49611,7 +52143,7 @@ function TraitProvider({
|
|
|
49611
52143
|
currentState: stateName,
|
|
49612
52144
|
availableEvents: trait.transitions.filter((t) => t.from === stateName).map((t) => t.event),
|
|
49613
52145
|
dispatch: (eventKey, payload) => {
|
|
49614
|
-
|
|
52146
|
+
log12.debug("Dispatch", () => ({
|
|
49615
52147
|
trait: trait.name,
|
|
49616
52148
|
event: eventKey,
|
|
49617
52149
|
payloadKeys: payload ? Object.keys(payload) : []
|
|
@@ -50195,7 +52727,7 @@ OrbitalThemeProvider.displayName = "OrbitalThemeProvider";
|
|
|
50195
52727
|
init_navigation();
|
|
50196
52728
|
init_verificationRegistry();
|
|
50197
52729
|
var PERF_NAMESPACE = "almadar:perf:canvas";
|
|
50198
|
-
var
|
|
52730
|
+
var log13 = createLogger(PERF_NAMESPACE);
|
|
50199
52731
|
var RING_SIZE = 50;
|
|
50200
52732
|
var ring = [];
|
|
50201
52733
|
var writeIdx = 0;
|
|
@@ -50250,7 +52782,7 @@ function perfEnd(name, startToken, detail) {
|
|
|
50250
52782
|
}
|
|
50251
52783
|
}
|
|
50252
52784
|
push({ name, durationMs, ts: endTs, detail });
|
|
50253
|
-
|
|
52785
|
+
log13.debug(name, () => ({ durationMs, ...detail ?? {} }));
|
|
50254
52786
|
}
|
|
50255
52787
|
function perfTime(name, fn, detail) {
|
|
50256
52788
|
const t = perfStart(name);
|
|
@@ -50268,7 +52800,7 @@ var profilerOnRender = (id, phase, actualDuration, baseDuration, _startTime, com
|
|
|
50268
52800
|
ts: commitTime,
|
|
50269
52801
|
detail: { baseDuration }
|
|
50270
52802
|
});
|
|
50271
|
-
|
|
52803
|
+
log13.debug(`profiler:${id}:${phase}`, () => ({ actualDuration, baseDuration }));
|
|
50272
52804
|
};
|
|
50273
52805
|
function getPerfSnapshot() {
|
|
50274
52806
|
if (ring.length < RING_SIZE) return ring.slice();
|