feat(ui): Phase 29 map visibility toggles
Adds the gear-icon popover on the map view with per-game persistence of every category toggle plus the wrap-mode radio. Hide-by-id and visibility-fog facilities land on the renderer so every flip applies within one frame without a Pixi remount; the wrap-mode toggle keeps its existing remount + camera-preserve path. A new server-side turn force-resets every flag to defaults so a hidden category never makes the player miss the next turn's news. Also fixes the FligthDistance → FlightDistance typo in pkg/calc/race.go (plus the single Go caller); the TS side keeps duplicating the formula until a race-level WASM bridge lands. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -31,7 +31,6 @@
|
||||
|
||||
import type {
|
||||
GameReport,
|
||||
ReportIncomingShipGroup,
|
||||
ReportLocalShipGroup,
|
||||
ReportOtherShipGroup,
|
||||
ReportPlanet,
|
||||
@@ -107,14 +106,51 @@ const PRIORITY_INCOMING_POINT = 6;
|
||||
const PRIORITY_INCOMING_LINE = 0;
|
||||
const PRIORITY_UNIDENTIFIED = 4;
|
||||
|
||||
/**
|
||||
* ShipGroupCategory tags every emitted primitive with the toggleable
|
||||
* surface it belongs to. The Phase 29 hide-set machinery in
|
||||
* `lib/active-view/map.svelte` looks these up via `categories` to
|
||||
* decide whether to hide the primitive when the matching `MapToggles`
|
||||
* flag is `false`.
|
||||
*/
|
||||
export type ShipGroupCategory =
|
||||
| "hyperspaceGroup"
|
||||
| "incomingGroup"
|
||||
| "unidentifiedGroup";
|
||||
|
||||
export interface ShipGroupPrimitives {
|
||||
primitives: (PointPrim | LinePrim)[];
|
||||
lookup: Map<PrimitiveID, ShipGroupRef>;
|
||||
categories: Map<PrimitiveID, ShipGroupCategory>;
|
||||
/**
|
||||
* planetDependents maps a planet number to the set of primitive
|
||||
* ids that should hide together with that planet. In Phase 29 the
|
||||
* hide-by-id machinery cascades planet visibility onto in-space
|
||||
* and incoming groups flying *to* the planet (their points + the
|
||||
* trajectory / track lines). Unidentified groups have no planet
|
||||
* anchor and therefore contribute nothing here.
|
||||
*/
|
||||
planetDependents: Map<number, Set<PrimitiveID>>;
|
||||
}
|
||||
|
||||
function addDependent(
|
||||
planetDependents: Map<number, Set<PrimitiveID>>,
|
||||
planetNumber: number,
|
||||
primitiveId: PrimitiveID,
|
||||
): void {
|
||||
let set = planetDependents.get(planetNumber);
|
||||
if (set === undefined) {
|
||||
set = new Set();
|
||||
planetDependents.set(planetNumber, set);
|
||||
}
|
||||
set.add(primitiveId);
|
||||
}
|
||||
|
||||
export function shipGroupsToPrimitives(report: GameReport): ShipGroupPrimitives {
|
||||
const primitives: (PointPrim | LinePrim)[] = [];
|
||||
const lookup = new Map<PrimitiveID, ShipGroupRef>();
|
||||
const categories = new Map<PrimitiveID, ShipGroupCategory>();
|
||||
const planetDependents = new Map<number, Set<PrimitiveID>>();
|
||||
const planetIndex = new Map<number, ReportPlanet>();
|
||||
for (const planet of report.planets) {
|
||||
planetIndex.set(planet.number, planet);
|
||||
@@ -129,6 +165,8 @@ export function shipGroupsToPrimitives(report: GameReport): ShipGroupPrimitives
|
||||
const id = SHIP_GROUP_ID_OFFSETS.local + i;
|
||||
primitives.push(makePoint(id, pos.x, pos.y, PRIORITY_LOCAL, STYLE_LOCAL_GROUP));
|
||||
lookup.set(id, { variant: "local", id: group.id });
|
||||
categories.set(id, "hyperspaceGroup");
|
||||
addDependent(planetDependents, group.destination, id);
|
||||
// Yellow dashed track from the origin planet to the destination
|
||||
// planet. The colour matches the in-space group point so the
|
||||
// player can read both as one entity at a glance. Wrap-aware
|
||||
@@ -140,9 +178,10 @@ export function shipGroupsToPrimitives(report: GameReport): ShipGroupPrimitives
|
||||
if (origin !== undefined && destination !== undefined) {
|
||||
const dx = torusShortestDelta(origin.x, destination.x, w);
|
||||
const dy = torusShortestDelta(origin.y, destination.y, h);
|
||||
const lineId = SHIP_GROUP_ID_OFFSETS.localLine + i;
|
||||
primitives.push({
|
||||
kind: "line",
|
||||
id: SHIP_GROUP_ID_OFFSETS.localLine + i,
|
||||
id: lineId,
|
||||
priority: PRIORITY_LOCAL_LINE,
|
||||
style: STYLE_LOCAL_INSPACE_LINE,
|
||||
hitSlopPx: 0,
|
||||
@@ -151,6 +190,8 @@ export function shipGroupsToPrimitives(report: GameReport): ShipGroupPrimitives
|
||||
x2: origin.x + dx,
|
||||
y2: origin.y + dy,
|
||||
});
|
||||
categories.set(lineId, "hyperspaceGroup");
|
||||
addDependent(planetDependents, group.destination, lineId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,6 +202,8 @@ export function shipGroupsToPrimitives(report: GameReport): ShipGroupPrimitives
|
||||
const id = SHIP_GROUP_ID_OFFSETS.other + i;
|
||||
primitives.push(makePoint(id, pos.x, pos.y, PRIORITY_OTHER, STYLE_OTHER_GROUP));
|
||||
lookup.set(id, { variant: "other", index: i });
|
||||
categories.set(id, "hyperspaceGroup");
|
||||
addDependent(planetDependents, group.destination, id);
|
||||
}
|
||||
|
||||
for (let i = 0; i < report.incomingShipGroups.length; i++) {
|
||||
@@ -189,6 +232,8 @@ export function shipGroupsToPrimitives(report: GameReport): ShipGroupPrimitives
|
||||
x2: destX,
|
||||
y2: destY,
|
||||
});
|
||||
categories.set(lineId, "incomingGroup");
|
||||
addDependent(planetDependents, group.destination, lineId);
|
||||
const pos = interpolateAlongLine(destX, destY, origin.x, origin.y, group.distance);
|
||||
const pointId = SHIP_GROUP_ID_OFFSETS.incoming + i;
|
||||
primitives.push(
|
||||
@@ -202,6 +247,8 @@ export function shipGroupsToPrimitives(report: GameReport): ShipGroupPrimitives
|
||||
),
|
||||
);
|
||||
lookup.set(pointId, { variant: "incoming", index: i });
|
||||
categories.set(pointId, "incomingGroup");
|
||||
addDependent(planetDependents, group.destination, pointId);
|
||||
}
|
||||
|
||||
for (let i = 0; i < report.unidentifiedShipGroups.length; i++) {
|
||||
@@ -218,9 +265,10 @@ export function shipGroupsToPrimitives(report: GameReport): ShipGroupPrimitives
|
||||
),
|
||||
);
|
||||
lookup.set(id, { variant: "unidentified", index: i });
|
||||
categories.set(id, "unidentifiedGroup");
|
||||
}
|
||||
|
||||
return { primitives, lookup };
|
||||
return { primitives, lookup, categories, planetDependents };
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user