@almadar/ui 5.47.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 +7 -13
- package/dist/components/game/molecules/three/index.css +0 -5
- package/dist/components/game/molecules/three/index.js +7 -13
- 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
|
@@ -10429,15 +10429,15 @@ function BattleBoard({
|
|
|
10429
10429
|
const board = boardEntity(entity) ?? {};
|
|
10430
10430
|
const tiles = propTiles ?? (Array.isArray(board.tiles) ? board.tiles : []);
|
|
10431
10431
|
const features = propFeatures ?? (Array.isArray(board.features) ? board.features : []);
|
|
10432
|
-
const boardWidth = num(board.boardWidth, 8);
|
|
10433
|
-
const boardHeight = num(board.boardHeight, 6);
|
|
10432
|
+
const boardWidth = num(board.gridWidth ?? board.boardWidth, 8);
|
|
10433
|
+
const boardHeight = num(board.gridHeight ?? board.boardHeight, 6);
|
|
10434
10434
|
const assetManifest = propAssetManifest ?? board.assetManifest;
|
|
10435
10435
|
const backgroundImage = board.backgroundImage;
|
|
10436
10436
|
const units = rows(board.units);
|
|
10437
10437
|
const selectedUnitId = board.selectedUnitId ?? null;
|
|
10438
10438
|
const currentPhase = str(board.phase) || "observation";
|
|
10439
10439
|
const currentTurn = num(board.turn, 1);
|
|
10440
|
-
const gameResult = board.
|
|
10440
|
+
const gameResult = board.result ?? null;
|
|
10441
10441
|
const eventBus = useEventBus();
|
|
10442
10442
|
const { t } = hooks.useTranslate();
|
|
10443
10443
|
const [hoveredTile, setHoveredTile] = React77.useState(null);
|
|
@@ -10458,7 +10458,7 @@ function BattleBoard({
|
|
|
10458
10458
|
const validMoves = React77.useMemo(() => {
|
|
10459
10459
|
if (!selectedUnit || currentPhase !== "movement") return [];
|
|
10460
10460
|
const moves = [];
|
|
10461
|
-
const range = num(
|
|
10461
|
+
const range = num(board.movementRange, 2);
|
|
10462
10462
|
const origin = unitPosition(selectedUnit);
|
|
10463
10463
|
for (let dy = -range; dy <= range; dy++) {
|
|
10464
10464
|
for (let dx = -range; dx <= range; dx++) {
|
|
@@ -18743,15 +18743,24 @@ function CastleBoard({
|
|
|
18743
18743
|
featureClickEvent,
|
|
18744
18744
|
unitClickEvent,
|
|
18745
18745
|
tileClickEvent,
|
|
18746
|
+
playAgainEvent,
|
|
18746
18747
|
className
|
|
18747
18748
|
}) {
|
|
18748
18749
|
const eventBus = useEventBus();
|
|
18750
|
+
const { t } = hooks.useTranslate();
|
|
18749
18751
|
const resolved = boardEntity(entity);
|
|
18750
18752
|
const tiles = propTiles ?? (Array.isArray(resolved?.tiles) ? resolved.tiles : []);
|
|
18751
18753
|
const features = propFeatures ?? (Array.isArray(resolved?.features) ? resolved.features : []);
|
|
18752
18754
|
const units = propUnits ?? (Array.isArray(resolved?.units) ? resolved.units : []);
|
|
18753
18755
|
const assetManifest = propAssetManifest ?? resolved?.assetManifest;
|
|
18754
18756
|
const backgroundImage = resolved?.backgroundImage;
|
|
18757
|
+
const gold = num(resolved?.gold);
|
|
18758
|
+
const health = num(resolved?.health);
|
|
18759
|
+
const maxHealth = num(resolved?.maxHealth);
|
|
18760
|
+
const wave = num(resolved?.wave);
|
|
18761
|
+
const tickCount = num(resolved?.tickCount);
|
|
18762
|
+
const buildings = rows(resolved?.buildings);
|
|
18763
|
+
const result = str(resolved?.result) || "none";
|
|
18755
18764
|
const [hoveredTile, setHoveredTile] = React77.useState(null);
|
|
18756
18765
|
const [selectedFeature, setSelectedFeature] = React77.useState(null);
|
|
18757
18766
|
const hoveredFeature = React77.useMemo(() => {
|
|
@@ -18764,7 +18773,7 @@ function CastleBoard({
|
|
|
18764
18773
|
(u) => u.position?.x === hoveredTile.x && u.position?.y === hoveredTile.y
|
|
18765
18774
|
) ?? null;
|
|
18766
18775
|
}, [hoveredTile, units]);
|
|
18767
|
-
const maxY = Math.max(...tiles.map((
|
|
18776
|
+
const maxY = Math.max(...tiles.map((t2) => t2.y), 0);
|
|
18768
18777
|
const baseOffsetX = (maxY + 1) * (exports.TILE_WIDTH * scale / 2);
|
|
18769
18778
|
const tileToScreen = React77.useCallback(
|
|
18770
18779
|
(tx, ty) => isoToScreen(tx, ty, scale, baseOffsetX),
|
|
@@ -18799,6 +18808,11 @@ function CastleBoard({
|
|
|
18799
18808
|
}
|
|
18800
18809
|
}, [units, onUnitClick, unitClickEvent, eventBus]);
|
|
18801
18810
|
const clearSelection = React77.useCallback(() => setSelectedFeature(null), []);
|
|
18811
|
+
const handlePlayAgain = React77.useCallback(() => {
|
|
18812
|
+
if (playAgainEvent) {
|
|
18813
|
+
eventBus.emit(`UI:${playAgainEvent}`, {});
|
|
18814
|
+
}
|
|
18815
|
+
}, [playAgainEvent, eventBus]);
|
|
18802
18816
|
const ctx = React77.useMemo(
|
|
18803
18817
|
() => ({
|
|
18804
18818
|
hoveredTile,
|
|
@@ -18807,11 +18821,18 @@ function CastleBoard({
|
|
|
18807
18821
|
selectedFeature,
|
|
18808
18822
|
clearSelection,
|
|
18809
18823
|
tileToScreen,
|
|
18810
|
-
scale
|
|
18824
|
+
scale,
|
|
18825
|
+
gold,
|
|
18826
|
+
health,
|
|
18827
|
+
maxHealth,
|
|
18828
|
+
wave,
|
|
18829
|
+
tickCount,
|
|
18830
|
+
buildings,
|
|
18831
|
+
result
|
|
18811
18832
|
}),
|
|
18812
|
-
[hoveredTile, hoveredFeature, hoveredUnit, selectedFeature, clearSelection, tileToScreen, scale]
|
|
18833
|
+
[hoveredTile, hoveredFeature, hoveredUnit, selectedFeature, clearSelection, tileToScreen, scale, gold, health, maxHealth, wave, tickCount, buildings, result]
|
|
18813
18834
|
);
|
|
18814
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("castle-board min-h-screen flex flex-col bg-background", className), children: [
|
|
18835
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("castle-board relative min-h-screen flex flex-col bg-background", className), children: [
|
|
18815
18836
|
header && header(ctx),
|
|
18816
18837
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 overflow-hidden", children: [
|
|
18817
18838
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 overflow-auto p-4 relative", children: [
|
|
@@ -18836,7 +18857,29 @@ function CastleBoard({
|
|
|
18836
18857
|
] }),
|
|
18837
18858
|
sidePanel && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-96 shrink-0 border-l border-border bg-surface overflow-y-auto", children: sidePanel(ctx) })
|
|
18838
18859
|
] }),
|
|
18839
|
-
footer && footer(ctx)
|
|
18860
|
+
footer && footer(ctx),
|
|
18861
|
+
result !== "none" && /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: "absolute inset-0 z-50 flex items-center justify-center bg-background/70 backdrop-blur-sm rounded-container", children: /* @__PURE__ */ jsxRuntime.jsxs(exports.VStack, { className: "text-center p-8", gap: "lg", children: [
|
|
18862
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
18863
|
+
exports.Typography,
|
|
18864
|
+
{
|
|
18865
|
+
variant: "h2",
|
|
18866
|
+
className: cn(
|
|
18867
|
+
"text-4xl font-black tracking-widest uppercase",
|
|
18868
|
+
result === "victory" ? "text-warning" : "text-error"
|
|
18869
|
+
),
|
|
18870
|
+
children: result === "victory" ? t("battle.victory") : t("battle.defeat")
|
|
18871
|
+
}
|
|
18872
|
+
),
|
|
18873
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
18874
|
+
exports.Button,
|
|
18875
|
+
{
|
|
18876
|
+
variant: "primary",
|
|
18877
|
+
className: "px-8 py-3 font-semibold",
|
|
18878
|
+
onClick: handlePlayAgain,
|
|
18879
|
+
children: t("battle.playAgain")
|
|
18880
|
+
}
|
|
18881
|
+
)
|
|
18882
|
+
] }) })
|
|
18840
18883
|
] });
|
|
18841
18884
|
}
|
|
18842
18885
|
var init_CastleBoard = __esm({
|
|
@@ -18844,6 +18887,10 @@ var init_CastleBoard = __esm({
|
|
|
18844
18887
|
"use client";
|
|
18845
18888
|
init_cn();
|
|
18846
18889
|
init_useEventBus();
|
|
18890
|
+
init_Box();
|
|
18891
|
+
init_Button();
|
|
18892
|
+
init_Typography();
|
|
18893
|
+
init_Stack();
|
|
18847
18894
|
init_IsometricCanvas();
|
|
18848
18895
|
init_boardEntity();
|
|
18849
18896
|
init_isometric();
|
|
@@ -19766,22 +19813,16 @@ function ClassifierBoard({
|
|
|
19766
19813
|
const { emit } = useEventBus();
|
|
19767
19814
|
const { t } = hooks.useTranslate();
|
|
19768
19815
|
const resolved = boardEntity(entity);
|
|
19769
|
-
const [localAssignments, setLocalAssignments] = React77.useState({});
|
|
19770
19816
|
const [headerError, setHeaderError] = React77.useState(false);
|
|
19771
|
-
const [localSubmitted, setLocalSubmitted] = React77.useState(false);
|
|
19772
|
-
const [localAttempts, setLocalAttempts] = React77.useState(0);
|
|
19773
|
-
const [showHint, setShowHint] = React77.useState(false);
|
|
19774
19817
|
const items = Array.isArray(resolved?.items) ? resolved.items : [];
|
|
19775
19818
|
const categories = Array.isArray(resolved?.categories) ? resolved.categories : [];
|
|
19776
|
-
const
|
|
19777
|
-
const
|
|
19778
|
-
const
|
|
19779
|
-
const assignments =
|
|
19780
|
-
if (item.assignedCategory != null) acc[item.id] = item.assignedCategory;
|
|
19819
|
+
const result = str(resolved?.result);
|
|
19820
|
+
const submitted = result === "win";
|
|
19821
|
+
const attempts = num(resolved?.attempts);
|
|
19822
|
+
const assignments = items.reduce((acc, item) => {
|
|
19823
|
+
if (item.assignedCategory != null && item.assignedCategory !== "") acc[item.id] = item.assignedCategory;
|
|
19781
19824
|
return acc;
|
|
19782
|
-
}, {})
|
|
19783
|
-
const attempts = entityDrivesResult ? num(resolved?.attempts) : localAttempts;
|
|
19784
|
-
const submitted = entityDrivesResult || localSubmitted;
|
|
19825
|
+
}, {});
|
|
19785
19826
|
const unassignedItems = items.filter((item) => !assignments[item.id]);
|
|
19786
19827
|
const allAssigned = items.length > 0 && Object.keys(assignments).length === items.length;
|
|
19787
19828
|
const results = submitted ? items.map((item) => ({
|
|
@@ -19789,54 +19830,25 @@ function ClassifierBoard({
|
|
|
19789
19830
|
assigned: assignments[item.id],
|
|
19790
19831
|
correct: assignments[item.id] === item.correctCategory
|
|
19791
19832
|
})) : [];
|
|
19792
|
-
const allCorrect =
|
|
19833
|
+
const allCorrect = result === "win";
|
|
19793
19834
|
const correctCount = results.filter((r) => r.correct).length;
|
|
19835
|
+
const showHint = attempts >= 2 && Boolean(str(resolved?.hint));
|
|
19794
19836
|
const handleAssign = (itemId, categoryId) => {
|
|
19795
19837
|
if (submitted) return;
|
|
19796
|
-
if (assignEvent) {
|
|
19797
|
-
emit(`UI:${assignEvent}`, { itemId, categoryId });
|
|
19798
|
-
}
|
|
19799
|
-
if (!entityHasAssignments) {
|
|
19800
|
-
setLocalAssignments((prev) => ({ ...prev, [itemId]: categoryId }));
|
|
19801
|
-
}
|
|
19838
|
+
if (assignEvent) emit(`UI:${assignEvent}`, { itemId, categoryId });
|
|
19802
19839
|
};
|
|
19803
19840
|
const handleUnassign = (itemId) => {
|
|
19804
19841
|
if (submitted) return;
|
|
19805
|
-
if (
|
|
19806
|
-
setLocalAssignments((prev) => {
|
|
19807
|
-
const next = { ...prev };
|
|
19808
|
-
delete next[itemId];
|
|
19809
|
-
return next;
|
|
19810
|
-
});
|
|
19811
|
-
}
|
|
19842
|
+
if (assignEvent) emit(`UI:${assignEvent}`, { itemId, categoryId: "" });
|
|
19812
19843
|
};
|
|
19813
|
-
const handleSubmit =
|
|
19814
|
-
if (checkEvent) {
|
|
19815
|
-
|
|
19816
|
-
|
|
19817
|
-
if (!entityDrivesResult) {
|
|
19818
|
-
setLocalSubmitted(true);
|
|
19819
|
-
setLocalAttempts((a) => a + 1);
|
|
19820
|
-
const correct = items.every((item) => assignments[item.id] === item.correctCategory);
|
|
19821
|
-
if (correct) {
|
|
19822
|
-
emit(`UI:${completeEvent}`, { success: true, attempts: attempts + 1 });
|
|
19823
|
-
}
|
|
19824
|
-
}
|
|
19825
|
-
}, [checkEvent, entityDrivesResult, items, assignments, attempts, completeEvent, emit]);
|
|
19826
|
-
const handleReset = () => {
|
|
19827
|
-
if (!entityDrivesResult) setLocalSubmitted(false);
|
|
19828
|
-
if (attempts >= 2 && str(resolved?.hint)) {
|
|
19829
|
-
setShowHint(true);
|
|
19844
|
+
const handleSubmit = () => {
|
|
19845
|
+
if (checkEvent) emit(`UI:${checkEvent}`, {});
|
|
19846
|
+
if (allAssigned && items.every((item) => assignments[item.id] === item.correctCategory)) {
|
|
19847
|
+
emit(`UI:${completeEvent}`, { success: true, attempts: attempts + 1 });
|
|
19830
19848
|
}
|
|
19831
19849
|
};
|
|
19832
19850
|
const handleFullReset = () => {
|
|
19833
|
-
if (playAgainEvent) {
|
|
19834
|
-
emit(`UI:${playAgainEvent}`, {});
|
|
19835
|
-
}
|
|
19836
|
-
setLocalAssignments({});
|
|
19837
|
-
setLocalSubmitted(false);
|
|
19838
|
-
setLocalAttempts(0);
|
|
19839
|
-
setShowHint(false);
|
|
19851
|
+
if (playAgainEvent) emit(`UI:${playAgainEvent}`, {});
|
|
19840
19852
|
};
|
|
19841
19853
|
if (!resolved) return null;
|
|
19842
19854
|
const theme = resolved.theme ?? void 0;
|
|
@@ -19875,17 +19887,17 @@ function ClassifierBoard({
|
|
|
19875
19887
|
/* @__PURE__ */ jsxRuntime.jsx(exports.Badge, { size: "sm", children: catItems.length })
|
|
19876
19888
|
] }),
|
|
19877
19889
|
/* @__PURE__ */ jsxRuntime.jsx(exports.HStack, { gap: "xs", className: "flex-wrap min-h-[2rem]", children: catItems.map((item) => {
|
|
19878
|
-
const
|
|
19890
|
+
const result2 = results.find((r) => r.item.id === item.id);
|
|
19879
19891
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
19880
19892
|
exports.Badge,
|
|
19881
19893
|
{
|
|
19882
19894
|
size: "sm",
|
|
19883
|
-
className: `cursor-pointer ${
|
|
19895
|
+
className: `cursor-pointer ${result2 ? result2.correct ? "border-success bg-success/10" : "border-error bg-error/10" : ""}`,
|
|
19884
19896
|
onClick: () => handleUnassign(item.id),
|
|
19885
19897
|
children: [
|
|
19886
19898
|
item.iconUrl && /* @__PURE__ */ jsxRuntime.jsx("img", { src: item.iconUrl, alt: "", className: "w-3 h-3 object-contain inline-block" }),
|
|
19887
19899
|
item.label,
|
|
19888
|
-
|
|
19900
|
+
result2 && /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { icon: result2.correct ? LucideIcons2.CheckCircle : LucideIcons2.XCircle, size: "xs", className: result2.correct ? "text-success" : "text-error" })
|
|
19889
19901
|
]
|
|
19890
19902
|
},
|
|
19891
19903
|
item.id
|
|
@@ -19914,10 +19926,10 @@ function ClassifierBoard({
|
|
|
19914
19926
|
] }) }),
|
|
19915
19927
|
showHint && hint && /* @__PURE__ */ jsxRuntime.jsx(exports.Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "body", children: hint }) }),
|
|
19916
19928
|
/* @__PURE__ */ jsxRuntime.jsxs(exports.HStack, { gap: "sm", justify: "center", children: [
|
|
19917
|
-
!submitted
|
|
19929
|
+
!submitted && /* @__PURE__ */ jsxRuntime.jsxs(exports.Button, { variant: "primary", onClick: handleSubmit, disabled: !allAssigned, children: [
|
|
19918
19930
|
/* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { icon: LucideIcons2.Send, size: "sm" }),
|
|
19919
19931
|
t("classifier.check")
|
|
19920
|
-
] })
|
|
19932
|
+
] }),
|
|
19921
19933
|
/* @__PURE__ */ jsxRuntime.jsxs(exports.Button, { variant: "secondary", onClick: handleFullReset, children: [
|
|
19922
19934
|
/* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { icon: LucideIcons2.RotateCcw, size: "sm" }),
|
|
19923
19935
|
t("classifier.reset")
|
|
@@ -20204,6 +20216,7 @@ function getComboScale(combo) {
|
|
|
20204
20216
|
return "";
|
|
20205
20217
|
}
|
|
20206
20218
|
function ComboCounter({
|
|
20219
|
+
assetUrl = DEFAULT_ASSET_URL,
|
|
20207
20220
|
combo = 5,
|
|
20208
20221
|
multiplier,
|
|
20209
20222
|
streak,
|
|
@@ -20223,6 +20236,17 @@ function ComboCounter({
|
|
|
20223
20236
|
className
|
|
20224
20237
|
),
|
|
20225
20238
|
children: [
|
|
20239
|
+
assetUrl && /* @__PURE__ */ jsxRuntime.jsx(
|
|
20240
|
+
"img",
|
|
20241
|
+
{
|
|
20242
|
+
src: assetUrl,
|
|
20243
|
+
alt: "combo",
|
|
20244
|
+
width: 24,
|
|
20245
|
+
height: 24,
|
|
20246
|
+
style: { imageRendering: "pixelated", objectFit: "contain" },
|
|
20247
|
+
className: "flex-shrink-0 mb-0.5"
|
|
20248
|
+
}
|
|
20249
|
+
),
|
|
20226
20250
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("font-black tabular-nums leading-none", sizes.combo, getComboIntensity(combo)), children: combo }),
|
|
20227
20251
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("font-bold uppercase tracking-wider text-muted-foreground", sizes.label), children: "combo" }),
|
|
20228
20252
|
multiplier != null && multiplier > 1 && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: cn("font-bold text-warning tabular-nums", sizes.multiplier), children: [
|
|
@@ -20237,10 +20261,11 @@ function ComboCounter({
|
|
|
20237
20261
|
}
|
|
20238
20262
|
);
|
|
20239
20263
|
}
|
|
20240
|
-
var sizeMap4;
|
|
20264
|
+
var DEFAULT_ASSET_URL, sizeMap4;
|
|
20241
20265
|
var init_ComboCounter = __esm({
|
|
20242
20266
|
"components/game/atoms/ComboCounter.tsx"() {
|
|
20243
20267
|
init_cn();
|
|
20268
|
+
DEFAULT_ASSET_URL = "https://almadar-kflow-assets.web.app/shared/effects/flash/flash00.png";
|
|
20244
20269
|
sizeMap4 = {
|
|
20245
20270
|
sm: { combo: "text-lg", label: "text-xs", multiplier: "text-xs" },
|
|
20246
20271
|
md: { combo: "text-2xl", label: "text-xs", multiplier: "text-sm" },
|
|
@@ -20649,7 +20674,7 @@ var init_CounterTemplate = __esm({
|
|
|
20649
20674
|
}
|
|
20650
20675
|
});
|
|
20651
20676
|
function ItemSlot({
|
|
20652
|
-
assetUrl =
|
|
20677
|
+
assetUrl = DEFAULT_ASSET_URL2,
|
|
20653
20678
|
icon = "sword",
|
|
20654
20679
|
label = "Iron Sword",
|
|
20655
20680
|
quantity,
|
|
@@ -20708,7 +20733,7 @@ function ItemSlot({
|
|
|
20708
20733
|
}
|
|
20709
20734
|
);
|
|
20710
20735
|
}
|
|
20711
|
-
var sizeMap5, rarityBorderMap, rarityGlowMap,
|
|
20736
|
+
var sizeMap5, rarityBorderMap, rarityGlowMap, DEFAULT_ASSET_URL2, assetSizeMap;
|
|
20712
20737
|
var init_ItemSlot = __esm({
|
|
20713
20738
|
"components/game/atoms/ItemSlot.tsx"() {
|
|
20714
20739
|
"use client";
|
|
@@ -20733,7 +20758,7 @@ var init_ItemSlot = __esm({
|
|
|
20733
20758
|
epic: "shadow-lg",
|
|
20734
20759
|
legendary: "shadow-lg"
|
|
20735
20760
|
};
|
|
20736
|
-
|
|
20761
|
+
DEFAULT_ASSET_URL2 = "https://almadar-kflow-assets.web.app/shared/isometric-dungeon/Isometric/chestClosed_E.png";
|
|
20737
20762
|
assetSizeMap = {
|
|
20738
20763
|
sm: 28,
|
|
20739
20764
|
md: 40,
|
|
@@ -27289,6 +27314,7 @@ var init_InventoryGrid = __esm({
|
|
|
27289
27314
|
}
|
|
27290
27315
|
});
|
|
27291
27316
|
function WaypointMarker({
|
|
27317
|
+
assetUrl = DEFAULT_ASSET_URL3,
|
|
27292
27318
|
label,
|
|
27293
27319
|
icon,
|
|
27294
27320
|
active = true,
|
|
@@ -27327,7 +27353,17 @@ function WaypointMarker({
|
|
|
27327
27353
|
active && !completed && "bg-info text-foreground",
|
|
27328
27354
|
!active && !completed && "bg-muted"
|
|
27329
27355
|
),
|
|
27330
|
-
children: completed ? checkIcon :
|
|
27356
|
+
children: completed ? checkIcon : assetUrl ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
27357
|
+
"img",
|
|
27358
|
+
{
|
|
27359
|
+
src: assetUrl,
|
|
27360
|
+
alt: label,
|
|
27361
|
+
width: sizes.img,
|
|
27362
|
+
height: sizes.img,
|
|
27363
|
+
style: { imageRendering: "pixelated", objectFit: "contain" },
|
|
27364
|
+
className: "flex-shrink-0"
|
|
27365
|
+
}
|
|
27366
|
+
) : icon ? typeof icon === "string" ? /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { name: icon }) : /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { icon }) : null
|
|
27331
27367
|
}
|
|
27332
27368
|
)
|
|
27333
27369
|
] }),
|
|
@@ -27344,15 +27380,16 @@ function WaypointMarker({
|
|
|
27344
27380
|
)
|
|
27345
27381
|
] });
|
|
27346
27382
|
}
|
|
27347
|
-
var sizeMap12, checkIcon;
|
|
27383
|
+
var DEFAULT_ASSET_URL3, sizeMap12, checkIcon;
|
|
27348
27384
|
var init_WaypointMarker = __esm({
|
|
27349
27385
|
"components/game/atoms/WaypointMarker.tsx"() {
|
|
27350
27386
|
init_cn();
|
|
27351
27387
|
init_Icon();
|
|
27388
|
+
DEFAULT_ASSET_URL3 = "https://almadar-kflow-assets.web.app/shared/world-map/battle_marker.png";
|
|
27352
27389
|
sizeMap12 = {
|
|
27353
|
-
sm: { dot: "w-4 h-4", ring: "w-6 h-6", label: "text-xs mt-1" },
|
|
27354
|
-
md: { dot: "w-6 h-6", ring: "w-8 h-8", label: "text-sm mt-1.5" },
|
|
27355
|
-
lg: { dot: "w-8 h-8", ring: "w-10 h-10", label: "text-base mt-2" }
|
|
27390
|
+
sm: { dot: "w-4 h-4", ring: "w-6 h-6", label: "text-xs mt-1", img: 12 },
|
|
27391
|
+
md: { dot: "w-6 h-6", ring: "w-8 h-8", label: "text-sm mt-1.5", img: 18 },
|
|
27392
|
+
lg: { dot: "w-8 h-8", ring: "w-10 h-10", label: "text-base mt-2", img: 24 }
|
|
27356
27393
|
};
|
|
27357
27394
|
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" }) });
|
|
27358
27395
|
WaypointMarker.displayName = "WaypointMarker";
|
|
@@ -29624,7 +29661,7 @@ var init_MapView = __esm({
|
|
|
29624
29661
|
shadowSize: [41, 41]
|
|
29625
29662
|
});
|
|
29626
29663
|
L.Marker.prototype.options.icon = defaultIcon;
|
|
29627
|
-
const { useEffect: useEffect74, useRef: useRef71, useCallback:
|
|
29664
|
+
const { useEffect: useEffect74, useRef: useRef71, useCallback: useCallback113, useState: useState105 } = React77__namespace.default;
|
|
29628
29665
|
const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
|
|
29629
29666
|
const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
|
|
29630
29667
|
function MapUpdater({ centerLat, centerLng, zoom }) {
|
|
@@ -29670,7 +29707,7 @@ var init_MapView = __esm({
|
|
|
29670
29707
|
}) {
|
|
29671
29708
|
const eventBus = useEventBus2();
|
|
29672
29709
|
const [clickedPosition, setClickedPosition] = useState105(null);
|
|
29673
|
-
const handleMapClick =
|
|
29710
|
+
const handleMapClick = useCallback113((lat, lng) => {
|
|
29674
29711
|
if (showClickedPin) {
|
|
29675
29712
|
setClickedPosition({ lat, lng });
|
|
29676
29713
|
}
|
|
@@ -29679,7 +29716,7 @@ var init_MapView = __esm({
|
|
|
29679
29716
|
eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
|
|
29680
29717
|
}
|
|
29681
29718
|
}, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
|
|
29682
|
-
const handleMarkerClick =
|
|
29719
|
+
const handleMarkerClick = useCallback113((marker) => {
|
|
29683
29720
|
onMarkerClick?.(marker);
|
|
29684
29721
|
if (markerClickEvent) {
|
|
29685
29722
|
eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
|
|
@@ -39122,44 +39159,27 @@ function DebuggerBoard({
|
|
|
39122
39159
|
const { t } = hooks.useTranslate();
|
|
39123
39160
|
const resolved = boardEntity(entity);
|
|
39124
39161
|
const [headerError, setHeaderError] = React77.useState(false);
|
|
39125
|
-
const [showHint, setShowHint] = React77.useState(false);
|
|
39126
39162
|
const lines = Array.isArray(resolved?.lines) ? resolved.lines : [];
|
|
39127
|
-
const result = resolved?.result
|
|
39163
|
+
const result = str(resolved?.result) || "none";
|
|
39128
39164
|
const attempts = num(resolved?.attempts);
|
|
39129
|
-
const submitted = result
|
|
39165
|
+
const submitted = result === "win";
|
|
39166
|
+
const showHint = !submitted && attempts >= 2 && Boolean(str(resolved?.hint));
|
|
39130
39167
|
const bugLines = lines.filter((l) => l.isBug);
|
|
39131
39168
|
const flaggedLines = lines.filter((l) => l.isFlagged);
|
|
39132
39169
|
const correctFlags = lines.filter((l) => l.isBug && l.isFlagged);
|
|
39133
39170
|
const falseFlags = lines.filter((l) => !l.isBug && l.isFlagged);
|
|
39134
|
-
const allCorrect =
|
|
39171
|
+
const allCorrect = submitted;
|
|
39135
39172
|
const toggleLine = (lineId) => {
|
|
39136
39173
|
if (submitted) return;
|
|
39137
|
-
if (toggleFlagEvent) {
|
|
39138
|
-
emit(`UI:${toggleFlagEvent}`, { lineId });
|
|
39139
|
-
}
|
|
39174
|
+
if (toggleFlagEvent) emit(`UI:${toggleFlagEvent}`, { lineId });
|
|
39140
39175
|
};
|
|
39141
39176
|
const handleSubmit = React77.useCallback(() => {
|
|
39142
|
-
if (checkEvent) {
|
|
39143
|
-
emit(`UI:${checkEvent}`, {});
|
|
39144
|
-
}
|
|
39177
|
+
if (checkEvent) emit(`UI:${checkEvent}`, {});
|
|
39145
39178
|
const correct = correctFlags.length === bugLines.length && falseFlags.length === 0;
|
|
39146
|
-
if (correct) {
|
|
39147
|
-
emit(`UI:${completeEvent}`, { success: true, attempts: attempts + 1 });
|
|
39148
|
-
}
|
|
39179
|
+
if (correct) emit(`UI:${completeEvent}`, { success: true, attempts: attempts + 1 });
|
|
39149
39180
|
}, [checkEvent, correctFlags.length, bugLines.length, falseFlags.length, attempts, completeEvent, emit]);
|
|
39150
39181
|
const handleReset = () => {
|
|
39151
|
-
if (playAgainEvent) {
|
|
39152
|
-
emit(`UI:${playAgainEvent}`, {});
|
|
39153
|
-
}
|
|
39154
|
-
if (attempts >= 2 && str(resolved?.hint)) {
|
|
39155
|
-
setShowHint(true);
|
|
39156
|
-
}
|
|
39157
|
-
};
|
|
39158
|
-
const handleFullReset = () => {
|
|
39159
|
-
if (playAgainEvent) {
|
|
39160
|
-
emit(`UI:${playAgainEvent}`, {});
|
|
39161
|
-
}
|
|
39162
|
-
setShowHint(false);
|
|
39182
|
+
if (playAgainEvent) emit(`UI:${playAgainEvent}`, {});
|
|
39163
39183
|
};
|
|
39164
39184
|
if (!resolved) return null;
|
|
39165
39185
|
const theme = resolved.theme ?? void 0;
|
|
@@ -39183,7 +39203,7 @@ function DebuggerBoard({
|
|
|
39183
39203
|
/* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "h4", weight: "bold", children: str(resolved.title) })
|
|
39184
39204
|
] }),
|
|
39185
39205
|
/* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "body", children: str(resolved.description) }),
|
|
39186
|
-
/* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "caption", className: "text-muted-foreground", children: t("debugger.findBugs", { count: String(
|
|
39206
|
+
/* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "caption", className: "text-muted-foreground", children: t("debugger.findBugs", { count: String(lines.filter((l) => l.isBug).length) }) })
|
|
39187
39207
|
] }) }),
|
|
39188
39208
|
/* @__PURE__ */ jsxRuntime.jsx(exports.Card, { className: "p-0 overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(exports.VStack, { gap: "none", children: lines.map((line, i) => {
|
|
39189
39209
|
const isFlagged = !!line.isFlagged;
|
|
@@ -39233,11 +39253,11 @@ function DebuggerBoard({
|
|
|
39233
39253
|
] }) }),
|
|
39234
39254
|
showHint && hint && /* @__PURE__ */ jsxRuntime.jsx(exports.Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "body", children: hint }) }),
|
|
39235
39255
|
/* @__PURE__ */ jsxRuntime.jsxs(exports.HStack, { gap: "sm", justify: "center", children: [
|
|
39236
|
-
!submitted
|
|
39256
|
+
!submitted && /* @__PURE__ */ jsxRuntime.jsxs(exports.Button, { variant: "primary", onClick: handleSubmit, disabled: flaggedLines.length === 0, children: [
|
|
39237
39257
|
/* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { icon: LucideIcons2.Send, size: "sm" }),
|
|
39238
39258
|
t("debugger.submit")
|
|
39239
|
-
] })
|
|
39240
|
-
/* @__PURE__ */ jsxRuntime.jsxs(exports.Button, { variant: "secondary", onClick:
|
|
39259
|
+
] }),
|
|
39260
|
+
/* @__PURE__ */ jsxRuntime.jsxs(exports.Button, { variant: "secondary", onClick: handleReset, children: [
|
|
39241
39261
|
/* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { icon: LucideIcons2.RotateCcw, size: "sm" }),
|
|
39242
39262
|
t("debugger.reset")
|
|
39243
39263
|
] })
|
|
@@ -39827,6 +39847,7 @@ var init_DrawerSlot = __esm({
|
|
|
39827
39847
|
}
|
|
39828
39848
|
});
|
|
39829
39849
|
function StateIndicator({
|
|
39850
|
+
assetUrl = DEFAULT_ASSET_URL4,
|
|
39830
39851
|
state = "idle",
|
|
39831
39852
|
label,
|
|
39832
39853
|
size = "md",
|
|
@@ -39849,18 +39870,29 @@ function StateIndicator({
|
|
|
39849
39870
|
className
|
|
39850
39871
|
),
|
|
39851
39872
|
children: [
|
|
39852
|
-
/* @__PURE__ */ jsxRuntime.jsx(exports.Box, { as: "span", children:
|
|
39873
|
+
/* @__PURE__ */ jsxRuntime.jsx(exports.Box, { as: "span", children: assetUrl ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
39874
|
+
"img",
|
|
39875
|
+
{
|
|
39876
|
+
src: assetUrl,
|
|
39877
|
+
alt: displayLabel,
|
|
39878
|
+
width: 16,
|
|
39879
|
+
height: 16,
|
|
39880
|
+
style: { imageRendering: "pixelated", objectFit: "contain" },
|
|
39881
|
+
className: "flex-shrink-0"
|
|
39882
|
+
}
|
|
39883
|
+
) : typeof config.icon === "string" ? /^[a-zA-Z0-9-]+$/.test(config.icon) ? /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { name: config.icon }) : config.icon : /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { icon: config.icon }) }),
|
|
39853
39884
|
/* @__PURE__ */ jsxRuntime.jsx(exports.Box, { as: "span", children: displayLabel })
|
|
39854
39885
|
]
|
|
39855
39886
|
}
|
|
39856
39887
|
);
|
|
39857
39888
|
}
|
|
39858
|
-
var DEFAULT_STATE_STYLES, DEFAULT_STYLE, SIZE_CLASSES;
|
|
39889
|
+
var DEFAULT_ASSET_URL4, DEFAULT_STATE_STYLES, DEFAULT_STYLE, SIZE_CLASSES;
|
|
39859
39890
|
var init_StateIndicator = __esm({
|
|
39860
39891
|
"components/game/atoms/StateIndicator.tsx"() {
|
|
39861
39892
|
init_Box();
|
|
39862
39893
|
init_Icon();
|
|
39863
39894
|
init_cn();
|
|
39895
|
+
DEFAULT_ASSET_URL4 = "https://almadar-kflow-assets.web.app/shared/isometric-dungeon/Isometric/chestClosed_E.png";
|
|
39864
39896
|
DEFAULT_STATE_STYLES = {
|
|
39865
39897
|
idle: { icon: "\u23F8", bgClass: "bg-muted" },
|
|
39866
39898
|
active: { icon: "\u25B6", bgClass: "bg-success" },
|
|
@@ -40334,39 +40366,40 @@ function EventHandlerBoard({
|
|
|
40334
40366
|
stepDurationMs = 800,
|
|
40335
40367
|
playEvent,
|
|
40336
40368
|
completeEvent,
|
|
40369
|
+
editRuleEvent,
|
|
40370
|
+
playAgainEvent,
|
|
40337
40371
|
className
|
|
40338
40372
|
}) {
|
|
40339
40373
|
const { emit } = useEventBus();
|
|
40340
40374
|
const { t } = hooks.useTranslate();
|
|
40341
40375
|
const resolved = boardEntity(entity);
|
|
40342
|
-
const
|
|
40343
|
-
const
|
|
40376
|
+
const objects = rows(resolved?.objects);
|
|
40377
|
+
const entityResult = str(resolved?.result) || "none";
|
|
40378
|
+
const isSuccess = entityResult === "win";
|
|
40379
|
+
const attempts = typeof resolved?.attempts === "number" ? resolved.attempts : 0;
|
|
40344
40380
|
const [selectedObjectId, setSelectedObjectId] = React77.useState(
|
|
40345
|
-
|
|
40381
|
+
objects[0] ? objId(objects[0]) : null
|
|
40346
40382
|
);
|
|
40347
40383
|
const [headerError, setHeaderError] = React77.useState(false);
|
|
40348
|
-
const [
|
|
40384
|
+
const [isPlaying, setIsPlaying] = React77.useState(false);
|
|
40349
40385
|
const [eventLog, setEventLog] = React77.useState([]);
|
|
40350
|
-
const [attempts, setAttempts] = React77.useState(0);
|
|
40351
40386
|
const timerRef = React77.useRef(null);
|
|
40352
40387
|
const logIdCounter = React77.useRef(0);
|
|
40353
40388
|
React77.useEffect(() => () => {
|
|
40354
40389
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
40355
40390
|
}, []);
|
|
40356
|
-
const selectedObject = objects.find((o) => objId(o) === selectedObjectId)
|
|
40391
|
+
const selectedObject = objects.find((o) => objId(o) === selectedObjectId) ?? null;
|
|
40357
40392
|
const handleRulesChange = React77.useCallback((objectId, rules) => {
|
|
40358
|
-
|
|
40359
|
-
|
|
40360
|
-
));
|
|
40361
|
-
}, []);
|
|
40393
|
+
if (editRuleEvent) emit(`UI:${editRuleEvent}`, { objectId, rules });
|
|
40394
|
+
}, [editRuleEvent, emit]);
|
|
40362
40395
|
const addLogEntry = React77.useCallback((icon, message, status = "done") => {
|
|
40363
40396
|
const id = `log-${logIdCounter.current++}`;
|
|
40364
40397
|
setEventLog((prev) => [...prev, { id, timestamp: Date.now(), icon, message, status }]);
|
|
40365
40398
|
}, []);
|
|
40366
40399
|
const handlePlay = React77.useCallback(() => {
|
|
40367
|
-
if (
|
|
40400
|
+
if (isPlaying || isSuccess) return;
|
|
40368
40401
|
if (playEvent) emit(`UI:${playEvent}`, {});
|
|
40369
|
-
|
|
40402
|
+
setIsPlaying(true);
|
|
40370
40403
|
setEventLog([]);
|
|
40371
40404
|
const allRules = [];
|
|
40372
40405
|
objects.forEach((obj) => {
|
|
@@ -40382,15 +40415,8 @@ function EventHandlerBoard({
|
|
|
40382
40415
|
let goalReached = false;
|
|
40383
40416
|
const processNext = () => {
|
|
40384
40417
|
if (eventQueue.length === 0 || stepIdx > 20) {
|
|
40385
|
-
|
|
40386
|
-
|
|
40387
|
-
if (completeEvent) {
|
|
40388
|
-
emit(`UI:${completeEvent}`, { success: true });
|
|
40389
|
-
}
|
|
40390
|
-
} else {
|
|
40391
|
-
setAttempts((prev) => prev + 1);
|
|
40392
|
-
setPlayState("fail");
|
|
40393
|
-
}
|
|
40418
|
+
setIsPlaying(false);
|
|
40419
|
+
if (goalReached && completeEvent) emit(`UI:${completeEvent}`, { success: true });
|
|
40394
40420
|
return;
|
|
40395
40421
|
}
|
|
40396
40422
|
const currentEvent = eventQueue.shift();
|
|
@@ -40421,21 +40447,19 @@ function EventHandlerBoard({
|
|
|
40421
40447
|
addLogEntry("\u{1F3AC}", t("eventHandler.simulationStarted", { events: triggers.join(", ") }), "active");
|
|
40422
40448
|
}
|
|
40423
40449
|
timerRef.current = setTimeout(processNext, stepDurationMs);
|
|
40424
|
-
}, [
|
|
40450
|
+
}, [isPlaying, isSuccess, objects, resolved, stepDurationMs, playEvent, completeEvent, emit, addLogEntry, t]);
|
|
40425
40451
|
const handleTryAgain = React77.useCallback(() => {
|
|
40426
40452
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
40427
|
-
|
|
40453
|
+
setIsPlaying(false);
|
|
40428
40454
|
setEventLog([]);
|
|
40429
40455
|
}, []);
|
|
40430
40456
|
const handleReset = React77.useCallback(() => {
|
|
40431
40457
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
40432
|
-
|
|
40433
|
-
setObjects([...resetObjects]);
|
|
40434
|
-
setPlayState("editing");
|
|
40458
|
+
setIsPlaying(false);
|
|
40435
40459
|
setEventLog([]);
|
|
40436
|
-
setSelectedObjectId(
|
|
40437
|
-
|
|
40438
|
-
}, [
|
|
40460
|
+
setSelectedObjectId(objects[0] ? objId(objects[0]) : null);
|
|
40461
|
+
if (playAgainEvent) emit(`UI:${playAgainEvent}`, {});
|
|
40462
|
+
}, [objects, playAgainEvent, emit]);
|
|
40439
40463
|
if (!resolved) return null;
|
|
40440
40464
|
const objectViewers = objects.map((obj) => {
|
|
40441
40465
|
const states = objStates(obj);
|
|
@@ -40504,12 +40528,12 @@ function EventHandlerBoard({
|
|
|
40504
40528
|
{
|
|
40505
40529
|
object: selectedObject,
|
|
40506
40530
|
onRulesChange: handleRulesChange,
|
|
40507
|
-
disabled:
|
|
40531
|
+
disabled: isPlaying
|
|
40508
40532
|
}
|
|
40509
40533
|
),
|
|
40510
40534
|
eventLog.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(EventLog, { entries: eventLog }),
|
|
40511
|
-
|
|
40512
|
-
|
|
40535
|
+
isSuccess && /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: "p-4 rounded-container bg-success/20 border border-success text-center", children: /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "h5", className: "text-success", children: str(resolved.successMessage) || t("eventHandler.chainComplete") }) }),
|
|
40536
|
+
!isPlaying && !isSuccess && attempts > 0 && /* @__PURE__ */ jsxRuntime.jsxs(exports.VStack, { gap: "sm", children: [
|
|
40513
40537
|
/* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: "p-4 rounded-container bg-warning/10 border border-warning/30 text-center", children: /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "body1", className: "text-foreground font-medium", children: t(encourageKey) }) }),
|
|
40514
40538
|
showHint && /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: "p-3 rounded-container bg-accent/10 border border-accent/30", children: /* @__PURE__ */ jsxRuntime.jsxs(exports.HStack, { className: "items-start", gap: "xs", children: [
|
|
40515
40539
|
/* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "body2", className: "text-accent font-bold shrink-0", children: "\u{1F4A1} " + t("game.hint") + ":" }),
|
|
@@ -40517,12 +40541,12 @@ function EventHandlerBoard({
|
|
|
40517
40541
|
] }) })
|
|
40518
40542
|
] }),
|
|
40519
40543
|
/* @__PURE__ */ jsxRuntime.jsxs(exports.HStack, { gap: "sm", children: [
|
|
40520
|
-
|
|
40544
|
+
!isPlaying && !isSuccess && attempts > 0 ? /* @__PURE__ */ jsxRuntime.jsx(exports.Button, { variant: "primary", onClick: handleTryAgain, children: "\u{1F504} " + t("puzzle.tryAgainButton") }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
40521
40545
|
exports.Button,
|
|
40522
40546
|
{
|
|
40523
40547
|
variant: "primary",
|
|
40524
40548
|
onClick: handlePlay,
|
|
40525
|
-
disabled:
|
|
40549
|
+
disabled: isPlaying || isSuccess,
|
|
40526
40550
|
children: "\u25B6 " + t("game.play")
|
|
40527
40551
|
}
|
|
40528
40552
|
),
|
|
@@ -43190,21 +43214,6 @@ var init_ModalSlot = __esm({
|
|
|
43190
43214
|
exports.ModalSlot.displayName = "ModalSlot";
|
|
43191
43215
|
}
|
|
43192
43216
|
});
|
|
43193
|
-
function getOpponentAction(strategy, actions, history) {
|
|
43194
|
-
const actionIds = actions.map((a) => a.id);
|
|
43195
|
-
switch (strategy) {
|
|
43196
|
-
case "always-cooperate":
|
|
43197
|
-
return actionIds[0];
|
|
43198
|
-
case "always-defect":
|
|
43199
|
-
return actionIds[actionIds.length - 1];
|
|
43200
|
-
case "tit-for-tat":
|
|
43201
|
-
if (history.length === 0) return actionIds[0];
|
|
43202
|
-
return history[history.length - 1].playerAction;
|
|
43203
|
-
case "random":
|
|
43204
|
-
default:
|
|
43205
|
-
return actionIds[Math.floor(Math.random() * actionIds.length)];
|
|
43206
|
-
}
|
|
43207
|
-
}
|
|
43208
43217
|
function NegotiatorBoard({
|
|
43209
43218
|
entity,
|
|
43210
43219
|
completeEvent = "PUZZLE_COMPLETE",
|
|
@@ -43226,28 +43235,35 @@ function NegotiatorBoard({
|
|
|
43226
43235
|
const playerTotal = num(resolved?.score);
|
|
43227
43236
|
const isComplete = result !== "none" || totalRounds > 0 && currentRound >= totalRounds;
|
|
43228
43237
|
const won = result === "win";
|
|
43229
|
-
const
|
|
43238
|
+
const lastPlayerAction = str(resolved?.lastPlayerAction);
|
|
43239
|
+
const lastOpponentAction = str(resolved?.lastOpponentAction);
|
|
43240
|
+
const lastPayoff = num(resolved?.lastPayoff);
|
|
43230
43241
|
const actions = Array.isArray(resolved?.actions) ? resolved.actions : [];
|
|
43231
43242
|
const payoffMatrix = Array.isArray(resolved?.payoffMatrix) ? resolved.payoffMatrix : [];
|
|
43243
|
+
const prevRoundRef = React77.useRef(currentRound);
|
|
43244
|
+
React77.useEffect(() => {
|
|
43245
|
+
if (currentRound > prevRoundRef.current && lastPlayerAction) {
|
|
43246
|
+
const opponentPayoffEntry = payoffMatrix.find(
|
|
43247
|
+
(p2) => p2.playerAction === lastPlayerAction && p2.opponentAction === lastOpponentAction
|
|
43248
|
+
);
|
|
43249
|
+
setHistory((prev) => [
|
|
43250
|
+
...prev,
|
|
43251
|
+
{
|
|
43252
|
+
round: currentRound,
|
|
43253
|
+
playerAction: lastPlayerAction,
|
|
43254
|
+
opponentAction: lastOpponentAction,
|
|
43255
|
+
playerPayoff: lastPayoff,
|
|
43256
|
+
opponentPayoff: opponentPayoffEntry?.opponentPayoff ?? 0
|
|
43257
|
+
}
|
|
43258
|
+
]);
|
|
43259
|
+
}
|
|
43260
|
+
prevRoundRef.current = currentRound;
|
|
43261
|
+
}, [currentRound, lastPlayerAction, lastOpponentAction, lastPayoff, payoffMatrix]);
|
|
43262
|
+
const opponentTotal = React77.useMemo(() => history.reduce((s, r) => s + r.opponentPayoff, 0), [history]);
|
|
43232
43263
|
const handleAction = React77.useCallback((actionId) => {
|
|
43233
43264
|
if (isComplete) return;
|
|
43234
|
-
const opponentAction = getOpponentAction(str(resolved?.opponentStrategy) || "random", actions, history);
|
|
43235
|
-
const payoff = payoffMatrix.find(
|
|
43236
|
-
(p2) => p2.playerAction === actionId && p2.opponentAction === opponentAction
|
|
43237
|
-
);
|
|
43238
|
-
const playerPayoff = payoff?.playerPayoff ?? 0;
|
|
43239
|
-
setHistory((prev) => [
|
|
43240
|
-
...prev,
|
|
43241
|
-
{
|
|
43242
|
-
round: prev.length + 1,
|
|
43243
|
-
playerAction: actionId,
|
|
43244
|
-
opponentAction,
|
|
43245
|
-
playerPayoff,
|
|
43246
|
-
opponentPayoff: payoff?.opponentPayoff ?? 0
|
|
43247
|
-
}
|
|
43248
|
-
]);
|
|
43249
43265
|
if (playRoundEvent) {
|
|
43250
|
-
emit(`UI:${playRoundEvent}`, { playerAction: actionId, payoff:
|
|
43266
|
+
emit(`UI:${playRoundEvent}`, { playerAction: actionId, payoff: 0 });
|
|
43251
43267
|
}
|
|
43252
43268
|
if (totalRounds > 0 && currentRound + 1 >= totalRounds) {
|
|
43253
43269
|
if (finishEvent) {
|
|
@@ -43257,10 +43273,11 @@ function NegotiatorBoard({
|
|
|
43257
43273
|
setShowHint(true);
|
|
43258
43274
|
}
|
|
43259
43275
|
}
|
|
43260
|
-
}, [isComplete, resolved, totalRounds, currentRound,
|
|
43276
|
+
}, [isComplete, resolved, totalRounds, currentRound, playRoundEvent, finishEvent, emit]);
|
|
43261
43277
|
const handleReset = React77.useCallback(() => {
|
|
43262
43278
|
setHistory([]);
|
|
43263
43279
|
setShowHint(false);
|
|
43280
|
+
prevRoundRef.current = 0;
|
|
43264
43281
|
if (playAgainEvent) {
|
|
43265
43282
|
emit(`UI:${playAgainEvent}`, {});
|
|
43266
43283
|
}
|
|
@@ -43494,6 +43511,7 @@ var init_PricingPageTemplate = __esm({
|
|
|
43494
43511
|
}
|
|
43495
43512
|
});
|
|
43496
43513
|
function ResourceCounter({
|
|
43514
|
+
assetUrl = DEFAULT_ASSET_URL5,
|
|
43497
43515
|
icon,
|
|
43498
43516
|
label = "Gold",
|
|
43499
43517
|
value = 250,
|
|
@@ -43513,7 +43531,17 @@ function ResourceCounter({
|
|
|
43513
43531
|
className
|
|
43514
43532
|
),
|
|
43515
43533
|
children: [
|
|
43516
|
-
|
|
43534
|
+
assetUrl ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
43535
|
+
"img",
|
|
43536
|
+
{
|
|
43537
|
+
src: assetUrl,
|
|
43538
|
+
alt: label,
|
|
43539
|
+
width: sizes.img,
|
|
43540
|
+
height: sizes.img,
|
|
43541
|
+
style: { imageRendering: "pixelated", objectFit: "contain" },
|
|
43542
|
+
className: "flex-shrink-0"
|
|
43543
|
+
}
|
|
43544
|
+
) : icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("flex-shrink-0", sizes.icon), children: typeof icon === "string" ? /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { name: icon }) : /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { icon }) }) : null,
|
|
43517
43545
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: label }),
|
|
43518
43546
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: cn("font-bold tabular-nums", color && (color in colorTokenClasses2 ? colorTokenClasses2[color] : color)), children: [
|
|
43519
43547
|
value,
|
|
@@ -43526,7 +43554,7 @@ function ResourceCounter({
|
|
|
43526
43554
|
}
|
|
43527
43555
|
);
|
|
43528
43556
|
}
|
|
43529
|
-
var colorTokenClasses2, sizeMap15;
|
|
43557
|
+
var colorTokenClasses2, DEFAULT_ASSET_URL5, sizeMap15;
|
|
43530
43558
|
var init_ResourceCounter = __esm({
|
|
43531
43559
|
"components/game/atoms/ResourceCounter.tsx"() {
|
|
43532
43560
|
init_cn();
|
|
@@ -43539,10 +43567,11 @@ var init_ResourceCounter = __esm({
|
|
|
43539
43567
|
error: "text-error",
|
|
43540
43568
|
muted: "text-muted-foreground"
|
|
43541
43569
|
};
|
|
43570
|
+
DEFAULT_ASSET_URL5 = "https://almadar-kflow-assets.web.app/shared/world-map/gold_mine.png";
|
|
43542
43571
|
sizeMap15 = {
|
|
43543
|
-
sm: { wrapper: "text-xs gap-1 px-1.5 py-0.5", icon: "text-sm" },
|
|
43544
|
-
md: { wrapper: "text-sm gap-1.5 px-2 py-1", icon: "text-base" },
|
|
43545
|
-
lg: { wrapper: "text-base gap-2 px-3 py-1.5", icon: "text-lg" }
|
|
43572
|
+
sm: { wrapper: "text-xs gap-1 px-1.5 py-0.5", icon: "text-sm", img: 16 },
|
|
43573
|
+
md: { wrapper: "text-sm gap-1.5 px-2 py-1", icon: "text-base", img: 20 },
|
|
43574
|
+
lg: { wrapper: "text-base gap-2 px-3 py-1.5", icon: "text-lg", img: 28 }
|
|
43546
43575
|
};
|
|
43547
43576
|
ResourceCounter.displayName = "ResourceCounter";
|
|
43548
43577
|
}
|
|
@@ -45650,17 +45679,24 @@ function SequencerBoard({
|
|
|
45650
45679
|
const { emit } = useEventBus();
|
|
45651
45680
|
const { t } = hooks.useTranslate();
|
|
45652
45681
|
const resolved = boardEntity(entity);
|
|
45653
|
-
const maxSlots = num(resolved?.maxSlots);
|
|
45682
|
+
const maxSlots = num(resolved?.maxSlots) || 3;
|
|
45654
45683
|
const solutions = Array.isArray(resolved?.solutions) ? resolved.solutions : [];
|
|
45655
45684
|
const availableActions = Array.isArray(resolved?.availableActions) ? resolved.availableActions : [];
|
|
45656
45685
|
const allowDuplicates = resolved?.allowDuplicates !== false;
|
|
45686
|
+
const entitySlots = Array.isArray(resolved?.slots) ? resolved.slots : [];
|
|
45687
|
+
const entityResult = str(resolved?.result);
|
|
45688
|
+
const entityAttempts = num(resolved?.attempts);
|
|
45689
|
+
const entityCurrentStep = typeof resolved?.currentStep === "number" ? resolved.currentStep : -1;
|
|
45690
|
+
const slots = Array.from({ length: maxSlots }, (_, i) => {
|
|
45691
|
+
const entitySlot = entitySlots.find((s) => s.index === i);
|
|
45692
|
+
if (!entitySlot?.placedActionId) return void 0;
|
|
45693
|
+
return availableActions.find((a) => a.id === entitySlot.placedActionId);
|
|
45694
|
+
});
|
|
45695
|
+
const isSuccess = entityResult === "win";
|
|
45696
|
+
const attempts = entityAttempts;
|
|
45697
|
+
const isPlayingBack = entityCurrentStep >= 0 && !isSuccess;
|
|
45698
|
+
const currentStep = entityCurrentStep;
|
|
45657
45699
|
const [headerError, setHeaderError] = React77.useState(false);
|
|
45658
|
-
const [slots, setSlots] = React77.useState(
|
|
45659
|
-
() => Array.from({ length: maxSlots }, () => void 0)
|
|
45660
|
-
);
|
|
45661
|
-
const [playState, setPlayState] = React77.useState("idle");
|
|
45662
|
-
const [currentStep, setCurrentStep] = React77.useState(-1);
|
|
45663
|
-
const [attempts, setAttempts] = React77.useState(0);
|
|
45664
45700
|
const [slotFeedback, setSlotFeedback] = React77.useState(
|
|
45665
45701
|
() => Array.from({ length: maxSlots }, () => null)
|
|
45666
45702
|
);
|
|
@@ -45669,11 +45705,6 @@ function SequencerBoard({
|
|
|
45669
45705
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
45670
45706
|
}, []);
|
|
45671
45707
|
const handleSlotDrop = React77.useCallback((index, item) => {
|
|
45672
|
-
setSlots((prev) => {
|
|
45673
|
-
const next = [...prev];
|
|
45674
|
-
next[index] = item;
|
|
45675
|
-
return next;
|
|
45676
|
-
});
|
|
45677
45708
|
setSlotFeedback((prev) => {
|
|
45678
45709
|
const next = [...prev];
|
|
45679
45710
|
next[index] = null;
|
|
@@ -45683,11 +45714,6 @@ function SequencerBoard({
|
|
|
45683
45714
|
if (placeEvent) emit(`UI:${placeEvent}`, { slotIndex: index, actionId: item.id });
|
|
45684
45715
|
}, [emit, placeEvent]);
|
|
45685
45716
|
const handleSlotRemove = React77.useCallback((index) => {
|
|
45686
|
-
setSlots((prev) => {
|
|
45687
|
-
const next = [...prev];
|
|
45688
|
-
next[index] = void 0;
|
|
45689
|
-
return next;
|
|
45690
|
-
});
|
|
45691
45717
|
setSlotFeedback((prev) => {
|
|
45692
45718
|
const next = [...prev];
|
|
45693
45719
|
next[index] = null;
|
|
@@ -45698,48 +45724,34 @@ function SequencerBoard({
|
|
|
45698
45724
|
}, [emit, removeEvent]);
|
|
45699
45725
|
const handleReset = React77.useCallback(() => {
|
|
45700
45726
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
45701
|
-
setSlots(Array.from({ length: maxSlots }, () => void 0));
|
|
45702
|
-
setPlayState("idle");
|
|
45703
|
-
setCurrentStep(-1);
|
|
45704
|
-
setAttempts(0);
|
|
45705
45727
|
setSlotFeedback(Array.from({ length: maxSlots }, () => null));
|
|
45706
45728
|
if (playAgainEvent) emit(`UI:${playAgainEvent}`, {});
|
|
45707
45729
|
}, [maxSlots, playAgainEvent, emit]);
|
|
45708
45730
|
const filledSlots = slots.filter((s) => !!s);
|
|
45709
|
-
const canPlay = filledSlots.length > 0 &&
|
|
45731
|
+
const canPlay = filledSlots.length > 0 && !isPlayingBack && !isSuccess;
|
|
45710
45732
|
const handlePlay = React77.useCallback(() => {
|
|
45711
45733
|
if (!canPlay) return;
|
|
45712
45734
|
setSlotFeedback(Array.from({ length: maxSlots }, () => null));
|
|
45713
45735
|
emit("UI:PLAY_SOUND", { key: "confirm" });
|
|
45714
45736
|
const sequence = slots.map((s) => s?.id || "");
|
|
45715
|
-
|
|
45716
|
-
|
|
45717
|
-
}
|
|
45718
|
-
setPlayState("playing");
|
|
45719
|
-
setCurrentStep(0);
|
|
45737
|
+
const playerIds = slots.filter(Boolean).map((s) => s?.id || "");
|
|
45738
|
+
if (playEvent) emit(`UI:${playEvent}`, { sequence });
|
|
45720
45739
|
let step = 0;
|
|
45721
45740
|
const advance = () => {
|
|
45722
45741
|
step++;
|
|
45742
|
+
emit("UI:STEP", { step });
|
|
45723
45743
|
if (step >= maxSlots) {
|
|
45744
|
+
if (checkEvent) emit(`UI:${checkEvent}`, { sequence: playerIds });
|
|
45724
45745
|
const playerSeq = slots.map((s) => s?.id);
|
|
45725
|
-
const playerIds = slots.filter(Boolean).map((s) => s?.id || "");
|
|
45726
45746
|
const success = solutions.some(
|
|
45727
45747
|
(sol) => sol.length === playerIds.length && sol.every((id, i) => id === playerIds[i])
|
|
45728
45748
|
);
|
|
45729
|
-
if (checkEvent) emit(`UI:${checkEvent}`, { sequence: playerIds });
|
|
45730
45749
|
if (success) {
|
|
45731
|
-
setPlayState("success");
|
|
45732
|
-
setCurrentStep(-1);
|
|
45733
45750
|
emit("UI:PLAY_SOUND", { key: "levelComplete" });
|
|
45734
|
-
if (completeEvent) {
|
|
45735
|
-
emit(`UI:${completeEvent}`, { success: true, sequence: playerIds });
|
|
45736
|
-
}
|
|
45751
|
+
if (completeEvent) emit(`UI:${completeEvent}`, { success: true, sequence: playerIds });
|
|
45737
45752
|
} else {
|
|
45738
|
-
setAttempts((prev) => prev + 1);
|
|
45739
45753
|
const feedback = computeSlotFeedback(playerSeq, solutions);
|
|
45740
45754
|
setSlotFeedback(feedback);
|
|
45741
|
-
setPlayState("idle");
|
|
45742
|
-
setCurrentStep(-1);
|
|
45743
45755
|
emit("UI:PLAY_SOUND", { key: "fail" });
|
|
45744
45756
|
const correctCount2 = feedback.filter((f3) => f3 === "correct").length;
|
|
45745
45757
|
for (let ci = 0; ci < correctCount2; ci++) {
|
|
@@ -45749,7 +45761,6 @@ function SequencerBoard({
|
|
|
45749
45761
|
}
|
|
45750
45762
|
}
|
|
45751
45763
|
} else {
|
|
45752
|
-
setCurrentStep(step);
|
|
45753
45764
|
timerRef.current = setTimeout(advance, stepDurationMs);
|
|
45754
45765
|
}
|
|
45755
45766
|
};
|
|
@@ -45799,7 +45810,7 @@ function SequencerBoard({
|
|
|
45799
45810
|
/* @__PURE__ */ jsxRuntime.jsxs(exports.VStack, { gap: "xs", children: [
|
|
45800
45811
|
/* @__PURE__ */ jsxRuntime.jsxs(exports.HStack, { className: "items-center justify-between", children: [
|
|
45801
45812
|
/* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "body2", className: "text-muted-foreground font-medium", children: t("sequencer.yourSequence") + ":" }),
|
|
45802
|
-
hasFeedback &&
|
|
45813
|
+
hasFeedback && !isPlayingBack && !isSuccess && /* @__PURE__ */ jsxRuntime.jsxs(exports.Typography, { variant: "caption", className: "text-muted-foreground", children: [
|
|
45803
45814
|
`${correctCount}/${maxSlots} `,
|
|
45804
45815
|
"\u2705"
|
|
45805
45816
|
] })
|
|
@@ -45811,7 +45822,7 @@ function SequencerBoard({
|
|
|
45811
45822
|
maxSlots,
|
|
45812
45823
|
onSlotDrop: handleSlotDrop,
|
|
45813
45824
|
onSlotRemove: handleSlotRemove,
|
|
45814
|
-
playing:
|
|
45825
|
+
playing: isPlayingBack,
|
|
45815
45826
|
currentStep,
|
|
45816
45827
|
categoryColors,
|
|
45817
45828
|
slotFeedback,
|
|
@@ -45819,7 +45830,7 @@ function SequencerBoard({
|
|
|
45819
45830
|
}
|
|
45820
45831
|
)
|
|
45821
45832
|
] }),
|
|
45822
|
-
|
|
45833
|
+
!isPlayingBack && /* @__PURE__ */ jsxRuntime.jsx(
|
|
45823
45834
|
ActionPalette,
|
|
45824
45835
|
{
|
|
45825
45836
|
actions: availableActions,
|
|
@@ -45829,8 +45840,8 @@ function SequencerBoard({
|
|
|
45829
45840
|
label: t("sequencer.dragActions")
|
|
45830
45841
|
}
|
|
45831
45842
|
),
|
|
45832
|
-
hasFeedback &&
|
|
45833
|
-
|
|
45843
|
+
hasFeedback && !isPlayingBack && !isSuccess && attempts > 0 && /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: "p-3 rounded-container bg-warning/10 border border-warning/30 text-center", children: /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "body2", className: "text-foreground", children: t(encourageKey) }) }),
|
|
45844
|
+
isSuccess && /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: "p-4 rounded-container bg-success/20 border border-success text-center", children: /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "h5", className: "text-success", children: str(resolved.successMessage) || t("sequencer.levelComplete") }) }),
|
|
45834
45845
|
/* @__PURE__ */ jsxRuntime.jsxs(exports.HStack, { gap: "sm", children: [
|
|
45835
45846
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
45836
45847
|
exports.Button,
|
|
@@ -46991,6 +47002,9 @@ function StateArchitectBoard({
|
|
|
46991
47002
|
stepDurationMs = 600,
|
|
46992
47003
|
testEvent,
|
|
46993
47004
|
completeEvent,
|
|
47005
|
+
addTransitionEvent,
|
|
47006
|
+
removeTransitionEvent,
|
|
47007
|
+
playAgainEvent,
|
|
46994
47008
|
className
|
|
46995
47009
|
}) {
|
|
46996
47010
|
const { emit } = useEventBus();
|
|
@@ -47003,14 +47017,16 @@ function StateArchitectBoard({
|
|
|
47003
47017
|
const testCases = Array.isArray(resolved?.testCases) ? resolved.testCases : [];
|
|
47004
47018
|
const entityTransitions = Array.isArray(resolved?.transitions) ? resolved.transitions : [];
|
|
47005
47019
|
const entityVariables = rows(resolved?.variables);
|
|
47006
|
-
const
|
|
47020
|
+
const transitions = entityTransitions;
|
|
47021
|
+
const attempts = typeof resolved?.attempts === "number" ? resolved.attempts : 0;
|
|
47022
|
+
const entityResult = str(resolved?.result) || "none";
|
|
47023
|
+
const isSuccess = entityResult === "win";
|
|
47024
|
+
const [isTesting, setIsTesting] = React77.useState(false);
|
|
47007
47025
|
const [headerError, setHeaderError] = React77.useState(false);
|
|
47008
|
-
const [playState, setPlayState] = React77.useState("editing");
|
|
47009
47026
|
const [currentState, setCurrentState] = React77.useState(initialState);
|
|
47010
47027
|
const [selectedState, setSelectedState] = React77.useState(null);
|
|
47011
47028
|
const [testResults, setTestResults] = React77.useState([]);
|
|
47012
47029
|
const [variables, setVariables] = React77.useState(() => [...entityVariables]);
|
|
47013
|
-
const [attempts, setAttempts] = React77.useState(0);
|
|
47014
47030
|
const timerRef = React77.useRef(null);
|
|
47015
47031
|
const [addingFrom, setAddingFrom] = React77.useState(null);
|
|
47016
47032
|
React77.useEffect(() => () => {
|
|
@@ -47020,7 +47036,7 @@ function StateArchitectBoard({
|
|
|
47020
47036
|
const GRAPH_H = 400;
|
|
47021
47037
|
const positions = React77.useMemo(() => layoutStates(entityStates, GRAPH_W, GRAPH_H), [entityStates]);
|
|
47022
47038
|
const handleStateClick = React77.useCallback((state) => {
|
|
47023
|
-
if (
|
|
47039
|
+
if (isTesting) return;
|
|
47024
47040
|
if (addingFrom) {
|
|
47025
47041
|
if (addingFrom !== state) {
|
|
47026
47042
|
const event = availableEvents[0] || "EVENT";
|
|
@@ -47030,20 +47046,20 @@ function StateArchitectBoard({
|
|
|
47030
47046
|
to: state,
|
|
47031
47047
|
event
|
|
47032
47048
|
};
|
|
47033
|
-
|
|
47049
|
+
if (addTransitionEvent) emit(`UI:${addTransitionEvent}`, { id: newTrans.id, from: newTrans.from, to: newTrans.to, event: newTrans.event });
|
|
47034
47050
|
}
|
|
47035
47051
|
setAddingFrom(null);
|
|
47036
47052
|
} else {
|
|
47037
47053
|
setSelectedState(state);
|
|
47038
47054
|
}
|
|
47039
|
-
}, [
|
|
47055
|
+
}, [isTesting, addingFrom, availableEvents, addTransitionEvent, emit]);
|
|
47040
47056
|
const handleStartAddTransition = React77.useCallback(() => {
|
|
47041
47057
|
if (!selectedState) return;
|
|
47042
47058
|
setAddingFrom(selectedState);
|
|
47043
47059
|
}, [selectedState]);
|
|
47044
47060
|
const handleRemoveTransition = React77.useCallback((transId) => {
|
|
47045
|
-
|
|
47046
|
-
}, []);
|
|
47061
|
+
if (removeTransitionEvent) emit(`UI:${removeTransitionEvent}`, { id: transId });
|
|
47062
|
+
}, [removeTransitionEvent, emit]);
|
|
47047
47063
|
const machine = React77.useMemo(() => ({
|
|
47048
47064
|
name: entityName,
|
|
47049
47065
|
description: str(resolved?.description),
|
|
@@ -47057,16 +47073,16 @@ function StateArchitectBoard({
|
|
|
47057
47073
|
}))
|
|
47058
47074
|
}), [entityName, resolved, entityStates, currentState, transitions]);
|
|
47059
47075
|
const handleTest = React77.useCallback(() => {
|
|
47060
|
-
if (
|
|
47076
|
+
if (isTesting) return;
|
|
47061
47077
|
if (testEvent) emit(`UI:${testEvent}`, {});
|
|
47062
|
-
|
|
47078
|
+
setIsTesting(true);
|
|
47063
47079
|
setTestResults([]);
|
|
47064
47080
|
const results = [];
|
|
47065
47081
|
let testIdx = 0;
|
|
47066
47082
|
const runNextTest = () => {
|
|
47067
47083
|
if (testIdx >= testCases.length) {
|
|
47068
47084
|
const allPassed = results.every((r) => r.passed);
|
|
47069
|
-
|
|
47085
|
+
setIsTesting(false);
|
|
47070
47086
|
setTestResults(results);
|
|
47071
47087
|
if (allPassed && completeEvent) {
|
|
47072
47088
|
emit(`UI:${completeEvent}`, {
|
|
@@ -47074,9 +47090,6 @@ function StateArchitectBoard({
|
|
|
47074
47090
|
passedTests: results.filter((r) => r.passed).length
|
|
47075
47091
|
});
|
|
47076
47092
|
}
|
|
47077
|
-
if (!allPassed) {
|
|
47078
|
-
setAttempts((prev) => prev + 1);
|
|
47079
|
-
}
|
|
47080
47093
|
return;
|
|
47081
47094
|
}
|
|
47082
47095
|
const testCase = testCases[testIdx];
|
|
@@ -47099,24 +47112,23 @@ function StateArchitectBoard({
|
|
|
47099
47112
|
timerRef.current = setTimeout(runNextTest, stepDurationMs);
|
|
47100
47113
|
};
|
|
47101
47114
|
timerRef.current = setTimeout(runNextTest, stepDurationMs);
|
|
47102
|
-
}, [
|
|
47115
|
+
}, [isTesting, transitions, testCases, initialState, stepDurationMs, testEvent, completeEvent, emit]);
|
|
47103
47116
|
const handleTryAgain = React77.useCallback(() => {
|
|
47104
47117
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
47105
|
-
|
|
47118
|
+
setIsTesting(false);
|
|
47106
47119
|
setCurrentState(initialState);
|
|
47107
47120
|
setTestResults([]);
|
|
47108
47121
|
}, [initialState]);
|
|
47109
47122
|
const handleReset = React77.useCallback(() => {
|
|
47110
47123
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
47111
|
-
|
|
47112
|
-
setPlayState("editing");
|
|
47124
|
+
setIsTesting(false);
|
|
47113
47125
|
setCurrentState(initialState);
|
|
47114
47126
|
setTestResults([]);
|
|
47115
47127
|
setVariables([...entityVariables]);
|
|
47116
47128
|
setSelectedState(null);
|
|
47117
47129
|
setAddingFrom(null);
|
|
47118
|
-
|
|
47119
|
-
}, [
|
|
47130
|
+
if (playAgainEvent) emit(`UI:${playAgainEvent}`, {});
|
|
47131
|
+
}, [initialState, entityVariables, playAgainEvent, emit]);
|
|
47120
47132
|
const codeData = React77.useMemo(() => ({
|
|
47121
47133
|
name: entityName,
|
|
47122
47134
|
states: entityStates,
|
|
@@ -47212,7 +47224,7 @@ function StateArchitectBoard({
|
|
|
47212
47224
|
]
|
|
47213
47225
|
}
|
|
47214
47226
|
),
|
|
47215
|
-
|
|
47227
|
+
!isTesting && /* @__PURE__ */ jsxRuntime.jsx(exports.HStack, { gap: "sm", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
47216
47228
|
exports.Button,
|
|
47217
47229
|
{
|
|
47218
47230
|
variant: "ghost",
|
|
@@ -47234,7 +47246,7 @@ function StateArchitectBoard({
|
|
|
47234
47246
|
t2.guardHint,
|
|
47235
47247
|
")"
|
|
47236
47248
|
] }),
|
|
47237
|
-
|
|
47249
|
+
!isTesting && /* @__PURE__ */ jsxRuntime.jsx(
|
|
47238
47250
|
exports.Button,
|
|
47239
47251
|
{
|
|
47240
47252
|
variant: "ghost",
|
|
@@ -47266,21 +47278,21 @@ function StateArchitectBoard({
|
|
|
47266
47278
|
resolved.showCodeView !== false && /* @__PURE__ */ jsxRuntime.jsx(StateJsonView, { data: codeData, label: "View Code" })
|
|
47267
47279
|
] })
|
|
47268
47280
|
] }),
|
|
47269
|
-
|
|
47270
|
-
|
|
47281
|
+
isSuccess && /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: "p-4 rounded-container bg-success/20 border border-success text-center", children: /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "h5", className: "text-success", children: str(resolved.successMessage) || t("stateArchitect.allPassed") }) }),
|
|
47282
|
+
!isTesting && !isSuccess && testResults.some((r) => !r.passed) && /* @__PURE__ */ jsxRuntime.jsxs(exports.VStack, { gap: "sm", children: [
|
|
47271
47283
|
/* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: "p-4 rounded-container bg-warning/10 border border-warning/30 text-center", children: /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "body1", className: "text-foreground font-medium", children: t(ENCOURAGEMENT_KEYS3[Math.min(attempts - 1, ENCOURAGEMENT_KEYS3.length - 1)] ?? ENCOURAGEMENT_KEYS3[0]) }) }),
|
|
47272
|
-
attempts >=
|
|
47284
|
+
!isSuccess && attempts >= 2 && Boolean(str(resolved?.hint)) && /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: "p-3 rounded-container bg-accent/10 border border-accent/30", children: /* @__PURE__ */ jsxRuntime.jsxs(exports.HStack, { className: "items-start", gap: "xs", children: [
|
|
47273
47285
|
/* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "body2", className: "text-accent font-bold shrink-0", children: "\u{1F4A1} " + t("game.hint") + ":" }),
|
|
47274
47286
|
/* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "body2", className: "text-foreground", children: hint })
|
|
47275
47287
|
] }) })
|
|
47276
47288
|
] }),
|
|
47277
47289
|
/* @__PURE__ */ jsxRuntime.jsxs(exports.HStack, { gap: "sm", children: [
|
|
47278
|
-
|
|
47290
|
+
!isTesting && !isSuccess && testResults.some((r) => !r.passed) ? /* @__PURE__ */ jsxRuntime.jsx(exports.Button, { variant: "primary", onClick: handleTryAgain, children: "\u{1F504} " + t("puzzle.tryAgainButton") }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
47279
47291
|
exports.Button,
|
|
47280
47292
|
{
|
|
47281
47293
|
variant: "primary",
|
|
47282
47294
|
onClick: handleTest,
|
|
47283
|
-
disabled:
|
|
47295
|
+
disabled: isTesting,
|
|
47284
47296
|
children: "\u25B6 " + t("game.runTests")
|
|
47285
47297
|
}
|
|
47286
47298
|
),
|
|
@@ -47360,6 +47372,7 @@ function formatDuration(seconds) {
|
|
|
47360
47372
|
return `${Math.round(seconds)}s`;
|
|
47361
47373
|
}
|
|
47362
47374
|
function StatusEffect({
|
|
47375
|
+
assetUrl = DEFAULT_ASSET_URL6,
|
|
47363
47376
|
icon = "shield",
|
|
47364
47377
|
label = "Shield",
|
|
47365
47378
|
duration = 30,
|
|
@@ -47380,7 +47393,17 @@ function StatusEffect({
|
|
|
47380
47393
|
),
|
|
47381
47394
|
title: label,
|
|
47382
47395
|
children: [
|
|
47383
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("flex items-center justify-center", sizes.icon), children:
|
|
47396
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("flex items-center justify-center", sizes.icon), children: assetUrl ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
47397
|
+
"img",
|
|
47398
|
+
{
|
|
47399
|
+
src: assetUrl,
|
|
47400
|
+
alt: label,
|
|
47401
|
+
width: sizes.img,
|
|
47402
|
+
height: sizes.img,
|
|
47403
|
+
style: { imageRendering: "pixelated", objectFit: "contain" },
|
|
47404
|
+
className: "flex-shrink-0"
|
|
47405
|
+
}
|
|
47406
|
+
) : typeof icon === "string" ? /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { name: icon, size: "sm" }) : /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { icon, size: "sm" }) }),
|
|
47384
47407
|
duration !== void 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
47385
47408
|
"span",
|
|
47386
47409
|
{
|
|
@@ -47407,15 +47430,16 @@ function StatusEffect({
|
|
|
47407
47430
|
label && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground mt-0.5 text-center whitespace-nowrap", children: label })
|
|
47408
47431
|
] });
|
|
47409
47432
|
}
|
|
47410
|
-
var sizeMap16, variantStyles9;
|
|
47433
|
+
var DEFAULT_ASSET_URL6, sizeMap16, variantStyles9;
|
|
47411
47434
|
var init_StatusEffect = __esm({
|
|
47412
47435
|
"components/game/atoms/StatusEffect.tsx"() {
|
|
47413
47436
|
init_cn();
|
|
47414
47437
|
init_Icon();
|
|
47438
|
+
DEFAULT_ASSET_URL6 = "https://almadar-kflow-assets.web.app/shared/effects/particles/flame_01.png";
|
|
47415
47439
|
sizeMap16 = {
|
|
47416
|
-
sm: { container: "w-8 h-8", icon: "text-sm", badge: "text-xs -top-1 -right-1 w-4 h-4", timer: "text-[9px]" },
|
|
47417
|
-
md: { container: "w-10 h-10", icon: "text-base", badge: "text-xs -top-1 -right-1 w-5 h-5", timer: "text-xs" },
|
|
47418
|
-
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" }
|
|
47440
|
+
sm: { container: "w-8 h-8", icon: "text-sm", badge: "text-xs -top-1 -right-1 w-4 h-4", timer: "text-[9px]", img: 20 },
|
|
47441
|
+
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 },
|
|
47442
|
+
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 }
|
|
47419
47443
|
};
|
|
47420
47444
|
variantStyles9 = {
|
|
47421
47445
|
buff: "border-success bg-success/20",
|
|
@@ -48106,17 +48130,12 @@ var init_UncontrolledBattleBoard = __esm({
|
|
|
48106
48130
|
}
|
|
48107
48131
|
});
|
|
48108
48132
|
function heroPosition(h) {
|
|
48133
|
+
if ("position" in h && h.position != null) return h.position;
|
|
48109
48134
|
return vec2(h.position);
|
|
48110
48135
|
}
|
|
48111
|
-
function heroOwner(h) {
|
|
48112
|
-
return str(h.owner);
|
|
48113
|
-
}
|
|
48114
48136
|
function heroMovement(h) {
|
|
48115
48137
|
return num(h.movement);
|
|
48116
48138
|
}
|
|
48117
|
-
function hexPassable(h) {
|
|
48118
|
-
return h.passable !== false;
|
|
48119
|
-
}
|
|
48120
48139
|
function defaultIsInRange(from, to, range) {
|
|
48121
48140
|
return Math.abs(from.x - to.x) + Math.abs(from.y - to.y) <= range;
|
|
48122
48141
|
}
|
|
@@ -48152,38 +48171,41 @@ function WorldMapBoard({
|
|
|
48152
48171
|
}) {
|
|
48153
48172
|
const eventBus = useEventBus();
|
|
48154
48173
|
const resolved = boardEntity(entity);
|
|
48155
|
-
const
|
|
48156
|
-
const
|
|
48174
|
+
const entityUnits = rows(resolved?.units);
|
|
48175
|
+
const entityTiles = rows(resolved?.tiles);
|
|
48157
48176
|
const features = propFeatures ?? (Array.isArray(resolved?.features) ? resolved.features : []);
|
|
48158
48177
|
const selectedHeroId = resolved?.selectedHeroId ?? null;
|
|
48159
48178
|
const assetManifest = propAssetManifest ?? resolved?.assetManifest;
|
|
48160
48179
|
const backgroundImage = resolved?.backgroundImage;
|
|
48161
48180
|
const [hoveredTile, setHoveredTile] = React77.useState(null);
|
|
48162
|
-
const selectedHero = React77.useMemo(
|
|
48163
|
-
() => heroes.find((h) => str(h.id) === selectedHeroId) ?? null,
|
|
48164
|
-
[heroes, selectedHeroId]
|
|
48165
|
-
);
|
|
48166
48181
|
const derivedTiles = React77.useMemo(
|
|
48167
|
-
() =>
|
|
48168
|
-
x: num(
|
|
48169
|
-
y: num(
|
|
48170
|
-
terrain: str(
|
|
48171
|
-
terrainSprite:
|
|
48182
|
+
() => entityTiles.map((t) => ({
|
|
48183
|
+
x: num(t.x),
|
|
48184
|
+
y: num(t.y),
|
|
48185
|
+
terrain: str(t.terrain),
|
|
48186
|
+
terrainSprite: t.terrainSprite == null ? void 0 : str(t.terrainSprite),
|
|
48187
|
+
passable: t.passable !== false
|
|
48172
48188
|
})),
|
|
48173
|
-
[
|
|
48189
|
+
[entityTiles]
|
|
48174
48190
|
);
|
|
48175
48191
|
const tiles = propTiles ?? derivedTiles;
|
|
48176
48192
|
const baseUnits = React77.useMemo(
|
|
48177
|
-
() => propUnits ??
|
|
48178
|
-
id: str(
|
|
48179
|
-
position: heroPosition(
|
|
48180
|
-
name: str(
|
|
48181
|
-
|
|
48182
|
-
|
|
48183
|
-
|
|
48184
|
-
|
|
48193
|
+
() => propUnits ?? entityUnits.map((u) => ({
|
|
48194
|
+
id: str(u.id),
|
|
48195
|
+
position: heroPosition(u),
|
|
48196
|
+
name: str(u.name),
|
|
48197
|
+
// lolo uses `team` field (not `owner`)
|
|
48198
|
+
team: str(u.team) === "enemy" ? "enemy" : "player",
|
|
48199
|
+
health: num(u.health) || 100,
|
|
48200
|
+
maxHealth: num(u.maxHealth) || 100,
|
|
48201
|
+
sprite: u.sprite == null ? void 0 : str(u.sprite)
|
|
48185
48202
|
})),
|
|
48186
|
-
[
|
|
48203
|
+
[entityUnits, propUnits]
|
|
48204
|
+
);
|
|
48205
|
+
const gameUnits = baseUnits;
|
|
48206
|
+
const selectedHero = React77.useMemo(
|
|
48207
|
+
() => gameUnits.find((u) => u.id === selectedHeroId) ?? null,
|
|
48208
|
+
[gameUnits, selectedHeroId]
|
|
48187
48209
|
);
|
|
48188
48210
|
const MOVE_SPEED_MS_PER_TILE = 300;
|
|
48189
48211
|
const movementAnimRef = React77.useRef(null);
|
|
@@ -48229,51 +48251,50 @@ function WorldMapBoard({
|
|
|
48229
48251
|
const validMoves = React77.useMemo(() => {
|
|
48230
48252
|
if (!selectedHero || heroMovement(selectedHero) <= 0) return [];
|
|
48231
48253
|
const sp = heroPosition(selectedHero);
|
|
48232
|
-
const
|
|
48254
|
+
const sTeam = str(selectedHero.team);
|
|
48233
48255
|
const range = heroMovement(selectedHero);
|
|
48234
48256
|
const moves = [];
|
|
48235
|
-
|
|
48236
|
-
const
|
|
48237
|
-
const
|
|
48238
|
-
if (
|
|
48239
|
-
if (
|
|
48240
|
-
if (!isInRange(sp, { x:
|
|
48241
|
-
if (
|
|
48242
|
-
const
|
|
48243
|
-
return
|
|
48257
|
+
tiles.forEach((t) => {
|
|
48258
|
+
const tx = t.x;
|
|
48259
|
+
const ty = t.y;
|
|
48260
|
+
if (t.passable === false) return;
|
|
48261
|
+
if (tx === sp.x && ty === sp.y) return;
|
|
48262
|
+
if (!isInRange(sp, { x: tx, y: ty }, range)) return;
|
|
48263
|
+
if (gameUnits.some((u) => {
|
|
48264
|
+
const up = u.position ?? { x: u.x ?? -1, y: u.y ?? -1 };
|
|
48265
|
+
return up.x === tx && up.y === ty && str(u.team) === sTeam;
|
|
48244
48266
|
})) return;
|
|
48245
|
-
moves.push({ x:
|
|
48267
|
+
moves.push({ x: tx, y: ty });
|
|
48246
48268
|
});
|
|
48247
48269
|
return moves;
|
|
48248
|
-
}, [selectedHero,
|
|
48270
|
+
}, [selectedHero, tiles, gameUnits, isInRange]);
|
|
48249
48271
|
const attackTargets = React77.useMemo(() => {
|
|
48250
48272
|
if (!selectedHero || heroMovement(selectedHero) <= 0) return [];
|
|
48251
48273
|
const sp = heroPosition(selectedHero);
|
|
48252
|
-
const
|
|
48274
|
+
const sTeam = str(selectedHero.team);
|
|
48253
48275
|
const range = heroMovement(selectedHero);
|
|
48254
|
-
return
|
|
48255
|
-
}, [selectedHero,
|
|
48256
|
-
const maxY = Math.max(...
|
|
48276
|
+
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 });
|
|
48277
|
+
}, [selectedHero, gameUnits, isInRange]);
|
|
48278
|
+
const maxY = Math.max(...tiles.map((t) => t.y), 0);
|
|
48257
48279
|
const baseOffsetX = (maxY + 1) * (exports.TILE_WIDTH * scale / 2);
|
|
48258
48280
|
const tileToScreen = React77.useCallback(
|
|
48259
48281
|
(tx, ty) => isoToScreen(tx, ty, scale, baseOffsetX),
|
|
48260
48282
|
[scale, baseOffsetX]
|
|
48261
48283
|
);
|
|
48262
48284
|
const hoveredHex = React77.useMemo(
|
|
48263
|
-
() => hoveredTile ?
|
|
48264
|
-
[hoveredTile,
|
|
48285
|
+
() => hoveredTile ? tiles.find((t) => t.x === hoveredTile.x && t.y === hoveredTile.y) ?? null : null,
|
|
48286
|
+
[hoveredTile, tiles]
|
|
48265
48287
|
);
|
|
48266
48288
|
const hoveredHero = React77.useMemo(
|
|
48267
|
-
() => hoveredTile ?
|
|
48268
|
-
const
|
|
48269
|
-
return
|
|
48289
|
+
() => hoveredTile ? gameUnits.find((u) => {
|
|
48290
|
+
const up = u.position ?? { x: u.x ?? -1, y: u.y ?? -1 };
|
|
48291
|
+
return up.x === hoveredTile.x && up.y === hoveredTile.y;
|
|
48270
48292
|
}) ?? null : null,
|
|
48271
|
-
[hoveredTile,
|
|
48293
|
+
[hoveredTile, gameUnits]
|
|
48272
48294
|
);
|
|
48273
48295
|
const handleTileClick = React77.useCallback((x, y) => {
|
|
48274
48296
|
if (movementAnimRef.current) return;
|
|
48275
|
-
const
|
|
48276
|
-
if (!hex) return;
|
|
48297
|
+
const tile = tiles.find((t) => t.x === x && t.y === y);
|
|
48277
48298
|
if (tileClickEvent) {
|
|
48278
48299
|
eventBus.emit(`UI:${tileClickEvent}`, { x, y });
|
|
48279
48300
|
}
|
|
@@ -48284,38 +48305,39 @@ function WorldMapBoard({
|
|
|
48284
48305
|
if (heroMoveEvent) {
|
|
48285
48306
|
eventBus.emit(`UI:${heroMoveEvent}`, { heroId, toX: x, toY: y });
|
|
48286
48307
|
}
|
|
48287
|
-
const feature = str(
|
|
48308
|
+
const feature = tile ? str(tile.feature) : "";
|
|
48288
48309
|
if (feature && feature !== "none") {
|
|
48289
|
-
|
|
48310
|
+
const tileRow = tile;
|
|
48311
|
+
onFeatureEnter?.(heroId, tileRow);
|
|
48290
48312
|
if (featureEnterEvent) {
|
|
48291
|
-
eventBus.emit(`UI:${featureEnterEvent}`, { heroId, feature, hex });
|
|
48313
|
+
eventBus.emit(`UI:${featureEnterEvent}`, { heroId, feature, hex: tileRow });
|
|
48292
48314
|
}
|
|
48293
48315
|
}
|
|
48294
48316
|
});
|
|
48295
48317
|
return;
|
|
48296
48318
|
}
|
|
48297
|
-
const enemy =
|
|
48298
|
-
const
|
|
48299
|
-
return
|
|
48319
|
+
const enemy = gameUnits.find((u) => {
|
|
48320
|
+
const up = u.position ?? { x: u.x ?? -1, y: u.y ?? -1 };
|
|
48321
|
+
return up.x === x && up.y === y && str(u.team) === "enemy";
|
|
48300
48322
|
});
|
|
48301
48323
|
if (selectedHero && enemy && attackTargets.some((t) => t.x === x && t.y === y)) {
|
|
48302
48324
|
const attackerId = str(selectedHero.id);
|
|
48303
|
-
const defenderId =
|
|
48325
|
+
const defenderId = enemy.id;
|
|
48304
48326
|
onBattleEncounter?.(attackerId, defenderId);
|
|
48305
48327
|
if (battleEncounterEvent) {
|
|
48306
48328
|
eventBus.emit(`UI:${battleEncounterEvent}`, { attackerId, defenderId });
|
|
48307
48329
|
}
|
|
48308
48330
|
}
|
|
48309
|
-
}, [
|
|
48331
|
+
}, [tiles, gameUnits, selectedHero, validMoves, attackTargets, startMoveAnimation, onHeroMove, onFeatureEnter, onBattleEncounter, eventBus, tileClickEvent, heroMoveEvent, featureEnterEvent, battleEncounterEvent]);
|
|
48310
48332
|
const handleUnitClick = React77.useCallback((unitId) => {
|
|
48311
|
-
const
|
|
48312
|
-
if (
|
|
48333
|
+
const unit = gameUnits.find((u) => u.id === unitId);
|
|
48334
|
+
if (unit && (str(unit.team) === "player" || allowMoveAllHeroes)) {
|
|
48313
48335
|
onHeroSelect?.(unitId);
|
|
48314
48336
|
if (heroSelectEvent) {
|
|
48315
48337
|
eventBus.emit(`UI:${heroSelectEvent}`, { heroId: unitId });
|
|
48316
48338
|
}
|
|
48317
48339
|
}
|
|
48318
|
-
}, [
|
|
48340
|
+
}, [gameUnits, onHeroSelect, allowMoveAllHeroes, eventBus, heroSelectEvent]);
|
|
48319
48341
|
const selectHero = React77.useCallback((id) => {
|
|
48320
48342
|
onHeroSelect?.(id);
|
|
48321
48343
|
if (heroSelectEvent) {
|