@almadar/std 16.154.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 (39) hide show
  1. package/behaviors/lolo/ui/game/molecules/std-tactics-board-2d.lolo +35 -21
  2. package/behaviors/lolo/ui/game/molecules/ui-canvas.lolo +5 -0
  3. package/behaviors/lolo/ui/game/organisms/ui-battle-board.lolo +122 -74
  4. package/behaviors/lolo/ui/game/organisms/ui-hex-strategy-board.lolo +153 -9
  5. package/behaviors/lolo/ui/game/organisms/ui-tactics-demo-2d.lolo +130 -8
  6. package/behaviors/lolo/ui/game/organisms/ui-tanks-board.lolo +147 -7
  7. package/behaviors/lolo/ui/game/organisms/ui-topdown-rts-board.lolo +291 -19
  8. package/behaviors/registry/factory-signatures.json +1893 -2294
  9. package/behaviors/registry/ui/game/molecules/std-tactics-board-2d.orb +798 -189
  10. package/behaviors/registry/ui/game/molecules/ui-canvas.orb +7 -0
  11. package/behaviors/registry/ui/game/organisms/ui-battle-board.orb +17 -1
  12. package/behaviors/registry/ui/game/organisms/ui-hex-strategy-board.orb +68 -1180
  13. package/behaviors/registry/ui/game/organisms/ui-tactics-demo-2d.orb +192 -322
  14. package/behaviors/registry/ui/game/organisms/ui-tanks-board.orb +97 -85
  15. package/behaviors/registry/ui/game/organisms/ui-topdown-rts-board.orb +1477 -259
  16. package/dist/behaviors/behaviors-embeddings.json +244 -236
  17. package/dist/behaviors/behaviors-registry.json +143 -772
  18. package/dist/behaviors/exports-reader.js +1099 -2090
  19. package/dist/behaviors/functions/index.d.ts +33 -26
  20. package/dist/behaviors/functions/index.js +1099 -2091
  21. package/dist/behaviors/index.d.ts +1 -1
  22. package/dist/behaviors/index.js +1100 -2091
  23. package/dist/behaviors/knob-embeddings.json +1 -1
  24. package/dist/behaviors/query.js +1099 -2090
  25. package/dist/behaviors/registry/factory-signatures.json +1893 -2294
  26. package/dist/behaviors/registry/ui/game/molecules/std-tactics-board-2d.orb +798 -189
  27. package/dist/behaviors/registry/ui/game/molecules/ui-canvas.orb +7 -0
  28. package/dist/behaviors/registry/ui/game/organisms/ui-battle-board.orb +17 -1
  29. package/dist/behaviors/registry/ui/game/organisms/ui-hex-strategy-board.orb +68 -1180
  30. package/dist/behaviors/registry/ui/game/organisms/ui-tactics-demo-2d.orb +192 -322
  31. package/dist/behaviors/registry/ui/game/organisms/ui-tanks-board.orb +97 -85
  32. package/dist/behaviors/registry/ui/game/organisms/ui-topdown-rts-board.orb +1477 -259
  33. package/dist/behaviors-embeddings.json +244 -236
  34. package/dist/behaviors-registry.json +143 -772
  35. package/dist/index.d.ts +1 -1
  36. package/dist/index.js +1100 -2091
  37. package/dist/knob-embeddings.json +1 -1
  38. package/dist/registry/factory-signatures.json +1893 -2294
  39. 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,32 +229,179 @@ orbital TopdownRtsBoardOrbital {
104
229
  }
105
230
 
106
231
  trait ScoreKeeper = Score.traits.ScoreKeeper -> GameState {
107
- config { running: true, pointsPerKill: 10, startScore: 0, initialEnemies: 2 }
108
- }
109
-
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 }
232
+ config { running: true, pointsPerKill: 10, startScore: 0, initialEnemies: 1 }
112
233
  }
113
234
 
114
235
  trait AnimClock = Frame.traits.AnimClock -> GameState {
115
236
  config { frames: [] }
116
237
  }
117
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
+ }
260
+ }
261
+
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
+ }
385
+ }
386
+
118
387
  trait Player = Frame.traits.PlayerIntent -> GameState {
119
388
  config {
120
389
  gridWidth: 8
121
390
  gridHeight: 6
122
391
  movementRange: 2
392
+ attackRange: 2
123
393
  projection: "flat"
124
394
  showMinimap: false
125
395
  scale: 0.45
126
- extraStats: [ { label: "Prod", value: @entity.productionPoints } ]
127
- extraAddonEvent: "PRODUCE"
128
- 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: "" } } ]
129
- 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: "" } } ]
130
- 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: "" } } }
131
403
  }
132
404
  }
133
405
 
134
- page "/topdown-rts-board" as TopdownRtsBoardPage -> Authority, FxDecay, RoundLogic, ScoreKeeper, Producer, Player, AnimClock
406
+ page "/topdown-rts-board" as TopdownRtsBoardPage -> Authority, FxDecay, RoundLogic, ScoreKeeper, Player, AnimClock, RtsClock, RtsEconomy, RtsWaves
135
407
  }