ui/phase-23: turn-report view with twenty sections and TOC
Replaces the Phase 10 report stub with a scrollable orchestrator that renders every FBS array as a dedicated section (galaxy summary, votes, player status, my/foreign sciences, my/foreign ship classes, battles, bombings, approaching groups, my/foreign/uninhabited/unknown planets, ships in production, cargo routes, my fleets, my/foreign/unidentified ship groups). A sticky table of contents (a <select> on mobile), "back to map" affordance, IntersectionObserver-driven active-section highlight, and SvelteKit Snapshot-based scroll save/restore round out the view. GameReport gains six new fields (players, otherScience, otherShipClass, battleIds, bombings, shipProductions); decodeReport, the synthetic- report loader, the e2e fixture builder, and EMPTY_SHIP_GROUPS extend in lockstep. ~90 new i18n keys land in en + ru together. The legacy-report parser is extended to populate the new sections from the dg/gplus text formats (Your Sciences, <Race> Sciences, <Race> Ship Types, Bombings, Ships In Production). Ships-in-production prod_used is derived through a new pkg/calc.ShipBuildCost helper; the engine's controller.ProduceShip refactors to call the same helper without any behaviour change (engine tests stay unchanged and green). Battles remain in the parser's Skipped list — the legacy text carries no stable per-battle UUID. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -60,6 +60,11 @@ already decodes from server responses
|
||||
| `UninhabitedPlanet[]` | `Uninhabited Planets` |
|
||||
| `UnidentifiedPlanet[]`| `Unidentified Planets` |
|
||||
| `LocalShipClass[]` | `Your Ship Types` |
|
||||
| `OtherShipClass[]` | `<Race> Ship Types` (Phase 23) |
|
||||
| `LocalScience[]` | `Your Sciences` (Phase 23) |
|
||||
| `OtherScience[]` | `<Race> Sciences` (Phase 23) |
|
||||
| `Bombing[]` | `Bombings` (Phase 23) |
|
||||
| `ShipProduction[]` | `Ships In Production` (Phase 23) |
|
||||
| `LocalGroup[]` | `Your Groups` (Phase 19) |
|
||||
| `LocalFleet[]` | `Your Fleets` (Phase 19) |
|
||||
| `IncomingGroup[]` | `Incoming Groups` (Phase 19) |
|
||||
@@ -78,29 +83,37 @@ tables (foreign-only knowledge the local player lacks) cause the entire
|
||||
group / fleet / incoming row to be dropped — preferable to fabricating
|
||||
a destination.
|
||||
|
||||
`ShipProduction.ProdUsed` is derived from the on-disk `Percent` and the
|
||||
producing planet's material/resources via [`pkg/calc.ShipBuildCost`]
|
||||
(the same helper the engine's `controller.ProduceShip` uses). The
|
||||
legacy text format does not carry a `prod_used` column directly; the
|
||||
derivation gives the cumulative production-equivalent of the build
|
||||
progress so far. The real engine's `ProdUsed` is the per-turn
|
||||
residual production poured into the partial ship, which is not
|
||||
recoverable from a single legacy snapshot. The two numbers stay in
|
||||
the same units and the same ballpark, which is good enough for the
|
||||
synthetic-mode UI — live engine reports come over the FBS wire and
|
||||
do not flow through this parser. A ships-in-production row pointing
|
||||
at a planet that did not appear in `Your Planets` (which would be a
|
||||
malformed legacy file) is dropped.
|
||||
|
||||
## Skipped sections (today)
|
||||
|
||||
These exist in legacy reports but either have no UI decoder yet or
|
||||
cannot be derived from the legacy text format at all. Each becomes
|
||||
in-scope as soon as its UI phase lands (see "Adding a new field"
|
||||
below).
|
||||
These exist in legacy reports but cannot be derived from the legacy
|
||||
text format at all. Each could become in-scope if a strong enough
|
||||
reason arises (see "Adding a new field" below).
|
||||
|
||||
- Foreign / other ship types (`<Race> Ship Types`)
|
||||
- Sciences, both local (`Your Sciences`) and foreign (`<Race> Sciences`)
|
||||
- Battles (`Battle at (#N) Name`, `Battle Protocol`) — battle rosters
|
||||
inside these blocks carry minimal columns (no origin / range /
|
||||
destination) and are intentionally skipped: parsing them would
|
||||
produce mostly-empty `OtherGroup` records that drift away from the
|
||||
typed contract.
|
||||
- Bombings (`Bombings`)
|
||||
- Ships in production (`Ships In Production`)
|
||||
- Battles (`Battle at (#N) Name`, `Battle Protocol`) — the wire schema
|
||||
carries battle UUIDs (`Report.Battle: []uuid.UUID`); the legacy text
|
||||
carries per-battle rosters with stripped columns (no origin / range /
|
||||
destination) and no stable identifier. Synthesising UUIDs from the
|
||||
text would invent data that future Phase 27 work would have to drop;
|
||||
the synthetic JSON therefore emits `battle: []`.
|
||||
- `OtherGroup[]` — no top-level legacy section. Foreign groups appear
|
||||
only inside battle rosters (see above), with stripped columns; the
|
||||
synthetic JSON emits `otherGroup: []`.
|
||||
- `UnidentifiedGroup[]` — no legacy section at all; synthetic JSON
|
||||
emits `unidentifiedGroup: []`.
|
||||
- `OtherShipClass[]` — present in legacy as `<Race> Ship Types`, but
|
||||
no UI decoder yet; synthetic JSON emits `otherShipClass: []`.
|
||||
- Cargo routes — no dedicated section in the legacy text format; the
|
||||
synthetic JSON emits `route: []`. The UI's overlay path
|
||||
(`applyOrderOverlay`) supports running on top of an empty `routes`.
|
||||
|
||||
Reference in New Issue
Block a user