@elite-dangerous-almanac/core 0.1.0-beta.1
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/LICENSE +48 -0
- package/PROVENANCE/SNAPSHOTS.md +36 -0
- package/PROVENANCE/astro/SOURCES.md +94 -0
- package/PROVENANCE/commodities/SOURCES.md +41 -0
- package/PROVENANCE/materials/SOURCES.md +69 -0
- package/PROVENANCE/ships/SOURCES.md +1580 -0
- package/README.md +148 -0
- package/THIRD_PARTY_NOTICES.md +202 -0
- package/dist/astro/codex-region-lookup.d.ts +169 -0
- package/dist/astro/codex-region-lookup.js +1 -0
- package/dist/astro/codex-region-lookup.js.map +1 -0
- package/dist/astro/codex-region.d.ts +149 -0
- package/dist/astro/codex-region.js +1 -0
- package/dist/astro/codex-region.js.map +1 -0
- package/dist/astro/galaxy-grid.d.ts +83 -0
- package/dist/astro/galaxy-grid.js +1 -0
- package/dist/astro/galaxy-grid.js.map +1 -0
- package/dist/astro/hand-authored-regions.d.ts +121 -0
- package/dist/astro/hand-authored-regions.js +1 -0
- package/dist/astro/hand-authored-regions.js.map +1 -0
- package/dist/astro/index.d.ts +140 -0
- package/dist/astro/index.js +1 -0
- package/dist/astro/index.js.map +1 -0
- package/dist/astro/mass-code.d.ts +55 -0
- package/dist/astro/mass-code.js +1 -0
- package/dist/astro/mass-code.js.map +1 -0
- package/dist/astro/naming-region-origins.d.ts +4 -0
- package/dist/astro/naming-region-origins.js +1 -0
- package/dist/astro/naming-region-origins.js.map +1 -0
- package/dist/astro/nebulae-all.d.ts +40 -0
- package/dist/astro/nebulae-all.js +1 -0
- package/dist/astro/nebulae-all.js.map +1 -0
- package/dist/astro/nebulae-planetary.d.ts +37 -0
- package/dist/astro/nebulae-planetary.js +1 -0
- package/dist/astro/nebulae-planetary.js.map +1 -0
- package/dist/astro/nebulae-procgen.d.ts +36 -0
- package/dist/astro/nebulae-procgen.js +1 -0
- package/dist/astro/nebulae-procgen.js.map +1 -0
- package/dist/astro/nebulae-real.d.ts +37 -0
- package/dist/astro/nebulae-real.js +1 -0
- package/dist/astro/nebulae-real.js.map +1 -0
- package/dist/astro/nebulae.d.ts +169 -0
- package/dist/astro/nebulae.js +1 -0
- package/dist/astro/nebulae.js.map +1 -0
- package/dist/astro/permit-locked-regions.d.ts +54 -0
- package/dist/astro/permit-locked-regions.js +1 -0
- package/dist/astro/permit-locked-regions.js.map +1 -0
- package/dist/astro/permit-locked-systems.d.ts +74 -0
- package/dist/astro/permit-locked-systems.js +1 -0
- package/dist/astro/permit-locked-systems.js.map +1 -0
- package/dist/astro/permit-locks.d.ts +130 -0
- package/dist/astro/permit-locks.js +1 -0
- package/dist/astro/permit-locks.js.map +1 -0
- package/dist/astro/procedural-system.d.ts +228 -0
- package/dist/astro/procedural-system.js +1 -0
- package/dist/astro/procedural-system.js.map +1 -0
- package/dist/astro/sector-name.d.ts +87 -0
- package/dist/astro/sector-name.js +1 -0
- package/dist/astro/sector-name.js.map +1 -0
- package/dist/astro/system-address-input.d.ts +76 -0
- package/dist/astro/system-address-input.js +1 -0
- package/dist/astro/system-address-input.js.map +1 -0
- package/dist/astro/system-address.d.ts +4 -0
- package/dist/astro/system-address.js +1 -0
- package/dist/astro/system-address.js.map +1 -0
- package/dist/astro/system-name.d.ts +187 -0
- package/dist/astro/system-name.js +1 -0
- package/dist/astro/system-name.js.map +1 -0
- package/dist/chunk-2FHHMYDC.js +1 -0
- package/dist/chunk-2FHHMYDC.js.map +1 -0
- package/dist/chunk-462OKHXR.js +1 -0
- package/dist/chunk-462OKHXR.js.map +1 -0
- package/dist/chunk-5H74FKY7.js +1 -0
- package/dist/chunk-5H74FKY7.js.map +1 -0
- package/dist/chunk-6LUEKHO5.js +1 -0
- package/dist/chunk-6LUEKHO5.js.map +1 -0
- package/dist/chunk-76XKY2Y2.js +1 -0
- package/dist/chunk-76XKY2Y2.js.map +1 -0
- package/dist/chunk-7EE5VIHR.js +1 -0
- package/dist/chunk-7EE5VIHR.js.map +1 -0
- package/dist/chunk-A3NM7SAJ.js +1 -0
- package/dist/chunk-A3NM7SAJ.js.map +1 -0
- package/dist/chunk-A6XPYSVR.js +1 -0
- package/dist/chunk-A6XPYSVR.js.map +1 -0
- package/dist/chunk-AA3K5XUE.js +1 -0
- package/dist/chunk-AA3K5XUE.js.map +1 -0
- package/dist/chunk-AVZI6VKA.js +1 -0
- package/dist/chunk-AVZI6VKA.js.map +1 -0
- package/dist/chunk-B5TT26XE.js +1 -0
- package/dist/chunk-B5TT26XE.js.map +1 -0
- package/dist/chunk-BNILZXJD.js +1 -0
- package/dist/chunk-BNILZXJD.js.map +1 -0
- package/dist/chunk-BRDQUJXV.js +1 -0
- package/dist/chunk-BRDQUJXV.js.map +1 -0
- package/dist/chunk-BTPV5CIF.js +1 -0
- package/dist/chunk-BTPV5CIF.js.map +1 -0
- package/dist/chunk-CI3ACMRA.js +1 -0
- package/dist/chunk-CI3ACMRA.js.map +1 -0
- package/dist/chunk-COE5ADYJ.js +1 -0
- package/dist/chunk-COE5ADYJ.js.map +1 -0
- package/dist/chunk-CWAX3BSH.js +1 -0
- package/dist/chunk-CWAX3BSH.js.map +1 -0
- package/dist/chunk-DACZE3HX.js +1 -0
- package/dist/chunk-DACZE3HX.js.map +1 -0
- package/dist/chunk-DURKO7JU.js +1 -0
- package/dist/chunk-DURKO7JU.js.map +1 -0
- package/dist/chunk-E45EDCYH.js +1 -0
- package/dist/chunk-E45EDCYH.js.map +1 -0
- package/dist/chunk-ELIZXUMI.js +1 -0
- package/dist/chunk-ELIZXUMI.js.map +1 -0
- package/dist/chunk-EYGVDJ2I.js +1 -0
- package/dist/chunk-EYGVDJ2I.js.map +1 -0
- package/dist/chunk-FGXWVFN6.js +1 -0
- package/dist/chunk-FGXWVFN6.js.map +1 -0
- package/dist/chunk-GJCB2Z72.js +1 -0
- package/dist/chunk-GJCB2Z72.js.map +1 -0
- package/dist/chunk-HI7FCS3G.js +1 -0
- package/dist/chunk-HI7FCS3G.js.map +1 -0
- package/dist/chunk-HKXXFIRI.js +1 -0
- package/dist/chunk-HKXXFIRI.js.map +1 -0
- package/dist/chunk-HTB52N6S.js +1 -0
- package/dist/chunk-HTB52N6S.js.map +1 -0
- package/dist/chunk-I7PIDRMU.js +1 -0
- package/dist/chunk-I7PIDRMU.js.map +1 -0
- package/dist/chunk-IH4NXKVW.js +1 -0
- package/dist/chunk-IH4NXKVW.js.map +1 -0
- package/dist/chunk-INNFH37U.js +1 -0
- package/dist/chunk-INNFH37U.js.map +1 -0
- package/dist/chunk-J2PNZQY4.js +1 -0
- package/dist/chunk-J2PNZQY4.js.map +1 -0
- package/dist/chunk-JQG4C67D.js +1 -0
- package/dist/chunk-JQG4C67D.js.map +1 -0
- package/dist/chunk-JTQVWIGL.js +1 -0
- package/dist/chunk-JTQVWIGL.js.map +1 -0
- package/dist/chunk-JWJ7RSZC.js +1 -0
- package/dist/chunk-JWJ7RSZC.js.map +1 -0
- package/dist/chunk-K3AMV27L.js +1 -0
- package/dist/chunk-K3AMV27L.js.map +1 -0
- package/dist/chunk-K7F6WC4T.js +1 -0
- package/dist/chunk-K7F6WC4T.js.map +1 -0
- package/dist/chunk-K7L7SMIR.js +1 -0
- package/dist/chunk-K7L7SMIR.js.map +1 -0
- package/dist/chunk-KG4EWDZZ.js +1 -0
- package/dist/chunk-KG4EWDZZ.js.map +1 -0
- package/dist/chunk-KMFUCORC.js +1 -0
- package/dist/chunk-KMFUCORC.js.map +1 -0
- package/dist/chunk-L2ZZXEZM.js +1 -0
- package/dist/chunk-L2ZZXEZM.js.map +1 -0
- package/dist/chunk-L747RVPO.js +1 -0
- package/dist/chunk-L747RVPO.js.map +1 -0
- package/dist/chunk-MFV4VZFP.js +1 -0
- package/dist/chunk-MFV4VZFP.js.map +1 -0
- package/dist/chunk-NWPK6Q3S.js +1 -0
- package/dist/chunk-NWPK6Q3S.js.map +1 -0
- package/dist/chunk-PMJG7PHU.js +1 -0
- package/dist/chunk-PMJG7PHU.js.map +1 -0
- package/dist/chunk-PP2VSA6M.js +1 -0
- package/dist/chunk-PP2VSA6M.js.map +1 -0
- package/dist/chunk-Q22LXT53.js +1 -0
- package/dist/chunk-Q22LXT53.js.map +1 -0
- package/dist/chunk-Q5MR36RW.js +1 -0
- package/dist/chunk-Q5MR36RW.js.map +1 -0
- package/dist/chunk-Q5XOGATC.js +1 -0
- package/dist/chunk-Q5XOGATC.js.map +1 -0
- package/dist/chunk-QTDBO7R2.js +1 -0
- package/dist/chunk-QTDBO7R2.js.map +1 -0
- package/dist/chunk-R4OD62HV.js +1 -0
- package/dist/chunk-R4OD62HV.js.map +1 -0
- package/dist/chunk-RD73TFGS.js +1 -0
- package/dist/chunk-RD73TFGS.js.map +1 -0
- package/dist/chunk-RIT6MOO5.js +1 -0
- package/dist/chunk-RIT6MOO5.js.map +1 -0
- package/dist/chunk-RVSXKQHE.js +1 -0
- package/dist/chunk-RVSXKQHE.js.map +1 -0
- package/dist/chunk-S4DBNX2B.js +1 -0
- package/dist/chunk-S4DBNX2B.js.map +1 -0
- package/dist/chunk-S4UWCHL6.js +1 -0
- package/dist/chunk-S4UWCHL6.js.map +1 -0
- package/dist/chunk-SQS7672E.js +1 -0
- package/dist/chunk-SQS7672E.js.map +1 -0
- package/dist/chunk-TLNHETGC.js +1 -0
- package/dist/chunk-TLNHETGC.js.map +1 -0
- package/dist/chunk-U6TMCYA6.js +1 -0
- package/dist/chunk-U6TMCYA6.js.map +1 -0
- package/dist/chunk-V4C6FIE2.js +1 -0
- package/dist/chunk-V4C6FIE2.js.map +1 -0
- package/dist/chunk-VXVUEF5U.js +1 -0
- package/dist/chunk-VXVUEF5U.js.map +1 -0
- package/dist/chunk-VZXL5KBR.js +1 -0
- package/dist/chunk-VZXL5KBR.js.map +1 -0
- package/dist/chunk-VZZ2XIRE.js +1 -0
- package/dist/chunk-VZZ2XIRE.js.map +1 -0
- package/dist/chunk-WV5YM7H5.js +1 -0
- package/dist/chunk-WV5YM7H5.js.map +1 -0
- package/dist/chunk-Y2MUIE5W.js +1 -0
- package/dist/chunk-Y2MUIE5W.js.map +1 -0
- package/dist/chunk-Z43DN4PY.js +1 -0
- package/dist/chunk-Z43DN4PY.js.map +1 -0
- package/dist/chunk-Z4GTTB7I.js +1 -0
- package/dist/chunk-Z4GTTB7I.js.map +1 -0
- package/dist/chunk-Z4OUB4SJ.js +1 -0
- package/dist/chunk-Z4OUB4SJ.js.map +1 -0
- package/dist/chunk-ZFT56QFR.js +1 -0
- package/dist/chunk-ZFT56QFR.js.map +1 -0
- package/dist/chunk-ZNCXENNB.js +1 -0
- package/dist/chunk-ZNCXENNB.js.map +1 -0
- package/dist/commodities/commodities-all.d.ts +25 -0
- package/dist/commodities/commodities-all.js +1 -0
- package/dist/commodities/commodities-all.js.map +1 -0
- package/dist/commodities/commodities-rare.d.ts +34 -0
- package/dist/commodities/commodities-rare.js +1 -0
- package/dist/commodities/commodities-rare.js.map +1 -0
- package/dist/commodities/commodities-standard.d.ts +34 -0
- package/dist/commodities/commodities-standard.js +1 -0
- package/dist/commodities/commodities-standard.js.map +1 -0
- package/dist/commodities/commodities.d.ts +142 -0
- package/dist/commodities/commodities.js +1 -0
- package/dist/commodities/commodities.js.map +1 -0
- package/dist/commodities/index.d.ts +30 -0
- package/dist/commodities/index.js +1 -0
- package/dist/commodities/index.js.map +1 -0
- package/dist/galactic-position-shLkm4Qg.d.ts +30 -0
- package/dist/materials/index.d.ts +47 -0
- package/dist/materials/index.js +1 -0
- package/dist/materials/index.js.map +1 -0
- package/dist/materials/materials-all.d.ts +26 -0
- package/dist/materials/materials-all.js +1 -0
- package/dist/materials/materials-all.js.map +1 -0
- package/dist/materials/materials-encoded.d.ts +31 -0
- package/dist/materials/materials-encoded.js +1 -0
- package/dist/materials/materials-encoded.js.map +1 -0
- package/dist/materials/materials-manufactured.d.ts +32 -0
- package/dist/materials/materials-manufactured.js +1 -0
- package/dist/materials/materials-manufactured.js.map +1 -0
- package/dist/materials/materials-raw.d.ts +31 -0
- package/dist/materials/materials-raw.js +1 -0
- package/dist/materials/materials-raw.js.map +1 -0
- package/dist/materials/materials.d.ts +277 -0
- package/dist/materials/materials.js +1 -0
- package/dist/materials/materials.js.map +1 -0
- package/dist/materials/micro-resources-all.d.ts +28 -0
- package/dist/materials/micro-resources-all.js +1 -0
- package/dist/materials/micro-resources-all.js.map +1 -0
- package/dist/materials/micro-resources-component.d.ts +29 -0
- package/dist/materials/micro-resources-component.js +1 -0
- package/dist/materials/micro-resources-component.js.map +1 -0
- package/dist/materials/micro-resources-consumable.d.ts +29 -0
- package/dist/materials/micro-resources-consumable.js +1 -0
- package/dist/materials/micro-resources-consumable.js.map +1 -0
- package/dist/materials/micro-resources-data.d.ts +29 -0
- package/dist/materials/micro-resources-data.js +1 -0
- package/dist/materials/micro-resources-data.js.map +1 -0
- package/dist/materials/micro-resources-item.d.ts +29 -0
- package/dist/materials/micro-resources-item.js +1 -0
- package/dist/materials/micro-resources-item.js.map +1 -0
- package/dist/materials/micro-resources.d.ts +136 -0
- package/dist/materials/micro-resources.js +1 -0
- package/dist/materials/micro-resources.js.map +1 -0
- package/dist/ship-loadout-Ba63RDf-.d.ts +1059 -0
- package/dist/ships/ammunition.d.ts +107 -0
- package/dist/ships/ammunition.js +1 -0
- package/dist/ships/ammunition.js.map +1 -0
- package/dist/ships/armour.d.ts +134 -0
- package/dist/ships/armour.js +1 -0
- package/dist/ships/armour.js.map +1 -0
- package/dist/ships/blueprint-costs.d.ts +128 -0
- package/dist/ships/blueprint-costs.js +1 -0
- package/dist/ships/blueprint-costs.js.map +1 -0
- package/dist/ships/blueprint-journal.d.ts +116 -0
- package/dist/ships/blueprint-journal.js +1 -0
- package/dist/ships/blueprint-journal.js.map +1 -0
- package/dist/ships/blueprints.d.ts +103 -0
- package/dist/ships/blueprints.js +1 -0
- package/dist/ships/blueprints.js.map +1 -0
- package/dist/ships/decorative-modifications.d.ts +176 -0
- package/dist/ships/decorative-modifications.js +1 -0
- package/dist/ships/decorative-modifications.js.map +1 -0
- package/dist/ships/engineering-options.d.ts +246 -0
- package/dist/ships/engineering-options.js +1 -0
- package/dist/ships/engineering-options.js.map +1 -0
- package/dist/ships/engineering.d.ts +229 -0
- package/dist/ships/engineering.js +1 -0
- package/dist/ships/engineering.js.map +1 -0
- package/dist/ships/experimental-effect-costs.d.ts +56 -0
- package/dist/ships/experimental-effect-costs.js +1 -0
- package/dist/ships/experimental-effect-costs.js.map +1 -0
- package/dist/ships/experimental-effects.d.ts +62 -0
- package/dist/ships/experimental-effects.js +1 -0
- package/dist/ships/experimental-effects.js.map +1 -0
- package/dist/ships/index.d.ts +205 -0
- package/dist/ships/index.js +1 -0
- package/dist/ships/index.js.map +1 -0
- package/dist/ships/jump-range.d.ts +115 -0
- package/dist/ships/jump-range.js +1 -0
- package/dist/ships/jump-range.js.map +1 -0
- package/dist/ships/loadout-calculations.d.ts +109 -0
- package/dist/ships/loadout-calculations.js +1 -0
- package/dist/ships/loadout-calculations.js.map +1 -0
- package/dist/ships/loadout-validation.d.ts +80 -0
- package/dist/ships/loadout-validation.js +1 -0
- package/dist/ships/loadout-validation.js.map +1 -0
- package/dist/ships/module-capabilities.d.ts +205 -0
- package/dist/ships/module-capabilities.js +1 -0
- package/dist/ships/module-capabilities.js.map +1 -0
- package/dist/ships/modules-all.d.ts +43 -0
- package/dist/ships/modules-all.js +1 -0
- package/dist/ships/modules-all.js.map +1 -0
- package/dist/ships/modules-core.d.ts +40 -0
- package/dist/ships/modules-core.js +1 -0
- package/dist/ships/modules-core.js.map +1 -0
- package/dist/ships/modules-hardpoint.d.ts +42 -0
- package/dist/ships/modules-hardpoint.js +1 -0
- package/dist/ships/modules-hardpoint.js.map +1 -0
- package/dist/ships/modules-internal.d.ts +40 -0
- package/dist/ships/modules-internal.js +1 -0
- package/dist/ships/modules-internal.js.map +1 -0
- package/dist/ships/modules-utility.d.ts +40 -0
- package/dist/ships/modules-utility.js +1 -0
- package/dist/ships/modules-utility.js.map +1 -0
- package/dist/ships/modules.d.ts +755 -0
- package/dist/ships/modules.js +1 -0
- package/dist/ships/modules.js.map +1 -0
- package/dist/ships/power.d.ts +168 -0
- package/dist/ships/power.js +1 -0
- package/dist/ships/power.js.map +1 -0
- package/dist/ships/pre-engineered-stats.d.ts +147 -0
- package/dist/ships/pre-engineered-stats.js +1 -0
- package/dist/ships/pre-engineered-stats.js.map +1 -0
- package/dist/ships/pre-engineered.d.ts +215 -0
- package/dist/ships/pre-engineered.js +1 -0
- package/dist/ships/pre-engineered.js.map +1 -0
- package/dist/ships/resistances.d.ts +208 -0
- package/dist/ships/resistances.js +1 -0
- package/dist/ships/resistances.js.map +1 -0
- package/dist/ships/shields.d.ts +221 -0
- package/dist/ships/shields.js +1 -0
- package/dist/ships/shields.js.map +1 -0
- package/dist/ships/ship-loadout.d.ts +16 -0
- package/dist/ships/ship-loadout.js +1 -0
- package/dist/ships/ship-loadout.js.map +1 -0
- package/dist/ships/ships.d.ts +191 -0
- package/dist/ships/ships.js +1 -0
- package/dist/ships/ships.js.map +1 -0
- package/dist/ships/slef.d.ts +318 -0
- package/dist/ships/slef.js +1 -0
- package/dist/ships/slef.js.map +1 -0
- package/dist/ships/slots.d.ts +418 -0
- package/dist/ships/slots.js +1 -0
- package/dist/ships/slots.js.map +1 -0
- package/dist/ships/source-purchase.d.ts +132 -0
- package/dist/ships/source-purchase.js +1 -0
- package/dist/ships/source-purchase.js.map +1 -0
- package/dist/ships/weapons.d.ts +380 -0
- package/dist/ships/weapons.js +1 -0
- package/dist/ships/weapons.js.map +1 -0
- package/dist/system-address-DYsN1qOT.d.ts +313 -0
- package/package.json +375 -0
|
@@ -0,0 +1,1059 @@
|
|
|
1
|
+
import { ModuleEngineering, LoadoutModule, LoadoutEvent, SlefHeader, Slef } from './ships/slef.js';
|
|
2
|
+
import { 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 { ShieldMetrics } from './ships/shields.js';
|
|
7
|
+
import { ArmourMetrics } from './ships/armour.js';
|
|
8
|
+
import { WeaponMetrics, WeaponTotals } from './ships/weapons.js';
|
|
9
|
+
import { AmmunitionCapacity } from './ships/ammunition.js';
|
|
10
|
+
import { PreEngineeredVariant } from './ships/pre-engineered.js';
|
|
11
|
+
import { SourcePurchaseRecord } from './ships/source-purchase.js';
|
|
12
|
+
import { CalculationResult, FuelCapacity } from './ships/loadout-calculations.js';
|
|
13
|
+
import { LoadoutValidation } from './ships/loadout-validation.js';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Immutable fitted-module snapshots returned by {@link ShipLoadout}.
|
|
17
|
+
*
|
|
18
|
+
* @packageDocumentation
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* A point-in-time, deeply frozen view of the module fitted in one slot.
|
|
23
|
+
*
|
|
24
|
+
* The view is detached from its {@link ShipLoadout}: later edits do not change it, and
|
|
25
|
+
* mutating it throws. Fetch a new view with {@link ShipLoadout.fittedModuleAt} after an
|
|
26
|
+
* state-changing edit; reads made without an intervening state change reuse the same
|
|
27
|
+
* frozen snapshot. All mutations live on `ShipLoadout`, keyed by {@link slot}; this
|
|
28
|
+
* avoids the stale-handle lifecycle that a live proxy would otherwise need.
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```ts
|
|
32
|
+
* import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
|
|
33
|
+
*
|
|
34
|
+
* declare const build: ShipLoadout;
|
|
35
|
+
*
|
|
36
|
+
* const before = build.fittedModuleAt('FrameShiftDrive')!;
|
|
37
|
+
* build.applyBlueprint(before.slot, 'FSD_LongRange', { grade: 5 });
|
|
38
|
+
* const after = build.fittedModuleAt(before.slot)!;
|
|
39
|
+
* before.engineering; // unchanged
|
|
40
|
+
* after.engineering; // the applied blueprint
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
interface FittedModule {
|
|
44
|
+
/** Slot key in the build's own spelling. */
|
|
45
|
+
readonly slot: string;
|
|
46
|
+
/** Frontier module symbol, e.g. `"Int_Hyperdrive_Size6_Class5"`. */
|
|
47
|
+
readonly symbol: string;
|
|
48
|
+
/** Whether the module was powered on, or `undefined` when unspecified. */
|
|
49
|
+
readonly on: boolean | undefined;
|
|
50
|
+
/** Zero-based power-priority group, or `undefined` when unspecified. */
|
|
51
|
+
readonly priority: number | undefined;
|
|
52
|
+
/** Module health in `[0, 1]`, or `undefined` when unspecified. */
|
|
53
|
+
readonly health: number | undefined;
|
|
54
|
+
/** Captured purchase value in credits, or `undefined` when unspecified. */
|
|
55
|
+
readonly value: number | undefined;
|
|
56
|
+
/** Applied engineering, or `undefined` for a stock module. */
|
|
57
|
+
readonly engineering: ModuleEngineering | undefined;
|
|
58
|
+
/** Detached, journal-shaped fitted record. */
|
|
59
|
+
readonly raw: LoadoutModule;
|
|
60
|
+
/** Snapshotted base module stats, or `null` when unresolved. */
|
|
61
|
+
readonly stats: OutfittingModule | null;
|
|
62
|
+
/**
|
|
63
|
+
* Post-engineering module stats, or `null` when unresolved. For weapons, journal
|
|
64
|
+
* damage per second is resolved back to per-round damage and falloff is capped at
|
|
65
|
+
* maximum range. Exact damage components follow the engineered total and disappear
|
|
66
|
+
* when a damage conversion replaces them with a fractional distribution.
|
|
67
|
+
*/
|
|
68
|
+
readonly effectiveStats: OutfittingModule | null;
|
|
69
|
+
/** Fully rearmed ammunition capacity, or `null` for modules without ammunition. */
|
|
70
|
+
readonly ammunition: AmmunitionCapacity | null;
|
|
71
|
+
/** Identified fixed pre-engineered variant, or `null` when not uniquely identified. */
|
|
72
|
+
readonly preEngineeredVariant: PreEngineeredVariant | null;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Immutable slot snapshots returned by {@link ShipLoadout}.
|
|
77
|
+
*
|
|
78
|
+
* @packageDocumentation
|
|
79
|
+
*/
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* A point-in-time, deeply frozen view of one hull mount.
|
|
83
|
+
*
|
|
84
|
+
* The view is detached from its {@link ShipLoadout}; after an edit that changes the
|
|
85
|
+
* build, call {@link ShipLoadout.slots} again for the current view. Reads made without an
|
|
86
|
+
* intervening state change reuse the same frozen snapshots. Mutations and candidate
|
|
87
|
+
* filtering stay on `ShipLoadout` and take the slot `key`, leaving this value serializable
|
|
88
|
+
* and free of lifecycle rules.
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* Walking a build's mounts. Slot keys come from the game and are not derivable from
|
|
92
|
+
* position, so read the slot's `key` rather than composing one.
|
|
93
|
+
*
|
|
94
|
+
* ```ts
|
|
95
|
+
* import { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
|
|
96
|
+
* import type { LoadoutEvent } from '@elite-dangerous-almanac/core/ships/slef';
|
|
97
|
+
*
|
|
98
|
+
* declare const event: LoadoutEvent;
|
|
99
|
+
*
|
|
100
|
+
* // Figures below are one build's — a Federal Corvette.
|
|
101
|
+
* const build = ShipLoadout.fromLoadout(event);
|
|
102
|
+
*
|
|
103
|
+
* build.slots().length; // -> 38 every mount on the hull
|
|
104
|
+
* build.slots('hardpoint').length; // -> 7
|
|
105
|
+
*
|
|
106
|
+
* const first = build.slots('hardpoint')[0];
|
|
107
|
+
* first?.key; // -> 'HugeHardpoint1' what ShipLoadout.setModule takes
|
|
108
|
+
* first?.name; // -> 'Huge Hardpoint 1' what a UI shows
|
|
109
|
+
* first?.size; // -> 4
|
|
110
|
+
* first?.module?.symbol; // -> 'hpt_beamlaser_gimbal_huge'; undefined when the mount is empty
|
|
111
|
+
* ```
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* The view is a snapshot, not a handle — re-read it after an edit.
|
|
115
|
+
*
|
|
116
|
+
* ```ts
|
|
117
|
+
* import { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
|
|
118
|
+
* import { HARDPOINT_MODULES } from '@elite-dangerous-almanac/core/ships/modules-hardpoint';
|
|
119
|
+
* import { getModuleBySymbol } from '@elite-dangerous-almanac/core/ships/modules';
|
|
120
|
+
*
|
|
121
|
+
* const build = ShipLoadout.empty('Sidewinder');
|
|
122
|
+
* const before = build.slots('hardpoint')[0];
|
|
123
|
+
* before?.key; // -> 'SmallHardpoint1'
|
|
124
|
+
* before?.module; // -> null
|
|
125
|
+
*
|
|
126
|
+
* const pulse = getModuleBySymbol('Hpt_PulseLaser_Fixed_Small', HARDPOINT_MODULES);
|
|
127
|
+
* if (pulse) build.setModule('SmallHardpoint1', pulse);
|
|
128
|
+
*
|
|
129
|
+
* before?.module; // -> still null — `before` describes the build as it was
|
|
130
|
+
* build.slots('hardpoint')[0]?.module?.symbol; // -> 'Hpt_PulseLaser_Fixed_Small'
|
|
131
|
+
* ```
|
|
132
|
+
*/
|
|
133
|
+
type LoadoutSlot = BuildSlot & {
|
|
134
|
+
/** Human-readable label, e.g. `"Frame Shift Drive"`. */
|
|
135
|
+
readonly name: string;
|
|
136
|
+
/** Frozen fitted-module snapshot, or `null` when this mount is empty. */
|
|
137
|
+
readonly module: FittedModule | null;
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* {@link ShipLoadout} — a mutable fitted-ship model that both **answers questions**
|
|
142
|
+
* about a build and **edits** it.
|
|
143
|
+
*
|
|
144
|
+
* Load one from a SLEF export (or a journal `Loadout` event) to read back the ship's
|
|
145
|
+
* identity, mass and fuel and ask for jump range and per-jump fuel; or start an
|
|
146
|
+
* {@link ShipLoadout.empty | empty} hull, enumerate its {@link ShipLoadout.slots | slots},
|
|
147
|
+
* and {@link ShipLoadout.setModule | fit} and {@link ShipLoadout.removeModule | remove}
|
|
148
|
+
* modules. It composes the data-free pieces of this folder — the SLEF parser
|
|
149
|
+
* (`./slef`), the jump-range maths (`./jump-range`), the slot model (`./slots`), and
|
|
150
|
+
* the module and ship catalogues (each record carrying its own stats).
|
|
151
|
+
*
|
|
152
|
+
* Instances are **mutable**: `setModule`/`removeModule` change the build in place and
|
|
153
|
+
* return `this` for chaining. Values a SLEF export already computed (its
|
|
154
|
+
* `UnladenMass`, `FuelCapacity`, …) are trusted verbatim; for a build assembled from
|
|
155
|
+
* scratch those figures are computed from the fitted modules and the hull's stats.
|
|
156
|
+
* Editing an imported build adjusts the supplied aggregate figures by the changed
|
|
157
|
+
* module's contribution; when that contribution is unknown, the affected figure is
|
|
158
|
+
* discarded and recomputed rather than allowed to go stale.
|
|
159
|
+
* `setModule` snapshots the complete record it receives, including resolved
|
|
160
|
+
* pre-engineered or caller-supplied stats, so every later metric uses the article that
|
|
161
|
+
* was actually fitted rather than resolving its symbol back to a stock module.
|
|
162
|
+
* Slot and fitted-module queries return deeply frozen point-in-time values; edits are
|
|
163
|
+
* made only through this facade, then observed by querying again.
|
|
164
|
+
*
|
|
165
|
+
* **Slot keys are matched case-insensitively.** Frontier writes `FrameShiftDrive` and
|
|
166
|
+
* `LargeMiningHardpoint1`, but a SLEF producer may lower-case every key as the
|
|
167
|
+
* specification's own example does — Inara writes `frameshiftdrive` and
|
|
168
|
+
* `largemininghardpoint1` — and both spellings name the same mount, whether you are
|
|
169
|
+
* reading it or fitting into it. What a build already carries is never rewritten to
|
|
170
|
+
* match, so re-exporting an import returns the producer's own spelling untouched.
|
|
171
|
+
*
|
|
172
|
+
* @remarks
|
|
173
|
+
* This is the batteries-included ship facade: resolving arbitrary journal module
|
|
174
|
+
* ids and engineering recipes requires the complete ship/module, blueprint, and
|
|
175
|
+
* experimental-effect catalogues. Import `./slef`, `./jump-range`, or an individual
|
|
176
|
+
* module catalogue instead when you only need one data-free operation or one
|
|
177
|
+
* outfitting category.
|
|
178
|
+
*
|
|
179
|
+
* @example
|
|
180
|
+
* ```ts
|
|
181
|
+
* declare const slefJsonString: string;
|
|
182
|
+
*
|
|
183
|
+
* import { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
|
|
184
|
+
*
|
|
185
|
+
* // Read a build:
|
|
186
|
+
* const build = ShipLoadout.fromSlef(slefJsonString);
|
|
187
|
+
* build.maxJumpRange(); // -> 89.41 (best single jump, one jump's fuel, no cargo)
|
|
188
|
+
*
|
|
189
|
+
* // Assemble one:
|
|
190
|
+
* import { getModuleBySymbol } from '@elite-dangerous-almanac/core/ships/modules';
|
|
191
|
+
* import { CORE_MODULES } from '@elite-dangerous-almanac/core/ships/modules-core';
|
|
192
|
+
* const conda = ShipLoadout.empty('Anaconda');
|
|
193
|
+
* conda.setModule('FrameShiftDrive', getModuleBySymbol('Int_Hyperdrive_Size6_Class5', CORE_MODULES)!);
|
|
194
|
+
* conda.slots('optional'); // every optional mount, occupied or empty, with size
|
|
195
|
+
* ```
|
|
196
|
+
*
|
|
197
|
+
* @packageDocumentation
|
|
198
|
+
*/
|
|
199
|
+
|
|
200
|
+
/** Optional mass overrides for a single calculation. */
|
|
201
|
+
interface JumpOptions {
|
|
202
|
+
/** Fuel in the tank for the jump, in tonnes. Defaults to the full main tank. */
|
|
203
|
+
readonly fuel?: number;
|
|
204
|
+
/** Cargo aboard, in tonnes. Defaults to `0` (unladen). */
|
|
205
|
+
readonly cargo?: number;
|
|
206
|
+
}
|
|
207
|
+
/** Options for {@link ShipLoadout.applyBlueprint}. */
|
|
208
|
+
interface ApplyBlueprintOptions {
|
|
209
|
+
/** The blueprint grade, `1`–`5`. */
|
|
210
|
+
readonly grade: number;
|
|
211
|
+
/**
|
|
212
|
+
* The engineering system's shared quality roll, `0`–`1`. Defaults to `1`
|
|
213
|
+
* (best roll). A legacy-engineered module's independently advanced attributes cannot be
|
|
214
|
+
* reconstructed from its single reported quality; import its stated modifiers instead.
|
|
215
|
+
*/
|
|
216
|
+
readonly quality?: number;
|
|
217
|
+
/** The experimental (special) effect's Frontier `fdname`, if any. */
|
|
218
|
+
readonly experimental?: string;
|
|
219
|
+
}
|
|
220
|
+
/** Options for the defence figures a build reports. */
|
|
221
|
+
interface DefenceOptions {
|
|
222
|
+
/**
|
|
223
|
+
* Pips to the systems capacitor, `0`–`4`, folded into the shield resistances.
|
|
224
|
+
* Defaults to `0` — the bare shield, as an outfitting screen shows it.
|
|
225
|
+
*/
|
|
226
|
+
readonly systemsPips?: number;
|
|
227
|
+
}
|
|
228
|
+
/** One fitted weapon and what it does, as {@link ShipLoadout.weaponMetrics} reports it. */
|
|
229
|
+
interface FittedWeaponMetrics {
|
|
230
|
+
/** The hardpoint's slot key, e.g. `"LargeHardpoint1"`. */
|
|
231
|
+
readonly slot: string;
|
|
232
|
+
/** The weapon's internal symbol. */
|
|
233
|
+
readonly symbol: string;
|
|
234
|
+
/** The weapon's display name, e.g. `"Multi-Cannon"`. */
|
|
235
|
+
readonly name: string;
|
|
236
|
+
/** Whether the weapon is switched on — a disabled weapon is excluded from the totals. */
|
|
237
|
+
readonly enabled: boolean;
|
|
238
|
+
/** What this weapon does per second, post-engineering. */
|
|
239
|
+
readonly metrics: WeaponMetrics;
|
|
240
|
+
/**
|
|
241
|
+
* How many rounds it holds when fully rearmed, post-engineering — `null` for a laser,
|
|
242
|
+
* which carries none. A capacity, not a rearm state: see {@link FittedModule.ammunition}.
|
|
243
|
+
*/
|
|
244
|
+
readonly ammunition: AmmunitionCapacity | null;
|
|
245
|
+
}
|
|
246
|
+
/** A build's firepower: every fitted weapon, and the totals across the enabled ones. */
|
|
247
|
+
interface BuildWeaponMetrics {
|
|
248
|
+
/** Every fitted weapon, in slot order. */
|
|
249
|
+
readonly weapons: readonly FittedWeaponMetrics[];
|
|
250
|
+
/** The additive totals across the **enabled** weapons. */
|
|
251
|
+
readonly total: WeaponTotals;
|
|
252
|
+
}
|
|
253
|
+
/** A build's jump ranges at the loads that matter, in light-years. */
|
|
254
|
+
interface JumpRangeSummary {
|
|
255
|
+
/**
|
|
256
|
+
* Best single jump: no cargo, and only one jump's fuel aboard — the figure the game
|
|
257
|
+
* and EDSY label "maximum jump range".
|
|
258
|
+
*/
|
|
259
|
+
readonly max: number;
|
|
260
|
+
/** Single jump on a full tank with an empty hold. */
|
|
261
|
+
readonly unladen: number;
|
|
262
|
+
/** Single jump on a full tank with a full hold. */
|
|
263
|
+
readonly laden: number;
|
|
264
|
+
/** Summed range of every jump on one full tank, empty hold. */
|
|
265
|
+
readonly totalUnladen: number;
|
|
266
|
+
/** Summed range of every jump on one full tank, full hold. */
|
|
267
|
+
readonly totalLaden: number;
|
|
268
|
+
}
|
|
269
|
+
/** A blueprint that can engineer a module, with the grades it offers. */
|
|
270
|
+
interface AvailableBlueprint {
|
|
271
|
+
/** The blueprint's Frontier `fdname`, e.g. `"FSD_LongRange"`. */
|
|
272
|
+
readonly fdname: string;
|
|
273
|
+
/** The grades the blueprint offers, ascending (e.g. `[1, 2, 3, 4, 5]`). */
|
|
274
|
+
readonly grades: readonly number[];
|
|
275
|
+
}
|
|
276
|
+
/** How to shape a build on the way out — see {@link ShipLoadout.toLoadoutEvent}. */
|
|
277
|
+
interface LoadoutExportOptions {
|
|
278
|
+
/**
|
|
279
|
+
* Module order. `'fitted'` — the default — keeps the order the build carries: an
|
|
280
|
+
* import's own `Modules[]` order, or the order modules were fitted. `'slots'`
|
|
281
|
+
* re-orders into outfitting-panel order; a module in a slot the hull's layout does
|
|
282
|
+
* not describe keeps its relative position at the end rather than being dropped.
|
|
283
|
+
*/
|
|
284
|
+
readonly moduleOrder?: 'fitted' | 'slots';
|
|
285
|
+
/**
|
|
286
|
+
* Write `On: true` / `Priority: 0` on modules that carry neither — as a journal
|
|
287
|
+
* always does and a build assembled here never does. Off by default, following
|
|
288
|
+
* SLEF's "require what is necessary, do not force the rest".
|
|
289
|
+
*/
|
|
290
|
+
readonly explicitPower?: boolean;
|
|
291
|
+
/**
|
|
292
|
+
* Which credits to quote. `'retail'` — the default — prices the build from the
|
|
293
|
+
* catalogue: the bare hull's `hullCost`, every fitted module's list price, and a
|
|
294
|
+
* `Rebuy` of 5% of the two.
|
|
295
|
+
*
|
|
296
|
+
* `'source'` quotes the build's {@link ShipLoadout.sourcePurchase | source purchase
|
|
297
|
+
* record} instead — `HullValue`, `ModulesValue`, `Rebuy` and the per-module `Value`
|
|
298
|
+
* figures exactly as the capture stated them, and nothing where it stated nothing.
|
|
299
|
+
* An unedited capture therefore re-exports its own credits unchanged.
|
|
300
|
+
*
|
|
301
|
+
* Each captured figure is pinned to what it was paid for, so an edit narrows the
|
|
302
|
+
* export rather than staling it. A slot whose module has been swapped is left
|
|
303
|
+
* unpriced, because the figure was paid for the article that *was* fitted; and
|
|
304
|
+
* `ModulesValue` and `Rebuy` are dropped once any priced module has been swapped or
|
|
305
|
+
* removed, since they then cover an article no longer aboard. Removing a module the
|
|
306
|
+
* capture listed but never priced is the one case this cannot detect: only the
|
|
307
|
+
* capture ever knew which unpriced modules its total counted.
|
|
308
|
+
*
|
|
309
|
+
* `HullValue` always stands: a captured hull figure names no slot, so no edit
|
|
310
|
+
* narrows it. Note that on a game capture it counts the hull *with* its stock
|
|
311
|
+
* fittings, and removing one of those leaves it overstating what is aboard.
|
|
312
|
+
*
|
|
313
|
+
* A build with no source record — one assembled here, or a capture that quoted no
|
|
314
|
+
* credits — exports no credit figure at all rather than falling back to retail.
|
|
315
|
+
*/
|
|
316
|
+
readonly credits?: 'retail' | 'source';
|
|
317
|
+
}
|
|
318
|
+
/** As {@link LoadoutExportOptions}, plus the SLEF envelope — see {@link ShipLoadout.toSlef}. */
|
|
319
|
+
interface SlefExportOptions extends LoadoutExportOptions {
|
|
320
|
+
/**
|
|
321
|
+
* The envelope header identifying the exporting application.
|
|
322
|
+
*
|
|
323
|
+
* SLEF attribution belongs to the application producing the export, not to this
|
|
324
|
+
* calculation library, so callers must provide it.
|
|
325
|
+
*/
|
|
326
|
+
readonly header: SlefHeader;
|
|
327
|
+
/** Spaces per indent for {@link ShipLoadout.toSlefString}. `0` (the default) is compact. */
|
|
328
|
+
readonly indent?: number;
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* A fitted ship — read a SLEF export, or assemble a hull from scratch.
|
|
332
|
+
*
|
|
333
|
+
* @remarks
|
|
334
|
+
* Jump calculations resolve the frame shift drive's constants from the drive's module
|
|
335
|
+
* record, applying any engineering the build carries (a Long Range blueprint's
|
|
336
|
+
* `FSDOptimalMass`, for instance). For a SLEF build, mass comes from the export's
|
|
337
|
+
* `UnladenMass`; for an assembled build it is the hull mass plus every fitted module's
|
|
338
|
+
* mass (armour defaults to the zero-mass lightweight alloy).
|
|
339
|
+
*
|
|
340
|
+
* @example
|
|
341
|
+
* Read a build a player already flies, and ask it what an outfitting screen shows.
|
|
342
|
+
* Every figure below is one build's — a Krait Phantom explorer. Figures the capture
|
|
343
|
+
* already stated — `unladenMass` here — are trusted verbatim; the rest are computed
|
|
344
|
+
* from the fit.
|
|
345
|
+
*
|
|
346
|
+
* ```ts
|
|
347
|
+
* import { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
|
|
348
|
+
* import type { LoadoutEvent } from '@elite-dangerous-almanac/core/ships/slef';
|
|
349
|
+
*
|
|
350
|
+
* // A `Loadout` line lifted from a player journal, parsed.
|
|
351
|
+
* declare const event: LoadoutEvent;
|
|
352
|
+
*
|
|
353
|
+
* const build = ShipLoadout.fromLoadout(event);
|
|
354
|
+
*
|
|
355
|
+
* build.shipSymbol; // -> 'krait_light'
|
|
356
|
+
* build.shipName; // -> 'Jenny Longuet'
|
|
357
|
+
* build.unladenMass; // -> 388.830017 (tonnes)
|
|
358
|
+
*
|
|
359
|
+
* build.maxJumpRange(); // -> 60.5478 (ly, best single jump)
|
|
360
|
+
* build.powerBudget().withinBudget; // -> true
|
|
361
|
+
* build.shieldMetrics()?.strength; // -> 743.12 (MJ)
|
|
362
|
+
* build.armourMetrics().hitPoints; // -> 307.8
|
|
363
|
+
* ```
|
|
364
|
+
*
|
|
365
|
+
* @example
|
|
366
|
+
* Assemble a hull instead. `empty` starts from the shipyard layout, `slots` enumerates
|
|
367
|
+
* the mounts, and `setModule` fits one — chainable, because the build is mutable.
|
|
368
|
+
*
|
|
369
|
+
* ```ts
|
|
370
|
+
* import { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
|
|
371
|
+
* import { getModuleBySymbol } from '@elite-dangerous-almanac/core/ships/modules';
|
|
372
|
+
* import { CORE_MODULES } from '@elite-dangerous-almanac/core/ships/modules-core';
|
|
373
|
+
*
|
|
374
|
+
* const conda = ShipLoadout.empty('Anaconda');
|
|
375
|
+
* conda.slots().length; // -> 39 (every mount, occupied or not)
|
|
376
|
+
* conda.slots('optional').length; // -> 14
|
|
377
|
+
* conda.validation.complete; // -> false (nothing fitted yet)
|
|
378
|
+
*
|
|
379
|
+
* const fsd = getModuleBySymbol('Int_Hyperdrive_Size6_Class5', CORE_MODULES);
|
|
380
|
+
* if (fsd) conda.setModule('FrameShiftDrive', fsd);
|
|
381
|
+
* ```
|
|
382
|
+
*
|
|
383
|
+
* @example
|
|
384
|
+
* Write a build back out. Retail credits are what the catalogue prices the fit at; pass
|
|
385
|
+
* `credits: 'source'` to export the figures a capture stated it paid instead — see
|
|
386
|
+
* {@link ShipLoadout.sourcePurchase}.
|
|
387
|
+
*
|
|
388
|
+
* ```ts
|
|
389
|
+
* import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
|
|
390
|
+
*
|
|
391
|
+
* declare const build: ShipLoadout;
|
|
392
|
+
*
|
|
393
|
+
* build.toLoadoutEvent(); // retail: hull cost plus every module's list price
|
|
394
|
+
* build.toLoadoutEvent({ credits: 'source' }); // the capture's own figures
|
|
395
|
+
* build.toSlefString({ header: { appName: 'MyApp', appVersion: '1.0.0' } });
|
|
396
|
+
* ```
|
|
397
|
+
*/
|
|
398
|
+
declare class ShipLoadout {
|
|
399
|
+
#private;
|
|
400
|
+
private constructor();
|
|
401
|
+
/**
|
|
402
|
+
* Build from a SLEF export.
|
|
403
|
+
*
|
|
404
|
+
* @param input - The SLEF JSON string, or an already-parsed SLEF object (see
|
|
405
|
+
* {@link parseSlef} for accepted shapes).
|
|
406
|
+
* @param index - Which entry to take when the export holds several builds.
|
|
407
|
+
* Defaults to the first.
|
|
408
|
+
* @returns The loadout for that entry.
|
|
409
|
+
* @throws {SyntaxError} If `input` is a string that is not valid JSON.
|
|
410
|
+
* @throws {TypeError} If the export holds no usable loadout, or `index` is out of
|
|
411
|
+
* range.
|
|
412
|
+
*/
|
|
413
|
+
static fromSlef(input: unknown, index?: number): ShipLoadout;
|
|
414
|
+
/**
|
|
415
|
+
* Build from a bare journal `Loadout` event (the `data` half of a SLEF entry).
|
|
416
|
+
*
|
|
417
|
+
* @param event - A `Loadout` event object.
|
|
418
|
+
* @returns The loadout.
|
|
419
|
+
* @remarks
|
|
420
|
+
* Capture/instance state (`timestamp`, `ShipID`, `HullHealth`, `Hot`) and engineering
|
|
421
|
+
* provenance (`Engineer`, `EngineerID`, `BlueprintID`) are deliberately excluded
|
|
422
|
+
* from the durable build. See {@link LoadoutEvent} and {@link ModuleEngineering}.
|
|
423
|
+
* A pre-engineered/reward module is identified from its reported stat signature when
|
|
424
|
+
* the evidence uniquely matches a catalogue variant. Its complete fixed stat block is
|
|
425
|
+
* then used as the fitted record, including values the capture omits; a separately
|
|
426
|
+
* applied experimental effect is included when matching and remains authoritative in
|
|
427
|
+
* the captured modifiers. Under-specified or ambiguous evidence stays unidentified.
|
|
428
|
+
* An ordinary weapon recipe on a Guardian weapon identifies a final pre-engineered
|
|
429
|
+
* article; the import preserves that identity, uses the catalogue's complete hand-set
|
|
430
|
+
* stat block when the exact article is known, exposes no engineering options for it,
|
|
431
|
+
* and refuses attempts to engineer it further. Explicit journal modifiers remain
|
|
432
|
+
* authoritative over that stat block.
|
|
433
|
+
*
|
|
434
|
+
* The event's credit figures are kept twice over: as the live `hullValue` /
|
|
435
|
+
* `modulesValue` / `rebuy`, which an edit may invalidate, and as the immutable
|
|
436
|
+
* {@link sourcePurchase} record, which no edit touches.
|
|
437
|
+
*
|
|
438
|
+
* @throws {TypeError} If the event is not shaped like one. What is checked is the
|
|
439
|
+
* structure a build is assembled from, and the types of the fields naming things in
|
|
440
|
+
* it: `event` must be an object with an array of module objects in `Modules`; each
|
|
441
|
+
* module needs a string `Slot` and `Item`, and no two may claim the same slot; a
|
|
442
|
+
* module's `Engineering` must be an object, and that block's `Modifiers` an array of
|
|
443
|
+
* objects each carrying a string `Label`, whenever their key is there **at all**;
|
|
444
|
+
* and `event.Ship`, the block's `BlueprintName` and its `ExperimentalEffect` must be
|
|
445
|
+
* strings **when they carry a value**. Every remaining field — every number, every
|
|
446
|
+
* flag, a modifier's value beside its label — is trusted, so use
|
|
447
|
+
* {@link ShipLoadout.fromSlef} (or {@link parseSlef}) for input you did not produce,
|
|
448
|
+
* which reports all of them.
|
|
449
|
+
*
|
|
450
|
+
* A modifier's `Label` is required rather than checked-when-present because it is
|
|
451
|
+
* the only thing saying which stat moved: {@link fittedModuleAt} and the
|
|
452
|
+
* pre-engineered identification both read it unconditionally, so an entry without
|
|
453
|
+
* one would import cleanly and then break the build it produced.
|
|
454
|
+
*
|
|
455
|
+
* `Engineering` and its `Modifiers` are the fields where a `null` is not the same as
|
|
456
|
+
* an omission, because a relay writing `null` for a block or list it does not have
|
|
457
|
+
* would otherwise be read as one. An **absent** `Ship` *is* an omission, and not a
|
|
458
|
+
* failure: it is a hull nothing can name, which {@link validation} reports as
|
|
459
|
+
* `unknownHull`. Nor is a partial `Engineering` block — a capture may state
|
|
460
|
+
* modifiers without naming the recipe.
|
|
461
|
+
*/
|
|
462
|
+
static fromLoadout(event: LoadoutEvent): ShipLoadout;
|
|
463
|
+
/**
|
|
464
|
+
* Start a new, empty build for a hull — no modules fitted.
|
|
465
|
+
*
|
|
466
|
+
* @param shipSymbol - The hull's internal symbol, e.g. `"Anaconda"`
|
|
467
|
+
* (case-insensitive).
|
|
468
|
+
* @returns An empty loadout whose {@link slots} come from the hull's declared
|
|
469
|
+
* layout.
|
|
470
|
+
* @throws {TypeError} If `shipSymbol` is not a string, or no hull with that symbol
|
|
471
|
+
* has a known slot layout.
|
|
472
|
+
* @example
|
|
473
|
+
* ```ts
|
|
474
|
+
* import { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
|
|
475
|
+
*
|
|
476
|
+
* ShipLoadout.empty('Sidewinder').slots('hardpoint').length; // -> 2
|
|
477
|
+
* ```
|
|
478
|
+
*/
|
|
479
|
+
static empty(shipSymbol: string): ShipLoadout;
|
|
480
|
+
/** The hull's internal id, e.g. `"explorer_nx"`. */
|
|
481
|
+
get shipSymbol(): string;
|
|
482
|
+
/** The player-given ship name, or `null` if the build has none. */
|
|
483
|
+
get shipName(): string | null;
|
|
484
|
+
/** The player-given ID plate, or `null` if the build has none. */
|
|
485
|
+
get shipIdent(): string | null;
|
|
486
|
+
/**
|
|
487
|
+
* Hull + modules mass with an empty tank and no cargo, in tonnes, or `null` if it
|
|
488
|
+
* cannot be determined (no `UnladenMass` in the export and either the hull or a
|
|
489
|
+
* fitted module has no known mass).
|
|
490
|
+
*
|
|
491
|
+
* @remarks
|
|
492
|
+
* A SLEF export's `UnladenMass` is trusted verbatim. Otherwise the mass is the
|
|
493
|
+
* hull's `hullMass` plus every fitted module's mass (post-engineering), with armour
|
|
494
|
+
* at the zero-mass lightweight default.
|
|
495
|
+
*/
|
|
496
|
+
get unladenMass(): number | null;
|
|
497
|
+
/**
|
|
498
|
+
* Unladen mass with diagnostics for every missing input.
|
|
499
|
+
*
|
|
500
|
+
* @returns A complete imported or computed mass, otherwise `null` plus the hull or
|
|
501
|
+
* module fields that prevented the calculation.
|
|
502
|
+
*/
|
|
503
|
+
get unladenMassResult(): CalculationResult<number>;
|
|
504
|
+
/**
|
|
505
|
+
* Fuel-tank capacities, in tonnes, or `null` when a tank or the hull's reserve
|
|
506
|
+
* capacity is unknown. A SLEF export's `FuelCapacity` is used when present;
|
|
507
|
+
* otherwise the main capacity is the sum of the fitted fuel tanks and the reserve
|
|
508
|
+
* comes from the hull's stats.
|
|
509
|
+
*/
|
|
510
|
+
get fuelCapacity(): FuelCapacity | null;
|
|
511
|
+
/** Fuel capacity with diagnostics instead of unknown tanks collapsing to zero. */
|
|
512
|
+
get fuelCapacityResult(): CalculationResult<FuelCapacity>;
|
|
513
|
+
/**
|
|
514
|
+
* Cargo capacity, in tonnes, or `null` when a fitted optional module cannot be
|
|
515
|
+
* classified. A SLEF export's `CargoCapacity` is used when present; otherwise it is
|
|
516
|
+
* the sum of the fitted cargo racks.
|
|
517
|
+
*/
|
|
518
|
+
get cargoCapacity(): number | null;
|
|
519
|
+
/** Cargo capacity with diagnostics instead of unknown racks collapsing to zero. */
|
|
520
|
+
get cargoCapacityResult(): CalculationResult<number>;
|
|
521
|
+
/**
|
|
522
|
+
* Hull cost in credits represented by the build, or `null` if unknown.
|
|
523
|
+
*
|
|
524
|
+
* @remarks
|
|
525
|
+
* This is the live figure, kept coherent with edits: an import's own `HullValue`
|
|
526
|
+
* until something invalidates it. For the capture's figure as captured — which no
|
|
527
|
+
* edit changes — read {@link sourcePurchase}.
|
|
528
|
+
*/
|
|
529
|
+
get hullValue(): number | null;
|
|
530
|
+
/**
|
|
531
|
+
* Fitted-modules cost in credits represented by the build, or `null` if
|
|
532
|
+
* unknown — including after an edit discarded an import's figure, since no catalogue
|
|
533
|
+
* records what a replaced module was bought for. {@link sourcePurchase} keeps the
|
|
534
|
+
* captured figure regardless.
|
|
535
|
+
*/
|
|
536
|
+
get modulesValue(): number | null;
|
|
537
|
+
/**
|
|
538
|
+
* Insurance rebuy cost in credits represented by the build, or `null` if
|
|
539
|
+
* unknown. Discarded by an edit for the same reason as {@link modulesValue}, and
|
|
540
|
+
* likewise preserved by {@link sourcePurchase}.
|
|
541
|
+
*/
|
|
542
|
+
get rebuy(): number | null;
|
|
543
|
+
/**
|
|
544
|
+
* What the capture this build came from said was **paid** for it — a read-only
|
|
545
|
+
* {@link SourcePurchaseRecord}, or `null` for a build assembled here or imported
|
|
546
|
+
* from a capture that quoted no credits at all.
|
|
547
|
+
*
|
|
548
|
+
* @remarks
|
|
549
|
+
* The record is provenance about the source, so it is fixed at import and **survives
|
|
550
|
+
* every edit**: fit, remove or engineer whatever you like and it still reports the
|
|
551
|
+
* figures the capture carried, for the modules the capture carried them for. That is
|
|
552
|
+
* what {@link hullValue}, {@link modulesValue} and {@link rebuy} cannot do — they
|
|
553
|
+
* describe the build in hand, so an edit that invalidates one drops it.
|
|
554
|
+
*
|
|
555
|
+
* The two answer different questions and neither substitutes for the other. A
|
|
556
|
+
* captured price belongs to one commander's purchase history, discounts included;
|
|
557
|
+
* the library's own figures are catalogue retail. Export picks between them
|
|
558
|
+
* explicitly, and quotes retail unless asked otherwise — see
|
|
559
|
+
* {@link LoadoutExportOptions.credits}.
|
|
560
|
+
*
|
|
561
|
+
* @example
|
|
562
|
+
* ```ts
|
|
563
|
+
* import { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
|
|
564
|
+
* import { getSourceModuleValue } from '@elite-dangerous-almanac/core/ships/source-purchase';
|
|
565
|
+
*
|
|
566
|
+
* declare const slefJson: string;
|
|
567
|
+
*
|
|
568
|
+
* const build = ShipLoadout.fromSlef(slefJson);
|
|
569
|
+
* const paid = build.sourcePurchase!;
|
|
570
|
+
* paid.hullValue; // -> 189326510, as captured
|
|
571
|
+
* getSourceModuleValue(paid, 'powerplant')?.value; // -> what that plant cost its owner
|
|
572
|
+
*
|
|
573
|
+
* build.removeModule('Slot05_Size4');
|
|
574
|
+
* build.modulesValue; // -> null unavailable after the edit
|
|
575
|
+
* paid.modulesValue; // -> 192625195, the captured figure
|
|
576
|
+
* ```
|
|
577
|
+
*/
|
|
578
|
+
get sourcePurchase(): SourcePurchaseRecord | null;
|
|
579
|
+
/**
|
|
580
|
+
* Structural validity and operational completeness of this build.
|
|
581
|
+
*
|
|
582
|
+
* @remarks
|
|
583
|
+
* Optional, hardpoint and utility mounts may be empty. Armour and all seven core
|
|
584
|
+
* mounts must be filled for `complete` to be true. An unknown hull or module is
|
|
585
|
+
* incomplete; a module in a nonexistent or incompatible slot is invalid.
|
|
586
|
+
*/
|
|
587
|
+
get validation(): LoadoutValidation;
|
|
588
|
+
/**
|
|
589
|
+
* Frozen point-in-time views of the hull's mounts in outfitting-panel order.
|
|
590
|
+
*
|
|
591
|
+
* @param kind - Optionally keep only one mount kind. Omit it for every mount.
|
|
592
|
+
* @returns Detached slot views. Repeated reads at the same build version reuse the
|
|
593
|
+
* same frozen array and records; every state-changing edit makes the next read produce
|
|
594
|
+
* new snapshots.
|
|
595
|
+
* @throws {TypeError} If the hull has no known slot layout.
|
|
596
|
+
* @example
|
|
597
|
+
* ```ts
|
|
598
|
+
* import { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
|
|
599
|
+
*
|
|
600
|
+
* const emptyHardpoints = ShipLoadout.empty('Sidewinder').slots('hardpoint');
|
|
601
|
+
* emptyHardpoints.every((slot) => slot.module === null); // true
|
|
602
|
+
* ```
|
|
603
|
+
*/
|
|
604
|
+
slots(kind?: SlotKind): readonly LoadoutSlot[];
|
|
605
|
+
/**
|
|
606
|
+
* A deeply frozen, point-in-time view of the module in a slot.
|
|
607
|
+
*
|
|
608
|
+
* @param slotKey - Slot key, matched case-insensitively.
|
|
609
|
+
* @returns A detached view, or `null` when the slot is empty or unknown. Repeated
|
|
610
|
+
* reads at the same build version reuse the same frozen record; every state-changing
|
|
611
|
+
* edit makes the next read produce a new snapshot.
|
|
612
|
+
* @throws {TypeError} If `slotKey` is not a string.
|
|
613
|
+
*/
|
|
614
|
+
fittedModuleAt(slotKey: string): FittedModule | null;
|
|
615
|
+
/**
|
|
616
|
+
* Every fitted module as a deeply frozen point-in-time view.
|
|
617
|
+
*
|
|
618
|
+
* @returns Detached module snapshots in the order the build carries them. The array
|
|
619
|
+
* and every nested record are frozen; query again after an edit for current state.
|
|
620
|
+
* @example
|
|
621
|
+
* ```ts
|
|
622
|
+
* import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
|
|
623
|
+
*
|
|
624
|
+
* declare const build: ShipLoadout;
|
|
625
|
+
*
|
|
626
|
+
* build.fittedModules().map((module) => `${module.slot}: ${module.symbol}`);
|
|
627
|
+
* ```
|
|
628
|
+
*/
|
|
629
|
+
fittedModules(): readonly FittedModule[];
|
|
630
|
+
/**
|
|
631
|
+
* Return the computable blueprints offered to a fitted module.
|
|
632
|
+
*
|
|
633
|
+
* @param slotKey - Slot key, matched case-insensitively.
|
|
634
|
+
* @returns Frozen blueprint descriptors in engineering-menu order, or an empty
|
|
635
|
+
* array when the slot is empty, unresolved, final, or has no engineering menu.
|
|
636
|
+
* @throws {TypeError} If `slotKey` is not a string.
|
|
637
|
+
* @example
|
|
638
|
+
* ```ts
|
|
639
|
+
* import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
|
|
640
|
+
*
|
|
641
|
+
* declare const build: ShipLoadout;
|
|
642
|
+
*
|
|
643
|
+
* build.availableBlueprints('FrameShiftDrive').map(({ fdname }) => fdname);
|
|
644
|
+
* ```
|
|
645
|
+
*/
|
|
646
|
+
availableBlueprints(slotKey: string): readonly AvailableBlueprint[];
|
|
647
|
+
/**
|
|
648
|
+
* Return the computable experimental effects offered to a fitted module.
|
|
649
|
+
*
|
|
650
|
+
* @param slotKey - Slot key, matched case-insensitively.
|
|
651
|
+
* @returns Frozen Frontier effect ids in engineering-menu order, or an empty array
|
|
652
|
+
* when the slot is empty, unresolved, final, or has no experimental menu.
|
|
653
|
+
* @throws {TypeError} If `slotKey` is not a string.
|
|
654
|
+
* @example
|
|
655
|
+
* ```ts
|
|
656
|
+
* import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
|
|
657
|
+
*
|
|
658
|
+
* declare const build: ShipLoadout;
|
|
659
|
+
*
|
|
660
|
+
* build.availableExperimentalEffects('FrameShiftDrive');
|
|
661
|
+
* // -> ['special_fsd_heavy', ...]
|
|
662
|
+
* ```
|
|
663
|
+
*/
|
|
664
|
+
availableExperimentalEffects(slotKey: string): readonly string[];
|
|
665
|
+
/**
|
|
666
|
+
* The modules that fit a given slot — its size, kind and any restriction all
|
|
667
|
+
* satisfied.
|
|
668
|
+
*
|
|
669
|
+
* @param slotKey - The slot key to fit, matched case-insensitively (journal spelling).
|
|
670
|
+
* @returns The fitting modules, in complete-catalogue order.
|
|
671
|
+
* @throws {RangeError} If the hull has no slot with that key.
|
|
672
|
+
* @throws {TypeError} If `slotKey` is not a string, or the hull has no known slot
|
|
673
|
+
* layout (a SLEF build on an unrecognised hull).
|
|
674
|
+
* @example
|
|
675
|
+
* ```ts
|
|
676
|
+
* import { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
|
|
677
|
+
*
|
|
678
|
+
* ShipLoadout.empty('Anaconda').modulesForSlot('FrameShiftDrive');
|
|
679
|
+
* ```
|
|
680
|
+
*/
|
|
681
|
+
modulesForSlot(slotKey: string): OutfittingModule[];
|
|
682
|
+
/**
|
|
683
|
+
* Fit a module into a slot, replacing whatever is there.
|
|
684
|
+
*
|
|
685
|
+
* @param slotKey - The slot key to fit into, matched case-insensitively (journal
|
|
686
|
+
* spelling). An occupied slot keeps the key the build already spells it with, so
|
|
687
|
+
* fitting into an import never renames one of its mounts.
|
|
688
|
+
* @param module - The module to fit (resolve it from a catalogue first, e.g. with
|
|
689
|
+
* {@link getModuleBySymbol}). The complete record is snapshotted, so a result from
|
|
690
|
+
* `getPreEngineeredStats` or a caller-supplied catalogue keeps its resolved stats.
|
|
691
|
+
* @returns `this`, for chaining.
|
|
692
|
+
* @throws {RangeError} If the hull has no slot with that key.
|
|
693
|
+
* @throws {TypeError} If `slotKey` is not a string; `module` is null/undefined (e.g. a
|
|
694
|
+
* `getModuleBySymbol` miss) or is not an outfitting module at all; the module does not
|
|
695
|
+
* fit the slot (wrong kind, too large, or a restriction the module does not satisfy);
|
|
696
|
+
* or the hull has no known slot layout (a SLEF build on an unrecognised hull).
|
|
697
|
+
* @example
|
|
698
|
+
* ```ts
|
|
699
|
+
* import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
|
|
700
|
+
*
|
|
701
|
+
* declare const build: ShipLoadout;
|
|
702
|
+
*
|
|
703
|
+
* import { getModuleBySymbol } from '@elite-dangerous-almanac/core/ships/modules';
|
|
704
|
+
* import { CORE_MODULES } from '@elite-dangerous-almanac/core/ships/modules-core';
|
|
705
|
+
* const fsd = getModuleBySymbol('Int_Hyperdrive_Size6_Class5', CORE_MODULES)!;
|
|
706
|
+
* const tank = getModuleBySymbol('Int_FuelTank_Size6_Class3', CORE_MODULES)!;
|
|
707
|
+
* build.setModule('FrameShiftDrive', fsd).setModule('Slot01_Size7', tank);
|
|
708
|
+
* ```
|
|
709
|
+
*/
|
|
710
|
+
setModule(slotKey: string, module: OutfittingModule): this;
|
|
711
|
+
/**
|
|
712
|
+
* Empty a slot.
|
|
713
|
+
*
|
|
714
|
+
* @param slotKey - The slot key to clear, matched case-insensitively (journal
|
|
715
|
+
* spelling).
|
|
716
|
+
* @returns `this`, for chaining. Clearing an already-empty slot is a no-op.
|
|
717
|
+
* @throws {TypeError} If `slotKey` is not a string, or names the built-in cargo
|
|
718
|
+
* hatch, which cannot be removed or replaced.
|
|
719
|
+
*/
|
|
720
|
+
removeModule(slotKey: string): this;
|
|
721
|
+
/**
|
|
722
|
+
* Engineer the module in a slot — apply a blueprint (with a grade and quality) and
|
|
723
|
+
* an optional experimental effect, computing the resulting stat modifiers.
|
|
724
|
+
*
|
|
725
|
+
* The modifiers are stored as an `Engineering` block on the fitted module, so the
|
|
726
|
+
* build's jump-range and mass calculations pick them up automatically. The block keeps
|
|
727
|
+
* the `BlueprintName` you passed, so it reads back the way the build declared it.
|
|
728
|
+
*
|
|
729
|
+
* **Which recipe an id names can depend on the module.** The game writes
|
|
730
|
+
* `Sensor_LongRange` and `Sensor_WideAngle` for both a sensor suite's modification and a
|
|
731
|
+
* utility scanner's, and the two roll different stats in opposite directions — Long
|
|
732
|
+
* Range costs the suite mass and the scanner power draw. So the id is resolved against
|
|
733
|
+
* the module's menu before anything is computed, and a wake scanner engineered
|
|
734
|
+
* `Sensor_LongRange` gets the scanner's numbers, which `BLUEPRINTS` keys
|
|
735
|
+
* `Scanner_LongRange`. Reading a stored block back the same way means resolving it the
|
|
736
|
+
* same way: `resolveBlueprintForModule` in `ships/blueprint-journal` is that lookup.
|
|
737
|
+
*
|
|
738
|
+
* @param slotKey - The slot whose module to engineer, matched case-insensitively
|
|
739
|
+
* (journal spelling).
|
|
740
|
+
* @param fdname - The blueprint recipe's Frontier `fdname`, e.g. `"FSD_LongRange"`.
|
|
741
|
+
* @param options - {@link ApplyBlueprintOptions}: `grade` (1–5), optional `quality`
|
|
742
|
+
* (0–1, default 1), and optional `experimental` effect `fdname`. A nullish
|
|
743
|
+
* `experimental` means no effect, the same as leaving it out. Each is read once,
|
|
744
|
+
* before anything is checked, so an accessor cannot answer the check and the use
|
|
745
|
+
* differently.
|
|
746
|
+
* @returns `this`, for chaining.
|
|
747
|
+
* @throws {RangeError} If the slot is empty, or the blueprint/grade/experimental is
|
|
748
|
+
* unknown, or `quality` is outside `[0, 1]`.
|
|
749
|
+
* @throws {TypeError} If `slotKey` or `fdname` is not a string, `options` is not an
|
|
750
|
+
* object, or `options.experimental` carries a value that is not a string — a nullish
|
|
751
|
+
* one is no effect, not a wrong type; the fitted module has no stats to engineer; or the id names a
|
|
752
|
+
* decorative modification, which names no recipe (see
|
|
753
|
+
* {@link DECORATIVE_MODIFICATIONS}); or the module is not offered the blueprint — by
|
|
754
|
+
* its engineering menu, by the journal spelling of an entry on that menu, by the
|
|
755
|
+
* generic spelling of a recipe that menu lists under a family's name, or by being sold
|
|
756
|
+
* already carrying it; the fitted article is final and accepts no further engineering;
|
|
757
|
+
* or the module is not offered the experimental effect, which its
|
|
758
|
+
* menu alone decides; or the catalogue does not carry every base stat the recipe
|
|
759
|
+
* modifies. Incomplete engineering is rejected rather than stored as a partial journal
|
|
760
|
+
* modifier block.
|
|
761
|
+
* @example
|
|
762
|
+
* ```ts
|
|
763
|
+
* import { getModuleBySymbol } from '@elite-dangerous-almanac/core/ships/modules';
|
|
764
|
+
* import { CORE_MODULES } from '@elite-dangerous-almanac/core/ships/modules-core';
|
|
765
|
+
* import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
|
|
766
|
+
*
|
|
767
|
+
* declare const build: ShipLoadout;
|
|
768
|
+
*
|
|
769
|
+
* const fsd = getModuleBySymbol('Int_Hyperdrive_Size6_Class5', CORE_MODULES)!;
|
|
770
|
+
*
|
|
771
|
+
* build.setModule('FrameShiftDrive', fsd)
|
|
772
|
+
* .applyBlueprint('FrameShiftDrive', 'FSD_LongRange', {
|
|
773
|
+
* grade: 5,
|
|
774
|
+
* experimental: 'special_fsd_heavy',
|
|
775
|
+
* });
|
|
776
|
+
* build.maxJumpRange(); // uses the engineered optimal mass
|
|
777
|
+
* ```
|
|
778
|
+
*/
|
|
779
|
+
applyBlueprint(slotKey: string, fdname: string, options: ApplyBlueprintOptions): this;
|
|
780
|
+
/**
|
|
781
|
+
* Strip the engineering from a slot's module, restoring its base stats.
|
|
782
|
+
*
|
|
783
|
+
* @param slotKey - The slot to de-engineer, matched case-insensitively (journal
|
|
784
|
+
* spelling).
|
|
785
|
+
* @returns `this`, for chaining. A no-op if the slot is empty or un-engineered.
|
|
786
|
+
* @throws {TypeError} If `slotKey` is not a string, or the fitted article is final
|
|
787
|
+
* pre-engineered and its baked engineering cannot be removed.
|
|
788
|
+
*/
|
|
789
|
+
clearEngineering(slotKey: string): this;
|
|
790
|
+
/**
|
|
791
|
+
* Switch a fitted module on or off.
|
|
792
|
+
*
|
|
793
|
+
* @param slotKey - The slot's journal key, e.g. `"PowerPlant"`, matched
|
|
794
|
+
* case-insensitively.
|
|
795
|
+
* @param on - `true` to power it, `false` to switch it off.
|
|
796
|
+
* @returns `this`, for chaining.
|
|
797
|
+
* @throws {RangeError} If the slot is empty.
|
|
798
|
+
* @throws {TypeError} If `slotKey` is not a string.
|
|
799
|
+
* @example
|
|
800
|
+
* ```ts
|
|
801
|
+
* import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
|
|
802
|
+
*
|
|
803
|
+
* declare const build: ShipLoadout;
|
|
804
|
+
*
|
|
805
|
+
* build.setModuleEnabled('TinyHardpoint6', false); // an unpowered heat sink
|
|
806
|
+
* ```
|
|
807
|
+
*/
|
|
808
|
+
setModuleEnabled(slotKey: string, on: boolean): this;
|
|
809
|
+
/**
|
|
810
|
+
* Set a fitted module's power-priority group.
|
|
811
|
+
*
|
|
812
|
+
* @param slotKey - The slot's journal key, matched case-insensitively.
|
|
813
|
+
* @param priority - The journal's **zero-based** group, `0`–`4`. Note that the
|
|
814
|
+
* outfitting panel — and {@link powerBudget}'s `bands[].priority` — number the same
|
|
815
|
+
* five groups `1`–`5`.
|
|
816
|
+
* @returns `this`, for chaining.
|
|
817
|
+
* @throws {RangeError} If the slot is empty, or `priority` is not an integer in `[0, 4]`.
|
|
818
|
+
* @throws {TypeError} If `slotKey` is not a string.
|
|
819
|
+
*/
|
|
820
|
+
setModulePriority(slotKey: string, priority: number): this;
|
|
821
|
+
/**
|
|
822
|
+
* This build as a journal `Loadout` event — the `data` half of a SLEF entry.
|
|
823
|
+
*
|
|
824
|
+
* @param options - Module ordering and how sparse to be about power state.
|
|
825
|
+
* @returns A fresh event. Every top-level figure is **recomputed** from the hull and
|
|
826
|
+
* the fitted modules rather than echoed from whatever an import supplied — the one
|
|
827
|
+
* exception being the credits, when `credits: 'source'` asks for the capture's own.
|
|
828
|
+
* Any figure that cannot be worked out is **left out** rather than emitted as a stale
|
|
829
|
+
* or zero value — SLEF requires nothing beyond `Ship` and `Modules`.
|
|
830
|
+
*
|
|
831
|
+
* Credits are quoted at **retail** by default: the bare hull's `hullCost` plus every
|
|
832
|
+
* fitted module's catalogue list price, with `Rebuy` 5% of the two. A source's own
|
|
833
|
+
* `HullValue` / `ModulesValue` / `Value` figures are deliberately not quoted here,
|
|
834
|
+
* because they record one commander's purchase history — the Deep Black's modules
|
|
835
|
+
* are all 12.25% off list — and purchase discounts are not a property of the build.
|
|
836
|
+
* They are not lost either: pass `credits: 'source'` to export the
|
|
837
|
+
* {@link sourcePurchase} record instead, as provenance rather than as a price.
|
|
838
|
+
* @example
|
|
839
|
+
* ```ts
|
|
840
|
+
* import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
|
|
841
|
+
*
|
|
842
|
+
* declare const build: ShipLoadout;
|
|
843
|
+
*
|
|
844
|
+
* const event = build.toLoadoutEvent();
|
|
845
|
+
* event.MaxJumpRange; // recomputed, not the exporter's claim
|
|
846
|
+
* event.HullValue; // the catalogue's list price
|
|
847
|
+
*
|
|
848
|
+
* build.toLoadoutEvent({ credits: 'source' }).HullValue; // what the capture paid
|
|
849
|
+
* ```
|
|
850
|
+
*/
|
|
851
|
+
toLoadoutEvent(options?: LoadoutExportOptions): LoadoutEvent;
|
|
852
|
+
/**
|
|
853
|
+
* This build as a one-entry SLEF export.
|
|
854
|
+
*
|
|
855
|
+
* @param options - Ordering, power state, and the envelope header.
|
|
856
|
+
* @returns The export. Several builds travel together as
|
|
857
|
+
* `toSlef([a.toLoadoutEvent(), b.toLoadoutEvent()])` using the function of the same
|
|
858
|
+
* name from `./slef`.
|
|
859
|
+
*/
|
|
860
|
+
toSlef(options: SlefExportOptions): Slef;
|
|
861
|
+
/**
|
|
862
|
+
* This build as SLEF JSON — ready to write to a file or put on the clipboard.
|
|
863
|
+
*
|
|
864
|
+
* @param options - As {@link toSlef}, plus `indent` (compact by default).
|
|
865
|
+
* @example
|
|
866
|
+
* ```ts
|
|
867
|
+
* import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
|
|
868
|
+
*
|
|
869
|
+
* declare const build: ShipLoadout;
|
|
870
|
+
*
|
|
871
|
+
* build.toSlefString({ header: { appName: 'MyApp', appVersion: '1.0.0' } });
|
|
872
|
+
* ```
|
|
873
|
+
*/
|
|
874
|
+
toSlefString(options: SlefExportOptions): string;
|
|
875
|
+
/**
|
|
876
|
+
* The resolved frame-shift-drive constants for this build — post-engineering,
|
|
877
|
+
* with any Guardian FSD Booster folded into `jumpBoost`.
|
|
878
|
+
*
|
|
879
|
+
* @throws {TypeError} If the build has no frame shift drive, or its required jump
|
|
880
|
+
* constants are missing from the stats catalogue.
|
|
881
|
+
*/
|
|
882
|
+
get frameShiftDrive(): FrameShiftDriveParams;
|
|
883
|
+
/**
|
|
884
|
+
* Best single-jump range, in light-years — no cargo, and exactly one jump's fuel
|
|
885
|
+
* aboard (the lightest the ship jumps). This is the figure the game and EDSY label
|
|
886
|
+
* "maximum jump range".
|
|
887
|
+
*
|
|
888
|
+
* @remarks
|
|
889
|
+
* Returns `0` when no fuel is available — an assembled build with no fuel tank
|
|
890
|
+
* fitted has an empty main tank, so there is nothing to jump on.
|
|
891
|
+
* @returns The best single jump, in light-years.
|
|
892
|
+
* @throws {TypeError} If the build has no usable frame shift drive, or its mass or
|
|
893
|
+
* fuel capacity cannot be determined.
|
|
894
|
+
*/
|
|
895
|
+
maxJumpRange(): number;
|
|
896
|
+
/**
|
|
897
|
+
* The range of a single jump for a chosen fuel and cargo load, in light-years.
|
|
898
|
+
*
|
|
899
|
+
* @param options - {@link JumpOptions}. `fuel` defaults to a full main tank,
|
|
900
|
+
* `cargo` to `0`.
|
|
901
|
+
* @returns The jump's range, in light-years.
|
|
902
|
+
* @throws {TypeError} If the build has no usable frame shift drive or its mass
|
|
903
|
+
* cannot be determined; also if fuel capacity is unknown and `options.fuel` is
|
|
904
|
+
* omitted.
|
|
905
|
+
*/
|
|
906
|
+
jumpRange(options?: JumpOptions): number;
|
|
907
|
+
/**
|
|
908
|
+
* Single-jump range on a full tank with a full cargo hold, in light-years.
|
|
909
|
+
*
|
|
910
|
+
* @returns The jump's range, in light-years.
|
|
911
|
+
* @throws {TypeError} If the build has no usable frame shift drive, or its mass,
|
|
912
|
+
* fuel capacity or cargo capacity cannot be determined.
|
|
913
|
+
*/
|
|
914
|
+
ladenJumpRange(): number;
|
|
915
|
+
/**
|
|
916
|
+
* The fuel a single jump of a given distance costs, in tonnes.
|
|
917
|
+
*
|
|
918
|
+
* @param distance - The jump distance, in light-years.
|
|
919
|
+
* @param options - {@link JumpOptions}. `fuel` defaults to a full main tank,
|
|
920
|
+
* `cargo` to `0`.
|
|
921
|
+
* @returns Fuel used, in tonnes (capped at the drive's max fuel per jump).
|
|
922
|
+
* @throws {TypeError} If the build has no usable frame shift drive or its mass
|
|
923
|
+
* cannot be determined; also if fuel capacity is unknown and `options.fuel` is
|
|
924
|
+
* omitted.
|
|
925
|
+
*/
|
|
926
|
+
fuelPerJump(distance: number, options?: JumpOptions): number;
|
|
927
|
+
/**
|
|
928
|
+
* Total multi-jump range on a full main tank, in light-years — the sum of
|
|
929
|
+
* successive jumps as the tank drains.
|
|
930
|
+
*
|
|
931
|
+
* @param options - `cargo` aboard, in tonnes; defaults to `0`.
|
|
932
|
+
* @returns The summed range of every jump on one full tank, in light-years.
|
|
933
|
+
* @throws {TypeError} If the build has no usable frame shift drive, or its mass or
|
|
934
|
+
* fuel capacity cannot be determined.
|
|
935
|
+
*/
|
|
936
|
+
totalRange(options?: {
|
|
937
|
+
readonly cargo?: number;
|
|
938
|
+
}): number;
|
|
939
|
+
/**
|
|
940
|
+
* Every jump figure at once — best, unladen, laden, and the multi-jump totals.
|
|
941
|
+
*
|
|
942
|
+
* @returns The {@link JumpRangeSummary}, in light-years. For a partial load, call
|
|
943
|
+
* {@link jumpRange} with the `fuel` and `cargo` you actually have.
|
|
944
|
+
* @throws {TypeError} If the build has no usable frame shift drive, or its mass,
|
|
945
|
+
* fuel capacity or cargo capacity cannot be determined.
|
|
946
|
+
* @example
|
|
947
|
+
* ```ts
|
|
948
|
+
* import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
|
|
949
|
+
*
|
|
950
|
+
* declare const build: ShipLoadout;
|
|
951
|
+
*
|
|
952
|
+
* const jumps = build.jumpRangeSummary();
|
|
953
|
+
* jumps.max; // -> 89.41 (one jump's fuel, empty hold)
|
|
954
|
+
* jumps.laden; // -> the range with the hold full
|
|
955
|
+
* // Half a tank and 32 t aboard, once the tank is known:
|
|
956
|
+
* const fuel = build.fuelCapacityResult;
|
|
957
|
+
* if (fuel.complete) build.jumpRange({ fuel: fuel.value.main / 2, cargo: 32 });
|
|
958
|
+
* ```
|
|
959
|
+
*/
|
|
960
|
+
jumpRangeSummary(): JumpRangeSummary;
|
|
961
|
+
/**
|
|
962
|
+
* The build's power budget: what the plant makes, what the modules draw with
|
|
963
|
+
* hardpoints retracted and deployed, and which priority groups stay lit.
|
|
964
|
+
*
|
|
965
|
+
* Draws are post-engineering, modules switched off in the journal are skipped, and
|
|
966
|
+
* weapons (plus the utility fittings that are not always powered) count only
|
|
967
|
+
* towards the deployed total.
|
|
968
|
+
*
|
|
969
|
+
* @returns The {@link PowerBudget}. With no power plant fitted, `available` is `0`
|
|
970
|
+
* and nothing is powered. A fitted module whose draw the catalogue cannot supply is
|
|
971
|
+
* named in {@link PowerBudget.unknownDraws} rather than counted as drawing nothing,
|
|
972
|
+
* which makes every total a lower bound while that list is non-empty.
|
|
973
|
+
* @example
|
|
974
|
+
* ```ts
|
|
975
|
+
* import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
|
|
976
|
+
*
|
|
977
|
+
* declare const build: ShipLoadout;
|
|
978
|
+
*
|
|
979
|
+
* const power = build.powerBudget();
|
|
980
|
+
* power.available; // -> 20.4 MW generated
|
|
981
|
+
* power.deployed; // -> 19.02 MW drawn, hardpoints out
|
|
982
|
+
* power.withinBudget; // -> true
|
|
983
|
+
* power.bands[4]?.poweredDeployed; // -> is priority group 5 still lit?
|
|
984
|
+
* ```
|
|
985
|
+
*/
|
|
986
|
+
powerBudget(): PowerBudget;
|
|
987
|
+
/**
|
|
988
|
+
* The build's shields: strength in megajoules, where it comes from, and the
|
|
989
|
+
* effective resistances.
|
|
990
|
+
*
|
|
991
|
+
* Shield strength scales with the **hull's** mass, not the build's, so fitting
|
|
992
|
+
* more modules never weakens it. Boosters, Guardian shield reinforcement and any
|
|
993
|
+
* engineering are all folded in; switched-off modules are ignored.
|
|
994
|
+
*
|
|
995
|
+
* @param options - {@link DefenceOptions}. `systemsPips` (0–4) folds the SYS
|
|
996
|
+
* capacitor's own resistance into the reported figures; it defaults to `0`, which
|
|
997
|
+
* is what an outfitting screen shows.
|
|
998
|
+
* @returns The {@link ShieldMetrics}, or `null` when the build has no shield
|
|
999
|
+
* generator fitted (or has one switched off).
|
|
1000
|
+
* @example
|
|
1001
|
+
* ```ts
|
|
1002
|
+
* import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
|
|
1003
|
+
*
|
|
1004
|
+
* declare const build: ShipLoadout;
|
|
1005
|
+
*
|
|
1006
|
+
* const shields = build.shieldMetrics();
|
|
1007
|
+
* shields?.strength; // -> MJ
|
|
1008
|
+
* shields?.resistances.thermal; // -> negative on a stock generator
|
|
1009
|
+
* build.shieldMetrics({ systemsPips: 4 })?.resistances.thermal; // -> with 4 pips to SYS
|
|
1010
|
+
* ```
|
|
1011
|
+
*/
|
|
1012
|
+
shieldMetrics(options?: DefenceOptions): ShieldMetrics | null;
|
|
1013
|
+
/**
|
|
1014
|
+
* The build's armour: hull hit points, the bulkhead and reinforcement each
|
|
1015
|
+
* contribute, and the effective resistances.
|
|
1016
|
+
*
|
|
1017
|
+
* @returns The {@link ArmourMetrics}. A build with no armour module fitted is
|
|
1018
|
+
* reported on the stock lightweight alloy the hull leaves the shipyard with, which
|
|
1019
|
+
* is what the game does.
|
|
1020
|
+
* @example
|
|
1021
|
+
* ```ts
|
|
1022
|
+
* import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
|
|
1023
|
+
*
|
|
1024
|
+
* declare const build: ShipLoadout;
|
|
1025
|
+
*
|
|
1026
|
+
* const hull = build.armourMetrics();
|
|
1027
|
+
* hull.hitPoints; // -> total hull points
|
|
1028
|
+
* hull.resistances.explosive; // -> lightweight alloy is explosively weak
|
|
1029
|
+
* hull.effectiveHitPoints.thermal; // -> thermal damage the hull can soak
|
|
1030
|
+
* ```
|
|
1031
|
+
*/
|
|
1032
|
+
armourMetrics(): ArmourMetrics;
|
|
1033
|
+
/**
|
|
1034
|
+
* The build's firepower: DPS, sustained DPS, weapons-capacitor draw, heat and power
|
|
1035
|
+
* draw for every fitted weapon, plus the totals.
|
|
1036
|
+
*
|
|
1037
|
+
* Every figure is post-engineering. A weapon switched off in the journal is still
|
|
1038
|
+
* listed — with its own metrics — but left out of the totals.
|
|
1039
|
+
*
|
|
1040
|
+
* @returns The {@link BuildWeaponMetrics}.
|
|
1041
|
+
* @example
|
|
1042
|
+
* ```ts
|
|
1043
|
+
* import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
|
|
1044
|
+
*
|
|
1045
|
+
* declare const build: ShipLoadout;
|
|
1046
|
+
*
|
|
1047
|
+
* const guns = build.weaponMetrics();
|
|
1048
|
+
* guns.total.damagePerSecond; // -> burst DPS across the hardpoints
|
|
1049
|
+
* guns.total.sustainedDamagePerSecond; // -> with reloads folded in
|
|
1050
|
+
* guns.total.energyPerSecond; // -> MW asked of the WEP capacitor
|
|
1051
|
+
* guns.total.powerDraw; // -> MW asked of the power plant when deployed
|
|
1052
|
+
* guns.weapons[0]?.metrics.damageByType.thermal;
|
|
1053
|
+
* guns.weapons[0]?.ammunition?.total; // -> rounds aboard when fully rearmed
|
|
1054
|
+
* ```
|
|
1055
|
+
*/
|
|
1056
|
+
weaponMetrics(): BuildWeaponMetrics;
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
export { type ApplyBlueprintOptions as A, type BuildWeaponMetrics as B, type DefenceOptions as D, type FittedModule as F, type JumpOptions as J, type LoadoutExportOptions as L, ShipLoadout as S, type AvailableBlueprint as a, type FittedWeaponMetrics as b, type JumpRangeSummary as c, type LoadoutSlot as d, type SlefExportOptions as e };
|