@elite-dangerous-almanac/core 0.2.0 → 0.2.2

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 (206) hide show
  1. package/PROVENANCE/ships/SOURCES.md +23 -0
  2. package/README.md +3 -2
  3. package/THIRD_PARTY_NOTICES.md +24 -2
  4. package/dist/astro/body-orbit.d.ts +174 -0
  5. package/dist/astro/body-orbit.js +1 -0
  6. package/dist/astro/body-orbit.js.map +1 -0
  7. package/dist/astro/body-physics.d.ts +228 -0
  8. package/dist/astro/body-physics.js +1 -0
  9. package/dist/astro/body-physics.js.map +1 -0
  10. package/dist/astro/body-rings.d.ts +223 -0
  11. package/dist/astro/body-rings.js +1 -0
  12. package/dist/astro/body-rings.js.map +1 -0
  13. package/dist/astro/codex-region-lookup.js +1 -1
  14. package/dist/astro/codex-region-lookup.js.map +1 -1
  15. package/dist/astro/index.d.ts +38 -1
  16. package/dist/astro/index.js +1 -1
  17. package/dist/astro/nebulae.d.ts +4 -4
  18. package/dist/astro/procedural-system.js +1 -1
  19. package/dist/astro/star-physics.d.ts +255 -0
  20. package/dist/astro/star-physics.js +1 -0
  21. package/dist/astro/star-physics.js.map +1 -0
  22. package/dist/body-scan-CEUYjCfH.d.ts +416 -0
  23. package/dist/chunk-37JIMWLK.js +1 -0
  24. package/dist/chunk-37JIMWLK.js.map +1 -0
  25. package/dist/{chunk-PA5EITW5.js → chunk-3LZXB2MC.js} +1 -1
  26. package/dist/{chunk-PA5EITW5.js.map → chunk-3LZXB2MC.js.map} +1 -1
  27. package/dist/chunk-3RTUSDQF.js +1 -0
  28. package/dist/chunk-3RTUSDQF.js.map +1 -0
  29. package/dist/chunk-4CBMQULR.js +1 -0
  30. package/dist/{chunk-4ZGUSHTP.js.map → chunk-4CBMQULR.js.map} +1 -1
  31. package/dist/{chunk-GZYPQIO2.js → chunk-4OTQBHQL.js} +1 -1
  32. package/dist/chunk-4OTQBHQL.js.map +1 -0
  33. package/dist/{chunk-QTAMQ6ME.js → chunk-5VWACBTN.js} +1 -1
  34. package/dist/chunk-65FZECUX.js +1 -0
  35. package/dist/chunk-65FZECUX.js.map +1 -0
  36. package/dist/chunk-6BFQIYGZ.js +1 -0
  37. package/dist/chunk-6BFQIYGZ.js.map +1 -0
  38. package/dist/chunk-6HA2YIKW.js +1 -0
  39. package/dist/chunk-6HA2YIKW.js.map +1 -0
  40. package/dist/{chunk-7EE5VIHR.js → chunk-6HMIF2RJ.js} +1 -1
  41. package/dist/chunk-6WTUY6ZX.js +1 -0
  42. package/dist/{chunk-V3AEUBHV.js.map → chunk-6WTUY6ZX.js.map} +1 -1
  43. package/dist/chunk-77TT4K53.js +1 -0
  44. package/dist/{chunk-MRTTQYT5.js → chunk-7EWZGDWY.js} +1 -1
  45. package/dist/{chunk-TBZJIQ5P.js → chunk-7TVFV3VO.js} +1 -1
  46. package/dist/chunk-7TVFV3VO.js.map +1 -0
  47. package/dist/chunk-7ZERP4TB.js +1 -0
  48. package/dist/{chunk-QY3L5BKN.js.map → chunk-7ZERP4TB.js.map} +1 -1
  49. package/dist/{chunk-Y6KJJMIM.js → chunk-A4QKXXZD.js} +1 -1
  50. package/dist/{chunk-Q5XOGATC.js → chunk-AIEC3LBT.js} +1 -1
  51. package/dist/chunk-B5VTFOK4.js +1 -0
  52. package/dist/chunk-B5VTFOK4.js.map +1 -0
  53. package/dist/chunk-DAQ3PJ4R.js +1 -0
  54. package/dist/chunk-DAQ3PJ4R.js.map +1 -0
  55. package/dist/{chunk-JGOAQLYW.js → chunk-F44QX47A.js} +1 -1
  56. package/dist/{chunk-EVJ32UF3.js → chunk-FA5JVXVG.js} +1 -1
  57. package/dist/{chunk-EVJ32UF3.js.map → chunk-FA5JVXVG.js.map} +1 -1
  58. package/dist/chunk-GBTCWNO6.js +1 -0
  59. package/dist/chunk-GBTCWNO6.js.map +1 -0
  60. package/dist/chunk-GGQMIQPC.js +1 -0
  61. package/dist/chunk-GGQMIQPC.js.map +1 -0
  62. package/dist/{chunk-EYGVDJ2I.js → chunk-GMTAFUAG.js} +1 -1
  63. package/dist/{chunk-Z43DN4PY.js → chunk-GTEHRZPN.js} +1 -1
  64. package/dist/{chunk-Z43DN4PY.js.map → chunk-GTEHRZPN.js.map} +1 -1
  65. package/dist/{chunk-HKXXFIRI.js → chunk-ITKZKREP.js} +1 -1
  66. package/dist/{chunk-OYR5HUQZ.js → chunk-IWFQ4ZKF.js} +1 -1
  67. package/dist/{chunk-ZCEAPJDH.js → chunk-J7BM5NGK.js} +1 -1
  68. package/dist/chunk-JMAXSXXQ.js +1 -0
  69. package/dist/chunk-JMAXSXXQ.js.map +1 -0
  70. package/dist/chunk-JO52LYO3.js +1 -0
  71. package/dist/chunk-M2TCZKRT.js +1 -0
  72. package/dist/chunk-M2TCZKRT.js.map +1 -0
  73. package/dist/chunk-M4FZRDAH.js +1 -0
  74. package/dist/chunk-M4FZRDAH.js.map +1 -0
  75. package/dist/chunk-NEXDA73Y.js +1 -0
  76. package/dist/chunk-NEXDA73Y.js.map +1 -0
  77. package/dist/chunk-OJC6AUL7.js +1 -0
  78. package/dist/chunk-OJC6AUL7.js.map +1 -0
  79. package/dist/chunk-P2MUFVJC.js +1 -0
  80. package/dist/chunk-P2MUFVJC.js.map +1 -0
  81. package/dist/{chunk-FYVPZBXN.js → chunk-Q5ALV3DI.js} +1 -1
  82. package/dist/{chunk-SQS7672E.js → chunk-Q6YDPREF.js} +1 -1
  83. package/dist/chunk-SS6XK336.js +1 -0
  84. package/dist/chunk-SS6XK336.js.map +1 -0
  85. package/dist/{chunk-OVUHQEH5.js → chunk-T4MKUKYS.js} +1 -1
  86. package/dist/{chunk-OVUHQEH5.js.map → chunk-T4MKUKYS.js.map} +1 -1
  87. package/dist/chunk-TMXKC6JL.js +1 -0
  88. package/dist/chunk-TMXKC6JL.js.map +1 -0
  89. package/dist/{chunk-XUHAPOM6.js → chunk-VEEBJFJ7.js} +1 -1
  90. package/dist/{chunk-L747RVPO.js → chunk-VQJXRPYI.js} +1 -1
  91. package/dist/{chunk-L747RVPO.js.map → chunk-VQJXRPYI.js.map} +1 -1
  92. package/dist/chunk-VTMCSCXV.js +1 -0
  93. package/dist/chunk-VTMCSCXV.js.map +1 -0
  94. package/dist/chunk-XQJERZUS.js +1 -0
  95. package/dist/chunk-XQJERZUS.js.map +1 -0
  96. package/dist/chunk-ZZ376WHL.js +1 -0
  97. package/dist/chunk-ZZ376WHL.js.map +1 -0
  98. package/dist/commodities/commodities-all.js +1 -1
  99. package/dist/commodities/commodities-rare.js +1 -1
  100. package/dist/commodities/commodities-standard.js +1 -1
  101. package/dist/commodities/commodities.d.ts +1 -1
  102. package/dist/commodities/commodities.js +1 -1
  103. package/dist/commodities/index.js +1 -1
  104. package/dist/equipment/index.js +1 -1
  105. package/dist/equipment/upgrade-costs.js +1 -1
  106. package/dist/equipment/upgrade-costs.js.map +1 -1
  107. package/dist/i18n/index.js +1 -1
  108. package/dist/materials/index.js +1 -1
  109. package/dist/materials/materials-all.js +1 -1
  110. package/dist/materials/materials-encoded.js +1 -1
  111. package/dist/materials/materials-manufactured.js +1 -1
  112. package/dist/materials/materials-raw.js +1 -1
  113. package/dist/materials/materials.d.ts +1 -1
  114. package/dist/materials/materials.js +1 -1
  115. package/dist/materials/micro-resources-all.js +1 -1
  116. package/dist/materials/micro-resources.d.ts +1 -1
  117. package/dist/materials/micro-resources.js +1 -1
  118. package/dist/ships/armour.js +1 -1
  119. package/dist/ships/build-metrics.d.ts +21 -232
  120. package/dist/ships/build-metrics.js +1 -1
  121. package/dist/ships/distributor.d.ts +1 -1
  122. package/dist/ships/distributor.js +1 -1
  123. package/dist/ships/heat.d.ts +1 -1
  124. package/dist/ships/heat.js +1 -1
  125. package/dist/ships/index.d.ts +3 -3
  126. package/dist/ships/index.js +1 -1
  127. package/dist/ships/jump-range.js +1 -1
  128. package/dist/ships/loadout-calculations.d.ts +2 -2
  129. package/dist/ships/loadout-validation.d.ts +111 -5
  130. package/dist/ships/loadout-validation.js +1 -1
  131. package/dist/ships/mobility-capacitor.d.ts +1 -1
  132. package/dist/ships/mobility-capacitor.js +1 -1
  133. package/dist/ships/mobility.js +1 -1
  134. package/dist/ships/modules-all.js +1 -1
  135. package/dist/ships/modules-core.js +1 -1
  136. package/dist/ships/modules-internal.js +1 -1
  137. package/dist/ships/modules.d.ts +21 -1
  138. package/dist/ships/modules.js +1 -1
  139. package/dist/ships/power.js +1 -1
  140. package/dist/ships/pre-engineered-stats.d.ts +17 -10
  141. package/dist/ships/pre-engineered-stats.js +1 -1
  142. package/dist/ships/resistances.js +1 -1
  143. package/dist/ships/shield-capacitor.d.ts +1 -1
  144. package/dist/ships/shield-capacitor.js +1 -1
  145. package/dist/ships/shield-recovery.js +1 -1
  146. package/dist/ships/shields.d.ts +1 -1
  147. package/dist/ships/shields.js +1 -1
  148. package/dist/ships/ship-loadout.d.ts +140 -18
  149. package/dist/ships/ship-loadout.js +1 -1
  150. package/dist/ships/slef.d.ts +4 -1
  151. package/dist/ships/slef.js +1 -1
  152. package/dist/ships/weapons-capacitor.js +1 -1
  153. package/dist/ships/weapons.js +1 -1
  154. package/package.json +18 -3
  155. package/dist/chunk-4KJ7CR74.js +0 -1
  156. package/dist/chunk-4KJ7CR74.js.map +0 -1
  157. package/dist/chunk-4ZGUSHTP.js +0 -1
  158. package/dist/chunk-6L56LWTT.js +0 -1
  159. package/dist/chunk-6L56LWTT.js.map +0 -1
  160. package/dist/chunk-6O4NRRSB.js +0 -1
  161. package/dist/chunk-6O4NRRSB.js.map +0 -1
  162. package/dist/chunk-7TQ2X6Q3.js +0 -1
  163. package/dist/chunk-7TQ2X6Q3.js.map +0 -1
  164. package/dist/chunk-B4ZSTOM4.js +0 -1
  165. package/dist/chunk-B4ZSTOM4.js.map +0 -1
  166. package/dist/chunk-D6YEHR5S.js +0 -1
  167. package/dist/chunk-D6YEHR5S.js.map +0 -1
  168. package/dist/chunk-EVW4Z4CB.js +0 -1
  169. package/dist/chunk-EVW4Z4CB.js.map +0 -1
  170. package/dist/chunk-GVNTKCVF.js +0 -1
  171. package/dist/chunk-GVNTKCVF.js.map +0 -1
  172. package/dist/chunk-GZYPQIO2.js.map +0 -1
  173. package/dist/chunk-JQG4C67D.js +0 -1
  174. package/dist/chunk-OYFMHDYT.js +0 -1
  175. package/dist/chunk-OYFMHDYT.js.map +0 -1
  176. package/dist/chunk-PY5L6WC5.js +0 -1
  177. package/dist/chunk-PY5L6WC5.js.map +0 -1
  178. package/dist/chunk-Q2L75GSI.js +0 -1
  179. package/dist/chunk-Q2L75GSI.js.map +0 -1
  180. package/dist/chunk-QJ7GB6FF.js +0 -1
  181. package/dist/chunk-QJ7GB6FF.js.map +0 -1
  182. package/dist/chunk-QY3L5BKN.js +0 -1
  183. package/dist/chunk-RRYBSAPX.js +0 -1
  184. package/dist/chunk-RRYBSAPX.js.map +0 -1
  185. package/dist/chunk-TBZJIQ5P.js.map +0 -1
  186. package/dist/chunk-V3AEUBHV.js +0 -1
  187. package/dist/chunk-V4C6FIE2.js +0 -1
  188. package/dist/chunk-VYDQHPY2.js +0 -1
  189. package/dist/chunk-VYDQHPY2.js.map +0 -1
  190. package/dist/chunk-YXPZ7QQB.js +0 -1
  191. package/dist/chunk-YXPZ7QQB.js.map +0 -1
  192. /package/dist/{chunk-QTAMQ6ME.js.map → chunk-5VWACBTN.js.map} +0 -0
  193. /package/dist/{chunk-7EE5VIHR.js.map → chunk-6HMIF2RJ.js.map} +0 -0
  194. /package/dist/{chunk-JQG4C67D.js.map → chunk-77TT4K53.js.map} +0 -0
  195. /package/dist/{chunk-MRTTQYT5.js.map → chunk-7EWZGDWY.js.map} +0 -0
  196. /package/dist/{chunk-Y6KJJMIM.js.map → chunk-A4QKXXZD.js.map} +0 -0
  197. /package/dist/{chunk-Q5XOGATC.js.map → chunk-AIEC3LBT.js.map} +0 -0
  198. /package/dist/{chunk-JGOAQLYW.js.map → chunk-F44QX47A.js.map} +0 -0
  199. /package/dist/{chunk-EYGVDJ2I.js.map → chunk-GMTAFUAG.js.map} +0 -0
  200. /package/dist/{chunk-HKXXFIRI.js.map → chunk-ITKZKREP.js.map} +0 -0
  201. /package/dist/{chunk-OYR5HUQZ.js.map → chunk-IWFQ4ZKF.js.map} +0 -0
  202. /package/dist/{chunk-ZCEAPJDH.js.map → chunk-J7BM5NGK.js.map} +0 -0
  203. /package/dist/{chunk-V4C6FIE2.js.map → chunk-JO52LYO3.js.map} +0 -0
  204. /package/dist/{chunk-FYVPZBXN.js.map → chunk-Q5ALV3DI.js.map} +0 -0
  205. /package/dist/{chunk-SQS7672E.js.map → chunk-Q6YDPREF.js.map} +0 -0
  206. /package/dist/{chunk-XUHAPOM6.js.map → chunk-VEEBJFJ7.js.map} +0 -0
@@ -18,8 +18,27 @@ import './module-families.js';
18
18
  * `ShipLoadout` reports neither: it is keyed by slot and `fromLoadout` throws a
19
19
  * `TypeError` on a duplicate, and every build fills its fixed mounts from the hull
20
20
  * defaults. Switch on them when you validate your own list; skip them for a build.
21
+ *
22
+ * `thrusterMassExceeded` is the one code that reads a figure rather than the structure,
23
+ * so it is reported only when the input states both a
24
+ * {@link LoadoutValidationInput.mass} and the fitted thrusters'
25
+ * {@link ValidationModule.thrusterMaxMass}. A build supplies both.
26
+ */
27
+ type LoadoutIssueCode = 'duplicateSlot' | 'unknownSlot' | 'missingRequiredSlot' | 'incompatibleModule' | 'duplicateExclusiveModule' | 'moduleLimitExceeded' | 'thrusterMassExceeded';
28
+ /**
29
+ * A load a thruster rating is read against, lightest first.
30
+ *
31
+ * @remarks
32
+ * `dry` is the fit alone — hull plus modules, an empty tank and no cargo. `unladen`
33
+ * adds a full main tank, and is the figure the game and every outfitting tool call a
34
+ * ship's unladen mass; note that {@link ships!ShipLoadout.unladenMass} is the `dry`
35
+ * figure, because that is what a journal's `UnladenMass` states. `laden` adds a full
36
+ * hold on top.
37
+ *
38
+ * A ship cannot undock without fuel, so failing at `dry` or `unladen` is an error.
39
+ * Failing only at `laden` is a warning: the hold is the one load a pilot chooses.
21
40
  */
22
- type LoadoutIssueCode = 'duplicateSlot' | 'unknownSlot' | 'missingRequiredSlot' | 'incompatibleModule' | 'duplicateExclusiveModule' | 'moduleLimitExceeded';
41
+ type ThrusterLoad = 'dry' | 'unladen' | 'laden';
23
42
  /** Stable machine-readable constraint behind an `incompatibleModule` issue. */
24
43
  type ModuleFitConstraint = 'immutableSlot' | 'armourRequired' | 'wrongHullArmour' | 'restrictedHull' | 'restrictedMount' | 'wrongCoreType' | 'hardpointRequired' | 'utilityRequired' | 'optionalInternalRequired' | 'coreModuleInOptionalSlot' | 'oversized' | 'unknownConstraint';
25
44
  /**
@@ -34,8 +53,18 @@ type LoadoutIssueParams = Readonly<Record<string, LoadoutIssueParam>>;
34
53
  interface LoadoutIssue {
35
54
  /** Machine-readable reason. */
36
55
  readonly code: LoadoutIssueCode;
37
- /** Invalid input is an error; a missing required module makes the build incomplete. */
38
- readonly severity: 'error' | 'incomplete';
56
+ /**
57
+ * Invalid input is an error; a missing required module makes the build incomplete;
58
+ * a warning is a build that flies, but not at every load it can carry.
59
+ *
60
+ * @remarks
61
+ * Only `error` clears {@link LoadoutValidation.valid}, and only `error` or
62
+ * `incomplete` clears {@link LoadoutValidation.complete}. A `warning` is a note
63
+ * against a legal, fully-mounted build, so it leaves both answers alone. Branch on
64
+ * {@link code} rather than on this: one severity covers findings that belong in
65
+ * different places on a panel.
66
+ */
67
+ readonly severity: 'error' | 'incomplete' | 'warning';
39
68
  /** Slot involved, in the build's own spelling when possible. */
40
69
  readonly slot?: string;
41
70
  /** Module symbol involved, when any. */
@@ -77,6 +106,18 @@ interface ValidationModule {
77
106
  readonly limitGroup?: ModuleLimitGroup;
78
107
  /** Per-ship count allowance increase this resolved module grants, when any. */
79
108
  readonly limitIncrease?: ModuleLimitIncrease;
109
+ /**
110
+ * The mass this module can still move, in tonnes — a thruster's post-engineering
111
+ * `maxMass`, and the top of its mass curve.
112
+ *
113
+ * @remarks
114
+ * Present only on the fitted thrusters, and only where their record carries the
115
+ * figure. Above it the curve contributes nothing and the ship does not move, which
116
+ * is what {@link LoadoutValidationInput.mass} is weighed against. Leave it off every
117
+ * other module: a shield generator's curve has a `maxMass` of its own and is not a
118
+ * limit on the build's mass.
119
+ */
120
+ readonly thrusterMaxMass?: number;
80
121
  }
81
122
  /** Input to {@link validateLoadout}. */
82
123
  interface LoadoutValidationInput {
@@ -86,12 +127,57 @@ interface LoadoutValidationInput {
86
127
  readonly slots: readonly BuildSlot[];
87
128
  /** Fitted modules. Duplicate keys must be retained here so they can be diagnosed. */
88
129
  readonly modules: readonly ValidationModule[];
130
+ /**
131
+ * What the assembled ship weighs, for the one rule that reads a figure: thrusters
132
+ * rated below the ship's mass cannot move it.
133
+ *
134
+ * Omit it to check structure alone.
135
+ */
136
+ readonly mass?: LoadoutMass;
137
+ }
138
+ /**
139
+ * What a build weighs at each load a thruster rating is read against, in tonnes.
140
+ *
141
+ * @remarks
142
+ * State as much as the build knows. {@link fuel} and {@link cargo} are *capacities*,
143
+ * not a chosen load: the rule weighs a full tank and a full hold, because those are the
144
+ * heaviest the build can become without being re-fitted. Leave one off and the loads
145
+ * above it simply go unchecked.
146
+ */
147
+ interface LoadoutMass {
148
+ /**
149
+ * Hull plus every fitted module, an empty tank and no cargo — a build's
150
+ * {@link ships!ShipLoadout.unladenMass | unladenMass}.
151
+ *
152
+ * @remarks
153
+ * Despite that name this is the *dry* figure: a journal's `UnladenMass` excludes
154
+ * fuel, while the game's own "unladen mass" readout includes a full tank. The two
155
+ * are told apart here as {@link ThrusterLoad}'s `dry` and `unladen`.
156
+ */
157
+ readonly dry: number;
158
+ /** Main-tank capacity. The reserve is not counted, as the flight model does not. */
159
+ readonly fuel?: number;
160
+ /** Cargo capacity, as fitted racks allow rather than as any hold currently holds. */
161
+ readonly cargo?: number;
89
162
  }
90
163
  /**
91
164
  * Validate a resolved fitted build without importing any catalogue.
92
165
  *
93
- * @param input - Hull layout and resolved module classifications.
166
+ * @param input - Hull layout and resolved module classifications, and optionally what
167
+ * the assembled ship weighs.
94
168
  * @returns Structural validity, operational completeness, and diagnostics.
169
+ * @remarks
170
+ * Every rule but one reads the structure alone. The exception is
171
+ * `thrusterMassExceeded`: state {@link LoadoutValidationInput.mass} and the fitted
172
+ * thrusters' {@link ValidationModule.thrusterMaxMass}, and a ship too heavy for its own
173
+ * thrusters is reported, because above that rating the thruster curve contributes
174
+ * nothing and the ship does not move at all.
175
+ *
176
+ * The rating is weighed against each {@link ThrusterLoad} the input can state, and the
177
+ * lightest load that is already too heavy is the one reported. A ship that cannot move
178
+ * `dry` or `unladen` is an error — it cannot leave a pad, where the tank is always
179
+ * full. One that only fails `laden` is a warning, and leaves the build both valid and
180
+ * complete: the hold is the one load a pilot chooses.
95
181
  * @example
96
182
  * ```ts
97
183
  * import { validateLoadout } from '@elite-dangerous-almanac/core/ships/loadout-validation';
@@ -99,9 +185,29 @@ interface LoadoutValidationInput {
99
185
  * const result = validateLoadout({ shipSymbol: 'CustomHull', slots: [], modules: [] });
100
186
  * result.valid; // -> true: no impossible fit was claimed
101
187
  * result.complete; // -> true: the supplied layout has no required mounts
188
+ *
189
+ * const overloaded = validateLoadout({
190
+ * shipSymbol: 'CustomHull',
191
+ * slots: [],
192
+ * mass: { dry: 60.6, fuel: 25 },
193
+ * modules: [
194
+ * {
195
+ * slot: 'MainEngines',
196
+ * symbol: 'Int_Engine_Size2_Class1',
197
+ * requiresKnownSlot: false,
198
+ * fitError: null,
199
+ * thrusterMaxMass: 72,
200
+ * },
201
+ * ],
202
+ * });
203
+ * overloaded.valid; // -> false
204
+ * overloaded.issues[0]?.code; // -> 'thrusterMassExceeded'
205
+ * overloaded.issues[0]?.params?.load; // -> 'unladen': it is the full tank that sinks it
102
206
  * ```
103
207
  * @throws {TypeError} If `input.slots` is not an array.
208
+ * @throws {RangeError} If a figure in `input.mass`, or a module's `thrusterMaxMass`, is
209
+ * present and is not a finite number of zero or more.
104
210
  */
105
211
  declare function validateLoadout(input: LoadoutValidationInput): LoadoutValidation;
106
212
 
107
- export { type LoadoutIssue, type LoadoutIssueCode, type LoadoutIssueParam, type LoadoutIssueParams, type LoadoutValidation, type LoadoutValidationInput, type ModuleFitConstraint, type ValidationModule, validateLoadout };
213
+ export { type LoadoutIssue, type LoadoutIssueCode, type LoadoutIssueParam, type LoadoutIssueParams, type LoadoutMass, type LoadoutValidation, type LoadoutValidationInput, type ModuleFitConstraint, type ThrusterLoad, type ValidationModule, validateLoadout };
@@ -1 +1 @@
1
- export{validateLoadout}from"../chunk-B4ZSTOM4.js"; //# sourceMappingURL=loadout-validation.js.map
1
+ export{validateLoadout}from"../chunk-OJC6AUL7.js"; //# sourceMappingURL=loadout-validation.js.map
@@ -17,7 +17,7 @@ import { MobilityInput, ThrusterParams } from './mobility.js';
17
17
  * {@link MobilityMetrics.boost}, along with the loaded mass and the two curve
18
18
  * multipliers these figures share.
19
19
  *
20
- * This module is data-free. {@link BuildMetrics.mobilityCapacitorMetrics} (in
20
+ * This module is data-free. {@link BuildMetrics.mobilityCapacitorMetricsResult} (in
21
21
  * `./build-metrics`) reads the hull, the loaded mass and the powered thrusters out of a
22
22
  * build and calls {@link mobilityCapacitorMetrics} for you.
23
23
  *
@@ -1 +1 @@
1
- export{mobilityCapacitorMetrics}from"../chunk-XUHAPOM6.js"; //# sourceMappingURL=mobility-capacitor.js.map
1
+ export{mobilityCapacitorMetrics}from"../chunk-VEEBJFJ7.js"; //# sourceMappingURL=mobility-capacitor.js.map
@@ -1 +1 @@
1
- export{mobilityMetrics,thrusterMassCurveMultiplier}from"../chunk-Y6KJJMIM.js"; //# sourceMappingURL=mobility.js.map
1
+ export{mobilityMetrics,thrusterMassCurveMultiplier}from"../chunk-A4QKXXZD.js"; //# sourceMappingURL=mobility.js.map
@@ -1 +1 @@
1
- export{ALL_MODULES}from"../chunk-QY3L5BKN.js"; //# sourceMappingURL=modules-all.js.map
1
+ export{ALL_MODULES}from"../chunk-7ZERP4TB.js"; //# sourceMappingURL=modules-all.js.map
@@ -1 +1 @@
1
- export{CORE_MODULES}from"../chunk-EVJ32UF3.js"; //# sourceMappingURL=modules-core.js.map
1
+ export{CORE_MODULES}from"../chunk-FA5JVXVG.js"; //# sourceMappingURL=modules-core.js.map
@@ -1 +1 @@
1
- export{INTERNAL_MODULES}from"../chunk-4ZGUSHTP.js"; //# sourceMappingURL=modules-internal.js.map
1
+ export{INTERNAL_MODULES}from"../chunk-4CBMQULR.js"; //# sourceMappingURL=modules-internal.js.map
@@ -44,7 +44,7 @@ import { ModuleSlot, SlotRestriction } from './slots.js';
44
44
  *
45
45
  * @remarks
46
46
  * **This is the one default that costs real bundle weight.** A lookup imported from
47
- * here pulls all four catalogues — 337.4 KiB minified (33.3 KiB gzipped) — since
47
+ * here pulls all four catalogues — ~338 KiB minified (~33 KiB gzipped) — since
48
48
  * that is what it falls back to, and passing an explicit catalogue does not undo it.
49
49
  * A build that must carry only one category should import that catalogue and search
50
50
  * it directly:
@@ -333,6 +333,26 @@ interface OutfittingModuleIdentity {
333
333
  * `"ELITE_HORIZONS_V_PLANETARY_LANDINGS"`. Present only on gated modules.
334
334
  */
335
335
  readonly entitlement?: string;
336
+ /**
337
+ * `true` on an article that arrives granted — with a hull or with a bundle — and
338
+ * that no outfitting screen sells. Absent on every module a station offers.
339
+ *
340
+ * @remarks
341
+ * The fifteen are the nine starter `*_free` fittings and the six bundle-granted
342
+ * Vessel Hangars. Each is a second identity for an article the game already sells:
343
+ * `Int_Engine_Size2_Class1_free` is the 2E Thrusters again, which is why
344
+ * {@link ShipLoadout.modulesForSlot} leaves them out — a picker that offered both
345
+ * would list "2E Thrusters" twice, once unpriced.
346
+ *
347
+ * They are still real fitted articles, so they stay in the catalogues and every
348
+ * lookup resolves one: a build imported from a journal can carry one, and
349
+ * {@link getModuleBySymbol} answers for it like any other symbol. Absent is not
350
+ * `false` — nothing carries `grantOnly: false`.
351
+ *
352
+ * Do not read it as a price: {@link OutfittingModule.cost} is missing on these but
353
+ * also on articles that are sold and simply unpriced by every registry.
354
+ */
355
+ readonly grantOnly?: true;
336
356
  /**
337
357
  * The hull symbol(s) a module is restricted to, when it is ship-specific — e.g.
338
358
  * `["Explorer_NX"]` for the Python Mk II's MkII Gravity Optimised thrusters.
@@ -1 +1 @@
1
- export{getBulkheadsForShip,getModuleBySymbol,getModulesByName}from"../chunk-PA5EITW5.js"; //# sourceMappingURL=modules.js.map
1
+ export{getBulkheadsForShip,getModuleBySymbol,getModulesByName}from"../chunk-3LZXB2MC.js"; //# sourceMappingURL=modules.js.map
@@ -1 +1 @@
1
- export{powerBudget}from"../chunk-D6YEHR5S.js";//# sourceMappingURL=power.js.map
1
+ export{powerBudget}from"../chunk-GGQMIQPC.js"; //# sourceMappingURL=power.js.map
@@ -15,8 +15,8 @@ import './slots.js';
15
15
  * arrives, not as the stock module leaves the shipyard. That is what
16
16
  * {@link getPreEngineeredStats} returns.
17
17
  *
18
- * This module imports every module record to resolve stats. Its resolver is 362.5 KiB
19
- * minified in a consumer bundle; the complete runtime API is 396.3 KiB (43.1 KiB
18
+ * This module imports every module record to resolve stats. Its resolver is ~363 KiB
19
+ * minified in a consumer bundle; the complete runtime API is ~397 KiB (~43 KiB
20
20
  * gzipped). Consumers that only list variants can import `./pre-engineered.js` without
21
21
  * these module catalogues.
22
22
  * A journal or SLEF module can instead be classified with
@@ -100,16 +100,23 @@ declare function getPreEngineeredJournalModifiers(variant: PreEngineeredVariant)
100
100
  *
101
101
  * A locked fixed article is also identified by its unique
102
102
  * symbol/blueprint/grade/experimental tuple when a SLEF capture omits the `Modifiers` key
103
- * entirely. A present empty or partial array does not use this shortcut: older library
104
- * exports can carry an ordinary roll with the same tuple, and its values must not be
105
- * replaced by reward stats. A third-party export can omit the array from such a roll;
106
- * that record is indistinguishable from the fixed article, so the catalogue identity
107
- * wins.
103
+ * entirely: being final, no ordinary roll could have written that tuple. A present empty
104
+ * or partial array does not use this shortcut: older library exports can carry an ordinary
105
+ * roll with the same tuple, and its values must not be replaced by reward stats. A third-
106
+ * party export can omit the array from such a roll; that record is indistinguishable from
107
+ * the fixed article, so the catalogue identity wins.
108
+ *
109
+ * An unlocked article that shares a blueprint with no craftable recipe of its base module
110
+ * is identified the same way, but by `ShipLoadout.fromLoadout` rather than here — that
111
+ * reading needs each module's engineering menu, a catalogue this module deliberately does
112
+ * not carry into a consumer's bundle.
108
113
  *
109
114
  * Frontier journals and captures may omit a derived modifier, so one predicted value may
110
- * be absent. Every stated predicted value must agree within journal float noise, and all
111
- * but at most one must be present. Ambiguous or incomplete evidence returns `null` rather
112
- * than guessing.
115
+ * be absent. Every stated predicted value must agree to within one part in ten thousand of
116
+ * the stat's unmodified base wide enough for a producer that stores the multiplier and
117
+ * re-derives the value, narrow enough that no other candidate fits — and all but at most
118
+ * one must be present. Ambiguous or incomplete evidence returns `null` rather than
119
+ * guessing.
113
120
  * Other variants without a published stat block cannot be identified.
114
121
  *
115
122
  * @param module - A module from a journal `Loadout` event or SLEF export.
@@ -1 +1 @@
1
- export{getPreEngineeredJournalModifiers,getPreEngineeredModifiers,getPreEngineeredStats,identifyPreEngineeredVariant,unresolvedModifiers}from"../chunk-GZYPQIO2.js"; //# sourceMappingURL=pre-engineered-stats.js.map
1
+ export{getPreEngineeredJournalModifiers,getPreEngineeredModifiers,getPreEngineeredStats,identifyPreEngineeredVariant,unresolvedModifiers}from"../chunk-4OTQBHQL.js"; //# sourceMappingURL=pre-engineered-stats.js.map
@@ -1 +1 @@
1
- export{effectiveHitPoints,mapDamageTypes,stackArmourResistance,stackShieldResistance,systemsResistance}from"../chunk-JGOAQLYW.js"; //# sourceMappingURL=resistances.js.map
1
+ export{effectiveHitPoints,mapDamageTypes,stackArmourResistance,stackShieldResistance,systemsResistance}from"../chunk-F44QX47A.js"; //# sourceMappingURL=resistances.js.map
@@ -22,7 +22,7 @@ import { DamageResistances, DamageTypeValues } from './resistances.js';
22
22
  * raised shield — is {@link shieldRecovery}, which takes the same allocation and the
23
23
  * generator's regeneration rates.
24
24
  *
25
- * This module is data-free. {@link BuildMetrics.shieldCapacitorMetrics} (in
25
+ * This module is data-free. {@link BuildMetrics.shieldCapacitorMetricsResult} (in
26
26
  * `./build-metrics`) resolves the powered generator, boosters and distributor for you.
27
27
  *
28
28
  * @remarks
@@ -1 +1 @@
1
- export{shieldCapacitorMetrics}from"../chunk-6L56LWTT.js"; //# sourceMappingURL=shield-capacitor.js.map
1
+ export{shieldCapacitorMetrics}from"../chunk-XQJERZUS.js"; //# sourceMappingURL=shield-capacitor.js.map
@@ -1 +1 @@
1
- export{cellBankSummary,shieldRecovery}from"../chunk-4KJ7CR74.js"; //# sourceMappingURL=shield-recovery.js.map
1
+ export{cellBankSummary,shieldRecovery}from"../chunk-JMAXSXXQ.js"; //# sourceMappingURL=shield-recovery.js.map
@@ -19,7 +19,7 @@ import { DamageResistances, DamageTypeValues, DamageResistanceParams } from './r
19
19
  * `./resistances`. Everything here is **pip-free**: the SYS capacitor's own resistance,
20
20
  * and the effective figures it buys, live in `./shield-capacitor`.
21
21
  *
22
- * This module is data-free. {@link BuildMetrics.shieldMetrics} (in `./build-metrics`)
22
+ * This module is data-free. {@link BuildMetrics.shieldMetricsResult} (in `./build-metrics`)
23
23
  * pulls the generator, boosters and reinforcement packages out of a build,
24
24
  * post-engineering, and calls {@link shieldMetrics} for you.
25
25
  *
@@ -1 +1 @@
1
- export{shieldMassCurveMultiplier,shieldMetrics,shieldStrength}from"../chunk-QTAMQ6ME.js"; //# sourceMappingURL=shields.js.map
1
+ export{shieldMassCurveMultiplier,shieldMetrics,shieldStrength}from"../chunk-5VWACBTN.js"; //# sourceMappingURL=shields.js.map
@@ -160,10 +160,17 @@ type LoadoutSlot = BuildSlot & {
160
160
  * A change made while normalizing a journal or SLEF loadout against the catalogues.
161
161
  *
162
162
  * @remarks
163
- * `ShipLoadout.fromLoadout` states the rule these outcomes report: a removable mount is
163
+ * `ShipLoadout.fromLoadout` states the rules these outcomes report: a removable mount is
164
164
  * `emptied` of an article the catalogue cannot resolve, and a fixed mount is `defaulted`
165
165
  * to the hull's stock article whenever the source left none it can hold — with a `null`
166
- * `sourceSymbol` when the source named nothing there at all.
166
+ * `sourceSymbol` when the source named nothing there at all. A module whose source stated
167
+ * a recipe and no `Modifiers` reports `unresolvedEngineering` when neither a craftable
168
+ * recipe nor a catalogued article answers to what it named, because that module alone
169
+ * keeps the figures of an unengineered one. Two further entries report a *reading* the
170
+ * import chose rather than a change it made: `ambiguousEngineering` where an identity-only
171
+ * block was rolled while a catalogued article answers to it just as well, and
172
+ * `rerolledEngineering` where a stated modifier block moved nothing the module has and the
173
+ * recipe beside it was rolled in its place.
167
174
  *
168
175
  * @example
169
176
  * ```ts
@@ -194,6 +201,57 @@ type LoadoutImportOutcome = {
194
201
  readonly sourceSymbol: string | null;
195
202
  /** Stock module identity installed in the mount. */
196
203
  readonly replacementSymbol: string;
204
+ } | {
205
+ /**
206
+ * The source stated engineering with no `Modifiers`, and what it named could
207
+ * not be rolled — an unknown or unoffered blueprint or experimental effect, a
208
+ * grade or quality outside the recipe, or a base stat the catalogues do not
209
+ * carry — so this module's figures are the unengineered ones.
210
+ */
211
+ readonly action: 'unresolvedEngineering';
212
+ /** Exact slot spelling used by the imported build. */
213
+ readonly slot: string;
214
+ /** Module identity the recipe was stated for. */
215
+ readonly sourceSymbol: string;
216
+ /** Recipe the source named, in its own spelling. */
217
+ readonly blueprintSymbol: string;
218
+ } | {
219
+ /**
220
+ * The source stated a recipe and no `Modifiers`, and both readings of that
221
+ * identity are legitimate: the module's own engineering menu offers the recipe,
222
+ * *and* a catalogued fixed article carries the same blueprint at the same grade
223
+ * and effect. The roll was fitted, because that is what nearly every such block
224
+ * is; {@link preEngineeredVariant} is the article passed over.
225
+ */
226
+ readonly action: 'ambiguousEngineering';
227
+ /** Exact slot spelling used by the imported build. */
228
+ readonly slot: string;
229
+ /** Module identity the recipe was stated for. */
230
+ readonly sourceSymbol: string;
231
+ /** Recipe the source named, in its own spelling. */
232
+ readonly blueprintSymbol: string;
233
+ /**
234
+ * The catalogued article the same block equally describes. Pass it to
235
+ * {@link ships!ShipLoadout.setPreEngineeredVariant |
236
+ * ShipLoadout.setPreEngineeredVariant} to take that reading instead.
237
+ */
238
+ readonly preEngineeredVariant: PreEngineeredVariant;
239
+ } | {
240
+ /**
241
+ * The source stated `Modifiers` that move no stat this module has — an empty
242
+ * array, or labels the catalogues model nothing for — and identified no
243
+ * catalogued article, so the module would have published unengineered figures
244
+ * while reporting that it is engineered. The recipe stated beside them was
245
+ * rolled at the stated grade and quality in their place, and the source's own
246
+ * modifier block is gone from the build.
247
+ */
248
+ readonly action: 'rerolledEngineering';
249
+ /** Exact slot spelling used by the imported build. */
250
+ readonly slot: string;
251
+ /** Module identity the recipe was stated for. */
252
+ readonly sourceSymbol: string;
253
+ /** Recipe the source named, in its own spelling. */
254
+ readonly blueprintSymbol: string;
197
255
  };
198
256
 
199
257
  /**
@@ -378,8 +436,9 @@ interface EngineeringNormalized {
378
436
  /** Discriminator for a successful normalization. */
379
437
  readonly kind: 'normalized';
380
438
  /**
381
- * Quality reported by the fitted module before normalization, in `[0, 1]`. It reads
382
- * `1` where a completed roll stated no modifiers and this call spelled them out.
439
+ * Quality reported by the fitted module before normalization, in `[0, 1]`. A block
440
+ * that stated no modifiers still reports the quality it stated, so this reads `1` for
441
+ * a completed roll whose figures this call was the first to spell out.
383
442
  */
384
443
  readonly previousQuality: number;
385
444
  /** Completed engineering quality. Always `1`. */
@@ -525,7 +584,7 @@ interface SlefExportOptions extends LoadoutExportOptions {
525
584
  * const metrics = BuildMetrics.of(build);
526
585
  * metrics.maxJumpRange(); // -> 60.5478 (ly, best single jump)
527
586
  * metrics.powerBudget().withinBudget; // -> true
528
- * metrics.shieldMetrics()?.strength; // -> 743.12 (MJ)
587
+ * metrics.shieldMetricsResult().value?.strength; // -> 743.12 (MJ)
529
588
  * metrics.armourMetrics().hitPoints; // -> 307.8
530
589
  * ```
531
590
  */
@@ -541,7 +600,8 @@ declare class ShipLoadout {
541
600
  * Defaults to the first.
542
601
  * @returns The loadout for that entry.
543
602
  * @remarks Module normalization follows {@link ShipLoadout.fromLoadout}; inspect
544
- * {@link importOutcomes} for modules that were emptied or defaulted.
603
+ * {@link importOutcomes} for modules that were emptied or defaulted, and for stated
604
+ * engineering it could not resolve.
545
605
  * @throws {SyntaxError} If `input` is a string that is not valid JSON.
546
606
  * @throws {TypeError} If the export holds no usable loadout, `index` is out of range,
547
607
  * or the selected entry names a hull absent from the catalogue.
@@ -560,6 +620,29 @@ declare class ShipLoadout {
560
620
  * and the catalogue's stat block then supplies the values the capture omits; the
561
621
  * capture's own modifiers stay authoritative over it.
562
622
  *
623
+ * **A recipe stated without `Modifiers` is rolled.** A journal writes the modifier
624
+ * block beside the recipe, but SLEF permits stating the recipe alone and Inara does,
625
+ * so such a block is materialised here at the grade and quality it states — otherwise
626
+ * the module would report that it is engineered while publishing the figures of one
627
+ * that is not. Where the module's own engineering menu offers the recipe, the block
628
+ * is read as an ordinary roll of it, even if a fixed article of that module carries
629
+ * the same blueprint at the same grade — a reading {@link importOutcomes} reports as
630
+ * `ambiguousEngineering`, carrying the article passed over so
631
+ * {@link setPreEngineeredVariant} can take the other one. A Mercenary article is read
632
+ * as its own article at the grade it was bought at, and as that purchase climbed by
633
+ * its bespoke recipe above it. Where the menu does not offer the recipe, no ordinary
634
+ * roll could have written the block, so a single catalogued article answering to it
635
+ * is fitted. Where neither answers, the module keeps unengineered figures and
636
+ * {@link importOutcomes} reports the slot as `unresolvedEngineering`.
637
+ *
638
+ * **A stated modifier block that moves nothing is replaced by the roll.** A block
639
+ * naming only stats the module has no value for describes some other module, and
640
+ * preserving it would publish unengineered figures under an engineered block, so the
641
+ * recipe stated beside it is rolled instead and the slot is reported as
642
+ * `rerolledEngineering`. Every block that moves at least one stat this module carries
643
+ * stays exactly as the source wrote it: a capture's own figures are what the game
644
+ * reported, and outrank anything recomputed here.
645
+ *
563
646
  * Modules are imported as one complete snapshot, so their order does not affect
564
647
  * per-ship count allowances. An entry stands as the event stated it when the mount
565
648
  * can hold the article the catalogue resolves, when its slot is a known cosmetic or
@@ -725,18 +808,28 @@ declare class ShipLoadout {
725
808
  */
726
809
  get sourcePurchase(): SourcePurchaseRecord | null;
727
810
  /**
728
- * Changes made while importing this build, in source order, followed by the fixed
729
- * mounts stocked from the hull defaults because the source named none, in the
730
- * defaults' own order.
811
+ * What the import made of this build: the changes it applied, in source order,
812
+ * followed by the fixed mounts stocked from the hull defaults because the source
813
+ * named none, in the defaults' own order, followed by what it made of each module's
814
+ * stated engineering.
731
815
  *
732
816
  * @returns A deeply frozen list. It is empty for builds created with
733
817
  * {@link ShipLoadout.empty} or {@link ShipLoadout.default}, and for imports that
734
- * needed no normalization.
818
+ * needed no normalization and read every stated recipe unambiguously.
735
819
  * @remarks
736
820
  * Each entry names the exact slot, and the source identity where the source gave one.
737
821
  * `emptied` means an unknown module was removed from a removable mount; `defaulted`
738
822
  * names the stock article fitted to armour, a core internal or the cargo hatch, with
739
823
  * a `null` `sourceSymbol` when the source named nothing there at all.
824
+ * `rerolledEngineering` names a module whose stated `Modifiers` moved no stat it
825
+ * carries, so the recipe beside them was rolled in their place.
826
+ *
827
+ * Two entries report no change to the fit at all. `unresolvedEngineering` means the
828
+ * source stated a recipe and no `Modifiers`, nothing the catalogues carry answers to
829
+ * it, and that module alone keeps the figures of an unengineered one.
830
+ * `ambiguousEngineering` means such a block had *two* answers — an ordinary roll and
831
+ * a catalogued fixed article — and carries the article that was passed over, ready
832
+ * for {@link setPreEngineeredVariant} (see {@link ShipLoadout.fromLoadout}).
740
833
  */
741
834
  get importOutcomes(): readonly LoadoutImportOutcome[];
742
835
  /**
@@ -744,11 +837,29 @@ declare class ShipLoadout {
744
837
  *
745
838
  * @remarks
746
839
  * `valid` asks whether the fit is legal: a module in a nonexistent or incompatible
747
- * slot, a duplicated exclusive family, or a module count past the build's allowance
748
- * makes it `false`. `complete` asks that *and* whether armour and the seven core
749
- * mounts are filled every build fills those, so on a build the two answers agree.
750
- * Neither question reports import normalization, so read {@link importOutcomes}
751
- * beside them.
840
+ * slot, a duplicated exclusive family, a module count past the build's allowance, or
841
+ * a ship heavier than its own thrusters can move makes it `false`. `complete` asks
842
+ * that *and* whether armour and the seven core mounts are filled every build fills
843
+ * those, so on a build the two answers agree. Neither question reports import
844
+ * normalization, so read {@link importOutcomes} beside them.
845
+ *
846
+ * The thruster rule weighs the fitted thrusters' post-engineering `maxMass` against
847
+ * what the ship comes to at each load it can reach without being re-fitted:
848
+ * {@link unladenMass} alone, then with a full {@link fuelCapacity | main tank}, then
849
+ * with a full {@link cargoCapacity | hold} as well. The lightest of those that is
850
+ * already too heavy is what gets reported. A ship that cannot move on a full tank is
851
+ * an error — it never leaves the pad, where the tank always is one — while a ship
852
+ * that only fails with the hold full is a warning, and leaves the build valid and
853
+ * complete: how much cargo to take is the pilot's call. Either way
854
+ * {@link ships!BuildMetrics.mobilityMetricsResult | BuildMetrics.mobilityMetricsResult} reports
855
+ * a speed of zero at the load in question.
856
+ *
857
+ * A capture may state a mass nobody can weigh — a negative `UnladenMass`, or an
858
+ * engineering modifier that drives a rating below zero. Neither is refused here:
859
+ * this method reports a build rather than rejecting one, so an unweighable figure is
860
+ * left out and the rule it feeds simply does not run. The figure itself is still
861
+ * reported, as a thrown one, by whichever {@link ships!BuildMetrics | BuildMetrics}
862
+ * calculation reads it.
752
863
  *
753
864
  * @returns The validation report, recomputed from the current fit on every call.
754
865
  */
@@ -836,6 +947,13 @@ declare class ShipLoadout {
836
947
  * satisfied, with candidates that would worsen a one-per-ship or module-count limit
837
948
  * omitted.
838
949
  *
950
+ * @remarks
951
+ * This is the outfitting *offer*, so the fifteen {@link ships!OutfittingModule.grantOnly | grantOnly}
952
+ * articles are never in it: each is a second identity for a module the game already
953
+ * sells — `Int_Engine_Size2_Class1_free` is the 2E Thrusters — and listing both puts
954
+ * the same article on the screen twice, once with no price. A build that already
955
+ * carries one keeps it; only the choices are filtered.
956
+ *
839
957
  * @param slotKey - The slot key to fit, matched case-insensitively (journal spelling).
840
958
  * @returns The fitting modules, in complete-catalogue order.
841
959
  * @throws {RangeError} If the hull has no slot with that key.
@@ -1019,9 +1137,13 @@ declare class ShipLoadout {
1019
1137
  * purchase identity. A refusal never changes the loadout.
1020
1138
  *
1021
1139
  * A block that names a blueprint and grade but states no `Modifiers` at all is rolled
1022
- * here too, even at quality `1` SLEF permits that identity-only shape and Inara
1023
- * writes it, so a capture of a completed roll would otherwise stay stock. A stated
1024
- * modifier array, empty or partial, is left alone at quality `1`.
1140
+ * here too, even at quality `1`, so a completed roll cannot stay stock. On an imported
1141
+ * build such a block is one {@link ShipLoadout.fromLoadout} did not roll: a catalogued
1142
+ * article it fitted instead, whose fixed modifiers this spells out unless the article
1143
+ * is final; a Mercenary article at the grade it was bought at, whose block no registry
1144
+ * publishes and which this refuses; or a recipe nothing answered to, which this
1145
+ * refuses for the reason the import could not roll it. A stated modifier array, empty
1146
+ * or partial, is left alone at quality `1`.
1025
1147
  *
1026
1148
  * @param slotKey - The engineered slot, matched case-insensitively.
1027
1149
  * @returns A frozen result identifying a normalized, unchanged or unsupported state.
@@ -1 +1 @@
1
- export{LoadoutEditError,ShipLoadout}from"../chunk-OYFMHDYT.js"; //# sourceMappingURL=ship-loadout.js.map
1
+ export{LoadoutEditError,ShipLoadout}from"../chunk-B5VTFOK4.js"; //# sourceMappingURL=ship-loadout.js.map
@@ -90,7 +90,10 @@ interface BlueprintModuleEngineering {
90
90
  * `BlueprintName`, `Level` and `Quality` — the specification's own example omits it —
91
91
  * so an export from another app may name the blueprint and its roll without spelling
92
92
  * out the resulting stats. Treat a missing array as "not stated", not as "nothing was
93
- * changed". A craftable recipe can be reconstructed with
93
+ * changed". {@link ShipLoadout.fromLoadout} resolves what a missing array implies —
94
+ * rolling the stated recipe, or fitting the catalogued article the identity can only
95
+ * mean — so a build imported through it needs none of this. Working from the wire
96
+ * shape directly, a craftable recipe is reconstructed with
94
97
  * {@link ShipLoadout.applyBlueprint}, or rolled where it stands with
95
98
  * {@link ShipLoadout.completeEngineeringGrade}, which spells out a stated identity
96
99
  * at quality `1`; resolve a fixed identity through the pre-engineered catalogue and
@@ -1 +1 @@
1
- export{getLoadoutModifier,inspectSlef,parseSlef,stringifySlef,toSlef}from"../chunk-OVUHQEH5.js"; //# sourceMappingURL=slef.js.map
1
+ export{getLoadoutModifier,inspectSlef,parseSlef,stringifySlef,toSlef}from"../chunk-T4MKUKYS.js"; //# sourceMappingURL=slef.js.map
@@ -1 +1 @@
1
- export{weaponsCapacitorMetrics}from"../chunk-RRYBSAPX.js"; //# sourceMappingURL=weapons-capacitor.js.map
1
+ export{weaponsCapacitorMetrics}from"../chunk-M4FZRDAH.js"; //# sourceMappingURL=weapons-capacitor.js.map
@@ -1 +1 @@
1
- export{armourPiercingFactor,combinedRateOfFire,damageFalloff,damagePerSecond,energyPerSecond,heatPerSecond,splitDamage,sumWeaponMetrics,sustainedDamagePerSecond,sustainedFireFactor,weaponMetrics}from"../chunk-7TQ2X6Q3.js";//# sourceMappingURL=weapons.js.map
1
+ export{armourPiercingFactor,combinedRateOfFire,damageFalloff,damagePerSecond,energyPerSecond,heatPerSecond,splitDamage,sumWeaponMetrics,sustainedDamagePerSecond,sustainedFireFactor,weaponMetrics}from"../chunk-37JIMWLK.js"; //# sourceMappingURL=weapons.js.map