Refactor universe sim and observer HUD
This commit is contained in:
@@ -6,14 +6,27 @@ import {
|
||||
import { describeFleetOrder } from "../fleet/runtime";
|
||||
import { getShipCargoAmount } from "../state/inventory";
|
||||
import type {
|
||||
FactionInstance,
|
||||
FleetInstance,
|
||||
PlanetInstance,
|
||||
ShipInstance,
|
||||
SolarSystemInstance,
|
||||
StationInstance,
|
||||
ViewLevel,
|
||||
} from "../types";
|
||||
|
||||
export function getSelectionTitle(selection: ShipInstance[], selectedStation?: StationInstance) {
|
||||
export function getSelectionTitle(
|
||||
selection: ShipInstance[],
|
||||
selectedStation?: StationInstance,
|
||||
selectedSystem?: SolarSystemInstance,
|
||||
selectedPlanet?: PlanetInstance,
|
||||
) {
|
||||
if (selectedPlanet) {
|
||||
return selectedPlanet.definition.label;
|
||||
}
|
||||
if (selectedSystem) {
|
||||
return selectedSystem.definition.label;
|
||||
}
|
||||
if (selectedStation) {
|
||||
return selectedStation.definition.label;
|
||||
}
|
||||
@@ -26,19 +39,114 @@ export function getSelectionTitle(selection: ShipInstance[], selectedStation?: S
|
||||
return `${selection.length} Ships Selected`;
|
||||
}
|
||||
|
||||
export function getSelectionStripLabels(
|
||||
selection: ShipInstance[],
|
||||
selectedStation?: StationInstance,
|
||||
selectedSystem?: SolarSystemInstance,
|
||||
selectedPlanet?: PlanetInstance,
|
||||
) {
|
||||
if (selectedPlanet) {
|
||||
return [selectedPlanet.definition.label];
|
||||
}
|
||||
if (selectedSystem) {
|
||||
return [selectedSystem.definition.label];
|
||||
}
|
||||
if (selectedStation) {
|
||||
return [selectedStation.definition.label];
|
||||
}
|
||||
if (selection.length === 0) {
|
||||
return [];
|
||||
}
|
||||
return selection.map((ship) => ship.definition.label);
|
||||
}
|
||||
|
||||
export function getSelectionCardsMarkup(
|
||||
selection: ShipInstance[],
|
||||
selectedStation: StationInstance | undefined,
|
||||
selectedSystem: SolarSystemInstance | undefined,
|
||||
selectedPlanet: PlanetInstance | undefined,
|
||||
) {
|
||||
if (selectedPlanet) {
|
||||
return renderCard(
|
||||
selectedPlanet.definition.label,
|
||||
[
|
||||
selectedPlanet.systemId,
|
||||
`Orbit ${Math.round(selectedPlanet.definition.orbitRadius)}`,
|
||||
`Size ${selectedPlanet.definition.size}`,
|
||||
selectedPlanet.definition.hasRing ? "Ringed" : "No ring",
|
||||
],
|
||||
);
|
||||
}
|
||||
if (selectedSystem) {
|
||||
return renderCard(
|
||||
selectedSystem.definition.label,
|
||||
[
|
||||
selectedSystem.strategicValue,
|
||||
`${selectedSystem.planets.length} planets`,
|
||||
`${selectedSystem.definition.resourceNodes.length} nodes`,
|
||||
`${selectedSystem.controllingFactionId ?? "Contested"} ${Math.round(selectedSystem.controlProgress)}%`,
|
||||
],
|
||||
);
|
||||
}
|
||||
if (selectedStation) {
|
||||
return renderCard(
|
||||
selectedStation.definition.label,
|
||||
[
|
||||
selectedStation.factionId,
|
||||
selectedStation.definition.category,
|
||||
`HP ${Math.round(selectedStation.health)}/${selectedStation.maxHealth}`,
|
||||
`Dock ${selectedStation.dockedShipIds.size}/${selectedStation.definition.dockingCapacity}`,
|
||||
],
|
||||
);
|
||||
}
|
||||
if (selection.length === 0) {
|
||||
return `<span class="selection-strip-empty">No active selection</span>`;
|
||||
}
|
||||
return selection
|
||||
.map((ship) =>
|
||||
renderCard(ship.definition.label, [
|
||||
ship.factionId,
|
||||
ship.state,
|
||||
ship.order.kind,
|
||||
`HP ${Math.round(ship.health)}/${ship.maxHealth}`,
|
||||
]),
|
||||
)
|
||||
.join("");
|
||||
}
|
||||
|
||||
export function getSelectionDetails(
|
||||
selection: ShipInstance[],
|
||||
selectedStation: StationInstance | undefined,
|
||||
selectedSystem: SolarSystemInstance | undefined,
|
||||
selectedPlanet: PlanetInstance | undefined,
|
||||
systems: SolarSystemInstance[],
|
||||
viewLevel: ViewLevel,
|
||||
ships: ShipInstance[],
|
||||
fleets: FleetInstance[],
|
||||
factions: FactionInstance[],
|
||||
) {
|
||||
if (selectedPlanet) {
|
||||
return `${selectedPlanet.definition.label} • ${selectedPlanet.systemId}\nOrbit Radius: ${Math.round(selectedPlanet.definition.orbitRadius)}\nSize: ${selectedPlanet.definition.size}\nOrbit Speed: ${selectedPlanet.definition.orbitSpeed.toFixed(2)}\nTilt: ${selectedPlanet.definition.tilt.toFixed(2)}\nRing: ${selectedPlanet.definition.hasRing ? "Yes" : "No"}`;
|
||||
}
|
||||
if (selectedSystem) {
|
||||
return `${selectedSystem.definition.label}\nType: ${selectedSystem.strategicValue}\nControl: ${selectedSystem.controllingFactionId ?? "Contested"} ${Math.round(selectedSystem.controlProgress)}%\nPlanets: ${selectedSystem.planets.length}\nResource Nodes: ${selectedSystem.definition.resourceNodes.length}\nGravity Well: ${Math.round(selectedSystem.gravityWellRadius)}`;
|
||||
}
|
||||
if (selectedStation) {
|
||||
return describeStation(selectedStation, ships, fleets);
|
||||
}
|
||||
if (selection.length === 0) {
|
||||
return `Systems online: ${systems.map((system) => system.definition.label).join(", ")}\nFleets active: ${fleets.length}\n\nOrders: Move, Patrol, Escort, Mine\nView: ${viewLevel}`;
|
||||
const central = systems
|
||||
.filter((system) => system.strategicValue === "central")
|
||||
.map((system) => `${system.definition.label}: ${system.controllingFactionId ?? "contested"} ${Math.round(system.controlProgress)}%`)
|
||||
.join("\n");
|
||||
const factionLines = factions
|
||||
.filter((faction) => faction.definition.kind === "empire")
|
||||
.map(
|
||||
(faction) =>
|
||||
`${faction.definition.label}: systems ${faction.ownedSystemIds.size} • mined ${Math.round(faction.oreMined)} • built ${faction.shipsBuilt} ships • losses ${faction.shipsLost}`,
|
||||
)
|
||||
.join("\n");
|
||||
return `Observer Mode\nSystems online: ${systems.length}\nFleets tracked: ${fleets.length}\nView: ${viewLevel}\n\nCentral systems:\n${central}\n\nEmpires:\n${factionLines}`;
|
||||
}
|
||||
|
||||
return selection
|
||||
@@ -49,7 +157,7 @@ export function getSelectionDetails(
|
||||
ship.definition.dockingCapacity && ship.definition.dockingCapacity > 0
|
||||
? `\nHangar: ${ship.dockedShipIds.size}/${ship.definition.dockingCapacity} for ${(ship.definition.dockingClasses ?? []).join(", ")}`
|
||||
: "";
|
||||
return `${ship.definition.label} • ${ship.systemId}\nClass: ${ship.definition.shipClass}\nState: ${ship.state}${dockedAt ? ` @ ${dockedAt}` : ""}\nOrder: ${ship.order.kind}\nFleet: ${ship.fleetId ?? "Independent"}${ship.isFleetCommander ? " • Commander" : ship.isWingLeader ? " • Wing Leader" : ""}\nBehavior: ${ship.behavior}\nCargo: ${Math.round(getShipCargoAmount(ship))}/${ship.definition.cargoCapacity || 0} ${getItemLabel(ship.cargoItemId)}\nFuel: ${ship.fuel.toFixed(0)}/${ship.maxFuel}\nEnergy: ${ship.energy.toFixed(0)}/${ship.maxEnergy}\nHold Type: ${ship.definition.cargoKind ?? "none"}${hangarStatus}\nModules: ${ship.definition.modules.map(getModuleLabel).join(", ")}`;
|
||||
return `${ship.definition.label} • ${ship.systemId}\nFaction: ${ship.factionId}\nClass: ${ship.definition.shipClass}\nState: ${ship.state}${dockedAt ? ` @ ${dockedAt}` : ""}\nOrder: ${ship.order.kind}\nFleet: ${ship.fleetId ?? "Independent"}${ship.isFleetCommander ? " • Commander" : ship.isWingLeader ? " • Wing Leader" : ""}\nBehavior: ${ship.behavior}\nHealth: ${Math.round(ship.health)}/${ship.maxHealth}\nCargo: ${Math.round(getShipCargoAmount(ship))}/${ship.definition.cargoCapacity || 0} ${getItemLabel(ship.cargoItemId)}\nFuel: ${ship.fuel.toFixed(0)}/${ship.maxFuel}\nEnergy: ${ship.energy.toFixed(0)}/${ship.maxEnergy}\nHold Type: ${ship.definition.cargoKind ?? "none"}${hangarStatus}\nModules: ${ship.definition.modules.map(getModuleLabel).join(", ")}`;
|
||||
},
|
||||
)
|
||||
.join("\n\n");
|
||||
@@ -88,7 +196,7 @@ export function describeStation(station: StationInstance, ships: ShipInstance[],
|
||||
? "Fabricating industrial parts and equipment"
|
||||
: "Managing local trade traffic";
|
||||
|
||||
return `${station.definition.label} • ${station.systemId}\nRole: ${station.definition.category}\nActivity: ${activity}\nLocal Fleets: ${localFleets}\nDocking: ${station.dockedShipIds.size}/${station.definition.dockingCapacity}\nFuel: ${station.fuel.toFixed(0)}/${station.maxFuel}\nEnergy: ${station.energy.toFixed(0)}/${station.maxEnergy}\nBulk Solid: ${Math.round(station.inventory["bulk-solid"])}\nContainer: ${Math.round(station.inventory.container)}\nManufactured: ${Math.round(station.inventory.manufactured)}\nModules: ${station.modules.map(getModuleLabel).join(", ")}\n${productionStatus}Radius: ${station.definition.radius}`;
|
||||
return `${station.definition.label} • ${station.systemId}\nFaction: ${station.factionId}\nRole: ${station.definition.category}\nActivity: ${activity}\nLocal Fleets: ${localFleets}\nDocking: ${station.dockedShipIds.size}/${station.definition.dockingCapacity}\nHealth: ${Math.round(station.health)}/${station.maxHealth}\nFuel: ${station.fuel.toFixed(0)}/${station.maxFuel}\nEnergy: ${station.energy.toFixed(0)}/${station.maxEnergy}\nBulk Solid: ${Math.round(station.inventory["bulk-solid"])}\nContainer: ${Math.round(station.inventory.container)}\nManufactured: ${Math.round(station.inventory.manufactured)}\nModules: ${station.modules.map(getModuleLabel).join(", ")}\n${productionStatus}Radius: ${station.definition.radius}`;
|
||||
}
|
||||
|
||||
export function getFleetWindowMarkup(
|
||||
@@ -178,6 +286,15 @@ function describeShipNode(ship: ShipInstance): string {
|
||||
return `${ship.definition.shipClass} • ${ship.state} • ${ship.order.kind} • ${ship.behavior}`;
|
||||
}
|
||||
|
||||
function renderCard(title: string, lines: string[]) {
|
||||
return `
|
||||
<article class="selection-strip-card">
|
||||
<span class="selection-strip-card-title">${title}</span>
|
||||
${lines.map((line) => `<span class="selection-strip-card-line">${line}</span>`).join("")}
|
||||
</article>
|
||||
`;
|
||||
}
|
||||
|
||||
function collectWingShipIds(fleet: FleetInstance, rootWingId: string): string[] {
|
||||
const wingIds = new Set<string>([rootWingId]);
|
||||
let changed = true;
|
||||
|
||||
Reference in New Issue
Block a user