@elite-dangerous-almanac/core 0.1.7 → 0.2.0

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.
Files changed (274) hide show
  1. package/PROVENANCE/i18n/SOURCES.md +2 -2
  2. package/PROVENANCE/ships/SOURCES.md +29 -9
  3. package/README.md +54 -40
  4. package/dist/astro/galaxy-grid.js +1 -1
  5. package/dist/astro/index.d.ts +1 -1
  6. package/dist/astro/index.js +1 -1
  7. package/dist/astro/naming-region-origins.d.ts +1 -1
  8. package/dist/astro/naming-region-origins.js +1 -1
  9. package/dist/astro/nebulae.d.ts +2 -2
  10. package/dist/astro/permit-locks.d.ts +2 -1
  11. package/dist/astro/permit-locks.js +1 -1
  12. package/dist/astro/procedural-system.d.ts +2 -1
  13. package/dist/astro/procedural-system.js +1 -1
  14. package/dist/astro/sector-name.d.ts +2 -1
  15. package/dist/astro/sector-name.js +1 -1
  16. package/dist/astro/system-address.d.ts +1 -1
  17. package/dist/astro/system-name.d.ts +14 -9
  18. package/dist/astro/system-name.js +1 -1
  19. package/dist/chunk-2W5MW376.js +1 -0
  20. package/dist/chunk-2W5MW376.js.map +1 -0
  21. package/dist/{chunk-VZZUNSDF.js → chunk-4KJ7CR74.js} +1 -1
  22. package/dist/{chunk-VZZUNSDF.js.map → chunk-4KJ7CR74.js.map} +1 -1
  23. package/dist/{chunk-6EUVIZAS.js → chunk-4QYTVSNR.js} +1 -1
  24. package/dist/{chunk-EKQCVCMK.js → chunk-5ZVYRX6Z.js} +1 -1
  25. package/dist/{chunk-EKQCVCMK.js.map → chunk-5ZVYRX6Z.js.map} +1 -1
  26. package/dist/chunk-6GJHUWMO.js +1 -0
  27. package/dist/chunk-6GJHUWMO.js.map +1 -0
  28. package/dist/chunk-6L56LWTT.js +1 -0
  29. package/dist/chunk-6L56LWTT.js.map +1 -0
  30. package/dist/{chunk-GQ5GX5TB.js → chunk-6O4NRRSB.js} +1 -1
  31. package/dist/chunk-6O4NRRSB.js.map +1 -0
  32. package/dist/{chunk-WNGQ3IAM.js → chunk-6UNAD74Z.js} +1 -1
  33. package/dist/{chunk-WNGQ3IAM.js.map → chunk-6UNAD74Z.js.map} +1 -1
  34. package/dist/{chunk-JPBMRJFC.js → chunk-77I24V6B.js} +1 -1
  35. package/dist/chunk-77I24V6B.js.map +1 -0
  36. package/dist/chunk-7ATBEOVC.js +1 -0
  37. package/dist/chunk-7ATBEOVC.js.map +1 -0
  38. package/dist/chunk-7TQ2X6Q3.js +1 -0
  39. package/dist/chunk-7TQ2X6Q3.js.map +1 -0
  40. package/dist/{chunk-6EPYVBAX.js → chunk-A6OINYNP.js} +1 -1
  41. package/dist/{chunk-Q3QCLNVG.js → chunk-AYAKU4YA.js} +1 -1
  42. package/dist/chunk-AYAKU4YA.js.map +1 -0
  43. package/dist/chunk-B7EYTZRK.js +1 -0
  44. package/dist/chunk-B7EYTZRK.js.map +1 -0
  45. package/dist/{chunk-EBAHNZ36.js → chunk-CIULJH3G.js} +1 -1
  46. package/dist/{chunk-EBAHNZ36.js.map → chunk-CIULJH3G.js.map} +1 -1
  47. package/dist/{chunk-SNADUQSJ.js → chunk-CJK2IBI2.js} +1 -1
  48. package/dist/{chunk-SNADUQSJ.js.map → chunk-CJK2IBI2.js.map} +1 -1
  49. package/dist/{chunk-DYPOL3CI.js → chunk-CJQ37JII.js} +1 -1
  50. package/dist/chunk-CJQ37JII.js.map +1 -0
  51. package/dist/chunk-D6YEHR5S.js +1 -0
  52. package/dist/chunk-D6YEHR5S.js.map +1 -0
  53. package/dist/{chunk-Z6XMXMVI.js → chunk-DBDCOHI4.js} +1 -1
  54. package/dist/chunk-DBDCOHI4.js.map +1 -0
  55. package/dist/{chunk-AFVYCQWL.js → chunk-DCB4COCL.js} +1 -1
  56. package/dist/{chunk-AFVYCQWL.js.map → chunk-DCB4COCL.js.map} +1 -1
  57. package/dist/{chunk-CJWFY6OX.js → chunk-DSMLYA2M.js} +1 -1
  58. package/dist/{chunk-CJWFY6OX.js.map → chunk-DSMLYA2M.js.map} +1 -1
  59. package/dist/{chunk-UXBCLFGU.js → chunk-DWRNXUAX.js} +1 -1
  60. package/dist/{chunk-UXBCLFGU.js.map → chunk-DWRNXUAX.js.map} +1 -1
  61. package/dist/{chunk-UHSNB5SV.js → chunk-EVJ32UF3.js} +1 -1
  62. package/dist/{chunk-UHSNB5SV.js.map → chunk-EVJ32UF3.js.map} +1 -1
  63. package/dist/chunk-EVW4Z4CB.js +1 -0
  64. package/dist/chunk-EVW4Z4CB.js.map +1 -0
  65. package/dist/{chunk-4S6WB7QR.js → chunk-FF2X4K5P.js} +1 -1
  66. package/dist/chunk-FF2X4K5P.js.map +1 -0
  67. package/dist/chunk-FYVPZBXN.js +1 -0
  68. package/dist/chunk-FYVPZBXN.js.map +1 -0
  69. package/dist/{chunk-QTZPA2FR.js → chunk-GLWPSVFV.js} +1 -1
  70. package/dist/chunk-GLWPSVFV.js.map +1 -0
  71. package/dist/chunk-GZYPQIO2.js +1 -0
  72. package/dist/chunk-GZYPQIO2.js.map +1 -0
  73. package/dist/chunk-H47K3UWG.js +1 -0
  74. package/dist/chunk-H47K3UWG.js.map +1 -0
  75. package/dist/chunk-JGOAQLYW.js +1 -0
  76. package/dist/chunk-JGOAQLYW.js.map +1 -0
  77. package/dist/{chunk-JWWYAMGD.js → chunk-MGRDB2BZ.js} +1 -1
  78. package/dist/{chunk-JWWYAMGD.js.map → chunk-MGRDB2BZ.js.map} +1 -1
  79. package/dist/{chunk-MKGJPVPS.js → chunk-MRTTQYT5.js} +1 -1
  80. package/dist/{chunk-MKGJPVPS.js.map → chunk-MRTTQYT5.js.map} +1 -1
  81. package/dist/chunk-MTJ4MS7W.js +1 -0
  82. package/dist/chunk-MTJ4MS7W.js.map +1 -0
  83. package/dist/chunk-NIURLW2F.js +1 -0
  84. package/dist/chunk-NIURLW2F.js.map +1 -0
  85. package/dist/chunk-OLKNYGGT.js +1 -0
  86. package/dist/chunk-OLKNYGGT.js.map +1 -0
  87. package/dist/{chunk-UXFMVZAY.js → chunk-OVUHQEH5.js} +1 -1
  88. package/dist/{chunk-UXFMVZAY.js.map → chunk-OVUHQEH5.js.map} +1 -1
  89. package/dist/chunk-OYFMHDYT.js +1 -0
  90. package/dist/chunk-OYFMHDYT.js.map +1 -0
  91. package/dist/chunk-OYR5HUQZ.js +1 -0
  92. package/dist/chunk-OYR5HUQZ.js.map +1 -0
  93. package/dist/{chunk-LLHGSBPI.js → chunk-PA5EITW5.js} +1 -1
  94. package/dist/{chunk-LLHGSBPI.js.map → chunk-PA5EITW5.js.map} +1 -1
  95. package/dist/chunk-PL75RTA2.js +1 -0
  96. package/dist/{chunk-2VPVZELZ.js.map → chunk-PL75RTA2.js.map} +1 -1
  97. package/dist/chunk-PY5L6WC5.js +1 -0
  98. package/dist/chunk-PY5L6WC5.js.map +1 -0
  99. package/dist/{chunk-W6EPHHTS.js → chunk-Q2L75GSI.js} +1 -1
  100. package/dist/chunk-Q2L75GSI.js.map +1 -0
  101. package/dist/chunk-QJ7GB6FF.js +1 -0
  102. package/dist/chunk-QJ7GB6FF.js.map +1 -0
  103. package/dist/chunk-QTAMQ6ME.js +1 -0
  104. package/dist/chunk-QTAMQ6ME.js.map +1 -0
  105. package/dist/{chunk-VDVFJXX5.js → chunk-QY3L5BKN.js} +1 -1
  106. package/dist/{chunk-FMPRCYKY.js → chunk-RRYBSAPX.js} +1 -1
  107. package/dist/chunk-RRYBSAPX.js.map +1 -0
  108. package/dist/{chunk-J42ZXLBL.js → chunk-T62GO4AA.js} +1 -1
  109. package/dist/chunk-T62GO4AA.js.map +1 -0
  110. package/dist/{chunk-E3BRVGJJ.js → chunk-TBZJIQ5P.js} +1 -1
  111. package/dist/{chunk-E3BRVGJJ.js.map → chunk-TBZJIQ5P.js.map} +1 -1
  112. package/dist/chunk-V3AEUBHV.js +1 -0
  113. package/dist/chunk-V3AEUBHV.js.map +1 -0
  114. package/dist/chunk-VYDQHPY2.js +1 -0
  115. package/dist/chunk-VYDQHPY2.js.map +1 -0
  116. package/dist/chunk-XUHAPOM6.js +1 -0
  117. package/dist/chunk-XUHAPOM6.js.map +1 -0
  118. package/dist/chunk-Y6KJJMIM.js +1 -0
  119. package/dist/chunk-Y6KJJMIM.js.map +1 -0
  120. package/dist/chunk-YXPZ7QQB.js +1 -0
  121. package/dist/chunk-YXPZ7QQB.js.map +1 -0
  122. package/dist/{chunk-Y6UZWNP4.js → chunk-ZCEAPJDH.js} +1 -1
  123. package/dist/{chunk-Y6UZWNP4.js.map → chunk-ZCEAPJDH.js.map} +1 -1
  124. package/dist/commodities/commodities.d.ts +20 -10
  125. package/dist/commodities/commodities.js +1 -1
  126. package/dist/commodities/index.d.ts +15 -4
  127. package/dist/commodities/index.js +1 -1
  128. package/dist/equipment/index.js +1 -1
  129. package/dist/equipment/modification-costs.d.ts +2 -1
  130. package/dist/equipment/modification-costs.js.map +1 -1
  131. package/dist/equipment/modification-journal.js +1 -1
  132. package/dist/equipment/modifications.d.ts +2 -1
  133. package/dist/equipment/modifications.js +1 -1
  134. package/dist/equipment/suits.d.ts +6 -3
  135. package/dist/equipment/suits.js +1 -1
  136. package/dist/equipment/upgrade-costs.d.ts +8 -4
  137. package/dist/equipment/upgrade-costs.js +1 -1
  138. package/dist/equipment/upgrade-costs.js.map +1 -1
  139. package/dist/equipment/weapons.d.ts +13 -5
  140. package/dist/equipment/weapons.js +1 -1
  141. package/dist/i18n/blueprints.d.ts +6 -6
  142. package/dist/i18n/blueprints.js +1 -1
  143. package/dist/i18n/diagnostics.d.ts +1 -13
  144. package/dist/i18n/engineering-groups.d.ts +1 -0
  145. package/dist/i18n/engineering-groups.js +1 -1
  146. package/dist/i18n/experimental-effect-descriptions.d.ts +4 -3
  147. package/dist/i18n/experimental-effect-descriptions.js +1 -1
  148. package/dist/i18n/experimental-effects.d.ts +5 -4
  149. package/dist/i18n/experimental-effects.js +1 -1
  150. package/dist/i18n/index.d.ts +1 -13
  151. package/dist/i18n/index.js +1 -1
  152. package/dist/i18n/pre-engineered.d.ts +7 -6
  153. package/dist/i18n/pre-engineered.js +1 -1
  154. package/dist/materials/index.d.ts +16 -4
  155. package/dist/materials/index.js +1 -1
  156. package/dist/materials/materials.d.ts +36 -19
  157. package/dist/materials/materials.js +1 -1
  158. package/dist/materials/micro-resources.d.ts +18 -7
  159. package/dist/materials/micro-resources.js +1 -1
  160. package/dist/ships/armour.d.ts +20 -4
  161. package/dist/ships/armour.js +1 -1
  162. package/dist/ships/blueprint-costs.d.ts +20 -17
  163. package/dist/ships/blueprint-costs.js +1 -1
  164. package/dist/ships/blueprint-journal.d.ts +9 -8
  165. package/dist/ships/blueprint-journal.js +1 -1
  166. package/dist/ships/blueprints.d.ts +14 -12
  167. package/dist/ships/blueprints.js +1 -1
  168. package/dist/ships/build-metrics.d.ts +1061 -0
  169. package/dist/ships/build-metrics.js +1 -0
  170. package/dist/ships/build-metrics.js.map +1 -0
  171. package/dist/ships/distributor.d.ts +10 -3
  172. package/dist/ships/distributor.js +1 -1
  173. package/dist/ships/engineering-options.d.ts +8 -6
  174. package/dist/ships/engineering-options.js +1 -1
  175. package/dist/ships/engineering.d.ts +2 -16
  176. package/dist/ships/engineering.js +1 -1
  177. package/dist/ships/experimental-effect-costs.d.ts +5 -5
  178. package/dist/ships/experimental-effect-costs.js +1 -1
  179. package/dist/ships/experimental-effects.d.ts +9 -8
  180. package/dist/ships/experimental-effects.js +1 -1
  181. package/dist/ships/heat.d.ts +7 -2
  182. package/dist/ships/heat.js +1 -1
  183. package/dist/ships/index.d.ts +34 -22
  184. package/dist/ships/index.js +1 -1
  185. package/dist/ships/jump-range.d.ts +10 -3
  186. package/dist/ships/jump-range.js +1 -1
  187. package/dist/ships/loadout-calculations.d.ts +1 -1
  188. package/dist/ships/loadout-calculations.js +1 -1
  189. package/dist/ships/mobility-capacitor.d.ts +90 -0
  190. package/dist/ships/mobility-capacitor.js +1 -0
  191. package/dist/ships/mobility-capacitor.js.map +1 -0
  192. package/dist/ships/mobility.d.ts +41 -17
  193. package/dist/ships/mobility.js +1 -1
  194. package/dist/ships/modules-all.js +1 -1
  195. package/dist/ships/modules-core.js +1 -1
  196. package/dist/ships/modules.d.ts +27 -1
  197. package/dist/ships/modules.js +1 -1
  198. package/dist/ships/power.d.ts +12 -5
  199. package/dist/ships/power.js +1 -1
  200. package/dist/ships/pre-engineered-stats.d.ts +10 -8
  201. package/dist/ships/pre-engineered-stats.js +1 -1
  202. package/dist/ships/pre-engineered.d.ts +6 -6
  203. package/dist/ships/pre-engineered.js +1 -1
  204. package/dist/ships/resistances.d.ts +2 -2
  205. package/dist/ships/resistances.js +1 -1
  206. package/dist/ships/shield-capacitor.d.ts +133 -0
  207. package/dist/ships/shield-capacitor.js +1 -0
  208. package/dist/ships/shield-capacitor.js.map +1 -0
  209. package/dist/ships/shield-recovery.d.ts +16 -2
  210. package/dist/ships/shield-recovery.js +1 -1
  211. package/dist/ships/shields.d.ts +86 -28
  212. package/dist/ships/shields.js +1 -1
  213. package/dist/ships/ship-loadout.d.ts +100 -671
  214. package/dist/ships/ship-loadout.js +1 -1
  215. package/dist/ships/ships.d.ts +7 -6
  216. package/dist/ships/ships.js +1 -1
  217. package/dist/ships/slef.d.ts +11 -9
  218. package/dist/ships/slef.js +1 -1
  219. package/dist/ships/source-purchase.d.ts +2 -1
  220. package/dist/ships/source-purchase.js +1 -1
  221. package/dist/ships/weapons-capacitor.d.ts +10 -3
  222. package/dist/ships/weapons-capacitor.js +1 -1
  223. package/dist/ships/weapons.d.ts +22 -6
  224. package/dist/ships/weapons.js +1 -1
  225. package/dist/{system-address-DYsN1qOT.d.ts → system-address-cyJaeZIS.d.ts} +2 -1
  226. package/package.json +17 -2
  227. package/dist/chunk-24INI4U7.js +0 -1
  228. package/dist/chunk-24INI4U7.js.map +0 -1
  229. package/dist/chunk-2FHHMYDC.js +0 -1
  230. package/dist/chunk-2FHHMYDC.js.map +0 -1
  231. package/dist/chunk-2TW4ZBI3.js +0 -1
  232. package/dist/chunk-2TW4ZBI3.js.map +0 -1
  233. package/dist/chunk-2VPVZELZ.js +0 -1
  234. package/dist/chunk-4S6WB7QR.js.map +0 -1
  235. package/dist/chunk-DVL5RBKX.js +0 -1
  236. package/dist/chunk-DVL5RBKX.js.map +0 -1
  237. package/dist/chunk-DYPOL3CI.js.map +0 -1
  238. package/dist/chunk-EXVCRIDP.js +0 -1
  239. package/dist/chunk-EXVCRIDP.js.map +0 -1
  240. package/dist/chunk-FGXWVFN6.js +0 -1
  241. package/dist/chunk-FGXWVFN6.js.map +0 -1
  242. package/dist/chunk-FMPRCYKY.js.map +0 -1
  243. package/dist/chunk-G3265B27.js +0 -1
  244. package/dist/chunk-G3265B27.js.map +0 -1
  245. package/dist/chunk-GQ5GX5TB.js.map +0 -1
  246. package/dist/chunk-IOJXLDJN.js +0 -1
  247. package/dist/chunk-IOJXLDJN.js.map +0 -1
  248. package/dist/chunk-IYU4WLFM.js +0 -1
  249. package/dist/chunk-IYU4WLFM.js.map +0 -1
  250. package/dist/chunk-J42ZXLBL.js.map +0 -1
  251. package/dist/chunk-JPBMRJFC.js.map +0 -1
  252. package/dist/chunk-LJI7VXJD.js +0 -1
  253. package/dist/chunk-LJI7VXJD.js.map +0 -1
  254. package/dist/chunk-OCND33TO.js +0 -1
  255. package/dist/chunk-OCND33TO.js.map +0 -1
  256. package/dist/chunk-P2QOL63K.js +0 -1
  257. package/dist/chunk-P2QOL63K.js.map +0 -1
  258. package/dist/chunk-Q3QCLNVG.js.map +0 -1
  259. package/dist/chunk-QTZPA2FR.js.map +0 -1
  260. package/dist/chunk-RLUS76LZ.js +0 -1
  261. package/dist/chunk-RLUS76LZ.js.map +0 -1
  262. package/dist/chunk-TEOJCBSG.js +0 -1
  263. package/dist/chunk-TEOJCBSG.js.map +0 -1
  264. package/dist/chunk-TMMGS6TC.js +0 -1
  265. package/dist/chunk-TMMGS6TC.js.map +0 -1
  266. package/dist/chunk-W6EPHHTS.js.map +0 -1
  267. package/dist/chunk-Z6XMXMVI.js.map +0 -1
  268. package/dist/chunk-ZNCXENNB.js +0 -1
  269. package/dist/chunk-ZNCXENNB.js.map +0 -1
  270. package/dist/chunk-ZZT2PQZ5.js +0 -1
  271. package/dist/chunk-ZZT2PQZ5.js.map +0 -1
  272. /package/dist/{chunk-6EUVIZAS.js.map → chunk-4QYTVSNR.js.map} +0 -0
  273. /package/dist/{chunk-6EPYVBAX.js.map → chunk-A6OINYNP.js.map} +0 -0
  274. /package/dist/{chunk-VDVFJXX5.js.map → chunk-QY3L5BKN.js.map} +0 -0
@@ -1,25 +1,13 @@
1
1
  import { ModuleEngineering, LoadoutModule, LoadoutEvent, SlefHeader, Slef } from './slef.js';
2
- import { TotalRangeDetails, FrameShiftDriveParams } from './jump-range.js';
3
2
  import { BuildSlot, SlotKind } from './slots.js';
4
- import { EngineeringMaterial } from './engineering.js';
5
- import { OutfittingModule, ProjectileRangeBoundaries } from './modules.js';
6
- import { PowerBudget } from './power.js';
7
- import { HeatMetrics } from './heat.js';
8
- import { ShieldMetrics } from './shields.js';
9
- import { ArmourMetrics } from './armour.js';
10
- import { WeaponMetrics, WeaponTotals } from './weapons.js';
11
- import { AmmunitionCapacity } from './ammunition.js';
12
- import { WeaponsCapacitorMetrics } from './weapons-capacitor.js';
13
- import { DistributorMetrics } from './distributor.js';
14
- import { MobilityMetrics } from './mobility.js';
15
- import { ShieldRecovery, CellBankSummary } from './shield-recovery.js';
3
+ import { OutfittingModule } from './modules.js';
16
4
  import { PreEngineeredVariant } from './pre-engineered.js';
5
+ import { AmmunitionCapacity } from './ammunition.js';
17
6
  import { SourcePurchaseRecord } from './source-purchase.js';
18
- import { FuelCapacity, CalculationResult } from './loadout-calculations.js';
7
+ import { FuelCapacity } from './loadout-calculations.js';
19
8
  import { ModuleFitConstraint, LoadoutIssueParams, LoadoutValidation } from './loadout-validation.js';
20
9
  import './engineering-options.js';
21
10
  import './module-families.js';
22
- import './resistances.js';
23
11
 
24
12
  /**
25
13
  * Immutable fitted-module snapshots returned by {@link ShipLoadout}.
@@ -209,8 +197,7 @@ type LoadoutImportOutcome = {
209
197
  };
210
198
 
211
199
  /**
212
- * {@link ShipLoadout} — a mutable fitted-ship model that both **answers questions**
213
- * about a build and **edits** it.
200
+ * {@link ShipLoadout} — a mutable fitted-ship model that **holds and edits** a build.
214
201
  *
215
202
  * Load one from a SLEF export or a journal `Loadout` event, or start from a
216
203
  * {@link ShipLoadout.default | default} or {@link ShipLoadout.empty | empty} hull, then
@@ -218,9 +205,15 @@ type LoadoutImportOutcome = {
218
205
  * build in place and return `this`; everything a query returns is a deeply frozen
219
206
  * snapshot, so query again after an edit rather than re-reading an earlier value.
220
207
  *
221
- * **Slot keys are matched case-insensitively.** Frontier writes `FrameShiftDrive`, a
222
- * SLEF producer may write `frameshiftdrive`, and both name the same mount. A build's own
223
- * spelling is never rewritten, so re-exporting an import returns it untouched.
208
+ * **What a build *calculates* lives next door.** Jump range, mass, cost, power, heat,
209
+ * mobility, shields, armour and firepower are on
210
+ * {@link ships!BuildMetrics | BuildMetrics}, over the same build:
211
+ * `BuildMetrics.of(build).maxJumpRange()`.
212
+ *
213
+ * **Slot keys are matched case-insensitively, with surrounding whitespace ignored.**
214
+ * Frontier writes `FrameShiftDrive`, a SLEF producer may write `frameshiftdrive`, and
215
+ * both name the same mount. A build's own spelling is never rewritten, so re-exporting
216
+ * an import returns it untouched.
224
217
  *
225
218
  * @remarks
226
219
  * This is the batteries-included ship facade: it carries the complete ship, module,
@@ -231,11 +224,12 @@ type LoadoutImportOutcome = {
231
224
  * ```ts
232
225
  * declare const slefJsonString: string;
233
226
  *
227
+ * import { BuildMetrics } from '@elite-dangerous-almanac/core/ships/build-metrics';
234
228
  * import { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
235
229
  *
236
230
  * // Read a build:
237
231
  * const build = ShipLoadout.fromSlef(slefJsonString);
238
- * build.maxJumpRange(); // -> 89.41 (best single jump, one jump's fuel, no cargo)
232
+ * BuildMetrics.of(build).maxJumpRange(); // -> 89.41 (best single jump, one jump's fuel, no cargo)
239
233
  *
240
234
  * // Assemble one:
241
235
  * import { getModuleBySymbol } from '@elite-dangerous-almanac/core/ships/modules';
@@ -330,13 +324,6 @@ type FixedMountRepairResult = {
330
324
  /** Stable refusal reason. */
331
325
  readonly reason: 'notFixedMount';
332
326
  };
333
- /** Optional mass overrides for a single calculation. */
334
- interface JumpOptions {
335
- /** Finite non-negative fuel load, in tonnes. Defaults to the full main tank. */
336
- readonly fuel?: number;
337
- /** Finite non-negative cargo load, in tonnes. Defaults to `0` (unladen). */
338
- readonly cargo?: number;
339
- }
340
327
  /** Options for {@link ShipLoadout.applyBlueprint}. */
341
328
  interface ApplyBlueprintOptions {
342
329
  /** The blueprint grade, `1`–`5`. */
@@ -347,8 +334,8 @@ interface ApplyBlueprintOptions {
347
334
  * reconstructed from its single reported quality; import its stated modifiers instead.
348
335
  */
349
336
  readonly quality?: number;
350
- /** The experimental (special) effect's Frontier `fdname`, if any. */
351
- readonly experimental?: string;
337
+ /** The experimental (special) effect's Frontier symbol, if any. */
338
+ readonly experimentalEffectSymbol?: string;
352
339
  }
353
340
  /** Stable reason {@link ShipLoadout.setExperimentalEffect} cannot perform an edit. */
354
341
  type ExperimentalEffectMutationCode = 'emptySlot' | 'notEngineered' | 'unknownExperimentalEffect' | 'unsupportedExperimentalEffect' | 'finalArticle' | 'unsupportedEngineering' | 'unidentifiedPreEngineeredVariant' | 'unresolvedModifiers';
@@ -356,17 +343,17 @@ type ExperimentalEffectMutationCode = 'emptySlot' | 'notEngineered' | 'unknownEx
356
343
  interface ExperimentalEffectUpdated {
357
344
  /** Discriminator for an edit that changed the fitted module. */
358
345
  readonly kind: 'updated';
359
- /** Effect id before the edit, or `null` when none was present. */
360
- readonly previousExperimental: string | null;
361
- /** Effect id after the edit, or `null` when it was removed. */
362
- readonly experimental: string | null;
346
+ /** Effect symbol before the edit, or `null` when none was present. */
347
+ readonly previousExperimentalEffectSymbol: string | null;
348
+ /** Effect symbol after the edit, or `null` when it was removed. */
349
+ readonly experimentalEffectSymbol: string | null;
363
350
  }
364
351
  /** Effect-only edit that requested the fitted module's current effect. */
365
352
  interface ExperimentalEffectUnchanged {
366
353
  /** Discriminator for a no-op edit. */
367
354
  readonly kind: 'unchanged';
368
- /** Current effect id, or `null` when none is present. */
369
- readonly experimental: string | null;
355
+ /** Current effect symbol, or `null` when none is present. */
356
+ readonly experimentalEffectSymbol: string | null;
370
357
  }
371
358
  /** Effect-only edit that cannot be performed losslessly. */
372
359
  interface ExperimentalEffectUnsupported {
@@ -390,7 +377,10 @@ interface EngineeringNormalizationUnchanged {
390
377
  interface EngineeringNormalized {
391
378
  /** Discriminator for a successful normalization. */
392
379
  readonly kind: 'normalized';
393
- /** Quality reported by the fitted module before normalization, in `[0, 1)`. */
380
+ /**
381
+ * Quality reported by the fitted module before normalization, in `[0, 1]`. It reads
382
+ * `1` where a completed roll stated no modifiers and this call spelled them out.
383
+ */
394
384
  readonly previousQuality: number;
395
385
  /** Completed engineering quality. Always `1`. */
396
386
  readonly quality: 1;
@@ -406,165 +396,10 @@ interface EngineeringNormalizationUnsupported {
406
396
  }
407
397
  /** Result of {@link ShipLoadout.completeEngineeringGrade}. */
408
398
  type EngineeringNormalizationResult = EngineeringNormalizationUnchanged | EngineeringNormalized | EngineeringNormalizationUnsupported;
409
- /** Options for the defence figures a build reports. */
410
- interface DefenceOptions {
411
- /**
412
- * Pips to the systems capacitor, `0`–`4`, folded into the shield resistances.
413
- * Defaults to `0` for {@link ShipLoadout.shieldMetrics} and `4` for
414
- * {@link ShipLoadout.shieldRecovery}.
415
- */
416
- readonly systemsPips?: number;
417
- }
418
- /** Optional load and ENG allocation for {@link ShipLoadout.mobilityMetrics}. */
419
- interface MobilityOptions extends JumpOptions {
420
- /** Pips assigned to the engines capacitor, `0`–`4`. Defaults to `4`. */
421
- readonly enginesPips?: number;
422
- }
423
- /** A standard fuel-and-cargo condition shared by jump and mobility views. */
424
- type StandardLoad = 'maximum' | 'unladen' | 'laden';
425
- /** Fuel and cargo carried for a {@link StandardLoad}, both in tonnes. */
426
- interface StandardLoadInputs {
427
- /** Main-tank fuel carried, in tonnes. */
428
- readonly fuel: number;
429
- /** Cargo carried, in tonnes. */
430
- readonly cargo: number;
431
- }
432
- /** Optional WEP allocation for {@link ShipLoadout.weaponsCapacitorMetrics}. */
433
- interface WeaponsOptions {
434
- /** Pips assigned to the weapons capacitor, `0`–`4`. Defaults to `4`. */
435
- readonly weaponsPips?: number;
436
- }
437
- /** Optional SYS, ENG and WEP allocations for {@link ShipLoadout.distributorMetrics}. */
438
- interface DistributorOptions {
439
- /** Pips assigned to the systems capacitor, `0`–`4`. Defaults to `4`. */
440
- readonly systemsPips?: number;
441
- /** Pips assigned to the engines capacitor, `0`–`4`. Defaults to `4`. */
442
- readonly enginesPips?: number;
443
- /** Pips assigned to the weapons capacitor, `0`–`4`. Defaults to `4`. */
444
- readonly weaponsPips?: number;
445
- }
446
- /**
447
- * Retail catalogue credits for an assembled build, as {@link ShipLoadout.buildCost} prices it.
448
- */
449
- interface BuildCredits {
450
- /**
451
- * Priced hull and modules together, in credits.
452
- *
453
- * A Mercenary article is bought with Merc Coin and has no credit price at all, but it
454
- * is counted here at the catalogue list price of the stock module it is built on, and
455
- * again in {@link BuildCost.mercCoins} at what it actually cost. Subtract the stock
456
- * module's price to quote credits a shop would really ask.
457
- */
458
- readonly total: number;
459
- /** Bare hull list price in credits. */
460
- readonly hull: number;
461
- /** Sum of every priced fitted module, in credits. A lower bound when `unpriced` is non-empty. */
462
- readonly modules: number;
463
- /**
464
- * Five percent of `total`, truncated to credits: what insurance bills to rebuild the
465
- * fit at catalogue prices. For what a capture said its own rebuy was, read
466
- * {@link ShipLoadout.rebuy}.
467
- */
468
- readonly rebuy: number;
469
- /** Fitted modules that could not be priced from the catalogue. */
470
- readonly unpriced: readonly {
471
- readonly slot: string;
472
- readonly symbol: string;
473
- }[];
474
- }
475
- /**
476
- * What an assembled build costs to own, in all three currencies the game charges for it.
477
- *
478
- * Every figure prices the **current fit** from the catalogues rather than reporting what a
479
- * capture said was paid; for the latter read {@link ShipLoadout.sourcePurchase}.
480
- */
481
- interface BuildCost {
482
- /** Shop credits for the hull and its fitted modules. */
483
- readonly credits: BuildCredits;
484
- /**
485
- * Merc Coin billed by the build: every Mercenary article's shop price plus every
486
- * blueprint's currency cost, including ordinary engineering-menu recipes that charge it.
487
- * A Mercenary article's blueprint is charged only above the grade it was sold at.
488
- */
489
- readonly mercCoins: number;
490
- /**
491
- * What the build's blueprints and experimental effects consume, one entry per distinct
492
- * material, counts summed across modules.
493
- *
494
- * Pre-engineered articles arrive engineered, so only what a player still has to roll on
495
- * top of one is charged. A fixed reward carries no craft recipe at all and contributes
496
- * nothing, and so does a modification whose recipe the catalogues do not price — a
497
- * capture may name a blueprint or effect no registry lists, and an unpriceable
498
- * modification is silently absent rather than reported the way
499
- * {@link BuildCredits.unpriced} reports an unpriceable module.
500
- */
501
- readonly materials: readonly EngineeringMaterial[];
502
- }
503
- /** One fitted weapon and what it does, as {@link ShipLoadout.weaponMetrics} reports it. */
504
- interface FittedWeaponMetrics {
505
- /** The hardpoint's slot key, e.g. `"LargeHardpoint1"`. */
506
- readonly slot: string;
507
- /** The weapon's internal symbol. */
508
- readonly symbol: string;
509
- /** The weapon's display name, e.g. `"Multi-Cannon"`. */
510
- readonly name: string;
511
- /** Whether the weapon is switched on — a disabled weapon is excluded from the totals. */
512
- readonly enabled: boolean;
513
- /** What this weapon does per second, post-engineering. */
514
- readonly metrics: WeaponMetrics;
515
- /**
516
- * How many rounds it holds when fully rearmed, post-engineering — `null` for a laser,
517
- * which carries none. A capacity, not a rearm state: see {@link FittedModule.ammunition}.
518
- */
519
- readonly ammunition: AmmunitionCapacity | null;
520
- /** Maximum effective range in metres, absent when the fitted weapon does not state one. */
521
- readonly maximumRange?: number;
522
- /** Damage-falloff start in metres, absent when the fitted weapon does not state one. */
523
- readonly falloffRange?: number;
524
- /**
525
- * Exact projectile boundary metadata, absent when unavailable. These are not
526
- * effective distances and remain separate from {@link maximumRange} and
527
- * {@link falloffRange}.
528
- */
529
- readonly projectileRange?: ProjectileRangeBoundaries;
530
- /** Armour-piercing rating, absent when unavailable. */
531
- readonly armourPiercing?: number;
532
- }
533
- /** A build's firepower: every fitted weapon, and the totals across the enabled ones. */
534
- interface BuildWeaponMetrics {
535
- /**
536
- * Every fitted weapon in hull slot order. Weapons in unknown or unmapped slots
537
- * follow the known slots in their original source order.
538
- */
539
- readonly weapons: readonly FittedWeaponMetrics[];
540
- /** The additive totals across the **enabled** weapons. */
541
- readonly total: WeaponTotals;
542
- }
543
- /**
544
- * A build's jump ranges at the loads that matter. The three single-jump values and
545
- * each total result's `range` are in light-years.
546
- */
547
- interface JumpRangeSummary {
548
- /**
549
- * Best single jump: no cargo, and only one jump's fuel aboard — the figure the game
550
- * and EDSY label "maximum jump range".
551
- */
552
- readonly max: number;
553
- /** Single jump on a full tank with an empty hold. */
554
- readonly unladen: number;
555
- /** Single jump on a full tank with a full hold. */
556
- readonly laden: number;
557
- /** Summed range and jump count on one jump's fuel, empty hold. */
558
- readonly totalMax: TotalRangeDetails;
559
- /** Summed range and jump count on one full tank, empty hold. */
560
- readonly totalUnladen: TotalRangeDetails;
561
- /** Summed range and jump count on one full tank, full hold. */
562
- readonly totalLaden: TotalRangeDetails;
563
- }
564
399
  /** A blueprint candidate for a module symbol, with its grades and availability route. */
565
400
  interface AvailableBlueprint {
566
- /** The blueprint's Frontier `fdname`, e.g. `"FSD_LongRange"`. */
567
- readonly fdname: string;
401
+ /** The blueprint's Frontier symbol, e.g. `"FSD_LongRange"`. */
402
+ readonly blueprintSymbol: string;
568
403
  /** The grades the blueprint offers, ascending (e.g. `[1, 2, 3, 4, 5]`). */
569
404
  readonly grades: readonly number[];
570
405
  /**
@@ -627,6 +462,46 @@ interface SlefExportOptions extends LoadoutExportOptions {
627
462
  /**
628
463
  * A fitted ship — read a SLEF export, or assemble a hull from scratch.
629
464
  *
465
+ * ## Member index
466
+ *
467
+ * - **Construct** — {@link fromSlef}, {@link fromLoadout}, {@link empty},
468
+ * {@link default}. The constructor is private; every build starts at one of these four.
469
+ * - **Inspect** — {@link shipSymbol}, {@link shipName}, {@link shipIdent},
470
+ * {@link unladenMass}, {@link cargoCapacity}, {@link fuelCapacity}, {@link hullValue},
471
+ * {@link modulesValue}, {@link rebuy}, {@link sourcePurchase}, {@link importOutcomes},
472
+ * {@link slots}, {@link fittedModuleAt}, {@link fittedModules},
473
+ * {@link modulesForSlot}, {@link availableBlueprints},
474
+ * {@link availableExperimentalEffects}, {@link validation | validation()}.
475
+ * - **Edit** — {@link setModule}, {@link removeModule}, {@link repairFixedMount},
476
+ * {@link applyBlueprint}, {@link setExperimentalEffect},
477
+ * {@link completeEngineeringGrade}, {@link setPreEngineeredVariant},
478
+ * {@link clearEngineering}, {@link setModuleEnabled}, {@link setModulePriority}. Each
479
+ * returns `this` unless it reports a result of its own.
480
+ * - **Analyse** — not here. Jump range, mass, cost, power, heat, mobility, shields,
481
+ * armour and firepower live on
482
+ * {@link ships!BuildMetrics | BuildMetrics}, which reads this build:
483
+ * `BuildMetrics.of(build).maxJumpRange()`. The split lets an outfitting editor import
484
+ * the editors without the calculations, and a viewer the calculations without the
485
+ * editors.
486
+ * - **Export** — {@link toLoadoutEvent}, {@link toSlef}, {@link toSlefString}.
487
+ *
488
+ * ## Properties against methods
489
+ *
490
+ * **A property is a fact this build already carries; a method does something.** Every
491
+ * getter above is an identity, an aggregate figure, or what a capture stated — it
492
+ * computes nothing, takes no options, and never throws. Everything that does work is a
493
+ * call: reading the catalogues, enumerating mounts, editing the fit, exporting it, and
494
+ * every figure on {@link ships!BuildMetrics | BuildMetrics}.
495
+ *
496
+ * The rule makes the split predictable, not harmless. Two of those calls take no
497
+ * argument and read like facts — {@link validation | validation()}, which revalidates
498
+ * the whole fit, and {@link fittedModules | fittedModules()}, which allocates and
499
+ * deeply freezes a fresh snapshot on every call — so they are methods by the rule above
500
+ * even though a reader may reach for them as properties. **A forgotten `()` still hands
501
+ * you the function rather than the value**, and in plain JavaScript nothing complains:
502
+ * `build.fittedModules` is a function reference, `build.fittedModules()` is the list.
503
+ * TypeScript catches it; a `.js` consumer will not.
504
+ *
630
505
  * @example
631
506
  * Read a build a player already flies, and ask it what an outfitting screen shows.
632
507
  * Every figure below is one build's — a Krait Phantom explorer. Figures the capture
@@ -634,6 +509,7 @@ interface SlefExportOptions extends LoadoutExportOptions {
634
509
  * describe survives import; the rest are computed from the fit.
635
510
  *
636
511
  * ```ts
512
+ * import { BuildMetrics } from '@elite-dangerous-almanac/core/ships/build-metrics';
637
513
  * import { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
638
514
  * import type { LoadoutEvent } from '@elite-dangerous-almanac/core/ships/slef';
639
515
  *
@@ -646,10 +522,11 @@ interface SlefExportOptions extends LoadoutExportOptions {
646
522
  * build.shipName; // -> 'Jenny Longuet'
647
523
  * build.unladenMass; // -> 388.830017 (tonnes)
648
524
  *
649
- * build.maxJumpRange(); // -> 60.5478 (ly, best single jump)
650
- * build.powerBudget().withinBudget; // -> true
651
- * build.shieldMetrics()?.strength; // -> 743.12 (MJ)
652
- * build.armourMetrics().hitPoints; // -> 307.8
525
+ * const metrics = BuildMetrics.of(build);
526
+ * metrics.maxJumpRange(); // -> 60.5478 (ly, best single jump)
527
+ * metrics.powerBudget().withinBudget; // -> true
528
+ * metrics.shieldMetrics()?.strength; // -> 743.12 (MJ)
529
+ * metrics.armourMetrics().hitPoints; // -> 307.8
653
530
  * ```
654
531
  */
655
532
  declare class ShipLoadout {
@@ -694,7 +571,7 @@ declare class ShipLoadout {
694
571
  * unresolved symbol, a resolved one the mount refuses, and no entry at all are
695
572
  * corrected alike, each keeping the source's `On`, `Priority` and `Health`. A
696
573
  * removable mount may stand empty, so an article *it* refuses stays where the event
697
- * put it and is reported by {@link validation} instead.
574
+ * put it and is reported by {@link validation | validation()} instead.
698
575
  *
699
576
  * Normalization makes the captured aggregates untrustworthy, so they are dropped:
700
577
  * {@link unladenMass}, {@link cargoCapacity} and {@link fuelCapacity} are recomputed
@@ -757,7 +634,7 @@ declare class ShipLoadout {
757
634
  * import { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
758
635
  *
759
636
  * const stock = ShipLoadout.default('SideWinder');
760
- * stock.validation.complete; // -> true
637
+ * stock.validation().complete; // -> true
761
638
  * stock.fittedModuleAt('FrameShiftDrive')?.symbol;
762
639
  * // -> 'Int_Hyperdrive_Size2_Class1'
763
640
  * ```
@@ -803,14 +680,14 @@ declare class ShipLoadout {
803
680
  * unknown — including after an edit or import normalization discarded an import's
804
681
  * figure, since no catalogue records what a replaced module was bought for. Unlike
805
682
  * mass and capacity it is not recomputed from what remains; {@link sourcePurchase}
806
- * keeps the captured figure and {@link buildCost} prices the current fit.
683
+ * keeps the captured figure and {@link ships!BuildMetrics.buildCost | BuildMetrics.buildCost} prices the current fit.
807
684
  */
808
685
  get modulesValue(): number | null;
809
686
  /**
810
687
  * Insurance rebuy cost in credits represented by the build, or `null` if
811
688
  * unknown. Discarded by an edit or by import normalization for the same reason as
812
689
  * {@link modulesValue}, and likewise kept by {@link sourcePurchase};
813
- * {@link buildCost} rebuys the current fit at catalogue prices instead.
690
+ * {@link ships!BuildMetrics.buildCost | BuildMetrics.buildCost} rebuys the current fit at catalogue prices instead.
814
691
  */
815
692
  get rebuy(): number | null;
816
693
  /**
@@ -872,8 +749,10 @@ declare class ShipLoadout {
872
749
  * mounts are filled — every build fills those, so on a build the two answers agree.
873
750
  * Neither question reports import normalization, so read {@link importOutcomes}
874
751
  * beside them.
752
+ *
753
+ * @returns The validation report, recomputed from the current fit on every call.
875
754
  */
876
- get validation(): LoadoutValidation;
755
+ validation(): LoadoutValidation;
877
756
  /**
878
757
  * Frozen point-in-time views of the hull's mounts in outfitting-panel order.
879
758
  *
@@ -930,7 +809,7 @@ declare class ShipLoadout {
930
809
  *
931
810
  * declare const build: ShipLoadout;
932
811
  *
933
- * build.availableBlueprints('FrameShiftDrive').map(({ fdname }) => fdname);
812
+ * build.availableBlueprints('FrameShiftDrive').map(({ blueprintSymbol }) => blueprintSymbol);
934
813
  * ```
935
814
  */
936
815
  availableBlueprints(slotKey: string): readonly AvailableBlueprint[];
@@ -1070,17 +949,17 @@ declare class ShipLoadout {
1070
949
  *
1071
950
  * @param slotKey - The slot whose module to engineer, matched case-insensitively
1072
951
  * (journal spelling).
1073
- * @param fdname - The blueprint recipe's Frontier `fdname`, e.g. `"FSD_LongRange"`.
952
+ * @param blueprintSymbol - The blueprint recipe's Frontier symbol, e.g. `"FSD_LongRange"`.
1074
953
  * @param options - {@link ApplyBlueprintOptions}: `grade` (1–5), optional `quality`
1075
- * (0–1, default 1), and optional `experimental` effect `fdname`. A nullish
954
+ * (0–1, default 1), and optional `experimental` effect symbol. A nullish
1076
955
  * `experimental` means no effect, the same as leaving it out. Each is read once,
1077
956
  * before anything is checked, so an accessor cannot answer the check and the use
1078
957
  * differently.
1079
958
  * @returns `this`, for chaining.
1080
959
  * @throws {RangeError} If the slot is empty, or the blueprint/grade/experimental is
1081
960
  * unknown, or `quality` is outside `[0, 1]`.
1082
- * @throws {TypeError} If `slotKey` or `fdname` is not a string, `options` is not an
1083
- * object, or `options.experimental` carries a value that is not a string — a nullish
961
+ * @throws {TypeError} If `slotKey` or `blueprintSymbol` is not a string, `options` is not an
962
+ * object, or `options.experimentalEffectSymbol` carries a value that is not a string — a nullish
1084
963
  * one is no effect, not a wrong type. Also if the fitted module has no stats to
1085
964
  * engineer, is final and accepts no further engineering, is not offered the blueprint
1086
965
  * by its own menu, is not offered the experimental effect by it, or the id names a
@@ -1090,6 +969,7 @@ declare class ShipLoadout {
1090
969
  * stored as a partial journal modifier block.
1091
970
  * @example
1092
971
  * ```ts
972
+ * import { BuildMetrics } from '@elite-dangerous-almanac/core/ships/build-metrics';
1093
973
  * import { getModuleBySymbol } from '@elite-dangerous-almanac/core/ships/modules';
1094
974
  * import { CORE_MODULES } from '@elite-dangerous-almanac/core/ships/modules-core';
1095
975
  * import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
@@ -1101,12 +981,12 @@ declare class ShipLoadout {
1101
981
  * build.setModule('FrameShiftDrive', fsd)
1102
982
  * .applyBlueprint('FrameShiftDrive', 'FSD_LongRange', {
1103
983
  * grade: 5,
1104
- * experimental: 'special_fsd_heavy',
984
+ * experimentalEffectSymbol: 'special_fsd_heavy',
1105
985
  * });
1106
- * build.maxJumpRange(); // uses the engineered optimal mass
986
+ * BuildMetrics.of(build).maxJumpRange(); // uses the engineered optimal mass
1107
987
  * ```
1108
988
  */
1109
- applyBlueprint(slotKey: string, fdname: string, options: ApplyBlueprintOptions): this;
989
+ applyBlueprint(slotKey: string, blueprintSymbol: string, options: ApplyBlueprintOptions): this;
1110
990
  /**
1111
991
  * Add, replace or remove only the fitted module's experimental effect.
1112
992
  *
@@ -1116,7 +996,7 @@ declare class ShipLoadout {
1116
996
  * leave the build unchanged and return stable structured data.
1117
997
  *
1118
998
  * @param slotKey - The engineered slot, matched case-insensitively.
1119
- * @param experimental - Experimental-effect `fdname`, or `null` to remove the effect.
999
+ * @param experimental - Experimental-effect symbol, or `null` to remove the effect.
1120
1000
  * @returns A frozen result identifying an update, no-op or lossless refusal.
1121
1001
  * @throws {TypeError} If `slotKey` or a non-null `experimental` is not a string.
1122
1002
  * @example
@@ -1138,6 +1018,11 @@ declare class ShipLoadout {
1138
1018
  * reward rebuilds its hand-authored modifiers and optional effect without losing its
1139
1019
  * purchase identity. A refusal never changes the loadout.
1140
1020
  *
1021
+ * A block that names a blueprint and grade but states no `Modifiers` at all is rolled
1022
+ * here too, even at quality `1` — SLEF permits that identity-only shape and Inara
1023
+ * writes it, so a capture of a completed roll would otherwise stay stock. A stated
1024
+ * modifier array, empty or partial, is left alone at quality `1`.
1025
+ *
1141
1026
  * @param slotKey - The engineered slot, matched case-insensitively.
1142
1027
  * @returns A frozen result identifying a normalized, unchanged or unsupported state.
1143
1028
  * @throws {TypeError} If `slotKey` is not a string.
@@ -1181,7 +1066,7 @@ declare class ShipLoadout {
1181
1066
  * import { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
1182
1067
  *
1183
1068
  * const festive = getPreEngineeredVariants('Hpt_FlakMortar_Turret_Medium')
1184
- * .find((variant) => variant.blueprint === 'Decorative_Red')!;
1069
+ * .find((variant) => variant.blueprintSymbol === 'Decorative_Red')!;
1185
1070
  * const build = ShipLoadout.empty('Krait_MkII')
1186
1071
  * .setPreEngineeredVariant('MediumHardpoint1', festive);
1187
1072
  * build.fittedModuleAt('MediumHardpoint1')?.effectiveStats?.damage; // -> 0.34
@@ -1226,7 +1111,7 @@ declare class ShipLoadout {
1226
1111
  *
1227
1112
  * @param slotKey - The slot's journal key, matched case-insensitively.
1228
1113
  * @param priority - The journal's **zero-based** group, `0`–`4`. Note that the
1229
- * outfitting panel — and {@link powerBudget}'s `bands[].priority` — number the same
1114
+ * outfitting panel — and {@link ships!BuildMetrics.powerBudget | BuildMetrics.powerBudget}'s `bands[].priority` — number the same
1230
1115
  * five groups `1`–`5`.
1231
1116
  * @returns `this`, for chaining.
1232
1117
  * @throws {RangeError} If the slot is empty, or `priority` is not an integer in `[0, 4]`.
@@ -1287,462 +1172,6 @@ declare class ShipLoadout {
1287
1172
  * ```
1288
1173
  */
1289
1174
  toSlefString(options: SlefExportOptions): string;
1290
- /**
1291
- * The resolved frame-shift-drive constants for this build — post-engineering,
1292
- * with any Guardian FSD Booster folded into `jumpBoost`.
1293
- *
1294
- * @throws {TypeError} If the fitted drive's record is missing any of its required
1295
- * jump constants.
1296
- */
1297
- get frameShiftDrive(): FrameShiftDriveParams;
1298
- /**
1299
- * The fitted frame shift drive's dimensionless mass factor at a chosen load.
1300
- *
1301
- * @param options - {@link JumpOptions}. `fuel` defaults to a full main tank and
1302
- * `cargo` to `0`.
1303
- * @returns `optMass / loadedMass`: `1` at the drive's optimised mass, below `1`
1304
- * above it and above `1` below it.
1305
- * @remarks
1306
- * This is the mass term used by the jump equation, not the three-point performance
1307
- * curve used by thrusters and shield generators. Main-tank fuel contributes to the
1308
- * loaded mass; the Guardian FSD Booster's additive range does not contribute to the
1309
- * factor.
1310
- * @throws {TypeError} If the build has no usable frame shift drive.
1311
- * @throws {RangeError} If fuel or cargo is not finite and non-negative, or loaded
1312
- * mass is zero.
1313
- * @example
1314
- * ```ts
1315
- * import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
1316
- *
1317
- * declare const build: ShipLoadout;
1318
- * build.frameShiftDriveMassFactor({ fuel: 8, cargo: 32 }); // dimensionless
1319
- * ```
1320
- */
1321
- frameShiftDriveMassFactor(options?: JumpOptions): number;
1322
- /**
1323
- * Best single-jump range, in light-years — no cargo, and exactly one jump's fuel
1324
- * aboard (the lightest the ship jumps). This is the figure the game and EDSY label
1325
- * "maximum jump range".
1326
- *
1327
- * @returns The best single jump, in light-years, or `0` for a capture that states a
1328
- * main tank of `0`.
1329
- * @throws {TypeError} If the build has no usable frame shift drive.
1330
- */
1331
- maxJumpRange(): number;
1332
- /**
1333
- * The range of a single jump for a chosen fuel and cargo load, in light-years.
1334
- *
1335
- * @param options - {@link JumpOptions}. `fuel` defaults to a full main tank,
1336
- * `cargo` to `0`.
1337
- * @returns The jump's range, in light-years.
1338
- * @throws {TypeError} If the build has no usable frame shift drive.
1339
- * @throws {RangeError} If fuel or cargo is not finite and non-negative.
1340
- */
1341
- jumpRange(options?: JumpOptions): number;
1342
- /**
1343
- * Single-jump range on a full tank with a full cargo hold, in light-years.
1344
- *
1345
- * @returns The jump's range, in light-years.
1346
- * @throws {TypeError} If the build has no usable frame shift drive.
1347
- */
1348
- ladenJumpRange(): number;
1349
- /**
1350
- * The fuel a single jump of a given distance costs, in tonnes.
1351
- *
1352
- * @param distance - The jump distance, in light-years.
1353
- * @param options - {@link JumpOptions}. `fuel` defaults to a full main tank,
1354
- * `cargo` to `0`.
1355
- * @returns Fuel used, in tonnes (capped at the drive's max fuel per jump).
1356
- * @throws {TypeError} If the build has no usable frame shift drive.
1357
- * @throws {RangeError} If fuel or cargo is not finite and non-negative.
1358
- */
1359
- fuelPerJump(distance: number, options?: JumpOptions): number;
1360
- /**
1361
- * Total range and jump count for a chosen fuel and cargo load.
1362
- *
1363
- * @param options - {@link JumpOptions}. `fuel` defaults to a full main tank,
1364
- * `cargo` to `0`.
1365
- * @returns Summed range in light-years and the jumps made before the tank is empty.
1366
- * @throws {TypeError} If the build has no usable frame shift drive.
1367
- * @throws {RangeError} If fuel or cargo is not finite and non-negative, or the
1368
- * fuel load would require more than 100,000 jumps.
1369
- * @example
1370
- * ```ts
1371
- * import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
1372
- *
1373
- * declare const build: ShipLoadout;
1374
- * build.totalRange().jumps; // jumps available from one full main tank
1375
- * build.totalRange({ fuel: 8, cargo: 32 }).range; // range for that partial load
1376
- * ```
1377
- */
1378
- totalRange(options?: JumpOptions): TotalRangeDetails;
1379
- /**
1380
- * Resolve one of the package's standard load conditions for jump and mobility views.
1381
- *
1382
- * @param load - `'maximum'` for one jump's fuel and no cargo, `'unladen'` for a
1383
- * full main tank and no cargo, or `'laden'` for a full main tank and full hold.
1384
- * @returns Fuel and cargo in tonnes. Only `'maximum'` can come back incomplete: it
1385
- * validates the whole fitted drive, jump booster included, so a complete one can be
1386
- * passed straight to {@link jumpRange}.
1387
- * @throws {RangeError} If `load` is not a recognised standard load.
1388
- * @example
1389
- * ```ts
1390
- * import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
1391
- *
1392
- * declare const build: ShipLoadout;
1393
- * const load = build.standardLoadResult('maximum');
1394
- * if (load.complete) build.mobilityMetrics({ ...load.value, enginesPips: 2 });
1395
- * ```
1396
- */
1397
- standardLoadResult(load: StandardLoad): CalculationResult<StandardLoadInputs>;
1398
- /**
1399
- * Every jump figure at once — best, unladen, laden, and each load's total.
1400
- *
1401
- * @returns The {@link JumpRangeSummary}. Single-jump figures and each total's
1402
- * `range` are in light-years. For a partial load, call {@link jumpRange} for one
1403
- * jump or {@link totalRange} for every jump with the `fuel` and `cargo` you
1404
- * actually have.
1405
- * @throws {TypeError} If the build has no usable frame shift drive.
1406
- * @example
1407
- * ```ts
1408
- * import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
1409
- *
1410
- * declare const build: ShipLoadout;
1411
- *
1412
- * const jumps = build.jumpRangeSummary();
1413
- * jumps.max; // -> 89.41 (one jump's fuel, empty hold)
1414
- * jumps.laden; // -> the range with the hold full
1415
- * jumps.totalMax.jumps; // the best jump expressed as a total
1416
- * // Half a tank and 32 t aboard:
1417
- * build.jumpRange({ fuel: build.fuelCapacity.main / 2, cargo: 32 });
1418
- * ```
1419
- */
1420
- jumpRangeSummary(): JumpRangeSummary;
1421
- /**
1422
- * The build's power budget: what the plant makes, what the modules draw with
1423
- * hardpoints retracted and deployed, and which priority groups stay lit.
1424
- *
1425
- * Draws are post-engineering, modules switched off in the journal are skipped, and
1426
- * weapons (plus the utility fittings that are not always powered) count only
1427
- * towards the deployed total.
1428
- *
1429
- * @returns The {@link PowerBudget}. `consumers` includes modules with positive
1430
- * draw; passive and zero-draw fittings are absent.
1431
- * @throws {RangeError} If a power capacity or module draw is negative or not finite.
1432
- * @example
1433
- * ```ts
1434
- * import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
1435
- *
1436
- * declare const build: ShipLoadout;
1437
- *
1438
- * const power = build.powerBudget();
1439
- * power.available; // -> 20.4 MW generated
1440
- * power.deployed; // -> 19.02 MW drawn, hardpoints out
1441
- * power.withinBudget; // -> true
1442
- * power.bands[4]?.poweredDeployed; // -> is priority group 5 still lit?
1443
- * ```
1444
- */
1445
- powerBudget(): PowerBudget;
1446
- /**
1447
- * The build's heat: what it idles at, what it runs at flying and jumping, and
1448
- * whether firing everything cooks it.
1449
- *
1450
- * Every figure is post-engineering. The heat a build makes follows what the plant
1451
- * actually feeds, so a module switched off — or one in a priority group the plant
1452
- * cannot keep lit — contributes nothing.
1453
- *
1454
- * @returns The {@link HeatMetrics}, or `null` when the build has no powered power
1455
- * plant.
1456
- * @example
1457
- * ```ts
1458
- * import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
1459
- *
1460
- * declare const build: ShipLoadout;
1461
- *
1462
- * const heat = build.heatMetrics();
1463
- * heat?.idle.gauge; // -> 0.23, i.e. the gauge reads 23%
1464
- * heat?.firingSustained.overheats; // -> false: the guns run cool enough to hold
1465
- * heat?.firingDrained.secondsToOverheat; // -> how long an alpha strike has on an empty WEP
1466
- * ```
1467
- */
1468
- heatMetrics(): HeatMetrics | null;
1469
- /**
1470
- * The build's speed, boost and rotation rates at a chosen load and ENG allocation.
1471
- *
1472
- * @remarks
1473
- * Main-tank fuel contributes to the flight model's loaded mass. Reserve-tank fuel
1474
- * does not: although the statistics panel includes it in the displayed current
1475
- * mass, ten observed builds reproduce their angular rates only when the reserve is
1476
- * excluded from the thruster mass curve.
1477
- *
1478
- * @param options - Fuel defaults to a full main tank, cargo to `0`, and ENG pips to `4`.
1479
- * @returns Loaded {@link MobilityMetrics}, or `null` when no fully described
1480
- * thrusters are powered with hardpoints retracted. Use
1481
- * {@link mobilityMetricsResult} to distinguish the unavailable conditions.
1482
- * @throws {RangeError} If fuel or cargo is not finite and non-negative, or
1483
- * `enginesPips` is outside `[0, 4]`.
1484
- * @example
1485
- * ```ts
1486
- * import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
1487
- *
1488
- * declare const build: ShipLoadout;
1489
- * build.mobilityMetrics({ cargo: 32, fuel: 8, enginesPips: 2 })?.speed; // -> m/s
1490
- * ```
1491
- */
1492
- mobilityMetrics(options?: MobilityOptions): MobilityMetrics | null;
1493
- /**
1494
- * The build's mobility with a diagnostic when its thrusters or retracted power
1495
- * supply is unavailable.
1496
- *
1497
- * @param options - Fuel defaults to a full main tank, cargo to `0`, and ENG pips to `4`.
1498
- * @returns A complete {@link MobilityMetrics} value, otherwise `null` plus the input
1499
- * or fitted-module state that prevented the calculation.
1500
- * @throws {RangeError} If fuel or cargo is not finite and non-negative, or
1501
- * `enginesPips` is outside `[0, 4]`.
1502
- * @example
1503
- * ```ts
1504
- * import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
1505
- *
1506
- * declare const build: ShipLoadout;
1507
- * const result = build.mobilityMetricsResult({ enginesPips: 2 });
1508
- * if (result.complete) result.value.speed; // metres per second
1509
- * else result.issues[0].reason; // unavailable-state discriminator
1510
- * ```
1511
- */
1512
- mobilityMetricsResult(options?: MobilityOptions): CalculationResult<MobilityMetrics>;
1513
- /**
1514
- * The build's shields: strength in megajoules, where it comes from, and the
1515
- * effective resistances.
1516
- *
1517
- * Shield strength scales with the **hull's** mass, not the build's, so fitting
1518
- * more modules never weakens it. Boosters, Guardian shield reinforcement and any
1519
- * engineering are all folded in; switched-off or shed boosters and reinforcement
1520
- * are ignored, while a switched-off or shed generator makes the metric unavailable.
1521
- *
1522
- * @param options - {@link DefenceOptions}. `systemsPips` (0–4) folds the SYS
1523
- * capacitor's own resistance into the reported figures; it defaults to `0`, which
1524
- * is what an outfitting screen shows.
1525
- * @returns The {@link ShieldMetrics}, or `null` when the build has no shield
1526
- * generator powered with hardpoints retracted. Use
1527
- * {@link shieldMetricsResult} to distinguish the unavailable conditions.
1528
- * @throws {RangeError} If `systemsPips` is outside `[0, 4]` or not finite.
1529
- * @example
1530
- * ```ts
1531
- * import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
1532
- *
1533
- * declare const build: ShipLoadout;
1534
- *
1535
- * const shields = build.shieldMetrics();
1536
- * shields?.strength; // -> MJ
1537
- * shields?.resistances.thermal; // -> negative on a stock generator
1538
- * build.shieldMetrics({ systemsPips: 4 })?.resistances.thermal; // -> with 4 pips to SYS
1539
- * ```
1540
- */
1541
- shieldMetrics(options?: DefenceOptions): ShieldMetrics | null;
1542
- /**
1543
- * The build's shields with a diagnostic when its hull, generator or retracted
1544
- * power supply is unavailable.
1545
- *
1546
- * @param options - {@link DefenceOptions}. `systemsPips` defaults to `0`.
1547
- * @returns A complete {@link ShieldMetrics} value, otherwise `null` plus the input
1548
- * or fitted-module state that prevented the calculation.
1549
- * @throws {RangeError} If `systemsPips` is outside `[0, 4]` or not finite.
1550
- * @example
1551
- * ```ts
1552
- * import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
1553
- *
1554
- * declare const build: ShipLoadout;
1555
- * const result = build.shieldMetricsResult();
1556
- * if (result.complete) result.value.strength; // megajoules
1557
- * else result.issues[0].reason; // unavailable-state discriminator
1558
- * ```
1559
- */
1560
- shieldMetricsResult(options?: DefenceOptions): CalculationResult<ShieldMetrics>;
1561
- /**
1562
- * Time for this build's shield to rise after collapse and then regenerate to full.
1563
- *
1564
- * @param options - SYS pips in `[0, 4]`, defaulting to `4`.
1565
- * @returns Recovery rates and seconds, or `null` when no shield generator is powered
1566
- * with hardpoints retracted. Use
1567
- * {@link shieldRecoveryResult} to distinguish the unavailable conditions.
1568
- * Insufficient zero-pip recharge produces `Infinity`.
1569
- * @throws {RangeError} If `systemsPips` is outside `[0, 4]` or not finite.
1570
- * @example
1571
- * ```ts
1572
- * import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
1573
- *
1574
- * declare const build: ShipLoadout;
1575
- * build.shieldRecovery({ systemsPips: 4 })?.recoveryTime; // -> seconds from collapse to 50%
1576
- * ```
1577
- */
1578
- shieldRecovery(options?: DefenceOptions): ShieldRecovery | null;
1579
- /**
1580
- * The build's shield recovery with a diagnostic when its hull, generator or
1581
- * retracted power supply is unavailable.
1582
- *
1583
- * @param options - SYS pips in `[0, 4]`, defaulting to `4`.
1584
- * @returns A complete {@link ShieldRecovery} value, otherwise `null` plus the input
1585
- * or fitted-module state that prevented the calculation.
1586
- * @throws {RangeError} If `systemsPips` is outside `[0, 4]` or not finite.
1587
- * @example
1588
- * ```ts
1589
- * import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
1590
- *
1591
- * declare const build: ShipLoadout;
1592
- * const result = build.shieldRecoveryResult();
1593
- * if (result.complete) result.value.recoveryTime; // seconds
1594
- * else result.issues[0].reason; // unavailable-state discriminator
1595
- * ```
1596
- */
1597
- shieldRecoveryResult(options?: DefenceOptions): CalculationResult<ShieldRecovery>;
1598
- /**
1599
- * Every fitted shield cell bank and the usable rearmed reinforcement pool.
1600
- *
1601
- * Every fitted bank remains in `banks`, where `powered` says whether it is switched
1602
- * on and its priority group is fed with hardpoints deployed. The totals include only
1603
- * those powered banks, so a build whose plant is switched off or outdrawn reports
1604
- * every bank unpowered and zero totals.
1605
- *
1606
- * @returns A frozen {@link CellBankSummary}; no banks is an empty list and zero totals.
1607
- * @example
1608
- * ```ts
1609
- * import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
1610
- *
1611
- * declare const build: ShipLoadout;
1612
- * build.cellBanks().totalRestorable; // -> MJ across every powered fitted cell
1613
- * ```
1614
- */
1615
- cellBanks(): CellBankSummary;
1616
- /**
1617
- * Price the whole build from the catalogues: shop credits, Merc Coin and the
1618
- * engineering materials its modifications consume.
1619
- *
1620
- * No modification is charged twice. A Mercenary article arrives at the grade it was sold at,
1621
- * so only the climb above that grade bills materials and further Merc Coin, and an
1622
- * experimental effect the article came with is free while one added on top is not. A
1623
- * fixed reward article — festive, Guardian, community-goal — identifies a recipe it
1624
- * was never rolled from, so it contributes no materials at all.
1625
- *
1626
- * @returns A frozen {@link BuildCost}. `credits.modules`, `credits.total` and
1627
- * `credits.rebuy` are lower bounds while {@link BuildCredits.unpriced} is non-empty;
1628
- * built-in hull fittings are free rather than unpriced.
1629
- * @remarks
1630
- * This is the one place `ShipLoadout` reads the material and Merc Coin cost
1631
- * catalogues, which is why the facade carries them; import
1632
- * {@link ships/blueprint-costs!getBlueprintCost | getBlueprintCost} and
1633
- * {@link ships/experimental-effect-costs!getExperimentalEffectCost | getExperimentalEffectCost}
1634
- * directly to price one recipe without a build.
1635
- * @example
1636
- * ```ts
1637
- * import { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
1638
- *
1639
- * const build = ShipLoadout.default('Anaconda');
1640
- * build.buildCost().credits.hull; // -> 142456440
1641
- * build.applyBlueprint('FrameShiftDrive', 'FSD_LongRange', { grade: 5 });
1642
- * build.buildCost().materials.find((material) => material.symbol === 'Arsenic')?.count; // -> 5
1643
- * ```
1644
- * @example
1645
- * ```ts
1646
- * import { getPreEngineeredVariants } from '@elite-dangerous-almanac/core/ships/pre-engineered';
1647
- * import { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
1648
- *
1649
- * const variant = getPreEngineeredVariants('Hpt_Railgun_Fixed_Medium')
1650
- * .find((candidate) => candidate.acquisition === 'mercenary')!;
1651
- * const build = ShipLoadout.default('Python')
1652
- * .setPreEngineeredVariant('MediumHardpoint1', variant);
1653
- * build.buildCost().mercCoins; // -> 950
1654
- * ```
1655
- */
1656
- buildCost(): BuildCost;
1657
- /**
1658
- * The build's armour: hull hit points, the bulkhead and reinforcement each
1659
- * contribute, and the effective resistances.
1660
- *
1661
- * @returns The {@link ArmourMetrics}, read off the fitted bulkhead.
1662
- * @example
1663
- * ```ts
1664
- * import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
1665
- *
1666
- * declare const build: ShipLoadout;
1667
- *
1668
- * const hull = build.armourMetrics();
1669
- * hull.hitPoints; // -> total hull points
1670
- * hull.resistances.explosive; // -> lightweight alloy is explosively weak
1671
- * hull.effectiveHitPoints.thermal; // -> thermal damage the hull can soak
1672
- * ```
1673
- */
1674
- armourMetrics(): ArmourMetrics;
1675
- /**
1676
- * The build's firepower: DPS, sustained DPS, weapons-capacitor draw, heat and power
1677
- * draw for every fitted weapon, plus the totals.
1678
- *
1679
- * Every figure is post-engineering. A weapon switched off in the journal is still
1680
- * listed — with its own metrics — but left out of the totals.
1681
- *
1682
- * @returns The {@link BuildWeaponMetrics}.
1683
- * @example
1684
- * ```ts
1685
- * import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
1686
- *
1687
- * declare const build: ShipLoadout;
1688
- *
1689
- * const guns = build.weaponMetrics();
1690
- * guns.total.damagePerSecond; // -> burst DPS across the hardpoints
1691
- * guns.total.sustainedDamagePerSecond; // -> with reloads folded in
1692
- * guns.total.energyPerSecond; // -> MW asked of the WEP capacitor
1693
- * guns.total.powerDraw; // -> MW asked of the power plant when deployed
1694
- * guns.weapons[0]?.metrics.damageByType.thermal;
1695
- * guns.weapons[0]?.maximumRange; // post-engineering metres, when known
1696
- * guns.weapons[0]?.armourPiercing; // post-engineering rating, when known
1697
- * guns.weapons[0]?.ammunition?.total; // -> rounds aboard when fully rearmed
1698
- * ```
1699
- */
1700
- weaponMetrics(): BuildWeaponMetrics;
1701
- /**
1702
- * WEP-capacitor recharge and endurance while every powered weapon fires.
1703
- *
1704
- * @param options - WEP pips in `[0, 4]`, defaulting to `4`.
1705
- * @returns Actual recharge, sustained draw, net drain and seconds from full to
1706
- * empty. The deployed power budget is applied to the distributor and weapons, so a
1707
- * module the plant sheds contributes nothing. With no powered distributor, capacity
1708
- * and recharge are zero. A load that draws no more than recharge reports
1709
- * `Infinity` for `timeToDrain`.
1710
- * @throws {RangeError} If `weaponsPips` is outside `[0, 4]` or not finite.
1711
- * @example
1712
- * ```ts
1713
- * import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
1714
- *
1715
- * declare const build: ShipLoadout;
1716
- * build.weaponsCapacitorMetrics({ weaponsPips: 2 }).timeToDrain; // seconds
1717
- * ```
1718
- */
1719
- weaponsCapacitorMetrics(options?: WeaponsOptions): WeaponsCapacitorMetrics;
1720
- /**
1721
- * All three power-distributor capacitors at selected pip allocations.
1722
- *
1723
- * @param options - SYS, ENG and WEP pips in `[0, 4]`, each defaulting
1724
- * independently to `4`. The allocations need not sum to six, which permits
1725
- * independent comparisons of the three maxima.
1726
- * @returns Capacity, rated four-pip recharge and actual pip-scaled recharge for
1727
- * SYS, ENG and WEP, or `null` when the distributor is switched off, its six
1728
- * capacitor stats cannot be resolved, or the retracted power budget sheds it. That
1729
- * retracted state represents the distributor itself; firing endurance in
1730
- * {@link weaponsCapacitorMetrics} separately applies the deployed state.
1731
- * @throws {RangeError} If any pip allocation is outside `[0, 4]` or not finite.
1732
- * @example
1733
- * ```ts
1734
- * import type { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
1735
- *
1736
- * declare const build: ShipLoadout;
1737
- * const distributor = build.distributorMetrics({
1738
- * systemsPips: 2,
1739
- * enginesPips: 2,
1740
- * weaponsPips: 2,
1741
- * });
1742
- * distributor?.engines.rechargeRate; // MJ/s
1743
- * ```
1744
- */
1745
- distributorMetrics(options?: DistributorOptions): DistributorMetrics | null;
1746
1175
  }
1747
1176
 
1748
- export { type ApplyBlueprintOptions, type AvailableBlueprint, type BuildCost, type BuildCredits, type BuildWeaponMetrics, type DefenceOptions, type DistributorOptions, type EngineeringNormalizationCode, type EngineeringNormalizationResult, type EngineeringNormalizationUnchanged, type EngineeringNormalizationUnsupported, type EngineeringNormalized, type ExperimentalEffectMutationCode, type ExperimentalEffectMutationResult, type ExperimentalEffectUnchanged, type ExperimentalEffectUnsupported, type ExperimentalEffectUpdated, type FittedModule, type FittedWeaponMetrics, type FixedMountRepairResult, type ImmovableReason, type JumpOptions, type JumpRangeSummary, LoadoutEditError, type LoadoutEditErrorCode, type LoadoutExportOptions, type LoadoutImportOutcome, type LoadoutSlot, type MobilityOptions, ShipLoadout, type SlefExportOptions, type StandardLoad, type StandardLoadInputs, type WeaponsOptions };
1177
+ export { type ApplyBlueprintOptions, type AvailableBlueprint, type EngineeringNormalizationCode, type EngineeringNormalizationResult, type EngineeringNormalizationUnchanged, type EngineeringNormalizationUnsupported, type EngineeringNormalized, type ExperimentalEffectMutationCode, type ExperimentalEffectMutationResult, type ExperimentalEffectUnchanged, type ExperimentalEffectUnsupported, type ExperimentalEffectUpdated, type FittedModule, type FixedMountRepairResult, type ImmovableReason, LoadoutEditError, type LoadoutEditErrorCode, type LoadoutExportOptions, type LoadoutImportOutcome, type LoadoutSlot, ShipLoadout, type SlefExportOptions };