@almadar/ui 5.46.0 → 5.48.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 +338 -316
- package/dist/avl/index.js +338 -316
- package/dist/components/game/atoms/ComboCounter.d.ts +4 -1
- package/dist/components/game/atoms/ResourceCounter.d.ts +4 -1
- package/dist/components/game/atoms/StateIndicator.d.ts +4 -7
- package/dist/components/game/atoms/StatusEffect.d.ts +4 -1
- package/dist/components/game/atoms/WaypointMarker.d.ts +4 -1
- package/dist/components/game/molecules/three/index.cjs +89 -80
- package/dist/components/game/molecules/three/index.css +0 -5
- package/dist/components/game/molecules/three/index.js +89 -80
- package/dist/components/game/organisms/CastleBoard.d.ts +10 -1
- package/dist/components/game/organisms/puzzles/event-handler/EventHandlerBoard.d.ts +9 -1
- package/dist/components/game/organisms/puzzles/state-architect/StateArchitectBoard.d.ts +14 -1
- package/dist/components/index.cjs +338 -316
- package/dist/components/index.js +338 -316
- package/dist/providers/index.cjs +338 -316
- package/dist/providers/index.js +338 -316
- package/dist/runtime/index.cjs +338 -316
- package/dist/runtime/index.js +338 -316
- package/package.json +1 -1
- package/tailwind-preset.cjs +1 -0
package/dist/providers/index.cjs
CHANGED
|
@@ -7413,6 +7413,7 @@ var init_Sprite = __esm({
|
|
|
7413
7413
|
}
|
|
7414
7414
|
});
|
|
7415
7415
|
function StateIndicator({
|
|
7416
|
+
assetUrl = DEFAULT_ASSET_URL,
|
|
7416
7417
|
state = "idle",
|
|
7417
7418
|
label,
|
|
7418
7419
|
size = "md",
|
|
@@ -7435,18 +7436,29 @@ function StateIndicator({
|
|
|
7435
7436
|
className
|
|
7436
7437
|
),
|
|
7437
7438
|
children: [
|
|
7438
|
-
/* @__PURE__ */ jsxRuntime.jsx(Box, { as: "span", children:
|
|
7439
|
+
/* @__PURE__ */ jsxRuntime.jsx(Box, { as: "span", children: assetUrl ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
7440
|
+
"img",
|
|
7441
|
+
{
|
|
7442
|
+
src: assetUrl,
|
|
7443
|
+
alt: displayLabel,
|
|
7444
|
+
width: 16,
|
|
7445
|
+
height: 16,
|
|
7446
|
+
style: { imageRendering: "pixelated", objectFit: "contain" },
|
|
7447
|
+
className: "flex-shrink-0"
|
|
7448
|
+
}
|
|
7449
|
+
) : typeof config.icon === "string" ? /^[a-zA-Z0-9-]+$/.test(config.icon) ? /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: config.icon }) : config.icon : /* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: config.icon }) }),
|
|
7439
7450
|
/* @__PURE__ */ jsxRuntime.jsx(Box, { as: "span", children: displayLabel })
|
|
7440
7451
|
]
|
|
7441
7452
|
}
|
|
7442
7453
|
);
|
|
7443
7454
|
}
|
|
7444
|
-
var DEFAULT_STATE_STYLES, DEFAULT_STYLE, SIZE_CLASSES;
|
|
7455
|
+
var DEFAULT_ASSET_URL, DEFAULT_STATE_STYLES, DEFAULT_STYLE, SIZE_CLASSES;
|
|
7445
7456
|
var init_StateIndicator = __esm({
|
|
7446
7457
|
"components/game/atoms/StateIndicator.tsx"() {
|
|
7447
7458
|
init_Box();
|
|
7448
7459
|
init_Icon();
|
|
7449
7460
|
init_cn();
|
|
7461
|
+
DEFAULT_ASSET_URL = "https://almadar-kflow-assets.web.app/shared/isometric-dungeon/Isometric/chestClosed_E.png";
|
|
7450
7462
|
DEFAULT_STATE_STYLES = {
|
|
7451
7463
|
idle: { icon: "\u23F8", bgClass: "bg-muted" },
|
|
7452
7464
|
active: { icon: "\u25B6", bgClass: "bg-success" },
|
|
@@ -7521,6 +7533,7 @@ var init_TimerDisplay = __esm({
|
|
|
7521
7533
|
}
|
|
7522
7534
|
});
|
|
7523
7535
|
function ResourceCounter({
|
|
7536
|
+
assetUrl = DEFAULT_ASSET_URL2,
|
|
7524
7537
|
icon,
|
|
7525
7538
|
label = "Gold",
|
|
7526
7539
|
value = 250,
|
|
@@ -7540,7 +7553,17 @@ function ResourceCounter({
|
|
|
7540
7553
|
className
|
|
7541
7554
|
),
|
|
7542
7555
|
children: [
|
|
7543
|
-
|
|
7556
|
+
assetUrl ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
7557
|
+
"img",
|
|
7558
|
+
{
|
|
7559
|
+
src: assetUrl,
|
|
7560
|
+
alt: label,
|
|
7561
|
+
width: sizes.img,
|
|
7562
|
+
height: sizes.img,
|
|
7563
|
+
style: { imageRendering: "pixelated", objectFit: "contain" },
|
|
7564
|
+
className: "flex-shrink-0"
|
|
7565
|
+
}
|
|
7566
|
+
) : icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("flex-shrink-0", sizes.icon), children: typeof icon === "string" ? /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: icon }) : /* @__PURE__ */ jsxRuntime.jsx(Icon, { icon }) }) : null,
|
|
7544
7567
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: label }),
|
|
7545
7568
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: cn("font-bold tabular-nums", color && (color in colorTokenClasses2 ? colorTokenClasses2[color] : color)), children: [
|
|
7546
7569
|
value,
|
|
@@ -7553,7 +7576,7 @@ function ResourceCounter({
|
|
|
7553
7576
|
}
|
|
7554
7577
|
);
|
|
7555
7578
|
}
|
|
7556
|
-
var colorTokenClasses2, sizeMap5;
|
|
7579
|
+
var colorTokenClasses2, DEFAULT_ASSET_URL2, sizeMap5;
|
|
7557
7580
|
var init_ResourceCounter = __esm({
|
|
7558
7581
|
"components/game/atoms/ResourceCounter.tsx"() {
|
|
7559
7582
|
init_cn();
|
|
@@ -7566,16 +7589,17 @@ var init_ResourceCounter = __esm({
|
|
|
7566
7589
|
error: "text-error",
|
|
7567
7590
|
muted: "text-muted-foreground"
|
|
7568
7591
|
};
|
|
7592
|
+
DEFAULT_ASSET_URL2 = "https://almadar-kflow-assets.web.app/shared/world-map/gold_mine.png";
|
|
7569
7593
|
sizeMap5 = {
|
|
7570
|
-
sm: { wrapper: "text-xs gap-1 px-1.5 py-0.5", icon: "text-sm" },
|
|
7571
|
-
md: { wrapper: "text-sm gap-1.5 px-2 py-1", icon: "text-base" },
|
|
7572
|
-
lg: { wrapper: "text-base gap-2 px-3 py-1.5", icon: "text-lg" }
|
|
7594
|
+
sm: { wrapper: "text-xs gap-1 px-1.5 py-0.5", icon: "text-sm", img: 16 },
|
|
7595
|
+
md: { wrapper: "text-sm gap-1.5 px-2 py-1", icon: "text-base", img: 20 },
|
|
7596
|
+
lg: { wrapper: "text-base gap-2 px-3 py-1.5", icon: "text-lg", img: 28 }
|
|
7573
7597
|
};
|
|
7574
7598
|
ResourceCounter.displayName = "ResourceCounter";
|
|
7575
7599
|
}
|
|
7576
7600
|
});
|
|
7577
7601
|
function ItemSlot({
|
|
7578
|
-
assetUrl =
|
|
7602
|
+
assetUrl = DEFAULT_ASSET_URL3,
|
|
7579
7603
|
icon = "sword",
|
|
7580
7604
|
label = "Iron Sword",
|
|
7581
7605
|
quantity,
|
|
@@ -7634,7 +7658,7 @@ function ItemSlot({
|
|
|
7634
7658
|
}
|
|
7635
7659
|
);
|
|
7636
7660
|
}
|
|
7637
|
-
var sizeMap6, rarityBorderMap, rarityGlowMap,
|
|
7661
|
+
var sizeMap6, rarityBorderMap, rarityGlowMap, DEFAULT_ASSET_URL3, assetSizeMap;
|
|
7638
7662
|
var init_ItemSlot = __esm({
|
|
7639
7663
|
"components/game/atoms/ItemSlot.tsx"() {
|
|
7640
7664
|
"use client";
|
|
@@ -7659,7 +7683,7 @@ var init_ItemSlot = __esm({
|
|
|
7659
7683
|
epic: "shadow-lg",
|
|
7660
7684
|
legendary: "shadow-lg"
|
|
7661
7685
|
};
|
|
7662
|
-
|
|
7686
|
+
DEFAULT_ASSET_URL3 = "https://almadar-kflow-assets.web.app/shared/isometric-dungeon/Isometric/chestClosed_E.png";
|
|
7663
7687
|
assetSizeMap = {
|
|
7664
7688
|
sm: 28,
|
|
7665
7689
|
md: 40,
|
|
@@ -7732,6 +7756,7 @@ function getComboScale(combo) {
|
|
|
7732
7756
|
return "";
|
|
7733
7757
|
}
|
|
7734
7758
|
function ComboCounter({
|
|
7759
|
+
assetUrl = DEFAULT_ASSET_URL4,
|
|
7735
7760
|
combo = 5,
|
|
7736
7761
|
multiplier,
|
|
7737
7762
|
streak,
|
|
@@ -7751,6 +7776,17 @@ function ComboCounter({
|
|
|
7751
7776
|
className
|
|
7752
7777
|
),
|
|
7753
7778
|
children: [
|
|
7779
|
+
assetUrl && /* @__PURE__ */ jsxRuntime.jsx(
|
|
7780
|
+
"img",
|
|
7781
|
+
{
|
|
7782
|
+
src: assetUrl,
|
|
7783
|
+
alt: "combo",
|
|
7784
|
+
width: 24,
|
|
7785
|
+
height: 24,
|
|
7786
|
+
style: { imageRendering: "pixelated", objectFit: "contain" },
|
|
7787
|
+
className: "flex-shrink-0 mb-0.5"
|
|
7788
|
+
}
|
|
7789
|
+
),
|
|
7754
7790
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("font-black tabular-nums leading-none", sizes.combo, getComboIntensity(combo)), children: combo }),
|
|
7755
7791
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("font-bold uppercase tracking-wider text-muted-foreground", sizes.label), children: "combo" }),
|
|
7756
7792
|
multiplier != null && multiplier > 1 && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: cn("font-bold text-warning tabular-nums", sizes.multiplier), children: [
|
|
@@ -7765,10 +7801,11 @@ function ComboCounter({
|
|
|
7765
7801
|
}
|
|
7766
7802
|
);
|
|
7767
7803
|
}
|
|
7768
|
-
var sizeMap8;
|
|
7804
|
+
var DEFAULT_ASSET_URL4, sizeMap8;
|
|
7769
7805
|
var init_ComboCounter = __esm({
|
|
7770
7806
|
"components/game/atoms/ComboCounter.tsx"() {
|
|
7771
7807
|
init_cn();
|
|
7808
|
+
DEFAULT_ASSET_URL4 = "https://almadar-kflow-assets.web.app/shared/effects/flash/flash00.png";
|
|
7772
7809
|
sizeMap8 = {
|
|
7773
7810
|
sm: { combo: "text-lg", label: "text-xs", multiplier: "text-xs" },
|
|
7774
7811
|
md: { combo: "text-2xl", label: "text-xs", multiplier: "text-sm" },
|
|
@@ -7862,6 +7899,7 @@ var init_XPBar = __esm({
|
|
|
7862
7899
|
}
|
|
7863
7900
|
});
|
|
7864
7901
|
function WaypointMarker({
|
|
7902
|
+
assetUrl = DEFAULT_ASSET_URL5,
|
|
7865
7903
|
label,
|
|
7866
7904
|
icon,
|
|
7867
7905
|
active = true,
|
|
@@ -7900,7 +7938,17 @@ function WaypointMarker({
|
|
|
7900
7938
|
active && !completed && "bg-info text-foreground",
|
|
7901
7939
|
!active && !completed && "bg-muted"
|
|
7902
7940
|
),
|
|
7903
|
-
children: completed ? checkIcon :
|
|
7941
|
+
children: completed ? checkIcon : assetUrl ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
7942
|
+
"img",
|
|
7943
|
+
{
|
|
7944
|
+
src: assetUrl,
|
|
7945
|
+
alt: label,
|
|
7946
|
+
width: sizes.img,
|
|
7947
|
+
height: sizes.img,
|
|
7948
|
+
style: { imageRendering: "pixelated", objectFit: "contain" },
|
|
7949
|
+
className: "flex-shrink-0"
|
|
7950
|
+
}
|
|
7951
|
+
) : icon ? typeof icon === "string" ? /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: icon }) : /* @__PURE__ */ jsxRuntime.jsx(Icon, { icon }) : null
|
|
7904
7952
|
}
|
|
7905
7953
|
)
|
|
7906
7954
|
] }),
|
|
@@ -7917,15 +7965,16 @@ function WaypointMarker({
|
|
|
7917
7965
|
)
|
|
7918
7966
|
] });
|
|
7919
7967
|
}
|
|
7920
|
-
var sizeMap10, checkIcon;
|
|
7968
|
+
var DEFAULT_ASSET_URL5, sizeMap10, checkIcon;
|
|
7921
7969
|
var init_WaypointMarker = __esm({
|
|
7922
7970
|
"components/game/atoms/WaypointMarker.tsx"() {
|
|
7923
7971
|
init_cn();
|
|
7924
7972
|
init_Icon();
|
|
7973
|
+
DEFAULT_ASSET_URL5 = "https://almadar-kflow-assets.web.app/shared/world-map/battle_marker.png";
|
|
7925
7974
|
sizeMap10 = {
|
|
7926
|
-
sm: { dot: "w-4 h-4", ring: "w-6 h-6", label: "text-xs mt-1" },
|
|
7927
|
-
md: { dot: "w-6 h-6", ring: "w-8 h-8", label: "text-sm mt-1.5" },
|
|
7928
|
-
lg: { dot: "w-8 h-8", ring: "w-10 h-10", label: "text-base mt-2" }
|
|
7975
|
+
sm: { dot: "w-4 h-4", ring: "w-6 h-6", label: "text-xs mt-1", img: 12 },
|
|
7976
|
+
md: { dot: "w-6 h-6", ring: "w-8 h-8", label: "text-sm mt-1.5", img: 18 },
|
|
7977
|
+
lg: { dot: "w-8 h-8", ring: "w-10 h-10", label: "text-base mt-2", img: 24 }
|
|
7929
7978
|
};
|
|
7930
7979
|
checkIcon = /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 3, className: "w-3/5 h-3/5", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M5 13l4 4L19 7", strokeLinecap: "round", strokeLinejoin: "round" }) });
|
|
7931
7980
|
WaypointMarker.displayName = "WaypointMarker";
|
|
@@ -7938,6 +7987,7 @@ function formatDuration(seconds) {
|
|
|
7938
7987
|
return `${Math.round(seconds)}s`;
|
|
7939
7988
|
}
|
|
7940
7989
|
function StatusEffect({
|
|
7990
|
+
assetUrl = DEFAULT_ASSET_URL6,
|
|
7941
7991
|
icon = "shield",
|
|
7942
7992
|
label = "Shield",
|
|
7943
7993
|
duration = 30,
|
|
@@ -7958,7 +8008,17 @@ function StatusEffect({
|
|
|
7958
8008
|
),
|
|
7959
8009
|
title: label,
|
|
7960
8010
|
children: [
|
|
7961
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("flex items-center justify-center", sizes.icon), children:
|
|
8011
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("flex items-center justify-center", sizes.icon), children: assetUrl ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
8012
|
+
"img",
|
|
8013
|
+
{
|
|
8014
|
+
src: assetUrl,
|
|
8015
|
+
alt: label,
|
|
8016
|
+
width: sizes.img,
|
|
8017
|
+
height: sizes.img,
|
|
8018
|
+
style: { imageRendering: "pixelated", objectFit: "contain" },
|
|
8019
|
+
className: "flex-shrink-0"
|
|
8020
|
+
}
|
|
8021
|
+
) : typeof icon === "string" ? /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: icon, size: "sm" }) : /* @__PURE__ */ jsxRuntime.jsx(Icon, { icon, size: "sm" }) }),
|
|
7962
8022
|
duration !== void 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
7963
8023
|
"span",
|
|
7964
8024
|
{
|
|
@@ -7985,15 +8045,16 @@ function StatusEffect({
|
|
|
7985
8045
|
label && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground mt-0.5 text-center whitespace-nowrap", children: label })
|
|
7986
8046
|
] });
|
|
7987
8047
|
}
|
|
7988
|
-
var sizeMap11, variantStyles7;
|
|
8048
|
+
var DEFAULT_ASSET_URL6, sizeMap11, variantStyles7;
|
|
7989
8049
|
var init_StatusEffect = __esm({
|
|
7990
8050
|
"components/game/atoms/StatusEffect.tsx"() {
|
|
7991
8051
|
init_cn();
|
|
7992
8052
|
init_Icon();
|
|
8053
|
+
DEFAULT_ASSET_URL6 = "https://almadar-kflow-assets.web.app/shared/effects/particles/flame_01.png";
|
|
7993
8054
|
sizeMap11 = {
|
|
7994
|
-
sm: { container: "w-8 h-8", icon: "text-sm", badge: "text-xs -top-1 -right-1 w-4 h-4", timer: "text-[9px]" },
|
|
7995
|
-
md: { container: "w-10 h-10", icon: "text-base", badge: "text-xs -top-1 -right-1 w-5 h-5", timer: "text-xs" },
|
|
7996
|
-
lg: { container: "w-12 h-12", icon: "text-lg", badge: "text-sm -top-1.5 -right-1.5 w-6 h-6", timer: "text-xs" }
|
|
8055
|
+
sm: { container: "w-8 h-8", icon: "text-sm", badge: "text-xs -top-1 -right-1 w-4 h-4", timer: "text-[9px]", img: 20 },
|
|
8056
|
+
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 },
|
|
8057
|
+
lg: { container: "w-12 h-12", icon: "text-lg", badge: "text-sm -top-1.5 -right-1.5 w-6 h-6", timer: "text-xs", img: 36 }
|
|
7997
8058
|
};
|
|
7998
8059
|
variantStyles7 = {
|
|
7999
8060
|
buff: "border-success bg-success/20",
|
|
@@ -11906,15 +11967,15 @@ function BattleBoard({
|
|
|
11906
11967
|
const board = boardEntity(entity) ?? {};
|
|
11907
11968
|
const tiles = propTiles ?? (Array.isArray(board.tiles) ? board.tiles : []);
|
|
11908
11969
|
const features = propFeatures ?? (Array.isArray(board.features) ? board.features : []);
|
|
11909
|
-
const boardWidth = num(board.boardWidth, 8);
|
|
11910
|
-
const boardHeight = num(board.boardHeight, 6);
|
|
11970
|
+
const boardWidth = num(board.gridWidth ?? board.boardWidth, 8);
|
|
11971
|
+
const boardHeight = num(board.gridHeight ?? board.boardHeight, 6);
|
|
11911
11972
|
const assetManifest = propAssetManifest ?? board.assetManifest;
|
|
11912
11973
|
const backgroundImage = board.backgroundImage;
|
|
11913
11974
|
const units = rows(board.units);
|
|
11914
11975
|
const selectedUnitId = board.selectedUnitId ?? null;
|
|
11915
11976
|
const currentPhase = str(board.phase) || "observation";
|
|
11916
11977
|
const currentTurn = num(board.turn, 1);
|
|
11917
|
-
const gameResult = board.
|
|
11978
|
+
const gameResult = board.result ?? null;
|
|
11918
11979
|
const eventBus = useEventBus();
|
|
11919
11980
|
const { t } = hooks.useTranslate();
|
|
11920
11981
|
const [hoveredTile, setHoveredTile] = React83.useState(null);
|
|
@@ -11935,7 +11996,7 @@ function BattleBoard({
|
|
|
11935
11996
|
const validMoves = React83.useMemo(() => {
|
|
11936
11997
|
if (!selectedUnit || currentPhase !== "movement") return [];
|
|
11937
11998
|
const moves = [];
|
|
11938
|
-
const range = num(
|
|
11999
|
+
const range = num(board.movementRange, 2);
|
|
11939
12000
|
const origin = unitPosition(selectedUnit);
|
|
11940
12001
|
for (let dy = -range; dy <= range; dy++) {
|
|
11941
12002
|
for (let dx = -range; dx <= range; dx++) {
|
|
@@ -20220,15 +20281,24 @@ function CastleBoard({
|
|
|
20220
20281
|
featureClickEvent,
|
|
20221
20282
|
unitClickEvent,
|
|
20222
20283
|
tileClickEvent,
|
|
20284
|
+
playAgainEvent,
|
|
20223
20285
|
className
|
|
20224
20286
|
}) {
|
|
20225
20287
|
const eventBus = useEventBus();
|
|
20288
|
+
const { t } = hooks.useTranslate();
|
|
20226
20289
|
const resolved = boardEntity(entity);
|
|
20227
20290
|
const tiles = propTiles ?? (Array.isArray(resolved?.tiles) ? resolved.tiles : []);
|
|
20228
20291
|
const features = propFeatures ?? (Array.isArray(resolved?.features) ? resolved.features : []);
|
|
20229
20292
|
const units = propUnits ?? (Array.isArray(resolved?.units) ? resolved.units : []);
|
|
20230
20293
|
const assetManifest = propAssetManifest ?? resolved?.assetManifest;
|
|
20231
20294
|
const backgroundImage = resolved?.backgroundImage;
|
|
20295
|
+
const gold = num(resolved?.gold);
|
|
20296
|
+
const health = num(resolved?.health);
|
|
20297
|
+
const maxHealth = num(resolved?.maxHealth);
|
|
20298
|
+
const wave = num(resolved?.wave);
|
|
20299
|
+
const tickCount = num(resolved?.tickCount);
|
|
20300
|
+
const buildings = rows(resolved?.buildings);
|
|
20301
|
+
const result = str(resolved?.result) || "none";
|
|
20232
20302
|
const [hoveredTile, setHoveredTile] = React83.useState(null);
|
|
20233
20303
|
const [selectedFeature, setSelectedFeature] = React83.useState(null);
|
|
20234
20304
|
const hoveredFeature = React83.useMemo(() => {
|
|
@@ -20241,7 +20311,7 @@ function CastleBoard({
|
|
|
20241
20311
|
(u) => u.position?.x === hoveredTile.x && u.position?.y === hoveredTile.y
|
|
20242
20312
|
) ?? null;
|
|
20243
20313
|
}, [hoveredTile, units]);
|
|
20244
|
-
const maxY = Math.max(...tiles.map((
|
|
20314
|
+
const maxY = Math.max(...tiles.map((t2) => t2.y), 0);
|
|
20245
20315
|
const baseOffsetX = (maxY + 1) * (TILE_WIDTH * scale / 2);
|
|
20246
20316
|
const tileToScreen = React83.useCallback(
|
|
20247
20317
|
(tx, ty) => isoToScreen(tx, ty, scale, baseOffsetX),
|
|
@@ -20276,6 +20346,11 @@ function CastleBoard({
|
|
|
20276
20346
|
}
|
|
20277
20347
|
}, [units, onUnitClick, unitClickEvent, eventBus]);
|
|
20278
20348
|
const clearSelection = React83.useCallback(() => setSelectedFeature(null), []);
|
|
20349
|
+
const handlePlayAgain = React83.useCallback(() => {
|
|
20350
|
+
if (playAgainEvent) {
|
|
20351
|
+
eventBus.emit(`UI:${playAgainEvent}`, {});
|
|
20352
|
+
}
|
|
20353
|
+
}, [playAgainEvent, eventBus]);
|
|
20279
20354
|
const ctx = React83.useMemo(
|
|
20280
20355
|
() => ({
|
|
20281
20356
|
hoveredTile,
|
|
@@ -20284,11 +20359,18 @@ function CastleBoard({
|
|
|
20284
20359
|
selectedFeature,
|
|
20285
20360
|
clearSelection,
|
|
20286
20361
|
tileToScreen,
|
|
20287
|
-
scale
|
|
20362
|
+
scale,
|
|
20363
|
+
gold,
|
|
20364
|
+
health,
|
|
20365
|
+
maxHealth,
|
|
20366
|
+
wave,
|
|
20367
|
+
tickCount,
|
|
20368
|
+
buildings,
|
|
20369
|
+
result
|
|
20288
20370
|
}),
|
|
20289
|
-
[hoveredTile, hoveredFeature, hoveredUnit, selectedFeature, clearSelection, tileToScreen, scale]
|
|
20371
|
+
[hoveredTile, hoveredFeature, hoveredUnit, selectedFeature, clearSelection, tileToScreen, scale, gold, health, maxHealth, wave, tickCount, buildings, result]
|
|
20290
20372
|
);
|
|
20291
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("castle-board min-h-screen flex flex-col bg-background", className), children: [
|
|
20373
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("castle-board relative min-h-screen flex flex-col bg-background", className), children: [
|
|
20292
20374
|
header && header(ctx),
|
|
20293
20375
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 overflow-hidden", children: [
|
|
20294
20376
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 overflow-auto p-4 relative", children: [
|
|
@@ -20313,7 +20395,29 @@ function CastleBoard({
|
|
|
20313
20395
|
] }),
|
|
20314
20396
|
sidePanel && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-96 shrink-0 border-l border-border bg-surface overflow-y-auto", children: sidePanel(ctx) })
|
|
20315
20397
|
] }),
|
|
20316
|
-
footer && footer(ctx)
|
|
20398
|
+
footer && footer(ctx),
|
|
20399
|
+
result !== "none" && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "absolute inset-0 z-50 flex items-center justify-center bg-background/70 backdrop-blur-sm rounded-container", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { className: "text-center p-8", gap: "lg", children: [
|
|
20400
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
20401
|
+
Typography,
|
|
20402
|
+
{
|
|
20403
|
+
variant: "h2",
|
|
20404
|
+
className: cn(
|
|
20405
|
+
"text-4xl font-black tracking-widest uppercase",
|
|
20406
|
+
result === "victory" ? "text-warning" : "text-error"
|
|
20407
|
+
),
|
|
20408
|
+
children: result === "victory" ? t("battle.victory") : t("battle.defeat")
|
|
20409
|
+
}
|
|
20410
|
+
),
|
|
20411
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
20412
|
+
Button,
|
|
20413
|
+
{
|
|
20414
|
+
variant: "primary",
|
|
20415
|
+
className: "px-8 py-3 font-semibold",
|
|
20416
|
+
onClick: handlePlayAgain,
|
|
20417
|
+
children: t("battle.playAgain")
|
|
20418
|
+
}
|
|
20419
|
+
)
|
|
20420
|
+
] }) })
|
|
20317
20421
|
] });
|
|
20318
20422
|
}
|
|
20319
20423
|
var init_CastleBoard = __esm({
|
|
@@ -20321,6 +20425,10 @@ var init_CastleBoard = __esm({
|
|
|
20321
20425
|
"use client";
|
|
20322
20426
|
init_cn();
|
|
20323
20427
|
init_useEventBus();
|
|
20428
|
+
init_Box();
|
|
20429
|
+
init_Button();
|
|
20430
|
+
init_Typography();
|
|
20431
|
+
init_Stack();
|
|
20324
20432
|
init_IsometricCanvas();
|
|
20325
20433
|
init_boardEntity();
|
|
20326
20434
|
init_isometric();
|
|
@@ -21197,22 +21305,16 @@ function ClassifierBoard({
|
|
|
21197
21305
|
const { emit } = useEventBus();
|
|
21198
21306
|
const { t } = hooks.useTranslate();
|
|
21199
21307
|
const resolved = boardEntity(entity);
|
|
21200
|
-
const [localAssignments, setLocalAssignments] = React83.useState({});
|
|
21201
21308
|
const [headerError, setHeaderError] = React83.useState(false);
|
|
21202
|
-
const [localSubmitted, setLocalSubmitted] = React83.useState(false);
|
|
21203
|
-
const [localAttempts, setLocalAttempts] = React83.useState(0);
|
|
21204
|
-
const [showHint, setShowHint] = React83.useState(false);
|
|
21205
21309
|
const items = Array.isArray(resolved?.items) ? resolved.items : [];
|
|
21206
21310
|
const categories = Array.isArray(resolved?.categories) ? resolved.categories : [];
|
|
21207
|
-
const
|
|
21208
|
-
const
|
|
21209
|
-
const
|
|
21210
|
-
const assignments =
|
|
21211
|
-
if (item.assignedCategory != null) acc[item.id] = item.assignedCategory;
|
|
21311
|
+
const result = str(resolved?.result);
|
|
21312
|
+
const submitted = result === "win";
|
|
21313
|
+
const attempts = num(resolved?.attempts);
|
|
21314
|
+
const assignments = items.reduce((acc, item) => {
|
|
21315
|
+
if (item.assignedCategory != null && item.assignedCategory !== "") acc[item.id] = item.assignedCategory;
|
|
21212
21316
|
return acc;
|
|
21213
|
-
}, {})
|
|
21214
|
-
const attempts = entityDrivesResult ? num(resolved?.attempts) : localAttempts;
|
|
21215
|
-
const submitted = entityDrivesResult || localSubmitted;
|
|
21317
|
+
}, {});
|
|
21216
21318
|
const unassignedItems = items.filter((item) => !assignments[item.id]);
|
|
21217
21319
|
const allAssigned = items.length > 0 && Object.keys(assignments).length === items.length;
|
|
21218
21320
|
const results = submitted ? items.map((item) => ({
|
|
@@ -21220,54 +21322,25 @@ function ClassifierBoard({
|
|
|
21220
21322
|
assigned: assignments[item.id],
|
|
21221
21323
|
correct: assignments[item.id] === item.correctCategory
|
|
21222
21324
|
})) : [];
|
|
21223
|
-
const allCorrect =
|
|
21325
|
+
const allCorrect = result === "win";
|
|
21224
21326
|
const correctCount = results.filter((r) => r.correct).length;
|
|
21327
|
+
const showHint = attempts >= 2 && Boolean(str(resolved?.hint));
|
|
21225
21328
|
const handleAssign = (itemId, categoryId) => {
|
|
21226
21329
|
if (submitted) return;
|
|
21227
|
-
if (assignEvent) {
|
|
21228
|
-
emit(`UI:${assignEvent}`, { itemId, categoryId });
|
|
21229
|
-
}
|
|
21230
|
-
if (!entityHasAssignments) {
|
|
21231
|
-
setLocalAssignments((prev) => ({ ...prev, [itemId]: categoryId }));
|
|
21232
|
-
}
|
|
21330
|
+
if (assignEvent) emit(`UI:${assignEvent}`, { itemId, categoryId });
|
|
21233
21331
|
};
|
|
21234
21332
|
const handleUnassign = (itemId) => {
|
|
21235
21333
|
if (submitted) return;
|
|
21236
|
-
if (
|
|
21237
|
-
setLocalAssignments((prev) => {
|
|
21238
|
-
const next = { ...prev };
|
|
21239
|
-
delete next[itemId];
|
|
21240
|
-
return next;
|
|
21241
|
-
});
|
|
21242
|
-
}
|
|
21334
|
+
if (assignEvent) emit(`UI:${assignEvent}`, { itemId, categoryId: "" });
|
|
21243
21335
|
};
|
|
21244
|
-
const handleSubmit =
|
|
21245
|
-
if (checkEvent) {
|
|
21246
|
-
|
|
21247
|
-
|
|
21248
|
-
if (!entityDrivesResult) {
|
|
21249
|
-
setLocalSubmitted(true);
|
|
21250
|
-
setLocalAttempts((a) => a + 1);
|
|
21251
|
-
const correct = items.every((item) => assignments[item.id] === item.correctCategory);
|
|
21252
|
-
if (correct) {
|
|
21253
|
-
emit(`UI:${completeEvent}`, { success: true, attempts: attempts + 1 });
|
|
21254
|
-
}
|
|
21255
|
-
}
|
|
21256
|
-
}, [checkEvent, entityDrivesResult, items, assignments, attempts, completeEvent, emit]);
|
|
21257
|
-
const handleReset = () => {
|
|
21258
|
-
if (!entityDrivesResult) setLocalSubmitted(false);
|
|
21259
|
-
if (attempts >= 2 && str(resolved?.hint)) {
|
|
21260
|
-
setShowHint(true);
|
|
21336
|
+
const handleSubmit = () => {
|
|
21337
|
+
if (checkEvent) emit(`UI:${checkEvent}`, {});
|
|
21338
|
+
if (allAssigned && items.every((item) => assignments[item.id] === item.correctCategory)) {
|
|
21339
|
+
emit(`UI:${completeEvent}`, { success: true, attempts: attempts + 1 });
|
|
21261
21340
|
}
|
|
21262
21341
|
};
|
|
21263
21342
|
const handleFullReset = () => {
|
|
21264
|
-
if (playAgainEvent) {
|
|
21265
|
-
emit(`UI:${playAgainEvent}`, {});
|
|
21266
|
-
}
|
|
21267
|
-
setLocalAssignments({});
|
|
21268
|
-
setLocalSubmitted(false);
|
|
21269
|
-
setLocalAttempts(0);
|
|
21270
|
-
setShowHint(false);
|
|
21343
|
+
if (playAgainEvent) emit(`UI:${playAgainEvent}`, {});
|
|
21271
21344
|
};
|
|
21272
21345
|
if (!resolved) return null;
|
|
21273
21346
|
const theme = resolved.theme ?? void 0;
|
|
@@ -21306,17 +21379,17 @@ function ClassifierBoard({
|
|
|
21306
21379
|
/* @__PURE__ */ jsxRuntime.jsx(Badge, { size: "sm", children: catItems.length })
|
|
21307
21380
|
] }),
|
|
21308
21381
|
/* @__PURE__ */ jsxRuntime.jsx(HStack, { gap: "xs", className: "flex-wrap min-h-[2rem]", children: catItems.map((item) => {
|
|
21309
|
-
const
|
|
21382
|
+
const result2 = results.find((r) => r.item.id === item.id);
|
|
21310
21383
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
21311
21384
|
Badge,
|
|
21312
21385
|
{
|
|
21313
21386
|
size: "sm",
|
|
21314
|
-
className: `cursor-pointer ${
|
|
21387
|
+
className: `cursor-pointer ${result2 ? result2.correct ? "border-success bg-success/10" : "border-error bg-error/10" : ""}`,
|
|
21315
21388
|
onClick: () => handleUnassign(item.id),
|
|
21316
21389
|
children: [
|
|
21317
21390
|
item.iconUrl && /* @__PURE__ */ jsxRuntime.jsx("img", { src: item.iconUrl, alt: "", className: "w-3 h-3 object-contain inline-block" }),
|
|
21318
21391
|
item.label,
|
|
21319
|
-
|
|
21392
|
+
result2 && /* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: result2.correct ? LucideIcons2.CheckCircle : LucideIcons2.XCircle, size: "xs", className: result2.correct ? "text-success" : "text-error" })
|
|
21320
21393
|
]
|
|
21321
21394
|
},
|
|
21322
21395
|
item.id
|
|
@@ -21345,10 +21418,10 @@ function ClassifierBoard({
|
|
|
21345
21418
|
] }) }),
|
|
21346
21419
|
showHint && hint && /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: hint }) }),
|
|
21347
21420
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", justify: "center", children: [
|
|
21348
|
-
!submitted
|
|
21421
|
+
!submitted && /* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "primary", onClick: handleSubmit, disabled: !allAssigned, children: [
|
|
21349
21422
|
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: LucideIcons2.Send, size: "sm" }),
|
|
21350
21423
|
t("classifier.check")
|
|
21351
|
-
] })
|
|
21424
|
+
] }),
|
|
21352
21425
|
/* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "secondary", onClick: handleFullReset, children: [
|
|
21353
21426
|
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: LucideIcons2.RotateCcw, size: "sm" }),
|
|
21354
21427
|
t("classifier.reset")
|
|
@@ -29377,7 +29450,7 @@ var init_MapView = __esm({
|
|
|
29377
29450
|
shadowSize: [41, 41]
|
|
29378
29451
|
});
|
|
29379
29452
|
L.Marker.prototype.options.icon = defaultIcon;
|
|
29380
|
-
const { useEffect: useEffect73, useRef: useRef68, useCallback:
|
|
29453
|
+
const { useEffect: useEffect73, useRef: useRef68, useCallback: useCallback111, useState: useState104 } = React83__namespace.default;
|
|
29381
29454
|
const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
|
|
29382
29455
|
const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
|
|
29383
29456
|
function MapUpdater({ centerLat, centerLng, zoom }) {
|
|
@@ -29423,7 +29496,7 @@ var init_MapView = __esm({
|
|
|
29423
29496
|
}) {
|
|
29424
29497
|
const eventBus = useEventBus2();
|
|
29425
29498
|
const [clickedPosition, setClickedPosition] = useState104(null);
|
|
29426
|
-
const handleMapClick =
|
|
29499
|
+
const handleMapClick = useCallback111((lat, lng) => {
|
|
29427
29500
|
if (showClickedPin) {
|
|
29428
29501
|
setClickedPosition({ lat, lng });
|
|
29429
29502
|
}
|
|
@@ -29432,7 +29505,7 @@ var init_MapView = __esm({
|
|
|
29432
29505
|
eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
|
|
29433
29506
|
}
|
|
29434
29507
|
}, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
|
|
29435
|
-
const handleMarkerClick =
|
|
29508
|
+
const handleMarkerClick = useCallback111((marker) => {
|
|
29436
29509
|
onMarkerClick?.(marker);
|
|
29437
29510
|
if (markerClickEvent) {
|
|
29438
29511
|
eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
|
|
@@ -38663,44 +38736,27 @@ function DebuggerBoard({
|
|
|
38663
38736
|
const { t } = hooks.useTranslate();
|
|
38664
38737
|
const resolved = boardEntity(entity);
|
|
38665
38738
|
const [headerError, setHeaderError] = React83.useState(false);
|
|
38666
|
-
const [showHint, setShowHint] = React83.useState(false);
|
|
38667
38739
|
const lines = Array.isArray(resolved?.lines) ? resolved.lines : [];
|
|
38668
|
-
const result = resolved?.result
|
|
38740
|
+
const result = str(resolved?.result) || "none";
|
|
38669
38741
|
const attempts = num(resolved?.attempts);
|
|
38670
|
-
const submitted = result
|
|
38742
|
+
const submitted = result === "win";
|
|
38743
|
+
const showHint = !submitted && attempts >= 2 && Boolean(str(resolved?.hint));
|
|
38671
38744
|
const bugLines = lines.filter((l) => l.isBug);
|
|
38672
38745
|
const flaggedLines = lines.filter((l) => l.isFlagged);
|
|
38673
38746
|
const correctFlags = lines.filter((l) => l.isBug && l.isFlagged);
|
|
38674
38747
|
const falseFlags = lines.filter((l) => !l.isBug && l.isFlagged);
|
|
38675
|
-
const allCorrect =
|
|
38748
|
+
const allCorrect = submitted;
|
|
38676
38749
|
const toggleLine = (lineId) => {
|
|
38677
38750
|
if (submitted) return;
|
|
38678
|
-
if (toggleFlagEvent) {
|
|
38679
|
-
emit(`UI:${toggleFlagEvent}`, { lineId });
|
|
38680
|
-
}
|
|
38751
|
+
if (toggleFlagEvent) emit(`UI:${toggleFlagEvent}`, { lineId });
|
|
38681
38752
|
};
|
|
38682
38753
|
const handleSubmit = React83.useCallback(() => {
|
|
38683
|
-
if (checkEvent) {
|
|
38684
|
-
emit(`UI:${checkEvent}`, {});
|
|
38685
|
-
}
|
|
38754
|
+
if (checkEvent) emit(`UI:${checkEvent}`, {});
|
|
38686
38755
|
const correct = correctFlags.length === bugLines.length && falseFlags.length === 0;
|
|
38687
|
-
if (correct) {
|
|
38688
|
-
emit(`UI:${completeEvent}`, { success: true, attempts: attempts + 1 });
|
|
38689
|
-
}
|
|
38756
|
+
if (correct) emit(`UI:${completeEvent}`, { success: true, attempts: attempts + 1 });
|
|
38690
38757
|
}, [checkEvent, correctFlags.length, bugLines.length, falseFlags.length, attempts, completeEvent, emit]);
|
|
38691
38758
|
const handleReset = () => {
|
|
38692
|
-
if (playAgainEvent) {
|
|
38693
|
-
emit(`UI:${playAgainEvent}`, {});
|
|
38694
|
-
}
|
|
38695
|
-
if (attempts >= 2 && str(resolved?.hint)) {
|
|
38696
|
-
setShowHint(true);
|
|
38697
|
-
}
|
|
38698
|
-
};
|
|
38699
|
-
const handleFullReset = () => {
|
|
38700
|
-
if (playAgainEvent) {
|
|
38701
|
-
emit(`UI:${playAgainEvent}`, {});
|
|
38702
|
-
}
|
|
38703
|
-
setShowHint(false);
|
|
38759
|
+
if (playAgainEvent) emit(`UI:${playAgainEvent}`, {});
|
|
38704
38760
|
};
|
|
38705
38761
|
if (!resolved) return null;
|
|
38706
38762
|
const theme = resolved.theme ?? void 0;
|
|
@@ -38724,7 +38780,7 @@ function DebuggerBoard({
|
|
|
38724
38780
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", weight: "bold", children: str(resolved.title) })
|
|
38725
38781
|
] }),
|
|
38726
38782
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: str(resolved.description) }),
|
|
38727
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-muted-foreground", children: t("debugger.findBugs", { count: String(
|
|
38783
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-muted-foreground", children: t("debugger.findBugs", { count: String(lines.filter((l) => l.isBug).length) }) })
|
|
38728
38784
|
] }) }),
|
|
38729
38785
|
/* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-0 overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(VStack, { gap: "none", children: lines.map((line, i) => {
|
|
38730
38786
|
const isFlagged = !!line.isFlagged;
|
|
@@ -38774,11 +38830,11 @@ function DebuggerBoard({
|
|
|
38774
38830
|
] }) }),
|
|
38775
38831
|
showHint && hint && /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: hint }) }),
|
|
38776
38832
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", justify: "center", children: [
|
|
38777
|
-
!submitted
|
|
38833
|
+
!submitted && /* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "primary", onClick: handleSubmit, disabled: flaggedLines.length === 0, children: [
|
|
38778
38834
|
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: LucideIcons2.Send, size: "sm" }),
|
|
38779
38835
|
t("debugger.submit")
|
|
38780
|
-
] })
|
|
38781
|
-
/* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "secondary", onClick:
|
|
38836
|
+
] }),
|
|
38837
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "secondary", onClick: handleReset, children: [
|
|
38782
38838
|
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: LucideIcons2.RotateCcw, size: "sm" }),
|
|
38783
38839
|
t("debugger.reset")
|
|
38784
38840
|
] })
|
|
@@ -39779,39 +39835,40 @@ function EventHandlerBoard({
|
|
|
39779
39835
|
stepDurationMs = 800,
|
|
39780
39836
|
playEvent,
|
|
39781
39837
|
completeEvent,
|
|
39838
|
+
editRuleEvent,
|
|
39839
|
+
playAgainEvent,
|
|
39782
39840
|
className
|
|
39783
39841
|
}) {
|
|
39784
39842
|
const { emit } = useEventBus();
|
|
39785
39843
|
const { t } = hooks.useTranslate();
|
|
39786
39844
|
const resolved = boardEntity(entity);
|
|
39787
|
-
const
|
|
39788
|
-
const
|
|
39845
|
+
const objects = rows(resolved?.objects);
|
|
39846
|
+
const entityResult = str(resolved?.result) || "none";
|
|
39847
|
+
const isSuccess = entityResult === "win";
|
|
39848
|
+
const attempts = typeof resolved?.attempts === "number" ? resolved.attempts : 0;
|
|
39789
39849
|
const [selectedObjectId, setSelectedObjectId] = React83.useState(
|
|
39790
|
-
|
|
39850
|
+
objects[0] ? objId(objects[0]) : null
|
|
39791
39851
|
);
|
|
39792
39852
|
const [headerError, setHeaderError] = React83.useState(false);
|
|
39793
|
-
const [
|
|
39853
|
+
const [isPlaying, setIsPlaying] = React83.useState(false);
|
|
39794
39854
|
const [eventLog, setEventLog] = React83.useState([]);
|
|
39795
|
-
const [attempts, setAttempts] = React83.useState(0);
|
|
39796
39855
|
const timerRef = React83.useRef(null);
|
|
39797
39856
|
const logIdCounter = React83.useRef(0);
|
|
39798
39857
|
React83.useEffect(() => () => {
|
|
39799
39858
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
39800
39859
|
}, []);
|
|
39801
|
-
const selectedObject = objects.find((o) => objId(o) === selectedObjectId)
|
|
39860
|
+
const selectedObject = objects.find((o) => objId(o) === selectedObjectId) ?? null;
|
|
39802
39861
|
const handleRulesChange = React83.useCallback((objectId, rules) => {
|
|
39803
|
-
|
|
39804
|
-
|
|
39805
|
-
));
|
|
39806
|
-
}, []);
|
|
39862
|
+
if (editRuleEvent) emit(`UI:${editRuleEvent}`, { objectId, rules });
|
|
39863
|
+
}, [editRuleEvent, emit]);
|
|
39807
39864
|
const addLogEntry = React83.useCallback((icon, message, status = "done") => {
|
|
39808
39865
|
const id = `log-${logIdCounter.current++}`;
|
|
39809
39866
|
setEventLog((prev) => [...prev, { id, timestamp: Date.now(), icon, message, status }]);
|
|
39810
39867
|
}, []);
|
|
39811
39868
|
const handlePlay = React83.useCallback(() => {
|
|
39812
|
-
if (
|
|
39869
|
+
if (isPlaying || isSuccess) return;
|
|
39813
39870
|
if (playEvent) emit(`UI:${playEvent}`, {});
|
|
39814
|
-
|
|
39871
|
+
setIsPlaying(true);
|
|
39815
39872
|
setEventLog([]);
|
|
39816
39873
|
const allRules = [];
|
|
39817
39874
|
objects.forEach((obj) => {
|
|
@@ -39827,15 +39884,8 @@ function EventHandlerBoard({
|
|
|
39827
39884
|
let goalReached = false;
|
|
39828
39885
|
const processNext = () => {
|
|
39829
39886
|
if (eventQueue.length === 0 || stepIdx > 20) {
|
|
39830
|
-
|
|
39831
|
-
|
|
39832
|
-
if (completeEvent) {
|
|
39833
|
-
emit(`UI:${completeEvent}`, { success: true });
|
|
39834
|
-
}
|
|
39835
|
-
} else {
|
|
39836
|
-
setAttempts((prev) => prev + 1);
|
|
39837
|
-
setPlayState("fail");
|
|
39838
|
-
}
|
|
39887
|
+
setIsPlaying(false);
|
|
39888
|
+
if (goalReached && completeEvent) emit(`UI:${completeEvent}`, { success: true });
|
|
39839
39889
|
return;
|
|
39840
39890
|
}
|
|
39841
39891
|
const currentEvent = eventQueue.shift();
|
|
@@ -39866,21 +39916,19 @@ function EventHandlerBoard({
|
|
|
39866
39916
|
addLogEntry("\u{1F3AC}", t("eventHandler.simulationStarted", { events: triggers.join(", ") }), "active");
|
|
39867
39917
|
}
|
|
39868
39918
|
timerRef.current = setTimeout(processNext, stepDurationMs);
|
|
39869
|
-
}, [
|
|
39919
|
+
}, [isPlaying, isSuccess, objects, resolved, stepDurationMs, playEvent, completeEvent, emit, addLogEntry, t]);
|
|
39870
39920
|
const handleTryAgain = React83.useCallback(() => {
|
|
39871
39921
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
39872
|
-
|
|
39922
|
+
setIsPlaying(false);
|
|
39873
39923
|
setEventLog([]);
|
|
39874
39924
|
}, []);
|
|
39875
39925
|
const handleReset = React83.useCallback(() => {
|
|
39876
39926
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
39877
|
-
|
|
39878
|
-
setObjects([...resetObjects]);
|
|
39879
|
-
setPlayState("editing");
|
|
39927
|
+
setIsPlaying(false);
|
|
39880
39928
|
setEventLog([]);
|
|
39881
|
-
setSelectedObjectId(
|
|
39882
|
-
|
|
39883
|
-
}, [
|
|
39929
|
+
setSelectedObjectId(objects[0] ? objId(objects[0]) : null);
|
|
39930
|
+
if (playAgainEvent) emit(`UI:${playAgainEvent}`, {});
|
|
39931
|
+
}, [objects, playAgainEvent, emit]);
|
|
39884
39932
|
if (!resolved) return null;
|
|
39885
39933
|
const objectViewers = objects.map((obj) => {
|
|
39886
39934
|
const states = objStates(obj);
|
|
@@ -39949,12 +39997,12 @@ function EventHandlerBoard({
|
|
|
39949
39997
|
{
|
|
39950
39998
|
object: selectedObject,
|
|
39951
39999
|
onRulesChange: handleRulesChange,
|
|
39952
|
-
disabled:
|
|
40000
|
+
disabled: isPlaying
|
|
39953
40001
|
}
|
|
39954
40002
|
),
|
|
39955
40003
|
eventLog.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(EventLog, { entries: eventLog }),
|
|
39956
|
-
|
|
39957
|
-
|
|
40004
|
+
isSuccess && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "p-4 rounded-container bg-success/20 border border-success text-center", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h5", className: "text-success", children: str(resolved.successMessage) || t("eventHandler.chainComplete") }) }),
|
|
40005
|
+
!isPlaying && !isSuccess && attempts > 0 && /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
39958
40006
|
/* @__PURE__ */ jsxRuntime.jsx(Box, { className: "p-4 rounded-container bg-warning/10 border border-warning/30 text-center", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body1", className: "text-foreground font-medium", children: t(encourageKey) }) }),
|
|
39959
40007
|
showHint && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "p-3 rounded-container bg-accent/10 border border-accent/30", children: /* @__PURE__ */ jsxRuntime.jsxs(HStack, { className: "items-start", gap: "xs", children: [
|
|
39960
40008
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-accent font-bold shrink-0", children: "\u{1F4A1} " + t("game.hint") + ":" }),
|
|
@@ -39962,12 +40010,12 @@ function EventHandlerBoard({
|
|
|
39962
40010
|
] }) })
|
|
39963
40011
|
] }),
|
|
39964
40012
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", children: [
|
|
39965
|
-
|
|
40013
|
+
!isPlaying && !isSuccess && attempts > 0 ? /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "primary", onClick: handleTryAgain, children: "\u{1F504} " + t("puzzle.tryAgainButton") }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
39966
40014
|
Button,
|
|
39967
40015
|
{
|
|
39968
40016
|
variant: "primary",
|
|
39969
40017
|
onClick: handlePlay,
|
|
39970
|
-
disabled:
|
|
40018
|
+
disabled: isPlaying || isSuccess,
|
|
39971
40019
|
children: "\u25B6 " + t("game.play")
|
|
39972
40020
|
}
|
|
39973
40021
|
),
|
|
@@ -42520,21 +42568,6 @@ var init_ModalSlot = __esm({
|
|
|
42520
42568
|
ModalSlot.displayName = "ModalSlot";
|
|
42521
42569
|
}
|
|
42522
42570
|
});
|
|
42523
|
-
function getOpponentAction(strategy, actions, history) {
|
|
42524
|
-
const actionIds = actions.map((a) => a.id);
|
|
42525
|
-
switch (strategy) {
|
|
42526
|
-
case "always-cooperate":
|
|
42527
|
-
return actionIds[0];
|
|
42528
|
-
case "always-defect":
|
|
42529
|
-
return actionIds[actionIds.length - 1];
|
|
42530
|
-
case "tit-for-tat":
|
|
42531
|
-
if (history.length === 0) return actionIds[0];
|
|
42532
|
-
return history[history.length - 1].playerAction;
|
|
42533
|
-
case "random":
|
|
42534
|
-
default:
|
|
42535
|
-
return actionIds[Math.floor(Math.random() * actionIds.length)];
|
|
42536
|
-
}
|
|
42537
|
-
}
|
|
42538
42571
|
function NegotiatorBoard({
|
|
42539
42572
|
entity,
|
|
42540
42573
|
completeEvent = "PUZZLE_COMPLETE",
|
|
@@ -42556,28 +42589,35 @@ function NegotiatorBoard({
|
|
|
42556
42589
|
const playerTotal = num(resolved?.score);
|
|
42557
42590
|
const isComplete = result !== "none" || totalRounds > 0 && currentRound >= totalRounds;
|
|
42558
42591
|
const won = result === "win";
|
|
42559
|
-
const
|
|
42592
|
+
const lastPlayerAction = str(resolved?.lastPlayerAction);
|
|
42593
|
+
const lastOpponentAction = str(resolved?.lastOpponentAction);
|
|
42594
|
+
const lastPayoff = num(resolved?.lastPayoff);
|
|
42560
42595
|
const actions = Array.isArray(resolved?.actions) ? resolved.actions : [];
|
|
42561
42596
|
const payoffMatrix = Array.isArray(resolved?.payoffMatrix) ? resolved.payoffMatrix : [];
|
|
42597
|
+
const prevRoundRef = React83.useRef(currentRound);
|
|
42598
|
+
React83.useEffect(() => {
|
|
42599
|
+
if (currentRound > prevRoundRef.current && lastPlayerAction) {
|
|
42600
|
+
const opponentPayoffEntry = payoffMatrix.find(
|
|
42601
|
+
(p2) => p2.playerAction === lastPlayerAction && p2.opponentAction === lastOpponentAction
|
|
42602
|
+
);
|
|
42603
|
+
setHistory((prev) => [
|
|
42604
|
+
...prev,
|
|
42605
|
+
{
|
|
42606
|
+
round: currentRound,
|
|
42607
|
+
playerAction: lastPlayerAction,
|
|
42608
|
+
opponentAction: lastOpponentAction,
|
|
42609
|
+
playerPayoff: lastPayoff,
|
|
42610
|
+
opponentPayoff: opponentPayoffEntry?.opponentPayoff ?? 0
|
|
42611
|
+
}
|
|
42612
|
+
]);
|
|
42613
|
+
}
|
|
42614
|
+
prevRoundRef.current = currentRound;
|
|
42615
|
+
}, [currentRound, lastPlayerAction, lastOpponentAction, lastPayoff, payoffMatrix]);
|
|
42616
|
+
const opponentTotal = React83.useMemo(() => history.reduce((s, r) => s + r.opponentPayoff, 0), [history]);
|
|
42562
42617
|
const handleAction = React83.useCallback((actionId) => {
|
|
42563
42618
|
if (isComplete) return;
|
|
42564
|
-
const opponentAction = getOpponentAction(str(resolved?.opponentStrategy) || "random", actions, history);
|
|
42565
|
-
const payoff = payoffMatrix.find(
|
|
42566
|
-
(p2) => p2.playerAction === actionId && p2.opponentAction === opponentAction
|
|
42567
|
-
);
|
|
42568
|
-
const playerPayoff = payoff?.playerPayoff ?? 0;
|
|
42569
|
-
setHistory((prev) => [
|
|
42570
|
-
...prev,
|
|
42571
|
-
{
|
|
42572
|
-
round: prev.length + 1,
|
|
42573
|
-
playerAction: actionId,
|
|
42574
|
-
opponentAction,
|
|
42575
|
-
playerPayoff,
|
|
42576
|
-
opponentPayoff: payoff?.opponentPayoff ?? 0
|
|
42577
|
-
}
|
|
42578
|
-
]);
|
|
42579
42619
|
if (playRoundEvent) {
|
|
42580
|
-
emit(`UI:${playRoundEvent}`, { playerAction: actionId, payoff:
|
|
42620
|
+
emit(`UI:${playRoundEvent}`, { playerAction: actionId, payoff: 0 });
|
|
42581
42621
|
}
|
|
42582
42622
|
if (totalRounds > 0 && currentRound + 1 >= totalRounds) {
|
|
42583
42623
|
if (finishEvent) {
|
|
@@ -42587,10 +42627,11 @@ function NegotiatorBoard({
|
|
|
42587
42627
|
setShowHint(true);
|
|
42588
42628
|
}
|
|
42589
42629
|
}
|
|
42590
|
-
}, [isComplete, resolved, totalRounds, currentRound,
|
|
42630
|
+
}, [isComplete, resolved, totalRounds, currentRound, playRoundEvent, finishEvent, emit]);
|
|
42591
42631
|
const handleReset = React83.useCallback(() => {
|
|
42592
42632
|
setHistory([]);
|
|
42593
42633
|
setShowHint(false);
|
|
42634
|
+
prevRoundRef.current = 0;
|
|
42594
42635
|
if (playAgainEvent) {
|
|
42595
42636
|
emit(`UI:${playAgainEvent}`, {});
|
|
42596
42637
|
}
|
|
@@ -44926,17 +44967,24 @@ function SequencerBoard({
|
|
|
44926
44967
|
const { emit } = useEventBus();
|
|
44927
44968
|
const { t } = hooks.useTranslate();
|
|
44928
44969
|
const resolved = boardEntity(entity);
|
|
44929
|
-
const maxSlots = num(resolved?.maxSlots);
|
|
44970
|
+
const maxSlots = num(resolved?.maxSlots) || 3;
|
|
44930
44971
|
const solutions = Array.isArray(resolved?.solutions) ? resolved.solutions : [];
|
|
44931
44972
|
const availableActions = Array.isArray(resolved?.availableActions) ? resolved.availableActions : [];
|
|
44932
44973
|
const allowDuplicates = resolved?.allowDuplicates !== false;
|
|
44974
|
+
const entitySlots = Array.isArray(resolved?.slots) ? resolved.slots : [];
|
|
44975
|
+
const entityResult = str(resolved?.result);
|
|
44976
|
+
const entityAttempts = num(resolved?.attempts);
|
|
44977
|
+
const entityCurrentStep = typeof resolved?.currentStep === "number" ? resolved.currentStep : -1;
|
|
44978
|
+
const slots = Array.from({ length: maxSlots }, (_, i) => {
|
|
44979
|
+
const entitySlot = entitySlots.find((s) => s.index === i);
|
|
44980
|
+
if (!entitySlot?.placedActionId) return void 0;
|
|
44981
|
+
return availableActions.find((a) => a.id === entitySlot.placedActionId);
|
|
44982
|
+
});
|
|
44983
|
+
const isSuccess = entityResult === "win";
|
|
44984
|
+
const attempts = entityAttempts;
|
|
44985
|
+
const isPlayingBack = entityCurrentStep >= 0 && !isSuccess;
|
|
44986
|
+
const currentStep = entityCurrentStep;
|
|
44933
44987
|
const [headerError, setHeaderError] = React83.useState(false);
|
|
44934
|
-
const [slots, setSlots] = React83.useState(
|
|
44935
|
-
() => Array.from({ length: maxSlots }, () => void 0)
|
|
44936
|
-
);
|
|
44937
|
-
const [playState, setPlayState] = React83.useState("idle");
|
|
44938
|
-
const [currentStep, setCurrentStep] = React83.useState(-1);
|
|
44939
|
-
const [attempts, setAttempts] = React83.useState(0);
|
|
44940
44988
|
const [slotFeedback, setSlotFeedback] = React83.useState(
|
|
44941
44989
|
() => Array.from({ length: maxSlots }, () => null)
|
|
44942
44990
|
);
|
|
@@ -44945,11 +44993,6 @@ function SequencerBoard({
|
|
|
44945
44993
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
44946
44994
|
}, []);
|
|
44947
44995
|
const handleSlotDrop = React83.useCallback((index, item) => {
|
|
44948
|
-
setSlots((prev) => {
|
|
44949
|
-
const next = [...prev];
|
|
44950
|
-
next[index] = item;
|
|
44951
|
-
return next;
|
|
44952
|
-
});
|
|
44953
44996
|
setSlotFeedback((prev) => {
|
|
44954
44997
|
const next = [...prev];
|
|
44955
44998
|
next[index] = null;
|
|
@@ -44959,11 +45002,6 @@ function SequencerBoard({
|
|
|
44959
45002
|
if (placeEvent) emit(`UI:${placeEvent}`, { slotIndex: index, actionId: item.id });
|
|
44960
45003
|
}, [emit, placeEvent]);
|
|
44961
45004
|
const handleSlotRemove = React83.useCallback((index) => {
|
|
44962
|
-
setSlots((prev) => {
|
|
44963
|
-
const next = [...prev];
|
|
44964
|
-
next[index] = void 0;
|
|
44965
|
-
return next;
|
|
44966
|
-
});
|
|
44967
45005
|
setSlotFeedback((prev) => {
|
|
44968
45006
|
const next = [...prev];
|
|
44969
45007
|
next[index] = null;
|
|
@@ -44974,48 +45012,34 @@ function SequencerBoard({
|
|
|
44974
45012
|
}, [emit, removeEvent]);
|
|
44975
45013
|
const handleReset = React83.useCallback(() => {
|
|
44976
45014
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
44977
|
-
setSlots(Array.from({ length: maxSlots }, () => void 0));
|
|
44978
|
-
setPlayState("idle");
|
|
44979
|
-
setCurrentStep(-1);
|
|
44980
|
-
setAttempts(0);
|
|
44981
45015
|
setSlotFeedback(Array.from({ length: maxSlots }, () => null));
|
|
44982
45016
|
if (playAgainEvent) emit(`UI:${playAgainEvent}`, {});
|
|
44983
45017
|
}, [maxSlots, playAgainEvent, emit]);
|
|
44984
45018
|
const filledSlots = slots.filter((s) => !!s);
|
|
44985
|
-
const canPlay = filledSlots.length > 0 &&
|
|
45019
|
+
const canPlay = filledSlots.length > 0 && !isPlayingBack && !isSuccess;
|
|
44986
45020
|
const handlePlay = React83.useCallback(() => {
|
|
44987
45021
|
if (!canPlay) return;
|
|
44988
45022
|
setSlotFeedback(Array.from({ length: maxSlots }, () => null));
|
|
44989
45023
|
emit("UI:PLAY_SOUND", { key: "confirm" });
|
|
44990
45024
|
const sequence = slots.map((s) => s?.id || "");
|
|
44991
|
-
|
|
44992
|
-
|
|
44993
|
-
}
|
|
44994
|
-
setPlayState("playing");
|
|
44995
|
-
setCurrentStep(0);
|
|
45025
|
+
const playerIds = slots.filter(Boolean).map((s) => s?.id || "");
|
|
45026
|
+
if (playEvent) emit(`UI:${playEvent}`, { sequence });
|
|
44996
45027
|
let step = 0;
|
|
44997
45028
|
const advance = () => {
|
|
44998
45029
|
step++;
|
|
45030
|
+
emit("UI:STEP", { step });
|
|
44999
45031
|
if (step >= maxSlots) {
|
|
45032
|
+
if (checkEvent) emit(`UI:${checkEvent}`, { sequence: playerIds });
|
|
45000
45033
|
const playerSeq = slots.map((s) => s?.id);
|
|
45001
|
-
const playerIds = slots.filter(Boolean).map((s) => s?.id || "");
|
|
45002
45034
|
const success = solutions.some(
|
|
45003
45035
|
(sol) => sol.length === playerIds.length && sol.every((id, i) => id === playerIds[i])
|
|
45004
45036
|
);
|
|
45005
|
-
if (checkEvent) emit(`UI:${checkEvent}`, { sequence: playerIds });
|
|
45006
45037
|
if (success) {
|
|
45007
|
-
setPlayState("success");
|
|
45008
|
-
setCurrentStep(-1);
|
|
45009
45038
|
emit("UI:PLAY_SOUND", { key: "levelComplete" });
|
|
45010
|
-
if (completeEvent) {
|
|
45011
|
-
emit(`UI:${completeEvent}`, { success: true, sequence: playerIds });
|
|
45012
|
-
}
|
|
45039
|
+
if (completeEvent) emit(`UI:${completeEvent}`, { success: true, sequence: playerIds });
|
|
45013
45040
|
} else {
|
|
45014
|
-
setAttempts((prev) => prev + 1);
|
|
45015
45041
|
const feedback = computeSlotFeedback(playerSeq, solutions);
|
|
45016
45042
|
setSlotFeedback(feedback);
|
|
45017
|
-
setPlayState("idle");
|
|
45018
|
-
setCurrentStep(-1);
|
|
45019
45043
|
emit("UI:PLAY_SOUND", { key: "fail" });
|
|
45020
45044
|
const correctCount2 = feedback.filter((f3) => f3 === "correct").length;
|
|
45021
45045
|
for (let ci = 0; ci < correctCount2; ci++) {
|
|
@@ -45025,7 +45049,6 @@ function SequencerBoard({
|
|
|
45025
45049
|
}
|
|
45026
45050
|
}
|
|
45027
45051
|
} else {
|
|
45028
|
-
setCurrentStep(step);
|
|
45029
45052
|
timerRef.current = setTimeout(advance, stepDurationMs);
|
|
45030
45053
|
}
|
|
45031
45054
|
};
|
|
@@ -45075,7 +45098,7 @@ function SequencerBoard({
|
|
|
45075
45098
|
/* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", children: [
|
|
45076
45099
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { className: "items-center justify-between", children: [
|
|
45077
45100
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-muted-foreground font-medium", children: t("sequencer.yourSequence") + ":" }),
|
|
45078
|
-
hasFeedback &&
|
|
45101
|
+
hasFeedback && !isPlayingBack && !isSuccess && /* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "caption", className: "text-muted-foreground", children: [
|
|
45079
45102
|
`${correctCount}/${maxSlots} `,
|
|
45080
45103
|
"\u2705"
|
|
45081
45104
|
] })
|
|
@@ -45087,7 +45110,7 @@ function SequencerBoard({
|
|
|
45087
45110
|
maxSlots,
|
|
45088
45111
|
onSlotDrop: handleSlotDrop,
|
|
45089
45112
|
onSlotRemove: handleSlotRemove,
|
|
45090
|
-
playing:
|
|
45113
|
+
playing: isPlayingBack,
|
|
45091
45114
|
currentStep,
|
|
45092
45115
|
categoryColors,
|
|
45093
45116
|
slotFeedback,
|
|
@@ -45095,7 +45118,7 @@ function SequencerBoard({
|
|
|
45095
45118
|
}
|
|
45096
45119
|
)
|
|
45097
45120
|
] }),
|
|
45098
|
-
|
|
45121
|
+
!isPlayingBack && /* @__PURE__ */ jsxRuntime.jsx(
|
|
45099
45122
|
ActionPalette,
|
|
45100
45123
|
{
|
|
45101
45124
|
actions: availableActions,
|
|
@@ -45105,8 +45128,8 @@ function SequencerBoard({
|
|
|
45105
45128
|
label: t("sequencer.dragActions")
|
|
45106
45129
|
}
|
|
45107
45130
|
),
|
|
45108
|
-
hasFeedback &&
|
|
45109
|
-
|
|
45131
|
+
hasFeedback && !isPlayingBack && !isSuccess && attempts > 0 && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "p-3 rounded-container bg-warning/10 border border-warning/30 text-center", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-foreground", children: t(encourageKey) }) }),
|
|
45132
|
+
isSuccess && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "p-4 rounded-container bg-success/20 border border-success text-center", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h5", className: "text-success", children: str(resolved.successMessage) || t("sequencer.levelComplete") }) }),
|
|
45110
45133
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", children: [
|
|
45111
45134
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
45112
45135
|
Button,
|
|
@@ -46156,6 +46179,9 @@ function StateArchitectBoard({
|
|
|
46156
46179
|
stepDurationMs = 600,
|
|
46157
46180
|
testEvent,
|
|
46158
46181
|
completeEvent,
|
|
46182
|
+
addTransitionEvent,
|
|
46183
|
+
removeTransitionEvent,
|
|
46184
|
+
playAgainEvent,
|
|
46159
46185
|
className
|
|
46160
46186
|
}) {
|
|
46161
46187
|
const { emit } = useEventBus();
|
|
@@ -46168,14 +46194,16 @@ function StateArchitectBoard({
|
|
|
46168
46194
|
const testCases = Array.isArray(resolved?.testCases) ? resolved.testCases : [];
|
|
46169
46195
|
const entityTransitions = Array.isArray(resolved?.transitions) ? resolved.transitions : [];
|
|
46170
46196
|
const entityVariables = rows(resolved?.variables);
|
|
46171
|
-
const
|
|
46197
|
+
const transitions = entityTransitions;
|
|
46198
|
+
const attempts = typeof resolved?.attempts === "number" ? resolved.attempts : 0;
|
|
46199
|
+
const entityResult = str(resolved?.result) || "none";
|
|
46200
|
+
const isSuccess = entityResult === "win";
|
|
46201
|
+
const [isTesting, setIsTesting] = React83.useState(false);
|
|
46172
46202
|
const [headerError, setHeaderError] = React83.useState(false);
|
|
46173
|
-
const [playState, setPlayState] = React83.useState("editing");
|
|
46174
46203
|
const [currentState, setCurrentState] = React83.useState(initialState);
|
|
46175
46204
|
const [selectedState, setSelectedState] = React83.useState(null);
|
|
46176
46205
|
const [testResults, setTestResults] = React83.useState([]);
|
|
46177
46206
|
const [variables, setVariables] = React83.useState(() => [...entityVariables]);
|
|
46178
|
-
const [attempts, setAttempts] = React83.useState(0);
|
|
46179
46207
|
const timerRef = React83.useRef(null);
|
|
46180
46208
|
const [addingFrom, setAddingFrom] = React83.useState(null);
|
|
46181
46209
|
React83.useEffect(() => () => {
|
|
@@ -46185,7 +46213,7 @@ function StateArchitectBoard({
|
|
|
46185
46213
|
const GRAPH_H = 400;
|
|
46186
46214
|
const positions = React83.useMemo(() => layoutStates(entityStates, GRAPH_W, GRAPH_H), [entityStates]);
|
|
46187
46215
|
const handleStateClick = React83.useCallback((state) => {
|
|
46188
|
-
if (
|
|
46216
|
+
if (isTesting) return;
|
|
46189
46217
|
if (addingFrom) {
|
|
46190
46218
|
if (addingFrom !== state) {
|
|
46191
46219
|
const event = availableEvents[0] || "EVENT";
|
|
@@ -46195,20 +46223,20 @@ function StateArchitectBoard({
|
|
|
46195
46223
|
to: state,
|
|
46196
46224
|
event
|
|
46197
46225
|
};
|
|
46198
|
-
|
|
46226
|
+
if (addTransitionEvent) emit(`UI:${addTransitionEvent}`, { id: newTrans.id, from: newTrans.from, to: newTrans.to, event: newTrans.event });
|
|
46199
46227
|
}
|
|
46200
46228
|
setAddingFrom(null);
|
|
46201
46229
|
} else {
|
|
46202
46230
|
setSelectedState(state);
|
|
46203
46231
|
}
|
|
46204
|
-
}, [
|
|
46232
|
+
}, [isTesting, addingFrom, availableEvents, addTransitionEvent, emit]);
|
|
46205
46233
|
const handleStartAddTransition = React83.useCallback(() => {
|
|
46206
46234
|
if (!selectedState) return;
|
|
46207
46235
|
setAddingFrom(selectedState);
|
|
46208
46236
|
}, [selectedState]);
|
|
46209
46237
|
const handleRemoveTransition = React83.useCallback((transId) => {
|
|
46210
|
-
|
|
46211
|
-
}, []);
|
|
46238
|
+
if (removeTransitionEvent) emit(`UI:${removeTransitionEvent}`, { id: transId });
|
|
46239
|
+
}, [removeTransitionEvent, emit]);
|
|
46212
46240
|
const machine = React83.useMemo(() => ({
|
|
46213
46241
|
name: entityName,
|
|
46214
46242
|
description: str(resolved?.description),
|
|
@@ -46222,16 +46250,16 @@ function StateArchitectBoard({
|
|
|
46222
46250
|
}))
|
|
46223
46251
|
}), [entityName, resolved, entityStates, currentState, transitions]);
|
|
46224
46252
|
const handleTest = React83.useCallback(() => {
|
|
46225
|
-
if (
|
|
46253
|
+
if (isTesting) return;
|
|
46226
46254
|
if (testEvent) emit(`UI:${testEvent}`, {});
|
|
46227
|
-
|
|
46255
|
+
setIsTesting(true);
|
|
46228
46256
|
setTestResults([]);
|
|
46229
46257
|
const results = [];
|
|
46230
46258
|
let testIdx = 0;
|
|
46231
46259
|
const runNextTest = () => {
|
|
46232
46260
|
if (testIdx >= testCases.length) {
|
|
46233
46261
|
const allPassed = results.every((r) => r.passed);
|
|
46234
|
-
|
|
46262
|
+
setIsTesting(false);
|
|
46235
46263
|
setTestResults(results);
|
|
46236
46264
|
if (allPassed && completeEvent) {
|
|
46237
46265
|
emit(`UI:${completeEvent}`, {
|
|
@@ -46239,9 +46267,6 @@ function StateArchitectBoard({
|
|
|
46239
46267
|
passedTests: results.filter((r) => r.passed).length
|
|
46240
46268
|
});
|
|
46241
46269
|
}
|
|
46242
|
-
if (!allPassed) {
|
|
46243
|
-
setAttempts((prev) => prev + 1);
|
|
46244
|
-
}
|
|
46245
46270
|
return;
|
|
46246
46271
|
}
|
|
46247
46272
|
const testCase = testCases[testIdx];
|
|
@@ -46264,24 +46289,23 @@ function StateArchitectBoard({
|
|
|
46264
46289
|
timerRef.current = setTimeout(runNextTest, stepDurationMs);
|
|
46265
46290
|
};
|
|
46266
46291
|
timerRef.current = setTimeout(runNextTest, stepDurationMs);
|
|
46267
|
-
}, [
|
|
46292
|
+
}, [isTesting, transitions, testCases, initialState, stepDurationMs, testEvent, completeEvent, emit]);
|
|
46268
46293
|
const handleTryAgain = React83.useCallback(() => {
|
|
46269
46294
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
46270
|
-
|
|
46295
|
+
setIsTesting(false);
|
|
46271
46296
|
setCurrentState(initialState);
|
|
46272
46297
|
setTestResults([]);
|
|
46273
46298
|
}, [initialState]);
|
|
46274
46299
|
const handleReset = React83.useCallback(() => {
|
|
46275
46300
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
46276
|
-
|
|
46277
|
-
setPlayState("editing");
|
|
46301
|
+
setIsTesting(false);
|
|
46278
46302
|
setCurrentState(initialState);
|
|
46279
46303
|
setTestResults([]);
|
|
46280
46304
|
setVariables([...entityVariables]);
|
|
46281
46305
|
setSelectedState(null);
|
|
46282
46306
|
setAddingFrom(null);
|
|
46283
|
-
|
|
46284
|
-
}, [
|
|
46307
|
+
if (playAgainEvent) emit(`UI:${playAgainEvent}`, {});
|
|
46308
|
+
}, [initialState, entityVariables, playAgainEvent, emit]);
|
|
46285
46309
|
const codeData = React83.useMemo(() => ({
|
|
46286
46310
|
name: entityName,
|
|
46287
46311
|
states: entityStates,
|
|
@@ -46377,7 +46401,7 @@ function StateArchitectBoard({
|
|
|
46377
46401
|
]
|
|
46378
46402
|
}
|
|
46379
46403
|
),
|
|
46380
|
-
|
|
46404
|
+
!isTesting && /* @__PURE__ */ jsxRuntime.jsx(HStack, { gap: "sm", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
46381
46405
|
Button,
|
|
46382
46406
|
{
|
|
46383
46407
|
variant: "ghost",
|
|
@@ -46399,7 +46423,7 @@ function StateArchitectBoard({
|
|
|
46399
46423
|
t2.guardHint,
|
|
46400
46424
|
")"
|
|
46401
46425
|
] }),
|
|
46402
|
-
|
|
46426
|
+
!isTesting && /* @__PURE__ */ jsxRuntime.jsx(
|
|
46403
46427
|
Button,
|
|
46404
46428
|
{
|
|
46405
46429
|
variant: "ghost",
|
|
@@ -46431,21 +46455,21 @@ function StateArchitectBoard({
|
|
|
46431
46455
|
resolved.showCodeView !== false && /* @__PURE__ */ jsxRuntime.jsx(StateJsonView, { data: codeData, label: "View Code" })
|
|
46432
46456
|
] })
|
|
46433
46457
|
] }),
|
|
46434
|
-
|
|
46435
|
-
|
|
46458
|
+
isSuccess && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "p-4 rounded-container bg-success/20 border border-success text-center", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h5", className: "text-success", children: str(resolved.successMessage) || t("stateArchitect.allPassed") }) }),
|
|
46459
|
+
!isTesting && !isSuccess && testResults.some((r) => !r.passed) && /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
46436
46460
|
/* @__PURE__ */ jsxRuntime.jsx(Box, { className: "p-4 rounded-container bg-warning/10 border border-warning/30 text-center", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body1", className: "text-foreground font-medium", children: t(ENCOURAGEMENT_KEYS3[Math.min(attempts - 1, ENCOURAGEMENT_KEYS3.length - 1)] ?? ENCOURAGEMENT_KEYS3[0]) }) }),
|
|
46437
|
-
attempts >=
|
|
46461
|
+
!isSuccess && attempts >= 2 && Boolean(str(resolved?.hint)) && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "p-3 rounded-container bg-accent/10 border border-accent/30", children: /* @__PURE__ */ jsxRuntime.jsxs(HStack, { className: "items-start", gap: "xs", children: [
|
|
46438
46462
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-accent font-bold shrink-0", children: "\u{1F4A1} " + t("game.hint") + ":" }),
|
|
46439
46463
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-foreground", children: hint })
|
|
46440
46464
|
] }) })
|
|
46441
46465
|
] }),
|
|
46442
46466
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", children: [
|
|
46443
|
-
|
|
46467
|
+
!isTesting && !isSuccess && testResults.some((r) => !r.passed) ? /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "primary", onClick: handleTryAgain, children: "\u{1F504} " + t("puzzle.tryAgainButton") }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
46444
46468
|
Button,
|
|
46445
46469
|
{
|
|
46446
46470
|
variant: "primary",
|
|
46447
46471
|
onClick: handleTest,
|
|
46448
|
-
disabled:
|
|
46472
|
+
disabled: isTesting,
|
|
46449
46473
|
children: "\u25B6 " + t("game.runTests")
|
|
46450
46474
|
}
|
|
46451
46475
|
),
|
|
@@ -47149,17 +47173,12 @@ var init_UncontrolledBattleBoard = __esm({
|
|
|
47149
47173
|
}
|
|
47150
47174
|
});
|
|
47151
47175
|
function heroPosition(h) {
|
|
47176
|
+
if ("position" in h && h.position != null) return h.position;
|
|
47152
47177
|
return vec2(h.position);
|
|
47153
47178
|
}
|
|
47154
|
-
function heroOwner(h) {
|
|
47155
|
-
return str(h.owner);
|
|
47156
|
-
}
|
|
47157
47179
|
function heroMovement(h) {
|
|
47158
47180
|
return num(h.movement);
|
|
47159
47181
|
}
|
|
47160
|
-
function hexPassable(h) {
|
|
47161
|
-
return h.passable !== false;
|
|
47162
|
-
}
|
|
47163
47182
|
function defaultIsInRange(from, to, range) {
|
|
47164
47183
|
return Math.abs(from.x - to.x) + Math.abs(from.y - to.y) <= range;
|
|
47165
47184
|
}
|
|
@@ -47195,38 +47214,41 @@ function WorldMapBoard({
|
|
|
47195
47214
|
}) {
|
|
47196
47215
|
const eventBus = useEventBus();
|
|
47197
47216
|
const resolved = boardEntity(entity);
|
|
47198
|
-
const
|
|
47199
|
-
const
|
|
47217
|
+
const entityUnits = rows(resolved?.units);
|
|
47218
|
+
const entityTiles = rows(resolved?.tiles);
|
|
47200
47219
|
const features = propFeatures ?? (Array.isArray(resolved?.features) ? resolved.features : []);
|
|
47201
47220
|
const selectedHeroId = resolved?.selectedHeroId ?? null;
|
|
47202
47221
|
const assetManifest = propAssetManifest ?? resolved?.assetManifest;
|
|
47203
47222
|
const backgroundImage = resolved?.backgroundImage;
|
|
47204
47223
|
const [hoveredTile, setHoveredTile] = React83.useState(null);
|
|
47205
|
-
const selectedHero = React83.useMemo(
|
|
47206
|
-
() => heroes.find((h) => str(h.id) === selectedHeroId) ?? null,
|
|
47207
|
-
[heroes, selectedHeroId]
|
|
47208
|
-
);
|
|
47209
47224
|
const derivedTiles = React83.useMemo(
|
|
47210
|
-
() =>
|
|
47211
|
-
x: num(
|
|
47212
|
-
y: num(
|
|
47213
|
-
terrain: str(
|
|
47214
|
-
terrainSprite:
|
|
47225
|
+
() => entityTiles.map((t) => ({
|
|
47226
|
+
x: num(t.x),
|
|
47227
|
+
y: num(t.y),
|
|
47228
|
+
terrain: str(t.terrain),
|
|
47229
|
+
terrainSprite: t.terrainSprite == null ? void 0 : str(t.terrainSprite),
|
|
47230
|
+
passable: t.passable !== false
|
|
47215
47231
|
})),
|
|
47216
|
-
[
|
|
47232
|
+
[entityTiles]
|
|
47217
47233
|
);
|
|
47218
47234
|
const tiles = propTiles ?? derivedTiles;
|
|
47219
47235
|
const baseUnits = React83.useMemo(
|
|
47220
|
-
() => propUnits ??
|
|
47221
|
-
id: str(
|
|
47222
|
-
position: heroPosition(
|
|
47223
|
-
name: str(
|
|
47224
|
-
|
|
47225
|
-
|
|
47226
|
-
|
|
47227
|
-
|
|
47236
|
+
() => propUnits ?? entityUnits.map((u) => ({
|
|
47237
|
+
id: str(u.id),
|
|
47238
|
+
position: heroPosition(u),
|
|
47239
|
+
name: str(u.name),
|
|
47240
|
+
// lolo uses `team` field (not `owner`)
|
|
47241
|
+
team: str(u.team) === "enemy" ? "enemy" : "player",
|
|
47242
|
+
health: num(u.health) || 100,
|
|
47243
|
+
maxHealth: num(u.maxHealth) || 100,
|
|
47244
|
+
sprite: u.sprite == null ? void 0 : str(u.sprite)
|
|
47228
47245
|
})),
|
|
47229
|
-
[
|
|
47246
|
+
[entityUnits, propUnits]
|
|
47247
|
+
);
|
|
47248
|
+
const gameUnits = baseUnits;
|
|
47249
|
+
const selectedHero = React83.useMemo(
|
|
47250
|
+
() => gameUnits.find((u) => u.id === selectedHeroId) ?? null,
|
|
47251
|
+
[gameUnits, selectedHeroId]
|
|
47230
47252
|
);
|
|
47231
47253
|
const MOVE_SPEED_MS_PER_TILE = 300;
|
|
47232
47254
|
const movementAnimRef = React83.useRef(null);
|
|
@@ -47272,51 +47294,50 @@ function WorldMapBoard({
|
|
|
47272
47294
|
const validMoves = React83.useMemo(() => {
|
|
47273
47295
|
if (!selectedHero || heroMovement(selectedHero) <= 0) return [];
|
|
47274
47296
|
const sp = heroPosition(selectedHero);
|
|
47275
|
-
const
|
|
47297
|
+
const sTeam = str(selectedHero.team);
|
|
47276
47298
|
const range = heroMovement(selectedHero);
|
|
47277
47299
|
const moves = [];
|
|
47278
|
-
|
|
47279
|
-
const
|
|
47280
|
-
const
|
|
47281
|
-
if (
|
|
47282
|
-
if (
|
|
47283
|
-
if (!isInRange(sp, { x:
|
|
47284
|
-
if (
|
|
47285
|
-
const
|
|
47286
|
-
return
|
|
47300
|
+
tiles.forEach((t) => {
|
|
47301
|
+
const tx = t.x;
|
|
47302
|
+
const ty = t.y;
|
|
47303
|
+
if (t.passable === false) return;
|
|
47304
|
+
if (tx === sp.x && ty === sp.y) return;
|
|
47305
|
+
if (!isInRange(sp, { x: tx, y: ty }, range)) return;
|
|
47306
|
+
if (gameUnits.some((u) => {
|
|
47307
|
+
const up = u.position ?? { x: u.x ?? -1, y: u.y ?? -1 };
|
|
47308
|
+
return up.x === tx && up.y === ty && str(u.team) === sTeam;
|
|
47287
47309
|
})) return;
|
|
47288
|
-
moves.push({ x:
|
|
47310
|
+
moves.push({ x: tx, y: ty });
|
|
47289
47311
|
});
|
|
47290
47312
|
return moves;
|
|
47291
|
-
}, [selectedHero,
|
|
47313
|
+
}, [selectedHero, tiles, gameUnits, isInRange]);
|
|
47292
47314
|
const attackTargets = React83.useMemo(() => {
|
|
47293
47315
|
if (!selectedHero || heroMovement(selectedHero) <= 0) return [];
|
|
47294
47316
|
const sp = heroPosition(selectedHero);
|
|
47295
|
-
const
|
|
47317
|
+
const sTeam = str(selectedHero.team);
|
|
47296
47318
|
const range = heroMovement(selectedHero);
|
|
47297
|
-
return
|
|
47298
|
-
}, [selectedHero,
|
|
47299
|
-
const maxY = Math.max(...
|
|
47319
|
+
return gameUnits.filter((u) => str(u.team) !== sTeam).filter((u) => isInRange(sp, u.position ?? { x: u.x ?? -1, y: u.y ?? -1 }, range)).map((u) => u.position ?? { x: u.x ?? -1, y: u.y ?? -1 });
|
|
47320
|
+
}, [selectedHero, gameUnits, isInRange]);
|
|
47321
|
+
const maxY = Math.max(...tiles.map((t) => t.y), 0);
|
|
47300
47322
|
const baseOffsetX = (maxY + 1) * (TILE_WIDTH * scale / 2);
|
|
47301
47323
|
const tileToScreen = React83.useCallback(
|
|
47302
47324
|
(tx, ty) => isoToScreen(tx, ty, scale, baseOffsetX),
|
|
47303
47325
|
[scale, baseOffsetX]
|
|
47304
47326
|
);
|
|
47305
47327
|
const hoveredHex = React83.useMemo(
|
|
47306
|
-
() => hoveredTile ?
|
|
47307
|
-
[hoveredTile,
|
|
47328
|
+
() => hoveredTile ? tiles.find((t) => t.x === hoveredTile.x && t.y === hoveredTile.y) ?? null : null,
|
|
47329
|
+
[hoveredTile, tiles]
|
|
47308
47330
|
);
|
|
47309
47331
|
const hoveredHero = React83.useMemo(
|
|
47310
|
-
() => hoveredTile ?
|
|
47311
|
-
const
|
|
47312
|
-
return
|
|
47332
|
+
() => hoveredTile ? gameUnits.find((u) => {
|
|
47333
|
+
const up = u.position ?? { x: u.x ?? -1, y: u.y ?? -1 };
|
|
47334
|
+
return up.x === hoveredTile.x && up.y === hoveredTile.y;
|
|
47313
47335
|
}) ?? null : null,
|
|
47314
|
-
[hoveredTile,
|
|
47336
|
+
[hoveredTile, gameUnits]
|
|
47315
47337
|
);
|
|
47316
47338
|
const handleTileClick = React83.useCallback((x, y) => {
|
|
47317
47339
|
if (movementAnimRef.current) return;
|
|
47318
|
-
const
|
|
47319
|
-
if (!hex) return;
|
|
47340
|
+
const tile = tiles.find((t) => t.x === x && t.y === y);
|
|
47320
47341
|
if (tileClickEvent) {
|
|
47321
47342
|
eventBus.emit(`UI:${tileClickEvent}`, { x, y });
|
|
47322
47343
|
}
|
|
@@ -47327,38 +47348,39 @@ function WorldMapBoard({
|
|
|
47327
47348
|
if (heroMoveEvent) {
|
|
47328
47349
|
eventBus.emit(`UI:${heroMoveEvent}`, { heroId, toX: x, toY: y });
|
|
47329
47350
|
}
|
|
47330
|
-
const feature = str(
|
|
47351
|
+
const feature = tile ? str(tile.feature) : "";
|
|
47331
47352
|
if (feature && feature !== "none") {
|
|
47332
|
-
|
|
47353
|
+
const tileRow = tile;
|
|
47354
|
+
onFeatureEnter?.(heroId, tileRow);
|
|
47333
47355
|
if (featureEnterEvent) {
|
|
47334
|
-
eventBus.emit(`UI:${featureEnterEvent}`, { heroId, feature, hex });
|
|
47356
|
+
eventBus.emit(`UI:${featureEnterEvent}`, { heroId, feature, hex: tileRow });
|
|
47335
47357
|
}
|
|
47336
47358
|
}
|
|
47337
47359
|
});
|
|
47338
47360
|
return;
|
|
47339
47361
|
}
|
|
47340
|
-
const enemy =
|
|
47341
|
-
const
|
|
47342
|
-
return
|
|
47362
|
+
const enemy = gameUnits.find((u) => {
|
|
47363
|
+
const up = u.position ?? { x: u.x ?? -1, y: u.y ?? -1 };
|
|
47364
|
+
return up.x === x && up.y === y && str(u.team) === "enemy";
|
|
47343
47365
|
});
|
|
47344
47366
|
if (selectedHero && enemy && attackTargets.some((t) => t.x === x && t.y === y)) {
|
|
47345
47367
|
const attackerId = str(selectedHero.id);
|
|
47346
|
-
const defenderId =
|
|
47368
|
+
const defenderId = enemy.id;
|
|
47347
47369
|
onBattleEncounter?.(attackerId, defenderId);
|
|
47348
47370
|
if (battleEncounterEvent) {
|
|
47349
47371
|
eventBus.emit(`UI:${battleEncounterEvent}`, { attackerId, defenderId });
|
|
47350
47372
|
}
|
|
47351
47373
|
}
|
|
47352
|
-
}, [
|
|
47374
|
+
}, [tiles, gameUnits, selectedHero, validMoves, attackTargets, startMoveAnimation, onHeroMove, onFeatureEnter, onBattleEncounter, eventBus, tileClickEvent, heroMoveEvent, featureEnterEvent, battleEncounterEvent]);
|
|
47353
47375
|
const handleUnitClick = React83.useCallback((unitId) => {
|
|
47354
|
-
const
|
|
47355
|
-
if (
|
|
47376
|
+
const unit = gameUnits.find((u) => u.id === unitId);
|
|
47377
|
+
if (unit && (str(unit.team) === "player" || allowMoveAllHeroes)) {
|
|
47356
47378
|
onHeroSelect?.(unitId);
|
|
47357
47379
|
if (heroSelectEvent) {
|
|
47358
47380
|
eventBus.emit(`UI:${heroSelectEvent}`, { heroId: unitId });
|
|
47359
47381
|
}
|
|
47360
47382
|
}
|
|
47361
|
-
}, [
|
|
47383
|
+
}, [gameUnits, onHeroSelect, allowMoveAllHeroes, eventBus, heroSelectEvent]);
|
|
47362
47384
|
const selectHero = React83.useCallback((id) => {
|
|
47363
47385
|
onHeroSelect?.(id);
|
|
47364
47386
|
if (heroSelectEvent) {
|