ui/phase-20: lock after Send + dashed tracks for in-flight & pending sends

Send joins Modernize / Dismantle / Transfer as a lockable command:
once any of the four lands in the draft for a group, every action
button on its inspector is disabled with a "command pending"
tooltip and the banner names the queued kind. Load / Unload /
Split / Join Fleet stay non-locking — they stack legitimately on
the engine side.

Two dashed overlays now run alongside the cargo-route arrows:

- Yellow dashed track for own in-space groups, drawn from the
  origin planet to the destination (matches the in-space point
  colour so eye reads both as one entity).
- Green dashed track for every wire-valid sendShipGroup command
  in the order draft, drawn from the source group's orbit planet
  to the chosen destination. Disappears when the command is
  removed from the order tab, when the engine rejects it, or
  when the group has left orbit (in-space track replaces it).

Both tracks are wrap-aware via torusShortestDelta and never
participate in hit-test.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Ilia Denisov
2026-05-10 17:55:43 +02:00
parent 2d201537ee
commit 54733bfb14
11 changed files with 511 additions and 58 deletions
+37 -18
View File
@@ -2177,14 +2177,15 @@ Artifacts:
planet with colonists onboard (engine reference
`controller/ship_group.go:177-179` — `UnloadColonists` is not
called over a foreign planet, so the cargo is lost)
- destructive-command lock: a `Modernize` / `Dismantle` /
`Transfer` order in the draft for a given group disables every
action button on that group's inspector and surfaces a banner
pointing to the order list. Cancelling the queued command in
the order tab releases the lock. Other commands (Send / Load /
Unload / Split / JoinFleet) do not lock — Send is naturally
followed by an out-of-orbit state at turn cutoff and the
remaining four can stack legitimately
- state-changing-command lock: a `Send` / `Modernize` /
`Dismantle` / `Transfer` order in the draft for a given group
disables every action button on that group's inspector and
surfaces a banner pointing to the order list. Cancelling the
queued command in the order tab releases the lock. Load /
Unload / Split / JoinFleet do not lock — they stack legitimately
on the engine side. Send used to be unlocked too, but a queued
Send is the visible commitment to launch this orbit, so the
inspector treats it the same as the three destructive variants
- `pkg/calc/ship.go.BlockUpgradeCost` (migrated from
`game/internal/controller/ship_group_upgrade.go`) — the bridge
rule says `ui/core/calc/` only wraps `pkg/calc/` formulas, so
@@ -2277,16 +2278,34 @@ Decisions during stage:
after a destination is chosen; cancelling the picker leaves no
form behind. Removing the destination control from the form
keeps the surface to one editable field at any time.
7. **Destructive-command lock**. Any `upgradeShipGroup`,
`dismantleShipGroup`, or `transferShipGroup` in the draft for a
given group id disables every action button on that group's
inspector with a "command pending" tooltip and renders a
banner pointing the player at the order list. Cancellation
from the order tab releases the lock. The three commands all
change the group's engine-side state at turn cutoff
(`StateUpgrade` / removal / `StateTransfer`), so any second
action would race the engine's pre-condition check anyway —
the lock surfaces that commitment up-front.
7. **State-changing-command lock**. Any `sendShipGroup`,
`upgradeShipGroup`, `dismantleShipGroup`, or `transferShipGroup`
in the draft for a given group id disables every action button
on that group's inspector with a "command pending" tooltip and
renders a banner pointing the player at the order list.
Cancellation from the order tab releases the lock. All four
commands flip the group out of `StateInOrbit` at turn cutoff
(`StateLaunched` / `StateUpgrade` / removal / `StateTransfer`),
so any second action would race the engine's pre-condition
check anyway — the lock surfaces that commitment up-front.
8. **Pending-Send map overlay**. A queued `sendShipGroup` for an
own group still in orbit renders as a green dashed line from
the orbit planet to the destination, drawn on the same
overlay layer as cargo-route arrows. The line is wrap-aware
(uses `torusShortestDelta`) and skipped when the engine has
marked the command `rejected` or `invalid`. Removed when the
group leaves orbit (Send applied) or the player cancels the
command from the order tab. Implemented in
`ui/frontend/src/map/pending-send-routes.ts`; the overlay
fingerprint in `lib/active-view/map.svelte` is extended so the
renderer's `setExtraPrimitives` re-runs on draft changes.
9. **Yellow dashed track for own in-space groups**. The map
already drew the in-space group point in yellow (`0xfff176`);
Phase 20 adds the matching yellow dashed line from the origin
planet to the destination so the player reads "this group is
moving" even when zoomed out. Wrap-aware via the same torus
delta. Implemented in `ui/frontend/src/map/ship-groups.ts`
alongside the existing in-space point primitive.
## Phase 21. Sciences — CRUD List + Designer