@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/avl/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
2
2
|
import * as React91 from 'react';
|
|
3
|
-
import React91__default, { createContext, useState, useMemo, useRef, useEffect, useContext, useCallback, Suspense, useLayoutEffect, Profiler, useReducer, useSyncExternalStore, lazy, useId } from 'react';
|
|
3
|
+
import React91__default, { createContext, useState, useMemo, useRef, useEffect, useContext, useCallback, Suspense, useLayoutEffect, Profiler, useReducer, useSyncExternalStore, lazy, useId, forwardRef, useImperativeHandle, Component } from 'react';
|
|
4
4
|
import { OrbitalProvider, EventBusContext, useTraitScope, VerificationProvider, TraitScopeProvider } from '@almadar/ui/providers';
|
|
5
5
|
import { createLogger, isLogLevelEnabled } from '@almadar/logger';
|
|
6
6
|
import ELK from 'elkjs/lib/elk.bundled.js';
|
|
@@ -39,6 +39,12 @@ import { FieldTypeSchema, isInlineTrait, isPageReference, isEntityCall, schemaTo
|
|
|
39
39
|
import { useDroppable, useDraggable, DndContext, DragOverlay, useSensors, useSensor, PointerSensor, KeyboardSensor, pointerWithin, rectIntersection, closestCorners } from '@dnd-kit/core';
|
|
40
40
|
import { sortableKeyboardCoordinates, useSortable, arrayMove, SortableContext, rectSortingStrategy, verticalListSortingStrategy } from '@dnd-kit/sortable';
|
|
41
41
|
import { CSS } from '@dnd-kit/utilities';
|
|
42
|
+
import * as THREE from 'three';
|
|
43
|
+
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
|
|
44
|
+
import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader.js';
|
|
45
|
+
import { GLTFLoader as GLTFLoader$1 } from 'three/examples/jsm/loaders/GLTFLoader';
|
|
46
|
+
import { Canvas, useThree } from '@react-three/fiber';
|
|
47
|
+
import { Grid as Grid$1, OrbitControls } from '@react-three/drei';
|
|
42
48
|
import { getPatternDefinition, getComponentForPattern as getComponentForPattern$1, isEntityAwarePattern } from '@almadar/patterns';
|
|
43
49
|
import { OrbitalServerRuntime } from '@almadar/runtime/OrbitalServerRuntime';
|
|
44
50
|
import { InMemoryPersistence, StateMachineManager, createContextFromBindings, interpolateValue, collectDeclaredConfigDefaults, createServerEffectHandlers, EffectExecutor } from '@almadar/runtime';
|
|
@@ -3173,8 +3179,8 @@ var init_Typography = __esm({
|
|
|
3173
3179
|
children
|
|
3174
3180
|
}) => {
|
|
3175
3181
|
const variant = variantProp ?? (level ? `h${level}` : "body1");
|
|
3176
|
-
const
|
|
3177
|
-
const Comp =
|
|
3182
|
+
const Component2 = as || defaultElements[variant];
|
|
3183
|
+
const Comp = Component2;
|
|
3178
3184
|
return /* @__PURE__ */ jsx(
|
|
3179
3185
|
Comp,
|
|
3180
3186
|
{
|
|
@@ -3483,7 +3489,7 @@ var init_Box = __esm({
|
|
|
3483
3489
|
position,
|
|
3484
3490
|
className,
|
|
3485
3491
|
children,
|
|
3486
|
-
as:
|
|
3492
|
+
as: Component2 = "div",
|
|
3487
3493
|
action,
|
|
3488
3494
|
actionPayload,
|
|
3489
3495
|
hoverEvent,
|
|
@@ -3515,7 +3521,7 @@ var init_Box = __esm({
|
|
|
3515
3521
|
}, [hoverEvent, eventBus, onMouseLeave]);
|
|
3516
3522
|
const isClickable = action || onClick;
|
|
3517
3523
|
return React91__default.createElement(
|
|
3518
|
-
|
|
3524
|
+
Component2,
|
|
3519
3525
|
{
|
|
3520
3526
|
ref,
|
|
3521
3527
|
className: cn(
|
|
@@ -3591,7 +3597,7 @@ var init_Stack = __esm({
|
|
|
3591
3597
|
className,
|
|
3592
3598
|
style,
|
|
3593
3599
|
children,
|
|
3594
|
-
as:
|
|
3600
|
+
as: Component2 = "div",
|
|
3595
3601
|
onClick,
|
|
3596
3602
|
onKeyDown,
|
|
3597
3603
|
role,
|
|
@@ -3609,7 +3615,7 @@ var init_Stack = __esm({
|
|
|
3609
3615
|
};
|
|
3610
3616
|
const isHorizontal = direction === "horizontal";
|
|
3611
3617
|
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";
|
|
3612
|
-
const Comp =
|
|
3618
|
+
const Comp = Component2;
|
|
3613
3619
|
return /* @__PURE__ */ jsx(
|
|
3614
3620
|
Comp,
|
|
3615
3621
|
{
|
|
@@ -4523,9 +4529,9 @@ function resolvePhosphor(name, weight, family) {
|
|
|
4523
4529
|
(lib) => {
|
|
4524
4530
|
const PhosphorComp = lib[target];
|
|
4525
4531
|
if (!PhosphorComp || typeof PhosphorComp !== "object") return null;
|
|
4526
|
-
const
|
|
4532
|
+
const Component2 = PhosphorComp;
|
|
4527
4533
|
const Adapter = (props) => /* @__PURE__ */ jsx(
|
|
4528
|
-
|
|
4534
|
+
Component2,
|
|
4529
4535
|
{
|
|
4530
4536
|
weight,
|
|
4531
4537
|
className: props.className,
|
|
@@ -4549,9 +4555,9 @@ function resolveTabler(name, family) {
|
|
|
4549
4555
|
(lib) => {
|
|
4550
4556
|
const TablerComp = lib[target];
|
|
4551
4557
|
if (!TablerComp || typeof TablerComp !== "object") return null;
|
|
4552
|
-
const
|
|
4558
|
+
const Component2 = TablerComp;
|
|
4553
4559
|
const Adapter = (props) => /* @__PURE__ */ jsx(
|
|
4554
|
-
|
|
4560
|
+
Component2,
|
|
4555
4561
|
{
|
|
4556
4562
|
stroke: props.strokeWidth ?? 1.5,
|
|
4557
4563
|
className: props.className,
|
|
@@ -4575,9 +4581,9 @@ function resolveFa(name, family) {
|
|
|
4575
4581
|
(lib) => {
|
|
4576
4582
|
const FaComp = lib[target];
|
|
4577
4583
|
if (!FaComp || typeof FaComp !== "function") return null;
|
|
4578
|
-
const
|
|
4584
|
+
const Component2 = FaComp;
|
|
4579
4585
|
const Adapter = (props) => /* @__PURE__ */ jsx(
|
|
4580
|
-
|
|
4586
|
+
Component2,
|
|
4581
4587
|
{
|
|
4582
4588
|
className: props.className,
|
|
4583
4589
|
style: props.style,
|
|
@@ -7969,10 +7975,10 @@ var init_Center = __esm({
|
|
|
7969
7975
|
className,
|
|
7970
7976
|
style,
|
|
7971
7977
|
children,
|
|
7972
|
-
as:
|
|
7978
|
+
as: Component2 = "div"
|
|
7973
7979
|
}) => {
|
|
7974
7980
|
const mergedStyle = minHeight ? { minHeight, ...style } : style;
|
|
7975
|
-
const Comp =
|
|
7981
|
+
const Comp = Component2;
|
|
7976
7982
|
return /* @__PURE__ */ jsx(
|
|
7977
7983
|
Comp,
|
|
7978
7984
|
{
|
|
@@ -10766,6 +10772,7 @@ var init_HealthBar = __esm({
|
|
|
10766
10772
|
}
|
|
10767
10773
|
});
|
|
10768
10774
|
function ScoreDisplay({
|
|
10775
|
+
assetUrl = DEFAULT_ASSET_URL,
|
|
10769
10776
|
value,
|
|
10770
10777
|
label,
|
|
10771
10778
|
icon,
|
|
@@ -10812,14 +10819,24 @@ function ScoreDisplay({
|
|
|
10812
10819
|
className
|
|
10813
10820
|
),
|
|
10814
10821
|
children: [
|
|
10815
|
-
|
|
10822
|
+
assetUrl ? /* @__PURE__ */ jsx(
|
|
10823
|
+
"img",
|
|
10824
|
+
{
|
|
10825
|
+
src: assetUrl,
|
|
10826
|
+
alt: "",
|
|
10827
|
+
width: 20,
|
|
10828
|
+
height: 20,
|
|
10829
|
+
style: { imageRendering: "pixelated", objectFit: "contain" },
|
|
10830
|
+
className: "flex-shrink-0"
|
|
10831
|
+
}
|
|
10832
|
+
) : icon ? /* @__PURE__ */ jsx("span", { className: "flex-shrink-0", children: typeof icon === "string" ? /* @__PURE__ */ jsx(Icon, { name: icon }) : /* @__PURE__ */ jsx(Icon, { icon }) }) : null,
|
|
10816
10833
|
label && /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: label }),
|
|
10817
10834
|
/* @__PURE__ */ jsx("span", { className: "tabular-nums", children: formattedValue })
|
|
10818
10835
|
]
|
|
10819
10836
|
}
|
|
10820
10837
|
);
|
|
10821
10838
|
}
|
|
10822
|
-
var sizeMap2;
|
|
10839
|
+
var sizeMap2, DEFAULT_ASSET_URL;
|
|
10823
10840
|
var init_ScoreDisplay = __esm({
|
|
10824
10841
|
"components/game/atoms/ScoreDisplay.tsx"() {
|
|
10825
10842
|
"use client";
|
|
@@ -10831,10 +10848,12 @@ var init_ScoreDisplay = __esm({
|
|
|
10831
10848
|
lg: "text-2xl",
|
|
10832
10849
|
xl: "text-4xl"
|
|
10833
10850
|
};
|
|
10851
|
+
DEFAULT_ASSET_URL = "https://almadar-kflow-assets.web.app/shared/effects/particles/star_01.png";
|
|
10834
10852
|
ScoreDisplay.displayName = "ScoreDisplay";
|
|
10835
10853
|
}
|
|
10836
10854
|
});
|
|
10837
10855
|
function ControlButton({
|
|
10856
|
+
assetUrl = DEFAULT_ASSET_URL2,
|
|
10838
10857
|
label,
|
|
10839
10858
|
icon,
|
|
10840
10859
|
size = "md",
|
|
@@ -10881,7 +10900,7 @@ function ControlButton({
|
|
|
10881
10900
|
},
|
|
10882
10901
|
[isPressed, releaseEvent, eventBus, onRelease]
|
|
10883
10902
|
);
|
|
10884
|
-
return /* @__PURE__ */
|
|
10903
|
+
return /* @__PURE__ */ jsx(
|
|
10885
10904
|
"button",
|
|
10886
10905
|
{
|
|
10887
10906
|
type: "button",
|
|
@@ -10902,20 +10921,27 @@ function ControlButton({
|
|
|
10902
10921
|
disabled && "opacity-50 cursor-not-allowed",
|
|
10903
10922
|
className
|
|
10904
10923
|
),
|
|
10905
|
-
children:
|
|
10906
|
-
|
|
10907
|
-
|
|
10908
|
-
|
|
10909
|
-
|
|
10910
|
-
|
|
10911
|
-
|
|
10912
|
-
|
|
10913
|
-
|
|
10914
|
-
|
|
10924
|
+
children: assetUrl ? /* @__PURE__ */ jsx(
|
|
10925
|
+
"img",
|
|
10926
|
+
{
|
|
10927
|
+
src: assetUrl,
|
|
10928
|
+
alt: "",
|
|
10929
|
+
width: 24,
|
|
10930
|
+
height: 24,
|
|
10931
|
+
style: { imageRendering: "pixelated", objectFit: "contain" },
|
|
10932
|
+
className: "flex-shrink-0"
|
|
10933
|
+
}
|
|
10934
|
+
) : icon ? /* @__PURE__ */ jsx("span", { className: "text-2xl", children: typeof icon === "string" ? /^[a-zA-Z0-9-]+$/.test(icon) ? (() => {
|
|
10935
|
+
const I = resolveIcon(icon);
|
|
10936
|
+
return I ? /* @__PURE__ */ jsx(I, { className: "w-6 h-6" }) : null;
|
|
10937
|
+
})() : icon : /* @__PURE__ */ (() => {
|
|
10938
|
+
const I = icon;
|
|
10939
|
+
return /* @__PURE__ */ jsx(I, { className: "w-6 h-6" });
|
|
10940
|
+
})() }) : label ? /* @__PURE__ */ jsx("span", { children: label }) : null
|
|
10915
10941
|
}
|
|
10916
10942
|
);
|
|
10917
10943
|
}
|
|
10918
|
-
var sizeMap3, shapeMap, variantMap;
|
|
10944
|
+
var sizeMap3, shapeMap, variantMap, DEFAULT_ASSET_URL2;
|
|
10919
10945
|
var init_ControlButton = __esm({
|
|
10920
10946
|
"components/game/atoms/ControlButton.tsx"() {
|
|
10921
10947
|
"use client";
|
|
@@ -10938,6 +10964,7 @@ var init_ControlButton = __esm({
|
|
|
10938
10964
|
secondary: "bg-secondary text-secondary-foreground border-border hover:bg-secondary-hover",
|
|
10939
10965
|
ghost: "bg-transparent text-foreground border-border hover:bg-muted"
|
|
10940
10966
|
};
|
|
10967
|
+
DEFAULT_ASSET_URL2 = "https://almadar-kflow-assets.web.app/shared/effects/particles/circle_01.png";
|
|
10941
10968
|
ControlButton.displayName = "ControlButton";
|
|
10942
10969
|
}
|
|
10943
10970
|
});
|
|
@@ -11017,7 +11044,7 @@ var init_Sprite = __esm({
|
|
|
11017
11044
|
}
|
|
11018
11045
|
});
|
|
11019
11046
|
function StateIndicator({
|
|
11020
|
-
assetUrl =
|
|
11047
|
+
assetUrl = DEFAULT_ASSET_URL3,
|
|
11021
11048
|
state = "idle",
|
|
11022
11049
|
label,
|
|
11023
11050
|
size = "md",
|
|
@@ -11056,13 +11083,13 @@ function StateIndicator({
|
|
|
11056
11083
|
}
|
|
11057
11084
|
);
|
|
11058
11085
|
}
|
|
11059
|
-
var
|
|
11086
|
+
var DEFAULT_ASSET_URL3, DEFAULT_STATE_STYLES, DEFAULT_STYLE, SIZE_CLASSES;
|
|
11060
11087
|
var init_StateIndicator = __esm({
|
|
11061
11088
|
"components/game/atoms/StateIndicator.tsx"() {
|
|
11062
11089
|
init_Box();
|
|
11063
11090
|
init_Icon();
|
|
11064
11091
|
init_cn();
|
|
11065
|
-
|
|
11092
|
+
DEFAULT_ASSET_URL3 = "https://almadar-kflow-assets.web.app/shared/isometric-dungeon/Isometric/chestClosed_E.png";
|
|
11066
11093
|
DEFAULT_STATE_STYLES = {
|
|
11067
11094
|
idle: { icon: "\u23F8", bgClass: "bg-muted" },
|
|
11068
11095
|
active: { icon: "\u25B6", bgClass: "bg-success" },
|
|
@@ -11137,7 +11164,7 @@ var init_TimerDisplay = __esm({
|
|
|
11137
11164
|
}
|
|
11138
11165
|
});
|
|
11139
11166
|
function ResourceCounter({
|
|
11140
|
-
assetUrl =
|
|
11167
|
+
assetUrl = DEFAULT_ASSET_URL4,
|
|
11141
11168
|
icon,
|
|
11142
11169
|
label = "Gold",
|
|
11143
11170
|
value = 250,
|
|
@@ -11180,7 +11207,7 @@ function ResourceCounter({
|
|
|
11180
11207
|
}
|
|
11181
11208
|
);
|
|
11182
11209
|
}
|
|
11183
|
-
var colorTokenClasses2,
|
|
11210
|
+
var colorTokenClasses2, DEFAULT_ASSET_URL4, sizeMap5;
|
|
11184
11211
|
var init_ResourceCounter = __esm({
|
|
11185
11212
|
"components/game/atoms/ResourceCounter.tsx"() {
|
|
11186
11213
|
init_cn();
|
|
@@ -11193,7 +11220,7 @@ var init_ResourceCounter = __esm({
|
|
|
11193
11220
|
error: "text-error",
|
|
11194
11221
|
muted: "text-muted-foreground"
|
|
11195
11222
|
};
|
|
11196
|
-
|
|
11223
|
+
DEFAULT_ASSET_URL4 = "https://almadar-kflow-assets.web.app/shared/world-map/gold_mine.png";
|
|
11197
11224
|
sizeMap5 = {
|
|
11198
11225
|
sm: { wrapper: "text-xs gap-1 px-1.5 py-0.5", icon: "text-sm", img: 16 },
|
|
11199
11226
|
md: { wrapper: "text-sm gap-1.5 px-2 py-1", icon: "text-base", img: 20 },
|
|
@@ -11203,7 +11230,7 @@ var init_ResourceCounter = __esm({
|
|
|
11203
11230
|
}
|
|
11204
11231
|
});
|
|
11205
11232
|
function ItemSlot({
|
|
11206
|
-
assetUrl =
|
|
11233
|
+
assetUrl = DEFAULT_ASSET_URL5,
|
|
11207
11234
|
icon = "sword",
|
|
11208
11235
|
label = "Iron Sword",
|
|
11209
11236
|
quantity,
|
|
@@ -11262,7 +11289,7 @@ function ItemSlot({
|
|
|
11262
11289
|
}
|
|
11263
11290
|
);
|
|
11264
11291
|
}
|
|
11265
|
-
var sizeMap6, rarityBorderMap, rarityGlowMap,
|
|
11292
|
+
var sizeMap6, rarityBorderMap, rarityGlowMap, DEFAULT_ASSET_URL5, assetSizeMap;
|
|
11266
11293
|
var init_ItemSlot = __esm({
|
|
11267
11294
|
"components/game/atoms/ItemSlot.tsx"() {
|
|
11268
11295
|
"use client";
|
|
@@ -11287,7 +11314,7 @@ var init_ItemSlot = __esm({
|
|
|
11287
11314
|
epic: "shadow-lg",
|
|
11288
11315
|
legendary: "shadow-lg"
|
|
11289
11316
|
};
|
|
11290
|
-
|
|
11317
|
+
DEFAULT_ASSET_URL5 = "https://almadar-kflow-assets.web.app/shared/isometric-dungeon/Isometric/chestClosed_E.png";
|
|
11291
11318
|
assetSizeMap = {
|
|
11292
11319
|
sm: 28,
|
|
11293
11320
|
md: 40,
|
|
@@ -11297,6 +11324,7 @@ var init_ItemSlot = __esm({
|
|
|
11297
11324
|
}
|
|
11298
11325
|
});
|
|
11299
11326
|
function TurnIndicator({
|
|
11327
|
+
assetUrl = DEFAULT_ASSET_URL6,
|
|
11300
11328
|
currentTurn = 1,
|
|
11301
11329
|
maxTurns,
|
|
11302
11330
|
activeTeam,
|
|
@@ -11329,14 +11357,24 @@ function TurnIndicator({
|
|
|
11329
11357
|
] }),
|
|
11330
11358
|
activeTeam && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
11331
11359
|
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "|" }),
|
|
11332
|
-
/* @__PURE__ */ jsx(
|
|
11360
|
+
assetUrl ? /* @__PURE__ */ jsx(
|
|
11361
|
+
"img",
|
|
11362
|
+
{
|
|
11363
|
+
src: assetUrl,
|
|
11364
|
+
alt: "",
|
|
11365
|
+
width: 12,
|
|
11366
|
+
height: 12,
|
|
11367
|
+
style: { imageRendering: "pixelated", objectFit: "contain" },
|
|
11368
|
+
className: "flex-shrink-0"
|
|
11369
|
+
}
|
|
11370
|
+
) : /* @__PURE__ */ jsx("span", { className: cn("rounded-full bg-success/20", sizes.dot) }),
|
|
11333
11371
|
/* @__PURE__ */ jsx("span", { className: "text-success", children: activeTeam })
|
|
11334
11372
|
] })
|
|
11335
11373
|
]
|
|
11336
11374
|
}
|
|
11337
11375
|
);
|
|
11338
11376
|
}
|
|
11339
|
-
var sizeMap7;
|
|
11377
|
+
var sizeMap7, DEFAULT_ASSET_URL6;
|
|
11340
11378
|
var init_TurnIndicator = __esm({
|
|
11341
11379
|
"components/game/atoms/TurnIndicator.tsx"() {
|
|
11342
11380
|
init_cn();
|
|
@@ -11345,6 +11383,7 @@ var init_TurnIndicator = __esm({
|
|
|
11345
11383
|
md: { wrapper: "text-sm gap-2 px-3 py-1", dot: "w-2 h-2" },
|
|
11346
11384
|
lg: { wrapper: "text-base gap-2.5 px-4 py-1.5", dot: "w-2.5 h-2.5" }
|
|
11347
11385
|
};
|
|
11386
|
+
DEFAULT_ASSET_URL6 = "https://almadar-kflow-assets.web.app/shared/effects/particles/symbol_01.png";
|
|
11348
11387
|
TurnIndicator.displayName = "TurnIndicator";
|
|
11349
11388
|
}
|
|
11350
11389
|
});
|
|
@@ -11360,7 +11399,7 @@ function getComboScale(combo) {
|
|
|
11360
11399
|
return "";
|
|
11361
11400
|
}
|
|
11362
11401
|
function ComboCounter({
|
|
11363
|
-
assetUrl =
|
|
11402
|
+
assetUrl = DEFAULT_ASSET_URL7,
|
|
11364
11403
|
combo = 5,
|
|
11365
11404
|
multiplier,
|
|
11366
11405
|
streak,
|
|
@@ -11405,11 +11444,11 @@ function ComboCounter({
|
|
|
11405
11444
|
}
|
|
11406
11445
|
);
|
|
11407
11446
|
}
|
|
11408
|
-
var
|
|
11447
|
+
var DEFAULT_ASSET_URL7, sizeMap8;
|
|
11409
11448
|
var init_ComboCounter = __esm({
|
|
11410
11449
|
"components/game/atoms/ComboCounter.tsx"() {
|
|
11411
11450
|
init_cn();
|
|
11412
|
-
|
|
11451
|
+
DEFAULT_ASSET_URL7 = "https://almadar-kflow-assets.web.app/shared/effects/flash/flash00.png";
|
|
11413
11452
|
sizeMap8 = {
|
|
11414
11453
|
sm: { combo: "text-lg", label: "text-xs", multiplier: "text-xs" },
|
|
11415
11454
|
md: { combo: "text-2xl", label: "text-xs", multiplier: "text-sm" },
|
|
@@ -11503,7 +11542,7 @@ var init_XPBar = __esm({
|
|
|
11503
11542
|
}
|
|
11504
11543
|
});
|
|
11505
11544
|
function WaypointMarker({
|
|
11506
|
-
assetUrl =
|
|
11545
|
+
assetUrl = DEFAULT_ASSET_URL8,
|
|
11507
11546
|
label,
|
|
11508
11547
|
icon,
|
|
11509
11548
|
active = true,
|
|
@@ -11569,12 +11608,12 @@ function WaypointMarker({
|
|
|
11569
11608
|
)
|
|
11570
11609
|
] });
|
|
11571
11610
|
}
|
|
11572
|
-
var
|
|
11611
|
+
var DEFAULT_ASSET_URL8, sizeMap10, checkIcon;
|
|
11573
11612
|
var init_WaypointMarker = __esm({
|
|
11574
11613
|
"components/game/atoms/WaypointMarker.tsx"() {
|
|
11575
11614
|
init_cn();
|
|
11576
11615
|
init_Icon();
|
|
11577
|
-
|
|
11616
|
+
DEFAULT_ASSET_URL8 = "https://almadar-kflow-assets.web.app/shared/world-map/battle_marker.png";
|
|
11578
11617
|
sizeMap10 = {
|
|
11579
11618
|
sm: { dot: "w-4 h-4", ring: "w-6 h-6", label: "text-xs mt-1", img: 12 },
|
|
11580
11619
|
md: { dot: "w-6 h-6", ring: "w-8 h-8", label: "text-sm mt-1.5", img: 18 },
|
|
@@ -11591,7 +11630,7 @@ function formatDuration(seconds) {
|
|
|
11591
11630
|
return `${Math.round(seconds)}s`;
|
|
11592
11631
|
}
|
|
11593
11632
|
function StatusEffect({
|
|
11594
|
-
assetUrl =
|
|
11633
|
+
assetUrl = DEFAULT_ASSET_URL9,
|
|
11595
11634
|
icon = "shield",
|
|
11596
11635
|
label = "Shield",
|
|
11597
11636
|
duration = 30,
|
|
@@ -11649,12 +11688,12 @@ function StatusEffect({
|
|
|
11649
11688
|
label && /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground mt-0.5 text-center whitespace-nowrap", children: label })
|
|
11650
11689
|
] });
|
|
11651
11690
|
}
|
|
11652
|
-
var
|
|
11691
|
+
var DEFAULT_ASSET_URL9, sizeMap11, variantStyles7;
|
|
11653
11692
|
var init_StatusEffect = __esm({
|
|
11654
11693
|
"components/game/atoms/StatusEffect.tsx"() {
|
|
11655
11694
|
init_cn();
|
|
11656
11695
|
init_Icon();
|
|
11657
|
-
|
|
11696
|
+
DEFAULT_ASSET_URL9 = "https://almadar-kflow-assets.web.app/shared/effects/particles/flame_01.png";
|
|
11658
11697
|
sizeMap11 = {
|
|
11659
11698
|
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 },
|
|
11660
11699
|
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 },
|
|
@@ -11669,6 +11708,7 @@ var init_StatusEffect = __esm({
|
|
|
11669
11708
|
}
|
|
11670
11709
|
});
|
|
11671
11710
|
function DamageNumber({
|
|
11711
|
+
assetUrl = DEFAULT_ASSET_URL10,
|
|
11672
11712
|
value = 42,
|
|
11673
11713
|
type = "damage",
|
|
11674
11714
|
size = "md",
|
|
@@ -11677,22 +11717,35 @@ function DamageNumber({
|
|
|
11677
11717
|
const displayText = type === "miss" ? "MISS" : type === "heal" ? `+${value}` : `${value}`;
|
|
11678
11718
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
11679
11719
|
/* @__PURE__ */ jsx("style", { children: floatKeyframes }),
|
|
11680
|
-
/* @__PURE__ */
|
|
11720
|
+
/* @__PURE__ */ jsxs(
|
|
11681
11721
|
"span",
|
|
11682
11722
|
{
|
|
11683
11723
|
className: cn(
|
|
11684
|
-
"inline-
|
|
11724
|
+
"inline-flex items-center gap-0.5 font-mono select-none pointer-events-none",
|
|
11685
11725
|
sizeMap12[size],
|
|
11686
11726
|
typeStyles[type],
|
|
11687
11727
|
className
|
|
11688
11728
|
),
|
|
11689
11729
|
style: { animation: "damageFloat 1s ease-out forwards" },
|
|
11690
|
-
children:
|
|
11730
|
+
children: [
|
|
11731
|
+
assetUrl && /* @__PURE__ */ jsx(
|
|
11732
|
+
"img",
|
|
11733
|
+
{
|
|
11734
|
+
src: assetUrl,
|
|
11735
|
+
alt: "",
|
|
11736
|
+
width: 14,
|
|
11737
|
+
height: 14,
|
|
11738
|
+
style: { imageRendering: "pixelated", objectFit: "contain" },
|
|
11739
|
+
className: "flex-shrink-0"
|
|
11740
|
+
}
|
|
11741
|
+
),
|
|
11742
|
+
displayText
|
|
11743
|
+
]
|
|
11691
11744
|
}
|
|
11692
11745
|
)
|
|
11693
11746
|
] });
|
|
11694
11747
|
}
|
|
11695
|
-
var sizeMap12, typeStyles, floatKeyframes;
|
|
11748
|
+
var sizeMap12, typeStyles, floatKeyframes, DEFAULT_ASSET_URL10;
|
|
11696
11749
|
var init_DamageNumber = __esm({
|
|
11697
11750
|
"components/game/atoms/DamageNumber.tsx"() {
|
|
11698
11751
|
init_cn();
|
|
@@ -11714,6 +11767,7 @@ var init_DamageNumber = __esm({
|
|
|
11714
11767
|
100% { opacity: 0; transform: translateY(-32px) scale(0.8); }
|
|
11715
11768
|
}
|
|
11716
11769
|
`;
|
|
11770
|
+
DEFAULT_ASSET_URL10 = "https://almadar-kflow-assets.web.app/shared/effects/particles/spark_01.png";
|
|
11717
11771
|
DamageNumber.displayName = "DamageNumber";
|
|
11718
11772
|
}
|
|
11719
11773
|
});
|
|
@@ -11802,6 +11856,7 @@ var init_ChoiceButton = __esm({
|
|
|
11802
11856
|
}
|
|
11803
11857
|
});
|
|
11804
11858
|
function ActionButton({
|
|
11859
|
+
assetUrl = DEFAULT_ASSET_URL11,
|
|
11805
11860
|
label = "Attack",
|
|
11806
11861
|
icon,
|
|
11807
11862
|
cooldown = 0,
|
|
@@ -11841,13 +11896,23 @@ function ActionButton({
|
|
|
11841
11896
|
}
|
|
11842
11897
|
}
|
|
11843
11898
|
),
|
|
11844
|
-
|
|
11899
|
+
assetUrl ? /* @__PURE__ */ jsx(
|
|
11900
|
+
"img",
|
|
11901
|
+
{
|
|
11902
|
+
src: assetUrl,
|
|
11903
|
+
alt: "",
|
|
11904
|
+
width: 16,
|
|
11905
|
+
height: 16,
|
|
11906
|
+
style: { imageRendering: "pixelated", objectFit: "contain" },
|
|
11907
|
+
className: cn("flex-shrink-0", sizes.icon)
|
|
11908
|
+
}
|
|
11909
|
+
) : icon ? /* @__PURE__ */ jsx("span", { className: cn("flex-shrink-0", sizes.icon), children: typeof icon === "string" ? (() => {
|
|
11845
11910
|
const I = resolveIcon(icon);
|
|
11846
11911
|
return I ? /* @__PURE__ */ jsx(I, { className: "w-4 h-4" }) : null;
|
|
11847
11912
|
})() : /* @__PURE__ */ (() => {
|
|
11848
11913
|
const I = icon;
|
|
11849
11914
|
return /* @__PURE__ */ jsx(I, { className: "w-4 h-4" });
|
|
11850
|
-
})() }),
|
|
11915
|
+
})() }) : null,
|
|
11851
11916
|
/* @__PURE__ */ jsx("span", { className: "relative z-10", children: label }),
|
|
11852
11917
|
hotkey && /* @__PURE__ */ jsx(
|
|
11853
11918
|
"span",
|
|
@@ -11863,7 +11928,7 @@ function ActionButton({
|
|
|
11863
11928
|
}
|
|
11864
11929
|
);
|
|
11865
11930
|
}
|
|
11866
|
-
var sizeMap13, variantStyles8;
|
|
11931
|
+
var sizeMap13, variantStyles8, DEFAULT_ASSET_URL11;
|
|
11867
11932
|
var init_ActionButton = __esm({
|
|
11868
11933
|
"components/game/atoms/ActionButton.tsx"() {
|
|
11869
11934
|
init_cn();
|
|
@@ -11878,6 +11943,7 @@ var init_ActionButton = __esm({
|
|
|
11878
11943
|
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary-hover border-border",
|
|
11879
11944
|
danger: "bg-error text-error-foreground hover:bg-error/90 border-error"
|
|
11880
11945
|
};
|
|
11946
|
+
DEFAULT_ASSET_URL11 = "https://almadar-kflow-assets.web.app/shared/effects/particles/slash_01.png";
|
|
11881
11947
|
ActionButton.displayName = "ActionButton";
|
|
11882
11948
|
}
|
|
11883
11949
|
});
|
|
@@ -12390,10 +12456,10 @@ var init_Container = __esm({
|
|
|
12390
12456
|
center = true,
|
|
12391
12457
|
className,
|
|
12392
12458
|
children,
|
|
12393
|
-
as:
|
|
12459
|
+
as: Component2 = "div"
|
|
12394
12460
|
}) => {
|
|
12395
12461
|
const resolvedSize = maxWidth ?? size ?? "lg";
|
|
12396
|
-
const Comp =
|
|
12462
|
+
const Comp = Component2;
|
|
12397
12463
|
return /* @__PURE__ */ jsx(
|
|
12398
12464
|
Comp,
|
|
12399
12465
|
{
|
|
@@ -27570,7 +27636,7 @@ var init_Flex = __esm({
|
|
|
27570
27636
|
basis,
|
|
27571
27637
|
className,
|
|
27572
27638
|
children,
|
|
27573
|
-
as:
|
|
27639
|
+
as: Component2 = "div"
|
|
27574
27640
|
}) => {
|
|
27575
27641
|
const flexStyle = {};
|
|
27576
27642
|
if (grow !== void 0 || shrink !== void 0 || basis !== void 0) {
|
|
@@ -27582,7 +27648,7 @@ var init_Flex = __esm({
|
|
|
27582
27648
|
flexStyle.flexBasis = typeof basis === "number" ? `${basis}px` : basis;
|
|
27583
27649
|
}
|
|
27584
27650
|
}
|
|
27585
|
-
const Comp =
|
|
27651
|
+
const Comp = Component2;
|
|
27586
27652
|
return /* @__PURE__ */ jsx(
|
|
27587
27653
|
Comp,
|
|
27588
27654
|
{
|
|
@@ -27702,11 +27768,11 @@ var init_Grid = __esm({
|
|
|
27702
27768
|
className,
|
|
27703
27769
|
style,
|
|
27704
27770
|
children,
|
|
27705
|
-
as:
|
|
27771
|
+
as: Component2 = "div"
|
|
27706
27772
|
}) => {
|
|
27707
27773
|
const mergedStyle = rows2 ? { gridTemplateRows: `repeat(${rows2}, minmax(0, 1fr))`, ...style } : style;
|
|
27708
27774
|
return React91__default.createElement(
|
|
27709
|
-
|
|
27775
|
+
Component2,
|
|
27710
27776
|
{
|
|
27711
27777
|
className: cn(
|
|
27712
27778
|
"grid",
|
|
@@ -29532,6 +29598,7 @@ var init_ProgressDots = __esm({
|
|
|
29532
29598
|
}
|
|
29533
29599
|
});
|
|
29534
29600
|
function StatBadge({
|
|
29601
|
+
assetUrl = DEFAULT_ASSET_URL12,
|
|
29535
29602
|
label,
|
|
29536
29603
|
value = 0,
|
|
29537
29604
|
max,
|
|
@@ -29555,7 +29622,17 @@ function StatBadge({
|
|
|
29555
29622
|
className
|
|
29556
29623
|
),
|
|
29557
29624
|
children: [
|
|
29558
|
-
|
|
29625
|
+
assetUrl ? /* @__PURE__ */ jsx(
|
|
29626
|
+
"img",
|
|
29627
|
+
{
|
|
29628
|
+
src: assetUrl,
|
|
29629
|
+
alt: "",
|
|
29630
|
+
width: 16,
|
|
29631
|
+
height: 16,
|
|
29632
|
+
style: { imageRendering: "pixelated", objectFit: "contain" },
|
|
29633
|
+
className: "flex-shrink-0"
|
|
29634
|
+
}
|
|
29635
|
+
) : 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,
|
|
29559
29636
|
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground font-medium", children: label }),
|
|
29560
29637
|
format === "hearts" && max && /* @__PURE__ */ jsx(
|
|
29561
29638
|
HealthBar,
|
|
@@ -29588,7 +29665,7 @@ function StatBadge({
|
|
|
29588
29665
|
}
|
|
29589
29666
|
);
|
|
29590
29667
|
}
|
|
29591
|
-
var sizeMap17, variantMap2;
|
|
29668
|
+
var sizeMap17, variantMap2, DEFAULT_ASSET_URL12;
|
|
29592
29669
|
var init_StatBadge = __esm({
|
|
29593
29670
|
"components/game/molecules/StatBadge.tsx"() {
|
|
29594
29671
|
init_cn();
|
|
@@ -29607,6 +29684,7 @@ var init_StatBadge = __esm({
|
|
|
29607
29684
|
warning: "bg-warning/15 border-warning/40 text-foreground",
|
|
29608
29685
|
danger: "bg-error/15 border-error/40 text-foreground"
|
|
29609
29686
|
};
|
|
29687
|
+
DEFAULT_ASSET_URL12 = "https://almadar-kflow-assets.web.app/shared/effects/particles/light_01.png";
|
|
29610
29688
|
StatBadge.displayName = "StatBadge";
|
|
29611
29689
|
}
|
|
29612
29690
|
});
|
|
@@ -30263,6 +30341,7 @@ var init_TurnPanel = __esm({
|
|
|
30263
30341
|
}
|
|
30264
30342
|
});
|
|
30265
30343
|
function EnemyPlate({
|
|
30344
|
+
assetUrl = DEFAULT_ASSET_URL13,
|
|
30266
30345
|
name = "Shadow Guard",
|
|
30267
30346
|
health = 80,
|
|
30268
30347
|
maxHealth = 100,
|
|
@@ -30280,15 +30359,28 @@ function EnemyPlate({
|
|
|
30280
30359
|
),
|
|
30281
30360
|
children: [
|
|
30282
30361
|
/* @__PURE__ */ jsxs(Box, { className: "flex items-center justify-between gap-2", children: [
|
|
30283
|
-
/* @__PURE__ */
|
|
30284
|
-
|
|
30285
|
-
|
|
30286
|
-
|
|
30287
|
-
|
|
30288
|
-
|
|
30289
|
-
|
|
30290
|
-
|
|
30291
|
-
|
|
30362
|
+
/* @__PURE__ */ jsxs(Box, { className: "flex items-center gap-1.5 min-w-0", children: [
|
|
30363
|
+
assetUrl && /* @__PURE__ */ jsx(
|
|
30364
|
+
"img",
|
|
30365
|
+
{
|
|
30366
|
+
src: assetUrl,
|
|
30367
|
+
alt: name,
|
|
30368
|
+
width: 24,
|
|
30369
|
+
height: 24,
|
|
30370
|
+
style: { objectFit: "cover", borderRadius: "50%" },
|
|
30371
|
+
className: "flex-shrink-0"
|
|
30372
|
+
}
|
|
30373
|
+
),
|
|
30374
|
+
/* @__PURE__ */ jsx(
|
|
30375
|
+
Typography,
|
|
30376
|
+
{
|
|
30377
|
+
variant: "caption",
|
|
30378
|
+
weight: "bold",
|
|
30379
|
+
className: "text-[var(--color-foreground)] truncate",
|
|
30380
|
+
children: name
|
|
30381
|
+
}
|
|
30382
|
+
)
|
|
30383
|
+
] }),
|
|
30292
30384
|
level != null && /* @__PURE__ */ jsxs(Badge, { variant: "neutral", size: "sm", children: [
|
|
30293
30385
|
"Lv.",
|
|
30294
30386
|
level
|
|
@@ -30333,7 +30425,7 @@ function EnemyPlate({
|
|
|
30333
30425
|
}
|
|
30334
30426
|
);
|
|
30335
30427
|
}
|
|
30336
|
-
var effectVariantMap2, DEFAULT_ENEMY_EFFECTS;
|
|
30428
|
+
var effectVariantMap2, DEFAULT_ENEMY_EFFECTS, DEFAULT_ASSET_URL13;
|
|
30337
30429
|
var init_EnemyPlate = __esm({
|
|
30338
30430
|
"components/game/molecules/EnemyPlate.tsx"() {
|
|
30339
30431
|
"use client";
|
|
@@ -30350,6 +30442,7 @@ var init_EnemyPlate = __esm({
|
|
|
30350
30442
|
DEFAULT_ENEMY_EFFECTS = [
|
|
30351
30443
|
{ icon: "flame", label: "Burn", variant: "debuff" }
|
|
30352
30444
|
];
|
|
30445
|
+
DEFAULT_ASSET_URL13 = "https://almadar-kflow-assets.web.app/shared/portraits/shadow-legion.png";
|
|
30353
30446
|
EnemyPlate.displayName = "EnemyPlate";
|
|
30354
30447
|
}
|
|
30355
30448
|
});
|
|
@@ -31881,13 +31974,13 @@ var init_MapView = __esm({
|
|
|
31881
31974
|
shadowSize: [41, 41]
|
|
31882
31975
|
});
|
|
31883
31976
|
L.Marker.prototype.options.icon = defaultIcon;
|
|
31884
|
-
const { useEffect:
|
|
31977
|
+
const { useEffect: useEffect84, useRef: useRef76, useCallback: useCallback124, useState: useState120 } = React91__default;
|
|
31885
31978
|
const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
|
|
31886
|
-
const { useEventBus:
|
|
31979
|
+
const { useEventBus: useEventBus4 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
|
|
31887
31980
|
function MapUpdater({ centerLat, centerLng, zoom }) {
|
|
31888
31981
|
const map = useMap();
|
|
31889
|
-
const prevRef =
|
|
31890
|
-
|
|
31982
|
+
const prevRef = useRef76({ centerLat, centerLng, zoom });
|
|
31983
|
+
useEffect84(() => {
|
|
31891
31984
|
const prev = prevRef.current;
|
|
31892
31985
|
if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
|
|
31893
31986
|
map.setView([centerLat, centerLng], zoom);
|
|
@@ -31898,7 +31991,7 @@ var init_MapView = __esm({
|
|
|
31898
31991
|
}
|
|
31899
31992
|
function MapClickHandler({ onMapClick }) {
|
|
31900
31993
|
const map = useMap();
|
|
31901
|
-
|
|
31994
|
+
useEffect84(() => {
|
|
31902
31995
|
if (!onMapClick) return;
|
|
31903
31996
|
const handler = (e) => {
|
|
31904
31997
|
onMapClick(e.latlng.lat, e.latlng.lng);
|
|
@@ -31925,9 +32018,9 @@ var init_MapView = __esm({
|
|
|
31925
32018
|
className,
|
|
31926
32019
|
showAttribution = true
|
|
31927
32020
|
}) {
|
|
31928
|
-
const eventBus =
|
|
31929
|
-
const [clickedPosition, setClickedPosition] =
|
|
31930
|
-
const handleMapClick =
|
|
32021
|
+
const eventBus = useEventBus4();
|
|
32022
|
+
const [clickedPosition, setClickedPosition] = useState120(null);
|
|
32023
|
+
const handleMapClick = useCallback124((lat, lng) => {
|
|
31931
32024
|
if (showClickedPin) {
|
|
31932
32025
|
setClickedPosition({ lat, lng });
|
|
31933
32026
|
}
|
|
@@ -31936,7 +32029,7 @@ var init_MapView = __esm({
|
|
|
31936
32029
|
eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
|
|
31937
32030
|
}
|
|
31938
32031
|
}, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
|
|
31939
|
-
const handleMarkerClick =
|
|
32032
|
+
const handleMarkerClick = useCallback124((marker) => {
|
|
31940
32033
|
onMarkerClick?.(marker);
|
|
31941
32034
|
if (markerClickEvent) {
|
|
31942
32035
|
eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
|
|
@@ -38654,10 +38747,10 @@ var init_Section = __esm({
|
|
|
38654
38747
|
children,
|
|
38655
38748
|
headerClassName,
|
|
38656
38749
|
contentClassName,
|
|
38657
|
-
as:
|
|
38750
|
+
as: Component2 = "section"
|
|
38658
38751
|
}) => {
|
|
38659
38752
|
const hasHeader = title || description || action;
|
|
38660
|
-
const Comp =
|
|
38753
|
+
const Comp = Component2;
|
|
38661
38754
|
return /* @__PURE__ */ jsxs(
|
|
38662
38755
|
Comp,
|
|
38663
38756
|
{
|
|
@@ -43222,6 +43315,1568 @@ var init_GameAudioToggle = __esm({
|
|
|
43222
43315
|
GameAudioToggle.displayName = "GameAudioToggle";
|
|
43223
43316
|
}
|
|
43224
43317
|
});
|
|
43318
|
+
function detectAssetRoot(modelUrl) {
|
|
43319
|
+
const idx = modelUrl.indexOf("/3d/");
|
|
43320
|
+
if (idx !== -1) {
|
|
43321
|
+
return modelUrl.substring(0, idx + 4);
|
|
43322
|
+
}
|
|
43323
|
+
return modelUrl.substring(0, modelUrl.lastIndexOf("/") + 1);
|
|
43324
|
+
}
|
|
43325
|
+
function createGLTFLoaderForUrl(url) {
|
|
43326
|
+
const loader = new GLTFLoader();
|
|
43327
|
+
loader.setResourcePath(detectAssetRoot(url));
|
|
43328
|
+
return loader;
|
|
43329
|
+
}
|
|
43330
|
+
var AssetLoader;
|
|
43331
|
+
var init_AssetLoader = __esm({
|
|
43332
|
+
"components/game/molecules/three/loaders/AssetLoader.ts"() {
|
|
43333
|
+
AssetLoader = class {
|
|
43334
|
+
constructor() {
|
|
43335
|
+
__publicField(this, "objLoader");
|
|
43336
|
+
__publicField(this, "textureLoader");
|
|
43337
|
+
__publicField(this, "modelCache");
|
|
43338
|
+
__publicField(this, "textureCache");
|
|
43339
|
+
__publicField(this, "loadingPromises");
|
|
43340
|
+
this.objLoader = new OBJLoader();
|
|
43341
|
+
this.textureLoader = new THREE.TextureLoader();
|
|
43342
|
+
this.modelCache = /* @__PURE__ */ new Map();
|
|
43343
|
+
this.textureCache = /* @__PURE__ */ new Map();
|
|
43344
|
+
this.loadingPromises = /* @__PURE__ */ new Map();
|
|
43345
|
+
}
|
|
43346
|
+
/**
|
|
43347
|
+
* Load a GLB/GLTF model
|
|
43348
|
+
* @param url - URL to the .glb or .gltf file
|
|
43349
|
+
* @returns Promise with loaded model scene and animations
|
|
43350
|
+
*/
|
|
43351
|
+
async loadModel(url) {
|
|
43352
|
+
if (this.modelCache.has(url)) {
|
|
43353
|
+
return this.modelCache.get(url);
|
|
43354
|
+
}
|
|
43355
|
+
if (this.loadingPromises.has(url)) {
|
|
43356
|
+
return this.loadingPromises.get(url);
|
|
43357
|
+
}
|
|
43358
|
+
const loader = createGLTFLoaderForUrl(url);
|
|
43359
|
+
const loadPromise = loader.loadAsync(url).then((gltf) => {
|
|
43360
|
+
const result = {
|
|
43361
|
+
scene: gltf.scene,
|
|
43362
|
+
animations: gltf.animations || []
|
|
43363
|
+
};
|
|
43364
|
+
this.modelCache.set(url, result);
|
|
43365
|
+
this.loadingPromises.delete(url);
|
|
43366
|
+
return result;
|
|
43367
|
+
}).catch((error) => {
|
|
43368
|
+
this.loadingPromises.delete(url);
|
|
43369
|
+
throw new Error(`Failed to load model ${url}: ${error.message}`);
|
|
43370
|
+
});
|
|
43371
|
+
this.loadingPromises.set(url, loadPromise);
|
|
43372
|
+
return loadPromise;
|
|
43373
|
+
}
|
|
43374
|
+
/**
|
|
43375
|
+
* Load an OBJ model (fallback for non-GLB assets)
|
|
43376
|
+
* @param url - URL to the .obj file
|
|
43377
|
+
* @returns Promise with loaded object group
|
|
43378
|
+
*/
|
|
43379
|
+
async loadOBJ(url) {
|
|
43380
|
+
if (this.modelCache.has(url)) {
|
|
43381
|
+
return this.modelCache.get(url).scene;
|
|
43382
|
+
}
|
|
43383
|
+
if (this.loadingPromises.has(url)) {
|
|
43384
|
+
const result = await this.loadingPromises.get(url);
|
|
43385
|
+
return result.scene;
|
|
43386
|
+
}
|
|
43387
|
+
const loadPromise = this.objLoader.loadAsync(url).then((group) => {
|
|
43388
|
+
const result = {
|
|
43389
|
+
scene: group,
|
|
43390
|
+
animations: []
|
|
43391
|
+
};
|
|
43392
|
+
this.modelCache.set(url, result);
|
|
43393
|
+
this.loadingPromises.delete(url);
|
|
43394
|
+
return result;
|
|
43395
|
+
}).catch((error) => {
|
|
43396
|
+
this.loadingPromises.delete(url);
|
|
43397
|
+
throw new Error(`Failed to load OBJ ${url}: ${error.message}`);
|
|
43398
|
+
});
|
|
43399
|
+
this.loadingPromises.set(url, loadPromise);
|
|
43400
|
+
return (await loadPromise).scene;
|
|
43401
|
+
}
|
|
43402
|
+
/**
|
|
43403
|
+
* Load a texture
|
|
43404
|
+
* @param url - URL to the texture image
|
|
43405
|
+
* @returns Promise with loaded texture
|
|
43406
|
+
*/
|
|
43407
|
+
async loadTexture(url) {
|
|
43408
|
+
if (this.textureCache.has(url)) {
|
|
43409
|
+
return this.textureCache.get(url);
|
|
43410
|
+
}
|
|
43411
|
+
if (this.loadingPromises.has(`texture:${url}`)) {
|
|
43412
|
+
return this.loadingPromises.get(`texture:${url}`);
|
|
43413
|
+
}
|
|
43414
|
+
const loadPromise = this.textureLoader.loadAsync(url).then((texture) => {
|
|
43415
|
+
texture.colorSpace = THREE.SRGBColorSpace;
|
|
43416
|
+
this.textureCache.set(url, texture);
|
|
43417
|
+
this.loadingPromises.delete(`texture:${url}`);
|
|
43418
|
+
return texture;
|
|
43419
|
+
}).catch((error) => {
|
|
43420
|
+
this.loadingPromises.delete(`texture:${url}`);
|
|
43421
|
+
throw new Error(`Failed to load texture ${url}: ${error.message}`);
|
|
43422
|
+
});
|
|
43423
|
+
this.loadingPromises.set(`texture:${url}`, loadPromise);
|
|
43424
|
+
return loadPromise;
|
|
43425
|
+
}
|
|
43426
|
+
/**
|
|
43427
|
+
* Preload multiple assets
|
|
43428
|
+
* @param urls - Array of asset URLs to preload
|
|
43429
|
+
* @returns Promise that resolves when all assets are loaded
|
|
43430
|
+
*/
|
|
43431
|
+
async preload(urls) {
|
|
43432
|
+
const promises = urls.map((url) => {
|
|
43433
|
+
if (url.endsWith(".glb") || url.endsWith(".gltf")) {
|
|
43434
|
+
return this.loadModel(url).catch(() => null);
|
|
43435
|
+
} else if (url.endsWith(".obj")) {
|
|
43436
|
+
return this.loadOBJ(url).catch(() => null);
|
|
43437
|
+
} else if (/\.(png|jpg|jpeg|webp)$/i.test(url)) {
|
|
43438
|
+
return this.loadTexture(url).catch(() => null);
|
|
43439
|
+
}
|
|
43440
|
+
return Promise.resolve(null);
|
|
43441
|
+
});
|
|
43442
|
+
await Promise.all(promises);
|
|
43443
|
+
}
|
|
43444
|
+
/**
|
|
43445
|
+
* Check if a model is cached
|
|
43446
|
+
* @param url - Model URL
|
|
43447
|
+
*/
|
|
43448
|
+
hasModel(url) {
|
|
43449
|
+
return this.modelCache.has(url);
|
|
43450
|
+
}
|
|
43451
|
+
/**
|
|
43452
|
+
* Check if a texture is cached
|
|
43453
|
+
* @param url - Texture URL
|
|
43454
|
+
*/
|
|
43455
|
+
hasTexture(url) {
|
|
43456
|
+
return this.textureCache.has(url);
|
|
43457
|
+
}
|
|
43458
|
+
/**
|
|
43459
|
+
* Get cached model (throws if not cached)
|
|
43460
|
+
* @param url - Model URL
|
|
43461
|
+
*/
|
|
43462
|
+
getModel(url) {
|
|
43463
|
+
const model = this.modelCache.get(url);
|
|
43464
|
+
if (!model) {
|
|
43465
|
+
throw new Error(`Model ${url} not in cache`);
|
|
43466
|
+
}
|
|
43467
|
+
return model;
|
|
43468
|
+
}
|
|
43469
|
+
/**
|
|
43470
|
+
* Get cached texture (throws if not cached)
|
|
43471
|
+
* @param url - Texture URL
|
|
43472
|
+
*/
|
|
43473
|
+
getTexture(url) {
|
|
43474
|
+
const texture = this.textureCache.get(url);
|
|
43475
|
+
if (!texture) {
|
|
43476
|
+
throw new Error(`Texture ${url} not in cache`);
|
|
43477
|
+
}
|
|
43478
|
+
return texture;
|
|
43479
|
+
}
|
|
43480
|
+
/**
|
|
43481
|
+
* Clear all caches
|
|
43482
|
+
*/
|
|
43483
|
+
clearCache() {
|
|
43484
|
+
this.textureCache.forEach((texture) => {
|
|
43485
|
+
texture.dispose();
|
|
43486
|
+
});
|
|
43487
|
+
this.modelCache.forEach((model) => {
|
|
43488
|
+
model.scene.traverse((child) => {
|
|
43489
|
+
if (child instanceof THREE.Mesh) {
|
|
43490
|
+
child.geometry.dispose();
|
|
43491
|
+
if (Array.isArray(child.material)) {
|
|
43492
|
+
child.material.forEach((m) => m.dispose());
|
|
43493
|
+
} else {
|
|
43494
|
+
child.material.dispose();
|
|
43495
|
+
}
|
|
43496
|
+
}
|
|
43497
|
+
});
|
|
43498
|
+
});
|
|
43499
|
+
this.modelCache.clear();
|
|
43500
|
+
this.textureCache.clear();
|
|
43501
|
+
this.loadingPromises.clear();
|
|
43502
|
+
}
|
|
43503
|
+
/**
|
|
43504
|
+
* Get cache statistics
|
|
43505
|
+
*/
|
|
43506
|
+
getStats() {
|
|
43507
|
+
return {
|
|
43508
|
+
models: this.modelCache.size,
|
|
43509
|
+
textures: this.textureCache.size,
|
|
43510
|
+
loading: this.loadingPromises.size
|
|
43511
|
+
};
|
|
43512
|
+
}
|
|
43513
|
+
};
|
|
43514
|
+
new AssetLoader();
|
|
43515
|
+
}
|
|
43516
|
+
});
|
|
43517
|
+
function useAssetLoader(options = {}) {
|
|
43518
|
+
const { preloadUrls = [], loader: customLoader } = options;
|
|
43519
|
+
const loaderRef = useRef(customLoader || new AssetLoader());
|
|
43520
|
+
const [state, setState] = useState({
|
|
43521
|
+
isLoading: false,
|
|
43522
|
+
progress: 0,
|
|
43523
|
+
loaded: 0,
|
|
43524
|
+
total: 0,
|
|
43525
|
+
errors: []
|
|
43526
|
+
});
|
|
43527
|
+
useEffect(() => {
|
|
43528
|
+
if (preloadUrls.length > 0) {
|
|
43529
|
+
preload(preloadUrls);
|
|
43530
|
+
}
|
|
43531
|
+
}, []);
|
|
43532
|
+
const updateProgress = useCallback((loaded, total) => {
|
|
43533
|
+
setState((prev) => ({
|
|
43534
|
+
...prev,
|
|
43535
|
+
loaded,
|
|
43536
|
+
total,
|
|
43537
|
+
progress: total > 0 ? Math.round(loaded / total * 100) : 0
|
|
43538
|
+
}));
|
|
43539
|
+
}, []);
|
|
43540
|
+
const loadModel = useCallback(
|
|
43541
|
+
async (url) => {
|
|
43542
|
+
setState((prev) => ({ ...prev, isLoading: true }));
|
|
43543
|
+
try {
|
|
43544
|
+
const model = await loaderRef.current.loadModel(url);
|
|
43545
|
+
setState((prev) => ({
|
|
43546
|
+
...prev,
|
|
43547
|
+
isLoading: false,
|
|
43548
|
+
loaded: prev.loaded + 1
|
|
43549
|
+
}));
|
|
43550
|
+
return model;
|
|
43551
|
+
} catch (error) {
|
|
43552
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
43553
|
+
setState((prev) => ({
|
|
43554
|
+
...prev,
|
|
43555
|
+
isLoading: false,
|
|
43556
|
+
errors: [...prev.errors, errorMsg]
|
|
43557
|
+
}));
|
|
43558
|
+
throw error;
|
|
43559
|
+
}
|
|
43560
|
+
},
|
|
43561
|
+
[]
|
|
43562
|
+
);
|
|
43563
|
+
const loadOBJ = useCallback(
|
|
43564
|
+
async (url) => {
|
|
43565
|
+
setState((prev) => ({ ...prev, isLoading: true }));
|
|
43566
|
+
try {
|
|
43567
|
+
const model = await loaderRef.current.loadOBJ(url);
|
|
43568
|
+
setState((prev) => ({
|
|
43569
|
+
...prev,
|
|
43570
|
+
isLoading: false,
|
|
43571
|
+
loaded: prev.loaded + 1
|
|
43572
|
+
}));
|
|
43573
|
+
return model;
|
|
43574
|
+
} catch (error) {
|
|
43575
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
43576
|
+
setState((prev) => ({
|
|
43577
|
+
...prev,
|
|
43578
|
+
isLoading: false,
|
|
43579
|
+
errors: [...prev.errors, errorMsg]
|
|
43580
|
+
}));
|
|
43581
|
+
throw error;
|
|
43582
|
+
}
|
|
43583
|
+
},
|
|
43584
|
+
[]
|
|
43585
|
+
);
|
|
43586
|
+
const loadTexture = useCallback(
|
|
43587
|
+
async (url) => {
|
|
43588
|
+
setState((prev) => ({ ...prev, isLoading: true }));
|
|
43589
|
+
try {
|
|
43590
|
+
const texture = await loaderRef.current.loadTexture(url);
|
|
43591
|
+
setState((prev) => ({
|
|
43592
|
+
...prev,
|
|
43593
|
+
isLoading: false,
|
|
43594
|
+
loaded: prev.loaded + 1
|
|
43595
|
+
}));
|
|
43596
|
+
return texture;
|
|
43597
|
+
} catch (error) {
|
|
43598
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
43599
|
+
setState((prev) => ({
|
|
43600
|
+
...prev,
|
|
43601
|
+
isLoading: false,
|
|
43602
|
+
errors: [...prev.errors, errorMsg]
|
|
43603
|
+
}));
|
|
43604
|
+
throw error;
|
|
43605
|
+
}
|
|
43606
|
+
},
|
|
43607
|
+
[]
|
|
43608
|
+
);
|
|
43609
|
+
const preload = useCallback(
|
|
43610
|
+
async (urls) => {
|
|
43611
|
+
setState((prev) => ({
|
|
43612
|
+
...prev,
|
|
43613
|
+
isLoading: true,
|
|
43614
|
+
total: urls.length,
|
|
43615
|
+
loaded: 0,
|
|
43616
|
+
errors: []
|
|
43617
|
+
}));
|
|
43618
|
+
let completed = 0;
|
|
43619
|
+
const errors = [];
|
|
43620
|
+
await Promise.all(
|
|
43621
|
+
urls.map(async (url) => {
|
|
43622
|
+
try {
|
|
43623
|
+
if (url.endsWith(".glb") || url.endsWith(".gltf")) {
|
|
43624
|
+
await loaderRef.current.loadModel(url);
|
|
43625
|
+
} else if (url.endsWith(".obj")) {
|
|
43626
|
+
await loaderRef.current.loadOBJ(url);
|
|
43627
|
+
} else if (/\.(png|jpg|jpeg|webp)$/i.test(url)) {
|
|
43628
|
+
await loaderRef.current.loadTexture(url);
|
|
43629
|
+
}
|
|
43630
|
+
completed++;
|
|
43631
|
+
updateProgress(completed, urls.length);
|
|
43632
|
+
} catch (error) {
|
|
43633
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
43634
|
+
errors.push(`${url}: ${errorMsg}`);
|
|
43635
|
+
completed++;
|
|
43636
|
+
updateProgress(completed, urls.length);
|
|
43637
|
+
}
|
|
43638
|
+
})
|
|
43639
|
+
);
|
|
43640
|
+
setState((prev) => ({
|
|
43641
|
+
...prev,
|
|
43642
|
+
isLoading: false,
|
|
43643
|
+
errors
|
|
43644
|
+
}));
|
|
43645
|
+
},
|
|
43646
|
+
[updateProgress]
|
|
43647
|
+
);
|
|
43648
|
+
const hasModel = useCallback((url) => {
|
|
43649
|
+
return loaderRef.current.hasModel(url);
|
|
43650
|
+
}, []);
|
|
43651
|
+
const hasTexture = useCallback((url) => {
|
|
43652
|
+
return loaderRef.current.hasTexture(url);
|
|
43653
|
+
}, []);
|
|
43654
|
+
const getModel = useCallback((url) => {
|
|
43655
|
+
try {
|
|
43656
|
+
return loaderRef.current.getModel(url);
|
|
43657
|
+
} catch {
|
|
43658
|
+
return void 0;
|
|
43659
|
+
}
|
|
43660
|
+
}, []);
|
|
43661
|
+
const getTexture = useCallback((url) => {
|
|
43662
|
+
try {
|
|
43663
|
+
return loaderRef.current.getTexture(url);
|
|
43664
|
+
} catch {
|
|
43665
|
+
return void 0;
|
|
43666
|
+
}
|
|
43667
|
+
}, []);
|
|
43668
|
+
const clearCache = useCallback(() => {
|
|
43669
|
+
loaderRef.current.clearCache();
|
|
43670
|
+
setState({
|
|
43671
|
+
isLoading: false,
|
|
43672
|
+
progress: 0,
|
|
43673
|
+
loaded: 0,
|
|
43674
|
+
total: 0,
|
|
43675
|
+
errors: []
|
|
43676
|
+
});
|
|
43677
|
+
}, []);
|
|
43678
|
+
return {
|
|
43679
|
+
...state,
|
|
43680
|
+
loadModel,
|
|
43681
|
+
loadOBJ,
|
|
43682
|
+
loadTexture,
|
|
43683
|
+
preload,
|
|
43684
|
+
hasModel,
|
|
43685
|
+
hasTexture,
|
|
43686
|
+
getModel,
|
|
43687
|
+
getTexture,
|
|
43688
|
+
clearCache
|
|
43689
|
+
};
|
|
43690
|
+
}
|
|
43691
|
+
var init_useAssetLoader = __esm({
|
|
43692
|
+
"components/game/molecules/three/hooks/useAssetLoader.ts"() {
|
|
43693
|
+
"use client";
|
|
43694
|
+
init_AssetLoader();
|
|
43695
|
+
}
|
|
43696
|
+
});
|
|
43697
|
+
function useGameCanvas3DEvents(options) {
|
|
43698
|
+
const {
|
|
43699
|
+
tileClickEvent,
|
|
43700
|
+
unitClickEvent,
|
|
43701
|
+
featureClickEvent,
|
|
43702
|
+
canvasClickEvent,
|
|
43703
|
+
tileHoverEvent,
|
|
43704
|
+
tileLeaveEvent,
|
|
43705
|
+
unitAnimationEvent,
|
|
43706
|
+
cameraChangeEvent,
|
|
43707
|
+
onTileClick,
|
|
43708
|
+
onUnitClick,
|
|
43709
|
+
onFeatureClick,
|
|
43710
|
+
onCanvasClick,
|
|
43711
|
+
onTileHover,
|
|
43712
|
+
onUnitAnimation
|
|
43713
|
+
} = options;
|
|
43714
|
+
const emit = useEmitEvent();
|
|
43715
|
+
const optionsRef = useRef(options);
|
|
43716
|
+
optionsRef.current = options;
|
|
43717
|
+
const handleTileClick = useCallback(
|
|
43718
|
+
(tile, event) => {
|
|
43719
|
+
if (tileClickEvent) {
|
|
43720
|
+
emit(tileClickEvent, {
|
|
43721
|
+
tileId: tile.id,
|
|
43722
|
+
x: tile.x,
|
|
43723
|
+
z: tile.z ?? tile.y ?? 0,
|
|
43724
|
+
type: tile.type,
|
|
43725
|
+
terrain: tile.terrain,
|
|
43726
|
+
elevation: tile.elevation
|
|
43727
|
+
});
|
|
43728
|
+
}
|
|
43729
|
+
optionsRef.current.onTileClick?.(tile, event);
|
|
43730
|
+
},
|
|
43731
|
+
[tileClickEvent, emit]
|
|
43732
|
+
);
|
|
43733
|
+
const handleUnitClick = useCallback(
|
|
43734
|
+
(unit, event) => {
|
|
43735
|
+
if (unitClickEvent) {
|
|
43736
|
+
emit(unitClickEvent, {
|
|
43737
|
+
unitId: unit.id,
|
|
43738
|
+
x: unit.x,
|
|
43739
|
+
z: unit.z ?? unit.y ?? 0,
|
|
43740
|
+
unitType: unit.unitType,
|
|
43741
|
+
name: unit.name,
|
|
43742
|
+
team: unit.team,
|
|
43743
|
+
faction: unit.faction,
|
|
43744
|
+
health: unit.health,
|
|
43745
|
+
maxHealth: unit.maxHealth
|
|
43746
|
+
});
|
|
43747
|
+
}
|
|
43748
|
+
optionsRef.current.onUnitClick?.(unit, event);
|
|
43749
|
+
},
|
|
43750
|
+
[unitClickEvent, emit]
|
|
43751
|
+
);
|
|
43752
|
+
const handleFeatureClick = useCallback(
|
|
43753
|
+
(feature, event) => {
|
|
43754
|
+
if (featureClickEvent) {
|
|
43755
|
+
emit(featureClickEvent, {
|
|
43756
|
+
featureId: feature.id,
|
|
43757
|
+
x: feature.x,
|
|
43758
|
+
z: feature.z ?? feature.y ?? 0,
|
|
43759
|
+
type: feature.type,
|
|
43760
|
+
elevation: feature.elevation
|
|
43761
|
+
});
|
|
43762
|
+
}
|
|
43763
|
+
optionsRef.current.onFeatureClick?.(feature, event);
|
|
43764
|
+
},
|
|
43765
|
+
[featureClickEvent, emit]
|
|
43766
|
+
);
|
|
43767
|
+
const handleCanvasClick = useCallback(
|
|
43768
|
+
(event) => {
|
|
43769
|
+
if (canvasClickEvent) {
|
|
43770
|
+
emit(canvasClickEvent, {
|
|
43771
|
+
clientX: event.clientX,
|
|
43772
|
+
clientY: event.clientY,
|
|
43773
|
+
button: event.button
|
|
43774
|
+
});
|
|
43775
|
+
}
|
|
43776
|
+
optionsRef.current.onCanvasClick?.(event);
|
|
43777
|
+
},
|
|
43778
|
+
[canvasClickEvent, emit]
|
|
43779
|
+
);
|
|
43780
|
+
const handleTileHover = useCallback(
|
|
43781
|
+
(tile, event) => {
|
|
43782
|
+
if (tile) {
|
|
43783
|
+
if (tileHoverEvent) {
|
|
43784
|
+
emit(tileHoverEvent, {
|
|
43785
|
+
tileId: tile.id,
|
|
43786
|
+
x: tile.x,
|
|
43787
|
+
z: tile.z ?? tile.y ?? 0,
|
|
43788
|
+
type: tile.type
|
|
43789
|
+
});
|
|
43790
|
+
}
|
|
43791
|
+
} else {
|
|
43792
|
+
if (tileLeaveEvent) {
|
|
43793
|
+
emit(tileLeaveEvent, {});
|
|
43794
|
+
}
|
|
43795
|
+
}
|
|
43796
|
+
optionsRef.current.onTileHover?.(tile, event);
|
|
43797
|
+
},
|
|
43798
|
+
[tileHoverEvent, tileLeaveEvent, emit]
|
|
43799
|
+
);
|
|
43800
|
+
const handleUnitAnimation = useCallback(
|
|
43801
|
+
(unitId, state) => {
|
|
43802
|
+
if (unitAnimationEvent) {
|
|
43803
|
+
emit(unitAnimationEvent, {
|
|
43804
|
+
unitId,
|
|
43805
|
+
state,
|
|
43806
|
+
timestamp: Date.now()
|
|
43807
|
+
});
|
|
43808
|
+
}
|
|
43809
|
+
optionsRef.current.onUnitAnimation?.(unitId, state);
|
|
43810
|
+
},
|
|
43811
|
+
[unitAnimationEvent, emit]
|
|
43812
|
+
);
|
|
43813
|
+
const handleCameraChange = useCallback(
|
|
43814
|
+
(position) => {
|
|
43815
|
+
if (cameraChangeEvent) {
|
|
43816
|
+
emit(cameraChangeEvent, {
|
|
43817
|
+
position,
|
|
43818
|
+
timestamp: Date.now()
|
|
43819
|
+
});
|
|
43820
|
+
}
|
|
43821
|
+
},
|
|
43822
|
+
[cameraChangeEvent, emit]
|
|
43823
|
+
);
|
|
43824
|
+
return {
|
|
43825
|
+
handleTileClick,
|
|
43826
|
+
handleUnitClick,
|
|
43827
|
+
handleFeatureClick,
|
|
43828
|
+
handleCanvasClick,
|
|
43829
|
+
handleTileHover,
|
|
43830
|
+
handleUnitAnimation,
|
|
43831
|
+
handleCameraChange
|
|
43832
|
+
};
|
|
43833
|
+
}
|
|
43834
|
+
var init_useGameCanvas3DEvents = __esm({
|
|
43835
|
+
"components/game/molecules/three/hooks/useGameCanvas3DEvents.ts"() {
|
|
43836
|
+
"use client";
|
|
43837
|
+
init_useEventBus();
|
|
43838
|
+
}
|
|
43839
|
+
});
|
|
43840
|
+
|
|
43841
|
+
// components/game/molecules/three/components/Canvas3DLoadingState.css
|
|
43842
|
+
var init_Canvas3DLoadingState = __esm({
|
|
43843
|
+
"components/game/molecules/three/components/Canvas3DLoadingState.css"() {
|
|
43844
|
+
}
|
|
43845
|
+
});
|
|
43846
|
+
function Canvas3DLoadingState({
|
|
43847
|
+
progress = 0,
|
|
43848
|
+
loaded = 0,
|
|
43849
|
+
total = 0,
|
|
43850
|
+
message = "Loading 3D Scene...",
|
|
43851
|
+
details,
|
|
43852
|
+
showSpinner = true,
|
|
43853
|
+
className
|
|
43854
|
+
}) {
|
|
43855
|
+
const clampedProgress = Math.max(0, Math.min(100, progress));
|
|
43856
|
+
const hasProgress = total > 0;
|
|
43857
|
+
return /* @__PURE__ */ jsxs("div", { className: `canvas-3d-loading ${className || ""}`, children: [
|
|
43858
|
+
/* @__PURE__ */ jsxs("div", { className: "canvas-3d-loading__content", children: [
|
|
43859
|
+
showSpinner && /* @__PURE__ */ jsxs("div", { className: "canvas-3d-loading__spinner", children: [
|
|
43860
|
+
/* @__PURE__ */ jsx("div", { className: "spinner__ring" }),
|
|
43861
|
+
/* @__PURE__ */ jsx("div", { className: "spinner__ring spinner__ring--secondary" })
|
|
43862
|
+
] }),
|
|
43863
|
+
/* @__PURE__ */ jsx("div", { className: "canvas-3d-loading__message", children: message }),
|
|
43864
|
+
details && /* @__PURE__ */ jsx("div", { className: "canvas-3d-loading__details", children: details }),
|
|
43865
|
+
hasProgress && /* @__PURE__ */ jsxs("div", { className: "canvas-3d-loading__progress", children: [
|
|
43866
|
+
/* @__PURE__ */ jsx("div", { className: "progress__bar", children: /* @__PURE__ */ jsx(
|
|
43867
|
+
"div",
|
|
43868
|
+
{
|
|
43869
|
+
className: "progress__fill",
|
|
43870
|
+
style: { width: `${clampedProgress}%` }
|
|
43871
|
+
}
|
|
43872
|
+
) }),
|
|
43873
|
+
/* @__PURE__ */ jsxs("div", { className: "progress__text", children: [
|
|
43874
|
+
/* @__PURE__ */ jsxs("span", { className: "progress__percentage", children: [
|
|
43875
|
+
clampedProgress,
|
|
43876
|
+
"%"
|
|
43877
|
+
] }),
|
|
43878
|
+
/* @__PURE__ */ jsxs("span", { className: "progress__count", children: [
|
|
43879
|
+
"(",
|
|
43880
|
+
loaded,
|
|
43881
|
+
"/",
|
|
43882
|
+
total,
|
|
43883
|
+
")"
|
|
43884
|
+
] })
|
|
43885
|
+
] })
|
|
43886
|
+
] })
|
|
43887
|
+
] }),
|
|
43888
|
+
/* @__PURE__ */ jsx("div", { className: "canvas-3d-loading__background", children: /* @__PURE__ */ jsx("div", { className: "bg__grid" }) })
|
|
43889
|
+
] });
|
|
43890
|
+
}
|
|
43891
|
+
var init_Canvas3DLoadingState2 = __esm({
|
|
43892
|
+
"components/game/molecules/three/components/Canvas3DLoadingState.tsx"() {
|
|
43893
|
+
init_Canvas3DLoadingState();
|
|
43894
|
+
}
|
|
43895
|
+
});
|
|
43896
|
+
|
|
43897
|
+
// components/game/molecules/three/components/Canvas3DErrorBoundary.css
|
|
43898
|
+
var init_Canvas3DErrorBoundary = __esm({
|
|
43899
|
+
"components/game/molecules/three/components/Canvas3DErrorBoundary.css"() {
|
|
43900
|
+
}
|
|
43901
|
+
});
|
|
43902
|
+
var log9, Canvas3DErrorBoundary;
|
|
43903
|
+
var init_Canvas3DErrorBoundary2 = __esm({
|
|
43904
|
+
"components/game/molecules/three/components/Canvas3DErrorBoundary.tsx"() {
|
|
43905
|
+
init_Canvas3DErrorBoundary();
|
|
43906
|
+
log9 = createLogger("almadar:ui:game:canvas3d:error-boundary");
|
|
43907
|
+
Canvas3DErrorBoundary = class extends Component {
|
|
43908
|
+
constructor(props) {
|
|
43909
|
+
super(props);
|
|
43910
|
+
__publicField(this, "handleReset", () => {
|
|
43911
|
+
this.setState({
|
|
43912
|
+
hasError: false,
|
|
43913
|
+
error: null,
|
|
43914
|
+
errorInfo: null
|
|
43915
|
+
});
|
|
43916
|
+
this.props.onReset?.();
|
|
43917
|
+
});
|
|
43918
|
+
this.state = {
|
|
43919
|
+
hasError: false,
|
|
43920
|
+
error: null,
|
|
43921
|
+
errorInfo: null
|
|
43922
|
+
};
|
|
43923
|
+
}
|
|
43924
|
+
static getDerivedStateFromError(error) {
|
|
43925
|
+
return {
|
|
43926
|
+
hasError: true,
|
|
43927
|
+
error,
|
|
43928
|
+
errorInfo: null
|
|
43929
|
+
};
|
|
43930
|
+
}
|
|
43931
|
+
componentDidCatch(error, errorInfo) {
|
|
43932
|
+
this.setState({ errorInfo });
|
|
43933
|
+
this.props.onError?.(error, errorInfo);
|
|
43934
|
+
log9.error("Error caught", { error });
|
|
43935
|
+
log9.error("Component stack", { componentStack: errorInfo.componentStack ?? "<none>" });
|
|
43936
|
+
}
|
|
43937
|
+
render() {
|
|
43938
|
+
if (this.state.hasError) {
|
|
43939
|
+
if (this.props.fallback) {
|
|
43940
|
+
return this.props.fallback;
|
|
43941
|
+
}
|
|
43942
|
+
return /* @__PURE__ */ jsx("div", { className: "canvas-3d-error", children: /* @__PURE__ */ jsxs("div", { className: "canvas-3d-error__content", children: [
|
|
43943
|
+
/* @__PURE__ */ jsx("div", { className: "canvas-3d-error__icon", children: "\u26A0\uFE0F" }),
|
|
43944
|
+
/* @__PURE__ */ jsx("h2", { className: "canvas-3d-error__title", children: "3D Scene Error" }),
|
|
43945
|
+
/* @__PURE__ */ jsx("p", { className: "canvas-3d-error__message", children: "Something went wrong while rendering the 3D scene." }),
|
|
43946
|
+
this.state.error && /* @__PURE__ */ jsxs("details", { className: "canvas-3d-error__details", children: [
|
|
43947
|
+
/* @__PURE__ */ jsx("summary", { children: "Error Details" }),
|
|
43948
|
+
/* @__PURE__ */ jsxs("pre", { className: "error__stack", children: [
|
|
43949
|
+
this.state.error.message,
|
|
43950
|
+
"\n",
|
|
43951
|
+
this.state.error.stack
|
|
43952
|
+
] }),
|
|
43953
|
+
this.state.errorInfo && /* @__PURE__ */ jsx("pre", { className: "error__component-stack", children: this.state.errorInfo.componentStack })
|
|
43954
|
+
] }),
|
|
43955
|
+
/* @__PURE__ */ jsxs("div", { className: "canvas-3d-error__actions", children: [
|
|
43956
|
+
/* @__PURE__ */ jsx(
|
|
43957
|
+
"button",
|
|
43958
|
+
{
|
|
43959
|
+
className: "error__button error__button--primary",
|
|
43960
|
+
onClick: this.handleReset,
|
|
43961
|
+
children: "Try Again"
|
|
43962
|
+
}
|
|
43963
|
+
),
|
|
43964
|
+
/* @__PURE__ */ jsx(
|
|
43965
|
+
"button",
|
|
43966
|
+
{
|
|
43967
|
+
className: "error__button error__button--secondary",
|
|
43968
|
+
onClick: () => window.location.reload(),
|
|
43969
|
+
children: "Reload Page"
|
|
43970
|
+
}
|
|
43971
|
+
)
|
|
43972
|
+
] })
|
|
43973
|
+
] }) });
|
|
43974
|
+
}
|
|
43975
|
+
return this.props.children;
|
|
43976
|
+
}
|
|
43977
|
+
};
|
|
43978
|
+
}
|
|
43979
|
+
});
|
|
43980
|
+
function detectAssetRoot2(modelUrl) {
|
|
43981
|
+
const idx = modelUrl.indexOf("/3d/");
|
|
43982
|
+
if (idx !== -1) {
|
|
43983
|
+
return modelUrl.substring(0, idx + 4);
|
|
43984
|
+
}
|
|
43985
|
+
return modelUrl.substring(0, modelUrl.lastIndexOf("/") + 1);
|
|
43986
|
+
}
|
|
43987
|
+
function useGLTFModel(url, resourceBasePath) {
|
|
43988
|
+
const [state, setState] = useState({
|
|
43989
|
+
model: null,
|
|
43990
|
+
isLoading: false,
|
|
43991
|
+
error: null
|
|
43992
|
+
});
|
|
43993
|
+
useEffect(() => {
|
|
43994
|
+
if (!url) {
|
|
43995
|
+
setState({ model: null, isLoading: false, error: null });
|
|
43996
|
+
return;
|
|
43997
|
+
}
|
|
43998
|
+
log10.debug("Loading", { url });
|
|
43999
|
+
setState((prev) => ({ ...prev, isLoading: true, error: null }));
|
|
44000
|
+
const assetRoot = resourceBasePath || detectAssetRoot2(url);
|
|
44001
|
+
const loader = new GLTFLoader$1();
|
|
44002
|
+
loader.setResourcePath(assetRoot);
|
|
44003
|
+
loader.load(
|
|
44004
|
+
url,
|
|
44005
|
+
(gltf) => {
|
|
44006
|
+
log10.debug("Loaded", { url });
|
|
44007
|
+
setState({
|
|
44008
|
+
model: gltf.scene,
|
|
44009
|
+
isLoading: false,
|
|
44010
|
+
error: null
|
|
44011
|
+
});
|
|
44012
|
+
},
|
|
44013
|
+
void 0,
|
|
44014
|
+
(err) => {
|
|
44015
|
+
log10.warn("Failed", { url, error: err instanceof Error ? err : String(err) });
|
|
44016
|
+
setState({
|
|
44017
|
+
model: null,
|
|
44018
|
+
isLoading: false,
|
|
44019
|
+
error: err instanceof Error ? err : new Error(String(err))
|
|
44020
|
+
});
|
|
44021
|
+
}
|
|
44022
|
+
);
|
|
44023
|
+
}, [url, resourceBasePath]);
|
|
44024
|
+
return state;
|
|
44025
|
+
}
|
|
44026
|
+
function ModelLoader({
|
|
44027
|
+
url,
|
|
44028
|
+
position = [0, 0, 0],
|
|
44029
|
+
scale = 1,
|
|
44030
|
+
rotation = [0, 0, 0],
|
|
44031
|
+
isSelected = false,
|
|
44032
|
+
isHovered = false,
|
|
44033
|
+
onClick,
|
|
44034
|
+
onHover,
|
|
44035
|
+
fallbackGeometry = "box",
|
|
44036
|
+
castShadow = true,
|
|
44037
|
+
receiveShadow = true,
|
|
44038
|
+
resourceBasePath
|
|
44039
|
+
}) {
|
|
44040
|
+
const { model: loadedModel, isLoading, error } = useGLTFModel(url, resourceBasePath);
|
|
44041
|
+
const model = useMemo(() => {
|
|
44042
|
+
if (!loadedModel) return null;
|
|
44043
|
+
const cloned = loadedModel.clone();
|
|
44044
|
+
cloned.traverse((child) => {
|
|
44045
|
+
if (child instanceof THREE.Mesh) {
|
|
44046
|
+
child.castShadow = castShadow;
|
|
44047
|
+
child.receiveShadow = receiveShadow;
|
|
44048
|
+
}
|
|
44049
|
+
});
|
|
44050
|
+
return cloned;
|
|
44051
|
+
}, [loadedModel, castShadow, receiveShadow]);
|
|
44052
|
+
const scaleArray = useMemo(() => {
|
|
44053
|
+
if (typeof scale === "number") {
|
|
44054
|
+
return [scale, scale, scale];
|
|
44055
|
+
}
|
|
44056
|
+
return scale;
|
|
44057
|
+
}, [scale]);
|
|
44058
|
+
const rotationRad = useMemo(() => {
|
|
44059
|
+
return [
|
|
44060
|
+
rotation[0] * Math.PI / 180,
|
|
44061
|
+
rotation[1] * Math.PI / 180,
|
|
44062
|
+
rotation[2] * Math.PI / 180
|
|
44063
|
+
];
|
|
44064
|
+
}, [rotation]);
|
|
44065
|
+
if (isLoading) {
|
|
44066
|
+
return /* @__PURE__ */ jsx("group", { position, children: /* @__PURE__ */ jsxs("mesh", { rotation: [Math.PI / 2, 0, 0], children: [
|
|
44067
|
+
/* @__PURE__ */ jsx("ringGeometry", { args: [0.3, 0.35, 16] }),
|
|
44068
|
+
/* @__PURE__ */ jsx("meshBasicMaterial", { color: "#4a90d9", transparent: true, opacity: 0.8 })
|
|
44069
|
+
] }) });
|
|
44070
|
+
}
|
|
44071
|
+
if (error || !model) {
|
|
44072
|
+
if (fallbackGeometry === "none") {
|
|
44073
|
+
return /* @__PURE__ */ jsx("group", { position });
|
|
44074
|
+
}
|
|
44075
|
+
const fallbackProps = {
|
|
44076
|
+
onClick,
|
|
44077
|
+
onPointerOver: () => onHover?.(true),
|
|
44078
|
+
onPointerOut: () => onHover?.(false)
|
|
44079
|
+
};
|
|
44080
|
+
return /* @__PURE__ */ jsxs("group", { position, children: [
|
|
44081
|
+
(isSelected || isHovered) && /* @__PURE__ */ jsxs("mesh", { position: [0, 0.02, 0], rotation: [-Math.PI / 2, 0, 0], children: [
|
|
44082
|
+
/* @__PURE__ */ jsx("ringGeometry", { args: [0.6, 0.7, 32] }),
|
|
44083
|
+
/* @__PURE__ */ jsx(
|
|
44084
|
+
"meshBasicMaterial",
|
|
44085
|
+
{
|
|
44086
|
+
color: isSelected ? 16755200 : 16777215,
|
|
44087
|
+
transparent: true,
|
|
44088
|
+
opacity: 0.5
|
|
44089
|
+
}
|
|
44090
|
+
)
|
|
44091
|
+
] }),
|
|
44092
|
+
fallbackGeometry === "box" && /* @__PURE__ */ jsxs("mesh", { ...fallbackProps, position: [0, 0.5, 0], children: [
|
|
44093
|
+
/* @__PURE__ */ jsx("boxGeometry", { args: [0.8, 0.8, 0.8] }),
|
|
44094
|
+
/* @__PURE__ */ jsx("meshStandardMaterial", { color: error ? 16729156 : 8947848 })
|
|
44095
|
+
] }),
|
|
44096
|
+
fallbackGeometry === "sphere" && /* @__PURE__ */ jsxs("mesh", { ...fallbackProps, position: [0, 0.5, 0], children: [
|
|
44097
|
+
/* @__PURE__ */ jsx("sphereGeometry", { args: [0.4, 16, 16] }),
|
|
44098
|
+
/* @__PURE__ */ jsx("meshStandardMaterial", { color: error ? 16729156 : 8947848 })
|
|
44099
|
+
] }),
|
|
44100
|
+
fallbackGeometry === "cylinder" && /* @__PURE__ */ jsxs("mesh", { ...fallbackProps, position: [0, 0.5, 0], children: [
|
|
44101
|
+
/* @__PURE__ */ jsx("cylinderGeometry", { args: [0.3, 0.3, 0.8, 16] }),
|
|
44102
|
+
/* @__PURE__ */ jsx("meshStandardMaterial", { color: error ? 16729156 : 8947848 })
|
|
44103
|
+
] })
|
|
44104
|
+
] });
|
|
44105
|
+
}
|
|
44106
|
+
return /* @__PURE__ */ jsxs(
|
|
44107
|
+
"group",
|
|
44108
|
+
{
|
|
44109
|
+
position,
|
|
44110
|
+
rotation: rotationRad,
|
|
44111
|
+
onClick,
|
|
44112
|
+
onPointerOver: () => onHover?.(true),
|
|
44113
|
+
onPointerOut: () => onHover?.(false),
|
|
44114
|
+
children: [
|
|
44115
|
+
(isSelected || isHovered) && /* @__PURE__ */ jsxs("mesh", { position: [0, 0.02, 0], rotation: [-Math.PI / 2, 0, 0], children: [
|
|
44116
|
+
/* @__PURE__ */ jsx("ringGeometry", { args: [0.6, 0.7, 32] }),
|
|
44117
|
+
/* @__PURE__ */ jsx(
|
|
44118
|
+
"meshBasicMaterial",
|
|
44119
|
+
{
|
|
44120
|
+
color: isSelected ? 16755200 : 16777215,
|
|
44121
|
+
transparent: true,
|
|
44122
|
+
opacity: 0.5
|
|
44123
|
+
}
|
|
44124
|
+
)
|
|
44125
|
+
] }),
|
|
44126
|
+
/* @__PURE__ */ jsx("primitive", { object: model, scale: scaleArray })
|
|
44127
|
+
]
|
|
44128
|
+
}
|
|
44129
|
+
);
|
|
44130
|
+
}
|
|
44131
|
+
var log10;
|
|
44132
|
+
var init_ModelLoader = __esm({
|
|
44133
|
+
"components/game/molecules/three/components/ModelLoader.tsx"() {
|
|
44134
|
+
"use client";
|
|
44135
|
+
log10 = createLogger("almadar:ui:game:model-loader");
|
|
44136
|
+
}
|
|
44137
|
+
});
|
|
44138
|
+
|
|
44139
|
+
// components/game/molecules/GameCanvas3D.css
|
|
44140
|
+
var init_GameCanvas3D = __esm({
|
|
44141
|
+
"components/game/molecules/GameCanvas3D.css"() {
|
|
44142
|
+
}
|
|
44143
|
+
});
|
|
44144
|
+
function CameraController({
|
|
44145
|
+
onCameraChange
|
|
44146
|
+
}) {
|
|
44147
|
+
const { camera } = useThree();
|
|
44148
|
+
useEffect(() => {
|
|
44149
|
+
if (onCameraChange) {
|
|
44150
|
+
onCameraChange({
|
|
44151
|
+
x: camera.position.x,
|
|
44152
|
+
y: camera.position.y,
|
|
44153
|
+
z: camera.position.z
|
|
44154
|
+
});
|
|
44155
|
+
}
|
|
44156
|
+
}, [camera.position, onCameraChange]);
|
|
44157
|
+
return null;
|
|
44158
|
+
}
|
|
44159
|
+
var DEFAULT_GRID_CONFIG, GameCanvas3D;
|
|
44160
|
+
var init_GameCanvas3D2 = __esm({
|
|
44161
|
+
"components/game/molecules/GameCanvas3D.tsx"() {
|
|
44162
|
+
"use client";
|
|
44163
|
+
init_AssetLoader();
|
|
44164
|
+
init_useAssetLoader();
|
|
44165
|
+
init_useGameCanvas3DEvents();
|
|
44166
|
+
init_Canvas3DLoadingState2();
|
|
44167
|
+
init_Canvas3DErrorBoundary2();
|
|
44168
|
+
init_ModelLoader();
|
|
44169
|
+
init_cn();
|
|
44170
|
+
init_GameCanvas3D();
|
|
44171
|
+
DEFAULT_GRID_CONFIG = {
|
|
44172
|
+
cellSize: 1,
|
|
44173
|
+
offsetX: 0,
|
|
44174
|
+
offsetZ: 0
|
|
44175
|
+
};
|
|
44176
|
+
GameCanvas3D = forwardRef(
|
|
44177
|
+
({
|
|
44178
|
+
tiles = [],
|
|
44179
|
+
units = [],
|
|
44180
|
+
features = [],
|
|
44181
|
+
events: events2 = [],
|
|
44182
|
+
orientation = "standard",
|
|
44183
|
+
cameraMode = "isometric",
|
|
44184
|
+
showGrid = true,
|
|
44185
|
+
showCoordinates = false,
|
|
44186
|
+
showTileInfo = false,
|
|
44187
|
+
overlay = "default",
|
|
44188
|
+
shadows = true,
|
|
44189
|
+
backgroundColor = "#1a1a2e",
|
|
44190
|
+
onTileClick,
|
|
44191
|
+
onUnitClick,
|
|
44192
|
+
onFeatureClick,
|
|
44193
|
+
onCanvasClick,
|
|
44194
|
+
onTileHover,
|
|
44195
|
+
onUnitAnimation,
|
|
44196
|
+
assetLoader: customAssetLoader,
|
|
44197
|
+
tileRenderer: CustomTileRenderer,
|
|
44198
|
+
unitRenderer: CustomUnitRenderer,
|
|
44199
|
+
featureRenderer: CustomFeatureRenderer,
|
|
44200
|
+
className,
|
|
44201
|
+
isLoading: externalLoading,
|
|
44202
|
+
error: externalError,
|
|
44203
|
+
entity,
|
|
44204
|
+
preloadAssets = [],
|
|
44205
|
+
tileClickEvent,
|
|
44206
|
+
unitClickEvent,
|
|
44207
|
+
featureClickEvent,
|
|
44208
|
+
canvasClickEvent,
|
|
44209
|
+
tileHoverEvent,
|
|
44210
|
+
tileLeaveEvent,
|
|
44211
|
+
unitAnimationEvent,
|
|
44212
|
+
cameraChangeEvent,
|
|
44213
|
+
loadingMessage = "Loading 3D Scene...",
|
|
44214
|
+
useInstancing = true,
|
|
44215
|
+
validMoves = [],
|
|
44216
|
+
attackTargets = [],
|
|
44217
|
+
selectedTileIds = [],
|
|
44218
|
+
selectedUnitId = null,
|
|
44219
|
+
children
|
|
44220
|
+
}, ref) => {
|
|
44221
|
+
const containerRef = useRef(null);
|
|
44222
|
+
const controlsRef = useRef(null);
|
|
44223
|
+
const [hoveredTile, setHoveredTile] = useState(null);
|
|
44224
|
+
const [internalError, setInternalError] = useState(null);
|
|
44225
|
+
const { isLoading: assetsLoading, progress, loaded, total } = useAssetLoader({
|
|
44226
|
+
preloadUrls: preloadAssets,
|
|
44227
|
+
loader: customAssetLoader
|
|
44228
|
+
});
|
|
44229
|
+
const eventHandlers = useGameCanvas3DEvents({
|
|
44230
|
+
tileClickEvent,
|
|
44231
|
+
unitClickEvent,
|
|
44232
|
+
featureClickEvent,
|
|
44233
|
+
canvasClickEvent,
|
|
44234
|
+
tileHoverEvent,
|
|
44235
|
+
tileLeaveEvent,
|
|
44236
|
+
unitAnimationEvent,
|
|
44237
|
+
cameraChangeEvent,
|
|
44238
|
+
onTileClick,
|
|
44239
|
+
onUnitClick,
|
|
44240
|
+
onFeatureClick,
|
|
44241
|
+
onCanvasClick,
|
|
44242
|
+
onTileHover,
|
|
44243
|
+
onUnitAnimation
|
|
44244
|
+
});
|
|
44245
|
+
const gridBounds = useMemo(() => {
|
|
44246
|
+
if (tiles.length === 0) {
|
|
44247
|
+
return { minX: 0, maxX: 10, minZ: 0, maxZ: 10 };
|
|
44248
|
+
}
|
|
44249
|
+
const xs = tiles.map((t) => t.x);
|
|
44250
|
+
const zs = tiles.map((t) => t.z || t.y || 0);
|
|
44251
|
+
return {
|
|
44252
|
+
minX: Math.min(...xs),
|
|
44253
|
+
maxX: Math.max(...xs),
|
|
44254
|
+
minZ: Math.min(...zs),
|
|
44255
|
+
maxZ: Math.max(...zs)
|
|
44256
|
+
};
|
|
44257
|
+
}, [tiles]);
|
|
44258
|
+
const cameraTarget = useMemo(() => {
|
|
44259
|
+
return [
|
|
44260
|
+
(gridBounds.minX + gridBounds.maxX) / 2,
|
|
44261
|
+
0,
|
|
44262
|
+
(gridBounds.minZ + gridBounds.maxZ) / 2
|
|
44263
|
+
];
|
|
44264
|
+
}, [gridBounds]);
|
|
44265
|
+
const gridConfig = useMemo(
|
|
44266
|
+
() => ({
|
|
44267
|
+
...DEFAULT_GRID_CONFIG,
|
|
44268
|
+
offsetX: -(gridBounds.maxX - gridBounds.minX) / 2,
|
|
44269
|
+
offsetZ: -(gridBounds.maxZ - gridBounds.minZ) / 2
|
|
44270
|
+
}),
|
|
44271
|
+
[gridBounds]
|
|
44272
|
+
);
|
|
44273
|
+
const gridToWorld = useCallback(
|
|
44274
|
+
(x, z, y = 0) => {
|
|
44275
|
+
const worldX = (x - gridBounds.minX) * gridConfig.cellSize;
|
|
44276
|
+
const worldZ = (z - gridBounds.minZ) * gridConfig.cellSize;
|
|
44277
|
+
return [worldX, y * gridConfig.cellSize, worldZ];
|
|
44278
|
+
},
|
|
44279
|
+
[gridBounds, gridConfig]
|
|
44280
|
+
);
|
|
44281
|
+
useImperativeHandle(ref, () => ({
|
|
44282
|
+
getCameraPosition: () => {
|
|
44283
|
+
if (controlsRef.current) {
|
|
44284
|
+
const pos = controlsRef.current.object.position;
|
|
44285
|
+
return new THREE.Vector3(pos.x, pos.y, pos.z);
|
|
44286
|
+
}
|
|
44287
|
+
return null;
|
|
44288
|
+
},
|
|
44289
|
+
setCameraPosition: (x, y, z) => {
|
|
44290
|
+
if (controlsRef.current) {
|
|
44291
|
+
controlsRef.current.object.position.set(x, y, z);
|
|
44292
|
+
controlsRef.current.update();
|
|
44293
|
+
}
|
|
44294
|
+
},
|
|
44295
|
+
lookAt: (x, y, z) => {
|
|
44296
|
+
if (controlsRef.current) {
|
|
44297
|
+
controlsRef.current.target.set(x, y, z);
|
|
44298
|
+
controlsRef.current.update();
|
|
44299
|
+
}
|
|
44300
|
+
},
|
|
44301
|
+
resetCamera: () => {
|
|
44302
|
+
if (controlsRef.current) {
|
|
44303
|
+
controlsRef.current.reset();
|
|
44304
|
+
}
|
|
44305
|
+
},
|
|
44306
|
+
screenshot: () => {
|
|
44307
|
+
const canvas = containerRef.current?.querySelector("canvas");
|
|
44308
|
+
if (canvas) {
|
|
44309
|
+
return canvas.toDataURL("image/png");
|
|
44310
|
+
}
|
|
44311
|
+
return null;
|
|
44312
|
+
},
|
|
44313
|
+
export: () => ({
|
|
44314
|
+
tiles,
|
|
44315
|
+
units,
|
|
44316
|
+
features
|
|
44317
|
+
})
|
|
44318
|
+
}));
|
|
44319
|
+
const handleTileClick = useCallback(
|
|
44320
|
+
(tile, event) => {
|
|
44321
|
+
eventHandlers.handleTileClick(tile, event);
|
|
44322
|
+
},
|
|
44323
|
+
[eventHandlers]
|
|
44324
|
+
);
|
|
44325
|
+
const handleUnitClick = useCallback(
|
|
44326
|
+
(unit, event) => {
|
|
44327
|
+
eventHandlers.handleUnitClick(unit, event);
|
|
44328
|
+
},
|
|
44329
|
+
[eventHandlers]
|
|
44330
|
+
);
|
|
44331
|
+
const handleFeatureClick = useCallback(
|
|
44332
|
+
(feature, event) => {
|
|
44333
|
+
if (event) {
|
|
44334
|
+
eventHandlers.handleFeatureClick(feature, event);
|
|
44335
|
+
}
|
|
44336
|
+
},
|
|
44337
|
+
[eventHandlers]
|
|
44338
|
+
);
|
|
44339
|
+
const handleTileHover = useCallback(
|
|
44340
|
+
(tile, event) => {
|
|
44341
|
+
setHoveredTile(tile);
|
|
44342
|
+
if (event) {
|
|
44343
|
+
eventHandlers.handleTileHover(tile, event);
|
|
44344
|
+
}
|
|
44345
|
+
},
|
|
44346
|
+
[eventHandlers]
|
|
44347
|
+
);
|
|
44348
|
+
const cameraConfig = useMemo(() => {
|
|
44349
|
+
const size = Math.max(
|
|
44350
|
+
gridBounds.maxX - gridBounds.minX,
|
|
44351
|
+
gridBounds.maxZ - gridBounds.minZ
|
|
44352
|
+
);
|
|
44353
|
+
const distance = size * 1.5;
|
|
44354
|
+
switch (cameraMode) {
|
|
44355
|
+
case "isometric":
|
|
44356
|
+
return {
|
|
44357
|
+
position: [distance, distance * 0.8, distance],
|
|
44358
|
+
fov: 45
|
|
44359
|
+
};
|
|
44360
|
+
case "top-down":
|
|
44361
|
+
return {
|
|
44362
|
+
position: [0, distance * 2, 0],
|
|
44363
|
+
fov: 45
|
|
44364
|
+
};
|
|
44365
|
+
case "perspective":
|
|
44366
|
+
default:
|
|
44367
|
+
return {
|
|
44368
|
+
position: [distance, distance, distance],
|
|
44369
|
+
fov: 45
|
|
44370
|
+
};
|
|
44371
|
+
}
|
|
44372
|
+
}, [cameraMode, gridBounds]);
|
|
44373
|
+
const DefaultTileRenderer = useCallback(
|
|
44374
|
+
({ tile, position }) => {
|
|
44375
|
+
const isSelected = tile.id ? selectedTileIds.includes(tile.id) : false;
|
|
44376
|
+
const isHovered = hoveredTile?.id === tile.id;
|
|
44377
|
+
const isValidMove = validMoves.some(
|
|
44378
|
+
(m) => m.x === tile.x && m.z === (tile.z ?? tile.y ?? 0)
|
|
44379
|
+
);
|
|
44380
|
+
const isAttackTarget = attackTargets.some(
|
|
44381
|
+
(m) => m.x === tile.x && m.z === (tile.z ?? tile.y ?? 0)
|
|
44382
|
+
);
|
|
44383
|
+
let color = 8421504;
|
|
44384
|
+
if (tile.type === "water") color = 4491468;
|
|
44385
|
+
else if (tile.type === "grass") color = 4500036;
|
|
44386
|
+
else if (tile.type === "sand") color = 14535816;
|
|
44387
|
+
else if (tile.type === "rock") color = 8947848;
|
|
44388
|
+
else if (tile.type === "snow") color = 15658734;
|
|
44389
|
+
let emissive = 0;
|
|
44390
|
+
if (isSelected) emissive = 4473924;
|
|
44391
|
+
else if (isAttackTarget) emissive = 4456448;
|
|
44392
|
+
else if (isValidMove) emissive = 17408;
|
|
44393
|
+
else if (isHovered) emissive = 2236962;
|
|
44394
|
+
if (tile.modelUrl) {
|
|
44395
|
+
return /* @__PURE__ */ jsx(
|
|
44396
|
+
"group",
|
|
44397
|
+
{
|
|
44398
|
+
position,
|
|
44399
|
+
onClick: (e) => handleTileClick(tile, e),
|
|
44400
|
+
onPointerEnter: (e) => handleTileHover(tile, e),
|
|
44401
|
+
onPointerLeave: (e) => handleTileHover(null, e),
|
|
44402
|
+
userData: { type: "tile", tileId: tile.id, gridX: tile.x, gridZ: tile.z ?? tile.y },
|
|
44403
|
+
children: /* @__PURE__ */ jsx(
|
|
44404
|
+
ModelLoader,
|
|
44405
|
+
{
|
|
44406
|
+
url: tile.modelUrl,
|
|
44407
|
+
scale: 0.95,
|
|
44408
|
+
fallbackGeometry: "box",
|
|
44409
|
+
castShadow: true,
|
|
44410
|
+
receiveShadow: true
|
|
44411
|
+
}
|
|
44412
|
+
)
|
|
44413
|
+
}
|
|
44414
|
+
);
|
|
44415
|
+
}
|
|
44416
|
+
return /* @__PURE__ */ jsxs(
|
|
44417
|
+
"mesh",
|
|
44418
|
+
{
|
|
44419
|
+
position,
|
|
44420
|
+
onClick: (e) => handleTileClick(tile, e),
|
|
44421
|
+
onPointerEnter: (e) => handleTileHover(tile, e),
|
|
44422
|
+
onPointerLeave: (e) => handleTileHover(null, e),
|
|
44423
|
+
userData: { type: "tile", tileId: tile.id, gridX: tile.x, gridZ: tile.z ?? tile.y },
|
|
44424
|
+
children: [
|
|
44425
|
+
/* @__PURE__ */ jsx("boxGeometry", { args: [0.95, 0.2, 0.95] }),
|
|
44426
|
+
/* @__PURE__ */ jsx("meshStandardMaterial", { color, emissive })
|
|
44427
|
+
]
|
|
44428
|
+
}
|
|
44429
|
+
);
|
|
44430
|
+
},
|
|
44431
|
+
[selectedTileIds, hoveredTile, validMoves, attackTargets, handleTileClick, handleTileHover]
|
|
44432
|
+
);
|
|
44433
|
+
const DefaultUnitRenderer = useCallback(
|
|
44434
|
+
({ unit, position }) => {
|
|
44435
|
+
const isSelected = selectedUnitId === unit.id;
|
|
44436
|
+
const color = unit.faction === "player" ? 4491519 : unit.faction === "enemy" ? 16729156 : 16777028;
|
|
44437
|
+
return /* @__PURE__ */ jsxs(
|
|
44438
|
+
"group",
|
|
44439
|
+
{
|
|
44440
|
+
position,
|
|
44441
|
+
onClick: (e) => handleUnitClick(unit, e),
|
|
44442
|
+
userData: { type: "unit", unitId: unit.id },
|
|
44443
|
+
children: [
|
|
44444
|
+
isSelected && /* @__PURE__ */ jsxs("mesh", { position: [0, 0.05, 0], rotation: [-Math.PI / 2, 0, 0], children: [
|
|
44445
|
+
/* @__PURE__ */ jsx("ringGeometry", { args: [0.4, 0.5, 32] }),
|
|
44446
|
+
/* @__PURE__ */ jsx("meshBasicMaterial", { color: "#ffff00", transparent: true, opacity: 0.8 })
|
|
44447
|
+
] }),
|
|
44448
|
+
unit.modelUrl ? (
|
|
44449
|
+
/* GLB unit model (box fallback while loading / on error) */
|
|
44450
|
+
/* @__PURE__ */ jsx(
|
|
44451
|
+
ModelLoader,
|
|
44452
|
+
{
|
|
44453
|
+
url: unit.modelUrl,
|
|
44454
|
+
scale: 0.5,
|
|
44455
|
+
fallbackGeometry: "box",
|
|
44456
|
+
castShadow: true
|
|
44457
|
+
}
|
|
44458
|
+
)
|
|
44459
|
+
) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
44460
|
+
/* @__PURE__ */ jsxs("mesh", { position: [0, 0.3, 0], children: [
|
|
44461
|
+
/* @__PURE__ */ jsx("cylinderGeometry", { args: [0.3, 0.3, 0.1, 8] }),
|
|
44462
|
+
/* @__PURE__ */ jsx("meshStandardMaterial", { color })
|
|
44463
|
+
] }),
|
|
44464
|
+
/* @__PURE__ */ jsxs("mesh", { position: [0, 0.6, 0], children: [
|
|
44465
|
+
/* @__PURE__ */ jsx("capsuleGeometry", { args: [0.2, 0.4, 4, 8] }),
|
|
44466
|
+
/* @__PURE__ */ jsx("meshStandardMaterial", { color })
|
|
44467
|
+
] }),
|
|
44468
|
+
/* @__PURE__ */ jsxs("mesh", { position: [0, 0.9, 0], children: [
|
|
44469
|
+
/* @__PURE__ */ jsx("sphereGeometry", { args: [0.12, 8, 8] }),
|
|
44470
|
+
/* @__PURE__ */ jsx("meshStandardMaterial", { color })
|
|
44471
|
+
] })
|
|
44472
|
+
] }),
|
|
44473
|
+
unit.health !== void 0 && unit.maxHealth !== void 0 && /* @__PURE__ */ jsxs("group", { position: [0, 1.2, 0], children: [
|
|
44474
|
+
/* @__PURE__ */ jsxs("mesh", { position: [-0.25, 0, 0], children: [
|
|
44475
|
+
/* @__PURE__ */ jsx("planeGeometry", { args: [0.5, 0.05] }),
|
|
44476
|
+
/* @__PURE__ */ jsx("meshBasicMaterial", { color: 3355443 })
|
|
44477
|
+
] }),
|
|
44478
|
+
/* @__PURE__ */ jsxs(
|
|
44479
|
+
"mesh",
|
|
44480
|
+
{
|
|
44481
|
+
position: [
|
|
44482
|
+
-0.25 + 0.5 * (unit.health / unit.maxHealth) / 2,
|
|
44483
|
+
0,
|
|
44484
|
+
0.01
|
|
44485
|
+
],
|
|
44486
|
+
children: [
|
|
44487
|
+
/* @__PURE__ */ jsx("planeGeometry", { args: [0.5 * (unit.health / unit.maxHealth), 0.05] }),
|
|
44488
|
+
/* @__PURE__ */ jsx(
|
|
44489
|
+
"meshBasicMaterial",
|
|
44490
|
+
{
|
|
44491
|
+
color: unit.health / unit.maxHealth > 0.5 ? 4500036 : unit.health / unit.maxHealth > 0.25 ? 11184708 : 16729156
|
|
44492
|
+
}
|
|
44493
|
+
)
|
|
44494
|
+
]
|
|
44495
|
+
}
|
|
44496
|
+
)
|
|
44497
|
+
] })
|
|
44498
|
+
]
|
|
44499
|
+
}
|
|
44500
|
+
);
|
|
44501
|
+
},
|
|
44502
|
+
[selectedUnitId, handleUnitClick]
|
|
44503
|
+
);
|
|
44504
|
+
const DefaultFeatureRenderer = useCallback(
|
|
44505
|
+
({
|
|
44506
|
+
feature,
|
|
44507
|
+
position
|
|
44508
|
+
}) => {
|
|
44509
|
+
if (feature.assetUrl) {
|
|
44510
|
+
return /* @__PURE__ */ jsx(
|
|
44511
|
+
ModelLoader,
|
|
44512
|
+
{
|
|
44513
|
+
url: feature.assetUrl,
|
|
44514
|
+
position,
|
|
44515
|
+
scale: 0.5,
|
|
44516
|
+
rotation: [0, feature.rotation ?? 0, 0],
|
|
44517
|
+
onClick: () => handleFeatureClick(feature, null),
|
|
44518
|
+
fallbackGeometry: "box"
|
|
44519
|
+
},
|
|
44520
|
+
feature.id
|
|
44521
|
+
);
|
|
44522
|
+
}
|
|
44523
|
+
if (feature.type === "tree") {
|
|
44524
|
+
return /* @__PURE__ */ jsxs(
|
|
44525
|
+
"group",
|
|
44526
|
+
{
|
|
44527
|
+
position,
|
|
44528
|
+
onClick: (e) => handleFeatureClick(feature, e),
|
|
44529
|
+
userData: { type: "feature", featureId: feature.id },
|
|
44530
|
+
children: [
|
|
44531
|
+
/* @__PURE__ */ jsxs("mesh", { position: [0, 0.4, 0], children: [
|
|
44532
|
+
/* @__PURE__ */ jsx("cylinderGeometry", { args: [0.1, 0.15, 0.8, 6] }),
|
|
44533
|
+
/* @__PURE__ */ jsx("meshStandardMaterial", { color: 9127187 })
|
|
44534
|
+
] }),
|
|
44535
|
+
/* @__PURE__ */ jsxs("mesh", { position: [0, 0.9, 0], children: [
|
|
44536
|
+
/* @__PURE__ */ jsx("coneGeometry", { args: [0.5, 0.8, 8] }),
|
|
44537
|
+
/* @__PURE__ */ jsx("meshStandardMaterial", { color: 2263842 })
|
|
44538
|
+
] })
|
|
44539
|
+
]
|
|
44540
|
+
}
|
|
44541
|
+
);
|
|
44542
|
+
}
|
|
44543
|
+
if (feature.type === "rock") {
|
|
44544
|
+
return /* @__PURE__ */ jsxs(
|
|
44545
|
+
"mesh",
|
|
44546
|
+
{
|
|
44547
|
+
position: [position[0], position[1] + 0.3, position[2]],
|
|
44548
|
+
onClick: (e) => handleFeatureClick(feature, e),
|
|
44549
|
+
userData: { type: "feature", featureId: feature.id },
|
|
44550
|
+
children: [
|
|
44551
|
+
/* @__PURE__ */ jsx("dodecahedronGeometry", { args: [0.3, 0] }),
|
|
44552
|
+
/* @__PURE__ */ jsx("meshStandardMaterial", { color: 8421504 })
|
|
44553
|
+
]
|
|
44554
|
+
}
|
|
44555
|
+
);
|
|
44556
|
+
}
|
|
44557
|
+
return null;
|
|
44558
|
+
},
|
|
44559
|
+
[handleFeatureClick]
|
|
44560
|
+
);
|
|
44561
|
+
if (externalLoading || assetsLoading && preloadAssets.length > 0) {
|
|
44562
|
+
return /* @__PURE__ */ jsx(
|
|
44563
|
+
Canvas3DLoadingState,
|
|
44564
|
+
{
|
|
44565
|
+
progress,
|
|
44566
|
+
loaded,
|
|
44567
|
+
total,
|
|
44568
|
+
message: loadingMessage,
|
|
44569
|
+
className
|
|
44570
|
+
}
|
|
44571
|
+
);
|
|
44572
|
+
}
|
|
44573
|
+
const displayError = externalError || internalError;
|
|
44574
|
+
if (displayError) {
|
|
44575
|
+
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: [
|
|
44576
|
+
"Error: ",
|
|
44577
|
+
displayError
|
|
44578
|
+
] }) }) });
|
|
44579
|
+
}
|
|
44580
|
+
return /* @__PURE__ */ jsx(
|
|
44581
|
+
Canvas3DErrorBoundary,
|
|
44582
|
+
{
|
|
44583
|
+
onError: (err) => setInternalError(err.message),
|
|
44584
|
+
onReset: () => setInternalError(null),
|
|
44585
|
+
children: /* @__PURE__ */ jsxs(
|
|
44586
|
+
"div",
|
|
44587
|
+
{
|
|
44588
|
+
ref: containerRef,
|
|
44589
|
+
className: cn("game-canvas-3d relative w-full h-full min-h-[85vh] overflow-hidden", className),
|
|
44590
|
+
"data-orientation": orientation,
|
|
44591
|
+
"data-camera-mode": cameraMode,
|
|
44592
|
+
"data-overlay": overlay,
|
|
44593
|
+
children: [
|
|
44594
|
+
/* @__PURE__ */ jsxs(
|
|
44595
|
+
Canvas,
|
|
44596
|
+
{
|
|
44597
|
+
shadows,
|
|
44598
|
+
camera: {
|
|
44599
|
+
position: cameraConfig.position,
|
|
44600
|
+
fov: cameraConfig.fov,
|
|
44601
|
+
near: 0.1,
|
|
44602
|
+
far: 1e3
|
|
44603
|
+
},
|
|
44604
|
+
style: { background: backgroundColor },
|
|
44605
|
+
onClick: (e) => {
|
|
44606
|
+
if (e.target === e.currentTarget) {
|
|
44607
|
+
eventHandlers.handleCanvasClick(e);
|
|
44608
|
+
}
|
|
44609
|
+
},
|
|
44610
|
+
children: [
|
|
44611
|
+
/* @__PURE__ */ jsx(CameraController, { onCameraChange: eventHandlers.handleCameraChange }),
|
|
44612
|
+
/* @__PURE__ */ jsx("ambientLight", { intensity: 0.6 }),
|
|
44613
|
+
/* @__PURE__ */ jsx(
|
|
44614
|
+
"directionalLight",
|
|
44615
|
+
{
|
|
44616
|
+
position: [10, 20, 10],
|
|
44617
|
+
intensity: 0.8,
|
|
44618
|
+
castShadow: shadows,
|
|
44619
|
+
"shadow-mapSize": [2048, 2048]
|
|
44620
|
+
}
|
|
44621
|
+
),
|
|
44622
|
+
/* @__PURE__ */ jsx("hemisphereLight", { intensity: 0.3, color: "#87ceeb", groundColor: "#362d1d" }),
|
|
44623
|
+
showGrid && /* @__PURE__ */ jsx(
|
|
44624
|
+
Grid$1,
|
|
44625
|
+
{
|
|
44626
|
+
args: [
|
|
44627
|
+
Math.max(gridBounds.maxX - gridBounds.minX + 2, 10),
|
|
44628
|
+
Math.max(gridBounds.maxZ - gridBounds.minZ + 2, 10)
|
|
44629
|
+
],
|
|
44630
|
+
position: [
|
|
44631
|
+
(gridBounds.maxX - gridBounds.minX) / 2 - 0.5,
|
|
44632
|
+
0,
|
|
44633
|
+
(gridBounds.maxZ - gridBounds.minZ) / 2 - 0.5
|
|
44634
|
+
],
|
|
44635
|
+
cellSize: 1,
|
|
44636
|
+
cellThickness: 1,
|
|
44637
|
+
cellColor: "#444444",
|
|
44638
|
+
sectionSize: 5,
|
|
44639
|
+
sectionThickness: 1.5,
|
|
44640
|
+
sectionColor: "#666666",
|
|
44641
|
+
fadeDistance: 50,
|
|
44642
|
+
fadeStrength: 1
|
|
44643
|
+
}
|
|
44644
|
+
),
|
|
44645
|
+
tiles.map((tile, index) => {
|
|
44646
|
+
const position = gridToWorld(
|
|
44647
|
+
tile.x,
|
|
44648
|
+
tile.z ?? tile.y ?? 0,
|
|
44649
|
+
tile.elevation ?? 0
|
|
44650
|
+
);
|
|
44651
|
+
const Renderer = CustomTileRenderer || DefaultTileRenderer;
|
|
44652
|
+
return /* @__PURE__ */ jsx(Renderer, { tile, position }, tile.id ?? `tile-${index}`);
|
|
44653
|
+
}),
|
|
44654
|
+
features.map((feature, index) => {
|
|
44655
|
+
const position = gridToWorld(
|
|
44656
|
+
feature.x,
|
|
44657
|
+
feature.z ?? feature.y ?? 0,
|
|
44658
|
+
(feature.elevation ?? 0) + 0.5
|
|
44659
|
+
);
|
|
44660
|
+
const Renderer = CustomFeatureRenderer || DefaultFeatureRenderer;
|
|
44661
|
+
return /* @__PURE__ */ jsx(Renderer, { feature, position }, feature.id ?? `feature-${index}`);
|
|
44662
|
+
}),
|
|
44663
|
+
units.map((unit) => {
|
|
44664
|
+
const position = gridToWorld(
|
|
44665
|
+
unit.x ?? 0,
|
|
44666
|
+
unit.z ?? unit.y ?? 0,
|
|
44667
|
+
(unit.elevation ?? 0) + 0.5
|
|
44668
|
+
);
|
|
44669
|
+
const Renderer = CustomUnitRenderer || DefaultUnitRenderer;
|
|
44670
|
+
return /* @__PURE__ */ jsx(Renderer, { unit, position }, unit.id);
|
|
44671
|
+
}),
|
|
44672
|
+
children,
|
|
44673
|
+
/* @__PURE__ */ jsx(
|
|
44674
|
+
OrbitControls,
|
|
44675
|
+
{
|
|
44676
|
+
ref: controlsRef,
|
|
44677
|
+
target: cameraTarget,
|
|
44678
|
+
enableDamping: true,
|
|
44679
|
+
dampingFactor: 0.05,
|
|
44680
|
+
minDistance: 2,
|
|
44681
|
+
maxDistance: 100,
|
|
44682
|
+
maxPolarAngle: Math.PI / 2 - 0.1
|
|
44683
|
+
}
|
|
44684
|
+
)
|
|
44685
|
+
]
|
|
44686
|
+
}
|
|
44687
|
+
),
|
|
44688
|
+
showCoordinates && hoveredTile && /* @__PURE__ */ jsxs("div", { className: "game-canvas-3d__coordinates", children: [
|
|
44689
|
+
"X: ",
|
|
44690
|
+
hoveredTile.x,
|
|
44691
|
+
", Z: ",
|
|
44692
|
+
hoveredTile.z ?? hoveredTile.y ?? 0
|
|
44693
|
+
] }),
|
|
44694
|
+
showTileInfo && hoveredTile && /* @__PURE__ */ jsxs("div", { className: "game-canvas-3d__tile-info", children: [
|
|
44695
|
+
/* @__PURE__ */ jsx("div", { className: "tile-info__type", children: hoveredTile.type }),
|
|
44696
|
+
hoveredTile.terrain && /* @__PURE__ */ jsx("div", { className: "tile-info__terrain", children: hoveredTile.terrain })
|
|
44697
|
+
] })
|
|
44698
|
+
]
|
|
44699
|
+
}
|
|
44700
|
+
)
|
|
44701
|
+
}
|
|
44702
|
+
);
|
|
44703
|
+
}
|
|
44704
|
+
);
|
|
44705
|
+
GameCanvas3D.displayName = "GameCanvas3D";
|
|
44706
|
+
}
|
|
44707
|
+
});
|
|
44708
|
+
function GameBoard3D({
|
|
44709
|
+
entity,
|
|
44710
|
+
tiles = [],
|
|
44711
|
+
features = [],
|
|
44712
|
+
cameraMode = "perspective",
|
|
44713
|
+
backgroundColor = "#2a1a1a",
|
|
44714
|
+
tileClickEvent,
|
|
44715
|
+
unitClickEvent,
|
|
44716
|
+
attackEvent,
|
|
44717
|
+
endTurnEvent,
|
|
44718
|
+
cancelEvent,
|
|
44719
|
+
playAgainEvent,
|
|
44720
|
+
gameEndEvent,
|
|
44721
|
+
className
|
|
44722
|
+
}) {
|
|
44723
|
+
const row = boardEntity(entity);
|
|
44724
|
+
const eventBus = useEventBus();
|
|
44725
|
+
const entityUnits = row ? rows(row.units) : [];
|
|
44726
|
+
const units = entityUnits;
|
|
44727
|
+
const selectedUnitId = row ? str(row.selectedUnitId) || null : null;
|
|
44728
|
+
const phase = row ? str(row.phase) : "observation";
|
|
44729
|
+
const result = row ? str(row.result) : "none";
|
|
44730
|
+
const validMoves = row && Array.isArray(row.validMoves) ? row.validMoves : [];
|
|
44731
|
+
const attackTargets = row && Array.isArray(row.attackTargets) ? row.attackTargets : [];
|
|
44732
|
+
const turn = row ? num(row.turn) : 0;
|
|
44733
|
+
const currentTeam = row ? str(row.currentTeam) : "player";
|
|
44734
|
+
const isGameOver = result !== "none";
|
|
44735
|
+
const gameEndEmittedRef = useRef(false);
|
|
44736
|
+
useEffect(() => {
|
|
44737
|
+
if ((result === "victory" || result === "defeat") && gameEndEvent) {
|
|
44738
|
+
if (!gameEndEmittedRef.current) {
|
|
44739
|
+
gameEndEmittedRef.current = true;
|
|
44740
|
+
eventBus.emit(`UI:${gameEndEvent}`, { result });
|
|
44741
|
+
}
|
|
44742
|
+
} else {
|
|
44743
|
+
gameEndEmittedRef.current = false;
|
|
44744
|
+
}
|
|
44745
|
+
}, [result, gameEndEvent, eventBus]);
|
|
44746
|
+
const checkGameEnd = useCallback(() => {
|
|
44747
|
+
const alivePlayer = entityUnits.filter((u) => unitTeam(u) === "player" && unitHealth(u) > 0);
|
|
44748
|
+
const aliveEnemy = entityUnits.filter((u) => unitTeam(u) === "enemy" && unitHealth(u) > 0);
|
|
44749
|
+
if (alivePlayer.length === 0 && gameEndEvent) {
|
|
44750
|
+
eventBus.emit(`UI:${gameEndEvent}`, { result: "defeat" });
|
|
44751
|
+
} else if (aliveEnemy.length === 0 && gameEndEvent) {
|
|
44752
|
+
eventBus.emit(`UI:${gameEndEvent}`, { result: "victory" });
|
|
44753
|
+
}
|
|
44754
|
+
}, [entityUnits, gameEndEvent, eventBus]);
|
|
44755
|
+
const handleUnitClickCallback = useCallback((isoUnit) => {
|
|
44756
|
+
if (phase !== "action" || !selectedUnitId || !attackEvent) return;
|
|
44757
|
+
const attackerRow = entityUnits.find((u) => str(u.id) === selectedUnitId);
|
|
44758
|
+
const targetRow = entityUnits.find((u) => str(u.id) === isoUnit.id);
|
|
44759
|
+
if (!attackerRow || !targetRow) return;
|
|
44760
|
+
if (unitTeam(targetRow) !== "enemy" || unitHealth(targetRow) <= 0) return;
|
|
44761
|
+
const ap = unitPosition(attackerRow);
|
|
44762
|
+
const tp = unitPosition(targetRow);
|
|
44763
|
+
const dx = Math.abs(ap.x - tp.x);
|
|
44764
|
+
const dy = Math.abs(ap.y - tp.y);
|
|
44765
|
+
if (dx <= 1 && dy <= 1 && dx + dy > 0) {
|
|
44766
|
+
const damage = Math.max(1, num(attackerRow.attack) - num(targetRow.defense));
|
|
44767
|
+
eventBus.emit(`UI:${attackEvent}`, {
|
|
44768
|
+
attackerId: str(attackerRow.id),
|
|
44769
|
+
targetId: str(targetRow.id),
|
|
44770
|
+
damage
|
|
44771
|
+
});
|
|
44772
|
+
setTimeout(checkGameEnd, 100);
|
|
44773
|
+
}
|
|
44774
|
+
}, [phase, selectedUnitId, entityUnits, attackEvent, eventBus, checkGameEnd]);
|
|
44775
|
+
const handleEndTurn = useCallback(() => {
|
|
44776
|
+
if (endTurnEvent) eventBus.emit(`UI:${endTurnEvent}`, {});
|
|
44777
|
+
}, [endTurnEvent, eventBus]);
|
|
44778
|
+
const handleCancel = useCallback(() => {
|
|
44779
|
+
if (cancelEvent) eventBus.emit(`UI:${cancelEvent}`, {});
|
|
44780
|
+
}, [cancelEvent, eventBus]);
|
|
44781
|
+
const handlePlayAgain = useCallback(() => {
|
|
44782
|
+
if (playAgainEvent) eventBus.emit(`UI:${playAgainEvent}`, {});
|
|
44783
|
+
}, [playAgainEvent, eventBus]);
|
|
44784
|
+
return /* @__PURE__ */ jsxs(VStack, { className: cn("game-board-3d block w-full min-h-[85vh] relative", className), children: [
|
|
44785
|
+
/* @__PURE__ */ jsxs("div", { className: "game-board-3d__status absolute top-3 left-3 z-10 flex gap-2 items-center", children: [
|
|
44786
|
+
/* @__PURE__ */ jsx(Typography, { variant: "small", className: "status__phase capitalize", children: phase.replace("_", " ") }),
|
|
44787
|
+
currentTeam && !isGameOver && /* @__PURE__ */ jsxs(Typography, { variant: "small", color: "muted", className: "status__team", children: [
|
|
44788
|
+
"\u2014 ",
|
|
44789
|
+
currentTeam === "player" ? "Your Turn" : "Enemy's Turn"
|
|
44790
|
+
] }),
|
|
44791
|
+
/* @__PURE__ */ jsxs(Typography, { variant: "small", color: "muted", className: "status__turn", children: [
|
|
44792
|
+
"Turn ",
|
|
44793
|
+
turn
|
|
44794
|
+
] })
|
|
44795
|
+
] }),
|
|
44796
|
+
/* @__PURE__ */ jsx(
|
|
44797
|
+
GameCanvas3D,
|
|
44798
|
+
{
|
|
44799
|
+
tiles,
|
|
44800
|
+
units,
|
|
44801
|
+
features,
|
|
44802
|
+
cameraMode,
|
|
44803
|
+
showGrid: true,
|
|
44804
|
+
showCoordinates: false,
|
|
44805
|
+
showTileInfo: false,
|
|
44806
|
+
shadows: true,
|
|
44807
|
+
backgroundColor,
|
|
44808
|
+
tileClickEvent,
|
|
44809
|
+
unitClickEvent,
|
|
44810
|
+
onUnitClick: handleUnitClickCallback,
|
|
44811
|
+
selectedUnitId,
|
|
44812
|
+
validMoves,
|
|
44813
|
+
attackTargets,
|
|
44814
|
+
className: "game-board-3d__canvas w-full min-h-[85vh]"
|
|
44815
|
+
}
|
|
44816
|
+
),
|
|
44817
|
+
!isGameOver && /* @__PURE__ */ jsxs(HStack, { className: "fixed bottom-6 right-6 z-50", gap: "sm", children: [
|
|
44818
|
+
(phase === "selection" || phase === "movement" || phase === "action") && /* @__PURE__ */ jsx(
|
|
44819
|
+
Button,
|
|
44820
|
+
{
|
|
44821
|
+
variant: "secondary",
|
|
44822
|
+
className: "shadow-xl",
|
|
44823
|
+
onClick: handleCancel,
|
|
44824
|
+
children: "Cancel"
|
|
44825
|
+
}
|
|
44826
|
+
),
|
|
44827
|
+
phase !== "enemy_turn" && /* @__PURE__ */ jsx(
|
|
44828
|
+
Button,
|
|
44829
|
+
{
|
|
44830
|
+
variant: "primary",
|
|
44831
|
+
className: "shadow-xl",
|
|
44832
|
+
onClick: handleEndTurn,
|
|
44833
|
+
children: "End Turn"
|
|
44834
|
+
}
|
|
44835
|
+
)
|
|
44836
|
+
] }),
|
|
44837
|
+
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: [
|
|
44838
|
+
/* @__PURE__ */ jsx(
|
|
44839
|
+
Typography,
|
|
44840
|
+
{
|
|
44841
|
+
variant: "h2",
|
|
44842
|
+
className: cn(
|
|
44843
|
+
"overlay__result",
|
|
44844
|
+
result === "victory" ? "text-yellow-400" : "text-red-500"
|
|
44845
|
+
),
|
|
44846
|
+
children: result === "victory" ? "Victory!" : "Defeat"
|
|
44847
|
+
}
|
|
44848
|
+
),
|
|
44849
|
+
/* @__PURE__ */ jsxs(Typography, { variant: "body", color: "muted", className: "overlay__turn-count", children: [
|
|
44850
|
+
"Completed in ",
|
|
44851
|
+
turn,
|
|
44852
|
+
" turn",
|
|
44853
|
+
turn !== 1 ? "s" : ""
|
|
44854
|
+
] }),
|
|
44855
|
+
/* @__PURE__ */ jsx(
|
|
44856
|
+
Button,
|
|
44857
|
+
{
|
|
44858
|
+
variant: "primary",
|
|
44859
|
+
className: "px-8 py-3 font-semibold",
|
|
44860
|
+
onClick: handlePlayAgain,
|
|
44861
|
+
children: "Play Again"
|
|
44862
|
+
}
|
|
44863
|
+
)
|
|
44864
|
+
] }) })
|
|
44865
|
+
] });
|
|
44866
|
+
}
|
|
44867
|
+
var init_GameBoard3D = __esm({
|
|
44868
|
+
"components/game/organisms/GameBoard3D.tsx"() {
|
|
44869
|
+
"use client";
|
|
44870
|
+
init_cn();
|
|
44871
|
+
init_Button();
|
|
44872
|
+
init_Typography();
|
|
44873
|
+
init_Stack();
|
|
44874
|
+
init_useEventBus();
|
|
44875
|
+
init_GameCanvas3D2();
|
|
44876
|
+
init_boardEntity();
|
|
44877
|
+
GameBoard3D.displayName = "GameBoard3D";
|
|
44878
|
+
}
|
|
44879
|
+
});
|
|
43225
44880
|
var GameShell;
|
|
43226
44881
|
var init_GameShell = __esm({
|
|
43227
44882
|
"components/game/templates/GameShell.tsx"() {
|
|
@@ -44764,6 +46419,236 @@ var init_NegotiatorBoard = __esm({
|
|
|
44764
46419
|
NegotiatorBoard.displayName = "NegotiatorBoard";
|
|
44765
46420
|
}
|
|
44766
46421
|
});
|
|
46422
|
+
function resolveEntity(entity) {
|
|
46423
|
+
if (!entity) return {};
|
|
46424
|
+
if (Array.isArray(entity)) return entity[0] ?? {};
|
|
46425
|
+
return entity;
|
|
46426
|
+
}
|
|
46427
|
+
function numField(row, key, fallback) {
|
|
46428
|
+
const v = row[key];
|
|
46429
|
+
return typeof v === "number" ? v : fallback;
|
|
46430
|
+
}
|
|
46431
|
+
function strField(row, key, fallback) {
|
|
46432
|
+
const v = row[key];
|
|
46433
|
+
return typeof v === "string" ? v : fallback;
|
|
46434
|
+
}
|
|
46435
|
+
function PlatformerBoard({
|
|
46436
|
+
entity,
|
|
46437
|
+
player: propPlayer,
|
|
46438
|
+
platforms: propPlatforms,
|
|
46439
|
+
result: propResult,
|
|
46440
|
+
lives: propLives,
|
|
46441
|
+
score: propScore,
|
|
46442
|
+
level: propLevel,
|
|
46443
|
+
worldWidth = 800,
|
|
46444
|
+
worldHeight = 400,
|
|
46445
|
+
canvasWidth = 800,
|
|
46446
|
+
canvasHeight = 400,
|
|
46447
|
+
playerSprite,
|
|
46448
|
+
tileSprites,
|
|
46449
|
+
bgColor,
|
|
46450
|
+
leftEvent = "LEFT",
|
|
46451
|
+
rightEvent = "RIGHT",
|
|
46452
|
+
jumpEvent = "JUMP",
|
|
46453
|
+
stopEvent = "STOP",
|
|
46454
|
+
playAgainEvent = "PLAY_AGAIN",
|
|
46455
|
+
gameEndEvent = "GAME_END",
|
|
46456
|
+
className
|
|
46457
|
+
}) {
|
|
46458
|
+
const row = resolveEntity(entity);
|
|
46459
|
+
const eventBus = useEventBus();
|
|
46460
|
+
const { t } = useTranslate();
|
|
46461
|
+
const result = propResult ?? strField(row, "result", "none");
|
|
46462
|
+
propLives ?? numField(row, "lives", 3);
|
|
46463
|
+
const score = propScore ?? numField(row, "score", 0);
|
|
46464
|
+
const level = propLevel ?? numField(row, "level", 1);
|
|
46465
|
+
const entityPlayer = row["player"];
|
|
46466
|
+
const player = propPlayer ?? entityPlayer ?? {
|
|
46467
|
+
x: 80,
|
|
46468
|
+
y: 320,
|
|
46469
|
+
width: 32,
|
|
46470
|
+
height: 48,
|
|
46471
|
+
vx: 0,
|
|
46472
|
+
vy: 0,
|
|
46473
|
+
grounded: false,
|
|
46474
|
+
facingRight: true
|
|
46475
|
+
};
|
|
46476
|
+
const entityPlatforms = Array.isArray(row["platforms"]) ? row["platforms"] : void 0;
|
|
46477
|
+
const platforms = propPlatforms ?? entityPlatforms ?? [
|
|
46478
|
+
{ x: 0, y: 368, width: 800, height: 32, type: "ground" },
|
|
46479
|
+
{ x: 150, y: 280, width: 160, height: 16, type: "platform" },
|
|
46480
|
+
{ x: 420, y: 220, width: 160, height: 16, type: "platform" },
|
|
46481
|
+
{ x: 580, y: 300, width: 80, height: 16, type: "hazard" },
|
|
46482
|
+
{ x: 700, y: 340, width: 64, height: 28, type: "goal" }
|
|
46483
|
+
];
|
|
46484
|
+
const handleRestart = useCallback(() => {
|
|
46485
|
+
if (playAgainEvent) {
|
|
46486
|
+
eventBus.emit(`UI:${playAgainEvent}`, {});
|
|
46487
|
+
}
|
|
46488
|
+
}, [playAgainEvent, eventBus]);
|
|
46489
|
+
const isGameOver = result === "won" || result === "lost";
|
|
46490
|
+
const gameEndEmittedRef = useRef(false);
|
|
46491
|
+
useEffect(() => {
|
|
46492
|
+
if ((result === "won" || result === "lost") && gameEndEvent) {
|
|
46493
|
+
if (!gameEndEmittedRef.current) {
|
|
46494
|
+
gameEndEmittedRef.current = true;
|
|
46495
|
+
eventBus.emit(`UI:${gameEndEvent}`, { result });
|
|
46496
|
+
}
|
|
46497
|
+
} else {
|
|
46498
|
+
gameEndEmittedRef.current = false;
|
|
46499
|
+
}
|
|
46500
|
+
}, [result, gameEndEvent, eventBus]);
|
|
46501
|
+
return /* @__PURE__ */ jsx(
|
|
46502
|
+
VStack,
|
|
46503
|
+
{
|
|
46504
|
+
className: cn("platformer-board relative bg-background", className),
|
|
46505
|
+
gap: "none",
|
|
46506
|
+
children: /* @__PURE__ */ jsxs(Box, { className: "relative", children: [
|
|
46507
|
+
/* @__PURE__ */ jsx(
|
|
46508
|
+
PlatformerCanvas,
|
|
46509
|
+
{
|
|
46510
|
+
player,
|
|
46511
|
+
platforms,
|
|
46512
|
+
worldWidth,
|
|
46513
|
+
worldHeight,
|
|
46514
|
+
canvasWidth,
|
|
46515
|
+
canvasHeight,
|
|
46516
|
+
followCamera: true,
|
|
46517
|
+
bgColor,
|
|
46518
|
+
playerSprite,
|
|
46519
|
+
tileSprites,
|
|
46520
|
+
leftEvent,
|
|
46521
|
+
rightEvent,
|
|
46522
|
+
jumpEvent,
|
|
46523
|
+
stopEvent
|
|
46524
|
+
}
|
|
46525
|
+
),
|
|
46526
|
+
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: [
|
|
46527
|
+
/* @__PURE__ */ jsx(
|
|
46528
|
+
Typography,
|
|
46529
|
+
{
|
|
46530
|
+
variant: "h2",
|
|
46531
|
+
className: cn(
|
|
46532
|
+
"text-4xl font-black tracking-widest uppercase",
|
|
46533
|
+
result === "won" ? "text-warning" : "text-error"
|
|
46534
|
+
),
|
|
46535
|
+
children: result === "won" ? t("platformer.won") : t("platformer.lost")
|
|
46536
|
+
}
|
|
46537
|
+
),
|
|
46538
|
+
result === "won" && /* @__PURE__ */ jsxs(Typography, { variant: "body1", className: "text-muted-foreground", children: [
|
|
46539
|
+
t("platformer.level"),
|
|
46540
|
+
" ",
|
|
46541
|
+
level,
|
|
46542
|
+
" \u2014 ",
|
|
46543
|
+
t("platformer.score"),
|
|
46544
|
+
": ",
|
|
46545
|
+
score
|
|
46546
|
+
] }),
|
|
46547
|
+
result === "lost" && /* @__PURE__ */ jsx(Typography, { variant: "body1", className: "text-muted-foreground", children: t("platformer.noLives") }),
|
|
46548
|
+
/* @__PURE__ */ jsx(
|
|
46549
|
+
Button,
|
|
46550
|
+
{
|
|
46551
|
+
variant: "primary",
|
|
46552
|
+
className: "px-8 py-3 font-semibold",
|
|
46553
|
+
onClick: handleRestart,
|
|
46554
|
+
children: result === "won" ? t("platformer.nextLevel") : t("platformer.playAgain")
|
|
46555
|
+
}
|
|
46556
|
+
)
|
|
46557
|
+
] }) })
|
|
46558
|
+
] })
|
|
46559
|
+
}
|
|
46560
|
+
);
|
|
46561
|
+
}
|
|
46562
|
+
var init_PlatformerBoard = __esm({
|
|
46563
|
+
"components/game/organisms/PlatformerBoard.tsx"() {
|
|
46564
|
+
"use client";
|
|
46565
|
+
init_cn();
|
|
46566
|
+
init_useEventBus();
|
|
46567
|
+
init_Box();
|
|
46568
|
+
init_Button();
|
|
46569
|
+
init_Typography();
|
|
46570
|
+
init_Stack();
|
|
46571
|
+
init_PlatformerCanvas();
|
|
46572
|
+
PlatformerBoard.displayName = "PlatformerBoard";
|
|
46573
|
+
}
|
|
46574
|
+
});
|
|
46575
|
+
function PlatformerTemplate({
|
|
46576
|
+
entity,
|
|
46577
|
+
platforms = DEFAULT_PLATFORMS,
|
|
46578
|
+
worldWidth = 800,
|
|
46579
|
+
worldHeight = 400,
|
|
46580
|
+
canvasWidth = 800,
|
|
46581
|
+
canvasHeight = 400,
|
|
46582
|
+
playerSprite = `${CDN3}/characters/platformChar_idle.png`,
|
|
46583
|
+
tileSprites = DEFAULT_TILE_SPRITES,
|
|
46584
|
+
bgColor = "#5c94fc",
|
|
46585
|
+
gameEndEvent = "GAME_END",
|
|
46586
|
+
className
|
|
46587
|
+
}) {
|
|
46588
|
+
const row = entity && !Array.isArray(entity) ? entity : void 0;
|
|
46589
|
+
const lives = typeof row?.["lives"] === "number" ? row["lives"] : 3;
|
|
46590
|
+
const score = typeof row?.["score"] === "number" ? row["score"] : 0;
|
|
46591
|
+
const level = typeof row?.["level"] === "number" ? row["level"] : 1;
|
|
46592
|
+
return /* @__PURE__ */ jsxs(VStack, { className: cn("platformer-template w-full", className), gap: "none", children: [
|
|
46593
|
+
/* @__PURE__ */ jsx(Box, { className: "relative", children: /* @__PURE__ */ jsx(
|
|
46594
|
+
GameHud,
|
|
46595
|
+
{
|
|
46596
|
+
position: "top",
|
|
46597
|
+
stats: [
|
|
46598
|
+
{ label: "Lives", value: lives, format: "number", variant: "danger" },
|
|
46599
|
+
{ label: "Level", value: level, format: "number", variant: "default" }
|
|
46600
|
+
]
|
|
46601
|
+
}
|
|
46602
|
+
) }),
|
|
46603
|
+
/* @__PURE__ */ jsx(
|
|
46604
|
+
PlatformerBoard,
|
|
46605
|
+
{
|
|
46606
|
+
entity,
|
|
46607
|
+
platforms,
|
|
46608
|
+
worldWidth,
|
|
46609
|
+
worldHeight,
|
|
46610
|
+
canvasWidth,
|
|
46611
|
+
canvasHeight,
|
|
46612
|
+
playerSprite,
|
|
46613
|
+
tileSprites,
|
|
46614
|
+
bgColor,
|
|
46615
|
+
leftEvent: "LEFT",
|
|
46616
|
+
rightEvent: "RIGHT",
|
|
46617
|
+
jumpEvent: "JUMP",
|
|
46618
|
+
stopEvent: "STOP",
|
|
46619
|
+
playAgainEvent: "PLAY_AGAIN",
|
|
46620
|
+
gameEndEvent
|
|
46621
|
+
}
|
|
46622
|
+
),
|
|
46623
|
+
/* @__PURE__ */ jsx(Box, { className: "px-4 py-2", children: /* @__PURE__ */ jsx(ScoreBoard, { score, level }) })
|
|
46624
|
+
] });
|
|
46625
|
+
}
|
|
46626
|
+
var CDN3, DEFAULT_TILE_SPRITES, DEFAULT_PLATFORMS;
|
|
46627
|
+
var init_PlatformerTemplate = __esm({
|
|
46628
|
+
"components/game/templates/PlatformerTemplate.tsx"() {
|
|
46629
|
+
init_cn();
|
|
46630
|
+
init_Box();
|
|
46631
|
+
init_Stack();
|
|
46632
|
+
init_PlatformerBoard();
|
|
46633
|
+
init_GameHud();
|
|
46634
|
+
init_ScoreBoard();
|
|
46635
|
+
CDN3 = "https://almadar-kflow-assets.web.app/shared/platformer";
|
|
46636
|
+
DEFAULT_TILE_SPRITES = {
|
|
46637
|
+
ground: `${CDN3}/tiles/platformPack_tile001.png`,
|
|
46638
|
+
platform: `${CDN3}/tiles/platformPack_tile004.png`,
|
|
46639
|
+
hazard: `${CDN3}/tiles/platformPack_tile017.png`,
|
|
46640
|
+
goal: `${CDN3}/tiles/platformPack_tile007.png`
|
|
46641
|
+
};
|
|
46642
|
+
DEFAULT_PLATFORMS = [
|
|
46643
|
+
{ x: 0, y: 368, width: 800, height: 32, type: "ground" },
|
|
46644
|
+
{ x: 150, y: 280, width: 160, height: 16, type: "platform" },
|
|
46645
|
+
{ x: 420, y: 220, width: 160, height: 16, type: "platform" },
|
|
46646
|
+
{ x: 580, y: 300, width: 80, height: 16, type: "hazard" },
|
|
46647
|
+
{ x: 700, y: 340, width: 64, height: 28, type: "goal" }
|
|
46648
|
+
];
|
|
46649
|
+
PlatformerTemplate.displayName = "PlatformerTemplate";
|
|
46650
|
+
}
|
|
46651
|
+
});
|
|
44767
46652
|
var PricingOrganism;
|
|
44768
46653
|
var init_PricingOrganism = __esm({
|
|
44769
46654
|
"components/marketing/organisms/PricingOrganism.tsx"() {
|
|
@@ -44886,6 +46771,356 @@ var init_PricingPageTemplate = __esm({
|
|
|
44886
46771
|
PricingPageTemplate.displayName = "PricingPageTemplate";
|
|
44887
46772
|
}
|
|
44888
46773
|
});
|
|
46774
|
+
function RoguelikeBoard({
|
|
46775
|
+
entity,
|
|
46776
|
+
tiles: propTiles,
|
|
46777
|
+
enemies: propEnemies,
|
|
46778
|
+
items: propItems,
|
|
46779
|
+
player: propPlayer,
|
|
46780
|
+
playerHp: propPlayerHp,
|
|
46781
|
+
playerMaxHp: propPlayerMaxHp,
|
|
46782
|
+
playerAttack: propPlayerAttack,
|
|
46783
|
+
depth: propDepth,
|
|
46784
|
+
result: propResult,
|
|
46785
|
+
phase: propPhase,
|
|
46786
|
+
stairsX: propStairsX,
|
|
46787
|
+
stairsY: propStairsY,
|
|
46788
|
+
assetManifest: propAssetManifest,
|
|
46789
|
+
scale = 0.45,
|
|
46790
|
+
unitScale = 1,
|
|
46791
|
+
moveEvent,
|
|
46792
|
+
playAgainEvent,
|
|
46793
|
+
gameEndEvent,
|
|
46794
|
+
className
|
|
46795
|
+
}) {
|
|
46796
|
+
const board = boardEntity(entity) ?? {};
|
|
46797
|
+
const tiles = propTiles ?? (Array.isArray(board.tiles) ? board.tiles : DEFAULT_TILES2);
|
|
46798
|
+
const enemies = propEnemies ?? (Array.isArray(board.enemies) ? board.enemies : DEFAULT_ENEMIES);
|
|
46799
|
+
const items = propItems ?? (Array.isArray(board.items) ? board.items : DEFAULT_ITEMS);
|
|
46800
|
+
const player = propPlayer ?? board.player ?? { x: 1, y: 1 };
|
|
46801
|
+
const playerHp = propPlayerHp ?? num(board.playerHp, 10);
|
|
46802
|
+
const playerMaxHp = propPlayerMaxHp ?? num(board.playerMaxHp, 10);
|
|
46803
|
+
const playerAttack = propPlayerAttack ?? num(board.playerAttack, 3);
|
|
46804
|
+
const depth = propDepth ?? num(board.depth, 1);
|
|
46805
|
+
const result = propResult ?? (str(board.result) || "none");
|
|
46806
|
+
const phase = propPhase ?? (str(board.phase) || "player_turn");
|
|
46807
|
+
propStairsX ?? num(board.stairsX, 3);
|
|
46808
|
+
propStairsY ?? num(board.stairsY, 3);
|
|
46809
|
+
const eventBus = useEventBus();
|
|
46810
|
+
const { t } = useTranslate();
|
|
46811
|
+
const [hoveredTile, setHoveredTile] = useState(null);
|
|
46812
|
+
const emitMove = useCallback((dx, dy) => {
|
|
46813
|
+
if (!moveEvent) return;
|
|
46814
|
+
eventBus.emit(`UI:${moveEvent}`, { dx, dy });
|
|
46815
|
+
}, [moveEvent, eventBus]);
|
|
46816
|
+
useEffect(() => {
|
|
46817
|
+
const handler = (e) => {
|
|
46818
|
+
if (result !== "none" || phase !== "player_turn") return;
|
|
46819
|
+
if (e.key === "ArrowUp" || e.key === "w") emitMove(0, -1);
|
|
46820
|
+
if (e.key === "ArrowDown" || e.key === "s") emitMove(0, 1);
|
|
46821
|
+
if (e.key === "ArrowLeft" || e.key === "a") emitMove(-1, 0);
|
|
46822
|
+
if (e.key === "ArrowRight" || e.key === "d") emitMove(1, 0);
|
|
46823
|
+
};
|
|
46824
|
+
window.addEventListener("keydown", handler);
|
|
46825
|
+
return () => window.removeEventListener("keydown", handler);
|
|
46826
|
+
}, [result, phase, emitMove]);
|
|
46827
|
+
useEffect(() => {
|
|
46828
|
+
if ((result === "won" || result === "lost") && gameEndEvent) {
|
|
46829
|
+
eventBus.emit(`UI:${gameEndEvent}`, { result });
|
|
46830
|
+
}
|
|
46831
|
+
}, [result, gameEndEvent, eventBus]);
|
|
46832
|
+
const handleTileClick = useCallback((x, y) => {
|
|
46833
|
+
if (result !== "none" || phase !== "player_turn") return;
|
|
46834
|
+
const dx = x - player.x;
|
|
46835
|
+
const dy = y - player.y;
|
|
46836
|
+
if (Math.abs(dx) + Math.abs(dy) === 1) {
|
|
46837
|
+
emitMove(dx, dy);
|
|
46838
|
+
}
|
|
46839
|
+
}, [result, phase, player, emitMove]);
|
|
46840
|
+
const handleReset = useCallback(() => {
|
|
46841
|
+
if (!playAgainEvent) return;
|
|
46842
|
+
eventBus.emit(`UI:${playAgainEvent}`, {});
|
|
46843
|
+
}, [playAgainEvent, eventBus]);
|
|
46844
|
+
const isoUnits = useMemo(() => {
|
|
46845
|
+
const liveEnemies = enemies.filter((e) => e.hp > 0);
|
|
46846
|
+
return [
|
|
46847
|
+
{
|
|
46848
|
+
id: "player",
|
|
46849
|
+
position: player,
|
|
46850
|
+
name: t("roguelike.player") || "Hero",
|
|
46851
|
+
team: "player",
|
|
46852
|
+
health: playerHp,
|
|
46853
|
+
maxHealth: playerMaxHp,
|
|
46854
|
+
unitType: "player",
|
|
46855
|
+
sprite: `${CDN4}/isometric-dungeon/Characters/Male/Male_0_Idle0.png`
|
|
46856
|
+
},
|
|
46857
|
+
...liveEnemies.map((e) => ({
|
|
46858
|
+
id: e.id,
|
|
46859
|
+
position: { x: e.x, y: e.y },
|
|
46860
|
+
name: t("roguelike.enemy") || "Enemy",
|
|
46861
|
+
team: "enemy",
|
|
46862
|
+
health: e.hp,
|
|
46863
|
+
maxHealth: 6,
|
|
46864
|
+
unitType: "enemy",
|
|
46865
|
+
sprite: `${CDN4}/sprite-sheets/shadow-legion-sprite-sheet-sw.png`
|
|
46866
|
+
}))
|
|
46867
|
+
];
|
|
46868
|
+
}, [player, enemies, playerHp, playerMaxHp, t]);
|
|
46869
|
+
const isoFeatures = useMemo(
|
|
46870
|
+
() => items.map((it) => ({
|
|
46871
|
+
id: it.id,
|
|
46872
|
+
x: it.x,
|
|
46873
|
+
y: it.y,
|
|
46874
|
+
type: it.kind,
|
|
46875
|
+
sprite: FEATURE_SPRITE[it.kind] ?? FEATURE_SPRITE.health_potion
|
|
46876
|
+
})),
|
|
46877
|
+
[items]
|
|
46878
|
+
);
|
|
46879
|
+
const validMoves = useMemo(() => {
|
|
46880
|
+
if (result !== "none" || phase !== "player_turn") return [];
|
|
46881
|
+
const dirs = [{ dx: 0, dy: -1 }, { dx: 0, dy: 1 }, { dx: -1, dy: 0 }, { dx: 1, dy: 0 }];
|
|
46882
|
+
return dirs.map(({ dx, dy }) => ({ x: player.x + dx, y: player.y + dy })).filter(({ x, y }) => {
|
|
46883
|
+
const tile = tiles.find((t2) => t2.x === x && t2.y === y);
|
|
46884
|
+
return tile?.passable ?? false;
|
|
46885
|
+
});
|
|
46886
|
+
}, [result, phase, player, tiles]);
|
|
46887
|
+
const isGameOver = result === "won" || result === "lost";
|
|
46888
|
+
return /* @__PURE__ */ jsxs(VStack, { className: cn("roguelike-board relative min-h-[600px] bg-background", className), gap: "none", children: [
|
|
46889
|
+
/* @__PURE__ */ jsxs(HStack, { className: "items-center justify-between px-4 py-2 border-b border-border", gap: "md", children: [
|
|
46890
|
+
/* @__PURE__ */ jsxs(HStack, { gap: "sm", className: "items-center", children: [
|
|
46891
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: t("roguelike.depth") || "Depth" }),
|
|
46892
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body1", className: "font-bold tabular-nums", children: depth })
|
|
46893
|
+
] }),
|
|
46894
|
+
/* @__PURE__ */ jsxs(HStack, { gap: "sm", className: "items-center", children: [
|
|
46895
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: t("roguelike.hp") || "HP" }),
|
|
46896
|
+
/* @__PURE__ */ jsxs(
|
|
46897
|
+
Typography,
|
|
46898
|
+
{
|
|
46899
|
+
variant: "body1",
|
|
46900
|
+
className: cn(
|
|
46901
|
+
"font-bold tabular-nums",
|
|
46902
|
+
playerHp <= Math.floor(playerMaxHp * 0.25) ? "text-error" : "text-success"
|
|
46903
|
+
),
|
|
46904
|
+
children: [
|
|
46905
|
+
playerHp,
|
|
46906
|
+
" / ",
|
|
46907
|
+
playerMaxHp
|
|
46908
|
+
]
|
|
46909
|
+
}
|
|
46910
|
+
)
|
|
46911
|
+
] }),
|
|
46912
|
+
/* @__PURE__ */ jsxs(HStack, { gap: "sm", className: "items-center", children: [
|
|
46913
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: t("roguelike.atk") || "ATK" }),
|
|
46914
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body1", className: "font-bold tabular-nums text-foreground", children: playerAttack })
|
|
46915
|
+
] }),
|
|
46916
|
+
/* @__PURE__ */ jsxs(HStack, { gap: "sm", className: "items-center", children: [
|
|
46917
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: t("roguelike.phase") || "Phase" }),
|
|
46918
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body2", className: "capitalize text-foreground", children: phase.replace("_", " ") })
|
|
46919
|
+
] })
|
|
46920
|
+
] }),
|
|
46921
|
+
/* @__PURE__ */ jsx(Box, { className: "relative flex-1", children: /* @__PURE__ */ jsx(
|
|
46922
|
+
IsometricCanvas_default,
|
|
46923
|
+
{
|
|
46924
|
+
tiles,
|
|
46925
|
+
units: isoUnits,
|
|
46926
|
+
features: isoFeatures,
|
|
46927
|
+
selectedUnitId: null,
|
|
46928
|
+
validMoves,
|
|
46929
|
+
attackTargets: [],
|
|
46930
|
+
hoveredTile,
|
|
46931
|
+
onTileClick: handleTileClick,
|
|
46932
|
+
onUnitClick: () => void 0,
|
|
46933
|
+
onTileHover: (x, y) => setHoveredTile({ x, y }),
|
|
46934
|
+
onTileLeave: () => setHoveredTile(null),
|
|
46935
|
+
scale,
|
|
46936
|
+
assetBaseUrl: propAssetManifest?.baseUrl ?? CDN4,
|
|
46937
|
+
assetManifest: propAssetManifest,
|
|
46938
|
+
unitScale
|
|
46939
|
+
}
|
|
46940
|
+
) }),
|
|
46941
|
+
!isGameOver && /* @__PURE__ */ jsx(HStack, { className: "justify-center gap-2 p-3", gap: "none", children: [
|
|
46942
|
+
{ label: "\u2191", dx: 0, dy: -1 },
|
|
46943
|
+
{ label: "\u2193", dx: 0, dy: 1 },
|
|
46944
|
+
{ label: "\u2190", dx: -1, dy: 0 },
|
|
46945
|
+
{ label: "\u2192", dx: 1, dy: 0 }
|
|
46946
|
+
].map(({ label, dx, dy }) => /* @__PURE__ */ jsx(
|
|
46947
|
+
Button,
|
|
46948
|
+
{
|
|
46949
|
+
variant: "secondary",
|
|
46950
|
+
className: "w-9 h-9 p-0 text-base font-mono",
|
|
46951
|
+
onClick: () => emitMove(dx, dy),
|
|
46952
|
+
disabled: phase !== "player_turn",
|
|
46953
|
+
children: label
|
|
46954
|
+
},
|
|
46955
|
+
label
|
|
46956
|
+
)) }),
|
|
46957
|
+
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: [
|
|
46958
|
+
/* @__PURE__ */ jsx(
|
|
46959
|
+
Typography,
|
|
46960
|
+
{
|
|
46961
|
+
variant: "h2",
|
|
46962
|
+
className: cn(
|
|
46963
|
+
"text-4xl font-black tracking-widest uppercase",
|
|
46964
|
+
result === "won" ? "text-warning" : "text-error"
|
|
46965
|
+
),
|
|
46966
|
+
children: result === "won" ? t("roguelike.victory") || "Victory!" : t("roguelike.defeat") || "Defeated!"
|
|
46967
|
+
}
|
|
46968
|
+
),
|
|
46969
|
+
result === "won" && /* @__PURE__ */ jsx(Typography, { variant: "body1", className: "text-muted-foreground", children: t("roguelike.cleared") || `Dungeon cleared! Depth reached: ${depth}` }),
|
|
46970
|
+
/* @__PURE__ */ jsx(
|
|
46971
|
+
Button,
|
|
46972
|
+
{
|
|
46973
|
+
variant: "primary",
|
|
46974
|
+
className: "px-8 py-3 font-semibold",
|
|
46975
|
+
onClick: handleReset,
|
|
46976
|
+
children: t("roguelike.playAgain") || "Play Again"
|
|
46977
|
+
}
|
|
46978
|
+
)
|
|
46979
|
+
] }) })
|
|
46980
|
+
] });
|
|
46981
|
+
}
|
|
46982
|
+
var CDN4, DEFAULT_TILES2, DEFAULT_ENEMIES, DEFAULT_ITEMS, FEATURE_SPRITE;
|
|
46983
|
+
var init_RoguelikeBoard = __esm({
|
|
46984
|
+
"components/game/organisms/RoguelikeBoard.tsx"() {
|
|
46985
|
+
"use client";
|
|
46986
|
+
init_cn();
|
|
46987
|
+
init_useEventBus();
|
|
46988
|
+
init_Box();
|
|
46989
|
+
init_Button();
|
|
46990
|
+
init_Typography();
|
|
46991
|
+
init_Stack();
|
|
46992
|
+
init_IsometricCanvas();
|
|
46993
|
+
init_boardEntity();
|
|
46994
|
+
CDN4 = "https://almadar-kflow-assets.web.app/shared";
|
|
46995
|
+
DEFAULT_TILES2 = [
|
|
46996
|
+
{ x: 0, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
46997
|
+
{ x: 1, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
46998
|
+
{ x: 2, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
46999
|
+
{ x: 3, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
47000
|
+
{ x: 4, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
47001
|
+
{ x: 0, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
47002
|
+
{ x: 1, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
|
|
47003
|
+
{ x: 2, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
|
|
47004
|
+
{ x: 3, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
|
|
47005
|
+
{ x: 4, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
47006
|
+
{ x: 0, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
47007
|
+
{ x: 1, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png` },
|
|
47008
|
+
{ x: 2, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png` },
|
|
47009
|
+
{ x: 3, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
|
|
47010
|
+
{ x: 4, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
47011
|
+
{ x: 0, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
47012
|
+
{ x: 1, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
|
|
47013
|
+
{ x: 2, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png` },
|
|
47014
|
+
{ x: 3, y: 3, terrain: "stairs", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stairs_E.png` },
|
|
47015
|
+
{ x: 4, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
47016
|
+
{ x: 0, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
47017
|
+
{ x: 1, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
47018
|
+
{ x: 2, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
47019
|
+
{ x: 3, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
47020
|
+
{ x: 4, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` }
|
|
47021
|
+
];
|
|
47022
|
+
DEFAULT_ENEMIES = [
|
|
47023
|
+
{ id: "e1", x: 3, y: 1, hp: 5, attack: 2 },
|
|
47024
|
+
{ id: "e2", x: 1, y: 3, hp: 4, attack: 1 }
|
|
47025
|
+
];
|
|
47026
|
+
DEFAULT_ITEMS = [
|
|
47027
|
+
{ id: "i1", x: 2, y: 2, kind: "health_potion" }
|
|
47028
|
+
];
|
|
47029
|
+
FEATURE_SPRITE = {
|
|
47030
|
+
health_potion: `${CDN4}/isometric-dungeon/Isometric/chestClosed_E.png`,
|
|
47031
|
+
sword: `${CDN4}/isometric-dungeon/Isometric/barrel_E.png`,
|
|
47032
|
+
shield: `${CDN4}/isometric-dungeon/Isometric/barrel_E.png`
|
|
47033
|
+
};
|
|
47034
|
+
RoguelikeBoard.displayName = "RoguelikeBoard";
|
|
47035
|
+
}
|
|
47036
|
+
});
|
|
47037
|
+
function RoguelikeTemplate({
|
|
47038
|
+
entity,
|
|
47039
|
+
scale = 0.45,
|
|
47040
|
+
unitScale = 1,
|
|
47041
|
+
tiles = DEFAULT_ROGUELIKE_TILES,
|
|
47042
|
+
enemies,
|
|
47043
|
+
items,
|
|
47044
|
+
stairsX,
|
|
47045
|
+
stairsY,
|
|
47046
|
+
assetManifest = DEFAULT_ROGUELIKE_MANIFEST,
|
|
47047
|
+
gameEndEvent,
|
|
47048
|
+
className
|
|
47049
|
+
}) {
|
|
47050
|
+
const resolved = entity && typeof entity === "object" && !Array.isArray(entity) ? entity : void 0;
|
|
47051
|
+
if (!resolved && !tiles && !assetManifest) return null;
|
|
47052
|
+
return /* @__PURE__ */ jsx(
|
|
47053
|
+
RoguelikeBoard,
|
|
47054
|
+
{
|
|
47055
|
+
entity: resolved,
|
|
47056
|
+
tiles,
|
|
47057
|
+
enemies,
|
|
47058
|
+
items,
|
|
47059
|
+
stairsX,
|
|
47060
|
+
stairsY,
|
|
47061
|
+
assetManifest,
|
|
47062
|
+
scale,
|
|
47063
|
+
unitScale,
|
|
47064
|
+
moveEvent: "MOVE",
|
|
47065
|
+
playAgainEvent: "PLAY_AGAIN",
|
|
47066
|
+
gameEndEvent: gameEndEvent ?? "GAME_END",
|
|
47067
|
+
className
|
|
47068
|
+
}
|
|
47069
|
+
);
|
|
47070
|
+
}
|
|
47071
|
+
var CDN5, DEFAULT_ROGUELIKE_TILES, DEFAULT_ROGUELIKE_MANIFEST;
|
|
47072
|
+
var init_RoguelikeTemplate = __esm({
|
|
47073
|
+
"components/game/templates/RoguelikeTemplate.tsx"() {
|
|
47074
|
+
init_RoguelikeBoard();
|
|
47075
|
+
CDN5 = "https://almadar-kflow-assets.web.app/shared";
|
|
47076
|
+
DEFAULT_ROGUELIKE_TILES = [
|
|
47077
|
+
{ x: 0, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
47078
|
+
{ x: 1, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
47079
|
+
{ x: 2, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
47080
|
+
{ x: 3, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
47081
|
+
{ x: 4, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
47082
|
+
{ x: 0, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
47083
|
+
{ x: 1, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirt_E.png` },
|
|
47084
|
+
{ x: 2, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirt_E.png` },
|
|
47085
|
+
{ x: 3, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirt_E.png` },
|
|
47086
|
+
{ x: 4, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
47087
|
+
{ x: 0, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
47088
|
+
{ x: 1, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirtTiles_E.png` },
|
|
47089
|
+
{ x: 2, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirtTiles_E.png` },
|
|
47090
|
+
{ x: 3, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirt_E.png` },
|
|
47091
|
+
{ x: 4, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
47092
|
+
{ x: 0, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
47093
|
+
{ x: 1, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirt_E.png` },
|
|
47094
|
+
{ x: 2, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/dirtTiles_E.png` },
|
|
47095
|
+
{ x: 3, y: 3, terrain: "stairs", passable: true, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stairs_E.png` },
|
|
47096
|
+
{ x: 4, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
47097
|
+
{ x: 0, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
47098
|
+
{ x: 1, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
47099
|
+
{ x: 2, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
47100
|
+
{ x: 3, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` },
|
|
47101
|
+
{ x: 4, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN5}/isometric-dungeon/Isometric/stoneInset_E.png` }
|
|
47102
|
+
];
|
|
47103
|
+
DEFAULT_ROGUELIKE_MANIFEST = {
|
|
47104
|
+
baseUrl: CDN5,
|
|
47105
|
+
terrains: {
|
|
47106
|
+
floor: "/isometric-dungeon/Isometric/dirt_E.png",
|
|
47107
|
+
wall: "/isometric-dungeon/Isometric/stoneInset_E.png",
|
|
47108
|
+
stairs: "/isometric-dungeon/Isometric/stairs_E.png",
|
|
47109
|
+
planks: "/isometric-dungeon/Isometric/planks_E.png"
|
|
47110
|
+
},
|
|
47111
|
+
units: {
|
|
47112
|
+
player: "/isometric-dungeon/Characters/Male/Male_0_Idle0.png",
|
|
47113
|
+
enemy: "/sprite-sheets/shadow-legion-sprite-sheet-sw.png"
|
|
47114
|
+
},
|
|
47115
|
+
features: {
|
|
47116
|
+
health_potion: "/isometric-dungeon/Isometric/chestClosed_E.png",
|
|
47117
|
+
sword: "/isometric-dungeon/Isometric/barrel_E.png",
|
|
47118
|
+
shield: "/isometric-dungeon/Isometric/barrel_E.png"
|
|
47119
|
+
}
|
|
47120
|
+
};
|
|
47121
|
+
RoguelikeTemplate.displayName = "RoguelikeTemplate";
|
|
47122
|
+
}
|
|
47123
|
+
});
|
|
44889
47124
|
|
|
44890
47125
|
// lib/traitRegistry.ts
|
|
44891
47126
|
function notifyListeners2() {
|
|
@@ -46139,7 +48374,7 @@ function getAllEvents(traits2) {
|
|
|
46139
48374
|
function EventDispatcherTab({ traits: traits2, schema }) {
|
|
46140
48375
|
const eventBus = useEventBus();
|
|
46141
48376
|
const { t } = useTranslate();
|
|
46142
|
-
const [
|
|
48377
|
+
const [log15, setLog] = React91.useState([]);
|
|
46143
48378
|
const prevStatesRef = React91.useRef(/* @__PURE__ */ new Map());
|
|
46144
48379
|
React91.useEffect(() => {
|
|
46145
48380
|
for (const trait of traits2) {
|
|
@@ -46203,9 +48438,9 @@ function EventDispatcherTab({ traits: traits2, schema }) {
|
|
|
46203
48438
|
/* @__PURE__ */ jsx(Typography, { variant: "small", weight: "medium", className: "text-gray-500 mb-1", children: t("debug.otherEvents") }),
|
|
46204
48439
|
/* @__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)) })
|
|
46205
48440
|
] }),
|
|
46206
|
-
|
|
48441
|
+
log15.length > 0 && /* @__PURE__ */ jsxs("div", { children: [
|
|
46207
48442
|
/* @__PURE__ */ jsx(Typography, { variant: "small", weight: "medium", className: "text-gray-500 mb-1", children: t("debug.recentTransitions") }),
|
|
46208
|
-
/* @__PURE__ */ jsx(Stack, { gap: "xs", children:
|
|
48443
|
+
/* @__PURE__ */ jsx(Stack, { gap: "xs", children: log15.map((entry, i) => /* @__PURE__ */ jsxs(Typography, { variant: "small", className: "font-mono text-xs", children: [
|
|
46209
48444
|
/* @__PURE__ */ jsx("span", { className: "text-purple-400", children: entry.traitName }),
|
|
46210
48445
|
" ",
|
|
46211
48446
|
/* @__PURE__ */ jsx("span", { className: "text-gray-500", children: entry.from }),
|
|
@@ -48126,9 +50361,9 @@ function VariablePanel({
|
|
|
48126
50361
|
/* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-muted-foreground font-medium", children: t("stateArchitect.variables", { name: entityName }) }),
|
|
48127
50362
|
variables.map((v) => {
|
|
48128
50363
|
const name = v.name == null ? "" : String(v.name);
|
|
48129
|
-
const value =
|
|
48130
|
-
const max =
|
|
48131
|
-
const min =
|
|
50364
|
+
const value = numField2(v.value);
|
|
50365
|
+
const max = numField2(v.max, 100);
|
|
50366
|
+
const min = numField2(v.min, 0);
|
|
48132
50367
|
const unit = v.unit == null ? "" : String(v.unit);
|
|
48133
50368
|
const pct = Math.round((value - min) / (max - min) * 100);
|
|
48134
50369
|
const isHigh = pct > 80;
|
|
@@ -48158,12 +50393,12 @@ function VariablePanel({
|
|
|
48158
50393
|
})
|
|
48159
50394
|
] });
|
|
48160
50395
|
}
|
|
48161
|
-
var
|
|
50396
|
+
var numField2;
|
|
48162
50397
|
var init_VariablePanel = __esm({
|
|
48163
50398
|
"components/game/organisms/puzzles/state-architect/VariablePanel.tsx"() {
|
|
48164
50399
|
init_atoms2();
|
|
48165
50400
|
init_cn();
|
|
48166
|
-
|
|
50401
|
+
numField2 = (v, fallback = 0) => {
|
|
48167
50402
|
const n = Number(v);
|
|
48168
50403
|
return Number.isFinite(n) ? n : fallback;
|
|
48169
50404
|
};
|
|
@@ -49016,6 +51251,289 @@ var init_ToastSlot = __esm({
|
|
|
49016
51251
|
ToastSlot.displayName = "ToastSlot";
|
|
49017
51252
|
}
|
|
49018
51253
|
});
|
|
51254
|
+
function tilesToIso(tiles) {
|
|
51255
|
+
return tiles.map((t) => ({
|
|
51256
|
+
x: t.x,
|
|
51257
|
+
y: t.y,
|
|
51258
|
+
terrain: t.terrain,
|
|
51259
|
+
terrainSprite: t.terrainSprite ?? TERRAIN_SPRITES[t.terrain ?? "ground"],
|
|
51260
|
+
passable: t.passable
|
|
51261
|
+
}));
|
|
51262
|
+
}
|
|
51263
|
+
function towersToUnits(towers) {
|
|
51264
|
+
return towers.map((t) => ({
|
|
51265
|
+
id: t.id,
|
|
51266
|
+
position: { x: t.x, y: t.y },
|
|
51267
|
+
name: "Tower",
|
|
51268
|
+
team: "player",
|
|
51269
|
+
sprite: TOWER_SPRITE,
|
|
51270
|
+
unitType: "guardian",
|
|
51271
|
+
health: 1,
|
|
51272
|
+
maxHealth: 1
|
|
51273
|
+
}));
|
|
51274
|
+
}
|
|
51275
|
+
function creepsToUnits(creeps) {
|
|
51276
|
+
return creeps.map((c) => ({
|
|
51277
|
+
id: c.id,
|
|
51278
|
+
position: { x: c.x, y: c.y },
|
|
51279
|
+
name: "Creep",
|
|
51280
|
+
team: "enemy",
|
|
51281
|
+
sprite: CREEP_SPRITE,
|
|
51282
|
+
unitType: "scrapper",
|
|
51283
|
+
health: c.hp,
|
|
51284
|
+
maxHealth: c.maxHp
|
|
51285
|
+
}));
|
|
51286
|
+
}
|
|
51287
|
+
function pathToFeatures(path) {
|
|
51288
|
+
return path.map((p2, i) => ({
|
|
51289
|
+
id: `path-${i}`,
|
|
51290
|
+
x: p2.x,
|
|
51291
|
+
y: p2.y,
|
|
51292
|
+
type: "path-marker",
|
|
51293
|
+
sprite: `${CDN6}world-map/road_straight.png`
|
|
51294
|
+
}));
|
|
51295
|
+
}
|
|
51296
|
+
function TowerDefenseBoard({
|
|
51297
|
+
entity,
|
|
51298
|
+
tiles: propTiles,
|
|
51299
|
+
path: propPath,
|
|
51300
|
+
towers: propTowers,
|
|
51301
|
+
creeps: propCreeps,
|
|
51302
|
+
gold: propGold,
|
|
51303
|
+
lives: propLives,
|
|
51304
|
+
wave: propWave,
|
|
51305
|
+
maxWaves: propMaxWaves,
|
|
51306
|
+
result: propResult,
|
|
51307
|
+
waveActive: propWaveActive,
|
|
51308
|
+
towerCost = 25,
|
|
51309
|
+
scale = 0.45,
|
|
51310
|
+
placeTowerEvent,
|
|
51311
|
+
startWaveEvent,
|
|
51312
|
+
playAgainEvent,
|
|
51313
|
+
gameEndEvent,
|
|
51314
|
+
className
|
|
51315
|
+
}) {
|
|
51316
|
+
const board = boardEntity(entity) ?? {};
|
|
51317
|
+
const eventBus = useEventBus();
|
|
51318
|
+
const { t } = useTranslate();
|
|
51319
|
+
const tiles = propTiles ?? rows(board.tiles);
|
|
51320
|
+
const path = propPath ?? rows(board.path);
|
|
51321
|
+
const towers = propTowers ?? rows(board.towers);
|
|
51322
|
+
const creeps = propCreeps ?? rows(board.creeps);
|
|
51323
|
+
const gold = propGold ?? num(board.gold, 100);
|
|
51324
|
+
const lives = propLives ?? num(board.lives, 20);
|
|
51325
|
+
const wave = propWave ?? num(board.wave, 1);
|
|
51326
|
+
const maxWaves = propMaxWaves ?? num(board.maxWaves, 5);
|
|
51327
|
+
const result = propResult ?? (str(board.result) || "none");
|
|
51328
|
+
const waveActive = propWaveActive ?? Boolean(board.waveActive);
|
|
51329
|
+
const [hoveredTile, setHoveredTile] = useState(null);
|
|
51330
|
+
const emittedGameEnd = useRef(false);
|
|
51331
|
+
if (result !== "none" && !emittedGameEnd.current) {
|
|
51332
|
+
emittedGameEnd.current = true;
|
|
51333
|
+
if (gameEndEvent) {
|
|
51334
|
+
eventBus.emit(`UI:${gameEndEvent}`, { result });
|
|
51335
|
+
}
|
|
51336
|
+
}
|
|
51337
|
+
if (result === "none") {
|
|
51338
|
+
emittedGameEnd.current = false;
|
|
51339
|
+
}
|
|
51340
|
+
const towerPositions = useMemo(() => new Set(towers.map((t2) => `${t2.x},${t2.y}`)), [towers]);
|
|
51341
|
+
const pathPositions = useMemo(() => new Set(path.map((p2) => `${p2.x},${p2.y}`)), [path]);
|
|
51342
|
+
const validMoves = useMemo(() => {
|
|
51343
|
+
if (result !== "none" || gold < towerCost) return [];
|
|
51344
|
+
return tiles.filter(
|
|
51345
|
+
(t2) => t2.passable !== false && !towerPositions.has(`${t2.x},${t2.y}`) && !pathPositions.has(`${t2.x},${t2.y}`)
|
|
51346
|
+
).map((t2) => ({ x: t2.x, y: t2.y }));
|
|
51347
|
+
}, [tiles, towerPositions, pathPositions, result, gold, towerCost]);
|
|
51348
|
+
const isoTiles = useMemo(() => tilesToIso(tiles), [tiles]);
|
|
51349
|
+
const towerUnits = useMemo(() => towersToUnits(towers), [towers]);
|
|
51350
|
+
const creepUnits = useMemo(() => creepsToUnits(creeps), [creeps]);
|
|
51351
|
+
const isoUnits = useMemo(() => [...towerUnits, ...creepUnits], [towerUnits, creepUnits]);
|
|
51352
|
+
const pathFeatures = useMemo(() => pathToFeatures(path), [path]);
|
|
51353
|
+
const handleTileClick = useCallback((x, y) => {
|
|
51354
|
+
if (result !== "none") return;
|
|
51355
|
+
if (pathPositions.has(`${x},${y}`)) return;
|
|
51356
|
+
if (towerPositions.has(`${x},${y}`)) return;
|
|
51357
|
+
if (gold < towerCost) return;
|
|
51358
|
+
if (placeTowerEvent) {
|
|
51359
|
+
eventBus.emit(`UI:${placeTowerEvent}`, { x, y });
|
|
51360
|
+
}
|
|
51361
|
+
}, [result, pathPositions, towerPositions, gold, towerCost, placeTowerEvent, eventBus]);
|
|
51362
|
+
const handleStartWave = useCallback(() => {
|
|
51363
|
+
if (startWaveEvent) {
|
|
51364
|
+
eventBus.emit(`UI:${startWaveEvent}`, { wave });
|
|
51365
|
+
}
|
|
51366
|
+
}, [startWaveEvent, wave, eventBus]);
|
|
51367
|
+
const handlePlayAgain = useCallback(() => {
|
|
51368
|
+
if (playAgainEvent) {
|
|
51369
|
+
eventBus.emit(`UI:${playAgainEvent}`, {});
|
|
51370
|
+
}
|
|
51371
|
+
}, [playAgainEvent, eventBus]);
|
|
51372
|
+
const canPlaceTower = gold >= towerCost && result === "none";
|
|
51373
|
+
const canStartWave = !waveActive && result === "none";
|
|
51374
|
+
return /* @__PURE__ */ jsxs(VStack, { className: cn("tower-defense-board relative min-h-[600px] bg-background", className), gap: "none", children: [
|
|
51375
|
+
/* @__PURE__ */ jsxs(
|
|
51376
|
+
HStack,
|
|
51377
|
+
{
|
|
51378
|
+
className: "px-4 py-2 border-b border-border bg-surface",
|
|
51379
|
+
gap: "lg",
|
|
51380
|
+
align: "center",
|
|
51381
|
+
children: [
|
|
51382
|
+
/* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
|
|
51383
|
+
/* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", children: t("td.gold") ?? "Gold" }),
|
|
51384
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body2", weight: "bold", className: "text-warning", children: gold })
|
|
51385
|
+
] }),
|
|
51386
|
+
/* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
|
|
51387
|
+
/* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", children: t("td.lives") ?? "Lives" }),
|
|
51388
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body2", weight: "bold", className: lives <= 5 ? "text-error" : "text-success", children: lives })
|
|
51389
|
+
] }),
|
|
51390
|
+
/* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
|
|
51391
|
+
/* @__PURE__ */ jsx(Typography, { variant: "small", color: "muted", children: t("td.wave") ?? "Wave" }),
|
|
51392
|
+
/* @__PURE__ */ jsxs(Typography, { variant: "body2", weight: "bold", children: [
|
|
51393
|
+
wave,
|
|
51394
|
+
" / ",
|
|
51395
|
+
maxWaves
|
|
51396
|
+
] })
|
|
51397
|
+
] }),
|
|
51398
|
+
/* @__PURE__ */ jsxs(Box, { className: "ml-auto", children: [
|
|
51399
|
+
canStartWave && /* @__PURE__ */ jsx(Button, { variant: "primary", size: "sm", onClick: handleStartWave, children: t("td.startWave") ?? "Start Wave" }),
|
|
51400
|
+
waveActive && /* @__PURE__ */ jsx(Typography, { variant: "small", className: "text-warning animate-pulse", children: t("td.waveInProgress") ?? "Wave in progress\u2026" })
|
|
51401
|
+
] })
|
|
51402
|
+
]
|
|
51403
|
+
}
|
|
51404
|
+
),
|
|
51405
|
+
/* @__PURE__ */ jsxs(Box, { className: "relative flex-1", children: [
|
|
51406
|
+
/* @__PURE__ */ jsx(
|
|
51407
|
+
IsometricCanvas_default,
|
|
51408
|
+
{
|
|
51409
|
+
tiles: isoTiles,
|
|
51410
|
+
units: isoUnits,
|
|
51411
|
+
features: pathFeatures,
|
|
51412
|
+
validMoves,
|
|
51413
|
+
hoveredTile,
|
|
51414
|
+
onTileClick: handleTileClick,
|
|
51415
|
+
onTileHover: (x, y) => setHoveredTile({ x, y }),
|
|
51416
|
+
onTileLeave: () => setHoveredTile(null),
|
|
51417
|
+
scale
|
|
51418
|
+
}
|
|
51419
|
+
),
|
|
51420
|
+
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)` }) })
|
|
51421
|
+
] }),
|
|
51422
|
+
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: [
|
|
51423
|
+
/* @__PURE__ */ jsx(
|
|
51424
|
+
Typography,
|
|
51425
|
+
{
|
|
51426
|
+
variant: "h2",
|
|
51427
|
+
className: cn(
|
|
51428
|
+
"text-4xl font-black tracking-widest uppercase",
|
|
51429
|
+
result === "won" ? "text-warning" : "text-error"
|
|
51430
|
+
),
|
|
51431
|
+
children: result === "won" ? t("td.victory") ?? "Victory!" : t("td.defeat") ?? "Defeat!"
|
|
51432
|
+
}
|
|
51433
|
+
),
|
|
51434
|
+
/* @__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." }),
|
|
51435
|
+
/* @__PURE__ */ jsx(
|
|
51436
|
+
Button,
|
|
51437
|
+
{
|
|
51438
|
+
variant: "primary",
|
|
51439
|
+
className: "px-8 py-3 font-semibold",
|
|
51440
|
+
onClick: handlePlayAgain,
|
|
51441
|
+
children: t("td.playAgain") ?? "Play Again"
|
|
51442
|
+
}
|
|
51443
|
+
)
|
|
51444
|
+
] }) })
|
|
51445
|
+
] });
|
|
51446
|
+
}
|
|
51447
|
+
var CDN6, TERRAIN_SPRITES, TOWER_SPRITE, CREEP_SPRITE;
|
|
51448
|
+
var init_TowerDefenseBoard = __esm({
|
|
51449
|
+
"components/game/organisms/TowerDefenseBoard.tsx"() {
|
|
51450
|
+
"use client";
|
|
51451
|
+
init_cn();
|
|
51452
|
+
init_useEventBus();
|
|
51453
|
+
init_Box();
|
|
51454
|
+
init_Button();
|
|
51455
|
+
init_Typography();
|
|
51456
|
+
init_Stack();
|
|
51457
|
+
init_IsometricCanvas();
|
|
51458
|
+
init_boardEntity();
|
|
51459
|
+
CDN6 = "https://almadar-kflow-assets.web.app/shared/";
|
|
51460
|
+
TERRAIN_SPRITES = {
|
|
51461
|
+
ground: `${CDN6}isometric-blocks/PNG/Platformer tiles/platformerTile_01.png`,
|
|
51462
|
+
path: `${CDN6}isometric-blocks/PNG/Platformer tiles/platformerTile_09.png`,
|
|
51463
|
+
wall: `${CDN6}isometric-blocks/PNG/Platformer tiles/platformerTile_05.png`
|
|
51464
|
+
};
|
|
51465
|
+
TOWER_SPRITE = `${CDN6}units/guardian.png`;
|
|
51466
|
+
CREEP_SPRITE = `${CDN6}units/scrapper.png`;
|
|
51467
|
+
TowerDefenseBoard.displayName = "TowerDefenseBoard";
|
|
51468
|
+
}
|
|
51469
|
+
});
|
|
51470
|
+
function TowerDefenseTemplate({
|
|
51471
|
+
entity,
|
|
51472
|
+
title = "Tower Defense",
|
|
51473
|
+
tiles,
|
|
51474
|
+
path,
|
|
51475
|
+
towers,
|
|
51476
|
+
gold,
|
|
51477
|
+
lives,
|
|
51478
|
+
maxWaves,
|
|
51479
|
+
towerCost,
|
|
51480
|
+
scale,
|
|
51481
|
+
placeTowerEvent,
|
|
51482
|
+
startWaveEvent,
|
|
51483
|
+
playAgainEvent,
|
|
51484
|
+
gameEndEvent,
|
|
51485
|
+
className
|
|
51486
|
+
}) {
|
|
51487
|
+
const resolved = entity && typeof entity === "object" && !Array.isArray(entity) ? entity : void 0;
|
|
51488
|
+
return /* @__PURE__ */ jsxs(
|
|
51489
|
+
Box,
|
|
51490
|
+
{
|
|
51491
|
+
display: "flex",
|
|
51492
|
+
fullHeight: true,
|
|
51493
|
+
className: cn("tower-defense-template flex-col", className),
|
|
51494
|
+
children: [
|
|
51495
|
+
/* @__PURE__ */ jsx(
|
|
51496
|
+
HStack,
|
|
51497
|
+
{
|
|
51498
|
+
gap: "sm",
|
|
51499
|
+
align: "center",
|
|
51500
|
+
className: "px-4 py-3 border-b-2 border-border bg-surface shrink-0",
|
|
51501
|
+
children: /* @__PURE__ */ jsx(Typography, { variant: "h4", children: title })
|
|
51502
|
+
}
|
|
51503
|
+
),
|
|
51504
|
+
/* @__PURE__ */ jsx(Box, { className: "flex-1 relative overflow-hidden", children: /* @__PURE__ */ jsx(
|
|
51505
|
+
TowerDefenseBoard,
|
|
51506
|
+
{
|
|
51507
|
+
entity: resolved,
|
|
51508
|
+
tiles,
|
|
51509
|
+
path,
|
|
51510
|
+
towers,
|
|
51511
|
+
gold,
|
|
51512
|
+
lives,
|
|
51513
|
+
maxWaves,
|
|
51514
|
+
towerCost,
|
|
51515
|
+
scale,
|
|
51516
|
+
placeTowerEvent,
|
|
51517
|
+
startWaveEvent,
|
|
51518
|
+
playAgainEvent,
|
|
51519
|
+
gameEndEvent,
|
|
51520
|
+
className: "h-full"
|
|
51521
|
+
}
|
|
51522
|
+
) })
|
|
51523
|
+
]
|
|
51524
|
+
}
|
|
51525
|
+
);
|
|
51526
|
+
}
|
|
51527
|
+
var init_TowerDefenseTemplate = __esm({
|
|
51528
|
+
"components/game/templates/TowerDefenseTemplate.tsx"() {
|
|
51529
|
+
init_cn();
|
|
51530
|
+
init_Box();
|
|
51531
|
+
init_Stack();
|
|
51532
|
+
init_Typography();
|
|
51533
|
+
init_TowerDefenseBoard();
|
|
51534
|
+
TowerDefenseTemplate.displayName = "TowerDefenseTemplate";
|
|
51535
|
+
}
|
|
51536
|
+
});
|
|
49019
51537
|
function useBattleState(initialUnits, eventConfig = {}, callbacks = {}) {
|
|
49020
51538
|
const eventBus = useEventBus();
|
|
49021
51539
|
const {
|
|
@@ -49525,48 +52043,48 @@ function WorldMapTemplate({
|
|
|
49525
52043
|
}
|
|
49526
52044
|
);
|
|
49527
52045
|
}
|
|
49528
|
-
var
|
|
52046
|
+
var CDN7, DEFAULT_WORLDMAP_TILES, DEFAULT_WORLDMAP_UNITS, DEFAULT_WORLDMAP_FEATURES, DEFAULT_WORLDMAP_MANIFEST;
|
|
49529
52047
|
var init_WorldMapTemplate = __esm({
|
|
49530
52048
|
"components/game/templates/WorldMapTemplate.tsx"() {
|
|
49531
52049
|
init_WorldMapBoard();
|
|
49532
|
-
|
|
52050
|
+
CDN7 = "https://almadar-kflow-assets.web.app/shared";
|
|
49533
52051
|
DEFAULT_WORLDMAP_TILES = [
|
|
49534
|
-
{ x: 0, y: 0, terrain: "mountain", passable: false, terrainSprite: `${
|
|
49535
|
-
{ x: 1, y: 0, terrain: "mountain", passable: false, terrainSprite: `${
|
|
49536
|
-
{ x: 2, y: 0, terrain: "water", passable: false, terrainSprite: `${
|
|
49537
|
-
{ x: 3, y: 0, terrain: "mountain", passable: false, terrainSprite: `${
|
|
49538
|
-
{ x: 4, y: 0, terrain: "mountain", passable: false, terrainSprite: `${
|
|
49539
|
-
{ x: 0, y: 1, terrain: "mountain", passable: false, terrainSprite: `${
|
|
49540
|
-
{ x: 1, y: 1, terrain: "grass", passable: true, terrainSprite: `${
|
|
49541
|
-
{ x: 2, y: 1, terrain: "grass", passable: true, terrainSprite: `${
|
|
49542
|
-
{ x: 3, y: 1, terrain: "grass", passable: true, terrainSprite: `${
|
|
49543
|
-
{ x: 4, y: 1, terrain: "water", passable: false, terrainSprite: `${
|
|
49544
|
-
{ x: 0, y: 2, terrain: "water", passable: false, terrainSprite: `${
|
|
49545
|
-
{ x: 1, y: 2, terrain: "grass", passable: true, terrainSprite: `${
|
|
49546
|
-
{ x: 2, y: 2, terrain: "grass", passable: true, terrainSprite: `${
|
|
49547
|
-
{ x: 3, y: 2, terrain: "grass", passable: true, terrainSprite: `${
|
|
49548
|
-
{ x: 4, y: 2, terrain: "mountain", passable: false, terrainSprite: `${
|
|
49549
|
-
{ x: 0, y: 3, terrain: "mountain", passable: false, terrainSprite: `${
|
|
49550
|
-
{ x: 1, y: 3, terrain: "grass", passable: true, terrainSprite: `${
|
|
49551
|
-
{ x: 2, y: 3, terrain: "grass", passable: true, terrainSprite: `${
|
|
49552
|
-
{ x: 3, y: 3, terrain: "grass", passable: true, terrainSprite: `${
|
|
49553
|
-
{ x: 4, y: 3, terrain: "mountain", passable: false, terrainSprite: `${
|
|
49554
|
-
{ x: 0, y: 4, terrain: "mountain", passable: false, terrainSprite: `${
|
|
49555
|
-
{ x: 1, y: 4, terrain: "water", passable: false, terrainSprite: `${
|
|
49556
|
-
{ x: 2, y: 4, terrain: "grass", passable: true, terrainSprite: `${
|
|
49557
|
-
{ x: 3, y: 4, terrain: "mountain", passable: false, terrainSprite: `${
|
|
49558
|
-
{ x: 4, y: 4, terrain: "mountain", passable: false, terrainSprite: `${
|
|
52052
|
+
{ x: 0, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
|
|
52053
|
+
{ x: 1, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
|
|
52054
|
+
{ x: 2, y: 0, terrain: "water", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
|
|
52055
|
+
{ x: 3, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
|
|
52056
|
+
{ x: 4, y: 0, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
|
|
52057
|
+
{ x: 0, y: 1, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
|
|
52058
|
+
{ x: 1, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
|
|
52059
|
+
{ x: 2, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
|
|
52060
|
+
{ x: 3, y: 1, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
|
|
52061
|
+
{ x: 4, y: 1, terrain: "water", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
|
|
52062
|
+
{ x: 0, y: 2, terrain: "water", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
|
|
52063
|
+
{ x: 1, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
|
|
52064
|
+
{ x: 2, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_03.png` },
|
|
52065
|
+
{ x: 3, y: 2, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
|
|
52066
|
+
{ x: 4, y: 2, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
|
|
52067
|
+
{ x: 0, y: 3, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
|
|
52068
|
+
{ x: 1, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
|
|
52069
|
+
{ x: 2, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
|
|
52070
|
+
{ x: 3, y: 3, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_03.png` },
|
|
52071
|
+
{ x: 4, y: 3, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
|
|
52072
|
+
{ x: 0, y: 4, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
|
|
52073
|
+
{ x: 1, y: 4, terrain: "water", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png` },
|
|
52074
|
+
{ x: 2, y: 4, terrain: "grass", passable: true, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png` },
|
|
52075
|
+
{ x: 3, y: 4, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` },
|
|
52076
|
+
{ x: 4, y: 4, terrain: "mountain", passable: false, terrainSprite: `${CDN7}/isometric-blocks/PNG/Platformer tiles/platformerTile_13.png` }
|
|
49559
52077
|
];
|
|
49560
52078
|
DEFAULT_WORLDMAP_UNITS = [
|
|
49561
|
-
{ id: "h1", position: { x: 1, y: 1 }, unitType: "hero", name: "Amir", team: "player", health: 10, maxHealth: 10, sprite: `${
|
|
49562
|
-
{ id: "h2", position: { x: 3, y: 3 }, unitType: "scout", name: "Archivist", team: "player", health: 10, maxHealth: 10, sprite: `${
|
|
52079
|
+
{ 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` },
|
|
52080
|
+
{ 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` }
|
|
49563
52081
|
];
|
|
49564
52082
|
DEFAULT_WORLDMAP_FEATURES = [
|
|
49565
|
-
{ id: "f1", x: 2, y: 2, type: "capital", sprite: `${
|
|
49566
|
-
{ id: "f2", x: 4, y: 2, type: "power_node", sprite: `${
|
|
52083
|
+
{ id: "f1", x: 2, y: 2, type: "capital", sprite: `${CDN7}/scenes/world/capital.png` },
|
|
52084
|
+
{ id: "f2", x: 4, y: 2, type: "power_node", sprite: `${CDN7}/world-map/power_node.png` }
|
|
49567
52085
|
];
|
|
49568
52086
|
DEFAULT_WORLDMAP_MANIFEST = {
|
|
49569
|
-
baseUrl:
|
|
52087
|
+
baseUrl: CDN7,
|
|
49570
52088
|
terrains: {
|
|
49571
52089
|
grass: "/isometric-blocks/PNG/Platformer tiles/platformerTile_01.png",
|
|
49572
52090
|
water: "/isometric-blocks/PNG/Platformer tiles/platformerTile_11.png",
|
|
@@ -49611,7 +52129,7 @@ function lazyThree(name, loader) {
|
|
|
49611
52129
|
ThreeWrapper.displayName = `Lazy(${name})`;
|
|
49612
52130
|
return ThreeWrapper;
|
|
49613
52131
|
}
|
|
49614
|
-
var ThreeBoundary, FeatureRenderer,
|
|
52132
|
+
var ThreeBoundary, FeatureRenderer, GameCanvas3D2, GameCanvas3DBattleTemplate, GameCanvas3DCastleTemplate, GameCanvas3DWorldMapTemplate, COMPONENT_REGISTRY;
|
|
49615
52133
|
var init_component_registry_generated = __esm({
|
|
49616
52134
|
"components/core/organisms/component-registry.generated.ts"() {
|
|
49617
52135
|
init_AboutPageTemplate();
|
|
@@ -49721,6 +52239,7 @@ var init_component_registry_generated = __esm({
|
|
|
49721
52239
|
init_FormSectionHeader();
|
|
49722
52240
|
init_GameAudioProvider();
|
|
49723
52241
|
init_GameAudioToggle();
|
|
52242
|
+
init_GameBoard3D();
|
|
49724
52243
|
init_GameCanvas2D();
|
|
49725
52244
|
init_GameHud();
|
|
49726
52245
|
init_GameMenu();
|
|
@@ -49778,7 +52297,9 @@ var init_component_registry_generated = __esm({
|
|
|
49778
52297
|
init_PageHeader();
|
|
49779
52298
|
init_Pagination();
|
|
49780
52299
|
init_PatternTile();
|
|
52300
|
+
init_PlatformerBoard();
|
|
49781
52301
|
init_PlatformerCanvas();
|
|
52302
|
+
init_PlatformerTemplate();
|
|
49782
52303
|
init_Popover();
|
|
49783
52304
|
init_PositionedCanvas();
|
|
49784
52305
|
init_PowerupSlots();
|
|
@@ -49802,6 +52323,8 @@ var init_component_registry_generated = __esm({
|
|
|
49802
52323
|
init_ResourceBar();
|
|
49803
52324
|
init_ResourceCounter();
|
|
49804
52325
|
init_RichBlockEditor();
|
|
52326
|
+
init_RoguelikeBoard();
|
|
52327
|
+
init_RoguelikeTemplate();
|
|
49805
52328
|
init_RuntimeDebugger2();
|
|
49806
52329
|
init_ScaledDiagram();
|
|
49807
52330
|
init_ScoreBoard();
|
|
@@ -49874,6 +52397,8 @@ var init_component_registry_generated = __esm({
|
|
|
49874
52397
|
init_Toast();
|
|
49875
52398
|
init_ToastSlot();
|
|
49876
52399
|
init_Tooltip();
|
|
52400
|
+
init_TowerDefenseBoard();
|
|
52401
|
+
init_TowerDefenseTemplate();
|
|
49877
52402
|
init_TraitFrame();
|
|
49878
52403
|
init_TraitSlot();
|
|
49879
52404
|
init_TrendIndicator();
|
|
@@ -49918,7 +52443,7 @@ var init_component_registry_generated = __esm({
|
|
|
49918
52443
|
}
|
|
49919
52444
|
};
|
|
49920
52445
|
FeatureRenderer = lazyThree("FeatureRenderer", () => import('@almadar/ui/components/molecules/game/three'));
|
|
49921
|
-
|
|
52446
|
+
GameCanvas3D2 = lazyThree("GameCanvas3D", () => import('@almadar/ui/components/molecules/game/three'));
|
|
49922
52447
|
GameCanvas3DBattleTemplate = lazyThree("GameCanvas3DBattleTemplate", () => import('@almadar/ui/components/molecules/game/three'));
|
|
49923
52448
|
GameCanvas3DCastleTemplate = lazyThree("GameCanvas3DCastleTemplate", () => import('@almadar/ui/components/molecules/game/three'));
|
|
49924
52449
|
GameCanvas3DWorldMapTemplate = lazyThree("GameCanvas3DWorldMapTemplate", () => import('@almadar/ui/components/molecules/game/three'));
|
|
@@ -50037,8 +52562,9 @@ var init_component_registry_generated = __esm({
|
|
|
50037
52562
|
"FormSectionHeader": FormSectionHeader,
|
|
50038
52563
|
"GameAudioProvider": GameAudioProvider,
|
|
50039
52564
|
"GameAudioToggle": GameAudioToggle,
|
|
52565
|
+
"GameBoard3D": GameBoard3D,
|
|
50040
52566
|
"GameCanvas2D": GameCanvas2D,
|
|
50041
|
-
"GameCanvas3D":
|
|
52567
|
+
"GameCanvas3D": GameCanvas3D2,
|
|
50042
52568
|
"GameCanvas3DBattleTemplate": GameCanvas3DBattleTemplate,
|
|
50043
52569
|
"GameCanvas3DCastleTemplate": GameCanvas3DCastleTemplate,
|
|
50044
52570
|
"GameCanvas3DWorldMapTemplate": GameCanvas3DWorldMapTemplate,
|
|
@@ -50100,7 +52626,9 @@ var init_component_registry_generated = __esm({
|
|
|
50100
52626
|
"PageHeader": PageHeader,
|
|
50101
52627
|
"Pagination": Pagination,
|
|
50102
52628
|
"PatternTile": PatternTile,
|
|
52629
|
+
"PlatformerBoard": PlatformerBoard,
|
|
50103
52630
|
"PlatformerCanvas": PlatformerCanvas,
|
|
52631
|
+
"PlatformerTemplate": PlatformerTemplate,
|
|
50104
52632
|
"Popover": Popover,
|
|
50105
52633
|
"PositionedCanvas": PositionedCanvas,
|
|
50106
52634
|
"PowerupSlots": PowerupSlots,
|
|
@@ -50124,6 +52652,8 @@ var init_component_registry_generated = __esm({
|
|
|
50124
52652
|
"ResourceBar": ResourceBar,
|
|
50125
52653
|
"ResourceCounter": ResourceCounter,
|
|
50126
52654
|
"RichBlockEditor": RichBlockEditor,
|
|
52655
|
+
"RoguelikeBoard": RoguelikeBoard,
|
|
52656
|
+
"RoguelikeTemplate": RoguelikeTemplate,
|
|
50127
52657
|
"RuntimeDebugger": RuntimeDebugger,
|
|
50128
52658
|
"ScaledDiagram": ScaledDiagram,
|
|
50129
52659
|
"ScoreBoard": ScoreBoard,
|
|
@@ -50199,6 +52729,8 @@ var init_component_registry_generated = __esm({
|
|
|
50199
52729
|
"Toast": Toast,
|
|
50200
52730
|
"ToastSlot": ToastSlot,
|
|
50201
52731
|
"Tooltip": Tooltip,
|
|
52732
|
+
"TowerDefenseBoard": TowerDefenseBoard,
|
|
52733
|
+
"TowerDefenseTemplate": TowerDefenseTemplate,
|
|
50202
52734
|
"TraitFrame": TraitFrame,
|
|
50203
52735
|
"TraitSlot": TraitSlot,
|
|
50204
52736
|
"TrendIndicator": TrendIndicator,
|
|
@@ -54685,7 +57217,7 @@ function convertObjectProps(props) {
|
|
|
54685
57217
|
function convertFnFormLambdasInProps(props) {
|
|
54686
57218
|
return convertObjectProps(props);
|
|
54687
57219
|
}
|
|
54688
|
-
var
|
|
57220
|
+
var log11 = createLogger("almadar:ui:effects:client-handlers");
|
|
54689
57221
|
function createClientEffectHandlers(options) {
|
|
54690
57222
|
const { eventBus, slotSetter, navigate, notify, callService } = options;
|
|
54691
57223
|
return {
|
|
@@ -54694,10 +57226,10 @@ function createClientEffectHandlers(options) {
|
|
|
54694
57226
|
eventBus.emit(prefixedEvent, payload);
|
|
54695
57227
|
},
|
|
54696
57228
|
persist: async () => {
|
|
54697
|
-
|
|
57229
|
+
log11.warn("persist is server-side only, ignored on client");
|
|
54698
57230
|
},
|
|
54699
57231
|
set: () => {
|
|
54700
|
-
|
|
57232
|
+
log11.warn("set is server-side only, ignored on client");
|
|
54701
57233
|
},
|
|
54702
57234
|
callService: async (service, action, params) => {
|
|
54703
57235
|
if (callService) return callService(service, action, params);
|
|
@@ -54726,10 +57258,10 @@ function createClientEffectHandlers(options) {
|
|
|
54726
57258
|
slotSetter.addPattern(slot, pattern, props);
|
|
54727
57259
|
},
|
|
54728
57260
|
navigate: navigate ?? ((path) => {
|
|
54729
|
-
|
|
57261
|
+
log11.warn("No navigate handler, ignoring", { path });
|
|
54730
57262
|
}),
|
|
54731
57263
|
notify: notify ?? ((msg, type) => {
|
|
54732
|
-
|
|
57264
|
+
log11.debug("notify", { type, message: msg });
|
|
54733
57265
|
})
|
|
54734
57266
|
};
|
|
54735
57267
|
}
|
|
@@ -55894,7 +58426,7 @@ OrbitalThemeProvider.displayName = "OrbitalThemeProvider";
|
|
|
55894
58426
|
init_navigation();
|
|
55895
58427
|
init_verificationRegistry();
|
|
55896
58428
|
var PERF_NAMESPACE = "almadar:perf:canvas";
|
|
55897
|
-
var
|
|
58429
|
+
var log12 = createLogger(PERF_NAMESPACE);
|
|
55898
58430
|
var RING_SIZE = 50;
|
|
55899
58431
|
var ring = [];
|
|
55900
58432
|
var writeIdx = 0;
|
|
@@ -55945,7 +58477,7 @@ function perfEnd(name, startToken, detail) {
|
|
|
55945
58477
|
}
|
|
55946
58478
|
}
|
|
55947
58479
|
push({ name, durationMs, ts: endTs, detail });
|
|
55948
|
-
|
|
58480
|
+
log12.debug(name, () => ({ durationMs, ...detail ?? {} }));
|
|
55949
58481
|
}
|
|
55950
58482
|
var profilerOnRender = (id, phase, actualDuration, baseDuration, _startTime, commitTime) => {
|
|
55951
58483
|
if (!isEnabled()) return;
|
|
@@ -55955,7 +58487,7 @@ var profilerOnRender = (id, phase, actualDuration, baseDuration, _startTime, com
|
|
|
55955
58487
|
ts: commitTime,
|
|
55956
58488
|
detail: { baseDuration }
|
|
55957
58489
|
});
|
|
55958
|
-
|
|
58490
|
+
log12.debug(`profiler:${id}:${phase}`, () => ({ actualDuration, baseDuration }));
|
|
55959
58491
|
};
|
|
55960
58492
|
|
|
55961
58493
|
// runtime/prepareSchemaForPreview.ts
|
|
@@ -56598,7 +59130,7 @@ init_useEventBus();
|
|
|
56598
59130
|
// components/avl/molecules/useCanvasDnd.tsx
|
|
56599
59131
|
init_useEventBus();
|
|
56600
59132
|
init_useAlmadarDndCollision();
|
|
56601
|
-
var
|
|
59133
|
+
var log13 = createLogger("almadar:ui:canvas-dnd");
|
|
56602
59134
|
function useCanvasDraggable({
|
|
56603
59135
|
id,
|
|
56604
59136
|
payload,
|
|
@@ -56637,7 +59169,7 @@ function defaultEmit(eventBus, drop) {
|
|
|
56637
59169
|
if (payload.kind === "pattern") {
|
|
56638
59170
|
const patternType = payload.data.type;
|
|
56639
59171
|
if (typeof patternType !== "string") {
|
|
56640
|
-
|
|
59172
|
+
log13.warn("default-emit:pattern:missing-type");
|
|
56641
59173
|
return;
|
|
56642
59174
|
}
|
|
56643
59175
|
const out = { patternType, containerNode: target.containerNode };
|
|
@@ -56646,23 +59178,23 @@ function defaultEmit(eventBus, drop) {
|
|
|
56646
59178
|
out.index = resolved.index;
|
|
56647
59179
|
}
|
|
56648
59180
|
eventBus.emit("UI:PATTERN_DROP", out);
|
|
56649
|
-
|
|
59181
|
+
log13.info("default-emit:pattern", { patternType, level: target.level });
|
|
56650
59182
|
return;
|
|
56651
59183
|
}
|
|
56652
59184
|
if (payload.kind === "behavior") {
|
|
56653
59185
|
const behaviorName = payload.data.name;
|
|
56654
59186
|
if (typeof behaviorName !== "string") {
|
|
56655
|
-
|
|
59187
|
+
log13.warn("default-emit:behavior:missing-name");
|
|
56656
59188
|
return;
|
|
56657
59189
|
}
|
|
56658
59190
|
eventBus.emit("UI:BEHAVIOR_DROP", {
|
|
56659
59191
|
behaviorName,
|
|
56660
59192
|
containerNode: target.containerNode
|
|
56661
59193
|
});
|
|
56662
|
-
|
|
59194
|
+
log13.info("default-emit:behavior", { behaviorName, level: target.level });
|
|
56663
59195
|
return;
|
|
56664
59196
|
}
|
|
56665
|
-
|
|
59197
|
+
log13.debug("default-emit:unhandled-kind", { kind: payload.kind });
|
|
56666
59198
|
}
|
|
56667
59199
|
function CanvasDndProvider({
|
|
56668
59200
|
children,
|
|
@@ -56678,9 +59210,9 @@ function CanvasDndProvider({
|
|
|
56678
59210
|
if (payload) {
|
|
56679
59211
|
setActivePayload(payload);
|
|
56680
59212
|
eventBus.emit("UI:DRAG_START", { kind: payload.kind, data: payload.data });
|
|
56681
|
-
|
|
59213
|
+
log13.info("dragStart", { id: e.active.id, kind: payload.kind });
|
|
56682
59214
|
} else {
|
|
56683
|
-
|
|
59215
|
+
log13.warn("dragStart:missing-payload", { id: e.active.id });
|
|
56684
59216
|
}
|
|
56685
59217
|
}, [eventBus]);
|
|
56686
59218
|
const handleDragEnd = React91__default.useCallback((e) => {
|
|
@@ -56690,7 +59222,7 @@ function CanvasDndProvider({
|
|
|
56690
59222
|
const overData = e.over?.data.current;
|
|
56691
59223
|
const target = overData?.target;
|
|
56692
59224
|
const accepts = overData?.accepts;
|
|
56693
|
-
|
|
59225
|
+
log13.info("dragEnd", {
|
|
56694
59226
|
activeId: e.active.id,
|
|
56695
59227
|
overId: e.over?.id,
|
|
56696
59228
|
hasPayload: !!payload,
|
|
@@ -56702,7 +59234,7 @@ function CanvasDndProvider({
|
|
|
56702
59234
|
}
|
|
56703
59235
|
if (!payload || !target) return;
|
|
56704
59236
|
if (accepts && !accepts.includes(payload.kind)) {
|
|
56705
|
-
|
|
59237
|
+
log13.debug("dragEnd:rejected:kind", { kind: payload.kind, accepts: [...accepts] });
|
|
56706
59238
|
return;
|
|
56707
59239
|
}
|
|
56708
59240
|
const activator = e.activatorEvent;
|
|
@@ -56714,7 +59246,7 @@ function CanvasDndProvider({
|
|
|
56714
59246
|
}, [eventBus, onDrop]);
|
|
56715
59247
|
const handleDragCancel = React91__default.useCallback(() => {
|
|
56716
59248
|
setActivePayload(null);
|
|
56717
|
-
|
|
59249
|
+
log13.info("dragCancel");
|
|
56718
59250
|
}, []);
|
|
56719
59251
|
return /* @__PURE__ */ jsxs(
|
|
56720
59252
|
DndContext,
|
|
@@ -58529,7 +61061,7 @@ init_AvlTransitionLane();
|
|
|
58529
61061
|
init_AvlSwimLane();
|
|
58530
61062
|
init_types();
|
|
58531
61063
|
init_avl_elk_layout();
|
|
58532
|
-
var
|
|
61064
|
+
var log14 = createLogger("almadar:ui:avl:trait-scene");
|
|
58533
61065
|
var SWIM_GUTTER2 = 120;
|
|
58534
61066
|
var CENTER_W2 = 360;
|
|
58535
61067
|
var AvlTraitScene = ({
|
|
@@ -58542,7 +61074,7 @@ var AvlTraitScene = ({
|
|
|
58542
61074
|
const dataKey = useMemo(() => JSON.stringify(data), [data]);
|
|
58543
61075
|
useEffect(() => {
|
|
58544
61076
|
computeTraitLayout(data).then(setLayout).catch((error) => {
|
|
58545
|
-
|
|
61077
|
+
log14.error("computeTraitLayout failed", { error: error instanceof Error ? error : String(error) });
|
|
58546
61078
|
});
|
|
58547
61079
|
}, [dataKey]);
|
|
58548
61080
|
if (!layout) {
|