Skip to content

ships.Class.ShipLoadout

github-actions[bot] edited this page Aug 19, 2026 · 75 revisions

@elite-dangerous-almanac/core / ships / ShipLoadout

Class: ShipLoadout

Defined in: src/ships/ship-loadout.ts:734

A fitted ship — read a SLEF export, or assemble a hull from scratch.

Remarks

Jump calculations resolve the frame shift drive's constants from the drive's module record, applying any engineering the build carries (a Long Range blueprint's FSDOptimalMass, for instance). Mass comes from the export's UnladenMass where unladenMass takes it; otherwise it is the hull mass plus every fitted module's mass (armour defaults to the zero-mass lightweight alloy).

Examples

Read a build a player already flies, and ask it what an outfitting screen shows. Every figure below is one build's — a Krait Phantom explorer. Figures the capture already stated — unladenMass here — are trusted verbatim while the fit they describe survives import; the rest are computed from the fit.

import { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
import type { LoadoutEvent } from '@elite-dangerous-almanac/core/ships/slef';

// A `Loadout` line lifted from a player journal, parsed.
declare const event: LoadoutEvent;

const build = ShipLoadout.fromLoadout(event);

build.shipSymbol; // -> 'krait_light'
build.shipName; // -> 'Jenny Longuet'
build.unladenMass; // -> 388.830017   (tonnes)

build.maxJumpRange(); // -> 60.5478   (ly, best single jump)
build.powerBudget().withinBudget; // -> true
build.shieldMetrics()?.strength; // -> 743.12  (MJ)
build.armourMetrics().hitPoints; // -> 307.8

Assemble a hull instead. empty starts from the shipyard layout, slots enumerates the mounts, and setModule fits one — chainable, because the build is mutable.

import { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
import { getModuleBySymbol } from '@elite-dangerous-almanac/core/ships/modules';
import { CORE_MODULES } from '@elite-dangerous-almanac/core/ships/modules-core';

const conda = ShipLoadout.empty('Anaconda');
conda.slots().length; // -> 39   (every mount, occupied or not)
conda.slots('optional').length; // -> 14
conda.validation.complete; // -> false  (nothing fitted yet)

const fsd = getModuleBySymbol('Int_Hyperdrive_Size6_Class5', CORE_MODULES);
if (fsd) conda.setModule('FrameShiftDrive', fsd);

Write a build back out. Retail credits are what the catalogue prices the fit at; pass credits: 'source' to export the figures a capture stated it paid instead — see ShipLoadout.sourcePurchase.

import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';

declare const build: ShipLoadout;

build.toLoadoutEvent(); // retail: hull cost plus every module's list price
build.toLoadoutEvent({ credits: 'source' }); // the capture's own figures
build.toSlefString({ header: { appName: 'MyApp', appVersion: '1.0.0' } });

Accessors

cargoCapacity

Get Signature

get cargoCapacity(): number | null

Defined in: src/ships/ship-loadout.ts:1093

Cargo capacity, in tonnes, or null when a fitted rack has no capacity stat. A SLEF export's CargoCapacity is used when present and import normalization left its fit alone, restoring an absent cargo hatch excepted; otherwise it is the sum of the fitted cargo racks.

Returns

number | null


cargoCapacityResult

Get Signature

get cargoCapacityResult(): CalculationResult<number>

Defined in: src/ships/ship-loadout.ts:1098

Cargo capacity with diagnostics when a fitted rack has no capacity stat.

Returns

CalculationResult<number>


frameShiftDrive

Get Signature

get frameShiftDrive(): FrameShiftDriveParams

Defined in: src/ships/ship-loadout.ts:2615

The resolved frame-shift-drive constants for this build — post-engineering, with any Guardian FSD Booster folded into jumpBoost.

Throws

If the build has no frame shift drive, or the fitted record is missing any of its required jump constants.

Returns

FrameShiftDriveParams


fuelCapacity

Get Signature

get fuelCapacity(): FuelCapacity | null

Defined in: src/ships/ship-loadout.ts:1067

Fuel-tank capacities, in tonnes, or null when a tank's capacity is unknown. A SLEF export's FuelCapacity is used when present and import normalization left its fit alone, restoring an absent cargo hatch excepted; otherwise the main capacity is the sum of the fitted fuel tanks and the reserve comes from the hull's stats.

Returns

FuelCapacity | null


fuelCapacityResult

Get Signature

get fuelCapacityResult(): CalculationResult<FuelCapacity>

Defined in: src/ships/ship-loadout.ts:1072

Fuel capacity with diagnostics when a fitted tank has no capacity stat.

Returns

CalculationResult<FuelCapacity>


hullValue

Get Signature

get hullValue(): number | null

Defined in: src/ships/ship-loadout.ts:1129

Hull cost in credits represented by the build, or null if unknown.

Remarks

This is the live figure, kept coherent with edits: an import's own HullValue until something invalidates it. For the capture's figure as captured — which no edit changes — read sourcePurchase.

Returns

number | null


importOutcomes

Get Signature

get importOutcomes(): readonly LoadoutImportOutcome[]

Defined in: src/ships/ship-loadout.ts:1207

Changes made while importing this build, in source order, followed by a restored cargo hatch when the source named none.

Remarks

Each entry names the exact slot and unresolved source identity. An emptied outcome means import removed an unknown module from a hardpoint, utility, optional internal, or unrecognised slot. A defaulted outcome names the stock replacement fitted to armour, a core internal, or the cargo hatch; its sourceSymbol is null only for a cargo hatch the source left out, which is the one mount import fills without being asked.

Returns

readonly LoadoutImportOutcome[]

A deeply frozen list. It is empty for builds created with ShipLoadout.empty or ShipLoadout.default, and for imports that needed no normalization.


modulesValue

Get Signature

get modulesValue(): number | null

Defined in: src/ships/ship-loadout.ts:1140

Fitted-modules cost in credits represented by the build, or null if unknown — including after an edit or import normalization discarded an import's figure, since no catalogue records what a replaced module was bought for. Unlike mass and capacity it is not recomputed from what remains; sourcePurchase keeps the captured figure and retailCredits prices the current fit.

Returns

number | null


rebuy

Get Signature

get rebuy(): number | null

Defined in: src/ships/ship-loadout.ts:1149

Insurance rebuy cost in credits represented by the build, or null if unknown. Discarded by an edit or by import normalization for the same reason as modulesValue, and likewise kept by sourcePurchase.

Returns

number | null


shipIdent

Get Signature

get shipIdent(): string | null

Defined in: src/ships/ship-loadout.ts:1018

The player-given ID plate, or null if the build has none.

Returns

string | null


shipName

Get Signature

get shipName(): string | null

Defined in: src/ships/ship-loadout.ts:1013

The player-given ship name, or null if the build has none.

Returns

string | null


shipSymbol

Get Signature

get shipSymbol(): string

Defined in: src/ships/ship-loadout.ts:1008

The hull's internal id, e.g. "explorer_nx".

Returns

string


sourcePurchase

Get Signature

get sourcePurchase(): SourcePurchaseRecord | null

Defined in: src/ships/ship-loadout.ts:1188

What the capture this build came from said was paid for it — a read-only SourcePurchaseRecord, or null for a build assembled here or imported from a capture that quoted no credits at all.

Remarks

The record is provenance about the source, so it is fixed at import and survives every edit: fit, remove or engineer whatever you like and it still reports the figures the capture carried, for the modules the capture carried them for. That is what hullValue, modulesValue and rebuy cannot do — they describe the build in hand, so an edit that invalidates one drops it.

The two answer different questions and neither substitutes for the other. A captured price belongs to one commander's purchase history, discounts included; the library's own figures are catalogue retail. Export picks between them explicitly, and quotes retail unless asked otherwise — see LoadoutExportOptions.credits.

Example
import { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
import { getSourceModuleValue } from '@elite-dangerous-almanac/core/ships/source-purchase';

declare const slefJson: string;

const build = ShipLoadout.fromSlef(slefJson);
const paid = build.sourcePurchase!;
paid.hullValue; // -> 189326510, as captured
getSourceModuleValue(paid, 'powerplant')?.value; // -> what that plant cost its owner

build.removeModule('Slot05_Size4');
build.modulesValue;                 // -> null   unavailable after the edit
paid.modulesValue;                  // -> 192625195, the captured figure
Returns

SourcePurchaseRecord | null


unladenMass

Get Signature

get unladenMass(): number | null

Defined in: src/ships/ship-loadout.ts:1036

Hull + modules mass with an empty tank and no cargo, in tonnes, or null if it cannot be determined (no UnladenMass in the export and a fitted module has no known mass).

Remarks

A SLEF export's UnladenMass is trusted verbatim unless import normalization changed the fit it described — restoring an absent cargo hatch does not. Otherwise the mass is the hull's hullMass plus every fitted module's mass (post-engineering), with armour at the zero-mass lightweight default — the normalized fit's mass, then, not the capture's, and complete either way. An importOutcomes entry whose sourceSymbol is not null is the only report of that.

Returns

number | null


unladenMassResult

Get Signature

get unladenMassResult(): CalculationResult<number>

Defined in: src/ships/ship-loadout.ts:1046

Unladen mass with diagnostics for every missing input.

Returns

CalculationResult<number>

A complete imported or computed mass, otherwise null plus the module fields that prevented the calculation.


validation

Get Signature

get validation(): LoadoutValidation

Defined in: src/ships/ship-loadout.ts:1222

Structural validity and operational completeness of this build.

Remarks

Optional, hardpoint and utility mounts may be empty. Armour and all seven core mounts must be filled for complete to be true. A module in a nonexistent or incompatible slot is invalid. Exclusive families and per-ship module-count allowances must also be satisfied. Neither question reports import normalization — the fit that remains really is legal and really is filled — so read importOutcomes beside them.

Returns

LoadoutValidation

Methods

applyBlueprint()

applyBlueprint(slotKey, fdname, options): this

Defined in: src/ships/ship-loadout.ts:1766

Engineer the module in a slot — apply a blueprint (with a grade and quality) and an optional experimental effect, computing the resulting stat modifiers.

The modifiers are stored with journal-equivalent labels and numeric values on the fitted module, so the build's jump-range and mass calculations pick them up automatically. The optional journal display-direction hint LessIsGood is omitted. The block keeps the BlueprintName you passed, so it reads back the way the build declared it. Values use Frontier's float32 arithmetic, and weapon recipe internals such as BurstInterval are exposed as the derived RateOfFire and DamagePerSecond labels a journal writes. Module-specific aliases likewise use the journal spelling (MaximumRange for a module's maximum range and Range for a scanner range). Recipe-only values remain available through FittedModule.effectiveStats and build calculations even though a journal does not serialize their labels; this is what keeps burst and reload-cycle calculations faithful after applying a recipe.

Which recipe an id names can depend on the module. The game writes Sensor_LongRange and Sensor_WideAngle for both a sensor suite's modification and a utility scanner's, and the two roll different stats in opposite directions — Long Range costs the suite mass and the scanner power draw. So the id is resolved against the module's menu before anything is computed, and a wake scanner engineered Sensor_LongRange gets the scanner's numbers, which BLUEPRINTS keys Scanner_LongRange. Reading a stored block back the same way means resolving it the same way: resolveBlueprintForModule in ships/blueprint-journal is that lookup.

Parameters

slotKey

string

The slot whose module to engineer, matched case-insensitively (journal spelling).

fdname

string

The blueprint recipe's Frontier fdname, e.g. "FSD_LongRange".

options

ApplyBlueprintOptions

ApplyBlueprintOptions: grade (1–5), optional quality (0–1, default 1), and optional experimental effect fdname. A nullish experimental means no effect, the same as leaving it out. Each is read once, before anything is checked, so an accessor cannot answer the check and the use differently.

Returns

this

this, for chaining.

Throws

If the slot is empty, or the blueprint/grade/experimental is unknown, or quality is outside [0, 1].

Throws

If slotKey or fdname is not a string, options is not an object, or options.experimental carries a value that is not a string — a nullish one is no effect, not a wrong type; the fitted module has no stats to engineer; or the id names a fixed event-reward identity, which names no craftable recipe; or the module is not offered the blueprint — by its engineering menu, by the journal spelling of an entry on that menu, by the generic spelling of a recipe that menu lists under a family's name, or by being a Mercenary article sold at grade 1 with that bespoke recipe; the fitted article is final and accepts no further engineering; or the module is not offered the experimental effect, which its menu alone decides; or the catalogue does not carry every base stat the recipe modifies. Incomplete engineering is rejected rather than stored as a partial journal modifier block.

Example

import { getModuleBySymbol } from '@elite-dangerous-almanac/core/ships/modules';
import { CORE_MODULES } from '@elite-dangerous-almanac/core/ships/modules-core';
import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';

declare const build: ShipLoadout;

const fsd = getModuleBySymbol('Int_Hyperdrive_Size6_Class5', CORE_MODULES)!;

build.setModule('FrameShiftDrive', fsd)
     .applyBlueprint('FrameShiftDrive', 'FSD_LongRange', {
         grade: 5,
         experimental: 'special_fsd_heavy',
     });
build.maxJumpRange(); // uses the engineered optimal mass

armourMetrics()

armourMetrics(): ArmourMetrics

Defined in: src/ships/ship-loadout.ts:3279

The build's armour: hull hit points, the bulkhead and reinforcement each contribute, and the effective resistances.

Returns

ArmourMetrics

The ArmourMetrics. A build with no armour module fitted is reported on the stock lightweight alloy the hull leaves the shipyard with, which is what the game does.

Example

import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';

declare const build: ShipLoadout;

const hull = build.armourMetrics();
hull.hitPoints;                  // -> total hull points
hull.resistances.explosive;      // -> lightweight alloy is explosively weak
hull.effectiveHitPoints.thermal; // -> thermal damage the hull can soak

availableBlueprints()

availableBlueprints(slotKey): readonly AvailableBlueprint[]

Defined in: src/ships/ship-loadout.ts:1371

Return the computable blueprint candidates for a fitted module symbol.

Parameters

slotKey

string

Slot key, matched case-insensitively.

Returns

readonly AvailableBlueprint[]

Frozen blueprint descriptors: the ordinary engineering menu first, then bespoke Mercenary upgrade recipes. An 'ordinary' candidate is available to the stock module; a 'mercenary' candidate is purchase-specific. Applying that bespoke blueprint identifies the matching Mercenary article even though its bare module symbol does not. Returns an empty array when the slot is empty, unresolved or final, or the module symbol has neither route.

Throws

If slotKey is not a string.

Example

import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';

declare const build: ShipLoadout;

build.availableBlueprints('FrameShiftDrive').map(({ fdname }) => fdname);

availableExperimentalEffects()

availableExperimentalEffects(slotKey): readonly string[]

Defined in: src/ships/ship-loadout.ts:1395

Return the computable experimental effects offered to a fitted module.

Parameters

slotKey

string

Slot key, matched case-insensitively.

Returns

readonly string[]

Frozen Frontier effect ids in engineering-menu order, or an empty array when the slot is empty, unresolved, final, or has no experimental menu.

Throws

If slotKey is not a string.

Example

import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';

declare const build: ShipLoadout;

build.availableExperimentalEffects('FrameShiftDrive');
// -> ['special_fsd_heavy', ...]

cellBanks()

cellBanks(): CellBankSummary

Defined in: src/ships/ship-loadout.ts:3184

Every fitted shield cell bank and the usable rearmed reinforcement pool.

Every fitted bank remains in banks, where powered says whether it is switched on and its priority group is fed with hardpoints deployed. The totals include only those powered banks. A build with no powered power plant — including one created by empty before a plant is fitted — reports every bank as unpowered and returns zero totals.

Returns

CellBankSummary

A frozen CellBankSummary; no banks is an empty list and zero totals.

Example

import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';

declare const build: ShipLoadout;
build.cellBanks().totalRestorable; // -> MJ across every powered fitted cell

clearEngineering()

clearEngineering(slotKey): this

Defined in: src/ships/ship-loadout.ts:2423

Strip engineering from a slot's module, restoring its base stats.

Parameters

slotKey

string

The slot to de-engineer, matched case-insensitively (journal spelling).

Returns

this

this, for chaining. A no-op if the slot is empty or unmodified.

Throws

If slotKey is not a string, or the fitted article is final pre-engineered and its baked engineering cannot be removed.

Remarks

Clearing a Mercenary article removes its purchase-exclusive blueprint identity. Its FittedModule.preEngineeredVariant then reads null.


completeEngineeringGrade()

completeEngineeringGrade(slotKey): EngineeringNormalizationResult

Defined in: src/ships/ship-loadout.ts:2166

Recompute the fitted module's current engineering identity at quality 1.

Imported modifier values remain authoritative until this method is called. An ordinary or Mercenary recipe is rerolled through the package calculator; a fixed reward rebuilds its hand-authored modifiers and optional effect without losing its purchase identity. A refusal never changes the loadout.

Parameters

slotKey

string

The engineered slot, matched case-insensitively.

Returns

EngineeringNormalizationResult

A frozen result identifying a normalized, unchanged or unsupported state.

Throws

If slotKey is not a string.

Example

import { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';

const partial = ShipLoadout.default('SideWinder').applyBlueprint(
    'FrameShiftDrive',
    'FSD_LongRange',
    { grade: 5, quality: 0.42 },
);
const imported = ShipLoadout.fromLoadout(partial.toLoadoutEvent());
imported.completeEngineeringGrade('FrameShiftDrive').kind; // -> 'normalized'
imported.fittedModuleAt('FrameShiftDrive')?.engineering?.Quality; // -> 1

distributorMetrics()

distributorMetrics(options?): DistributorMetrics | null

Defined in: src/ships/ship-loadout.ts:3404

All three power-distributor capacitors at selected pip allocations.

Parameters

options?

DistributorOptions = {}

SYS, ENG and WEP pips in [0, 4], each defaulting independently to 4. The allocations need not sum to six, which permits independent comparisons of the three maxima.

Returns

DistributorMetrics | null

Capacity, rated four-pip recharge and actual pip-scaled recharge for SYS, ENG and WEP, or null when no distributor is fitted, it is switched off, its six capacitor stats cannot be resolved, or the retracted power budget sheds it. The retracted state represents the distributor itself; firing endurance in weaponsCapacitorMetrics separately applies the deployed state.

Throws

If any pip allocation is outside [0, 4] or not finite.

Example

import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';

declare const build: ShipLoadout;
const distributor = build.distributorMetrics({
  systemsPips: 2,
  enginesPips: 2,
  weaponsPips: 2,
});
distributor?.engines.rechargeRate; // MJ/s

fittedModuleAt()

fittedModuleAt(slotKey): FittedModule | null

Defined in: src/ships/ship-loadout.ts:1305

A deeply frozen, point-in-time view of the module in a slot.

Parameters

slotKey

string

Slot key, matched case-insensitively.

Returns

FittedModule | null

A detached, frozen view, or null when the slot is empty or unknown.

Throws

If slotKey is not a string.


fittedModules()

fittedModules(): readonly FittedModule[]

Defined in: src/ships/ship-loadout.ts:1341

Every fitted module as a deeply frozen point-in-time view.

Returns

readonly FittedModule[]

Detached module snapshots in the order the build carries them. The array and every nested record are frozen; query again after an edit for current state.

Example

import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';

declare const build: ShipLoadout;

build.fittedModules().map((module) => `${module.slot}: ${module.symbol}`);

frameShiftDriveMassFactor()

frameShiftDriveMassFactor(options?): number

Defined in: src/ships/ship-loadout.ts:2651

The fitted frame shift drive's dimensionless mass factor at a chosen load.

Parameters

options?

JumpOptions = {}

JumpOptions. fuel defaults to a full main tank and cargo to 0.

Returns

number

optMass / loadedMass: 1 at the drive's optimised mass, below 1 above it and above 1 below it.

Remarks

This is the mass term used by the jump equation, not the three-point performance curve used by thrusters and shield generators. Main-tank fuel contributes to the loaded mass; the Guardian FSD Booster's additive range does not contribute to the factor.

Throws

If the build has no usable frame shift drive or its mass cannot be determined; also if fuel capacity is unknown and options.fuel is omitted.

Throws

If fuel or cargo is not finite and non-negative, or loaded mass is zero.

Example

import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';

declare const build: ShipLoadout;
build.frameShiftDriveMassFactor({ fuel: 8, cargo: 32 }); // dimensionless

fuelPerJump()

fuelPerJump(distance, options?): number

Defined in: src/ships/ship-loadout.ts:2719

The fuel a single jump of a given distance costs, in tonnes.

Parameters

distance

number

The jump distance, in light-years.

options?

JumpOptions = {}

JumpOptions. fuel defaults to a full main tank, cargo to 0.

Returns

number

Fuel used, in tonnes (capped at the drive's max fuel per jump).

Throws

If the build has no usable frame shift drive or its mass cannot be determined; also if fuel capacity is unknown and options.fuel is omitted.

Throws

If fuel or cargo is not finite and non-negative.


heatMetrics()

heatMetrics(): HeatMetrics | null

Defined in: src/ships/ship-loadout.ts:2959

The build's heat: what it idles at, what it runs at flying and jumping, and whether firing everything cooks it.

Every figure is post-engineering. The heat a build makes follows what the plant actually feeds, so a module switched off — or one in a priority group the plant cannot keep lit — contributes nothing.

Returns

HeatMetrics | null

The HeatMetrics, or null when the build has no powered power plant.

Example

import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';

declare const build: ShipLoadout;

const heat = build.heatMetrics();
heat?.idle.gauge;                      // -> 0.23, i.e. the gauge reads 23%
heat?.firingSustained.overheats;       // -> false: the guns run cool enough to hold
heat?.firingDrained.secondsToOverheat; // -> how long an alpha strike has on an empty WEP

jumpRange()

jumpRange(options?): number

Defined in: src/ships/ship-loadout.ts:2689

The range of a single jump for a chosen fuel and cargo load, in light-years.

Parameters

options?

JumpOptions = {}

JumpOptions. fuel defaults to a full main tank, cargo to 0.

Returns

number

The jump's range, in light-years.

Throws

If the build has no usable frame shift drive or its mass cannot be determined; also if fuel capacity is unknown and options.fuel is omitted.

Throws

If fuel or cargo is not finite and non-negative.


jumpRangeSummary()

jumpRangeSummary(): JumpRangeSummary

Defined in: src/ships/ship-loadout.ts:2885

Every jump figure at once — best, unladen, laden, and each load's total.

Returns

JumpRangeSummary

The JumpRangeSummary. Single-jump figures and each total's range are in light-years. For a partial load, call jumpRange for one jump or totalRange for every jump with the fuel and cargo you actually have.

Throws

If the build has no usable frame shift drive, or its mass, fuel capacity or cargo capacity cannot be determined.

Example

import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';

declare const build: ShipLoadout;

const jumps = build.jumpRangeSummary();
jumps.max;    // -> 89.41  (one jump's fuel, empty hold)
jumps.laden;  // -> the range with the hold full
jumps.totalMax.jumps; // the best jump expressed as a total
// Half a tank and 32 t aboard, once the tank is known:
const fuel = build.fuelCapacityResult;
if (fuel.complete) build.jumpRange({ fuel: fuel.value.main / 2, cargo: 32 });

ladenJumpRange()

ladenJumpRange(): number

Defined in: src/ships/ship-loadout.ts:2703

Single-jump range on a full tank with a full cargo hold, in light-years.

Returns

number

The jump's range, in light-years.

Throws

If the build has no usable frame shift drive, or its mass, fuel capacity or cargo capacity cannot be determined.


maxJumpRange()

maxJumpRange(): number

Defined in: src/ships/ship-loadout.ts:2673

Best single-jump range, in light-years — no cargo, and exactly one jump's fuel aboard (the lightest the ship jumps). This is the figure the game and EDSY label "maximum jump range".

Returns

number

The best single jump, in light-years.

Remarks

Returns 0 when no fuel is available — an assembled build with no fuel tank fitted has an empty main tank, so there is nothing to jump on.

Throws

If the build has no usable frame shift drive, or its mass or fuel capacity cannot be determined.


mercCoinCost()

mercCoinCost(): number

Defined in: src/ships/ship-loadout.ts:3252

Total the Merc Coin prices of the Mercenary articles fitted to this build.

Returns

number

The total in Merc Coin, or 0 when no fitted article is a Mercenary purchase. Credit prices and rebuy remain available from retailCredits.

Remarks

The total counts both articles fitted through setPreEngineeredVariant and purchases implied by applying their Mercenary-only blueprint through applyBlueprint. The blueprint identifies the purchase at grade 1 and after later upgrades; the current grade does not change the original shop price.

Example

import { getPreEngineeredVariants } from '@elite-dangerous-almanac/core/ships/pre-engineered';
import { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';

const variant = getPreEngineeredVariants('Hpt_Railgun_Fixed_Medium')
    .find((candidate) => candidate.acquisition === 'mercenary')!;
const build = ShipLoadout.default('Python')
    .setPreEngineeredVariant('MediumHardpoint1', variant);
build.mercCoinCost(); // -> 950

mobilityMetrics()

mobilityMetrics(options?): MobilityMetrics | null

Defined in: src/ships/ship-loadout.ts:2993

The build's speed, boost and rotation rates at a chosen load and ENG allocation.

Parameters

options?

MobilityOptions = {}

Fuel defaults to a full main tank, cargo to 0, and ENG pips to 4.

Returns

MobilityMetrics | null

Loaded MobilityMetrics, or null when no fully described thrusters are powered with hardpoints retracted. Use mobilityMetricsResult to distinguish the unavailable conditions.

Remarks

Main-tank fuel contributes to the flight model's loaded mass. Reserve-tank fuel does not: although the statistics panel includes it in the displayed current mass, ten observed builds reproduce their angular rates only when the reserve is excluded from the thruster mass curve.

Throws

If mass or an omitted main-tank fuel load cannot be determined.

Throws

If fuel or cargo is not finite and non-negative, or enginesPips is outside [0, 4].

Example

import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';

declare const build: ShipLoadout;
build.mobilityMetrics({ cargo: 32, fuel: 8, enginesPips: 2 })?.speed; // -> m/s

mobilityMetricsResult()

mobilityMetricsResult(options?): CalculationResult<MobilityMetrics>

Defined in: src/ships/ship-loadout.ts:3019

The build's mobility with a diagnostic when its thrusters or retracted power supply is unavailable.

Parameters

options?

MobilityOptions = {}

Fuel defaults to a full main tank, cargo to 0, and ENG pips to 4.

Returns

CalculationResult<MobilityMetrics>

A complete MobilityMetrics value, otherwise null plus the input or fitted-module state that prevented the calculation.

Throws

If mass or an omitted main-tank fuel load cannot be determined.

Throws

If fuel or cargo is not finite and non-negative, or enginesPips is outside [0, 4].

Example

import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';

declare const build: ShipLoadout;
const result = build.mobilityMetricsResult({ enginesPips: 2 });
if (result.complete) result.value.speed; // metres per second
else result.issues[0].reason;            // unavailable-state discriminator

modulesForSlot()

modulesForSlot(slotKey): OutfittingModule[]

Defined in: src/ships/ship-loadout.ts:1418

The modules that fit a given slot — its size, kind and any restriction all satisfied, with candidates that would worsen a one-per-ship or module-count limit omitted.

Parameters

slotKey

string

The slot key to fit, matched case-insensitively (journal spelling).

Returns

OutfittingModule[]

The fitting modules, in complete-catalogue order.

Throws

If the hull has no slot with that key.

Throws

If slotKey is not a string.

Example

import { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';

ShipLoadout.empty('Anaconda').modulesForSlot('FrameShiftDrive');

powerBudget()

powerBudget(): PowerBudget

Defined in: src/ships/ship-loadout.ts:2924

The build's power budget: what the plant makes, what the modules draw with hardpoints retracted and deployed, and which priority groups stay lit.

Draws are post-engineering, modules switched off in the journal are skipped, and weapons (plus the utility fittings that are not always powered) count only towards the deployed total.

Returns

PowerBudget

The PowerBudget. With no power plant fitted, available is 0 and nothing is powered. consumers includes modules with positive draw; passive and zero-draw fittings are absent.

Throws

If a power capacity or module draw is negative or not finite.

Example

import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';

declare const build: ShipLoadout;

const power = build.powerBudget();
power.available;                  // -> 20.4 MW generated
power.deployed;                   // -> 19.02 MW drawn, hardpoints out
power.withinBudget;               // -> true
power.bands[4]?.poweredDeployed;  // -> is priority group 5 still lit?

removeModule()

removeModule(slotKey): this

Defined in: src/ships/ship-loadout.ts:1656

Empty a slot.

Parameters

slotKey

string

The slot key to clear, matched case-insensitively (journal spelling).

Returns

this

this, for chaining. Clearing an already-empty removable slot is a no-op.

Throws

If slotKey is not a string.

Throws

If the slot is the built-in cargo hatch; is a required core or armour mount; or removing the module would worsen a per-ship module-count excess. Required mounts may be replaced with setModule but cannot be emptied.


repairFixedMount()

repairFixedMount(slotKey): FixedMountRepairResult

Defined in: src/ships/ship-loadout.ts:1463

Restore a missing or invalid fixed mount from this hull's stock loadout.

Parameters

slotKey

string

Fixed slot key, matched case-insensitively.

Returns

FixedMountRepairResult

A frozen FixedMountRepairResult. Refusals leave the build unchanged.

Remarks

This is the narrow repair path for mounts that setModule deliberately does not expose as ordinary edits, including the built-in cargo hatch. The stock article keeps the mount's On, Priority and Health and none of the replaced module's engineering or captured value, as import normalization does. Live aggregates follow the same rules as every package-owned refit. The immutable sourcePurchase record is unchanged; source-credit export leaves a replaced slot unpriced, while its aggregate totals remain valid for an unpriced or zero-priced cargo hatch. Resolved valid core and armour alternatives are left unchanged.

Throws

If slotKey is not a string.

Throws

If a known hull has no slot with that key.

Example

import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';

declare const imported: ShipLoadout;
const result = imported.repairFixedMount('CargoHatch');
if (result.status === 'repaired') console.log(result.symbol.toLowerCase());

retailCredits()

retailCredits(): RetailCredits

Defined in: src/ships/ship-loadout.ts:3207

Price this build from current catalogue list prices without creating a journal event.

Returns

RetailCredits

Hull, module and five-percent rebuy credits. modules and rebuy remain lower bounds when RetailCredits.unpriced is non-empty; built-in hull fittings are free.

Example

import { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';

ShipLoadout.default('Anaconda').retailCredits().hull; // -> 142456440

See

mercCoinCost for Mercenary purchase prices.


setExperimentalEffect()

setExperimentalEffect(slotKey, experimental): ExperimentalEffectMutationResult

Defined in: src/ships/ship-loadout.ts:1967

Add, replace or remove only the fitted module's experimental effect.

Ordinary and Mercenary engineering is recomputed at its current blueprint, grade and quality. A fixed reward instead retains its hand-authored modifiers and purchase identity while the requested effect is composed with them. Refused edits leave the build unchanged and return stable structured data.

Parameters

slotKey

string

The engineered slot, matched case-insensitively.

experimental

string | null

Experimental-effect fdname, or null to remove the effect.

Returns

ExperimentalEffectMutationResult

A frozen result identifying an update, no-op or lossless refusal.

Throws

If slotKey or a non-null experimental is not a string.

Example

import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';

declare const build: ShipLoadout;

build.setExperimentalEffect('FrameShiftDrive', 'special_fsd_heavy');
build.setExperimentalEffect('FrameShiftDrive', null);

setModule()

setModule(slotKey, module): this

Defined in: src/ships/ship-loadout.ts:1565

Fit a module into a slot, replacing whatever is there.

Parameters

slotKey

string

The slot key to fit into, matched case-insensitively (journal spelling). An occupied slot keeps the key the build already spells it with, so fitting into an import never renames one of its mounts.

module

OutfittingModule

The module to fit (resolve it from a catalogue first, e.g. with getModuleBySymbol). The complete record is snapshotted, so a result from getPreEngineeredStats or a caller-supplied catalogue keeps its resolved stats.

Returns

this

this, for chaining.

Remarks

This is an incremental editor: every call must avoid worsening the current build's module-count excess. Fit an allowance-increasing module before the weapons it permits. To consume a complete order-independent snapshot, use ShipLoadout.fromLoadout.

Fitting is a fresh mount: the slot's On, Priority and Health are reset. Set them again if your screen keeps a priority group across a swap. repairFixedMount keeps them, standing in for an article that failed rather than for one the player chose.

Throws

If the hull has no slot with that key.

Throws

If slotKey is not a string; module is null/undefined (e.g. a getModuleBySymbol miss) or is not an outfitting module at all.

Throws

If the module does not fit the slot (wrong kind, too large, or a restriction the module does not satisfy), conflicts with a one-per-ship family already fitted elsewhere, or worsens a per-ship module-count excess.

Example

import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';

declare const build: ShipLoadout;

import { getModuleBySymbol } from '@elite-dangerous-almanac/core/ships/modules';
import { CORE_MODULES } from '@elite-dangerous-almanac/core/ships/modules-core';
const fsd = getModuleBySymbol('Int_Hyperdrive_Size6_Class5', CORE_MODULES)!;
const tank = getModuleBySymbol('Int_FuelTank_Size6_Class3', CORE_MODULES)!;
build.setModule('FrameShiftDrive', fsd).setModule('Slot01_Size7', tank);

setModuleEnabled()

setModuleEnabled(slotKey, on): this

Defined in: src/ships/ship-loadout.ts:2462

Switch a fitted module on or off.

Parameters

slotKey

string

The slot's journal key, e.g. "PowerPlant", matched case-insensitively.

on

boolean

true to power it, false to switch it off.

Returns

this

this, for chaining.

Throws

If the slot is empty.

Throws

If slotKey is not a string.

Example

import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';

declare const build: ShipLoadout;

build.setModuleEnabled('TinyHardpoint6', false); // an unpowered heat sink

setModulePriority()

setModulePriority(slotKey, priority): this

Defined in: src/ships/ship-loadout.ts:2478

Set a fitted module's power-priority group.

Parameters

slotKey

string

The slot's journal key, matched case-insensitively.

priority

number

The journal's zero-based group, 04. Note that the outfitting panel — and powerBudget's bands[].priority — number the same five groups 15.

Returns

this

this, for chaining.

Throws

If the slot is empty, or priority is not an integer in [0, 4].

Throws

If slotKey is not a string.


setPreEngineeredVariant()

setPreEngineeredVariant(slotKey, variant): this

Defined in: src/ships/ship-loadout.ts:2354

Fit a pre-engineered variant into a slot, replacing whatever is there.

The variant's fixed stats and journal engineering block are resolved together. Articles carry Level, Quality: 1, any baked experimental effect and their fixed modifiers. Because the variant names its base module, a decorative identity cannot be applied to an unrelated damage-bearing module. A Mercenary variant whose fixed modifier block has not been published retains the stock catalogue stats and omits Modifiers rather than claiming it changes none.

Parameters

slotKey

string

The slot key to fit into, matched case-insensitively.

variant

PreEngineeredVariant

The pre-engineered catalogue variant to fit.

Returns

this

this, for chaining.

Throws

If variant is not a pre-engineered variant or one of its authored modifier labels cannot be resolved for its base module.

Throws

If no catalogue row matches the supplied module, blueprint, grade, experimental effect and acquisition route.

Throws

If the variant's base module does not fit the slot or violates a fitted-module limit.

Example

import { getPreEngineeredVariants } from '@elite-dangerous-almanac/core/ships/pre-engineered';
import { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';

const festive = getPreEngineeredVariants('Hpt_FlakMortar_Turret_Medium')
    .find((variant) => variant.blueprint === 'Decorative_Red')!;
const build = ShipLoadout.empty('Krait_MkII')
    .setPreEngineeredVariant('MediumHardpoint1', festive);
build.fittedModuleAt('MediumHardpoint1')?.effectiveStats?.damage; // -> 0.34

shieldMetrics()

shieldMetrics(options?): ShieldMetrics | null

Defined in: src/ships/ship-loadout.ts:3071

The build's shields: strength in megajoules, where it comes from, and the effective resistances.

Shield strength scales with the hull's mass, not the build's, so fitting more modules never weakens it. Boosters, Guardian shield reinforcement and any engineering are all folded in; switched-off or shed boosters and reinforcement are ignored, while a switched-off or shed generator makes the metric unavailable.

Parameters

options?

DefenceOptions = {}

DefenceOptions. systemsPips (0–4) folds the SYS capacitor's own resistance into the reported figures; it defaults to 0, which is what an outfitting screen shows.

Returns

ShieldMetrics | null

The ShieldMetrics, or null when the build has no shield generator powered with hardpoints retracted. Use shieldMetricsResult to distinguish the unavailable conditions.

Throws

If systemsPips is outside [0, 4] or not finite.

Example

import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';

declare const build: ShipLoadout;

const shields = build.shieldMetrics();
shields?.strength;              // -> MJ
shields?.resistances.thermal;   // -> negative on a stock generator
build.shieldMetrics({ systemsPips: 4 })?.resistances.thermal; // -> with 4 pips to SYS

shieldMetricsResult()

shieldMetricsResult(options?): CalculationResult<ShieldMetrics>

Defined in: src/ships/ship-loadout.ts:3094

The build's shields with a diagnostic when its hull, generator or retracted power supply is unavailable.

Parameters

options?

DefenceOptions = {}

DefenceOptions. systemsPips defaults to 0.

Returns

CalculationResult<ShieldMetrics>

A complete ShieldMetrics value, otherwise null plus the input or fitted-module state that prevented the calculation.

Throws

If systemsPips is outside [0, 4] or not finite.

Example

import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';

declare const build: ShipLoadout;
const result = build.shieldMetricsResult();
if (result.complete) result.value.strength; // megajoules
else result.issues[0].reason;               // unavailable-state discriminator

shieldRecovery()

shieldRecovery(options?): ShieldRecovery | null

Defined in: src/ships/ship-loadout.ts:3127

Time for this build's shield to rise after collapse and then regenerate to full.

Parameters

options?

DefenceOptions = {}

SYS pips in [0, 4], defaulting to 4.

Returns

ShieldRecovery | null

Recovery rates and seconds, or null when no shield generator is powered with hardpoints retracted. Use shieldRecoveryResult to distinguish the unavailable conditions. A missing distributor or insufficient zero-pip recharge produces Infinity.

Throws

If systemsPips is outside [0, 4] or not finite.

Example

import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';

declare const build: ShipLoadout;
build.shieldRecovery({ systemsPips: 4 })?.recoveryTime; // -> seconds from collapse to 50%

shieldRecoveryResult()

shieldRecoveryResult(options?): CalculationResult<ShieldRecovery>

Defined in: src/ships/ship-loadout.ts:3150

The build's shield recovery with a diagnostic when its hull, generator or retracted power supply is unavailable.

Parameters

options?

DefenceOptions = {}

SYS pips in [0, 4], defaulting to 4.

Returns

CalculationResult<ShieldRecovery>

A complete ShieldRecovery value, otherwise null plus the input or fitted-module state that prevented the calculation.

Throws

If systemsPips is outside [0, 4] or not finite.

Example

import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';

declare const build: ShipLoadout;
const result = build.shieldRecoveryResult();
if (result.complete) result.value.recoveryTime; // seconds
else result.issues[0].reason; // unavailable-state discriminator

slots()

slots(kind?): readonly LoadoutSlot[]

Defined in: src/ships/ship-loadout.ts:1265

Frozen point-in-time views of the hull's mounts in outfitting-panel order.

Parameters

kind?

SlotKind

Optionally keep only one mount kind. Omit it for every mount.

Returns

readonly LoadoutSlot[]

Detached, frozen slot views. Repeated reads for the same kind reuse the same snapshots until a state-changing edit.

Example

import { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';

const emptyHardpoints = ShipLoadout.empty('Sidewinder').slots('hardpoint');
emptyHardpoints.every((slot) => slot.module === null); // true

standardLoadResult()

standardLoadResult(load): CalculationResult<StandardLoadInputs>

Defined in: src/ships/ship-loadout.ts:2776

Resolve one of the package's standard load conditions for jump and mobility views.

Parameters

load

StandardLoad

'maximum' for one jump's fuel and no cargo, 'unladen' for a full main tank and no cargo, or 'laden' for a full main tank and full hold.

Returns

CalculationResult<StandardLoadInputs>

Fuel and cargo in tonnes, or structured diagnostics for unavailable capacities. 'maximum' also reports every mass or frame-shift-drive fact needed to use that load in a jump calculation. A complete maximum result can therefore be passed safely to jumpRange; it validates the whole fitted drive, including an active jump booster, even though only the drive's maximum fuel determines the returned load.

Throws

If load is not a recognised standard load.

Example

import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';

declare const build: ShipLoadout;
const load = build.standardLoadResult('maximum');
if (load.complete) build.mobilityMetrics({ ...load.value, enginesPips: 2 });

toLoadoutEvent()

toLoadoutEvent(options?): LoadoutEvent

Defined in: src/ships/ship-loadout.ts:2536

This build as a journal Loadout event — the data half of a SLEF entry.

Parameters

options?

LoadoutExportOptions = {}

Module ordering and how sparse to be about power state.

Returns

LoadoutEvent

A fresh event. Every top-level figure is recomputed from the hull and the fitted modules rather than echoed from whatever an import supplied — the one exception being the credits, when credits: 'source' asks for the capture's own. Any figure that cannot be worked out is left out rather than emitted as a stale or zero value — SLEF requires nothing beyond Ship and Modules.

Credits are quoted at retail by default: the bare hull's hullCost plus every fitted module's catalogue list price, with Rebuy 5% of the two. A source's own HullValue / ModulesValue / Value figures are deliberately not quoted here, because they record one commander's purchase history — the Deep Black's modules are all 12.25% off list — and purchase discounts are not a property of the build. They are not lost either: pass credits: 'source' to export the sourcePurchase record instead, as provenance rather than as a price.

Example

import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';

declare const build: ShipLoadout;

const event = build.toLoadoutEvent();
event.MaxJumpRange; // recomputed, not the exporter's claim
event.HullValue;    // the catalogue's list price

build.toLoadoutEvent({ credits: 'source' }).HullValue; // what the capture paid

toSlef()

toSlef(options): Slef

Defined in: src/ships/ship-loadout.ts:2568

This build as a one-entry SLEF export.

Parameters

options

SlefExportOptions

Ordering, power state, and the envelope header.

Returns

Slef

The export. Several builds travel together as toSlef([a.toLoadoutEvent(), b.toLoadoutEvent()]) using the function of the same name from ./slef.


toSlefString()

toSlefString(options): string

Defined in: src/ships/ship-loadout.ts:2585

This build as SLEF JSON — ready to write to a file or put on the clipboard.

Parameters

options

SlefExportOptions

As toSlef, plus indent (compact by default).

Returns

string

Example

import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';

declare const build: ShipLoadout;

build.toSlefString({ header: { appName: 'MyApp', appVersion: '1.0.0' } });

totalRange()

totalRange(options?): TotalRangeDetails

Defined in: src/ships/ship-loadout.ts:2746

Total range and jump count for a chosen fuel and cargo load.

Parameters

options?

JumpOptions = {}

JumpOptions. fuel defaults to a full main tank, cargo to 0.

Returns

TotalRangeDetails

Summed range in light-years and the jumps made before the tank is empty.

Throws

If the build has no usable frame shift drive, or its mass or fuel capacity cannot be determined; fuel capacity is not required when options.fuel is supplied.

Throws

If fuel or cargo is not finite and non-negative, or the fuel load would require more than 100,000 jumps.

Example

import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';

declare const build: ShipLoadout;
build.totalRange().jumps; // jumps available from one full main tank
build.totalRange({ fuel: 8, cargo: 32 }).range; // range for that partial load

weaponMetrics()

weaponMetrics(): BuildWeaponMetrics

Defined in: src/ships/ship-loadout.ts:3312

The build's firepower: DPS, sustained DPS, weapons-capacitor draw, heat and power draw for every fitted weapon, plus the totals.

Every figure is post-engineering. A weapon switched off in the journal is still listed — with its own metrics — but left out of the totals.

Returns

BuildWeaponMetrics

The BuildWeaponMetrics.

Example

import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';

declare const build: ShipLoadout;

const guns = build.weaponMetrics();
guns.total.damagePerSecond;          // -> burst DPS across the hardpoints
guns.total.sustainedDamagePerSecond; // -> with reloads folded in
guns.total.energyPerSecond;          // -> MW asked of the WEP capacitor
guns.total.powerDraw;                // -> MW asked of the power plant when deployed
guns.weapons[0]?.metrics.damageByType.thermal;
guns.weapons[0]?.maximumRange;        // post-engineering metres, when known
guns.weapons[0]?.armourPiercing;      // post-engineering rating, when known
guns.weapons[0]?.ammunition?.total;  // -> rounds aboard when fully rearmed

weaponsCapacitorMetrics()

weaponsCapacitorMetrics(options?): WeaponsCapacitorMetrics

Defined in: src/ships/ship-loadout.ts:3362

WEP-capacitor recharge and endurance while every powered weapon fires.

Parameters

options?

WeaponsOptions = {}

WEP pips in [0, 4], defaulting to 4.

Returns

WeaponsCapacitorMetrics

Actual recharge, sustained draw, net drain and seconds from full to empty. The deployed power budget is applied to the distributor and weapons, so a module the plant sheds contributes nothing. With no powered distributor, capacity and recharge are zero. A load that draws no more than recharge reports Infinity for timeToDrain.

Throws

If weaponsPips is outside [0, 4] or not finite.

Example

import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';

declare const build: ShipLoadout;
build.weaponsCapacitorMetrics({ weaponsPips: 2 }).timeToDrain; // seconds

default()

static default(shipSymbol): ShipLoadout

Defined in: src/ships/ship-loadout.ts:985

Start a new build with the modules supplied on a stock ship.

Parameters

shipSymbol

string

The hull's internal symbol, e.g. "SideWinder" (case-insensitive).

Returns

ShipLoadout

A complete, ready-to-edit stock loadout. The build is independent of the frozen shared catalogue: edits affect this instance only.

Throws

If shipSymbol is not a string, or no default loadout exists for that hull.

Remarks

This batteries-included factory resolves calculations through the complete module catalogue already used by ShipLoadout. If only the stock slot/module identities are needed, getDefaultLoadout from ./default-loadouts avoids that cost.

Example

import { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';

const stock = ShipLoadout.default('SideWinder');
stock.validation.complete; // -> true
stock.fittedModuleAt('FrameShiftDrive')?.symbol;
// -> 'Int_Hyperdrive_Size2_Class1'

empty()

static empty(shipSymbol): ShipLoadout

Defined in: src/ships/ship-loadout.ts:940

Start a new build for a hull with no editable modules fitted.

Parameters

shipSymbol

string

The hull's internal symbol, e.g. "Anaconda" (case-insensitive).

Returns

ShipLoadout

An otherwise empty loadout whose slots come from the hull's declared layout. The hull's immutable default cargo hatch is fitted because it is part of the ship rather than an outfitting choice.

Throws

If shipSymbol is not a string, or no hull with that symbol has a known slot layout.

Example

import { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';

ShipLoadout.empty('Sidewinder').slots('hardpoint').length; // -> 2

fromLoadout()

static fromLoadout(event): ShipLoadout

Defined in: src/ships/ship-loadout.ts:888

Build from a bare journal Loadout event (the data half of a SLEF entry).

Parameters

event

LoadoutEvent

A Loadout event object.

Returns

ShipLoadout

The loadout.

Remarks

Capture/instance state (timestamp, ShipID, HullHealth, Hot) and engineering provenance (Engineer, EngineerID, BlueprintID) are deliberately excluded from the durable build. See LoadoutEvent and ModuleEngineering. A reward module is identified when its reported stat signature uniquely matches a catalogue variant. That reward's complete fixed stat block is then used as the fitted record, including values the capture omits; a separately applied experimental effect is included when matching and remains authoritative in the captured modifiers. A Mercenary module is instead identified by the bespoke blueprint available only to its purchase, including after a later grade upgrade. Its unpublished purchase modifiers are not inferred; the capture's current engineering remains authoritative. A fixed catalogue article can also be identified by its complete symbol/blueprint/grade/experimental identity when a SLEF capture omits the Modifiers key entirely. A present modifier array must pass the stat-signature match instead, so an older exported stock roll sharing that identity remains stock. A third-party export could also omit the array from an ordinary historical AX roll; that record is indistinguishable from the fixed reward, so the catalogue identity wins. Other under-specified or ambiguous evidence stays unidentified. An ordinary weapon recipe on a Guardian weapon identifies a final pre-engineered article; the import preserves that identity, uses the catalogue's complete hand-set stat block when the exact article is known, exposes no engineering options for it, and refuses attempts to engineer it further. Explicit journal modifiers remain authoritative over that stat block.

The event's credit figures are kept twice over: as the live hullValue / modulesValue / rebuy, which an edit may invalidate, and as the immutable sourcePurchase record, which no edit touches.

Modules are imported as one complete snapshot: their array order does not affect per-ship count allowances, and any aggregate violation is reported by validation. An entry is kept as the event stated it when the catalogue identifies its Item, when its slot is a known cosmetic or hull-geometry key (PaintJob, ShipCockpit, a numbered decal, …), or when it is a ModularCargoBayDoor* article in the cargo-hatch mount — the catalogue carries that one built-in article once, for every hull family that names its own symbol.

Everything else is normalized, and every change is recorded by importOutcomes. An unresolved module in a hardpoint, utility, optional internal or unrecognised slot is discarded. Armour, all seven core internals and the cargo hatch are fixed mounts: an unresolved module there is replaced with the hull's stock module, which keeps the source's On, Priority and Health and none of its engineering or captured value. A fixed mount the event names no module for is left empty, and validation reports an incomplete build where such a mount is required — the cargo hatch excepted, which is part of the hull rather than an outfitting choice and is restored from the hull's default loadout.

Normalization makes the captured aggregates untrustworthy, so the event's figures are dropped: unladenMass, cargoCapacity and fuelCapacity are recomputed from the fit that remains, while modulesValue and rebuy read null — no catalogue records what the discarded module was bought for — and sourcePurchase still reports the captured figures. The cargo hatch is the exception, being weightless and free: restoring an absent one, or importing a hull-family hatch the catalogue resolves, leaves every figure standing. Replacing an unresolved hatch does not, and source-credit export then keeps its totals only when that hatch was unpriced or valued at zero.

Use this factory rather than replaying a complete loadout through the incremental setModule editor.

Throws

If the event is not shaped like one. What is checked is the structure a build is assembled from, and the types of the fields naming things in it: event must be an object with an array of module objects in Modules; each module needs a string Slot and Item, and no two may claim the same slot; a module's Engineering must be an object, and that block's Modifiers an array of objects each carrying a string Label, whenever their key is there at all; event.Ship must name a known hull; the block's BlueprintName and its ExperimentalEffect must be strings when they carry a value. Every remaining field — every number, every flag, a modifier's value beside its label — is trusted, so use ShipLoadout.fromSlef (or parseSlef) for input you did not produce, which reports all of them.

A modifier's Label is required rather than checked-when-present because it is the only thing saying which stat moved: fittedModuleAt and the pre-engineered identification both read it unconditionally, so an entry without one would import cleanly and then break the build it produced.

Ship, Engineering and Modifiers are fields where null is not an omission: Ship is required, while a relay writing null for an optional block or list it does not have would otherwise be read as one. A partial Engineering block is accepted because a capture may state modifiers without naming the recipe.


fromSlef()

static fromSlef(input, index?): ShipLoadout

Defined in: src/ships/ship-loadout.ts:783

Build from a SLEF export.

Parameters

input

unknown

The SLEF JSON string, or an already-parsed SLEF object (see parseSlef for accepted shapes).

index?

number = 0

Which entry to take when the export holds several builds. Defaults to the first.

Returns

ShipLoadout

The loadout for that entry.

Remarks

Module normalization follows ShipLoadout.fromLoadout; inspect importOutcomes for modules that were emptied or defaulted.

Throws

If input is a string that is not valid JSON.

Throws

If the export holds no usable loadout, index is out of range, or the selected entry names a hull absent from the catalogue.

API

Guides
astro
Classes (1)
ProceduralSystem

Properties

Accessors

Methods

Interfaces (16)
Type Aliases (3)
Variables (11)
Functions (37)
Subpath modules (3)
commodities
Interfaces (1)
Type Aliases (1)
Variables (3)
Functions (3)
equipment
Interfaces (6)
Type Aliases (8)
Variables (3)
Functions (10)
Subpath modules (2)
i18n
Interfaces (1)
Type Aliases (1)
Functions (17)
materials
Enumerations (2)
Interfaces (2)
Type Aliases (2)
Variables (9)
Functions (9)
ships
Classes (3)
BuildMetrics

Methods

LoadoutEditError

Constructors

Properties

Methods

ShipLoadout

Accessors

Methods

Interfaces (125)
Type Aliases (44)
Variables (10)
Functions (85)
Subpath modules (8)

Clone this wiki locally