@almadar/ui 5.56.0 → 5.58.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.
@@ -10498,13 +10498,29 @@ var init_boardEntity = __esm({
10498
10498
  "components/game/organisms/boardEntity.ts"() {
10499
10499
  }
10500
10500
  });
10501
+ function buildDefaultBattleTiles() {
10502
+ const tiles = [];
10503
+ for (let y = 0; y < BATTLE_GRID_H; y++) {
10504
+ for (let x = 0; x < BATTLE_GRID_W; x++) {
10505
+ const variant = (x * 3 + y * 7 + (x ^ y)) % BATTLE_TERRAIN_SPRITES.length;
10506
+ tiles.push({
10507
+ x,
10508
+ y,
10509
+ terrain: ["grass", "dirt", "planks", "stone", "stone"][variant],
10510
+ terrainSprite: BATTLE_TERRAIN_SPRITES[variant],
10511
+ passable: true
10512
+ });
10513
+ }
10514
+ }
10515
+ return tiles;
10516
+ }
10501
10517
  function BattleBoard({
10502
10518
  entity,
10503
10519
  tiles: propTiles,
10504
10520
  units: propUnits,
10505
10521
  features: propFeatures,
10506
10522
  assetManifest: propAssetManifest,
10507
- scale = 0.45,
10523
+ scale = 0.25,
10508
10524
  unitScale = 1,
10509
10525
  spriteHeightRatio = 1.5,
10510
10526
  spriteMaxWidthRatio = 0.6,
@@ -10531,10 +10547,11 @@ function BattleBoard({
10531
10547
  className
10532
10548
  }) {
10533
10549
  const board = boardEntity(entity) ?? {};
10534
- const tiles = propTiles ?? (Array.isArray(board.tiles) ? board.tiles : []);
10550
+ const rawTiles = propTiles ?? (Array.isArray(board.tiles) ? board.tiles : []);
10551
+ const tiles = rawTiles.length === 0 ? DEFAULT_BATTLE_TILES : rawTiles;
10535
10552
  const features = propFeatures ?? (Array.isArray(board.features) ? board.features : []);
10536
- const boardWidth = num(board.gridWidth ?? board.boardWidth, 8);
10537
- const boardHeight = num(board.gridHeight ?? board.boardHeight, 6);
10553
+ const boardWidth = num(board.gridWidth ?? board.boardWidth, BATTLE_GRID_W);
10554
+ const boardHeight = num(board.gridHeight ?? board.boardHeight, BATTLE_GRID_H);
10538
10555
  const assetManifest = propAssetManifest ?? board.assetManifest;
10539
10556
  const backgroundImage = board.backgroundImage;
10540
10557
  const units = rows(board.units);
@@ -10856,6 +10873,7 @@ function BattleBoard({
10856
10873
  ] }) }))
10857
10874
  ] });
10858
10875
  }
10876
+ var BATTLE_CDN, BATTLE_GRID_W, BATTLE_GRID_H, BATTLE_TERRAIN_SPRITES, DEFAULT_BATTLE_TILES;
10859
10877
  var init_BattleBoard = __esm({
10860
10878
  "components/game/organisms/BattleBoard.tsx"() {
10861
10879
  "use client";
@@ -10868,6 +10886,17 @@ var init_BattleBoard = __esm({
10868
10886
  init_IsometricCanvas();
10869
10887
  init_boardEntity();
10870
10888
  init_isometric();
10889
+ BATTLE_CDN = "https://almadar-kflow-assets.web.app/shared";
10890
+ BATTLE_GRID_W = 16;
10891
+ BATTLE_GRID_H = 16;
10892
+ BATTLE_TERRAIN_SPRITES = [
10893
+ `${BATTLE_CDN}/isometric-dungeon/Isometric/dirt_E.png`,
10894
+ `${BATTLE_CDN}/isometric-dungeon/Isometric/dirtTiles_E.png`,
10895
+ `${BATTLE_CDN}/isometric-dungeon/Isometric/planks_E.png`,
10896
+ `${BATTLE_CDN}/isometric-dungeon/Isometric/stoneTile_E.png`,
10897
+ `${BATTLE_CDN}/isometric-dungeon/Isometric/stoneInset_E.png`
10898
+ ];
10899
+ DEFAULT_BATTLE_TILES = buildDefaultBattleTiles();
10871
10900
  BattleBoard.displayName = "BattleBoard";
10872
10901
  }
10873
10902
  });
@@ -10875,7 +10904,7 @@ function BattleTemplate({
10875
10904
  entity,
10876
10905
  scale = 0.45,
10877
10906
  unitScale = 1,
10878
- tiles = DEFAULT_BATTLE_TILES,
10907
+ tiles = DEFAULT_BATTLE_TILES2,
10879
10908
  units = DEFAULT_BATTLE_UNITS,
10880
10909
  features = DEFAULT_BATTLE_FEATURES,
10881
10910
  assetManifest = DEFAULT_BATTLE_MANIFEST,
@@ -10904,12 +10933,12 @@ function BattleTemplate({
10904
10933
  }
10905
10934
  );
10906
10935
  }
10907
- var CDN, DEFAULT_BATTLE_TILES, DEFAULT_BATTLE_UNITS, DEFAULT_BATTLE_FEATURES, DEFAULT_BATTLE_MANIFEST;
10936
+ var CDN, DEFAULT_BATTLE_TILES2, DEFAULT_BATTLE_UNITS, DEFAULT_BATTLE_FEATURES, DEFAULT_BATTLE_MANIFEST;
10908
10937
  var init_BattleTemplate = __esm({
10909
10938
  "components/game/templates/BattleTemplate.tsx"() {
10910
10939
  init_BattleBoard();
10911
10940
  CDN = "https://almadar-kflow-assets.web.app/shared";
10912
- DEFAULT_BATTLE_TILES = [
10941
+ DEFAULT_BATTLE_TILES2 = [
10913
10942
  { x: 0, y: 0, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
10914
10943
  { x: 1, y: 0, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
10915
10944
  { x: 2, y: 0, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
@@ -29866,13 +29895,13 @@ var init_MapView = __esm({
29866
29895
  shadowSize: [41, 41]
29867
29896
  });
29868
29897
  L.Marker.prototype.options.icon = defaultIcon;
29869
- const { useEffect: useEffect80, useRef: useRef78, useCallback: useCallback120, useState: useState110 } = React76__default;
29898
+ const { useEffect: useEffect81, useRef: useRef78, useCallback: useCallback120, useState: useState110 } = React76__default;
29870
29899
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
29871
29900
  const { useEventBus: useEventBus3 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
29872
29901
  function MapUpdater({ centerLat, centerLng, zoom }) {
29873
29902
  const map = useMap();
29874
29903
  const prevRef = useRef78({ centerLat, centerLng, zoom });
29875
- useEffect80(() => {
29904
+ useEffect81(() => {
29876
29905
  const prev = prevRef.current;
29877
29906
  if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
29878
29907
  map.setView([centerLat, centerLng], zoom);
@@ -29883,7 +29912,7 @@ var init_MapView = __esm({
29883
29912
  }
29884
29913
  function MapClickHandler({ onMapClick }) {
29885
29914
  const map = useMap();
29886
- useEffect80(() => {
29915
+ useEffect81(() => {
29887
29916
  if (!onMapClick) return;
29888
29917
  const handler = (e) => {
29889
29918
  onMapClick(e.latlng.lat, e.latlng.lng);
@@ -42887,7 +42916,6 @@ var init_GameCanvas3D2 = __esm({
42887
42916
  selectedTileIds = [],
42888
42917
  selectedUnitId = null,
42889
42918
  unitScale = 1,
42890
- scale = 0.45,
42891
42919
  children
42892
42920
  }, ref) => {
42893
42921
  const containerRef = useRef(null);
@@ -43334,7 +43362,7 @@ var init_GameCanvas3D2 = __esm({
43334
43362
  fadeStrength: 1
43335
43363
  }
43336
43364
  ),
43337
- /* @__PURE__ */ jsxs("group", { scale, children: [
43365
+ /* @__PURE__ */ jsxs("group", { children: [
43338
43366
  tiles.map((tile, index) => {
43339
43367
  const position = gridToWorld(
43340
43368
  tile.x,
@@ -45651,6 +45679,35 @@ var init_ResourceCounter = __esm({
45651
45679
  ResourceCounter.displayName = "ResourceCounter";
45652
45680
  }
45653
45681
  });
45682
+ function dungeonTerrain(x, y, stairsX, stairsY) {
45683
+ const isBorder = x === 0 || y === 0 || x === DUNGEON_GRID_W - 1 || y === DUNGEON_GRID_H - 1;
45684
+ const isPillar = x % 4 === 0 && y % 4 === 0 && !isBorder;
45685
+ const isWall = isBorder || isPillar;
45686
+ if (x === stairsX && y === stairsY) {
45687
+ return { terrain: "stairs", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stairs_E.png` };
45688
+ }
45689
+ if (isWall) {
45690
+ return { terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` };
45691
+ }
45692
+ const variant = (x * 3 + y * 7) % 5;
45693
+ const sprites = [
45694
+ `${CDN4}/isometric-dungeon/Isometric/dirt_E.png`,
45695
+ `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png`,
45696
+ `${CDN4}/isometric-dungeon/Isometric/planks_E.png`,
45697
+ `${CDN4}/isometric-dungeon/Isometric/stoneTile_E.png`,
45698
+ `${CDN4}/isometric-dungeon/Isometric/dirt_E.png`
45699
+ ];
45700
+ return { terrain: "floor", passable: true, terrainSprite: sprites[variant] };
45701
+ }
45702
+ function buildDefaultDungeonTiles(stairsX, stairsY) {
45703
+ const tiles = [];
45704
+ for (let y = 0; y < DUNGEON_GRID_H; y++) {
45705
+ for (let x = 0; x < DUNGEON_GRID_W; x++) {
45706
+ tiles.push({ x, y, ...dungeonTerrain(x, y, stairsX, stairsY) });
45707
+ }
45708
+ }
45709
+ return tiles;
45710
+ }
45654
45711
  function RoguelikeBoard({
45655
45712
  entity,
45656
45713
  tiles: propTiles,
@@ -45666,7 +45723,7 @@ function RoguelikeBoard({
45666
45723
  stairsX: propStairsX,
45667
45724
  stairsY: propStairsY,
45668
45725
  assetManifest: propAssetManifest,
45669
- scale = 0.45,
45726
+ scale = 0.25,
45670
45727
  unitScale = 1,
45671
45728
  spriteHeightRatio = 1.5,
45672
45729
  spriteMaxWidthRatio = 0.6,
@@ -45676,7 +45733,9 @@ function RoguelikeBoard({
45676
45733
  className
45677
45734
  }) {
45678
45735
  const board = boardEntity(entity) ?? {};
45679
- const tiles = propTiles ?? (Array.isArray(board.tiles) ? board.tiles : DEFAULT_TILES2);
45736
+ const resolvedStairsX = propStairsX ?? num(board.stairsX, 14);
45737
+ const resolvedStairsY = propStairsY ?? num(board.stairsY, 14);
45738
+ const tiles = propTiles ?? (Array.isArray(board.tiles) && board.tiles.length >= DUNGEON_GRID_W * DUNGEON_GRID_H ? board.tiles : buildDefaultDungeonTiles(resolvedStairsX, resolvedStairsY));
45680
45739
  const enemies = propEnemies ?? (Array.isArray(board.enemies) ? board.enemies : DEFAULT_ENEMIES);
45681
45740
  const items = propItems ?? (Array.isArray(board.items) ? board.items : DEFAULT_ITEMS);
45682
45741
  const player = propPlayer ?? board.player ?? { x: 1, y: 1 };
@@ -45686,8 +45745,8 @@ function RoguelikeBoard({
45686
45745
  const depth = propDepth ?? num(board.depth, 1);
45687
45746
  const result = propResult ?? (str(board.result) || "none");
45688
45747
  const phase = propPhase ?? (str(board.phase) || "player_turn");
45689
- propStairsX ?? num(board.stairsX, 3);
45690
- propStairsY ?? num(board.stairsY, 3);
45748
+ propStairsX ?? num(board.stairsX, 14);
45749
+ propStairsY ?? num(board.stairsY, 14);
45691
45750
  const eventBus = useEventBus();
45692
45751
  const { t } = useTranslate();
45693
45752
  const [hoveredTile, setHoveredTile] = useState(null);
@@ -45863,7 +45922,7 @@ function RoguelikeBoard({
45863
45922
  ] }) })
45864
45923
  ] });
45865
45924
  }
45866
- var CDN4, DEFAULT_TILES2, DEFAULT_ENEMIES, DEFAULT_ITEMS, FEATURE_SPRITE;
45925
+ var CDN4, DUNGEON_GRID_W, DUNGEON_GRID_H, DEFAULT_ENEMIES, DEFAULT_ITEMS, FEATURE_SPRITE;
45867
45926
  var init_RoguelikeBoard = __esm({
45868
45927
  "components/game/organisms/RoguelikeBoard.tsx"() {
45869
45928
  "use client";
@@ -45876,39 +45935,19 @@ var init_RoguelikeBoard = __esm({
45876
45935
  init_IsometricCanvas();
45877
45936
  init_boardEntity();
45878
45937
  CDN4 = "https://almadar-kflow-assets.web.app/shared";
45879
- DEFAULT_TILES2 = [
45880
- { x: 0, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
45881
- { x: 1, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
45882
- { x: 2, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
45883
- { x: 3, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
45884
- { x: 4, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
45885
- { x: 0, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
45886
- { x: 1, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
45887
- { x: 2, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
45888
- { x: 3, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
45889
- { x: 4, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
45890
- { x: 0, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
45891
- { x: 1, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png` },
45892
- { x: 2, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png` },
45893
- { x: 3, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
45894
- { x: 4, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
45895
- { x: 0, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
45896
- { x: 1, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
45897
- { x: 2, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png` },
45898
- { x: 3, y: 3, terrain: "stairs", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stairs_E.png` },
45899
- { x: 4, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
45900
- { x: 0, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
45901
- { x: 1, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
45902
- { x: 2, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
45903
- { x: 3, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
45904
- { x: 4, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` }
45905
- ];
45938
+ DUNGEON_GRID_W = 16;
45939
+ DUNGEON_GRID_H = 16;
45940
+ buildDefaultDungeonTiles(14, 14);
45906
45941
  DEFAULT_ENEMIES = [
45907
- { id: "e1", x: 3, y: 1, hp: 5, attack: 2 },
45908
- { id: "e2", x: 1, y: 3, hp: 4, attack: 1 }
45942
+ { id: "e1", x: 5, y: 2, hp: 5, attack: 2 },
45943
+ { id: "e2", x: 9, y: 6, hp: 4, attack: 1 },
45944
+ { id: "e3", x: 3, y: 10, hp: 6, attack: 2 },
45945
+ { id: "e4", x: 12, y: 8, hp: 5, attack: 3 }
45909
45946
  ];
45910
45947
  DEFAULT_ITEMS = [
45911
- { id: "i1", x: 2, y: 2, kind: "health_potion" }
45948
+ { id: "i1", x: 3, y: 3, kind: "health_potion" },
45949
+ { id: "i2", x: 7, y: 9, kind: "sword" },
45950
+ { id: "i3", x: 11, y: 5, kind: "shield" }
45912
45951
  ];
45913
45952
  FEATURE_SPRITE = {
45914
45953
  health_potion: `${CDN4}/isometric-dungeon/Isometric/chestClosed_E.png`,
@@ -50357,6 +50396,22 @@ var init_ToastSlot = __esm({
50357
50396
  ToastSlot.displayName = "ToastSlot";
50358
50397
  }
50359
50398
  });
50399
+ function buildDefaultTDTiles() {
50400
+ const pathSet = new Set(DEFAULT_TD_PATH.map((p2) => `${p2.x},${p2.y}`));
50401
+ const tiles = [];
50402
+ for (let y = 0; y < TD_GRID_H; y++) {
50403
+ for (let x = 0; x < TD_GRID_W; x++) {
50404
+ if (pathSet.has(`${x},${y}`)) {
50405
+ tiles.push({ x, y, terrain: "path", passable: false, terrainSprite: TERRAIN_SPRITES.path });
50406
+ } else {
50407
+ const variant = (x * 3 + y * 5 + (x ^ y)) % 3;
50408
+ const terrainKey = ["ground", "grass", "dirt"][variant];
50409
+ tiles.push({ x, y, terrain: terrainKey, passable: true, terrainSprite: TERRAIN_SPRITES[terrainKey] ?? TERRAIN_SPRITES.ground });
50410
+ }
50411
+ }
50412
+ }
50413
+ return tiles;
50414
+ }
50360
50415
  function tilesToIso(tiles) {
50361
50416
  return tiles.map((t) => ({
50362
50417
  x: t.x,
@@ -50399,12 +50454,25 @@ function pathToFeatures(path) {
50399
50454
  sprite: `${CDN6}world-map/road_straight.png`
50400
50455
  }));
50401
50456
  }
50457
+ function heroToUnit(hero) {
50458
+ return {
50459
+ id: hero.id,
50460
+ position: { x: hero.x, y: hero.y },
50461
+ name: "Hero",
50462
+ team: "player",
50463
+ sprite: HERO_SPRITE,
50464
+ unitType: "amir",
50465
+ health: 1,
50466
+ maxHealth: 1
50467
+ };
50468
+ }
50402
50469
  function TowerDefenseBoard({
50403
50470
  entity,
50404
50471
  tiles: propTiles,
50405
50472
  path: propPath,
50406
50473
  towers: propTowers,
50407
50474
  creeps: propCreeps,
50475
+ hero: propHero,
50408
50476
  gold: propGold,
50409
50477
  lives: propLives,
50410
50478
  wave: propWave,
@@ -50412,7 +50480,7 @@ function TowerDefenseBoard({
50412
50480
  result: propResult,
50413
50481
  waveActive: propWaveActive,
50414
50482
  towerCost = 25,
50415
- scale = 0.45,
50483
+ scale = 0.25,
50416
50484
  unitScale = 1,
50417
50485
  spriteHeightRatio = 1.5,
50418
50486
  spriteMaxWidthRatio = 0.6,
@@ -50420,15 +50488,19 @@ function TowerDefenseBoard({
50420
50488
  startWaveEvent,
50421
50489
  playAgainEvent,
50422
50490
  gameEndEvent,
50491
+ moveHeroEvent,
50423
50492
  className
50424
50493
  }) {
50425
50494
  const board = boardEntity(entity) ?? {};
50426
50495
  const eventBus = useEventBus();
50427
50496
  const { t } = useTranslate();
50428
- const tiles = propTiles ?? rows(board.tiles);
50429
- const path = propPath ?? rows(board.path);
50497
+ const rawTiles = propTiles ?? rows(board.tiles);
50498
+ const tiles = rawTiles.length >= TD_GRID_W * TD_GRID_H ? rawTiles : DEFAULT_TD_TILES;
50499
+ const rawPath = propPath ?? rows(board.path);
50500
+ const path = rawPath.length > 0 ? rawPath : DEFAULT_TD_PATH;
50430
50501
  const towers = propTowers ?? rows(board.towers);
50431
50502
  const creeps = propCreeps ?? rows(board.creeps);
50503
+ const hero = propHero ?? { id: "hero", x: 8, y: 8 };
50432
50504
  const gold = propGold ?? num(board.gold, 100);
50433
50505
  const lives = propLives ?? num(board.lives, 20);
50434
50506
  const wave = propWave ?? num(board.wave, 1);
@@ -50446,6 +50518,31 @@ function TowerDefenseBoard({
50446
50518
  if (result === "none") {
50447
50519
  emittedGameEnd.current = false;
50448
50520
  }
50521
+ const moveHeroEventRef = useRef(moveHeroEvent);
50522
+ moveHeroEventRef.current = moveHeroEvent;
50523
+ const resultRef = useRef(result);
50524
+ resultRef.current = result;
50525
+ useEffect(() => {
50526
+ function onKeyDown(e) {
50527
+ const evt = moveHeroEventRef.current;
50528
+ if (!evt || resultRef.current !== "none") return;
50529
+ let dx = 0;
50530
+ let dy = 0;
50531
+ if (e.key === "ArrowUp") {
50532
+ dy = -1;
50533
+ } else if (e.key === "ArrowDown") {
50534
+ dy = 1;
50535
+ } else if (e.key === "ArrowLeft") {
50536
+ dx = -1;
50537
+ } else if (e.key === "ArrowRight") {
50538
+ dx = 1;
50539
+ } else return;
50540
+ e.preventDefault();
50541
+ eventBus.emit(`UI:${evt}`, { dx, dy });
50542
+ }
50543
+ window.addEventListener("keydown", onKeyDown);
50544
+ return () => window.removeEventListener("keydown", onKeyDown);
50545
+ }, [eventBus]);
50449
50546
  const towerPositions = useMemo(() => new Set(towers.map((t2) => `${t2.x},${t2.y}`)), [towers]);
50450
50547
  const pathPositions = useMemo(() => new Set(path.map((p2) => `${p2.x},${p2.y}`)), [path]);
50451
50548
  const validMoves = useMemo(() => {
@@ -50457,7 +50554,8 @@ function TowerDefenseBoard({
50457
50554
  const isoTiles = useMemo(() => tilesToIso(tiles), [tiles]);
50458
50555
  const towerUnits = useMemo(() => towersToUnits(towers), [towers]);
50459
50556
  const creepUnits = useMemo(() => creepsToUnits(creeps), [creeps]);
50460
- const isoUnits = useMemo(() => [...towerUnits, ...creepUnits], [towerUnits, creepUnits]);
50557
+ const heroUnit = useMemo(() => heroToUnit(hero), [hero]);
50558
+ const isoUnits = useMemo(() => [...towerUnits, ...creepUnits, heroUnit], [towerUnits, creepUnits, heroUnit]);
50461
50559
  const pathFeatures = useMemo(() => pathToFeatures(path), [path]);
50462
50560
  const handleTileClick = useCallback((x, y) => {
50463
50561
  if (result !== "none") return;
@@ -50556,7 +50654,7 @@ function TowerDefenseBoard({
50556
50654
  ] }) })
50557
50655
  ] });
50558
50656
  }
50559
- var CDN6, TERRAIN_SPRITES, TOWER_SPRITE, CREEP_SPRITE;
50657
+ var CDN6, TD_GRID_W, TD_GRID_H, TERRAIN_SPRITES, DEFAULT_TD_PATH, DEFAULT_TD_TILES, TOWER_SPRITE, CREEP_SPRITE, HERO_SPRITE;
50560
50658
  var init_TowerDefenseBoard = __esm({
50561
50659
  "components/game/organisms/TowerDefenseBoard.tsx"() {
50562
50660
  "use client";
@@ -50569,13 +50667,70 @@ var init_TowerDefenseBoard = __esm({
50569
50667
  init_IsometricCanvas();
50570
50668
  init_boardEntity();
50571
50669
  CDN6 = "https://almadar-kflow-assets.web.app/shared/";
50670
+ TD_GRID_W = 16;
50671
+ TD_GRID_H = 16;
50572
50672
  TERRAIN_SPRITES = {
50573
50673
  ground: `${CDN6}isometric-blocks/PNG/Platformer tiles/platformerTile_01.png`,
50574
50674
  path: `${CDN6}isometric-blocks/PNG/Platformer tiles/platformerTile_09.png`,
50575
- wall: `${CDN6}isometric-blocks/PNG/Platformer tiles/platformerTile_05.png`
50576
- };
50577
- TOWER_SPRITE = `${CDN6}units/guardian.png`;
50578
- CREEP_SPRITE = `${CDN6}units/scrapper.png`;
50675
+ wall: `${CDN6}isometric-blocks/PNG/Platformer tiles/platformerTile_05.png`,
50676
+ grass: `${CDN6}isometric-dungeon/Isometric/dirt_E.png`,
50677
+ dirt: `${CDN6}isometric-dungeon/Isometric/dirtTiles_E.png`
50678
+ };
50679
+ DEFAULT_TD_PATH = [
50680
+ { x: 2, y: 0 },
50681
+ { x: 2, y: 1 },
50682
+ { x: 2, y: 2 },
50683
+ { x: 2, y: 3 },
50684
+ { x: 3, y: 3 },
50685
+ { x: 4, y: 3 },
50686
+ { x: 5, y: 3 },
50687
+ { x: 6, y: 3 },
50688
+ { x: 7, y: 3 },
50689
+ { x: 8, y: 3 },
50690
+ { x: 9, y: 3 },
50691
+ { x: 10, y: 3 },
50692
+ { x: 11, y: 3 },
50693
+ { x: 12, y: 3 },
50694
+ { x: 13, y: 3 },
50695
+ { x: 13, y: 4 },
50696
+ { x: 13, y: 5 },
50697
+ { x: 13, y: 6 },
50698
+ { x: 13, y: 7 },
50699
+ { x: 12, y: 7 },
50700
+ { x: 11, y: 7 },
50701
+ { x: 10, y: 7 },
50702
+ { x: 9, y: 7 },
50703
+ { x: 8, y: 7 },
50704
+ { x: 7, y: 7 },
50705
+ { x: 6, y: 7 },
50706
+ { x: 5, y: 7 },
50707
+ { x: 4, y: 7 },
50708
+ { x: 3, y: 7 },
50709
+ { x: 2, y: 7 },
50710
+ { x: 2, y: 8 },
50711
+ { x: 2, y: 9 },
50712
+ { x: 2, y: 10 },
50713
+ { x: 2, y: 11 },
50714
+ { x: 3, y: 11 },
50715
+ { x: 4, y: 11 },
50716
+ { x: 5, y: 11 },
50717
+ { x: 6, y: 11 },
50718
+ { x: 7, y: 11 },
50719
+ { x: 8, y: 11 },
50720
+ { x: 9, y: 11 },
50721
+ { x: 10, y: 11 },
50722
+ { x: 11, y: 11 },
50723
+ { x: 12, y: 11 },
50724
+ { x: 13, y: 11 },
50725
+ { x: 13, y: 12 },
50726
+ { x: 13, y: 13 },
50727
+ { x: 13, y: 14 },
50728
+ { x: 13, y: 15 }
50729
+ ];
50730
+ DEFAULT_TD_TILES = buildDefaultTDTiles();
50731
+ TOWER_SPRITE = `${CDN6}sprite-sheets/guardian-sprite-sheet-se.png`;
50732
+ CREEP_SPRITE = `${CDN6}sprite-sheets/scrapper-sprite-sheet-se.png`;
50733
+ HERO_SPRITE = `${CDN6}sprite-sheets/amir-sprite-sheet-se.png`;
50579
50734
  TowerDefenseBoard.displayName = "TowerDefenseBoard";
50580
50735
  }
50581
50736
  });
@@ -50850,6 +51005,17 @@ function heroPosition(h) {
50850
51005
  function heroMovement(h) {
50851
51006
  return num(h.movement);
50852
51007
  }
51008
+ function buildDefaultWorldTiles() {
51009
+ const tiles = [];
51010
+ for (let y = 0; y < WORLD_GRID_H; y++) {
51011
+ for (let x = 0; x < WORLD_GRID_W; x++) {
51012
+ const isBorder = x === 0 || y === 0 || x === WORLD_GRID_W - 1 || y === WORLD_GRID_H - 1;
51013
+ const def = isBorder ? WORLD_TERRAIN_DEFS[3] : WORLD_TERRAIN_DEFS[(x * 5 + y * 3 + (x ^ y)) % (WORLD_TERRAIN_DEFS.length - 1)];
51014
+ tiles.push({ x, y, terrain: def.terrain, terrainSprite: def.sprite, passable: def.passable });
51015
+ }
51016
+ }
51017
+ return tiles;
51018
+ }
50853
51019
  function defaultIsInRange(from, to, range) {
50854
51020
  return Math.abs(from.x - to.x) + Math.abs(from.y - to.y) <= range;
50855
51021
  }
@@ -50860,7 +51026,7 @@ function WorldMapBoard({
50860
51026
  features: propFeatures,
50861
51027
  assetManifest: propAssetManifest,
50862
51028
  isLoading,
50863
- scale = 0.4,
51029
+ scale = 0.25,
50864
51030
  unitScale = 2.5,
50865
51031
  spriteHeightRatio = 1.5,
50866
51032
  spriteMaxWidthRatio = 0.6,
@@ -50904,7 +51070,8 @@ function WorldMapBoard({
50904
51070
  })),
50905
51071
  [entityTiles]
50906
51072
  );
50907
- const tiles = propTiles ?? derivedTiles;
51073
+ const rawTiles = propTiles ?? (derivedTiles.length > 0 ? derivedTiles : null);
51074
+ const tiles = rawTiles != null && rawTiles.length >= WORLD_GRID_W * WORLD_GRID_H ? rawTiles : DEFAULT_WORLD_TILES;
50908
51075
  const baseUnits = useMemo(
50909
51076
  () => propUnits ?? entityUnits.map((u) => ({
50910
51077
  id: str(u.id),
@@ -51114,6 +51281,7 @@ function WorldMapBoard({
51114
51281
  footer && footer(ctx)
51115
51282
  ] });
51116
51283
  }
51284
+ var WORLD_CDN, WORLD_GRID_W, WORLD_GRID_H, WORLD_TERRAIN_DEFS, DEFAULT_WORLD_TILES;
51117
51285
  var init_WorldMapBoard = __esm({
51118
51286
  "components/game/organisms/WorldMapBoard.tsx"() {
51119
51287
  "use client";
@@ -51124,6 +51292,17 @@ var init_WorldMapBoard = __esm({
51124
51292
  init_IsometricCanvas();
51125
51293
  init_boardEntity();
51126
51294
  init_isometric();
51295
+ WORLD_CDN = "https://almadar-kflow-assets.web.app/shared";
51296
+ WORLD_GRID_W = 16;
51297
+ WORLD_GRID_H = 16;
51298
+ WORLD_TERRAIN_DEFS = [
51299
+ { terrain: "grass", sprite: `${WORLD_CDN}/isometric-dungeon/Isometric/dirt_E.png`, passable: true },
51300
+ { terrain: "dirt", sprite: `${WORLD_CDN}/isometric-dungeon/Isometric/dirtTiles_E.png`, passable: true },
51301
+ { terrain: "forest", sprite: `${WORLD_CDN}/isometric-dungeon/Isometric/planks_E.png`, passable: true },
51302
+ { terrain: "stone", sprite: `${WORLD_CDN}/isometric-dungeon/Isometric/stoneInset_E.png`, passable: false },
51303
+ { terrain: "castle", sprite: `${WORLD_CDN}/isometric-dungeon/Isometric/stoneTile_E.png`, passable: true }
51304
+ ];
51305
+ DEFAULT_WORLD_TILES = buildDefaultWorldTiles();
51127
51306
  WorldMapBoard.displayName = "WorldMapBoard";
51128
51307
  }
51129
51308
  });