@shipload/sdk 1.0.0-next.56 → 1.0.0-next.59

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.
@@ -1595,125 +1595,31 @@
1595
1595
  "sourceSubclass": 10210
1596
1596
  },
1597
1597
  {
1598
- "outputItemId": 10216,
1599
- "outputMass": 3600000,
1600
- "inputs": [
1601
- {
1602
- "itemId": 10005,
1603
- "quantity": 150
1604
- },
1605
- {
1606
- "itemId": 10002,
1607
- "quantity": 150
1608
- },
1609
- {
1610
- "itemId": 10010,
1611
- "quantity": 150
1612
- },
1613
- {
1614
- "itemId": 10009,
1615
- "quantity": 150
1616
- },
1617
- {
1618
- "itemId": 10004,
1619
- "quantity": 150
1620
- },
1621
- {
1622
- "itemId": 10211,
1623
- "quantity": 1
1624
- }
1625
- ],
1626
- "statSlots": [
1627
- {
1628
- "sources": [
1629
- {
1630
- "inputIndex": 0,
1631
- "statIndex": 0
1632
- },
1633
- {
1634
- "inputIndex": 5,
1635
- "statIndex": 0
1636
- }
1637
- ]
1638
- },
1639
- {
1640
- "sources": [
1641
- {
1642
- "inputIndex": 1,
1643
- "statIndex": 0
1644
- },
1645
- {
1646
- "inputIndex": 5,
1647
- "statIndex": 1
1648
- }
1649
- ]
1650
- },
1651
- {
1652
- "sources": [
1653
- {
1654
- "inputIndex": 2,
1655
- "statIndex": 0
1656
- },
1657
- {
1658
- "inputIndex": 5,
1659
- "statIndex": 2
1660
- }
1661
- ]
1662
- },
1663
- {
1664
- "sources": [
1665
- {
1666
- "inputIndex": 3,
1667
- "statIndex": 0
1668
- },
1669
- {
1670
- "inputIndex": 5,
1671
- "statIndex": 3
1672
- }
1673
- ]
1674
- },
1675
- {
1676
- "sources": [
1677
- {
1678
- "inputIndex": 4,
1679
- "statIndex": 0
1680
- },
1681
- {
1682
- "inputIndex": 5,
1683
- "statIndex": 4
1684
- }
1685
- ]
1686
- }
1687
- ],
1688
- "blendWeights": [],
1689
- "sourceSubclass": 10211
1690
- },
1691
- {
1692
- "outputItemId": 10217,
1693
- "outputMass": 3600000,
1598
+ "outputItemId": 10218,
1599
+ "outputMass": 2400000,
1694
1600
  "inputs": [
1695
1601
  {
1696
1602
  "itemId": 10005,
1697
- "quantity": 150
1603
+ "quantity": 100
1698
1604
  },
1699
1605
  {
1700
1606
  "itemId": 10002,
1701
- "quantity": 150
1607
+ "quantity": 100
1702
1608
  },
1703
1609
  {
1704
1610
  "itemId": 10010,
1705
- "quantity": 150
1611
+ "quantity": 100
1706
1612
  },
1707
1613
  {
1708
1614
  "itemId": 10009,
1709
- "quantity": 150
1615
+ "quantity": 100
1710
1616
  },
1711
1617
  {
1712
1618
  "itemId": 10004,
1713
- "quantity": 150
1619
+ "quantity": 100
1714
1620
  },
1715
1621
  {
1716
- "itemId": 10211,
1622
+ "itemId": 10210,
1717
1623
  "quantity": 1
1718
1624
  }
1719
1625
  ],
@@ -1780,7 +1686,7 @@
1780
1686
  }
1781
1687
  ],
1782
1688
  "blendWeights": [],
1783
- "sourceSubclass": 10211
1689
+ "sourceSubclass": 10210
1784
1690
  },
1785
1691
  {
1786
1692
  "outputItemId": 20001,
@@ -2365,8 +2271,102 @@
2365
2271
  "sourceSubclass": 10200
2366
2272
  },
2367
2273
  {
2368
- "outputItemId": 20210,
2369
- "outputMass": 3840000,
2274
+ "outputItemId": 20212,
2275
+ "outputMass": 4320000,
2276
+ "inputs": [
2277
+ {
2278
+ "itemId": 20001,
2279
+ "quantity": 200
2280
+ },
2281
+ {
2282
+ "itemId": 20008,
2283
+ "quantity": 200
2284
+ },
2285
+ {
2286
+ "itemId": 20007,
2287
+ "quantity": 200
2288
+ },
2289
+ {
2290
+ "itemId": 20003,
2291
+ "quantity": 200
2292
+ },
2293
+ {
2294
+ "itemId": 20006,
2295
+ "quantity": 200
2296
+ },
2297
+ {
2298
+ "itemId": 10211,
2299
+ "quantity": 1
2300
+ }
2301
+ ],
2302
+ "statSlots": [
2303
+ {
2304
+ "sources": [
2305
+ {
2306
+ "inputIndex": 0,
2307
+ "statIndex": 0
2308
+ },
2309
+ {
2310
+ "inputIndex": 5,
2311
+ "statIndex": 0
2312
+ }
2313
+ ]
2314
+ },
2315
+ {
2316
+ "sources": [
2317
+ {
2318
+ "inputIndex": 1,
2319
+ "statIndex": 0
2320
+ },
2321
+ {
2322
+ "inputIndex": 5,
2323
+ "statIndex": 1
2324
+ }
2325
+ ]
2326
+ },
2327
+ {
2328
+ "sources": [
2329
+ {
2330
+ "inputIndex": 2,
2331
+ "statIndex": 0
2332
+ },
2333
+ {
2334
+ "inputIndex": 5,
2335
+ "statIndex": 2
2336
+ }
2337
+ ]
2338
+ },
2339
+ {
2340
+ "sources": [
2341
+ {
2342
+ "inputIndex": 3,
2343
+ "statIndex": 0
2344
+ },
2345
+ {
2346
+ "inputIndex": 5,
2347
+ "statIndex": 3
2348
+ }
2349
+ ]
2350
+ },
2351
+ {
2352
+ "sources": [
2353
+ {
2354
+ "inputIndex": 4,
2355
+ "statIndex": 0
2356
+ },
2357
+ {
2358
+ "inputIndex": 5,
2359
+ "statIndex": 4
2360
+ }
2361
+ ]
2362
+ }
2363
+ ],
2364
+ "blendWeights": [],
2365
+ "sourceSubclass": 10211
2366
+ },
2367
+ {
2368
+ "outputItemId": 20213,
2369
+ "outputMass": 5760000,
2370
2370
  "inputs": [
2371
2371
  {
2372
2372
  "itemId": 20005,
@@ -2389,7 +2389,7 @@
2389
2389
  "quantity": 150
2390
2390
  },
2391
2391
  {
2392
- "itemId": 10211,
2392
+ "itemId": 20212,
2393
2393
  "quantity": 1
2394
2394
  }
2395
2395
  ],
@@ -2456,11 +2456,11 @@
2456
2456
  }
2457
2457
  ],
2458
2458
  "blendWeights": [],
2459
- "sourceSubclass": 10211
2459
+ "sourceSubclass": 20212
2460
2460
  },
2461
2461
  {
2462
- "outputItemId": 20211,
2463
- "outputMass": 3840000,
2462
+ "outputItemId": 20214,
2463
+ "outputMass": 5760000,
2464
2464
  "inputs": [
2465
2465
  {
2466
2466
  "itemId": 20005,
@@ -2483,7 +2483,7 @@
2483
2483
  "quantity": 150
2484
2484
  },
2485
2485
  {
2486
- "itemId": 10214,
2486
+ "itemId": 20212,
2487
2487
  "quantity": 1
2488
2488
  }
2489
2489
  ],
@@ -2550,6 +2550,6 @@
2550
2550
  }
2551
2551
  ],
2552
2552
  "blendWeights": [],
2553
- "sourceSubclass": 10214
2553
+ "sourceSubclass": 20212
2554
2554
  }
2555
2555
  ]
@@ -21,14 +21,13 @@ import {
21
21
  ITEM_CRAFTER_T1,
22
22
  ITEM_LOADER_T1,
23
23
  ITEM_SHIP_T1_PACKED,
24
- ITEM_ROUSTABOUT_T1_PACKED,
25
- ITEM_PROSPECTOR_T1_PACKED,
26
- ITEM_TENDER_T1_PACKED,
27
- ITEM_TUG_T1_PACKED,
28
- ITEM_PORTER_T1_PACKED,
29
- ITEM_WRANGLER_T1_PACKED,
30
- ITEM_DREDGER_T1_PACKED,
31
- ITEM_WRIGHT_T1_PACKED,
24
+ ITEM_ROUSTABOUT_T1A_PACKED,
25
+ ITEM_PROSPECTOR_T1A_PACKED,
26
+ ITEM_TENDER_T1A_PACKED,
27
+ ITEM_TUG_T1A_PACKED,
28
+ ITEM_PORTER_T1A_PACKED,
29
+ ITEM_SMITH_T1A_PACKED,
30
+ ITEM_WRIGHT_T1A_PACKED,
32
31
  ITEM_ENGINE_T1,
33
32
  ITEM_GENERATOR_T1,
34
33
  ITEM_BUILDER_T1,
@@ -72,14 +71,13 @@ test('computeBaseCapacity uses ship-hull formula for every ship-class entity', (
72
71
  const expected = computeBaseCapacity(ITEM_SHIP_T1_PACKED, stats)
73
72
  expect(expected).toBeGreaterThan(0)
74
73
  for (const itemId of [
75
- ITEM_ROUSTABOUT_T1_PACKED,
76
- ITEM_PROSPECTOR_T1_PACKED,
77
- ITEM_TENDER_T1_PACKED,
78
- ITEM_TUG_T1_PACKED,
79
- ITEM_PORTER_T1_PACKED,
80
- ITEM_WRANGLER_T1_PACKED,
81
- ITEM_DREDGER_T1_PACKED,
82
- ITEM_WRIGHT_T1_PACKED,
74
+ ITEM_ROUSTABOUT_T1A_PACKED,
75
+ ITEM_PROSPECTOR_T1A_PACKED,
76
+ ITEM_TENDER_T1A_PACKED,
77
+ ITEM_TUG_T1A_PACKED,
78
+ ITEM_PORTER_T1A_PACKED,
79
+ ITEM_SMITH_T1A_PACKED,
80
+ ITEM_WRIGHT_T1A_PACKED,
83
81
  ]) {
84
82
  expect(computeBaseCapacity(itemId, stats)).toBe(expected)
85
83
  }
@@ -223,7 +221,7 @@ test('engine and generator capabilities use tapered quality consistently', () =>
223
221
  {type: 'generator', outputPct: 100, maxTier: 1},
224
222
  ]
225
223
 
226
- const result = computeEntityCapabilities({}, ITEM_ROUSTABOUT_T1_PACKED, modules, layout)
224
+ const result = computeEntityCapabilities({}, ITEM_ROUSTABOUT_T1A_PACKED, modules, layout)
227
225
  const engines = computeEngineCapabilities({volatility: 500, thermal: 500})
228
226
 
229
227
  expect(result.engines).toEqual({
@@ -0,0 +1,17 @@
1
+ import {describe, expect, test} from 'bun:test'
2
+ import {usedInputStatKeys} from './crafting'
3
+ import {ITEM_BUILDER_T1} from '../data/item-ids'
4
+
5
+ describe('usedInputStatKeys', () => {
6
+ test('maps each input to the stat keys the blend actually consumes', () => {
7
+ // Ceramic.hardness feeds the output's resonance slot; a name match would miss it.
8
+ expect(usedInputStatKeys(ITEM_BUILDER_T1)).toEqual([
9
+ ['resonance'],
10
+ ['hardness', 'fineness'],
11
+ ])
12
+ })
13
+
14
+ test('returns an empty array for an unknown recipe', () => {
15
+ expect(usedInputStatKeys(999999)).toEqual([])
16
+ })
17
+ })
@@ -66,6 +66,24 @@ function keyForRecipeInputStat(recipe: Recipe, inputIndex: number, statIndex: nu
66
66
  return innerKeys[statIndex] ?? ''
67
67
  }
68
68
 
69
+ export function usedInputStatKeys(outputItemId: number): string[][] {
70
+ const recipe = getRecipe(outputItemId)
71
+ if (!recipe) return []
72
+ const usedIdx = recipe.inputs.map(() => new Set<number>())
73
+ for (const slot of recipe.statSlots) {
74
+ for (const src of slot.sources) {
75
+ usedIdx[src.inputIndex]?.add(src.statIndex)
76
+ }
77
+ }
78
+ return recipe.inputs.map((input, i) => {
79
+ const keys = getItemStatKeys(input.itemId)
80
+ return [...usedIdx[i]]
81
+ .sort((a, b) => a - b)
82
+ .map((idx) => keys[idx] ?? '')
83
+ .filter(Boolean)
84
+ })
85
+ }
86
+
69
87
  export function decodeCraftedItemStats(itemId: number, stats: bigint): Record<string, number> {
70
88
  const keys = getItemStatKeys(itemId)
71
89
  const result: Record<string, number> = {}
@@ -15,13 +15,11 @@ import {
15
15
  ITEM_CRAFTER_T1,
16
16
  ITEM_BUILDER_T1,
17
17
  ITEM_EXTRACTOR_T1_PACKED,
18
- ITEM_ROUSTABOUT_T1_PACKED,
19
- ITEM_PROSPECTOR_T1_PACKED,
20
- ITEM_TENDER_T1_PACKED,
21
- ITEM_TUG_T1_PACKED,
22
- ITEM_PORTER_T1_PACKED,
23
- ITEM_WRANGLER_T1_PACKED,
24
- ITEM_DREDGER_T1_PACKED,
18
+ ITEM_ROUSTABOUT_T1A_PACKED,
19
+ ITEM_PROSPECTOR_T1A_PACKED,
20
+ ITEM_TENDER_T1A_PACKED,
21
+ ITEM_TUG_T1A_PACKED,
22
+ ITEM_PORTER_T1A_PACKED,
25
23
  } from '../data/item-ids'
26
24
 
27
25
  test('getAllRecipes returns the full catalog including the gatherer', () => {
@@ -38,7 +36,7 @@ test('getRecipeConsumers lists every recipe that consumes Sensor', () => {
38
36
  ITEM_CRAFTER_T1,
39
37
  ITEM_BUILDER_T1,
40
38
  ITEM_EXTRACTOR_T1_PACKED,
41
- ITEM_ROUSTABOUT_T1_PACKED,
39
+ ITEM_ROUSTABOUT_T1A_PACKED,
42
40
  ].sort((a, b) => a - b)
43
41
  )
44
42
  })
@@ -82,9 +80,9 @@ test('getResourceDemand scales by quantity', () => {
82
80
  expect(getResourceDemand(ITEM_PLATE, 3)).toEqual({ore: 30})
83
81
  })
84
82
 
85
- test('getComponentDemand reports Resin as consumed by nine recipes', () => {
83
+ test('getComponentDemand reports Resin as consumed by eight recipes', () => {
86
84
  const demand = getComponentDemand()
87
85
  const resin = demand.find((d) => d.itemId === ITEM_RESIN)
88
86
  expect(resin).toBeDefined()
89
- expect(resin?.consumerCount).toBe(9)
87
+ expect(resin?.consumerCount).toBe(8)
90
88
  })
@@ -319,7 +319,11 @@ export {
319
319
  availableForItem,
320
320
  cargoReadyAt,
321
321
  taskCargoEffect,
322
+ calcCounterpartDelivery,
323
+ cargoKey,
324
+ cargoInputKey,
322
325
  } from './scheduling/availability'
326
+ export type {CargoInput, IncomingSource} from './scheduling/availability'
323
327
 
324
328
  export {maxCraftable} from './capabilities/craftable'
325
329
 
@@ -412,6 +416,7 @@ export {
412
416
  decodeStat,
413
417
  decodeStats,
414
418
  decodeCraftedItemStats,
419
+ usedInputStatKeys,
415
420
  blendStacks,
416
421
  computeComponentStats,
417
422
  blendComponentStacks,
@@ -23,23 +23,23 @@ import {
23
23
  ITEM_GATHERER_T1,
24
24
  ITEM_GATHERER_T2,
25
25
  ITEM_GENERATOR_T1,
26
- ITEM_HAULER_SHIP_T2_PACKED,
27
26
  ITEM_HAULER_T1,
28
27
  ITEM_HAULER_T2,
29
28
  ITEM_BATTERY_T1,
30
29
  ITEM_LAUNCHER_T1,
31
30
  ITEM_LOADER_T1,
32
- ITEM_PROSPECTOR_T1_PACKED,
33
- ITEM_PROSPECTOR_T2_PACKED,
34
- ITEM_ROUSTABOUT_T1_PACKED,
31
+ ITEM_PROSPECTOR_T1A_PACKED,
32
+ ITEM_PROSPECTOR_T2A_PACKED,
33
+ ITEM_PROSPECTOR_T2B_PACKED,
34
+ ITEM_ROUSTABOUT_T1A_PACKED,
35
35
  ITEM_SHIP_T1_PACKED,
36
+ ITEM_SMITH_T1A_PACKED,
36
37
  ITEM_STORAGE_T1,
37
- ITEM_TENDER_T1_PACKED,
38
- ITEM_TUG_T1_PACKED,
39
- ITEM_PORTER_T1_PACKED,
40
- ITEM_WRANGLER_T1_PACKED,
41
- ITEM_WRIGHT_T1_PACKED,
42
- ITEM_DREDGER_T1_PACKED,
38
+ ITEM_TENDER_T1A_PACKED,
39
+ ITEM_TUG_T1A_PACKED,
40
+ ITEM_PORTER_T1A_PACKED,
41
+ ITEM_WRIGHT_T1A_PACKED,
42
+ ITEM_DREDGER_T2A_PACKED,
43
43
  ITEM_WAREHOUSE_T1_PACKED,
44
44
  ITEM_WARP_T1,
45
45
  } from '../data/item-ids'
@@ -149,22 +149,20 @@ export function entityDisplayName(itemId: number): string {
149
149
  switch (itemId) {
150
150
  case ITEM_SHIP_T1_PACKED:
151
151
  return 'Ship'
152
- case ITEM_ROUSTABOUT_T1_PACKED:
152
+ case ITEM_ROUSTABOUT_T1A_PACKED:
153
153
  return 'Roustabout'
154
- case ITEM_PROSPECTOR_T1_PACKED:
154
+ case ITEM_PROSPECTOR_T1A_PACKED:
155
155
  return 'Prospector'
156
- case ITEM_TENDER_T1_PACKED:
156
+ case ITEM_TENDER_T1A_PACKED:
157
157
  return 'Tender'
158
- case ITEM_TUG_T1_PACKED:
158
+ case ITEM_TUG_T1A_PACKED:
159
159
  return 'Tug'
160
- case ITEM_PORTER_T1_PACKED:
160
+ case ITEM_PORTER_T1A_PACKED:
161
161
  return 'Porter'
162
- case ITEM_WRANGLER_T1_PACKED:
163
- return 'Wrangler'
164
- case ITEM_WRIGHT_T1_PACKED:
162
+ case ITEM_WRIGHT_T1A_PACKED:
165
163
  return 'Wright'
166
- case ITEM_DREDGER_T1_PACKED:
167
- return 'Dredger'
164
+ case ITEM_SMITH_T1A_PACKED:
165
+ return 'Smith'
168
166
  case ITEM_WAREHOUSE_T1_PACKED:
169
167
  return 'Warehouse'
170
168
  case ITEM_EXTRACTOR_T1_PACKED:
@@ -177,10 +175,12 @@ export function entityDisplayName(itemId: number): string {
177
175
  return 'Container'
178
176
  case ITEM_CONTAINER_T2_PACKED:
179
177
  return 'Container'
180
- case ITEM_PROSPECTOR_T2_PACKED:
178
+ case ITEM_PROSPECTOR_T2A_PACKED:
181
179
  return 'Prospector'
182
- case ITEM_HAULER_SHIP_T2_PACKED:
183
- return 'Tug'
180
+ case ITEM_PROSPECTOR_T2B_PACKED:
181
+ return 'Prospector'
182
+ case ITEM_DREDGER_T2A_PACKED:
183
+ return 'Dredger'
184
184
  default:
185
185
  return 'Entity'
186
186
  }
@@ -8,6 +8,7 @@ import {entityMetadata, itemMetadata} from '../data/metadata'
8
8
  import {
9
9
  getModuleCapabilityType,
10
10
  isModuleItem,
11
+ MODULE_BUILDER,
11
12
  MODULE_CRAFTER,
12
13
  MODULE_ENGINE,
13
14
  MODULE_BATTERY,
@@ -21,6 +22,7 @@ import {decodeCraftedItemStats, decodeStat} from '../derivation/crafting'
21
22
  import {getStatDefinitions} from '../derivation/stats'
22
23
  import {
23
24
  computeCrafterCapabilities,
25
+ computeBuilderCapabilities,
24
26
  computeBatteryCapabilities,
25
27
  computeEngineCapabilities,
26
28
  computeGathererCapabilities,
@@ -210,6 +212,16 @@ function computeCapabilityGroup(
210
212
  ],
211
213
  }
212
214
  }
215
+ case MODULE_BUILDER: {
216
+ const caps = computeBuilderCapabilities(stats)
217
+ return {
218
+ capability: 'Build',
219
+ attributes: [
220
+ {label: 'Speed', value: caps.speed},
221
+ {label: 'Drain', value: toWholeEnergy(caps.drain)},
222
+ ],
223
+ }
224
+ }
213
225
  case MODULE_HAULER: {
214
226
  const caps = computeHaulerCapabilities(stats, tier)
215
227
  return {