@shipload/sdk 2.0.0-rc13 → 2.0.0-rc15

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.
@@ -96,39 +96,39 @@ export const components: ComponentDefinition[] = [
96
96
  {
97
97
  id: ITEM_HULL_PLATES,
98
98
  name: 'Hull Plates',
99
- description: 'Structural plating formed from metal. Used in hulls, containers, and frames.',
99
+ description: 'Structural plating formed from ore. Used in hulls, containers, and frames.',
100
100
  color: '#7B8D9E',
101
101
  mass: 50000,
102
102
  stats: [
103
- {key: 'strength', source: 'metal'},
104
- {key: 'density', source: 'metal'},
103
+ {key: 'strength', source: 'ore'},
104
+ {key: 'density', source: 'ore'},
105
105
  ],
106
- recipe: [{category: 'metal', quantity: 15}],
106
+ recipe: [{category: 'ore', quantity: 15}],
107
107
  usedIn: [
108
108
  {type: 'entity', name: 'Container'},
109
- {type: 'entity', name: 'Warehouse T1'},
110
- {type: 'entity', name: 'Ship T1'},
109
+ {type: 'entity', name: 'Warehouse'},
110
+ {type: 'entity', name: 'Ship'},
111
111
  ],
112
112
  },
113
113
  {
114
114
  id: ITEM_CARGO_LINING,
115
115
  name: 'Cargo Lining',
116
116
  description:
117
- 'Precision-formed composite lining for cargo storage. Combines precious metal shaping with organic sealing.',
118
- color: '#D4A843',
117
+ 'Composite lining formed from fine regolith bound in biomass polymer. Dense enough to seal cargo holds, flexible enough to absorb vibration.',
118
+ color: '#C4A57B',
119
119
  mass: 30000,
120
120
  stats: [
121
- {key: 'ductility', source: 'precious'},
122
- {key: 'purity', source: 'organic'},
121
+ {key: 'fineness', source: 'regolith'},
122
+ {key: 'saturation', source: 'biomass'},
123
123
  ],
124
124
  recipe: [
125
- {category: 'precious', quantity: 6},
126
- {category: 'organic', quantity: 14},
125
+ {category: 'regolith' as ResourceCategory, quantity: 10},
126
+ {category: 'biomass' as ResourceCategory, quantity: 20},
127
127
  ],
128
128
  usedIn: [
129
129
  {type: 'entity', name: 'Container'},
130
- {type: 'entity', name: 'Warehouse T1'},
131
- {type: 'entity', name: 'Ship T1'},
130
+ {type: 'module', name: 'Loader'},
131
+ {type: 'module', name: 'Storage'},
132
132
  ],
133
133
  },
134
134
  {
@@ -147,73 +147,76 @@ export const components: ComponentDefinition[] = [
147
147
  {
148
148
  id: ITEM_POWER_CELL,
149
149
  name: 'Power Cell',
150
- description: 'Crystalline energy storage matrix formed from resonant minerals.',
151
- color: '#7B5AE8',
150
+ description: 'Crystalline energy storage matrix. Resonant lattices retain and release charge.',
151
+ color: '#4ADBFF',
152
152
  mass: 30000,
153
153
  stats: [
154
- {key: 'resonance', source: 'mineral'},
155
- {key: 'clarity', source: 'mineral'},
154
+ {key: 'resonance', source: 'crystal'},
155
+ {key: 'reflectivity', source: 'crystal'},
156
+ ],
157
+ recipe: [{category: 'crystal' as ResourceCategory, quantity: 20}],
158
+ usedIn: [
159
+ {type: 'module', name: 'Generator'},
160
+ {type: 'module', name: 'Hauler'},
156
161
  ],
157
- recipe: [{category: 'mineral' as ResourceCategory, quantity: 20}],
158
- usedIn: [{type: 'module', name: 'Generator'}],
159
162
  },
160
163
  {
161
164
  id: ITEM_MATTER_CONDUIT,
162
165
  name: 'Matter Conduit',
163
- description: 'Heavy-duty metal shaft used in gathering equipment.',
166
+ description: 'Heavy-duty ore shaft used in gathering equipment.',
164
167
  color: '#7B8D9E',
165
168
  mass: 50000,
166
169
  stats: [
167
- {key: 'strength', source: 'metal'},
168
- {key: 'tolerance', source: 'metal'},
170
+ {key: 'strength', source: 'ore'},
171
+ {key: 'tolerance', source: 'ore'},
169
172
  ],
170
- recipe: [{category: 'metal' as ResourceCategory, quantity: 15}],
173
+ recipe: [{category: 'ore' as ResourceCategory, quantity: 15}],
171
174
  usedIn: [{type: 'module', name: 'Gatherer'}],
172
175
  },
173
176
  {
174
177
  id: ITEM_SURVEY_PROBE,
175
178
  name: 'Survey Probe',
176
- description: 'Precious metal sensor array for deep resource detection.',
177
- color: '#D4A843',
179
+ description: 'Crystal-lattice sensor array for deep resource detection.',
180
+ color: '#4ADBFF',
178
181
  mass: 30000,
179
182
  stats: [
180
- {key: 'conductivity', source: 'precious'},
181
- {key: 'reflectivity', source: 'precious'},
183
+ {key: 'conductivity', source: 'crystal'},
184
+ {key: 'reflectivity', source: 'crystal'},
182
185
  ],
183
- recipe: [{category: 'precious' as ResourceCategory, quantity: 10}],
186
+ recipe: [{category: 'crystal' as ResourceCategory, quantity: 10}],
184
187
  usedIn: [{type: 'module', name: 'Gatherer'}],
185
188
  },
186
189
  {
187
190
  id: ITEM_CARGO_ARM,
188
191
  name: 'Cargo Arm',
189
- description: 'Flexible organic composite arm for cargo handling.',
190
- color: '#6B8E5A',
192
+ description: 'Flexible biomass composite arm for cargo handling.',
193
+ color: '#5A8B3E',
191
194
  mass: 30000,
192
195
  stats: [
193
- {key: 'plasticity', source: 'organic'},
194
- {key: 'insulation', source: 'organic'},
196
+ {key: 'plasticity', source: 'biomass'},
197
+ {key: 'insulation', source: 'biomass'},
195
198
  ],
196
- recipe: [{category: 'organic' as ResourceCategory, quantity: 32}],
199
+ recipe: [{category: 'biomass' as ResourceCategory, quantity: 32}],
197
200
  usedIn: [{type: 'module', name: 'Loader'}],
198
201
  },
199
202
  {
200
203
  id: ITEM_TOOL_BIT,
201
204
  name: 'Tool Bit',
202
- description: 'Dense mineral cutting head for manufacturing operations.',
203
- color: '#B8A9C9',
205
+ description: 'Dense regolith cutting head for manufacturing operations.',
206
+ color: '#C4A57B',
204
207
  mass: 30000,
205
208
  stats: [
206
- {key: 'hardness', source: 'mineral'},
207
- {key: 'clarity', source: 'mineral'},
209
+ {key: 'hardness', source: 'regolith'},
210
+ {key: 'composition', source: 'regolith'},
208
211
  ],
209
- recipe: [{category: 'mineral' as ResourceCategory, quantity: 20}],
212
+ recipe: [{category: 'regolith' as ResourceCategory, quantity: 20}],
210
213
  usedIn: [{type: 'module', name: 'Manufacturing'}],
211
214
  },
212
215
  {
213
216
  id: ITEM_REACTION_CHAMBER,
214
217
  name: 'Reaction Chamber',
215
218
  description: 'Gas-pressurized vessel for controlled manufacturing reactions.',
216
- color: '#7EC8E3',
219
+ color: '#B8E4A0',
217
220
  mass: 50000,
218
221
  stats: [
219
222
  {key: 'reactivity', source: 'gas'},
@@ -226,48 +229,48 @@ export const components: ComponentDefinition[] = [
226
229
  id: ITEM_FOCUSING_ARRAY,
227
230
  name: 'Focusing Array',
228
231
  description:
229
- "Precision-formed precious-metal lens array. Routes the haul beam's energy efficiently to the target lock.",
230
- color: '#D4A843',
232
+ "Precision-formed crystal lens array. Routes the haul beam's energy efficiently to the target lock.",
233
+ color: '#4ADBFF',
231
234
  mass: 40000,
232
235
  stats: [
233
- {key: 'conductivity', source: 'precious'},
234
- {key: 'ductility', source: 'precious'},
236
+ {key: 'conductivity', source: 'crystal'},
237
+ {key: 'resonance', source: 'crystal'},
235
238
  ],
236
- recipe: [{category: 'precious' as ResourceCategory, quantity: 25}],
237
- usedIn: [{type: 'module', name: 'Hauler Module T1'}],
239
+ recipe: [{category: 'crystal' as ResourceCategory, quantity: 25}],
240
+ usedIn: [{type: 'module', name: 'Hauler'}],
238
241
  },
239
242
  {
240
243
  id: ITEM_HULL_PLATES_T2,
241
244
  name: 'Hull Plates T2',
242
- description: 'Advanced structural plating reinforced with tier 2 metals.',
245
+ description: 'Advanced structural plating reinforced with tier 2 ore.',
243
246
  color: '#9BADB8',
244
247
  mass: 50000,
245
248
  stats: [
246
- {key: 'strength', source: 'metal'},
247
- {key: 'density', source: 'metal'},
249
+ {key: 'strength', source: 'ore'},
250
+ {key: 'density', source: 'ore'},
248
251
  ],
249
252
  recipe: [
250
253
  {itemId: ITEM_HULL_PLATES, quantity: 2},
251
- {category: 'metal', quantity: 15},
254
+ {category: 'ore', quantity: 15},
252
255
  ],
253
- usedIn: [{type: 'entity', name: 'Container T2'}],
256
+ usedIn: [{type: 'entity', name: 'Container'}],
254
257
  },
255
258
  {
256
259
  id: ITEM_CARGO_LINING_T2,
257
- name: 'Cargo Lining T2',
258
- description: 'Advanced composite lining with improved storage properties.',
259
- color: '#E0B84D',
260
- mass: 30000,
260
+ name: 'Cargo Lining',
261
+ description: 'Advanced composite lining reinforced with tier 2 regolith and biomass polymer.',
262
+ color: '#C4A57B',
263
+ mass: 45000,
261
264
  stats: [
262
- {key: 'ductility', source: 'precious'},
263
- {key: 'purity', source: 'organic'},
265
+ {key: 'fineness', source: 'regolith'},
266
+ {key: 'saturation', source: 'biomass'},
264
267
  ],
265
268
  recipe: [
266
269
  {itemId: ITEM_CARGO_LINING, quantity: 2},
267
- {category: 'precious', quantity: 6},
268
- {category: 'organic', quantity: 14},
270
+ {category: 'regolith' as ResourceCategory, quantity: 5},
271
+ {category: 'biomass' as ResourceCategory, quantity: 10},
269
272
  ],
270
- usedIn: [{type: 'entity', name: 'Container T2'}],
273
+ usedIn: [{type: 'entity', name: 'Container'}],
271
274
  },
272
275
  ]
273
276
 
@@ -285,13 +288,13 @@ export const entityRecipes: EntityRecipe[] = [
285
288
  stats: [
286
289
  {key: 'strength', sourceComponentId: ITEM_HULL_PLATES, sourceStatKey: 'strength'},
287
290
  {key: 'density', sourceComponentId: ITEM_HULL_PLATES, sourceStatKey: 'density'},
288
- {key: 'ductility', sourceComponentId: ITEM_CARGO_LINING, sourceStatKey: 'ductility'},
289
- {key: 'purity', sourceComponentId: ITEM_CARGO_LINING, sourceStatKey: 'purity'},
291
+ {key: 'fineness', sourceComponentId: ITEM_CARGO_LINING, sourceStatKey: 'fineness'},
292
+ {key: 'saturation', sourceComponentId: ITEM_CARGO_LINING, sourceStatKey: 'saturation'},
290
293
  ],
291
294
  },
292
295
  {
293
296
  id: 'ship-t1',
294
- name: 'Ship T1',
297
+ name: 'Ship',
295
298
  description: 'General-purpose vessel with 5 module slots.',
296
299
  color: '#4AE898',
297
300
  packedItemId: ITEM_SHIP_T1_PACKED,
@@ -302,8 +305,8 @@ export const entityRecipes: EntityRecipe[] = [
302
305
  stats: [
303
306
  {key: 'strength', sourceComponentId: ITEM_HULL_PLATES, sourceStatKey: 'strength'},
304
307
  {key: 'density', sourceComponentId: ITEM_HULL_PLATES, sourceStatKey: 'density'},
305
- {key: 'ductility', sourceComponentId: ITEM_CARGO_LINING, sourceStatKey: 'ductility'},
306
- {key: 'purity', sourceComponentId: ITEM_CARGO_LINING, sourceStatKey: 'purity'},
308
+ {key: 'fineness', sourceComponentId: ITEM_CARGO_LINING, sourceStatKey: 'fineness'},
309
+ {key: 'saturation', sourceComponentId: ITEM_CARGO_LINING, sourceStatKey: 'saturation'},
307
310
  ],
308
311
  moduleSlots: [
309
312
  {type: MODULE_ANY},
@@ -315,7 +318,7 @@ export const entityRecipes: EntityRecipe[] = [
315
318
  },
316
319
  {
317
320
  id: 'warehouse-t1',
318
- name: 'Warehouse T1',
321
+ name: 'Warehouse',
319
322
  description: 'Massive stationary storage facility with a single loader module slot.',
320
323
  color: '#EAB308',
321
324
  packedItemId: ITEM_WAREHOUSE_T1_PACKED,
@@ -326,8 +329,8 @@ export const entityRecipes: EntityRecipe[] = [
326
329
  stats: [
327
330
  {key: 'strength', sourceComponentId: ITEM_HULL_PLATES, sourceStatKey: 'strength'},
328
331
  {key: 'density', sourceComponentId: ITEM_HULL_PLATES, sourceStatKey: 'density'},
329
- {key: 'ductility', sourceComponentId: ITEM_CARGO_LINING, sourceStatKey: 'ductility'},
330
- {key: 'purity', sourceComponentId: ITEM_CARGO_LINING, sourceStatKey: 'purity'},
332
+ {key: 'fineness', sourceComponentId: ITEM_CARGO_LINING, sourceStatKey: 'fineness'},
333
+ {key: 'saturation', sourceComponentId: ITEM_CARGO_LINING, sourceStatKey: 'saturation'},
331
334
  ],
332
335
  moduleSlots: [
333
336
  {type: MODULE_LOADER, label: 'Loader'},
@@ -339,7 +342,7 @@ export const entityRecipes: EntityRecipe[] = [
339
342
  },
340
343
  {
341
344
  id: 'container-t2',
342
- name: 'Container T2',
345
+ name: 'Container',
343
346
  description: 'Advanced cargo container with improved capacity formulas.',
344
347
  color: '#9BADB8',
345
348
  packedItemId: ITEM_CONTAINER_T2_PACKED,
@@ -350,8 +353,12 @@ export const entityRecipes: EntityRecipe[] = [
350
353
  stats: [
351
354
  {key: 'strength', sourceComponentId: ITEM_HULL_PLATES_T2, sourceStatKey: 'strength'},
352
355
  {key: 'density', sourceComponentId: ITEM_HULL_PLATES_T2, sourceStatKey: 'density'},
353
- {key: 'ductility', sourceComponentId: ITEM_CARGO_LINING_T2, sourceStatKey: 'ductility'},
354
- {key: 'purity', sourceComponentId: ITEM_CARGO_LINING_T2, sourceStatKey: 'purity'},
356
+ {key: 'fineness', sourceComponentId: ITEM_CARGO_LINING_T2, sourceStatKey: 'fineness'},
357
+ {
358
+ key: 'saturation',
359
+ sourceComponentId: ITEM_CARGO_LINING_T2,
360
+ sourceStatKey: 'saturation',
361
+ },
355
362
  ],
356
363
  },
357
364
  ]
@@ -384,14 +391,14 @@ export const moduleRecipes: ModuleRecipe[] = [
384
391
  {
385
392
  id: 'generator-t1',
386
393
  name: 'Generator',
387
- description: 'Basic energy system. Stores and recharges energy from resonant minerals.',
388
- color: '#7B5AE8',
394
+ description: 'Basic energy system. Stores and recharges energy from resonant crystals.',
395
+ color: '#4ADBFF',
389
396
  itemId: ITEM_GENERATOR_T1,
390
397
  moduleType: MODULE_GENERATOR,
391
398
  recipe: [{itemId: ITEM_POWER_CELL, quantity: 5}],
392
399
  stats: [
393
400
  {key: 'resonance', sourceComponentId: ITEM_POWER_CELL, sourceStatKey: 'resonance'},
394
- {key: 'clarity', sourceComponentId: ITEM_POWER_CELL, sourceStatKey: 'clarity'},
401
+ {key: 'reflectivity', sourceComponentId: ITEM_POWER_CELL, sourceStatKey: 'reflectivity'},
395
402
  ],
396
403
  },
397
404
  {
@@ -429,7 +436,7 @@ export const moduleRecipes: ModuleRecipe[] = [
429
436
  id: 'loader-t1',
430
437
  name: 'Loader',
431
438
  description: 'Basic cargo handling system. Loads and unloads cargo with articulated arms.',
432
- color: '#6B8E5A',
439
+ color: '#5A8B3E',
433
440
  itemId: ITEM_LOADER_T1,
434
441
  moduleType: MODULE_LOADER,
435
442
  recipe: [
@@ -437,7 +444,7 @@ export const moduleRecipes: ModuleRecipe[] = [
437
444
  {itemId: ITEM_CARGO_ARM, quantity: 3},
438
445
  ],
439
446
  stats: [
440
- {key: 'ductility', sourceComponentId: ITEM_CARGO_LINING, sourceStatKey: 'ductility'},
447
+ {key: 'fineness', sourceComponentId: ITEM_CARGO_LINING, sourceStatKey: 'fineness'},
441
448
  {key: 'plasticity', sourceComponentId: ITEM_CARGO_ARM, sourceStatKey: 'plasticity'},
442
449
  ],
443
450
  },
@@ -446,7 +453,7 @@ export const moduleRecipes: ModuleRecipe[] = [
446
453
  name: 'Manufacturing',
447
454
  description:
448
455
  'Basic crafting system. Processes materials using reaction chambers and cutting tools.',
449
- color: '#7EC8E3',
456
+ color: '#B8E4A0',
450
457
  itemId: ITEM_MANUFACTURING_T1,
451
458
  moduleType: MODULE_CRAFTER,
452
459
  recipe: [
@@ -459,7 +466,7 @@ export const moduleRecipes: ModuleRecipe[] = [
459
466
  sourceComponentId: ITEM_REACTION_CHAMBER,
460
467
  sourceStatKey: 'reactivity',
461
468
  },
462
- {key: 'clarity', sourceComponentId: ITEM_TOOL_BIT, sourceStatKey: 'clarity'},
469
+ {key: 'composition', sourceComponentId: ITEM_TOOL_BIT, sourceStatKey: 'composition'},
463
470
  ],
464
471
  },
465
472
  {
@@ -475,17 +482,17 @@ export const moduleRecipes: ModuleRecipe[] = [
475
482
  ],
476
483
  stats: [
477
484
  {key: 'strength', sourceComponentId: ITEM_HULL_PLATES, sourceStatKey: 'strength'},
478
- {key: 'ductility', sourceComponentId: ITEM_HULL_PLATES, sourceStatKey: 'ductility'},
479
- {key: 'purity', sourceComponentId: ITEM_CARGO_LINING, sourceStatKey: 'purity'},
480
- {key: 'density', sourceComponentId: ITEM_CARGO_LINING, sourceStatKey: 'density'},
485
+ {key: 'density', sourceComponentId: ITEM_HULL_PLATES, sourceStatKey: 'density'},
486
+ {key: 'fineness', sourceComponentId: ITEM_CARGO_LINING, sourceStatKey: 'fineness'},
487
+ {key: 'saturation', sourceComponentId: ITEM_CARGO_LINING, sourceStatKey: 'saturation'},
481
488
  ],
482
489
  },
483
490
  {
484
491
  id: 'hauler-t1',
485
- name: 'Hauler Module T1',
492
+ name: 'Hauler',
486
493
  description:
487
494
  'Projects a haul beam to lock onto and transport containers or warehouses through group travel.',
488
- color: '#D4A843',
495
+ color: '#4ADBFF',
489
496
  itemId: ITEM_HAULER_T1,
490
497
  moduleType: MODULE_HAULER,
491
498
  recipe: [
@@ -493,14 +500,13 @@ export const moduleRecipes: ModuleRecipe[] = [
493
500
  {itemId: ITEM_FOCUSING_ARRAY, quantity: 3},
494
501
  ],
495
502
  stats: [
496
- {key: 'capacity', sourceComponentId: ITEM_POWER_CELL, sourceStatKey: 'resonance'},
503
+ {key: 'resonance', sourceComponentId: ITEM_POWER_CELL, sourceStatKey: 'resonance'},
504
+ {key: 'reflectivity', sourceComponentId: ITEM_POWER_CELL, sourceStatKey: 'reflectivity'},
497
505
  {
498
- key: 'efficiency',
506
+ key: 'conductivity',
499
507
  sourceComponentId: ITEM_FOCUSING_ARRAY,
500
508
  sourceStatKey: 'conductivity',
501
509
  },
502
- {key: 'drain', sourceComponentId: ITEM_POWER_CELL, sourceStatKey: 'clarity'},
503
- {key: 'ductility', sourceComponentId: ITEM_FOCUSING_ARRAY, sourceStatKey: 'ductility'},
504
510
  ],
505
511
  },
506
512
  ]
@@ -22,27 +22,27 @@ export interface CategoryStacks {
22
22
  }
23
23
 
24
24
  export function encodeStats(values: number[]): bigint {
25
- let seed = 0n
25
+ let stats = 0n
26
26
  for (let i = 0; i < values.length && i < 6; i++) {
27
- seed |= BigInt(values[i] & 0x3ff) << BigInt(i * 10)
27
+ stats |= BigInt(values[i] & 0x3ff) << BigInt(i * 10)
28
28
  }
29
- return seed
29
+ return stats
30
30
  }
31
31
 
32
- export function decodeStat(seed: bigint, index: number): number {
33
- return Number((seed >> BigInt(index * 10)) & 0x3ffn)
32
+ export function decodeStat(stats: bigint, index: number): number {
33
+ return Number((stats >> BigInt(index * 10)) & 0x3ffn)
34
34
  }
35
35
 
36
- export function decodeStats(seed: bigint, count: number): number[] {
37
- const stats: number[] = []
36
+ export function decodeStats(stats: bigint, count: number): number[] {
37
+ const result: number[] = []
38
38
  for (let i = 0; i < count; i++) {
39
- stats.push(decodeStat(seed, i))
39
+ result.push(decodeStat(stats, i))
40
40
  }
41
- return stats
41
+ return result
42
42
  }
43
43
 
44
- function mapStatsToKeys(seed: bigint, statDefs: {key: string}[]): Record<string, number> {
45
- const values = decodeStats(seed, statDefs.length)
44
+ function mapStatsToKeys(stats: bigint, statDefs: {key: string}[]): Record<string, number> {
45
+ const values = decodeStats(stats, statDefs.length)
46
46
  const result: Record<string, number> = {}
47
47
  for (let i = 0; i < statDefs.length; i++) {
48
48
  result[statDefs[i].key] = values[i]
@@ -50,15 +50,15 @@ function mapStatsToKeys(seed: bigint, statDefs: {key: string}[]): Record<string,
50
50
  return result
51
51
  }
52
52
 
53
- export function decodeCraftedItemStats(itemId: number, seed: bigint): Record<string, number> {
53
+ export function decodeCraftedItemStats(itemId: number, stats: bigint): Record<string, number> {
54
54
  const comp = getComponentById(itemId)
55
- if (comp) return mapStatsToKeys(seed, comp.stats)
55
+ if (comp) return mapStatsToKeys(stats, comp.stats)
56
56
 
57
57
  const entityRecipe = entityRecipes.find((r) => r.packedItemId === itemId)
58
- if (entityRecipe) return mapStatsToKeys(seed, entityRecipe.stats)
58
+ if (entityRecipe) return mapStatsToKeys(stats, entityRecipe.stats)
59
59
 
60
60
  const moduleRecipe = moduleRecipes.find((r) => r.itemId === itemId)
61
- if (moduleRecipe) return mapStatsToKeys(seed, moduleRecipe.stats)
61
+ if (moduleRecipe) return mapStatsToKeys(stats, moduleRecipe.stats)
62
62
 
63
63
  return {}
64
64
  }
@@ -126,20 +126,20 @@ export function computeEntityStats(
126
126
  })
127
127
  }
128
128
 
129
- function decodeStackStats(itemId: number, seed: UInt64): Record<string, number> {
129
+ function decodeStackStats(itemId: number, stats: UInt64): Record<string, number> {
130
130
  if (itemId >= 10000) {
131
- return decodeCraftedItemStats(itemId, BigInt(seed.toString()))
131
+ return decodeCraftedItemStats(itemId, BigInt(stats.toString()))
132
132
  }
133
- const raw = deriveResourceStats(BigInt(seed.toString()))
134
- return {stat1: raw.stat1, stat2: raw.stat2, stat3: raw.stat3}
133
+ const s = BigInt(stats.toString())
134
+ return {stat1: decodeStat(s, 0), stat2: decodeStat(s, 1), stat3: decodeStat(s, 2)}
135
135
  }
136
136
 
137
137
  export const categoryItemMass: Record<string, number> = {
138
- metal: 30000,
139
- precious: 40000,
138
+ ore: 30000,
139
+ crystal: 40000,
140
140
  gas: 15000,
141
- mineral: 22000,
142
- organic: 15000,
141
+ regolith: 22000,
142
+ biomass: 15000,
143
143
  }
144
144
 
145
145
  export function computeInputMass(
@@ -187,11 +187,11 @@ export function blendCrossGroup(sources: {value: number; weight: number}[]): num
187
187
 
188
188
  export function blendCargoStacks(
189
189
  itemId: number,
190
- stacks: {quantity: number; seed: UInt64}[]
190
+ stacks: {quantity: number; stats: UInt64}[]
191
191
  ): UInt64 {
192
192
  const decoded = stacks.map((s) => ({
193
193
  quantity: s.quantity,
194
- stats: decodeStackStats(itemId, s.seed),
194
+ stats: decodeStackStats(itemId, s.stats),
195
195
  }))
196
196
  const allKeys = Object.keys(decoded[0]?.stats ?? {})
197
197
  const blended = allKeys.map((key) => Math.max(1, Math.min(999, blendStacks(decoded, key))))
@@ -201,23 +201,22 @@ export function blendCargoStacks(
201
201
  export interface RecipeSlotInput {
202
202
  itemId: number
203
203
  category: ResourceCategory | undefined
204
- stacks: {quantity: number; seed: bigint}[]
204
+ stacks: {quantity: number; stats: bigint}[]
205
205
  }
206
206
 
207
207
  function decodeRawStackToCategoryStats(
208
- seed: bigint,
208
+ stats: bigint,
209
209
  category: ResourceCategory
210
210
  ): Record<string, number> {
211
- const raw = deriveResourceStats(seed)
212
211
  const defs = getStatDefinitions(category)
213
212
  const result: Record<string, number> = {}
214
- if (defs[0]) result[defs[0].key] = raw.stat1
215
- if (defs[1]) result[defs[1].key] = raw.stat2
216
- if (defs[2]) result[defs[2].key] = raw.stat3
213
+ if (defs[0]) result[defs[0].key] = decodeStat(stats, 0)
214
+ if (defs[1]) result[defs[1].key] = decodeStat(stats, 1)
215
+ if (defs[2]) result[defs[2].key] = decodeStat(stats, 2)
217
216
  return result
218
217
  }
219
218
 
220
- export function computeCraftedOutputSeed(
219
+ export function computeCraftedOutputStats(
221
220
  outputItemId: number,
222
221
  slotInputs: RecipeSlotInput[]
223
222
  ): UInt64 {
@@ -230,8 +229,8 @@ export function computeCraftedOutputSeed(
230
229
  const stacks: StackInput[] = slot.stacks.map((s) => ({
231
230
  quantity: s.quantity,
232
231
  stats: slotIsComponent
233
- ? decodeCraftedItemStats(slot.itemId, s.seed)
234
- : decodeRawStackToCategoryStats(s.seed, slot.category!),
232
+ ? decodeCraftedItemStats(slot.itemId, s.stats)
233
+ : decodeRawStackToCategoryStats(s.stats, slot.category!),
235
234
  }))
236
235
  categoryStacks.push({category: slot.category, stacks})
237
236
  }
@@ -257,7 +256,7 @@ export function computeCraftedOutputSeed(
257
256
  for (const s of slot.stacks) {
258
257
  list.push({
259
258
  quantity: s.quantity,
260
- stats: decodeCraftedItemStats(slot.itemId, s.seed),
259
+ stats: decodeCraftedItemStats(slot.itemId, s.stats),
261
260
  })
262
261
  }
263
262
  }
@@ -269,5 +268,20 @@ export function computeCraftedOutputSeed(
269
268
  return UInt64.from(encodeStats(ordered))
270
269
  }
271
270
 
272
- throw new Error(`computeCraftedOutputSeed: no recipe found for outputItemId=${outputItemId}`)
271
+ throw new Error(`computeCraftedOutputStats: no recipe found for outputItemId=${outputItemId}`)
272
+ }
273
+
274
+ /**
275
+ * Mirrors the contract's gather-time transform. Takes a deposit's entropy
276
+ * seed (bigint from deriveStratum), derives stats via weibull hashing, and
277
+ * returns a UInt64 whose bit-packed form matches what the contract writes
278
+ * to cargo_item.stats on gather.
279
+ *
280
+ * Use this whenever off-chain code simulates a gather (testmap, player
281
+ * scanners that project cargo outcomes) and needs a value that matches
282
+ * what on-chain cargo would carry.
283
+ */
284
+ export function encodeGatheredCargoStats(depositSeed: bigint): UInt64 {
285
+ const raw = deriveResourceStats(depositSeed)
286
+ return UInt64.from(encodeStats([raw.stat1, raw.stat2, raw.stat3]))
273
287
  }
@@ -24,21 +24,21 @@ interface ResourceEntry {
24
24
  }
25
25
 
26
26
  const RESOURCE_CATALOG: ResourceEntry[] = [
27
- {id: 26, tier: 't1'},
28
- {id: 13, tier: 't2'},
29
- {id: 24, tier: 't3'},
30
- {id: 29, tier: 't1'},
31
- {id: 47, tier: 't2'},
32
- {id: 79, tier: 't3'},
33
- {id: 1, tier: 't1'},
34
- {id: 2, tier: 't2'},
35
- {id: 18, tier: 't3'},
36
- {id: 14, tier: 't1'},
37
- {id: 1000, tier: 't2'},
38
- {id: 1001, tier: 't3'},
39
- {id: 6, tier: 't1'},
40
- {id: 1003, tier: 't2'},
41
- {id: 1002, tier: 't3'},
27
+ {id: 101, tier: 't1'},
28
+ {id: 102, tier: 't2'},
29
+ {id: 103, tier: 't3'},
30
+ {id: 201, tier: 't1'},
31
+ {id: 202, tier: 't2'},
32
+ {id: 203, tier: 't3'},
33
+ {id: 301, tier: 't1'},
34
+ {id: 302, tier: 't2'},
35
+ {id: 303, tier: 't3'},
36
+ {id: 401, tier: 't1'},
37
+ {id: 402, tier: 't2'},
38
+ {id: 403, tier: 't3'},
39
+ {id: 501, tier: 't1'},
40
+ {id: 502, tier: 't2'},
41
+ {id: 503, tier: 't3'},
42
42
  ]
43
43
 
44
44
  export function getDepthThreshold(tier: ResourceTier): number {
@@ -91,14 +91,14 @@ export function getResourceWeight(itemId: number, stratum: number): number {
91
91
  }
92
92
  }
93
93
 
94
- const ASTEROID_RESOURCES = [26, 13, 24, 29, 47]
95
- const NEBULA_RESOURCES = [47, 79, 1, 2, 18]
96
- const GAS_GIANT_RESOURCES = [1, 2, 18, 14, 6]
97
- const ROCKY_RESOURCES = [26, 13, 24, 14, 1000, 1001, 1002]
98
- const TERRESTRIAL_RESOURCES = [29, 47, 14, 1000, 6, 1003, 1002]
99
- const ICY_RESOURCES = [26, 1, 2, 14, 1001, 6, 1003]
100
- const OCEAN_RESOURCES = [29, 79, 1, 18, 6, 1003, 1002]
101
- const INDUSTRIAL_RESOURCES = [26, 13, 24, 29, 79, 1000, 1001]
94
+ const ASTEROID_RESOURCES = [101, 102, 103, 201, 202]
95
+ const NEBULA_RESOURCES = [202, 203, 301, 302, 303]
96
+ const GAS_GIANT_RESOURCES = [301, 302, 303, 401, 501]
97
+ const ROCKY_RESOURCES = [101, 102, 103, 401, 402, 403, 503]
98
+ const TERRESTRIAL_RESOURCES = [201, 202, 401, 402, 501, 502, 503]
99
+ const ICY_RESOURCES = [101, 301, 302, 401, 403, 501, 502]
100
+ const OCEAN_RESOURCES = [201, 203, 301, 303, 501, 502, 503]
101
+ const INDUSTRIAL_RESOURCES = [101, 102, 103, 201, 203, 402, 403]
102
102
 
103
103
  export function getLocationCandidates(locationType: number, subtype: number): number[] {
104
104
  if (locationType === 2) return ASTEROID_RESOURCES