@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/components/index.js
CHANGED
|
@@ -10384,15 +10384,15 @@ function BattleBoard({
|
|
|
10384
10384
|
const board = boardEntity(entity) ?? {};
|
|
10385
10385
|
const tiles = propTiles ?? (Array.isArray(board.tiles) ? board.tiles : []);
|
|
10386
10386
|
const features = propFeatures ?? (Array.isArray(board.features) ? board.features : []);
|
|
10387
|
-
const boardWidth = num(board.boardWidth, 8);
|
|
10388
|
-
const boardHeight = num(board.boardHeight, 6);
|
|
10387
|
+
const boardWidth = num(board.gridWidth ?? board.boardWidth, 8);
|
|
10388
|
+
const boardHeight = num(board.gridHeight ?? board.boardHeight, 6);
|
|
10389
10389
|
const assetManifest = propAssetManifest ?? board.assetManifest;
|
|
10390
10390
|
const backgroundImage = board.backgroundImage;
|
|
10391
10391
|
const units = rows(board.units);
|
|
10392
10392
|
const selectedUnitId = board.selectedUnitId ?? null;
|
|
10393
10393
|
const currentPhase = str(board.phase) || "observation";
|
|
10394
10394
|
const currentTurn = num(board.turn, 1);
|
|
10395
|
-
const gameResult = board.
|
|
10395
|
+
const gameResult = board.result ?? null;
|
|
10396
10396
|
const eventBus = useEventBus();
|
|
10397
10397
|
const { t } = useTranslate();
|
|
10398
10398
|
const [hoveredTile, setHoveredTile] = useState(null);
|
|
@@ -10413,7 +10413,7 @@ function BattleBoard({
|
|
|
10413
10413
|
const validMoves = useMemo(() => {
|
|
10414
10414
|
if (!selectedUnit || currentPhase !== "movement") return [];
|
|
10415
10415
|
const moves = [];
|
|
10416
|
-
const range = num(
|
|
10416
|
+
const range = num(board.movementRange, 2);
|
|
10417
10417
|
const origin = unitPosition(selectedUnit);
|
|
10418
10418
|
for (let dy = -range; dy <= range; dy++) {
|
|
10419
10419
|
for (let dx = -range; dx <= range; dx++) {
|
|
@@ -18698,15 +18698,24 @@ function CastleBoard({
|
|
|
18698
18698
|
featureClickEvent,
|
|
18699
18699
|
unitClickEvent,
|
|
18700
18700
|
tileClickEvent,
|
|
18701
|
+
playAgainEvent,
|
|
18701
18702
|
className
|
|
18702
18703
|
}) {
|
|
18703
18704
|
const eventBus = useEventBus();
|
|
18705
|
+
const { t } = useTranslate();
|
|
18704
18706
|
const resolved = boardEntity(entity);
|
|
18705
18707
|
const tiles = propTiles ?? (Array.isArray(resolved?.tiles) ? resolved.tiles : []);
|
|
18706
18708
|
const features = propFeatures ?? (Array.isArray(resolved?.features) ? resolved.features : []);
|
|
18707
18709
|
const units = propUnits ?? (Array.isArray(resolved?.units) ? resolved.units : []);
|
|
18708
18710
|
const assetManifest = propAssetManifest ?? resolved?.assetManifest;
|
|
18709
18711
|
const backgroundImage = resolved?.backgroundImage;
|
|
18712
|
+
const gold = num(resolved?.gold);
|
|
18713
|
+
const health = num(resolved?.health);
|
|
18714
|
+
const maxHealth = num(resolved?.maxHealth);
|
|
18715
|
+
const wave = num(resolved?.wave);
|
|
18716
|
+
const tickCount = num(resolved?.tickCount);
|
|
18717
|
+
const buildings = rows(resolved?.buildings);
|
|
18718
|
+
const result = str(resolved?.result) || "none";
|
|
18710
18719
|
const [hoveredTile, setHoveredTile] = useState(null);
|
|
18711
18720
|
const [selectedFeature, setSelectedFeature] = useState(null);
|
|
18712
18721
|
const hoveredFeature = useMemo(() => {
|
|
@@ -18719,7 +18728,7 @@ function CastleBoard({
|
|
|
18719
18728
|
(u) => u.position?.x === hoveredTile.x && u.position?.y === hoveredTile.y
|
|
18720
18729
|
) ?? null;
|
|
18721
18730
|
}, [hoveredTile, units]);
|
|
18722
|
-
const maxY = Math.max(...tiles.map((
|
|
18731
|
+
const maxY = Math.max(...tiles.map((t2) => t2.y), 0);
|
|
18723
18732
|
const baseOffsetX = (maxY + 1) * (TILE_WIDTH * scale / 2);
|
|
18724
18733
|
const tileToScreen = useCallback(
|
|
18725
18734
|
(tx, ty) => isoToScreen(tx, ty, scale, baseOffsetX),
|
|
@@ -18754,6 +18763,11 @@ function CastleBoard({
|
|
|
18754
18763
|
}
|
|
18755
18764
|
}, [units, onUnitClick, unitClickEvent, eventBus]);
|
|
18756
18765
|
const clearSelection = useCallback(() => setSelectedFeature(null), []);
|
|
18766
|
+
const handlePlayAgain = useCallback(() => {
|
|
18767
|
+
if (playAgainEvent) {
|
|
18768
|
+
eventBus.emit(`UI:${playAgainEvent}`, {});
|
|
18769
|
+
}
|
|
18770
|
+
}, [playAgainEvent, eventBus]);
|
|
18757
18771
|
const ctx = useMemo(
|
|
18758
18772
|
() => ({
|
|
18759
18773
|
hoveredTile,
|
|
@@ -18762,11 +18776,18 @@ function CastleBoard({
|
|
|
18762
18776
|
selectedFeature,
|
|
18763
18777
|
clearSelection,
|
|
18764
18778
|
tileToScreen,
|
|
18765
|
-
scale
|
|
18779
|
+
scale,
|
|
18780
|
+
gold,
|
|
18781
|
+
health,
|
|
18782
|
+
maxHealth,
|
|
18783
|
+
wave,
|
|
18784
|
+
tickCount,
|
|
18785
|
+
buildings,
|
|
18786
|
+
result
|
|
18766
18787
|
}),
|
|
18767
|
-
[hoveredTile, hoveredFeature, hoveredUnit, selectedFeature, clearSelection, tileToScreen, scale]
|
|
18788
|
+
[hoveredTile, hoveredFeature, hoveredUnit, selectedFeature, clearSelection, tileToScreen, scale, gold, health, maxHealth, wave, tickCount, buildings, result]
|
|
18768
18789
|
);
|
|
18769
|
-
return /* @__PURE__ */ jsxs("div", { className: cn("castle-board min-h-screen flex flex-col bg-background", className), children: [
|
|
18790
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("castle-board relative min-h-screen flex flex-col bg-background", className), children: [
|
|
18770
18791
|
header && header(ctx),
|
|
18771
18792
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-1 overflow-hidden", children: [
|
|
18772
18793
|
/* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-auto p-4 relative", children: [
|
|
@@ -18791,7 +18812,29 @@ function CastleBoard({
|
|
|
18791
18812
|
] }),
|
|
18792
18813
|
sidePanel && /* @__PURE__ */ jsx("div", { className: "w-96 shrink-0 border-l border-border bg-surface overflow-y-auto", children: sidePanel(ctx) })
|
|
18793
18814
|
] }),
|
|
18794
|
-
footer && footer(ctx)
|
|
18815
|
+
footer && footer(ctx),
|
|
18816
|
+
result !== "none" && /* @__PURE__ */ jsx(Box, { className: "absolute inset-0 z-50 flex items-center justify-center bg-background/70 backdrop-blur-sm rounded-container", children: /* @__PURE__ */ jsxs(VStack, { className: "text-center p-8", gap: "lg", children: [
|
|
18817
|
+
/* @__PURE__ */ jsx(
|
|
18818
|
+
Typography,
|
|
18819
|
+
{
|
|
18820
|
+
variant: "h2",
|
|
18821
|
+
className: cn(
|
|
18822
|
+
"text-4xl font-black tracking-widest uppercase",
|
|
18823
|
+
result === "victory" ? "text-warning" : "text-error"
|
|
18824
|
+
),
|
|
18825
|
+
children: result === "victory" ? t("battle.victory") : t("battle.defeat")
|
|
18826
|
+
}
|
|
18827
|
+
),
|
|
18828
|
+
/* @__PURE__ */ jsx(
|
|
18829
|
+
Button,
|
|
18830
|
+
{
|
|
18831
|
+
variant: "primary",
|
|
18832
|
+
className: "px-8 py-3 font-semibold",
|
|
18833
|
+
onClick: handlePlayAgain,
|
|
18834
|
+
children: t("battle.playAgain")
|
|
18835
|
+
}
|
|
18836
|
+
)
|
|
18837
|
+
] }) })
|
|
18795
18838
|
] });
|
|
18796
18839
|
}
|
|
18797
18840
|
var init_CastleBoard = __esm({
|
|
@@ -18799,6 +18842,10 @@ var init_CastleBoard = __esm({
|
|
|
18799
18842
|
"use client";
|
|
18800
18843
|
init_cn();
|
|
18801
18844
|
init_useEventBus();
|
|
18845
|
+
init_Box();
|
|
18846
|
+
init_Button();
|
|
18847
|
+
init_Typography();
|
|
18848
|
+
init_Stack();
|
|
18802
18849
|
init_IsometricCanvas();
|
|
18803
18850
|
init_boardEntity();
|
|
18804
18851
|
init_isometric();
|
|
@@ -19721,22 +19768,16 @@ function ClassifierBoard({
|
|
|
19721
19768
|
const { emit } = useEventBus();
|
|
19722
19769
|
const { t } = useTranslate();
|
|
19723
19770
|
const resolved = boardEntity(entity);
|
|
19724
|
-
const [localAssignments, setLocalAssignments] = useState({});
|
|
19725
19771
|
const [headerError, setHeaderError] = useState(false);
|
|
19726
|
-
const [localSubmitted, setLocalSubmitted] = useState(false);
|
|
19727
|
-
const [localAttempts, setLocalAttempts] = useState(0);
|
|
19728
|
-
const [showHint, setShowHint] = useState(false);
|
|
19729
19772
|
const items = Array.isArray(resolved?.items) ? resolved.items : [];
|
|
19730
19773
|
const categories = Array.isArray(resolved?.categories) ? resolved.categories : [];
|
|
19731
|
-
const
|
|
19732
|
-
const
|
|
19733
|
-
const
|
|
19734
|
-
const assignments =
|
|
19735
|
-
if (item.assignedCategory != null) acc[item.id] = item.assignedCategory;
|
|
19774
|
+
const result = str(resolved?.result);
|
|
19775
|
+
const submitted = result === "win";
|
|
19776
|
+
const attempts = num(resolved?.attempts);
|
|
19777
|
+
const assignments = items.reduce((acc, item) => {
|
|
19778
|
+
if (item.assignedCategory != null && item.assignedCategory !== "") acc[item.id] = item.assignedCategory;
|
|
19736
19779
|
return acc;
|
|
19737
|
-
}, {})
|
|
19738
|
-
const attempts = entityDrivesResult ? num(resolved?.attempts) : localAttempts;
|
|
19739
|
-
const submitted = entityDrivesResult || localSubmitted;
|
|
19780
|
+
}, {});
|
|
19740
19781
|
const unassignedItems = items.filter((item) => !assignments[item.id]);
|
|
19741
19782
|
const allAssigned = items.length > 0 && Object.keys(assignments).length === items.length;
|
|
19742
19783
|
const results = submitted ? items.map((item) => ({
|
|
@@ -19744,54 +19785,25 @@ function ClassifierBoard({
|
|
|
19744
19785
|
assigned: assignments[item.id],
|
|
19745
19786
|
correct: assignments[item.id] === item.correctCategory
|
|
19746
19787
|
})) : [];
|
|
19747
|
-
const allCorrect =
|
|
19788
|
+
const allCorrect = result === "win";
|
|
19748
19789
|
const correctCount = results.filter((r) => r.correct).length;
|
|
19790
|
+
const showHint = attempts >= 2 && Boolean(str(resolved?.hint));
|
|
19749
19791
|
const handleAssign = (itemId, categoryId) => {
|
|
19750
19792
|
if (submitted) return;
|
|
19751
|
-
if (assignEvent) {
|
|
19752
|
-
emit(`UI:${assignEvent}`, { itemId, categoryId });
|
|
19753
|
-
}
|
|
19754
|
-
if (!entityHasAssignments) {
|
|
19755
|
-
setLocalAssignments((prev) => ({ ...prev, [itemId]: categoryId }));
|
|
19756
|
-
}
|
|
19793
|
+
if (assignEvent) emit(`UI:${assignEvent}`, { itemId, categoryId });
|
|
19757
19794
|
};
|
|
19758
19795
|
const handleUnassign = (itemId) => {
|
|
19759
19796
|
if (submitted) return;
|
|
19760
|
-
if (
|
|
19761
|
-
setLocalAssignments((prev) => {
|
|
19762
|
-
const next = { ...prev };
|
|
19763
|
-
delete next[itemId];
|
|
19764
|
-
return next;
|
|
19765
|
-
});
|
|
19766
|
-
}
|
|
19797
|
+
if (assignEvent) emit(`UI:${assignEvent}`, { itemId, categoryId: "" });
|
|
19767
19798
|
};
|
|
19768
|
-
const handleSubmit =
|
|
19769
|
-
if (checkEvent) {
|
|
19770
|
-
|
|
19771
|
-
|
|
19772
|
-
if (!entityDrivesResult) {
|
|
19773
|
-
setLocalSubmitted(true);
|
|
19774
|
-
setLocalAttempts((a) => a + 1);
|
|
19775
|
-
const correct = items.every((item) => assignments[item.id] === item.correctCategory);
|
|
19776
|
-
if (correct) {
|
|
19777
|
-
emit(`UI:${completeEvent}`, { success: true, attempts: attempts + 1 });
|
|
19778
|
-
}
|
|
19779
|
-
}
|
|
19780
|
-
}, [checkEvent, entityDrivesResult, items, assignments, attempts, completeEvent, emit]);
|
|
19781
|
-
const handleReset = () => {
|
|
19782
|
-
if (!entityDrivesResult) setLocalSubmitted(false);
|
|
19783
|
-
if (attempts >= 2 && str(resolved?.hint)) {
|
|
19784
|
-
setShowHint(true);
|
|
19799
|
+
const handleSubmit = () => {
|
|
19800
|
+
if (checkEvent) emit(`UI:${checkEvent}`, {});
|
|
19801
|
+
if (allAssigned && items.every((item) => assignments[item.id] === item.correctCategory)) {
|
|
19802
|
+
emit(`UI:${completeEvent}`, { success: true, attempts: attempts + 1 });
|
|
19785
19803
|
}
|
|
19786
19804
|
};
|
|
19787
19805
|
const handleFullReset = () => {
|
|
19788
|
-
if (playAgainEvent) {
|
|
19789
|
-
emit(`UI:${playAgainEvent}`, {});
|
|
19790
|
-
}
|
|
19791
|
-
setLocalAssignments({});
|
|
19792
|
-
setLocalSubmitted(false);
|
|
19793
|
-
setLocalAttempts(0);
|
|
19794
|
-
setShowHint(false);
|
|
19806
|
+
if (playAgainEvent) emit(`UI:${playAgainEvent}`, {});
|
|
19795
19807
|
};
|
|
19796
19808
|
if (!resolved) return null;
|
|
19797
19809
|
const theme = resolved.theme ?? void 0;
|
|
@@ -19830,17 +19842,17 @@ function ClassifierBoard({
|
|
|
19830
19842
|
/* @__PURE__ */ jsx(Badge, { size: "sm", children: catItems.length })
|
|
19831
19843
|
] }),
|
|
19832
19844
|
/* @__PURE__ */ jsx(HStack, { gap: "xs", className: "flex-wrap min-h-[2rem]", children: catItems.map((item) => {
|
|
19833
|
-
const
|
|
19845
|
+
const result2 = results.find((r) => r.item.id === item.id);
|
|
19834
19846
|
return /* @__PURE__ */ jsxs(
|
|
19835
19847
|
Badge,
|
|
19836
19848
|
{
|
|
19837
19849
|
size: "sm",
|
|
19838
|
-
className: `cursor-pointer ${
|
|
19850
|
+
className: `cursor-pointer ${result2 ? result2.correct ? "border-success bg-success/10" : "border-error bg-error/10" : ""}`,
|
|
19839
19851
|
onClick: () => handleUnassign(item.id),
|
|
19840
19852
|
children: [
|
|
19841
19853
|
item.iconUrl && /* @__PURE__ */ jsx("img", { src: item.iconUrl, alt: "", className: "w-3 h-3 object-contain inline-block" }),
|
|
19842
19854
|
item.label,
|
|
19843
|
-
|
|
19855
|
+
result2 && /* @__PURE__ */ jsx(Icon, { icon: result2.correct ? CheckCircle : XCircle, size: "xs", className: result2.correct ? "text-success" : "text-error" })
|
|
19844
19856
|
]
|
|
19845
19857
|
},
|
|
19846
19858
|
item.id
|
|
@@ -19869,10 +19881,10 @@ function ClassifierBoard({
|
|
|
19869
19881
|
] }) }),
|
|
19870
19882
|
showHint && hint && /* @__PURE__ */ jsx(Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsx(Typography, { variant: "body", children: hint }) }),
|
|
19871
19883
|
/* @__PURE__ */ jsxs(HStack, { gap: "sm", justify: "center", children: [
|
|
19872
|
-
!submitted
|
|
19884
|
+
!submitted && /* @__PURE__ */ jsxs(Button, { variant: "primary", onClick: handleSubmit, disabled: !allAssigned, children: [
|
|
19873
19885
|
/* @__PURE__ */ jsx(Icon, { icon: Send, size: "sm" }),
|
|
19874
19886
|
t("classifier.check")
|
|
19875
|
-
] })
|
|
19887
|
+
] }),
|
|
19876
19888
|
/* @__PURE__ */ jsxs(Button, { variant: "secondary", onClick: handleFullReset, children: [
|
|
19877
19889
|
/* @__PURE__ */ jsx(Icon, { icon: RotateCcw, size: "sm" }),
|
|
19878
19890
|
t("classifier.reset")
|
|
@@ -20159,6 +20171,7 @@ function getComboScale(combo) {
|
|
|
20159
20171
|
return "";
|
|
20160
20172
|
}
|
|
20161
20173
|
function ComboCounter({
|
|
20174
|
+
assetUrl = DEFAULT_ASSET_URL,
|
|
20162
20175
|
combo = 5,
|
|
20163
20176
|
multiplier,
|
|
20164
20177
|
streak,
|
|
@@ -20178,6 +20191,17 @@ function ComboCounter({
|
|
|
20178
20191
|
className
|
|
20179
20192
|
),
|
|
20180
20193
|
children: [
|
|
20194
|
+
assetUrl && /* @__PURE__ */ jsx(
|
|
20195
|
+
"img",
|
|
20196
|
+
{
|
|
20197
|
+
src: assetUrl,
|
|
20198
|
+
alt: "combo",
|
|
20199
|
+
width: 24,
|
|
20200
|
+
height: 24,
|
|
20201
|
+
style: { imageRendering: "pixelated", objectFit: "contain" },
|
|
20202
|
+
className: "flex-shrink-0 mb-0.5"
|
|
20203
|
+
}
|
|
20204
|
+
),
|
|
20181
20205
|
/* @__PURE__ */ jsx("span", { className: cn("font-black tabular-nums leading-none", sizes.combo, getComboIntensity(combo)), children: combo }),
|
|
20182
20206
|
/* @__PURE__ */ jsx("span", { className: cn("font-bold uppercase tracking-wider text-muted-foreground", sizes.label), children: "combo" }),
|
|
20183
20207
|
multiplier != null && multiplier > 1 && /* @__PURE__ */ jsxs("span", { className: cn("font-bold text-warning tabular-nums", sizes.multiplier), children: [
|
|
@@ -20192,10 +20216,11 @@ function ComboCounter({
|
|
|
20192
20216
|
}
|
|
20193
20217
|
);
|
|
20194
20218
|
}
|
|
20195
|
-
var sizeMap4;
|
|
20219
|
+
var DEFAULT_ASSET_URL, sizeMap4;
|
|
20196
20220
|
var init_ComboCounter = __esm({
|
|
20197
20221
|
"components/game/atoms/ComboCounter.tsx"() {
|
|
20198
20222
|
init_cn();
|
|
20223
|
+
DEFAULT_ASSET_URL = "https://almadar-kflow-assets.web.app/shared/effects/flash/flash00.png";
|
|
20199
20224
|
sizeMap4 = {
|
|
20200
20225
|
sm: { combo: "text-lg", label: "text-xs", multiplier: "text-xs" },
|
|
20201
20226
|
md: { combo: "text-2xl", label: "text-xs", multiplier: "text-sm" },
|
|
@@ -20604,7 +20629,7 @@ var init_CounterTemplate = __esm({
|
|
|
20604
20629
|
}
|
|
20605
20630
|
});
|
|
20606
20631
|
function ItemSlot({
|
|
20607
|
-
assetUrl =
|
|
20632
|
+
assetUrl = DEFAULT_ASSET_URL2,
|
|
20608
20633
|
icon = "sword",
|
|
20609
20634
|
label = "Iron Sword",
|
|
20610
20635
|
quantity,
|
|
@@ -20663,7 +20688,7 @@ function ItemSlot({
|
|
|
20663
20688
|
}
|
|
20664
20689
|
);
|
|
20665
20690
|
}
|
|
20666
|
-
var sizeMap5, rarityBorderMap, rarityGlowMap,
|
|
20691
|
+
var sizeMap5, rarityBorderMap, rarityGlowMap, DEFAULT_ASSET_URL2, assetSizeMap;
|
|
20667
20692
|
var init_ItemSlot = __esm({
|
|
20668
20693
|
"components/game/atoms/ItemSlot.tsx"() {
|
|
20669
20694
|
"use client";
|
|
@@ -20688,7 +20713,7 @@ var init_ItemSlot = __esm({
|
|
|
20688
20713
|
epic: "shadow-lg",
|
|
20689
20714
|
legendary: "shadow-lg"
|
|
20690
20715
|
};
|
|
20691
|
-
|
|
20716
|
+
DEFAULT_ASSET_URL2 = "https://almadar-kflow-assets.web.app/shared/isometric-dungeon/Isometric/chestClosed_E.png";
|
|
20692
20717
|
assetSizeMap = {
|
|
20693
20718
|
sm: 28,
|
|
20694
20719
|
md: 40,
|
|
@@ -27244,6 +27269,7 @@ var init_InventoryGrid = __esm({
|
|
|
27244
27269
|
}
|
|
27245
27270
|
});
|
|
27246
27271
|
function WaypointMarker({
|
|
27272
|
+
assetUrl = DEFAULT_ASSET_URL3,
|
|
27247
27273
|
label,
|
|
27248
27274
|
icon,
|
|
27249
27275
|
active = true,
|
|
@@ -27282,7 +27308,17 @@ function WaypointMarker({
|
|
|
27282
27308
|
active && !completed && "bg-info text-foreground",
|
|
27283
27309
|
!active && !completed && "bg-muted"
|
|
27284
27310
|
),
|
|
27285
|
-
children: completed ? checkIcon :
|
|
27311
|
+
children: completed ? checkIcon : assetUrl ? /* @__PURE__ */ jsx(
|
|
27312
|
+
"img",
|
|
27313
|
+
{
|
|
27314
|
+
src: assetUrl,
|
|
27315
|
+
alt: label,
|
|
27316
|
+
width: sizes.img,
|
|
27317
|
+
height: sizes.img,
|
|
27318
|
+
style: { imageRendering: "pixelated", objectFit: "contain" },
|
|
27319
|
+
className: "flex-shrink-0"
|
|
27320
|
+
}
|
|
27321
|
+
) : icon ? typeof icon === "string" ? /* @__PURE__ */ jsx(Icon, { name: icon }) : /* @__PURE__ */ jsx(Icon, { icon }) : null
|
|
27286
27322
|
}
|
|
27287
27323
|
)
|
|
27288
27324
|
] }),
|
|
@@ -27299,15 +27335,16 @@ function WaypointMarker({
|
|
|
27299
27335
|
)
|
|
27300
27336
|
] });
|
|
27301
27337
|
}
|
|
27302
|
-
var sizeMap12, checkIcon;
|
|
27338
|
+
var DEFAULT_ASSET_URL3, sizeMap12, checkIcon;
|
|
27303
27339
|
var init_WaypointMarker = __esm({
|
|
27304
27340
|
"components/game/atoms/WaypointMarker.tsx"() {
|
|
27305
27341
|
init_cn();
|
|
27306
27342
|
init_Icon();
|
|
27343
|
+
DEFAULT_ASSET_URL3 = "https://almadar-kflow-assets.web.app/shared/world-map/battle_marker.png";
|
|
27307
27344
|
sizeMap12 = {
|
|
27308
|
-
sm: { dot: "w-4 h-4", ring: "w-6 h-6", label: "text-xs mt-1" },
|
|
27309
|
-
md: { dot: "w-6 h-6", ring: "w-8 h-8", label: "text-sm mt-1.5" },
|
|
27310
|
-
lg: { dot: "w-8 h-8", ring: "w-10 h-10", label: "text-base mt-2" }
|
|
27345
|
+
sm: { dot: "w-4 h-4", ring: "w-6 h-6", label: "text-xs mt-1", img: 12 },
|
|
27346
|
+
md: { dot: "w-6 h-6", ring: "w-8 h-8", label: "text-sm mt-1.5", img: 18 },
|
|
27347
|
+
lg: { dot: "w-8 h-8", ring: "w-10 h-10", label: "text-base mt-2", img: 24 }
|
|
27311
27348
|
};
|
|
27312
27349
|
checkIcon = /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 3, className: "w-3/5 h-3/5", children: /* @__PURE__ */ jsx("path", { d: "M5 13l4 4L19 7", strokeLinecap: "round", strokeLinejoin: "round" }) });
|
|
27313
27350
|
WaypointMarker.displayName = "WaypointMarker";
|
|
@@ -29579,7 +29616,7 @@ var init_MapView = __esm({
|
|
|
29579
29616
|
shadowSize: [41, 41]
|
|
29580
29617
|
});
|
|
29581
29618
|
L.Marker.prototype.options.icon = defaultIcon;
|
|
29582
|
-
const { useEffect: useEffect74, useRef: useRef71, useCallback:
|
|
29619
|
+
const { useEffect: useEffect74, useRef: useRef71, useCallback: useCallback113, useState: useState105 } = React77__default;
|
|
29583
29620
|
const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
|
|
29584
29621
|
const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
|
|
29585
29622
|
function MapUpdater({ centerLat, centerLng, zoom }) {
|
|
@@ -29625,7 +29662,7 @@ var init_MapView = __esm({
|
|
|
29625
29662
|
}) {
|
|
29626
29663
|
const eventBus = useEventBus2();
|
|
29627
29664
|
const [clickedPosition, setClickedPosition] = useState105(null);
|
|
29628
|
-
const handleMapClick =
|
|
29665
|
+
const handleMapClick = useCallback113((lat, lng) => {
|
|
29629
29666
|
if (showClickedPin) {
|
|
29630
29667
|
setClickedPosition({ lat, lng });
|
|
29631
29668
|
}
|
|
@@ -29634,7 +29671,7 @@ var init_MapView = __esm({
|
|
|
29634
29671
|
eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
|
|
29635
29672
|
}
|
|
29636
29673
|
}, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
|
|
29637
|
-
const handleMarkerClick =
|
|
29674
|
+
const handleMarkerClick = useCallback113((marker) => {
|
|
29638
29675
|
onMarkerClick?.(marker);
|
|
29639
29676
|
if (markerClickEvent) {
|
|
29640
29677
|
eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
|
|
@@ -39077,44 +39114,27 @@ function DebuggerBoard({
|
|
|
39077
39114
|
const { t } = useTranslate();
|
|
39078
39115
|
const resolved = boardEntity(entity);
|
|
39079
39116
|
const [headerError, setHeaderError] = useState(false);
|
|
39080
|
-
const [showHint, setShowHint] = useState(false);
|
|
39081
39117
|
const lines = Array.isArray(resolved?.lines) ? resolved.lines : [];
|
|
39082
|
-
const result = resolved?.result
|
|
39118
|
+
const result = str(resolved?.result) || "none";
|
|
39083
39119
|
const attempts = num(resolved?.attempts);
|
|
39084
|
-
const submitted = result
|
|
39120
|
+
const submitted = result === "win";
|
|
39121
|
+
const showHint = !submitted && attempts >= 2 && Boolean(str(resolved?.hint));
|
|
39085
39122
|
const bugLines = lines.filter((l) => l.isBug);
|
|
39086
39123
|
const flaggedLines = lines.filter((l) => l.isFlagged);
|
|
39087
39124
|
const correctFlags = lines.filter((l) => l.isBug && l.isFlagged);
|
|
39088
39125
|
const falseFlags = lines.filter((l) => !l.isBug && l.isFlagged);
|
|
39089
|
-
const allCorrect =
|
|
39126
|
+
const allCorrect = submitted;
|
|
39090
39127
|
const toggleLine = (lineId) => {
|
|
39091
39128
|
if (submitted) return;
|
|
39092
|
-
if (toggleFlagEvent) {
|
|
39093
|
-
emit(`UI:${toggleFlagEvent}`, { lineId });
|
|
39094
|
-
}
|
|
39129
|
+
if (toggleFlagEvent) emit(`UI:${toggleFlagEvent}`, { lineId });
|
|
39095
39130
|
};
|
|
39096
39131
|
const handleSubmit = useCallback(() => {
|
|
39097
|
-
if (checkEvent) {
|
|
39098
|
-
emit(`UI:${checkEvent}`, {});
|
|
39099
|
-
}
|
|
39132
|
+
if (checkEvent) emit(`UI:${checkEvent}`, {});
|
|
39100
39133
|
const correct = correctFlags.length === bugLines.length && falseFlags.length === 0;
|
|
39101
|
-
if (correct) {
|
|
39102
|
-
emit(`UI:${completeEvent}`, { success: true, attempts: attempts + 1 });
|
|
39103
|
-
}
|
|
39134
|
+
if (correct) emit(`UI:${completeEvent}`, { success: true, attempts: attempts + 1 });
|
|
39104
39135
|
}, [checkEvent, correctFlags.length, bugLines.length, falseFlags.length, attempts, completeEvent, emit]);
|
|
39105
39136
|
const handleReset = () => {
|
|
39106
|
-
if (playAgainEvent) {
|
|
39107
|
-
emit(`UI:${playAgainEvent}`, {});
|
|
39108
|
-
}
|
|
39109
|
-
if (attempts >= 2 && str(resolved?.hint)) {
|
|
39110
|
-
setShowHint(true);
|
|
39111
|
-
}
|
|
39112
|
-
};
|
|
39113
|
-
const handleFullReset = () => {
|
|
39114
|
-
if (playAgainEvent) {
|
|
39115
|
-
emit(`UI:${playAgainEvent}`, {});
|
|
39116
|
-
}
|
|
39117
|
-
setShowHint(false);
|
|
39137
|
+
if (playAgainEvent) emit(`UI:${playAgainEvent}`, {});
|
|
39118
39138
|
};
|
|
39119
39139
|
if (!resolved) return null;
|
|
39120
39140
|
const theme = resolved.theme ?? void 0;
|
|
@@ -39138,7 +39158,7 @@ function DebuggerBoard({
|
|
|
39138
39158
|
/* @__PURE__ */ jsx(Typography, { variant: "h4", weight: "bold", children: str(resolved.title) })
|
|
39139
39159
|
] }),
|
|
39140
39160
|
/* @__PURE__ */ jsx(Typography, { variant: "body", children: str(resolved.description) }),
|
|
39141
|
-
/* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-muted-foreground", children: t("debugger.findBugs", { count: String(
|
|
39161
|
+
/* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-muted-foreground", children: t("debugger.findBugs", { count: String(lines.filter((l) => l.isBug).length) }) })
|
|
39142
39162
|
] }) }),
|
|
39143
39163
|
/* @__PURE__ */ jsx(Card, { className: "p-0 overflow-hidden", children: /* @__PURE__ */ jsx(VStack, { gap: "none", children: lines.map((line, i) => {
|
|
39144
39164
|
const isFlagged = !!line.isFlagged;
|
|
@@ -39188,11 +39208,11 @@ function DebuggerBoard({
|
|
|
39188
39208
|
] }) }),
|
|
39189
39209
|
showHint && hint && /* @__PURE__ */ jsx(Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsx(Typography, { variant: "body", children: hint }) }),
|
|
39190
39210
|
/* @__PURE__ */ jsxs(HStack, { gap: "sm", justify: "center", children: [
|
|
39191
|
-
!submitted
|
|
39211
|
+
!submitted && /* @__PURE__ */ jsxs(Button, { variant: "primary", onClick: handleSubmit, disabled: flaggedLines.length === 0, children: [
|
|
39192
39212
|
/* @__PURE__ */ jsx(Icon, { icon: Send, size: "sm" }),
|
|
39193
39213
|
t("debugger.submit")
|
|
39194
|
-
] })
|
|
39195
|
-
/* @__PURE__ */ jsxs(Button, { variant: "secondary", onClick:
|
|
39214
|
+
] }),
|
|
39215
|
+
/* @__PURE__ */ jsxs(Button, { variant: "secondary", onClick: handleReset, children: [
|
|
39196
39216
|
/* @__PURE__ */ jsx(Icon, { icon: RotateCcw, size: "sm" }),
|
|
39197
39217
|
t("debugger.reset")
|
|
39198
39218
|
] })
|
|
@@ -39782,6 +39802,7 @@ var init_DrawerSlot = __esm({
|
|
|
39782
39802
|
}
|
|
39783
39803
|
});
|
|
39784
39804
|
function StateIndicator({
|
|
39805
|
+
assetUrl = DEFAULT_ASSET_URL4,
|
|
39785
39806
|
state = "idle",
|
|
39786
39807
|
label,
|
|
39787
39808
|
size = "md",
|
|
@@ -39804,18 +39825,29 @@ function StateIndicator({
|
|
|
39804
39825
|
className
|
|
39805
39826
|
),
|
|
39806
39827
|
children: [
|
|
39807
|
-
/* @__PURE__ */ jsx(Box, { as: "span", children:
|
|
39828
|
+
/* @__PURE__ */ jsx(Box, { as: "span", children: assetUrl ? /* @__PURE__ */ jsx(
|
|
39829
|
+
"img",
|
|
39830
|
+
{
|
|
39831
|
+
src: assetUrl,
|
|
39832
|
+
alt: displayLabel,
|
|
39833
|
+
width: 16,
|
|
39834
|
+
height: 16,
|
|
39835
|
+
style: { imageRendering: "pixelated", objectFit: "contain" },
|
|
39836
|
+
className: "flex-shrink-0"
|
|
39837
|
+
}
|
|
39838
|
+
) : typeof config.icon === "string" ? /^[a-zA-Z0-9-]+$/.test(config.icon) ? /* @__PURE__ */ jsx(Icon, { name: config.icon }) : config.icon : /* @__PURE__ */ jsx(Icon, { icon: config.icon }) }),
|
|
39808
39839
|
/* @__PURE__ */ jsx(Box, { as: "span", children: displayLabel })
|
|
39809
39840
|
]
|
|
39810
39841
|
}
|
|
39811
39842
|
);
|
|
39812
39843
|
}
|
|
39813
|
-
var DEFAULT_STATE_STYLES, DEFAULT_STYLE, SIZE_CLASSES;
|
|
39844
|
+
var DEFAULT_ASSET_URL4, DEFAULT_STATE_STYLES, DEFAULT_STYLE, SIZE_CLASSES;
|
|
39814
39845
|
var init_StateIndicator = __esm({
|
|
39815
39846
|
"components/game/atoms/StateIndicator.tsx"() {
|
|
39816
39847
|
init_Box();
|
|
39817
39848
|
init_Icon();
|
|
39818
39849
|
init_cn();
|
|
39850
|
+
DEFAULT_ASSET_URL4 = "https://almadar-kflow-assets.web.app/shared/isometric-dungeon/Isometric/chestClosed_E.png";
|
|
39819
39851
|
DEFAULT_STATE_STYLES = {
|
|
39820
39852
|
idle: { icon: "\u23F8", bgClass: "bg-muted" },
|
|
39821
39853
|
active: { icon: "\u25B6", bgClass: "bg-success" },
|
|
@@ -40289,39 +40321,40 @@ function EventHandlerBoard({
|
|
|
40289
40321
|
stepDurationMs = 800,
|
|
40290
40322
|
playEvent,
|
|
40291
40323
|
completeEvent,
|
|
40324
|
+
editRuleEvent,
|
|
40325
|
+
playAgainEvent,
|
|
40292
40326
|
className
|
|
40293
40327
|
}) {
|
|
40294
40328
|
const { emit } = useEventBus();
|
|
40295
40329
|
const { t } = useTranslate();
|
|
40296
40330
|
const resolved = boardEntity(entity);
|
|
40297
|
-
const
|
|
40298
|
-
const
|
|
40331
|
+
const objects = rows(resolved?.objects);
|
|
40332
|
+
const entityResult = str(resolved?.result) || "none";
|
|
40333
|
+
const isSuccess = entityResult === "win";
|
|
40334
|
+
const attempts = typeof resolved?.attempts === "number" ? resolved.attempts : 0;
|
|
40299
40335
|
const [selectedObjectId, setSelectedObjectId] = useState(
|
|
40300
|
-
|
|
40336
|
+
objects[0] ? objId(objects[0]) : null
|
|
40301
40337
|
);
|
|
40302
40338
|
const [headerError, setHeaderError] = useState(false);
|
|
40303
|
-
const [
|
|
40339
|
+
const [isPlaying, setIsPlaying] = useState(false);
|
|
40304
40340
|
const [eventLog, setEventLog] = useState([]);
|
|
40305
|
-
const [attempts, setAttempts] = useState(0);
|
|
40306
40341
|
const timerRef = useRef(null);
|
|
40307
40342
|
const logIdCounter = useRef(0);
|
|
40308
40343
|
useEffect(() => () => {
|
|
40309
40344
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
40310
40345
|
}, []);
|
|
40311
|
-
const selectedObject = objects.find((o) => objId(o) === selectedObjectId)
|
|
40346
|
+
const selectedObject = objects.find((o) => objId(o) === selectedObjectId) ?? null;
|
|
40312
40347
|
const handleRulesChange = useCallback((objectId, rules) => {
|
|
40313
|
-
|
|
40314
|
-
|
|
40315
|
-
));
|
|
40316
|
-
}, []);
|
|
40348
|
+
if (editRuleEvent) emit(`UI:${editRuleEvent}`, { objectId, rules });
|
|
40349
|
+
}, [editRuleEvent, emit]);
|
|
40317
40350
|
const addLogEntry = useCallback((icon, message, status = "done") => {
|
|
40318
40351
|
const id = `log-${logIdCounter.current++}`;
|
|
40319
40352
|
setEventLog((prev) => [...prev, { id, timestamp: Date.now(), icon, message, status }]);
|
|
40320
40353
|
}, []);
|
|
40321
40354
|
const handlePlay = useCallback(() => {
|
|
40322
|
-
if (
|
|
40355
|
+
if (isPlaying || isSuccess) return;
|
|
40323
40356
|
if (playEvent) emit(`UI:${playEvent}`, {});
|
|
40324
|
-
|
|
40357
|
+
setIsPlaying(true);
|
|
40325
40358
|
setEventLog([]);
|
|
40326
40359
|
const allRules = [];
|
|
40327
40360
|
objects.forEach((obj) => {
|
|
@@ -40337,15 +40370,8 @@ function EventHandlerBoard({
|
|
|
40337
40370
|
let goalReached = false;
|
|
40338
40371
|
const processNext = () => {
|
|
40339
40372
|
if (eventQueue.length === 0 || stepIdx > 20) {
|
|
40340
|
-
|
|
40341
|
-
|
|
40342
|
-
if (completeEvent) {
|
|
40343
|
-
emit(`UI:${completeEvent}`, { success: true });
|
|
40344
|
-
}
|
|
40345
|
-
} else {
|
|
40346
|
-
setAttempts((prev) => prev + 1);
|
|
40347
|
-
setPlayState("fail");
|
|
40348
|
-
}
|
|
40373
|
+
setIsPlaying(false);
|
|
40374
|
+
if (goalReached && completeEvent) emit(`UI:${completeEvent}`, { success: true });
|
|
40349
40375
|
return;
|
|
40350
40376
|
}
|
|
40351
40377
|
const currentEvent = eventQueue.shift();
|
|
@@ -40376,21 +40402,19 @@ function EventHandlerBoard({
|
|
|
40376
40402
|
addLogEntry("\u{1F3AC}", t("eventHandler.simulationStarted", { events: triggers.join(", ") }), "active");
|
|
40377
40403
|
}
|
|
40378
40404
|
timerRef.current = setTimeout(processNext, stepDurationMs);
|
|
40379
|
-
}, [
|
|
40405
|
+
}, [isPlaying, isSuccess, objects, resolved, stepDurationMs, playEvent, completeEvent, emit, addLogEntry, t]);
|
|
40380
40406
|
const handleTryAgain = useCallback(() => {
|
|
40381
40407
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
40382
|
-
|
|
40408
|
+
setIsPlaying(false);
|
|
40383
40409
|
setEventLog([]);
|
|
40384
40410
|
}, []);
|
|
40385
40411
|
const handleReset = useCallback(() => {
|
|
40386
40412
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
40387
|
-
|
|
40388
|
-
setObjects([...resetObjects]);
|
|
40389
|
-
setPlayState("editing");
|
|
40413
|
+
setIsPlaying(false);
|
|
40390
40414
|
setEventLog([]);
|
|
40391
|
-
setSelectedObjectId(
|
|
40392
|
-
|
|
40393
|
-
}, [
|
|
40415
|
+
setSelectedObjectId(objects[0] ? objId(objects[0]) : null);
|
|
40416
|
+
if (playAgainEvent) emit(`UI:${playAgainEvent}`, {});
|
|
40417
|
+
}, [objects, playAgainEvent, emit]);
|
|
40394
40418
|
if (!resolved) return null;
|
|
40395
40419
|
const objectViewers = objects.map((obj) => {
|
|
40396
40420
|
const states = objStates(obj);
|
|
@@ -40459,12 +40483,12 @@ function EventHandlerBoard({
|
|
|
40459
40483
|
{
|
|
40460
40484
|
object: selectedObject,
|
|
40461
40485
|
onRulesChange: handleRulesChange,
|
|
40462
|
-
disabled:
|
|
40486
|
+
disabled: isPlaying
|
|
40463
40487
|
}
|
|
40464
40488
|
),
|
|
40465
40489
|
eventLog.length > 0 && /* @__PURE__ */ jsx(EventLog, { entries: eventLog }),
|
|
40466
|
-
|
|
40467
|
-
|
|
40490
|
+
isSuccess && /* @__PURE__ */ jsx(Box, { className: "p-4 rounded-container bg-success/20 border border-success text-center", children: /* @__PURE__ */ jsx(Typography, { variant: "h5", className: "text-success", children: str(resolved.successMessage) || t("eventHandler.chainComplete") }) }),
|
|
40491
|
+
!isPlaying && !isSuccess && attempts > 0 && /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
|
|
40468
40492
|
/* @__PURE__ */ jsx(Box, { className: "p-4 rounded-container bg-warning/10 border border-warning/30 text-center", children: /* @__PURE__ */ jsx(Typography, { variant: "body1", className: "text-foreground font-medium", children: t(encourageKey) }) }),
|
|
40469
40493
|
showHint && /* @__PURE__ */ jsx(Box, { className: "p-3 rounded-container bg-accent/10 border border-accent/30", children: /* @__PURE__ */ jsxs(HStack, { className: "items-start", gap: "xs", children: [
|
|
40470
40494
|
/* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-accent font-bold shrink-0", children: "\u{1F4A1} " + t("game.hint") + ":" }),
|
|
@@ -40472,12 +40496,12 @@ function EventHandlerBoard({
|
|
|
40472
40496
|
] }) })
|
|
40473
40497
|
] }),
|
|
40474
40498
|
/* @__PURE__ */ jsxs(HStack, { gap: "sm", children: [
|
|
40475
|
-
|
|
40499
|
+
!isPlaying && !isSuccess && attempts > 0 ? /* @__PURE__ */ jsx(Button, { variant: "primary", onClick: handleTryAgain, children: "\u{1F504} " + t("puzzle.tryAgainButton") }) : /* @__PURE__ */ jsx(
|
|
40476
40500
|
Button,
|
|
40477
40501
|
{
|
|
40478
40502
|
variant: "primary",
|
|
40479
40503
|
onClick: handlePlay,
|
|
40480
|
-
disabled:
|
|
40504
|
+
disabled: isPlaying || isSuccess,
|
|
40481
40505
|
children: "\u25B6 " + t("game.play")
|
|
40482
40506
|
}
|
|
40483
40507
|
),
|
|
@@ -43145,21 +43169,6 @@ var init_ModalSlot = __esm({
|
|
|
43145
43169
|
ModalSlot.displayName = "ModalSlot";
|
|
43146
43170
|
}
|
|
43147
43171
|
});
|
|
43148
|
-
function getOpponentAction(strategy, actions, history) {
|
|
43149
|
-
const actionIds = actions.map((a) => a.id);
|
|
43150
|
-
switch (strategy) {
|
|
43151
|
-
case "always-cooperate":
|
|
43152
|
-
return actionIds[0];
|
|
43153
|
-
case "always-defect":
|
|
43154
|
-
return actionIds[actionIds.length - 1];
|
|
43155
|
-
case "tit-for-tat":
|
|
43156
|
-
if (history.length === 0) return actionIds[0];
|
|
43157
|
-
return history[history.length - 1].playerAction;
|
|
43158
|
-
case "random":
|
|
43159
|
-
default:
|
|
43160
|
-
return actionIds[Math.floor(Math.random() * actionIds.length)];
|
|
43161
|
-
}
|
|
43162
|
-
}
|
|
43163
43172
|
function NegotiatorBoard({
|
|
43164
43173
|
entity,
|
|
43165
43174
|
completeEvent = "PUZZLE_COMPLETE",
|
|
@@ -43181,28 +43190,35 @@ function NegotiatorBoard({
|
|
|
43181
43190
|
const playerTotal = num(resolved?.score);
|
|
43182
43191
|
const isComplete = result !== "none" || totalRounds > 0 && currentRound >= totalRounds;
|
|
43183
43192
|
const won = result === "win";
|
|
43184
|
-
const
|
|
43193
|
+
const lastPlayerAction = str(resolved?.lastPlayerAction);
|
|
43194
|
+
const lastOpponentAction = str(resolved?.lastOpponentAction);
|
|
43195
|
+
const lastPayoff = num(resolved?.lastPayoff);
|
|
43185
43196
|
const actions = Array.isArray(resolved?.actions) ? resolved.actions : [];
|
|
43186
43197
|
const payoffMatrix = Array.isArray(resolved?.payoffMatrix) ? resolved.payoffMatrix : [];
|
|
43198
|
+
const prevRoundRef = useRef(currentRound);
|
|
43199
|
+
useEffect(() => {
|
|
43200
|
+
if (currentRound > prevRoundRef.current && lastPlayerAction) {
|
|
43201
|
+
const opponentPayoffEntry = payoffMatrix.find(
|
|
43202
|
+
(p2) => p2.playerAction === lastPlayerAction && p2.opponentAction === lastOpponentAction
|
|
43203
|
+
);
|
|
43204
|
+
setHistory((prev) => [
|
|
43205
|
+
...prev,
|
|
43206
|
+
{
|
|
43207
|
+
round: currentRound,
|
|
43208
|
+
playerAction: lastPlayerAction,
|
|
43209
|
+
opponentAction: lastOpponentAction,
|
|
43210
|
+
playerPayoff: lastPayoff,
|
|
43211
|
+
opponentPayoff: opponentPayoffEntry?.opponentPayoff ?? 0
|
|
43212
|
+
}
|
|
43213
|
+
]);
|
|
43214
|
+
}
|
|
43215
|
+
prevRoundRef.current = currentRound;
|
|
43216
|
+
}, [currentRound, lastPlayerAction, lastOpponentAction, lastPayoff, payoffMatrix]);
|
|
43217
|
+
const opponentTotal = useMemo(() => history.reduce((s, r) => s + r.opponentPayoff, 0), [history]);
|
|
43187
43218
|
const handleAction = useCallback((actionId) => {
|
|
43188
43219
|
if (isComplete) return;
|
|
43189
|
-
const opponentAction = getOpponentAction(str(resolved?.opponentStrategy) || "random", actions, history);
|
|
43190
|
-
const payoff = payoffMatrix.find(
|
|
43191
|
-
(p2) => p2.playerAction === actionId && p2.opponentAction === opponentAction
|
|
43192
|
-
);
|
|
43193
|
-
const playerPayoff = payoff?.playerPayoff ?? 0;
|
|
43194
|
-
setHistory((prev) => [
|
|
43195
|
-
...prev,
|
|
43196
|
-
{
|
|
43197
|
-
round: prev.length + 1,
|
|
43198
|
-
playerAction: actionId,
|
|
43199
|
-
opponentAction,
|
|
43200
|
-
playerPayoff,
|
|
43201
|
-
opponentPayoff: payoff?.opponentPayoff ?? 0
|
|
43202
|
-
}
|
|
43203
|
-
]);
|
|
43204
43220
|
if (playRoundEvent) {
|
|
43205
|
-
emit(`UI:${playRoundEvent}`, { playerAction: actionId, payoff:
|
|
43221
|
+
emit(`UI:${playRoundEvent}`, { playerAction: actionId, payoff: 0 });
|
|
43206
43222
|
}
|
|
43207
43223
|
if (totalRounds > 0 && currentRound + 1 >= totalRounds) {
|
|
43208
43224
|
if (finishEvent) {
|
|
@@ -43212,10 +43228,11 @@ function NegotiatorBoard({
|
|
|
43212
43228
|
setShowHint(true);
|
|
43213
43229
|
}
|
|
43214
43230
|
}
|
|
43215
|
-
}, [isComplete, resolved, totalRounds, currentRound,
|
|
43231
|
+
}, [isComplete, resolved, totalRounds, currentRound, playRoundEvent, finishEvent, emit]);
|
|
43216
43232
|
const handleReset = useCallback(() => {
|
|
43217
43233
|
setHistory([]);
|
|
43218
43234
|
setShowHint(false);
|
|
43235
|
+
prevRoundRef.current = 0;
|
|
43219
43236
|
if (playAgainEvent) {
|
|
43220
43237
|
emit(`UI:${playAgainEvent}`, {});
|
|
43221
43238
|
}
|
|
@@ -43449,6 +43466,7 @@ var init_PricingPageTemplate = __esm({
|
|
|
43449
43466
|
}
|
|
43450
43467
|
});
|
|
43451
43468
|
function ResourceCounter({
|
|
43469
|
+
assetUrl = DEFAULT_ASSET_URL5,
|
|
43452
43470
|
icon,
|
|
43453
43471
|
label = "Gold",
|
|
43454
43472
|
value = 250,
|
|
@@ -43468,7 +43486,17 @@ function ResourceCounter({
|
|
|
43468
43486
|
className
|
|
43469
43487
|
),
|
|
43470
43488
|
children: [
|
|
43471
|
-
|
|
43489
|
+
assetUrl ? /* @__PURE__ */ jsx(
|
|
43490
|
+
"img",
|
|
43491
|
+
{
|
|
43492
|
+
src: assetUrl,
|
|
43493
|
+
alt: label,
|
|
43494
|
+
width: sizes.img,
|
|
43495
|
+
height: sizes.img,
|
|
43496
|
+
style: { imageRendering: "pixelated", objectFit: "contain" },
|
|
43497
|
+
className: "flex-shrink-0"
|
|
43498
|
+
}
|
|
43499
|
+
) : icon ? /* @__PURE__ */ jsx("span", { className: cn("flex-shrink-0", sizes.icon), children: typeof icon === "string" ? /* @__PURE__ */ jsx(Icon, { name: icon }) : /* @__PURE__ */ jsx(Icon, { icon }) }) : null,
|
|
43472
43500
|
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: label }),
|
|
43473
43501
|
/* @__PURE__ */ jsxs("span", { className: cn("font-bold tabular-nums", color && (color in colorTokenClasses2 ? colorTokenClasses2[color] : color)), children: [
|
|
43474
43502
|
value,
|
|
@@ -43481,7 +43509,7 @@ function ResourceCounter({
|
|
|
43481
43509
|
}
|
|
43482
43510
|
);
|
|
43483
43511
|
}
|
|
43484
|
-
var colorTokenClasses2, sizeMap15;
|
|
43512
|
+
var colorTokenClasses2, DEFAULT_ASSET_URL5, sizeMap15;
|
|
43485
43513
|
var init_ResourceCounter = __esm({
|
|
43486
43514
|
"components/game/atoms/ResourceCounter.tsx"() {
|
|
43487
43515
|
init_cn();
|
|
@@ -43494,10 +43522,11 @@ var init_ResourceCounter = __esm({
|
|
|
43494
43522
|
error: "text-error",
|
|
43495
43523
|
muted: "text-muted-foreground"
|
|
43496
43524
|
};
|
|
43525
|
+
DEFAULT_ASSET_URL5 = "https://almadar-kflow-assets.web.app/shared/world-map/gold_mine.png";
|
|
43497
43526
|
sizeMap15 = {
|
|
43498
|
-
sm: { wrapper: "text-xs gap-1 px-1.5 py-0.5", icon: "text-sm" },
|
|
43499
|
-
md: { wrapper: "text-sm gap-1.5 px-2 py-1", icon: "text-base" },
|
|
43500
|
-
lg: { wrapper: "text-base gap-2 px-3 py-1.5", icon: "text-lg" }
|
|
43527
|
+
sm: { wrapper: "text-xs gap-1 px-1.5 py-0.5", icon: "text-sm", img: 16 },
|
|
43528
|
+
md: { wrapper: "text-sm gap-1.5 px-2 py-1", icon: "text-base", img: 20 },
|
|
43529
|
+
lg: { wrapper: "text-base gap-2 px-3 py-1.5", icon: "text-lg", img: 28 }
|
|
43501
43530
|
};
|
|
43502
43531
|
ResourceCounter.displayName = "ResourceCounter";
|
|
43503
43532
|
}
|
|
@@ -45605,17 +45634,24 @@ function SequencerBoard({
|
|
|
45605
45634
|
const { emit } = useEventBus();
|
|
45606
45635
|
const { t } = useTranslate();
|
|
45607
45636
|
const resolved = boardEntity(entity);
|
|
45608
|
-
const maxSlots = num(resolved?.maxSlots);
|
|
45637
|
+
const maxSlots = num(resolved?.maxSlots) || 3;
|
|
45609
45638
|
const solutions = Array.isArray(resolved?.solutions) ? resolved.solutions : [];
|
|
45610
45639
|
const availableActions = Array.isArray(resolved?.availableActions) ? resolved.availableActions : [];
|
|
45611
45640
|
const allowDuplicates = resolved?.allowDuplicates !== false;
|
|
45641
|
+
const entitySlots = Array.isArray(resolved?.slots) ? resolved.slots : [];
|
|
45642
|
+
const entityResult = str(resolved?.result);
|
|
45643
|
+
const entityAttempts = num(resolved?.attempts);
|
|
45644
|
+
const entityCurrentStep = typeof resolved?.currentStep === "number" ? resolved.currentStep : -1;
|
|
45645
|
+
const slots = Array.from({ length: maxSlots }, (_, i) => {
|
|
45646
|
+
const entitySlot = entitySlots.find((s) => s.index === i);
|
|
45647
|
+
if (!entitySlot?.placedActionId) return void 0;
|
|
45648
|
+
return availableActions.find((a) => a.id === entitySlot.placedActionId);
|
|
45649
|
+
});
|
|
45650
|
+
const isSuccess = entityResult === "win";
|
|
45651
|
+
const attempts = entityAttempts;
|
|
45652
|
+
const isPlayingBack = entityCurrentStep >= 0 && !isSuccess;
|
|
45653
|
+
const currentStep = entityCurrentStep;
|
|
45612
45654
|
const [headerError, setHeaderError] = useState(false);
|
|
45613
|
-
const [slots, setSlots] = useState(
|
|
45614
|
-
() => Array.from({ length: maxSlots }, () => void 0)
|
|
45615
|
-
);
|
|
45616
|
-
const [playState, setPlayState] = useState("idle");
|
|
45617
|
-
const [currentStep, setCurrentStep] = useState(-1);
|
|
45618
|
-
const [attempts, setAttempts] = useState(0);
|
|
45619
45655
|
const [slotFeedback, setSlotFeedback] = useState(
|
|
45620
45656
|
() => Array.from({ length: maxSlots }, () => null)
|
|
45621
45657
|
);
|
|
@@ -45624,11 +45660,6 @@ function SequencerBoard({
|
|
|
45624
45660
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
45625
45661
|
}, []);
|
|
45626
45662
|
const handleSlotDrop = useCallback((index, item) => {
|
|
45627
|
-
setSlots((prev) => {
|
|
45628
|
-
const next = [...prev];
|
|
45629
|
-
next[index] = item;
|
|
45630
|
-
return next;
|
|
45631
|
-
});
|
|
45632
45663
|
setSlotFeedback((prev) => {
|
|
45633
45664
|
const next = [...prev];
|
|
45634
45665
|
next[index] = null;
|
|
@@ -45638,11 +45669,6 @@ function SequencerBoard({
|
|
|
45638
45669
|
if (placeEvent) emit(`UI:${placeEvent}`, { slotIndex: index, actionId: item.id });
|
|
45639
45670
|
}, [emit, placeEvent]);
|
|
45640
45671
|
const handleSlotRemove = useCallback((index) => {
|
|
45641
|
-
setSlots((prev) => {
|
|
45642
|
-
const next = [...prev];
|
|
45643
|
-
next[index] = void 0;
|
|
45644
|
-
return next;
|
|
45645
|
-
});
|
|
45646
45672
|
setSlotFeedback((prev) => {
|
|
45647
45673
|
const next = [...prev];
|
|
45648
45674
|
next[index] = null;
|
|
@@ -45653,48 +45679,34 @@ function SequencerBoard({
|
|
|
45653
45679
|
}, [emit, removeEvent]);
|
|
45654
45680
|
const handleReset = useCallback(() => {
|
|
45655
45681
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
45656
|
-
setSlots(Array.from({ length: maxSlots }, () => void 0));
|
|
45657
|
-
setPlayState("idle");
|
|
45658
|
-
setCurrentStep(-1);
|
|
45659
|
-
setAttempts(0);
|
|
45660
45682
|
setSlotFeedback(Array.from({ length: maxSlots }, () => null));
|
|
45661
45683
|
if (playAgainEvent) emit(`UI:${playAgainEvent}`, {});
|
|
45662
45684
|
}, [maxSlots, playAgainEvent, emit]);
|
|
45663
45685
|
const filledSlots = slots.filter((s) => !!s);
|
|
45664
|
-
const canPlay = filledSlots.length > 0 &&
|
|
45686
|
+
const canPlay = filledSlots.length > 0 && !isPlayingBack && !isSuccess;
|
|
45665
45687
|
const handlePlay = useCallback(() => {
|
|
45666
45688
|
if (!canPlay) return;
|
|
45667
45689
|
setSlotFeedback(Array.from({ length: maxSlots }, () => null));
|
|
45668
45690
|
emit("UI:PLAY_SOUND", { key: "confirm" });
|
|
45669
45691
|
const sequence = slots.map((s) => s?.id || "");
|
|
45670
|
-
|
|
45671
|
-
|
|
45672
|
-
}
|
|
45673
|
-
setPlayState("playing");
|
|
45674
|
-
setCurrentStep(0);
|
|
45692
|
+
const playerIds = slots.filter(Boolean).map((s) => s?.id || "");
|
|
45693
|
+
if (playEvent) emit(`UI:${playEvent}`, { sequence });
|
|
45675
45694
|
let step = 0;
|
|
45676
45695
|
const advance = () => {
|
|
45677
45696
|
step++;
|
|
45697
|
+
emit("UI:STEP", { step });
|
|
45678
45698
|
if (step >= maxSlots) {
|
|
45699
|
+
if (checkEvent) emit(`UI:${checkEvent}`, { sequence: playerIds });
|
|
45679
45700
|
const playerSeq = slots.map((s) => s?.id);
|
|
45680
|
-
const playerIds = slots.filter(Boolean).map((s) => s?.id || "");
|
|
45681
45701
|
const success = solutions.some(
|
|
45682
45702
|
(sol) => sol.length === playerIds.length && sol.every((id, i) => id === playerIds[i])
|
|
45683
45703
|
);
|
|
45684
|
-
if (checkEvent) emit(`UI:${checkEvent}`, { sequence: playerIds });
|
|
45685
45704
|
if (success) {
|
|
45686
|
-
setPlayState("success");
|
|
45687
|
-
setCurrentStep(-1);
|
|
45688
45705
|
emit("UI:PLAY_SOUND", { key: "levelComplete" });
|
|
45689
|
-
if (completeEvent) {
|
|
45690
|
-
emit(`UI:${completeEvent}`, { success: true, sequence: playerIds });
|
|
45691
|
-
}
|
|
45706
|
+
if (completeEvent) emit(`UI:${completeEvent}`, { success: true, sequence: playerIds });
|
|
45692
45707
|
} else {
|
|
45693
|
-
setAttempts((prev) => prev + 1);
|
|
45694
45708
|
const feedback = computeSlotFeedback(playerSeq, solutions);
|
|
45695
45709
|
setSlotFeedback(feedback);
|
|
45696
|
-
setPlayState("idle");
|
|
45697
|
-
setCurrentStep(-1);
|
|
45698
45710
|
emit("UI:PLAY_SOUND", { key: "fail" });
|
|
45699
45711
|
const correctCount2 = feedback.filter((f3) => f3 === "correct").length;
|
|
45700
45712
|
for (let ci = 0; ci < correctCount2; ci++) {
|
|
@@ -45704,7 +45716,6 @@ function SequencerBoard({
|
|
|
45704
45716
|
}
|
|
45705
45717
|
}
|
|
45706
45718
|
} else {
|
|
45707
|
-
setCurrentStep(step);
|
|
45708
45719
|
timerRef.current = setTimeout(advance, stepDurationMs);
|
|
45709
45720
|
}
|
|
45710
45721
|
};
|
|
@@ -45754,7 +45765,7 @@ function SequencerBoard({
|
|
|
45754
45765
|
/* @__PURE__ */ jsxs(VStack, { gap: "xs", children: [
|
|
45755
45766
|
/* @__PURE__ */ jsxs(HStack, { className: "items-center justify-between", children: [
|
|
45756
45767
|
/* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-muted-foreground font-medium", children: t("sequencer.yourSequence") + ":" }),
|
|
45757
|
-
hasFeedback &&
|
|
45768
|
+
hasFeedback && !isPlayingBack && !isSuccess && /* @__PURE__ */ jsxs(Typography, { variant: "caption", className: "text-muted-foreground", children: [
|
|
45758
45769
|
`${correctCount}/${maxSlots} `,
|
|
45759
45770
|
"\u2705"
|
|
45760
45771
|
] })
|
|
@@ -45766,7 +45777,7 @@ function SequencerBoard({
|
|
|
45766
45777
|
maxSlots,
|
|
45767
45778
|
onSlotDrop: handleSlotDrop,
|
|
45768
45779
|
onSlotRemove: handleSlotRemove,
|
|
45769
|
-
playing:
|
|
45780
|
+
playing: isPlayingBack,
|
|
45770
45781
|
currentStep,
|
|
45771
45782
|
categoryColors,
|
|
45772
45783
|
slotFeedback,
|
|
@@ -45774,7 +45785,7 @@ function SequencerBoard({
|
|
|
45774
45785
|
}
|
|
45775
45786
|
)
|
|
45776
45787
|
] }),
|
|
45777
|
-
|
|
45788
|
+
!isPlayingBack && /* @__PURE__ */ jsx(
|
|
45778
45789
|
ActionPalette,
|
|
45779
45790
|
{
|
|
45780
45791
|
actions: availableActions,
|
|
@@ -45784,8 +45795,8 @@ function SequencerBoard({
|
|
|
45784
45795
|
label: t("sequencer.dragActions")
|
|
45785
45796
|
}
|
|
45786
45797
|
),
|
|
45787
|
-
hasFeedback &&
|
|
45788
|
-
|
|
45798
|
+
hasFeedback && !isPlayingBack && !isSuccess && attempts > 0 && /* @__PURE__ */ jsx(Box, { className: "p-3 rounded-container bg-warning/10 border border-warning/30 text-center", children: /* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-foreground", children: t(encourageKey) }) }),
|
|
45799
|
+
isSuccess && /* @__PURE__ */ jsx(Box, { className: "p-4 rounded-container bg-success/20 border border-success text-center", children: /* @__PURE__ */ jsx(Typography, { variant: "h5", className: "text-success", children: str(resolved.successMessage) || t("sequencer.levelComplete") }) }),
|
|
45789
45800
|
/* @__PURE__ */ jsxs(HStack, { gap: "sm", children: [
|
|
45790
45801
|
/* @__PURE__ */ jsx(
|
|
45791
45802
|
Button,
|
|
@@ -46946,6 +46957,9 @@ function StateArchitectBoard({
|
|
|
46946
46957
|
stepDurationMs = 600,
|
|
46947
46958
|
testEvent,
|
|
46948
46959
|
completeEvent,
|
|
46960
|
+
addTransitionEvent,
|
|
46961
|
+
removeTransitionEvent,
|
|
46962
|
+
playAgainEvent,
|
|
46949
46963
|
className
|
|
46950
46964
|
}) {
|
|
46951
46965
|
const { emit } = useEventBus();
|
|
@@ -46958,14 +46972,16 @@ function StateArchitectBoard({
|
|
|
46958
46972
|
const testCases = Array.isArray(resolved?.testCases) ? resolved.testCases : [];
|
|
46959
46973
|
const entityTransitions = Array.isArray(resolved?.transitions) ? resolved.transitions : [];
|
|
46960
46974
|
const entityVariables = rows(resolved?.variables);
|
|
46961
|
-
const
|
|
46975
|
+
const transitions = entityTransitions;
|
|
46976
|
+
const attempts = typeof resolved?.attempts === "number" ? resolved.attempts : 0;
|
|
46977
|
+
const entityResult = str(resolved?.result) || "none";
|
|
46978
|
+
const isSuccess = entityResult === "win";
|
|
46979
|
+
const [isTesting, setIsTesting] = useState(false);
|
|
46962
46980
|
const [headerError, setHeaderError] = useState(false);
|
|
46963
|
-
const [playState, setPlayState] = useState("editing");
|
|
46964
46981
|
const [currentState, setCurrentState] = useState(initialState);
|
|
46965
46982
|
const [selectedState, setSelectedState] = useState(null);
|
|
46966
46983
|
const [testResults, setTestResults] = useState([]);
|
|
46967
46984
|
const [variables, setVariables] = useState(() => [...entityVariables]);
|
|
46968
|
-
const [attempts, setAttempts] = useState(0);
|
|
46969
46985
|
const timerRef = useRef(null);
|
|
46970
46986
|
const [addingFrom, setAddingFrom] = useState(null);
|
|
46971
46987
|
useEffect(() => () => {
|
|
@@ -46975,7 +46991,7 @@ function StateArchitectBoard({
|
|
|
46975
46991
|
const GRAPH_H = 400;
|
|
46976
46992
|
const positions = useMemo(() => layoutStates(entityStates, GRAPH_W, GRAPH_H), [entityStates]);
|
|
46977
46993
|
const handleStateClick = useCallback((state) => {
|
|
46978
|
-
if (
|
|
46994
|
+
if (isTesting) return;
|
|
46979
46995
|
if (addingFrom) {
|
|
46980
46996
|
if (addingFrom !== state) {
|
|
46981
46997
|
const event = availableEvents[0] || "EVENT";
|
|
@@ -46985,20 +47001,20 @@ function StateArchitectBoard({
|
|
|
46985
47001
|
to: state,
|
|
46986
47002
|
event
|
|
46987
47003
|
};
|
|
46988
|
-
|
|
47004
|
+
if (addTransitionEvent) emit(`UI:${addTransitionEvent}`, { id: newTrans.id, from: newTrans.from, to: newTrans.to, event: newTrans.event });
|
|
46989
47005
|
}
|
|
46990
47006
|
setAddingFrom(null);
|
|
46991
47007
|
} else {
|
|
46992
47008
|
setSelectedState(state);
|
|
46993
47009
|
}
|
|
46994
|
-
}, [
|
|
47010
|
+
}, [isTesting, addingFrom, availableEvents, addTransitionEvent, emit]);
|
|
46995
47011
|
const handleStartAddTransition = useCallback(() => {
|
|
46996
47012
|
if (!selectedState) return;
|
|
46997
47013
|
setAddingFrom(selectedState);
|
|
46998
47014
|
}, [selectedState]);
|
|
46999
47015
|
const handleRemoveTransition = useCallback((transId) => {
|
|
47000
|
-
|
|
47001
|
-
}, []);
|
|
47016
|
+
if (removeTransitionEvent) emit(`UI:${removeTransitionEvent}`, { id: transId });
|
|
47017
|
+
}, [removeTransitionEvent, emit]);
|
|
47002
47018
|
const machine = useMemo(() => ({
|
|
47003
47019
|
name: entityName,
|
|
47004
47020
|
description: str(resolved?.description),
|
|
@@ -47012,16 +47028,16 @@ function StateArchitectBoard({
|
|
|
47012
47028
|
}))
|
|
47013
47029
|
}), [entityName, resolved, entityStates, currentState, transitions]);
|
|
47014
47030
|
const handleTest = useCallback(() => {
|
|
47015
|
-
if (
|
|
47031
|
+
if (isTesting) return;
|
|
47016
47032
|
if (testEvent) emit(`UI:${testEvent}`, {});
|
|
47017
|
-
|
|
47033
|
+
setIsTesting(true);
|
|
47018
47034
|
setTestResults([]);
|
|
47019
47035
|
const results = [];
|
|
47020
47036
|
let testIdx = 0;
|
|
47021
47037
|
const runNextTest = () => {
|
|
47022
47038
|
if (testIdx >= testCases.length) {
|
|
47023
47039
|
const allPassed = results.every((r) => r.passed);
|
|
47024
|
-
|
|
47040
|
+
setIsTesting(false);
|
|
47025
47041
|
setTestResults(results);
|
|
47026
47042
|
if (allPassed && completeEvent) {
|
|
47027
47043
|
emit(`UI:${completeEvent}`, {
|
|
@@ -47029,9 +47045,6 @@ function StateArchitectBoard({
|
|
|
47029
47045
|
passedTests: results.filter((r) => r.passed).length
|
|
47030
47046
|
});
|
|
47031
47047
|
}
|
|
47032
|
-
if (!allPassed) {
|
|
47033
|
-
setAttempts((prev) => prev + 1);
|
|
47034
|
-
}
|
|
47035
47048
|
return;
|
|
47036
47049
|
}
|
|
47037
47050
|
const testCase = testCases[testIdx];
|
|
@@ -47054,24 +47067,23 @@ function StateArchitectBoard({
|
|
|
47054
47067
|
timerRef.current = setTimeout(runNextTest, stepDurationMs);
|
|
47055
47068
|
};
|
|
47056
47069
|
timerRef.current = setTimeout(runNextTest, stepDurationMs);
|
|
47057
|
-
}, [
|
|
47070
|
+
}, [isTesting, transitions, testCases, initialState, stepDurationMs, testEvent, completeEvent, emit]);
|
|
47058
47071
|
const handleTryAgain = useCallback(() => {
|
|
47059
47072
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
47060
|
-
|
|
47073
|
+
setIsTesting(false);
|
|
47061
47074
|
setCurrentState(initialState);
|
|
47062
47075
|
setTestResults([]);
|
|
47063
47076
|
}, [initialState]);
|
|
47064
47077
|
const handleReset = useCallback(() => {
|
|
47065
47078
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
47066
|
-
|
|
47067
|
-
setPlayState("editing");
|
|
47079
|
+
setIsTesting(false);
|
|
47068
47080
|
setCurrentState(initialState);
|
|
47069
47081
|
setTestResults([]);
|
|
47070
47082
|
setVariables([...entityVariables]);
|
|
47071
47083
|
setSelectedState(null);
|
|
47072
47084
|
setAddingFrom(null);
|
|
47073
|
-
|
|
47074
|
-
}, [
|
|
47085
|
+
if (playAgainEvent) emit(`UI:${playAgainEvent}`, {});
|
|
47086
|
+
}, [initialState, entityVariables, playAgainEvent, emit]);
|
|
47075
47087
|
const codeData = useMemo(() => ({
|
|
47076
47088
|
name: entityName,
|
|
47077
47089
|
states: entityStates,
|
|
@@ -47167,7 +47179,7 @@ function StateArchitectBoard({
|
|
|
47167
47179
|
]
|
|
47168
47180
|
}
|
|
47169
47181
|
),
|
|
47170
|
-
|
|
47182
|
+
!isTesting && /* @__PURE__ */ jsx(HStack, { gap: "sm", children: /* @__PURE__ */ jsx(
|
|
47171
47183
|
Button,
|
|
47172
47184
|
{
|
|
47173
47185
|
variant: "ghost",
|
|
@@ -47189,7 +47201,7 @@ function StateArchitectBoard({
|
|
|
47189
47201
|
t2.guardHint,
|
|
47190
47202
|
")"
|
|
47191
47203
|
] }),
|
|
47192
|
-
|
|
47204
|
+
!isTesting && /* @__PURE__ */ jsx(
|
|
47193
47205
|
Button,
|
|
47194
47206
|
{
|
|
47195
47207
|
variant: "ghost",
|
|
@@ -47221,21 +47233,21 @@ function StateArchitectBoard({
|
|
|
47221
47233
|
resolved.showCodeView !== false && /* @__PURE__ */ jsx(StateJsonView, { data: codeData, label: "View Code" })
|
|
47222
47234
|
] })
|
|
47223
47235
|
] }),
|
|
47224
|
-
|
|
47225
|
-
|
|
47236
|
+
isSuccess && /* @__PURE__ */ jsx(Box, { className: "p-4 rounded-container bg-success/20 border border-success text-center", children: /* @__PURE__ */ jsx(Typography, { variant: "h5", className: "text-success", children: str(resolved.successMessage) || t("stateArchitect.allPassed") }) }),
|
|
47237
|
+
!isTesting && !isSuccess && testResults.some((r) => !r.passed) && /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
|
|
47226
47238
|
/* @__PURE__ */ jsx(Box, { className: "p-4 rounded-container bg-warning/10 border border-warning/30 text-center", children: /* @__PURE__ */ jsx(Typography, { variant: "body1", className: "text-foreground font-medium", children: t(ENCOURAGEMENT_KEYS3[Math.min(attempts - 1, ENCOURAGEMENT_KEYS3.length - 1)] ?? ENCOURAGEMENT_KEYS3[0]) }) }),
|
|
47227
|
-
attempts >=
|
|
47239
|
+
!isSuccess && attempts >= 2 && Boolean(str(resolved?.hint)) && /* @__PURE__ */ jsx(Box, { className: "p-3 rounded-container bg-accent/10 border border-accent/30", children: /* @__PURE__ */ jsxs(HStack, { className: "items-start", gap: "xs", children: [
|
|
47228
47240
|
/* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-accent font-bold shrink-0", children: "\u{1F4A1} " + t("game.hint") + ":" }),
|
|
47229
47241
|
/* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-foreground", children: hint })
|
|
47230
47242
|
] }) })
|
|
47231
47243
|
] }),
|
|
47232
47244
|
/* @__PURE__ */ jsxs(HStack, { gap: "sm", children: [
|
|
47233
|
-
|
|
47245
|
+
!isTesting && !isSuccess && testResults.some((r) => !r.passed) ? /* @__PURE__ */ jsx(Button, { variant: "primary", onClick: handleTryAgain, children: "\u{1F504} " + t("puzzle.tryAgainButton") }) : /* @__PURE__ */ jsx(
|
|
47234
47246
|
Button,
|
|
47235
47247
|
{
|
|
47236
47248
|
variant: "primary",
|
|
47237
47249
|
onClick: handleTest,
|
|
47238
|
-
disabled:
|
|
47250
|
+
disabled: isTesting,
|
|
47239
47251
|
children: "\u25B6 " + t("game.runTests")
|
|
47240
47252
|
}
|
|
47241
47253
|
),
|
|
@@ -47315,6 +47327,7 @@ function formatDuration(seconds) {
|
|
|
47315
47327
|
return `${Math.round(seconds)}s`;
|
|
47316
47328
|
}
|
|
47317
47329
|
function StatusEffect({
|
|
47330
|
+
assetUrl = DEFAULT_ASSET_URL6,
|
|
47318
47331
|
icon = "shield",
|
|
47319
47332
|
label = "Shield",
|
|
47320
47333
|
duration = 30,
|
|
@@ -47335,7 +47348,17 @@ function StatusEffect({
|
|
|
47335
47348
|
),
|
|
47336
47349
|
title: label,
|
|
47337
47350
|
children: [
|
|
47338
|
-
/* @__PURE__ */ jsx("span", { className: cn("flex items-center justify-center", sizes.icon), children:
|
|
47351
|
+
/* @__PURE__ */ jsx("span", { className: cn("flex items-center justify-center", sizes.icon), children: assetUrl ? /* @__PURE__ */ jsx(
|
|
47352
|
+
"img",
|
|
47353
|
+
{
|
|
47354
|
+
src: assetUrl,
|
|
47355
|
+
alt: label,
|
|
47356
|
+
width: sizes.img,
|
|
47357
|
+
height: sizes.img,
|
|
47358
|
+
style: { imageRendering: "pixelated", objectFit: "contain" },
|
|
47359
|
+
className: "flex-shrink-0"
|
|
47360
|
+
}
|
|
47361
|
+
) : typeof icon === "string" ? /* @__PURE__ */ jsx(Icon, { name: icon, size: "sm" }) : /* @__PURE__ */ jsx(Icon, { icon, size: "sm" }) }),
|
|
47339
47362
|
duration !== void 0 && /* @__PURE__ */ jsx(
|
|
47340
47363
|
"span",
|
|
47341
47364
|
{
|
|
@@ -47362,15 +47385,16 @@ function StatusEffect({
|
|
|
47362
47385
|
label && /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground mt-0.5 text-center whitespace-nowrap", children: label })
|
|
47363
47386
|
] });
|
|
47364
47387
|
}
|
|
47365
|
-
var sizeMap16, variantStyles9;
|
|
47388
|
+
var DEFAULT_ASSET_URL6, sizeMap16, variantStyles9;
|
|
47366
47389
|
var init_StatusEffect = __esm({
|
|
47367
47390
|
"components/game/atoms/StatusEffect.tsx"() {
|
|
47368
47391
|
init_cn();
|
|
47369
47392
|
init_Icon();
|
|
47393
|
+
DEFAULT_ASSET_URL6 = "https://almadar-kflow-assets.web.app/shared/effects/particles/flame_01.png";
|
|
47370
47394
|
sizeMap16 = {
|
|
47371
|
-
sm: { container: "w-8 h-8", icon: "text-sm", badge: "text-xs -top-1 -right-1 w-4 h-4", timer: "text-[9px]" },
|
|
47372
|
-
md: { container: "w-10 h-10", icon: "text-base", badge: "text-xs -top-1 -right-1 w-5 h-5", timer: "text-xs" },
|
|
47373
|
-
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" }
|
|
47395
|
+
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 },
|
|
47396
|
+
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 },
|
|
47397
|
+
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 }
|
|
47374
47398
|
};
|
|
47375
47399
|
variantStyles9 = {
|
|
47376
47400
|
buff: "border-success bg-success/20",
|
|
@@ -48061,17 +48085,12 @@ var init_UncontrolledBattleBoard = __esm({
|
|
|
48061
48085
|
}
|
|
48062
48086
|
});
|
|
48063
48087
|
function heroPosition(h) {
|
|
48088
|
+
if ("position" in h && h.position != null) return h.position;
|
|
48064
48089
|
return vec2(h.position);
|
|
48065
48090
|
}
|
|
48066
|
-
function heroOwner(h) {
|
|
48067
|
-
return str(h.owner);
|
|
48068
|
-
}
|
|
48069
48091
|
function heroMovement(h) {
|
|
48070
48092
|
return num(h.movement);
|
|
48071
48093
|
}
|
|
48072
|
-
function hexPassable(h) {
|
|
48073
|
-
return h.passable !== false;
|
|
48074
|
-
}
|
|
48075
48094
|
function defaultIsInRange(from, to, range) {
|
|
48076
48095
|
return Math.abs(from.x - to.x) + Math.abs(from.y - to.y) <= range;
|
|
48077
48096
|
}
|
|
@@ -48107,38 +48126,41 @@ function WorldMapBoard({
|
|
|
48107
48126
|
}) {
|
|
48108
48127
|
const eventBus = useEventBus();
|
|
48109
48128
|
const resolved = boardEntity(entity);
|
|
48110
|
-
const
|
|
48111
|
-
const
|
|
48129
|
+
const entityUnits = rows(resolved?.units);
|
|
48130
|
+
const entityTiles = rows(resolved?.tiles);
|
|
48112
48131
|
const features = propFeatures ?? (Array.isArray(resolved?.features) ? resolved.features : []);
|
|
48113
48132
|
const selectedHeroId = resolved?.selectedHeroId ?? null;
|
|
48114
48133
|
const assetManifest = propAssetManifest ?? resolved?.assetManifest;
|
|
48115
48134
|
const backgroundImage = resolved?.backgroundImage;
|
|
48116
48135
|
const [hoveredTile, setHoveredTile] = useState(null);
|
|
48117
|
-
const selectedHero = useMemo(
|
|
48118
|
-
() => heroes.find((h) => str(h.id) === selectedHeroId) ?? null,
|
|
48119
|
-
[heroes, selectedHeroId]
|
|
48120
|
-
);
|
|
48121
48136
|
const derivedTiles = useMemo(
|
|
48122
|
-
() =>
|
|
48123
|
-
x: num(
|
|
48124
|
-
y: num(
|
|
48125
|
-
terrain: str(
|
|
48126
|
-
terrainSprite:
|
|
48137
|
+
() => entityTiles.map((t) => ({
|
|
48138
|
+
x: num(t.x),
|
|
48139
|
+
y: num(t.y),
|
|
48140
|
+
terrain: str(t.terrain),
|
|
48141
|
+
terrainSprite: t.terrainSprite == null ? void 0 : str(t.terrainSprite),
|
|
48142
|
+
passable: t.passable !== false
|
|
48127
48143
|
})),
|
|
48128
|
-
[
|
|
48144
|
+
[entityTiles]
|
|
48129
48145
|
);
|
|
48130
48146
|
const tiles = propTiles ?? derivedTiles;
|
|
48131
48147
|
const baseUnits = useMemo(
|
|
48132
|
-
() => propUnits ??
|
|
48133
|
-
id: str(
|
|
48134
|
-
position: heroPosition(
|
|
48135
|
-
name: str(
|
|
48136
|
-
|
|
48137
|
-
|
|
48138
|
-
|
|
48139
|
-
|
|
48148
|
+
() => propUnits ?? entityUnits.map((u) => ({
|
|
48149
|
+
id: str(u.id),
|
|
48150
|
+
position: heroPosition(u),
|
|
48151
|
+
name: str(u.name),
|
|
48152
|
+
// lolo uses `team` field (not `owner`)
|
|
48153
|
+
team: str(u.team) === "enemy" ? "enemy" : "player",
|
|
48154
|
+
health: num(u.health) || 100,
|
|
48155
|
+
maxHealth: num(u.maxHealth) || 100,
|
|
48156
|
+
sprite: u.sprite == null ? void 0 : str(u.sprite)
|
|
48140
48157
|
})),
|
|
48141
|
-
[
|
|
48158
|
+
[entityUnits, propUnits]
|
|
48159
|
+
);
|
|
48160
|
+
const gameUnits = baseUnits;
|
|
48161
|
+
const selectedHero = useMemo(
|
|
48162
|
+
() => gameUnits.find((u) => u.id === selectedHeroId) ?? null,
|
|
48163
|
+
[gameUnits, selectedHeroId]
|
|
48142
48164
|
);
|
|
48143
48165
|
const MOVE_SPEED_MS_PER_TILE = 300;
|
|
48144
48166
|
const movementAnimRef = useRef(null);
|
|
@@ -48184,51 +48206,50 @@ function WorldMapBoard({
|
|
|
48184
48206
|
const validMoves = useMemo(() => {
|
|
48185
48207
|
if (!selectedHero || heroMovement(selectedHero) <= 0) return [];
|
|
48186
48208
|
const sp = heroPosition(selectedHero);
|
|
48187
|
-
const
|
|
48209
|
+
const sTeam = str(selectedHero.team);
|
|
48188
48210
|
const range = heroMovement(selectedHero);
|
|
48189
48211
|
const moves = [];
|
|
48190
|
-
|
|
48191
|
-
const
|
|
48192
|
-
const
|
|
48193
|
-
if (
|
|
48194
|
-
if (
|
|
48195
|
-
if (!isInRange(sp, { x:
|
|
48196
|
-
if (
|
|
48197
|
-
const
|
|
48198
|
-
return
|
|
48212
|
+
tiles.forEach((t) => {
|
|
48213
|
+
const tx = t.x;
|
|
48214
|
+
const ty = t.y;
|
|
48215
|
+
if (t.passable === false) return;
|
|
48216
|
+
if (tx === sp.x && ty === sp.y) return;
|
|
48217
|
+
if (!isInRange(sp, { x: tx, y: ty }, range)) return;
|
|
48218
|
+
if (gameUnits.some((u) => {
|
|
48219
|
+
const up = u.position ?? { x: u.x ?? -1, y: u.y ?? -1 };
|
|
48220
|
+
return up.x === tx && up.y === ty && str(u.team) === sTeam;
|
|
48199
48221
|
})) return;
|
|
48200
|
-
moves.push({ x:
|
|
48222
|
+
moves.push({ x: tx, y: ty });
|
|
48201
48223
|
});
|
|
48202
48224
|
return moves;
|
|
48203
|
-
}, [selectedHero,
|
|
48225
|
+
}, [selectedHero, tiles, gameUnits, isInRange]);
|
|
48204
48226
|
const attackTargets = useMemo(() => {
|
|
48205
48227
|
if (!selectedHero || heroMovement(selectedHero) <= 0) return [];
|
|
48206
48228
|
const sp = heroPosition(selectedHero);
|
|
48207
|
-
const
|
|
48229
|
+
const sTeam = str(selectedHero.team);
|
|
48208
48230
|
const range = heroMovement(selectedHero);
|
|
48209
|
-
return
|
|
48210
|
-
}, [selectedHero,
|
|
48211
|
-
const maxY = Math.max(...
|
|
48231
|
+
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 });
|
|
48232
|
+
}, [selectedHero, gameUnits, isInRange]);
|
|
48233
|
+
const maxY = Math.max(...tiles.map((t) => t.y), 0);
|
|
48212
48234
|
const baseOffsetX = (maxY + 1) * (TILE_WIDTH * scale / 2);
|
|
48213
48235
|
const tileToScreen = useCallback(
|
|
48214
48236
|
(tx, ty) => isoToScreen(tx, ty, scale, baseOffsetX),
|
|
48215
48237
|
[scale, baseOffsetX]
|
|
48216
48238
|
);
|
|
48217
48239
|
const hoveredHex = useMemo(
|
|
48218
|
-
() => hoveredTile ?
|
|
48219
|
-
[hoveredTile,
|
|
48240
|
+
() => hoveredTile ? tiles.find((t) => t.x === hoveredTile.x && t.y === hoveredTile.y) ?? null : null,
|
|
48241
|
+
[hoveredTile, tiles]
|
|
48220
48242
|
);
|
|
48221
48243
|
const hoveredHero = useMemo(
|
|
48222
|
-
() => hoveredTile ?
|
|
48223
|
-
const
|
|
48224
|
-
return
|
|
48244
|
+
() => hoveredTile ? gameUnits.find((u) => {
|
|
48245
|
+
const up = u.position ?? { x: u.x ?? -1, y: u.y ?? -1 };
|
|
48246
|
+
return up.x === hoveredTile.x && up.y === hoveredTile.y;
|
|
48225
48247
|
}) ?? null : null,
|
|
48226
|
-
[hoveredTile,
|
|
48248
|
+
[hoveredTile, gameUnits]
|
|
48227
48249
|
);
|
|
48228
48250
|
const handleTileClick = useCallback((x, y) => {
|
|
48229
48251
|
if (movementAnimRef.current) return;
|
|
48230
|
-
const
|
|
48231
|
-
if (!hex) return;
|
|
48252
|
+
const tile = tiles.find((t) => t.x === x && t.y === y);
|
|
48232
48253
|
if (tileClickEvent) {
|
|
48233
48254
|
eventBus.emit(`UI:${tileClickEvent}`, { x, y });
|
|
48234
48255
|
}
|
|
@@ -48239,38 +48260,39 @@ function WorldMapBoard({
|
|
|
48239
48260
|
if (heroMoveEvent) {
|
|
48240
48261
|
eventBus.emit(`UI:${heroMoveEvent}`, { heroId, toX: x, toY: y });
|
|
48241
48262
|
}
|
|
48242
|
-
const feature = str(
|
|
48263
|
+
const feature = tile ? str(tile.feature) : "";
|
|
48243
48264
|
if (feature && feature !== "none") {
|
|
48244
|
-
|
|
48265
|
+
const tileRow = tile;
|
|
48266
|
+
onFeatureEnter?.(heroId, tileRow);
|
|
48245
48267
|
if (featureEnterEvent) {
|
|
48246
|
-
eventBus.emit(`UI:${featureEnterEvent}`, { heroId, feature, hex });
|
|
48268
|
+
eventBus.emit(`UI:${featureEnterEvent}`, { heroId, feature, hex: tileRow });
|
|
48247
48269
|
}
|
|
48248
48270
|
}
|
|
48249
48271
|
});
|
|
48250
48272
|
return;
|
|
48251
48273
|
}
|
|
48252
|
-
const enemy =
|
|
48253
|
-
const
|
|
48254
|
-
return
|
|
48274
|
+
const enemy = gameUnits.find((u) => {
|
|
48275
|
+
const up = u.position ?? { x: u.x ?? -1, y: u.y ?? -1 };
|
|
48276
|
+
return up.x === x && up.y === y && str(u.team) === "enemy";
|
|
48255
48277
|
});
|
|
48256
48278
|
if (selectedHero && enemy && attackTargets.some((t) => t.x === x && t.y === y)) {
|
|
48257
48279
|
const attackerId = str(selectedHero.id);
|
|
48258
|
-
const defenderId =
|
|
48280
|
+
const defenderId = enemy.id;
|
|
48259
48281
|
onBattleEncounter?.(attackerId, defenderId);
|
|
48260
48282
|
if (battleEncounterEvent) {
|
|
48261
48283
|
eventBus.emit(`UI:${battleEncounterEvent}`, { attackerId, defenderId });
|
|
48262
48284
|
}
|
|
48263
48285
|
}
|
|
48264
|
-
}, [
|
|
48286
|
+
}, [tiles, gameUnits, selectedHero, validMoves, attackTargets, startMoveAnimation, onHeroMove, onFeatureEnter, onBattleEncounter, eventBus, tileClickEvent, heroMoveEvent, featureEnterEvent, battleEncounterEvent]);
|
|
48265
48287
|
const handleUnitClick = useCallback((unitId) => {
|
|
48266
|
-
const
|
|
48267
|
-
if (
|
|
48288
|
+
const unit = gameUnits.find((u) => u.id === unitId);
|
|
48289
|
+
if (unit && (str(unit.team) === "player" || allowMoveAllHeroes)) {
|
|
48268
48290
|
onHeroSelect?.(unitId);
|
|
48269
48291
|
if (heroSelectEvent) {
|
|
48270
48292
|
eventBus.emit(`UI:${heroSelectEvent}`, { heroId: unitId });
|
|
48271
48293
|
}
|
|
48272
48294
|
}
|
|
48273
|
-
}, [
|
|
48295
|
+
}, [gameUnits, onHeroSelect, allowMoveAllHeroes, eventBus, heroSelectEvent]);
|
|
48274
48296
|
const selectHero = useCallback((id) => {
|
|
48275
48297
|
onHeroSelect?.(id);
|
|
48276
48298
|
if (heroSelectEvent) {
|