A launched nuke reveals where it lands to every player #142

Merged
agra merged 11 commits from task/3560-a-launched-nuke-reveals-where-it-lands-t into main 2026-10-24 12:42:02 +03:00
Owner

Tracker: #3560

From a nuke's launch until its blast's animation ends, every player sees the ground round its target as if a unit of theirs stood there. The server sends what stands there to everyone, every player's units may target it, and each client lifts its fog there. What it showed stays explored afterwards.

One shared rule in src/shared/nuke.ts gives the disc and the window. The server's sight, combat and the client's fog all read it.

  • The disc: every tile whose centre lies within REVEAL_RADIUS of the impact. That is the blast's widest drawn ring, at 1.35 × BLAST_RADIUS ≈ 13.36 tiles.
  • The window: from the launch until BLAST_SECONDS (15 s) after the landing, 25 s in all. BLAST_SECONDS is the client's former NUKE_AFTER, the time by which the blast's effect is gone, now one shared constant. The fallout's 90 s is not part of it.

Steps

  1. The server reveals a strike's disc to every player from its launch until its blast ends.
    • The shared rule and its constants.
    • The Game keeps landed strikes through their window. They are saved, so MAP_VERSION goes to 20, and Nukes on the wire carries them.
    • The host stamps the disc into every session's sight, and combat counts it as every player's sight.
    • Play checks: the 14 seeded AI matches and npm run bench.
  2. The replica knows each strike's window, and its blast ends by the same tick.
    • The replica keeps the landed strikes on its local clock and gives the rule's sight sources.
    • Detonations learned from a late frame are dated at the strike's due tick.
    • A test pins that the blast's drawn parts go on the first tick the reveal stops.
  3. The client lifts its fog over the disc through the window.
    • The view hands the reveal's sources to the fog, and the Map Yard draws the reveal under ?fog&doom=nuke.
    • The changelog and the in-game help record the change.
    • Draw checks: the Map Yard bench, the fog's cost in Node, and renders.

Decisions (each overridable by Agra)

  • D1, the disc's radius: the outer shock ring's widest radius. It covers the ground under both rings, the dust, the glow and the cloud's foot. The embers fly further, but they draw above the fog.
  • D2, the window's end: a strike reveals while tick < due + BLAST_TICKS, on the server's tick and on the client's local tick alike. The effect is disposed of at the same seconds, so the reveal holds through the effect's last drawn frame.
  • D3, combat: the reveal is sight for combat too. A revealed enemy that the player orders an attack on is fired on once in range. Otherwise the unit would walk into range and hold fire.
  • D4, the wire: Nukes carries each landed strike still inside its window, so a client that syncs after a landing lifts its fog while the server sends what stands there. Deriving the window from the fallout zones instead was weighed and not taken: it would tie the reveal to the fallout's rule.
  • D5, detonation dates: the replica dates a detonation it learns from a frame at the strike's due tick. Its effect then ends on the tick the reveal does, and it lines up with the server's blast.
  • D6, stamping: the server stamps the disc per session on every tick, not into the per-owner static layer.
  • D7, who sees it: every session sees the disc: players, spectators' views and AI seats alike.

Acceptance walk

At bc281f2 against main d4a6158. Its tree is the tree step 3 was reviewed and benched at (9ffb2a4).

  • Server: met. host.test.ts's reveal test keeps the other player's tank, 11.4 tiles from the impact, in the launcher's and a viewer's replicas from the launch through due + BLAST_TICKS − 1. Both get UnitHidden for it at due + BLAST_TICKS. A tank 14.56 tiles out is in neither replica at any tick. nuke.test.ts's reveal test has a third player's Artillery target the tank and fire on it through the window and hold fire after it, with a no-launch control.
  • Client fog: met. reveal.test.ts reads the fog sheet's live and explored textures for two clients: seen over the disc through due + BLAST_TICKS − 1, explored fog from due + BLAST_TICKS, and nothing lit past it. Mutants of revealing in whole-tree copies: <= for < and BLAST_TICKS − 1 for BLAST_TICKS each fail it. They also fail the host, combat, save, rule and replica tests. Dropping the reveals from fogFriends fails it too.
  • One constant: met. BLAST_SECONDS / BLAST_TICKS in src/shared/nuke.ts are the only window. render/nuke.ts disposes of the effect and fades the cloud by BLAST_SECONDS, and NUKE_AFTER is gone. Disposing of the effect 1 s later fails nuke.test.ts's three disposal tests.
  • A live walk in a scratch copy of the head drove a real ServerHost into a Replica, a Fog fed by fogFriends, and a NukeLayer posed as main.ts poses it, at draw phases 0 and 0.99. The sides were the launcher, a viewer, a spectator of the viewer and a player joining at due + 10, with frames on time and 3 ticks late.
    • Each held the tank and the disc seen through due + BLAST_TICKS − 1, and explored fog from due + BLAST_TICKS.
    • replica.reveals() matched game.reveals() on every tick once the frames had arrived.
    • The effect drew on exactly the ticks the reveal held, and never without it. Under the − 1 mutant it drew one tick without the reveal, and under the 1 s mutant 30 ticks.
    • The late joiner drew no blast, as the plan's scope says.
  • Play: met.
    • The 14 seeded AI matches all ran to their end. 8 traces are identical to main, all of them matches with no launch. The other 6 (medium-1, -2, -3 and large-1, -2, -3) first differ after a launch. All 14 end for the same reason with the same seats standing.
    • npm run bench (battle, economy, cities and churn at 128 and 256, seed 11, wan) is identical to main in hash, gameHash, commandHash, commands and every client's raw and deflated bytes.
  • Draw: step 3's Map Yard bench covers this tree. One load per arm and view of the Map Yard (iPhone 15 landscape, WebKit) draws the same calls and triangles on main and on the head at rest (67, 65 and 41 calls at 1×, 0.5× and 0.25×). It does the same under ?fog&doom=nuke (88, 86 and 72 calls).
  • Records: met. MAP_VERSION is 20, one above main's 19. changelog.md's "Current" bullet and the help's bomb paragraph say the window and the disc from the shared constants (15 s, 13.4 tiles).
  • Gate: sak-gate full #1 (tracker gate run 300) at bc281f2 passed: npm test 980/980 in 65.4 s, test:phone 180/180.
Tracker: [#3560](https://sak.swipelab.com/tasks/3560) From a nuke's launch until its blast's animation ends, every player sees the ground round its target as if a unit of theirs stood there. The server sends what stands there to everyone, every player's units may target it, and each client lifts its fog there. What it showed stays explored afterwards. One shared rule in `src/shared/nuke.ts` gives the disc and the window. The server's sight, combat and the client's fog all read it. - **The disc:** every tile whose centre lies within `REVEAL_RADIUS` of the impact. That is the blast's widest drawn ring, at 1.35 × BLAST_RADIUS ≈ 13.36 tiles. - **The window:** from the launch until `BLAST_SECONDS` (15 s) after the landing, 25 s in all. `BLAST_SECONDS` is the client's former `NUKE_AFTER`, the time by which the blast's effect is gone, now one shared constant. The fallout's 90 s is not part of it. ## Steps 1. **The server reveals a strike's disc to every player from its launch until its blast ends.** - The shared rule and its constants. - The Game keeps landed strikes through their window. They are saved, so MAP_VERSION goes to 20, and Nukes on the wire carries them. - The host stamps the disc into every session's sight, and combat counts it as every player's sight. - Play checks: the 14 seeded AI matches and `npm run bench`. 2. **The replica knows each strike's window, and its blast ends by the same tick.** - The replica keeps the landed strikes on its local clock and gives the rule's sight sources. - Detonations learned from a late frame are dated at the strike's due tick. - A test pins that the blast's drawn parts go on the first tick the reveal stops. 3. **The client lifts its fog over the disc through the window.** - The view hands the reveal's sources to the fog, and the Map Yard draws the reveal under `?fog&doom=nuke`. - The changelog and the in-game help record the change. - Draw checks: the Map Yard bench, the fog's cost in Node, and renders. ## Decisions (each overridable by Agra) - **D1, the disc's radius:** the outer shock ring's widest radius. It covers the ground under both rings, the dust, the glow and the cloud's foot. The embers fly further, but they draw above the fog. - **D2, the window's end:** a strike reveals while `tick < due + BLAST_TICKS`, on the server's tick and on the client's local tick alike. The effect is disposed of at the same seconds, so the reveal holds through the effect's last drawn frame. - **D3, combat:** the reveal is sight for combat too. A revealed enemy that the player orders an attack on is fired on once in range. Otherwise the unit would walk into range and hold fire. - **D4, the wire:** Nukes carries each landed strike still inside its window, so a client that syncs after a landing lifts its fog while the server sends what stands there. Deriving the window from the fallout zones instead was weighed and not taken: it would tie the reveal to the fallout's rule. - **D5, detonation dates:** the replica dates a detonation it learns from a frame at the strike's due tick. Its effect then ends on the tick the reveal does, and it lines up with the server's blast. - **D6, stamping:** the server stamps the disc per session on every tick, not into the per-owner static layer. - **D7, who sees it:** every session sees the disc: players, spectators' views and AI seats alike. ## Acceptance walk At bc281f2 against main d4a6158. Its tree is the tree step 3 was reviewed and benched at (9ffb2a4). - **Server: met.** host.test.ts's reveal test keeps the other player's tank, 11.4 tiles from the impact, in the launcher's and a viewer's replicas from the launch through `due + BLAST_TICKS − 1`. Both get UnitHidden for it at `due + BLAST_TICKS`. A tank 14.56 tiles out is in neither replica at any tick. nuke.test.ts's reveal test has a third player's Artillery target the tank and fire on it through the window and hold fire after it, with a no-launch control. - **Client fog: met.** reveal.test.ts reads the fog sheet's `live` and `explored` textures for two clients: seen over the disc through `due + BLAST_TICKS − 1`, explored fog from `due + BLAST_TICKS`, and nothing lit past it. Mutants of `revealing` in whole-tree copies: `<=` for `<` and `BLAST_TICKS − 1` for `BLAST_TICKS` each fail it. They also fail the host, combat, save, rule and replica tests. Dropping the reveals from `fogFriends` fails it too. - **One constant: met.** `BLAST_SECONDS` / `BLAST_TICKS` in src/shared/nuke.ts are the only window. render/nuke.ts disposes of the effect and fades the cloud by `BLAST_SECONDS`, and `NUKE_AFTER` is gone. Disposing of the effect 1 s later fails nuke.test.ts's three disposal tests. - **A live walk** in a scratch copy of the head drove a real `ServerHost` into a Replica, a Fog fed by `fogFriends`, and a NukeLayer posed as main.ts poses it, at draw phases 0 and 0.99. The sides were the launcher, a viewer, a spectator of the viewer and a player joining at `due + 10`, with frames on time and 3 ticks late. - Each held the tank and the disc seen through `due + BLAST_TICKS − 1`, and explored fog from `due + BLAST_TICKS`. - `replica.reveals()` matched `game.reveals()` on every tick once the frames had arrived. - The effect drew on exactly the ticks the reveal held, and never without it. Under the `− 1` mutant it drew one tick without the reveal, and under the 1 s mutant 30 ticks. - The late joiner drew no blast, as the plan's scope says. - **Play: met.** - The 14 seeded AI matches all ran to their end. 8 traces are identical to main, all of them matches with no launch. The other 6 (medium-1, -2, -3 and large-1, -2, -3) first differ after a launch. All 14 end for the same reason with the same seats standing. - `npm run bench` (battle, economy, cities and churn at 128 and 256, seed 11, wan) is identical to main in hash, gameHash, commandHash, commands and every client's raw and deflated bytes. - **Draw:** step 3's Map Yard bench covers this tree. One load per arm and view of the Map Yard (iPhone 15 landscape, WebKit) draws the same calls and triangles on main and on the head at rest (67, 65 and 41 calls at 1×, 0.5× and 0.25×). It does the same under `?fog&doom=nuke` (88, 86 and 72 calls). - **Records: met.** MAP_VERSION is 20, one above main's 19. changelog.md's "Current" bullet and the help's bomb paragraph say the window and the disc from the shared constants (15 s, 13.4 tiles). - **Gate:** `sak-gate full` #1 (tracker gate run 300) at bc281f2 passed: `npm test` 980/980 in 65.4 s, `test:phone` 180/180.
agra added 11 commits 2026-10-24 11:38:45 +03:00
agra merged commit d3604f1858 into main 2026-10-24 12:42:02 +03:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
agra/mini-alert!142
No description provided.