feat: simplifying the simulation
This commit is contained in:
@@ -3,8 +3,8 @@ namespace SpaceGame.Simulation.Api.Contracts;
|
|||||||
public sealed record ShipSnapshot(
|
public sealed record ShipSnapshot(
|
||||||
string Id,
|
string Id,
|
||||||
string Label,
|
string Label,
|
||||||
string Role,
|
string Kind,
|
||||||
string ShipClass,
|
string Class,
|
||||||
string SystemId,
|
string SystemId,
|
||||||
Vector3Dto LocalPosition,
|
Vector3Dto LocalPosition,
|
||||||
Vector3Dto LocalVelocity,
|
Vector3Dto LocalVelocity,
|
||||||
@@ -19,8 +19,7 @@ public sealed record ShipSnapshot(
|
|||||||
string? CommanderId,
|
string? CommanderId,
|
||||||
string? PolicySetId,
|
string? PolicySetId,
|
||||||
float CargoCapacity,
|
float CargoCapacity,
|
||||||
string? CargoItemId,
|
|
||||||
float WorkerPopulation,
|
|
||||||
float TravelSpeed,
|
float TravelSpeed,
|
||||||
string TravelSpeedUnit,
|
string TravelSpeedUnit,
|
||||||
IReadOnlyList<InventoryEntry> Inventory,
|
IReadOnlyList<InventoryEntry> Inventory,
|
||||||
@@ -33,8 +32,8 @@ public sealed record ShipSnapshot(
|
|||||||
public sealed record ShipDelta(
|
public sealed record ShipDelta(
|
||||||
string Id,
|
string Id,
|
||||||
string Label,
|
string Label,
|
||||||
string Role,
|
string Kind,
|
||||||
string ShipClass,
|
string Class,
|
||||||
string SystemId,
|
string SystemId,
|
||||||
Vector3Dto LocalPosition,
|
Vector3Dto LocalPosition,
|
||||||
Vector3Dto LocalVelocity,
|
Vector3Dto LocalVelocity,
|
||||||
@@ -49,8 +48,7 @@ public sealed record ShipDelta(
|
|||||||
string? CommanderId,
|
string? CommanderId,
|
||||||
string? PolicySetId,
|
string? PolicySetId,
|
||||||
float CargoCapacity,
|
float CargoCapacity,
|
||||||
string? CargoItemId,
|
|
||||||
float WorkerPopulation,
|
|
||||||
float TravelSpeed,
|
float TravelSpeed,
|
||||||
string TravelSpeedUnit,
|
string TravelSpeedUnit,
|
||||||
IReadOnlyList<InventoryEntry> Inventory,
|
IReadOnlyList<InventoryEntry> Inventory,
|
||||||
|
|||||||
@@ -147,20 +147,19 @@ public sealed class ShipDefinition
|
|||||||
{
|
{
|
||||||
public required string Id { get; set; }
|
public required string Id { get; set; }
|
||||||
public required string Label { get; set; }
|
public required string Label { get; set; }
|
||||||
public required string Role { get; set; }
|
public required string Kind { get; set; }
|
||||||
public required string ShipClass { get; set; }
|
public required string Class { get; set; }
|
||||||
public float Speed { get; set; }
|
public float Speed { get; set; }
|
||||||
public float WarpSpeed { get; set; }
|
public float WarpSpeed { get; set; }
|
||||||
public float FtlSpeed { get; set; }
|
public float FtlSpeed { get; set; }
|
||||||
public float SpoolTime { get; set; }
|
public float SpoolTime { get; set; }
|
||||||
public float CargoCapacity { get; set; }
|
public float CargoCapacity { get; set; }
|
||||||
public string? CargoKind { get; set; }
|
public string? CargoKind { get; set; }
|
||||||
public string? CargoItemId { get; set; }
|
|
||||||
public required string Color { get; set; }
|
public required string Color { get; set; }
|
||||||
public required string HullColor { get; set; }
|
public required string HullColor { get; set; }
|
||||||
public float Size { get; set; }
|
public float Size { get; set; }
|
||||||
public float MaxHealth { get; set; }
|
public float MaxHealth { get; set; }
|
||||||
public List<string> Modules { get; set; } = [];
|
public List<string> Capabilities { get; set; } = [];
|
||||||
public ConstructionDefinition? Construction { get; set; }
|
public ConstructionDefinition? Construction { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ internal sealed class ShipBehaviorStateMachine
|
|||||||
{
|
{
|
||||||
idleState,
|
idleState,
|
||||||
new PatrolShipBehaviorState(),
|
new PatrolShipBehaviorState(),
|
||||||
new ResourceHarvestShipBehaviorState("auto-mine", "ore", "mining-turret"),
|
new ResourceHarvestShipBehaviorState("auto-mine", "ore", "mining"),
|
||||||
new ConstructStationShipBehaviorState(),
|
new ConstructStationShipBehaviorState(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ public sealed class ShipRuntime
|
|||||||
public required ControllerTaskRuntime ControllerTask { get; set; }
|
public required ControllerTaskRuntime ControllerTask { get; set; }
|
||||||
public float ActionTimer { get; set; }
|
public float ActionTimer { get; set; }
|
||||||
public Dictionary<string, float> Inventory { get; } = new(StringComparer.Ordinal);
|
public Dictionary<string, float> Inventory { get; } = new(StringComparer.Ordinal);
|
||||||
public float WorkerPopulation { get; set; }
|
|
||||||
public string DockedStationId { get; set; }
|
public string DockedStationId { get; set; }
|
||||||
public int? AssignedDockingPadIndex { get; set; }
|
public int? AssignedDockingPadIndex { get; set; }
|
||||||
public string? CommanderId { get; set; }
|
public string? CommanderId { get; set; }
|
||||||
@@ -62,4 +62,5 @@ public sealed class ControllerTaskRuntime
|
|||||||
public string? TargetNodeId { get; set; }
|
public string? TargetNodeId { get; set; }
|
||||||
public Vector3? TargetPosition { get; set; }
|
public Vector3? TargetPosition { get; set; }
|
||||||
public float Threshold { get; set; }
|
public float Threshold { get; set; }
|
||||||
|
public string? ItemId { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,8 +62,7 @@ public enum ControllerTaskKind
|
|||||||
Unload,
|
Unload,
|
||||||
DeliverConstruction,
|
DeliverConstruction,
|
||||||
BuildConstructionSite,
|
BuildConstructionSite,
|
||||||
LoadWorkers,
|
|
||||||
UnloadWorkers,
|
|
||||||
ConstructModule,
|
ConstructModule,
|
||||||
Undock,
|
Undock,
|
||||||
}
|
}
|
||||||
@@ -105,8 +104,7 @@ public static class ShipTaskKinds
|
|||||||
public const string Undock = "undock";
|
public const string Undock = "undock";
|
||||||
public const string LoadCargo = "load-cargo";
|
public const string LoadCargo = "load-cargo";
|
||||||
public const string UnloadCargo = "unload-cargo";
|
public const string UnloadCargo = "unload-cargo";
|
||||||
public const string LoadWorkers = "load-workers";
|
|
||||||
public const string UnloadWorkers = "unload-workers";
|
|
||||||
public const string MineNode = "mine-node";
|
public const string MineNode = "mine-node";
|
||||||
public const string HarvestGas = "harvest-gas";
|
public const string HarvestGas = "harvest-gas";
|
||||||
public const string DeliverToStation = "deliver-to-station";
|
public const string DeliverToStation = "deliver-to-station";
|
||||||
@@ -229,8 +227,7 @@ public static class SimulationEnumMappings
|
|||||||
ControllerTaskKind.Unload => "unload",
|
ControllerTaskKind.Unload => "unload",
|
||||||
ControllerTaskKind.DeliverConstruction => "deliver-construction",
|
ControllerTaskKind.DeliverConstruction => "deliver-construction",
|
||||||
ControllerTaskKind.BuildConstructionSite => "build-construction-site",
|
ControllerTaskKind.BuildConstructionSite => "build-construction-site",
|
||||||
ControllerTaskKind.LoadWorkers => "load-workers",
|
|
||||||
ControllerTaskKind.UnloadWorkers => "unload-workers",
|
|
||||||
ControllerTaskKind.ConstructModule => "construct-module",
|
ControllerTaskKind.ConstructModule => "construct-module",
|
||||||
ControllerTaskKind.Undock => "undock",
|
ControllerTaskKind.Undock => "undock",
|
||||||
_ => throw new ArgumentOutOfRangeException(nameof(kind), kind, null),
|
_ => throw new ArgumentOutOfRangeException(nameof(kind), kind, null),
|
||||||
|
|||||||
@@ -379,7 +379,7 @@ public sealed partial class ScenarioLoader
|
|||||||
IReadOnlyDictionary<string, List<Vector3>> patrolRoutes,
|
IReadOnlyDictionary<string, List<Vector3>> patrolRoutes,
|
||||||
StationRuntime? refinery)
|
StationRuntime? refinery)
|
||||||
{
|
{
|
||||||
if (string.Equals(definition.Role, "construction", StringComparison.Ordinal) && refinery is not null)
|
if (string.Equals(definition.Kind, "construction", StringComparison.Ordinal) && refinery is not null)
|
||||||
{
|
{
|
||||||
return new DefaultBehaviorRuntime
|
return new DefaultBehaviorRuntime
|
||||||
{
|
{
|
||||||
@@ -389,12 +389,12 @@ public sealed partial class ScenarioLoader
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (HasModules(definition, "reactor-core", "capacitor-bank", "mining-turret") && refinery is not null)
|
if (HasCapabilities(definition, "mining") && refinery is not null)
|
||||||
{
|
{
|
||||||
return CreateResourceHarvestBehavior("auto-mine", scenario.MiningDefaults.NodeSystemId, refinery.Id);
|
return CreateResourceHarvestBehavior("auto-mine", scenario.MiningDefaults.NodeSystemId, refinery.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (HasModules(definition, "reactor-core", "capacitor-bank", "gun-turret") && patrolRoutes.TryGetValue(systemId, out var route))
|
if (string.Equals(definition.Kind, "military", StringComparison.Ordinal) && patrolRoutes.TryGetValue(systemId, out var route))
|
||||||
{
|
{
|
||||||
return new DefaultBehaviorRuntime
|
return new DefaultBehaviorRuntime
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -400,8 +400,8 @@ public sealed partial class ScenarioLoader
|
|||||||
private static bool HasInstalledModules(StationRuntime station, params string[] modules) =>
|
private static bool HasInstalledModules(StationRuntime station, params string[] modules) =>
|
||||||
modules.All((moduleId) => station.Modules.Any((candidate) => string.Equals(candidate.ModuleId, moduleId, StringComparison.Ordinal)));
|
modules.All((moduleId) => station.Modules.Any((candidate) => string.Equals(candidate.ModuleId, moduleId, StringComparison.Ordinal)));
|
||||||
|
|
||||||
private static bool HasModules(ShipDefinition definition, params string[] modules) =>
|
private static bool HasCapabilities(ShipDefinition definition, params string[] capabilities) =>
|
||||||
modules.All((moduleId) => definition.Modules.Contains(moduleId, StringComparer.Ordinal));
|
capabilities.All((cap) => definition.Capabilities.Contains(cap, StringComparer.Ordinal));
|
||||||
|
|
||||||
private static void AddStationModule(StationRuntime station, IReadOnlyDictionary<string, ModuleDefinition> moduleDefinitions, string moduleId)
|
private static void AddStationModule(StationRuntime station, IReadOnlyDictionary<string, ModuleDefinition> moduleDefinitions, string moduleId)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -27,8 +27,7 @@ public sealed partial class SimulationEngine
|
|||||||
ControllerTaskKind.Unload => UpdateUnload(ship, world, deltaSeconds),
|
ControllerTaskKind.Unload => UpdateUnload(ship, world, deltaSeconds),
|
||||||
ControllerTaskKind.DeliverConstruction => UpdateDeliverConstruction(ship, world, deltaSeconds),
|
ControllerTaskKind.DeliverConstruction => UpdateDeliverConstruction(ship, world, deltaSeconds),
|
||||||
ControllerTaskKind.BuildConstructionSite => UpdateBuildConstructionSite(ship, world, deltaSeconds),
|
ControllerTaskKind.BuildConstructionSite => UpdateBuildConstructionSite(ship, world, deltaSeconds),
|
||||||
ControllerTaskKind.LoadWorkers => UpdateLoadWorkers(ship, world, deltaSeconds),
|
|
||||||
ControllerTaskKind.UnloadWorkers => UpdateUnloadWorkers(ship, world, deltaSeconds),
|
|
||||||
ControllerTaskKind.ConstructModule => UpdateConstructModule(ship, world, deltaSeconds),
|
ControllerTaskKind.ConstructModule => UpdateConstructModule(ship, world, deltaSeconds),
|
||||||
ControllerTaskKind.Undock => UpdateUndock(ship, world, deltaSeconds),
|
ControllerTaskKind.Undock => UpdateUndock(ship, world, deltaSeconds),
|
||||||
_ => UpdateIdle(ship, world, deltaSeconds),
|
_ => UpdateIdle(ship, world, deltaSeconds),
|
||||||
@@ -58,6 +57,12 @@ public sealed partial class SimulationEngine
|
|||||||
|
|
||||||
if (ship.SystemId != task.TargetSystemId)
|
if (ship.SystemId != task.TargetSystemId)
|
||||||
{
|
{
|
||||||
|
if (!HasShipCapabilities(ship.Definition, "ftl"))
|
||||||
|
{
|
||||||
|
ship.State = ShipState.Idle;
|
||||||
|
return "none";
|
||||||
|
}
|
||||||
|
|
||||||
var destinationEntryNode = ResolveSystemEntryNode(world, task.TargetSystemId);
|
var destinationEntryNode = ResolveSystemEntryNode(world, task.TargetSystemId);
|
||||||
var destinationEntryPosition = destinationEntryNode?.Position ?? Vector3.Zero;
|
var destinationEntryPosition = destinationEntryNode?.Position ?? Vector3.Zero;
|
||||||
return UpdateFtlTransit(ship, world, deltaSeconds, task.TargetSystemId, destinationEntryPosition, destinationEntryNode);
|
return UpdateFtlTransit(ship, world, deltaSeconds, task.TargetSystemId, destinationEntryPosition, destinationEntryNode);
|
||||||
@@ -66,6 +71,11 @@ public sealed partial class SimulationEngine
|
|||||||
var currentNode = ResolveCurrentNode(world, ship);
|
var currentNode = ResolveCurrentNode(world, ship);
|
||||||
if (targetNode is not null && currentNode is not null && !string.Equals(currentNode.Id, targetNode.Id, StringComparison.Ordinal))
|
if (targetNode is not null && currentNode is not null && !string.Equals(currentNode.Id, targetNode.Id, StringComparison.Ordinal))
|
||||||
{
|
{
|
||||||
|
if (!HasShipCapabilities(ship.Definition, "warp"))
|
||||||
|
{
|
||||||
|
return UpdateLocalTravel(ship, world, deltaSeconds, task.TargetSystemId, targetPosition, targetNode, task.Threshold);
|
||||||
|
}
|
||||||
|
|
||||||
return UpdateWarpTransit(ship, world, deltaSeconds, targetPosition, targetNode);
|
return UpdateWarpTransit(ship, world, deltaSeconds, targetPosition, targetNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,14 +5,8 @@ namespace SpaceGame.Simulation.Api.Simulation;
|
|||||||
|
|
||||||
public sealed partial class SimulationEngine
|
public sealed partial class SimulationEngine
|
||||||
{
|
{
|
||||||
private static bool HasShipModules(ShipDefinition definition, params string[] modules) =>
|
private static bool HasShipCapabilities(ShipDefinition definition, params string[] capabilities) =>
|
||||||
modules.All(moduleId => definition.Modules.Contains(moduleId, StringComparer.Ordinal));
|
capabilities.All(cap => definition.Capabilities.Contains(cap, StringComparer.Ordinal));
|
||||||
|
|
||||||
private static bool CanTransportWorkers(ShipRuntime ship) =>
|
|
||||||
CountModules(ship.Definition.Modules, "habitat-ring") > 0;
|
|
||||||
|
|
||||||
private static float GetWorkerTransportCapacity(ShipRuntime ship) =>
|
|
||||||
CountModules(ship.Definition.Modules, "habitat-ring") * 120f;
|
|
||||||
|
|
||||||
private static int CountStationModules(StationRuntime station, string moduleId) =>
|
private static int CountStationModules(StationRuntime station, string moduleId) =>
|
||||||
station.Modules.Count(module => string.Equals(module.ModuleId, moduleId, StringComparison.Ordinal));
|
station.Modules.Count(module => string.Equals(module.ModuleId, moduleId, StringComparison.Ordinal));
|
||||||
@@ -56,8 +50,8 @@ public sealed partial class SimulationEngine
|
|||||||
|
|
||||||
var moduleCapacity = storageClass switch
|
var moduleCapacity = storageClass switch
|
||||||
{
|
{
|
||||||
"bulk-solid" => bulkBays * 1000f,
|
"solid" => bulkBays * 1000f,
|
||||||
"bulk-liquid" => liquidTanks * 500f,
|
"liquid" => liquidTanks * 500f,
|
||||||
"container" => containerBays * 800f,
|
"container" => containerBays * 800f,
|
||||||
"manufactured" => containerBays * 200f,
|
"manufactured" => containerBays * 200f,
|
||||||
_ => 0f,
|
_ => 0f,
|
||||||
@@ -102,15 +96,13 @@ public sealed partial class SimulationEngine
|
|||||||
private static bool HasStationModules(StationRuntime station, params string[] modules) =>
|
private static bool HasStationModules(StationRuntime station, params string[] modules) =>
|
||||||
modules.All(moduleId => station.Modules.Any(candidate => string.Equals(candidate.ModuleId, moduleId, StringComparison.Ordinal)));
|
modules.All(moduleId => station.Modules.Any(candidate => string.Equals(candidate.ModuleId, moduleId, StringComparison.Ordinal)));
|
||||||
|
|
||||||
private static bool CanExtractNode(ShipRuntime ship, ResourceNodeRuntime node) =>
|
private static bool CanExtractNode(ShipRuntime ship, ResourceNodeRuntime node, SimulationWorld world) =>
|
||||||
node.ItemId switch
|
HasShipCapabilities(ship.Definition, "mining")
|
||||||
{
|
&& world.ItemDefinitions.TryGetValue(node.ItemId, out var item)
|
||||||
"ore" => HasShipModules(ship.Definition, "mining-turret"),
|
&& string.Equals(item.CargoKind, ship.Definition.CargoKind, StringComparison.Ordinal);
|
||||||
_ => false,
|
|
||||||
};
|
|
||||||
|
|
||||||
private static bool CanBuildClaimBeacon(ShipRuntime ship) =>
|
private static bool CanBuildClaimBeacon(ShipRuntime ship) =>
|
||||||
string.Equals(ship.Definition.Role, "military", StringComparison.Ordinal);
|
string.Equals(ship.Definition.Kind, "military", StringComparison.Ordinal);
|
||||||
|
|
||||||
private static float ComputeWorkforceRatio(float population, float workforceRequired)
|
private static float ComputeWorkforceRatio(float population, float workforceRequired)
|
||||||
{
|
{
|
||||||
@@ -126,8 +118,8 @@ public sealed partial class SimulationEngine
|
|||||||
private static string? GetStorageRequirement(string storageClass) =>
|
private static string? GetStorageRequirement(string storageClass) =>
|
||||||
storageClass switch
|
storageClass switch
|
||||||
{
|
{
|
||||||
"bulk-solid" => "bulk-bay",
|
"solid" => "bulk-bay",
|
||||||
"bulk-liquid" => "liquid-tank",
|
"liquid" => "liquid-tank",
|
||||||
_ => null,
|
_ => null,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -143,8 +143,8 @@ public sealed partial class SimulationEngine
|
|||||||
world.Ships.Select(ship => ToShipDelta(world, ship)).Select(ship => new ShipSnapshot(
|
world.Ships.Select(ship => ToShipDelta(world, ship)).Select(ship => new ShipSnapshot(
|
||||||
ship.Id,
|
ship.Id,
|
||||||
ship.Label,
|
ship.Label,
|
||||||
ship.Role,
|
ship.Kind,
|
||||||
ship.ShipClass,
|
ship.Class,
|
||||||
ship.SystemId,
|
ship.SystemId,
|
||||||
ship.LocalPosition,
|
ship.LocalPosition,
|
||||||
ship.LocalVelocity,
|
ship.LocalVelocity,
|
||||||
@@ -159,8 +159,6 @@ public sealed partial class SimulationEngine
|
|||||||
ship.CommanderId,
|
ship.CommanderId,
|
||||||
ship.PolicySetId,
|
ship.PolicySetId,
|
||||||
ship.CargoCapacity,
|
ship.CargoCapacity,
|
||||||
ship.CargoItemId,
|
|
||||||
ship.WorkerPopulation,
|
|
||||||
ship.TravelSpeed,
|
ship.TravelSpeed,
|
||||||
ship.TravelSpeedUnit,
|
ship.TravelSpeedUnit,
|
||||||
ship.Inventory,
|
ship.Inventory,
|
||||||
@@ -482,7 +480,6 @@ public sealed partial class SimulationEngine
|
|||||||
ship.DockedStationId ?? "none",
|
ship.DockedStationId ?? "none",
|
||||||
ship.CommanderId ?? "none",
|
ship.CommanderId ?? "none",
|
||||||
ship.PolicySetId ?? "none",
|
ship.PolicySetId ?? "none",
|
||||||
ship.WorkerPopulation.ToString("0.###"),
|
|
||||||
ship.SpatialState.SpaceLayer,
|
ship.SpatialState.SpaceLayer,
|
||||||
ship.SpatialState.CurrentNodeId ?? "none",
|
ship.SpatialState.CurrentNodeId ?? "none",
|
||||||
ship.SpatialState.CurrentBubbleId ?? "none",
|
ship.SpatialState.CurrentBubbleId ?? "none",
|
||||||
@@ -586,7 +583,7 @@ public sealed partial class SimulationEngine
|
|||||||
|
|
||||||
private static IReadOnlyList<StationStorageUsageSnapshot> ToStationStorageUsageSnapshots(SimulationWorld world, StationRuntime station)
|
private static IReadOnlyList<StationStorageUsageSnapshot> ToStationStorageUsageSnapshots(SimulationWorld world, StationRuntime station)
|
||||||
{
|
{
|
||||||
string[] storageClasses = ["bulk-solid", "bulk-liquid", "container", "manufactured"];
|
string[] storageClasses = ["solid", "liquid", "container", "manufactured"];
|
||||||
return storageClasses
|
return storageClasses
|
||||||
.Select(storageClass => new StationStorageUsageSnapshot(
|
.Select(storageClass => new StationStorageUsageSnapshot(
|
||||||
storageClass,
|
storageClass,
|
||||||
@@ -666,8 +663,8 @@ public sealed partial class SimulationEngine
|
|||||||
private ShipDelta ToShipDelta(SimulationWorld world, ShipRuntime ship) => new(
|
private ShipDelta ToShipDelta(SimulationWorld world, ShipRuntime ship) => new(
|
||||||
ship.Id,
|
ship.Id,
|
||||||
ship.Definition.Label,
|
ship.Definition.Label,
|
||||||
ship.Definition.Role,
|
ship.Definition.Kind,
|
||||||
ship.Definition.ShipClass,
|
ship.Definition.Class,
|
||||||
ship.SystemId,
|
ship.SystemId,
|
||||||
ToDto(ship.Position),
|
ToDto(ship.Position),
|
||||||
ToDto(ship.Velocity),
|
ToDto(ship.Velocity),
|
||||||
@@ -682,8 +679,7 @@ public sealed partial class SimulationEngine
|
|||||||
ship.CommanderId,
|
ship.CommanderId,
|
||||||
ship.PolicySetId,
|
ship.PolicySetId,
|
||||||
ship.Definition.CargoCapacity,
|
ship.Definition.CargoCapacity,
|
||||||
ship.Definition.CargoItemId,
|
|
||||||
ship.WorkerPopulation,
|
|
||||||
ToShipTravelSpeed(ship).Speed,
|
ToShipTravelSpeed(ship).Speed,
|
||||||
ToShipTravelSpeed(ship).Unit,
|
ToShipTravelSpeed(ship).Unit,
|
||||||
ToInventoryEntries(ship.Inventory),
|
ToInventoryEntries(ship.Inventory),
|
||||||
@@ -705,14 +701,7 @@ public sealed partial class SimulationEngine
|
|||||||
ShipState.Docking => CreateShipActionProgress("Docking", ship.ActionTimer, MathF.Max(world.Balance.DockingDuration, 0.1f)),
|
ShipState.Docking => CreateShipActionProgress("Docking", ship.ActionTimer, MathF.Max(world.Balance.DockingDuration, 0.1f)),
|
||||||
ShipState.Undocking => CreateShipActionProgress("Undocking", ship.ActionTimer, MathF.Max(world.Balance.UndockingDuration, 0.1f)),
|
ShipState.Undocking => CreateShipActionProgress("Undocking", ship.ActionTimer, MathF.Max(world.Balance.UndockingDuration, 0.1f)),
|
||||||
ShipState.Transferring => CreateShipRemainingActionProgress("Transfer", ship.TrackedActionTotal, GetShipCargoAmount(ship)),
|
ShipState.Transferring => CreateShipRemainingActionProgress("Transfer", ship.TrackedActionTotal, GetShipCargoAmount(ship)),
|
||||||
ShipState.Loading => CreateShipRemainingActionProgress(
|
ShipState.Loading or ShipState.Unloading => null,
|
||||||
"Load workers",
|
|
||||||
ship.TrackedActionTotal,
|
|
||||||
MathF.Max(0f, ship.TrackedActionTotal - ship.WorkerPopulation)),
|
|
||||||
ShipState.Unloading => CreateShipRemainingActionProgress(
|
|
||||||
"Unload workers",
|
|
||||||
ship.TrackedActionTotal,
|
|
||||||
ship.WorkerPopulation),
|
|
||||||
ShipState.DeliveringConstruction => ship.ControllerTask.TargetEntityId is null
|
ShipState.DeliveringConstruction => ship.ControllerTask.TargetEntityId is null
|
||||||
? null
|
? null
|
||||||
: world.ConstructionSites.FirstOrDefault(site => site.Id == ship.ControllerTask.TargetEntityId) is not { } site
|
: world.ConstructionSites.FirstOrDefault(site => site.Id == ship.ControllerTask.TargetEntityId) is not { } site
|
||||||
|
|||||||
@@ -106,10 +106,38 @@ public sealed partial class SimulationEngine
|
|||||||
|
|
||||||
private static string? GetNextStationModuleToBuild(StationRuntime station, SimulationWorld world)
|
private static string? GetNextStationModuleToBuild(StationRuntime station, SimulationWorld world)
|
||||||
{
|
{
|
||||||
|
// Expand storage before it becomes a bottleneck
|
||||||
|
const float StorageExpansionThreshold = 0.85f;
|
||||||
|
var storageExpansionCandidates = new[]
|
||||||
|
{
|
||||||
|
("solid", "bulk-bay"),
|
||||||
|
("liquid", "liquid-tank"),
|
||||||
|
("container", "container-bay"),
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (var (storageClass, moduleId) in storageExpansionCandidates)
|
||||||
|
{
|
||||||
|
var capacity = GetStationStorageCapacity(station, storageClass);
|
||||||
|
if (capacity <= 0.01f)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var used = station.Inventory
|
||||||
|
.Where(entry => world.ItemDefinitions.TryGetValue(entry.Key, out var def) && def.CargoKind == storageClass)
|
||||||
|
.Sum(entry => entry.Value);
|
||||||
|
|
||||||
|
if (used / capacity >= StorageExpansionThreshold && world.ModuleRecipes.ContainsKey(moduleId))
|
||||||
|
{
|
||||||
|
return moduleId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var priorities = GetFactionExpansionPressure(world, station.FactionId) > 0f
|
var priorities = GetFactionExpansionPressure(world, station.FactionId) > 0f
|
||||||
? new (string ModuleId, int TargetCount)[]
|
? new (string ModuleId, int TargetCount)[]
|
||||||
{
|
{
|
||||||
("refinery-stack", 1),
|
("refinery-stack", 1),
|
||||||
|
("bulk-bay", 1),
|
||||||
("container-bay", 1),
|
("container-bay", 1),
|
||||||
("fabricator-array", 2),
|
("fabricator-array", 2),
|
||||||
("component-factory", 1),
|
("component-factory", 1),
|
||||||
@@ -120,6 +148,7 @@ public sealed partial class SimulationEngine
|
|||||||
: new (string ModuleId, int TargetCount)[]
|
: new (string ModuleId, int TargetCount)[]
|
||||||
{
|
{
|
||||||
("refinery-stack", 1),
|
("refinery-stack", 1),
|
||||||
|
("bulk-bay", 1),
|
||||||
("container-bay", 1),
|
("container-bay", 1),
|
||||||
("fabricator-array", 2),
|
("fabricator-array", 2),
|
||||||
("component-factory", 1),
|
("component-factory", 1),
|
||||||
|
|||||||
@@ -25,17 +25,14 @@ public sealed partial class SimulationEngine
|
|||||||
ship.TrackedActionTotal = MathF.Max(total, 0.01f);
|
ship.TrackedActionTotal = MathF.Max(total, 0.01f);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static float GetShipCargoAmount(ShipRuntime ship)
|
internal static float GetShipCargoAmount(ShipRuntime ship) =>
|
||||||
{
|
ship.Inventory.Values.Sum();
|
||||||
var cargoItemId = ship.Definition.CargoItemId;
|
|
||||||
return cargoItemId is null ? 0f : GetInventoryAmount(ship.Inventory, cargoItemId);
|
|
||||||
}
|
|
||||||
|
|
||||||
private string UpdateExtract(ShipRuntime ship, SimulationWorld world, float deltaSeconds)
|
private string UpdateExtract(ShipRuntime ship, SimulationWorld world, float deltaSeconds)
|
||||||
{
|
{
|
||||||
var task = ship.ControllerTask;
|
var task = ship.ControllerTask;
|
||||||
var node = world.Nodes.FirstOrDefault(candidate => candidate.Id == task.TargetEntityId);
|
var node = world.Nodes.FirstOrDefault(candidate => candidate.Id == task.TargetEntityId);
|
||||||
if (node is null || task.TargetPosition is null || !CanExtractNode(ship, node))
|
if (node is null || task.TargetPosition is null || !CanExtractNode(ship, node, world))
|
||||||
{
|
{
|
||||||
ship.State = ShipState.Idle;
|
ship.State = ShipState.Idle;
|
||||||
ship.TargetPosition = ship.Position;
|
ship.TargetPosition = ship.Position;
|
||||||
@@ -79,10 +76,7 @@ public sealed partial class SimulationEngine
|
|||||||
return node.OreRemaining <= 0.01f ? "node-depleted" : "cargo-full";
|
return node.OreRemaining <= 0.01f ? "node-depleted" : "cargo-full";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ship.Definition.CargoItemId is not null)
|
AddInventory(ship.Inventory, node.ItemId, mined);
|
||||||
{
|
|
||||||
AddInventory(ship.Inventory, ship.Definition.CargoItemId, mined);
|
|
||||||
}
|
|
||||||
|
|
||||||
node.OreRemaining -= mined;
|
node.OreRemaining -= mined;
|
||||||
node.OreRemaining = MathF.Max(0f, node.OreRemaining);
|
node.OreRemaining = MathF.Max(0f, node.OreRemaining);
|
||||||
@@ -167,23 +161,21 @@ public sealed partial class SimulationEngine
|
|||||||
ship.ActionTimer = 0f;
|
ship.ActionTimer = 0f;
|
||||||
ship.State = ShipState.Transferring;
|
ship.State = ShipState.Transferring;
|
||||||
BeginTrackedAction(ship, "transferring", GetShipCargoAmount(ship));
|
BeginTrackedAction(ship, "transferring", GetShipCargoAmount(ship));
|
||||||
var cargoItemId = ship.Definition.CargoItemId;
|
|
||||||
var moved = cargoItemId is null ? 0f : MathF.Min(GetInventoryAmount(ship.Inventory, cargoItemId), world.Balance.TransferRate * deltaSeconds);
|
|
||||||
if (cargoItemId is not null)
|
|
||||||
{
|
|
||||||
var accepted = TryAddStationInventory(world, station, cargoItemId, moved);
|
|
||||||
RemoveInventory(ship.Inventory, cargoItemId, accepted);
|
|
||||||
moved = accepted;
|
|
||||||
}
|
|
||||||
|
|
||||||
var faction = world.Factions.FirstOrDefault(candidate => candidate.Id == ship.FactionId);
|
var faction = world.Factions.FirstOrDefault(candidate => candidate.Id == ship.FactionId);
|
||||||
if (faction is not null && cargoItemId == "ore")
|
foreach (var (itemId, amount) in ship.Inventory.ToList())
|
||||||
{
|
{
|
||||||
faction.OreMined += moved;
|
var moved = MathF.Min(amount, world.Balance.TransferRate * deltaSeconds);
|
||||||
faction.Credits += moved * 0.4f;
|
var accepted = TryAddStationInventory(world, station, itemId, moved);
|
||||||
|
RemoveInventory(ship.Inventory, itemId, accepted);
|
||||||
|
if (faction is not null && string.Equals(itemId, "ore", StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
faction.OreMined += accepted;
|
||||||
|
faction.Credits += accepted * 0.4f;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return cargoItemId is null || GetInventoryAmount(ship.Inventory, cargoItemId) <= 0.01f ? "unloaded" : "none";
|
return GetShipCargoAmount(ship) <= 0.01f ? "unloaded" : "none";
|
||||||
}
|
}
|
||||||
|
|
||||||
private string UpdateLoadCargo(ShipRuntime ship, SimulationWorld world, float deltaSeconds)
|
private string UpdateLoadCargo(ShipRuntime ship, SimulationWorld world, float deltaSeconds)
|
||||||
@@ -209,19 +201,19 @@ public sealed partial class SimulationEngine
|
|||||||
ship.Position = ship.TargetPosition;
|
ship.Position = ship.TargetPosition;
|
||||||
ship.ActionTimer = 0f;
|
ship.ActionTimer = 0f;
|
||||||
ship.State = ShipState.Loading;
|
ship.State = ShipState.Loading;
|
||||||
|
var itemId = ship.ControllerTask.ItemId;
|
||||||
BeginTrackedAction(ship, "loading", MathF.Max(0f, ship.Definition.CargoCapacity - GetShipCargoAmount(ship)));
|
BeginTrackedAction(ship, "loading", MathF.Max(0f, ship.Definition.CargoCapacity - GetShipCargoAmount(ship)));
|
||||||
var cargoItemId = ship.Definition.CargoItemId;
|
|
||||||
var transfer = MathF.Min(world.Balance.TransferRate * deltaSeconds, ship.Definition.CargoCapacity - GetShipCargoAmount(ship));
|
var transfer = MathF.Min(world.Balance.TransferRate * deltaSeconds, ship.Definition.CargoCapacity - GetShipCargoAmount(ship));
|
||||||
var moved = cargoItemId is null ? 0f : MathF.Min(transfer, GetInventoryAmount(station.Inventory, cargoItemId));
|
var moved = itemId is null ? 0f : MathF.Min(transfer, GetInventoryAmount(station.Inventory, itemId));
|
||||||
if (cargoItemId is not null && moved > 0.01f)
|
if (itemId is not null && moved > 0.01f)
|
||||||
{
|
{
|
||||||
RemoveInventory(station.Inventory, cargoItemId, moved);
|
RemoveInventory(station.Inventory, itemId, moved);
|
||||||
AddInventory(ship.Inventory, cargoItemId, moved);
|
AddInventory(ship.Inventory, itemId, moved);
|
||||||
}
|
}
|
||||||
|
|
||||||
return cargoItemId is null
|
return itemId is null
|
||||||
|| GetShipCargoAmount(ship) >= ship.Definition.CargoCapacity - 0.01f
|
|| GetShipCargoAmount(ship) >= ship.Definition.CargoCapacity - 0.01f
|
||||||
|| GetInventoryAmount(station.Inventory, cargoItemId) <= 0.01f
|
|| GetInventoryAmount(station.Inventory, itemId) <= 0.01f
|
||||||
? "loaded"
|
? "loaded"
|
||||||
: "none";
|
: "none";
|
||||||
}
|
}
|
||||||
@@ -411,65 +403,6 @@ public sealed partial class SimulationEngine
|
|||||||
private static bool IsShipWithinSupportRange(ShipRuntime ship, Vector3 supportPosition, float threshold) =>
|
private static bool IsShipWithinSupportRange(ShipRuntime ship, Vector3 supportPosition, float threshold) =>
|
||||||
ship.Position.DistanceTo(supportPosition) <= MathF.Max(threshold, 6f);
|
ship.Position.DistanceTo(supportPosition) <= MathF.Max(threshold, 6f);
|
||||||
|
|
||||||
private string UpdateLoadWorkers(ShipRuntime ship, SimulationWorld world, float deltaSeconds)
|
|
||||||
{
|
|
||||||
if (ship.DockedStationId is null || !CanTransportWorkers(ship))
|
|
||||||
{
|
|
||||||
ship.State = ShipState.Blocked;
|
|
||||||
return "failed";
|
|
||||||
}
|
|
||||||
|
|
||||||
var station = world.Stations.FirstOrDefault(candidate => candidate.Id == ship.DockedStationId);
|
|
||||||
if (station is null || station.Population <= 0.01f)
|
|
||||||
{
|
|
||||||
ship.State = ShipState.Idle;
|
|
||||||
return "none";
|
|
||||||
}
|
|
||||||
|
|
||||||
var transfer = MathF.Min(station.Population, GetWorkerTransportCapacity(ship) - ship.WorkerPopulation);
|
|
||||||
var totalTransfer = MathF.Min(station.Population, GetWorkerTransportCapacity(ship) - ship.WorkerPopulation);
|
|
||||||
transfer = MathF.Min(transfer, 4f * deltaSeconds);
|
|
||||||
if (transfer <= 0.01f)
|
|
||||||
{
|
|
||||||
return "none";
|
|
||||||
}
|
|
||||||
|
|
||||||
station.Population = MathF.Max(0f, station.Population - transfer);
|
|
||||||
ship.WorkerPopulation += transfer;
|
|
||||||
ship.State = ShipState.Loading;
|
|
||||||
BeginTrackedAction(ship, "loading", totalTransfer);
|
|
||||||
return ship.WorkerPopulation >= GetWorkerTransportCapacity(ship) - 0.01f ? "workers-loaded" : "none";
|
|
||||||
}
|
|
||||||
|
|
||||||
private string UpdateUnloadWorkers(ShipRuntime ship, SimulationWorld world, float deltaSeconds)
|
|
||||||
{
|
|
||||||
if (ship.DockedStationId is null || !CanTransportWorkers(ship))
|
|
||||||
{
|
|
||||||
ship.State = ShipState.Blocked;
|
|
||||||
return "failed";
|
|
||||||
}
|
|
||||||
|
|
||||||
var station = world.Stations.FirstOrDefault(candidate => candidate.Id == ship.DockedStationId);
|
|
||||||
if (station is null || ship.WorkerPopulation <= 0.01f)
|
|
||||||
{
|
|
||||||
ship.State = ShipState.Idle;
|
|
||||||
return "none";
|
|
||||||
}
|
|
||||||
|
|
||||||
var transfer = MathF.Min(ship.WorkerPopulation, MathF.Max(0f, station.PopulationCapacity - station.Population));
|
|
||||||
var totalTransfer = transfer;
|
|
||||||
transfer = MathF.Min(transfer, 4f * deltaSeconds);
|
|
||||||
if (transfer <= 0.01f)
|
|
||||||
{
|
|
||||||
return "none";
|
|
||||||
}
|
|
||||||
|
|
||||||
ship.WorkerPopulation = MathF.Max(0f, ship.WorkerPopulation - transfer);
|
|
||||||
station.Population = MathF.Min(station.PopulationCapacity, station.Population + transfer);
|
|
||||||
ship.State = ShipState.Unloading;
|
|
||||||
BeginTrackedAction(ship, "unloading", totalTransfer);
|
|
||||||
return ship.WorkerPopulation <= 0.01f ? "workers-unloaded" : "none";
|
|
||||||
}
|
|
||||||
|
|
||||||
private string UpdateUndock(ShipRuntime ship, SimulationWorld world, float deltaSeconds)
|
private string UpdateUndock(ShipRuntime ship, SimulationWorld world, float deltaSeconds)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -152,7 +152,7 @@ public sealed partial class SimulationEngine
|
|||||||
.FirstOrDefault()
|
.FirstOrDefault()
|
||||||
: world.Nodes.FirstOrDefault(candidate => candidate.Id == behavior.NodeId && candidate.OreRemaining > 0.01f);
|
: world.Nodes.FirstOrDefault(candidate => candidate.Id == behavior.NodeId && candidate.OreRemaining > 0.01f);
|
||||||
|
|
||||||
if (refinery is null || node is null || !HasShipModules(ship.Definition, "reactor-core", "capacitor-bank", requiredModule))
|
if (refinery is null || node is null || !HasShipCapabilities(ship.Definition, requiredModule))
|
||||||
{
|
{
|
||||||
behavior.Kind = "idle";
|
behavior.Kind = "idle";
|
||||||
ship.ControllerTask = CreateIdleTask(world.Balance.ArrivalThreshold);
|
ship.ControllerTask = CreateIdleTask(world.Balance.ArrivalThreshold);
|
||||||
@@ -505,8 +505,7 @@ public sealed partial class SimulationEngine
|
|||||||
"unload" => ControllerTaskKind.Unload,
|
"unload" => ControllerTaskKind.Unload,
|
||||||
"deliver-construction" => ControllerTaskKind.DeliverConstruction,
|
"deliver-construction" => ControllerTaskKind.DeliverConstruction,
|
||||||
"build-construction-site" => ControllerTaskKind.BuildConstructionSite,
|
"build-construction-site" => ControllerTaskKind.BuildConstructionSite,
|
||||||
"load-workers" => ControllerTaskKind.LoadWorkers,
|
|
||||||
"unload-workers" => ControllerTaskKind.UnloadWorkers,
|
|
||||||
"construct-module" => ControllerTaskKind.ConstructModule,
|
"construct-module" => ControllerTaskKind.ConstructModule,
|
||||||
"undock" => ControllerTaskKind.Undock,
|
"undock" => ControllerTaskKind.Undock,
|
||||||
_ => ControllerTaskKind.Idle,
|
_ => ControllerTaskKind.Idle,
|
||||||
|
|||||||
@@ -235,7 +235,7 @@ public sealed partial class SimulationEngine
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.Equals(shipDefinition.Role, "military", StringComparison.Ordinal)
|
if (!string.Equals(shipDefinition.Kind, "military", StringComparison.Ordinal)
|
||||||
|| !FactionNeedsMoreWarships(world, station.FactionId))
|
|| !FactionNeedsMoreWarships(world, station.FactionId))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@@ -394,7 +394,7 @@ public sealed partial class SimulationEngine
|
|||||||
{
|
{
|
||||||
var militaryShipCount = world.Ships.Count(ship =>
|
var militaryShipCount = world.Ships.Count(ship =>
|
||||||
ship.FactionId == factionId
|
ship.FactionId == factionId
|
||||||
&& string.Equals(ship.Definition.Role, "military", StringComparison.Ordinal));
|
&& string.Equals(ship.Definition.Kind, "military", StringComparison.Ordinal));
|
||||||
var targetSystems = Math.Max(1, Math.Min(StrategicControlTargetSystems, world.Systems.Count));
|
var targetSystems = Math.Max(1, Math.Min(StrategicControlTargetSystems, world.Systems.Count));
|
||||||
var controlledSystems = GetFactionControlledSystemsCount(world, factionId);
|
var controlledSystems = GetFactionControlledSystemsCount(world, factionId);
|
||||||
var expansionDeficit = Math.Max(0, targetSystems - controlledSystems);
|
var expansionDeficit = Math.Max(0, targetSystems - controlledSystems);
|
||||||
@@ -448,7 +448,7 @@ public sealed partial class SimulationEngine
|
|||||||
|
|
||||||
private static DefaultBehaviorRuntime CreateSpawnedShipBehavior(ShipDefinition definition, StationRuntime station)
|
private static DefaultBehaviorRuntime CreateSpawnedShipBehavior(ShipDefinition definition, StationRuntime station)
|
||||||
{
|
{
|
||||||
if (!string.Equals(definition.Role, "military", StringComparison.Ordinal))
|
if (!string.Equals(definition.Kind, "military", StringComparison.Ordinal))
|
||||||
{
|
{
|
||||||
return new DefaultBehaviorRuntime
|
return new DefaultBehaviorRuntime
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ import type { InventoryEntry, Vector3Dto } from "./contractsCommon";
|
|||||||
export interface ShipSnapshot {
|
export interface ShipSnapshot {
|
||||||
id: string;
|
id: string;
|
||||||
label: string;
|
label: string;
|
||||||
role: string;
|
kind: string;
|
||||||
shipClass: string;
|
class: string;
|
||||||
systemId: string;
|
systemId: string;
|
||||||
localPosition: Vector3Dto;
|
localPosition: Vector3Dto;
|
||||||
localVelocity: Vector3Dto;
|
localVelocity: Vector3Dto;
|
||||||
@@ -19,8 +19,7 @@ export interface ShipSnapshot {
|
|||||||
commanderId?: string | null;
|
commanderId?: string | null;
|
||||||
policySetId?: string | null;
|
policySetId?: string | null;
|
||||||
cargoCapacity: number;
|
cargoCapacity: number;
|
||||||
cargoItemId?: string | null;
|
|
||||||
workerPopulation: number;
|
|
||||||
travelSpeed: number;
|
travelSpeed: number;
|
||||||
travelSpeedUnit: string;
|
travelSpeedUnit: string;
|
||||||
inventory: InventoryEntry[];
|
inventory: InventoryEntry[];
|
||||||
|
|||||||
@@ -26,9 +26,7 @@ export function renderFactionStrip(
|
|||||||
|
|
||||||
return ships
|
return ships
|
||||||
.map((ship) => {
|
.map((ship) => {
|
||||||
const cargo = ship.cargoItemId
|
const cargo = ship.inventory.reduce((sum, e) => sum + e.amount, 0);
|
||||||
? inventoryAmount(ship.inventory, ship.cargoItemId)
|
|
||||||
: 0;
|
|
||||||
const shipLocation = describeShipLocation(world, ship);
|
const shipLocation = describeShipLocation(world, ship);
|
||||||
const shipState = describeShipState(world, ship);
|
const shipState = describeShipState(world, ship);
|
||||||
const shipAction = describeShipCurrentAction(ship);
|
const shipAction = describeShipCurrentAction(ship);
|
||||||
@@ -42,7 +40,7 @@ export function renderFactionStrip(
|
|||||||
<div class="ship-card-header">
|
<div class="ship-card-header">
|
||||||
<h3>${ship.label}</h3>
|
<h3>${ship.label}</h3>
|
||||||
<div class="ship-card-meta">
|
<div class="ship-card-meta">
|
||||||
<span class="ship-card-badge">${ship.shipClass}</span>
|
<span class="ship-card-badge">${ship.class}</span>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="ship-card-history-button"
|
class="ship-card-history-button"
|
||||||
|
|||||||
@@ -196,10 +196,7 @@ export function updateDetailPanel(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const parent = describeSelectionParent(selected);
|
const parent = describeSelectionParent(selected);
|
||||||
const cargoUsed = ship.cargoItemId
|
const cargoUsed = ship.inventory.reduce((sum, e) => sum + e.amount, 0);
|
||||||
? inventoryAmount(ship.inventory, ship.cargoItemId)
|
|
||||||
: 0;
|
|
||||||
const cargoLabel = ship.cargoItemId ?? "none";
|
|
||||||
const shipState = describeShipState(world, ship);
|
const shipState = describeShipState(world, ship);
|
||||||
const shipAction = describeShipCurrentAction(ship);
|
const shipAction = describeShipCurrentAction(ship);
|
||||||
detailTitleEl.textContent = ship.label;
|
detailTitleEl.textContent = ship.label;
|
||||||
@@ -217,7 +214,7 @@ export function updateDetailPanel(
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
` : ""}
|
` : ""}
|
||||||
<p>Cargo ${cargoLabel} ${cargoUsed.toFixed(0)} / ${ship.cargoCapacity.toFixed(0)}</p>
|
<p>Cargo ${cargoUsed.toFixed(0)} / ${ship.cargoCapacity.toFixed(0)}</p>
|
||||||
<p>Inventory ${formatInventory(ship.inventory)}</p>
|
<p>Inventory ${formatInventory(ship.inventory)}</p>
|
||||||
<p>Speed ${formatShipSpeed(ship)}</p>
|
<p>Speed ${formatShipSpeed(ship)}</p>
|
||||||
<p>Camera ${cameraMode === "follow" && cameraTargetShipId === ship.id ? "camera-follow" : "tactical"}<br>Press C to toggle follow</p>
|
<p>Camera ${cameraMode === "follow" && cameraTargetShipId === ship.id ? "camera-follow" : "tactical"}<br>Press C to toggle follow</p>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import * as THREE from "three";
|
|||||||
import type { ShipSnapshot } from "./contracts";
|
import type { ShipSnapshot } from "./contracts";
|
||||||
|
|
||||||
export function shipSize(ship: ShipSnapshot) {
|
export function shipSize(ship: ShipSnapshot) {
|
||||||
switch (ship.shipClass) {
|
switch (ship.class) {
|
||||||
case "capital":
|
case "capital":
|
||||||
return 18;
|
return 18;
|
||||||
case "cruiser":
|
case "cruiser":
|
||||||
@@ -20,11 +20,11 @@ export function shipLength(ship: ShipSnapshot) {
|
|||||||
return shipSize(ship) * 2.6;
|
return shipSize(ship) * 2.6;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function shipColor(role: ShipSnapshot["role"]) {
|
export function shipColor(kind: ShipSnapshot["kind"]) {
|
||||||
if (role === "mining") {
|
if (kind === "mining") {
|
||||||
return "#ffcf6e";
|
return "#ffcf6e";
|
||||||
}
|
}
|
||||||
if (role === "transport") {
|
if (kind === "transport") {
|
||||||
return "#9ff0aa";
|
return "#9ff0aa";
|
||||||
}
|
}
|
||||||
return "#8bc0ff";
|
return "#8bc0ff";
|
||||||
@@ -40,7 +40,7 @@ export function shipPresentationColor(ship: ShipSnapshot) {
|
|||||||
if (ship.spatialState.movementRegime === "ftl-transit") {
|
if (ship.spatialState.movementRegime === "ftl-transit") {
|
||||||
return "#ff6ad5";
|
return "#ff6ad5";
|
||||||
}
|
}
|
||||||
return shipColor(ship.role);
|
return shipColor(ship.kind);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function spatialNodeColor(kind: string) {
|
export function spatialNodeColor(kind: string) {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"name": "Raw Ore",
|
"name": "Raw Ore",
|
||||||
"description": "Unprocessed asteroid ore used as the main industrial feedstock.",
|
"description": "Unprocessed asteroid ore used as the main industrial feedstock.",
|
||||||
"type": "resource",
|
"type": "resource",
|
||||||
"cargoKind": "bulk-solid",
|
"cargoKind": "solid",
|
||||||
"volume": 1.2
|
"volume": 1.2
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -12,12 +12,15 @@
|
|||||||
"name": "Water",
|
"name": "Water",
|
||||||
"description": "Life-support and agricultural input.",
|
"description": "Life-support and agricultural input.",
|
||||||
"type": "commodity",
|
"type": "commodity",
|
||||||
"cargoKind": "bulk-liquid",
|
"cargoKind": "liquid",
|
||||||
"volume": 1.0,
|
"volume": 1.0,
|
||||||
"construction": {
|
"construction": {
|
||||||
"recipeId": "water-reclamation",
|
"recipeId": "water-reclamation",
|
||||||
"facilityCategory": "farm",
|
"facilityCategory": "farm",
|
||||||
"requiredModules": ["liquid-tank", "solar-array"],
|
"requiredModules": [
|
||||||
|
"liquid-tank",
|
||||||
|
"solar-array"
|
||||||
|
],
|
||||||
"requirements": [],
|
"requirements": [],
|
||||||
"cycleTime": 6,
|
"cycleTime": 6,
|
||||||
"batchSize": 12,
|
"batchSize": 12,
|
||||||
@@ -36,9 +39,14 @@
|
|||||||
"construction": {
|
"construction": {
|
||||||
"recipeId": "ore-refining",
|
"recipeId": "ore-refining",
|
||||||
"facilityCategory": "station",
|
"facilityCategory": "station",
|
||||||
"requiredModules": ["refinery-stack"],
|
"requiredModules": [
|
||||||
|
"refinery-stack"
|
||||||
|
],
|
||||||
"requirements": [
|
"requirements": [
|
||||||
{ "itemId": "ore", "amount": 60 }
|
{
|
||||||
|
"itemId": "ore",
|
||||||
|
"amount": 60
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"cycleTime": 8,
|
"cycleTime": 8,
|
||||||
"batchSize": 60,
|
"batchSize": 60,
|
||||||
@@ -57,9 +65,14 @@
|
|||||||
"construction": {
|
"construction": {
|
||||||
"recipeId": "hull-fabrication",
|
"recipeId": "hull-fabrication",
|
||||||
"facilityCategory": "station",
|
"facilityCategory": "station",
|
||||||
"requiredModules": ["fabricator-array"],
|
"requiredModules": [
|
||||||
|
"fabricator-array"
|
||||||
|
],
|
||||||
"requirements": [
|
"requirements": [
|
||||||
{ "itemId": "refined-metals", "amount": 70 }
|
{
|
||||||
|
"itemId": "refined-metals",
|
||||||
|
"amount": 70
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"cycleTime": 10,
|
"cycleTime": 10,
|
||||||
"batchSize": 35,
|
"batchSize": 35,
|
||||||
@@ -78,9 +91,14 @@
|
|||||||
"construction": {
|
"construction": {
|
||||||
"recipeId": "ammo-fabrication",
|
"recipeId": "ammo-fabrication",
|
||||||
"facilityCategory": "station",
|
"facilityCategory": "station",
|
||||||
"requiredModules": ["fabricator-array"],
|
"requiredModules": [
|
||||||
|
"fabricator-array"
|
||||||
|
],
|
||||||
"requirements": [
|
"requirements": [
|
||||||
{ "itemId": "refined-metals", "amount": 24 }
|
{
|
||||||
|
"itemId": "refined-metals",
|
||||||
|
"amount": 24
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"cycleTime": 6,
|
"cycleTime": 6,
|
||||||
"batchSize": 30,
|
"batchSize": 30,
|
||||||
@@ -89,27 +107,6 @@
|
|||||||
"priority": 34
|
"priority": 34
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"id": "naval-guns",
|
|
||||||
"name": "Naval Guns",
|
|
||||||
"description": "Shipboard turret and cannon assemblies.",
|
|
||||||
"type": "component",
|
|
||||||
"cargoKind": "manufactured",
|
|
||||||
"volume": 1.4,
|
|
||||||
"construction": {
|
|
||||||
"recipeId": "gun-assembly",
|
|
||||||
"facilityCategory": "station",
|
|
||||||
"requiredModules": ["fabricator-array"],
|
|
||||||
"requirements": [
|
|
||||||
{ "itemId": "refined-metals", "amount": 36 }
|
|
||||||
],
|
|
||||||
"cycleTime": 9,
|
|
||||||
"batchSize": 12,
|
|
||||||
"productsPerHour": 4800,
|
|
||||||
"maxEfficiency": 1,
|
|
||||||
"priority": 32
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"id": "ship-equipment",
|
"id": "ship-equipment",
|
||||||
"name": "Ship Equipment",
|
"name": "Ship Equipment",
|
||||||
@@ -120,10 +117,18 @@
|
|||||||
"construction": {
|
"construction": {
|
||||||
"recipeId": "equipment-assembly",
|
"recipeId": "equipment-assembly",
|
||||||
"facilityCategory": "station",
|
"facilityCategory": "station",
|
||||||
"requiredModules": ["fabricator-array"],
|
"requiredModules": [
|
||||||
|
"fabricator-array"
|
||||||
|
],
|
||||||
"requirements": [
|
"requirements": [
|
||||||
{ "itemId": "refined-metals", "amount": 28 },
|
{
|
||||||
{ "itemId": "water", "amount": 8 }
|
"itemId": "refined-metals",
|
||||||
|
"amount": 28
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"itemId": "water",
|
||||||
|
"amount": 8
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"cycleTime": 11,
|
"cycleTime": 11,
|
||||||
"batchSize": 18,
|
"batchSize": 18,
|
||||||
@@ -142,11 +147,18 @@
|
|||||||
"construction": {
|
"construction": {
|
||||||
"recipeId": "ship-parts-integration",
|
"recipeId": "ship-parts-integration",
|
||||||
"facilityCategory": "station",
|
"facilityCategory": "station",
|
||||||
"requiredModules": ["fabricator-array"],
|
"requiredModules": [
|
||||||
|
"fabricator-array"
|
||||||
|
],
|
||||||
"requirements": [
|
"requirements": [
|
||||||
{ "itemId": "hull-sections", "amount": 24 },
|
{
|
||||||
{ "itemId": "naval-guns", "amount": 6 },
|
"itemId": "hull-sections",
|
||||||
{ "itemId": "ship-equipment", "amount": 10 }
|
"amount": 24
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"itemId": "ship-equipment",
|
||||||
|
"amount": 10
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"cycleTime": 14,
|
"cycleTime": 14,
|
||||||
"batchSize": 20,
|
"batchSize": 20,
|
||||||
@@ -165,10 +177,18 @@
|
|||||||
"construction": {
|
"construction": {
|
||||||
"recipeId": "drone-parts-assembly",
|
"recipeId": "drone-parts-assembly",
|
||||||
"facilityCategory": "station",
|
"facilityCategory": "station",
|
||||||
"requiredModules": ["fabricator-array"],
|
"requiredModules": [
|
||||||
|
"fabricator-array"
|
||||||
|
],
|
||||||
"requirements": [
|
"requirements": [
|
||||||
{ "itemId": "refined-metals", "amount": 12 },
|
{
|
||||||
{ "itemId": "ship-equipment", "amount": 6 }
|
"itemId": "refined-metals",
|
||||||
|
"amount": 12
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"itemId": "ship-equipment",
|
||||||
|
"amount": 6
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"cycleTime": 7,
|
"cycleTime": 7,
|
||||||
"batchSize": 16,
|
"batchSize": 16,
|
||||||
@@ -187,10 +207,19 @@
|
|||||||
"construction": {
|
"construction": {
|
||||||
"recipeId": "command-bridge-module-assembly",
|
"recipeId": "command-bridge-module-assembly",
|
||||||
"facilityCategory": "station",
|
"facilityCategory": "station",
|
||||||
"requiredModules": ["component-factory", "container-bay"],
|
"requiredModules": [
|
||||||
|
"component-factory",
|
||||||
|
"container-bay"
|
||||||
|
],
|
||||||
"requirements": [
|
"requirements": [
|
||||||
{ "itemId": "refined-metals", "amount": 20 },
|
{
|
||||||
{ "itemId": "ship-equipment", "amount": 10 }
|
"itemId": "refined-metals",
|
||||||
|
"amount": 20
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"itemId": "ship-equipment",
|
||||||
|
"amount": 10
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"cycleTime": 9,
|
"cycleTime": 9,
|
||||||
"batchSize": 1,
|
"batchSize": 1,
|
||||||
@@ -209,10 +238,19 @@
|
|||||||
"construction": {
|
"construction": {
|
||||||
"recipeId": "reactor-core-module-assembly",
|
"recipeId": "reactor-core-module-assembly",
|
||||||
"facilityCategory": "station",
|
"facilityCategory": "station",
|
||||||
"requiredModules": ["component-factory", "container-bay"],
|
"requiredModules": [
|
||||||
|
"component-factory",
|
||||||
|
"container-bay"
|
||||||
|
],
|
||||||
"requirements": [
|
"requirements": [
|
||||||
{ "itemId": "refined-metals", "amount": 30 },
|
{
|
||||||
{ "itemId": "ship-equipment", "amount": 8 }
|
"itemId": "refined-metals",
|
||||||
|
"amount": 30
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"itemId": "ship-equipment",
|
||||||
|
"amount": 8
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"cycleTime": 10,
|
"cycleTime": 10,
|
||||||
"batchSize": 1,
|
"batchSize": 1,
|
||||||
@@ -231,10 +269,19 @@
|
|||||||
"construction": {
|
"construction": {
|
||||||
"recipeId": "capacitor-bank-module-assembly",
|
"recipeId": "capacitor-bank-module-assembly",
|
||||||
"facilityCategory": "station",
|
"facilityCategory": "station",
|
||||||
"requiredModules": ["component-factory", "container-bay"],
|
"requiredModules": [
|
||||||
|
"component-factory",
|
||||||
|
"container-bay"
|
||||||
|
],
|
||||||
"requirements": [
|
"requirements": [
|
||||||
{ "itemId": "refined-metals", "amount": 18 },
|
{
|
||||||
{ "itemId": "ship-equipment", "amount": 4 }
|
"itemId": "refined-metals",
|
||||||
|
"amount": 18
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"itemId": "ship-equipment",
|
||||||
|
"amount": 4
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"cycleTime": 9,
|
"cycleTime": 9,
|
||||||
"batchSize": 1,
|
"batchSize": 1,
|
||||||
@@ -253,10 +300,19 @@
|
|||||||
"construction": {
|
"construction": {
|
||||||
"recipeId": "ion-drive-module-assembly",
|
"recipeId": "ion-drive-module-assembly",
|
||||||
"facilityCategory": "station",
|
"facilityCategory": "station",
|
||||||
"requiredModules": ["component-factory", "container-bay"],
|
"requiredModules": [
|
||||||
|
"component-factory",
|
||||||
|
"container-bay"
|
||||||
|
],
|
||||||
"requirements": [
|
"requirements": [
|
||||||
{ "itemId": "refined-metals", "amount": 22 },
|
{
|
||||||
{ "itemId": "ship-equipment", "amount": 8 }
|
"itemId": "refined-metals",
|
||||||
|
"amount": 22
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"itemId": "ship-equipment",
|
||||||
|
"amount": 8
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"cycleTime": 10,
|
"cycleTime": 10,
|
||||||
"batchSize": 1,
|
"batchSize": 1,
|
||||||
@@ -275,10 +331,19 @@
|
|||||||
"construction": {
|
"construction": {
|
||||||
"recipeId": "ftl-core-module-assembly",
|
"recipeId": "ftl-core-module-assembly",
|
||||||
"facilityCategory": "station",
|
"facilityCategory": "station",
|
||||||
"requiredModules": ["component-factory", "container-bay"],
|
"requiredModules": [
|
||||||
|
"component-factory",
|
||||||
|
"container-bay"
|
||||||
|
],
|
||||||
"requirements": [
|
"requirements": [
|
||||||
{ "itemId": "refined-metals", "amount": 34 },
|
{
|
||||||
{ "itemId": "ship-equipment", "amount": 14 }
|
"itemId": "refined-metals",
|
||||||
|
"amount": 34
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"itemId": "ship-equipment",
|
||||||
|
"amount": 14
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"cycleTime": 12,
|
"cycleTime": 12,
|
||||||
"batchSize": 1,
|
"batchSize": 1,
|
||||||
@@ -297,10 +362,15 @@
|
|||||||
"construction": {
|
"construction": {
|
||||||
"recipeId": "gun-turret-module-assembly",
|
"recipeId": "gun-turret-module-assembly",
|
||||||
"facilityCategory": "station",
|
"facilityCategory": "station",
|
||||||
"requiredModules": ["component-factory", "container-bay"],
|
"requiredModules": [
|
||||||
|
"component-factory",
|
||||||
|
"container-bay"
|
||||||
|
],
|
||||||
"requirements": [
|
"requirements": [
|
||||||
{ "itemId": "naval-guns", "amount": 8 },
|
{
|
||||||
{ "itemId": "refined-metals", "amount": 12 }
|
"itemId": "refined-metals",
|
||||||
|
"amount": 12
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"cycleTime": 8,
|
"cycleTime": 8,
|
||||||
"batchSize": 1,
|
"batchSize": 1,
|
||||||
@@ -319,11 +389,23 @@
|
|||||||
"construction": {
|
"construction": {
|
||||||
"recipeId": "carrier-bay-module-assembly",
|
"recipeId": "carrier-bay-module-assembly",
|
||||||
"facilityCategory": "station",
|
"facilityCategory": "station",
|
||||||
"requiredModules": ["component-factory", "container-bay"],
|
"requiredModules": [
|
||||||
|
"component-factory",
|
||||||
|
"container-bay"
|
||||||
|
],
|
||||||
"requirements": [
|
"requirements": [
|
||||||
{ "itemId": "hull-sections", "amount": 18 },
|
{
|
||||||
{ "itemId": "refined-metals", "amount": 18 },
|
"itemId": "hull-sections",
|
||||||
{ "itemId": "ship-equipment", "amount": 10 }
|
"amount": 18
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"itemId": "refined-metals",
|
||||||
|
"amount": 18
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"itemId": "ship-equipment",
|
||||||
|
"amount": 10
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"cycleTime": 14,
|
"cycleTime": 14,
|
||||||
"batchSize": 1,
|
"batchSize": 1,
|
||||||
@@ -342,11 +424,23 @@
|
|||||||
"construction": {
|
"construction": {
|
||||||
"recipeId": "habitat-ring-module-assembly",
|
"recipeId": "habitat-ring-module-assembly",
|
||||||
"facilityCategory": "station",
|
"facilityCategory": "station",
|
||||||
"requiredModules": ["component-factory", "container-bay"],
|
"requiredModules": [
|
||||||
|
"component-factory",
|
||||||
|
"container-bay"
|
||||||
|
],
|
||||||
"requirements": [
|
"requirements": [
|
||||||
{ "itemId": "hull-sections", "amount": 14 },
|
{
|
||||||
{ "itemId": "ship-equipment", "amount": 8 },
|
"itemId": "hull-sections",
|
||||||
{ "itemId": "water", "amount": 10 }
|
"amount": 14
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"itemId": "ship-equipment",
|
||||||
|
"amount": 8
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"itemId": "water",
|
||||||
|
"amount": 10
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"cycleTime": 12,
|
"cycleTime": 12,
|
||||||
"batchSize": 1,
|
"batchSize": 1,
|
||||||
@@ -365,10 +459,19 @@
|
|||||||
"construction": {
|
"construction": {
|
||||||
"recipeId": "bulk-bay-module-assembly",
|
"recipeId": "bulk-bay-module-assembly",
|
||||||
"facilityCategory": "station",
|
"facilityCategory": "station",
|
||||||
"requiredModules": ["component-factory", "container-bay"],
|
"requiredModules": [
|
||||||
|
"component-factory",
|
||||||
|
"container-bay"
|
||||||
|
],
|
||||||
"requirements": [
|
"requirements": [
|
||||||
{ "itemId": "refined-metals", "amount": 16 },
|
{
|
||||||
{ "itemId": "hull-sections", "amount": 10 }
|
"itemId": "refined-metals",
|
||||||
|
"amount": 16
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"itemId": "hull-sections",
|
||||||
|
"amount": 10
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"cycleTime": 8,
|
"cycleTime": 8,
|
||||||
"batchSize": 1,
|
"batchSize": 1,
|
||||||
@@ -387,10 +490,19 @@
|
|||||||
"construction": {
|
"construction": {
|
||||||
"recipeId": "container-bay-module-assembly",
|
"recipeId": "container-bay-module-assembly",
|
||||||
"facilityCategory": "station",
|
"facilityCategory": "station",
|
||||||
"requiredModules": ["component-factory", "container-bay"],
|
"requiredModules": [
|
||||||
|
"component-factory",
|
||||||
|
"container-bay"
|
||||||
|
],
|
||||||
"requirements": [
|
"requirements": [
|
||||||
{ "itemId": "refined-metals", "amount": 12 },
|
{
|
||||||
{ "itemId": "ship-equipment", "amount": 4 }
|
"itemId": "refined-metals",
|
||||||
|
"amount": 12
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"itemId": "ship-equipment",
|
||||||
|
"amount": 4
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"cycleTime": 8,
|
"cycleTime": 8,
|
||||||
"batchSize": 1,
|
"batchSize": 1,
|
||||||
@@ -409,10 +521,19 @@
|
|||||||
"construction": {
|
"construction": {
|
||||||
"recipeId": "liquid-tank-module-assembly",
|
"recipeId": "liquid-tank-module-assembly",
|
||||||
"facilityCategory": "station",
|
"facilityCategory": "station",
|
||||||
"requiredModules": ["component-factory", "container-bay"],
|
"requiredModules": [
|
||||||
|
"component-factory",
|
||||||
|
"container-bay"
|
||||||
|
],
|
||||||
"requirements": [
|
"requirements": [
|
||||||
{ "itemId": "refined-metals", "amount": 14 },
|
{
|
||||||
{ "itemId": "ship-equipment", "amount": 4 }
|
"itemId": "refined-metals",
|
||||||
|
"amount": 14
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"itemId": "ship-equipment",
|
||||||
|
"amount": 4
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"cycleTime": 8,
|
"cycleTime": 8,
|
||||||
"batchSize": 1,
|
"batchSize": 1,
|
||||||
@@ -431,10 +552,19 @@
|
|||||||
"construction": {
|
"construction": {
|
||||||
"recipeId": "mining-turret-module-assembly",
|
"recipeId": "mining-turret-module-assembly",
|
||||||
"facilityCategory": "station",
|
"facilityCategory": "station",
|
||||||
"requiredModules": ["component-factory", "container-bay"],
|
"requiredModules": [
|
||||||
|
"component-factory",
|
||||||
|
"container-bay"
|
||||||
|
],
|
||||||
"requirements": [
|
"requirements": [
|
||||||
{ "itemId": "refined-metals", "amount": 18 },
|
{
|
||||||
{ "itemId": "ship-equipment", "amount": 6 }
|
"itemId": "refined-metals",
|
||||||
|
"amount": 18
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"itemId": "ship-equipment",
|
||||||
|
"amount": 6
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"cycleTime": 9,
|
"cycleTime": 9,
|
||||||
"batchSize": 1,
|
"batchSize": 1,
|
||||||
@@ -453,10 +583,19 @@
|
|||||||
"construction": {
|
"construction": {
|
||||||
"recipeId": "fabricator-array-module-assembly",
|
"recipeId": "fabricator-array-module-assembly",
|
||||||
"facilityCategory": "station",
|
"facilityCategory": "station",
|
||||||
"requiredModules": ["component-factory", "container-bay"],
|
"requiredModules": [
|
||||||
|
"component-factory",
|
||||||
|
"container-bay"
|
||||||
|
],
|
||||||
"requirements": [
|
"requirements": [
|
||||||
{ "itemId": "refined-metals", "amount": 24 },
|
{
|
||||||
{ "itemId": "ship-equipment", "amount": 10 }
|
"itemId": "refined-metals",
|
||||||
|
"amount": 24
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"itemId": "ship-equipment",
|
||||||
|
"amount": 10
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"cycleTime": 11,
|
"cycleTime": 11,
|
||||||
"batchSize": 1,
|
"batchSize": 1,
|
||||||
@@ -464,167 +603,5 @@
|
|||||||
"maxEfficiency": 1,
|
"maxEfficiency": 1,
|
||||||
"priority": 20
|
"priority": 20
|
||||||
}
|
}
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "trade-hub-kit",
|
|
||||||
"name": "Trade Hub Kit",
|
|
||||||
"description": "Deployable prefab package for a trade hub station.",
|
|
||||||
"type": "kit",
|
|
||||||
"cargoKind": "manufactured",
|
|
||||||
"volume": 6.0,
|
|
||||||
"construction": {
|
|
||||||
"recipeId": "trade-hub-assembly",
|
|
||||||
"facilityCategory": "station",
|
|
||||||
"requiredModules": ["fabricator-array"],
|
|
||||||
"requirements": [
|
|
||||||
{ "itemId": "ship-parts", "amount": 26 },
|
|
||||||
{ "itemId": "ship-equipment", "amount": 16 },
|
|
||||||
{ "itemId": "drone-parts", "amount": 10 }
|
|
||||||
],
|
|
||||||
"cycleTime": 18,
|
|
||||||
"batchSize": 1,
|
|
||||||
"productsPerHour": 200,
|
|
||||||
"maxEfficiency": 1,
|
|
||||||
"priority": 24
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "refinery-kit",
|
|
||||||
"name": "Refinery Kit",
|
|
||||||
"description": "Deployable prefab package for a refining station.",
|
|
||||||
"type": "kit",
|
|
||||||
"cargoKind": "manufactured",
|
|
||||||
"volume": 6.5,
|
|
||||||
"construction": {
|
|
||||||
"recipeId": "refinery-assembly",
|
|
||||||
"facilityCategory": "station",
|
|
||||||
"requiredModules": ["fabricator-array"],
|
|
||||||
"requirements": [
|
|
||||||
{ "itemId": "ship-parts", "amount": 32 },
|
|
||||||
{ "itemId": "hull-sections", "amount": 24 },
|
|
||||||
{ "itemId": "ship-equipment", "amount": 14 }
|
|
||||||
],
|
|
||||||
"cycleTime": 20,
|
|
||||||
"batchSize": 1,
|
|
||||||
"productsPerHour": 180,
|
|
||||||
"maxEfficiency": 1,
|
|
||||||
"priority": 26
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "farm-ring-kit",
|
|
||||||
"name": "Farm Ring Kit",
|
|
||||||
"description": "Deployable prefab package for a farm station.",
|
|
||||||
"type": "kit",
|
|
||||||
"cargoKind": "manufactured",
|
|
||||||
"volume": 6.0,
|
|
||||||
"construction": {
|
|
||||||
"recipeId": "farm-ring-assembly",
|
|
||||||
"facilityCategory": "station",
|
|
||||||
"requiredModules": ["fabricator-array"],
|
|
||||||
"requirements": [
|
|
||||||
{ "itemId": "ship-parts", "amount": 22 },
|
|
||||||
{ "itemId": "ship-equipment", "amount": 18 },
|
|
||||||
{ "itemId": "water", "amount": 22 }
|
|
||||||
],
|
|
||||||
"cycleTime": 18,
|
|
||||||
"batchSize": 1,
|
|
||||||
"productsPerHour": 200,
|
|
||||||
"maxEfficiency": 1,
|
|
||||||
"priority": 22
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "manufactory-kit",
|
|
||||||
"name": "Manufactory Kit",
|
|
||||||
"description": "Deployable prefab package for an orbital manufactory.",
|
|
||||||
"type": "kit",
|
|
||||||
"cargoKind": "manufactured",
|
|
||||||
"volume": 7.0,
|
|
||||||
"construction": {
|
|
||||||
"recipeId": "manufactory-assembly",
|
|
||||||
"facilityCategory": "station",
|
|
||||||
"requiredModules": ["fabricator-array"],
|
|
||||||
"requirements": [
|
|
||||||
{ "itemId": "ship-parts", "amount": 34 },
|
|
||||||
{ "itemId": "hull-sections", "amount": 16 },
|
|
||||||
{ "itemId": "ship-equipment", "amount": 18 }
|
|
||||||
],
|
|
||||||
"cycleTime": 22,
|
|
||||||
"batchSize": 1,
|
|
||||||
"productsPerHour": 163.6,
|
|
||||||
"maxEfficiency": 1,
|
|
||||||
"priority": 28
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "shipyard-kit",
|
|
||||||
"name": "Shipyard Kit",
|
|
||||||
"description": "Deployable prefab package for an orbital shipyard.",
|
|
||||||
"type": "kit",
|
|
||||||
"cargoKind": "manufactured",
|
|
||||||
"volume": 8.0,
|
|
||||||
"construction": {
|
|
||||||
"recipeId": "shipyard-assembly",
|
|
||||||
"facilityCategory": "station",
|
|
||||||
"requiredModules": ["fabricator-array"],
|
|
||||||
"requirements": [
|
|
||||||
{ "itemId": "ship-parts", "amount": 42 },
|
|
||||||
{ "itemId": "hull-sections", "amount": 30 },
|
|
||||||
{ "itemId": "naval-guns", "amount": 10 }
|
|
||||||
],
|
|
||||||
"cycleTime": 26,
|
|
||||||
"batchSize": 1,
|
|
||||||
"productsPerHour": 138.5,
|
|
||||||
"maxEfficiency": 1,
|
|
||||||
"priority": 30
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "defense-grid-kit",
|
|
||||||
"name": "Defense Grid Kit",
|
|
||||||
"description": "Deployable prefab package for a defense platform.",
|
|
||||||
"type": "kit",
|
|
||||||
"cargoKind": "manufactured",
|
|
||||||
"volume": 7.0,
|
|
||||||
"construction": {
|
|
||||||
"recipeId": "defense-grid-assembly",
|
|
||||||
"facilityCategory": "station",
|
|
||||||
"requiredModules": ["fabricator-array"],
|
|
||||||
"requirements": [
|
|
||||||
{ "itemId": "ship-parts", "amount": 18 },
|
|
||||||
{ "itemId": "naval-guns", "amount": 12 },
|
|
||||||
{ "itemId": "ammo-crates", "amount": 18 }
|
|
||||||
],
|
|
||||||
"cycleTime": 16,
|
|
||||||
"batchSize": 1,
|
|
||||||
"productsPerHour": 225,
|
|
||||||
"maxEfficiency": 1,
|
|
||||||
"priority": 20
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "stargate-kit",
|
|
||||||
"name": "Stargate Kit",
|
|
||||||
"description": "Deployable prefab package for a stargate structure.",
|
|
||||||
"type": "kit",
|
|
||||||
"cargoKind": "manufactured",
|
|
||||||
"volume": 10.0,
|
|
||||||
"construction": {
|
|
||||||
"recipeId": "stargate-assembly",
|
|
||||||
"facilityCategory": "station",
|
|
||||||
"requiredModules": ["fabricator-array"],
|
|
||||||
"requirements": [
|
|
||||||
{ "itemId": "ship-parts", "amount": 60 },
|
|
||||||
{ "itemId": "hull-sections", "amount": 44 },
|
|
||||||
{ "itemId": "ship-equipment", "amount": 26 },
|
|
||||||
{ "itemId": "naval-guns", "amount": 8 }
|
|
||||||
],
|
|
||||||
"cycleTime": 34,
|
|
||||||
"batchSize": 1,
|
|
||||||
"productsPerHour": 105.9,
|
|
||||||
"maxEfficiency": 1,
|
|
||||||
"priority": 36
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
{
|
{
|
||||||
"id": "frigate",
|
"id": "frigate",
|
||||||
"label": "Vanguard Frigate",
|
"label": "Vanguard Frigate",
|
||||||
"role": "military",
|
"kind": "military",
|
||||||
"shipClass": "frigate",
|
"class": "frigate",
|
||||||
"speed": 120000,
|
"speed": 120000,
|
||||||
"warpSpeed": 0.22,
|
"warpSpeed": 0.22,
|
||||||
"ftlSpeed": 0.75,
|
"ftlSpeed": 0.75,
|
||||||
@@ -13,13 +13,9 @@
|
|||||||
"hullColor": "#1f4f78",
|
"hullColor": "#1f4f78",
|
||||||
"size": 4,
|
"size": 4,
|
||||||
"maxHealth": 100,
|
"maxHealth": 100,
|
||||||
"modules": [
|
"capabilities": [
|
||||||
"command-bridge",
|
"warp",
|
||||||
"reactor-core",
|
"ftl"
|
||||||
"capacitor-bank",
|
|
||||||
"ion-drive",
|
|
||||||
"ftl-core",
|
|
||||||
"gun-turret"
|
|
||||||
],
|
],
|
||||||
"construction": {
|
"construction": {
|
||||||
"recipeId": "frigate-construction",
|
"recipeId": "frigate-construction",
|
||||||
@@ -69,8 +65,8 @@
|
|||||||
{
|
{
|
||||||
"id": "destroyer",
|
"id": "destroyer",
|
||||||
"label": "Bulwark Destroyer",
|
"label": "Bulwark Destroyer",
|
||||||
"role": "military",
|
"kind": "military",
|
||||||
"shipClass": "destroyer",
|
"class": "destroyer",
|
||||||
"speed": 95000,
|
"speed": 95000,
|
||||||
"warpSpeed": 0.18,
|
"warpSpeed": 0.18,
|
||||||
"ftlSpeed": 0.68,
|
"ftlSpeed": 0.68,
|
||||||
@@ -80,14 +76,9 @@
|
|||||||
"hullColor": "#6a2e26",
|
"hullColor": "#6a2e26",
|
||||||
"size": 7,
|
"size": 7,
|
||||||
"maxHealth": 240,
|
"maxHealth": 240,
|
||||||
"modules": [
|
"capabilities": [
|
||||||
"command-bridge",
|
"warp",
|
||||||
"reactor-core",
|
"ftl"
|
||||||
"capacitor-bank",
|
|
||||||
"ion-drive",
|
|
||||||
"ftl-core",
|
|
||||||
"gun-turret",
|
|
||||||
"gun-turret"
|
|
||||||
],
|
],
|
||||||
"construction": {
|
"construction": {
|
||||||
"recipeId": "destroyer-construction",
|
"recipeId": "destroyer-construction",
|
||||||
@@ -137,8 +128,8 @@
|
|||||||
{
|
{
|
||||||
"id": "cruiser",
|
"id": "cruiser",
|
||||||
"label": "Aegis Cruiser",
|
"label": "Aegis Cruiser",
|
||||||
"role": "military",
|
"kind": "military",
|
||||||
"shipClass": "cruiser",
|
"class": "cruiser",
|
||||||
"speed": 85000,
|
"speed": 85000,
|
||||||
"warpSpeed": 0.16,
|
"warpSpeed": 0.16,
|
||||||
"ftlSpeed": 0.62,
|
"ftlSpeed": 0.62,
|
||||||
@@ -148,14 +139,9 @@
|
|||||||
"hullColor": "#314562",
|
"hullColor": "#314562",
|
||||||
"size": 10,
|
"size": 10,
|
||||||
"maxHealth": 340,
|
"maxHealth": 340,
|
||||||
"modules": [
|
"capabilities": [
|
||||||
"command-bridge",
|
"warp",
|
||||||
"reactor-core",
|
"ftl"
|
||||||
"capacitor-bank",
|
|
||||||
"ion-drive",
|
|
||||||
"ftl-core",
|
|
||||||
"gun-turret",
|
|
||||||
"gun-turret"
|
|
||||||
],
|
],
|
||||||
"construction": {
|
"construction": {
|
||||||
"recipeId": "cruiser-construction",
|
"recipeId": "cruiser-construction",
|
||||||
@@ -205,8 +191,8 @@
|
|||||||
{
|
{
|
||||||
"id": "carrier",
|
"id": "carrier",
|
||||||
"label": "Citadel Carrier",
|
"label": "Citadel Carrier",
|
||||||
"role": "military",
|
"kind": "military",
|
||||||
"shipClass": "capital",
|
"class": "capital",
|
||||||
"speed": 60000,
|
"speed": 60000,
|
||||||
"warpSpeed": 0.12,
|
"warpSpeed": 0.12,
|
||||||
"ftlSpeed": 0.5,
|
"ftlSpeed": 0.5,
|
||||||
@@ -216,16 +202,9 @@
|
|||||||
"hullColor": "#35586d",
|
"hullColor": "#35586d",
|
||||||
"size": 16,
|
"size": 16,
|
||||||
"maxHealth": 900,
|
"maxHealth": 900,
|
||||||
"modules": [
|
"capabilities": [
|
||||||
"command-bridge",
|
"warp",
|
||||||
"reactor-core",
|
"ftl"
|
||||||
"capacitor-bank",
|
|
||||||
"ion-drive",
|
|
||||||
"ftl-core",
|
|
||||||
"carrier-bay",
|
|
||||||
"carrier-bay",
|
|
||||||
"gun-turret",
|
|
||||||
"habitat-ring"
|
|
||||||
],
|
],
|
||||||
"dockingCapacity": 6,
|
"dockingCapacity": 6,
|
||||||
"dockingClasses": [
|
"dockingClasses": [
|
||||||
@@ -274,10 +253,6 @@
|
|||||||
{
|
{
|
||||||
"itemId": "gun-turret-module",
|
"itemId": "gun-turret-module",
|
||||||
"amount": 1
|
"amount": 1
|
||||||
},
|
|
||||||
{
|
|
||||||
"itemId": "habitat-ring-module",
|
|
||||||
"amount": 1
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"cycleTime": 60,
|
"cycleTime": 60,
|
||||||
@@ -289,8 +264,8 @@
|
|||||||
{
|
{
|
||||||
"id": "hauler",
|
"id": "hauler",
|
||||||
"label": "Atlas Hauler",
|
"label": "Atlas Hauler",
|
||||||
"role": "transport",
|
"kind": "transport",
|
||||||
"shipClass": "industrial",
|
"class": "industrial",
|
||||||
"speed": 70000,
|
"speed": 70000,
|
||||||
"warpSpeed": 0.14,
|
"warpSpeed": 0.14,
|
||||||
"ftlSpeed": 0.55,
|
"ftlSpeed": 0.55,
|
||||||
@@ -301,13 +276,9 @@
|
|||||||
"hullColor": "#365f2a",
|
"hullColor": "#365f2a",
|
||||||
"size": 8,
|
"size": 8,
|
||||||
"maxHealth": 180,
|
"maxHealth": 180,
|
||||||
"modules": [
|
"capabilities": [
|
||||||
"command-bridge",
|
"warp",
|
||||||
"reactor-core",
|
"ftl"
|
||||||
"capacitor-bank",
|
|
||||||
"ion-drive",
|
|
||||||
"ftl-core",
|
|
||||||
"container-bay"
|
|
||||||
],
|
],
|
||||||
"construction": {
|
"construction": {
|
||||||
"recipeId": "hauler-construction",
|
"recipeId": "hauler-construction",
|
||||||
@@ -357,27 +328,21 @@
|
|||||||
{
|
{
|
||||||
"id": "constructor",
|
"id": "constructor",
|
||||||
"label": "Pioneer Constructor",
|
"label": "Pioneer Constructor",
|
||||||
"role": "construction",
|
"kind": "construction",
|
||||||
"shipClass": "industrial",
|
"class": "industrial",
|
||||||
"speed": 65000,
|
"speed": 65000,
|
||||||
"warpSpeed": 0.13,
|
"warpSpeed": 0.13,
|
||||||
"ftlSpeed": 0.48,
|
"ftlSpeed": 0.48,
|
||||||
"spoolTime": 3.5,
|
"spoolTime": 3.5,
|
||||||
"cargoCapacity": 160,
|
"cargoCapacity": 160,
|
||||||
"cargoKind": "manufactured",
|
"cargoKind": "manufactured",
|
||||||
"cargoItemId": "drone-parts",
|
|
||||||
"color": "#9af0c1",
|
"color": "#9af0c1",
|
||||||
"hullColor": "#2d5d47",
|
"hullColor": "#2d5d47",
|
||||||
"size": 9,
|
"size": 9,
|
||||||
"maxHealth": 220,
|
"maxHealth": 220,
|
||||||
"modules": [
|
"capabilities": [
|
||||||
"command-bridge",
|
"warp",
|
||||||
"reactor-core",
|
"ftl"
|
||||||
"capacitor-bank",
|
|
||||||
"ion-drive",
|
|
||||||
"ftl-core",
|
|
||||||
"fabricator-array",
|
|
||||||
"container-bay"
|
|
||||||
],
|
],
|
||||||
"construction": {
|
"construction": {
|
||||||
"recipeId": "constructor-construction",
|
"recipeId": "constructor-construction",
|
||||||
@@ -431,27 +396,22 @@
|
|||||||
{
|
{
|
||||||
"id": "miner",
|
"id": "miner",
|
||||||
"label": "Prospector Miner",
|
"label": "Prospector Miner",
|
||||||
"role": "mining",
|
"kind": "mining",
|
||||||
"shipClass": "industrial",
|
"class": "industrial",
|
||||||
"speed": 75000,
|
"speed": 75000,
|
||||||
"warpSpeed": 0.15,
|
"warpSpeed": 0.15,
|
||||||
"ftlSpeed": 0.5,
|
"ftlSpeed": 0.5,
|
||||||
"spoolTime": 3.1,
|
"spoolTime": 3.1,
|
||||||
"cargoCapacity": 120,
|
"cargoCapacity": 120,
|
||||||
"cargoKind": "bulk-solid",
|
"cargoKind": "solid",
|
||||||
"cargoItemId": "ore",
|
|
||||||
"color": "#ffdd75",
|
"color": "#ffdd75",
|
||||||
"hullColor": "#68552b",
|
"hullColor": "#68552b",
|
||||||
"size": 6,
|
"size": 6,
|
||||||
"maxHealth": 150,
|
"maxHealth": 150,
|
||||||
"modules": [
|
"capabilities": [
|
||||||
"command-bridge",
|
"warp",
|
||||||
"reactor-core",
|
"ftl",
|
||||||
"capacitor-bank",
|
"mining"
|
||||||
"ion-drive",
|
|
||||||
"ftl-core",
|
|
||||||
"mining-turret",
|
|
||||||
"bulk-bay"
|
|
||||||
],
|
],
|
||||||
"construction": {
|
"construction": {
|
||||||
"recipeId": "miner-construction",
|
"recipeId": "miner-construction",
|
||||||
|
|||||||
Reference in New Issue
Block a user