@elite-dangerous-almanac/core 0.2.6 → 0.2.8
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/equipment/SOURCES.md +149 -27
- package/PROVENANCE/i18n/SOURCES.md +251 -40
- package/PROVENANCE/ships/SOURCES.md +232 -63
- package/README.md +21 -6
- package/THIRD_PARTY_NOTICES.md +4 -1
- package/dist/{chunk-AAU7OM47.js → chunk-2OBUSQA7.js} +1 -1
- package/dist/{chunk-AAU7OM47.js.map → chunk-2OBUSQA7.js.map} +1 -1
- package/dist/chunk-3GNYPM6J.js +1 -0
- package/dist/chunk-3GNYPM6J.js.map +1 -0
- package/dist/{chunk-A6OINYNP.js → chunk-3WGXGBW5.js} +1 -1
- package/dist/{chunk-ABSDZINM.js → chunk-5YEHJM6V.js} +1 -1
- package/dist/{chunk-ABSDZINM.js.map → chunk-5YEHJM6V.js.map} +1 -1
- package/dist/{chunk-7S7ZTZZY.js → chunk-7EWZGDWY.js} +1 -1
- package/dist/chunk-A7IVMYNF.js +1 -0
- package/dist/chunk-A7IVMYNF.js.map +1 -0
- package/dist/{chunk-KPJ77VPS.js → chunk-BJU27V6C.js} +1 -1
- package/dist/{chunk-KPJ77VPS.js.map → chunk-BJU27V6C.js.map} +1 -1
- package/dist/chunk-C3LLPLLD.js +1 -0
- package/dist/chunk-C3LLPLLD.js.map +1 -0
- package/dist/chunk-DAQ3PJ4R.js +1 -0
- package/dist/chunk-DAQ3PJ4R.js.map +1 -0
- package/dist/chunk-DHACRCLI.js +1 -0
- package/dist/chunk-DHACRCLI.js.map +1 -0
- package/dist/chunk-EHFHRQEP.js +1 -0
- package/dist/{chunk-LOWDDWDT.js.map → chunk-EHFHRQEP.js.map} +1 -1
- package/dist/{chunk-YCGISPDR.js → chunk-ETWMPMZP.js} +1 -1
- package/dist/chunk-FJIWJYKO.js +1 -0
- package/dist/chunk-FJIWJYKO.js.map +1 -0
- package/dist/chunk-GIGRBFIJ.js +1 -0
- package/dist/{chunk-MGRDB2BZ.js.map → chunk-GIGRBFIJ.js.map} +1 -1
- package/dist/{chunk-4CBMQULR.js → chunk-IMNOEFUE.js} +1 -1
- package/dist/{chunk-4CBMQULR.js.map → chunk-IMNOEFUE.js.map} +1 -1
- package/dist/chunk-IN36YSS4.js +1 -0
- package/dist/chunk-IN36YSS4.js.map +1 -0
- package/dist/chunk-IUSMAX5T.js +1 -0
- package/dist/{chunk-6GJHUWMO.js.map → chunk-IUSMAX5T.js.map} +1 -1
- package/dist/{chunk-XQJERZUS.js → chunk-JCYOE3C4.js} +1 -1
- package/dist/{chunk-XQJERZUS.js.map → chunk-JCYOE3C4.js.map} +1 -1
- package/dist/chunk-LWNBWRKL.js +1 -0
- package/dist/{chunk-B7EYTZRK.js.map → chunk-LWNBWRKL.js.map} +1 -1
- package/dist/chunk-M6J7KP7G.js +1 -0
- package/dist/chunk-M6J7KP7G.js.map +1 -0
- package/dist/chunk-MT5AHPNP.js +1 -0
- package/dist/{chunk-3CKWT2F3.js.map → chunk-MT5AHPNP.js.map} +1 -1
- package/dist/chunk-OLKOWR7S.js +1 -0
- package/dist/chunk-OLKOWR7S.js.map +1 -0
- package/dist/chunk-QJECDMQQ.js +1 -0
- package/dist/{chunk-LZYHBFJC.js.map → chunk-QJECDMQQ.js.map} +1 -1
- package/dist/chunk-SC4MEHVY.js +1 -0
- package/dist/chunk-SC4MEHVY.js.map +1 -0
- package/dist/chunk-T7IQHFQ2.js +1 -0
- package/dist/chunk-T7IQHFQ2.js.map +1 -0
- package/dist/chunk-W5ULI75F.js +1 -0
- package/dist/chunk-W5ULI75F.js.map +1 -0
- package/dist/chunk-WV7QCDL5.js +1 -0
- package/dist/chunk-WV7QCDL5.js.map +1 -0
- package/dist/{chunk-SDXUPP4P.js → chunk-XSLPWM5N.js} +1 -1
- package/dist/{chunk-S3MONE55.js → chunk-YJAH6DFY.js} +1 -1
- package/dist/chunk-YJAH6DFY.js.map +1 -0
- package/dist/chunk-ZZTDEDXJ.js +1 -0
- package/dist/{chunk-FA5JVXVG.js.map → chunk-ZZTDEDXJ.js.map} +1 -1
- package/dist/equipment/engineering.d.ts +53 -1
- package/dist/equipment/engineering.js +1 -1
- package/dist/equipment/index.d.ts +13 -2
- package/dist/equipment/index.js +1 -1
- package/dist/equipment/modification-journal.js +1 -1
- package/dist/equipment/modifications.d.ts +32 -9
- package/dist/equipment/modifications.js +1 -1
- package/dist/equipment/suits.d.ts +32 -2
- package/dist/equipment/suits.js +1 -1
- package/dist/equipment/upgrade-costs.js +1 -1
- package/dist/equipment/weapons.d.ts +16 -2
- package/dist/equipment/weapons.js +1 -1
- package/dist/i18n/index.d.ts +76 -0
- package/dist/i18n/index.js +1 -1
- package/dist/i18n/modules.d.ts +10 -7
- package/dist/i18n/modules.js +1 -1
- package/dist/i18n/personal-modifications.d.ts +68 -0
- package/dist/i18n/personal-modifications.js +1 -0
- package/dist/i18n/personal-modifications.js.map +1 -0
- package/dist/i18n/personal-weapons.d.ts +33 -0
- package/dist/i18n/personal-weapons.js +1 -0
- package/dist/i18n/personal-weapons.js.map +1 -0
- package/dist/i18n/pre-engineered.js +1 -1
- package/dist/i18n/suits.d.ts +59 -0
- package/dist/i18n/suits.js +1 -0
- package/dist/i18n/suits.js.map +1 -0
- package/dist/materials/index.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.js +1 -1
- package/dist/ships/blueprint-journal.js +1 -1
- package/dist/ships/build-metrics.js +1 -1
- package/dist/ships/engineering-options.d.ts +2 -2
- package/dist/ships/engineering-options.js +1 -1
- package/dist/ships/engineering.js +1 -1
- package/dist/ships/index.d.ts +5 -5
- package/dist/ships/index.js +1 -1
- package/dist/ships/loadout-calculations.d.ts +11 -2
- package/dist/ships/loadout-calculations.js +1 -1
- package/dist/ships/loadout-validation.d.ts +7 -2
- package/dist/ships/loadout-validation.js +1 -1
- package/dist/ships/modules-all.d.ts +2 -2
- package/dist/ships/modules-all.js +1 -1
- package/dist/ships/modules-core.d.ts +3 -3
- package/dist/ships/modules-core.js +1 -1
- package/dist/ships/modules-hardpoint.d.ts +1 -1
- package/dist/ships/modules-internal.d.ts +17 -6
- package/dist/ships/modules-internal.js +1 -1
- package/dist/ships/modules-utility.d.ts +1 -1
- package/dist/ships/modules.d.ts +14 -7
- package/dist/ships/modules.js +1 -1
- package/dist/ships/pre-engineered-stats.js +1 -1
- package/dist/ships/pre-engineered.js +1 -1
- package/dist/ships/shield-capacitor.js +1 -1
- package/dist/ships/ship-loadout.d.ts +71 -23
- package/dist/ships/ship-loadout.js +1 -1
- package/dist/ships/weapons.js +1 -1
- package/package.json +13 -1
- package/dist/chunk-3CKWT2F3.js +0 -1
- package/dist/chunk-3P455LF4.js +0 -1
- package/dist/chunk-3P455LF4.js.map +0 -1
- package/dist/chunk-5QSCLEEB.js +0 -1
- package/dist/chunk-5QSCLEEB.js.map +0 -1
- package/dist/chunk-6GJHUWMO.js +0 -1
- package/dist/chunk-B7EYTZRK.js +0 -1
- package/dist/chunk-C5HG4GJI.js +0 -1
- package/dist/chunk-C5HG4GJI.js.map +0 -1
- package/dist/chunk-DCB4COCL.js +0 -1
- package/dist/chunk-DCB4COCL.js.map +0 -1
- package/dist/chunk-E3AUKPSQ.js +0 -1
- package/dist/chunk-E3AUKPSQ.js.map +0 -1
- package/dist/chunk-FA5JVXVG.js +0 -1
- package/dist/chunk-GISL7YML.js +0 -1
- package/dist/chunk-GISL7YML.js.map +0 -1
- package/dist/chunk-KLC5XT6F.js +0 -1
- package/dist/chunk-KLC5XT6F.js.map +0 -1
- package/dist/chunk-LOWDDWDT.js +0 -1
- package/dist/chunk-LZYHBFJC.js +0 -1
- package/dist/chunk-MGRDB2BZ.js +0 -1
- package/dist/chunk-NBLLW7TH.js +0 -1
- package/dist/chunk-NBLLW7TH.js.map +0 -1
- package/dist/chunk-OJC6AUL7.js +0 -1
- package/dist/chunk-OJC6AUL7.js.map +0 -1
- package/dist/chunk-S3MONE55.js.map +0 -1
- /package/dist/{chunk-A6OINYNP.js.map → chunk-3WGXGBW5.js.map} +0 -0
- /package/dist/{chunk-7S7ZTZZY.js.map → chunk-7EWZGDWY.js.map} +0 -0
- /package/dist/{chunk-YCGISPDR.js.map → chunk-ETWMPMZP.js.map} +0 -0
- /package/dist/{chunk-SDXUPP4P.js.map → chunk-XSLPWM5N.js.map} +0 -0
|
@@ -9,7 +9,7 @@ import './slots.js';
|
|
|
9
9
|
*
|
|
10
10
|
* @remarks
|
|
11
11
|
* **This module pulls in every module catalogue** — it exists for consumers that
|
|
12
|
-
* really do want to search all
|
|
12
|
+
* really do want to search all 1194 modules (a "resolve any module id" lookup, say).
|
|
13
13
|
* If you only need one category, import that catalogue's module
|
|
14
14
|
* (`./modules-core`, `./modules-internal`, `./modules-hardpoint`,
|
|
15
15
|
* `./modules-utility`) and nothing else gets bundled.
|
|
@@ -35,7 +35,7 @@ import './slots.js';
|
|
|
35
35
|
* ```ts
|
|
36
36
|
* import { ALL_MODULES } from '@elite-dangerous-almanac/core/ships/modules-all';
|
|
37
37
|
*
|
|
38
|
-
* ALL_MODULES.length; // ->
|
|
38
|
+
* ALL_MODULES.length; // -> 1194
|
|
39
39
|
* ALL_MODULES.filter((m) => m.category === 'utility').length; // -> 35
|
|
40
40
|
* ```
|
|
41
41
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export{ALL_MODULES}from"../chunk-
|
|
1
|
+
export{ALL_MODULES}from"../chunk-MT5AHPNP.js"; //# sourceMappingURL=modules-all.js.map
|
|
@@ -20,20 +20,20 @@ import './slots.js';
|
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
|
-
* All
|
|
23
|
+
* All 516 core internal modules, in Frontier's registry order.
|
|
24
24
|
*
|
|
25
25
|
* @remarks
|
|
26
26
|
* Every record has `category: 'core'`, added from the file it was read from
|
|
27
27
|
* rather than repeated on every record. To keep the other three categories out of
|
|
28
28
|
* your bundle, search this array directly — `CORE_MODULES.find((m) =>
|
|
29
29
|
* m.symbol.toLowerCase() === wanted)`, lower-cased because a journal's symbols are —
|
|
30
|
-
* rather than with the lookups in `./modules`, which default to all
|
|
30
|
+
* rather than with the lookups in `./modules`, which default to all 1194 modules.
|
|
31
31
|
*
|
|
32
32
|
* @example
|
|
33
33
|
* ```ts
|
|
34
34
|
* import { CORE_MODULES } from '@elite-dangerous-almanac/core/ships/modules-core';
|
|
35
35
|
*
|
|
36
|
-
* CORE_MODULES.length; // ->
|
|
36
|
+
* CORE_MODULES.length; // -> 516
|
|
37
37
|
* ```
|
|
38
38
|
*/
|
|
39
39
|
declare const CORE_MODULES: readonly OutfittingModule[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export{CORE_MODULES}from"../chunk-
|
|
1
|
+
export{CORE_MODULES}from"../chunk-ZZTDEDXJ.js"; //# sourceMappingURL=modules-core.js.map
|
|
@@ -28,7 +28,7 @@ import './slots.js';
|
|
|
28
28
|
* rather than repeated on every record. To keep the other three categories out of
|
|
29
29
|
* your bundle, search this array directly — `HARDPOINT_MODULES.find((m) =>
|
|
30
30
|
* m.symbol.toLowerCase() === wanted)`, lower-cased because a journal's symbols are —
|
|
31
|
-
* rather than with the lookups in `./modules`, which default to all
|
|
31
|
+
* rather than with the lookups in `./modules`, which default to all 1194 modules.
|
|
32
32
|
*
|
|
33
33
|
* @example
|
|
34
34
|
* ```ts
|
|
@@ -7,7 +7,9 @@ import './slots.js';
|
|
|
7
7
|
* The **optional internal** modules — the `internal` outfitting category:
|
|
8
8
|
* everything that fills an optional internal slot (cargo racks, shield generators,
|
|
9
9
|
* fuel scoops, refineries, passenger cabins, limpet and planetary controllers,
|
|
10
|
-
* hull/module reinforcement, …)
|
|
10
|
+
* hull/module reinforcement, …), plus the articles the registry files here that an
|
|
11
|
+
* optional slot does not take: the hull's own Cargo Hatch and the Guardian hybrid
|
|
12
|
+
* power plants and distributors, which go in a core mount.
|
|
11
13
|
*
|
|
12
14
|
* The other categories live in `./modules-core`, `./modules-hardpoint` and
|
|
13
15
|
* `./modules-utility`, so importing this module never bundles them.
|
|
@@ -20,14 +22,23 @@ import './slots.js';
|
|
|
20
22
|
*/
|
|
21
23
|
|
|
22
24
|
/**
|
|
23
|
-
* All 484
|
|
25
|
+
* All 484 modules in the `internal` outfitting category, in registry order.
|
|
24
26
|
*
|
|
25
27
|
* @remarks
|
|
26
28
|
* Every record has `category: 'internal'`, added from the file it was read from
|
|
27
|
-
* rather than repeated on every record.
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
29
|
+
* rather than repeated on every record. **The category is the registry's filing, not a
|
|
30
|
+
* fitting rule**, so do not read a fit off it: `ModularCargoBayDoor` (family
|
|
31
|
+
* `cargoHatches`) is the hull's built-in Cargo Hatch and goes in the fixed `CargoHatch`
|
|
32
|
+
* mount alone; the fifteen Guardian hybrid power plants and distributors carry a core
|
|
33
|
+
* {@link ships!OutfittingModule.slot | slot} and fit only that core mount; and others
|
|
34
|
+
* here reserve a restricted mount or a named hull. Ask
|
|
35
|
+
* {@link ships!ShipLoadout.modulesForSlot | ShipLoadout.modulesForSlot} what a mount
|
|
36
|
+
* takes rather than filtering this array by size.
|
|
37
|
+
*
|
|
38
|
+
* To keep the other three categories out of your bundle, search this array directly —
|
|
39
|
+
* `INTERNAL_MODULES.find((m) => m.symbol.toLowerCase() === wanted)`, lower-cased because
|
|
40
|
+
* a journal's symbols are — rather than with the lookups in `./modules`, which default
|
|
41
|
+
* to all 1194 modules.
|
|
31
42
|
*
|
|
32
43
|
* @example
|
|
33
44
|
* ```ts
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export{INTERNAL_MODULES}from"../chunk-
|
|
1
|
+
export{INTERNAL_MODULES}from"../chunk-IMNOEFUE.js"; //# sourceMappingURL=modules-internal.js.map
|
|
@@ -27,7 +27,7 @@ import './slots.js';
|
|
|
27
27
|
* rather than repeated on every record. To keep the other three categories out of
|
|
28
28
|
* your bundle, search this array directly — `UTILITY_MODULES.find((m) =>
|
|
29
29
|
* m.symbol.toLowerCase() === wanted)`, lower-cased because a journal's symbols are —
|
|
30
|
-
* rather than with the lookups in `./modules`, which default to all
|
|
30
|
+
* rather than with the lookups in `./modules`, which default to all 1194 modules.
|
|
31
31
|
*
|
|
32
32
|
* @example
|
|
33
33
|
* ```ts
|
package/dist/ships/modules.d.ts
CHANGED
|
@@ -10,7 +10,7 @@ import { ModuleSlot, SlotRestriction } from './slots.js';
|
|
|
10
10
|
* together — and the functions that find one ({@link getModuleBySymbol},
|
|
11
11
|
* {@link getModulesByName}, {@link getBulkheadsForShip}).
|
|
12
12
|
*
|
|
13
|
-
* **Every lookup searches all
|
|
13
|
+
* **Every lookup searches all 1194 modules by default.** A journal `Item` string does
|
|
14
14
|
* not identify its outfitting category, so callers need no category for lookup:
|
|
15
15
|
*
|
|
16
16
|
* ```ts
|
|
@@ -23,11 +23,11 @@ import { ModuleSlot, SlotRestriction } from './slots.js';
|
|
|
23
23
|
*
|
|
24
24
|
* | Module | Export | Entries |
|
|
25
25
|
* | --- | --- | --- |
|
|
26
|
-
* | `./modules-core` | `CORE_MODULES` |
|
|
26
|
+
* | `./modules-core` | `CORE_MODULES` | 516 |
|
|
27
27
|
* | `./modules-internal` | `INTERNAL_MODULES` | 484 |
|
|
28
28
|
* | `./modules-hardpoint` | `HARDPOINT_MODULES` | 159 |
|
|
29
29
|
* | `./modules-utility` | `UTILITY_MODULES` | 35 |
|
|
30
|
-
* | `./modules-all` | `ALL_MODULES` |
|
|
30
|
+
* | `./modules-all` | `ALL_MODULES` | 1194 (the default) |
|
|
31
31
|
*
|
|
32
32
|
* Those four are for **listing** a category — an outfitting screen's hardpoint tab.
|
|
33
33
|
* They make poor narrowing arguments: no module symbol or display name is shared
|
|
@@ -73,7 +73,11 @@ import { ModuleSlot, SlotRestriction } from './slots.js';
|
|
|
73
73
|
* which are the same seven {@link CoreSlotType}s plus armour. A fuel tank is a `core`
|
|
74
74
|
* module that also fits an optional slot.
|
|
75
75
|
* - `internal` — optional internals (cargo racks, shield generators, fuel scoops,
|
|
76
|
-
* passenger cabins, limpet and planetary controllers, …).
|
|
76
|
+
* passenger cabins, limpet and planetary controllers, …). The registry also files two
|
|
77
|
+
* kinds of article here that no optional slot takes: the built-in Cargo Hatch, which
|
|
78
|
+
* fits the hull's own fixed `CargoHatch` mount, and the Guardian hybrid power plants
|
|
79
|
+
* and distributors, which carry a core {@link OutfittingModule.slot | slot} and fit
|
|
80
|
+
* only that core mount.
|
|
77
81
|
* - `hardpoint` — the weapons and tools mounted on a hardpoint.
|
|
78
82
|
* - `utility` — the small utility-mount fittings (chaff, heat sinks, point defence,
|
|
79
83
|
* shield boosters, scanners).
|
|
@@ -435,7 +439,8 @@ interface OutfittingModuleIdentity {
|
|
|
435
439
|
*
|
|
436
440
|
* @remarks
|
|
437
441
|
* Absent on the handful of records no registry prices: the starter `*_free`
|
|
438
|
-
* variants, the
|
|
442
|
+
* variants, the two Community Goal Corrosion Resistant Cargo Racks, and the 1B
|
|
443
|
+
* shield generator — records no outfitting
|
|
439
444
|
* registry carries a figure for — among them the two Corrosion Resistant Cargo
|
|
440
445
|
* Racks no station sells, which are not free. Treat `undefined` as "unknown", never
|
|
441
446
|
* as free — see [`data/ships/SOURCES.md`](https://github.com/DarkSession/Elite-Dangerous-Almanac/blob/main/data/ships/SOURCES.md).
|
|
@@ -525,7 +530,7 @@ interface OutfittingModuleStats {
|
|
|
525
530
|
*
|
|
526
531
|
* @remarks
|
|
527
532
|
* A sparse capability flag on the 36 Overcharge drives and absent everywhere else,
|
|
528
|
-
* including on the
|
|
533
|
+
* including on the 31 ordinary drives of the same sizes and ratings. Read it rather
|
|
529
534
|
* than matching `Int_Hyperdrive_Overcharge` on the symbol: the capability is the
|
|
530
535
|
* record's to state, and a pre-engineered or fitted article carries the flag
|
|
531
536
|
* through while its symbol is not always the one you looked up.
|
|
@@ -569,6 +574,8 @@ interface OutfittingModuleStats {
|
|
|
569
574
|
readonly fuelCapacity?: number;
|
|
570
575
|
/** Cargo rack: capacity, in tonnes. */
|
|
571
576
|
readonly cargoCapacity?: number;
|
|
577
|
+
/** Passenger cabin: capacity, in passenger berths. */
|
|
578
|
+
readonly cabinCapacity?: number;
|
|
572
579
|
/** Shield generator: regeneration rate, MJ per second. */
|
|
573
580
|
readonly shieldRegenRate?: number;
|
|
574
581
|
/** Shield generator: broken (down) regeneration rate, MJ per second. */
|
|
@@ -795,7 +802,7 @@ interface OutfittingModule extends OutfittingModuleIdentity, OutfittingModuleSta
|
|
|
795
802
|
* @param symbol - The internal identifier, e.g. `"Hpt_PulseLaser_Fixed_Small"`.
|
|
796
803
|
* Leading/trailing whitespace and case are ignored, so the journal's lower-cased
|
|
797
804
|
* form resolves too.
|
|
798
|
-
* @param modules - Optional subset to search instead of all
|
|
805
|
+
* @param modules - Optional subset to search instead of all 1194 modules —
|
|
799
806
|
* `CORE_MODULES`, `INTERNAL_MODULES`, `HARDPOINT_MODULES`, `UTILITY_MODULES`, or any
|
|
800
807
|
* array you have filtered yourself. Omit it unless you specifically want to exclude
|
|
801
808
|
* the other categories; a symbol is unique across all four.
|
package/dist/ships/modules.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export{getBulkheadsForShip,getModuleBySymbol,getModulesByName}from"../chunk-
|
|
1
|
+
export{getBulkheadsForShip,getModuleBySymbol,getModulesByName}from"../chunk-5YEHJM6V.js"; //# sourceMappingURL=modules.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export{getPreEngineeredJournalModifiers,getPreEngineeredModifiers,getPreEngineeredStats,identifyPreEngineeredVariant,unresolvedModifiers}from"../chunk-
|
|
1
|
+
export{getPreEngineeredJournalModifiers,getPreEngineeredModifiers,getPreEngineeredStats,identifyPreEngineeredVariant,unresolvedModifiers}from"../chunk-IN36YSS4.js"; //# sourceMappingURL=pre-engineered-stats.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export{PRE_ENGINEERED_MODULES,getPreEngineeredVariants,isPreEngineered}from"../chunk-
|
|
1
|
+
export{PRE_ENGINEERED_MODULES,getPreEngineeredVariants,isPreEngineered}from"../chunk-BJU27V6C.js"; //# sourceMappingURL=pre-engineered.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export{shieldCapacitorMetrics}from"../chunk-
|
|
1
|
+
export{shieldCapacitorMetrics}from"../chunk-JCYOE3C4.js"; //# sourceMappingURL=shield-capacitor.js.map
|
|
@@ -161,12 +161,13 @@ type LoadoutSlot = BuildSlot & {
|
|
|
161
161
|
*
|
|
162
162
|
* @remarks
|
|
163
163
|
* `ShipLoadout.fromLoadout` states the rules these outcomes report: a removable mount is
|
|
164
|
-
* `emptied` of an article the catalogue cannot resolve,
|
|
165
|
-
*
|
|
166
|
-
*
|
|
167
|
-
*
|
|
168
|
-
*
|
|
169
|
-
*
|
|
164
|
+
* `emptied` of an article the catalogue cannot resolve, while armour, a core internal,
|
|
165
|
+
* the cargo hatch and the planetary approach suite are `defaulted` to the hull's stock
|
|
166
|
+
* article whenever the source left none they can hold — with a `null` `sourceSymbol` when
|
|
167
|
+
* the source named nothing there at all. A module whose source stated a recipe and no
|
|
168
|
+
* `Modifiers` reports `unresolvedEngineering` when neither a craftable recipe nor a
|
|
169
|
+
* catalogued article answers to what it named, because that module alone keeps the
|
|
170
|
+
* figures of an unengineered one. Two further entries report a *reading* the
|
|
170
171
|
* import chose rather than a change it made: `ambiguousEngineering` where an identity-only
|
|
171
172
|
* block was rolled while a catalogued article answers to it just as well, and
|
|
172
173
|
* `rerolledEngineering` where a stated modifier block moved nothing the module has and the
|
|
@@ -193,7 +194,7 @@ type LoadoutImportOutcome = {
|
|
|
193
194
|
/** Unresolved module identity supplied by the source. */
|
|
194
195
|
readonly sourceSymbol: string;
|
|
195
196
|
} | {
|
|
196
|
-
/** The hull's stock module was installed in a
|
|
197
|
+
/** The hull's stock module was installed in a mount import keeps filled. */
|
|
197
198
|
readonly action: 'defaulted';
|
|
198
199
|
/** Exact slot spelling used by the normalized build. */
|
|
199
200
|
readonly slot: string;
|
|
@@ -327,7 +328,7 @@ type LoadoutEditErrorCode = 'immutableSlot' | 'requiredSlot' | 'incompatibleModu
|
|
|
327
328
|
* import { CORE_MODULES } from '@elite-dangerous-almanac/core/ships/modules-core';
|
|
328
329
|
*
|
|
329
330
|
* const build = ShipLoadout.empty('SideWinder');
|
|
330
|
-
* const drive = getModuleBySymbol('
|
|
331
|
+
* const drive = getModuleBySymbol('Int_Hyperdrive_Overcharge_Size8_Class5', CORE_MODULES)!;
|
|
331
332
|
* try {
|
|
332
333
|
* build.setModule('FrameShiftDrive', drive);
|
|
333
334
|
* } catch (error) {
|
|
@@ -526,7 +527,8 @@ interface SlefExportOptions extends LoadoutExportOptions {
|
|
|
526
527
|
* - **Construct** — {@link fromSlef}, {@link fromLoadout}, {@link empty},
|
|
527
528
|
* {@link default}. The constructor is private; every build starts at one of these four.
|
|
528
529
|
* - **Inspect** — {@link shipSymbol}, {@link shipName}, {@link shipIdent},
|
|
529
|
-
* {@link unladenMass}, {@link cargoCapacity}, {@link
|
|
530
|
+
* {@link unladenMass}, {@link cargoCapacity}, {@link passengerCapacity},
|
|
531
|
+
* {@link fuelCapacity}, {@link hullValue},
|
|
530
532
|
* {@link modulesValue}, {@link rebuy}, {@link sourcePurchase}, {@link importOutcomes},
|
|
531
533
|
* {@link slots}, {@link fittedModuleAt}, {@link fittedModules},
|
|
532
534
|
* {@link modulesForSlot}, {@link availableBlueprints},
|
|
@@ -649,19 +651,29 @@ declare class ShipLoadout {
|
|
|
649
651
|
* hull-geometry key (`PaintJob`, `ShipCockpit`, a numbered decal, …), or when it is
|
|
650
652
|
* the built-in cargo hatch. Everything else is normalized, and every change is
|
|
651
653
|
* recorded by {@link importOutcomes}: an unresolved module in a removable mount is
|
|
652
|
-
* discarded, while armour, the seven core internals
|
|
653
|
-
* from the hull defaults whenever the event left
|
|
654
|
-
* unresolved symbol, a resolved one the mount
|
|
655
|
-
* corrected alike, each keeping the source's `On`,
|
|
656
|
-
* removable mount may stand empty, so an article
|
|
657
|
-
* put it and is reported by
|
|
654
|
+
* discarded, while armour, the seven core internals, the cargo hatch and the
|
|
655
|
+
* planetary approach suite are filled from the hull defaults whenever the event left
|
|
656
|
+
* no article that mount can hold — an unresolved symbol, a resolved one the mount
|
|
657
|
+
* refuses, and no entry at all are corrected alike, each keeping the source's `On`,
|
|
658
|
+
* `Priority` and `Health`. Every other removable mount may stand empty, so an article
|
|
659
|
+
* *it* refuses stays where the event put it and is reported by
|
|
660
|
+
* {@link validation | validation()} instead.
|
|
661
|
+
*
|
|
662
|
+
* **The approach suite is stocked because silence about it is not a decision.** Every
|
|
663
|
+
* hull is supplied with the advanced suite, which is weightless and draws no power, so
|
|
664
|
+
* no build gains by shedding one — while an exporter that carries no such mount, as
|
|
665
|
+
* Inara does not, writes no entry for it either. The suite therefore joins the mounts
|
|
666
|
+
* an absent entry fills rather than empties. It stays removable afterwards, so a build
|
|
667
|
+
* that really does fly without one is one {@link removeModule} away.
|
|
658
668
|
*
|
|
659
669
|
* Normalization makes the captured aggregates untrustworthy, so they are dropped:
|
|
660
670
|
* {@link unladenMass}, {@link cargoCapacity} and {@link fuelCapacity} are recomputed
|
|
661
671
|
* from the fit that remains, {@link modulesValue} and {@link rebuy} read `null`, and
|
|
662
672
|
* {@link sourcePurchase} still reports what the capture stated. A mount stocked from
|
|
663
|
-
* *absence* is the exception
|
|
664
|
-
*
|
|
673
|
+
* *absence* is the exception and every figure stands: the bulkhead and the cargo hatch
|
|
674
|
+
* are free and weightless, and the approach suite is weightless and costs 500 Cr —
|
|
675
|
+
* too little to drop a commander's whole purchase record over, so the credit figures
|
|
676
|
+
* may understate the fit by that much and no more.
|
|
665
677
|
*
|
|
666
678
|
* Use this factory rather than replaying a complete loadout through the incremental
|
|
667
679
|
* {@link setModule} editor.
|
|
@@ -749,6 +761,35 @@ declare class ShipLoadout {
|
|
|
749
761
|
* {@link unladenMass}, otherwise the sum of the fitted racks.
|
|
750
762
|
*/
|
|
751
763
|
get cargoCapacity(): number;
|
|
764
|
+
/**
|
|
765
|
+
* Passenger capacity, in berths — the sum of the fitted cabins' `cabinCapacity`, and
|
|
766
|
+
* `0` for a build carrying no cabin.
|
|
767
|
+
*
|
|
768
|
+
* @remarks
|
|
769
|
+
* Always computed from the fit, unlike {@link cargoCapacity} and
|
|
770
|
+
* {@link fuelCapacity}: a journal `Loadout` states no passenger figure to prefer, so
|
|
771
|
+
* an imported build reports the cabins it lists. Berths are seats, not occupants, and
|
|
772
|
+
* a passenger is massless, so filling them changes nothing
|
|
773
|
+
* {@link ships!BuildMetrics | BuildMetrics} calculates.
|
|
774
|
+
*
|
|
775
|
+
* A cabin serves one class of passenger, and no stat field states which: every cabin
|
|
776
|
+
* is in the `passengerCabins` family, and `rating` disagrees between the two lines,
|
|
777
|
+
* the Mk II cabins running one rating better than the Mk I cabins of the same class.
|
|
778
|
+
* A screen that splits berths into economy, business, first and luxury reads the
|
|
779
|
+
* `_Class1`–`_Class4` suffix of each fitted cabin's `symbol`, which is that order on
|
|
780
|
+
* both lines — the Mk II line stopping at business — and does not change with the
|
|
781
|
+
* display locale.
|
|
782
|
+
*
|
|
783
|
+
* @example
|
|
784
|
+
* ```ts
|
|
785
|
+
* import { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
|
|
786
|
+
*
|
|
787
|
+
* // The stock Beluga Liner leaves the yard with two size-6 and two size-4 business
|
|
788
|
+
* // class cabins.
|
|
789
|
+
* ShipLoadout.default('BelugaLiner').passengerCapacity; // -> 44
|
|
790
|
+
* ```
|
|
791
|
+
*/
|
|
792
|
+
get passengerCapacity(): number;
|
|
752
793
|
/**
|
|
753
794
|
* Hull cost in credits represented by the build, or `null` if unknown.
|
|
754
795
|
*
|
|
@@ -809,8 +850,8 @@ declare class ShipLoadout {
|
|
|
809
850
|
get sourcePurchase(): SourcePurchaseRecord | null;
|
|
810
851
|
/**
|
|
811
852
|
* What the import made of this build: the changes it applied, in source order,
|
|
812
|
-
* followed by the
|
|
813
|
-
*
|
|
853
|
+
* followed by the mounts stocked from the hull defaults because the source named
|
|
854
|
+
* none, in the defaults' own order, followed by what it made of each module's
|
|
814
855
|
* stated engineering.
|
|
815
856
|
*
|
|
816
857
|
* @returns A deeply frozen list. It is empty for builds created with
|
|
@@ -819,8 +860,9 @@ declare class ShipLoadout {
|
|
|
819
860
|
* @remarks
|
|
820
861
|
* Each entry names the exact slot, and the source identity where the source gave one.
|
|
821
862
|
* `emptied` means an unknown module was removed from a removable mount; `defaulted`
|
|
822
|
-
* names the stock article fitted to armour, a core internal
|
|
823
|
-
* a `null` `sourceSymbol` when the source named
|
|
863
|
+
* names the stock article fitted to armour, a core internal, the cargo hatch or the
|
|
864
|
+
* planetary approach suite, with a `null` `sourceSymbol` when the source named
|
|
865
|
+
* nothing there at all.
|
|
824
866
|
* `rerolledEngineering` names a module whose stated `Modifiers` moved no stat it
|
|
825
867
|
* carries, so the recipe beside them was rolled in their place.
|
|
826
868
|
*
|
|
@@ -954,6 +996,12 @@ declare class ShipLoadout {
|
|
|
954
996
|
* the same article on the screen twice, once with no price. A build that already
|
|
955
997
|
* carries one keeps it; only the choices are filtered.
|
|
956
998
|
*
|
|
999
|
+
* The Cargo Hatch is absent for the same reason it cannot be removed: it is part of
|
|
1000
|
+
* the hull. The source registry files it under the `internal` category — which is
|
|
1001
|
+
* why {@link ships/modules-internal!INTERNAL_MODULES | INTERNAL_MODULES} carries it
|
|
1002
|
+
* — but the hull is built with one and the fixed `CargoHatch` mount is the only
|
|
1003
|
+
* place it goes, so no mount this method describes accepts it.
|
|
1004
|
+
*
|
|
957
1005
|
* @param slotKey - The slot key to fit, matched case-insensitively (journal spelling).
|
|
958
1006
|
* @returns The fitting modules, in complete-catalogue order.
|
|
959
1007
|
* @throws {RangeError} If the hull has no slot with that key.
|
|
@@ -1008,8 +1056,8 @@ declare class ShipLoadout {
|
|
|
1008
1056
|
* {@link getModuleBySymbol}). The complete record is snapshotted, so a result from
|
|
1009
1057
|
* `getPreEngineeredStats` or a record you adjusted yourself keeps its stats — but it
|
|
1010
1058
|
* must name an article the built-in catalogue carries, and it may not drop that
|
|
1011
|
-
* article's `mass`, `cargoCapacity` or `fuelCapacity`, which every
|
|
1012
|
-
* state one as anything but a finite number.
|
|
1059
|
+
* article's `mass`, `cargoCapacity`, `cabinCapacity` or `fuelCapacity`, which every
|
|
1060
|
+
* build sums, nor state one as anything but a finite number.
|
|
1013
1061
|
* @returns `this`, for chaining.
|
|
1014
1062
|
* @throws {RangeError} If the hull has no slot with that key.
|
|
1015
1063
|
* @throws {TypeError} If `slotKey` is not a string, or `module` fails any of the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export{LoadoutEditError,ShipLoadout}from"../chunk-
|
|
1
|
+
export{LoadoutEditError,ShipLoadout}from"../chunk-SC4MEHVY.js"; //# sourceMappingURL=ship-loadout.js.map
|
package/dist/ships/weapons.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export{armourPiercingFactor,combinedRateOfFire,damageFalloff,damagePerSecond,energyPerSecond,heatPerSecond,splitDamage,sumWeaponMetrics,sustainedDamagePerSecond,sustainedFireFactor,weaponMetrics}from"../chunk-
|
|
1
|
+
export{armourPiercingFactor,combinedRateOfFire,damageFalloff,damagePerSecond,energyPerSecond,heatPerSecond,splitDamage,sumWeaponMetrics,sustainedDamagePerSecond,sustainedFireFactor,weaponMetrics}from"../chunk-2OBUSQA7.js"; //# sourceMappingURL=weapons.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elite-dangerous-almanac/core",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.8",
|
|
4
4
|
"description": "Elite Dangerous static data and calculations: astronomy, ships and outfitting, personal equipment and engineering, materials, and market commodities.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -236,6 +236,14 @@
|
|
|
236
236
|
"types": "./dist/i18n/module-families.d.ts",
|
|
237
237
|
"import": "./dist/i18n/module-families.js"
|
|
238
238
|
},
|
|
239
|
+
"./i18n/personal-modifications": {
|
|
240
|
+
"types": "./dist/i18n/personal-modifications.d.ts",
|
|
241
|
+
"import": "./dist/i18n/personal-modifications.js"
|
|
242
|
+
},
|
|
243
|
+
"./i18n/personal-weapons": {
|
|
244
|
+
"types": "./dist/i18n/personal-weapons.d.ts",
|
|
245
|
+
"import": "./dist/i18n/personal-weapons.js"
|
|
246
|
+
},
|
|
239
247
|
"./i18n/pre-engineered": {
|
|
240
248
|
"types": "./dist/i18n/pre-engineered.d.ts",
|
|
241
249
|
"import": "./dist/i18n/pre-engineered.js"
|
|
@@ -244,6 +252,10 @@
|
|
|
244
252
|
"types": "./dist/i18n/slots.d.ts",
|
|
245
253
|
"import": "./dist/i18n/slots.js"
|
|
246
254
|
},
|
|
255
|
+
"./i18n/suits": {
|
|
256
|
+
"types": "./dist/i18n/suits.d.ts",
|
|
257
|
+
"import": "./dist/i18n/suits.js"
|
|
258
|
+
},
|
|
247
259
|
"./materials": {
|
|
248
260
|
"types": "./dist/materials/index.d.ts",
|
|
249
261
|
"import": "./dist/materials/index.js"
|
package/dist/chunk-3CKWT2F3.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{CORE_MODULES}from"./chunk-FA5JVXVG.js";import{HARDPOINT_MODULES}from"./chunk-773VO2GK.js";import{INTERNAL_MODULES}from"./chunk-4CBMQULR.js";import{UTILITY_MODULES}from"./chunk-ELT3FEA4.js";var ALL_MODULES=Object.freeze([...CORE_MODULES,...INTERNAL_MODULES,...HARDPOINT_MODULES,...UTILITY_MODULES]);export{ALL_MODULES};//# sourceMappingURL=chunk-3CKWT2F3.js.map
|
package/dist/chunk-3P455LF4.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{fixedSlotReason,validateLoadout}from"./chunk-OJC6AUL7.js";import{calculateModuleLimits}from"./chunk-KPETDYQX.js";import{publishLoadoutInternals,normalizeLoadoutEvent,preEngineeredVariantFor,moduleFitProblem,effectiveModule,moduleFitError}from"./chunk-GISL7YML.js";import{getShipBySymbol}from"./chunk-6UNAD74Z.js";import{parseSlef,toSlef,stringifySlef,getLoadoutModifier}from"./chunk-T4MKUKYS.js";import{getSourceModuleValue}from"./chunk-NIURLW2F.js";import{statesInertModifiers,rolledOverFixedArticle,isNonOutfittingSlot,isBuiltInHullModule,cloneLoadoutModule,cloneModuleStats,availableBlueprintsFor,availableExperimentalsFor,ownKeyIn,FITTED_ITEM,blueprintAvailableFor,blueprintRoutesFor,experimentalAvailableFor,primitiveEngineeringInputsFor,missingBaseLabels,journalModifiersFor,getPreEngineeredStats,getPreEngineeredJournalModifiers,getPreEngineeredModifiers,ordinaryEngineeringProof,unresolvedModifiers,matchingKeyIn,isCargoHatchSlot,orderBySlotLayout}from"./chunk-NBLLW7TH.js";import{builtInModuleBySymbol}from"./chunk-ABSDZINM.js";import{getPreEngineeredVariants}from"./chunk-KPJ77VPS.js";import{ALL_MODULES}from"./chunk-3CKWT2F3.js";import{singleJumpRange}from"./chunk-VTMCSCXV.js";import{calculateUnladenMass,calculateCargoCapacity,calculateFuelCapacity}from"./chunk-DCB4COCL.js";import{getBlueprintGrade}from"./chunk-AYAKU4YA.js";import{getDefaultLoadout}from"./chunk-GRIK3EDH.js";import{getExperimentalEffect}from"./chunk-77I24V6B.js";import{ammunitionCapacity}from"./chunk-AA3K5XUE.js";import{baseStats,computeModifiers,labelsForDamageType,scaleForLabel}from"./chunk-5QSCLEEB.js";import{resolveBlueprintForModule}from"./chunk-SDXUPP4P.js";import{getExperimentalsForModule}from"./chunk-LOWDDWDT.js";import{loadoutSlotName}from"./chunk-KAA4VOOB.js";import{parseSlotName,enumerateSlots}from"./chunk-RAO35XDF.js";import{normalizeKey,CATALOGUE_KEY}from"./chunk-BKWLI44T.js";import{truncate,describeValue,requireString,requireStringIfPresent}from"./chunk-PKWVG2JY.js";import{deepFreeze}from"./chunk-DURKO7JU.js";var REBUY_FRACTION=.05;function exportLoadoutEvent(input,options){const fromSource=options.credits==="source";const source=fromSource?input.sourcePurchase:null;const totals=source!==null&&!input.sourceTotalsVoided&&sourceTotalsHold(input.modules,source)?source:null;const hullValue=fromSource?source?.hullValue??null:input.retailHullValue;const modulesValue=fromSource?totals?.modulesValue??null:computedModulesValue(input.modules,input.statsFor);const rebuy=fromSource?totals?.rebuy??null:hullValue===null||modulesValue===null?null:Math.trunc((hullValue+modulesValue)*REBUY_FRACTION);return{Ship:input.shipSymbol.toLowerCase(),...input.shipName===void 0?{}:{ShipName:input.shipName},...input.shipIdent===void 0?{}:{ShipIdent:input.shipIdent},...hullValue===null?{}:{HullValue:hullValue},...modulesValue===null?{}:{ModulesValue:modulesValue},UnladenMass:input.unladenMass,CargoCapacity:input.cargoCapacity,...input.maxJumpRange===null?{}:{MaxJumpRange:input.maxJumpRange},FuelCapacity:{Main:input.fuelCapacity.main,Reserve:input.fuelCapacity.reserve},...rebuy===null?{}:{Rebuy:rebuy},Modules:exportModules(input,options,fromSource)}}function exportModules(input,options,fromSource){const ordered=options.moduleOrder==="slots"?slotOrderedModules(input.modules,input.layout):[...input.modules.values()];return ordered.map(module=>{const on=module.On??(options.explicitPower?true:void 0);const priority=module.Priority??(options.explicitPower?0:void 0);const value=fromSource?sourceModuleValue(module,input.sourcePurchase):moduleValue(module,input.statsFor);return{Slot:module.Slot,Item:module.Item.toLowerCase(),...on===void 0?{}:{On:on},...priority===void 0?{}:{Priority:priority},...module.Health===void 0?{}:{Health:module.Health},...typeof value==="number"?{Value:value}:{},...module.Engineering===void 0?{}:{Engineering:cloneLoadoutModule(module).Engineering}}})}function slotOrderedModules(modules,layout){return orderBySlotLayout([...modules.values()],layout,module=>module.Slot)}function computedModulesValue(modules,statsFor){let sum=0;for(const module of modules.values()){const value=moduleValue(module,statsFor);if(value==="unknown")return null;if(value!=="free")sum+=value}return sum}function moduleValue(module,statsFor){const stats=statsFor(module);if(stats!==null)return stats.cost??"unknown";return isNonOutfittingSlot(module.Slot)||isBuiltInHullModule(module)?"free":"unknown"}var SOURCE_ITEM="ShipLoadout: sourcePurchase moduleValues[].item";function sourceModuleValue(module,source){const entry=source===null?null:getSourceModuleValue(source,module.Slot);if(entry===null)return"unknown";return normalizeKey(entry.item,SOURCE_ITEM)===normalizeKey(module.Item,FITTED_ITEM)?entry.value:"unknown"}function sourceTotalsHold(modules,source){for(const entry of source.moduleValues){const key=matchingKeyIn(modules,entry.slot);const fitted=key===null?void 0:modules.get(key);if(!fitted)return false;if(isCargoHatchSlot(entry.slot)&&entry.value===0)continue;if(normalizeKey(fitted.Item,FITTED_ITEM)!==normalizeKey(entry.item,SOURCE_ITEM)){return false}}return true}var SLOT_KEY="ShipLoadout: slotKey";var FITTED_SLOT="ShipLoadout: fitted module Slot";var LoadoutEditError=class extends TypeError{code;constraint;params;constructor(message,code,params,constraint){super(message);this.code=code;this.params=deepFreeze(structuredClone(params));if(constraint!==void 0)this.constraint=constraint}};var experimentalEffectUnsupported=(code,params)=>deepFreeze({kind:"unsupported",code:code,params:params});var engineeringNormalizationUnsupported=(code,params)=>deepFreeze({kind:"unsupported",code:code,params:params});function weighable(tonnes){return tonnes!==void 0&&Number.isFinite(tonnes)&&tonnes>=0?tonnes:void 0}var AGGREGATE_STATS=["mass","cargoCapacity","fuelCapacity"];var ShipLoadout=class _ShipLoadout{#ship;#shipSymbol;#modules;#moduleStats;#primitiveModifiers;#top;#sourcePurchase;#importOutcomes;#slotCache=/* @__PURE__ */new Map;#layoutCache;constructor(ship,shipSymbol,modules,top,sourcePurchase=null,moduleStats=/* @__PURE__ */new Map,primitiveModifiers=/* @__PURE__ */new Map,importOutcomes=deepFreeze([])){this.#ship=ship;this.#shipSymbol=shipSymbol;this.#modules=modules;this.#top=top;this.#sourcePurchase=sourcePurchase;this.#moduleStats=moduleStats;this.#primitiveModifiers=primitiveModifiers;this.#importOutcomes=importOutcomes;publishLoadoutInternals(this,{ship:ship,modules:()=>[...this.#modules.values()],effectiveModules:()=>this.#modulesForEffectiveStats(),effectiveModule:module=>this.#moduleForEffectiveStats(module),statsFor:module=>this.#statsFor(module),layout:()=>this.#layout(),resolveDrive:()=>this.#resolveDrive(),frameShiftDriveModule:()=>this.#frameShiftDrive()?.module,calculationModules:()=>this.#calculationModules(),statedMainFuel:()=>this.#top.FuelCapacity?.Main})}static fromSlef(input,index=0){const entries=parseSlef(input);const entry=entries[index];if(!entry){throw new TypeError(`ShipLoadout.fromSlef: no entry at index ${truncate(index)} (have ${entries.length})`)}const imported=normalizeLoadoutEvent(entry.data);const ship=getShipBySymbol(imported.shipSymbol);if(!ship){throw new TypeError(`ShipLoadout.fromSlef: unknown hull "${truncate(imported.shipSymbol)}"`)}return _ShipLoadout.#fromImported(imported,ship)}static fromLoadout(event){if(event===null||typeof event!=="object"){throw new TypeError(`ShipLoadout.fromLoadout: event must be a Loadout event, received ${describeValue(event)}`)}const imported=normalizeLoadoutEvent(event);const ship=getShipBySymbol(imported.shipSymbol);if(!ship){throw new TypeError(`ShipLoadout.fromLoadout: unknown hull "${truncate(imported.shipSymbol)}"`)}return _ShipLoadout.#fromImported(imported,ship)}static#fromImported(imported,ship){const outcomes=[...imported.outcomes];const loadout=new _ShipLoadout(ship,imported.shipSymbol,imported.modules,imported.top,imported.sourcePurchase,imported.moduleStats,imported.primitiveModifiers,outcomes);const{UnladenMass:UnladenMass,CargoCapacity:CargoCapacity,FuelCapacity:FuelCapacity}=imported.top;for(const module of[...imported.modules.values()]){const unresolved=loadout.#rollStatedRecipe(module);if(unresolved!==null)outcomes.push(unresolved)}if(UnladenMass!==void 0)loadout.#top.UnladenMass=UnladenMass;if(CargoCapacity!==void 0)loadout.#top.CargoCapacity=CargoCapacity;if(FuelCapacity!==void 0)loadout.#top.FuelCapacity=FuelCapacity;deepFreeze(outcomes);return loadout}#rollStatedRecipe(module){const engineering=module.Engineering;if(!engineering||typeof engineering.BlueprintName!=="string")return null;const stated=engineering.Modifiers;const stats=this.#statsFor(module);if(stated!==void 0&&(this.#moduleStats.has(module.Slot)||stats===null||!statesInertModifiers(stats,stated))){return null}if(stated===void 0&&this.#moduleStats.has(module.Slot)){const variant=preEngineeredVariantFor(module);if(variant?.acquisition!=="mercenary"||engineering.Level<=variant.grade){return null}}try{this.applyBlueprint(module.Slot,engineering.BlueprintName,{grade:engineering.Level,quality:engineering.Quality??1,...typeof engineering.ExperimentalEffect==="string"?{experimentalEffectSymbol:engineering.ExperimentalEffect}:{}});if(stated!==void 0){return{action:"rerolledEngineering",slot:module.Slot,sourceSymbol:module.Item,blueprintSymbol:engineering.BlueprintName}}const passedOver=rolledOverFixedArticle(module.Item,engineering);return passedOver===null?null:{action:"ambiguousEngineering",slot:module.Slot,sourceSymbol:module.Item,blueprintSymbol:engineering.BlueprintName,preEngineeredVariant:passedOver}}catch(error){if(!(error instanceof TypeError)&&!(error instanceof RangeError))throw error;return{action:"unresolvedEngineering",slot:module.Slot,sourceSymbol:module.Item,blueprintSymbol:engineering.BlueprintName}}}static empty(shipSymbol){const requested=requireString(shipSymbol,"ShipLoadout.empty: shipSymbol");const ship=getShipBySymbol(requested);if(!ship){throw new TypeError(`ShipLoadout.empty: no slot layout for hull "${truncate(shipSymbol)}"`)}const fitted=(getDefaultLoadout(ship.symbol)?.modules??[]).filter(module=>{const parsed=parseSlotName(module.slot);return parsed!==null&&fixedSlotReason(parsed)!==null});return new _ShipLoadout(ship,ship.symbol,new Map(fitted.map(module=>[module.slot,{Slot:module.slot,Item:module.symbol}])),{})}static default(shipSymbol){const requested=requireString(shipSymbol,"ShipLoadout.default: shipSymbol");const ship=getShipBySymbol(requested);if(!ship){throw new TypeError(`ShipLoadout.default: no default loadout for hull "${truncate(shipSymbol)}"`)}const loadout=getDefaultLoadout(ship.symbol);return new _ShipLoadout(ship,loadout.symbol,new Map(loadout.modules.map(module=>[module.slot,{Slot:module.slot,Item:module.symbol}])),{})}get shipSymbol(){return this.#shipSymbol}get shipName(){return this.#top.ShipName??null}get shipIdent(){return this.#top.ShipIdent??null}get unladenMass(){return this.#top.UnladenMass??this.#computedUnladenMass()}#computedUnladenMass(){return calculateUnladenMass(this.#ship.hullMass,this.#calculationModules())}get fuelCapacity(){const cap=this.#top.FuelCapacity;if(cap?.Main!==void 0&&cap.Reserve!==void 0){return Object.freeze({main:cap.Main,reserve:cap.Reserve})}const computed=this.#computedFuelCapacity();return Object.freeze({main:cap?.Main??computed.main,reserve:cap?.Reserve??computed.reserve})}get cargoCapacity(){return this.#top.CargoCapacity??this.#computedCargoCapacity()}#computedCargoCapacity(){return calculateCargoCapacity(this.#calculationModules())}#computedFuelCapacity(){return calculateFuelCapacity(this.#ship.reserveFuelCapacity,this.#calculationModules())}get hullValue(){return this.#top.HullValue??null}get modulesValue(){return this.#top.ModulesValue??null}get rebuy(){return this.#top.Rebuy??null}get sourcePurchase(){return this.#sourcePurchase}get importOutcomes(){return this.#importOutcomes}validation(){const slots=this.#layout();const byKey=new Map(slots.map(slot=>[normalizeKey(slot.key,CATALOGUE_KEY),slot]));const modules=[...this.#modules.values()].map(module=>{const stats=this.#statsFor(module);const slot=byKey.get(normalizeKey(module.Slot,FITTED_SLOT));const builtIn=stats===null&&isNonOutfittingSlot(module.Slot)||isBuiltInHullModule(module);const fitProblem=stats&&slot&&!builtIn?moduleFitProblem(this.#shipSymbol,slot,stats):null;const thrusterMaxMass=weighable(stats?.slot==="thrusters"?effectiveModule(this.#moduleForEffectiveStats(module),stats)?.maxMass:void 0);return{slot:module.Slot,symbol:module.Item,requiresKnownSlot:!builtIn,fitError:fitProblem?.message??null,...fitProblem===null?{}:{fitConstraint:fitProblem.constraint},...fitProblem?.params===void 0?{}:{fitParams:fitProblem.params},...stats?.exclusionGroup===void 0?{}:{exclusionGroup:stats.exclusionGroup},...stats?.limitGroup===void 0?{}:{limitGroup:stats.limitGroup},...stats?.limitIncrease===void 0?{}:{limitIncrease:stats.limitIncrease},...thrusterMaxMass===void 0?{}:{thrusterMaxMass:thrusterMaxMass}}});const dry=weighable(this.unladenMass);const fuel=weighable(this.fuelCapacity.main);const cargo=weighable(this.cargoCapacity);const mass=dry===void 0?void 0:{dry:dry,...fuel===void 0?{}:{fuel:fuel},...fuel===void 0||cargo===void 0?{}:{cargo:cargo}};return validateLoadout({shipSymbol:this.#shipSymbol,slots:slots,modules:modules,...mass===void 0?{}:{mass:mass}})}slots(kind){const cached=this.#slotCache.get(kind);if(cached!==void 0)return cached;const slots=kind===void 0?this.#layout():this.#layout().filter(slot=>slot.kind===kind);const currentLimits=this.#moduleLimits();const value=deepFreeze(slots.map(slot=>{const stats=this.#moduleStatsAt(slot.key);const fixedReason=fixedSlotReason(slot);const immovableReason=fixedReason!==null?fixedReason:stats?.limitIncrease!==void 0&&this.#moduleLimitRegression(slot.key,null,currentLimits,stats)!==null?"moduleLimit":null;return{...slot,name:loadoutSlotName(slot),module:this.fittedModuleAt(slot.key),removable:immovableReason===null,...immovableReason===null?{}:{immovableReason:immovableReason}}}));this.#slotCache.set(kind,value);return value}fittedModuleAt(slotKey){const module=this.#fittedModuleFor(slotKey);if(!module)return null;const raw=cloneLoadoutModule(module);const stats=this.#statsFor(module);const effective=effectiveModule(this.#moduleForEffectiveStats(module),stats);return deepFreeze({slot:module.Slot,symbol:raw.Item,on:raw.On,priority:raw.Priority,health:raw.Health,value:raw.Value,engineering:raw.Engineering,raw:raw,stats:stats===null?null:cloneModuleStats(stats),effectiveStats:effective===null?null:cloneModuleStats(effective),ammunition:ammunitionCapacity(effective),preEngineeredVariant:preEngineeredVariantFor(raw)})}fittedModules(){return deepFreeze([...this.#modules.keys()].flatMap(key=>{const fitted=this.fittedModuleAt(key);return fitted===null?[]:[fitted]}))}availableBlueprints(slotKey){const module=this.#fittedModuleFor(slotKey);return deepFreeze(module?availableBlueprintsFor(module.Item,this.#statsFor(module)):[])}availableExperimentalEffects(slotKey){const module=this.#fittedModuleFor(slotKey);return deepFreeze(module?availableExperimentalsFor(module.Item,this.#statsFor(module)):[])}modulesForSlot(slotKey){const slot=this.#requireSlot(slotKey);const occupied=new Set([...this.#modules.values()].flatMap(fitted=>{if(normalizeKey(fitted.Slot,FITTED_SLOT)===normalizeKey(slot.key,CATALOGUE_KEY))return[];const group=this.#statsFor(fitted)?.exclusionGroup;return group===void 0?[]:[group]}));const currentLimits=this.#moduleLimits();const currentStats=this.#moduleStatsAt(slot.key);return ALL_MODULES.filter(module=>module.grantOnly===void 0&&moduleFitError(this.#shipSymbol,slot,module)===null&&(module.exclusionGroup===void 0||!occupied.has(module.exclusionGroup))&&this.#moduleLimitRegression(slot.key,module,currentLimits,currentStats)===null)}repairFixedMount(slotKey){const requested=requireString(slotKey,SLOT_KEY);const wanted=normalizeKey(requested,SLOT_KEY);const slot=this.#requireSlot(requested);const fittedKey=this.#fittedKey(requested);const resultSlot=fittedKey??requested;const canonicalKey=slot.key;if(fixedSlotReason(slot)===null){return deepFreeze({status:"refused",slot:resultSlot,reason:"notFixedMount"})}const current=this.#fittedModuleFor(requested);const currentStats=current?this.#statsFor(current):null;const valid=current!==void 0&¤tStats!==null&&(slot.kind==="cargoHatch"?isBuiltInHullModule(current):moduleFitProblem(this.#shipSymbol,slot,currentStats)===null);if(valid){return deepFreeze({status:"unchanged",slot:current.Slot,symbol:current.Item})}const defaultModule=getDefaultLoadout(this.#shipSymbol)?.modules.find(module=>normalizeKey(module.slot,CATALOGUE_KEY)===wanted);if(!defaultModule){return deepFreeze({status:"defaultUnavailable",slot:resultSlot})}const ownKey=ownKeyIn(this.#modules,canonicalKey);const replacement={Slot:ownKey,Item:defaultModule.symbol,...current?.On===void 0?{}:{On:current.On},...current?.Priority===void 0?{}:{Priority:current.Priority},...current?.Health===void 0?{}:{Health:current.Health}};const replacementStats=builtInModuleBySymbol(defaultModule.symbol,"ShipLoadout.repairFixedMount")??(isBuiltInHullModule(replacement)?builtInModuleBySymbol("ModularCargoBayDoor","ShipLoadout.repairFixedMount"):null);if(!replacementStats){return deepFreeze({status:"defaultUnavailable",slot:resultSlot,symbol:defaultModule.symbol})}this.#replaceModule(ownKey,replacement,replacementStats);return deepFreeze({status:"repaired",slot:ownKey,symbol:defaultModule.symbol})}setModule(slotKey,module){const slot=this.#requireSlot(slotKey);if(module===null||module===void 0){throw new TypeError(`ShipLoadout.setModule: no module supplied for "${truncate(slotKey)}" (did the module lookup return undefined?)`)}if(typeof module.symbol!=="string"){throw new TypeError(`ShipLoadout.setModule: module for "${truncate(slotKey)}" must be an outfitting module, received ${describeValue(module)}`)}module=cloneModuleStats(module);const catalogued=builtInModuleBySymbol(module.symbol,FITTED_ITEM);if(catalogued===null){throw new TypeError(`ShipLoadout.setModule: no module is catalogued as "${truncate(module.symbol)}"`)}for(const field of AGGREGATE_STATS){const stated=module[field];if(stated===void 0){if(catalogued[field]===void 0)continue;throw new TypeError(`ShipLoadout.setModule: the supplied record for "${truncate(module.symbol)}" has no ${field}`)}if(typeof stated!=="number"||!Number.isFinite(stated)){throw new TypeError(`ShipLoadout.setModule: the supplied record for "${truncate(module.symbol)}" states a ${field} of ${describeValue(stated)}`)}}const problem=moduleFitProblem(this.#shipSymbol,slot,module);if(problem){if(problem.constraint==="immutableSlot"){throw new LoadoutEditError(`ShipLoadout.setModule: ${truncate(module.symbol)} → ${truncate(slotKey)}: ${problem.message}`,"immutableSlot",{slot:slot.key})}throw new LoadoutEditError(`ShipLoadout.setModule: ${truncate(module.symbol)} → ${truncate(slotKey)}: ${problem.message}`,"incompatibleModule",{...problem.params,slot:slot.key,symbol:module.symbol,constraint:problem.constraint},problem.constraint)}if(module.exclusionGroup!==void 0){const conflict=[...this.#modules.values()].find(fitted=>normalizeKey(fitted.Slot,FITTED_SLOT)!==normalizeKey(slot.key,CATALOGUE_KEY)&&this.#statsFor(fitted)?.exclusionGroup===module.exclusionGroup);if(conflict){throw new LoadoutEditError(`ShipLoadout.setModule: ${truncate(module.symbol)} → ${truncate(slotKey)}: ${module.exclusionGroup} is limited to one per ship (already fitted in ${truncate(conflict.Slot)})`,"duplicateExclusiveModule",{exclusionGroup:module.exclusionGroup,slot:slot.key,symbol:module.symbol,previousSlot:conflict.Slot,previousSymbol:conflict.Item})}}const limitProblem=this.#moduleLimitRegression(slot.key,module);if(limitProblem!==null){throw new LoadoutEditError(`ShipLoadout.setModule: ${truncate(module.symbol)} → ${truncate(slotKey)}: ${limitProblem.group} would have ${limitProblem.count} modules but the ship allows ${limitProblem.limit}`,"moduleLimitExceeded",{group:limitProblem.group,count:limitProblem.count,limit:limitProblem.limit,slot:slot.key,symbol:module.symbol})}const key=this.#fittedKey(slotKey)??slot.key;this.#replaceModule(key,{Slot:key,Item:module.symbol},module);return this}removeModule(slotKey){const wanted=normalizeKey(slotKey,SLOT_KEY);if(wanted==="cargohatch"){throw new LoadoutEditError("ShipLoadout.removeModule: the cargoHatch slot cannot be changed","immutableSlot",{slot:"CargoHatch"})}const parsed=parseSlotName(slotKey);const slot=this.#layout().find(candidate=>normalizeKey(candidate.key,CATALOGUE_KEY)===wanted);if(parsed!==null&&fixedSlotReason(parsed)==="requiredSlot"){const fittedKey=this.#fittedKey(slotKey);const key2=slot?.key??fittedKey??slotKey;throw new LoadoutEditError(`ShipLoadout.removeModule: the ${truncate(key2)} slot is required and cannot be emptied`,"requiredSlot",{slot:key2})}const key=this.#fittedKey(slotKey);if(key!==null){const limitProblem=this.#moduleLimitRegression(key,null);if(limitProblem!==null){const fitted=this.#modules.get(key);throw new LoadoutEditError(`ShipLoadout.removeModule: ${truncate(slotKey)}: ${limitProblem.group} would have ${limitProblem.count} modules but the ship allows ${limitProblem.limit}`,"moduleLimitExceeded",{group:limitProblem.group,count:limitProblem.count,limit:limitProblem.limit,slot:key,...fitted===void 0?{}:{symbol:fitted.Item}})}this.#replaceModule(key,null)}return this}applyBlueprint(slotKey,blueprintSymbol,options){requireString(blueprintSymbol,"ShipLoadout.applyBlueprint: blueprintSymbol");if(options===null||typeof options!=="object"){throw new TypeError(`ShipLoadout.applyBlueprint: options must be an object with a grade, received ${describeValue(options)}`)}const wantedGrade=options.grade;const wantedQuality=options.quality;const wantedExperimental=options.experimentalEffectSymbol??void 0;requireStringIfPresent(wantedExperimental,"ShipLoadout.applyBlueprint: options.experimentalEffectSymbol");const module=this.#fittedModuleFor(slotKey);if(!module){throw new RangeError(`ShipLoadout.applyBlueprint: slot "${truncate(slotKey)}" is empty`)}const fittedStats=this.#statsFor(module);if(!fittedStats){throw new TypeError(`ShipLoadout.applyBlueprint: no stats for module "${truncate(module.Item)}"`)}const recipe=resolveBlueprintForModule(module.Item,blueprintSymbol);const named=recipe===blueprintSymbol?`"${truncate(blueprintSymbol)}"`:`"${truncate(blueprintSymbol)}" (${truncate(recipe)} on this module)`;const written=blueprintSymbol.trim().toLowerCase();const resolved=recipe.trim().toLowerCase();if(getPreEngineeredVariants(module.Item).some(variant=>variant.acquisition==="eventReward"&&(variant.blueprintSymbol.toLowerCase()===written||variant.blueprintSymbol.toLowerCase()===resolved))){throw new TypeError(`ShipLoadout.applyBlueprint: ${named} is a fixed pre-engineered identity, not a craftable blueprint; use setPreEngineeredVariant to fit its fixed article`)}if(!Number.isInteger(wantedGrade)||wantedGrade<1||wantedGrade>5){throw new RangeError(`ShipLoadout.applyBlueprint: no blueprint ${named} grade ${truncate(wantedGrade)}`)}const grade=getBlueprintGrade(recipe,wantedGrade);if(!grade){throw new RangeError(`ShipLoadout.applyBlueprint: no blueprint ${named} grade ${truncate(wantedGrade)}`)}let experimental;if(wantedExperimental!==void 0){experimental=getExperimentalEffect(wantedExperimental);if(!experimental){throw new RangeError(`ShipLoadout.applyBlueprint: unknown experimental effect "${truncate(wantedExperimental)}"`)}}const quality=wantedQuality??1;if(!Number.isFinite(quality)||quality<0||quality>1){throw new RangeError(`ShipLoadout.applyBlueprint: quality must be a finite number in [0, 1]`)}if(fittedStats.engineeringLocked){throw new TypeError(`ShipLoadout.applyBlueprint: module "${truncate(module.Item)}" is a final pre-engineered article and accepts no further engineering`)}if(!blueprintAvailableFor(module.Item,blueprintSymbol)){const offered=[...blueprintRoutesFor(module.Item)].map(([blueprint,route])=>`${blueprint} (${route})`);throw new TypeError(offered.length>0?`ShipLoadout.applyBlueprint: module "${truncate(module.Item)}" is not offered blueprint ${named}; available candidates are ${offered.join(", ")}`:`ShipLoadout.applyBlueprint: no registry lists an engineering menu for module "${truncate(module.Item)}"`)}if(wantedExperimental!==void 0&&!experimentalAvailableFor(module.Item,wantedExperimental)){const offered=getExperimentalsForModule(module.Item);throw new TypeError(`ShipLoadout.applyBlueprint: module "${truncate(module.Item)}" is not offered experimental effect "${truncate(wantedExperimental)}"; it takes ${offered.length>0?offered.join(", "):"no experimental effect"}`)}const stats=this.#engineeringBaseStats(module)??fittedStats;const base=baseStats(stats);const canonical=primitiveEngineeringInputsFor(stats,grade,experimental);const missing=missingBaseLabels(stats,base,canonical.grade.features,canonical.experimental?.modifiers);if(missing.length>0){throw new TypeError(`ShipLoadout.applyBlueprint: cannot compute ${named} for module "${truncate(module.Item)}"; missing base stats for ${missing.join(", ")}`)}const damageDistribution=experimental?.damageDistribution??grade.damageDistribution;const primitiveModifiers=computeModifiers(base,canonical.grade,quality,canonical.experimental);const modifiers=journalModifiersFor(stats,primitiveModifiers);if(damageDistribution){for(const type of["kinetic","thermal","explosive","absolute"]){const value=damageDistribution[type];if(value===void 0)continue;const label=labelsForDamageType(type)[0];if(label===void 0)continue;const damageModifier={Label:label,Value:value*scaleForLabel(label),OriginalValue:(stats.damageDistribution?.[type]??0)*scaleForLabel(label)};modifiers.push(damageModifier);primitiveModifiers.push(damageModifier)}}const engineering={BlueprintName:blueprintSymbol,Level:wantedGrade,Quality:quality,...wantedExperimental!==void 0?{ExperimentalEffect:wantedExperimental}:{},Modifiers:modifiers};this.#replaceModule(module.Slot,{...module,Engineering:engineering},stats,primitiveModifiers);return this}setExperimentalEffect(slotKey,experimental){if(experimental!==null){requireString(experimental,"ShipLoadout.setExperimentalEffect: experimental")}const wanted=experimental;const module=this.#fittedModuleFor(slotKey);if(!module)return experimentalEffectUnsupported("emptySlot",{slot:slotKey});const stats=this.#statsFor(module);if(!stats){return experimentalEffectUnsupported("unsupportedEngineering",{slot:module.Slot,symbol:module.Item})}const engineering=module.Engineering;if(!engineering){return experimentalEffectUnsupported("notEngineered",{slot:module.Slot,symbol:module.Item})}if(stats.engineeringLocked){return experimentalEffectUnsupported("finalArticle",{slot:module.Slot,symbol:module.Item})}const previous=engineering.ExperimentalEffect??null;if(previous===null&&wanted===null||previous!==null&&wanted!==null&&previous.trim().toLowerCase()===wanted.trim().toLowerCase()){return deepFreeze({kind:"unchanged",experimentalEffectSymbol:previous})}const variant=preEngineeredVariantFor(module);let effect;if(wanted!==null){effect=getExperimentalEffect(wanted);if(!effect){return experimentalEffectUnsupported("unknownExperimentalEffect",{slot:module.Slot,symbol:module.Item,experimental:wanted})}const restoresBakedEffect=variant?.experimentalEffectSymbol!==void 0&&variant.acquisition!=="mercenary"&&variant.experimentalEffectSymbol.trim().toLowerCase()===wanted.trim().toLowerCase();if(!experimentalAvailableFor(module.Item,wanted)&&!restoresBakedEffect){return experimentalEffectUnsupported("unsupportedExperimentalEffect",{slot:module.Slot,symbol:module.Item,experimental:wanted})}}if(variant&&variant.acquisition!=="mercenary"){const stock=this.#engineeringBaseStats(module);if(!stock){return experimentalEffectUnsupported("unsupportedEngineering",{slot:module.Slot,symbol:module.Item})}const missing=missingBaseLabels(stock,baseStats(stock),[],effect?.modifiers);if(missing.length>0){return experimentalEffectUnsupported("unresolvedModifiers",{slot:module.Slot,symbol:module.Item,labels:missing})}const{experimentalEffectSymbol:originalEffect,...withoutEffect}=variant;const adjusted=wanted===null?withoutEffect:{...withoutEffect,experimentalEffectSymbol:wanted};const resolved=getPreEngineeredStats(withoutEffect);if(!resolved){return experimentalEffectUnsupported("unsupportedEngineering",{slot:module.Slot,symbol:module.Item})}const replacement={BlueprintName:engineering.BlueprintName,Level:engineering.Level,Quality:engineering.Quality,...wanted===null?{}:{ExperimentalEffect:wanted},Modifiers:getPreEngineeredJournalModifiers(adjusted)};this.#replaceModule(module.Slot,{...module,Engineering:replacement},cloneModuleStats(resolved),getPreEngineeredModifiers(adjusted))}else{const blueprint=engineering.BlueprintName;const grade=engineering.Level;const quality=engineering.Quality;if(typeof blueprint!=="string"||!Number.isInteger(grade)||grade<1||grade>5){return experimentalEffectUnsupported("unsupportedEngineering",{slot:module.Slot,symbol:module.Item})}const currentEffect=previous===null?void 0:getExperimentalEffect(previous)??null;if(ordinaryEngineeringProof(module.Item,engineering,currentEffect)==="unproven"){return experimentalEffectUnsupported("unidentifiedPreEngineeredVariant",{slot:module.Slot,symbol:module.Item,blueprint:blueprint})}const recipe=resolveBlueprintForModule(module.Item,blueprint);const blueprintGrade=getBlueprintGrade(recipe,grade);if(!blueprintGrade||!blueprintAvailableFor(module.Item,blueprint)||!Number.isFinite(quality)||quality<0||quality>1){return experimentalEffectUnsupported("unsupportedEngineering",{slot:module.Slot,symbol:module.Item,blueprint:blueprint,grade:grade})}const base=this.#engineeringBaseStats(module)??stats;const canonical=primitiveEngineeringInputsFor(base,blueprintGrade,effect);const missing=missingBaseLabels(base,baseStats(base),canonical.grade.features,canonical.experimental?.modifiers);if(missing.length>0){return experimentalEffectUnsupported("unresolvedModifiers",{slot:module.Slot,symbol:module.Item,labels:missing})}this.applyBlueprint(module.Slot,blueprint,{grade:grade,quality:quality,...wanted===null?{}:{experimentalEffectSymbol:wanted}})}return deepFreeze({kind:"updated",previousExperimentalEffectSymbol:previous,experimentalEffectSymbol:wanted})}completeEngineeringGrade(slotKey){const module=this.#fittedModuleFor(slotKey);if(!module)return engineeringNormalizationUnsupported("emptySlot",{slot:slotKey});const stats=this.#statsFor(module);if(!stats){return engineeringNormalizationUnsupported("unsupportedEngineering",{slot:module.Slot,symbol:module.Item})}const engineering=module.Engineering;if(!engineering){return engineeringNormalizationUnsupported("notEngineered",{slot:module.Slot,symbol:module.Item})}if(stats.engineeringLocked){return engineeringNormalizationUnsupported("finalArticle",{slot:module.Slot,symbol:module.Item})}if(engineering.Quality===1&&engineering.Modifiers!==void 0){return deepFreeze({kind:"unchanged"})}const previousQuality=engineering.Quality;if(!Number.isFinite(previousQuality)||previousQuality<0||previousQuality>1){return engineeringNormalizationUnsupported("invalidQuality",{slot:module.Slot,symbol:module.Item})}const experimental=engineering.ExperimentalEffect??null;const effect=experimental===null?void 0:getExperimentalEffect(experimental)??void 0;if(experimental!==null&&!effect){return engineeringNormalizationUnsupported("unknownExperimentalEffect",{slot:module.Slot,symbol:module.Item,experimental:experimental})}const blueprint=engineering.BlueprintName;const grade=engineering.Level;if(typeof blueprint!=="string"||!Number.isInteger(grade)||grade<1||grade>5){return engineeringNormalizationUnsupported("unsupportedEngineering",{slot:module.Slot,symbol:module.Item})}const variant=preEngineeredVariantFor(module);const restoresBakedEffect=variant?.experimentalEffectSymbol!==void 0&&variant.acquisition!=="mercenary"&&variant.experimentalEffectSymbol.trim().toLowerCase()===experimental?.trim().toLowerCase();if(experimental!==null&&!experimentalAvailableFor(module.Item,experimental)&&!restoresBakedEffect){return engineeringNormalizationUnsupported("unsupportedExperimentalEffect",{slot:module.Slot,symbol:module.Item,experimental:experimental})}if(variant&&variant.acquisition!=="mercenary"){const stock=this.#engineeringBaseStats(module);if(!stock){return engineeringNormalizationUnsupported("unsupportedEngineering",{slot:module.Slot,symbol:module.Item})}const missing=missingBaseLabels(stock,baseStats(stock),[],effect?.modifiers);if(missing.length>0){return engineeringNormalizationUnsupported("unresolvedModifiers",{slot:module.Slot,symbol:module.Item,labels:missing})}const{experimentalEffectSymbol:originalEffect,...withoutEffect}=variant;const adjusted=experimental===null?withoutEffect:{...withoutEffect,experimentalEffectSymbol:experimental};const resolved=getPreEngineeredStats(withoutEffect);if(!resolved){return engineeringNormalizationUnsupported("unsupportedEngineering",{slot:module.Slot,symbol:module.Item})}const replacement={BlueprintName:engineering.BlueprintName,Level:engineering.Level,Quality:1,...experimental===null?{}:{ExperimentalEffect:experimental},Modifiers:getPreEngineeredJournalModifiers(adjusted)};this.#replaceModule(module.Slot,{...module,Engineering:replacement},cloneModuleStats(resolved),getPreEngineeredModifiers(adjusted))}else{const proof=ordinaryEngineeringProof(module.Item,engineering,effect);if(proof==="unproven"||proof==="proven"&&!blueprintAvailableFor(module.Item,blueprint)){return engineeringNormalizationUnsupported("unidentifiedPreEngineeredVariant",{slot:module.Slot,symbol:module.Item,blueprint:blueprint})}const recipe=resolveBlueprintForModule(module.Item,blueprint);const blueprintGrade=getBlueprintGrade(recipe,grade);if(!blueprintGrade||!blueprintAvailableFor(module.Item,blueprint)){return engineeringNormalizationUnsupported("unsupportedEngineering",{slot:module.Slot,symbol:module.Item,blueprint:blueprint,grade:grade})}const base=this.#engineeringBaseStats(module)??stats;const canonical=primitiveEngineeringInputsFor(base,blueprintGrade,effect);const missing=missingBaseLabels(base,baseStats(base),canonical.grade.features,canonical.experimental?.modifiers);if(missing.length>0){return engineeringNormalizationUnsupported("unresolvedModifiers",{slot:module.Slot,symbol:module.Item,labels:missing})}this.applyBlueprint(module.Slot,blueprint,{grade:grade,quality:1,...experimental===null?{}:{experimentalEffectSymbol:experimental}})}return deepFreeze({kind:"normalized",previousQuality:previousQuality,quality:1})}setPreEngineeredVariant(slotKey,variant){if(variant===null||typeof variant!=="object"){throw new TypeError(`ShipLoadout.setPreEngineeredVariant: variant must be a pre-engineered variant, received ${describeValue(variant)}`)}requireString(variant.symbol,"ShipLoadout.setPreEngineeredVariant: variant.symbol");requireString(variant.blueprintSymbol,"ShipLoadout.setPreEngineeredVariant: variant.blueprintSymbol");requireString(variant.acquisition,"ShipLoadout.setPreEngineeredVariant: variant.acquisition");requireStringIfPresent(variant.experimentalEffectSymbol,"ShipLoadout.setPreEngineeredVariant: variant.experimentalEffectSymbol");const known=getPreEngineeredVariants(variant.symbol).find(candidate=>candidate.blueprintSymbol.toLowerCase()===variant.blueprintSymbol.toLowerCase()&&candidate.grade===variant.grade&&(candidate.experimentalEffectSymbol?.toLowerCase()??"")===(variant.experimentalEffectSymbol?.toLowerCase()??"")&&candidate.acquisition===variant.acquisition);if(!known){throw new RangeError(`ShipLoadout.setPreEngineeredVariant: no catalogued variant "${truncate(variant.blueprintSymbol)}" for module "${truncate(variant.symbol)}"`)}const stats=getPreEngineeredStats(known);const unresolved=unresolvedModifiers(known);if(unresolved.length>0){throw new TypeError(`ShipLoadout.setPreEngineeredVariant: cannot resolve "${truncate(variant.blueprintSymbol)}" for module "${truncate(variant.symbol)}"; missing base stats for ${unresolved.join(", ")}`)}this.setModule(slotKey,stats);const module=this.#fittedModuleFor(slotKey);const journalModifiers=getPreEngineeredJournalModifiers(known);const engineering={BlueprintName:known.blueprintSymbol,Level:known.grade,Quality:1,...known.experimentalEffectSymbol===void 0?{}:{ExperimentalEffect:known.experimentalEffectSymbol},...journalModifiers.length>0?{Modifiers:journalModifiers}:{}};this.#replaceModule(module.Slot,{...module,Engineering:engineering},cloneModuleStats(stats),getPreEngineeredModifiers(known));return this}clearEngineering(slotKey){const module=this.#fittedModuleFor(slotKey);if(module&&this.#statsFor(module)?.engineeringLocked){throw new TypeError(`ShipLoadout.clearEngineering: module "${truncate(module.Item)}" is a final pre-engineered article and its engineering cannot be removed`)}if(module?.Engineering){const baseStats2=this.#engineeringBaseStats(module);const bare={Slot:module.Slot,Item:module.Item};if(module.On!==void 0)bare.On=module.On;if(module.Priority!==void 0){bare.Priority=module.Priority}if(module.Health!==void 0)bare.Health=module.Health;if(module.Value!==void 0)bare.Value=module.Value;this.#replaceModule(module.Slot,bare,baseStats2??void 0)}return this}setModuleEnabled(slotKey,on){this.#patchModule(slotKey,{On:on});return this}setModulePriority(slotKey,priority){if(!Number.isInteger(priority)||priority<0||priority>4){throw new RangeError(`ShipLoadout: power priority must be an integer 0-4, got ${truncate(priority)}`)}this.#patchModule(slotKey,{Priority:priority});return this}#patchModule(slotKey,patch){const module=this.#fittedModuleFor(slotKey);if(!module){throw new RangeError(`ShipLoadout: slot "${truncate(slotKey)}" is empty`)}this.#modules.set(module.Slot,cloneLoadoutModule({...module,...patch}));this.#slotCache.clear()}toLoadoutEvent(options={}){const unladenMass=this.#computedUnladenMass();const cargoCapacity=this.#computedCargoCapacity();const fuel=this.#computedFuelCapacity();const maxJumpRange=this.#exportableJumpRange(unladenMass);return exportLoadoutEvent({shipSymbol:this.#shipSymbol,...this.#top.ShipName===void 0?{}:{shipName:this.#top.ShipName},...this.#top.ShipIdent===void 0?{}:{shipIdent:this.#top.ShipIdent},modules:this.#modules,layout:this.#layout(),sourcePurchase:this.#sourcePurchase,retailHullValue:this.#ship.hullCost,unladenMass:unladenMass,cargoCapacity:cargoCapacity,fuelCapacity:fuel,maxJumpRange:maxJumpRange,sourceTotalsVoided:this.#importOutcomes.some(outcome=>outcome.sourceSymbol===null&&parseSlotName(outcome.slot)?.kind==="core"),statsFor:module=>this.#statsFor(module)},options)}toSlef(options){return toSlef(this.toLoadoutEvent(options),options.header)}toSlefString(options){return stringifySlef(this.toSlef(options),{indent:options.indent??0})}#exportableJumpRange(unladenMass){let drive;try{drive=this.#resolveDrive()}catch{return null}if(drive===null)return null;const tank=this.#computedFuelCapacity();return singleJumpRange(unladenMass,Math.min(tank.main,drive.maxFuel),drive)}#layout(){if(this.#layoutCache===void 0){this.#layoutCache=Object.freeze(enumerateSlots(this.#ship))}return this.#layoutCache}#requireSlot(slotKey){const wanted=normalizeKey(slotKey,SLOT_KEY);const slot=this.#layout().find(s=>normalizeKey(s.key,CATALOGUE_KEY)===wanted);if(!slot){throw new RangeError(`ShipLoadout: hull "${truncate(this.#shipSymbol)}" has no slot "${truncate(slotKey)}"`)}return slot}#fittedKey(slotKey){return matchingKeyIn(this.#modules,normalizeKey(slotKey,SLOT_KEY))}#fittedModuleFor(slotKey){const key=this.#fittedKey(slotKey);return key===null?void 0:this.#modules.get(key)}#calculationModules(){return[...this.#modules.values()].map(module=>({mass:this.#moduleMass(module),cargoCapacity:this.#moduleCapacity(module,"CargoCapacity","cargoCapacity"),fuelCapacity:this.#moduleCapacity(module,"FuelCapacity","fuelCapacity")}))}#moduleLimits(){const entries=[...this.#modules.values()].flatMap(module=>{const stats=this.#statsFor(module);return stats===null?[]:[stats]});return calculateModuleLimits(entries)}#moduleStatsAt(slotKey){const fitted=this.#fittedModuleFor(slotKey);return fitted===void 0?null:this.#statsFor(fitted)}#engineeringBaseStats(module){const fitted=this.#statsFor(module);if(!module.Engineering||preEngineeredVariantFor(module)===null)return fitted;const stock=builtInModuleBySymbol(module.Item,FITTED_ITEM);if(!stock)return fitted;return fitted?.engineeringLocked?cloneModuleStats({...stock,engineeringLocked:true}):stock}#moduleForEffectiveStats(module){const modifiers=this.#primitiveModifiers.get(module.Slot);if(modifiers===void 0||module.Engineering===void 0)return module;return{...module,Engineering:{...module.Engineering,Modifiers:modifiers}}}#modulesForEffectiveStats(){return[...this.#modules.values()].map(module=>this.#moduleForEffectiveStats(module))}#moduleLimitRegression(slotKey,replacement,current=this.#moduleLimits(),previous=this.#moduleStatsAt(slotKey)){if(previous?.limitGroup===void 0&&previous?.limitIncrease===void 0&&replacement?.limitGroup===void 0&&replacement?.limitIncrease===void 0){return null}for(const usage of current){const count=usage.count-Number(previous?.limitGroup===usage.group)+Number(replacement?.limitGroup===usage.group);const increase=usage.increase-(previous?.limitIncrease?.group===usage.group?previous.limitIncrease.amount:0)+(replacement?.limitIncrease?.group===usage.group?replacement.limitIncrease.amount:0);const limit=usage.baseLimit+increase;const excess=Math.max(0,count-limit);if(excess>usage.excess){return{...usage,increase:increase,limit:limit,count:count,excess:excess}}}return null}#replaceModule(slotKey,replacement,replacementStats,primitiveModifiers){const previous=this.#modules.get(slotKey)??null;this.#adjustImportedFigures(previous,replacement,replacementStats);if(replacement===null){this.#modules.delete(slotKey);this.#moduleStats.delete(slotKey);this.#primitiveModifiers.delete(slotKey)}else{this.#modules.set(slotKey,cloneLoadoutModule(replacement));if(replacementStats!==void 0)this.#moduleStats.set(slotKey,replacementStats);if(primitiveModifiers===void 0)this.#primitiveModifiers.delete(slotKey);else this.#primitiveModifiers.set(slotKey,primitiveModifiers)}this.#slotCache.clear()}#adjustImportedFigures(previous,next,nextStats){if(this.#top.UnladenMass!==void 0){this.#top.UnladenMass+=this.#moduleMass(next,nextStats)-this.#moduleMass(previous)}if(this.#top.CargoCapacity!==void 0){this.#top.CargoCapacity+=this.#moduleCapacity(next,"CargoCapacity","cargoCapacity",nextStats)-this.#moduleCapacity(previous,"CargoCapacity","cargoCapacity")}if(this.#top.FuelCapacity?.Main!==void 0){const reserve=this.#top.FuelCapacity.Reserve;this.#top.FuelCapacity={Main:this.#top.FuelCapacity.Main+this.#moduleCapacity(next,"FuelCapacity","fuelCapacity",nextStats)-this.#moduleCapacity(previous,"FuelCapacity","fuelCapacity"),...reserve===void 0?{}:{Reserve:reserve}}}if(normalizeKey(previous?.Item,FITTED_ITEM)===normalizeKey(next?.Item,FITTED_ITEM)){return}if(previous!==null&&isCargoHatchSlot(previous.Slot)||next!==null&&isCargoHatchSlot(next.Slot)){return}delete this.#top.ModulesValue;delete this.#top.Rebuy}#moduleMass(module,statsOverride){if(module===null)return 0;if(isCargoHatchSlot(module.Slot))return 0;const modified=getLoadoutModifier(module,"Mass");if(modified!==null)return modified;return(statsOverride??this.#statsFor(module))?.mass??0}#moduleCapacity(module,modifierLabel,field,statsOverride){if(module===null)return 0;if(isCargoHatchSlot(module.Slot))return 0;const modified=getLoadoutModifier(module,modifierLabel);if(modified!==null)return modified;return(statsOverride??this.#statsFor(module))?.[field]??0}#frameShiftDrive(){for(const m of this.#modules.values()){const stats=this.#statsFor(m);if(stats?.slot==="frameShiftDrive")return{module:m,stats:stats}}return void 0}#resolveDrive(){const fsd=this.#frameShiftDrive();if(!fsd)return null;const{module:fsdModule,stats:base}=fsd;if(base.fuelMul===void 0||base.fuelPower===void 0){throw new TypeError(`ShipLoadout: the fitted record for frame shift drive "${truncate(fsdModule.Item)}" has no jump constants`)}const optMass=getLoadoutModifier(fsdModule,"FSDOptimalMass")??base.optMass;const maxFuel=getLoadoutModifier(fsdModule,"MaxFuelPerJump")??base.maxFuel;if(optMass===void 0||maxFuel===void 0){const missing=[...optMass===void 0?["optMass"]:[],...maxFuel===void 0?["maxFuel"]:[]];throw new TypeError(`ShipLoadout: the fitted record for frame shift drive "${truncate(fsdModule.Item)}" has no ${missing.join(" or ")}`)}return{optMass:optMass,maxFuel:maxFuel,fuelMul:base.fuelMul,fuelPower:base.fuelPower,jumpBoost:this.#resolveJumpBoost()}}#resolveJumpBoost(){for(const m of this.#modules.values()){const stats=this.#statsFor(m);if(stats?.engineeringGroup!=="fsdBoosters"&&(stats?.jumpBoost===void 0||stats.jumpBoost===0)){continue}if(m.On===false)continue;if(stats?.jumpBoost===void 0){throw new TypeError(`ShipLoadout: the fitted record for FSD booster "${truncate(m.Item)}" has no jumpBoost`)}return stats.jumpBoost}return 0}#statsFor(module){if(module===null)return null;const stats=this.#moduleStats.get(module.Slot)??builtInModuleBySymbol(module.Item,FITTED_ITEM);if(stats)return stats;return isBuiltInHullModule(module)?builtInModuleBySymbol("ModularCargoBayDoor","ShipLoadout: built-in module"):null}};export{LoadoutEditError,ShipLoadout};//# sourceMappingURL=chunk-3P455LF4.js.map
|