@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.
- package/behaviors/lolo/ui/game/molecules/std-crew-board-2d.lolo +4 -4
- package/behaviors/lolo/ui/game/molecules/std-dungeon-board-2d.lolo +6 -6
- package/behaviors/lolo/ui/game/molecules/std-tactics-board-2d.lolo +74 -28
- package/behaviors/lolo/ui/game/molecules/std-worldmap-board-2d.lolo +2 -2
- package/behaviors/lolo/ui/game/molecules/ui-canvas.lolo +5 -0
- package/behaviors/lolo/ui/game/organisms/ui-arena-board.lolo +2 -2
- package/behaviors/lolo/ui/game/organisms/ui-battle-board.lolo +159 -8
- package/behaviors/lolo/ui/game/organisms/ui-builder-board.lolo +5 -20
- package/behaviors/lolo/ui/game/organisms/ui-card-battler-board.lolo +2 -0
- package/behaviors/lolo/ui/game/organisms/ui-castle-board.lolo +3 -3
- package/behaviors/lolo/ui/game/organisms/ui-city-builder-board.lolo +9 -7
- package/behaviors/lolo/ui/game/organisms/ui-grid-tactics-demo-board.lolo +2 -2
- package/behaviors/lolo/ui/game/organisms/ui-hex-strategy-board.lolo +158 -10
- package/behaviors/lolo/ui/game/organisms/ui-holiday-runner-board.lolo +1 -1
- package/behaviors/lolo/ui/game/organisms/ui-minigolf-board.lolo +22 -22
- package/behaviors/lolo/ui/game/organisms/ui-pinball-board.lolo +7 -7
- package/behaviors/lolo/ui/game/organisms/ui-pirate-board.lolo +14 -14
- package/behaviors/lolo/ui/game/organisms/ui-platformer-board.lolo +4 -0
- package/behaviors/lolo/ui/game/organisms/ui-sports-board.lolo +10 -7
- package/behaviors/lolo/ui/game/organisms/ui-tactics-demo-2d.lolo +135 -9
- package/behaviors/lolo/ui/game/organisms/ui-tanks-board.lolo +152 -8
- package/behaviors/lolo/ui/game/organisms/ui-topdown-rts-board.lolo +293 -17
- package/behaviors/lolo/ui/game/organisms/ui-tower-defense-board.lolo +8 -8
- package/behaviors/lolo/ui/game/organisms/ui-uncontrolled-battle-board.lolo +5 -5
- package/behaviors/lolo/ui/game/organisms/ui-world-map-board.lolo +3 -3
- package/behaviors/registry/factory-signatures.json +1893 -2294
- package/behaviors/registry/ui/game/molecules/std-crew-board-2d.orb +10 -12
- package/behaviors/registry/ui/game/molecules/std-dungeon-board-2d.orb +15 -18
- package/behaviors/registry/ui/game/molecules/std-tactics-board-2d.orb +1726 -395
- package/behaviors/registry/ui/game/molecules/std-worldmap-board-2d.orb +7 -60
- package/behaviors/registry/ui/game/molecules/ui-canvas.orb +7 -0
- package/behaviors/registry/ui/game/organisms/ui-arena-board.orb +5 -6
- package/behaviors/registry/ui/game/organisms/ui-battle-board.orb +103 -100
- package/behaviors/registry/ui/game/organisms/ui-builder-board.orb +21 -226
- package/behaviors/registry/ui/game/organisms/ui-card-battler-board.orb +42 -0
- package/behaviors/registry/ui/game/organisms/ui-castle-board.orb +30 -9
- package/behaviors/registry/ui/game/organisms/ui-city-builder-board.orb +49 -0
- package/behaviors/registry/ui/game/organisms/ui-grid-tactics-demo-board.orb +5 -6
- package/behaviors/registry/ui/game/organisms/ui-hex-strategy-board.orb +95 -1187
- package/behaviors/registry/ui/game/organisms/ui-holiday-runner-board.orb +2 -3
- package/behaviors/registry/ui/game/organisms/ui-minigolf-board.orb +55 -11
- package/behaviors/registry/ui/game/organisms/ui-pinball-board.orb +8 -8
- package/behaviors/registry/ui/game/organisms/ui-pirate-board.orb +14 -0
- package/behaviors/registry/ui/game/organisms/ui-platformer-board.orb +72 -0
- package/behaviors/registry/ui/game/organisms/ui-sports-board.orb +60 -0
- package/behaviors/registry/ui/game/organisms/ui-tactics-demo-2d.orb +222 -332
- package/behaviors/registry/ui/game/organisms/ui-tanks-board.orb +127 -95
- package/behaviors/registry/ui/game/organisms/ui-topdown-rts-board.orb +1501 -264
- package/behaviors/registry/ui/game/organisms/ui-tower-defense-board.orb +8 -0
- package/behaviors/registry/ui/game/organisms/ui-uncontrolled-battle-board.orb +5 -0
- package/behaviors/registry/ui/game/organisms/ui-world-map-board.orb +8 -12
- package/dist/behaviors/behaviors-embeddings.json +244 -236
- package/dist/behaviors/behaviors-registry.json +193 -812
- package/dist/behaviors/exports-reader.js +1099 -2090
- package/dist/behaviors/functions/index.d.ts +33 -26
- package/dist/behaviors/functions/index.js +1099 -2091
- package/dist/behaviors/index.d.ts +1 -1
- package/dist/behaviors/index.js +1100 -2091
- package/dist/behaviors/knob-embeddings.json +1 -1
- package/dist/behaviors/query.js +1099 -2090
- package/dist/behaviors/registry/factory-signatures.json +1893 -2294
- package/dist/behaviors/registry/ui/game/molecules/std-crew-board-2d.orb +10 -12
- package/dist/behaviors/registry/ui/game/molecules/std-dungeon-board-2d.orb +15 -18
- package/dist/behaviors/registry/ui/game/molecules/std-tactics-board-2d.orb +1726 -395
- package/dist/behaviors/registry/ui/game/molecules/std-worldmap-board-2d.orb +7 -60
- package/dist/behaviors/registry/ui/game/molecules/ui-canvas.orb +7 -0
- package/dist/behaviors/registry/ui/game/organisms/ui-arena-board.orb +5 -6
- package/dist/behaviors/registry/ui/game/organisms/ui-battle-board.orb +103 -100
- package/dist/behaviors/registry/ui/game/organisms/ui-builder-board.orb +21 -226
- package/dist/behaviors/registry/ui/game/organisms/ui-card-battler-board.orb +42 -0
- package/dist/behaviors/registry/ui/game/organisms/ui-castle-board.orb +30 -9
- package/dist/behaviors/registry/ui/game/organisms/ui-city-builder-board.orb +49 -0
- package/dist/behaviors/registry/ui/game/organisms/ui-grid-tactics-demo-board.orb +5 -6
- package/dist/behaviors/registry/ui/game/organisms/ui-hex-strategy-board.orb +95 -1187
- package/dist/behaviors/registry/ui/game/organisms/ui-holiday-runner-board.orb +2 -3
- package/dist/behaviors/registry/ui/game/organisms/ui-minigolf-board.orb +55 -11
- package/dist/behaviors/registry/ui/game/organisms/ui-pinball-board.orb +8 -8
- package/dist/behaviors/registry/ui/game/organisms/ui-pirate-board.orb +14 -0
- package/dist/behaviors/registry/ui/game/organisms/ui-platformer-board.orb +72 -0
- package/dist/behaviors/registry/ui/game/organisms/ui-sports-board.orb +60 -0
- package/dist/behaviors/registry/ui/game/organisms/ui-tactics-demo-2d.orb +222 -332
- package/dist/behaviors/registry/ui/game/organisms/ui-tanks-board.orb +127 -95
- package/dist/behaviors/registry/ui/game/organisms/ui-topdown-rts-board.orb +1501 -264
- package/dist/behaviors/registry/ui/game/organisms/ui-tower-defense-board.orb +8 -0
- package/dist/behaviors/registry/ui/game/organisms/ui-uncontrolled-battle-board.orb +5 -0
- package/dist/behaviors/registry/ui/game/organisms/ui-world-map-board.orb +8 -12
- package/dist/behaviors-embeddings.json +244 -236
- package/dist/behaviors-registry.json +193 -812
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1100 -2091
- package/dist/knob-embeddings.json +1 -1
- package/dist/registry/factory-signatures.json +1893 -2294
- package/package.json +2 -2
|
@@ -1,5 +1,123 @@
|
|
|
1
1
|
app ui-tactics-demo-2d "1.0.0"
|
|
2
|
-
"
|
|
2
|
+
"Micro grid-tactics demo: thin organism composing the std-tactics-board-2d frame + std-score. Two soldiers vs one raider on a 3x3 flat grid — the minimal reference consumer of the tactics frame. Flat hand-authored svg theme supplied via config."
|
|
3
|
+
;; @capabilities "turn-based combat, strategy gameplay"
|
|
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, commanding two soldiers on a 3x3 flat grid
|
|
10
|
+
;; against a single raider. Statuses verified 2026-07-30 by guard-truth
|
|
11
|
+
;; probes (almadar-tools play_transition, 8/8) and a scripted playthrough
|
|
12
|
+
;; (29/29 checks) driving the real game on the runtime-verify catalog
|
|
13
|
+
;; through window.__orbitalVerification — events in, canvas drawables +
|
|
14
|
+
;; HUD DOM + bus event log out. Asset sprites 404 until the CDN push
|
|
15
|
+
;; lands; they are verified at the drawable-descriptor (URL) level.
|
|
16
|
+
;;
|
|
17
|
+
;; THE GENRE (what a grid-tactics player expects, at demo scale): you command
|
|
18
|
+
;; a tiny squad, not an army. Positioning is the whole game — you read the
|
|
19
|
+
;; grid, step each soldier inside the raider's reach, and commit to the
|
|
20
|
+
;; strike. Every End Turn hands the board to the raider AI, which closes the
|
|
21
|
+
;; distance and punishes an adjacent soldier. The kill is the economy: it
|
|
22
|
+
;; scores, and wiping the enemy wins the skirmish. A round looks like:
|
|
23
|
+
;; select a soldier -> green reach cells -> move -> the soldier STAYS
|
|
24
|
+
;; selected and auto-arms (red cells = enemies in reach) -> strike for 2 ->
|
|
25
|
+
;; the soldier is SPENT (dims, cannot act again this turn) -> activate the
|
|
26
|
+
;; next soldier -> End Turn -> the raider strikes an adjacent soldier for 1
|
|
27
|
+
;; or steps 1 cell toward the nearest soldier -> repeat. Each unit may move
|
|
28
|
+
;; ONCE and attack ONCE per turn (movedIds/actedIds track the activation;
|
|
29
|
+
;; End Turn resets both). The raider has 2 hp, so one 2-damage strike kills
|
|
30
|
+
;; it; a kill scores 10 and flips the Result to victory.
|
|
31
|
+
;; ============================================================================
|
|
32
|
+
;;
|
|
33
|
+
;; PLAYER — "I maneuver my two soldiers and take the raider down."
|
|
34
|
+
;;
|
|
35
|
+
;; 1. I open the board and see the whole skirmish framed on screen —
|
|
36
|
+
;; grass under every cell, my soldiers on the west column, the raider
|
|
37
|
+
;; on the east, and the HUD showing Result/Phase/Turn/Score.
|
|
38
|
+
;; WORKS. Boot paints 9 flat cells whose terrain drawables all point
|
|
39
|
+
;; at svg/flat/terrain/grass.svg, 3 units (2v1: soldiers x=0, raider
|
|
40
|
+
;; x=2), HUD reads "none / observation / 0 / 0". Verified in the
|
|
41
|
+
;; catalog playthrough (s01-boot.png).
|
|
42
|
+
;; 2. Every unit on the board is a visible sprite with a name label and a
|
|
43
|
+
;; health bar I can read at a glance.
|
|
44
|
+
;; WORKS. Each unit's drawable url-rewrites to its svg idle frame
|
|
45
|
+
;; (4-frame breathing, cycled by the AnimClock tick — descriptors
|
|
46
|
+
;; showed soldier.idle-N.svg cycling) anchored "ground", with the
|
|
47
|
+
;; black backing + green health fraction above and the name label.
|
|
48
|
+
;; All 3 bars read full (1.00) at boot; labels Soldier A / Soldier B
|
|
49
|
+
;; / Raider all painted.
|
|
50
|
+
;; 3. I click one of MY soldiers and the cells it can reach light up.
|
|
51
|
+
;; WORKS. Clicking p1 sets phase "selection" and lights exactly 4
|
|
52
|
+
;; green cells — the range-2 manhattan diamond from (0,0) minus the
|
|
53
|
+
;; two occupied cells (s03-select.png). SPENT soldiers (in actedIds)
|
|
54
|
+
;; are not selectable: play_transition on the attack arm with
|
|
55
|
+
;; actedIds ["p1"] returns guard=fail.
|
|
56
|
+
;; 4. I click a lit cell and the soldier moves there — and stays selected,
|
|
57
|
+
;; auto-armed, so I can strike immediately. One move per turn.
|
|
58
|
+
;; WORKS. p1 walked (0,0)->(1,1): the walk animation plays (caught
|
|
59
|
+
;; mid-cycle, s04-walk.png), the authority re-validates and writes
|
|
60
|
+
;; the position, and the unit lands in phase "action". A second
|
|
61
|
+
;; TILE_CLICK the same turn is denied (movedIds guard — unit held
|
|
62
|
+
;; at (1,1)), and re-clicking the moved unit lights zero green
|
|
63
|
+
;; cells. Guard truth: play_transition move pass / already-moved
|
|
64
|
+
;; fail / out-of-bounds fail.
|
|
65
|
+
;; 5. Adjacent enemies I can strike light up red — right after my move,
|
|
66
|
+
;; or when I click my selected soldier again.
|
|
67
|
+
;; WORKS. Post-move auto-arm computes red cells from the NEW position:
|
|
68
|
+
;; after p1 -> (1,1) the raider's cell (2,1) lit red (s05-armed.png).
|
|
69
|
+
;; Living enemies at manhattan distance <= attackRange (config,
|
|
70
|
+
;; default 1) light red.
|
|
71
|
+
;; 6. I click a red-lit enemy — or any enemy in reach, even without arming
|
|
72
|
+
;; first — and it takes a hit; my soldier is then spent for the turn.
|
|
73
|
+
;; WORKS. The attack arm fires whenever a living selected unit has a
|
|
74
|
+
;; living enemy in reach, regardless of phase — a direct click on the
|
|
75
|
+
;; raider from phase "selection" landed the 2-damage kill. A "-2"
|
|
76
|
+
;; damage number + hit fx sprite spawn at the target (BURST, ttl 3),
|
|
77
|
+
;; and the attacker joins actedIds: it dimmed to 0.45 opacity.
|
|
78
|
+
;; Guard truth via play_transition: in-range pass, out-of-range
|
|
79
|
+
;; fail, already-acted fail. (On this 2hp-raider board the first
|
|
80
|
+
;; strike also ends the game, so spent-select denial is proven by
|
|
81
|
+
;; the guard probe rather than a mid-game click.)
|
|
82
|
+
;; 7. I change my mind mid-selection and back out cleanly.
|
|
83
|
+
;; WORKS. CANCEL clears selection, highlights, and phase back to
|
|
84
|
+
;; "observation" (green 4 -> 0). Guard truth: play_transition pass.
|
|
85
|
+
;; 8. I end my turn and the raider takes theirs — it closes in and fights
|
|
86
|
+
;; back, and my soldiers are fresh again.
|
|
87
|
+
;; WORKS. END_TURN bumps Turn (0 -> 1), clears selection + both
|
|
88
|
+
;; activation lists, and emits AI_TURN; the authority struck the
|
|
89
|
+
;; adjacent p1 for 1 (hp 3 -> 2, health bar shrank) — the raider was
|
|
90
|
+
;; already in reach, so no step was needed (s08-ai-turn.png). After
|
|
91
|
+
;; the reset p1 was selectable again (phase "selection").
|
|
92
|
+
;; 9. When I kill the raider I am rewarded — score ticks up and the
|
|
93
|
+
;; corpse stays on the field.
|
|
94
|
+
;; WORKS. The kill scored +10 (ScoreKeeper on UNITS_CHANGED; HUD
|
|
95
|
+
;; Score 0 -> 10), the corpse renders its death frame
|
|
96
|
+
;; (raider.death-0.svg descriptor), and its health bar + name label
|
|
97
|
+
;; dropped from the canvas (s09-kill.png).
|
|
98
|
+
;; 10. When the raider falls, I win and the game tells me — then the
|
|
99
|
+
;; board freezes.
|
|
100
|
+
;; WORKS. Result flips to "victory" (RoundLogic on UNITS_CHANGED),
|
|
101
|
+
;; GAME_END fires on the bus, and every UNIT_CLICK / TILE_CLICK arm
|
|
102
|
+
;; is guarded on result == "none" — a post-game click on p2 selected
|
|
103
|
+
;; nothing and lit zero cells (s10-victory.png).
|
|
104
|
+
;;
|
|
105
|
+
;; ASSET INVENTORY (hand-authored svg, almadar-kflow-assets.web.app
|
|
106
|
+
;; /shared/ui-tactics-demo-2d/svg/flat/, generated by tools/asset-workflow
|
|
107
|
+
;; svg-generator from the sibling .md descriptions)
|
|
108
|
+
;;
|
|
109
|
+
;; Terrain terrain/grass.svg — full-cell flat tile, drawn at
|
|
110
|
+
;; width/height 1 so no gaps show between cells.
|
|
111
|
+
;; Units units/{soldier,raider}.svg + animation frames
|
|
112
|
+
;; .{idle-0..3, walk-0..1, attack-0, hit-0, death-0}.svg; the
|
|
113
|
+
;; frame swaps url-rewrites name.svg -> name.<anim>-<i>.svg and a
|
|
114
|
+
;; hidden warm-up layer preloads every frame so swaps never pop.
|
|
115
|
+
;; player: p1 Soldier A 3hp (0,0) p2 Soldier B 3hp (0,2)
|
|
116
|
+
;; enemy: e1 Raider 2hp (2,1)
|
|
117
|
+
;; Effects effects/hit.svg (BURST "hit" fx at the struck cell).
|
|
118
|
+
;; UI chrome ui/panel-frame.svg = game-shell background + HUD panel.
|
|
119
|
+
;; ============================================================================
|
|
120
|
+
|
|
3
121
|
orbital TacticsDemo2DOrbital {
|
|
4
122
|
uses Frame from "std/behaviors/std-tactics-board-2d"
|
|
5
123
|
uses Score from "std/behaviors/std-score"
|
|
@@ -68,13 +186,15 @@ orbital TacticsDemo2DOrbital {
|
|
|
68
186
|
|
|
69
187
|
entity GameState [runtime, shared] {
|
|
70
188
|
id : string!
|
|
71
|
-
units : [Unit] = [ { id: "p1", position: { x: 0, y: 0 }, x: 0, y: 0, z: 0, team: "player", health: 3, maxHealth: 3, unitType: "soldier", name: "Soldier A", modelUrl: { url: "https://almadar-kflow-assets.web.app/shared/
|
|
189
|
+
units : [Unit] = [ { id: "p1", position: { x: 0, y: 0 }, x: 0, y: 0, z: 0, team: "player", health: 3, maxHealth: 3, unitType: "soldier", name: "Soldier A", modelUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-tactics-demo-2d/svg/flat/units/soldier.svg", role: "npc", category: "soldier", animations: ["idle","walk","attack","hit","death"], style: "", dimension: "2d", aspect: "1:1", name: "soldier", thumbnailUrl: "" } }, { id: "p2", position: { x: 0, y: 2 }, x: 0, y: 2, z: 0, team: "player", health: 3, maxHealth: 3, unitType: "soldier", name: "Soldier B", modelUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-tactics-demo-2d/svg/flat/units/soldier.svg", role: "npc", category: "soldier", animations: ["idle","walk","attack","hit","death"], style: "", dimension: "2d", aspect: "1:1", name: "soldier", thumbnailUrl: "" } }, { id: "e1", position: { x: 2, y: 1 }, x: 2, y: 1, z: 0, team: "enemy", health: 2, maxHealth: 2, unitType: "raider", name: "Raider", modelUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-tactics-demo-2d/svg/flat/units/raider.svg", role: "npc", category: "raider", animations: ["idle","walk","attack","hit","death"], style: "", dimension: "2d", aspect: "1:1", name: "raider", thumbnailUrl: "" } } ]
|
|
72
190
|
fx : [Fx] = []
|
|
73
|
-
tiles : [Tile] = [ { id: "t-0-0", x: 0, y: 0, terrain: "grass", passable: true
|
|
191
|
+
tiles : [Tile] = [ { id: "t-0-0", x: 0, y: 0, terrain: "grass", passable: true }, { id: "t-1-0", x: 1, y: 0, terrain: "grass", passable: true }, { id: "t-2-0", x: 2, y: 0, terrain: "grass", passable: true }, { id: "t-0-1", x: 0, y: 1, terrain: "grass", passable: true }, { id: "t-1-1", x: 1, y: 1, terrain: "grass", passable: true }, { id: "t-2-1", x: 2, y: 1, terrain: "grass", passable: true }, { id: "t-0-2", x: 0, y: 2, terrain: "grass", passable: true }, { id: "t-1-2", x: 1, y: 2, terrain: "grass", passable: true }, { id: "t-2-2", x: 2, y: 2, terrain: "grass", passable: true } ]
|
|
74
192
|
result : string = "none"
|
|
75
193
|
selectedUnitId : string = ""
|
|
76
194
|
validMoves : [ValidMove] = []
|
|
77
195
|
attackTargets : [ValidMove] = []
|
|
196
|
+
movedIds : [string] = []
|
|
197
|
+
actedIds : [string] = []
|
|
78
198
|
uiPhase : string = "observation"
|
|
79
199
|
turn : number = 0
|
|
80
200
|
score : number = 0
|
|
@@ -87,8 +207,8 @@ orbital TacticsDemo2DOrbital {
|
|
|
87
207
|
gridWidth: 3
|
|
88
208
|
gridHeight: 3
|
|
89
209
|
attackDamage: 2
|
|
90
|
-
units: [ { id: "p1", position: { x: 0, y: 0 }, x: 0, y: 0, z: 0, team: "player", health: 3, maxHealth: 3, unitType: "soldier", name: "Soldier A", modelUrl: { url: "https://almadar-kflow-assets.web.app/shared/
|
|
91
|
-
tiles: [ { id: "t-0-0", x: 0, y: 0, terrain: "grass", passable: true
|
|
210
|
+
units: [ { id: "p1", position: { x: 0, y: 0 }, x: 0, y: 0, z: 0, team: "player", health: 3, maxHealth: 3, unitType: "soldier", name: "Soldier A", modelUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-tactics-demo-2d/svg/flat/units/soldier.svg", role: "npc", category: "soldier", animations: ["idle","walk","attack","hit","death"], style: "", dimension: "2d", aspect: "1:1", name: "soldier", thumbnailUrl: "" } }, { id: "p2", position: { x: 0, y: 2 }, x: 0, y: 2, z: 0, team: "player", health: 3, maxHealth: 3, unitType: "soldier", name: "Soldier B", modelUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-tactics-demo-2d/svg/flat/units/soldier.svg", role: "npc", category: "soldier", animations: ["idle","walk","attack","hit","death"], style: "", dimension: "2d", aspect: "1:1", name: "soldier", thumbnailUrl: "" } }, { id: "e1", position: { x: 2, y: 1 }, x: 2, y: 1, z: 0, team: "enemy", health: 2, maxHealth: 2, unitType: "raider", name: "Raider", modelUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-tactics-demo-2d/svg/flat/units/raider.svg", role: "npc", category: "raider", animations: ["idle","walk","attack","hit","death"], style: "", dimension: "2d", aspect: "1:1", name: "raider", thumbnailUrl: "" } } ]
|
|
211
|
+
tiles: [ { id: "t-0-0", x: 0, y: 0, terrain: "grass", passable: true }, { id: "t-1-0", x: 1, y: 0, terrain: "grass", passable: true }, { id: "t-2-0", x: 2, y: 0, terrain: "grass", passable: true }, { id: "t-0-1", x: 0, y: 1, terrain: "grass", passable: true }, { id: "t-1-1", x: 1, y: 1, terrain: "grass", passable: true }, { id: "t-2-1", x: 2, y: 1, terrain: "grass", passable: true }, { id: "t-0-2", x: 0, y: 2, terrain: "grass", passable: true }, { id: "t-1-2", x: 1, y: 2, terrain: "grass", passable: true }, { id: "t-2-2", x: 2, y: 2, terrain: "grass", passable: true } ]
|
|
92
212
|
}
|
|
93
213
|
}
|
|
94
214
|
|
|
@@ -101,7 +221,11 @@ orbital TacticsDemo2DOrbital {
|
|
|
101
221
|
}
|
|
102
222
|
|
|
103
223
|
trait ScoreKeeper = Score.traits.ScoreKeeper -> GameState {
|
|
104
|
-
config { running: true, initialEnemies: 1 }
|
|
224
|
+
config { running: true, pointsPerKill: 10, startScore: 0, initialEnemies: 1 }
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
trait AnimClock = Frame.traits.AnimClock -> GameState {
|
|
228
|
+
config { frames: [] }
|
|
105
229
|
}
|
|
106
230
|
|
|
107
231
|
trait Player = Frame.traits.PlayerIntent -> GameState {
|
|
@@ -109,13 +233,15 @@ orbital TacticsDemo2DOrbital {
|
|
|
109
233
|
gridWidth: 3
|
|
110
234
|
gridHeight: 3
|
|
111
235
|
movementRange: 2
|
|
112
|
-
features: []
|
|
113
|
-
assetManifest: { terrains: {}, units: {}, features: {}, effects: {} }
|
|
114
236
|
projection: "flat"
|
|
115
237
|
showMinimap: false
|
|
116
238
|
scale: 1
|
|
239
|
+
backgroundAsset: { url: "https://almadar-kflow-assets.web.app/shared/ui-tactics-demo-2d/svg/flat/ui/panel-frame.svg", role: "ui", category: "ui", animations: [], style: "adventure", dimension: "2d", aspect: "1:1", name: "panel-frame", thumbnailUrl: "" }
|
|
240
|
+
hudBackgroundAsset: { url: "https://almadar-kflow-assets.web.app/shared/ui-tactics-demo-2d/svg/flat/ui/panel-frame.svg", role: "ui", category: "ui", animations: [], style: "adventure", dimension: "2d", aspect: "1:1", name: "panel-frame", thumbnailUrl: "" }
|
|
241
|
+
features: []
|
|
242
|
+
assetManifest: { terrains: { grass: { url: "https://almadar-kflow-assets.web.app/shared/ui-tactics-demo-2d/svg/flat/terrain/grass.svg", role: "tile", category: "grass", animations: ["static"], style: "", dimension: "2d", aspect: "1:1", name: "grass", thumbnailUrl: "" } }, units: { soldier: { url: "https://almadar-kflow-assets.web.app/shared/ui-tactics-demo-2d/svg/flat/units/soldier.svg", role: "npc", category: "soldier", animations: ["idle","walk","attack","hit","death"], style: "", dimension: "2d", aspect: "1:1", name: "soldier", thumbnailUrl: "" }, raider: { url: "https://almadar-kflow-assets.web.app/shared/ui-tactics-demo-2d/svg/flat/units/raider.svg", role: "npc", category: "raider", animations: ["idle","walk","attack","hit","death"], style: "", dimension: "2d", aspect: "1:1", name: "raider", thumbnailUrl: "" } }, features: {}, effects: { hit: { url: "https://almadar-kflow-assets.web.app/shared/ui-tactics-demo-2d/svg/flat/effects/hit.svg", role: "effect", category: "hit", animations: ["static"], style: "", dimension: "2d", aspect: "1:1", name: "hit", thumbnailUrl: "" } }, ui: { panel-frame: { url: "https://almadar-kflow-assets.web.app/shared/ui-tactics-demo-2d/svg/flat/ui/panel-frame.svg", role: "ui", category: "ui", animations: [], style: "adventure", dimension: "2d", aspect: "1:1", name: "panel-frame", thumbnailUrl: "" } } }
|
|
117
243
|
}
|
|
118
244
|
}
|
|
119
245
|
|
|
120
|
-
page "/tactics-demo-2d" as TacticsDemo2DPage -> Authority, FxDecay, RoundLogic, ScoreKeeper, Player
|
|
246
|
+
page "/tactics-demo-2d" as TacticsDemo2DPage -> Authority, FxDecay, RoundLogic, ScoreKeeper, Player, AnimClock
|
|
121
247
|
}
|
|
@@ -1,6 +1,143 @@
|
|
|
1
1
|
app ui-tanks-board "1.0.0"
|
|
2
|
-
"Sci-fi tank grid-tactics
|
|
2
|
+
"Sci-fi tank grid-tactics skirmish: thin organism composing the std-tactics-board-2d frame + std-score. Flat-projection hand-authored svg theme (desert ground, sand strip, sandbag cover, tank sprites) supplied entirely via config."
|
|
3
3
|
;; @capabilities "tank grid-tactics combat, top-down tank movement, sci-fi themed battle, turn-based tank strategy"
|
|
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, commanding the lone tank Alpha on an 8x6 flat
|
|
10
|
+
;; desert grid against two enemy tanks (Bravo, Charlie). Status re-verified
|
|
11
|
+
;; 2026-07-30 by scripted playthroughs driving the real game on the
|
|
12
|
+
;; runtime-verify catalog through window.__orbitalVerification — events in,
|
|
13
|
+
;; canvas drawables + HUD DOM + bus event log out: victory run 33/35 (the 2
|
|
14
|
+
;; anim-frame misses were 400ms-sampling artifacts, both proven by the
|
|
15
|
+
;; focused probe), focused probe 7/7, defeat run 4/4.
|
|
16
|
+
;;
|
|
17
|
+
;; THE GENRE (what a tank-tactics player expects): armored warfare in
|
|
18
|
+
;; miniature — one precious hull, not a swarm. You maneuver for firing
|
|
19
|
+
;; position: your cannon reaches TWO cells (attackRange 2), so you can shell
|
|
20
|
+
;; an enemy before it can answer, because the enemy AI only fires at
|
|
21
|
+
;; point-blank (1 cell) and otherwise rolls 1 cell toward you each turn.
|
|
22
|
+
;; Every shot and every move is a commitment: each tank moves ONCE and fires
|
|
23
|
+
;; ONCE per turn (movedIds/actedIds), then sits spent until End Turn.
|
|
24
|
+
;; Kills are the economy: each enemy destroyed scores 10. You win by
|
|
25
|
+
;; destroying both enemy tanks; you lose the moment Alpha is destroyed.
|
|
26
|
+
;; A round looks like: select Alpha -> green reach cells -> move -> Alpha
|
|
27
|
+
;; STAYS selected and auto-arms (red cells = enemies in cannon reach) ->
|
|
28
|
+
;; fire for 3 -> Alpha is SPENT (dims, cannot act again this turn) ->
|
|
29
|
+
;; End Turn -> each living enemy strikes Alpha for 1 if adjacent, else
|
|
30
|
+
;; steps 1 cell toward Alpha -> repeat.
|
|
31
|
+
;; ============================================================================
|
|
32
|
+
;;
|
|
33
|
+
;; PLAYER — "I outmaneuver the enemy armor and destroy it before it closes
|
|
34
|
+
;; to point-blank."
|
|
35
|
+
;;
|
|
36
|
+
;; 1. I open the board and see the whole battlefield framed on screen —
|
|
37
|
+
;; terrain under every cell (desert ground with a sand strip), my tank
|
|
38
|
+
;; at the west, the enemy tanks at the east, sandbag cover in the
|
|
39
|
+
;; middle, and the HUD showing Result/Phase/Turn/Score.
|
|
40
|
+
;; WORKS. Boot paints 48 full-cell flat terrain sprites (ground with
|
|
41
|
+
;; a sand strip), 3 tanks (Alpha (1,1) west; Bravo (6,0), Charlie
|
|
42
|
+
;; (6,4) east), 6 sandbag features ground-anchored 1x1 at
|
|
43
|
+
;; (2,1)(3,2)(4,3)(5,3)(5,4)(2,4); HUD reads
|
|
44
|
+
;; "none / observation / 0 / 0". Drawable descriptors point at the
|
|
45
|
+
;; svg/flat CDN URLs (browser 404s expected this wave — the CDN push
|
|
46
|
+
;; is coordinator-handled; verified at descriptor level).
|
|
47
|
+
;; 2. Every tank on the board is a visible sprite with a name label and a
|
|
48
|
+
;; health bar I can read at a glance.
|
|
49
|
+
;; WORKS. Each tank paints its svg idle frame (4-frame breathing
|
|
50
|
+
;; squash/stretch anchored at the feet, cycled by the AnimClock) with
|
|
51
|
+
;; the black backing + green health fraction above and the name
|
|
52
|
+
;; label. All 3 bars read 1.00 at boot, all 3 labels paint. Dead
|
|
53
|
+
;; tanks drop the bar and label and switch to the death frame
|
|
54
|
+
;; (verified on both kills and on Alpha's own defeat).
|
|
55
|
+
;; 3. I click Alpha and the cells it can reach light up green.
|
|
56
|
+
;; WORKS. Clicking t1 sets phase "selection" and lights exactly 10
|
|
57
|
+
;; green cells — the range-2 manhattan diamond from (1,1) minus
|
|
58
|
+
;; out-of-bounds cells (none occupied at boot).
|
|
59
|
+
;; 4. I click a lit cell and Alpha moves there — and stays selected,
|
|
60
|
+
;; auto-armed, so I can fire immediately; it cannot move again this
|
|
61
|
+
;; turn.
|
|
62
|
+
;; WORKS. t1 walked (1,1)->(3,1): the walk animation plays (2-frame
|
|
63
|
+
;; cycle), the authority writes the position, phase lands on
|
|
64
|
+
;; "action", and the move is SPENT — a second TILE_CLICK is ignored
|
|
65
|
+
;; (tank stays at (3,1)) and a re-select lights zero green cells
|
|
66
|
+
;; (movedIds guard). One move per turn, no chaining.
|
|
67
|
+
;; 5. Enemies inside my cannon reach (2 cells) light up red — right after
|
|
68
|
+
;; my move, or when I click Alpha again.
|
|
69
|
+
;; WORKS. With Alpha at (2,2) and Charlie at (4,2), the post-move
|
|
70
|
+
;; auto-arm lit exactly {(4,2)} red — every living enemy within
|
|
71
|
+
;; attackRange 2 of the NEW cell — and the manual re-click arm
|
|
72
|
+
;; recomputed the same red set (phase "action").
|
|
73
|
+
;; 6. I click a red-lit enemy — or any enemy in reach, even without arming
|
|
74
|
+
;; first — and it takes a shell; Alpha is then spent for the turn. An
|
|
75
|
+
;; enemy OUT of reach does nothing when clicked.
|
|
76
|
+
;; WORKS. Direct enemy-click attack: t2 frac 1.00 -> 0.70 (10hp, -3),
|
|
77
|
+
;; BURST "-3" + hit.svg fx sprite at the target, attack frame on
|
|
78
|
+
;; Alpha, hit frame on the target (both caught by 100ms polling), and
|
|
79
|
+
;; Alpha joins actedIds: dims to 0.45 opacity, unselectable until End
|
|
80
|
+
;; Turn. Negative probe: clicking far-away t3 (distance 5) changed
|
|
81
|
+
;; nothing — phase and score untouched.
|
|
82
|
+
;; 7. I change my mind mid-selection and back out cleanly.
|
|
83
|
+
;; WORKS. CANCEL clears selection, highlights, and phase — verified
|
|
84
|
+
;; green cells 10 -> 0 and phase back to "observation".
|
|
85
|
+
;; 8. I end my turn and the enemy takes theirs — they close in and fight
|
|
86
|
+
;; back, and Alpha is fresh again.
|
|
87
|
+
;; WORKS. END_TURN bumps Turn, clears selection + both activation
|
|
88
|
+
;; lists (Alpha selectable again next turn), and emits AI_TURN; the
|
|
89
|
+
;; authority steps each living enemy 1 cell (diagonally — both axes)
|
|
90
|
+
;; toward Alpha and strikes for 1 when adjacent (verified: enemy
|
|
91
|
+
;; positions changed every turn; the defeat run ground Alpha 10->0).
|
|
92
|
+
;; LIMITATION: enemies POP to their new cell — the authority applies
|
|
93
|
+
;; the step silently and the single walk-anim slot is player-facing;
|
|
94
|
+
;; per-enemy MOVE fan-out is atom surgery, deferred.
|
|
95
|
+
;; 9. When I destroy an enemy I am rewarded — score ticks up, and the
|
|
96
|
+
;; wreck stays on the field without blocking movement.
|
|
97
|
+
;; WORKS x2. Each kill: Score +10 (verified 10 then 20 on the HUD)
|
|
98
|
+
;; and the wreck renders its death frame. Corpses are excluded from
|
|
99
|
+
;; the occupancy filters (health > 0) so their cells stay walkable —
|
|
100
|
+
;; inherited from the frame molecule's guards.
|
|
101
|
+
;; 10. When the last enemy tank falls, I win and the game tells me — then
|
|
102
|
+
;; the board freezes.
|
|
103
|
+
;; WORKS. Both enemies destroyed: Result flips to "victory"
|
|
104
|
+
;; (RoundLogic on UNITS_CHANGED), GAME_END fires, and the board is
|
|
105
|
+
;; FROZEN — post-game UNIT_CLICK selects nothing (phase stays
|
|
106
|
+
;; "observation", zero highlights). Reload to play again.
|
|
107
|
+
;; 11. If Alpha is destroyed, I lose and the game tells me — then the
|
|
108
|
+
;; board freezes.
|
|
109
|
+
;; WORKS. Defeat run (Alpha marches to point-blank and never fires):
|
|
110
|
+
;; adjacent enemy fire ground Alpha to 0, Result flipped to "defeat",
|
|
111
|
+
;; GAME_END fired, and the board froze (post-game clicks do nothing).
|
|
112
|
+
;;
|
|
113
|
+
;; MULTIPLAYER NOTE: GameState is [runtime, shared], so every connected
|
|
114
|
+
;; client watches the same skirmish on the same frame; intents serialize
|
|
115
|
+
;; through the server authority. There is no per-seat turn ownership yet —
|
|
116
|
+
;; any client can drive Alpha.
|
|
117
|
+
;;
|
|
118
|
+
;; ASSET INVENTORY (hand-authored svg, almadar-kflow-assets.web.app
|
|
119
|
+
;; /shared/ui-tanks-board/svg/flat/, generated by tools/asset-workflow
|
|
120
|
+
;; svg-generator from the sibling .md descriptions)
|
|
121
|
+
;;
|
|
122
|
+
;; Terrain terrain/ground.svg, terrain/sand.svg — full-cell flat tiles
|
|
123
|
+
;; (rounded-rect desert ground; sandy strip) drawn at
|
|
124
|
+
;; width/height 1.
|
|
125
|
+
;; Units units/{tank,tank_enemy}.svg + animation frames
|
|
126
|
+
;; .{idle-0..3, walk-0..1, attack-0, hit-0, death-0}.svg; the
|
|
127
|
+
;; frame swaps url-rewrite name.svg -> name.<anim>-<i>.svg and a
|
|
128
|
+
;; hidden warm-up layer preloads every frame so swaps never pop.
|
|
129
|
+
;; player: t1 Alpha 10hp (1,1) -> tank.svg
|
|
130
|
+
;; enemy: t2 Bravo 10hp (6,0) -> tank_enemy.svg
|
|
131
|
+
;; t3 Charlie 8hp (6,4) -> tank_enemy.svg
|
|
132
|
+
;; Features features/obstacle.svg — six sandbag-cover cells at
|
|
133
|
+
;; (2,1) (3,2) (4,3) (5,3) (5,4) (2,4), drawn from
|
|
134
|
+
;; config.features anchored "ground" at 1x1 so they sit ON their
|
|
135
|
+
;; cell. Decorative: they do not block movement (all tiles
|
|
136
|
+
;; passable).
|
|
137
|
+
;; Effects effects/hit.svg (BURST "hit" fx on every landed shell),
|
|
138
|
+
;; effects/explosion.svg (manifest-only).
|
|
139
|
+
;; UI chrome ui/panel-frame.svg = game-shell background + HUD panel.
|
|
140
|
+
;; ============================================================================
|
|
4
141
|
orbital TanksBoardOrbital {
|
|
5
142
|
uses Frame from "std/behaviors/std-tactics-board-2d"
|
|
6
143
|
uses Score from "std/behaviors/std-score"
|
|
@@ -69,13 +206,15 @@ orbital TanksBoardOrbital {
|
|
|
69
206
|
|
|
70
207
|
entity GameState [runtime, shared] {
|
|
71
208
|
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-tanks-board/
|
|
209
|
+
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-tanks-board/svg/flat/units/tank.svg", role: "npc", category: "tank", animations: ["idle","walk","attack","hit","death"], style: "sci-fi", dimension: "2d", aspect: "1:1", name: "tank", 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-tanks-board/svg/flat/units/tank_enemy.svg", role: "npc", category: "tank_enemy", animations: ["idle","walk","attack","hit","death"], style: "sci-fi", dimension: "2d", aspect: "1:1", name: "tank_enemy", thumbnailUrl: "" } }, { id: "t3", position: { x: 6, y: 4 }, x: 6, y: 4, z: 0, team: "enemy", health: 8, maxHealth: 8, unitType: "tank", name: "Charlie", modelUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-tanks-board/svg/flat/units/tank_enemy.svg", role: "npc", category: "tank_enemy", animations: ["idle","walk","attack","hit","death"], style: "sci-fi", dimension: "2d", aspect: "1:1", name: "tank_enemy", thumbnailUrl: "" } } ]
|
|
73
210
|
fx : [Fx] = []
|
|
74
211
|
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: "sand", passable: true }, { id: "t-4-2", x: 4, y: 2, terrain: "sand", passable: true }, { id: "t-5-2", x: 5, y: 2, terrain: "sand", 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: "sand", passable: true }, { id: "t-3-3", x: 3, y: 3, terrain: "sand", passable: true }, { id: "t-4-3", x: 4, y: 3, terrain: "sand", passable: true }, { id: "t-5-3", x: 5, y: 3, terrain: "sand", 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: "sand", passable: true }, { id: "t-4-4", x: 4, y: 4, terrain: "sand", 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 } ]
|
|
75
212
|
result : string = "none"
|
|
76
213
|
selectedUnitId : string = ""
|
|
77
214
|
validMoves : [ValidMove] = []
|
|
78
215
|
attackTargets : [ValidMove] = []
|
|
216
|
+
movedIds : [string] = []
|
|
217
|
+
actedIds : [string] = []
|
|
79
218
|
uiPhase : string = "observation"
|
|
80
219
|
turn : number = 0
|
|
81
220
|
score : number = 0
|
|
@@ -88,7 +227,7 @@ orbital TanksBoardOrbital {
|
|
|
88
227
|
gridWidth: 8
|
|
89
228
|
gridHeight: 6
|
|
90
229
|
attackDamage: 3
|
|
91
|
-
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-tanks-board/
|
|
230
|
+
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-tanks-board/svg/flat/units/tank.svg", role: "npc", category: "tank", animations: ["idle","walk","attack","hit","death"], style: "sci-fi", dimension: "2d", aspect: "1:1", name: "tank", 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-tanks-board/svg/flat/units/tank_enemy.svg", role: "npc", category: "tank_enemy", animations: ["idle","walk","attack","hit","death"], style: "sci-fi", dimension: "2d", aspect: "1:1", name: "tank_enemy", thumbnailUrl: "" } }, { id: "t3", position: { x: 6, y: 4 }, x: 6, y: 4, z: 0, team: "enemy", health: 8, maxHealth: 8, unitType: "tank", name: "Charlie", modelUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-tanks-board/svg/flat/units/tank_enemy.svg", role: "npc", category: "tank_enemy", animations: ["idle","walk","attack","hit","death"], style: "sci-fi", dimension: "2d", aspect: "1:1", name: "tank_enemy", thumbnailUrl: "" } } ]
|
|
92
231
|
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: "sand", passable: true }, { id: "t-4-2", x: 4, y: 2, terrain: "sand", passable: true }, { id: "t-5-2", x: 5, y: 2, terrain: "sand", 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: "sand", passable: true }, { id: "t-3-3", x: 3, y: 3, terrain: "sand", passable: true }, { id: "t-4-3", x: 4, y: 3, terrain: "sand", passable: true }, { id: "t-5-3", x: 5, y: 3, terrain: "sand", 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: "sand", passable: true }, { id: "t-4-4", x: 4, y: 4, terrain: "sand", 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 } ]
|
|
93
232
|
}
|
|
94
233
|
}
|
|
@@ -105,20 +244,25 @@ orbital TanksBoardOrbital {
|
|
|
105
244
|
config { running: true, pointsPerKill: 10, startScore: 0, initialEnemies: 2 }
|
|
106
245
|
}
|
|
107
246
|
|
|
247
|
+
trait AnimClock = Frame.traits.AnimClock -> GameState {
|
|
248
|
+
config { frames: [] }
|
|
249
|
+
}
|
|
250
|
+
|
|
108
251
|
trait Player = Frame.traits.PlayerIntent -> GameState {
|
|
109
252
|
config {
|
|
110
253
|
gridWidth: 8
|
|
111
254
|
gridHeight: 6
|
|
112
255
|
movementRange: 2
|
|
256
|
+
attackRange: 2
|
|
113
257
|
projection: "flat"
|
|
114
258
|
showMinimap: false
|
|
115
259
|
scale: 0.45
|
|
116
|
-
backgroundAsset: { url: "https://almadar-kflow-assets.web.app/shared/
|
|
117
|
-
hudBackgroundAsset: { url: "https://almadar-kflow-assets.web.app/shared/
|
|
118
|
-
features: [ { id: "f1", x: 2, y: 1, type: "obstacle", assetUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-tanks-board/
|
|
119
|
-
assetManifest: { terrains: { ground: { url: "https://almadar-kflow-assets.web.app/shared/ui-tanks-board/
|
|
260
|
+
backgroundAsset: { url: "https://almadar-kflow-assets.web.app/shared/ui-tanks-board/svg/flat/ui/panel-frame.svg", role: "ui", category: "ui", animations: [], style: "sci-fi", dimension: "2d", aspect: "1:1", name: "panel-frame", thumbnailUrl: "" }
|
|
261
|
+
hudBackgroundAsset: { url: "https://almadar-kflow-assets.web.app/shared/ui-tanks-board/svg/flat/ui/panel-frame.svg", role: "ui", category: "ui", animations: [], style: "sci-fi", dimension: "2d", aspect: "1:1", name: "panel-frame", thumbnailUrl: "" }
|
|
262
|
+
features: [ { id: "f1", x: 2, y: 1, type: "obstacle", assetUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-tanks-board/svg/flat/features/obstacle.svg", role: "decoration", category: "obstacle", animations: ["static"], style: "sci-fi", 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-tanks-board/svg/flat/features/obstacle.svg", role: "decoration", category: "obstacle", animations: ["static"], style: "sci-fi", 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-tanks-board/svg/flat/features/obstacle.svg", role: "decoration", category: "obstacle", animations: ["static"], style: "sci-fi", dimension: "2d", aspect: "1:1", name: "obstacle", thumbnailUrl: "" } }, { id: "f4", x: 5, y: 3, type: "obstacle", assetUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-tanks-board/svg/flat/features/obstacle.svg", role: "decoration", category: "obstacle", animations: ["static"], style: "sci-fi", dimension: "2d", aspect: "1:1", name: "obstacle", thumbnailUrl: "" } }, { id: "f5", x: 5, y: 4, type: "obstacle", assetUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-tanks-board/svg/flat/features/obstacle.svg", role: "decoration", category: "obstacle", animations: ["static"], style: "sci-fi", dimension: "2d", aspect: "1:1", name: "obstacle", thumbnailUrl: "" } }, { id: "f6", x: 2, y: 4, type: "obstacle", assetUrl: { url: "https://almadar-kflow-assets.web.app/shared/ui-tanks-board/svg/flat/features/obstacle.svg", role: "decoration", category: "obstacle", animations: ["static"], style: "sci-fi", dimension: "2d", aspect: "1:1", name: "obstacle", thumbnailUrl: "" } } ]
|
|
263
|
+
assetManifest: { terrains: { ground: { url: "https://almadar-kflow-assets.web.app/shared/ui-tanks-board/svg/flat/terrain/ground.svg", role: "tile", category: "ground", animations: ["static"], style: "sci-fi", dimension: "2d", aspect: "1:1", name: "ground", thumbnailUrl: "" }, sand: { url: "https://almadar-kflow-assets.web.app/shared/ui-tanks-board/svg/flat/terrain/sand.svg", role: "tile", category: "sand", animations: ["static"], style: "sci-fi", dimension: "2d", aspect: "1:1", name: "sand", thumbnailUrl: "" } }, units: { tank: { url: "https://almadar-kflow-assets.web.app/shared/ui-tanks-board/svg/flat/units/tank.svg", role: "npc", category: "tank", animations: ["idle","walk","attack","hit","death"], style: "sci-fi", dimension: "2d", aspect: "1:1", name: "tank", thumbnailUrl: "" }, tank_enemy: { url: "https://almadar-kflow-assets.web.app/shared/ui-tanks-board/svg/flat/units/tank_enemy.svg", role: "npc", category: "tank_enemy", animations: ["idle","walk","attack","hit","death"], style: "sci-fi", dimension: "2d", aspect: "1:1", name: "tank_enemy", thumbnailUrl: "" } }, features: { obstacle: { url: "https://almadar-kflow-assets.web.app/shared/ui-tanks-board/svg/flat/features/obstacle.svg", role: "decoration", category: "obstacle", animations: ["static"], style: "sci-fi", dimension: "2d", aspect: "1:1", name: "obstacle", thumbnailUrl: "" } }, effects: { hit: { url: "https://almadar-kflow-assets.web.app/shared/ui-tanks-board/svg/flat/effects/hit.svg", role: "effect", category: "hit", animations: ["static"], style: "sci-fi", dimension: "2d", aspect: "1:1", name: "hit", thumbnailUrl: "" }, explosion: { url: "https://almadar-kflow-assets.web.app/shared/ui-tanks-board/svg/flat/effects/explosion.svg", role: "effect", category: "explosion", animations: ["static"], style: "sci-fi", dimension: "2d", aspect: "1:1", name: "explosion", thumbnailUrl: "" } } }
|
|
120
264
|
}
|
|
121
265
|
}
|
|
122
266
|
|
|
123
|
-
page "/tanks-board" as TanksBoardPage -> Authority, FxDecay, RoundLogic, ScoreKeeper, Player
|
|
267
|
+
page "/tanks-board" as TanksBoardPage -> Authority, FxDecay, RoundLogic, ScoreKeeper, Player, AnimClock
|
|
124
268
|
}
|