@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
@@ -0,0 +1,1061 @@
1
+ import { FrameShiftDriveParams, TotalRangeDetails } from './jump-range.js';
2
+ import { EngineeringMaterial } from './engineering.js';
3
+ import { ProjectileRangeBoundaries } from './modules.js';
4
+ import { PowerBudget } from './power.js';
5
+ import { HeatMetrics } from './heat.js';
6
+ import { ShieldMetrics } from './shields.js';
7
+ import { ShieldCapacitorMetrics } from './shield-capacitor.js';
8
+ import { ArmourMetrics } from './armour.js';
9
+ import { WeaponMetrics, WeaponTotals } from './weapons.js';
10
+ import { AmmunitionCapacity } from './ammunition.js';
11
+ import { WeaponsCapacitorMetrics } from './weapons-capacitor.js';
12
+ import { DistributorMetrics } from './distributor.js';
13
+ import { ThrusterParams, MobilityMetrics } from './mobility.js';
14
+ import { MobilityCapacitorMetrics } from './mobility-capacitor.js';
15
+ import { ShieldRecovery, CellBankSummary } from './shield-recovery.js';
16
+ import { CalculationResult } from './loadout-calculations.js';
17
+ import { ShipLoadout } from './ship-loadout.js';
18
+ import './slef.js';
19
+ import './engineering-options.js';
20
+ import './module-families.js';
21
+ import './slots.js';
22
+ import './resistances.js';
23
+ import './pre-engineered.js';
24
+ import './source-purchase.js';
25
+ import './loadout-validation.js';
26
+
27
+ /**
28
+ * {@link BuildMetrics} — everything a fitted build can be **asked**, over a
29
+ * {@link ships!ShipLoadout | ShipLoadout} that does the fitting.
30
+ *
31
+ * `ShipLoadout` constructs, inspects and edits a fit. This entry point is the other
32
+ * half: jump range, mass, cost, power, heat, mobility, shields, armour and firepower.
33
+ * They are split so an outfitting editor can import the editing surface without pulling
34
+ * in the analysis surface, and a build viewer can import the analysis without the
35
+ * editors.
36
+ *
37
+ * A view holds the build itself, not a snapshot of it. `ShipLoadout` is mutable, so a
38
+ * view made once keeps answering for the build as it stands — fit a module and ask
39
+ * again.
40
+ *
41
+ * @remarks
42
+ * Every calculation here is also available data-free: `./jump-range`, `./power`,
43
+ * `./heat`, `./mobility`, `./mobility-capacitor`, `./shields`, `./shield-capacitor`,
44
+ * `./shield-recovery`, `./armour`, `./weapons`, `./weapons-capacitor` and
45
+ * `./distributor` each take a plain input object and import no catalogue. This class is the convenience that reads those inputs off a build.
46
+ *
47
+ * **Unavailable metrics come in pairs.** Eight metrics depend on build state that may not
48
+ * be there — no module fitted, a record that does not state a number, a switch turned
49
+ * off, a priority group the plant sheds. Each is offered twice: a nullable method that
50
+ * is the convenience, and a `…Result` companion carrying the same value plus the reason
51
+ * it is unavailable. `standardLoad` / `standardLoadResult` is the same pair for a load
52
+ * condition the fitted drive may not support.
53
+ *
54
+ * @example
55
+ * ```ts
56
+ * import { BuildMetrics } from '@elite-dangerous-almanac/core/ships/build-metrics';
57
+ * import { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
58
+ *
59
+ * const metrics = BuildMetrics.of(ShipLoadout.default('Anaconda'));
60
+ * metrics.powerBudget().withinBudget; // -> true
61
+ * metrics.armourMetrics().hitPoints; // -> 945
62
+ * ```
63
+ *
64
+ * @packageDocumentation
65
+ */
66
+
67
+ /** Optional mass overrides for a single calculation. */
68
+ interface JumpOptions {
69
+ /** Finite non-negative fuel load, in tonnes. Defaults to the full main tank. */
70
+ readonly fuel?: number;
71
+ /** Finite non-negative cargo load, in tonnes. Defaults to `0` (unladen). */
72
+ readonly cargo?: number;
73
+ }
74
+ /**
75
+ * Optional SYS allocation for {@link BuildMetrics.shieldCapacitorMetrics}.
76
+ *
77
+ * @remarks
78
+ * Its own type, rather than one shared with {@link ShieldRecoveryOptions}, because the
79
+ * two answer different questions from the same allocation — resistance here, recharge
80
+ * there — and each is free to document its own rule.
81
+ * {@link BuildMetrics.shieldMetrics} takes no allocation at all: the bare shield is
82
+ * pip-free.
83
+ */
84
+ interface ShieldCapacitorOptions {
85
+ /**
86
+ * Pips to the systems capacitor, `0`–`4`. Defaults to `4` — a full SYS capacitor,
87
+ * the condition the game's own panel quotes. Pass `0` for the bare shield, whose
88
+ * effective figures then equal {@link BuildMetrics.shieldMetrics}.
89
+ */
90
+ readonly systemsPips?: number;
91
+ }
92
+ /**
93
+ * Optional SYS allocation for {@link BuildMetrics.shieldRecovery}.
94
+ *
95
+ * @remarks
96
+ * See {@link ShieldCapacitorOptions} for why recovery has an options type of its own.
97
+ */
98
+ interface ShieldRecoveryOptions {
99
+ /**
100
+ * Pips to the systems capacitor, `0`–`4`, which feed the recovery. Defaults to `4`
101
+ * — a full SYS capacitor, which is the condition the game reports recovery at.
102
+ */
103
+ readonly systemsPips?: number;
104
+ }
105
+ /** Optional load and ENG allocation for {@link BuildMetrics.mobilityCapacitorMetrics}. */
106
+ interface MobilityCapacitorOptions extends JumpOptions {
107
+ /**
108
+ * Pips assigned to the engines capacitor, `0`–`4`. Defaults to `4`, which reproduces
109
+ * {@link BuildMetrics.mobilityMetrics} exactly.
110
+ */
111
+ readonly enginesPips?: number;
112
+ }
113
+ /** A standard fuel-and-cargo condition shared by jump and mobility views. */
114
+ type StandardLoad = 'maximum' | 'unladen' | 'laden';
115
+ /** What a {@link StandardLoad} carries, and what the ship weighs carrying it. */
116
+ interface StandardLoadInputs {
117
+ /** Main-tank fuel carried, in tonnes. */
118
+ readonly fuel: number;
119
+ /** Cargo carried, in tonnes. */
120
+ readonly cargo: number;
121
+ /**
122
+ * What the ship weighs at this load, in tonnes:
123
+ * {@link ships!ShipLoadout.unladenMass | unladenMass} plus `fuel` plus
124
+ * `cargo`.
125
+ *
126
+ * @remarks
127
+ * This is the mass the jump and mobility calculations run on, so it is the figure
128
+ * to show beside them rather than one reassembled by the caller. The reserve tank
129
+ * is **not** in it: the game's statistics panel counts the reserve in the current
130
+ * mass it displays, and neither calculation here does — see
131
+ * {@link BuildMetrics.mobilityMetrics}. Add
132
+ * {@link ships!FuelCapacity.reserve | FuelCapacity.reserve} to
133
+ * match the panel.
134
+ *
135
+ * The extra `fuel` and `cargo` are the load a screen labels; the mass is what they
136
+ * add up to, and passing the whole value back into {@link BuildMetrics.jumpRange} or
137
+ * {@link BuildMetrics.mobilityMetrics} is unaffected by its presence.
138
+ */
139
+ readonly mass: number;
140
+ }
141
+ /** Optional WEP allocation for {@link BuildMetrics.weaponsCapacitorMetrics}. */
142
+ interface WeaponsOptions {
143
+ /** Pips assigned to the weapons capacitor, `0`–`4`. Defaults to `4`. */
144
+ readonly weaponsPips?: number;
145
+ }
146
+ /** Optional SYS, ENG and WEP allocations for {@link BuildMetrics.distributorMetrics}. */
147
+ interface DistributorOptions {
148
+ /** Pips assigned to the systems capacitor, `0`–`4`. Defaults to `4`. */
149
+ readonly systemsPips?: number;
150
+ /** Pips assigned to the engines capacitor, `0`–`4`. Defaults to `4`. */
151
+ readonly enginesPips?: number;
152
+ /** Pips assigned to the weapons capacitor, `0`–`4`. Defaults to `4`. */
153
+ readonly weaponsPips?: number;
154
+ }
155
+ /** Retail catalogue credits for an assembled build, as {@link BuildMetrics.buildCost} prices it. */
156
+ interface BuildCredits {
157
+ /**
158
+ * Priced hull and modules together, in credits.
159
+ *
160
+ * A Mercenary article is bought with Merc Coin and has no credit price at all, but it
161
+ * is counted here at the catalogue list price of the stock module it is built on, and
162
+ * again in {@link BuildCost.mercCoins} at what it actually cost. Subtract the stock
163
+ * module's price to quote credits a shop would really ask.
164
+ */
165
+ readonly total: number;
166
+ /** Bare hull list price in credits. */
167
+ readonly hull: number;
168
+ /** Sum of every priced fitted module, in credits. A lower bound when `unpriced` is non-empty. */
169
+ readonly modules: number;
170
+ /**
171
+ * Five percent of `total`, truncated to credits: what insurance bills to rebuild the
172
+ * fit at catalogue prices. For what a capture said its own rebuy was, read
173
+ * {@link ships!ShipLoadout.rebuy | ShipLoadout.rebuy}.
174
+ */
175
+ readonly rebuy: number;
176
+ /** Fitted modules that could not be priced from the catalogue. */
177
+ readonly unpriced: readonly {
178
+ readonly slot: string;
179
+ readonly symbol: string;
180
+ }[];
181
+ }
182
+ /**
183
+ * What an assembled build costs to own, in all three currencies the game charges for it.
184
+ *
185
+ * Every figure prices the **current fit** from the catalogues rather than reporting what a
186
+ * capture said was paid; for the latter read
187
+ * {@link ships!ShipLoadout.sourcePurchase | ShipLoadout.sourcePurchase}.
188
+ */
189
+ interface BuildCost {
190
+ /** Shop credits for the hull and its fitted modules. */
191
+ readonly credits: BuildCredits;
192
+ /**
193
+ * Merc Coin billed by the build: every Mercenary article's shop price plus every
194
+ * blueprint's currency cost, including ordinary engineering-menu recipes that charge it.
195
+ * A Mercenary article's blueprint is charged only above the grade it was sold at.
196
+ */
197
+ readonly mercCoins: number;
198
+ /**
199
+ * What the build's blueprints and experimental effects consume, one entry per distinct
200
+ * material, counts summed across modules.
201
+ *
202
+ * Pre-engineered articles arrive engineered, so only what a player still has to roll on
203
+ * top of one is charged. A fixed reward carries no craft recipe at all and contributes
204
+ * nothing, and so does a modification whose recipe the catalogues do not price — a
205
+ * capture may name a blueprint or effect no registry lists, and an unpriceable
206
+ * modification is silently absent rather than reported the way
207
+ * {@link BuildCredits.unpriced} reports an unpriceable module.
208
+ */
209
+ readonly materials: readonly EngineeringMaterial[];
210
+ }
211
+ /**
212
+ * What an assembled build weighs, broken down the way {@link BuildMetrics.buildMass}
213
+ * weighs it. Every figure is in tonnes.
214
+ *
215
+ * @remarks
216
+ * The mass counterpart of {@link BuildCredits}, and the same split: what the bare hull
217
+ * contributes, what the fit adds, and the total. `fuel` and `cargo` are the chosen load
218
+ * on top of that, so `total` is the mass the jump and mobility calculations run on.
219
+ */
220
+ interface BuildMass {
221
+ /** Bare hull mass — the {@link ships!Ship.hullMass | hullMass} of the hull being flown. */
222
+ readonly hull: number;
223
+ /**
224
+ * Every fitted module's post-engineering mass, summed.
225
+ *
226
+ * @remarks
227
+ * Lightweight blueprints are already folded in, and the cargo hatch weighs nothing.
228
+ * A fitted record with no mass at all contributes `0` rather than making the total
229
+ * unavailable — mass is the one figure no article can be missing (see
230
+ * {@link ships!ShipLoadout.unladenMass | ShipLoadout.unladenMass}),
231
+ * which is why there is no `unpriced` counterpart to {@link BuildCredits.unpriced}
232
+ * here.
233
+ */
234
+ readonly modules: number;
235
+ /**
236
+ * The ship with an empty tank and no cargo —
237
+ * {@link ships!ShipLoadout.unladenMass | ShipLoadout.unladenMass}.
238
+ *
239
+ * @remarks
240
+ * `hull` and `modules` are always computed from the hull record and the current
241
+ * fit, while this is the build's own unladen mass, which for an unedited import is
242
+ * the figure the **capture** stated. The two agree on anything assembled here; where
243
+ * a capture disagrees with the catalogues, this is the one the jump and mobility
244
+ * calculations use and the decomposition is what the catalogues say it is made of.
245
+ */
246
+ readonly unladen: number;
247
+ /** Main-tank fuel counted, in tonnes. Defaults to a full main tank. */
248
+ readonly fuel: number;
249
+ /** Cargo counted, in tonnes. Defaults to an empty hold. */
250
+ readonly cargo: number;
251
+ /** `unladen + fuel + cargo`: what the ship weighs at the chosen load. */
252
+ readonly total: number;
253
+ }
254
+ /** One fitted weapon and what it does, as {@link BuildMetrics.weaponMetrics} reports it. */
255
+ interface FittedWeaponMetrics {
256
+ /** The hardpoint's slot key, e.g. `"LargeHardpoint1"`. */
257
+ readonly slot: string;
258
+ /** The weapon's internal symbol. */
259
+ readonly symbol: string;
260
+ /** The weapon's display name, e.g. `"Multi-Cannon"`. */
261
+ readonly name: string;
262
+ /** Whether the weapon is switched on — a disabled weapon is excluded from the totals. */
263
+ readonly enabled: boolean;
264
+ /** What this weapon does per second, post-engineering. */
265
+ readonly metrics: WeaponMetrics;
266
+ /**
267
+ * How many rounds it holds when fully rearmed, post-engineering — `null` for a laser,
268
+ * which carries none. A capacity, not a rearm state: see
269
+ * {@link ships!FittedModule.ammunition | FittedModule.ammunition}.
270
+ */
271
+ readonly ammunition: AmmunitionCapacity | null;
272
+ /** Maximum effective range in metres, absent when the fitted weapon does not state one. */
273
+ readonly maximumRange?: number;
274
+ /** Damage-falloff start in metres, absent when the fitted weapon does not state one. */
275
+ readonly falloffRange?: number;
276
+ /**
277
+ * Exact projectile boundary metadata, absent when unavailable. These are not
278
+ * effective distances and remain separate from {@link maximumRange} and
279
+ * {@link falloffRange}.
280
+ */
281
+ readonly projectileRange?: ProjectileRangeBoundaries;
282
+ /** Armour-piercing rating, absent when unavailable. */
283
+ readonly armourPiercing?: number;
284
+ }
285
+ /** A build's firepower: every fitted weapon, and the totals across the enabled ones. */
286
+ interface BuildWeaponMetrics {
287
+ /**
288
+ * Every fitted weapon in hull slot order. Weapons in unknown or unmapped slots
289
+ * follow the known slots in their original source order.
290
+ */
291
+ readonly weapons: readonly FittedWeaponMetrics[];
292
+ /** The additive totals across the **enabled** weapons. */
293
+ readonly total: WeaponTotals;
294
+ }
295
+ /**
296
+ * A build's jump ranges at the loads that matter. The three single-jump values and
297
+ * each total result's `range` are in light-years.
298
+ */
299
+ interface JumpRangeSummary {
300
+ /**
301
+ * Best single jump: no cargo, and only one jump's fuel aboard — the figure the game
302
+ * and EDSY label "maximum jump range".
303
+ */
304
+ readonly max: number;
305
+ /** Single jump on a full tank with an empty hold. */
306
+ readonly unladen: number;
307
+ /** Single jump on a full tank with a full hold. */
308
+ readonly laden: number;
309
+ /** Summed range and jump count on one jump's fuel, empty hold. */
310
+ readonly totalMax: TotalRangeDetails;
311
+ /** Summed range and jump count on one full tank, empty hold. */
312
+ readonly totalUnladen: TotalRangeDetails;
313
+ /** Summed range and jump count on one full tank, full hold. */
314
+ readonly totalLaden: TotalRangeDetails;
315
+ }
316
+ /**
317
+ * Every figure a fitted build can be asked for.
318
+ *
319
+ * ## Member index
320
+ *
321
+ * - **Attach** — {@link of}.
322
+ * - **Jump** — {@link frameShiftDrive}, {@link frameShiftDriveMassFactor},
323
+ * {@link maxJumpRange}, {@link jumpRange}, {@link ladenJumpRange}, {@link fuelPerJump},
324
+ * {@link totalRange}, {@link jumpRangeSummary}, {@link standardLoad},
325
+ * {@link standardLoadResult}.
326
+ * - **Mass and cost** — {@link buildMass}, {@link buildCost}.
327
+ * - **Power and heat** — {@link powerBudget}, {@link heatMetrics},
328
+ * {@link heatMetricsResult}.
329
+ * - **Mobility** — {@link thrusters}, {@link mobilityMetrics},
330
+ * {@link mobilityMetricsResult}, {@link mobilityCapacitorMetrics},
331
+ * {@link mobilityCapacitorMetricsResult}.
332
+ * - **Defence** — {@link armourMetrics}, {@link shieldMetrics},
333
+ * {@link shieldMetricsResult}, {@link shieldCapacitorMetrics},
334
+ * {@link shieldCapacitorMetricsResult}, {@link shieldRecovery},
335
+ * {@link shieldRecoveryResult}, {@link cellBanks}.
336
+ * - **Offence** — {@link weaponMetrics}, {@link weaponsCapacitorMetrics},
337
+ * {@link distributorMetrics}, {@link distributorMetricsResult}.
338
+ *
339
+ * Every member is a method. Nothing here is a fact the fit already carries — each one
340
+ * computes from build state — so there are no properties to confuse with them.
341
+ */
342
+ declare class BuildMetrics {
343
+ #private;
344
+ private constructor();
345
+ /**
346
+ * Attach a metrics view to a build.
347
+ *
348
+ * @param build - The build to read. The view holds it rather than copying it, so
349
+ * later edits are visible to every subsequent call.
350
+ * @returns The view.
351
+ * @throws {TypeError} If `build` is not a {@link ships!ShipLoadout | ShipLoadout}.
352
+ * @example
353
+ * ```ts
354
+ * import { BuildMetrics } from '@elite-dangerous-almanac/core/ships/build-metrics';
355
+ * import { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
356
+ *
357
+ * const build = ShipLoadout.default('Anaconda');
358
+ * const metrics = BuildMetrics.of(build);
359
+ * metrics.buildMass().modules; // -> 664
360
+ * build.removeModule('Slot03_Size6'); // unfit the 40 t shield generator
361
+ * metrics.buildMass().modules; // -> 624, the same view reading the edited build
362
+ * ```
363
+ */
364
+ static of(build: ShipLoadout): BuildMetrics;
365
+ /**
366
+ * The build this view reads.
367
+ *
368
+ * @returns The same {@link ships!ShipLoadout | ShipLoadout} that was
369
+ * passed to {@link of} — the aggregate figures, the slots and the editors are all on
370
+ * it.
371
+ */
372
+ loadout(): ShipLoadout;
373
+ /**
374
+ * The resolved frame-shift-drive constants for this build — post-engineering,
375
+ * with any Guardian FSD Booster folded into `jumpBoost`.
376
+ *
377
+ * @returns The drive's constants.
378
+ * @throws {TypeError} If no frame shift drive is fitted, or the fitted drive's
379
+ * record is missing any of its required jump constants.
380
+ */
381
+ frameShiftDrive(): FrameShiftDriveParams;
382
+ /**
383
+ * The fitted thrusters' post-engineering mass curve, or `null` when the build has
384
+ * none — the thruster counterpart of {@link frameShiftDrive}.
385
+ *
386
+ * @remarks
387
+ * A {@link ships!ThrusterParams | ThrusterParams} carries the three masses the
388
+ * curve is defined over and the multiplier at each, plus the separate `speedCurve`
389
+ * and `rotationCurve` an enhanced-performance thruster refines them with. Pass it
390
+ * straight to
391
+ * {@link ships!thrusterMassCurveMultiplier | thrusterMassCurveMultiplier} for the
392
+ * multiplier at a mass of your own, or read `optMass` and `maxMass` against
393
+ * {@link ships!MobilityMetrics.loadedMass | loadedMass} for where this build sits
394
+ * on the curve.
395
+ *
396
+ * This is the fitted article's curve, so a switched-off or shed thruster still has
397
+ * one; {@link mobilityMetricsResult} is what judges whether the build can use it.
398
+ * It answers `null` rather than throwing — unlike {@link frameShiftDrive}, which the
399
+ * jump equation cannot do without — when no thrusters are fitted or the fitted
400
+ * record carries no complete curve.
401
+ *
402
+ * @example
403
+ * ```ts
404
+ * import { BuildMetrics } from '@elite-dangerous-almanac/core/ships/build-metrics';
405
+ * import { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
406
+ *
407
+ * const metrics = BuildMetrics.of(ShipLoadout.default('Anaconda'));
408
+ * metrics.thrusters()?.optMass; // -> 1440, tonnes
409
+ * metrics.thrusters()?.maxMass; // -> 2160, past which the ship does not move at all
410
+ * ```
411
+ */
412
+ thrusters(): ThrusterParams | null;
413
+ /**
414
+ * The fitted frame shift drive's dimensionless mass factor at a chosen load.
415
+ *
416
+ * @param options - {@link JumpOptions}. `fuel` defaults to a full main tank and
417
+ * `cargo` to `0`.
418
+ * @returns `optMass / loadedMass`: `1` at the drive's optimised mass, below `1`
419
+ * above it and above `1` below it.
420
+ * @remarks
421
+ * This is the mass term used by the jump equation, not the three-point performance
422
+ * curve used by thrusters and shield generators. Main-tank fuel contributes to the
423
+ * loaded mass; the Guardian FSD Booster's additive range does not contribute to the
424
+ * factor.
425
+ * @throws {TypeError} If the build has no usable frame shift drive.
426
+ * @throws {RangeError} If fuel or cargo is not finite and non-negative, or loaded
427
+ * mass is zero.
428
+ * @example
429
+ * ```ts
430
+ * import type { BuildMetrics } from '@elite-dangerous-almanac/core/ships/build-metrics';
431
+ *
432
+ * declare const metrics: BuildMetrics;
433
+ * metrics.frameShiftDriveMassFactor({ fuel: 8, cargo: 32 }); // dimensionless
434
+ * ```
435
+ */
436
+ frameShiftDriveMassFactor(options?: JumpOptions): number;
437
+ /**
438
+ * Best single-jump range, in light-years — no cargo, and exactly one jump's fuel
439
+ * aboard (the lightest the ship jumps). This is the figure the game and EDSY label
440
+ * "maximum jump range".
441
+ *
442
+ * @returns The best single jump, in light-years, or `0` for a capture that states a
443
+ * main tank of `0`.
444
+ * @throws {TypeError} If the build has no usable frame shift drive.
445
+ */
446
+ maxJumpRange(): number;
447
+ /**
448
+ * The range of a single jump for a chosen fuel and cargo load, in light-years.
449
+ *
450
+ * @param options - {@link JumpOptions}. `fuel` defaults to a full main tank,
451
+ * `cargo` to `0`.
452
+ * @returns The jump's range, in light-years.
453
+ * @throws {TypeError} If the build has no usable frame shift drive.
454
+ * @throws {RangeError} If fuel or cargo is not finite and non-negative.
455
+ */
456
+ jumpRange(options?: JumpOptions): number;
457
+ /**
458
+ * Single-jump range on a full tank with a full cargo hold, in light-years.
459
+ *
460
+ * @returns The jump's range, in light-years.
461
+ * @throws {TypeError} If the build has no usable frame shift drive.
462
+ */
463
+ ladenJumpRange(): number;
464
+ /**
465
+ * The fuel a single jump of a given distance costs, in tonnes.
466
+ *
467
+ * @param distance - The jump distance, in light-years.
468
+ * @param options - {@link JumpOptions}. `fuel` defaults to a full main tank,
469
+ * `cargo` to `0`.
470
+ * @returns Fuel used, in tonnes (capped at the drive's max fuel per jump).
471
+ * @throws {TypeError} If the build has no usable frame shift drive.
472
+ * @throws {RangeError} If fuel or cargo is not finite and non-negative.
473
+ */
474
+ fuelPerJump(distance: number, options?: JumpOptions): number;
475
+ /**
476
+ * Total range and jump count for a chosen fuel and cargo load.
477
+ *
478
+ * @param options - {@link JumpOptions}. `fuel` defaults to a full main tank,
479
+ * `cargo` to `0`.
480
+ * @returns Summed range in light-years and the jumps made before the tank is empty.
481
+ * @throws {TypeError} If the build has no usable frame shift drive.
482
+ * @throws {RangeError} If fuel or cargo is not finite and non-negative, or the
483
+ * fuel load would require more than 100,000 jumps.
484
+ * @example
485
+ * ```ts
486
+ * import type { BuildMetrics } from '@elite-dangerous-almanac/core/ships/build-metrics';
487
+ *
488
+ * declare const metrics: BuildMetrics;
489
+ * metrics.totalRange().jumps; // jumps available from one full main tank
490
+ * metrics.totalRange({ fuel: 8, cargo: 32 }).range; // range for that partial load
491
+ * ```
492
+ */
493
+ totalRange(options?: JumpOptions): TotalRangeDetails;
494
+ /**
495
+ * One of the package's standard load conditions, or `null` when the fitted drive
496
+ * cannot support it.
497
+ *
498
+ * @param load - `'maximum'` for one jump's fuel and no cargo, `'unladen'` for a
499
+ * full main tank and no cargo, or `'laden'` for a full main tank and full hold.
500
+ * @returns The fuel and cargo carried and the {@link StandardLoadInputs.mass}, or
501
+ * `null`. Only `'maximum'` can answer `null`: it validates the whole fitted drive,
502
+ * jump booster included, so a non-null one can be passed straight to
503
+ * {@link jumpRange}. Use {@link standardLoadResult} to learn why it is unavailable.
504
+ * @throws {RangeError} If `load` is not a recognised standard load.
505
+ * @example
506
+ * ```ts
507
+ * import { BuildMetrics } from '@elite-dangerous-almanac/core/ships/build-metrics';
508
+ * import { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
509
+ *
510
+ * const metrics = BuildMetrics.of(ShipLoadout.default('Anaconda'));
511
+ * metrics.standardLoad('laden')?.mass; // -> 1210, tonnes with a full tank and hold
512
+ * ```
513
+ */
514
+ standardLoad(load: StandardLoad): StandardLoadInputs | null;
515
+ /**
516
+ * Resolve one of the package's standard load conditions for jump and mobility views.
517
+ *
518
+ * @param load - `'maximum'` for one jump's fuel and no cargo, `'unladen'` for a
519
+ * full main tank and no cargo, or `'laden'` for a full main tank and full hold.
520
+ * @returns The fuel and cargo carried, and the {@link StandardLoadInputs.mass} the
521
+ * ship weighs carrying them, all in tonnes. Only `'maximum'` can come back
522
+ * incomplete: it validates the whole fitted drive, jump booster included, so a
523
+ * complete one can be passed straight to {@link jumpRange}.
524
+ * @throws {RangeError} If `load` is not a recognised standard load.
525
+ * @example
526
+ * ```ts
527
+ * import type { BuildMetrics } from '@elite-dangerous-almanac/core/ships/build-metrics';
528
+ *
529
+ * declare const metrics: BuildMetrics;
530
+ * const load = metrics.standardLoadResult('maximum');
531
+ * if (load.complete) metrics.mobilityCapacitorMetrics({ ...load.value, enginesPips: 2 });
532
+ * ```
533
+ */
534
+ standardLoadResult(load: StandardLoad): CalculationResult<StandardLoadInputs>;
535
+ /**
536
+ * Every jump figure at once — best, unladen, laden, and each load's total.
537
+ *
538
+ * @returns The {@link JumpRangeSummary}. Single-jump figures and each total's
539
+ * `range` are in light-years. For a partial load, call {@link jumpRange} for one
540
+ * jump or {@link totalRange} for every jump with the `fuel` and `cargo` you
541
+ * actually have.
542
+ * @throws {TypeError} If the build has no usable frame shift drive.
543
+ * @example
544
+ * ```ts
545
+ * import type { BuildMetrics } from '@elite-dangerous-almanac/core/ships/build-metrics';
546
+ *
547
+ * declare const metrics: BuildMetrics;
548
+ *
549
+ * const jumps = metrics.jumpRangeSummary();
550
+ * jumps.max; // -> 89.41 (one jump's fuel, empty hold)
551
+ * jumps.laden; // -> the range with the hold full
552
+ * jumps.totalMax.jumps; // the best jump expressed as a total
553
+ * ```
554
+ */
555
+ jumpRangeSummary(): JumpRangeSummary;
556
+ /**
557
+ * Weigh the whole build: the hull, the fitted modules, and the load on top of them.
558
+ *
559
+ * @remarks
560
+ * The mass companion to {@link buildCost}, answering the same question in tonnes
561
+ * that that one answers in credits. Every module's mass is post-engineering, so a
562
+ * Lightweight roll is already in `modules`.
563
+ *
564
+ * The reserve tank is **not** counted. The main tank is the fuel the drive and the
565
+ * flight model see, and it is what {@link jumpRange} and {@link mobilityMetrics}
566
+ * weigh; the game's statistics panel additionally counts the reserve in the current
567
+ * mass it displays, so add
568
+ * {@link ships!ShipLoadout.fuelCapacity | fuelCapacity}`.reserve` to
569
+ * reproduce that reading.
570
+ *
571
+ * @param options - {@link JumpOptions}. `fuel` defaults to a full main tank and
572
+ * `cargo` to `0`, matching {@link jumpRange} and {@link mobilityMetrics}. Pass
573
+ * {@link standardLoad} to weigh one of the standard loads.
574
+ * @returns A frozen {@link BuildMass}, every figure in tonnes.
575
+ * @throws {RangeError} If fuel or cargo is not finite and non-negative.
576
+ * @example
577
+ * ```ts
578
+ * import { BuildMetrics } from '@elite-dangerous-almanac/core/ships/build-metrics';
579
+ * import { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
580
+ *
581
+ * const build = ShipLoadout.default('Anaconda');
582
+ * const mass = BuildMetrics.of(build).buildMass();
583
+ * mass.hull; // -> 400
584
+ * mass.modules; // -> 664
585
+ * mass.total; // -> 1096, a full main tank and an empty hold
586
+ * BuildMetrics.of(build).buildMass({ cargo: build.cargoCapacity }).total; // -> 1210
587
+ * ```
588
+ */
589
+ buildMass(options?: JumpOptions): BuildMass;
590
+ /**
591
+ * Price the whole build from the catalogues: shop credits, Merc Coin and the
592
+ * engineering materials its modifications consume.
593
+ *
594
+ * No modification is charged twice. A Mercenary article arrives at the grade it was sold at,
595
+ * so only the climb above that grade bills materials and further Merc Coin, and an
596
+ * experimental effect the article came with is free while one added on top is not. A
597
+ * fixed reward article — festive, Guardian, community-goal — identifies a recipe it
598
+ * was never rolled from, so it contributes no materials at all.
599
+ *
600
+ * @returns A frozen {@link BuildCost}. `credits.modules`, `credits.total` and
601
+ * `credits.rebuy` are lower bounds while {@link BuildCredits.unpriced} is non-empty;
602
+ * built-in hull fittings are free rather than unpriced.
603
+ * @remarks
604
+ * This is the one place the build metrics read the material and Merc Coin cost
605
+ * catalogues; import
606
+ * {@link ships/blueprint-costs!getBlueprintCost | getBlueprintCost} and
607
+ * {@link ships/experimental-effect-costs!getExperimentalEffectCost | getExperimentalEffectCost}
608
+ * directly to price one recipe without a build.
609
+ * @example
610
+ * ```ts
611
+ * import { BuildMetrics } from '@elite-dangerous-almanac/core/ships/build-metrics';
612
+ * import { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
613
+ *
614
+ * const build = ShipLoadout.default('Anaconda');
615
+ * BuildMetrics.of(build).buildCost().credits.hull; // -> 142456440
616
+ * build.applyBlueprint('FrameShiftDrive', 'FSD_LongRange', { grade: 5 });
617
+ * BuildMetrics.of(build)
618
+ * .buildCost()
619
+ * .materials.find((material) => material.symbol === 'Arsenic')?.count; // -> 5
620
+ * ```
621
+ * @example
622
+ * ```ts
623
+ * import { BuildMetrics } from '@elite-dangerous-almanac/core/ships/build-metrics';
624
+ * import { getPreEngineeredVariants } from '@elite-dangerous-almanac/core/ships/pre-engineered';
625
+ * import { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
626
+ *
627
+ * const variant = getPreEngineeredVariants('Hpt_Railgun_Fixed_Medium')
628
+ * .find((candidate) => candidate.acquisition === 'mercenary')!;
629
+ * const build = ShipLoadout.default('Python')
630
+ * .setPreEngineeredVariant('MediumHardpoint1', variant);
631
+ * BuildMetrics.of(build).buildCost().mercCoins; // -> 950
632
+ * ```
633
+ */
634
+ buildCost(): BuildCost;
635
+ /**
636
+ * The build's power budget: what the plant makes, what the modules draw with
637
+ * hardpoints retracted and deployed, and which priority groups stay lit.
638
+ *
639
+ * Draws are post-engineering, modules switched off in the journal are skipped, and
640
+ * weapons (plus the utility fittings that are not always powered) count only
641
+ * towards the deployed total.
642
+ *
643
+ * @returns The {@link PowerBudget}. `consumers` includes modules with positive
644
+ * draw; passive and zero-draw fittings are absent.
645
+ * @throws {RangeError} If a power capacity or module draw is negative or not finite.
646
+ * @example
647
+ * ```ts
648
+ * import type { BuildMetrics } from '@elite-dangerous-almanac/core/ships/build-metrics';
649
+ *
650
+ * declare const metrics: BuildMetrics;
651
+ *
652
+ * const power = metrics.powerBudget();
653
+ * power.available; // -> 20.4 MW generated
654
+ * power.deployed; // -> 19.02 MW drawn, hardpoints out
655
+ * power.withinBudget; // -> true
656
+ * power.bands[4]?.poweredDeployed; // -> is priority group 5 still lit?
657
+ * ```
658
+ */
659
+ powerBudget(): PowerBudget;
660
+ /**
661
+ * The build's heat: what it idles at, what it runs at flying and jumping, and
662
+ * whether firing everything cooks it.
663
+ *
664
+ * Every figure is post-engineering. The heat a build makes follows what the plant
665
+ * actually feeds, so a module switched off — or one in a priority group the plant
666
+ * cannot keep lit — contributes nothing.
667
+ *
668
+ * @returns The {@link HeatMetrics}, or `null` when the build has no powered power
669
+ * plant whose heat efficiency it can read. Use {@link heatMetricsResult} to
670
+ * distinguish the unavailable conditions.
671
+ * @example
672
+ * ```ts
673
+ * import type { BuildMetrics } from '@elite-dangerous-almanac/core/ships/build-metrics';
674
+ *
675
+ * declare const metrics: BuildMetrics;
676
+ *
677
+ * const heat = metrics.heatMetrics();
678
+ * heat?.idle.gauge; // -> 0.23, i.e. the gauge reads 23%
679
+ * heat?.firingSustained.overheats; // -> false: the guns run cool enough to hold
680
+ * heat?.firingDrained.secondsToOverheat; // -> how long an alpha strike has on an empty WEP
681
+ * ```
682
+ */
683
+ heatMetrics(): HeatMetrics | null;
684
+ /**
685
+ * The build's heat with a diagnostic when its power plant is unavailable.
686
+ *
687
+ * @returns A complete {@link HeatMetrics} value, otherwise `null` plus the fitted
688
+ * power plant's state: `missing` when none is fitted, `disabled` when it is
689
+ * switched off, and `unresolved` when its record does not state a heat efficiency.
690
+ * @example
691
+ * ```ts
692
+ * import type { BuildMetrics } from '@elite-dangerous-almanac/core/ships/build-metrics';
693
+ *
694
+ * declare const metrics: BuildMetrics;
695
+ * const result = metrics.heatMetricsResult();
696
+ * if (result.complete) result.value.idle.gauge; // 0 to 1
697
+ * else result.issues[0].reason; // unavailable-state discriminator
698
+ * ```
699
+ */
700
+ heatMetricsResult(): CalculationResult<HeatMetrics>;
701
+ /**
702
+ * The build's speed, boost and rotation rates at a chosen load and **full ENG**.
703
+ *
704
+ * @remarks
705
+ * Main-tank fuel contributes to the flight model's loaded mass. Reserve-tank fuel
706
+ * does not: although the statistics panel includes it in the displayed current
707
+ * mass, ten observed builds reproduce their angular rates only when the reserve is
708
+ * excluded from the thruster mass curve.
709
+ *
710
+ * These are the four-ENG-pip figures. A **lower** allocation is
711
+ * {@link mobilityCapacitorMetrics}, which owns the pip story the way
712
+ * {@link weaponsCapacitorMetrics} owns WEP's.
713
+ *
714
+ * @param options - Fuel defaults to a full main tank and cargo to `0`.
715
+ * @returns Loaded {@link MobilityMetrics}, or `null` when no fully described
716
+ * thrusters are powered with hardpoints retracted. Use
717
+ * {@link mobilityMetricsResult} to distinguish the unavailable conditions.
718
+ * @throws {RangeError} If fuel or cargo is not finite and non-negative.
719
+ * @example
720
+ * ```ts
721
+ * import type { BuildMetrics } from '@elite-dangerous-almanac/core/ships/build-metrics';
722
+ *
723
+ * declare const metrics: BuildMetrics;
724
+ * metrics.mobilityMetrics({ cargo: 32, fuel: 8 })?.speed; // -> m/s at four ENG pips
725
+ * ```
726
+ */
727
+ mobilityMetrics(options?: JumpOptions): MobilityMetrics | null;
728
+ /**
729
+ * The build's mobility with a diagnostic when its thrusters or retracted power
730
+ * supply is unavailable.
731
+ *
732
+ * @param options - Fuel defaults to a full main tank and cargo to `0`.
733
+ * @returns A complete {@link MobilityMetrics} value, otherwise `null` plus the input
734
+ * or fitted-module state that prevented the calculation.
735
+ * @throws {RangeError} If fuel or cargo is not finite and non-negative.
736
+ * @example
737
+ * ```ts
738
+ * import type { BuildMetrics } from '@elite-dangerous-almanac/core/ships/build-metrics';
739
+ *
740
+ * declare const metrics: BuildMetrics;
741
+ * const result = metrics.mobilityMetricsResult();
742
+ * if (result.complete) result.value.speed; // metres per second
743
+ * else result.issues[0].reason; // unavailable-state discriminator
744
+ * ```
745
+ */
746
+ mobilityMetricsResult(options?: JumpOptions): CalculationResult<MobilityMetrics>;
747
+ /**
748
+ * The build's speed and rotation rates at a chosen load and ENG-pip allocation.
749
+ *
750
+ * Boost is not here: it does not move with the allocation, so it stays on
751
+ * {@link mobilityMetrics} beside the loaded mass and the two curve multipliers these
752
+ * figures share.
753
+ *
754
+ * @param options - {@link MobilityCapacitorOptions}. Fuel defaults to a full main
755
+ * tank, cargo to `0`, and `enginesPips` to `4` — which reproduces
756
+ * {@link mobilityMetrics} exactly.
757
+ * @returns The {@link MobilityCapacitorMetrics}, or `null` when no fully described
758
+ * thrusters are powered with hardpoints retracted. Use
759
+ * {@link mobilityCapacitorMetricsResult} to distinguish the unavailable conditions.
760
+ * @throws {RangeError} If fuel or cargo is not finite and non-negative, or
761
+ * `enginesPips` is outside `[0, 4]`.
762
+ * @example
763
+ * ```ts
764
+ * import { BuildMetrics } from '@elite-dangerous-almanac/core/ships/build-metrics';
765
+ * import { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
766
+ *
767
+ * const metrics = BuildMetrics.of(ShipLoadout.default('SideWinder'));
768
+ * metrics.mobilityCapacitorMetrics({ enginesPips: 0 })?.enginesPips; // -> 0
769
+ * ```
770
+ */
771
+ mobilityCapacitorMetrics(options?: MobilityCapacitorOptions): MobilityCapacitorMetrics | null;
772
+ /**
773
+ * The build's ENG capacitor with a diagnostic when its thrusters or retracted power
774
+ * supply is unavailable.
775
+ *
776
+ * @param options - {@link MobilityCapacitorOptions}.
777
+ * @returns A complete {@link MobilityCapacitorMetrics} value, otherwise `null` plus
778
+ * the input or fitted-module state that prevented the calculation — the same
779
+ * diagnostics {@link mobilityMetricsResult} reports, since the two read one build.
780
+ * @throws {RangeError} If fuel or cargo is not finite and non-negative, or
781
+ * `enginesPips` is outside `[0, 4]`.
782
+ * @example
783
+ * ```ts
784
+ * import { BuildMetrics } from '@elite-dangerous-almanac/core/ships/build-metrics';
785
+ * import { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
786
+ *
787
+ * const grounded = ShipLoadout.default('SideWinder').setModuleEnabled('MainEngines', false);
788
+ * const result = BuildMetrics.of(grounded).mobilityCapacitorMetricsResult();
789
+ * result.issues[0]?.reason; // -> 'disabled'
790
+ * ```
791
+ */
792
+ mobilityCapacitorMetricsResult(options?: MobilityCapacitorOptions): CalculationResult<MobilityCapacitorMetrics>;
793
+ /**
794
+ * The build's shields: strength in megajoules, where it comes from, and the
795
+ * effective resistances.
796
+ *
797
+ * Shield strength scales with the **hull's** mass, not the build's, so fitting
798
+ * more modules never weakens it. Boosters, Guardian shield reinforcement and any
799
+ * engineering are all folded in; switched-off or shed boosters and reinforcement
800
+ * are ignored, while a switched-off or shed generator makes the metric unavailable.
801
+ *
802
+ * These are the **pip-free** figures, which is what an outfitting screen shows. What
803
+ * the SYS capacitor makes of them is {@link shieldCapacitorMetrics}, which owns the
804
+ * pip story the way {@link weaponsCapacitorMetrics} owns WEP's.
805
+ *
806
+ * @returns The {@link ShieldMetrics}, or `null` when the build has no shield
807
+ * generator powered with hardpoints retracted. Use
808
+ * {@link shieldMetricsResult} to distinguish the unavailable conditions.
809
+ * @example
810
+ * ```ts
811
+ * import type { BuildMetrics } from '@elite-dangerous-almanac/core/ships/build-metrics';
812
+ *
813
+ * declare const metrics: BuildMetrics;
814
+ *
815
+ * const shields = metrics.shieldMetrics();
816
+ * shields?.strength; // -> MJ
817
+ * shields?.resistances.thermal; // -> negative on a stock generator
818
+ * metrics.shieldCapacitorMetrics()?.effectiveResistances.thermal; // -> with 4 pips to SYS
819
+ * ```
820
+ */
821
+ shieldMetrics(): ShieldMetrics | null;
822
+ /**
823
+ * The build's shields with a diagnostic when its hull, generator or retracted
824
+ * power supply is unavailable.
825
+ *
826
+ * @returns A complete {@link ShieldMetrics} value, otherwise `null` plus the input
827
+ * or fitted-module state that prevented the calculation.
828
+ * @example
829
+ * ```ts
830
+ * import type { BuildMetrics } from '@elite-dangerous-almanac/core/ships/build-metrics';
831
+ *
832
+ * declare const metrics: BuildMetrics;
833
+ * const result = metrics.shieldMetricsResult();
834
+ * if (result.complete) result.value.strength; // megajoules
835
+ * else result.issues[0].reason; // unavailable-state discriminator
836
+ * ```
837
+ */
838
+ shieldMetricsResult(): CalculationResult<ShieldMetrics>;
839
+ /**
840
+ * The build's SYS capacitor: what the pips hold and recharge, the resistance they
841
+ * add, and what the shields are worth with them folded in.
842
+ *
843
+ * The effective resistances and hit points here are the ones the game's own panel
844
+ * shows while the allocation stands; {@link shieldMetrics} is the bare shield they
845
+ * are built from. Both come from one pass over the build, so a screen showing them
846
+ * side by side need not compute the shield twice.
847
+ *
848
+ * @param options - {@link ShieldCapacitorOptions}. `systemsPips` (0–4) defaults to
849
+ * `4`; at `0` the effective figures equal {@link shieldMetrics}.
850
+ * @returns The {@link ShieldCapacitorMetrics}, or `null` when the build has no
851
+ * shield generator powered with hardpoints retracted, or a fitted distributor does
852
+ * not state its SYS figures. Use {@link shieldCapacitorMetricsResult} to distinguish
853
+ * the unavailable conditions. With no distributor fitted, capacity and recharge are
854
+ * zero — the modelled truth for a build that has no SYS capacitor at all.
855
+ * @throws {RangeError} If `systemsPips` is outside `[0, 4]` or not finite.
856
+ * @example
857
+ * ```ts
858
+ * import { BuildMetrics } from '@elite-dangerous-almanac/core/ships/build-metrics';
859
+ * import { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
860
+ *
861
+ * const metrics = BuildMetrics.of(ShipLoadout.default('SideWinder'));
862
+ * const sys = metrics.shieldCapacitorMetrics({ systemsPips: 4 });
863
+ * sys?.systemsResistance; // -> 0.6
864
+ * // Effective hit points behind those pips, against the shield's weakest type.
865
+ * (sys?.effectiveHitPoints.thermal ?? 0) > (metrics.shieldMetrics()?.strength ?? 0); // -> true
866
+ * ```
867
+ */
868
+ shieldCapacitorMetrics(options?: ShieldCapacitorOptions): ShieldCapacitorMetrics | null;
869
+ /**
870
+ * The build's SYS capacitor with a diagnostic when its generator, retracted power
871
+ * supply or distributor record is unavailable.
872
+ *
873
+ * @param options - {@link ShieldCapacitorOptions}. `systemsPips` defaults to `4`.
874
+ * @returns A complete {@link ShieldCapacitorMetrics} value, otherwise `null` plus
875
+ * the input or fitted-module state that prevented the calculation: the shield
876
+ * diagnostics {@link shieldMetricsResult} reports, plus
877
+ * `powerDistributor`/`unresolved` for a fitted distributor whose record does not
878
+ * state its SYS capacity or recharge.
879
+ * @throws {RangeError} If `systemsPips` is outside `[0, 4]` or not finite.
880
+ * @example
881
+ * ```ts
882
+ * import { BuildMetrics } from '@elite-dangerous-almanac/core/ships/build-metrics';
883
+ * import { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
884
+ *
885
+ * const unshielded = ShipLoadout.default('SideWinder').removeModule('Slot01_Size2');
886
+ * const result = BuildMetrics.of(unshielded).shieldCapacitorMetricsResult();
887
+ * result.issues[0]?.reason; // -> 'missing'
888
+ * ```
889
+ */
890
+ shieldCapacitorMetricsResult(options?: ShieldCapacitorOptions): CalculationResult<ShieldCapacitorMetrics>;
891
+ /**
892
+ * Time for this build's shield to rise after collapse and then regenerate to full.
893
+ *
894
+ * @param options - {@link ShieldRecoveryOptions}. SYS pips in `[0, 4]`, defaulting
895
+ * to `4` — **not** the `0` {@link shieldMetrics} defaults to.
896
+ * @returns Recovery rates and seconds, or `null` when no shield generator is powered
897
+ * with hardpoints retracted. Use
898
+ * {@link shieldRecoveryResult} to distinguish the unavailable conditions.
899
+ * Insufficient zero-pip recharge produces `Infinity`.
900
+ * @throws {RangeError} If `systemsPips` is outside `[0, 4]` or not finite.
901
+ * @example
902
+ * ```ts
903
+ * import type { BuildMetrics } from '@elite-dangerous-almanac/core/ships/build-metrics';
904
+ *
905
+ * declare const metrics: BuildMetrics;
906
+ * metrics.shieldRecovery({ systemsPips: 4 })?.recoveryTime; // -> seconds from collapse to 50%
907
+ * ```
908
+ */
909
+ shieldRecovery(options?: ShieldRecoveryOptions): ShieldRecovery | null;
910
+ /**
911
+ * The build's shield recovery with a diagnostic when its hull, generator or
912
+ * retracted power supply is unavailable.
913
+ *
914
+ * @param options - {@link ShieldRecoveryOptions}. SYS pips in `[0, 4]`, defaulting
915
+ * to `4`.
916
+ * @returns A complete {@link ShieldRecovery} value, otherwise `null` plus the input
917
+ * or fitted-module state that prevented the calculation.
918
+ * @throws {RangeError} If `systemsPips` is outside `[0, 4]` or not finite.
919
+ * @example
920
+ * ```ts
921
+ * import type { BuildMetrics } from '@elite-dangerous-almanac/core/ships/build-metrics';
922
+ *
923
+ * declare const metrics: BuildMetrics;
924
+ * const result = metrics.shieldRecoveryResult();
925
+ * if (result.complete) result.value.recoveryTime; // seconds
926
+ * else result.issues[0].reason; // unavailable-state discriminator
927
+ * ```
928
+ */
929
+ shieldRecoveryResult(options?: ShieldRecoveryOptions): CalculationResult<ShieldRecovery>;
930
+ /**
931
+ * Every fitted shield cell bank and the usable rearmed reinforcement pool.
932
+ *
933
+ * Every fitted bank remains in `banks`, where `powered` says whether it is switched
934
+ * on and its priority group is fed with hardpoints deployed. The totals include only
935
+ * those powered banks, so a build whose plant is switched off or outdrawn reports
936
+ * every bank unpowered and zero totals.
937
+ *
938
+ * @returns A frozen {@link CellBankSummary}; no banks is an empty list and zero totals.
939
+ * @example
940
+ * ```ts
941
+ * import type { BuildMetrics } from '@elite-dangerous-almanac/core/ships/build-metrics';
942
+ *
943
+ * declare const metrics: BuildMetrics;
944
+ * metrics.cellBanks().totalRestorable; // -> MJ across every powered fitted cell
945
+ * ```
946
+ */
947
+ cellBanks(): CellBankSummary;
948
+ /**
949
+ * The build's armour: hull hit points, the bulkhead and reinforcement each
950
+ * contribute, and the effective resistances.
951
+ *
952
+ * @returns The {@link ArmourMetrics}, read off the fitted bulkhead.
953
+ * @example
954
+ * ```ts
955
+ * import type { BuildMetrics } from '@elite-dangerous-almanac/core/ships/build-metrics';
956
+ *
957
+ * declare const metrics: BuildMetrics;
958
+ *
959
+ * const hull = metrics.armourMetrics();
960
+ * hull.hitPoints; // -> total hull points
961
+ * hull.resistances.explosive; // -> lightweight alloy is explosively weak
962
+ * hull.effectiveHitPoints.thermal; // -> thermal damage the hull can soak
963
+ * ```
964
+ */
965
+ armourMetrics(): ArmourMetrics;
966
+ /**
967
+ * The build's firepower: DPS, sustained DPS, weapons-capacitor draw, heat and power
968
+ * draw for every fitted weapon, plus the totals.
969
+ *
970
+ * Every figure is post-engineering. A weapon switched off in the journal is still
971
+ * listed — with its own metrics — but left out of the totals.
972
+ *
973
+ * @returns The {@link BuildWeaponMetrics}.
974
+ * @example
975
+ * ```ts
976
+ * import type { BuildMetrics } from '@elite-dangerous-almanac/core/ships/build-metrics';
977
+ *
978
+ * declare const metrics: BuildMetrics;
979
+ *
980
+ * const guns = metrics.weaponMetrics();
981
+ * guns.total.damagePerSecond; // -> burst DPS across the hardpoints
982
+ * guns.total.sustainedDamagePerSecond; // -> with reloads folded in
983
+ * guns.total.energyPerSecond; // -> MW asked of the WEP capacitor
984
+ * guns.total.powerDraw; // -> MW asked of the power plant when deployed
985
+ * guns.weapons[0]?.metrics.damageByType.thermal;
986
+ * guns.weapons[0]?.maximumRange; // post-engineering metres, when known
987
+ * guns.weapons[0]?.armourPiercing; // post-engineering rating, when known
988
+ * guns.weapons[0]?.ammunition?.total; // -> rounds aboard when fully rearmed
989
+ * ```
990
+ */
991
+ weaponMetrics(): BuildWeaponMetrics;
992
+ /**
993
+ * WEP-capacitor recharge and endurance while every powered weapon fires.
994
+ *
995
+ * @param options - WEP pips in `[0, 4]`, defaulting to `4`.
996
+ * @returns Actual recharge, sustained draw, net drain and seconds from full to
997
+ * empty. The deployed power budget is applied to the distributor and weapons, so a
998
+ * module the plant sheds contributes nothing. With no powered distributor, capacity
999
+ * and recharge are zero. A load that draws no more than recharge reports
1000
+ * `Infinity` for `timeToDrain`.
1001
+ * @throws {RangeError} If `weaponsPips` is outside `[0, 4]` or not finite.
1002
+ * @example
1003
+ * ```ts
1004
+ * import type { BuildMetrics } from '@elite-dangerous-almanac/core/ships/build-metrics';
1005
+ *
1006
+ * declare const metrics: BuildMetrics;
1007
+ * metrics.weaponsCapacitorMetrics({ weaponsPips: 2 }).timeToDrain; // seconds
1008
+ * ```
1009
+ */
1010
+ weaponsCapacitorMetrics(options?: WeaponsOptions): WeaponsCapacitorMetrics;
1011
+ /**
1012
+ * All three power-distributor capacitors at selected pip allocations.
1013
+ *
1014
+ * @param options - SYS, ENG and WEP pips in `[0, 4]`, each defaulting
1015
+ * independently to `4`. The allocations need not sum to six, which permits
1016
+ * independent comparisons of the three maxima.
1017
+ * @returns Capacity, rated four-pip recharge and actual pip-scaled recharge for
1018
+ * SYS, ENG and WEP, or `null` when the distributor is not fitted, switched off,
1019
+ * shed by the retracted power budget, or its six capacitor stats cannot be
1020
+ * resolved. Use {@link distributorMetricsResult} to distinguish those four. That
1021
+ * retracted state represents the distributor itself; firing endurance in
1022
+ * {@link weaponsCapacitorMetrics} separately applies the deployed state.
1023
+ * @throws {RangeError} If any pip allocation is outside `[0, 4]` or not finite.
1024
+ * @example
1025
+ * ```ts
1026
+ * import type { BuildMetrics } from '@elite-dangerous-almanac/core/ships/build-metrics';
1027
+ *
1028
+ * declare const metrics: BuildMetrics;
1029
+ * const distributor = metrics.distributorMetrics({
1030
+ * systemsPips: 2,
1031
+ * enginesPips: 2,
1032
+ * weaponsPips: 2,
1033
+ * });
1034
+ * distributor?.engines.rechargeRate; // MJ/s
1035
+ * ```
1036
+ */
1037
+ distributorMetrics(options?: DistributorOptions): DistributorMetrics | null;
1038
+ /**
1039
+ * The build's distributor with a diagnostic when it is unavailable.
1040
+ *
1041
+ * @param options - SYS, ENG and WEP pips in `[0, 4]`, each defaulting to `4`.
1042
+ * @returns A complete {@link DistributorMetrics} value, otherwise `null` plus the
1043
+ * fitted distributor's state: `missing` when none is fitted, `disabled` when it is
1044
+ * switched off, `shed` when the retracted power budget does not feed it, and
1045
+ * `unresolved` when its record does not state all six capacitor figures.
1046
+ * @throws {RangeError} If any pip allocation is outside `[0, 4]` or not finite.
1047
+ * @example
1048
+ * ```ts
1049
+ * import { BuildMetrics } from '@elite-dangerous-almanac/core/ships/build-metrics';
1050
+ * import { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
1051
+ *
1052
+ * const build = ShipLoadout.default('Anaconda').setModuleEnabled('PowerDistributor', false);
1053
+ * const result = BuildMetrics.of(build).distributorMetricsResult();
1054
+ * result.complete; // -> false
1055
+ * result.issues[0]?.reason; // -> 'disabled'
1056
+ * ```
1057
+ */
1058
+ distributorMetricsResult(options?: DistributorOptions): CalculationResult<DistributorMetrics>;
1059
+ }
1060
+
1061
+ export { type BuildCost, type BuildCredits, type BuildMass, BuildMetrics, type BuildWeaponMetrics, type DistributorOptions, type FittedWeaponMetrics, type JumpOptions, type JumpRangeSummary, type MobilityCapacitorOptions, type ShieldCapacitorOptions, type ShieldRecoveryOptions, type StandardLoad, type StandardLoadInputs, type WeaponsOptions };