@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.
@@ -10544,13 +10544,29 @@ var init_boardEntity = __esm({
10544
10544
  "components/game/organisms/boardEntity.ts"() {
10545
10545
  }
10546
10546
  });
10547
+ function buildDefaultBattleTiles() {
10548
+ const tiles = [];
10549
+ for (let y = 0; y < BATTLE_GRID_H; y++) {
10550
+ for (let x = 0; x < BATTLE_GRID_W; x++) {
10551
+ const variant = (x * 3 + y * 7 + (x ^ y)) % BATTLE_TERRAIN_SPRITES.length;
10552
+ tiles.push({
10553
+ x,
10554
+ y,
10555
+ terrain: ["grass", "dirt", "planks", "stone", "stone"][variant],
10556
+ terrainSprite: BATTLE_TERRAIN_SPRITES[variant],
10557
+ passable: true
10558
+ });
10559
+ }
10560
+ }
10561
+ return tiles;
10562
+ }
10547
10563
  function BattleBoard({
10548
10564
  entity,
10549
10565
  tiles: propTiles,
10550
10566
  units: propUnits,
10551
10567
  features: propFeatures,
10552
10568
  assetManifest: propAssetManifest,
10553
- scale = 0.45,
10569
+ scale = 0.25,
10554
10570
  unitScale = 1,
10555
10571
  spriteHeightRatio = 1.5,
10556
10572
  spriteMaxWidthRatio = 0.6,
@@ -10577,10 +10593,11 @@ function BattleBoard({
10577
10593
  className
10578
10594
  }) {
10579
10595
  const board = boardEntity(entity) ?? {};
10580
- const tiles = propTiles ?? (Array.isArray(board.tiles) ? board.tiles : []);
10596
+ const rawTiles = propTiles ?? (Array.isArray(board.tiles) ? board.tiles : []);
10597
+ const tiles = rawTiles.length === 0 ? DEFAULT_BATTLE_TILES : rawTiles;
10581
10598
  const features = propFeatures ?? (Array.isArray(board.features) ? board.features : []);
10582
- const boardWidth = num(board.gridWidth ?? board.boardWidth, 8);
10583
- const boardHeight = num(board.gridHeight ?? board.boardHeight, 6);
10599
+ const boardWidth = num(board.gridWidth ?? board.boardWidth, BATTLE_GRID_W);
10600
+ const boardHeight = num(board.gridHeight ?? board.boardHeight, BATTLE_GRID_H);
10584
10601
  const assetManifest = propAssetManifest ?? board.assetManifest;
10585
10602
  const backgroundImage = board.backgroundImage;
10586
10603
  const units = rows(board.units);
@@ -10902,6 +10919,7 @@ function BattleBoard({
10902
10919
  ] }) }))
10903
10920
  ] });
10904
10921
  }
10922
+ var BATTLE_CDN, BATTLE_GRID_W, BATTLE_GRID_H, BATTLE_TERRAIN_SPRITES, DEFAULT_BATTLE_TILES;
10905
10923
  var init_BattleBoard = __esm({
10906
10924
  "components/game/organisms/BattleBoard.tsx"() {
10907
10925
  "use client";
@@ -10914,6 +10932,17 @@ var init_BattleBoard = __esm({
10914
10932
  init_IsometricCanvas();
10915
10933
  init_boardEntity();
10916
10934
  init_isometric();
10935
+ BATTLE_CDN = "https://almadar-kflow-assets.web.app/shared";
10936
+ BATTLE_GRID_W = 16;
10937
+ BATTLE_GRID_H = 16;
10938
+ BATTLE_TERRAIN_SPRITES = [
10939
+ `${BATTLE_CDN}/isometric-dungeon/Isometric/dirt_E.png`,
10940
+ `${BATTLE_CDN}/isometric-dungeon/Isometric/dirtTiles_E.png`,
10941
+ `${BATTLE_CDN}/isometric-dungeon/Isometric/planks_E.png`,
10942
+ `${BATTLE_CDN}/isometric-dungeon/Isometric/stoneTile_E.png`,
10943
+ `${BATTLE_CDN}/isometric-dungeon/Isometric/stoneInset_E.png`
10944
+ ];
10945
+ DEFAULT_BATTLE_TILES = buildDefaultBattleTiles();
10917
10946
  BattleBoard.displayName = "BattleBoard";
10918
10947
  }
10919
10948
  });
@@ -10921,7 +10950,7 @@ function BattleTemplate({
10921
10950
  entity,
10922
10951
  scale = 0.45,
10923
10952
  unitScale = 1,
10924
- tiles = DEFAULT_BATTLE_TILES,
10953
+ tiles = DEFAULT_BATTLE_TILES2,
10925
10954
  units = DEFAULT_BATTLE_UNITS,
10926
10955
  features = DEFAULT_BATTLE_FEATURES,
10927
10956
  assetManifest = DEFAULT_BATTLE_MANIFEST,
@@ -10950,12 +10979,12 @@ function BattleTemplate({
10950
10979
  }
10951
10980
  );
10952
10981
  }
10953
- var CDN, DEFAULT_BATTLE_TILES, DEFAULT_BATTLE_UNITS, DEFAULT_BATTLE_FEATURES, DEFAULT_BATTLE_MANIFEST;
10982
+ var CDN, DEFAULT_BATTLE_TILES2, DEFAULT_BATTLE_UNITS, DEFAULT_BATTLE_FEATURES, DEFAULT_BATTLE_MANIFEST;
10954
10983
  var init_BattleTemplate = __esm({
10955
10984
  "components/game/templates/BattleTemplate.tsx"() {
10956
10985
  init_BattleBoard();
10957
10986
  CDN = "https://almadar-kflow-assets.web.app/shared";
10958
- DEFAULT_BATTLE_TILES = [
10987
+ DEFAULT_BATTLE_TILES2 = [
10959
10988
  { x: 0, y: 0, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
10960
10989
  { x: 1, y: 0, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
10961
10990
  { x: 2, y: 0, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
@@ -29912,13 +29941,13 @@ var init_MapView = __esm({
29912
29941
  shadowSize: [41, 41]
29913
29942
  });
29914
29943
  L.Marker.prototype.options.icon = defaultIcon;
29915
- const { useEffect: useEffect80, useRef: useRef78, useCallback: useCallback120, useState: useState110 } = React76__namespace.default;
29944
+ const { useEffect: useEffect81, useRef: useRef78, useCallback: useCallback120, useState: useState110 } = React76__namespace.default;
29916
29945
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
29917
29946
  const { useEventBus: useEventBus3 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
29918
29947
  function MapUpdater({ centerLat, centerLng, zoom }) {
29919
29948
  const map = useMap();
29920
29949
  const prevRef = useRef78({ centerLat, centerLng, zoom });
29921
- useEffect80(() => {
29950
+ useEffect81(() => {
29922
29951
  const prev = prevRef.current;
29923
29952
  if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
29924
29953
  map.setView([centerLat, centerLng], zoom);
@@ -29929,7 +29958,7 @@ var init_MapView = __esm({
29929
29958
  }
29930
29959
  function MapClickHandler({ onMapClick }) {
29931
29960
  const map = useMap();
29932
- useEffect80(() => {
29961
+ useEffect81(() => {
29933
29962
  if (!onMapClick) return;
29934
29963
  const handler = (e) => {
29935
29964
  onMapClick(e.latlng.lat, e.latlng.lng);
@@ -42933,7 +42962,6 @@ var init_GameCanvas3D2 = __esm({
42933
42962
  selectedTileIds = [],
42934
42963
  selectedUnitId = null,
42935
42964
  unitScale = 1,
42936
- scale = 0.45,
42937
42965
  children
42938
42966
  }, ref) => {
42939
42967
  const containerRef = React76.useRef(null);
@@ -43380,7 +43408,7 @@ var init_GameCanvas3D2 = __esm({
43380
43408
  fadeStrength: 1
43381
43409
  }
43382
43410
  ),
43383
- /* @__PURE__ */ jsxRuntime.jsxs("group", { scale, children: [
43411
+ /* @__PURE__ */ jsxRuntime.jsxs("group", { children: [
43384
43412
  tiles.map((tile, index) => {
43385
43413
  const position = gridToWorld(
43386
43414
  tile.x,
@@ -45697,6 +45725,35 @@ var init_ResourceCounter = __esm({
45697
45725
  ResourceCounter.displayName = "ResourceCounter";
45698
45726
  }
45699
45727
  });
45728
+ function dungeonTerrain(x, y, stairsX, stairsY) {
45729
+ const isBorder = x === 0 || y === 0 || x === DUNGEON_GRID_W - 1 || y === DUNGEON_GRID_H - 1;
45730
+ const isPillar = x % 4 === 0 && y % 4 === 0 && !isBorder;
45731
+ const isWall = isBorder || isPillar;
45732
+ if (x === stairsX && y === stairsY) {
45733
+ return { terrain: "stairs", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stairs_E.png` };
45734
+ }
45735
+ if (isWall) {
45736
+ return { terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` };
45737
+ }
45738
+ const variant = (x * 3 + y * 7) % 5;
45739
+ const sprites = [
45740
+ `${CDN4}/isometric-dungeon/Isometric/dirt_E.png`,
45741
+ `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png`,
45742
+ `${CDN4}/isometric-dungeon/Isometric/planks_E.png`,
45743
+ `${CDN4}/isometric-dungeon/Isometric/stoneTile_E.png`,
45744
+ `${CDN4}/isometric-dungeon/Isometric/dirt_E.png`
45745
+ ];
45746
+ return { terrain: "floor", passable: true, terrainSprite: sprites[variant] };
45747
+ }
45748
+ function buildDefaultDungeonTiles(stairsX, stairsY) {
45749
+ const tiles = [];
45750
+ for (let y = 0; y < DUNGEON_GRID_H; y++) {
45751
+ for (let x = 0; x < DUNGEON_GRID_W; x++) {
45752
+ tiles.push({ x, y, ...dungeonTerrain(x, y, stairsX, stairsY) });
45753
+ }
45754
+ }
45755
+ return tiles;
45756
+ }
45700
45757
  function RoguelikeBoard({
45701
45758
  entity,
45702
45759
  tiles: propTiles,
@@ -45712,7 +45769,7 @@ function RoguelikeBoard({
45712
45769
  stairsX: propStairsX,
45713
45770
  stairsY: propStairsY,
45714
45771
  assetManifest: propAssetManifest,
45715
- scale = 0.45,
45772
+ scale = 0.25,
45716
45773
  unitScale = 1,
45717
45774
  spriteHeightRatio = 1.5,
45718
45775
  spriteMaxWidthRatio = 0.6,
@@ -45722,7 +45779,9 @@ function RoguelikeBoard({
45722
45779
  className
45723
45780
  }) {
45724
45781
  const board = boardEntity(entity) ?? {};
45725
- const tiles = propTiles ?? (Array.isArray(board.tiles) ? board.tiles : DEFAULT_TILES2);
45782
+ const resolvedStairsX = propStairsX ?? num(board.stairsX, 14);
45783
+ const resolvedStairsY = propStairsY ?? num(board.stairsY, 14);
45784
+ const tiles = propTiles ?? (Array.isArray(board.tiles) && board.tiles.length >= DUNGEON_GRID_W * DUNGEON_GRID_H ? board.tiles : buildDefaultDungeonTiles(resolvedStairsX, resolvedStairsY));
45726
45785
  const enemies = propEnemies ?? (Array.isArray(board.enemies) ? board.enemies : DEFAULT_ENEMIES);
45727
45786
  const items = propItems ?? (Array.isArray(board.items) ? board.items : DEFAULT_ITEMS);
45728
45787
  const player = propPlayer ?? board.player ?? { x: 1, y: 1 };
@@ -45732,8 +45791,8 @@ function RoguelikeBoard({
45732
45791
  const depth = propDepth ?? num(board.depth, 1);
45733
45792
  const result = propResult ?? (str(board.result) || "none");
45734
45793
  const phase = propPhase ?? (str(board.phase) || "player_turn");
45735
- propStairsX ?? num(board.stairsX, 3);
45736
- propStairsY ?? num(board.stairsY, 3);
45794
+ propStairsX ?? num(board.stairsX, 14);
45795
+ propStairsY ?? num(board.stairsY, 14);
45737
45796
  const eventBus = useEventBus();
45738
45797
  const { t } = hooks.useTranslate();
45739
45798
  const [hoveredTile, setHoveredTile] = React76.useState(null);
@@ -45909,7 +45968,7 @@ function RoguelikeBoard({
45909
45968
  ] }) })
45910
45969
  ] });
45911
45970
  }
45912
- var CDN4, DEFAULT_TILES2, DEFAULT_ENEMIES, DEFAULT_ITEMS, FEATURE_SPRITE;
45971
+ var CDN4, DUNGEON_GRID_W, DUNGEON_GRID_H, DEFAULT_ENEMIES, DEFAULT_ITEMS, FEATURE_SPRITE;
45913
45972
  var init_RoguelikeBoard = __esm({
45914
45973
  "components/game/organisms/RoguelikeBoard.tsx"() {
45915
45974
  "use client";
@@ -45922,39 +45981,19 @@ var init_RoguelikeBoard = __esm({
45922
45981
  init_IsometricCanvas();
45923
45982
  init_boardEntity();
45924
45983
  CDN4 = "https://almadar-kflow-assets.web.app/shared";
45925
- DEFAULT_TILES2 = [
45926
- { x: 0, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
45927
- { x: 1, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
45928
- { x: 2, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
45929
- { x: 3, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
45930
- { x: 4, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
45931
- { x: 0, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
45932
- { x: 1, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
45933
- { x: 2, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
45934
- { x: 3, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
45935
- { x: 4, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
45936
- { x: 0, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
45937
- { x: 1, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png` },
45938
- { x: 2, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png` },
45939
- { x: 3, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
45940
- { x: 4, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
45941
- { x: 0, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
45942
- { x: 1, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
45943
- { x: 2, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png` },
45944
- { x: 3, y: 3, terrain: "stairs", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stairs_E.png` },
45945
- { x: 4, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
45946
- { x: 0, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
45947
- { x: 1, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
45948
- { x: 2, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
45949
- { x: 3, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
45950
- { x: 4, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` }
45951
- ];
45984
+ DUNGEON_GRID_W = 16;
45985
+ DUNGEON_GRID_H = 16;
45986
+ buildDefaultDungeonTiles(14, 14);
45952
45987
  DEFAULT_ENEMIES = [
45953
- { id: "e1", x: 3, y: 1, hp: 5, attack: 2 },
45954
- { id: "e2", x: 1, y: 3, hp: 4, attack: 1 }
45988
+ { id: "e1", x: 5, y: 2, hp: 5, attack: 2 },
45989
+ { id: "e2", x: 9, y: 6, hp: 4, attack: 1 },
45990
+ { id: "e3", x: 3, y: 10, hp: 6, attack: 2 },
45991
+ { id: "e4", x: 12, y: 8, hp: 5, attack: 3 }
45955
45992
  ];
45956
45993
  DEFAULT_ITEMS = [
45957
- { id: "i1", x: 2, y: 2, kind: "health_potion" }
45994
+ { id: "i1", x: 3, y: 3, kind: "health_potion" },
45995
+ { id: "i2", x: 7, y: 9, kind: "sword" },
45996
+ { id: "i3", x: 11, y: 5, kind: "shield" }
45958
45997
  ];
45959
45998
  FEATURE_SPRITE = {
45960
45999
  health_potion: `${CDN4}/isometric-dungeon/Isometric/chestClosed_E.png`,
@@ -50403,6 +50442,22 @@ var init_ToastSlot = __esm({
50403
50442
  exports.ToastSlot.displayName = "ToastSlot";
50404
50443
  }
50405
50444
  });
50445
+ function buildDefaultTDTiles() {
50446
+ const pathSet = new Set(DEFAULT_TD_PATH.map((p2) => `${p2.x},${p2.y}`));
50447
+ const tiles = [];
50448
+ for (let y = 0; y < TD_GRID_H; y++) {
50449
+ for (let x = 0; x < TD_GRID_W; x++) {
50450
+ if (pathSet.has(`${x},${y}`)) {
50451
+ tiles.push({ x, y, terrain: "path", passable: false, terrainSprite: TERRAIN_SPRITES.path });
50452
+ } else {
50453
+ const variant = (x * 3 + y * 5 + (x ^ y)) % 3;
50454
+ const terrainKey = ["ground", "grass", "dirt"][variant];
50455
+ tiles.push({ x, y, terrain: terrainKey, passable: true, terrainSprite: TERRAIN_SPRITES[terrainKey] ?? TERRAIN_SPRITES.ground });
50456
+ }
50457
+ }
50458
+ }
50459
+ return tiles;
50460
+ }
50406
50461
  function tilesToIso(tiles) {
50407
50462
  return tiles.map((t) => ({
50408
50463
  x: t.x,
@@ -50445,12 +50500,25 @@ function pathToFeatures(path) {
50445
50500
  sprite: `${CDN6}world-map/road_straight.png`
50446
50501
  }));
50447
50502
  }
50503
+ function heroToUnit(hero) {
50504
+ return {
50505
+ id: hero.id,
50506
+ position: { x: hero.x, y: hero.y },
50507
+ name: "Hero",
50508
+ team: "player",
50509
+ sprite: HERO_SPRITE,
50510
+ unitType: "amir",
50511
+ health: 1,
50512
+ maxHealth: 1
50513
+ };
50514
+ }
50448
50515
  function TowerDefenseBoard({
50449
50516
  entity,
50450
50517
  tiles: propTiles,
50451
50518
  path: propPath,
50452
50519
  towers: propTowers,
50453
50520
  creeps: propCreeps,
50521
+ hero: propHero,
50454
50522
  gold: propGold,
50455
50523
  lives: propLives,
50456
50524
  wave: propWave,
@@ -50458,7 +50526,7 @@ function TowerDefenseBoard({
50458
50526
  result: propResult,
50459
50527
  waveActive: propWaveActive,
50460
50528
  towerCost = 25,
50461
- scale = 0.45,
50529
+ scale = 0.25,
50462
50530
  unitScale = 1,
50463
50531
  spriteHeightRatio = 1.5,
50464
50532
  spriteMaxWidthRatio = 0.6,
@@ -50466,15 +50534,19 @@ function TowerDefenseBoard({
50466
50534
  startWaveEvent,
50467
50535
  playAgainEvent,
50468
50536
  gameEndEvent,
50537
+ moveHeroEvent,
50469
50538
  className
50470
50539
  }) {
50471
50540
  const board = boardEntity(entity) ?? {};
50472
50541
  const eventBus = useEventBus();
50473
50542
  const { t } = hooks.useTranslate();
50474
- const tiles = propTiles ?? rows(board.tiles);
50475
- const path = propPath ?? rows(board.path);
50543
+ const rawTiles = propTiles ?? rows(board.tiles);
50544
+ const tiles = rawTiles.length >= TD_GRID_W * TD_GRID_H ? rawTiles : DEFAULT_TD_TILES;
50545
+ const rawPath = propPath ?? rows(board.path);
50546
+ const path = rawPath.length > 0 ? rawPath : DEFAULT_TD_PATH;
50476
50547
  const towers = propTowers ?? rows(board.towers);
50477
50548
  const creeps = propCreeps ?? rows(board.creeps);
50549
+ const hero = propHero ?? { id: "hero", x: 8, y: 8 };
50478
50550
  const gold = propGold ?? num(board.gold, 100);
50479
50551
  const lives = propLives ?? num(board.lives, 20);
50480
50552
  const wave = propWave ?? num(board.wave, 1);
@@ -50492,6 +50564,31 @@ function TowerDefenseBoard({
50492
50564
  if (result === "none") {
50493
50565
  emittedGameEnd.current = false;
50494
50566
  }
50567
+ const moveHeroEventRef = React76.useRef(moveHeroEvent);
50568
+ moveHeroEventRef.current = moveHeroEvent;
50569
+ const resultRef = React76.useRef(result);
50570
+ resultRef.current = result;
50571
+ React76.useEffect(() => {
50572
+ function onKeyDown(e) {
50573
+ const evt = moveHeroEventRef.current;
50574
+ if (!evt || resultRef.current !== "none") return;
50575
+ let dx = 0;
50576
+ let dy = 0;
50577
+ if (e.key === "ArrowUp") {
50578
+ dy = -1;
50579
+ } else if (e.key === "ArrowDown") {
50580
+ dy = 1;
50581
+ } else if (e.key === "ArrowLeft") {
50582
+ dx = -1;
50583
+ } else if (e.key === "ArrowRight") {
50584
+ dx = 1;
50585
+ } else return;
50586
+ e.preventDefault();
50587
+ eventBus.emit(`UI:${evt}`, { dx, dy });
50588
+ }
50589
+ window.addEventListener("keydown", onKeyDown);
50590
+ return () => window.removeEventListener("keydown", onKeyDown);
50591
+ }, [eventBus]);
50495
50592
  const towerPositions = React76.useMemo(() => new Set(towers.map((t2) => `${t2.x},${t2.y}`)), [towers]);
50496
50593
  const pathPositions = React76.useMemo(() => new Set(path.map((p2) => `${p2.x},${p2.y}`)), [path]);
50497
50594
  const validMoves = React76.useMemo(() => {
@@ -50503,7 +50600,8 @@ function TowerDefenseBoard({
50503
50600
  const isoTiles = React76.useMemo(() => tilesToIso(tiles), [tiles]);
50504
50601
  const towerUnits = React76.useMemo(() => towersToUnits(towers), [towers]);
50505
50602
  const creepUnits = React76.useMemo(() => creepsToUnits(creeps), [creeps]);
50506
- const isoUnits = React76.useMemo(() => [...towerUnits, ...creepUnits], [towerUnits, creepUnits]);
50603
+ const heroUnit = React76.useMemo(() => heroToUnit(hero), [hero]);
50604
+ const isoUnits = React76.useMemo(() => [...towerUnits, ...creepUnits, heroUnit], [towerUnits, creepUnits, heroUnit]);
50507
50605
  const pathFeatures = React76.useMemo(() => pathToFeatures(path), [path]);
50508
50606
  const handleTileClick = React76.useCallback((x, y) => {
50509
50607
  if (result !== "none") return;
@@ -50602,7 +50700,7 @@ function TowerDefenseBoard({
50602
50700
  ] }) })
50603
50701
  ] });
50604
50702
  }
50605
- var CDN6, TERRAIN_SPRITES, TOWER_SPRITE, CREEP_SPRITE;
50703
+ var CDN6, TD_GRID_W, TD_GRID_H, TERRAIN_SPRITES, DEFAULT_TD_PATH, DEFAULT_TD_TILES, TOWER_SPRITE, CREEP_SPRITE, HERO_SPRITE;
50606
50704
  var init_TowerDefenseBoard = __esm({
50607
50705
  "components/game/organisms/TowerDefenseBoard.tsx"() {
50608
50706
  "use client";
@@ -50615,13 +50713,70 @@ var init_TowerDefenseBoard = __esm({
50615
50713
  init_IsometricCanvas();
50616
50714
  init_boardEntity();
50617
50715
  CDN6 = "https://almadar-kflow-assets.web.app/shared/";
50716
+ TD_GRID_W = 16;
50717
+ TD_GRID_H = 16;
50618
50718
  TERRAIN_SPRITES = {
50619
50719
  ground: `${CDN6}isometric-blocks/PNG/Platformer tiles/platformerTile_01.png`,
50620
50720
  path: `${CDN6}isometric-blocks/PNG/Platformer tiles/platformerTile_09.png`,
50621
- wall: `${CDN6}isometric-blocks/PNG/Platformer tiles/platformerTile_05.png`
50622
- };
50623
- TOWER_SPRITE = `${CDN6}units/guardian.png`;
50624
- CREEP_SPRITE = `${CDN6}units/scrapper.png`;
50721
+ wall: `${CDN6}isometric-blocks/PNG/Platformer tiles/platformerTile_05.png`,
50722
+ grass: `${CDN6}isometric-dungeon/Isometric/dirt_E.png`,
50723
+ dirt: `${CDN6}isometric-dungeon/Isometric/dirtTiles_E.png`
50724
+ };
50725
+ DEFAULT_TD_PATH = [
50726
+ { x: 2, y: 0 },
50727
+ { x: 2, y: 1 },
50728
+ { x: 2, y: 2 },
50729
+ { x: 2, y: 3 },
50730
+ { x: 3, y: 3 },
50731
+ { x: 4, y: 3 },
50732
+ { x: 5, y: 3 },
50733
+ { x: 6, y: 3 },
50734
+ { x: 7, y: 3 },
50735
+ { x: 8, y: 3 },
50736
+ { x: 9, y: 3 },
50737
+ { x: 10, y: 3 },
50738
+ { x: 11, y: 3 },
50739
+ { x: 12, y: 3 },
50740
+ { x: 13, y: 3 },
50741
+ { x: 13, y: 4 },
50742
+ { x: 13, y: 5 },
50743
+ { x: 13, y: 6 },
50744
+ { x: 13, y: 7 },
50745
+ { x: 12, y: 7 },
50746
+ { x: 11, y: 7 },
50747
+ { x: 10, y: 7 },
50748
+ { x: 9, y: 7 },
50749
+ { x: 8, y: 7 },
50750
+ { x: 7, y: 7 },
50751
+ { x: 6, y: 7 },
50752
+ { x: 5, y: 7 },
50753
+ { x: 4, y: 7 },
50754
+ { x: 3, y: 7 },
50755
+ { x: 2, y: 7 },
50756
+ { x: 2, y: 8 },
50757
+ { x: 2, y: 9 },
50758
+ { x: 2, y: 10 },
50759
+ { x: 2, y: 11 },
50760
+ { x: 3, y: 11 },
50761
+ { x: 4, y: 11 },
50762
+ { x: 5, y: 11 },
50763
+ { x: 6, y: 11 },
50764
+ { x: 7, y: 11 },
50765
+ { x: 8, y: 11 },
50766
+ { x: 9, y: 11 },
50767
+ { x: 10, y: 11 },
50768
+ { x: 11, y: 11 },
50769
+ { x: 12, y: 11 },
50770
+ { x: 13, y: 11 },
50771
+ { x: 13, y: 12 },
50772
+ { x: 13, y: 13 },
50773
+ { x: 13, y: 14 },
50774
+ { x: 13, y: 15 }
50775
+ ];
50776
+ DEFAULT_TD_TILES = buildDefaultTDTiles();
50777
+ TOWER_SPRITE = `${CDN6}sprite-sheets/guardian-sprite-sheet-se.png`;
50778
+ CREEP_SPRITE = `${CDN6}sprite-sheets/scrapper-sprite-sheet-se.png`;
50779
+ HERO_SPRITE = `${CDN6}sprite-sheets/amir-sprite-sheet-se.png`;
50625
50780
  TowerDefenseBoard.displayName = "TowerDefenseBoard";
50626
50781
  }
50627
50782
  });
@@ -50896,6 +51051,17 @@ function heroPosition(h) {
50896
51051
  function heroMovement(h) {
50897
51052
  return num(h.movement);
50898
51053
  }
51054
+ function buildDefaultWorldTiles() {
51055
+ const tiles = [];
51056
+ for (let y = 0; y < WORLD_GRID_H; y++) {
51057
+ for (let x = 0; x < WORLD_GRID_W; x++) {
51058
+ const isBorder = x === 0 || y === 0 || x === WORLD_GRID_W - 1 || y === WORLD_GRID_H - 1;
51059
+ const def = isBorder ? WORLD_TERRAIN_DEFS[3] : WORLD_TERRAIN_DEFS[(x * 5 + y * 3 + (x ^ y)) % (WORLD_TERRAIN_DEFS.length - 1)];
51060
+ tiles.push({ x, y, terrain: def.terrain, terrainSprite: def.sprite, passable: def.passable });
51061
+ }
51062
+ }
51063
+ return tiles;
51064
+ }
50899
51065
  function defaultIsInRange(from, to, range) {
50900
51066
  return Math.abs(from.x - to.x) + Math.abs(from.y - to.y) <= range;
50901
51067
  }
@@ -50906,7 +51072,7 @@ function WorldMapBoard({
50906
51072
  features: propFeatures,
50907
51073
  assetManifest: propAssetManifest,
50908
51074
  isLoading,
50909
- scale = 0.4,
51075
+ scale = 0.25,
50910
51076
  unitScale = 2.5,
50911
51077
  spriteHeightRatio = 1.5,
50912
51078
  spriteMaxWidthRatio = 0.6,
@@ -50950,7 +51116,8 @@ function WorldMapBoard({
50950
51116
  })),
50951
51117
  [entityTiles]
50952
51118
  );
50953
- const tiles = propTiles ?? derivedTiles;
51119
+ const rawTiles = propTiles ?? (derivedTiles.length > 0 ? derivedTiles : null);
51120
+ const tiles = rawTiles != null && rawTiles.length >= WORLD_GRID_W * WORLD_GRID_H ? rawTiles : DEFAULT_WORLD_TILES;
50954
51121
  const baseUnits = React76.useMemo(
50955
51122
  () => propUnits ?? entityUnits.map((u) => ({
50956
51123
  id: str(u.id),
@@ -51160,6 +51327,7 @@ function WorldMapBoard({
51160
51327
  footer && footer(ctx)
51161
51328
  ] });
51162
51329
  }
51330
+ var WORLD_CDN, WORLD_GRID_W, WORLD_GRID_H, WORLD_TERRAIN_DEFS, DEFAULT_WORLD_TILES;
51163
51331
  var init_WorldMapBoard = __esm({
51164
51332
  "components/game/organisms/WorldMapBoard.tsx"() {
51165
51333
  "use client";
@@ -51170,6 +51338,17 @@ var init_WorldMapBoard = __esm({
51170
51338
  init_IsometricCanvas();
51171
51339
  init_boardEntity();
51172
51340
  init_isometric();
51341
+ WORLD_CDN = "https://almadar-kflow-assets.web.app/shared";
51342
+ WORLD_GRID_W = 16;
51343
+ WORLD_GRID_H = 16;
51344
+ WORLD_TERRAIN_DEFS = [
51345
+ { terrain: "grass", sprite: `${WORLD_CDN}/isometric-dungeon/Isometric/dirt_E.png`, passable: true },
51346
+ { terrain: "dirt", sprite: `${WORLD_CDN}/isometric-dungeon/Isometric/dirtTiles_E.png`, passable: true },
51347
+ { terrain: "forest", sprite: `${WORLD_CDN}/isometric-dungeon/Isometric/planks_E.png`, passable: true },
51348
+ { terrain: "stone", sprite: `${WORLD_CDN}/isometric-dungeon/Isometric/stoneInset_E.png`, passable: false },
51349
+ { terrain: "castle", sprite: `${WORLD_CDN}/isometric-dungeon/Isometric/stoneTile_E.png`, passable: true }
51350
+ ];
51351
+ DEFAULT_WORLD_TILES = buildDefaultWorldTiles();
51173
51352
  WorldMapBoard.displayName = "WorldMapBoard";
51174
51353
  }
51175
51354
  });