@elite-dangerous-almanac/core 0.1.0-beta.9 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/PROVENANCE/i18n/SOURCES.md +71 -12
- package/PROVENANCE/ships/SOURCES.md +74 -48
- package/README.md +34 -2
- package/THIRD_PARTY_NOTICES.md +3 -3
- package/dist/astro/codex-region-lookup.js +1 -1
- package/dist/astro/codex-region.js +1 -1
- package/dist/astro/galaxy-grid.js +1 -1
- package/dist/astro/index.js +1 -1
- package/dist/astro/mass-code.js +1 -1
- package/dist/astro/naming-region-origins.js +1 -1
- package/dist/astro/nebulae.js +1 -1
- package/dist/astro/permit-locked-regions.js +1 -1
- package/dist/astro/permit-locked-systems.js +1 -1
- package/dist/astro/permit-locks.js +1 -1
- package/dist/astro/procedural-system.js +1 -1
- package/dist/astro/sector-name.js +1 -1
- package/dist/astro/system-address-input.js +1 -1
- package/dist/astro/system-address.js +1 -1
- package/dist/astro/system-name.js +1 -1
- package/dist/{chunk-KQDJTDLV.js → chunk-2J2UV4ZX.js} +1 -1
- package/dist/{chunk-DB54PH3X.js → chunk-6EPYVBAX.js} +1 -1
- package/dist/{chunk-U6TMCYA6.js → chunk-6EUVIZAS.js} +1 -1
- package/dist/chunk-6RLMBSXE.js +1 -0
- package/dist/chunk-6RLMBSXE.js.map +1 -0
- package/dist/{chunk-NWPK6Q3S.js → chunk-ADLVPKUV.js} +1 -1
- package/dist/{chunk-S4DBNX2B.js → chunk-BKWLI44T.js} +1 -1
- package/dist/chunk-BMM6GQAU.js +1 -0
- package/dist/chunk-BMM6GQAU.js.map +1 -0
- package/dist/{chunk-WV5YM7H5.js → chunk-BMT3U46U.js} +1 -1
- package/dist/chunk-CTJQPQRA.js +1 -0
- package/dist/{chunk-NSSWYRHN.js.map → chunk-CTJQPQRA.js.map} +1 -1
- package/dist/chunk-DAQ3PJ4R.js +1 -0
- package/dist/chunk-DAQ3PJ4R.js.map +1 -0
- package/dist/{chunk-BTPV5CIF.js → chunk-DI5RXSJR.js} +1 -1
- package/dist/{chunk-YDBRGW4G.js → chunk-DLLBARN5.js} +1 -1
- package/dist/{chunk-J2PNZQY4.js → chunk-DVL5RBKX.js} +1 -1
- package/dist/{chunk-VXVUEF5U.js → chunk-E3BRVGJJ.js} +1 -1
- package/dist/{chunk-MFV4VZFP.js → chunk-EBAHNZ36.js} +1 -1
- package/dist/{chunk-BSOIPL4A.js → chunk-EJMNNQIS.js} +1 -1
- package/dist/{chunk-BSOIPL4A.js.map → chunk-EJMNNQIS.js.map} +1 -1
- package/dist/{chunk-QF3NYGUJ.js → chunk-EKWLAHRG.js} +1 -1
- package/dist/chunk-EU42PAV4.js +1 -0
- package/dist/{chunk-32PVERNH.js.map → chunk-EU42PAV4.js.map} +1 -1
- package/dist/{chunk-Q22LXT53.js → chunk-FEER4ERG.js} +1 -1
- package/dist/{chunk-G3AMKCOE.js → chunk-FGNJ7EVM.js} +1 -1
- package/dist/{chunk-JWJ7RSZC.js → chunk-G3265B27.js} +1 -1
- package/dist/chunk-GKDEI2SQ.js +1 -0
- package/dist/chunk-GKDEI2SQ.js.map +1 -0
- package/dist/chunk-GOMBLS2T.js +1 -0
- package/dist/chunk-GOMBLS2T.js.map +1 -0
- package/dist/{chunk-V3DW67W2.js → chunk-GRIK3EDH.js} +1 -1
- package/dist/chunk-H3HMVGEY.js +1 -0
- package/dist/chunk-H3HMVGEY.js.map +1 -0
- package/dist/{chunk-UXZJMZEU.js → chunk-HRVIHQ4A.js} +1 -1
- package/dist/{chunk-QTDBO7R2.js → chunk-IYU4WLFM.js} +1 -1
- package/dist/{chunk-5EUX3L76.js → chunk-JWWYAMGD.js} +1 -1
- package/dist/chunk-KAA4VOOB.js +1 -0
- package/dist/chunk-KAA4VOOB.js.map +1 -0
- package/dist/{chunk-ZFT56QFR.js → chunk-L7CLUYZ6.js} +1 -1
- package/dist/{chunk-4AE22CHV.js → chunk-M5IBENCW.js} +1 -1
- package/dist/chunk-M5IBENCW.js.map +1 -0
- package/dist/{chunk-IH4NXKVW.js → chunk-NEEFT7WH.js} +1 -1
- package/dist/{chunk-VZXL5KBR.js → chunk-NLBUKXNV.js} +1 -1
- package/dist/{chunk-4OSCSACF.js → chunk-OCND33TO.js} +1 -1
- package/dist/{chunk-PMJG7PHU.js → chunk-PHPLZEFS.js} +1 -1
- package/dist/chunk-PKWVG2JY.js +1 -0
- package/dist/chunk-PKWVG2JY.js.map +1 -0
- package/dist/chunk-PNZCLQDJ.js +1 -0
- package/dist/{chunk-53ERRGPM.js.map → chunk-PNZCLQDJ.js.map} +1 -1
- package/dist/{chunk-DACZE3HX.js → chunk-POZTXBSN.js} +1 -1
- package/dist/chunk-Q4E2V6RE.js +1 -0
- package/dist/chunk-Q4E2V6RE.js.map +1 -0
- package/dist/{chunk-DNTN34M4.js → chunk-QI22FKBG.js} +1 -1
- package/dist/chunk-QTZPA2FR.js +1 -0
- package/dist/{chunk-TH4S5MVD.js.map → chunk-QTZPA2FR.js.map} +1 -1
- package/dist/{chunk-MNXWK7PA.js → chunk-R26GVRMI.js} +1 -1
- package/dist/{chunk-I7PIDRMU.js → chunk-RAO35XDF.js} +1 -1
- package/dist/chunk-TFPIPIMU.js +1 -0
- package/dist/chunk-TFPIPIMU.js.map +1 -0
- package/dist/chunk-TLA6LHLN.js +1 -0
- package/dist/{chunk-V4C6FIE2.js.map → chunk-TLA6LHLN.js.map} +1 -1
- package/dist/{chunk-JYQE53FL.js → chunk-TMMGS6TC.js} +1 -1
- package/dist/{chunk-ZAHNOQGG.js → chunk-UBYO7VZR.js} +1 -1
- package/dist/{chunk-Z4GTTB7I.js → chunk-UXBCLFGU.js} +1 -1
- package/dist/{chunk-RKLJ7EEE.js → chunk-UXFMVZAY.js} +1 -1
- package/dist/chunk-VB3XZGIB.js +1 -0
- package/dist/chunk-VB3XZGIB.js.map +1 -0
- package/dist/chunk-VKN65H2U.js +1 -0
- package/dist/chunk-VKN65H2U.js.map +1 -0
- package/dist/chunk-VSNS7Y3M.js +1 -0
- package/dist/chunk-VSNS7Y3M.js.map +1 -0
- package/dist/{chunk-MPZGCTRG.js → chunk-VZZUNSDF.js} +1 -1
- package/dist/chunk-VZZUNSDF.js.map +1 -0
- package/dist/{chunk-ZJB5UYNE.js → chunk-W5G2NUCZ.js} +1 -1
- package/dist/{chunk-ZJB5UYNE.js.map → chunk-W5G2NUCZ.js.map} +1 -1
- package/dist/{chunk-IJRKEODR.js → chunk-WNGQ3IAM.js} +1 -1
- package/dist/{chunk-VARPO47V.js → chunk-XN6Q7LWU.js} +1 -1
- package/dist/chunk-XT6KKGSE.js +1 -0
- package/dist/chunk-XT6KKGSE.js.map +1 -0
- package/dist/{chunk-KMFUCORC.js → chunk-Y6UZWNP4.js} +1 -1
- package/dist/{chunk-QMQHIZGS.js → chunk-YU5GND2Q.js} +1 -1
- package/dist/chunk-YU5GND2Q.js.map +1 -0
- package/dist/commodities/commodities.js +1 -1
- package/dist/commodities/index.js +1 -1
- package/dist/equipment/index.js +1 -1
- package/dist/equipment/modification-costs.js +1 -1
- package/dist/equipment/modification-journal.js +1 -1
- package/dist/equipment/modifications.js +1 -1
- package/dist/equipment/suits.js +1 -1
- package/dist/equipment/upgrade-costs.js +1 -1
- package/dist/equipment/weapons.js +1 -1
- package/dist/i18n/blueprints.js +1 -1
- package/dist/i18n/diagnostics.d.ts +62 -0
- package/dist/i18n/diagnostics.js +1 -0
- package/dist/i18n/diagnostics.js.map +1 -0
- package/dist/i18n/engineering-groups.d.ts +20 -0
- package/dist/i18n/engineering-groups.js +1 -0
- package/dist/i18n/engineering-groups.js.map +1 -0
- package/dist/i18n/experimental-effect-descriptions.d.ts +20 -0
- package/dist/i18n/experimental-effect-descriptions.js +1 -0
- package/dist/i18n/experimental-effect-descriptions.js.map +1 -0
- package/dist/i18n/experimental-effects.js +1 -1
- package/dist/i18n/index.d.ts +27 -0
- package/dist/i18n/index.js +1 -1
- package/dist/i18n/materials.js +1 -1
- package/dist/i18n/micro-resources.js +1 -1
- package/dist/i18n/modules.js +1 -1
- package/dist/i18n/pre-engineered.d.ts +39 -0
- package/dist/i18n/pre-engineered.js +1 -0
- package/dist/i18n/pre-engineered.js.map +1 -0
- package/dist/i18n/ships.d.ts +36 -0
- package/dist/i18n/ships.js +1 -0
- package/dist/i18n/ships.js.map +1 -0
- package/dist/i18n/slots.d.ts +42 -0
- package/dist/i18n/slots.js +1 -0
- package/dist/i18n/slots.js.map +1 -0
- package/dist/materials/index.js +1 -1
- package/dist/materials/materials-all.js +1 -1
- package/dist/materials/materials.js +1 -1
- package/dist/materials/micro-resources-all.js +1 -1
- package/dist/materials/micro-resources.js +1 -1
- package/dist/ships/blueprint-costs.d.ts +13 -11
- package/dist/ships/blueprint-costs.js +1 -1
- package/dist/ships/blueprint-costs.js.map +1 -1
- package/dist/ships/blueprint-journal.d.ts +6 -7
- package/dist/ships/blueprint-journal.js +1 -1
- package/dist/ships/blueprints.js +1 -1
- package/dist/ships/default-loadouts.js +1 -1
- package/dist/ships/engineering-options.d.ts +28 -29
- package/dist/ships/engineering-options.js +1 -1
- package/dist/ships/experimental-effect-costs.js +1 -1
- package/dist/ships/experimental-effects.js +1 -1
- package/dist/ships/gunsights.js +1 -1
- package/dist/ships/heat.d.ts +22 -0
- package/dist/ships/heat.js +1 -1
- package/dist/ships/index.d.ts +6 -5
- package/dist/ships/index.js +1 -1
- package/dist/ships/loadout-calculations.d.ts +21 -11
- package/dist/ships/loadout-calculations.js +1 -1
- package/dist/ships/loadout-validation.d.ts +7 -6
- package/dist/ships/loadout-validation.js +1 -1
- package/dist/ships/modules-all.js +1 -1
- package/dist/ships/modules-hardpoint.js +1 -1
- package/dist/ships/modules-internal.js +1 -1
- package/dist/ships/modules.d.ts +5 -5
- package/dist/ships/modules.js +1 -1
- package/dist/ships/power.d.ts +39 -11
- package/dist/ships/power.js +1 -1
- package/dist/ships/pre-engineered-stats.d.ts +20 -4
- package/dist/ships/pre-engineered-stats.js +1 -1
- package/dist/ships/pre-engineered.d.ts +7 -8
- package/dist/ships/pre-engineered.js +1 -1
- package/dist/ships/shield-recovery.d.ts +12 -6
- package/dist/ships/shield-recovery.js +1 -1
- package/dist/ships/ship-loadout.d.ts +1793 -19
- package/dist/ships/ship-loadout.js +1 -1
- package/dist/ships/ships.js +1 -1
- package/dist/ships/slef.js +1 -1
- package/dist/ships/slots.js +1 -1
- package/dist/ships/source-purchase.js +1 -1
- package/package.json +26 -2
- package/dist/chunk-32PVERNH.js +0 -1
- package/dist/chunk-4AE22CHV.js.map +0 -1
- package/dist/chunk-4WC5NHBJ.js +0 -1
- package/dist/chunk-4WC5NHBJ.js.map +0 -1
- package/dist/chunk-53ERRGPM.js +0 -1
- package/dist/chunk-5W43EQEQ.js +0 -1
- package/dist/chunk-5W43EQEQ.js.map +0 -1
- package/dist/chunk-76XKY2Y2.js +0 -1
- package/dist/chunk-76XKY2Y2.js.map +0 -1
- package/dist/chunk-B5TT26XE.js +0 -1
- package/dist/chunk-B5TT26XE.js.map +0 -1
- package/dist/chunk-BYBT5XSW.js +0 -1
- package/dist/chunk-BYBT5XSW.js.map +0 -1
- package/dist/chunk-KLIYDSYF.js +0 -1
- package/dist/chunk-KLIYDSYF.js.map +0 -1
- package/dist/chunk-MPZGCTRG.js.map +0 -1
- package/dist/chunk-NSSWYRHN.js +0 -1
- package/dist/chunk-QMQHIZGS.js.map +0 -1
- package/dist/chunk-RF2IKLWQ.js +0 -1
- package/dist/chunk-RF2IKLWQ.js.map +0 -1
- package/dist/chunk-TH4S5MVD.js +0 -1
- package/dist/chunk-V4C6FIE2.js +0 -1
- package/dist/ship-loadout-BsfKbvKe.d.ts +0 -1455
- /package/dist/{chunk-KQDJTDLV.js.map → chunk-2J2UV4ZX.js.map} +0 -0
- /package/dist/{chunk-DB54PH3X.js.map → chunk-6EPYVBAX.js.map} +0 -0
- /package/dist/{chunk-U6TMCYA6.js.map → chunk-6EUVIZAS.js.map} +0 -0
- /package/dist/{chunk-NWPK6Q3S.js.map → chunk-ADLVPKUV.js.map} +0 -0
- /package/dist/{chunk-S4DBNX2B.js.map → chunk-BKWLI44T.js.map} +0 -0
- /package/dist/{chunk-WV5YM7H5.js.map → chunk-BMT3U46U.js.map} +0 -0
- /package/dist/{chunk-BTPV5CIF.js.map → chunk-DI5RXSJR.js.map} +0 -0
- /package/dist/{chunk-YDBRGW4G.js.map → chunk-DLLBARN5.js.map} +0 -0
- /package/dist/{chunk-J2PNZQY4.js.map → chunk-DVL5RBKX.js.map} +0 -0
- /package/dist/{chunk-VXVUEF5U.js.map → chunk-E3BRVGJJ.js.map} +0 -0
- /package/dist/{chunk-MFV4VZFP.js.map → chunk-EBAHNZ36.js.map} +0 -0
- /package/dist/{chunk-QF3NYGUJ.js.map → chunk-EKWLAHRG.js.map} +0 -0
- /package/dist/{chunk-Q22LXT53.js.map → chunk-FEER4ERG.js.map} +0 -0
- /package/dist/{chunk-G3AMKCOE.js.map → chunk-FGNJ7EVM.js.map} +0 -0
- /package/dist/{chunk-JWJ7RSZC.js.map → chunk-G3265B27.js.map} +0 -0
- /package/dist/{chunk-V3DW67W2.js.map → chunk-GRIK3EDH.js.map} +0 -0
- /package/dist/{chunk-UXZJMZEU.js.map → chunk-HRVIHQ4A.js.map} +0 -0
- /package/dist/{chunk-QTDBO7R2.js.map → chunk-IYU4WLFM.js.map} +0 -0
- /package/dist/{chunk-5EUX3L76.js.map → chunk-JWWYAMGD.js.map} +0 -0
- /package/dist/{chunk-ZFT56QFR.js.map → chunk-L7CLUYZ6.js.map} +0 -0
- /package/dist/{chunk-IH4NXKVW.js.map → chunk-NEEFT7WH.js.map} +0 -0
- /package/dist/{chunk-VZXL5KBR.js.map → chunk-NLBUKXNV.js.map} +0 -0
- /package/dist/{chunk-4OSCSACF.js.map → chunk-OCND33TO.js.map} +0 -0
- /package/dist/{chunk-PMJG7PHU.js.map → chunk-PHPLZEFS.js.map} +0 -0
- /package/dist/{chunk-DACZE3HX.js.map → chunk-POZTXBSN.js.map} +0 -0
- /package/dist/{chunk-DNTN34M4.js.map → chunk-QI22FKBG.js.map} +0 -0
- /package/dist/{chunk-MNXWK7PA.js.map → chunk-R26GVRMI.js.map} +0 -0
- /package/dist/{chunk-I7PIDRMU.js.map → chunk-RAO35XDF.js.map} +0 -0
- /package/dist/{chunk-JYQE53FL.js.map → chunk-TMMGS6TC.js.map} +0 -0
- /package/dist/{chunk-ZAHNOQGG.js.map → chunk-UBYO7VZR.js.map} +0 -0
- /package/dist/{chunk-Z4GTTB7I.js.map → chunk-UXBCLFGU.js.map} +0 -0
- /package/dist/{chunk-RKLJ7EEE.js.map → chunk-UXFMVZAY.js.map} +0 -0
- /package/dist/{chunk-IJRKEODR.js.map → chunk-WNGQ3IAM.js.map} +0 -0
- /package/dist/{chunk-VARPO47V.js.map → chunk-XN6Q7LWU.js.map} +0 -0
- /package/dist/{chunk-KMFUCORC.js.map → chunk-Y6UZWNP4.js.map} +0 -0
|
@@ -1,1455 +0,0 @@
|
|
|
1
|
-
import { ModuleEngineering, LoadoutModule, LoadoutEvent, SlefHeader, Slef } from './ships/slef.js';
|
|
2
|
-
import { TotalRangeDetails, FrameShiftDriveParams } from './ships/jump-range.js';
|
|
3
|
-
import { BuildSlot, SlotKind } from './ships/slots.js';
|
|
4
|
-
import { OutfittingModule } from './ships/modules.js';
|
|
5
|
-
import { PowerBudget } from './ships/power.js';
|
|
6
|
-
import { HeatMetrics } from './ships/heat.js';
|
|
7
|
-
import { ShieldMetrics } from './ships/shields.js';
|
|
8
|
-
import { ArmourMetrics } from './ships/armour.js';
|
|
9
|
-
import { WeaponMetrics, WeaponTotals } from './ships/weapons.js';
|
|
10
|
-
import { AmmunitionCapacity } from './ships/ammunition.js';
|
|
11
|
-
import { WeaponsCapacitorMetrics } from './ships/weapons-capacitor.js';
|
|
12
|
-
import { DistributorMetrics } from './ships/distributor.js';
|
|
13
|
-
import { MobilityMetrics } from './ships/mobility.js';
|
|
14
|
-
import { ShieldRecovery, CellBankSummary } from './ships/shield-recovery.js';
|
|
15
|
-
import { PreEngineeredVariant } from './ships/pre-engineered.js';
|
|
16
|
-
import { SourcePurchaseRecord } from './ships/source-purchase.js';
|
|
17
|
-
import { CalculationResult, FuelCapacity } from './ships/loadout-calculations.js';
|
|
18
|
-
import { ModuleFitConstraint, LoadoutIssueParams, LoadoutValidation } from './ships/loadout-validation.js';
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Immutable fitted-module snapshots returned by {@link ShipLoadout}.
|
|
22
|
-
*
|
|
23
|
-
* @packageDocumentation
|
|
24
|
-
*/
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* A point-in-time, deeply frozen view of the module fitted in one slot.
|
|
28
|
-
*
|
|
29
|
-
* The view is detached from its {@link ShipLoadout}: later edits do not change it, and
|
|
30
|
-
* mutating it throws. Fetch a new view with {@link ShipLoadout.fittedModuleAt} after an
|
|
31
|
-
* state-changing edit; reads made without an intervening state change reuse the same
|
|
32
|
-
* frozen snapshot. All mutations live on `ShipLoadout`, keyed by {@link slot}; this
|
|
33
|
-
* avoids the stale-handle lifecycle that a live proxy would otherwise need.
|
|
34
|
-
*
|
|
35
|
-
* @example
|
|
36
|
-
* ```ts
|
|
37
|
-
* import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
|
|
38
|
-
*
|
|
39
|
-
* declare const build: ShipLoadout;
|
|
40
|
-
*
|
|
41
|
-
* const before = build.fittedModuleAt('FrameShiftDrive')!;
|
|
42
|
-
* build.applyBlueprint(before.slot, 'FSD_LongRange', { grade: 5 });
|
|
43
|
-
* const after = build.fittedModuleAt(before.slot)!;
|
|
44
|
-
* before.engineering; // unchanged
|
|
45
|
-
* after.engineering; // the applied blueprint
|
|
46
|
-
* ```
|
|
47
|
-
*/
|
|
48
|
-
interface FittedModule {
|
|
49
|
-
/** Slot key in the build's own spelling. */
|
|
50
|
-
readonly slot: string;
|
|
51
|
-
/** Frontier module symbol, e.g. `"Int_Hyperdrive_Size6_Class5"`. */
|
|
52
|
-
readonly symbol: string;
|
|
53
|
-
/** Whether the module was powered on, or `undefined` when unspecified. */
|
|
54
|
-
readonly on: boolean | undefined;
|
|
55
|
-
/** Zero-based power-priority group, or `undefined` when unspecified. */
|
|
56
|
-
readonly priority: number | undefined;
|
|
57
|
-
/** Module health in `[0, 1]`, or `undefined` when unspecified. */
|
|
58
|
-
readonly health: number | undefined;
|
|
59
|
-
/** Captured purchase value in credits, or `undefined` when unspecified. */
|
|
60
|
-
readonly value: number | undefined;
|
|
61
|
-
/** Applied engineering state; otherwise `undefined`. */
|
|
62
|
-
readonly engineering: ModuleEngineering | undefined;
|
|
63
|
-
/** Detached, journal-shaped fitted record. */
|
|
64
|
-
readonly raw: LoadoutModule;
|
|
65
|
-
/**
|
|
66
|
-
* Snapshotted fitted-article stats before its journal modifier block is folded, or
|
|
67
|
-
* `null` when unresolved.
|
|
68
|
-
*
|
|
69
|
-
* A stock or ordinarily engineered module exposes its base catalogue record. A fixed
|
|
70
|
-
* pre-engineered variant exposes its resolved article record here as well as through
|
|
71
|
-
* {@link effectiveStats}, so stats omitted by a journal capture still describe the
|
|
72
|
-
* article. Clearing or replacing that fixed engineering restores the stock record
|
|
73
|
-
* before applying the next recipe.
|
|
74
|
-
*/
|
|
75
|
-
readonly stats: OutfittingModule | null;
|
|
76
|
-
/**
|
|
77
|
-
* Post-engineering module stats, or `null` when unresolved. For weapons, journal
|
|
78
|
-
* damage per second is resolved back to per-round damage and falloff is capped at
|
|
79
|
-
* maximum range. Exact damage components follow the engineered total and disappear
|
|
80
|
-
* when a damage conversion replaces them with a fractional distribution.
|
|
81
|
-
* A module engineered through {@link ShipLoadout.applyBlueprint} also retains
|
|
82
|
-
* recipe-only burst values that its journal-shaped modifier block does not serialize.
|
|
83
|
-
* A festive variant fitted through {@link ShipLoadout.setPreEngineeredVariant} uses
|
|
84
|
-
* its fixed modifier block.
|
|
85
|
-
*/
|
|
86
|
-
readonly effectiveStats: OutfittingModule | null;
|
|
87
|
-
/** Fully rearmed ammunition capacity, or `null` for modules without ammunition. */
|
|
88
|
-
readonly ammunition: AmmunitionCapacity | null;
|
|
89
|
-
/** Identified fixed pre-engineered variant, or `null` when not uniquely identified. */
|
|
90
|
-
readonly preEngineeredVariant: PreEngineeredVariant | null;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* Immutable slot snapshots returned by {@link ShipLoadout}.
|
|
95
|
-
*
|
|
96
|
-
* @packageDocumentation
|
|
97
|
-
*/
|
|
98
|
-
|
|
99
|
-
/** Stable reason a hull mount cannot be emptied through {@link ShipLoadout.removeModule}. */
|
|
100
|
-
type ImmovableReason = 'cargoHatch' | 'moduleLimit';
|
|
101
|
-
/**
|
|
102
|
-
* A point-in-time, deeply frozen view of one hull mount.
|
|
103
|
-
*
|
|
104
|
-
* The view is detached from its {@link ShipLoadout}; after an edit that changes the
|
|
105
|
-
* build, call {@link ShipLoadout.slots} again for the current view. Reads made without an
|
|
106
|
-
* intervening state change reuse the same frozen snapshots. Mutations and candidate
|
|
107
|
-
* filtering stay on `ShipLoadout` and take the slot `key`, leaving this value serializable
|
|
108
|
-
* and free of lifecycle rules.
|
|
109
|
-
*
|
|
110
|
-
* @example
|
|
111
|
-
* Walking a build's mounts. Slot keys come from the game and are not derivable from
|
|
112
|
-
* position, so read the slot's `key` rather than composing one.
|
|
113
|
-
*
|
|
114
|
-
* ```ts
|
|
115
|
-
* import { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
|
|
116
|
-
* import type { LoadoutEvent } from '@elite-dangerous-almanac/core/ships/slef';
|
|
117
|
-
*
|
|
118
|
-
* declare const event: LoadoutEvent;
|
|
119
|
-
*
|
|
120
|
-
* // Figures below are one build's — a Federal Corvette.
|
|
121
|
-
* const build = ShipLoadout.fromLoadout(event);
|
|
122
|
-
*
|
|
123
|
-
* build.slots().length; // -> 38 every mount on the hull
|
|
124
|
-
* build.slots('hardpoint').length; // -> 7
|
|
125
|
-
*
|
|
126
|
-
* const first = build.slots('hardpoint')[0];
|
|
127
|
-
* first?.key; // -> 'HugeHardpoint1' what ShipLoadout.setModule takes
|
|
128
|
-
* first?.name; // -> 'Huge Hardpoint 1' what a UI shows
|
|
129
|
-
* first?.size; // -> 4
|
|
130
|
-
* first?.module?.symbol; // -> 'hpt_beamlaser_gimbal_huge'; undefined when the mount is empty
|
|
131
|
-
* ```
|
|
132
|
-
*
|
|
133
|
-
* @example
|
|
134
|
-
* The view is a snapshot, not a handle — re-read it after an edit.
|
|
135
|
-
*
|
|
136
|
-
* ```ts
|
|
137
|
-
* import { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
|
|
138
|
-
* import { HARDPOINT_MODULES } from '@elite-dangerous-almanac/core/ships/modules-hardpoint';
|
|
139
|
-
* import { getModuleBySymbol } from '@elite-dangerous-almanac/core/ships/modules';
|
|
140
|
-
*
|
|
141
|
-
* const build = ShipLoadout.empty('Sidewinder');
|
|
142
|
-
* const before = build.slots('hardpoint')[0];
|
|
143
|
-
* before?.key; // -> 'SmallHardpoint1'
|
|
144
|
-
* before?.module; // -> null
|
|
145
|
-
*
|
|
146
|
-
* const pulse = getModuleBySymbol('Hpt_PulseLaser_Fixed_Small', HARDPOINT_MODULES);
|
|
147
|
-
* if (pulse) build.setModule('SmallHardpoint1', pulse);
|
|
148
|
-
*
|
|
149
|
-
* before?.module; // -> still null — `before` describes the build as it was
|
|
150
|
-
* build.slots('hardpoint')[0]?.module?.symbol; // -> 'Hpt_PulseLaser_Fixed_Small'
|
|
151
|
-
* ```
|
|
152
|
-
*/
|
|
153
|
-
type LoadoutSlot = BuildSlot & {
|
|
154
|
-
/** Human-readable label, e.g. `"Frame Shift Drive"`. */
|
|
155
|
-
readonly name: string;
|
|
156
|
-
/** Frozen fitted-module snapshot, or `null` when this mount is empty. */
|
|
157
|
-
readonly module: FittedModule | null;
|
|
158
|
-
/** Whether {@link ShipLoadout.removeModule} may empty this mount. */
|
|
159
|
-
readonly removable: boolean;
|
|
160
|
-
/**
|
|
161
|
-
* Machine-readable reason the mount cannot currently be emptied: `cargoHatch` for
|
|
162
|
-
* the built-in hatch, or `moduleLimit` when removing a fitted allowance-increasing
|
|
163
|
-
* module would leave too many limited modules. Absent when {@link removable} is true.
|
|
164
|
-
*/
|
|
165
|
-
readonly immovableReason?: ImmovableReason;
|
|
166
|
-
};
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* {@link ShipLoadout} — a mutable fitted-ship model that both **answers questions**
|
|
170
|
-
* about a build and **edits** it.
|
|
171
|
-
*
|
|
172
|
-
* Load one from a SLEF export (or a journal `Loadout` event) to read back the ship's
|
|
173
|
-
* identity, mass and fuel and ask for jump range and per-jump fuel; or start an
|
|
174
|
-
* {@link ShipLoadout.default | default} or {@link ShipLoadout.empty | empty} hull,
|
|
175
|
-
* enumerate its {@link ShipLoadout.slots | slots}, and
|
|
176
|
-
* {@link ShipLoadout.setModule | fit} and {@link ShipLoadout.removeModule | remove}
|
|
177
|
-
* modules. It composes the data-free pieces of this folder — the SLEF parser
|
|
178
|
-
* (`./slef`), the jump-range maths (`./jump-range`), the slot model (`./slots`), and
|
|
179
|
-
* the module and ship catalogues (each record carrying its own stats).
|
|
180
|
-
*
|
|
181
|
-
* Instances are **mutable**: `setModule`/`removeModule` change the build in place and
|
|
182
|
-
* return `this` for chaining. Values a SLEF export already computed (its
|
|
183
|
-
* `UnladenMass`, `FuelCapacity`, …) are trusted verbatim; for a build assembled from
|
|
184
|
-
* scratch those figures are computed from the fitted modules and the hull's stats.
|
|
185
|
-
* Editing an imported build adjusts the supplied aggregate figures by the changed
|
|
186
|
-
* module's contribution; when that contribution is unknown, the affected figure is
|
|
187
|
-
* discarded and recomputed rather than allowed to go stale.
|
|
188
|
-
* `setModule` snapshots the complete record it receives, including resolved
|
|
189
|
-
* pre-engineered or caller-supplied stats, so every later metric uses the article that
|
|
190
|
-
* was actually fitted rather than resolving its symbol back to a stock module.
|
|
191
|
-
* Slot and fitted-module queries return deeply frozen point-in-time values; edits are
|
|
192
|
-
* made only through this facade, then observed by querying again.
|
|
193
|
-
*
|
|
194
|
-
* **Slot keys are matched case-insensitively.** Frontier writes `FrameShiftDrive` and
|
|
195
|
-
* `LargeMiningHardpoint1`, but a SLEF producer may lower-case every key as the
|
|
196
|
-
* specification's own example does — Inara writes `frameshiftdrive` and
|
|
197
|
-
* `largemininghardpoint1` — and both spellings name the same mount, whether you are
|
|
198
|
-
* reading it or fitting into it. What a build already carries is never rewritten to
|
|
199
|
-
* match, so re-exporting an import returns the producer's own spelling untouched.
|
|
200
|
-
*
|
|
201
|
-
* @remarks
|
|
202
|
-
* This is the batteries-included ship facade: resolving arbitrary journal module
|
|
203
|
-
* ids and engineering recipes requires the complete ship/module, blueprint, and
|
|
204
|
-
* experimental-effect catalogues. Import `./slef`, `./jump-range`, or an individual
|
|
205
|
-
* module catalogue instead when you only need one data-free operation or one
|
|
206
|
-
* outfitting category.
|
|
207
|
-
*
|
|
208
|
-
* @example
|
|
209
|
-
* ```ts
|
|
210
|
-
* declare const slefJsonString: string;
|
|
211
|
-
*
|
|
212
|
-
* import { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
|
|
213
|
-
*
|
|
214
|
-
* // Read a build:
|
|
215
|
-
* const build = ShipLoadout.fromSlef(slefJsonString);
|
|
216
|
-
* build.maxJumpRange(); // -> 89.41 (best single jump, one jump's fuel, no cargo)
|
|
217
|
-
*
|
|
218
|
-
* // Assemble one:
|
|
219
|
-
* import { getModuleBySymbol } from '@elite-dangerous-almanac/core/ships/modules';
|
|
220
|
-
* import { CORE_MODULES } from '@elite-dangerous-almanac/core/ships/modules-core';
|
|
221
|
-
* const conda = ShipLoadout.empty('Anaconda');
|
|
222
|
-
* conda.setModule('FrameShiftDrive', getModuleBySymbol('Int_Hyperdrive_Size6_Class5', CORE_MODULES)!);
|
|
223
|
-
* conda.slots('optional'); // every optional mount, occupied or empty, with size
|
|
224
|
-
* ```
|
|
225
|
-
*
|
|
226
|
-
* @packageDocumentation
|
|
227
|
-
*/
|
|
228
|
-
|
|
229
|
-
/**
|
|
230
|
-
* Stable machine-readable reason a {@link ShipLoadout} edit was refused:
|
|
231
|
-
* `immutableSlot`, an incompatible fit, a duplicate one-per-ship family, or a module
|
|
232
|
-
* count beyond the build's current allowance.
|
|
233
|
-
*/
|
|
234
|
-
type LoadoutEditErrorCode = 'immutableSlot' | 'incompatibleModule' | 'duplicateExclusiveModule' | 'moduleLimitExceeded';
|
|
235
|
-
/**
|
|
236
|
-
* An editor request that the current hull or build constraints cannot accept.
|
|
237
|
-
*
|
|
238
|
-
* @remarks
|
|
239
|
-
* This remains a `TypeError`, so existing `instanceof TypeError` handling continues to
|
|
240
|
-
* work. Localized editors should switch on {@link code}, then use {@link constraint}
|
|
241
|
-
* and {@link params} instead of parsing the English fallback in `message`.
|
|
242
|
-
*
|
|
243
|
-
* @example
|
|
244
|
-
* ```ts
|
|
245
|
-
* import {
|
|
246
|
-
* LoadoutEditError,
|
|
247
|
-
* ShipLoadout,
|
|
248
|
-
* } from '@elite-dangerous-almanac/core/ships/ship-loadout';
|
|
249
|
-
* import { getModuleBySymbol } from '@elite-dangerous-almanac/core/ships/modules';
|
|
250
|
-
* import { CORE_MODULES } from '@elite-dangerous-almanac/core/ships/modules-core';
|
|
251
|
-
*
|
|
252
|
-
* const build = ShipLoadout.empty('SideWinder');
|
|
253
|
-
* const drive = getModuleBySymbol('Int_Hyperdrive_Size8_Class5', CORE_MODULES)!;
|
|
254
|
-
* try {
|
|
255
|
-
* build.setModule('FrameShiftDrive', drive);
|
|
256
|
-
* } catch (error) {
|
|
257
|
-
* if (error instanceof LoadoutEditError) error.constraint; // -> 'oversized'
|
|
258
|
-
* }
|
|
259
|
-
* ```
|
|
260
|
-
*/
|
|
261
|
-
declare class LoadoutEditError extends TypeError {
|
|
262
|
-
/** Stable category for the refused edit. */
|
|
263
|
-
readonly code: LoadoutEditErrorCode;
|
|
264
|
-
/** More specific fitting rule for an `incompatibleModule` failure. */
|
|
265
|
-
readonly constraint?: ModuleFitConstraint;
|
|
266
|
-
/** Language-neutral values used by the English fallback message. */
|
|
267
|
-
readonly params: LoadoutIssueParams;
|
|
268
|
-
/**
|
|
269
|
-
* Construct a structured loadout-edit error.
|
|
270
|
-
*
|
|
271
|
-
* @param message - English fallback suitable for logs.
|
|
272
|
-
* @param code - Stable category for the refused edit.
|
|
273
|
-
* @param params - Language-neutral values used to render the failure.
|
|
274
|
-
* @param constraint - Specific fitting rule, when `code` is `incompatibleModule`.
|
|
275
|
-
*/
|
|
276
|
-
constructor(message: string, code: LoadoutEditErrorCode, params: LoadoutIssueParams, constraint?: ModuleFitConstraint);
|
|
277
|
-
}
|
|
278
|
-
/** Optional mass overrides for a single calculation. */
|
|
279
|
-
interface JumpOptions {
|
|
280
|
-
/** Finite non-negative fuel load, in tonnes. Defaults to the full main tank. */
|
|
281
|
-
readonly fuel?: number;
|
|
282
|
-
/** Finite non-negative cargo load, in tonnes. Defaults to `0` (unladen). */
|
|
283
|
-
readonly cargo?: number;
|
|
284
|
-
}
|
|
285
|
-
/** Options for {@link ShipLoadout.applyBlueprint}. */
|
|
286
|
-
interface ApplyBlueprintOptions {
|
|
287
|
-
/** The blueprint grade, `1`–`5`. */
|
|
288
|
-
readonly grade: number;
|
|
289
|
-
/**
|
|
290
|
-
* The engineering system's shared quality roll, `0`–`1`. Defaults to `1`
|
|
291
|
-
* (best roll). A legacy-engineered module's independently advanced attributes cannot be
|
|
292
|
-
* reconstructed from its single reported quality; import its stated modifiers instead.
|
|
293
|
-
*/
|
|
294
|
-
readonly quality?: number;
|
|
295
|
-
/** The experimental (special) effect's Frontier `fdname`, if any. */
|
|
296
|
-
readonly experimental?: string;
|
|
297
|
-
}
|
|
298
|
-
/** Options for the defence figures a build reports. */
|
|
299
|
-
interface DefenceOptions {
|
|
300
|
-
/**
|
|
301
|
-
* Pips to the systems capacitor, `0`–`4`, folded into the shield resistances.
|
|
302
|
-
* Defaults to `0` for {@link ShipLoadout.shieldMetrics} and `4` for
|
|
303
|
-
* {@link ShipLoadout.shieldRecovery}.
|
|
304
|
-
*/
|
|
305
|
-
readonly systemsPips?: number;
|
|
306
|
-
}
|
|
307
|
-
/** Optional load and ENG allocation for {@link ShipLoadout.mobilityMetrics}. */
|
|
308
|
-
interface MobilityOptions extends JumpOptions {
|
|
309
|
-
/** Pips assigned to the engines capacitor, `0`–`4`. Defaults to `4`. */
|
|
310
|
-
readonly enginesPips?: number;
|
|
311
|
-
}
|
|
312
|
-
/** Optional WEP allocation for {@link ShipLoadout.weaponsCapacitorMetrics}. */
|
|
313
|
-
interface WeaponsOptions {
|
|
314
|
-
/** Pips assigned to the weapons capacitor, `0`–`4`. Defaults to `4`. */
|
|
315
|
-
readonly weaponsPips?: number;
|
|
316
|
-
}
|
|
317
|
-
/** Optional SYS, ENG and WEP allocations for {@link ShipLoadout.distributorMetrics}. */
|
|
318
|
-
interface DistributorOptions {
|
|
319
|
-
/** Pips assigned to the systems capacitor, `0`–`4`. Defaults to `4`. */
|
|
320
|
-
readonly systemsPips?: number;
|
|
321
|
-
/** Pips assigned to the engines capacitor, `0`–`4`. Defaults to `4`. */
|
|
322
|
-
readonly enginesPips?: number;
|
|
323
|
-
/** Pips assigned to the weapons capacitor, `0`–`4`. Defaults to `4`. */
|
|
324
|
-
readonly weaponsPips?: number;
|
|
325
|
-
}
|
|
326
|
-
/** Retail catalogue credits for an assembled build. */
|
|
327
|
-
interface RetailCredits {
|
|
328
|
-
/** Bare hull list price in credits, or `null` for an unknown hull. */
|
|
329
|
-
readonly hull: number | null;
|
|
330
|
-
/** Sum of every priced fitted module, in credits. A lower bound when `unpriced` is non-empty. */
|
|
331
|
-
readonly modules: number;
|
|
332
|
-
/** Five percent of the priced hull and modules, truncated to credits, or `null` for an unknown hull. */
|
|
333
|
-
readonly rebuy: number | null;
|
|
334
|
-
/** Fitted modules that could not be priced from the catalogue. */
|
|
335
|
-
readonly unpriced: readonly {
|
|
336
|
-
readonly slot: string;
|
|
337
|
-
readonly symbol: string;
|
|
338
|
-
}[];
|
|
339
|
-
}
|
|
340
|
-
/** One fitted weapon and what it does, as {@link ShipLoadout.weaponMetrics} reports it. */
|
|
341
|
-
interface FittedWeaponMetrics {
|
|
342
|
-
/** The hardpoint's slot key, e.g. `"LargeHardpoint1"`. */
|
|
343
|
-
readonly slot: string;
|
|
344
|
-
/** The weapon's internal symbol. */
|
|
345
|
-
readonly symbol: string;
|
|
346
|
-
/** The weapon's display name, e.g. `"Multi-Cannon"`. */
|
|
347
|
-
readonly name: string;
|
|
348
|
-
/** Whether the weapon is switched on — a disabled weapon is excluded from the totals. */
|
|
349
|
-
readonly enabled: boolean;
|
|
350
|
-
/** What this weapon does per second, post-engineering. */
|
|
351
|
-
readonly metrics: WeaponMetrics;
|
|
352
|
-
/**
|
|
353
|
-
* How many rounds it holds when fully rearmed, post-engineering — `null` for a laser,
|
|
354
|
-
* which carries none. A capacity, not a rearm state: see {@link FittedModule.ammunition}.
|
|
355
|
-
*/
|
|
356
|
-
readonly ammunition: AmmunitionCapacity | null;
|
|
357
|
-
}
|
|
358
|
-
/** A build's firepower: every fitted weapon, and the totals across the enabled ones. */
|
|
359
|
-
interface BuildWeaponMetrics {
|
|
360
|
-
/** Every fitted weapon, in slot order. */
|
|
361
|
-
readonly weapons: readonly FittedWeaponMetrics[];
|
|
362
|
-
/** The additive totals across the **enabled** weapons. */
|
|
363
|
-
readonly total: WeaponTotals;
|
|
364
|
-
}
|
|
365
|
-
/**
|
|
366
|
-
* A build's jump ranges at the loads that matter. The three single-jump values and
|
|
367
|
-
* each total result's `range` are in light-years.
|
|
368
|
-
*/
|
|
369
|
-
interface JumpRangeSummary {
|
|
370
|
-
/**
|
|
371
|
-
* Best single jump: no cargo, and only one jump's fuel aboard — the figure the game
|
|
372
|
-
* and EDSY label "maximum jump range".
|
|
373
|
-
*/
|
|
374
|
-
readonly max: number;
|
|
375
|
-
/** Single jump on a full tank with an empty hold. */
|
|
376
|
-
readonly unladen: number;
|
|
377
|
-
/** Single jump on a full tank with a full hold. */
|
|
378
|
-
readonly laden: number;
|
|
379
|
-
/** Summed range and jump count on one jump's fuel, empty hold. */
|
|
380
|
-
readonly totalMax: TotalRangeDetails;
|
|
381
|
-
/** Summed range and jump count on one full tank, empty hold. */
|
|
382
|
-
readonly totalUnladen: TotalRangeDetails;
|
|
383
|
-
/** Summed range and jump count on one full tank, full hold. */
|
|
384
|
-
readonly totalLaden: TotalRangeDetails;
|
|
385
|
-
}
|
|
386
|
-
/** A blueprint candidate for a module symbol, with its grades and availability route. */
|
|
387
|
-
interface AvailableBlueprint {
|
|
388
|
-
/** The blueprint's Frontier `fdname`, e.g. `"FSD_LongRange"`. */
|
|
389
|
-
readonly fdname: string;
|
|
390
|
-
/** The grades the blueprint offers, ascending (e.g. `[1, 2, 3, 4, 5]`). */
|
|
391
|
-
readonly grades: readonly number[];
|
|
392
|
-
/**
|
|
393
|
-
* Why the recipe is listed: `'ordinary'` for the stock module's engineering menu,
|
|
394
|
-
* or `'mercenary'` for a bespoke recipe attached to a Mercenary purchase.
|
|
395
|
-
*
|
|
396
|
-
* @remarks
|
|
397
|
-
* A Mercenary article shares its module symbol with the stock article, so a loadout
|
|
398
|
-
* cannot tell which one was purchased. `'mercenary'` means the recipe is available
|
|
399
|
-
* only through that purchase route; it does not identify the fitted article as one.
|
|
400
|
-
*/
|
|
401
|
-
readonly route: 'ordinary' | 'mercenary';
|
|
402
|
-
}
|
|
403
|
-
/** How to shape a build on the way out — see {@link ShipLoadout.toLoadoutEvent}. */
|
|
404
|
-
interface LoadoutExportOptions {
|
|
405
|
-
/**
|
|
406
|
-
* Module order. `'fitted'` — the default — keeps the order the build carries: an
|
|
407
|
-
* import's own `Modules[]` order, or the order modules were fitted. `'slots'`
|
|
408
|
-
* re-orders into outfitting-panel order; a module in a slot the hull's layout does
|
|
409
|
-
* not describe keeps its relative position at the end rather than being dropped.
|
|
410
|
-
*/
|
|
411
|
-
readonly moduleOrder?: 'fitted' | 'slots';
|
|
412
|
-
/**
|
|
413
|
-
* Write `On: true` / `Priority: 0` on modules that carry neither — as a journal
|
|
414
|
-
* always does and a build assembled here never does. Off by default, following
|
|
415
|
-
* SLEF's "require what is necessary, do not force the rest".
|
|
416
|
-
*/
|
|
417
|
-
readonly explicitPower?: boolean;
|
|
418
|
-
/**
|
|
419
|
-
* Which credits to quote. `'retail'` — the default — prices the build from the
|
|
420
|
-
* catalogue: the bare hull's `hullCost`, every fitted module's list price, and a
|
|
421
|
-
* `Rebuy` of 5% of the two.
|
|
422
|
-
*
|
|
423
|
-
* `'source'` quotes the build's {@link ShipLoadout.sourcePurchase | source purchase
|
|
424
|
-
* record} instead — `HullValue`, `ModulesValue`, `Rebuy` and the per-module `Value`
|
|
425
|
-
* figures exactly as the capture stated them, and nothing where it stated nothing.
|
|
426
|
-
* An unedited capture therefore re-exports its own credits unchanged.
|
|
427
|
-
*
|
|
428
|
-
* Each captured figure is pinned to what it was paid for, so an edit narrows the
|
|
429
|
-
* export rather than staling it. A slot whose module has been swapped is left
|
|
430
|
-
* unpriced, because the figure was paid for the article that *was* fitted; and
|
|
431
|
-
* `ModulesValue` and `Rebuy` are dropped once any priced module has been swapped or
|
|
432
|
-
* removed, since they then cover an article no longer aboard. Removing a module the
|
|
433
|
-
* capture listed but never priced is the one case this cannot detect: only the
|
|
434
|
-
* capture ever knew which unpriced modules its total counted.
|
|
435
|
-
*
|
|
436
|
-
* `HullValue` always stands: a captured hull figure names no slot, so no edit
|
|
437
|
-
* narrows it. Note that on a game capture it counts the hull *with* its stock
|
|
438
|
-
* fittings, and removing one of those leaves it overstating what is aboard.
|
|
439
|
-
*
|
|
440
|
-
* A build with no source record — one assembled here, or a capture that quoted no
|
|
441
|
-
* credits — exports no credit figure at all rather than falling back to retail.
|
|
442
|
-
*/
|
|
443
|
-
readonly credits?: 'retail' | 'source';
|
|
444
|
-
}
|
|
445
|
-
/** As {@link LoadoutExportOptions}, plus the SLEF envelope — see {@link ShipLoadout.toSlef}. */
|
|
446
|
-
interface SlefExportOptions extends LoadoutExportOptions {
|
|
447
|
-
/**
|
|
448
|
-
* The envelope header identifying the exporting application.
|
|
449
|
-
*
|
|
450
|
-
* SLEF attribution belongs to the application producing the export, not to this
|
|
451
|
-
* calculation library, so callers must provide it.
|
|
452
|
-
*/
|
|
453
|
-
readonly header: SlefHeader;
|
|
454
|
-
/** Spaces per indent for {@link ShipLoadout.toSlefString}. `0` (the default) is compact. */
|
|
455
|
-
readonly indent?: number;
|
|
456
|
-
}
|
|
457
|
-
/**
|
|
458
|
-
* A fitted ship — read a SLEF export, or assemble a hull from scratch.
|
|
459
|
-
*
|
|
460
|
-
* @remarks
|
|
461
|
-
* Jump calculations resolve the frame shift drive's constants from the drive's module
|
|
462
|
-
* record, applying any engineering the build carries (a Long Range blueprint's
|
|
463
|
-
* `FSDOptimalMass`, for instance). For a SLEF build, mass comes from the export's
|
|
464
|
-
* `UnladenMass`; for an assembled build it is the hull mass plus every fitted module's
|
|
465
|
-
* mass (armour defaults to the zero-mass lightweight alloy).
|
|
466
|
-
*
|
|
467
|
-
* @example
|
|
468
|
-
* Read a build a player already flies, and ask it what an outfitting screen shows.
|
|
469
|
-
* Every figure below is one build's — a Krait Phantom explorer. Figures the capture
|
|
470
|
-
* already stated — `unladenMass` here — are trusted verbatim; the rest are computed
|
|
471
|
-
* from the fit.
|
|
472
|
-
*
|
|
473
|
-
* ```ts
|
|
474
|
-
* import { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
|
|
475
|
-
* import type { LoadoutEvent } from '@elite-dangerous-almanac/core/ships/slef';
|
|
476
|
-
*
|
|
477
|
-
* // A `Loadout` line lifted from a player journal, parsed.
|
|
478
|
-
* declare const event: LoadoutEvent;
|
|
479
|
-
*
|
|
480
|
-
* const build = ShipLoadout.fromLoadout(event);
|
|
481
|
-
*
|
|
482
|
-
* build.shipSymbol; // -> 'krait_light'
|
|
483
|
-
* build.shipName; // -> 'Jenny Longuet'
|
|
484
|
-
* build.unladenMass; // -> 388.830017 (tonnes)
|
|
485
|
-
*
|
|
486
|
-
* build.maxJumpRange(); // -> 60.5478 (ly, best single jump)
|
|
487
|
-
* build.powerBudget().withinBudget; // -> true
|
|
488
|
-
* build.shieldMetrics()?.strength; // -> 743.12 (MJ)
|
|
489
|
-
* build.armourMetrics().hitPoints; // -> 307.8
|
|
490
|
-
* ```
|
|
491
|
-
*
|
|
492
|
-
* @example
|
|
493
|
-
* Assemble a hull instead. `empty` starts from the shipyard layout, `slots` enumerates
|
|
494
|
-
* the mounts, and `setModule` fits one — chainable, because the build is mutable.
|
|
495
|
-
*
|
|
496
|
-
* ```ts
|
|
497
|
-
* import { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
|
|
498
|
-
* import { getModuleBySymbol } from '@elite-dangerous-almanac/core/ships/modules';
|
|
499
|
-
* import { CORE_MODULES } from '@elite-dangerous-almanac/core/ships/modules-core';
|
|
500
|
-
*
|
|
501
|
-
* const conda = ShipLoadout.empty('Anaconda');
|
|
502
|
-
* conda.slots().length; // -> 39 (every mount, occupied or not)
|
|
503
|
-
* conda.slots('optional').length; // -> 14
|
|
504
|
-
* conda.validation.complete; // -> false (nothing fitted yet)
|
|
505
|
-
*
|
|
506
|
-
* const fsd = getModuleBySymbol('Int_Hyperdrive_Size6_Class5', CORE_MODULES);
|
|
507
|
-
* if (fsd) conda.setModule('FrameShiftDrive', fsd);
|
|
508
|
-
* ```
|
|
509
|
-
*
|
|
510
|
-
* @example
|
|
511
|
-
* Write a build back out. Retail credits are what the catalogue prices the fit at; pass
|
|
512
|
-
* `credits: 'source'` to export the figures a capture stated it paid instead — see
|
|
513
|
-
* {@link ShipLoadout.sourcePurchase}.
|
|
514
|
-
*
|
|
515
|
-
* ```ts
|
|
516
|
-
* import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
|
|
517
|
-
*
|
|
518
|
-
* declare const build: ShipLoadout;
|
|
519
|
-
*
|
|
520
|
-
* build.toLoadoutEvent(); // retail: hull cost plus every module's list price
|
|
521
|
-
* build.toLoadoutEvent({ credits: 'source' }); // the capture's own figures
|
|
522
|
-
* build.toSlefString({ header: { appName: 'MyApp', appVersion: '1.0.0' } });
|
|
523
|
-
* ```
|
|
524
|
-
*/
|
|
525
|
-
declare class ShipLoadout {
|
|
526
|
-
#private;
|
|
527
|
-
private constructor();
|
|
528
|
-
/**
|
|
529
|
-
* Build from a SLEF export.
|
|
530
|
-
*
|
|
531
|
-
* @param input - The SLEF JSON string, or an already-parsed SLEF object (see
|
|
532
|
-
* {@link parseSlef} for accepted shapes).
|
|
533
|
-
* @param index - Which entry to take when the export holds several builds.
|
|
534
|
-
* Defaults to the first.
|
|
535
|
-
* @returns The loadout for that entry.
|
|
536
|
-
* @throws {SyntaxError} If `input` is a string that is not valid JSON.
|
|
537
|
-
* @throws {TypeError} If the export holds no usable loadout, or `index` is out of
|
|
538
|
-
* range.
|
|
539
|
-
*/
|
|
540
|
-
static fromSlef(input: unknown, index?: number): ShipLoadout;
|
|
541
|
-
/**
|
|
542
|
-
* Build from a bare journal `Loadout` event (the `data` half of a SLEF entry).
|
|
543
|
-
*
|
|
544
|
-
* @param event - A `Loadout` event object.
|
|
545
|
-
* @returns The loadout.
|
|
546
|
-
* @remarks
|
|
547
|
-
* Capture/instance state (`timestamp`, `ShipID`, `HullHealth`, `Hot`) and engineering
|
|
548
|
-
* provenance (`Engineer`, `EngineerID`, `BlueprintID`) are deliberately excluded
|
|
549
|
-
* from the durable build. See {@link LoadoutEvent} and {@link ModuleEngineering}.
|
|
550
|
-
* A pre-engineered/reward module is identified from its reported stat signature when
|
|
551
|
-
* the evidence uniquely matches a catalogue variant. Its complete fixed stat block is
|
|
552
|
-
* then used as the fitted record, including values the capture omits; a separately
|
|
553
|
-
* applied experimental effect is included when matching and remains authoritative in
|
|
554
|
-
* the captured modifiers. Under-specified or ambiguous evidence stays unidentified.
|
|
555
|
-
* An ordinary weapon recipe on a Guardian weapon identifies a final pre-engineered
|
|
556
|
-
* article; the import preserves that identity, uses the catalogue's complete hand-set
|
|
557
|
-
* stat block when the exact article is known, exposes no engineering options for it,
|
|
558
|
-
* and refuses attempts to engineer it further. Explicit journal modifiers remain
|
|
559
|
-
* authoritative over that stat block.
|
|
560
|
-
*
|
|
561
|
-
* The event's credit figures are kept twice over: as the live `hullValue` /
|
|
562
|
-
* `modulesValue` / `rebuy`, which an edit may invalidate, and as the immutable
|
|
563
|
-
* {@link sourcePurchase} record, which no edit touches.
|
|
564
|
-
*
|
|
565
|
-
* Modules are imported as one complete snapshot: their array order does not affect
|
|
566
|
-
* per-ship count allowances, and any aggregate violation is reported by
|
|
567
|
-
* {@link validation}. Use this factory rather than replaying a complete loadout
|
|
568
|
-
* through the incremental {@link setModule} editor.
|
|
569
|
-
*
|
|
570
|
-
* @throws {TypeError} If the event is not shaped like one. What is checked is the
|
|
571
|
-
* structure a build is assembled from, and the types of the fields naming things in
|
|
572
|
-
* it: `event` must be an object with an array of module objects in `Modules`; each
|
|
573
|
-
* module needs a string `Slot` and `Item`, and no two may claim the same slot; a
|
|
574
|
-
* module's `Engineering` must be an object, and that block's `Modifiers` an array of
|
|
575
|
-
* objects each carrying a string `Label`, whenever their key is there **at all**;
|
|
576
|
-
* and `event.Ship`, the block's `BlueprintName` and its `ExperimentalEffect` must be
|
|
577
|
-
* strings **when they carry a value**. Every remaining field — every number, every
|
|
578
|
-
* flag, a modifier's value beside its label — is trusted, so use
|
|
579
|
-
* {@link ShipLoadout.fromSlef} (or {@link parseSlef}) for input you did not produce,
|
|
580
|
-
* which reports all of them.
|
|
581
|
-
*
|
|
582
|
-
* A modifier's `Label` is required rather than checked-when-present because it is
|
|
583
|
-
* the only thing saying which stat moved: {@link fittedModuleAt} and the
|
|
584
|
-
* pre-engineered identification both read it unconditionally, so an entry without
|
|
585
|
-
* one would import cleanly and then break the build it produced.
|
|
586
|
-
*
|
|
587
|
-
* `Engineering` and its `Modifiers` are the fields where a `null` is not the same as
|
|
588
|
-
* an omission, because a relay writing `null` for a block or list it does not have
|
|
589
|
-
* would otherwise be read as one. An **absent** `Ship` *is* an omission, and not a
|
|
590
|
-
* failure: it is a hull nothing can name, which {@link validation} reports as
|
|
591
|
-
* `unknownHull`. Nor is a partial `Engineering` block — a capture may state
|
|
592
|
-
* modifiers without naming the recipe.
|
|
593
|
-
*/
|
|
594
|
-
static fromLoadout(event: LoadoutEvent): ShipLoadout;
|
|
595
|
-
/**
|
|
596
|
-
* Start a new, empty build for a hull — no modules fitted.
|
|
597
|
-
*
|
|
598
|
-
* @param shipSymbol - The hull's internal symbol, e.g. `"Anaconda"`
|
|
599
|
-
* (case-insensitive).
|
|
600
|
-
* @returns An empty loadout whose {@link slots} come from the hull's declared
|
|
601
|
-
* layout.
|
|
602
|
-
* @throws {TypeError} If `shipSymbol` is not a string, or no hull with that symbol
|
|
603
|
-
* has a known slot layout.
|
|
604
|
-
* @example
|
|
605
|
-
* ```ts
|
|
606
|
-
* import { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
|
|
607
|
-
*
|
|
608
|
-
* ShipLoadout.empty('Sidewinder').slots('hardpoint').length; // -> 2
|
|
609
|
-
* ```
|
|
610
|
-
*/
|
|
611
|
-
static empty(shipSymbol: string): ShipLoadout;
|
|
612
|
-
/**
|
|
613
|
-
* Start a new build with the modules supplied on a stock ship.
|
|
614
|
-
*
|
|
615
|
-
* @param shipSymbol - The hull's internal symbol, e.g. `"SideWinder"`
|
|
616
|
-
* (case-insensitive).
|
|
617
|
-
* @returns A complete, ready-to-edit stock loadout. The build is independent of the
|
|
618
|
-
* frozen shared catalogue: edits affect this instance only.
|
|
619
|
-
* @throws {TypeError} If `shipSymbol` is not a string, or no default loadout exists
|
|
620
|
-
* for that hull.
|
|
621
|
-
* @remarks
|
|
622
|
-
* This batteries-included factory resolves calculations through the complete module
|
|
623
|
-
* catalogue already used by `ShipLoadout`. If only the stock slot/module identities
|
|
624
|
-
* are needed, `getDefaultLoadout` from `./default-loadouts` avoids that cost.
|
|
625
|
-
* @example
|
|
626
|
-
* ```ts
|
|
627
|
-
* import { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
|
|
628
|
-
*
|
|
629
|
-
* const stock = ShipLoadout.default('SideWinder');
|
|
630
|
-
* stock.validation.complete; // -> true
|
|
631
|
-
* stock.fittedModuleAt('FrameShiftDrive')?.symbol;
|
|
632
|
-
* // -> 'Int_Hyperdrive_Size2_Class1'
|
|
633
|
-
* ```
|
|
634
|
-
*/
|
|
635
|
-
static default(shipSymbol: string): ShipLoadout;
|
|
636
|
-
/** The hull's internal id, e.g. `"explorer_nx"`. */
|
|
637
|
-
get shipSymbol(): string;
|
|
638
|
-
/** The player-given ship name, or `null` if the build has none. */
|
|
639
|
-
get shipName(): string | null;
|
|
640
|
-
/** The player-given ID plate, or `null` if the build has none. */
|
|
641
|
-
get shipIdent(): string | null;
|
|
642
|
-
/**
|
|
643
|
-
* Hull + modules mass with an empty tank and no cargo, in tonnes, or `null` if it
|
|
644
|
-
* cannot be determined (no `UnladenMass` in the export and either the hull or a
|
|
645
|
-
* fitted module has no known mass).
|
|
646
|
-
*
|
|
647
|
-
* @remarks
|
|
648
|
-
* A SLEF export's `UnladenMass` is trusted verbatim. Otherwise the mass is the
|
|
649
|
-
* hull's `hullMass` plus every fitted module's mass (post-engineering), with armour
|
|
650
|
-
* at the zero-mass lightweight default.
|
|
651
|
-
*/
|
|
652
|
-
get unladenMass(): number | null;
|
|
653
|
-
/**
|
|
654
|
-
* Unladen mass with diagnostics for every missing input.
|
|
655
|
-
*
|
|
656
|
-
* @returns A complete imported or computed mass, otherwise `null` plus the hull or
|
|
657
|
-
* module fields that prevented the calculation.
|
|
658
|
-
*/
|
|
659
|
-
get unladenMassResult(): CalculationResult<number>;
|
|
660
|
-
/**
|
|
661
|
-
* Fuel-tank capacities, in tonnes, or `null` when a tank or the hull's reserve
|
|
662
|
-
* capacity is unknown. A SLEF export's `FuelCapacity` is used when present;
|
|
663
|
-
* otherwise the main capacity is the sum of the fitted fuel tanks and the reserve
|
|
664
|
-
* comes from the hull's stats.
|
|
665
|
-
*/
|
|
666
|
-
get fuelCapacity(): FuelCapacity | null;
|
|
667
|
-
/** Fuel capacity with diagnostics instead of unknown tanks collapsing to zero. */
|
|
668
|
-
get fuelCapacityResult(): CalculationResult<FuelCapacity>;
|
|
669
|
-
/**
|
|
670
|
-
* Cargo capacity, in tonnes, or `null` when a fitted optional module cannot be
|
|
671
|
-
* classified. A SLEF export's `CargoCapacity` is used when present; otherwise it is
|
|
672
|
-
* the sum of the fitted cargo racks.
|
|
673
|
-
*/
|
|
674
|
-
get cargoCapacity(): number | null;
|
|
675
|
-
/** Cargo capacity with diagnostics instead of unknown racks collapsing to zero. */
|
|
676
|
-
get cargoCapacityResult(): CalculationResult<number>;
|
|
677
|
-
/**
|
|
678
|
-
* Hull cost in credits represented by the build, or `null` if unknown.
|
|
679
|
-
*
|
|
680
|
-
* @remarks
|
|
681
|
-
* This is the live figure, kept coherent with edits: an import's own `HullValue`
|
|
682
|
-
* until something invalidates it. For the capture's figure as captured — which no
|
|
683
|
-
* edit changes — read {@link sourcePurchase}.
|
|
684
|
-
*/
|
|
685
|
-
get hullValue(): number | null;
|
|
686
|
-
/**
|
|
687
|
-
* Fitted-modules cost in credits represented by the build, or `null` if
|
|
688
|
-
* unknown — including after an edit discarded an import's figure, since no catalogue
|
|
689
|
-
* records what a replaced module was bought for. {@link sourcePurchase} keeps the
|
|
690
|
-
* captured figure regardless.
|
|
691
|
-
*/
|
|
692
|
-
get modulesValue(): number | null;
|
|
693
|
-
/**
|
|
694
|
-
* Insurance rebuy cost in credits represented by the build, or `null` if
|
|
695
|
-
* unknown. Discarded by an edit for the same reason as {@link modulesValue}, and
|
|
696
|
-
* likewise preserved by {@link sourcePurchase}.
|
|
697
|
-
*/
|
|
698
|
-
get rebuy(): number | null;
|
|
699
|
-
/**
|
|
700
|
-
* What the capture this build came from said was **paid** for it — a read-only
|
|
701
|
-
* {@link SourcePurchaseRecord}, or `null` for a build assembled here or imported
|
|
702
|
-
* from a capture that quoted no credits at all.
|
|
703
|
-
*
|
|
704
|
-
* @remarks
|
|
705
|
-
* The record is provenance about the source, so it is fixed at import and **survives
|
|
706
|
-
* every edit**: fit, remove or engineer whatever you like and it still reports the
|
|
707
|
-
* figures the capture carried, for the modules the capture carried them for. That is
|
|
708
|
-
* what {@link hullValue}, {@link modulesValue} and {@link rebuy} cannot do — they
|
|
709
|
-
* describe the build in hand, so an edit that invalidates one drops it.
|
|
710
|
-
*
|
|
711
|
-
* The two answer different questions and neither substitutes for the other. A
|
|
712
|
-
* captured price belongs to one commander's purchase history, discounts included;
|
|
713
|
-
* the library's own figures are catalogue retail. Export picks between them
|
|
714
|
-
* explicitly, and quotes retail unless asked otherwise — see
|
|
715
|
-
* {@link LoadoutExportOptions.credits}.
|
|
716
|
-
*
|
|
717
|
-
* @example
|
|
718
|
-
* ```ts
|
|
719
|
-
* import { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
|
|
720
|
-
* import { getSourceModuleValue } from '@elite-dangerous-almanac/core/ships/source-purchase';
|
|
721
|
-
*
|
|
722
|
-
* declare const slefJson: string;
|
|
723
|
-
*
|
|
724
|
-
* const build = ShipLoadout.fromSlef(slefJson);
|
|
725
|
-
* const paid = build.sourcePurchase!;
|
|
726
|
-
* paid.hullValue; // -> 189326510, as captured
|
|
727
|
-
* getSourceModuleValue(paid, 'powerplant')?.value; // -> what that plant cost its owner
|
|
728
|
-
*
|
|
729
|
-
* build.removeModule('Slot05_Size4');
|
|
730
|
-
* build.modulesValue; // -> null unavailable after the edit
|
|
731
|
-
* paid.modulesValue; // -> 192625195, the captured figure
|
|
732
|
-
* ```
|
|
733
|
-
*/
|
|
734
|
-
get sourcePurchase(): SourcePurchaseRecord | null;
|
|
735
|
-
/**
|
|
736
|
-
* Structural validity and operational completeness of this build.
|
|
737
|
-
*
|
|
738
|
-
* @remarks
|
|
739
|
-
* Optional, hardpoint and utility mounts may be empty. Armour and all seven core
|
|
740
|
-
* mounts must be filled for `complete` to be true. An unknown hull or module is
|
|
741
|
-
* incomplete; a module in a nonexistent or incompatible slot is invalid. Exclusive
|
|
742
|
-
* families and per-ship module-count allowances must also be satisfied.
|
|
743
|
-
*/
|
|
744
|
-
get validation(): LoadoutValidation;
|
|
745
|
-
/**
|
|
746
|
-
* Frozen point-in-time views of the hull's mounts in outfitting-panel order.
|
|
747
|
-
*
|
|
748
|
-
* @param kind - Optionally keep only one mount kind. Omit it for every mount.
|
|
749
|
-
* @returns Detached slot views. Repeated reads at the same build version reuse the
|
|
750
|
-
* same frozen array and records; every state-changing edit makes the next read produce
|
|
751
|
-
* new snapshots.
|
|
752
|
-
* @throws {TypeError} If the hull has no known slot layout.
|
|
753
|
-
* @example
|
|
754
|
-
* ```ts
|
|
755
|
-
* import { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
|
|
756
|
-
*
|
|
757
|
-
* const emptyHardpoints = ShipLoadout.empty('Sidewinder').slots('hardpoint');
|
|
758
|
-
* emptyHardpoints.every((slot) => slot.module === null); // true
|
|
759
|
-
* ```
|
|
760
|
-
*/
|
|
761
|
-
slots(kind?: SlotKind): readonly LoadoutSlot[];
|
|
762
|
-
/**
|
|
763
|
-
* A deeply frozen, point-in-time view of the module in a slot.
|
|
764
|
-
*
|
|
765
|
-
* @param slotKey - Slot key, matched case-insensitively.
|
|
766
|
-
* @returns A detached view, or `null` when the slot is empty or unknown. Repeated
|
|
767
|
-
* reads at the same build version reuse the same frozen record; every state-changing
|
|
768
|
-
* edit makes the next read produce a new snapshot.
|
|
769
|
-
* @throws {TypeError} If `slotKey` is not a string.
|
|
770
|
-
*/
|
|
771
|
-
fittedModuleAt(slotKey: string): FittedModule | null;
|
|
772
|
-
/**
|
|
773
|
-
* Every fitted module as a deeply frozen point-in-time view.
|
|
774
|
-
*
|
|
775
|
-
* @returns Detached module snapshots in the order the build carries them. The array
|
|
776
|
-
* and every nested record are frozen; query again after an edit for current state.
|
|
777
|
-
* @example
|
|
778
|
-
* ```ts
|
|
779
|
-
* import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
|
|
780
|
-
*
|
|
781
|
-
* declare const build: ShipLoadout;
|
|
782
|
-
*
|
|
783
|
-
* build.fittedModules().map((module) => `${module.slot}: ${module.symbol}`);
|
|
784
|
-
* ```
|
|
785
|
-
*/
|
|
786
|
-
fittedModules(): readonly FittedModule[];
|
|
787
|
-
/**
|
|
788
|
-
* Return the computable blueprint candidates for a fitted module symbol.
|
|
789
|
-
*
|
|
790
|
-
* @param slotKey - Slot key, matched case-insensitively.
|
|
791
|
-
* @returns Frozen blueprint descriptors: the ordinary engineering menu first, then
|
|
792
|
-
* bespoke Mercenary upgrade recipes. An `'ordinary'` candidate is available to the
|
|
793
|
-
* stock module; a `'mercenary'` candidate requires the caller to confirm that the
|
|
794
|
-
* fitted article is the matching Mercenary purchase, because its symbol alone cannot.
|
|
795
|
-
* Returns an empty array when the slot is empty, unresolved or final, or the module
|
|
796
|
-
* symbol has neither route.
|
|
797
|
-
* @throws {TypeError} If `slotKey` is not a string.
|
|
798
|
-
* @example
|
|
799
|
-
* ```ts
|
|
800
|
-
* import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
|
|
801
|
-
*
|
|
802
|
-
* declare const build: ShipLoadout;
|
|
803
|
-
*
|
|
804
|
-
* build.availableBlueprints('FrameShiftDrive').map(({ fdname }) => fdname);
|
|
805
|
-
* ```
|
|
806
|
-
*/
|
|
807
|
-
availableBlueprints(slotKey: string): readonly AvailableBlueprint[];
|
|
808
|
-
/**
|
|
809
|
-
* Return the computable experimental effects offered to a fitted module.
|
|
810
|
-
*
|
|
811
|
-
* @param slotKey - Slot key, matched case-insensitively.
|
|
812
|
-
* @returns Frozen Frontier effect ids in engineering-menu order, or an empty array
|
|
813
|
-
* when the slot is empty, unresolved, final, or has no experimental menu.
|
|
814
|
-
* @throws {TypeError} If `slotKey` is not a string.
|
|
815
|
-
* @example
|
|
816
|
-
* ```ts
|
|
817
|
-
* import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
|
|
818
|
-
*
|
|
819
|
-
* declare const build: ShipLoadout;
|
|
820
|
-
*
|
|
821
|
-
* build.availableExperimentalEffects('FrameShiftDrive');
|
|
822
|
-
* // -> ['special_fsd_heavy', ...]
|
|
823
|
-
* ```
|
|
824
|
-
*/
|
|
825
|
-
availableExperimentalEffects(slotKey: string): readonly string[];
|
|
826
|
-
/**
|
|
827
|
-
* The modules that fit a given slot — its size, kind and any restriction all
|
|
828
|
-
* satisfied, with candidates that would worsen a one-per-ship or module-count limit
|
|
829
|
-
* omitted.
|
|
830
|
-
*
|
|
831
|
-
* @param slotKey - The slot key to fit, matched case-insensitively (journal spelling).
|
|
832
|
-
* @returns The fitting modules, in complete-catalogue order.
|
|
833
|
-
* @throws {RangeError} If the hull has no slot with that key.
|
|
834
|
-
* @throws {TypeError} If `slotKey` is not a string, or the hull has no known slot
|
|
835
|
-
* layout (a SLEF build on an unrecognised hull).
|
|
836
|
-
* @example
|
|
837
|
-
* ```ts
|
|
838
|
-
* import { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
|
|
839
|
-
*
|
|
840
|
-
* ShipLoadout.empty('Anaconda').modulesForSlot('FrameShiftDrive');
|
|
841
|
-
* ```
|
|
842
|
-
*/
|
|
843
|
-
modulesForSlot(slotKey: string): OutfittingModule[];
|
|
844
|
-
/**
|
|
845
|
-
* Fit a module into a slot, replacing whatever is there.
|
|
846
|
-
*
|
|
847
|
-
* @remarks
|
|
848
|
-
* This is an incremental editor: every call must avoid worsening the current
|
|
849
|
-
* build's module-count excess. Fit an allowance-increasing module before the weapons
|
|
850
|
-
* it permits. To consume a complete order-independent snapshot, use
|
|
851
|
-
* {@link ShipLoadout.fromLoadout}.
|
|
852
|
-
*
|
|
853
|
-
* @param slotKey - The slot key to fit into, matched case-insensitively (journal
|
|
854
|
-
* spelling). An occupied slot keeps the key the build already spells it with, so
|
|
855
|
-
* fitting into an import never renames one of its mounts.
|
|
856
|
-
* @param module - The module to fit (resolve it from a catalogue first, e.g. with
|
|
857
|
-
* {@link getModuleBySymbol}). The complete record is snapshotted, so a result from
|
|
858
|
-
* `getPreEngineeredStats` or a caller-supplied catalogue keeps its resolved stats.
|
|
859
|
-
* @returns `this`, for chaining.
|
|
860
|
-
* @throws {RangeError} If the hull has no slot with that key.
|
|
861
|
-
* @throws {TypeError} If `slotKey` is not a string; `module` is null/undefined (e.g. a
|
|
862
|
-
* `getModuleBySymbol` miss) or is not an outfitting module at all; or the hull has no
|
|
863
|
-
* known slot layout (a SLEF build on an unrecognised hull).
|
|
864
|
-
* @throws {LoadoutEditError} If the module does not fit the slot (wrong kind, too
|
|
865
|
-
* large, or a restriction the module does not satisfy), conflicts with a one-per-ship
|
|
866
|
-
* family already fitted elsewhere, or worsens a per-ship module-count excess.
|
|
867
|
-
* @example
|
|
868
|
-
* ```ts
|
|
869
|
-
* import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
|
|
870
|
-
*
|
|
871
|
-
* declare const build: ShipLoadout;
|
|
872
|
-
*
|
|
873
|
-
* import { getModuleBySymbol } from '@elite-dangerous-almanac/core/ships/modules';
|
|
874
|
-
* import { CORE_MODULES } from '@elite-dangerous-almanac/core/ships/modules-core';
|
|
875
|
-
* const fsd = getModuleBySymbol('Int_Hyperdrive_Size6_Class5', CORE_MODULES)!;
|
|
876
|
-
* const tank = getModuleBySymbol('Int_FuelTank_Size6_Class3', CORE_MODULES)!;
|
|
877
|
-
* build.setModule('FrameShiftDrive', fsd).setModule('Slot01_Size7', tank);
|
|
878
|
-
* ```
|
|
879
|
-
*/
|
|
880
|
-
setModule(slotKey: string, module: OutfittingModule): this;
|
|
881
|
-
/**
|
|
882
|
-
* Empty a slot.
|
|
883
|
-
*
|
|
884
|
-
* @param slotKey - The slot key to clear, matched case-insensitively (journal
|
|
885
|
-
* spelling).
|
|
886
|
-
* @returns `this`, for chaining. Clearing an already-empty slot is a no-op.
|
|
887
|
-
* @throws {TypeError} If `slotKey` is not a string.
|
|
888
|
-
* @throws {LoadoutEditError} If the slot is the built-in cargo hatch, which cannot
|
|
889
|
-
* be removed or replaced, or removing the module would worsen a per-ship
|
|
890
|
-
* module-count excess.
|
|
891
|
-
*/
|
|
892
|
-
removeModule(slotKey: string): this;
|
|
893
|
-
/**
|
|
894
|
-
* Engineer the module in a slot — apply a blueprint (with a grade and quality) and
|
|
895
|
-
* an optional experimental effect, computing the resulting stat modifiers.
|
|
896
|
-
*
|
|
897
|
-
* The modifiers are stored with journal-equivalent labels and numeric values on the
|
|
898
|
-
* fitted module, so the build's jump-range and mass calculations pick them up
|
|
899
|
-
* automatically. The optional journal display-direction hint `LessIsGood` is omitted.
|
|
900
|
-
* The block keeps the `BlueprintName` you passed, so it reads back the way the build
|
|
901
|
-
* declared it. Values use Frontier's float32 arithmetic, and weapon recipe internals
|
|
902
|
-
* such as `BurstInterval` are exposed as the derived `RateOfFire` and
|
|
903
|
-
* `DamagePerSecond` labels a journal writes. Module-specific aliases likewise use the
|
|
904
|
-
* journal spelling (`MaximumRange` for a module's maximum range and `Range` for a
|
|
905
|
-
* scanner range).
|
|
906
|
-
* Recipe-only values remain available through {@link FittedModule.effectiveStats} and
|
|
907
|
-
* build calculations even though a journal does not serialize their labels; this is
|
|
908
|
-
* what keeps burst and reload-cycle calculations faithful after applying a recipe.
|
|
909
|
-
*
|
|
910
|
-
* **Which recipe an id names can depend on the module.** The game writes
|
|
911
|
-
* `Sensor_LongRange` and `Sensor_WideAngle` for both a sensor suite's modification and a
|
|
912
|
-
* utility scanner's, and the two roll different stats in opposite directions — Long
|
|
913
|
-
* Range costs the suite mass and the scanner power draw. So the id is resolved against
|
|
914
|
-
* the module's menu before anything is computed, and a wake scanner engineered
|
|
915
|
-
* `Sensor_LongRange` gets the scanner's numbers, which `BLUEPRINTS` keys
|
|
916
|
-
* `Scanner_LongRange`. Reading a stored block back the same way means resolving it the
|
|
917
|
-
* same way: `resolveBlueprintForModule` in `ships/blueprint-journal` is that lookup.
|
|
918
|
-
*
|
|
919
|
-
* @param slotKey - The slot whose module to engineer, matched case-insensitively
|
|
920
|
-
* (journal spelling).
|
|
921
|
-
* @param fdname - The blueprint recipe's Frontier `fdname`, e.g. `"FSD_LongRange"`.
|
|
922
|
-
* @param options - {@link ApplyBlueprintOptions}: `grade` (1–5), optional `quality`
|
|
923
|
-
* (0–1, default 1), and optional `experimental` effect `fdname`. A nullish
|
|
924
|
-
* `experimental` means no effect, the same as leaving it out. Each is read once,
|
|
925
|
-
* before anything is checked, so an accessor cannot answer the check and the use
|
|
926
|
-
* differently.
|
|
927
|
-
* @returns `this`, for chaining.
|
|
928
|
-
* @throws {RangeError} If the slot is empty, or the blueprint/grade/experimental is
|
|
929
|
-
* unknown, or `quality` is outside `[0, 1]`.
|
|
930
|
-
* @throws {TypeError} If `slotKey` or `fdname` is not a string, `options` is not an
|
|
931
|
-
* object, or `options.experimental` carries a value that is not a string — a nullish
|
|
932
|
-
* one is no effect, not a wrong type; the fitted module has no stats to engineer; or the id names a
|
|
933
|
-
* fixed event-reward identity, which names no craftable recipe; or the module is not offered the blueprint — by
|
|
934
|
-
* its engineering menu, by the journal spelling of an entry on that menu, by the
|
|
935
|
-
* generic spelling of a recipe that menu lists under a family's name, or by being a
|
|
936
|
-
* Mercenary article sold at grade 1 with that bespoke recipe; the fitted article is
|
|
937
|
-
* final and accepts no further engineering;
|
|
938
|
-
* or the module is not offered the experimental effect, which its
|
|
939
|
-
* menu alone decides; or the catalogue does not carry every base stat the recipe
|
|
940
|
-
* modifies. Incomplete engineering is rejected rather than stored as a partial journal
|
|
941
|
-
* modifier block.
|
|
942
|
-
* @example
|
|
943
|
-
* ```ts
|
|
944
|
-
* import { getModuleBySymbol } from '@elite-dangerous-almanac/core/ships/modules';
|
|
945
|
-
* import { CORE_MODULES } from '@elite-dangerous-almanac/core/ships/modules-core';
|
|
946
|
-
* import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
|
|
947
|
-
*
|
|
948
|
-
* declare const build: ShipLoadout;
|
|
949
|
-
*
|
|
950
|
-
* const fsd = getModuleBySymbol('Int_Hyperdrive_Size6_Class5', CORE_MODULES)!;
|
|
951
|
-
*
|
|
952
|
-
* build.setModule('FrameShiftDrive', fsd)
|
|
953
|
-
* .applyBlueprint('FrameShiftDrive', 'FSD_LongRange', {
|
|
954
|
-
* grade: 5,
|
|
955
|
-
* experimental: 'special_fsd_heavy',
|
|
956
|
-
* });
|
|
957
|
-
* build.maxJumpRange(); // uses the engineered optimal mass
|
|
958
|
-
* ```
|
|
959
|
-
*/
|
|
960
|
-
applyBlueprint(slotKey: string, fdname: string, options: ApplyBlueprintOptions): this;
|
|
961
|
-
/**
|
|
962
|
-
* Fit a pre-engineered variant into a slot, replacing whatever is there.
|
|
963
|
-
*
|
|
964
|
-
* The variant's fixed stats and journal engineering block are resolved together.
|
|
965
|
-
* Articles carry `Level`, `Quality: 1`, any baked experimental effect and their fixed
|
|
966
|
-
* modifiers. Because the variant names its base module, a decorative identity cannot
|
|
967
|
-
* be applied to an unrelated damage-bearing module.
|
|
968
|
-
* A Mercenary variant whose fixed modifier block has not been published retains the
|
|
969
|
-
* stock catalogue stats and omits `Modifiers` rather than claiming it changes none.
|
|
970
|
-
*
|
|
971
|
-
* @param slotKey - The slot key to fit into, matched case-insensitively.
|
|
972
|
-
* @param variant - The pre-engineered catalogue variant to fit.
|
|
973
|
-
* @returns `this`, for chaining.
|
|
974
|
-
* @throws {TypeError} If `variant` is not a pre-engineered variant or one of its
|
|
975
|
-
* authored modifier labels cannot be resolved for its base module.
|
|
976
|
-
* @throws {RangeError} If no catalogue row matches the supplied module, blueprint,
|
|
977
|
-
* grade, experimental effect and acquisition route.
|
|
978
|
-
* @throws {LoadoutEditError} If the variant's base module does not fit the slot or
|
|
979
|
-
* violates a fitted-module limit.
|
|
980
|
-
* @example
|
|
981
|
-
* ```ts
|
|
982
|
-
* import { getPreEngineeredVariants } from '@elite-dangerous-almanac/core/ships/pre-engineered';
|
|
983
|
-
* import { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
|
|
984
|
-
*
|
|
985
|
-
* const festive = getPreEngineeredVariants('Hpt_FlakMortar_Turret_Medium')
|
|
986
|
-
* .find((variant) => variant.blueprint === 'Decorative_Red')!;
|
|
987
|
-
* const build = ShipLoadout.empty('Krait_MkII')
|
|
988
|
-
* .setPreEngineeredVariant('MediumHardpoint1', festive);
|
|
989
|
-
* build.fittedModuleAt('MediumHardpoint1')?.effectiveStats?.damage; // -> 0.34
|
|
990
|
-
* ```
|
|
991
|
-
*/
|
|
992
|
-
setPreEngineeredVariant(slotKey: string, variant: PreEngineeredVariant): this;
|
|
993
|
-
/**
|
|
994
|
-
* Strip engineering from a slot's module,
|
|
995
|
-
* restoring its base stats.
|
|
996
|
-
*
|
|
997
|
-
* @param slotKey - The slot to de-engineer, matched case-insensitively (journal
|
|
998
|
-
* spelling).
|
|
999
|
-
* @returns `this`, for chaining. A no-op if the slot is empty or unmodified.
|
|
1000
|
-
* @throws {TypeError} If `slotKey` is not a string, or the fitted article is final
|
|
1001
|
-
* pre-engineered and its baked engineering cannot be removed.
|
|
1002
|
-
*/
|
|
1003
|
-
clearEngineering(slotKey: string): this;
|
|
1004
|
-
/**
|
|
1005
|
-
* Switch a fitted module on or off.
|
|
1006
|
-
*
|
|
1007
|
-
* @param slotKey - The slot's journal key, e.g. `"PowerPlant"`, matched
|
|
1008
|
-
* case-insensitively.
|
|
1009
|
-
* @param on - `true` to power it, `false` to switch it off.
|
|
1010
|
-
* @returns `this`, for chaining.
|
|
1011
|
-
* @throws {RangeError} If the slot is empty.
|
|
1012
|
-
* @throws {TypeError} If `slotKey` is not a string.
|
|
1013
|
-
* @example
|
|
1014
|
-
* ```ts
|
|
1015
|
-
* import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
|
|
1016
|
-
*
|
|
1017
|
-
* declare const build: ShipLoadout;
|
|
1018
|
-
*
|
|
1019
|
-
* build.setModuleEnabled('TinyHardpoint6', false); // an unpowered heat sink
|
|
1020
|
-
* ```
|
|
1021
|
-
*/
|
|
1022
|
-
setModuleEnabled(slotKey: string, on: boolean): this;
|
|
1023
|
-
/**
|
|
1024
|
-
* Set a fitted module's power-priority group.
|
|
1025
|
-
*
|
|
1026
|
-
* @param slotKey - The slot's journal key, matched case-insensitively.
|
|
1027
|
-
* @param priority - The journal's **zero-based** group, `0`–`4`. Note that the
|
|
1028
|
-
* outfitting panel — and {@link powerBudget}'s `bands[].priority` — number the same
|
|
1029
|
-
* five groups `1`–`5`.
|
|
1030
|
-
* @returns `this`, for chaining.
|
|
1031
|
-
* @throws {RangeError} If the slot is empty, or `priority` is not an integer in `[0, 4]`.
|
|
1032
|
-
* @throws {TypeError} If `slotKey` is not a string.
|
|
1033
|
-
*/
|
|
1034
|
-
setModulePriority(slotKey: string, priority: number): this;
|
|
1035
|
-
/**
|
|
1036
|
-
* This build as a journal `Loadout` event — the `data` half of a SLEF entry.
|
|
1037
|
-
*
|
|
1038
|
-
* @param options - Module ordering and how sparse to be about power state.
|
|
1039
|
-
* @returns A fresh event. Every top-level figure is **recomputed** from the hull and
|
|
1040
|
-
* the fitted modules rather than echoed from whatever an import supplied — the one
|
|
1041
|
-
* exception being the credits, when `credits: 'source'` asks for the capture's own.
|
|
1042
|
-
* Any figure that cannot be worked out is **left out** rather than emitted as a stale
|
|
1043
|
-
* or zero value — SLEF requires nothing beyond `Ship` and `Modules`.
|
|
1044
|
-
*
|
|
1045
|
-
* Credits are quoted at **retail** by default: the bare hull's `hullCost` plus every
|
|
1046
|
-
* fitted module's catalogue list price, with `Rebuy` 5% of the two. A source's own
|
|
1047
|
-
* `HullValue` / `ModulesValue` / `Value` figures are deliberately not quoted here,
|
|
1048
|
-
* because they record one commander's purchase history — the Deep Black's modules
|
|
1049
|
-
* are all 12.25% off list — and purchase discounts are not a property of the build.
|
|
1050
|
-
* They are not lost either: pass `credits: 'source'` to export the
|
|
1051
|
-
* {@link sourcePurchase} record instead, as provenance rather than as a price.
|
|
1052
|
-
* @example
|
|
1053
|
-
* ```ts
|
|
1054
|
-
* import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
|
|
1055
|
-
*
|
|
1056
|
-
* declare const build: ShipLoadout;
|
|
1057
|
-
*
|
|
1058
|
-
* const event = build.toLoadoutEvent();
|
|
1059
|
-
* event.MaxJumpRange; // recomputed, not the exporter's claim
|
|
1060
|
-
* event.HullValue; // the catalogue's list price
|
|
1061
|
-
*
|
|
1062
|
-
* build.toLoadoutEvent({ credits: 'source' }).HullValue; // what the capture paid
|
|
1063
|
-
* ```
|
|
1064
|
-
*/
|
|
1065
|
-
toLoadoutEvent(options?: LoadoutExportOptions): LoadoutEvent;
|
|
1066
|
-
/**
|
|
1067
|
-
* This build as a one-entry SLEF export.
|
|
1068
|
-
*
|
|
1069
|
-
* @param options - Ordering, power state, and the envelope header.
|
|
1070
|
-
* @returns The export. Several builds travel together as
|
|
1071
|
-
* `toSlef([a.toLoadoutEvent(), b.toLoadoutEvent()])` using the function of the same
|
|
1072
|
-
* name from `./slef`.
|
|
1073
|
-
*/
|
|
1074
|
-
toSlef(options: SlefExportOptions): Slef;
|
|
1075
|
-
/**
|
|
1076
|
-
* This build as SLEF JSON — ready to write to a file or put on the clipboard.
|
|
1077
|
-
*
|
|
1078
|
-
* @param options - As {@link toSlef}, plus `indent` (compact by default).
|
|
1079
|
-
* @example
|
|
1080
|
-
* ```ts
|
|
1081
|
-
* import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
|
|
1082
|
-
*
|
|
1083
|
-
* declare const build: ShipLoadout;
|
|
1084
|
-
*
|
|
1085
|
-
* build.toSlefString({ header: { appName: 'MyApp', appVersion: '1.0.0' } });
|
|
1086
|
-
* ```
|
|
1087
|
-
*/
|
|
1088
|
-
toSlefString(options: SlefExportOptions): string;
|
|
1089
|
-
/**
|
|
1090
|
-
* The resolved frame-shift-drive constants for this build — post-engineering,
|
|
1091
|
-
* with any Guardian FSD Booster folded into `jumpBoost`.
|
|
1092
|
-
*
|
|
1093
|
-
* @throws {TypeError} If the build has no frame shift drive, or its required jump
|
|
1094
|
-
* constants are missing from the stats catalogue.
|
|
1095
|
-
*/
|
|
1096
|
-
get frameShiftDrive(): FrameShiftDriveParams;
|
|
1097
|
-
/**
|
|
1098
|
-
* The fitted frame shift drive's dimensionless mass factor at a chosen load.
|
|
1099
|
-
*
|
|
1100
|
-
* @param options - {@link JumpOptions}. `fuel` defaults to a full main tank and
|
|
1101
|
-
* `cargo` to `0`.
|
|
1102
|
-
* @returns `optMass / loadedMass`: `1` at the drive's optimised mass, below `1`
|
|
1103
|
-
* above it and above `1` below it.
|
|
1104
|
-
* @remarks
|
|
1105
|
-
* This is the mass term used by the jump equation, not the three-point performance
|
|
1106
|
-
* curve used by thrusters and shield generators. Main-tank fuel contributes to the
|
|
1107
|
-
* loaded mass; the Guardian FSD Booster's additive range does not contribute to the
|
|
1108
|
-
* factor.
|
|
1109
|
-
* @throws {TypeError} If the build has no usable frame shift drive or its mass
|
|
1110
|
-
* cannot be determined; also if fuel capacity is unknown and `options.fuel` is
|
|
1111
|
-
* omitted.
|
|
1112
|
-
* @throws {RangeError} If fuel or cargo is not finite and non-negative, or loaded
|
|
1113
|
-
* mass is zero.
|
|
1114
|
-
* @example
|
|
1115
|
-
* ```ts
|
|
1116
|
-
* import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
|
|
1117
|
-
*
|
|
1118
|
-
* declare const build: ShipLoadout;
|
|
1119
|
-
* build.frameShiftDriveMassFactor({ fuel: 8, cargo: 32 }); // dimensionless
|
|
1120
|
-
* ```
|
|
1121
|
-
*/
|
|
1122
|
-
frameShiftDriveMassFactor(options?: JumpOptions): number;
|
|
1123
|
-
/**
|
|
1124
|
-
* Best single-jump range, in light-years — no cargo, and exactly one jump's fuel
|
|
1125
|
-
* aboard (the lightest the ship jumps). This is the figure the game and EDSY label
|
|
1126
|
-
* "maximum jump range".
|
|
1127
|
-
*
|
|
1128
|
-
* @remarks
|
|
1129
|
-
* Returns `0` when no fuel is available — an assembled build with no fuel tank
|
|
1130
|
-
* fitted has an empty main tank, so there is nothing to jump on.
|
|
1131
|
-
* @returns The best single jump, in light-years.
|
|
1132
|
-
* @throws {TypeError} If the build has no usable frame shift drive, or its mass or
|
|
1133
|
-
* fuel capacity cannot be determined.
|
|
1134
|
-
*/
|
|
1135
|
-
maxJumpRange(): number;
|
|
1136
|
-
/**
|
|
1137
|
-
* The range of a single jump for a chosen fuel and cargo load, in light-years.
|
|
1138
|
-
*
|
|
1139
|
-
* @param options - {@link JumpOptions}. `fuel` defaults to a full main tank,
|
|
1140
|
-
* `cargo` to `0`.
|
|
1141
|
-
* @returns The jump's range, in light-years.
|
|
1142
|
-
* @throws {TypeError} If the build has no usable frame shift drive or its mass
|
|
1143
|
-
* cannot be determined; also if fuel capacity is unknown and `options.fuel` is
|
|
1144
|
-
* omitted.
|
|
1145
|
-
* @throws {RangeError} If fuel or cargo is not finite and non-negative.
|
|
1146
|
-
*/
|
|
1147
|
-
jumpRange(options?: JumpOptions): number;
|
|
1148
|
-
/**
|
|
1149
|
-
* Single-jump range on a full tank with a full cargo hold, in light-years.
|
|
1150
|
-
*
|
|
1151
|
-
* @returns The jump's range, in light-years.
|
|
1152
|
-
* @throws {TypeError} If the build has no usable frame shift drive, or its mass,
|
|
1153
|
-
* fuel capacity or cargo capacity cannot be determined.
|
|
1154
|
-
*/
|
|
1155
|
-
ladenJumpRange(): number;
|
|
1156
|
-
/**
|
|
1157
|
-
* The fuel a single jump of a given distance costs, in tonnes.
|
|
1158
|
-
*
|
|
1159
|
-
* @param distance - The jump distance, in light-years.
|
|
1160
|
-
* @param options - {@link JumpOptions}. `fuel` defaults to a full main tank,
|
|
1161
|
-
* `cargo` to `0`.
|
|
1162
|
-
* @returns Fuel used, in tonnes (capped at the drive's max fuel per jump).
|
|
1163
|
-
* @throws {TypeError} If the build has no usable frame shift drive or its mass
|
|
1164
|
-
* cannot be determined; also if fuel capacity is unknown and `options.fuel` is
|
|
1165
|
-
* omitted.
|
|
1166
|
-
* @throws {RangeError} If fuel or cargo is not finite and non-negative.
|
|
1167
|
-
*/
|
|
1168
|
-
fuelPerJump(distance: number, options?: JumpOptions): number;
|
|
1169
|
-
/**
|
|
1170
|
-
* Total range and jump count for a chosen fuel and cargo load.
|
|
1171
|
-
*
|
|
1172
|
-
* @param options - {@link JumpOptions}. `fuel` defaults to a full main tank,
|
|
1173
|
-
* `cargo` to `0`.
|
|
1174
|
-
* @returns Summed range in light-years and the jumps made before the tank is empty.
|
|
1175
|
-
* @throws {TypeError} If the build has no usable frame shift drive, or its mass or
|
|
1176
|
-
* fuel capacity cannot be determined; fuel capacity is not required when
|
|
1177
|
-
* `options.fuel` is supplied.
|
|
1178
|
-
* @throws {RangeError} If fuel or cargo is not finite and non-negative, or the
|
|
1179
|
-
* fuel load would require more than 100,000 jumps.
|
|
1180
|
-
* @example
|
|
1181
|
-
* ```ts
|
|
1182
|
-
* import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
|
|
1183
|
-
*
|
|
1184
|
-
* declare const build: ShipLoadout;
|
|
1185
|
-
* build.totalRange().jumps; // jumps available from one full main tank
|
|
1186
|
-
* build.totalRange({ fuel: 8, cargo: 32 }).range; // range for that partial load
|
|
1187
|
-
* ```
|
|
1188
|
-
*/
|
|
1189
|
-
totalRange(options?: JumpOptions): TotalRangeDetails;
|
|
1190
|
-
/**
|
|
1191
|
-
* Every jump figure at once — best, unladen, laden, and each load's total.
|
|
1192
|
-
*
|
|
1193
|
-
* @returns The {@link JumpRangeSummary}. Single-jump figures and each total's
|
|
1194
|
-
* `range` are in light-years. For a partial load, call {@link jumpRange} for one
|
|
1195
|
-
* jump or {@link totalRange} for every jump with the `fuel` and `cargo` you
|
|
1196
|
-
* actually have.
|
|
1197
|
-
* @throws {TypeError} If the build has no usable frame shift drive, or its mass,
|
|
1198
|
-
* fuel capacity or cargo capacity cannot be determined.
|
|
1199
|
-
* @example
|
|
1200
|
-
* ```ts
|
|
1201
|
-
* import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
|
|
1202
|
-
*
|
|
1203
|
-
* declare const build: ShipLoadout;
|
|
1204
|
-
*
|
|
1205
|
-
* const jumps = build.jumpRangeSummary();
|
|
1206
|
-
* jumps.max; // -> 89.41 (one jump's fuel, empty hold)
|
|
1207
|
-
* jumps.laden; // -> the range with the hold full
|
|
1208
|
-
* jumps.totalMax.jumps; // the best jump expressed as a total
|
|
1209
|
-
* // Half a tank and 32 t aboard, once the tank is known:
|
|
1210
|
-
* const fuel = build.fuelCapacityResult;
|
|
1211
|
-
* if (fuel.complete) build.jumpRange({ fuel: fuel.value.main / 2, cargo: 32 });
|
|
1212
|
-
* ```
|
|
1213
|
-
*/
|
|
1214
|
-
jumpRangeSummary(): JumpRangeSummary;
|
|
1215
|
-
/**
|
|
1216
|
-
* The build's power budget: what the plant makes, what the modules draw with
|
|
1217
|
-
* hardpoints retracted and deployed, and which priority groups stay lit.
|
|
1218
|
-
*
|
|
1219
|
-
* Draws are post-engineering, modules switched off in the journal are skipped, and
|
|
1220
|
-
* weapons (plus the utility fittings that are not always powered) count only
|
|
1221
|
-
* towards the deployed total.
|
|
1222
|
-
*
|
|
1223
|
-
* @returns The {@link PowerBudget}. With no power plant fitted, `available` is `0`
|
|
1224
|
-
* and nothing is powered. A fitted module whose draw the catalogue cannot supply is
|
|
1225
|
-
* named in {@link PowerBudget.unknownDraws} rather than counted as drawing nothing,
|
|
1226
|
-
* which makes every total a lower bound while that list is non-empty.
|
|
1227
|
-
* @example
|
|
1228
|
-
* ```ts
|
|
1229
|
-
* import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
|
|
1230
|
-
*
|
|
1231
|
-
* declare const build: ShipLoadout;
|
|
1232
|
-
*
|
|
1233
|
-
* const power = build.powerBudget();
|
|
1234
|
-
* power.available; // -> 20.4 MW generated
|
|
1235
|
-
* power.deployed; // -> 19.02 MW drawn, hardpoints out
|
|
1236
|
-
* power.withinBudget; // -> true
|
|
1237
|
-
* power.bands[4]?.poweredDeployed; // -> is priority group 5 still lit?
|
|
1238
|
-
* ```
|
|
1239
|
-
*/
|
|
1240
|
-
powerBudget(): PowerBudget;
|
|
1241
|
-
/**
|
|
1242
|
-
* The build's heat: what it idles at, what it runs at flying and jumping, and
|
|
1243
|
-
* whether firing everything cooks it.
|
|
1244
|
-
*
|
|
1245
|
-
* Every figure is post-engineering. The heat a build makes follows what the plant
|
|
1246
|
-
* actually feeds, so a module switched off — or one in a priority group the plant
|
|
1247
|
-
* cannot keep lit — contributes nothing.
|
|
1248
|
-
*
|
|
1249
|
-
* @returns The {@link HeatMetrics}, or `null` when the build has no powered power
|
|
1250
|
-
* plant or its hull is unknown. A build carrying a module the catalogues cannot
|
|
1251
|
-
* resolve is answered rather than refused, with that module named in
|
|
1252
|
-
* {@link HeatMetrics.unknownDraws}: read what that entry says about the figures
|
|
1253
|
-
* before showing them, because they are then a projection over the rest of the build
|
|
1254
|
-
* rather than an answer for it.
|
|
1255
|
-
* @example
|
|
1256
|
-
* ```ts
|
|
1257
|
-
* import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
|
|
1258
|
-
*
|
|
1259
|
-
* declare const build: ShipLoadout;
|
|
1260
|
-
*
|
|
1261
|
-
* const heat = build.heatMetrics();
|
|
1262
|
-
* heat?.idle.gauge; // -> 0.23, i.e. the gauge reads 23%
|
|
1263
|
-
* heat?.firingSustained.overheats; // -> false: the guns run cool enough to hold
|
|
1264
|
-
* heat?.firingDrained.secondsToOverheat; // -> how long an alpha strike has on an empty WEP
|
|
1265
|
-
* ```
|
|
1266
|
-
*/
|
|
1267
|
-
heatMetrics(): HeatMetrics | null;
|
|
1268
|
-
/**
|
|
1269
|
-
* The build's speed, boost and rotation rates at a chosen load and ENG allocation.
|
|
1270
|
-
*
|
|
1271
|
-
* @remarks
|
|
1272
|
-
* Main-tank fuel contributes to the flight model's loaded mass. Reserve-tank fuel
|
|
1273
|
-
* does not: although the statistics panel includes it in the displayed current
|
|
1274
|
-
* mass, ten observed builds reproduce their angular rates only when the reserve is
|
|
1275
|
-
* excluded from the thruster mass curve.
|
|
1276
|
-
*
|
|
1277
|
-
* @param options - Fuel defaults to a full main tank, cargo to `0`, and ENG pips to `4`.
|
|
1278
|
-
* @returns Loaded {@link MobilityMetrics}, or `null` when no powered, fully described
|
|
1279
|
-
* thrusters are fitted.
|
|
1280
|
-
* @throws {TypeError} If mass or an omitted main-tank fuel load cannot be determined.
|
|
1281
|
-
* @throws {RangeError} If fuel or cargo is not finite and non-negative, or
|
|
1282
|
-
* `enginesPips` is outside `[0, 4]`.
|
|
1283
|
-
* @example
|
|
1284
|
-
* ```ts
|
|
1285
|
-
* import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
|
|
1286
|
-
*
|
|
1287
|
-
* declare const build: ShipLoadout;
|
|
1288
|
-
* build.mobilityMetrics({ cargo: 32, fuel: 8, enginesPips: 2 })?.speed; // -> m/s
|
|
1289
|
-
* ```
|
|
1290
|
-
*/
|
|
1291
|
-
mobilityMetrics(options?: MobilityOptions): MobilityMetrics | null;
|
|
1292
|
-
/**
|
|
1293
|
-
* The build's shields: strength in megajoules, where it comes from, and the
|
|
1294
|
-
* effective resistances.
|
|
1295
|
-
*
|
|
1296
|
-
* Shield strength scales with the **hull's** mass, not the build's, so fitting
|
|
1297
|
-
* more modules never weakens it. Boosters, Guardian shield reinforcement and any
|
|
1298
|
-
* engineering are all folded in; switched-off modules are ignored.
|
|
1299
|
-
*
|
|
1300
|
-
* @param options - {@link DefenceOptions}. `systemsPips` (0–4) folds the SYS
|
|
1301
|
-
* capacitor's own resistance into the reported figures; it defaults to `0`, which
|
|
1302
|
-
* is what an outfitting screen shows.
|
|
1303
|
-
* @returns The {@link ShieldMetrics}, or `null` when the build has no shield
|
|
1304
|
-
* generator fitted (or has one switched off).
|
|
1305
|
-
* @example
|
|
1306
|
-
* ```ts
|
|
1307
|
-
* import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
|
|
1308
|
-
*
|
|
1309
|
-
* declare const build: ShipLoadout;
|
|
1310
|
-
*
|
|
1311
|
-
* const shields = build.shieldMetrics();
|
|
1312
|
-
* shields?.strength; // -> MJ
|
|
1313
|
-
* shields?.resistances.thermal; // -> negative on a stock generator
|
|
1314
|
-
* build.shieldMetrics({ systemsPips: 4 })?.resistances.thermal; // -> with 4 pips to SYS
|
|
1315
|
-
* ```
|
|
1316
|
-
*/
|
|
1317
|
-
shieldMetrics(options?: DefenceOptions): ShieldMetrics | null;
|
|
1318
|
-
/**
|
|
1319
|
-
* Time for this build's shield to rise after collapse and then regenerate to full.
|
|
1320
|
-
*
|
|
1321
|
-
* @param options - SYS pips in `[0, 4]`, defaulting to `4`.
|
|
1322
|
-
* @returns Recovery rates and seconds, or `null` with no powered shield generator.
|
|
1323
|
-
* A missing distributor or insufficient zero-pip recharge produces `Infinity`.
|
|
1324
|
-
* @throws {RangeError} If `systemsPips` is outside `[0, 4]` or not finite.
|
|
1325
|
-
* @example
|
|
1326
|
-
* ```ts
|
|
1327
|
-
* import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
|
|
1328
|
-
*
|
|
1329
|
-
* declare const build: ShipLoadout;
|
|
1330
|
-
* build.shieldRecovery({ systemsPips: 4 })?.recoveryTime; // -> seconds from collapse to 50%
|
|
1331
|
-
* ```
|
|
1332
|
-
*/
|
|
1333
|
-
shieldRecovery(options?: DefenceOptions): ShieldRecovery | null;
|
|
1334
|
-
/**
|
|
1335
|
-
* Every fitted shield cell bank and the complete rearmed reinforcement pool.
|
|
1336
|
-
*
|
|
1337
|
-
* @returns A frozen {@link CellBankSummary}; no banks is an empty list and zero totals.
|
|
1338
|
-
* @example
|
|
1339
|
-
* ```ts
|
|
1340
|
-
* import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
|
|
1341
|
-
*
|
|
1342
|
-
* declare const build: ShipLoadout;
|
|
1343
|
-
* build.cellBanks().totalRestorable; // -> MJ across every fitted cell
|
|
1344
|
-
* ```
|
|
1345
|
-
*/
|
|
1346
|
-
cellBanks(): CellBankSummary;
|
|
1347
|
-
/**
|
|
1348
|
-
* Price this build from current catalogue list prices without creating a journal event.
|
|
1349
|
-
*
|
|
1350
|
-
* @returns Hull, module and five-percent rebuy credits. `modules` and `rebuy` remain
|
|
1351
|
-
* lower bounds when {@link RetailCredits.unpriced} is non-empty; built-in hull fittings are free.
|
|
1352
|
-
* @example
|
|
1353
|
-
* ```ts
|
|
1354
|
-
* import { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
|
|
1355
|
-
*
|
|
1356
|
-
* ShipLoadout.default('Anaconda').retailCredits().hull; // -> 142456440
|
|
1357
|
-
* ```
|
|
1358
|
-
*/
|
|
1359
|
-
retailCredits(): RetailCredits;
|
|
1360
|
-
/**
|
|
1361
|
-
* The build's armour: hull hit points, the bulkhead and reinforcement each
|
|
1362
|
-
* contribute, and the effective resistances.
|
|
1363
|
-
*
|
|
1364
|
-
* @returns The {@link ArmourMetrics}. A build with no armour module fitted is
|
|
1365
|
-
* reported on the stock lightweight alloy the hull leaves the shipyard with, which
|
|
1366
|
-
* is what the game does.
|
|
1367
|
-
* @example
|
|
1368
|
-
* ```ts
|
|
1369
|
-
* import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
|
|
1370
|
-
*
|
|
1371
|
-
* declare const build: ShipLoadout;
|
|
1372
|
-
*
|
|
1373
|
-
* const hull = build.armourMetrics();
|
|
1374
|
-
* hull.hitPoints; // -> total hull points
|
|
1375
|
-
* hull.resistances.explosive; // -> lightweight alloy is explosively weak
|
|
1376
|
-
* hull.effectiveHitPoints.thermal; // -> thermal damage the hull can soak
|
|
1377
|
-
* ```
|
|
1378
|
-
*/
|
|
1379
|
-
armourMetrics(): ArmourMetrics;
|
|
1380
|
-
/**
|
|
1381
|
-
* The build's firepower: DPS, sustained DPS, weapons-capacitor draw, heat and power
|
|
1382
|
-
* draw for every fitted weapon, plus the totals.
|
|
1383
|
-
*
|
|
1384
|
-
* Every figure is post-engineering. A weapon switched off in the journal is still
|
|
1385
|
-
* listed — with its own metrics — but left out of the totals.
|
|
1386
|
-
*
|
|
1387
|
-
* @returns The {@link BuildWeaponMetrics}.
|
|
1388
|
-
* @example
|
|
1389
|
-
* ```ts
|
|
1390
|
-
* import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
|
|
1391
|
-
*
|
|
1392
|
-
* declare const build: ShipLoadout;
|
|
1393
|
-
*
|
|
1394
|
-
* const guns = build.weaponMetrics();
|
|
1395
|
-
* guns.total.damagePerSecond; // -> burst DPS across the hardpoints
|
|
1396
|
-
* guns.total.sustainedDamagePerSecond; // -> with reloads folded in
|
|
1397
|
-
* guns.total.energyPerSecond; // -> MW asked of the WEP capacitor
|
|
1398
|
-
* guns.total.powerDraw; // -> MW asked of the power plant when deployed
|
|
1399
|
-
* guns.weapons[0]?.metrics.damageByType.thermal;
|
|
1400
|
-
* guns.weapons[0]?.ammunition?.total; // -> rounds aboard when fully rearmed
|
|
1401
|
-
* ```
|
|
1402
|
-
*/
|
|
1403
|
-
weaponMetrics(): BuildWeaponMetrics;
|
|
1404
|
-
/**
|
|
1405
|
-
* WEP-capacitor recharge and endurance while every powered weapon fires.
|
|
1406
|
-
*
|
|
1407
|
-
* @param options - WEP pips in `[0, 4]`, defaulting to `4`.
|
|
1408
|
-
* @returns Actual recharge, sustained draw, net drain and seconds from full to
|
|
1409
|
-
* empty. The deployed power budget is applied to the distributor and weapons, so a
|
|
1410
|
-
* module the plant sheds contributes nothing. A module with an unresolved power
|
|
1411
|
-
* draw is assumed powered, consistently with {@link powerBudget}; inspect its
|
|
1412
|
-
* `unknownDraws` when that distinction matters. With no powered distributor,
|
|
1413
|
-
* capacity and recharge are zero. A load that draws no more than recharge reports
|
|
1414
|
-
* `Infinity` for `timeToDrain`.
|
|
1415
|
-
* @throws {RangeError} If `weaponsPips` is outside `[0, 4]` or not finite.
|
|
1416
|
-
* @example
|
|
1417
|
-
* ```ts
|
|
1418
|
-
* import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
|
|
1419
|
-
*
|
|
1420
|
-
* declare const build: ShipLoadout;
|
|
1421
|
-
* build.weaponsCapacitorMetrics({ weaponsPips: 2 }).timeToDrain; // seconds
|
|
1422
|
-
* ```
|
|
1423
|
-
*/
|
|
1424
|
-
weaponsCapacitorMetrics(options?: WeaponsOptions): WeaponsCapacitorMetrics;
|
|
1425
|
-
/**
|
|
1426
|
-
* All three power-distributor capacitors at selected pip allocations.
|
|
1427
|
-
*
|
|
1428
|
-
* @param options - SYS, ENG and WEP pips in `[0, 4]`, each defaulting
|
|
1429
|
-
* independently to `4`. The allocations need not sum to six, which permits
|
|
1430
|
-
* independent comparisons of the three maxima.
|
|
1431
|
-
* @returns Capacity, rated four-pip recharge and actual pip-scaled recharge for
|
|
1432
|
-
* SYS, ENG and WEP, or `null` when no distributor is fitted, it is switched off,
|
|
1433
|
-
* its six capacitor stats cannot be resolved, or the retracted power budget sheds
|
|
1434
|
-
* it. The retracted state represents the distributor itself; firing endurance in
|
|
1435
|
-
* {@link weaponsCapacitorMetrics} separately applies the deployed state. A module
|
|
1436
|
-
* with unresolved power draw is assumed powered, consistently with
|
|
1437
|
-
* {@link powerBudget}; inspect its `unknownDraws` when that distinction matters.
|
|
1438
|
-
* @throws {RangeError} If any pip allocation is outside `[0, 4]` or not finite.
|
|
1439
|
-
* @example
|
|
1440
|
-
* ```ts
|
|
1441
|
-
* import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
|
|
1442
|
-
*
|
|
1443
|
-
* declare const build: ShipLoadout;
|
|
1444
|
-
* const distributor = build.distributorMetrics({
|
|
1445
|
-
* systemsPips: 2,
|
|
1446
|
-
* enginesPips: 2,
|
|
1447
|
-
* weaponsPips: 2,
|
|
1448
|
-
* });
|
|
1449
|
-
* distributor?.engines.rechargeRate; // MJ/s
|
|
1450
|
-
* ```
|
|
1451
|
-
*/
|
|
1452
|
-
distributorMetrics(options?: DistributorOptions): DistributorMetrics | null;
|
|
1453
|
-
}
|
|
1454
|
-
|
|
1455
|
-
export { type ApplyBlueprintOptions as A, type BuildWeaponMetrics as B, type DefenceOptions as D, type FittedModule as F, type ImmovableReason as I, type JumpOptions as J, LoadoutEditError as L, type MobilityOptions as M, type RetailCredits as R, ShipLoadout as S, type WeaponsOptions as W, type AvailableBlueprint as a, type DistributorOptions as b, type FittedWeaponMetrics as c, type JumpRangeSummary as d, type LoadoutEditErrorCode as e, type LoadoutExportOptions as f, type LoadoutSlot as g, type SlefExportOptions as h };
|