blockyard 0.1.0 → 0.1.1
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/CHANGELOG.md +108 -0
- package/README.md +13 -11
- package/SECURITY.md +2 -2
- package/docs/API.md +1 -1
- package/docs/ARCHITECTURE.md +36 -5
- package/docs/CONFIGURATION.md +6 -4
- package/docs/DEFECTS.md +4 -1
- package/docs/GETTING-STARTED.md +14 -7
- package/docs/INSTALL.md +7 -4
- package/docs/PLAN-SCORCHED-YARD.md +456 -0
- package/docs/PLAN-SKIES.md +142 -0
- package/docs/SECURITY-AUDIT-2026-09-16.md +647 -0
- package/docs/SECURITY.md +26 -7
- package/docs/TROUBLESHOOTING.md +10 -5
- package/docs/USER-GUIDE.md +239 -9
- package/package.json +4 -2
- package/public/css/app.css +87 -0
- package/public/index.html +58 -6
- package/public/js/app.js +60 -19
- package/public/js/blockanoid.js +15 -7
- package/public/js/blockout.js +15 -7
- package/public/js/blockscene3d.js +51 -11
- package/public/js/depthchart.js +1 -1
- package/public/js/details3d.js +25 -2
- package/public/js/explorer.js +7 -1
- package/public/js/livingsky.js +494 -0
- package/public/js/login.js +3 -2
- package/public/js/mining.js +4 -4
- package/public/js/panels.js +27 -18
- package/public/js/safenext.js +14 -0
- package/public/js/scorched.js +1051 -0
- package/public/js/scorchedai.js +227 -0
- package/public/js/scorchedair.js +286 -0
- package/public/js/scorchedfx.js +376 -0
- package/public/js/scorchedshop.js +105 -0
- package/public/js/scorchedwind.js +69 -0
- package/public/js/scorchedyard.js +1338 -0
- package/public/js/settings.js +266 -80
- package/public/js/tetrust.js +15 -6
- package/public/js/tetsound.js +35 -5
- package/scripts/check.js +46 -0
- package/scripts/index-build.js +9 -2
- package/scripts/pool-map.js +152 -36
- package/scripts/setup.js +108 -10
- package/scripts/shots.mjs +21 -0
- package/scripts/smoke.sh +6 -5
- package/scripts/ui.js +4 -2
- package/server/auth/sessions.js +33 -13
- package/server/chain/blockfile.js +64 -5
- package/server/chain/index/build.js +432 -56
- package/server/chain/index/heights.js +29 -3
- package/server/chain/index/live.js +13 -7
- package/server/chain/index/rows.js +6 -1
- package/server/chain/index/store.js +28 -5
- package/server/chain/index/worker.js +23 -11
- package/server/collect/logparse.js +65 -18
- package/server/collect/markets.js +76 -7
- package/server/collect/mining.js +32 -0
- package/server/collect/monitor.js +24 -11
- package/server/collect/network.js +19 -9
- package/server/config.js +7 -0
- package/server/http/api.js +70 -13
- package/server/http/server.js +22 -5
- package/server/http/sse.js +53 -7
- package/server/main.js +13 -3
- package/server/rpc/allowlist.js +26 -0
- package/server/rpc/client.js +30 -2
- package/server/store/audit.js +6 -1
- package/server/store/history.js +19 -3
- package/server/store/ledger.js +15 -4
- package/systemd/blockyard.service +34 -3
|
@@ -0,0 +1,456 @@
|
|
|
1
|
+
# Scorched Yard — a plan for a Scorched Earth Diversion
|
|
2
|
+
|
|
3
|
+
*Scoped 2026-09-16, before any code. Operator: "Scope out a plan for re-creating the classic PC
|
|
4
|
+
DOS game Scorched Earth using our engine. I suggest using blocks to generate the deformable
|
|
5
|
+
landscape unless you have a better idea. Make it at least 3 player. 1 Human Player and 2 AI
|
|
6
|
+
Players. Try to reproduce it as faithfully as possible, but make it look fabulous as an
|
|
7
|
+
additional new diversion."*
|
|
8
|
+
|
|
9
|
+
The working name is **Scorched Yard** (Tetrust, Blockout, Blockanoid, Scorched Yard). The name,
|
|
10
|
+
like every "decision" flagged below, is the operator's to change.
|
|
11
|
+
|
|
12
|
+
## 1. What Scorched Earth is, and what "faithful" means here
|
|
13
|
+
|
|
14
|
+
Scorched Earth (Wendell Hicken, 1991) is a turn-based artillery game: two to ten tanks sit on a
|
|
15
|
+
randomly generated side-view landscape; each turn a player sets a **barrel angle** (0–180°) and a
|
|
16
|
+
**power** (0–1000), picks a **weapon**, and fires. Shells fly under **gravity** and **wind**,
|
|
17
|
+
carve **craters** out of the ground where they land, and the dirt above a crater **falls** to fill
|
|
18
|
+
it. Tanks take damage from blasts, fall when the ground goes from under them (and take damage
|
|
19
|
+
for the fall unless they have a parachute), and die in a blast of their own. Between rounds
|
|
20
|
+
every player spends the **cash** they earned on weapons and defensive items in a **shop**. The
|
|
21
|
+
game is a fixed number of rounds; the winner is the highest score.
|
|
22
|
+
|
|
23
|
+
What makes it *Scorched Earth* rather than any artillery game, and what this plan reproduces:
|
|
24
|
+
|
|
25
|
+
- the deformable dirt that falls and settles, so every crater reshapes the fight;
|
|
26
|
+
- wind that changes between turns (or every shot, as a setting), and the four **wall** modes:
|
|
27
|
+
concrete (shells explode on the edge), rubber (they bounce), wraparound, and none;
|
|
28
|
+
- the weapon roster with its personalities — Baby Missile to Death's Head, Funky Bomb, MIRV,
|
|
29
|
+
Leapfrog, Rollers that run downhill, Napalm that flows and burns, Diggers and Sandhogs that
|
|
30
|
+
tunnel, Riot charges that clear dirt without hurting, Dirt Clods and a Ton of Dirt that add
|
|
31
|
+
it, Tracers that show the wind, the Laser;
|
|
32
|
+
- the items — Shields (plain, deflector, force), Parachutes, Batteries, Mag Deflector, Auto
|
|
33
|
+
Defense, Fuel (tanks can drive), Contact Triggers, Heat Guidance;
|
|
34
|
+
- the AI personalities by name — Moron, Shooter, Poolshark, Tosser, Chooser, Spoiler, Cyborg,
|
|
35
|
+
Unknown — with their distinct habits;
|
|
36
|
+
- cash for kills, interest between rounds, the shop with weapons sold in packs;
|
|
37
|
+
- and the small things people remember: tanks that talk ("Nuke 'em"), the death explosion,
|
|
38
|
+
the trace of the last shot, the sky that changes each round.
|
|
39
|
+
|
|
40
|
+
What it will not reproduce: the VGA look. The original is 640×350 pixels of flat colour; this
|
|
41
|
+
one is built from the engine's cubes on the oblique camera, with the effects library for the
|
|
42
|
+
blasts and the star field or a day sky behind it. Faithful in the mechanics, fabulous in the
|
|
43
|
+
look.
|
|
44
|
+
|
|
45
|
+
## 2. The landscape: blocks, as suggested — and how
|
|
46
|
+
|
|
47
|
+
The operator's suggestion is the right one, with one refinement. The playfield is a grid of
|
|
48
|
+
`W × H` cells (proposed **80 × 40**, an aspect of 2:1 like the original's 640×350 minus its
|
|
49
|
+
status bar); the ground is a **bitmap of dirt cells** over that grid, not merely a height per
|
|
50
|
+
column, so that tunnels, overhangs and caves exist (Diggers and Sandhogs need them, and so does
|
|
51
|
+
the moment when a Nuke leaves an arch of dirt that then collapses). Each column also keeps its
|
|
52
|
+
top for the fast questions (where does a shell land, where does a tank sit).
|
|
53
|
+
|
|
54
|
+
*(M1 found otherwise: under the oblique camera a tile's height climbs 0.3 of a row per unit, so a
|
|
55
|
+
tall run does not stack against the run above it -- the strata drew as floating ribbons. The land
|
|
56
|
+
is a cube per cell after all, on its own canvas redrawn only when the dirt changes, with the
|
|
57
|
+
actors on a transparent canvas over it; the tile budget below is therefore per change, not per
|
|
58
|
+
frame, and the measured build for 1,600 cubes is well under a frame.)*
|
|
59
|
+
|
|
60
|
+
The plan as first written: the engine draws it as **one tile per vertical run of dirt**, not one cube per cell:
|
|
61
|
+
`{ txid: 't<x>:<base>', x, y: base, s: 1, tall: runLength, color }`. A column with no holes is
|
|
62
|
+
one tile; a column with a tunnel is two or three. That keeps the tile count at a few hundred
|
|
63
|
+
(the block-space board draws a thousand at full resolution without trouble) while every cell
|
|
64
|
+
stays individually removable. Colour comes from **strata**: a grass or snow cap, soil, clay,
|
|
65
|
+
rock, and a magma glow at the very bottom, with a per-column hash nudging each shade so the
|
|
66
|
+
face is not flat colour. A run that crosses a stratum boundary is split so each piece keeps
|
|
67
|
+
its stratum's colour. `cellTops` in the engine already reads a heightmap off a tile set; the
|
|
68
|
+
game keeps its own to avoid the round trip.
|
|
69
|
+
|
|
70
|
+
**Generation** follows the original's landscape styles as a setting: rolling hills (a sum of
|
|
71
|
+
low-frequency sines with seeded phases), mountains (higher amplitude, a ridge), a valley, a
|
|
72
|
+
plateau, flat, and random. Tanks are placed on the surface at spaced columns, the surface under
|
|
73
|
+
each tank flattened for two cells, as the original does. Everything is drawn from a seeded RNG
|
|
74
|
+
(`agents.rng`) so a round is reproducible in tests.
|
|
75
|
+
|
|
76
|
+
**Craters.** A blast of radius `r` at `(cx, cy)` clears every dirt cell inside the circle. Dirt
|
|
77
|
+
weapons add cells the same way. Diggers clear along the shell's path. Napalm converts cells at
|
|
78
|
+
the surface it flows over.
|
|
79
|
+
|
|
80
|
+
**Settling.** After any change, every column is scanned: a run of dirt above a hole falls until
|
|
81
|
+
it rests on the run below it. The rules commit the new bitmap at once; the screen animates the
|
|
82
|
+
fall with the engine's own `fallMs`/`bounceDrop` timing by handing the falling runs to the
|
|
83
|
+
board with a `floor` offset that decays to zero (the same mechanism as Tetrust's cleared-line
|
|
84
|
+
drift, in reverse). Tanks standing on a falling run fall with it and take the original's fall
|
|
85
|
+
damage unless a parachute is fitted (which then is consumed).
|
|
86
|
+
|
|
87
|
+
## 3. Physics, shells, and walls
|
|
88
|
+
|
|
89
|
+
All motion is in the plane of the playfield, in grid units, integrated with substeps the way
|
|
90
|
+
Blockout does (`MAX_STEP` per substep, so a full-power shot never tunnels through a two-cell
|
|
91
|
+
ridge; a test holds this at coarse frame times). The shell is a tile: `{ txid: 'shell', x, y,
|
|
92
|
+
s: 0.4, sphere: true }` with a lit trail drawn over it (`chargeTrail`/`bloom`). Its state is
|
|
93
|
+
`{ x, y, vx, vy }`; each substep applies gravity `g` (a setting, the original's 1.0 = Earth) and
|
|
94
|
+
wind `w` (a per-turn value; "wind changes every shot" is a setting, as is "no wind"); a
|
|
95
|
+
viscosity setting damps velocity as the original's "air viscosity" does.
|
|
96
|
+
|
|
97
|
+
Collision each substep: with dirt (the cell at `floor(x), floor(y)` is dirt), with a tank's
|
|
98
|
+
hitbox (2 wide × 1.4 tall), with the floor (`y ≤ 0`), and with the walls by mode:
|
|
99
|
+
|
|
100
|
+
- **concrete**: the shell explodes at the wall;
|
|
101
|
+
- **rubber**: `vx = -vx × 0.8` and it carries on;
|
|
102
|
+
- **wraparound**: `x` wraps to the other side;
|
|
103
|
+
- **none**: the shell is lost off the side (the original's "no walls").
|
|
104
|
+
|
|
105
|
+
The ceiling is open: a shell can leave the top of the screen and come back down; while it is
|
|
106
|
+
above the field the side panel shows a marker at its `x` and its height.
|
|
107
|
+
|
|
108
|
+
Every weapon is a shell with a **behaviour**: what it does on impact, at its apex, on every
|
|
109
|
+
bounce, or every substep. That table is the whole roster (§4); the physics is shared.
|
|
110
|
+
|
|
111
|
+
## 4. The roster
|
|
112
|
+
|
|
113
|
+
*Checked against the manual on 2026-09-16* (SCORCH.DOC, the copy at abandonwaredos.com). The
|
|
114
|
+
manual's tables are the ones below; `public/js/scorchedshop.js` carries them as data, with each
|
|
115
|
+
blast radius (pixels on the original's 640-wide screen) divided by 6.67 for a 96-cell field.
|
|
116
|
+
Damage is ours: the manual does not number it. The manual's own defaults: **$0 to start, 5%
|
|
117
|
+
interest, walls NONE, computers buy ON**; ours starts with $10,000 so the first shop has a use
|
|
118
|
+
(a setting, down to 0).
|
|
119
|
+
|
|
120
|
+
**Weapons** (cost · bundle · radius px · arms level): Baby Missile $400·10·10·0 (unlimited: you
|
|
121
|
+
always have 99) · Missile $1,875·5·20·0 · Baby Nuke $10,000·3·40·0 · Nuke $12,000·1·75·1 · Leap
|
|
122
|
+
Frog $10,000·2·20/25/30·3 · Funky Bomb $7,000·2·80·4 · MIRV $10,000·3·20·2 · Death's Head
|
|
123
|
+
$20,000·1·35 ×9 warheads·4 · Napalm $10,000·10·2 · Hot Napalm $20,000·2·4 · Tracer $10·20·0 ·
|
|
124
|
+
Smoke Tracer $500·10·1 · Baby Roller $5,000·10·10·2 · Roller $6,000·5·20·2 · Heavy Roller
|
|
125
|
+
$6,750·2·45·3 · Riot Charge $2,000·10·36 (a wedge from the turret)·2 · Riot Blast $5,000·5·60
|
|
126
|
+
(wider wedge)·3 · Riot Bomb $5,000·5·30·3 · Heavy Riot Bomb $4,750·2·45·3 · Baby Digger
|
|
127
|
+
$3,000·10·0 · Digger $2,500·5·0 · Heavy Digger $6,750·2·1 · Baby Sandhog $10,000·10·0 · Sandhog
|
|
128
|
+
$16,750·5·0 · Heavy Sandhog $25,000·2·1 · Dirt Clod $5,000·10·20·0 · Dirt Ball $5,000·5·35·0 ·
|
|
129
|
+
Ton of Dirt $6,750·2·70·1 · Liquid Dirt $5,000·10·2 · Dirt Charge $5,000·5 (a wedge of dirt)·1 ·
|
|
130
|
+
Earth Disrupter $5,000·10·0 · Plasma Blast $9,000·5·10–75·3 · Laser $5,000·5·2.
|
|
131
|
+
|
|
132
|
+
**Accessories**: Heat Guidance $10,000·6 · Ballistic Guidance $10,000·2 · Horz Guidance
|
|
133
|
+
$15,000·5 · Vert Guidance $20,000·5 · Lazy Boy $20,000·2 · Parachute $10,000·8 · Battery
|
|
134
|
+
$5,000·10 · Mag Deflector $10,000·2 · Shield $20,000·3 · Force Shield $25,000·3 · Heavy Shield
|
|
135
|
+
$30,000·2 · Super Mag $40,000·2 · Auto Defense $1,500·1 · Fuel Tank $10,000·10 · Contact
|
|
136
|
+
Trigger $1,000·25. (The guidance systems and Lazy Boy are v2.) Shield strengths are not
|
|
137
|
+
numbered in the manual; ours are 60 / 100 / 150.
|
|
138
|
+
|
|
139
|
+
**The computer players, in the manual's words** (for M3): Moron — "pick an angle and power, and
|
|
140
|
+
shoot"; Shooter — "significantly deadlier … only if they have a straight line of fire";
|
|
141
|
+
Poolshark — "act like Shooters unless … rebounding walls. Then they try to rebound shots";
|
|
142
|
+
Tosser — "start out like Morons, but they'll refine their aim … until they hit"; Chooser —
|
|
143
|
+
"have all the above methods available … decide which one will be most effective"; Spoiler —
|
|
144
|
+
"taking into account the wind factor and gravity, they will get a perfect shot almost every
|
|
145
|
+
time"; Cyborg — "use methods similar to the Spoilers, but are much nastier … attack tanks who
|
|
146
|
+
are weakened, winning, or have attacked them"; Unknown — "one of the above will be chosen
|
|
147
|
+
randomly … you will not be notified". Walls in the original: CONCRETE, PADDED, RUBBER, SPRING,
|
|
148
|
+
WRAP, RANDOM, ERRATIC, NONE.
|
|
149
|
+
|
|
150
|
+
The table as first planned, superseded by the above:
|
|
151
|
+
|
|
152
|
+
### Weapons (v1 — the first playable set)
|
|
153
|
+
|
|
154
|
+
| weapon | behaviour | crater r | blast damage |
|
|
155
|
+
|---|---|---|---|
|
|
156
|
+
| Baby Missile | explodes on impact | 1.5 | small |
|
|
157
|
+
| Missile | explodes on impact | 2.5 | moderate |
|
|
158
|
+
| Baby Nuke | explodes on impact | 4 | heavy |
|
|
159
|
+
| Nuke | explodes on impact | 6.5 | very heavy |
|
|
160
|
+
| Death's Head | explodes on impact | 9 | most of the field |
|
|
161
|
+
| Funky Bomb | bursts into 6 bomblets that scatter and explode | 2 each | moderate each |
|
|
162
|
+
| MIRV | splits at apex into 5 shells fanning out | 2.5 each | moderate each |
|
|
163
|
+
| Leapfrog | explodes, then bounces on twice more, exploding each time | 2.5 ×3 | moderate ×3 |
|
|
164
|
+
| Tracer | no crater, no damage; leaves its arc drawn until the next shot | 0 | 0 |
|
|
165
|
+
| Smoke Tracer | as Tracer, with a smoke trail that drifts on the wind | 0 | 0 |
|
|
166
|
+
| Roller | on landing rolls downhill until it meets a tank or the bottom of a dip, then explodes | 2.5 | moderate |
|
|
167
|
+
| Heavy Roller | as Roller, bigger | 4 | heavy |
|
|
168
|
+
| Riot Charge / Riot Blast / Riot Bomb | clears dirt in a small / medium / large radius, no damage to tanks | 3 / 5 / 7 | 0 |
|
|
169
|
+
| Dirt Clod / Dirt Ball / Ton of Dirt | adds a ball of dirt on impact | +2 / +4 / +7 | 0 |
|
|
170
|
+
| Napalm / Hot Napalm | on impact becomes liquid that flows downhill and burns what it touches over several turns' worth of frames | surface | burn per contact |
|
|
171
|
+
| Sandhog / Heavy Sandhog | on impact tunnels on along its heading through dirt, exploding at the end | 1 along the bore, 3 at the end | moderate at the end |
|
|
172
|
+
| Baby Digger / Digger / Heavy Digger | on impact digs straight down, exploding at the end | 1 / 1.5 / 2 along the bore | small at the end |
|
|
173
|
+
| Laser | instant straight line from the barrel; burns dirt and tanks along it | 0.6 along the line | moderate, by exposure |
|
|
174
|
+
|
|
175
|
+
### Items (v1)
|
|
176
|
+
|
|
177
|
+
| item | what it does |
|
|
178
|
+
|---|---|
|
|
179
|
+
| Shield | absorbs damage until spent (a coloured halo on the tank; the halo dims as it goes) |
|
|
180
|
+
| Deflector Shield | as Shield, and shells that hit it bounce off |
|
|
181
|
+
| Force Shield | a stronger Shield |
|
|
182
|
+
| Parachute | opens when the tank falls, cancelling fall damage; one per fall |
|
|
183
|
+
| Battery | restores health, used from the item slot on your turn |
|
|
184
|
+
| Mag Deflector | shells passing near the tank are pushed away (a field, not a wall) |
|
|
185
|
+
| Auto Defense | on the turn a shield would help, it is raised automatically |
|
|
186
|
+
| Fuel Tank | lets the tank drive left or right along the surface, one cell per unit of fuel |
|
|
187
|
+
| Contact Trigger | the shell explodes on the first thing it touches, including a shield or a tank's hull, rather than only on dirt |
|
|
188
|
+
| Heat Guidance | the shell bends toward the nearest tank in its last part of flight |
|
|
189
|
+
|
|
190
|
+
### v2 (after the first playable build)
|
|
191
|
+
|
|
192
|
+
Plasma Blast, Earth Disrupter, Liquid Dirt, Lazy Boy (a guided shell the player steers), the
|
|
193
|
+
"suicide" options, and the talk table's full set of taunts.
|
|
194
|
+
|
|
195
|
+
## 5. Turns, rounds, and the economy
|
|
196
|
+
|
|
197
|
+
- A **game** is `rounds` rounds (setting; default 5). Each round: generate a landscape (new
|
|
198
|
+
seed), place every living-and-dead tank afresh with full health (100), wind for the round.
|
|
199
|
+
- A **turn**: the current tank's player sets angle, power and weapon (or drives, or uses an
|
|
200
|
+
item), then fires. The shell plays out, craters carve, dirt settles, tanks fall, damage is
|
|
201
|
+
applied, deaths explode. Then the next living tank in order. Turn order rotates each round.
|
|
202
|
+
- **Death**: health ≤ 0. The tank explodes with the force of a random weapon from its own
|
|
203
|
+
inventory (the original's habit; a setting to turn it off), which can chain. The killer is
|
|
204
|
+
credited: cash per point of damage dealt, and a kill bonus; a tank that kills itself pays.
|
|
205
|
+
- **Round end**: one or zero tanks alive. Survivors score; interest is paid on cash (setting,
|
|
206
|
+
default 5%); the **shop** opens for every human player (AI players buy by their personality's
|
|
207
|
+
taste: Chooser buys wisely, Moron buys Baby Missiles). The shop lists every weapon and item
|
|
208
|
+
with its price and pack size and the count owned, and shows cash.
|
|
209
|
+
- **Game end**: the highest score; the scoreboard shows kills, damage dealt, cash left, and the
|
|
210
|
+
weapon that did the most damage. High scores in `localStorage` as the other games keep them.
|
|
211
|
+
|
|
212
|
+
## 6. The three players, and the AI
|
|
213
|
+
|
|
214
|
+
At least three players: the human plus two AI, default. The setting allows two to six, any
|
|
215
|
+
mix of human and AI, each with a name and a colour (the original's tank colours), and the
|
|
216
|
+
personality per AI player. All-AI is allowed: it is the demo the original shipped with, and it
|
|
217
|
+
runs on the Kiosk as an attract mode if the operator wants it there.
|
|
218
|
+
|
|
219
|
+
**Personalities**, each a strategy in `scorchedai.js`:
|
|
220
|
+
|
|
221
|
+
- **Moron**: random angle and power, cheapest weapon.
|
|
222
|
+
- **Shooter**: aims at the nearest tank with a rough ballistic guess, then **corrects from the
|
|
223
|
+
last shot's miss** (bisects power, then angle); picks a bigger weapon when close.
|
|
224
|
+
- **Tosser**: high lobs (angles 60–85°) with the Shooter's correction; likes Funky Bombs and
|
|
225
|
+
MIRVs, which suit lobs.
|
|
226
|
+
- **Poolshark**: only exists under rubber walls; aims bank shots off a wall, correcting the
|
|
227
|
+
same way.
|
|
228
|
+
- **Chooser**: the Shooter's aim with a weapon chosen by the distance and the target's health
|
|
229
|
+
(a Nuke on a close, healthy target; a Baby Missile to finish one off); spends its cash well.
|
|
230
|
+
- **Spoiler**: the Chooser's aim aimed at the current **leader**, not the nearest.
|
|
231
|
+
- **Cyborg**: solves the shot outright — angle and power from the target's position, gravity
|
|
232
|
+
and wind, by a short numeric search that integrates the same physics the shell uses — with a
|
|
233
|
+
small error that shrinks each round; the hardest opponent.
|
|
234
|
+
- **Unknown**: one of the above, drawn at the start of each round.
|
|
235
|
+
|
|
236
|
+
A test holds each one to its habit: the Cyborg hits a stationary tank on flat ground within
|
|
237
|
+
two shots; the Shooter's misses shrink monotonically; the Moron's do not.
|
|
238
|
+
|
|
239
|
+
The AI shares nothing with the screen: it takes the rules' state and returns
|
|
240
|
+
`{ angle, power, weapon }` (or `{ drive }` / `{ item }`), so it is testable headless and could
|
|
241
|
+
one day be an effect (the missile agent already flies arcs across the block-space board).
|
|
242
|
+
|
|
243
|
+
## 7. The look: fabulous, on this engine
|
|
244
|
+
|
|
245
|
+
- **The field** on the oblique camera (`oblique: { ox: 0.10, oy: 0.30 }`, `dome: 0`, `light:
|
|
246
|
+
'overhead'`), the strata colours above, a faint neon grid off by default (the court games'
|
|
247
|
+
quiet grid as an option), the space floor.
|
|
248
|
+
- **The sky** as its own canvas behind a transparent board, exactly as Tetrust does: the star
|
|
249
|
+
field with the galaxy by default; **day skies** as an option — dawn, noon, dusk, storm —
|
|
250
|
+
built from `softStops` fills (a sun disc with a halo, a band of colour at the horizon), and a
|
|
251
|
+
seeded pick per round so the sky changes as the original's did. Weather that the original
|
|
252
|
+
only hinted at can be real here: rain streaks under the storm sky, snow on the caps.
|
|
253
|
+
- **Tanks**: a two-cube hull in the player's colour with a sheen, a turret cube, and a barrel
|
|
254
|
+
as a `poly`+`rot` tile that turns with the angle; a floating name and health bar over it;
|
|
255
|
+
the shield as a translucent halo ring (`ring`, `bloom`); the parachute as a `poly` canopy
|
|
256
|
+
while falling.
|
|
257
|
+
- **Shells**: a `sphere` tile with a hot trail; MIRV's split as a spark burst; the Roller as a
|
|
258
|
+
spinning `poly`; napalm as lit, flickering surface cells that dim as they burn out; the
|
|
259
|
+
Laser with `drawSaberLine`'s glow and core.
|
|
260
|
+
- **Blasts**, by size: a white flash and a shockwave ring for small shells; the supernova's
|
|
261
|
+
treatment for nukes — flash, `gasCloud` smoke that rises and drifts on the wind,
|
|
262
|
+
`lensFlare`, a shockwave that lights the cubes it crosses (through the same per-tile
|
|
263
|
+
lighting the effects use, `heads` with a colour and a radius) and shakes the tanks it
|
|
264
|
+
reaches; Death's Head whites the sky out for a moment.
|
|
265
|
+
- **Dirt** falls with the engine's gravity and lands with its bounce; dust puffs where it
|
|
266
|
+
lands. A tank's death is a fireworks shell in its colour, the hull tumbling as a `poly`.
|
|
267
|
+
- **The last shot's trace** stays drawn until the next, as the original's did; Tracers keep
|
|
268
|
+
theirs for the turn.
|
|
269
|
+
- **Sound** through `tetsound.js`: a thump for the shot, a whistle that falls as the shell
|
|
270
|
+
does, a crack or a rumble for the blast by size (the synth gains a noise burst for this — a
|
|
271
|
+
short buffer of noise, still no files), a hiss for napalm, a chime for the turn, a fanfare
|
|
272
|
+
for a kill; a chiptune theme of its own with the music switch.
|
|
273
|
+
- **Talk**: a line over the tank when it fires or is hit, from the original's tables ("Nuke
|
|
274
|
+
'em", "Just wait 'til my turn", "Oops"), a setting.
|
|
275
|
+
|
|
276
|
+
None of this is on the critical path: M1 plays with plain cubes, a flash and a ring.
|
|
277
|
+
|
|
278
|
+
## 8. Controls and the side panel
|
|
279
|
+
|
|
280
|
+
Keys, following the original where it had them: **←/→** angle by 1° (Shift: 5°), **↑/↓**
|
|
281
|
+
power by 10 (Shift: 1, Ctrl: 100), **PgUp/PgDn** or **[ ]** weapon, **Tab** item, **Space** or
|
|
282
|
+
**Enter** fire, **A/D** drive (with fuel), **B** battery, **S** shield, **Esc** pause, **F**
|
|
283
|
+
fast shells (skips the flight's slow part), **N** next round from the scoreboard. Mouse: drag
|
|
284
|
+
from the tank to aim (direction is the angle, length is the power), click fire. Touch the same.
|
|
285
|
+
|
|
286
|
+
The side panel (the `.tethud` card): whose turn (name, colour), angle and power readouts, the
|
|
287
|
+
weapon with its count, cash, the wind gauge (an arrow with the value), every tank's health
|
|
288
|
+
bar, the round counter; Keys; Switches (stars, galaxy, music, sfx, fast shells, talk); High
|
|
289
|
+
scores. Between rounds the panel becomes the shop.
|
|
290
|
+
|
|
291
|
+
## 9. Files, settings, wiring, tests
|
|
292
|
+
|
|
293
|
+
**Files** (the rules/screen split every game here keeps):
|
|
294
|
+
|
|
295
|
+
- `public/js/scorched.js` — rules, zero DOM: landscape generation, the dirt bitmap and its
|
|
296
|
+
tops, craters and settling, tanks, the shell integrator with walls and wind, damage, turns,
|
|
297
|
+
rounds, cash; `newGame(opts, seed)`, `fire(g, angle, power, weapon)`, `step(g, dtMs)`,
|
|
298
|
+
`tiles(g)`; every random choice from a seeded stream.
|
|
299
|
+
- `public/js/scorchedshop.js` — the weapon and item table (behaviour, price, pack, damage,
|
|
300
|
+
radius) as data; the shop's arithmetic.
|
|
301
|
+
- `public/js/scorchedai.js` — the personalities.
|
|
302
|
+
- `public/js/scorchedyard.js` — the screen: `FIELD` and `SKY` options, the frame loop with the
|
|
303
|
+
page/hidden pause, input, the panel and the shop DOM, the effects drawn over the board, the
|
|
304
|
+
sounds, `localStorage` scores, `renderScorchedYard(s, state, h)`.
|
|
305
|
+
- `public/js/tetsound.js` — the new sound names and a noise burst.
|
|
306
|
+
|
|
307
|
+
**Settings** (`settings.js`): a `scorched` group in the Diversions row with `stars`, `galaxy`,
|
|
308
|
+
`galaxyAt`, `sky` (space / dawn / noon / dusk / storm / random), `grid`, `gridColour`,
|
|
309
|
+
`gridBrightness`, `neon` (the tanks' finish), `sfx`, `music`, `talk`, `fastShells`, and the
|
|
310
|
+
game's rules that the original exposed: `players` (2–6), `ai` (the personalities per slot),
|
|
311
|
+
`rounds`, `walls`, `gravity`, `wind` (none / steady / changes each shot), `viscosity`,
|
|
312
|
+
`landscape`, `startCash`, `interest`, `deathBlast`. `scorchedOptions(s)` merges the sky's
|
|
313
|
+
make-up as `tetrustOptions` does.
|
|
314
|
+
|
|
315
|
+
**Wiring**: the menu button and the `<section class="page" data-page="scorched">` in
|
|
316
|
+
`index.html` (the `.tetrust` layout with a `.seyard` well at `aspect-ratio: 2 / 1`), the import,
|
|
317
|
+
`case` and `DIVERSION_PAGES` entry in `app.js`, the CSS rules beside the other wells.
|
|
318
|
+
|
|
319
|
+
**Tests**, mirroring `tetris.test.js` and `breakout.test.js` (headless, seeded):
|
|
320
|
+
|
|
321
|
+
- landscape: each style generates within bounds, tanks sit on the surface, the same seed gives
|
|
322
|
+
the same field;
|
|
323
|
+
- craters and settling: a blast removes exactly the cells inside the circle; dirt above a hole
|
|
324
|
+
falls until it rests; nothing floats after settling; dirt weapons add; diggers bore;
|
|
325
|
+
- shells: a shot at 45°/500 lands where the closed form says (no wind); wind shifts it; a
|
|
326
|
+
full-power shot at a coarse frame time does not tunnel a two-cell ridge; each wall mode does
|
|
327
|
+
what it says; the ceiling is open;
|
|
328
|
+
- weapons: MIRV splits into five at the apex; Leapfrog explodes three times; the Roller rolls
|
|
329
|
+
downhill and stops in the dip; napalm flows to the low side; the Laser is a line;
|
|
330
|
+
- damage and death: blast damage by distance, fall damage, the parachute, shields absorb and
|
|
331
|
+
the deflector bounces, death explodes with an inventory weapon and credits the killer;
|
|
332
|
+
- rounds and cash: kill cash, interest, the shop refuses what you cannot afford, packs add
|
|
333
|
+
their count, scores over a game;
|
|
334
|
+
- AI: the personality tests in §6;
|
|
335
|
+
- `tiles(g)` shape and stable ids; the field refuses hover; the sky canvas is separate;
|
|
336
|
+
- the canvas rules (`viewer-canvas-rules.test.js`) extended to the new screen module if it
|
|
337
|
+
draws; `web-contract`, `nav-menu` and `settings` tests pass by construction;
|
|
338
|
+
- `npm run counts:fix` after.
|
|
339
|
+
|
|
340
|
+
**Docs**: a USER-GUIDE section (playing, the roster, the AI, the switches), CHANGELOG, AGENTS.
|
|
341
|
+
|
|
342
|
+
## 10. Milestones
|
|
343
|
+
|
|
344
|
+
Each milestone is playable at its end and lands as its own commit set, tests included.
|
|
345
|
+
|
|
346
|
+
| # | milestone | what is playable |
|
|
347
|
+
|---|---|---|
|
|
348
|
+
| M0 | this plan, signed off: name, defaults, v1 roster, sky default | — |
|
|
349
|
+
| M1 | **the core**: landscape, tanks, Baby Missile → Nuke, craters, settling, falls, damage, death, turns, one human vs two Morons, keys and mouse, plain flash and ring, the panel | a full round |
|
|
350
|
+
| M2 | **the roster**: every v1 weapon and item, the walls, wind modes, fuel, the checked price table, the shop between rounds, cash and interest, a game of N rounds, the scoreboard, high scores | the game — *landed 2026-09-16; the price table is as remembered, not yet checked against SCORCH.DOC* |
|
|
351
|
+
| M3 | **the AI**: Shooter, Tosser, Poolshark, Chooser, Spoiler, Cyborg, Unknown, AI shopping | a real opponent — *landed 2026-09-16* |
|
|
352
|
+
| M4 | **fabulous**: strata, day skies and weather, the tank models, the blast treatments, dirt dust, death fireworks, traces, sound and music, talk | the look — *landed 2026-09-16 (the Living sky serves as the day sky, with an hour per round)* |
|
|
353
|
+
| M5 | **finish**: the settings tab, Kiosk attract mode (if wanted), docs, the full test set, `counts:fix`, screenshots for the guide and the announcement | ship — *landed 2026-09-16; the attract mode is the game's own **watch** switch rather than a Kiosk panel: the Kiosk is the two boards and the chain, and a game among them would have pushed one of those off the wall* |
|
|
354
|
+
|
|
355
|
+
Rough size, from the three games that exist: M1 is the largest single step (about the size of
|
|
356
|
+
Blockanoid's first cut); M2 and M4 are each about that again; M3 and M5 are smaller.
|
|
357
|
+
|
|
358
|
+
## 11. Decisions for the operator
|
|
359
|
+
|
|
360
|
+
1. **The name.** Scorched Yard, or another.
|
|
361
|
+
2. **Field size**: 80 × 40 cells (proposed), or finer (96 × 48) for smoother hills at some
|
|
362
|
+
frame cost on a small machine.
|
|
363
|
+
3. **Default sky**: the star field with the galaxy (matches the other games), or a day sky.
|
|
364
|
+
4. **Death blast** from the inventory: on by default (faithful) or off (kinder).
|
|
365
|
+
5. **All-AI on the Kiosk**: worth having as an attract mode, or not.
|
|
366
|
+
6. **v1 roster** as listed in §4, or a shorter first cut (missiles, nukes, MIRV, Funky Bomb,
|
|
367
|
+
Roller, Napalm, Dirt Clod, Riot Bomb, Tracer, Shield, Parachute) to reach M2 sooner.
|
|
368
|
+
|
|
369
|
+
## 12. A better control system (scoped 2026-09-16; rescoped the same day; landed the same day)
|
|
370
|
+
|
|
371
|
+
*Landed: C1 (the ramp, the nudges, the wheel, typed numbers, R), then C2 (click a tank to mark it, the
|
|
372
|
+
miss on the panel, C to correct), C3 (the weapon grid on W, 1–9, Q, the item pills as buttons), C4
|
|
373
|
+
(the aim guide, short by default, beside cheat mode) and C5 (the fire button names the weapon, the
|
|
374
|
+
last of a kind asks once, the keys as a table). One change from the scope: the drag on the field
|
|
375
|
+
was kept, since it was in use, with a press on your own tank turning the barrel alone.*
|
|
376
|
+
|
|
377
|
+
The first scope proposed a catapult: press on your tank, pull back, release. The operator's answer
|
|
378
|
+
was that it sucks as a control scheme, and on inspection it does -- the drag that shipped in M1 is
|
|
379
|
+
already that gesture, and it is the weakest thing on the screen:
|
|
380
|
+
|
|
381
|
+
* **It is coarse.** The field is about 1,300 screen pixels for 1,000 units of power, and the pull
|
|
382
|
+
only uses the part of it between the tank and the pointer. Four or five units of power per pixel,
|
|
383
|
+
against the keyboard's one.
|
|
384
|
+
* **It forgets.** Every grab starts from wherever the pointer went down, so the aim you spent the
|
|
385
|
+
last turn finding is gone the moment you touch the field.
|
|
386
|
+
* **It cannot bracket.** Artillery is not aiming, it is CORRECTING: fire, watch, move the power by
|
|
387
|
+
half the miss, fire again. That is a sequence of small deltas on a remembered number, which is
|
|
388
|
+
the one thing a drag gesture is bad at.
|
|
389
|
+
|
|
390
|
+
So: the keyboard and the readouts are the control system, the pointer picks TARGETS rather than
|
|
391
|
+
setting numbers, and everything below is about making small corrections fast and exact.
|
|
392
|
+
|
|
393
|
+
### C1 — the numbers, fast and exact. The one worth doing first
|
|
394
|
+
|
|
395
|
+
* **Hold to repeat, with a ramp.** A held arrow steps 1, then 2, then 5 after half a second, so
|
|
396
|
+
crossing 180 degrees takes a second and a half and the last degree still takes one press.
|
|
397
|
+
* **Modifiers that are written down**: Shift fine (1 power, 0.5 degree), Ctrl coarse (100 power,
|
|
398
|
+
5 degrees). They exist today and nothing says so outside a paragraph of bullets.
|
|
399
|
+
* **`,` and `.` nudge the power by one**, the classic bracket, without a modifier.
|
|
400
|
+
* **The wheel over the field**: power, and with Shift the angle. The pointer is already there.
|
|
401
|
+
* **The readouts become inputs.** Click the angle or the power on the HUD and type the number; the
|
|
402
|
+
angle and power a player is reading off a previous shot go in directly.
|
|
403
|
+
* **`R` repeats the last shot exactly** -- same angle, same power, same weapon. The most missed
|
|
404
|
+
convenience in the original.
|
|
405
|
+
|
|
406
|
+
### C2 — correcting, which is what the game is actually made of
|
|
407
|
+
|
|
408
|
+
Click a tank (or press `1`..`4`) to mark it as your TARGET. The HUD then shows, under the power,
|
|
409
|
+
**where your last shot landed relative to it**: "12 short" or "5 over". One key, `C`, applies the
|
|
410
|
+
classic halving correction to the power in that direction -- the Tosser's own arithmetic, offered
|
|
411
|
+
to the human. Nothing is solved for you: the correction is from YOUR last shot, so wind changes
|
|
412
|
+
and the hills are still yours to read. Off is a setting for anyone who wants the 1991 experience.
|
|
413
|
+
|
|
414
|
+
### C3 — the weapon grid, and the items as buttons
|
|
415
|
+
|
|
416
|
+
`[` and `]` stay. Beside them:
|
|
417
|
+
|
|
418
|
+
* **a grid** dropping out of the weapon line: what you own, counts and blast radii, biggest first,
|
|
419
|
+
click to pick, `W` to open, Escape to close;
|
|
420
|
+
* **1--9 for the nine you own**, in shop order, which is how a Scorched Earth player thinks ("the
|
|
421
|
+
nukes are on 4") -- when a target is marked they still pick the target, so weapons take a
|
|
422
|
+
modifier or their own row: settled at build time, whichever reads better with C2;
|
|
423
|
+
* **`Q` for the last weapon fired**, so a ranging Baby Missile then the real thing is two keys;
|
|
424
|
+
* **the item pills become buttons**. They already name themselves and their key; they should take
|
|
425
|
+
a click too.
|
|
426
|
+
|
|
427
|
+
### C4 — the ranging arc, optional
|
|
428
|
+
|
|
429
|
+
A ghost path from the muzzle under the current angle, power, wind and gravity, drawn as dim beads
|
|
430
|
+
on the flat plane the wind uses. A setting, because it changes the game: **off** (the original),
|
|
431
|
+
**short** -- the first fifth of the flight, enough to read the lean without giving the landing
|
|
432
|
+
away -- or **full**. Default short. One truncated `simulateShot` per change of aim.
|
|
433
|
+
|
|
434
|
+
### C5 — what the panel says
|
|
435
|
+
|
|
436
|
+
The **fire button carries the weapon and its count** ("fire · Nuke ×1"), so an expensive shot is
|
|
437
|
+
visible before it goes, and it asks once before the last of a one-of-a-kind (a setting, on by
|
|
438
|
+
default: the most common regret in the original). The keys legend becomes a two-column table with
|
|
439
|
+
the modifiers written out.
|
|
440
|
+
|
|
441
|
+
### The pointer, after all this
|
|
442
|
+
|
|
443
|
+
The drag that sets angle and power goes. In its place: **a click on the field marks a target**
|
|
444
|
+
(C2), **a drag with the right button pans nothing and cancels** (there is nothing to pan), and a
|
|
445
|
+
**press on your own tank still turns the barrel** for a coarse first approximation, angle only,
|
|
446
|
+
power untouched -- which is the one part of the gesture that was worth keeping, because the angle
|
|
447
|
+
is the cheap half of the aim and the power is the half you bracket. Touch gets the same, with the
|
|
448
|
+
HUD's fire button and the pills, which are already thumb-sized.
|
|
449
|
+
|
|
450
|
+
### Order, size and risk
|
|
451
|
+
|
|
452
|
+
C1 and C2 change how the game feels and neither touches the rules: both are `scorchedyard.js`, its
|
|
453
|
+
key and pointer handlers, and `aim()` doing the committing as it does now. C3 is a menu and some
|
|
454
|
+
buttons. C4 needs a setting and a truncated `simulateShot`. C5 is copy and one confirm. Nothing
|
|
455
|
+
here needs a change in `scorched.js`, so the tests that hold the physics keep holding them; the new
|
|
456
|
+
tests are the key map, the ramp's arithmetic, and the correction C2 applies for a given miss.
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# Plan: one sky per board — Galaxy or Earth
|
|
2
|
+
|
|
3
|
+
*Landed 2026-09-16, as scoped, in one change: the schema and its idempotent migration, the Sky tab's
|
|
4
|
+
map and two headings, one Sky choice per board tab, the games' one sky button, the rename, the docs.
|
|
5
|
+
The operator's own installation came forward as every board Galaxy and Scorched Yard none (its
|
|
6
|
+
stars had been off), and was set to Earth through the new map, one click.*
|
|
7
|
+
|
|
8
|
+
Operator, 2026-09-16: "The skybox settings are not clear in the preferences, for which sky settings
|
|
9
|
+
apply to which panel. eg: I want the sky for Scorched Yard to be the Earth Sky. The Galaxy view
|
|
10
|
+
should be the default background for all other 3D backgrounds."
|
|
11
|
+
|
|
12
|
+
## 1. Why it is confusing today
|
|
13
|
+
|
|
14
|
+
The settings describe the sky twice, from two directions, and neither says which board it is
|
|
15
|
+
talking about.
|
|
16
|
+
|
|
17
|
+
* **One global choice.** Display settings → Sky → *Sky* picks Space or Living sky **for every
|
|
18
|
+
board at once**. Wanting Earth over the artillery and the galaxy behind the candles is not a
|
|
19
|
+
thing the sheet can say.
|
|
20
|
+
* **Six scattered "Star field" switches.** Block space, Markets, Tetrust, Blockout, Blockanoid and
|
|
21
|
+
Scorched Yard each carry a `stars` toggle in their own tab. It reads as "stars on or off", but
|
|
22
|
+
under the Living sky it means "draw the day or draw nothing" — which is the black-sky report
|
|
23
|
+
from earlier today.
|
|
24
|
+
* **Four private galaxy switches.** The games each carry a `galaxy` and a `galaxyAt` of their own,
|
|
25
|
+
beside the Sky tab's galaxy and galaxyAt, so the same spiral is switched in five places.
|
|
26
|
+
* **Nothing joins them up.** No page says "Block space: Space · Scorched Yard: Earth". The player
|
|
27
|
+
has to hold the mapping in their head, and the mapping is one global switch plus six local ones.
|
|
28
|
+
|
|
29
|
+
## 2. The shape it should have
|
|
30
|
+
|
|
31
|
+
**Two skies, named as things; each board picks one: Galaxy or Earth.**
|
|
32
|
+
|
|
33
|
+
(Operator, later the same day: "Space is too confusing with 'Block Space' — let's rename it
|
|
34
|
+
'Galaxy'." So the star-field sky is the **Galaxy** sky throughout, and the word "space" is not a
|
|
35
|
+
sky anywhere in the sheet. The one thing it collides with is the Galaxy sky's own *Spiral galaxy*
|
|
36
|
+
toggle, which lays the stars on arms or scatters them: that row becomes **Spiral arms**, and its
|
|
37
|
+
placement row **Arms centre**.)
|
|
38
|
+
|
|
39
|
+
* The **Sky** tab becomes a catalogue with a summary at the top:
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
WHICH SKY, WHERE
|
|
43
|
+
Block space ·········· Galaxy (also the Kiosk's left panel)
|
|
44
|
+
Markets & Price ······ Galaxy (also the Kiosk's right panel)
|
|
45
|
+
Tetrust ·············· Galaxy
|
|
46
|
+
Blockout ············· Galaxy
|
|
47
|
+
Blockanoid ··········· Galaxy
|
|
48
|
+
Scorched Yard ········ Earth
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Every row is a select: **Galaxy · Earth · None**. Changing it here is the same as changing it in
|
|
52
|
+
the board's own tab. This table is the whole answer to "which settings apply to which panel".
|
|
53
|
+
|
|
54
|
+
* Below it, **two titled sections**, each describing one sky and nothing else:
|
|
55
|
+
* **Galaxy** — the star field, its density and brightness, the spiral arms and where their
|
|
56
|
+
centre sits, nebulae, dust lanes, clusters, distant galaxies, colours, glints.
|
|
57
|
+
* **Earth** — the clock (real, a day every 24 minutes, a fixed hour), the weather, cloud cover,
|
|
58
|
+
latitude, sun rays, rainbow, shooting stars.
|
|
59
|
+
|
|
60
|
+
Neither section is ever dimmed: a sky's controls are always live, because some board may be
|
|
61
|
+
using it. The dimming added this morning goes away, since it was compensating for the global
|
|
62
|
+
switch.
|
|
63
|
+
|
|
64
|
+
* Each **board tab** carries exactly one sky control: **Sky: Galaxy / Earth / None**, first in its
|
|
65
|
+
group, with a hint that points at the Sky tab for the make-up. Its `stars`, `galaxy` and
|
|
66
|
+
`galaxyAt` rows are gone. The arms' placement stays a property of the Galaxy sky, set once.
|
|
67
|
+
|
|
68
|
+
* The games' **panel switches** follow: the `stars` and `galaxy` buttons on Tetrust, Blockout,
|
|
69
|
+
Blockanoid and Scorched Yard become one **sky** button that cycles Galaxy → Earth → None and shows
|
|
70
|
+
which it is on.
|
|
71
|
+
|
|
72
|
+
* **"Living sky" is renamed "Earth sky"** everywhere, which is what the operator calls it and is
|
|
73
|
+
shorter.
|
|
74
|
+
|
|
75
|
+
## 3. Defaults
|
|
76
|
+
|
|
77
|
+
Galaxy for every board — it is BlockYard's signature — except **Scorched Yard, which ships with
|
|
78
|
+
Earth**: an artillery duel wants a day and a horizon, and it already turns each round to its
|
|
79
|
+
own hour. Nothing else changes look by default.
|
|
80
|
+
|
|
81
|
+
## 4. What existing settings become
|
|
82
|
+
|
|
83
|
+
The stored shape today is one `sky.type` plus six `<board>.stars`. The new shape is one
|
|
84
|
+
`<board>.sky` per board, with values `galaxy | earth | none`. The mapping that preserves exactly
|
|
85
|
+
what every installation draws right now:
|
|
86
|
+
|
|
87
|
+
| stored today | becomes |
|
|
88
|
+
|---|---|
|
|
89
|
+
| `<board>.stars: false` | `<board>.sky: 'none'` |
|
|
90
|
+
| `<board>.stars: true` and `sky.type: 'space'` | `<board>.sky: 'galaxy'` |
|
|
91
|
+
| `<board>.stars: true` and `sky.type: 'living'` | `<board>.sky: 'earth'` |
|
|
92
|
+
| `<board>.galaxy`, `<board>.galaxyAt` (the games') | dropped; `sky.galaxy` / `sky.galaxyAt` stand |
|
|
93
|
+
| `sky.type` | dropped |
|
|
94
|
+
|
|
95
|
+
Because settings stored on the server carry no schema version, a migration there runs on **every
|
|
96
|
+
boot** — so this one is written to be idempotent: it acts only when the old key is present and the
|
|
97
|
+
new one is absent, and then removes the old key. A store already in the new shape is untouched.
|
|
98
|
+
(The same fact is why the wind mode was not migrated this morning; here the transform is a rename,
|
|
99
|
+
which is safe to repeat.)
|
|
100
|
+
|
|
101
|
+
The operator's own installation comes forward as: every board Galaxy except Scorched Yard, which
|
|
102
|
+
has `stars: false` under `type: 'living'` today — that would become `none`, which is not what was
|
|
103
|
+
asked for. The migration special-cases nothing; the sheet's new table makes it a one-click change,
|
|
104
|
+
and the plan's landing note will say so.
|
|
105
|
+
|
|
106
|
+
## 5. Where the code changes
|
|
107
|
+
|
|
108
|
+
* `public/js/settings.js` — DEFAULTS: `sky.type` out, `<board>.sky` in; the games' galaxy keys out.
|
|
109
|
+
PANEL_GROUPS: the Sky group rebuilt as summary + two sections (the summary is a new row kind,
|
|
110
|
+
`skymap`, that app.js renders as the table); each board group gets its `sky` choice row.
|
|
111
|
+
`skyFor(n, board)` replaces `skyExtras` + the per-board `stars` plumbing: it answers `{ stars,
|
|
112
|
+
skyType, ...earth, ...deepSky }` for a board, and the seven option builders call it. Migration
|
|
113
|
+
`MIGRATIONS[5]`, idempotent as above; `SCHEMA_VERSION` 6.
|
|
114
|
+
* `public/js/app.js` — renders the `skymap` row as the table of selects, wired to the same
|
|
115
|
+
`data-cfgset` path as any choice, so a change in either place is one change.
|
|
116
|
+
* `public/js/details3d.js` — reads `skyType === 'earth'` (accepting `'living'` for one release);
|
|
117
|
+
the star field is drawn for `'galaxy'` (and `'space'` for one release).
|
|
118
|
+
* The boards — `mining.js`, `markets.js`, `kiosk.js`, `tetrust.js`, `blockout.js`, `blockanoid.js`,
|
|
119
|
+
`scorchedyard.js`: take their sky from `skyFor`; the games' panel switch becomes the cycle
|
|
120
|
+
button; `index.html` loses the four `stars` / `galaxy` buttons and gains four `sky` buttons.
|
|
121
|
+
* Docs — USER-GUIDE's Sky section rewritten around the table; CONFIGURATION's settings keys;
|
|
122
|
+
CHANGELOG.
|
|
123
|
+
* Tests — `settings.test.js` (shape, defaults, the migration on all four stored combinations, and
|
|
124
|
+
that it is idempotent when run twice), `finish.test.js` (each option builder's `stars`/`skyType`
|
|
125
|
+
for each value), the games' page-wiring tests (the switch ids), `viewer-canvas-rules` unchanged.
|
|
126
|
+
A test also holds the sheet to never labelling a sky "Space": the word belongs to Block space.
|
|
127
|
+
|
|
128
|
+
## 6. Size and order
|
|
129
|
+
|
|
130
|
+
About a day's change across settings, the seven boards and their tests; no renderer work beyond
|
|
131
|
+
the one rename. Landing order: schema and migration first (with the tests that prove nothing
|
|
132
|
+
changes on screen), then the Sky tab, then the boards one at a time, then the panel switches and
|
|
133
|
+
the rename, then the docs. Each step leaves the suite green and the boards drawing what they drew.
|
|
134
|
+
|
|
135
|
+
## 7. What is deliberately not in this
|
|
136
|
+
|
|
137
|
+
* No per-board Earth parameters (a different hour for the candles than for the artillery). One
|
|
138
|
+
Earth, one Galaxy; a board chooses between them. Scorched Yard's per-round hour is the game's own
|
|
139
|
+
business and stays.
|
|
140
|
+
* No third sky. The catalogue shape makes adding one a section and a value, later.
|
|
141
|
+
* The internal option name `space` on the Block space board (its deck texture and floor style) is
|
|
142
|
+
not renamed: it is a board style, not a sky, and nothing in the sheet shows the word.
|