@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.
@@ -11564,13 +11564,29 @@ var init_boardEntity = __esm({
11564
11564
  "components/game/organisms/boardEntity.ts"() {
11565
11565
  }
11566
11566
  });
11567
+ function buildDefaultBattleTiles() {
11568
+ const tiles = [];
11569
+ for (let y = 0; y < BATTLE_GRID_H; y++) {
11570
+ for (let x = 0; x < BATTLE_GRID_W; x++) {
11571
+ const variant = (x * 3 + y * 7 + (x ^ y)) % BATTLE_TERRAIN_SPRITES.length;
11572
+ tiles.push({
11573
+ x,
11574
+ y,
11575
+ terrain: ["grass", "dirt", "planks", "stone", "stone"][variant],
11576
+ terrainSprite: BATTLE_TERRAIN_SPRITES[variant],
11577
+ passable: true
11578
+ });
11579
+ }
11580
+ }
11581
+ return tiles;
11582
+ }
11567
11583
  function BattleBoard({
11568
11584
  entity,
11569
11585
  tiles: propTiles,
11570
11586
  units: propUnits,
11571
11587
  features: propFeatures,
11572
11588
  assetManifest: propAssetManifest,
11573
- scale = 0.45,
11589
+ scale = 0.25,
11574
11590
  unitScale = 1,
11575
11591
  spriteHeightRatio = 1.5,
11576
11592
  spriteMaxWidthRatio = 0.6,
@@ -11597,10 +11613,11 @@ function BattleBoard({
11597
11613
  className
11598
11614
  }) {
11599
11615
  const board = boardEntity(entity) ?? {};
11600
- const tiles = propTiles ?? (Array.isArray(board.tiles) ? board.tiles : []);
11616
+ const rawTiles = propTiles ?? (Array.isArray(board.tiles) ? board.tiles : []);
11617
+ const tiles = rawTiles.length === 0 ? DEFAULT_BATTLE_TILES : rawTiles;
11601
11618
  const features = propFeatures ?? (Array.isArray(board.features) ? board.features : []);
11602
- const boardWidth = num(board.gridWidth ?? board.boardWidth, 8);
11603
- const boardHeight = num(board.gridHeight ?? board.boardHeight, 6);
11619
+ const boardWidth = num(board.gridWidth ?? board.boardWidth, BATTLE_GRID_W);
11620
+ const boardHeight = num(board.gridHeight ?? board.boardHeight, BATTLE_GRID_H);
11604
11621
  const assetManifest = propAssetManifest ?? board.assetManifest;
11605
11622
  const backgroundImage = board.backgroundImage;
11606
11623
  const units = rows(board.units);
@@ -11922,6 +11939,7 @@ function BattleBoard({
11922
11939
  ] }) }))
11923
11940
  ] });
11924
11941
  }
11942
+ var BATTLE_CDN, BATTLE_GRID_W, BATTLE_GRID_H, BATTLE_TERRAIN_SPRITES, DEFAULT_BATTLE_TILES;
11925
11943
  var init_BattleBoard = __esm({
11926
11944
  "components/game/organisms/BattleBoard.tsx"() {
11927
11945
  "use client";
@@ -11934,6 +11952,17 @@ var init_BattleBoard = __esm({
11934
11952
  init_IsometricCanvas();
11935
11953
  init_boardEntity();
11936
11954
  init_isometric();
11955
+ BATTLE_CDN = "https://almadar-kflow-assets.web.app/shared";
11956
+ BATTLE_GRID_W = 16;
11957
+ BATTLE_GRID_H = 16;
11958
+ BATTLE_TERRAIN_SPRITES = [
11959
+ `${BATTLE_CDN}/isometric-dungeon/Isometric/dirt_E.png`,
11960
+ `${BATTLE_CDN}/isometric-dungeon/Isometric/dirtTiles_E.png`,
11961
+ `${BATTLE_CDN}/isometric-dungeon/Isometric/planks_E.png`,
11962
+ `${BATTLE_CDN}/isometric-dungeon/Isometric/stoneTile_E.png`,
11963
+ `${BATTLE_CDN}/isometric-dungeon/Isometric/stoneInset_E.png`
11964
+ ];
11965
+ DEFAULT_BATTLE_TILES = buildDefaultBattleTiles();
11937
11966
  BattleBoard.displayName = "BattleBoard";
11938
11967
  }
11939
11968
  });
@@ -11941,7 +11970,7 @@ function BattleTemplate({
11941
11970
  entity,
11942
11971
  scale = 0.45,
11943
11972
  unitScale = 1,
11944
- tiles = DEFAULT_BATTLE_TILES,
11973
+ tiles = DEFAULT_BATTLE_TILES2,
11945
11974
  units = DEFAULT_BATTLE_UNITS,
11946
11975
  features = DEFAULT_BATTLE_FEATURES,
11947
11976
  assetManifest = DEFAULT_BATTLE_MANIFEST,
@@ -11970,12 +11999,12 @@ function BattleTemplate({
11970
11999
  }
11971
12000
  );
11972
12001
  }
11973
- var CDN, DEFAULT_BATTLE_TILES, DEFAULT_BATTLE_UNITS, DEFAULT_BATTLE_FEATURES, DEFAULT_BATTLE_MANIFEST;
12002
+ var CDN, DEFAULT_BATTLE_TILES2, DEFAULT_BATTLE_UNITS, DEFAULT_BATTLE_FEATURES, DEFAULT_BATTLE_MANIFEST;
11974
12003
  var init_BattleTemplate = __esm({
11975
12004
  "components/game/templates/BattleTemplate.tsx"() {
11976
12005
  init_BattleBoard();
11977
12006
  CDN = "https://almadar-kflow-assets.web.app/shared";
11978
- DEFAULT_BATTLE_TILES = [
12007
+ DEFAULT_BATTLE_TILES2 = [
11979
12008
  { x: 0, y: 0, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
11980
12009
  { x: 1, y: 0, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
11981
12010
  { x: 2, y: 0, terrain: "stone", passable: false, terrainSprite: `${CDN}/isometric-blocks/PNG/Abstract tiles/abstractTile_07.png` },
@@ -29144,13 +29173,13 @@ var init_MapView = __esm({
29144
29173
  shadowSize: [41, 41]
29145
29174
  });
29146
29175
  L.Marker.prototype.options.icon = defaultIcon;
29147
- const { useEffect: useEffect81, useRef: useRef75, useCallback: useCallback119, useState: useState113 } = React81__default;
29176
+ const { useEffect: useEffect82, useRef: useRef75, useCallback: useCallback119, useState: useState113 } = React81__default;
29148
29177
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
29149
29178
  const { useEventBus: useEventBus4 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
29150
29179
  function MapUpdater({ centerLat, centerLng, zoom }) {
29151
29180
  const map = useMap();
29152
29181
  const prevRef = useRef75({ centerLat, centerLng, zoom });
29153
- useEffect81(() => {
29182
+ useEffect82(() => {
29154
29183
  const prev = prevRef.current;
29155
29184
  if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
29156
29185
  map.setView([centerLat, centerLng], zoom);
@@ -29161,7 +29190,7 @@ var init_MapView = __esm({
29161
29190
  }
29162
29191
  function MapClickHandler({ onMapClick }) {
29163
29192
  const map = useMap();
29164
- useEffect81(() => {
29193
+ useEffect82(() => {
29165
29194
  if (!onMapClick) return;
29166
29195
  const handler = (e) => {
29167
29196
  onMapClick(e.latlng.lat, e.latlng.lng);
@@ -41838,7 +41867,6 @@ var init_GameCanvas3D2 = __esm({
41838
41867
  selectedTileIds = [],
41839
41868
  selectedUnitId = null,
41840
41869
  unitScale = 1,
41841
- scale = 0.45,
41842
41870
  children
41843
41871
  }, ref) => {
41844
41872
  const containerRef = useRef(null);
@@ -42285,7 +42313,7 @@ var init_GameCanvas3D2 = __esm({
42285
42313
  fadeStrength: 1
42286
42314
  }
42287
42315
  ),
42288
- /* @__PURE__ */ jsxs("group", { scale, children: [
42316
+ /* @__PURE__ */ jsxs("group", { children: [
42289
42317
  tiles.map((tile, index) => {
42290
42318
  const position = gridToWorld(
42291
42319
  tile.x,
@@ -44428,6 +44456,35 @@ var init_PricingPageTemplate = __esm({
44428
44456
  PricingPageTemplate.displayName = "PricingPageTemplate";
44429
44457
  }
44430
44458
  });
44459
+ function dungeonTerrain(x, y, stairsX, stairsY) {
44460
+ const isBorder = x === 0 || y === 0 || x === DUNGEON_GRID_W - 1 || y === DUNGEON_GRID_H - 1;
44461
+ const isPillar = x % 4 === 0 && y % 4 === 0 && !isBorder;
44462
+ const isWall = isBorder || isPillar;
44463
+ if (x === stairsX && y === stairsY) {
44464
+ return { terrain: "stairs", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stairs_E.png` };
44465
+ }
44466
+ if (isWall) {
44467
+ return { terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` };
44468
+ }
44469
+ const variant = (x * 3 + y * 7) % 5;
44470
+ const sprites = [
44471
+ `${CDN4}/isometric-dungeon/Isometric/dirt_E.png`,
44472
+ `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png`,
44473
+ `${CDN4}/isometric-dungeon/Isometric/planks_E.png`,
44474
+ `${CDN4}/isometric-dungeon/Isometric/stoneTile_E.png`,
44475
+ `${CDN4}/isometric-dungeon/Isometric/dirt_E.png`
44476
+ ];
44477
+ return { terrain: "floor", passable: true, terrainSprite: sprites[variant] };
44478
+ }
44479
+ function buildDefaultDungeonTiles(stairsX, stairsY) {
44480
+ const tiles = [];
44481
+ for (let y = 0; y < DUNGEON_GRID_H; y++) {
44482
+ for (let x = 0; x < DUNGEON_GRID_W; x++) {
44483
+ tiles.push({ x, y, ...dungeonTerrain(x, y, stairsX, stairsY) });
44484
+ }
44485
+ }
44486
+ return tiles;
44487
+ }
44431
44488
  function RoguelikeBoard({
44432
44489
  entity,
44433
44490
  tiles: propTiles,
@@ -44443,7 +44500,7 @@ function RoguelikeBoard({
44443
44500
  stairsX: propStairsX,
44444
44501
  stairsY: propStairsY,
44445
44502
  assetManifest: propAssetManifest,
44446
- scale = 0.45,
44503
+ scale = 0.25,
44447
44504
  unitScale = 1,
44448
44505
  spriteHeightRatio = 1.5,
44449
44506
  spriteMaxWidthRatio = 0.6,
@@ -44453,7 +44510,9 @@ function RoguelikeBoard({
44453
44510
  className
44454
44511
  }) {
44455
44512
  const board = boardEntity(entity) ?? {};
44456
- const tiles = propTiles ?? (Array.isArray(board.tiles) ? board.tiles : DEFAULT_TILES2);
44513
+ const resolvedStairsX = propStairsX ?? num(board.stairsX, 14);
44514
+ const resolvedStairsY = propStairsY ?? num(board.stairsY, 14);
44515
+ const tiles = propTiles ?? (Array.isArray(board.tiles) && board.tiles.length >= DUNGEON_GRID_W * DUNGEON_GRID_H ? board.tiles : buildDefaultDungeonTiles(resolvedStairsX, resolvedStairsY));
44457
44516
  const enemies = propEnemies ?? (Array.isArray(board.enemies) ? board.enemies : DEFAULT_ENEMIES);
44458
44517
  const items = propItems ?? (Array.isArray(board.items) ? board.items : DEFAULT_ITEMS);
44459
44518
  const player = propPlayer ?? board.player ?? { x: 1, y: 1 };
@@ -44463,8 +44522,8 @@ function RoguelikeBoard({
44463
44522
  const depth = propDepth ?? num(board.depth, 1);
44464
44523
  const result = propResult ?? (str(board.result) || "none");
44465
44524
  const phase = propPhase ?? (str(board.phase) || "player_turn");
44466
- propStairsX ?? num(board.stairsX, 3);
44467
- propStairsY ?? num(board.stairsY, 3);
44525
+ propStairsX ?? num(board.stairsX, 14);
44526
+ propStairsY ?? num(board.stairsY, 14);
44468
44527
  const eventBus = useEventBus();
44469
44528
  const { t } = useTranslate();
44470
44529
  const [hoveredTile, setHoveredTile] = useState(null);
@@ -44640,7 +44699,7 @@ function RoguelikeBoard({
44640
44699
  ] }) })
44641
44700
  ] });
44642
44701
  }
44643
- var CDN4, DEFAULT_TILES2, DEFAULT_ENEMIES, DEFAULT_ITEMS, FEATURE_SPRITE;
44702
+ var CDN4, DUNGEON_GRID_W, DUNGEON_GRID_H, DEFAULT_ENEMIES, DEFAULT_ITEMS, FEATURE_SPRITE;
44644
44703
  var init_RoguelikeBoard = __esm({
44645
44704
  "components/game/organisms/RoguelikeBoard.tsx"() {
44646
44705
  "use client";
@@ -44653,39 +44712,19 @@ var init_RoguelikeBoard = __esm({
44653
44712
  init_IsometricCanvas();
44654
44713
  init_boardEntity();
44655
44714
  CDN4 = "https://almadar-kflow-assets.web.app/shared";
44656
- DEFAULT_TILES2 = [
44657
- { x: 0, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
44658
- { x: 1, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
44659
- { x: 2, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
44660
- { x: 3, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
44661
- { x: 4, y: 0, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
44662
- { x: 0, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
44663
- { x: 1, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
44664
- { x: 2, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
44665
- { x: 3, y: 1, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
44666
- { x: 4, y: 1, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
44667
- { x: 0, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
44668
- { x: 1, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png` },
44669
- { x: 2, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png` },
44670
- { x: 3, y: 2, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
44671
- { x: 4, y: 2, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
44672
- { x: 0, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
44673
- { x: 1, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirt_E.png` },
44674
- { x: 2, y: 3, terrain: "floor", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/dirtTiles_E.png` },
44675
- { x: 3, y: 3, terrain: "stairs", passable: true, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stairs_E.png` },
44676
- { x: 4, y: 3, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
44677
- { x: 0, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
44678
- { x: 1, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
44679
- { x: 2, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
44680
- { x: 3, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` },
44681
- { x: 4, y: 4, terrain: "wall", passable: false, terrainSprite: `${CDN4}/isometric-dungeon/Isometric/stoneInset_E.png` }
44682
- ];
44715
+ DUNGEON_GRID_W = 16;
44716
+ DUNGEON_GRID_H = 16;
44717
+ buildDefaultDungeonTiles(14, 14);
44683
44718
  DEFAULT_ENEMIES = [
44684
- { id: "e1", x: 3, y: 1, hp: 5, attack: 2 },
44685
- { id: "e2", x: 1, y: 3, hp: 4, attack: 1 }
44719
+ { id: "e1", x: 5, y: 2, hp: 5, attack: 2 },
44720
+ { id: "e2", x: 9, y: 6, hp: 4, attack: 1 },
44721
+ { id: "e3", x: 3, y: 10, hp: 6, attack: 2 },
44722
+ { id: "e4", x: 12, y: 8, hp: 5, attack: 3 }
44686
44723
  ];
44687
44724
  DEFAULT_ITEMS = [
44688
- { id: "i1", x: 2, y: 2, kind: "health_potion" }
44725
+ { id: "i1", x: 3, y: 3, kind: "health_potion" },
44726
+ { id: "i2", x: 7, y: 9, kind: "sword" },
44727
+ { id: "i3", x: 11, y: 5, kind: "shield" }
44689
44728
  ];
44690
44729
  FEATURE_SPRITE = {
44691
44730
  health_potion: `${CDN4}/isometric-dungeon/Isometric/chestClosed_E.png`,
@@ -48912,6 +48951,22 @@ var init_ToastSlot = __esm({
48912
48951
  ToastSlot.displayName = "ToastSlot";
48913
48952
  }
48914
48953
  });
48954
+ function buildDefaultTDTiles() {
48955
+ const pathSet = new Set(DEFAULT_TD_PATH.map((p2) => `${p2.x},${p2.y}`));
48956
+ const tiles = [];
48957
+ for (let y = 0; y < TD_GRID_H; y++) {
48958
+ for (let x = 0; x < TD_GRID_W; x++) {
48959
+ if (pathSet.has(`${x},${y}`)) {
48960
+ tiles.push({ x, y, terrain: "path", passable: false, terrainSprite: TERRAIN_SPRITES.path });
48961
+ } else {
48962
+ const variant = (x * 3 + y * 5 + (x ^ y)) % 3;
48963
+ const terrainKey = ["ground", "grass", "dirt"][variant];
48964
+ tiles.push({ x, y, terrain: terrainKey, passable: true, terrainSprite: TERRAIN_SPRITES[terrainKey] ?? TERRAIN_SPRITES.ground });
48965
+ }
48966
+ }
48967
+ }
48968
+ return tiles;
48969
+ }
48915
48970
  function tilesToIso(tiles) {
48916
48971
  return tiles.map((t) => ({
48917
48972
  x: t.x,
@@ -48954,12 +49009,25 @@ function pathToFeatures(path) {
48954
49009
  sprite: `${CDN6}world-map/road_straight.png`
48955
49010
  }));
48956
49011
  }
49012
+ function heroToUnit(hero) {
49013
+ return {
49014
+ id: hero.id,
49015
+ position: { x: hero.x, y: hero.y },
49016
+ name: "Hero",
49017
+ team: "player",
49018
+ sprite: HERO_SPRITE,
49019
+ unitType: "amir",
49020
+ health: 1,
49021
+ maxHealth: 1
49022
+ };
49023
+ }
48957
49024
  function TowerDefenseBoard({
48958
49025
  entity,
48959
49026
  tiles: propTiles,
48960
49027
  path: propPath,
48961
49028
  towers: propTowers,
48962
49029
  creeps: propCreeps,
49030
+ hero: propHero,
48963
49031
  gold: propGold,
48964
49032
  lives: propLives,
48965
49033
  wave: propWave,
@@ -48967,7 +49035,7 @@ function TowerDefenseBoard({
48967
49035
  result: propResult,
48968
49036
  waveActive: propWaveActive,
48969
49037
  towerCost = 25,
48970
- scale = 0.45,
49038
+ scale = 0.25,
48971
49039
  unitScale = 1,
48972
49040
  spriteHeightRatio = 1.5,
48973
49041
  spriteMaxWidthRatio = 0.6,
@@ -48975,15 +49043,19 @@ function TowerDefenseBoard({
48975
49043
  startWaveEvent,
48976
49044
  playAgainEvent,
48977
49045
  gameEndEvent,
49046
+ moveHeroEvent,
48978
49047
  className
48979
49048
  }) {
48980
49049
  const board = boardEntity(entity) ?? {};
48981
49050
  const eventBus = useEventBus();
48982
49051
  const { t } = useTranslate();
48983
- const tiles = propTiles ?? rows(board.tiles);
48984
- const path = propPath ?? rows(board.path);
49052
+ const rawTiles = propTiles ?? rows(board.tiles);
49053
+ const tiles = rawTiles.length >= TD_GRID_W * TD_GRID_H ? rawTiles : DEFAULT_TD_TILES;
49054
+ const rawPath = propPath ?? rows(board.path);
49055
+ const path = rawPath.length > 0 ? rawPath : DEFAULT_TD_PATH;
48985
49056
  const towers = propTowers ?? rows(board.towers);
48986
49057
  const creeps = propCreeps ?? rows(board.creeps);
49058
+ const hero = propHero ?? { id: "hero", x: 8, y: 8 };
48987
49059
  const gold = propGold ?? num(board.gold, 100);
48988
49060
  const lives = propLives ?? num(board.lives, 20);
48989
49061
  const wave = propWave ?? num(board.wave, 1);
@@ -49001,6 +49073,31 @@ function TowerDefenseBoard({
49001
49073
  if (result === "none") {
49002
49074
  emittedGameEnd.current = false;
49003
49075
  }
49076
+ const moveHeroEventRef = useRef(moveHeroEvent);
49077
+ moveHeroEventRef.current = moveHeroEvent;
49078
+ const resultRef = useRef(result);
49079
+ resultRef.current = result;
49080
+ useEffect(() => {
49081
+ function onKeyDown(e) {
49082
+ const evt = moveHeroEventRef.current;
49083
+ if (!evt || resultRef.current !== "none") return;
49084
+ let dx = 0;
49085
+ let dy = 0;
49086
+ if (e.key === "ArrowUp") {
49087
+ dy = -1;
49088
+ } else if (e.key === "ArrowDown") {
49089
+ dy = 1;
49090
+ } else if (e.key === "ArrowLeft") {
49091
+ dx = -1;
49092
+ } else if (e.key === "ArrowRight") {
49093
+ dx = 1;
49094
+ } else return;
49095
+ e.preventDefault();
49096
+ eventBus.emit(`UI:${evt}`, { dx, dy });
49097
+ }
49098
+ window.addEventListener("keydown", onKeyDown);
49099
+ return () => window.removeEventListener("keydown", onKeyDown);
49100
+ }, [eventBus]);
49004
49101
  const towerPositions = useMemo(() => new Set(towers.map((t2) => `${t2.x},${t2.y}`)), [towers]);
49005
49102
  const pathPositions = useMemo(() => new Set(path.map((p2) => `${p2.x},${p2.y}`)), [path]);
49006
49103
  const validMoves = useMemo(() => {
@@ -49012,7 +49109,8 @@ function TowerDefenseBoard({
49012
49109
  const isoTiles = useMemo(() => tilesToIso(tiles), [tiles]);
49013
49110
  const towerUnits = useMemo(() => towersToUnits(towers), [towers]);
49014
49111
  const creepUnits = useMemo(() => creepsToUnits(creeps), [creeps]);
49015
- const isoUnits = useMemo(() => [...towerUnits, ...creepUnits], [towerUnits, creepUnits]);
49112
+ const heroUnit = useMemo(() => heroToUnit(hero), [hero]);
49113
+ const isoUnits = useMemo(() => [...towerUnits, ...creepUnits, heroUnit], [towerUnits, creepUnits, heroUnit]);
49016
49114
  const pathFeatures = useMemo(() => pathToFeatures(path), [path]);
49017
49115
  const handleTileClick = useCallback((x, y) => {
49018
49116
  if (result !== "none") return;
@@ -49111,7 +49209,7 @@ function TowerDefenseBoard({
49111
49209
  ] }) })
49112
49210
  ] });
49113
49211
  }
49114
- var CDN6, TERRAIN_SPRITES, TOWER_SPRITE, CREEP_SPRITE;
49212
+ var CDN6, TD_GRID_W, TD_GRID_H, TERRAIN_SPRITES, DEFAULT_TD_PATH, DEFAULT_TD_TILES, TOWER_SPRITE, CREEP_SPRITE, HERO_SPRITE;
49115
49213
  var init_TowerDefenseBoard = __esm({
49116
49214
  "components/game/organisms/TowerDefenseBoard.tsx"() {
49117
49215
  "use client";
@@ -49124,13 +49222,70 @@ var init_TowerDefenseBoard = __esm({
49124
49222
  init_IsometricCanvas();
49125
49223
  init_boardEntity();
49126
49224
  CDN6 = "https://almadar-kflow-assets.web.app/shared/";
49225
+ TD_GRID_W = 16;
49226
+ TD_GRID_H = 16;
49127
49227
  TERRAIN_SPRITES = {
49128
49228
  ground: `${CDN6}isometric-blocks/PNG/Platformer tiles/platformerTile_01.png`,
49129
49229
  path: `${CDN6}isometric-blocks/PNG/Platformer tiles/platformerTile_09.png`,
49130
- wall: `${CDN6}isometric-blocks/PNG/Platformer tiles/platformerTile_05.png`
49131
- };
49132
- TOWER_SPRITE = `${CDN6}units/guardian.png`;
49133
- CREEP_SPRITE = `${CDN6}units/scrapper.png`;
49230
+ wall: `${CDN6}isometric-blocks/PNG/Platformer tiles/platformerTile_05.png`,
49231
+ grass: `${CDN6}isometric-dungeon/Isometric/dirt_E.png`,
49232
+ dirt: `${CDN6}isometric-dungeon/Isometric/dirtTiles_E.png`
49233
+ };
49234
+ DEFAULT_TD_PATH = [
49235
+ { x: 2, y: 0 },
49236
+ { x: 2, y: 1 },
49237
+ { x: 2, y: 2 },
49238
+ { x: 2, y: 3 },
49239
+ { x: 3, y: 3 },
49240
+ { x: 4, y: 3 },
49241
+ { x: 5, y: 3 },
49242
+ { x: 6, y: 3 },
49243
+ { x: 7, y: 3 },
49244
+ { x: 8, y: 3 },
49245
+ { x: 9, y: 3 },
49246
+ { x: 10, y: 3 },
49247
+ { x: 11, y: 3 },
49248
+ { x: 12, y: 3 },
49249
+ { x: 13, y: 3 },
49250
+ { x: 13, y: 4 },
49251
+ { x: 13, y: 5 },
49252
+ { x: 13, y: 6 },
49253
+ { x: 13, y: 7 },
49254
+ { x: 12, y: 7 },
49255
+ { x: 11, y: 7 },
49256
+ { x: 10, y: 7 },
49257
+ { x: 9, y: 7 },
49258
+ { x: 8, y: 7 },
49259
+ { x: 7, y: 7 },
49260
+ { x: 6, y: 7 },
49261
+ { x: 5, y: 7 },
49262
+ { x: 4, y: 7 },
49263
+ { x: 3, y: 7 },
49264
+ { x: 2, y: 7 },
49265
+ { x: 2, y: 8 },
49266
+ { x: 2, y: 9 },
49267
+ { x: 2, y: 10 },
49268
+ { x: 2, y: 11 },
49269
+ { x: 3, y: 11 },
49270
+ { x: 4, y: 11 },
49271
+ { x: 5, y: 11 },
49272
+ { x: 6, y: 11 },
49273
+ { x: 7, y: 11 },
49274
+ { x: 8, y: 11 },
49275
+ { x: 9, y: 11 },
49276
+ { x: 10, y: 11 },
49277
+ { x: 11, y: 11 },
49278
+ { x: 12, y: 11 },
49279
+ { x: 13, y: 11 },
49280
+ { x: 13, y: 12 },
49281
+ { x: 13, y: 13 },
49282
+ { x: 13, y: 14 },
49283
+ { x: 13, y: 15 }
49284
+ ];
49285
+ DEFAULT_TD_TILES = buildDefaultTDTiles();
49286
+ TOWER_SPRITE = `${CDN6}sprite-sheets/guardian-sprite-sheet-se.png`;
49287
+ CREEP_SPRITE = `${CDN6}sprite-sheets/scrapper-sprite-sheet-se.png`;
49288
+ HERO_SPRITE = `${CDN6}sprite-sheets/amir-sprite-sheet-se.png`;
49134
49289
  TowerDefenseBoard.displayName = "TowerDefenseBoard";
49135
49290
  }
49136
49291
  });
@@ -49405,6 +49560,17 @@ function heroPosition(h) {
49405
49560
  function heroMovement(h) {
49406
49561
  return num(h.movement);
49407
49562
  }
49563
+ function buildDefaultWorldTiles() {
49564
+ const tiles = [];
49565
+ for (let y = 0; y < WORLD_GRID_H; y++) {
49566
+ for (let x = 0; x < WORLD_GRID_W; x++) {
49567
+ const isBorder = x === 0 || y === 0 || x === WORLD_GRID_W - 1 || y === WORLD_GRID_H - 1;
49568
+ const def = isBorder ? WORLD_TERRAIN_DEFS[3] : WORLD_TERRAIN_DEFS[(x * 5 + y * 3 + (x ^ y)) % (WORLD_TERRAIN_DEFS.length - 1)];
49569
+ tiles.push({ x, y, terrain: def.terrain, terrainSprite: def.sprite, passable: def.passable });
49570
+ }
49571
+ }
49572
+ return tiles;
49573
+ }
49408
49574
  function defaultIsInRange(from, to, range) {
49409
49575
  return Math.abs(from.x - to.x) + Math.abs(from.y - to.y) <= range;
49410
49576
  }
@@ -49415,7 +49581,7 @@ function WorldMapBoard({
49415
49581
  features: propFeatures,
49416
49582
  assetManifest: propAssetManifest,
49417
49583
  isLoading,
49418
- scale = 0.4,
49584
+ scale = 0.25,
49419
49585
  unitScale = 2.5,
49420
49586
  spriteHeightRatio = 1.5,
49421
49587
  spriteMaxWidthRatio = 0.6,
@@ -49459,7 +49625,8 @@ function WorldMapBoard({
49459
49625
  })),
49460
49626
  [entityTiles]
49461
49627
  );
49462
- const tiles = propTiles ?? derivedTiles;
49628
+ const rawTiles = propTiles ?? (derivedTiles.length > 0 ? derivedTiles : null);
49629
+ const tiles = rawTiles != null && rawTiles.length >= WORLD_GRID_W * WORLD_GRID_H ? rawTiles : DEFAULT_WORLD_TILES;
49463
49630
  const baseUnits = useMemo(
49464
49631
  () => propUnits ?? entityUnits.map((u) => ({
49465
49632
  id: str(u.id),
@@ -49669,6 +49836,7 @@ function WorldMapBoard({
49669
49836
  footer && footer(ctx)
49670
49837
  ] });
49671
49838
  }
49839
+ var WORLD_CDN, WORLD_GRID_W, WORLD_GRID_H, WORLD_TERRAIN_DEFS, DEFAULT_WORLD_TILES;
49672
49840
  var init_WorldMapBoard = __esm({
49673
49841
  "components/game/organisms/WorldMapBoard.tsx"() {
49674
49842
  "use client";
@@ -49679,6 +49847,17 @@ var init_WorldMapBoard = __esm({
49679
49847
  init_IsometricCanvas();
49680
49848
  init_boardEntity();
49681
49849
  init_isometric();
49850
+ WORLD_CDN = "https://almadar-kflow-assets.web.app/shared";
49851
+ WORLD_GRID_W = 16;
49852
+ WORLD_GRID_H = 16;
49853
+ WORLD_TERRAIN_DEFS = [
49854
+ { terrain: "grass", sprite: `${WORLD_CDN}/isometric-dungeon/Isometric/dirt_E.png`, passable: true },
49855
+ { terrain: "dirt", sprite: `${WORLD_CDN}/isometric-dungeon/Isometric/dirtTiles_E.png`, passable: true },
49856
+ { terrain: "forest", sprite: `${WORLD_CDN}/isometric-dungeon/Isometric/planks_E.png`, passable: true },
49857
+ { terrain: "stone", sprite: `${WORLD_CDN}/isometric-dungeon/Isometric/stoneInset_E.png`, passable: false },
49858
+ { terrain: "castle", sprite: `${WORLD_CDN}/isometric-dungeon/Isometric/stoneTile_E.png`, passable: true }
49859
+ ];
49860
+ DEFAULT_WORLD_TILES = buildDefaultWorldTiles();
49682
49861
  WorldMapBoard.displayName = "WorldMapBoard";
49683
49862
  }
49684
49863
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@almadar/ui",
3
- "version": "5.56.0",
3
+ "version": "5.58.0",
4
4
  "description": "React UI components, hooks, and providers for Almadar",
5
5
  "type": "module",
6
6
  "sideEffects": [