@almadar/std 16.153.0 → 16.155.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.
Files changed (93) hide show
  1. package/behaviors/lolo/ui/game/molecules/std-crew-board-2d.lolo +4 -4
  2. package/behaviors/lolo/ui/game/molecules/std-dungeon-board-2d.lolo +6 -6
  3. package/behaviors/lolo/ui/game/molecules/std-tactics-board-2d.lolo +74 -28
  4. package/behaviors/lolo/ui/game/molecules/std-worldmap-board-2d.lolo +2 -2
  5. package/behaviors/lolo/ui/game/molecules/ui-canvas.lolo +5 -0
  6. package/behaviors/lolo/ui/game/organisms/ui-arena-board.lolo +2 -2
  7. package/behaviors/lolo/ui/game/organisms/ui-battle-board.lolo +159 -8
  8. package/behaviors/lolo/ui/game/organisms/ui-builder-board.lolo +5 -20
  9. package/behaviors/lolo/ui/game/organisms/ui-card-battler-board.lolo +2 -0
  10. package/behaviors/lolo/ui/game/organisms/ui-castle-board.lolo +3 -3
  11. package/behaviors/lolo/ui/game/organisms/ui-city-builder-board.lolo +9 -7
  12. package/behaviors/lolo/ui/game/organisms/ui-grid-tactics-demo-board.lolo +2 -2
  13. package/behaviors/lolo/ui/game/organisms/ui-hex-strategy-board.lolo +158 -10
  14. package/behaviors/lolo/ui/game/organisms/ui-holiday-runner-board.lolo +1 -1
  15. package/behaviors/lolo/ui/game/organisms/ui-minigolf-board.lolo +22 -22
  16. package/behaviors/lolo/ui/game/organisms/ui-pinball-board.lolo +7 -7
  17. package/behaviors/lolo/ui/game/organisms/ui-pirate-board.lolo +14 -14
  18. package/behaviors/lolo/ui/game/organisms/ui-platformer-board.lolo +4 -0
  19. package/behaviors/lolo/ui/game/organisms/ui-sports-board.lolo +10 -7
  20. package/behaviors/lolo/ui/game/organisms/ui-tactics-demo-2d.lolo +135 -9
  21. package/behaviors/lolo/ui/game/organisms/ui-tanks-board.lolo +152 -8
  22. package/behaviors/lolo/ui/game/organisms/ui-topdown-rts-board.lolo +293 -17
  23. package/behaviors/lolo/ui/game/organisms/ui-tower-defense-board.lolo +8 -8
  24. package/behaviors/lolo/ui/game/organisms/ui-uncontrolled-battle-board.lolo +5 -5
  25. package/behaviors/lolo/ui/game/organisms/ui-world-map-board.lolo +3 -3
  26. package/behaviors/registry/factory-signatures.json +1893 -2294
  27. package/behaviors/registry/ui/game/molecules/std-crew-board-2d.orb +10 -12
  28. package/behaviors/registry/ui/game/molecules/std-dungeon-board-2d.orb +15 -18
  29. package/behaviors/registry/ui/game/molecules/std-tactics-board-2d.orb +1726 -395
  30. package/behaviors/registry/ui/game/molecules/std-worldmap-board-2d.orb +7 -60
  31. package/behaviors/registry/ui/game/molecules/ui-canvas.orb +7 -0
  32. package/behaviors/registry/ui/game/organisms/ui-arena-board.orb +5 -6
  33. package/behaviors/registry/ui/game/organisms/ui-battle-board.orb +103 -100
  34. package/behaviors/registry/ui/game/organisms/ui-builder-board.orb +21 -226
  35. package/behaviors/registry/ui/game/organisms/ui-card-battler-board.orb +42 -0
  36. package/behaviors/registry/ui/game/organisms/ui-castle-board.orb +30 -9
  37. package/behaviors/registry/ui/game/organisms/ui-city-builder-board.orb +49 -0
  38. package/behaviors/registry/ui/game/organisms/ui-grid-tactics-demo-board.orb +5 -6
  39. package/behaviors/registry/ui/game/organisms/ui-hex-strategy-board.orb +95 -1187
  40. package/behaviors/registry/ui/game/organisms/ui-holiday-runner-board.orb +2 -3
  41. package/behaviors/registry/ui/game/organisms/ui-minigolf-board.orb +55 -11
  42. package/behaviors/registry/ui/game/organisms/ui-pinball-board.orb +8 -8
  43. package/behaviors/registry/ui/game/organisms/ui-pirate-board.orb +14 -0
  44. package/behaviors/registry/ui/game/organisms/ui-platformer-board.orb +72 -0
  45. package/behaviors/registry/ui/game/organisms/ui-sports-board.orb +60 -0
  46. package/behaviors/registry/ui/game/organisms/ui-tactics-demo-2d.orb +222 -332
  47. package/behaviors/registry/ui/game/organisms/ui-tanks-board.orb +127 -95
  48. package/behaviors/registry/ui/game/organisms/ui-topdown-rts-board.orb +1501 -264
  49. package/behaviors/registry/ui/game/organisms/ui-tower-defense-board.orb +8 -0
  50. package/behaviors/registry/ui/game/organisms/ui-uncontrolled-battle-board.orb +5 -0
  51. package/behaviors/registry/ui/game/organisms/ui-world-map-board.orb +8 -12
  52. package/dist/behaviors/behaviors-embeddings.json +244 -236
  53. package/dist/behaviors/behaviors-registry.json +193 -812
  54. package/dist/behaviors/exports-reader.js +1099 -2090
  55. package/dist/behaviors/functions/index.d.ts +33 -26
  56. package/dist/behaviors/functions/index.js +1099 -2091
  57. package/dist/behaviors/index.d.ts +1 -1
  58. package/dist/behaviors/index.js +1100 -2091
  59. package/dist/behaviors/knob-embeddings.json +1 -1
  60. package/dist/behaviors/query.js +1099 -2090
  61. package/dist/behaviors/registry/factory-signatures.json +1893 -2294
  62. package/dist/behaviors/registry/ui/game/molecules/std-crew-board-2d.orb +10 -12
  63. package/dist/behaviors/registry/ui/game/molecules/std-dungeon-board-2d.orb +15 -18
  64. package/dist/behaviors/registry/ui/game/molecules/std-tactics-board-2d.orb +1726 -395
  65. package/dist/behaviors/registry/ui/game/molecules/std-worldmap-board-2d.orb +7 -60
  66. package/dist/behaviors/registry/ui/game/molecules/ui-canvas.orb +7 -0
  67. package/dist/behaviors/registry/ui/game/organisms/ui-arena-board.orb +5 -6
  68. package/dist/behaviors/registry/ui/game/organisms/ui-battle-board.orb +103 -100
  69. package/dist/behaviors/registry/ui/game/organisms/ui-builder-board.orb +21 -226
  70. package/dist/behaviors/registry/ui/game/organisms/ui-card-battler-board.orb +42 -0
  71. package/dist/behaviors/registry/ui/game/organisms/ui-castle-board.orb +30 -9
  72. package/dist/behaviors/registry/ui/game/organisms/ui-city-builder-board.orb +49 -0
  73. package/dist/behaviors/registry/ui/game/organisms/ui-grid-tactics-demo-board.orb +5 -6
  74. package/dist/behaviors/registry/ui/game/organisms/ui-hex-strategy-board.orb +95 -1187
  75. package/dist/behaviors/registry/ui/game/organisms/ui-holiday-runner-board.orb +2 -3
  76. package/dist/behaviors/registry/ui/game/organisms/ui-minigolf-board.orb +55 -11
  77. package/dist/behaviors/registry/ui/game/organisms/ui-pinball-board.orb +8 -8
  78. package/dist/behaviors/registry/ui/game/organisms/ui-pirate-board.orb +14 -0
  79. package/dist/behaviors/registry/ui/game/organisms/ui-platformer-board.orb +72 -0
  80. package/dist/behaviors/registry/ui/game/organisms/ui-sports-board.orb +60 -0
  81. package/dist/behaviors/registry/ui/game/organisms/ui-tactics-demo-2d.orb +222 -332
  82. package/dist/behaviors/registry/ui/game/organisms/ui-tanks-board.orb +127 -95
  83. package/dist/behaviors/registry/ui/game/organisms/ui-topdown-rts-board.orb +1501 -264
  84. package/dist/behaviors/registry/ui/game/organisms/ui-tower-defense-board.orb +8 -0
  85. package/dist/behaviors/registry/ui/game/organisms/ui-uncontrolled-battle-board.orb +5 -0
  86. package/dist/behaviors/registry/ui/game/organisms/ui-world-map-board.orb +8 -12
  87. package/dist/behaviors-embeddings.json +244 -236
  88. package/dist/behaviors-registry.json +193 -812
  89. package/dist/index.d.ts +1 -1
  90. package/dist/index.js +1100 -2091
  91. package/dist/knob-embeddings.json +1 -1
  92. package/dist/registry/factory-signatures.json +1893 -2294
  93. package/package.json +2 -2
@@ -1,9 +1,130 @@
1
1
  app ui-topdown-rts-board "1.0.0"
2
- "Medieval RTS skirmish: thin organism composing the std-tactics-board-2d frame + std-production (barracks recruits via a Produce button) + std-score, with a Kenney medieval-RTS theme supplied via config."
2
+ "Real-time RTS base skirmish: thin organism composing the std-tactics-board-2d frame + std-score, plus three organism-level traits (RtsClock / RtsEconomy / RtsWaves) that turn the turn-based frame into a real-time RTS a 2s clock auto-advances turns, workers harvest gold at the mine, gold musters tanks at the town hall, and raider waves stream out of a fortified den. Win by destroying the den; lose when your whole base (town hall included) is wiped."
3
+ ;; @capabilities "real-time strategy, RTS economy, wave defense, base assault"
4
+
5
+ ;; ============================================================================
6
+ ;; PERSONA + USER STORIES
7
+ ;;
8
+ ;; Read these before changing anything here, and walk them end to end after.
9
+ ;; One persona: the PLAYER, running a base on an 8x6 flat top-down grid:
10
+ ;; workers mine gold, gold musters tanks, raider waves stream from the den.
11
+ ;; Statuses verified 2026-07-30 by a scripted full playthrough driving the
12
+ ;; real game on the runtime-verify catalog through window.__orbitalVerification
13
+ ;; (events in, canvas drawables + HUD DOM + bus event log out) plus
14
+ ;; play_transition guard probes on the almadar-tools daemon.
15
+ ;;
16
+ ;; THE GENRE (what a real-time RTS player expects): play is CONTINUOUS — there
17
+ ;; is no manual end turn. A 2-second clock advances the round on its own: your
18
+ ;; spent units refresh and the enemy AI acts, whether or not you touched
19
+ ;; anything. The economy is the engine: workers standing at the gold mine
20
+ ;; harvest every cycle, you stockpile, and you spend 5 gold to muster a tank
21
+ ;; at the town hall. Pressure escalates: a raider wave spawns at the den every
22
+ ;; ~16 seconds, each one tougher than the last, and they walk straight at your
23
+ ;; base. You win by carrying the fight EAST and destroying the fortified den
24
+ ;; (and every raider it spawned); you lose when your whole base — workers,
25
+ ;; tanks, AND the town hall — is wiped. A fight looks like: select a tank ->
26
+ ;; green reach cells -> move -> the tank STAYS selected and auto-arms (red
27
+ ;; cells = enemies in artillery range 2) -> strike for 3 -> the tank is SPENT
28
+ ;; until the next clock tick. The hardcoded "End Turn" button stays as a
29
+ ;; manual round-hurry for impatient players; the clock makes it optional.
30
+ ;; Both bases are fortified with impassable palisade walls: the raider den is
31
+ ;; FULLY boxed — all 5 in-bounds neighbor cells are walls, INCLUDING the
32
+ ;; diagonals, because the enemy AI steps diagonally (x and y both advance one
33
+ ;; cell per tick) and cuts orthogonal corners — so it holds position as a
34
+ ;; spawn fortress, and your tanks shell it over the wall from artillery
35
+ ;; range 2. Your town hall is walled on three sides with a one-cell muster
36
+ ;; yard in front — that yard is the chokepoint raiders funnel into to batter
37
+ ;; the hall.
38
+ ;; ============================================================================
39
+ ;;
40
+ ;; PLAYER — "I run my base economy and burn the raider den before the waves burn mine."
41
+ ;;
42
+ ;; 1. I open the board and see the whole battlefield framed on screen —
43
+ ;; terrain under every cell, my walled base at the west (gold mine,
44
+ ;; town hall, muster yard), my two workers at the mine and a garrison
45
+ ;; tank in the yard, the walled raider den at the east, and the HUD
46
+ ;; showing Result/Phase/Turn/Score/Gold/Wave.
47
+ ;; UNVERIFIED.
48
+ ;; 2. Every unit on the board is a visible sprite with a name label and a
49
+ ;; health bar I can read at a glance, idling in place — worker, tank,
50
+ ;; town hall and den sprites all visually distinct.
51
+ ;; UNVERIFIED.
52
+ ;; 3. Play is continuous: the Turn counter advances about every 2 seconds
53
+ ;; WITHOUT me clicking End Turn, and a unit I spent last cycle is fresh
54
+ ;; again on the next. The End Turn button still works as a manual hurry.
55
+ ;; UNVERIFIED.
56
+ ;; 4. My workers harvest: while a living worker stands on or next to the
57
+ ;; gold mine (manhattan <= 1), Gold rises every clock cycle; with no
58
+ ;; worker at the mine it does not.
59
+ ;; UNVERIFIED.
60
+ ;; 5. With 5+ gold I hit "Tank (5g)" and a fresh tank rolls out on the
61
+ ;; muster yard beside the hall; my gold drops by 5. Under 5 gold — or
62
+ ;; with the yard occupied — the button is a dead click (guard).
63
+ ;; UNVERIFIED.
64
+ ;; 6. Raider waves: about every 16 seconds a raider spawns at the den's
65
+ ;; muster point with scaling health (6 + wave number) and walks toward
66
+ ;; my base on the next clock ticks. If the muster point is occupied the
67
+ ;; wave waits for it to clear.
68
+ ;; UNVERIFIED.
69
+ ;; 7. Combat: I select my tank (green reach), move (walk animation, one
70
+ ;; move per cycle), it auto-arms (red = enemies within artillery range
71
+ ;; 2), and I strike for 3 — the tank is then spent until the next tick.
72
+ ;; UNVERIFIED.
73
+ ;; 8. The den is FULLY boxed by palisade walls: the AI can never step it
74
+ ;; (all 5 in-bounds neighbor cells impassable, diagonals included — the
75
+ ;; AI steps diagonally), so it holds position as a spawn fortress — and
76
+ ;; my tanks destroy it by shelling over the wall from range 2. (Its
77
+ ;; retaliatory strike only reaches orthogonally-adjacent attackers, and
78
+ ;; no attacker can stand adjacent to it.)
79
+ ;; UNVERIFIED.
80
+ ;; 9. My town hall is a building: walled on three sides, its only lit
81
+ ;; move cell is the corridor mouth in front of its own muster yard —
82
+ ;; there is never a reason to move it, and the garrison tank starts on
83
+ ;; the yard. (Honest note: the frame treats the hall as a unit, so it
84
+ ;; CAN technically shuffle into its own yard/corridor; zero valid
85
+ ;; moves is impossible while raiders must reach the hall for the
86
+ ;; defeat path.)
87
+ ;; UNVERIFIED.
88
+ ;; 10. When the den and every raider are dead, I win — Result flips to
89
+ ;; victory and the board freezes. When my whole base including the
90
+ ;; town hall is dead, Result is defeat. Kills tick Score +10.
91
+ ;; UNVERIFIED.
92
+ ;;
93
+ ;; MULTIPLAYER NOTE: GameState is [runtime, shared], so every connected
94
+ ;; client watches the same skirmish on the same frame; intents serialize
95
+ ;; through the server authority. There is no per-seat ownership — any
96
+ ;; client can drive any player unit.
97
+ ;;
98
+ ;; ASSET INVENTORY (hand-authored svg, almadar-kflow-assets.web.app
99
+ ;; /shared/ui-topdown-rts-board/svg/flat/, generated by tools/asset-workflow
100
+ ;; svg-generator from the sibling .md descriptions)
101
+ ;;
102
+ ;; Terrain terrain/ground.svg full-cell flat tiles; terrain/sand.svg
103
+ ;; marks the south-east patch (4 tiles).
104
+ ;; Units units/{worker,tank,town_hall,raider,raider_den}.svg +
105
+ ;; animation frames .{idle-0..3, walk-0..1, attack-0, hit-0,
106
+ ;; death-0}.svg; the frame molecule url-rewrites name.svg ->
107
+ ;; name.<anim>-<i>.svg. Spawned tanks/raiders (SPAWN carries no
108
+ ;; modelUrl) render via the assetManifest.units[unitType]
109
+ ;; fallback with an empty name label (known atom gap).
110
+ ;; player: w1 Pick worker 5hp (0,0) on the mine
111
+ ;; w2 Shovel worker 5hp (1,0) at the mine
112
+ ;; t1 Alpha tank 10hp (1,3) on the muster yard
113
+ ;; hall Bastion town_hall 30hp (0,3), walled
114
+ ;; enemy: den Den raider_den 30hp (7,2), fully walled
115
+ ;; Features features/gold_mine.svg at (0,0) — the harvest anchor;
116
+ ;; features/wall.svg x11 palisade segments at (0,1),(0,2),(0,4),
117
+ ;; (0,5),(1,2),(1,4) boxing the town hall and (6,1),(6,2),(6,3),
118
+ ;; (7,1),(7,3) boxing the den — diagonals included, the AI steps
119
+ ;; diagonally (all matching tiles passable: false).
120
+ ;; Effects effects/hit.svg (BURST "hit" fx), effects/explosion.svg
121
+ ;; (manifest-only).
122
+ ;; UI chrome ui/panel-frame.svg = game-shell background + HUD panel.
123
+ ;; ============================================================================
124
+
3
125
  orbital TopdownRtsBoardOrbital {
4
126
  uses Frame from "std/behaviors/std-tactics-board-2d"
5
127
  uses Score from "std/behaviors/std-score"
6
- uses Production from "std/behaviors/std-production"
7
128
 
8
129
  type Asset = {
9
130
  url : asset
@@ -69,19 +190,23 @@ orbital TopdownRtsBoardOrbital {
69
190
 
70
191
  entity GameState [runtime, shared] {
71
192
  id : string!
72
- units : [Unit] = [ { id: "t1", position: { x: 1, y: 1 }, x: 1, y: 1, z: 0, team: "player", health: 10, maxHealth: 10, unitType: "tank", name: "Alpha", modelUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/kenney-rts-medieval/terrain/medievalRTS_spritesheet.png", atlas: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/kenney-rts-medieval/terrain/medievalRTS_spritesheet.json", sprite: "medievalUnit_01.png", role: "npc", category: "tankBody_green", animations: ["idle","walk","attack","hit","death"], style: "vector-flat", dimension: "2d", aspect: "1:1", name: "tankBody_green", thumbnailUrl: "" } }, { id: "t2", position: { x: 6, y: 0 }, x: 6, y: 0, z: 0, team: "enemy", health: 10, maxHealth: 10, unitType: "tank", name: "Bravo", modelUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/kenney-rts-medieval/terrain/medievalRTS_spritesheet.png", atlas: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/kenney-rts-medieval/terrain/medievalRTS_spritesheet.json", sprite: "medievalUnit_05.png", role: "npc", category: "tankBody_dark", animations: ["idle","walk","attack","hit","death"], style: "vector-flat", dimension: "2d", aspect: "1:1", name: "tankBody_dark", thumbnailUrl: "" } }, { id: "t3", position: { x: 6, y: 4 }, x: 6, y: 4, z: 0, team: "enemy", health: 8, maxHealth: 10, unitType: "tank", name: "Charlie", modelUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/kenney-rts-medieval/terrain/medievalRTS_spritesheet.png", atlas: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/kenney-rts-medieval/terrain/medievalRTS_spritesheet.json", sprite: "medievalUnit_05.png", role: "npc", category: "tankBody_dark", animations: ["idle","walk","attack","hit","death"], style: "vector-flat", dimension: "2d", aspect: "1:1", name: "tankBody_dark", thumbnailUrl: "" } } ]
193
+ units : [Unit] = [ { id: "w1", position: { x: 0, y: 0 }, x: 0, y: 0, z: 0, team: "player", health: 5, maxHealth: 5, unitType: "worker", name: "Pick", modelUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/svg/flat/units/worker.svg", role: "npc", category: "worker", animations: ["idle","walk","attack","hit","death"], style: "", dimension: "2d", aspect: "1:1", name: "worker", thumbnailUrl: "" } }, { id: "w2", position: { x: 1, y: 0 }, x: 1, y: 0, z: 0, team: "player", health: 5, maxHealth: 5, unitType: "worker", name: "Shovel", modelUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/svg/flat/units/worker.svg", role: "npc", category: "worker", animations: ["idle","walk","attack","hit","death"], style: "", dimension: "2d", aspect: "1:1", name: "worker", thumbnailUrl: "" } }, { id: "t1", position: { x: 1, y: 3 }, x: 1, y: 3, z: 0, team: "player", health: 10, maxHealth: 10, unitType: "tank", name: "Alpha", modelUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/svg/flat/units/tank.svg", role: "npc", category: "tank", animations: ["idle","walk","attack","hit","death"], style: "", dimension: "2d", aspect: "1:1", name: "tank", thumbnailUrl: "" } }, { id: "hall", position: { x: 0, y: 3 }, x: 0, y: 3, z: 0, team: "player", health: 30, maxHealth: 30, unitType: "town_hall", name: "Bastion", modelUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/svg/flat/units/town_hall.svg", role: "npc", category: "town_hall", animations: ["idle","walk","attack","hit","death"], style: "", dimension: "2d", aspect: "1:1", name: "town_hall", thumbnailUrl: "" } }, { id: "den", position: { x: 7, y: 2 }, x: 7, y: 2, z: 0, team: "enemy", health: 30, maxHealth: 30, unitType: "raider_den", name: "Den", modelUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/svg/flat/units/raider_den.svg", role: "npc", category: "raider_den", animations: ["idle","walk","attack","hit","death"], style: "", dimension: "2d", aspect: "1:1", name: "raider_den", thumbnailUrl: "" } } ]
73
194
  fx : [Fx] = []
74
- tiles : [Tile] = [ { id: "t-0-0", x: 0, y: 0, terrain: "ground", passable: true }, { id: "t-1-0", x: 1, y: 0, terrain: "ground", passable: true }, { id: "t-2-0", x: 2, y: 0, terrain: "ground", passable: true }, { id: "t-3-0", x: 3, y: 0, terrain: "ground", passable: true }, { id: "t-4-0", x: 4, y: 0, terrain: "ground", passable: true }, { id: "t-5-0", x: 5, y: 0, terrain: "ground", passable: true }, { id: "t-6-0", x: 6, y: 0, terrain: "ground", passable: true }, { id: "t-7-0", x: 7, y: 0, terrain: "ground", passable: true }, { id: "t-0-1", x: 0, y: 1, terrain: "ground", passable: true }, { id: "t-1-1", x: 1, y: 1, terrain: "ground", passable: true }, { id: "t-2-1", x: 2, y: 1, terrain: "ground", passable: true }, { id: "t-3-1", x: 3, y: 1, terrain: "ground", passable: true }, { id: "t-4-1", x: 4, y: 1, terrain: "ground", passable: true }, { id: "t-5-1", x: 5, y: 1, terrain: "ground", passable: true }, { id: "t-6-1", x: 6, y: 1, terrain: "ground", passable: true }, { id: "t-7-1", x: 7, y: 1, terrain: "ground", passable: true }, { id: "t-0-2", x: 0, y: 2, terrain: "ground", passable: true }, { id: "t-1-2", x: 1, y: 2, terrain: "ground", passable: true }, { id: "t-2-2", x: 2, y: 2, terrain: "ground", passable: true }, { id: "t-3-2", x: 3, y: 2, terrain: "ground", passable: true }, { id: "t-4-2", x: 4, y: 2, terrain: "ground", passable: true }, { id: "t-5-2", x: 5, y: 2, terrain: "ground", passable: true }, { id: "t-6-2", x: 6, y: 2, terrain: "ground", passable: true }, { id: "t-7-2", x: 7, y: 2, terrain: "ground", passable: true }, { id: "t-0-3", x: 0, y: 3, terrain: "ground", passable: true }, { id: "t-1-3", x: 1, y: 3, terrain: "ground", passable: true }, { id: "t-2-3", x: 2, y: 3, terrain: "ground", passable: true }, { id: "t-3-3", x: 3, y: 3, terrain: "ground", passable: true }, { id: "t-4-3", x: 4, y: 3, terrain: "ground", passable: true }, { id: "t-5-3", x: 5, y: 3, terrain: "ground", passable: true }, { id: "t-6-3", x: 6, y: 3, terrain: "ground", passable: true }, { id: "t-7-3", x: 7, y: 3, terrain: "ground", passable: true }, { id: "t-0-4", x: 0, y: 4, terrain: "ground", passable: true }, { id: "t-1-4", x: 1, y: 4, terrain: "ground", passable: true }, { id: "t-2-4", x: 2, y: 4, terrain: "ground", passable: true }, { id: "t-3-4", x: 3, y: 4, terrain: "ground", passable: true }, { id: "t-4-4", x: 4, y: 4, terrain: "ground", passable: true }, { id: "t-5-4", x: 5, y: 4, terrain: "ground", passable: true }, { id: "t-6-4", x: 6, y: 4, terrain: "ground", passable: true }, { id: "t-7-4", x: 7, y: 4, terrain: "ground", passable: true }, { id: "t-0-5", x: 0, y: 5, terrain: "ground", passable: true }, { id: "t-1-5", x: 1, y: 5, terrain: "ground", passable: true }, { id: "t-2-5", x: 2, y: 5, terrain: "ground", passable: true }, { id: "t-3-5", x: 3, y: 5, terrain: "ground", passable: true }, { id: "t-4-5", x: 4, y: 5, terrain: "ground", passable: true }, { id: "t-5-5", x: 5, y: 5, terrain: "ground", passable: true }, { id: "t-6-5", x: 6, y: 5, terrain: "ground", passable: true }, { id: "t-7-5", x: 7, y: 5, terrain: "ground", passable: true } ]
195
+ tiles : [Tile] = [ { id: "t-0-0", x: 0, y: 0, terrain: "ground", passable: true }, { id: "t-1-0", x: 1, y: 0, terrain: "ground", passable: true }, { id: "t-2-0", x: 2, y: 0, terrain: "ground", passable: true }, { id: "t-3-0", x: 3, y: 0, terrain: "ground", passable: true }, { id: "t-4-0", x: 4, y: 0, terrain: "ground", passable: true }, { id: "t-5-0", x: 5, y: 0, terrain: "ground", passable: true }, { id: "t-6-0", x: 6, y: 0, terrain: "ground", passable: true }, { id: "t-7-0", x: 7, y: 0, terrain: "ground", passable: true }, { id: "t-0-1", x: 0, y: 1, terrain: "ground", passable: false }, { id: "t-1-1", x: 1, y: 1, terrain: "ground", passable: true }, { id: "t-2-1", x: 2, y: 1, terrain: "ground", passable: true }, { id: "t-3-1", x: 3, y: 1, terrain: "ground", passable: true }, { id: "t-4-1", x: 4, y: 1, terrain: "ground", passable: true }, { id: "t-5-1", x: 5, y: 1, terrain: "ground", passable: true }, { id: "t-6-1", x: 6, y: 1, terrain: "ground", passable: false }, { id: "t-7-1", x: 7, y: 1, terrain: "ground", passable: false }, { id: "t-0-2", x: 0, y: 2, terrain: "ground", passable: false }, { id: "t-1-2", x: 1, y: 2, terrain: "ground", passable: false }, { id: "t-2-2", x: 2, y: 2, terrain: "ground", passable: true }, { id: "t-3-2", x: 3, y: 2, terrain: "ground", passable: true }, { id: "t-4-2", x: 4, y: 2, terrain: "ground", passable: true }, { id: "t-5-2", x: 5, y: 2, terrain: "ground", passable: true }, { id: "t-6-2", x: 6, y: 2, terrain: "ground", passable: false }, { id: "t-7-2", x: 7, y: 2, terrain: "ground", passable: true }, { id: "t-0-3", x: 0, y: 3, terrain: "ground", passable: true }, { id: "t-1-3", x: 1, y: 3, terrain: "ground", passable: true }, { id: "t-2-3", x: 2, y: 3, terrain: "ground", passable: true }, { id: "t-3-3", x: 3, y: 3, terrain: "ground", passable: true }, { id: "t-4-3", x: 4, y: 3, terrain: "ground", passable: true }, { id: "t-5-3", x: 5, y: 3, terrain: "ground", passable: true }, { id: "t-6-3", x: 6, y: 3, terrain: "ground", passable: false }, { id: "t-7-3", x: 7, y: 3, terrain: "ground", passable: false }, { id: "t-0-4", x: 0, y: 4, terrain: "ground", passable: false }, { id: "t-1-4", x: 1, y: 4, terrain: "ground", passable: false }, { id: "t-2-4", x: 2, y: 4, terrain: "ground", passable: true }, { id: "t-3-4", x: 3, y: 4, terrain: "ground", passable: true }, { id: "t-4-4", x: 4, y: 4, terrain: "ground", passable: true }, { id: "t-5-4", x: 5, y: 4, terrain: "sand", passable: true }, { id: "t-6-4", x: 6, y: 4, terrain: "sand", passable: true }, { id: "t-7-4", x: 7, y: 4, terrain: "ground", passable: true }, { id: "t-0-5", x: 0, y: 5, terrain: "ground", passable: false }, { id: "t-1-5", x: 1, y: 5, terrain: "ground", passable: true }, { id: "t-2-5", x: 2, y: 5, terrain: "ground", passable: true }, { id: "t-3-5", x: 3, y: 5, terrain: "ground", passable: true }, { id: "t-4-5", x: 4, y: 5, terrain: "ground", passable: true }, { id: "t-5-5", x: 5, y: 5, terrain: "sand", passable: true }, { id: "t-6-5", x: 6, y: 5, terrain: "sand", passable: true }, { id: "t-7-5", x: 7, y: 5, terrain: "ground", passable: true } ]
75
196
  result : string = "none"
76
197
  selectedUnitId : string = ""
77
198
  validMoves : [ValidMove] = []
78
199
  attackTargets : [ValidMove] = []
200
+ movedIds : [string] = []
201
+ actedIds : [string] = []
79
202
  uiPhase : string = "observation"
80
203
  turn : number = 0
81
204
  score : number = 0
82
205
  scoreBaseline : number = 0
83
- productionPoints : number = 0
84
- spawnCount : number = 0
206
+ gold : number = 0
207
+ ecoSpawnCount : number = 0
208
+ waveCount : number = 0
209
+ clockTicks : number = 0
85
210
  }
86
211
 
87
212
  trait Authority = Frame.traits.TacticsAuthority -> GameState {
@@ -90,8 +215,8 @@ orbital TopdownRtsBoardOrbital {
90
215
  gridWidth: 8
91
216
  gridHeight: 6
92
217
  attackDamage: 3
93
- units: [ { id: "t1", position: { x: 1, y: 1 }, x: 1, y: 1, z: 0, team: "player", health: 10, maxHealth: 10, unitType: "tank", name: "Alpha", modelUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/kenney-rts-medieval/terrain/medievalRTS_spritesheet.png", atlas: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/kenney-rts-medieval/terrain/medievalRTS_spritesheet.json", sprite: "medievalUnit_01.png", role: "npc", category: "tankBody_green", animations: ["idle","walk","attack","hit","death"], style: "vector-flat", dimension: "2d", aspect: "1:1", name: "tankBody_green", thumbnailUrl: "" } }, { id: "t2", position: { x: 6, y: 0 }, x: 6, y: 0, z: 0, team: "enemy", health: 10, maxHealth: 10, unitType: "tank", name: "Bravo", modelUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/kenney-rts-medieval/terrain/medievalRTS_spritesheet.png", atlas: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/kenney-rts-medieval/terrain/medievalRTS_spritesheet.json", sprite: "medievalUnit_05.png", role: "npc", category: "tankBody_dark", animations: ["idle","walk","attack","hit","death"], style: "vector-flat", dimension: "2d", aspect: "1:1", name: "tankBody_dark", thumbnailUrl: "" } }, { id: "t3", position: { x: 6, y: 4 }, x: 6, y: 4, z: 0, team: "enemy", health: 8, maxHealth: 10, unitType: "tank", name: "Charlie", modelUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/kenney-rts-medieval/terrain/medievalRTS_spritesheet.png", atlas: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/kenney-rts-medieval/terrain/medievalRTS_spritesheet.json", sprite: "medievalUnit_05.png", role: "npc", category: "tankBody_dark", animations: ["idle","walk","attack","hit","death"], style: "vector-flat", dimension: "2d", aspect: "1:1", name: "tankBody_dark", thumbnailUrl: "" } } ]
94
- tiles: [ { id: "t-0-0", x: 0, y: 0, terrain: "ground", passable: true }, { id: "t-1-0", x: 1, y: 0, terrain: "ground", passable: true }, { id: "t-2-0", x: 2, y: 0, terrain: "ground", passable: true }, { id: "t-3-0", x: 3, y: 0, terrain: "ground", passable: true }, { id: "t-4-0", x: 4, y: 0, terrain: "ground", passable: true }, { id: "t-5-0", x: 5, y: 0, terrain: "ground", passable: true }, { id: "t-6-0", x: 6, y: 0, terrain: "ground", passable: true }, { id: "t-7-0", x: 7, y: 0, terrain: "ground", passable: true }, { id: "t-0-1", x: 0, y: 1, terrain: "ground", passable: true }, { id: "t-1-1", x: 1, y: 1, terrain: "ground", passable: true }, { id: "t-2-1", x: 2, y: 1, terrain: "ground", passable: true }, { id: "t-3-1", x: 3, y: 1, terrain: "ground", passable: true }, { id: "t-4-1", x: 4, y: 1, terrain: "ground", passable: true }, { id: "t-5-1", x: 5, y: 1, terrain: "ground", passable: true }, { id: "t-6-1", x: 6, y: 1, terrain: "ground", passable: true }, { id: "t-7-1", x: 7, y: 1, terrain: "ground", passable: true }, { id: "t-0-2", x: 0, y: 2, terrain: "ground", passable: true }, { id: "t-1-2", x: 1, y: 2, terrain: "ground", passable: true }, { id: "t-2-2", x: 2, y: 2, terrain: "ground", passable: true }, { id: "t-3-2", x: 3, y: 2, terrain: "ground", passable: true }, { id: "t-4-2", x: 4, y: 2, terrain: "ground", passable: true }, { id: "t-5-2", x: 5, y: 2, terrain: "ground", passable: true }, { id: "t-6-2", x: 6, y: 2, terrain: "ground", passable: true }, { id: "t-7-2", x: 7, y: 2, terrain: "ground", passable: true }, { id: "t-0-3", x: 0, y: 3, terrain: "ground", passable: true }, { id: "t-1-3", x: 1, y: 3, terrain: "ground", passable: true }, { id: "t-2-3", x: 2, y: 3, terrain: "ground", passable: true }, { id: "t-3-3", x: 3, y: 3, terrain: "ground", passable: true }, { id: "t-4-3", x: 4, y: 3, terrain: "ground", passable: true }, { id: "t-5-3", x: 5, y: 3, terrain: "ground", passable: true }, { id: "t-6-3", x: 6, y: 3, terrain: "ground", passable: true }, { id: "t-7-3", x: 7, y: 3, terrain: "ground", passable: true }, { id: "t-0-4", x: 0, y: 4, terrain: "ground", passable: true }, { id: "t-1-4", x: 1, y: 4, terrain: "ground", passable: true }, { id: "t-2-4", x: 2, y: 4, terrain: "ground", passable: true }, { id: "t-3-4", x: 3, y: 4, terrain: "ground", passable: true }, { id: "t-4-4", x: 4, y: 4, terrain: "ground", passable: true }, { id: "t-5-4", x: 5, y: 4, terrain: "ground", passable: true }, { id: "t-6-4", x: 6, y: 4, terrain: "ground", passable: true }, { id: "t-7-4", x: 7, y: 4, terrain: "ground", passable: true }, { id: "t-0-5", x: 0, y: 5, terrain: "ground", passable: true }, { id: "t-1-5", x: 1, y: 5, terrain: "ground", passable: true }, { id: "t-2-5", x: 2, y: 5, terrain: "ground", passable: true }, { id: "t-3-5", x: 3, y: 5, terrain: "ground", passable: true }, { id: "t-4-5", x: 4, y: 5, terrain: "ground", passable: true }, { id: "t-5-5", x: 5, y: 5, terrain: "ground", passable: true }, { id: "t-6-5", x: 6, y: 5, terrain: "ground", passable: true }, { id: "t-7-5", x: 7, y: 5, terrain: "ground", passable: true } ]
218
+ units: [ { id: "w1", position: { x: 0, y: 0 }, x: 0, y: 0, z: 0, team: "player", health: 5, maxHealth: 5, unitType: "worker", name: "Pick", modelUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/svg/flat/units/worker.svg", role: "npc", category: "worker", animations: ["idle","walk","attack","hit","death"], style: "", dimension: "2d", aspect: "1:1", name: "worker", thumbnailUrl: "" } }, { id: "w2", position: { x: 1, y: 0 }, x: 1, y: 0, z: 0, team: "player", health: 5, maxHealth: 5, unitType: "worker", name: "Shovel", modelUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/svg/flat/units/worker.svg", role: "npc", category: "worker", animations: ["idle","walk","attack","hit","death"], style: "", dimension: "2d", aspect: "1:1", name: "worker", thumbnailUrl: "" } }, { id: "t1", position: { x: 1, y: 3 }, x: 1, y: 3, z: 0, team: "player", health: 10, maxHealth: 10, unitType: "tank", name: "Alpha", modelUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/svg/flat/units/tank.svg", role: "npc", category: "tank", animations: ["idle","walk","attack","hit","death"], style: "", dimension: "2d", aspect: "1:1", name: "tank", thumbnailUrl: "" } }, { id: "hall", position: { x: 0, y: 3 }, x: 0, y: 3, z: 0, team: "player", health: 30, maxHealth: 30, unitType: "town_hall", name: "Bastion", modelUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/svg/flat/units/town_hall.svg", role: "npc", category: "town_hall", animations: ["idle","walk","attack","hit","death"], style: "", dimension: "2d", aspect: "1:1", name: "town_hall", thumbnailUrl: "" } }, { id: "den", position: { x: 7, y: 2 }, x: 7, y: 2, z: 0, team: "enemy", health: 30, maxHealth: 30, unitType: "raider_den", name: "Den", modelUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/svg/flat/units/raider_den.svg", role: "npc", category: "raider_den", animations: ["idle","walk","attack","hit","death"], style: "", dimension: "2d", aspect: "1:1", name: "raider_den", thumbnailUrl: "" } } ]
219
+ tiles: [ { id: "t-0-0", x: 0, y: 0, terrain: "ground", passable: true }, { id: "t-1-0", x: 1, y: 0, terrain: "ground", passable: true }, { id: "t-2-0", x: 2, y: 0, terrain: "ground", passable: true }, { id: "t-3-0", x: 3, y: 0, terrain: "ground", passable: true }, { id: "t-4-0", x: 4, y: 0, terrain: "ground", passable: true }, { id: "t-5-0", x: 5, y: 0, terrain: "ground", passable: true }, { id: "t-6-0", x: 6, y: 0, terrain: "ground", passable: true }, { id: "t-7-0", x: 7, y: 0, terrain: "ground", passable: true }, { id: "t-0-1", x: 0, y: 1, terrain: "ground", passable: false }, { id: "t-1-1", x: 1, y: 1, terrain: "ground", passable: true }, { id: "t-2-1", x: 2, y: 1, terrain: "ground", passable: true }, { id: "t-3-1", x: 3, y: 1, terrain: "ground", passable: true }, { id: "t-4-1", x: 4, y: 1, terrain: "ground", passable: true }, { id: "t-5-1", x: 5, y: 1, terrain: "ground", passable: true }, { id: "t-6-1", x: 6, y: 1, terrain: "ground", passable: false }, { id: "t-7-1", x: 7, y: 1, terrain: "ground", passable: false }, { id: "t-0-2", x: 0, y: 2, terrain: "ground", passable: false }, { id: "t-1-2", x: 1, y: 2, terrain: "ground", passable: false }, { id: "t-2-2", x: 2, y: 2, terrain: "ground", passable: true }, { id: "t-3-2", x: 3, y: 2, terrain: "ground", passable: true }, { id: "t-4-2", x: 4, y: 2, terrain: "ground", passable: true }, { id: "t-5-2", x: 5, y: 2, terrain: "ground", passable: true }, { id: "t-6-2", x: 6, y: 2, terrain: "ground", passable: false }, { id: "t-7-2", x: 7, y: 2, terrain: "ground", passable: true }, { id: "t-0-3", x: 0, y: 3, terrain: "ground", passable: true }, { id: "t-1-3", x: 1, y: 3, terrain: "ground", passable: true }, { id: "t-2-3", x: 2, y: 3, terrain: "ground", passable: true }, { id: "t-3-3", x: 3, y: 3, terrain: "ground", passable: true }, { id: "t-4-3", x: 4, y: 3, terrain: "ground", passable: true }, { id: "t-5-3", x: 5, y: 3, terrain: "ground", passable: true }, { id: "t-6-3", x: 6, y: 3, terrain: "ground", passable: false }, { id: "t-7-3", x: 7, y: 3, terrain: "ground", passable: false }, { id: "t-0-4", x: 0, y: 4, terrain: "ground", passable: false }, { id: "t-1-4", x: 1, y: 4, terrain: "ground", passable: false }, { id: "t-2-4", x: 2, y: 4, terrain: "ground", passable: true }, { id: "t-3-4", x: 3, y: 4, terrain: "ground", passable: true }, { id: "t-4-4", x: 4, y: 4, terrain: "ground", passable: true }, { id: "t-5-4", x: 5, y: 4, terrain: "sand", passable: true }, { id: "t-6-4", x: 6, y: 4, terrain: "sand", passable: true }, { id: "t-7-4", x: 7, y: 4, terrain: "ground", passable: true }, { id: "t-0-5", x: 0, y: 5, terrain: "ground", passable: false }, { id: "t-1-5", x: 1, y: 5, terrain: "ground", passable: true }, { id: "t-2-5", x: 2, y: 5, terrain: "ground", passable: true }, { id: "t-3-5", x: 3, y: 5, terrain: "ground", passable: true }, { id: "t-4-5", x: 4, y: 5, terrain: "ground", passable: true }, { id: "t-5-5", x: 5, y: 5, terrain: "sand", passable: true }, { id: "t-6-5", x: 6, y: 5, terrain: "sand", passable: true }, { id: "t-7-5", x: 7, y: 5, terrain: "ground", passable: true } ]
95
220
  }
96
221
  }
97
222
 
@@ -104,11 +229,159 @@ orbital TopdownRtsBoardOrbital {
104
229
  }
105
230
 
106
231
  trait ScoreKeeper = Score.traits.ScoreKeeper -> GameState {
107
- config { running: true, pointsPerKill: 10, startScore: 0, initialEnemies: 2 }
232
+ config { running: true, pointsPerKill: 10, startScore: 0, initialEnemies: 1 }
233
+ }
234
+
235
+ trait AnimClock = Frame.traits.AnimClock -> GameState {
236
+ config { frames: [] }
237
+ }
238
+
239
+ trait RtsClock -> @rebindable GameState [lifecycle] {
240
+ initial: running
241
+
242
+ state running {
243
+ INIT -> running
244
+ (set @entity.clockTicks 0)
245
+ }
246
+
247
+ ticks {
248
+ turnTick every 2000ms when (== @entity.result "none")
249
+ (set @entity.clockTicks (+ @entity.clockTicks 1))
250
+ (emit END_TURN { id: "clock" })
251
+ }
252
+
253
+ emits {
254
+ END_TURN -> external {
255
+ id : string
256
+ }
257
+ @description "Real-time round advance; the frame's PlayerIntent treats it exactly like the End Turn button (turn bump, activation reset, AI_TURN)"
258
+ @tier "domain"
259
+ }
108
260
  }
109
261
 
110
- trait Producer = Production.traits.Producer -> GameState {
111
- config { running: true, startPoints: 3, pointsPerTurn: 2, spawnCost: 3, spawnX: 0, spawnY: 0, spawnTeam: "player", spawnUnitType: "tank", spawnHealth: 10 }
262
+ trait RtsEconomy -> @rebindable GameState [lifecycle] {
263
+ initial: active
264
+
265
+ state active {
266
+ INIT -> active
267
+ (set @entity.gold @config.startGold)
268
+ (set @entity.ecoSpawnCount 0)
269
+
270
+ BUILD_TANK -> active when (and @config.running (and (== @entity.result "none") (and (>= @entity.gold @config.tankCost) (== (array/len (array/filter @entity.units (fn u (and (> @u.health 0) (and (== (object/get (object/get @u position) x) @config.tankSpawnX) (== (object/get (object/get @u position) y) @config.tankSpawnY)))))) 0))))
271
+ (set @entity.gold (- @entity.gold @config.tankCost))
272
+ (emit SPAWN { id: (str/concat "rts-t-" @entity.ecoSpawnCount), x: @config.tankSpawnX, y: @config.tankSpawnY, team: "player", health: @config.tankHealth, maxHealth: @config.tankHealth, unitType: "tank" })
273
+ (set @entity.ecoSpawnCount (+ @entity.ecoSpawnCount 1))
274
+ }
275
+
276
+ ticks {
277
+ harvestTick every 2000ms when (and @config.running (== @entity.result "none"))
278
+ (set @entity.gold (+ @entity.gold (* (array/len (array/filter @entity.units (fn u (and (== @u.team "player") (and (> @u.health 0) (and (== @u.unitType "worker") (<= (grid/manhattan-distance (object/get @u position) { x: @config.mineX, y: @config.mineY }) 1))))))) @config.goldPerWorkerTick)))
279
+ }
280
+
281
+ emits {
282
+ SPAWN -> external {
283
+ id : string!
284
+ x : number!
285
+ y : number!
286
+ team : string!
287
+ health : number!
288
+ maxHealth : number!
289
+ unitType : string!
290
+ }
291
+ @description "Mustered-tank intent applied by the grid-tactics authority (the sole units writer)"
292
+ @tier "domain"
293
+ }
294
+
295
+ listens {
296
+ BUILD_TANK { id : string }
297
+ }
298
+
299
+ config {
300
+ running : boolean = true
301
+ @label "Running"
302
+ @description "When true, workers harvest and BUILD_TANK musters; toggle to freeze the economy."
303
+ @tier "domain"
304
+ startGold : number = 3
305
+ @label "Start Gold"
306
+ @description "Gold stockpile set on INIT."
307
+ @tier "domain"
308
+ goldPerWorkerTick : number = 1
309
+ @label "Gold Per Worker Tick"
310
+ @description "Gold each living worker at the mine harvests every 2s cycle."
311
+ @tier "domain"
312
+ tankCost : number = 5
313
+ @label "Tank Cost"
314
+ @description "Gold spent per mustered tank; BUILD_TANK only fires when affordable and the yard is clear."
315
+ @tier "domain"
316
+ tankHealth : number = 10
317
+ @label "Tank Health"
318
+ @description "Health/maxHealth of mustered tanks."
319
+ @tier "domain"
320
+ mineX : number = 0
321
+ @label "Mine X"
322
+ @description "Grid column of the gold-mine harvest anchor."
323
+ @tier "domain"
324
+ mineY : number = 0
325
+ @label "Mine Y"
326
+ @description "Grid row of the gold-mine harvest anchor."
327
+ @tier "domain"
328
+ tankSpawnX : number = 1
329
+ @label "Tank Spawn X"
330
+ @description "Grid column of the muster yard where new tanks roll out."
331
+ @tier "domain"
332
+ tankSpawnY : number = 3
333
+ @label "Tank Spawn Y"
334
+ @description "Grid row of the muster yard where new tanks roll out."
335
+ @tier "domain"
336
+ }
337
+ }
338
+
339
+ trait RtsWaves -> @rebindable GameState [lifecycle] {
340
+ initial: active
341
+
342
+ state active {
343
+ INIT -> active
344
+ (set @entity.waveCount 0)
345
+ }
346
+
347
+ ticks {
348
+ waveTick every 16000ms when (and @config.running (and (== @entity.result "none") (== (array/len (array/filter @entity.units (fn u (and (> @u.health 0) (and (== (object/get (object/get @u position) x) @config.waveSpawnX) (== (object/get (object/get @u position) y) @config.waveSpawnY)))))) 0)))
349
+ (emit SPAWN { id: (str/concat "rts-w-" @entity.waveCount), x: @config.waveSpawnX, y: @config.waveSpawnY, team: "enemy", health: (+ @config.waveBaseHealth @entity.waveCount), maxHealth: (+ @config.waveBaseHealth @entity.waveCount), unitType: "raider" })
350
+ (set @entity.waveCount (+ @entity.waveCount 1))
351
+ }
352
+
353
+ emits {
354
+ SPAWN -> external {
355
+ id : string!
356
+ x : number!
357
+ y : number!
358
+ team : string!
359
+ health : number!
360
+ maxHealth : number!
361
+ unitType : string!
362
+ }
363
+ @description "Raider-wave intent applied by the grid-tactics authority (the sole units writer)"
364
+ @tier "domain"
365
+ }
366
+
367
+ config {
368
+ running : boolean = true
369
+ @label "Running"
370
+ @description "When true, raider waves spawn every 16s; toggle to freeze the waves."
371
+ @tier "domain"
372
+ waveSpawnX : number = 7
373
+ @label "Wave Spawn X"
374
+ @description "Grid column of the den muster point where raiders stream in."
375
+ @tier "domain"
376
+ waveSpawnY : number = 5
377
+ @label "Wave Spawn Y"
378
+ @description "Grid row of the den muster point where raiders stream in."
379
+ @tier "domain"
380
+ waveBaseHealth : number = 6
381
+ @label "Wave Base Health"
382
+ @description "Health of the first raider wave; each later wave adds +1."
383
+ @tier "domain"
384
+ }
112
385
  }
113
386
 
114
387
  trait Player = Frame.traits.PlayerIntent -> GameState {
@@ -116,16 +389,19 @@ orbital TopdownRtsBoardOrbital {
116
389
  gridWidth: 8
117
390
  gridHeight: 6
118
391
  movementRange: 2
392
+ attackRange: 2
119
393
  projection: "flat"
120
394
  showMinimap: false
121
395
  scale: 0.45
122
- extraStats: [ { label: "Prod", value: @entity.productionPoints } ]
123
- extraAddonEvent: "PRODUCE"
124
- extraAddons: [ { type: "button", action: PRODUCE, label: "Produce (3)", variant: "secondary", iconAsset: { url: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/kenney-rts-medieval/terrain/medievalRTS_spritesheet.png", atlas: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/kenney-rts-medieval/terrain/medievalRTS_spritesheet.json", sprite: "medievalStructure_01.png", role: "ui", category: "ui", animations: [], style: "vector-flat", dimension: "2d", aspect: "1:1", name: "icon-produce", thumbnailUrl: "" } } ]
125
- features: [ { id: "f1", x: 2, y: 1, type: "obstacle", assetUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/kenney-rts-medieval/terrain/medievalRTS_spritesheet.png", atlas: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/kenney-rts-medieval/terrain/medievalRTS_spritesheet.json", sprite: "medievalEnvironment_01.png", role: "decoration", category: "obstacle", animations: ["static"], style: "vector-flat", dimension: "2d", aspect: "1:1", name: "obstacle", thumbnailUrl: "" } }, { id: "f2", x: 3, y: 2, type: "obstacle", assetUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/kenney-rts-medieval/terrain/medievalRTS_spritesheet.png", atlas: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/kenney-rts-medieval/terrain/medievalRTS_spritesheet.json", sprite: "medievalEnvironment_01.png", role: "decoration", category: "obstacle", animations: ["static"], style: "vector-flat", dimension: "2d", aspect: "1:1", name: "obstacle", thumbnailUrl: "" } }, { id: "f3", x: 4, y: 3, type: "obstacle", assetUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/kenney-rts-medieval/terrain/medievalRTS_spritesheet.png", atlas: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/kenney-rts-medieval/terrain/medievalRTS_spritesheet.json", sprite: "medievalEnvironment_01.png", role: "decoration", category: "obstacle", animations: ["static"], style: "vector-flat", dimension: "2d", aspect: "1:1", name: "obstacle", thumbnailUrl: "" } }, { id: "barracks1", x: 0, y: 0, type: "barracks", assetUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/kenney-rts-medieval/terrain/medievalRTS_spritesheet.png", atlas: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/kenney-rts-medieval/terrain/medievalRTS_spritesheet.json", sprite: "medievalStructure_01.png", role: "decoration", category: "barracks", animations: ["static"], style: "vector-flat", dimension: "2d", aspect: "1:1", name: "barracks", thumbnailUrl: "" } } ]
126
- assetManifest: { terrains: { ground: { url: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/kenney-rts-medieval/terrain/medievalRTS_spritesheet.png", atlas: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/kenney-rts-medieval/terrain/medievalRTS_spritesheet.json", sprite: "medievalTile_41.png", role: "tile", category: "ground", animations: ["static"], style: "vector-flat", dimension: "2d", aspect: "1:1", name: "ground", thumbnailUrl: "" }, sand: { url: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/kenney-rts-medieval/terrain/medievalRTS_spritesheet.png", atlas: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/kenney-rts-medieval/terrain/medievalRTS_spritesheet.json", sprite: "medievalTile_13.png", role: "tile", category: "sand", animations: ["static"], style: "vector-flat", dimension: "2d", aspect: "1:1", name: "sand", thumbnailUrl: "" } }, units: { tank: { url: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/kenney-rts-medieval/terrain/medievalRTS_spritesheet.png", atlas: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/kenney-rts-medieval/terrain/medievalRTS_spritesheet.json", sprite: "medievalUnit_01.png", role: "npc", category: "tank", animations: ["idle","walk","attack","hit","death"], style: "vector-flat", dimension: "2d", aspect: "1:1", name: "tank", thumbnailUrl: "" } }, features: { obstacle: { url: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/kenney-rts-medieval/terrain/medievalRTS_spritesheet.png", atlas: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/kenney-rts-medieval/terrain/medievalRTS_spritesheet.json", sprite: "medievalEnvironment_01.png", role: "decoration", category: "obstacle", animations: ["static"], style: "vector-flat", dimension: "2d", aspect: "1:1", name: "obstacle", thumbnailUrl: "" }, barracks: { url: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/kenney-rts-medieval/terrain/medievalRTS_spritesheet.png", atlas: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/kenney-rts-medieval/terrain/medievalRTS_spritesheet.json", sprite: "medievalStructure_01.png", role: "decoration", category: "barracks", animations: ["static"], style: "vector-flat", dimension: "2d", aspect: "1:1", name: "barracks", thumbnailUrl: "" } }, effects: { explosion: { url: "https://almadar-kflow-assets.web.app/shared/_shared/kenney-explosion-pack/effects/spritesheet_regularExplosion.png", atlas: "https://almadar-kflow-assets.web.app/shared/_shared/kenney-explosion-pack/effects/spritesheet_regularExplosion.json", sprite: "regularExplosion04.png", role: "effect", category: "explosion", animations: ["static"], style: "vector-flat", dimension: "2d", aspect: "8:1", name: "explosion", thumbnailUrl: "" } } }
396
+ backgroundAsset: { url: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/svg/flat/ui/panel-frame.svg", role: "ui", category: "ui", animations: [], style: "", dimension: "2d", aspect: "1:1", name: "panel-frame", thumbnailUrl: "" }
397
+ hudBackgroundAsset: { url: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/svg/flat/ui/panel-frame.svg", role: "ui", category: "ui", animations: [], style: "", dimension: "2d", aspect: "1:1", name: "panel-frame", thumbnailUrl: "" }
398
+ extraStats: [ { label: "Gold", value: @entity.gold }, { label: "Wave", value: @entity.waveCount } ]
399
+ extraAddonEvent: "BUILD_TANK"
400
+ extraAddons: [ { type: "button", action: BUILD_TANK, label: "Tank (5g)", variant: "secondary" } ]
401
+ features: [ { id: "mine1", x: 0, y: 0, type: "gold_mine", assetUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/svg/flat/features/gold_mine.svg", role: "decoration", category: "gold_mine", animations: ["static"], style: "", dimension: "2d", aspect: "1:1", name: "gold_mine", thumbnailUrl: "" } }, { id: "wall1", x: 0, y: 1, type: "wall", assetUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/svg/flat/features/wall.svg", role: "decoration", category: "wall", animations: ["static"], style: "", dimension: "2d", aspect: "1:1", name: "wall", thumbnailUrl: "" } }, { id: "wall2", x: 0, y: 2, type: "wall", assetUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/svg/flat/features/wall.svg", role: "decoration", category: "wall", animations: ["static"], style: "", dimension: "2d", aspect: "1:1", name: "wall", thumbnailUrl: "" } }, { id: "wall3", x: 0, y: 4, type: "wall", assetUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/svg/flat/features/wall.svg", role: "decoration", category: "wall", animations: ["static"], style: "", dimension: "2d", aspect: "1:1", name: "wall", thumbnailUrl: "" } }, { id: "wall4", x: 0, y: 5, type: "wall", assetUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/svg/flat/features/wall.svg", role: "decoration", category: "wall", animations: ["static"], style: "", dimension: "2d", aspect: "1:1", name: "wall", thumbnailUrl: "" } }, { id: "wall5", x: 1, y: 2, type: "wall", assetUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/svg/flat/features/wall.svg", role: "decoration", category: "wall", animations: ["static"], style: "", dimension: "2d", aspect: "1:1", name: "wall", thumbnailUrl: "" } }, { id: "wall6", x: 1, y: 4, type: "wall", assetUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/svg/flat/features/wall.svg", role: "decoration", category: "wall", animations: ["static"], style: "", dimension: "2d", aspect: "1:1", name: "wall", thumbnailUrl: "" } }, { id: "wall7", x: 6, y: 1, type: "wall", assetUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/svg/flat/features/wall.svg", role: "decoration", category: "wall", animations: ["static"], style: "", dimension: "2d", aspect: "1:1", name: "wall", thumbnailUrl: "" } }, { id: "wall8", x: 6, y: 2, type: "wall", assetUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/svg/flat/features/wall.svg", role: "decoration", category: "wall", animations: ["static"], style: "", dimension: "2d", aspect: "1:1", name: "wall", thumbnailUrl: "" } }, { id: "wall9", x: 6, y: 3, type: "wall", assetUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/svg/flat/features/wall.svg", role: "decoration", category: "wall", animations: ["static"], style: "", dimension: "2d", aspect: "1:1", name: "wall", thumbnailUrl: "" } }, { id: "wall10", x: 7, y: 1, type: "wall", assetUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/svg/flat/features/wall.svg", role: "decoration", category: "wall", animations: ["static"], style: "", dimension: "2d", aspect: "1:1", name: "wall", thumbnailUrl: "" } }, { id: "wall11", x: 7, y: 3, type: "wall", assetUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/svg/flat/features/wall.svg", role: "decoration", category: "wall", animations: ["static"], style: "", dimension: "2d", aspect: "1:1", name: "wall", thumbnailUrl: "" } } ]
402
+ assetManifest: { terrains: { ground: { url: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/svg/flat/terrain/ground.svg", role: "tile", category: "ground", animations: ["static"], style: "", dimension: "2d", aspect: "1:1", name: "ground", thumbnailUrl: "" }, sand: { url: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/svg/flat/terrain/sand.svg", role: "tile", category: "sand", animations: ["static"], style: "", dimension: "2d", aspect: "1:1", name: "sand", thumbnailUrl: "" } }, units: { tank: { url: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/svg/flat/units/tank.svg", role: "npc", category: "tank", animations: ["idle","walk","attack","hit","death"], style: "", dimension: "2d", aspect: "1:1", name: "tank", thumbnailUrl: "" }, raider: { url: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/svg/flat/units/raider.svg", role: "npc", category: "raider", animations: ["idle","walk","attack","hit","death"], style: "", dimension: "2d", aspect: "1:1", name: "raider", thumbnailUrl: "" }, worker: { url: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/svg/flat/units/worker.svg", role: "npc", category: "worker", animations: ["idle","walk","attack","hit","death"], style: "", dimension: "2d", aspect: "1:1", name: "worker", thumbnailUrl: "" }, town_hall: { url: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/svg/flat/units/town_hall.svg", role: "npc", category: "town_hall", animations: ["idle","walk","attack","hit","death"], style: "", dimension: "2d", aspect: "1:1", name: "town_hall", thumbnailUrl: "" }, raider_den: { url: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/svg/flat/units/raider_den.svg", role: "npc", category: "raider_den", animations: ["idle","walk","attack","hit","death"], style: "", dimension: "2d", aspect: "1:1", name: "raider_den", thumbnailUrl: "" } }, features: { gold_mine: { url: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/svg/flat/features/gold_mine.svg", role: "decoration", category: "gold_mine", animations: ["static"], style: "", dimension: "2d", aspect: "1:1", name: "gold_mine", thumbnailUrl: "" }, wall: { url: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/svg/flat/features/wall.svg", role: "decoration", category: "wall", animations: ["static"], style: "", dimension: "2d", aspect: "1:1", name: "wall", thumbnailUrl: "" } }, effects: { hit: { url: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/svg/flat/effects/hit.svg", role: "effect", category: "hit", animations: ["static"], style: "", dimension: "2d", aspect: "1:1", name: "hit", thumbnailUrl: "" }, explosion: { url: "https://almadar-kflow-assets.web.app/shared/ui-topdown-rts-board/svg/flat/effects/explosion.svg", role: "effect", category: "explosion", animations: ["static"], style: "", dimension: "2d", aspect: "1:1", name: "explosion", thumbnailUrl: "" } } }
127
403
  }
128
404
  }
129
405
 
130
- page "/topdown-rts-board" as TopdownRtsBoardPage -> Authority, FxDecay, RoundLogic, ScoreKeeper, Producer, Player
406
+ page "/topdown-rts-board" as TopdownRtsBoardPage -> Authority, FxDecay, RoundLogic, ScoreKeeper, Player, AnimClock, RtsClock, RtsEconomy, RtsWaves
131
407
  }
@@ -124,7 +124,7 @@ orbital TowerDefenseBoardOrbital {
124
124
  hudBackgroundAsset: { url: "https://almadar-kflow-assets.web.app/shared/_shared/kenney-ui-adventure-pack/ui/uipack_rpg_sheet.png", atlas: "https://almadar-kflow-assets.web.app/shared/_shared/kenney-ui-adventure-pack/ui/uipack_rpg_sheet.json", sprite: "panel_beige.png", role: "ui", category: "ui", animations: [], style: "vector", variant: "", dimension: "2d", aspect: "1:1", name: "panel-frame", thumbnailUrl: "" }
125
125
  hud: { type: game-hud, stats: [ { label: "Gold", value: @entity.gold, iconUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-tower-defense-board/kenney-cartography-pack/ui/spritesheet_default.png", atlas: "https://almadar-kflow-assets.web.app/shared/ui-tower-defense-board/kenney-cartography-pack/ui/spritesheet_default.json", sprite: "chest.png", role: "ui", category: "ui", animations: [], style: "vector", variant: "", dimension: "2d", aspect: "1:1", name: "icon-gold", thumbnailUrl: "" } }, { label: "Lives", value: @entity.lives, max: @config.lives, format: "bar", iconUrl: { url: "https://almadar-kflow-assets.web.app/shared/_shared/kenney-emote-pack/ui/vector_style1.png", atlas: "https://almadar-kflow-assets.web.app/shared/_shared/kenney-emote-pack/ui/vector_style1.json", sprite: "emote_heart.png", role: "ui", category: "ui", animations: [], style: "vector", variant: "", dimension: "2d", aspect: "1:1", name: "icon-lives", thumbnailUrl: "" } }, { label: "Wave", value: @entity.wave, max: @config.maxWaves, iconUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-tower-defense-board/kenney-cartography-pack/ui/spritesheet_default.png", atlas: "https://almadar-kflow-assets.web.app/shared/ui-tower-defense-board/kenney-cartography-pack/ui/spritesheet_default.json", sprite: "flag.png", role: "ui", category: "ui", animations: [], style: "vector", variant: "", dimension: "2d", aspect: "1:1", name: "icon-wave", thumbnailUrl: "" } }, { label: "Towers", value: (array/len @entity.towers), iconUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-tower-defense-board/kenney-cartography-pack/ui/spritesheet_default.png", atlas: "https://almadar-kflow-assets.web.app/shared/ui-tower-defense-board/kenney-cartography-pack/ui/spritesheet_default.json", sprite: "tower.png", role: "ui", category: "ui", animations: [], style: "vector", variant: "", dimension: "2d", aspect: "1:1", name: "icon-towers", thumbnailUrl: "" } } ] }
126
126
  addons: { type: button, action: START_WAVE, label: "Start Wave", iconAsset: { url: "https://almadar-kflow-assets.web.app/shared/_shared/kenney-mobile-controls/ui/icons-default.png", atlas: "https://almadar-kflow-assets.web.app/shared/_shared/kenney-mobile-controls/ui/icons-default.json", sprite: "icon_play", role: "ui", category: "ui", animations: [], style: "vector", variant: "", dimension: "2d", aspect: "1:1", name: "icon-start-wave", thumbnailUrl: "" }, variant: primary }
127
- children: [ { type: canvas, camera: { zoom: @config.scale }, projection: "isometric", showMinimap: true, tileClickEvent: PLACE_TOWER, unitClickEvent: UNIT_CLICK, children: [
127
+ children: [ { type: canvas, fit: true, camera: { zoom: @config.scale }, projection: "isometric", showMinimap: true, tileClickEvent: PLACE_TOWER, unitClickEvent: UNIT_CLICK, children: [
128
128
  { type: draw-sprite-layer, items: (array/map @config.tiles (fn t { type: draw-sprite, position: { x: (object/get @t x), y: (object/get @t y) }, asset: (object/get @t terrainSprite) })) }
129
129
  { type: draw-sprite-layer, items: (array/map @entity.towers (fn t { type: draw-sprite, position: { x: (object/get @t x), y: (object/get @t y) }, asset: (object/get (object/get @config.assetManifest features) "tower") })) }
130
130
  { type: draw-shape-layer, items: (array/map @entity.validMoves (fn m { type: draw-shape, shape: "cell", position: { x: (object/get @m x), y: (object/get @m y) }, fill: "rgba(74,222,128,0.4)" })) }
@@ -146,7 +146,7 @@ orbital TowerDefenseBoardOrbital {
146
146
  hudBackgroundAsset: { url: "https://almadar-kflow-assets.web.app/shared/_shared/kenney-ui-adventure-pack/ui/uipack_rpg_sheet.png", atlas: "https://almadar-kflow-assets.web.app/shared/_shared/kenney-ui-adventure-pack/ui/uipack_rpg_sheet.json", sprite: "panel_beige.png", role: "ui", category: "ui", animations: [], style: "vector", variant: "", dimension: "2d", aspect: "1:1", name: "panel-frame", thumbnailUrl: "" }
147
147
  hud: { type: game-hud, stats: [ { label: "Gold", value: @entity.gold, iconUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-tower-defense-board/kenney-cartography-pack/ui/spritesheet_default.png", atlas: "https://almadar-kflow-assets.web.app/shared/ui-tower-defense-board/kenney-cartography-pack/ui/spritesheet_default.json", sprite: "chest.png", role: "ui", category: "ui", animations: [], style: "vector", variant: "", dimension: "2d", aspect: "1:1", name: "icon-gold", thumbnailUrl: "" } }, { label: "Lives", value: @entity.lives, max: @config.lives, format: "bar", iconUrl: { url: "https://almadar-kflow-assets.web.app/shared/_shared/kenney-emote-pack/ui/vector_style1.png", atlas: "https://almadar-kflow-assets.web.app/shared/_shared/kenney-emote-pack/ui/vector_style1.json", sprite: "emote_heart.png", role: "ui", category: "ui", animations: [], style: "vector", variant: "", dimension: "2d", aspect: "1:1", name: "icon-lives", thumbnailUrl: "" } }, { label: "Wave", value: @entity.wave, max: @config.maxWaves, iconUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-tower-defense-board/kenney-cartography-pack/ui/spritesheet_default.png", atlas: "https://almadar-kflow-assets.web.app/shared/ui-tower-defense-board/kenney-cartography-pack/ui/spritesheet_default.json", sprite: "flag.png", role: "ui", category: "ui", animations: [], style: "vector", variant: "", dimension: "2d", aspect: "1:1", name: "icon-wave", thumbnailUrl: "" } }, { label: "Towers", value: (array/len @entity.towers), iconUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-tower-defense-board/kenney-cartography-pack/ui/spritesheet_default.png", atlas: "https://almadar-kflow-assets.web.app/shared/ui-tower-defense-board/kenney-cartography-pack/ui/spritesheet_default.json", sprite: "tower.png", role: "ui", category: "ui", animations: [], style: "vector", variant: "", dimension: "2d", aspect: "1:1", name: "icon-towers", thumbnailUrl: "" } } ] }
148
148
  addons: { type: button, action: START_WAVE, label: "Start Wave", iconAsset: { url: "https://almadar-kflow-assets.web.app/shared/_shared/kenney-mobile-controls/ui/icons-default.png", atlas: "https://almadar-kflow-assets.web.app/shared/_shared/kenney-mobile-controls/ui/icons-default.json", sprite: "icon_play", role: "ui", category: "ui", animations: [], style: "vector", variant: "", dimension: "2d", aspect: "1:1", name: "icon-start-wave", thumbnailUrl: "" }, variant: primary }
149
- children: [ { type: canvas, camera: { zoom: @config.scale }, projection: "isometric", showMinimap: true, tileClickEvent: PLACE_TOWER, unitClickEvent: UNIT_CLICK, children: [
149
+ children: [ { type: canvas, fit: true, camera: { zoom: @config.scale }, projection: "isometric", showMinimap: true, tileClickEvent: PLACE_TOWER, unitClickEvent: UNIT_CLICK, children: [
150
150
  { type: draw-sprite-layer, items: (array/map @config.tiles (fn t { type: draw-sprite, position: { x: (object/get @t x), y: (object/get @t y) }, asset: (object/get @t terrainSprite) })) }
151
151
  { type: draw-sprite-layer, items: (array/map @entity.towers (fn t { type: draw-sprite, position: { x: (object/get @t x), y: (object/get @t y) }, asset: (object/get (object/get @config.assetManifest features) "tower") })) }
152
152
  { type: draw-shape-layer, items: (array/map @entity.validMoves (fn m { type: draw-shape, shape: "cell", position: { x: (object/get @m x), y: (object/get @m y) }, fill: "rgba(74,222,128,0.4)" })) }
@@ -168,7 +168,7 @@ orbital TowerDefenseBoardOrbital {
168
168
  hudBackgroundAsset: { url: "https://almadar-kflow-assets.web.app/shared/_shared/kenney-ui-adventure-pack/ui/uipack_rpg_sheet.png", atlas: "https://almadar-kflow-assets.web.app/shared/_shared/kenney-ui-adventure-pack/ui/uipack_rpg_sheet.json", sprite: "panel_beige.png", role: "ui", category: "ui", animations: [], style: "vector", variant: "", dimension: "2d", aspect: "1:1", name: "panel-frame", thumbnailUrl: "" }
169
169
  hud: { type: game-hud, stats: [ { label: "Gold", value: @entity.gold, iconUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-tower-defense-board/kenney-cartography-pack/ui/spritesheet_default.png", atlas: "https://almadar-kflow-assets.web.app/shared/ui-tower-defense-board/kenney-cartography-pack/ui/spritesheet_default.json", sprite: "chest.png", role: "ui", category: "ui", animations: [], style: "vector", variant: "", dimension: "2d", aspect: "1:1", name: "icon-gold", thumbnailUrl: "" } }, { label: "Lives", value: @entity.lives, max: @config.lives, format: "bar", iconUrl: { url: "https://almadar-kflow-assets.web.app/shared/_shared/kenney-emote-pack/ui/vector_style1.png", atlas: "https://almadar-kflow-assets.web.app/shared/_shared/kenney-emote-pack/ui/vector_style1.json", sprite: "emote_heart.png", role: "ui", category: "ui", animations: [], style: "vector", variant: "", dimension: "2d", aspect: "1:1", name: "icon-lives", thumbnailUrl: "" } }, { label: "Wave", value: @entity.wave, max: @config.maxWaves, iconUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-tower-defense-board/kenney-cartography-pack/ui/spritesheet_default.png", atlas: "https://almadar-kflow-assets.web.app/shared/ui-tower-defense-board/kenney-cartography-pack/ui/spritesheet_default.json", sprite: "flag.png", role: "ui", category: "ui", animations: [], style: "vector", variant: "", dimension: "2d", aspect: "1:1", name: "icon-wave", thumbnailUrl: "" } }, { label: "Towers", value: (array/len @entity.towers), iconUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-tower-defense-board/kenney-cartography-pack/ui/spritesheet_default.png", atlas: "https://almadar-kflow-assets.web.app/shared/ui-tower-defense-board/kenney-cartography-pack/ui/spritesheet_default.json", sprite: "tower.png", role: "ui", category: "ui", animations: [], style: "vector", variant: "", dimension: "2d", aspect: "1:1", name: "icon-towers", thumbnailUrl: "" } } ] }
170
170
  addons: { type: button, action: START_WAVE, label: "Start Wave", iconAsset: { url: "https://almadar-kflow-assets.web.app/shared/_shared/kenney-mobile-controls/ui/icons-default.png", atlas: "https://almadar-kflow-assets.web.app/shared/_shared/kenney-mobile-controls/ui/icons-default.json", sprite: "icon_play", role: "ui", category: "ui", animations: [], style: "vector", variant: "", dimension: "2d", aspect: "1:1", name: "icon-start-wave", thumbnailUrl: "" }, variant: primary }
171
- children: [ { type: canvas, camera: { zoom: @config.scale }, projection: "isometric", showMinimap: true, tileClickEvent: PLACE_TOWER, unitClickEvent: UNIT_CLICK, children: [
171
+ children: [ { type: canvas, fit: true, camera: { zoom: @config.scale }, projection: "isometric", showMinimap: true, tileClickEvent: PLACE_TOWER, unitClickEvent: UNIT_CLICK, children: [
172
172
  { type: draw-sprite-layer, items: (array/map @config.tiles (fn t { type: draw-sprite, position: { x: (object/get @t x), y: (object/get @t y) }, asset: (object/get @t terrainSprite) })) }
173
173
  { type: draw-sprite-layer, items: (array/map @entity.towers (fn t { type: draw-sprite, position: { x: (object/get @t x), y: (object/get @t y) }, asset: (object/get (object/get @config.assetManifest features) "tower") })) }
174
174
  { type: draw-shape-layer, items: (array/map @entity.validMoves (fn m { type: draw-shape, shape: "cell", position: { x: (object/get @m x), y: (object/get @m y) }, fill: "rgba(74,222,128,0.4)" })) }
@@ -188,7 +188,7 @@ orbital TowerDefenseBoardOrbital {
188
188
  hudBackgroundAsset: { url: "https://almadar-kflow-assets.web.app/shared/_shared/kenney-ui-adventure-pack/ui/uipack_rpg_sheet.png", atlas: "https://almadar-kflow-assets.web.app/shared/_shared/kenney-ui-adventure-pack/ui/uipack_rpg_sheet.json", sprite: "panel_beige.png", role: "ui", category: "ui", animations: [], style: "vector", variant: "", dimension: "2d", aspect: "1:1", name: "panel-frame", thumbnailUrl: "" }
189
189
  hud: { type: game-hud, stats: [ { label: "Gold", value: @entity.gold, iconUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-tower-defense-board/kenney-cartography-pack/ui/spritesheet_default.png", atlas: "https://almadar-kflow-assets.web.app/shared/ui-tower-defense-board/kenney-cartography-pack/ui/spritesheet_default.json", sprite: "chest.png", role: "ui", category: "ui", animations: [], style: "vector", variant: "", dimension: "2d", aspect: "1:1", name: "icon-gold", thumbnailUrl: "" } }, { label: "Lives", value: @entity.lives, max: @config.lives, format: "bar", iconUrl: { url: "https://almadar-kflow-assets.web.app/shared/_shared/kenney-emote-pack/ui/vector_style1.png", atlas: "https://almadar-kflow-assets.web.app/shared/_shared/kenney-emote-pack/ui/vector_style1.json", sprite: "emote_heart.png", role: "ui", category: "ui", animations: [], style: "vector", variant: "", dimension: "2d", aspect: "1:1", name: "icon-lives", thumbnailUrl: "" } }, { label: "Wave", value: @entity.wave, max: @config.maxWaves, iconUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-tower-defense-board/kenney-cartography-pack/ui/spritesheet_default.png", atlas: "https://almadar-kflow-assets.web.app/shared/ui-tower-defense-board/kenney-cartography-pack/ui/spritesheet_default.json", sprite: "flag.png", role: "ui", category: "ui", animations: [], style: "vector", variant: "", dimension: "2d", aspect: "1:1", name: "icon-wave", thumbnailUrl: "" } }, { label: "Towers", value: (array/len @entity.towers), iconUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-tower-defense-board/kenney-cartography-pack/ui/spritesheet_default.png", atlas: "https://almadar-kflow-assets.web.app/shared/ui-tower-defense-board/kenney-cartography-pack/ui/spritesheet_default.json", sprite: "tower.png", role: "ui", category: "ui", animations: [], style: "vector", variant: "", dimension: "2d", aspect: "1:1", name: "icon-towers", thumbnailUrl: "" } } ] }
190
190
  overlay: { type: game-menu, title: (if (== @entity.result "won") "VICTORY" "DEFEAT"), subtitle: (if (== @entity.result "won") "All waves survived" "The base has fallen"), options: [ { id: "again", label: "Play Again", event: "PLAY_AGAIN", variant: "primary" } ] }
191
- children: [ { type: canvas, camera: { zoom: @config.scale }, projection: "isometric", showMinimap: true, tileClickEvent: PLACE_TOWER, unitClickEvent: UNIT_CLICK, children: [
191
+ children: [ { type: canvas, fit: true, camera: { zoom: @config.scale }, projection: "isometric", showMinimap: true, tileClickEvent: PLACE_TOWER, unitClickEvent: UNIT_CLICK, children: [
192
192
  { type: draw-sprite-layer, items: (array/map @config.tiles (fn t { type: draw-sprite, position: { x: (object/get @t x), y: (object/get @t y) }, asset: (object/get @t terrainSprite) })) }
193
193
  { type: draw-sprite-layer, items: (array/map @entity.towers (fn t { type: draw-sprite, position: { x: (object/get @t x), y: (object/get @t y) }, asset: (object/get (object/get @config.assetManifest features) "tower") })) }
194
194
  { type: draw-shape-layer, items: (array/map @entity.validMoves (fn m { type: draw-shape, shape: "cell", position: { x: (object/get @m x), y: (object/get @m y) }, fill: "rgba(74,222,128,0.4)" })) }
@@ -223,7 +223,7 @@ orbital TowerDefenseBoardOrbital {
223
223
  hudBackgroundAsset: { url: "https://almadar-kflow-assets.web.app/shared/_shared/kenney-ui-adventure-pack/ui/uipack_rpg_sheet.png", atlas: "https://almadar-kflow-assets.web.app/shared/_shared/kenney-ui-adventure-pack/ui/uipack_rpg_sheet.json", sprite: "panel_beige.png", role: "ui", category: "ui", animations: [], style: "vector", variant: "", dimension: "2d", aspect: "1:1", name: "panel-frame", thumbnailUrl: "" }
224
224
  hud: { type: game-hud, stats: [ { label: "Gold", value: @entity.gold, iconUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-tower-defense-board/kenney-cartography-pack/ui/spritesheet_default.png", atlas: "https://almadar-kflow-assets.web.app/shared/ui-tower-defense-board/kenney-cartography-pack/ui/spritesheet_default.json", sprite: "chest.png", role: "ui", category: "ui", animations: [], style: "vector", variant: "", dimension: "2d", aspect: "1:1", name: "icon-gold", thumbnailUrl: "" } }, { label: "Lives", value: @entity.lives, max: @config.lives, format: "bar", iconUrl: { url: "https://almadar-kflow-assets.web.app/shared/_shared/kenney-emote-pack/ui/vector_style1.png", atlas: "https://almadar-kflow-assets.web.app/shared/_shared/kenney-emote-pack/ui/vector_style1.json", sprite: "emote_heart.png", role: "ui", category: "ui", animations: [], style: "vector", variant: "", dimension: "2d", aspect: "1:1", name: "icon-lives", thumbnailUrl: "" } }, { label: "Wave", value: @entity.wave, max: @config.maxWaves, iconUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-tower-defense-board/kenney-cartography-pack/ui/spritesheet_default.png", atlas: "https://almadar-kflow-assets.web.app/shared/ui-tower-defense-board/kenney-cartography-pack/ui/spritesheet_default.json", sprite: "flag.png", role: "ui", category: "ui", animations: [], style: "vector", variant: "", dimension: "2d", aspect: "1:1", name: "icon-wave", thumbnailUrl: "" } }, { label: "Towers", value: (array/len @entity.towers), iconUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-tower-defense-board/kenney-cartography-pack/ui/spritesheet_default.png", atlas: "https://almadar-kflow-assets.web.app/shared/ui-tower-defense-board/kenney-cartography-pack/ui/spritesheet_default.json", sprite: "tower.png", role: "ui", category: "ui", animations: [], style: "vector", variant: "", dimension: "2d", aspect: "1:1", name: "icon-towers", thumbnailUrl: "" } } ] }
225
225
  addons: { type: button, action: START_WAVE, label: "Start Wave", iconAsset: { url: "https://almadar-kflow-assets.web.app/shared/_shared/kenney-mobile-controls/ui/icons-default.png", atlas: "https://almadar-kflow-assets.web.app/shared/_shared/kenney-mobile-controls/ui/icons-default.json", sprite: "icon_play", role: "ui", category: "ui", animations: [], style: "vector", variant: "", dimension: "2d", aspect: "1:1", name: "icon-start-wave", thumbnailUrl: "" }, variant: primary }
226
- children: [ { type: canvas, camera: { zoom: @config.scale }, projection: "isometric", showMinimap: true, tileClickEvent: PLACE_TOWER, unitClickEvent: UNIT_CLICK, children: [
226
+ children: [ { type: canvas, fit: true, camera: { zoom: @config.scale }, projection: "isometric", showMinimap: true, tileClickEvent: PLACE_TOWER, unitClickEvent: UNIT_CLICK, children: [
227
227
  { type: draw-sprite-layer, items: (array/map @config.tiles (fn t { type: draw-sprite, position: { x: (object/get @t x), y: (object/get @t y) }, asset: (object/get @t terrainSprite) })) }
228
228
  { type: draw-sprite-layer, items: (array/map @entity.towers (fn t { type: draw-sprite, position: { x: (object/get @t x), y: (object/get @t y) }, asset: (object/get (object/get @config.assetManifest features) "tower") })) }
229
229
  { type: draw-shape-layer, items: (array/map @entity.validMoves (fn m { type: draw-shape, shape: "cell", position: { x: (object/get @m x), y: (object/get @m y) }, fill: "rgba(74,222,128,0.4)" })) }
@@ -248,7 +248,7 @@ orbital TowerDefenseBoardOrbital {
248
248
  hudBackgroundAsset: { url: "https://almadar-kflow-assets.web.app/shared/_shared/kenney-ui-adventure-pack/ui/uipack_rpg_sheet.png", atlas: "https://almadar-kflow-assets.web.app/shared/_shared/kenney-ui-adventure-pack/ui/uipack_rpg_sheet.json", sprite: "panel_beige.png", role: "ui", category: "ui", animations: [], style: "vector", variant: "", dimension: "2d", aspect: "1:1", name: "panel-frame", thumbnailUrl: "" }
249
249
  hud: { type: game-hud, stats: [ { label: "Gold", value: @entity.gold, iconUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-tower-defense-board/kenney-cartography-pack/ui/spritesheet_default.png", atlas: "https://almadar-kflow-assets.web.app/shared/ui-tower-defense-board/kenney-cartography-pack/ui/spritesheet_default.json", sprite: "chest.png", role: "ui", category: "ui", animations: [], style: "vector", variant: "", dimension: "2d", aspect: "1:1", name: "icon-gold", thumbnailUrl: "" } }, { label: "Lives", value: @entity.lives, max: @config.lives, format: "bar", iconUrl: { url: "https://almadar-kflow-assets.web.app/shared/_shared/kenney-emote-pack/ui/vector_style1.png", atlas: "https://almadar-kflow-assets.web.app/shared/_shared/kenney-emote-pack/ui/vector_style1.json", sprite: "emote_heart.png", role: "ui", category: "ui", animations: [], style: "vector", variant: "", dimension: "2d", aspect: "1:1", name: "icon-lives", thumbnailUrl: "" } }, { label: "Wave", value: @entity.wave, max: @config.maxWaves, iconUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-tower-defense-board/kenney-cartography-pack/ui/spritesheet_default.png", atlas: "https://almadar-kflow-assets.web.app/shared/ui-tower-defense-board/kenney-cartography-pack/ui/spritesheet_default.json", sprite: "flag.png", role: "ui", category: "ui", animations: [], style: "vector", variant: "", dimension: "2d", aspect: "1:1", name: "icon-wave", thumbnailUrl: "" } }, { label: "Towers", value: (array/len @entity.towers), iconUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-tower-defense-board/kenney-cartography-pack/ui/spritesheet_default.png", atlas: "https://almadar-kflow-assets.web.app/shared/ui-tower-defense-board/kenney-cartography-pack/ui/spritesheet_default.json", sprite: "tower.png", role: "ui", category: "ui", animations: [], style: "vector", variant: "", dimension: "2d", aspect: "1:1", name: "icon-towers", thumbnailUrl: "" } } ] }
250
250
  addons: { type: button, action: START_WAVE, label: "Start Wave", iconAsset: { url: "https://almadar-kflow-assets.web.app/shared/_shared/kenney-mobile-controls/ui/icons-default.png", atlas: "https://almadar-kflow-assets.web.app/shared/_shared/kenney-mobile-controls/ui/icons-default.json", sprite: "icon_play", role: "ui", category: "ui", animations: [], style: "vector", variant: "", dimension: "2d", aspect: "1:1", name: "icon-start-wave", thumbnailUrl: "" }, variant: primary }
251
- children: [ { type: canvas, camera: { zoom: @config.scale }, projection: "isometric", showMinimap: true, tileClickEvent: PLACE_TOWER, unitClickEvent: UNIT_CLICK, children: [
251
+ children: [ { type: canvas, fit: true, camera: { zoom: @config.scale }, projection: "isometric", showMinimap: true, tileClickEvent: PLACE_TOWER, unitClickEvent: UNIT_CLICK, children: [
252
252
  { type: draw-sprite-layer, items: (array/map @config.tiles (fn t { type: draw-sprite, position: { x: (object/get @t x), y: (object/get @t y) }, asset: (object/get @t terrainSprite) })) }
253
253
  { type: draw-sprite-layer, items: (array/map @entity.towers (fn t { type: draw-sprite, position: { x: (object/get @t x), y: (object/get @t y) }, asset: (object/get (object/get @config.assetManifest features) "tower") })) }
254
254
  { type: draw-shape-layer, items: (array/map @entity.validMoves (fn m { type: draw-shape, shape: "cell", position: { x: (object/get @m x), y: (object/get @m y) }, fill: "rgba(74,222,128,0.4)" })) }
@@ -279,7 +279,7 @@ orbital TowerDefenseBoardOrbital {
279
279
  hudBackgroundAsset: { url: "https://almadar-kflow-assets.web.app/shared/_shared/kenney-ui-adventure-pack/ui/uipack_rpg_sheet.png", atlas: "https://almadar-kflow-assets.web.app/shared/_shared/kenney-ui-adventure-pack/ui/uipack_rpg_sheet.json", sprite: "panel_beige.png", role: "ui", category: "ui", animations: [], style: "vector", variant: "", dimension: "2d", aspect: "1:1", name: "panel-frame", thumbnailUrl: "" }
280
280
  hud: { type: game-hud, stats: [ { label: "Gold", value: @entity.gold, iconUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-tower-defense-board/kenney-cartography-pack/ui/spritesheet_default.png", atlas: "https://almadar-kflow-assets.web.app/shared/ui-tower-defense-board/kenney-cartography-pack/ui/spritesheet_default.json", sprite: "chest.png", role: "ui", category: "ui", animations: [], style: "vector", variant: "", dimension: "2d", aspect: "1:1", name: "icon-gold", thumbnailUrl: "" } }, { label: "Lives", value: @entity.lives, max: @config.lives, format: "bar", iconUrl: { url: "https://almadar-kflow-assets.web.app/shared/_shared/kenney-emote-pack/ui/vector_style1.png", atlas: "https://almadar-kflow-assets.web.app/shared/_shared/kenney-emote-pack/ui/vector_style1.json", sprite: "emote_heart.png", role: "ui", category: "ui", animations: [], style: "vector", variant: "", dimension: "2d", aspect: "1:1", name: "icon-lives", thumbnailUrl: "" } }, { label: "Wave", value: @entity.wave, max: @config.maxWaves, iconUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-tower-defense-board/kenney-cartography-pack/ui/spritesheet_default.png", atlas: "https://almadar-kflow-assets.web.app/shared/ui-tower-defense-board/kenney-cartography-pack/ui/spritesheet_default.json", sprite: "flag.png", role: "ui", category: "ui", animations: [], style: "vector", variant: "", dimension: "2d", aspect: "1:1", name: "icon-wave", thumbnailUrl: "" } }, { label: "Towers", value: (array/len @entity.towers), iconUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-tower-defense-board/kenney-cartography-pack/ui/spritesheet_default.png", atlas: "https://almadar-kflow-assets.web.app/shared/ui-tower-defense-board/kenney-cartography-pack/ui/spritesheet_default.json", sprite: "tower.png", role: "ui", category: "ui", animations: [], style: "vector", variant: "", dimension: "2d", aspect: "1:1", name: "icon-towers", thumbnailUrl: "" } } ] }
281
281
  addons: { type: button, action: START_WAVE, label: "Start Wave", iconAsset: { url: "https://almadar-kflow-assets.web.app/shared/_shared/kenney-mobile-controls/ui/icons-default.png", atlas: "https://almadar-kflow-assets.web.app/shared/_shared/kenney-mobile-controls/ui/icons-default.json", sprite: "icon_play", role: "ui", category: "ui", animations: [], style: "vector", variant: "", dimension: "2d", aspect: "1:1", name: "icon-start-wave", thumbnailUrl: "" }, variant: primary }
282
- children: [ { type: canvas, camera: { zoom: @config.scale }, projection: "isometric", showMinimap: true, tileClickEvent: PLACE_TOWER, unitClickEvent: UNIT_CLICK, children: [
282
+ children: [ { type: canvas, fit: true, camera: { zoom: @config.scale }, projection: "isometric", showMinimap: true, tileClickEvent: PLACE_TOWER, unitClickEvent: UNIT_CLICK, children: [
283
283
  { type: draw-sprite-layer, items: (array/map @config.tiles (fn t { type: draw-sprite, position: { x: (object/get @t x), y: (object/get @t y) }, asset: (object/get @t terrainSprite) })) }
284
284
  { type: draw-sprite-layer, items: (array/map @entity.towers (fn t { type: draw-sprite, position: { x: (object/get @t x), y: (object/get @t y) }, asset: (object/get (object/get @config.assetManifest features) "tower") })) }
285
285
  { type: draw-shape-layer, items: (array/map @entity.validMoves (fn m { type: draw-shape, shape: "cell", position: { x: (object/get @m x), y: (object/get @m y) }, fill: "rgba(74,222,128,0.4)" })) }
@@ -304,7 +304,7 @@ orbital TowerDefenseBoardOrbital {
304
304
  hudBackgroundAsset: { url: "https://almadar-kflow-assets.web.app/shared/_shared/kenney-ui-adventure-pack/ui/uipack_rpg_sheet.png", atlas: "https://almadar-kflow-assets.web.app/shared/_shared/kenney-ui-adventure-pack/ui/uipack_rpg_sheet.json", sprite: "panel_beige.png", role: "ui", category: "ui", animations: [], style: "vector", variant: "", dimension: "2d", aspect: "1:1", name: "panel-frame", thumbnailUrl: "" }
305
305
  hud: { type: game-hud, stats: [ { label: "Gold", value: @entity.gold, iconUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-tower-defense-board/kenney-cartography-pack/ui/spritesheet_default.png", atlas: "https://almadar-kflow-assets.web.app/shared/ui-tower-defense-board/kenney-cartography-pack/ui/spritesheet_default.json", sprite: "chest.png", role: "ui", category: "ui", animations: [], style: "vector", variant: "", dimension: "2d", aspect: "1:1", name: "icon-gold", thumbnailUrl: "" } }, { label: "Lives", value: @entity.lives, max: @config.lives, format: "bar", iconUrl: { url: "https://almadar-kflow-assets.web.app/shared/_shared/kenney-emote-pack/ui/vector_style1.png", atlas: "https://almadar-kflow-assets.web.app/shared/_shared/kenney-emote-pack/ui/vector_style1.json", sprite: "emote_heart.png", role: "ui", category: "ui", animations: [], style: "vector", variant: "", dimension: "2d", aspect: "1:1", name: "icon-lives", thumbnailUrl: "" } }, { label: "Wave", value: @entity.wave, max: @config.maxWaves, iconUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-tower-defense-board/kenney-cartography-pack/ui/spritesheet_default.png", atlas: "https://almadar-kflow-assets.web.app/shared/ui-tower-defense-board/kenney-cartography-pack/ui/spritesheet_default.json", sprite: "flag.png", role: "ui", category: "ui", animations: [], style: "vector", variant: "", dimension: "2d", aspect: "1:1", name: "icon-wave", thumbnailUrl: "" } }, { label: "Towers", value: (array/len @entity.towers), iconUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-tower-defense-board/kenney-cartography-pack/ui/spritesheet_default.png", atlas: "https://almadar-kflow-assets.web.app/shared/ui-tower-defense-board/kenney-cartography-pack/ui/spritesheet_default.json", sprite: "tower.png", role: "ui", category: "ui", animations: [], style: "vector", variant: "", dimension: "2d", aspect: "1:1", name: "icon-towers", thumbnailUrl: "" } } ] }
306
306
  addons: { type: button, action: START_WAVE, label: "Start Wave", iconAsset: { url: "https://almadar-kflow-assets.web.app/shared/_shared/kenney-mobile-controls/ui/icons-default.png", atlas: "https://almadar-kflow-assets.web.app/shared/_shared/kenney-mobile-controls/ui/icons-default.json", sprite: "icon_play", role: "ui", category: "ui", animations: [], style: "vector", variant: "", dimension: "2d", aspect: "1:1", name: "icon-start-wave", thumbnailUrl: "" }, variant: primary }
307
- children: [ { type: canvas, camera: { zoom: @config.scale }, projection: "isometric", showMinimap: true, tileClickEvent: PLACE_TOWER, unitClickEvent: UNIT_CLICK, children: [
307
+ children: [ { type: canvas, fit: true, camera: { zoom: @config.scale }, projection: "isometric", showMinimap: true, tileClickEvent: PLACE_TOWER, unitClickEvent: UNIT_CLICK, children: [
308
308
  { type: draw-sprite-layer, items: (array/map @config.tiles (fn t { type: draw-sprite, position: { x: (object/get @t x), y: (object/get @t y) }, asset: (object/get @t terrainSprite) })) }
309
309
  { type: draw-sprite-layer, items: (array/map @entity.towers (fn t { type: draw-sprite, position: { x: (object/get @t x), y: (object/get @t y) }, asset: (object/get (object/get @config.assetManifest features) "tower") })) }
310
310
  { type: draw-shape-layer, items: (array/map @entity.validMoves (fn m { type: draw-shape, shape: "cell", position: { x: (object/get @m x), y: (object/get @m y) }, fill: "rgba(74,222,128,0.4)" })) }