@shipload/sdk 2.0.0-rc7 → 2.0.0-rc9

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.
@@ -1,20 +1,25 @@
1
- import {MODULE_ENGINE, MODULE_GENERATOR, MODULE_EXTRACTOR, MODULE_LOADER, MODULE_CRAFTER, ITEM_ENGINE_T1, ITEM_GENERATOR_T1, ITEM_EXTRACTOR_T1, ITEM_LOADER_T1, ITEM_MANUFACTURING_T1} from '../capabilities/modules'
1
+ import {MODULE_ANY, MODULE_ENGINE, MODULE_GENERATOR, MODULE_EXTRACTOR, MODULE_LOADER, MODULE_CRAFTER, MODULE_STORAGE, ITEM_ENGINE_T1, ITEM_GENERATOR_T1, ITEM_EXTRACTOR_T1, ITEM_LOADER_T1, ITEM_MANUFACTURING_T1, ITEM_STORAGE_T1} from '../capabilities/modules'
2
2
  import type {ResourceCategory} from '../types'
3
3
 
4
- export {ITEM_ENGINE_T1, ITEM_GENERATOR_T1, ITEM_EXTRACTOR_T1, ITEM_LOADER_T1, ITEM_MANUFACTURING_T1}
4
+ export {ITEM_ENGINE_T1, ITEM_GENERATOR_T1, ITEM_EXTRACTOR_T1, ITEM_LOADER_T1, ITEM_MANUFACTURING_T1, ITEM_STORAGE_T1}
5
5
 
6
- export const ITEM_DRILL_SHAFT = 10009
7
- export const ITEM_EXTRACTION_PROBE = 10010
8
- export const ITEM_CARGO_ARM = 10011
9
- export const ITEM_TOOL_BIT = 10012
10
- export const ITEM_REACTION_CHAMBER = 10013
6
+ export const ITEM_DRILL_SHAFT = 10005
7
+ export const ITEM_EXTRACTION_PROBE = 10006
8
+ export const ITEM_CARGO_ARM = 10007
9
+ export const ITEM_TOOL_BIT = 10008
10
+ export const ITEM_REACTION_CHAMBER = 10009
11
11
 
12
12
  export const ITEM_HULL_PLATES = 10001
13
13
  export const ITEM_CARGO_LINING = 10002
14
- export const ITEM_CONTAINER_PACKED = 10003
15
- export const ITEM_THRUSTER_CORE = 10004
16
- export const ITEM_POWER_CELL = 10005
17
- export const ITEM_SHIP_T1_PACKED = 10008
14
+ export const ITEM_CONTAINER_T1_PACKED = 10200
15
+ export const ITEM_THRUSTER_CORE = 10003
16
+ export const ITEM_POWER_CELL = 10004
17
+ export const ITEM_SHIP_T1_PACKED = 10201
18
+ export const ITEM_WAREHOUSE_T1_PACKED = 10202
19
+
20
+ export const ITEM_HULL_PLATES_T2 = 20001
21
+ export const ITEM_CARGO_LINING_T2 = 20002
22
+ export const ITEM_CONTAINER_T2_PACKED = 20200
18
23
 
19
24
  export interface RecipeInput {
20
25
  category?: ResourceCategory
@@ -38,6 +43,11 @@ export interface ComponentDefinition {
38
43
  usedIn: {type: 'entity' | 'module'; name: string}[]
39
44
  }
40
45
 
46
+ export interface ModuleSlot {
47
+ type: number
48
+ label?: string
49
+ }
50
+
41
51
  export interface EntityRecipe {
42
52
  id: string
43
53
  name: string
@@ -46,6 +56,7 @@ export interface EntityRecipe {
46
56
  packedItemId: number
47
57
  recipe: RecipeInput[]
48
58
  stats: {key: string; sourceComponentId: number; sourceStatKey: string}[]
59
+ moduleSlots?: ModuleSlot[]
49
60
  }
50
61
 
51
62
  export interface CraftableItem {
@@ -68,7 +79,7 @@ export const components: ComponentDefinition[] = [
68
79
  {key: 'density', source: 'metal'},
69
80
  ],
70
81
  recipe: [{category: 'metal', quantity: 15}],
71
- usedIn: [{type: 'entity', name: 'Container'}, {type: 'entity', name: 'Ship T1'}],
82
+ usedIn: [{type: 'entity', name: 'Container'}, {type: 'entity', name: 'Warehouse T1'}, {type: 'entity', name: 'Ship T1'}],
72
83
  },
73
84
  {
74
85
  id: ITEM_CARGO_LINING,
@@ -85,7 +96,7 @@ export const components: ComponentDefinition[] = [
85
96
  {category: 'precious', quantity: 6},
86
97
  {category: 'organic', quantity: 14},
87
98
  ],
88
- usedIn: [{type: 'entity', name: 'Container'}, {type: 'entity', name: 'Ship T1'}],
99
+ usedIn: [{type: 'entity', name: 'Container'}, {type: 'entity', name: 'Warehouse T1'}, {type: 'entity', name: 'Ship T1'}],
89
100
  },
90
101
  {
91
102
  id: ITEM_THRUSTER_CORE,
@@ -98,7 +109,7 @@ export const components: ComponentDefinition[] = [
98
109
  {key: 'thermal', source: 'gas'},
99
110
  ],
100
111
  recipe: [{category: 'gas' as ResourceCategory, quantity: 32}],
101
- usedIn: [{type: 'module', name: 'Engine Module T1'}],
112
+ usedIn: [{type: 'module', name: 'Engine'}],
102
113
  },
103
114
  {
104
115
  id: ITEM_POWER_CELL,
@@ -111,7 +122,7 @@ export const components: ComponentDefinition[] = [
111
122
  {key: 'clarity', source: 'mineral'},
112
123
  ],
113
124
  recipe: [{category: 'mineral' as ResourceCategory, quantity: 20}],
114
- usedIn: [{type: 'module', name: 'Generator Module T1'}],
125
+ usedIn: [{type: 'module', name: 'Generator'}],
115
126
  },
116
127
  {
117
128
  id: ITEM_DRILL_SHAFT,
@@ -124,7 +135,7 @@ export const components: ComponentDefinition[] = [
124
135
  {key: 'tolerance', source: 'metal'},
125
136
  ],
126
137
  recipe: [{category: 'metal' as ResourceCategory, quantity: 15}],
127
- usedIn: [{type: 'module', name: 'Extractor Module T1'}],
138
+ usedIn: [{type: 'module', name: 'Extractor'}],
128
139
  },
129
140
  {
130
141
  id: ITEM_EXTRACTION_PROBE,
@@ -137,7 +148,7 @@ export const components: ComponentDefinition[] = [
137
148
  {key: 'reflectivity', source: 'precious'},
138
149
  ],
139
150
  recipe: [{category: 'precious' as ResourceCategory, quantity: 10}],
140
- usedIn: [{type: 'module', name: 'Extractor Module T1'}],
151
+ usedIn: [{type: 'module', name: 'Extractor'}],
141
152
  },
142
153
  {
143
154
  id: ITEM_CARGO_ARM,
@@ -150,7 +161,7 @@ export const components: ComponentDefinition[] = [
150
161
  {key: 'insulation', source: 'organic'},
151
162
  ],
152
163
  recipe: [{category: 'organic' as ResourceCategory, quantity: 32}],
153
- usedIn: [{type: 'module', name: 'Loader Module T1'}],
164
+ usedIn: [{type: 'module', name: 'Loader'}],
154
165
  },
155
166
  {
156
167
  id: ITEM_TOOL_BIT,
@@ -163,7 +174,7 @@ export const components: ComponentDefinition[] = [
163
174
  {key: 'clarity', source: 'mineral'},
164
175
  ],
165
176
  recipe: [{category: 'mineral' as ResourceCategory, quantity: 20}],
166
- usedIn: [{type: 'module', name: 'Manufacturing Module T1'}],
177
+ usedIn: [{type: 'module', name: 'Manufacturing'}],
167
178
  },
168
179
  {
169
180
  id: ITEM_REACTION_CHAMBER,
@@ -176,7 +187,40 @@ export const components: ComponentDefinition[] = [
176
187
  {key: 'thermal', source: 'gas'},
177
188
  ],
178
189
  recipe: [{category: 'gas' as ResourceCategory, quantity: 32}],
179
- usedIn: [{type: 'module', name: 'Manufacturing Module T1'}],
190
+ usedIn: [{type: 'module', name: 'Manufacturing'}],
191
+ },
192
+ {
193
+ id: ITEM_HULL_PLATES_T2,
194
+ name: 'Hull Plates T2',
195
+ description: 'Advanced structural plating reinforced with tier 2 metals.',
196
+ color: '#9BADB8',
197
+ mass: 50000,
198
+ stats: [
199
+ {key: 'strength', source: 'metal'},
200
+ {key: 'density', source: 'metal'},
201
+ ],
202
+ recipe: [
203
+ {itemId: ITEM_HULL_PLATES, quantity: 2},
204
+ {category: 'metal', quantity: 15},
205
+ ],
206
+ usedIn: [{type: 'entity', name: 'Container T2'}],
207
+ },
208
+ {
209
+ id: ITEM_CARGO_LINING_T2,
210
+ name: 'Cargo Lining T2',
211
+ description: 'Advanced composite lining with improved storage properties.',
212
+ color: '#E0B84D',
213
+ mass: 30000,
214
+ stats: [
215
+ {key: 'ductility', source: 'precious'},
216
+ {key: 'purity', source: 'organic'},
217
+ ],
218
+ recipe: [
219
+ {itemId: ITEM_CARGO_LINING, quantity: 2},
220
+ {category: 'precious', quantity: 6},
221
+ {category: 'organic', quantity: 14},
222
+ ],
223
+ usedIn: [{type: 'entity', name: 'Container T2'}],
180
224
  },
181
225
  ]
182
226
 
@@ -186,7 +230,7 @@ export const entityRecipes: EntityRecipe[] = [
186
230
  name: 'Container',
187
231
  description: 'Passive floating cargo storage in space. Towed by ships.',
188
232
  color: '#7B8D9E',
189
- packedItemId: ITEM_CONTAINER_PACKED,
233
+ packedItemId: ITEM_CONTAINER_T1_PACKED,
190
234
  recipe: [
191
235
  {itemId: ITEM_HULL_PLATES, quantity: 6},
192
236
  {itemId: ITEM_CARGO_LINING, quantity: 2},
@@ -214,6 +258,54 @@ export const entityRecipes: EntityRecipe[] = [
214
258
  {key: 'ductility', sourceComponentId: ITEM_CARGO_LINING, sourceStatKey: 'ductility'},
215
259
  {key: 'purity', sourceComponentId: ITEM_CARGO_LINING, sourceStatKey: 'purity'},
216
260
  ],
261
+ moduleSlots: [
262
+ {type: MODULE_ANY},
263
+ {type: MODULE_ANY},
264
+ {type: MODULE_ANY},
265
+ {type: MODULE_ANY},
266
+ {type: MODULE_ANY},
267
+ ],
268
+ },
269
+ {
270
+ id: 'warehouse-t1',
271
+ name: 'Warehouse T1',
272
+ description: 'Massive stationary storage facility with a single loader module slot.',
273
+ color: '#EAB308',
274
+ packedItemId: ITEM_WAREHOUSE_T1_PACKED,
275
+ recipe: [
276
+ {itemId: ITEM_HULL_PLATES, quantity: 20},
277
+ {itemId: ITEM_CARGO_LINING, quantity: 10},
278
+ ],
279
+ stats: [
280
+ {key: 'strength', sourceComponentId: ITEM_HULL_PLATES, sourceStatKey: 'strength'},
281
+ {key: 'density', sourceComponentId: ITEM_HULL_PLATES, sourceStatKey: 'density'},
282
+ {key: 'ductility', sourceComponentId: ITEM_CARGO_LINING, sourceStatKey: 'ductility'},
283
+ {key: 'purity', sourceComponentId: ITEM_CARGO_LINING, sourceStatKey: 'purity'},
284
+ ],
285
+ moduleSlots: [
286
+ {type: MODULE_LOADER, label: 'Loader'},
287
+ {type: MODULE_STORAGE, label: 'Storage'},
288
+ {type: MODULE_STORAGE, label: 'Storage'},
289
+ {type: MODULE_STORAGE, label: 'Storage'},
290
+ {type: MODULE_STORAGE, label: 'Storage'},
291
+ ],
292
+ },
293
+ {
294
+ id: 'container-t2',
295
+ name: 'Container T2',
296
+ description: 'Advanced cargo container with improved capacity formulas.',
297
+ color: '#9BADB8',
298
+ packedItemId: ITEM_CONTAINER_T2_PACKED,
299
+ recipe: [
300
+ {itemId: ITEM_HULL_PLATES_T2, quantity: 6},
301
+ {itemId: ITEM_CARGO_LINING_T2, quantity: 2},
302
+ ],
303
+ stats: [
304
+ {key: 'strength', sourceComponentId: ITEM_HULL_PLATES_T2, sourceStatKey: 'strength'},
305
+ {key: 'density', sourceComponentId: ITEM_HULL_PLATES_T2, sourceStatKey: 'density'},
306
+ {key: 'ductility', sourceComponentId: ITEM_CARGO_LINING_T2, sourceStatKey: 'ductility'},
307
+ {key: 'purity', sourceComponentId: ITEM_CARGO_LINING_T2, sourceStatKey: 'purity'},
308
+ ],
217
309
  },
218
310
  ]
219
311
 
@@ -231,7 +323,7 @@ export interface ModuleRecipe {
231
323
  export const moduleRecipes: ModuleRecipe[] = [
232
324
  {
233
325
  id: 'engine-t1',
234
- name: 'Engine Module T1',
326
+ name: 'Engine',
235
327
  description: 'Basic propulsion system. Converts volatile gases into thrust.',
236
328
  color: '#E86344',
237
329
  itemId: ITEM_ENGINE_T1,
@@ -244,7 +336,7 @@ export const moduleRecipes: ModuleRecipe[] = [
244
336
  },
245
337
  {
246
338
  id: 'generator-t1',
247
- name: 'Generator Module T1',
339
+ name: 'Generator',
248
340
  description: 'Basic energy system. Stores and recharges energy from resonant minerals.',
249
341
  color: '#7B5AE8',
250
342
  itemId: ITEM_GENERATOR_T1,
@@ -257,7 +349,7 @@ export const moduleRecipes: ModuleRecipe[] = [
257
349
  },
258
350
  {
259
351
  id: 'extractor-t1',
260
- name: 'Extractor Module T1',
352
+ name: 'Extractor',
261
353
  description: 'Basic extraction system. Drills and probes for raw resources.',
262
354
  color: '#7B8D9E',
263
355
  itemId: ITEM_EXTRACTOR_T1,
@@ -276,7 +368,7 @@ export const moduleRecipes: ModuleRecipe[] = [
276
368
  },
277
369
  {
278
370
  id: 'loader-t1',
279
- name: 'Loader Module T1',
371
+ name: 'Loader',
280
372
  description: 'Basic cargo handling system. Loads and unloads cargo with articulated arms.',
281
373
  color: '#6B8E5A',
282
374
  itemId: ITEM_LOADER_T1,
@@ -292,7 +384,7 @@ export const moduleRecipes: ModuleRecipe[] = [
292
384
  },
293
385
  {
294
386
  id: 'manufacturing-t1',
295
- name: 'Manufacturing Module T1',
387
+ name: 'Manufacturing',
296
388
  description: 'Basic crafting system. Processes materials using reaction chambers and cutting tools.',
297
389
  color: '#7EC8E3',
298
390
  itemId: ITEM_MANUFACTURING_T1,
@@ -306,6 +398,24 @@ export const moduleRecipes: ModuleRecipe[] = [
306
398
  {key: 'clarity', sourceComponentId: ITEM_TOOL_BIT, sourceStatKey: 'clarity'},
307
399
  ],
308
400
  },
401
+ {
402
+ id: 'storage-t1',
403
+ name: 'Storage',
404
+ description: 'Expands cargo capacity based on hull material quality',
405
+ color: '#8B7355',
406
+ itemId: ITEM_STORAGE_T1,
407
+ moduleType: MODULE_STORAGE,
408
+ recipe: [
409
+ {itemId: ITEM_HULL_PLATES, quantity: 8},
410
+ {itemId: ITEM_CARGO_LINING, quantity: 4},
411
+ ],
412
+ stats: [
413
+ {key: 'strength', sourceComponentId: ITEM_HULL_PLATES, sourceStatKey: 'strength'},
414
+ {key: 'ductility', sourceComponentId: ITEM_HULL_PLATES, sourceStatKey: 'ductility'},
415
+ {key: 'purity', sourceComponentId: ITEM_CARGO_LINING, sourceStatKey: 'purity'},
416
+ {key: 'density', sourceComponentId: ITEM_CARGO_LINING, sourceStatKey: 'density'},
417
+ ],
418
+ },
309
419
  ]
310
420
 
311
421
  export function getModuleRecipe(id: string): ModuleRecipe | undefined {
@@ -328,6 +438,11 @@ export function getEntityRecipeByItemId(itemId: number): EntityRecipe | undefine
328
438
  return entityRecipes.find((r) => r.packedItemId === itemId)
329
439
  }
330
440
 
441
+ export function getEntitySlotLayout(packedItemId: number): ModuleSlot[] {
442
+ const recipe = getEntityRecipeByItemId(packedItemId)
443
+ return recipe?.moduleSlots ?? []
444
+ }
445
+
331
446
  export function getAllCraftableItems(): CraftableItem[] {
332
447
  const items: CraftableItem[] = []
333
448
  for (const comp of components) {
@@ -0,0 +1,41 @@
1
+ export type CraftedItemCategory = 'component' | 'module' | 'entity' | 'resource'
2
+
3
+ export const ITEM_TYPE_RESOURCE = 0
4
+ export const ITEM_TYPE_COMPONENT = 1
5
+ export const ITEM_TYPE_MODULE = 2
6
+ export const ITEM_TYPE_ENTITY = 3
7
+
8
+ export function itemTypeCode(id: number): number {
9
+ switch (itemCategory(id)) {
10
+ case 'resource': return ITEM_TYPE_RESOURCE
11
+ case 'component': return ITEM_TYPE_COMPONENT
12
+ case 'module': return ITEM_TYPE_MODULE
13
+ case 'entity': return ITEM_TYPE_ENTITY
14
+ }
15
+ }
16
+
17
+ export function itemTier(id: number): number {
18
+ if (id < 10000) return 0
19
+ return Math.floor(id / 10000)
20
+ }
21
+
22
+ export function itemOffset(id: number): number {
23
+ return id % 10000
24
+ }
25
+
26
+ export function itemCategory(id: number): CraftedItemCategory {
27
+ if (id < 10000) return 'resource'
28
+ const offset = itemOffset(id)
29
+ if (offset >= 200) return 'entity'
30
+ if (offset >= 100) return 'module'
31
+ return 'component'
32
+ }
33
+
34
+ export function isRelatedItem(a: number, b: number): boolean {
35
+ if (a < 10000 || b < 10000) return false
36
+ return itemOffset(a) === itemOffset(b)
37
+ }
38
+
39
+ export function isCraftedItem(id: number): boolean {
40
+ return id >= 10000
41
+ }
@@ -27,10 +27,14 @@ export function encodeStats(values: number[]): bigint {
27
27
  return seed
28
28
  }
29
29
 
30
+ export function decodeStat(seed: bigint, index: number): number {
31
+ return Number((seed >> BigInt(index * 10)) & 0x3ffn)
32
+ }
33
+
30
34
  export function decodeStats(seed: bigint, count: number): number[] {
31
35
  const stats: number[] = []
32
36
  for (let i = 0; i < count; i++) {
33
- stats.push(Number((seed >> BigInt(i * 10)) & 0x3ffn))
37
+ stats.push(decodeStat(seed, i))
34
38
  }
35
39
  return stats
36
40
  }
@@ -128,6 +132,59 @@ function decodeStackStats(itemId: number, seed: UInt64): Record<string, number>
128
132
  return {stat1: raw.stat1, stat2: raw.stat2, stat3: raw.stat3}
129
133
  }
130
134
 
135
+ export const categoryItemMass: Record<string, number> = {
136
+ metal: 30000,
137
+ precious: 40000,
138
+ gas: 15000,
139
+ mineral: 22000,
140
+ organic: 15000,
141
+ }
142
+
143
+ export function computeInputMass(
144
+ itemId: string | number,
145
+ itemType: 'component' | 'module' | 'entity'
146
+ ): number {
147
+ if (itemType === 'component') {
148
+ const comp = getComponentById(itemId as number)
149
+ if (!comp) return 0
150
+ return comp.recipe.reduce((sum, input) => {
151
+ const mass = input.category ? (categoryItemMass[input.category] ?? 0) : 0
152
+ return sum + mass * input.quantity
153
+ }, 0)
154
+ }
155
+ if (itemType === 'module') {
156
+ const mod = getModuleRecipe(itemId as string)
157
+ if (!mod) return 0
158
+ return mod.recipe.reduce((sum, input) => {
159
+ const comp = input.itemId ? getComponentById(input.itemId) : undefined
160
+ return sum + (comp?.mass ?? 0) * input.quantity
161
+ }, 0)
162
+ }
163
+ if (itemType === 'entity') {
164
+ const ent = getEntityRecipe(itemId as string)
165
+ if (!ent) return 0
166
+ return ent.recipe.reduce((sum, input) => {
167
+ const comp = input.itemId ? getComponentById(input.itemId) : undefined
168
+ return sum + (comp?.mass ?? 0) * input.quantity
169
+ }, 0)
170
+ }
171
+ return 0
172
+ }
173
+
174
+ export function blendCrossGroup(
175
+ sources: {value: number; weight: number}[]
176
+ ): number {
177
+ let weightedSum = 0
178
+ let totalWeight = 0
179
+ for (const src of sources) {
180
+ weightedSum += src.value * src.weight
181
+ totalWeight += src.weight
182
+ }
183
+ if (totalWeight === 0) return 1
184
+ const result = Math.floor(weightedSum / totalWeight)
185
+ return Math.max(1, Math.min(999, result))
186
+ }
187
+
131
188
  export function blendCargoStacks(
132
189
  itemId: number,
133
190
  stacks: {quantity: number; seed: UInt64}[]
@@ -86,3 +86,21 @@ export function computeContainerCapabilities(stats: Record<string, number>): {
86
86
 
87
87
  return {hullmass, capacity}
88
88
  }
89
+
90
+ export function computeContainerT2Capabilities(stats: Record<string, number>): {
91
+ hullmass: number
92
+ capacity: number
93
+ } {
94
+ const strength = stats['strength'] ?? 0
95
+ const density = stats['density'] ?? 0
96
+ const ductility = stats['ductility'] ?? 0
97
+ const purity = stats['purity'] ?? 0
98
+
99
+ const hullmass = 20000 + 50 * density
100
+
101
+ const statSum = strength + ductility + purity
102
+ const exponent = statSum / 2500
103
+ const capacity = Math.floor(1500000 * Math.pow(10, exponent))
104
+
105
+ return {hullmass, capacity}
106
+ }
@@ -30,7 +30,7 @@ export function makeShip(state: ShipStateInput): Ship {
30
30
  }
31
31
 
32
32
  export function makeWarehouse(state: WarehouseStateInput): Warehouse {
33
- const entityInfo = ServerContract.Types.entity_info.from({
33
+ const info: Record<string, unknown> = {
34
34
  type: Name.from('warehouse'),
35
35
  id: UInt64.from(state.id),
36
36
  owner: Name.from(state.owner),
@@ -39,13 +39,15 @@ export function makeWarehouse(state: WarehouseStateInput): Warehouse {
39
39
  capacity: UInt32.from(state.capacity),
40
40
  cargomass: UInt32.from(0),
41
41
  cargo: state.cargo || [],
42
- loaders: state.loaders,
43
42
  is_idle: !state.schedule,
44
43
  current_task_elapsed: UInt32.from(0),
45
44
  current_task_remaining: UInt32.from(0),
46
45
  pending_tasks: [],
47
- schedule: state.schedule,
48
- })
46
+ }
47
+ if (state.hullmass !== undefined) info.hullmass = UInt32.from(state.hullmass)
48
+ if (state.loaders) info.loaders = state.loaders
49
+ if (state.schedule) info.schedule = state.schedule
50
+ const entityInfo = ServerContract.Types.entity_info.from(info)
49
51
  return new Warehouse(entityInfo)
50
52
  }
51
53
 
@@ -24,7 +24,7 @@ export function computeEngineCapabilities(stats: Record<string, number>): {
24
24
 
25
25
  return {
26
26
  thrust: 400 + Math.floor(vol * 3 / 4),
27
- drain: Math.max(16, 30 - Math.floor(thm / 70)),
27
+ drain: Math.max(30, 50 - Math.floor(thm / 70)),
28
28
  }
29
29
  }
30
30
 
@@ -87,3 +87,36 @@ export function computeManufacturingCapabilities(stats: Record<string, number>):
87
87
  drain: Math.max(5, 30 - Math.floor(clr / 33)),
88
88
  }
89
89
  }
90
+
91
+ export function computeStorageCapabilities(
92
+ stats: Record<string, number>,
93
+ baseCapacity: number
94
+ ): {
95
+ capacityBonus: number
96
+ } {
97
+ const strength = stats.strength ?? 500
98
+ const ductility = stats.ductility ?? 500
99
+ const purity = stats.purity ?? 500
100
+
101
+ const statSum = strength + ductility + purity
102
+ const capacityBonus = Math.floor(baseCapacity * (10 + Math.floor(statSum * 10 / 2997)) / 100)
103
+
104
+ return {capacityBonus}
105
+ }
106
+
107
+ export function computeWarehouseHullCapabilities(stats: Record<string, number>): {
108
+ hullmass: number
109
+ capacity: number
110
+ } {
111
+ const density = stats.density ?? 500
112
+ const strength = stats.strength ?? 500
113
+ const ductility = stats.ductility ?? 500
114
+ const purity = stats.purity ?? 500
115
+
116
+ const hullmass = 25000 + 75 * density
117
+ const statSum = strength + ductility + purity
118
+ const exponent = statSum / 2997.0
119
+ const capacity = Math.floor(20000000 * Math.pow(10, exponent))
120
+
121
+ return {hullmass, capacity}
122
+ }
@@ -12,8 +12,9 @@ export interface WarehouseStateInput {
12
12
  owner: string
13
13
  name: string
14
14
  coordinates: CoordinatesType | {x: number; y: number; z?: number}
15
+ hullmass?: number
15
16
  capacity: number
16
- loaders: ServerContract.Types.loader_stats
17
+ loaders?: ServerContract.Types.loader_stats
17
18
  schedule?: ServerContract.Types.schedule
18
19
  cargo?: ServerContract.Types.cargo_item[]
19
20
  }
@@ -82,4 +83,9 @@ export class Warehouse extends ServerContract.Types.entity_info {
82
83
  get orbitalAltitude(): number {
83
84
  return this.coordinates.z?.toNumber() || 0
84
85
  }
86
+
87
+ get totalMass(): UInt64 {
88
+ const hull = this.hullmass ? UInt64.from(this.hullmass) : UInt64.from(0)
89
+ return hull.adding(this.totalCargoMass)
90
+ }
85
91
  }
@@ -141,7 +141,28 @@ export * from './types/capabilities'
141
141
  export * from './types/entity'
142
142
  export * from './capabilities'
143
143
 
144
- export {categoryColors, tierColors, categoryIcons, componentIcon, moduleIcon} from './data/colors'
144
+ export {categoryColors, tierColors, categoryIcons, componentIcon, moduleIcon, itemIcons} from './data/colors'
145
+
146
+ export {itemTier, itemOffset, itemCategory, isRelatedItem, isCraftedItem} from './data/tiers'
147
+ export type {CraftedItemCategory} from './data/tiers'
148
+
149
+ export {getCategoryInfo} from './data/categories'
150
+ export type {CategoryInfo} from './data/categories'
151
+
152
+ export {getPlanetSubtypes, getPlanetSubtype} from './data/locations'
153
+ export type {PlanetSubtypeInfo} from './data/locations'
154
+
155
+ export {
156
+ capabilityNames,
157
+ capabilityAttributes,
158
+ statMappings,
159
+ isInvertedAttribute,
160
+ getCapabilityAttributes,
161
+ getStatMappings,
162
+ getStatMappingsForStat,
163
+ getStatMappingsForCapability,
164
+ } from './data/capabilities'
165
+ export type {CapabilityAttribute, StatMapping} from './data/capabilities'
145
166
 
146
167
  export {
147
168
  components,
@@ -157,12 +178,13 @@ export {
157
178
  getComponentsForStat,
158
179
  ITEM_HULL_PLATES,
159
180
  ITEM_CARGO_LINING,
160
- ITEM_CONTAINER_PACKED,
181
+ ITEM_CONTAINER_T1_PACKED,
161
182
  ITEM_THRUSTER_CORE,
162
183
  ITEM_POWER_CELL,
163
184
  ITEM_ENGINE_T1,
164
185
  ITEM_GENERATOR_T1,
165
186
  ITEM_SHIP_T1_PACKED,
187
+ ITEM_WAREHOUSE_T1_PACKED,
166
188
  ITEM_DRILL_SHAFT,
167
189
  ITEM_EXTRACTION_PROBE,
168
190
  ITEM_CARGO_ARM,
@@ -171,6 +193,10 @@ export {
171
193
  ITEM_EXTRACTOR_T1,
172
194
  ITEM_LOADER_T1,
173
195
  ITEM_MANUFACTURING_T1,
196
+ ITEM_STORAGE_T1,
197
+ ITEM_HULL_PLATES_T2,
198
+ ITEM_CARGO_LINING_T2,
199
+ ITEM_CONTAINER_T2_PACKED,
174
200
  } from './data/recipes'
175
201
  export type {
176
202
  ComponentDefinition,
@@ -178,11 +204,13 @@ export type {
178
204
  RecipeInput,
179
205
  EntityRecipe,
180
206
  ModuleRecipe,
207
+ ModuleSlot,
181
208
  CraftableItem,
182
209
  } from './data/recipes'
183
210
 
184
211
  export {
185
212
  encodeStats,
213
+ decodeStat,
186
214
  decodeStats,
187
215
  decodeCraftedItemStats,
188
216
  blendStacks,
@@ -190,10 +218,13 @@ export {
190
218
  blendComponentStacks,
191
219
  computeEntityStats,
192
220
  blendCargoStacks,
221
+ blendCrossGroup,
222
+ categoryItemMass,
223
+ computeInputMass,
193
224
  } from './derivation/crafting'
194
225
  export type {StackInput, CategoryStacks} from './derivation/crafting'
195
226
 
196
- export {computeContainerCapabilities} from './entities/container'
227
+ export {computeContainerCapabilities, computeContainerT2Capabilities} from './entities/container'
197
228
 
198
229
  export {
199
230
  computeShipHullCapabilities,
@@ -202,7 +233,45 @@ export {
202
233
  computeExtractorCapabilities,
203
234
  computeLoaderCapabilities,
204
235
  computeManufacturingCapabilities,
236
+ computeWarehouseHullCapabilities,
237
+ computeStorageCapabilities,
205
238
  } from './entities/ship-deploy'
206
239
 
207
240
  export {resolveItem} from './resolution/resolve-item'
208
- export type {ResolvedItem, ResolvedItemStat, ResolvedAttributeGroup, ResolvedItemType} from './resolution/resolve-item'
241
+ export type {ResolvedItem, ResolvedItemStat, ResolvedAttributeGroup, ResolvedModuleSlot, ResolvedItemType} from './resolution/resolve-item'
242
+
243
+ export * as NFT from './nft'
244
+ export {
245
+ deserializeAsset,
246
+ deserializeResource,
247
+ deserializeComponent,
248
+ deserializeModule,
249
+ deserializeEntity,
250
+ readCommonBase,
251
+ } from './nft/deserializers'
252
+ export type {NFTCargoItem, NFTModuleSlot, NFTInstalledModule, NFTCommonBase} from './nft/deserializers'
253
+
254
+ export {
255
+ buildEntityDescription,
256
+ formatModuleLine,
257
+ entityDisplayName,
258
+ moduleDisplayName,
259
+ computeBaseHullmass,
260
+ computeBaseCapacityShip,
261
+ computeBaseCapacityWarehouse,
262
+ computeEngineThrust,
263
+ computeEngineDrain,
264
+ computeGeneratorCap,
265
+ computeGeneratorRech,
266
+ computeExtractorRate,
267
+ computeExtractorDrain,
268
+ computeExtractorDepth,
269
+ computeExtractorDrill,
270
+ computeLoaderMass,
271
+ computeLoaderThrust,
272
+ computeCrafterSpeed,
273
+ computeCrafterDrain,
274
+ } from './nft/description'
275
+
276
+ export {getEntitySlotLayout} from './data/recipes'
277
+ export {ITEM_TYPE_RESOURCE, ITEM_TYPE_COMPONENT, ITEM_TYPE_MODULE, ITEM_TYPE_ENTITY, itemTypeCode} from './data/tiers'