@almadar/ui 5.55.0 → 5.57.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.
@@ -11097,6 +11097,8 @@ function IsometricCanvas({
11097
11097
  showMinimap = true,
11098
11098
  enableCamera = true,
11099
11099
  unitScale = 1,
11100
+ spriteHeightRatio = 1.5,
11101
+ spriteMaxWidthRatio = 0.6,
11100
11102
  // Asset resolution
11101
11103
  getTerrainSprite,
11102
11104
  getFeatureSprite,
@@ -11487,8 +11489,8 @@ function IsometricCanvas({
11487
11489
  const breatheOffset = 0.8 * scale * (1 + Math.sin(animTime * 2e-3 + (unit.position.x * 3.7 + unit.position.y * 5.3)));
11488
11490
  const unitSpriteUrl = resolveUnitSpriteUrl(unit);
11489
11491
  const img = unitSpriteUrl ? getImage(unitSpriteUrl) : null;
11490
- const unitDrawH = scaledFloorHeight * 1.5 * unitScale;
11491
- const maxUnitW = scaledTileWidth * 0.6 * unitScale;
11492
+ const unitDrawH = scaledFloorHeight * spriteHeightRatio * unitScale;
11493
+ const maxUnitW = scaledTileWidth * spriteMaxWidthRatio * unitScale;
11492
11494
  const ar = img ? img.naturalWidth / img.naturalHeight : 0.5;
11493
11495
  let drawH = unitDrawH;
11494
11496
  let drawW = unitDrawH * ar;
@@ -11864,14 +11866,32 @@ var init_boardEntity = __esm({
11864
11866
  "components/game/organisms/boardEntity.ts"() {
11865
11867
  }
11866
11868
  });
11869
+ function buildDefaultBattleTiles() {
11870
+ const tiles = [];
11871
+ for (let y = 0; y < BATTLE_GRID_H; y++) {
11872
+ for (let x = 0; x < BATTLE_GRID_W; x++) {
11873
+ const variant = (x * 3 + y * 7 + (x ^ y)) % BATTLE_TERRAIN_SPRITES.length;
11874
+ tiles.push({
11875
+ x,
11876
+ y,
11877
+ terrain: ["grass", "dirt", "planks", "stone", "stone"][variant],
11878
+ terrainSprite: BATTLE_TERRAIN_SPRITES[variant],
11879
+ passable: true
11880
+ });
11881
+ }
11882
+ }
11883
+ return tiles;
11884
+ }
11867
11885
  function BattleBoard({
11868
11886
  entity,
11869
11887
  tiles: propTiles,
11870
11888
  units: propUnits,
11871
11889
  features: propFeatures,
11872
11890
  assetManifest: propAssetManifest,
11873
- scale = 0.45,
11891
+ scale = 0.25,
11874
11892
  unitScale = 1,
11893
+ spriteHeightRatio = 1.5,
11894
+ spriteMaxWidthRatio = 0.6,
11875
11895
  header,
11876
11896
  sidebar,
11877
11897
  actions,
@@ -11895,10 +11915,11 @@ function BattleBoard({
11895
11915
  className
11896
11916
  }) {
11897
11917
  const board = boardEntity(entity) ?? {};
11898
- const tiles = propTiles ?? (Array.isArray(board.tiles) ? board.tiles : []);
11918
+ const rawTiles = propTiles ?? (Array.isArray(board.tiles) ? board.tiles : []);
11919
+ const tiles = rawTiles.length === 0 ? DEFAULT_BATTLE_TILES : rawTiles;
11899
11920
  const features = propFeatures ?? (Array.isArray(board.features) ? board.features : []);
11900
- const boardWidth = num(board.gridWidth ?? board.boardWidth, 8);
11901
- const boardHeight = num(board.gridHeight ?? board.boardHeight, 6);
11921
+ const boardWidth = num(board.gridWidth ?? board.boardWidth, BATTLE_GRID_W);
11922
+ const boardHeight = num(board.gridHeight ?? board.boardHeight, BATTLE_GRID_H);
11902
11923
  const assetManifest = propAssetManifest ?? board.assetManifest;
11903
11924
  const backgroundImage = board.backgroundImage;
11904
11925
  const units = rows(board.units);
@@ -12162,7 +12183,9 @@ function BattleBoard({
12162
12183
  hasActiveEffects: hasActiveEffects2,
12163
12184
  effectSpriteUrls,
12164
12185
  resolveUnitFrame,
12165
- unitScale
12186
+ unitScale,
12187
+ spriteHeightRatio,
12188
+ spriteMaxWidthRatio
12166
12189
  }
12167
12190
  ),
12168
12191
  overlay && overlay(ctx)
@@ -12218,6 +12241,7 @@ function BattleBoard({
12218
12241
  ] }) }))
12219
12242
  ] });
12220
12243
  }
12244
+ var BATTLE_CDN, BATTLE_GRID_W, BATTLE_GRID_H, BATTLE_TERRAIN_SPRITES, DEFAULT_BATTLE_TILES;
12221
12245
  var init_BattleBoard = __esm({
12222
12246
  "components/game/organisms/BattleBoard.tsx"() {
12223
12247
  "use client";
@@ -12230,6 +12254,17 @@ var init_BattleBoard = __esm({
12230
12254
  init_IsometricCanvas();
12231
12255
  init_boardEntity();
12232
12256
  init_isometric();
12257
+ BATTLE_CDN = "https://almadar-kflow-assets.web.app/shared";
12258
+ BATTLE_GRID_W = 16;
12259
+ BATTLE_GRID_H = 16;
12260
+ BATTLE_TERRAIN_SPRITES = [
12261
+ `${BATTLE_CDN}/isometric-dungeon/Isometric/dirt_E.png`,
12262
+ `${BATTLE_CDN}/isometric-dungeon/Isometric/dirtTiles_E.png`,
12263
+ `${BATTLE_CDN}/isometric-dungeon/Isometric/planks_E.png`,
12264
+ `${BATTLE_CDN}/isometric-dungeon/Isometric/stoneTile_E.png`,
12265
+ `${BATTLE_CDN}/isometric-dungeon/Isometric/stoneInset_E.png`
12266
+ ];
12267
+ DEFAULT_BATTLE_TILES = buildDefaultBattleTiles();
12233
12268
  BattleBoard.displayName = "BattleBoard";
12234
12269
  }
12235
12270
  });
@@ -12237,7 +12272,7 @@ function BattleTemplate({
12237
12272
  entity,
12238
12273
  scale = 0.45,
12239
12274
  unitScale = 1,
12240
- tiles = DEFAULT_BATTLE_TILES,
12275
+ tiles = DEFAULT_BATTLE_TILES2,
12241
12276
  units = DEFAULT_BATTLE_UNITS,
12242
12277
  features = DEFAULT_BATTLE_FEATURES,
12243
12278
  assetManifest = DEFAULT_BATTLE_MANIFEST,
@@ -12266,12 +12301,12 @@ function BattleTemplate({
12266
12301
  }
12267
12302
  );
12268
12303
  }
12269
- var CDN, DEFAULT_BATTLE_TILES, DEFAULT_BATTLE_UNITS, DEFAULT_BATTLE_FEATURES, DEFAULT_BATTLE_MANIFEST;
12304
+ var CDN, DEFAULT_BATTLE_TILES2, DEFAULT_BATTLE_UNITS, DEFAULT_BATTLE_FEATURES, DEFAULT_BATTLE_MANIFEST;
12270
12305
  var init_BattleTemplate = __esm({
12271
12306
  "components/game/templates/BattleTemplate.tsx"() {
12272
12307
  init_BattleBoard();
12273
12308
  CDN = "https://almadar-kflow-assets.web.app/shared";
12274
- DEFAULT_BATTLE_TILES = [
12309
+ DEFAULT_BATTLE_TILES2 = [
12275
12310
  { x: 0, y: 0, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
12276
12311
  { x: 1, y: 0, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
12277
12312
  { x: 2, y: 0, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
@@ -42133,6 +42168,7 @@ var init_GameCanvas3D2 = __esm({
42133
42168
  attackTargets = [],
42134
42169
  selectedTileIds = [],
42135
42170
  selectedUnitId = null,
42171
+ unitScale = 1,
42136
42172
  children
42137
42173
  }, ref) => {
42138
42174
  const containerRef = useRef(null);
@@ -42349,12 +42385,18 @@ var init_GameCanvas3D2 = __esm({
42349
42385
  },
42350
42386
  [selectedTileIds, hoveredTile, validMoves, attackTargets, handleTileClick, handleTileHover]
42351
42387
  );
42388
+ const UNIT_BASE_MODEL_SCALE = 0.5;
42389
+ const UNIT_BASE_BILLBOARD_HEIGHT = 1.2;
42390
+ const UNIT_BASE_PRIMITIVE_RADIUS = 0.3;
42352
42391
  const DefaultUnitRenderer = useCallback(
42353
42392
  ({ unit, position }) => {
42354
42393
  const isSelected = selectedUnitId === unit.id;
42355
42394
  const color = unit.faction === "player" ? 4491519 : unit.faction === "enemy" ? 16729156 : 16777028;
42356
42395
  const hasAtlas = unitAtlasUrl(unit) !== null;
42357
42396
  const initialFrame = hasAtlas ? resolveUnitFrame(unit.id) : null;
42397
+ const modelScale = UNIT_BASE_MODEL_SCALE * unitScale;
42398
+ const billboardHeight = UNIT_BASE_BILLBOARD_HEIGHT * unitScale;
42399
+ const primitiveRadius = UNIT_BASE_PRIMITIVE_RADIUS * unitScale;
42358
42400
  return /* @__PURE__ */ jsxs(
42359
42401
  "group",
42360
42402
  {
@@ -42372,7 +42414,8 @@ var init_GameCanvas3D2 = __esm({
42372
42414
  UnitSpriteBillboard,
42373
42415
  {
42374
42416
  sheetUrl: initialFrame.sheetUrl,
42375
- resolveFrame: () => resolveUnitFrame(unit.id)
42417
+ resolveFrame: () => resolveUnitFrame(unit.id),
42418
+ height: billboardHeight
42376
42419
  }
42377
42420
  ) })
42378
42421
  ) : unit.modelUrl ? (
@@ -42381,22 +42424,22 @@ var init_GameCanvas3D2 = __esm({
42381
42424
  ModelLoader,
42382
42425
  {
42383
42426
  url: unit.modelUrl,
42384
- scale: 0.5,
42427
+ scale: modelScale,
42385
42428
  fallbackGeometry: "box",
42386
42429
  castShadow: true
42387
42430
  }
42388
42431
  )
42389
42432
  ) : /* @__PURE__ */ jsxs(Fragment, { children: [
42390
- /* @__PURE__ */ jsxs("mesh", { position: [0, 0.3, 0], children: [
42391
- /* @__PURE__ */ jsx("cylinderGeometry", { args: [0.3, 0.3, 0.1, 8] }),
42433
+ /* @__PURE__ */ jsxs("mesh", { position: [0, primitiveRadius, 0], children: [
42434
+ /* @__PURE__ */ jsx("cylinderGeometry", { args: [primitiveRadius, primitiveRadius, primitiveRadius * 0.33, 8] }),
42392
42435
  /* @__PURE__ */ jsx("meshStandardMaterial", { color })
42393
42436
  ] }),
42394
- /* @__PURE__ */ jsxs("mesh", { position: [0, 0.6, 0], children: [
42395
- /* @__PURE__ */ jsx("capsuleGeometry", { args: [0.2, 0.4, 4, 8] }),
42437
+ /* @__PURE__ */ jsxs("mesh", { position: [0, primitiveRadius * 2, 0], children: [
42438
+ /* @__PURE__ */ jsx("capsuleGeometry", { args: [primitiveRadius * 0.67, primitiveRadius * 1.33, 4, 8] }),
42396
42439
  /* @__PURE__ */ jsx("meshStandardMaterial", { color })
42397
42440
  ] }),
42398
- /* @__PURE__ */ jsxs("mesh", { position: [0, 0.9, 0], children: [
42399
- /* @__PURE__ */ jsx("sphereGeometry", { args: [0.12, 8, 8] }),
42441
+ /* @__PURE__ */ jsxs("mesh", { position: [0, primitiveRadius * 3, 0], children: [
42442
+ /* @__PURE__ */ jsx("sphereGeometry", { args: [primitiveRadius * 0.4, 8, 8] }),
42400
42443
  /* @__PURE__ */ jsx("meshStandardMaterial", { color })
42401
42444
  ] })
42402
42445
  ] }),
@@ -42429,7 +42472,7 @@ var init_GameCanvas3D2 = __esm({
42429
42472
  }
42430
42473
  );
42431
42474
  },
42432
- [selectedUnitId, handleUnitClick, resolveUnitFrame]
42475
+ [selectedUnitId, handleUnitClick, resolveUnitFrame, unitScale]
42433
42476
  );
42434
42477
  const DefaultFeatureRenderer = useCallback(
42435
42478
  ({
@@ -42572,33 +42615,35 @@ var init_GameCanvas3D2 = __esm({
42572
42615
  fadeStrength: 1
42573
42616
  }
42574
42617
  ),
42575
- tiles.map((tile, index) => {
42576
- const position = gridToWorld(
42577
- tile.x,
42578
- tile.z ?? tile.y ?? 0,
42579
- tile.elevation ?? 0
42580
- );
42581
- const Renderer = CustomTileRenderer || DefaultTileRenderer;
42582
- return /* @__PURE__ */ jsx(Renderer, { tile, position }, tile.id ?? `tile-${index}`);
42583
- }),
42584
- features.map((feature, index) => {
42585
- const position = gridToWorld(
42586
- feature.x,
42587
- feature.z ?? feature.y ?? 0,
42588
- (feature.elevation ?? 0) + 0.5
42589
- );
42590
- const Renderer = CustomFeatureRenderer || DefaultFeatureRenderer;
42591
- return /* @__PURE__ */ jsx(Renderer, { feature, position }, feature.id ?? `feature-${index}`);
42592
- }),
42593
- units.map((unit) => {
42594
- const position = gridToWorld(
42595
- unit.x ?? 0,
42596
- unit.z ?? unit.y ?? 0,
42597
- (unit.elevation ?? 0) + 0.5
42598
- );
42599
- const Renderer = CustomUnitRenderer || DefaultUnitRenderer;
42600
- return /* @__PURE__ */ jsx(Renderer, { unit, position }, unit.id);
42601
- }),
42618
+ /* @__PURE__ */ jsxs("group", { children: [
42619
+ tiles.map((tile, index) => {
42620
+ const position = gridToWorld(
42621
+ tile.x,
42622
+ tile.z ?? tile.y ?? 0,
42623
+ tile.elevation ?? 0
42624
+ );
42625
+ const Renderer = CustomTileRenderer || DefaultTileRenderer;
42626
+ return /* @__PURE__ */ jsx(Renderer, { tile, position }, tile.id ?? `tile-${index}`);
42627
+ }),
42628
+ features.map((feature, index) => {
42629
+ const position = gridToWorld(
42630
+ feature.x,
42631
+ feature.z ?? feature.y ?? 0,
42632
+ (feature.elevation ?? 0) + 0.5
42633
+ );
42634
+ const Renderer = CustomFeatureRenderer || DefaultFeatureRenderer;
42635
+ return /* @__PURE__ */ jsx(Renderer, { feature, position }, feature.id ?? `feature-${index}`);
42636
+ }),
42637
+ units.map((unit) => {
42638
+ const position = gridToWorld(
42639
+ unit.x ?? 0,
42640
+ unit.z ?? unit.y ?? 0,
42641
+ (unit.elevation ?? 0) + 0.5
42642
+ );
42643
+ const Renderer = CustomUnitRenderer || DefaultUnitRenderer;
42644
+ return /* @__PURE__ */ jsx(Renderer, { unit, position }, unit.id);
42645
+ })
42646
+ ] }),
42602
42647
  children,
42603
42648
  /* @__PURE__ */ jsx(
42604
42649
  OrbitControls,
@@ -42641,6 +42686,8 @@ function GameBoard3D({
42641
42686
  features = [],
42642
42687
  cameraMode = "perspective",
42643
42688
  backgroundColor = "#2a1a1a",
42689
+ unitScale = 1,
42690
+ scale = 0.45,
42644
42691
  tileClickEvent,
42645
42692
  unitClickEvent,
42646
42693
  attackEvent,
@@ -42741,6 +42788,8 @@ function GameBoard3D({
42741
42788
  selectedUnitId,
42742
42789
  validMoves,
42743
42790
  attackTargets,
42791
+ unitScale,
42792
+ scale,
42744
42793
  className: "game-board-3d__canvas w-full min-h-[85vh]"
42745
42794
  }
42746
42795
  ),
@@ -44709,6 +44758,35 @@ var init_PricingPageTemplate = __esm({
44709
44758
  PricingPageTemplate.displayName = "PricingPageTemplate";
44710
44759
  }
44711
44760
  });
44761
+ function dungeonTerrain(x, y, stairsX, stairsY) {
44762
+ const isBorder = x === 0 || y === 0 || x === DUNGEON_GRID_W - 1 || y === DUNGEON_GRID_H - 1;
44763
+ const isPillar = x % 4 === 0 && y % 4 === 0 && !isBorder;
44764
+ const isWall = isBorder || isPillar;
44765
+ if (x === stairsX && y === stairsY) {
44766
+ return { terrain: "stairs", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stairs_E.png` };
44767
+ }
44768
+ if (isWall) {
44769
+ return { terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` };
44770
+ }
44771
+ const variant = (x * 3 + y * 7) % 5;
44772
+ const sprites = [
44773
+ `${CDN4}/isometric-dungeon/Isometric/dirt_E.png`,
44774
+ `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png`,
44775
+ `${CDN4}/isometric-dungeon/Isometric/planks_E.png`,
44776
+ `${CDN4}/isometric-dungeon/Isometric/stoneTile_E.png`,
44777
+ `${CDN4}/isometric-dungeon/Isometric/dirt_E.png`
44778
+ ];
44779
+ return { terrain: "floor", passable: true, terrainSprite: sprites[variant] };
44780
+ }
44781
+ function buildDefaultDungeonTiles(stairsX, stairsY) {
44782
+ const tiles = [];
44783
+ for (let y = 0; y < DUNGEON_GRID_H; y++) {
44784
+ for (let x = 0; x < DUNGEON_GRID_W; x++) {
44785
+ tiles.push({ x, y, ...dungeonTerrain(x, y, stairsX, stairsY) });
44786
+ }
44787
+ }
44788
+ return tiles;
44789
+ }
44712
44790
  function RoguelikeBoard({
44713
44791
  entity,
44714
44792
  tiles: propTiles,
@@ -44724,15 +44802,19 @@ function RoguelikeBoard({
44724
44802
  stairsX: propStairsX,
44725
44803
  stairsY: propStairsY,
44726
44804
  assetManifest: propAssetManifest,
44727
- scale = 0.45,
44805
+ scale = 0.25,
44728
44806
  unitScale = 1,
44807
+ spriteHeightRatio = 1.5,
44808
+ spriteMaxWidthRatio = 0.6,
44729
44809
  moveEvent,
44730
44810
  playAgainEvent,
44731
44811
  gameEndEvent,
44732
44812
  className
44733
44813
  }) {
44734
44814
  const board = boardEntity(entity) ?? {};
44735
- const tiles = propTiles ?? (Array.isArray(board.tiles) ? board.tiles : DEFAULT_TILES2);
44815
+ const resolvedStairsX = propStairsX ?? num(board.stairsX, 14);
44816
+ const resolvedStairsY = propStairsY ?? num(board.stairsY, 14);
44817
+ const tiles = propTiles ?? (Array.isArray(board.tiles) && board.tiles.length >= DUNGEON_GRID_W * DUNGEON_GRID_H ? board.tiles : buildDefaultDungeonTiles(resolvedStairsX, resolvedStairsY));
44736
44818
  const enemies = propEnemies ?? (Array.isArray(board.enemies) ? board.enemies : DEFAULT_ENEMIES);
44737
44819
  const items = propItems ?? (Array.isArray(board.items) ? board.items : DEFAULT_ITEMS);
44738
44820
  const player = propPlayer ?? board.player ?? { x: 1, y: 1 };
@@ -44742,8 +44824,8 @@ function RoguelikeBoard({
44742
44824
  const depth = propDepth ?? num(board.depth, 1);
44743
44825
  const result = propResult ?? (str(board.result) || "none");
44744
44826
  const phase = propPhase ?? (str(board.phase) || "player_turn");
44745
- propStairsX ?? num(board.stairsX, 3);
44746
- propStairsY ?? num(board.stairsY, 3);
44827
+ propStairsX ?? num(board.stairsX, 14);
44828
+ propStairsY ?? num(board.stairsY, 14);
44747
44829
  const eventBus = useEventBus();
44748
44830
  const { t } = useTranslate();
44749
44831
  const [hoveredTile, setHoveredTile] = useState(null);
@@ -44873,7 +44955,9 @@ function RoguelikeBoard({
44873
44955
  scale,
44874
44956
  assetBaseUrl: propAssetManifest?.baseUrl ?? CDN4,
44875
44957
  assetManifest: propAssetManifest,
44876
- unitScale
44958
+ unitScale,
44959
+ spriteHeightRatio,
44960
+ spriteMaxWidthRatio
44877
44961
  }
44878
44962
  ) }),
44879
44963
  !isGameOver && /* @__PURE__ */ jsx(HStack, { className: "justify-center gap-2 p-3", gap: "none", children: [
@@ -44917,7 +45001,7 @@ function RoguelikeBoard({
44917
45001
  ] }) })
44918
45002
  ] });
44919
45003
  }
44920
- var CDN4, DEFAULT_TILES2, DEFAULT_ENEMIES, DEFAULT_ITEMS, FEATURE_SPRITE;
45004
+ var CDN4, DUNGEON_GRID_W, DUNGEON_GRID_H, DEFAULT_ENEMIES, DEFAULT_ITEMS, FEATURE_SPRITE;
44921
45005
  var init_RoguelikeBoard = __esm({
44922
45006
  "components/game/organisms/RoguelikeBoard.tsx"() {
44923
45007
  "use client";
@@ -44930,39 +45014,19 @@ var init_RoguelikeBoard = __esm({
44930
45014
  init_IsometricCanvas();
44931
45015
  init_boardEntity();
44932
45016
  CDN4 = "https://almadar-kflow-assets.web.app/shared";
44933
- DEFAULT_TILES2 = [
44934
- { x: 0, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
44935
- { x: 1, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
44936
- { x: 2, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
44937
- { x: 3, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
44938
- { x: 4, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
44939
- { x: 0, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
44940
- { x: 1, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
44941
- { x: 2, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
44942
- { x: 3, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
44943
- { x: 4, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
44944
- { x: 0, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
44945
- { x: 1, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png` },
44946
- { x: 2, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png` },
44947
- { x: 3, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
44948
- { x: 4, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
44949
- { x: 0, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
44950
- { x: 1, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
44951
- { x: 2, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png` },
44952
- { x: 3, y: 3, terrain: "stairs", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stairs_E.png` },
44953
- { x: 4, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
44954
- { x: 0, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
44955
- { x: 1, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
44956
- { x: 2, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
44957
- { x: 3, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
44958
- { x: 4, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` }
44959
- ];
45017
+ DUNGEON_GRID_W = 16;
45018
+ DUNGEON_GRID_H = 16;
45019
+ buildDefaultDungeonTiles(14, 14);
44960
45020
  DEFAULT_ENEMIES = [
44961
- { id: "e1", x: 3, y: 1, hp: 5, attack: 2 },
44962
- { id: "e2", x: 1, y: 3, hp: 4, attack: 1 }
45021
+ { id: "e1", x: 5, y: 2, hp: 5, attack: 2 },
45022
+ { id: "e2", x: 9, y: 6, hp: 4, attack: 1 },
45023
+ { id: "e3", x: 3, y: 10, hp: 6, attack: 2 },
45024
+ { id: "e4", x: 12, y: 8, hp: 5, attack: 3 }
44963
45025
  ];
44964
45026
  DEFAULT_ITEMS = [
44965
- { id: "i1", x: 2, y: 2, kind: "health_potion" }
45027
+ { id: "i1", x: 3, y: 3, kind: "health_potion" },
45028
+ { id: "i2", x: 7, y: 9, kind: "sword" },
45029
+ { id: "i3", x: 11, y: 5, kind: "shield" }
44966
45030
  ];
44967
45031
  FEATURE_SPRITE = {
44968
45032
  health_potion: `${CDN4}/isometric-dungeon/Isometric/chestClosed_E.png`,
@@ -49170,6 +49234,22 @@ var init_ToastSlot = __esm({
49170
49234
  ToastSlot.displayName = "ToastSlot";
49171
49235
  }
49172
49236
  });
49237
+ function buildDefaultTDTiles() {
49238
+ const pathSet = new Set(DEFAULT_TD_PATH.map((p2) => `${p2.x},${p2.y}`));
49239
+ const tiles = [];
49240
+ for (let y = 0; y < TD_GRID_H; y++) {
49241
+ for (let x = 0; x < TD_GRID_W; x++) {
49242
+ if (pathSet.has(`${x},${y}`)) {
49243
+ tiles.push({ x, y, terrain: "path", passable: false, terrainSprite: TERRAIN_SPRITES.path });
49244
+ } else {
49245
+ const variant = (x * 3 + y * 5 + (x ^ y)) % 3;
49246
+ const terrainKey = ["ground", "grass", "dirt"][variant];
49247
+ tiles.push({ x, y, terrain: terrainKey, passable: true, terrainSprite: TERRAIN_SPRITES[terrainKey] ?? TERRAIN_SPRITES.ground });
49248
+ }
49249
+ }
49250
+ }
49251
+ return tiles;
49252
+ }
49173
49253
  function tilesToIso(tiles) {
49174
49254
  return tiles.map((t) => ({
49175
49255
  x: t.x,
@@ -49225,7 +49305,10 @@ function TowerDefenseBoard({
49225
49305
  result: propResult,
49226
49306
  waveActive: propWaveActive,
49227
49307
  towerCost = 25,
49228
- scale = 0.45,
49308
+ scale = 0.25,
49309
+ unitScale = 1,
49310
+ spriteHeightRatio = 1.5,
49311
+ spriteMaxWidthRatio = 0.6,
49229
49312
  placeTowerEvent,
49230
49313
  startWaveEvent,
49231
49314
  playAgainEvent,
@@ -49235,8 +49318,10 @@ function TowerDefenseBoard({
49235
49318
  const board = boardEntity(entity) ?? {};
49236
49319
  const eventBus = useEventBus();
49237
49320
  const { t } = useTranslate();
49238
- const tiles = propTiles ?? rows(board.tiles);
49239
- const path = propPath ?? rows(board.path);
49321
+ const rawTiles = propTiles ?? rows(board.tiles);
49322
+ const tiles = rawTiles.length >= TD_GRID_W * TD_GRID_H ? rawTiles : DEFAULT_TD_TILES;
49323
+ const rawPath = propPath ?? rows(board.path);
49324
+ const path = rawPath.length > 0 ? rawPath : DEFAULT_TD_PATH;
49240
49325
  const towers = propTowers ?? rows(board.towers);
49241
49326
  const creeps = propCreeps ?? rows(board.creeps);
49242
49327
  const gold = propGold ?? num(board.gold, 100);
@@ -49333,7 +49418,10 @@ function TowerDefenseBoard({
49333
49418
  onTileClick: handleTileClick,
49334
49419
  onTileHover: (x, y) => setHoveredTile({ x, y }),
49335
49420
  onTileLeave: () => setHoveredTile(null),
49336
- scale
49421
+ scale,
49422
+ unitScale,
49423
+ spriteHeightRatio,
49424
+ spriteMaxWidthRatio
49337
49425
  }
49338
49426
  ),
49339
49427
  hoveredTile && canPlaceTower && validMoves.some((m) => m.x === hoveredTile.x && m.y === hoveredTile.y) && /* @__PURE__ */ jsx(Box, { className: "absolute bottom-4 left-1/2 -translate-x-1/2 z-10 bg-background/80 rounded px-3 py-1 backdrop-blur-sm pointer-events-none", children: /* @__PURE__ */ jsx(Typography, { variant: "small", children: t("td.placeTower") ?? `Place tower (${towerCost} gold)` }) })
@@ -49363,7 +49451,7 @@ function TowerDefenseBoard({
49363
49451
  ] }) })
49364
49452
  ] });
49365
49453
  }
49366
- var CDN6, TERRAIN_SPRITES, TOWER_SPRITE, CREEP_SPRITE;
49454
+ var CDN6, TD_GRID_W, TD_GRID_H, TERRAIN_SPRITES, DEFAULT_TD_PATH, DEFAULT_TD_TILES, TOWER_SPRITE, CREEP_SPRITE;
49367
49455
  var init_TowerDefenseBoard = __esm({
49368
49456
  "components/game/organisms/TowerDefenseBoard.tsx"() {
49369
49457
  "use client";
@@ -49376,11 +49464,67 @@ var init_TowerDefenseBoard = __esm({
49376
49464
  init_IsometricCanvas();
49377
49465
  init_boardEntity();
49378
49466
  CDN6 = "https://almadar-kflow-assets.web.app/shared/";
49467
+ TD_GRID_W = 16;
49468
+ TD_GRID_H = 16;
49379
49469
  TERRAIN_SPRITES = {
49380
49470
  ground: `${CDN6}isometric-blocks/PNG/Platformer tiles/platformerTile_01.png`,
49381
49471
  path: `${CDN6}isometric-blocks/PNG/Platformer tiles/platformerTile_09.png`,
49382
- wall: `${CDN6}isometric-blocks/PNG/Platformer tiles/platformerTile_05.png`
49383
- };
49472
+ wall: `${CDN6}isometric-blocks/PNG/Platformer tiles/platformerTile_05.png`,
49473
+ grass: `${CDN6}isometric-dungeon/Isometric/dirt_E.png`,
49474
+ dirt: `${CDN6}isometric-dungeon/Isometric/dirtTiles_E.png`
49475
+ };
49476
+ DEFAULT_TD_PATH = [
49477
+ { x: 2, y: 0 },
49478
+ { x: 2, y: 1 },
49479
+ { x: 2, y: 2 },
49480
+ { x: 2, y: 3 },
49481
+ { x: 3, y: 3 },
49482
+ { x: 4, y: 3 },
49483
+ { x: 5, y: 3 },
49484
+ { x: 6, y: 3 },
49485
+ { x: 7, y: 3 },
49486
+ { x: 8, y: 3 },
49487
+ { x: 9, y: 3 },
49488
+ { x: 10, y: 3 },
49489
+ { x: 11, y: 3 },
49490
+ { x: 12, y: 3 },
49491
+ { x: 13, y: 3 },
49492
+ { x: 13, y: 4 },
49493
+ { x: 13, y: 5 },
49494
+ { x: 13, y: 6 },
49495
+ { x: 13, y: 7 },
49496
+ { x: 12, y: 7 },
49497
+ { x: 11, y: 7 },
49498
+ { x: 10, y: 7 },
49499
+ { x: 9, y: 7 },
49500
+ { x: 8, y: 7 },
49501
+ { x: 7, y: 7 },
49502
+ { x: 6, y: 7 },
49503
+ { x: 5, y: 7 },
49504
+ { x: 4, y: 7 },
49505
+ { x: 3, y: 7 },
49506
+ { x: 2, y: 7 },
49507
+ { x: 2, y: 8 },
49508
+ { x: 2, y: 9 },
49509
+ { x: 2, y: 10 },
49510
+ { x: 2, y: 11 },
49511
+ { x: 3, y: 11 },
49512
+ { x: 4, y: 11 },
49513
+ { x: 5, y: 11 },
49514
+ { x: 6, y: 11 },
49515
+ { x: 7, y: 11 },
49516
+ { x: 8, y: 11 },
49517
+ { x: 9, y: 11 },
49518
+ { x: 10, y: 11 },
49519
+ { x: 11, y: 11 },
49520
+ { x: 12, y: 11 },
49521
+ { x: 13, y: 11 },
49522
+ { x: 13, y: 12 },
49523
+ { x: 13, y: 13 },
49524
+ { x: 13, y: 14 },
49525
+ { x: 13, y: 15 }
49526
+ ];
49527
+ DEFAULT_TD_TILES = buildDefaultTDTiles();
49384
49528
  TOWER_SPRITE = `${CDN6}units/guardian.png`;
49385
49529
  CREEP_SPRITE = `${CDN6}units/scrapper.png`;
49386
49530
  TowerDefenseBoard.displayName = "TowerDefenseBoard";
@@ -49657,6 +49801,17 @@ function heroPosition(h) {
49657
49801
  function heroMovement(h) {
49658
49802
  return num(h.movement);
49659
49803
  }
49804
+ function buildDefaultWorldTiles() {
49805
+ const tiles = [];
49806
+ for (let y = 0; y < WORLD_GRID_H; y++) {
49807
+ for (let x = 0; x < WORLD_GRID_W; x++) {
49808
+ const isBorder = x === 0 || y === 0 || x === WORLD_GRID_W - 1 || y === WORLD_GRID_H - 1;
49809
+ const def = isBorder ? WORLD_TERRAIN_DEFS[3] : WORLD_TERRAIN_DEFS[(x * 5 + y * 3 + (x ^ y)) % (WORLD_TERRAIN_DEFS.length - 1)];
49810
+ tiles.push({ x, y, terrain: def.terrain, terrainSprite: def.sprite, passable: def.passable });
49811
+ }
49812
+ }
49813
+ return tiles;
49814
+ }
49660
49815
  function defaultIsInRange(from, to, range) {
49661
49816
  return Math.abs(from.x - to.x) + Math.abs(from.y - to.y) <= range;
49662
49817
  }
@@ -49667,8 +49822,10 @@ function WorldMapBoard({
49667
49822
  features: propFeatures,
49668
49823
  assetManifest: propAssetManifest,
49669
49824
  isLoading,
49670
- scale = 0.4,
49825
+ scale = 0.25,
49671
49826
  unitScale = 2.5,
49827
+ spriteHeightRatio = 1.5,
49828
+ spriteMaxWidthRatio = 0.6,
49672
49829
  allowMoveAllHeroes = false,
49673
49830
  isInRange = defaultIsInRange,
49674
49831
  heroSelectEvent,
@@ -49709,7 +49866,8 @@ function WorldMapBoard({
49709
49866
  })),
49710
49867
  [entityTiles]
49711
49868
  );
49712
- const tiles = propTiles ?? derivedTiles;
49869
+ const rawTiles = propTiles ?? (derivedTiles.length > 0 ? derivedTiles : null);
49870
+ const tiles = rawTiles != null && rawTiles.length >= WORLD_GRID_W * WORLD_GRID_H ? rawTiles : DEFAULT_WORLD_TILES;
49713
49871
  const baseUnits = useMemo(
49714
49872
  () => propUnits ?? entityUnits.map((u) => ({
49715
49873
  id: str(u.id),
@@ -49906,6 +50064,8 @@ function WorldMapBoard({
49906
50064
  effectSpriteUrls,
49907
50065
  resolveUnitFrame,
49908
50066
  unitScale,
50067
+ spriteHeightRatio,
50068
+ spriteMaxWidthRatio,
49909
50069
  diamondTopY,
49910
50070
  enableCamera
49911
50071
  }
@@ -49917,6 +50077,7 @@ function WorldMapBoard({
49917
50077
  footer && footer(ctx)
49918
50078
  ] });
49919
50079
  }
50080
+ var WORLD_CDN, WORLD_GRID_W, WORLD_GRID_H, WORLD_TERRAIN_DEFS, DEFAULT_WORLD_TILES;
49920
50081
  var init_WorldMapBoard = __esm({
49921
50082
  "components/game/organisms/WorldMapBoard.tsx"() {
49922
50083
  "use client";
@@ -49927,6 +50088,17 @@ var init_WorldMapBoard = __esm({
49927
50088
  init_IsometricCanvas();
49928
50089
  init_boardEntity();
49929
50090
  init_isometric();
50091
+ WORLD_CDN = "https://almadar-kflow-assets.web.app/shared";
50092
+ WORLD_GRID_W = 16;
50093
+ WORLD_GRID_H = 16;
50094
+ WORLD_TERRAIN_DEFS = [
50095
+ { terrain: "grass", sprite: `${WORLD_CDN}/isometric-dungeon/Isometric/dirt_E.png`, passable: true },
50096
+ { terrain: "dirt", sprite: `${WORLD_CDN}/isometric-dungeon/Isometric/dirtTiles_E.png`, passable: true },
50097
+ { terrain: "forest", sprite: `${WORLD_CDN}/isometric-dungeon/Isometric/planks_E.png`, passable: true },
50098
+ { terrain: "stone", sprite: `${WORLD_CDN}/isometric-dungeon/Isometric/stoneInset_E.png`, passable: false },
50099
+ { terrain: "castle", sprite: `${WORLD_CDN}/isometric-dungeon/Isometric/stoneTile_E.png`, passable: true }
50100
+ ];
50101
+ DEFAULT_WORLD_TILES = buildDefaultWorldTiles();
49930
50102
  WorldMapBoard.displayName = "WorldMapBoard";
49931
50103
  }
49932
50104
  });