@elite-dangerous-almanac/core 0.1.0-beta.1

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