@shipload/sdk 2.0.0-rc20 → 2.0.0-rc21
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.
- package/lib/shipload.d.ts +187 -117
- package/lib/shipload.js +2963 -1949
- package/lib/shipload.js.map +1 -1
- package/lib/shipload.m.js +2908 -1936
- package/lib/shipload.m.js.map +1 -1
- package/package.json +1 -1
- package/src/capabilities/modules.ts +36 -7
- package/src/capabilities/storage.ts +1 -1
- package/src/contracts/server.ts +69 -1
- package/src/data/entities.json +50 -0
- package/src/data/item-ids.ts +75 -0
- package/src/data/items.json +250 -15
- package/src/data/metadata.ts +208 -0
- package/src/data/recipes-runtime.ts +65 -0
- package/src/data/recipes.json +878 -0
- package/src/derivation/crafting.ts +172 -111
- package/src/derivation/resources.ts +14 -38
- package/src/entities/container.ts +4 -4
- package/src/entities/entity-inventory.ts +2 -2
- package/src/entities/makers.ts +18 -10
- package/src/entities/ship-deploy.ts +8 -8
- package/src/index-module.ts +2 -47
- package/src/market/items.ts +23 -75
- package/src/nft/description.ts +7 -7
- package/src/nft/deserializers.ts +6 -4
- package/src/resolution/display-name.ts +8 -4
- package/src/resolution/resolve-item.ts +80 -65
- package/src/scheduling/projection.ts +8 -28
- package/src/travel/travel.ts +8 -7
- package/src/types.ts +27 -33
- package/src/data/recipes.ts +0 -587
|
@@ -1,13 +1,7 @@
|
|
|
1
1
|
import {UInt64} from '@wharfkit/antelope'
|
|
2
2
|
import type {ResourceCategory} from '../types'
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
getComponentById,
|
|
6
|
-
getEntityRecipe,
|
|
7
|
-
getEntityRecipeByItemId,
|
|
8
|
-
getModuleRecipe,
|
|
9
|
-
moduleRecipes,
|
|
10
|
-
} from '../data/recipes'
|
|
3
|
+
import {findItemByCategoryAndTier, getRecipe, Recipe} from '../data/recipes-runtime'
|
|
4
|
+
import {getItem} from '../market/items'
|
|
11
5
|
import {getStatDefinitions} from './stats'
|
|
12
6
|
import {deriveResourceStats} from './stratum'
|
|
13
7
|
|
|
@@ -41,26 +35,45 @@ export function decodeStats(stats: bigint, count: number): number[] {
|
|
|
41
35
|
return result
|
|
42
36
|
}
|
|
43
37
|
|
|
44
|
-
function
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
38
|
+
function getItemStatKeys(itemId: number): string[] {
|
|
39
|
+
const item = getItem(itemId)
|
|
40
|
+
if (item.type === 'resource') {
|
|
41
|
+
if (!item.category) return []
|
|
42
|
+
return getStatDefinitions(item.category).map((d) => d.key)
|
|
49
43
|
}
|
|
50
|
-
|
|
44
|
+
const recipe = getRecipe(itemId)
|
|
45
|
+
if (!recipe) return []
|
|
46
|
+
return recipe.statSlots.map((slot) => keyForStatSlot(recipe, slot))
|
|
51
47
|
}
|
|
52
48
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
const
|
|
58
|
-
if (
|
|
49
|
+
function keyForStatSlot(
|
|
50
|
+
recipe: Recipe,
|
|
51
|
+
slot: {sources: {inputIndex: number; statIndex: number}[]}
|
|
52
|
+
): string {
|
|
53
|
+
const src = slot.sources[0]
|
|
54
|
+
if (!src) return ''
|
|
55
|
+
return keyForRecipeInputStat(recipe, src.inputIndex, src.statIndex)
|
|
56
|
+
}
|
|
59
57
|
|
|
60
|
-
|
|
61
|
-
|
|
58
|
+
function keyForRecipeInputStat(recipe: Recipe, inputIndex: number, statIndex: number): string {
|
|
59
|
+
const input = recipe.inputs[inputIndex]
|
|
60
|
+
if (!input) return ''
|
|
61
|
+
if ('category' in input) {
|
|
62
|
+
const defs = getStatDefinitions(input.category)
|
|
63
|
+
return defs[statIndex]?.key ?? ''
|
|
64
|
+
}
|
|
65
|
+
// itemId-typed input — its stats follow that item's own statSlots layout.
|
|
66
|
+
const innerKeys = getItemStatKeys(input.itemId)
|
|
67
|
+
return innerKeys[statIndex] ?? ''
|
|
68
|
+
}
|
|
62
69
|
|
|
63
|
-
|
|
70
|
+
export function decodeCraftedItemStats(itemId: number, stats: bigint): Record<string, number> {
|
|
71
|
+
const keys = getItemStatKeys(itemId)
|
|
72
|
+
const result: Record<string, number> = {}
|
|
73
|
+
for (let i = 0; i < keys.length; i++) {
|
|
74
|
+
if (keys[i]) result[keys[i]] = decodeStat(stats, i)
|
|
75
|
+
}
|
|
76
|
+
return result
|
|
64
77
|
}
|
|
65
78
|
|
|
66
79
|
export function blendStacks(stacks: StackInput[], statKey: string): number {
|
|
@@ -75,20 +88,6 @@ export function blendStacks(stacks: StackInput[], statKey: string): number {
|
|
|
75
88
|
return Math.floor(weightedSum / totalQty)
|
|
76
89
|
}
|
|
77
90
|
|
|
78
|
-
export function computeComponentStats(
|
|
79
|
-
componentId: number,
|
|
80
|
-
categoryStacks: CategoryStacks[]
|
|
81
|
-
): {key: string; value: number}[] {
|
|
82
|
-
const comp = getComponentById(componentId)
|
|
83
|
-
if (!comp) return []
|
|
84
|
-
|
|
85
|
-
return comp.stats.map((statDef) => {
|
|
86
|
-
const matching = categoryStacks.find((cs) => cs.category === statDef.source)
|
|
87
|
-
const value = matching ? blendStacks(matching.stacks, statDef.key) : 0
|
|
88
|
-
return {key: statDef.key, value: Math.max(1, Math.min(999, value))}
|
|
89
|
-
})
|
|
90
|
-
}
|
|
91
|
-
|
|
92
91
|
export function blendComponentStacks(
|
|
93
92
|
stacks: {quantity: number; stats: Record<string, number>}[]
|
|
94
93
|
): Record<string, number> {
|
|
@@ -107,11 +106,35 @@ export function blendComponentStacks(
|
|
|
107
106
|
return result
|
|
108
107
|
}
|
|
109
108
|
|
|
109
|
+
export function computeComponentStats(
|
|
110
|
+
componentId: number,
|
|
111
|
+
categoryStacks: CategoryStacks[]
|
|
112
|
+
): {key: string; value: number}[] {
|
|
113
|
+
const recipe = getRecipe(componentId)
|
|
114
|
+
if (!recipe) return []
|
|
115
|
+
|
|
116
|
+
return recipe.statSlots.map((slot) => {
|
|
117
|
+
const src = slot.sources[0]
|
|
118
|
+
const key = keyForStatSlot(recipe, slot)
|
|
119
|
+
const input = src ? recipe.inputs[src.inputIndex] : undefined
|
|
120
|
+
if (!input || !('category' in input)) {
|
|
121
|
+
return {key, value: Math.max(1, Math.min(999, 0))}
|
|
122
|
+
}
|
|
123
|
+
const matching = categoryStacks.find((cs) => cs.category === input.category)
|
|
124
|
+
const value = matching ? blendStacks(matching.stacks, key) : 0
|
|
125
|
+
return {key, value: Math.max(1, Math.min(999, value))}
|
|
126
|
+
})
|
|
127
|
+
}
|
|
128
|
+
|
|
110
129
|
export function computeEntityStats(
|
|
111
|
-
|
|
130
|
+
entityItemIdOrLegacyId: number | string,
|
|
112
131
|
componentStacks: Record<number, {quantity: number; stats: Record<string, number>}[]>
|
|
113
132
|
): {key: string; value: number}[] {
|
|
114
|
-
const
|
|
133
|
+
const itemId =
|
|
134
|
+
typeof entityItemIdOrLegacyId === 'number'
|
|
135
|
+
? entityItemIdOrLegacyId
|
|
136
|
+
: legacyEntityIdToItemId(entityItemIdOrLegacyId)
|
|
137
|
+
const recipe = getRecipe(itemId)
|
|
115
138
|
if (!recipe) return []
|
|
116
139
|
|
|
117
140
|
const blendedByComponent: Record<number, Record<string, number>> = {}
|
|
@@ -119,13 +142,35 @@ export function computeEntityStats(
|
|
|
119
142
|
blendedByComponent[Number(compId)] = blendComponentStacks(stacks)
|
|
120
143
|
}
|
|
121
144
|
|
|
122
|
-
return recipe.
|
|
123
|
-
const
|
|
124
|
-
const
|
|
125
|
-
return {key
|
|
145
|
+
return recipe.statSlots.map((slot) => {
|
|
146
|
+
const src = slot.sources[0]
|
|
147
|
+
const key = keyForStatSlot(recipe, slot)
|
|
148
|
+
if (!src) return {key, value: 1}
|
|
149
|
+
const input = recipe.inputs[src.inputIndex]
|
|
150
|
+
if (!input || 'category' in input) {
|
|
151
|
+
return {key, value: 1}
|
|
152
|
+
}
|
|
153
|
+
const blended = blendedByComponent[input.itemId] ?? {}
|
|
154
|
+
const value = blended[key] ?? 0
|
|
155
|
+
return {key, value: Math.max(1, Math.min(999, value))}
|
|
126
156
|
})
|
|
127
157
|
}
|
|
128
158
|
|
|
159
|
+
function legacyEntityIdToItemId(id: string): number {
|
|
160
|
+
switch (id) {
|
|
161
|
+
case 'container':
|
|
162
|
+
return 10200
|
|
163
|
+
case 'ship-t1':
|
|
164
|
+
return 10201
|
|
165
|
+
case 'warehouse-t1':
|
|
166
|
+
return 10202
|
|
167
|
+
case 'container-t2':
|
|
168
|
+
return 20200
|
|
169
|
+
default:
|
|
170
|
+
return 0
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
129
174
|
function decodeStackStats(itemId: number, stats: UInt64): Record<string, number> {
|
|
130
175
|
if (itemId >= 10000) {
|
|
131
176
|
return decodeCraftedItemStats(itemId, BigInt(stats.toString()))
|
|
@@ -134,43 +179,20 @@ function decodeStackStats(itemId: number, stats: UInt64): Record<string, number>
|
|
|
134
179
|
return {stat1: decodeStat(s, 0), stat2: decodeStat(s, 1), stat3: decodeStat(s, 2)}
|
|
135
180
|
}
|
|
136
181
|
|
|
137
|
-
export
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
gas: 15000,
|
|
141
|
-
regolith: 22000,
|
|
142
|
-
biomass: 15000,
|
|
143
|
-
}
|
|
182
|
+
export function computeInputMass(itemId: number): number {
|
|
183
|
+
const recipe = getRecipe(itemId)
|
|
184
|
+
if (!recipe) throw new Error(`computeInputMass: no recipe found for itemId=${itemId}`)
|
|
144
185
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
)
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
const mass = input.category ? categoryItemMass[input.category] ?? 0 : 0
|
|
154
|
-
return sum + mass * input.quantity
|
|
155
|
-
}, 0)
|
|
156
|
-
}
|
|
157
|
-
if (itemType === 'module') {
|
|
158
|
-
const mod = getModuleRecipe(itemId as string)
|
|
159
|
-
if (!mod) return 0
|
|
160
|
-
return mod.recipe.reduce((sum, input) => {
|
|
161
|
-
const comp = input.itemId ? getComponentById(input.itemId) : undefined
|
|
162
|
-
return sum + (comp?.mass ?? 0) * input.quantity
|
|
163
|
-
}, 0)
|
|
164
|
-
}
|
|
165
|
-
if (itemType === 'entity') {
|
|
166
|
-
const ent = getEntityRecipe(itemId as string)
|
|
167
|
-
if (!ent) return 0
|
|
168
|
-
return ent.recipe.reduce((sum, input) => {
|
|
169
|
-
const comp = input.itemId ? getComponentById(input.itemId) : undefined
|
|
170
|
-
return sum + (comp?.mass ?? 0) * input.quantity
|
|
171
|
-
}, 0)
|
|
186
|
+
let total = 0
|
|
187
|
+
for (const input of recipe.inputs) {
|
|
188
|
+
if ('itemId' in input) {
|
|
189
|
+
total += getItem(input.itemId).mass * input.quantity
|
|
190
|
+
} else {
|
|
191
|
+
const item = findItemByCategoryAndTier(input.category, input.tier)
|
|
192
|
+
total += item.mass * input.quantity
|
|
193
|
+
}
|
|
172
194
|
}
|
|
173
|
-
return
|
|
195
|
+
return total
|
|
174
196
|
}
|
|
175
197
|
|
|
176
198
|
export function blendCrossGroup(sources: {value: number; weight: number}[]): number {
|
|
@@ -220,39 +242,41 @@ export function computeCraftedOutputStats(
|
|
|
220
242
|
outputItemId: number,
|
|
221
243
|
slotInputs: RecipeSlotInput[]
|
|
222
244
|
): UInt64 {
|
|
223
|
-
const
|
|
224
|
-
if (
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
const slotIsComponent = getComponentById(slot.itemId) !== undefined
|
|
229
|
-
const stacks: StackInput[] = slot.stacks.map((s) => ({
|
|
230
|
-
quantity: s.quantity,
|
|
231
|
-
stats: slotIsComponent
|
|
232
|
-
? decodeCraftedItemStats(slot.itemId, s.stats)
|
|
233
|
-
: decodeRawStackToCategoryStats(s.stats, slot.category!),
|
|
234
|
-
}))
|
|
235
|
-
categoryStacks.push({category: slot.category, stacks})
|
|
236
|
-
}
|
|
237
|
-
const stats = computeComponentStats(outputItemId, categoryStacks)
|
|
238
|
-
const ordered = component.stats.map((statDef) => {
|
|
239
|
-
const found = stats.find((s) => s.key === statDef.key)
|
|
240
|
-
return found ? found.value : 0
|
|
241
|
-
})
|
|
242
|
-
return UInt64.from(encodeStats(ordered))
|
|
245
|
+
const recipe = getRecipe(outputItemId)
|
|
246
|
+
if (!recipe) {
|
|
247
|
+
throw new Error(
|
|
248
|
+
`computeCraftedOutputStats: no recipe found for outputItemId=${outputItemId}`
|
|
249
|
+
)
|
|
243
250
|
}
|
|
244
251
|
|
|
245
|
-
const
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
{}
|
|
252
|
+
const outputItem = getItem(outputItemId)
|
|
253
|
+
|
|
254
|
+
if (outputItem.type === 'entity') {
|
|
249
255
|
for (const slot of slotInputs) {
|
|
250
256
|
if (slot.category !== undefined) {
|
|
251
257
|
throw new Error(
|
|
252
|
-
`entity recipe ${
|
|
258
|
+
`entity recipe ${outputItemId} expects component inputs but slot itemId=${slot.itemId} has category=${slot.category}`
|
|
253
259
|
)
|
|
254
260
|
}
|
|
255
|
-
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// Decode each slot's stacks into key→value maps using the slot item's
|
|
265
|
+
// own stat layout, so blending works regardless of recipe shape.
|
|
266
|
+
const decodedByItem: Record<number, {quantity: number; stats: Record<string, number>}[]> = {}
|
|
267
|
+
const decodedByCategory: Partial<Record<ResourceCategory, StackInput[]>> = {}
|
|
268
|
+
|
|
269
|
+
for (const slot of slotInputs) {
|
|
270
|
+
if (slot.category !== undefined) {
|
|
271
|
+
const list = (decodedByCategory[slot.category] ??= [])
|
|
272
|
+
for (const s of slot.stacks) {
|
|
273
|
+
list.push({
|
|
274
|
+
quantity: s.quantity,
|
|
275
|
+
stats: decodeRawStackToCategoryStats(s.stats, slot.category),
|
|
276
|
+
})
|
|
277
|
+
}
|
|
278
|
+
} else {
|
|
279
|
+
const list = (decodedByItem[slot.itemId] ??= [])
|
|
256
280
|
for (const s of slot.stacks) {
|
|
257
281
|
list.push({
|
|
258
282
|
quantity: s.quantity,
|
|
@@ -260,15 +284,52 @@ export function computeCraftedOutputStats(
|
|
|
260
284
|
})
|
|
261
285
|
}
|
|
262
286
|
}
|
|
263
|
-
const stats = computeEntityStats(entityRecipe.id, componentStacks)
|
|
264
|
-
const ordered = entityRecipe.stats.map((statDef) => {
|
|
265
|
-
const found = stats.find((s) => s.key === statDef.key)
|
|
266
|
-
return found ? found.value : 0
|
|
267
|
-
})
|
|
268
|
-
return UInt64.from(encodeStats(ordered))
|
|
269
287
|
}
|
|
270
288
|
|
|
271
|
-
|
|
289
|
+
// Pre-blend itemId inputs once per item id.
|
|
290
|
+
const blendedByItem: Record<number, Record<string, number>> = {}
|
|
291
|
+
for (const [id, stacks] of Object.entries(decodedByItem)) {
|
|
292
|
+
blendedByItem[Number(id)] = blendComponentStacks(stacks)
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
const out: number[] = []
|
|
296
|
+
for (const slot of recipe.statSlots) {
|
|
297
|
+
if (slot.sources.length === 0) {
|
|
298
|
+
out.push(0)
|
|
299
|
+
continue
|
|
300
|
+
}
|
|
301
|
+
if (slot.sources.length === 1 || recipe.blendWeights.length === 0) {
|
|
302
|
+
const src = slot.sources[0]
|
|
303
|
+
const key = keyForRecipeInputStat(recipe, src.inputIndex, src.statIndex)
|
|
304
|
+
const input = recipe.inputs[src.inputIndex]
|
|
305
|
+
let value = 0
|
|
306
|
+
if (input && 'category' in input) {
|
|
307
|
+
value = blendStacks(decodedByCategory[input.category] ?? [], key)
|
|
308
|
+
} else if (input) {
|
|
309
|
+
value = blendedByItem[input.itemId]?.[key] ?? 0
|
|
310
|
+
}
|
|
311
|
+
out.push(Math.max(1, Math.min(999, value)))
|
|
312
|
+
} else {
|
|
313
|
+
let weightedSum = 0
|
|
314
|
+
let totalWeight = 0
|
|
315
|
+
for (const src of slot.sources) {
|
|
316
|
+
const key = keyForRecipeInputStat(recipe, src.inputIndex, src.statIndex)
|
|
317
|
+
const input = recipe.inputs[src.inputIndex]
|
|
318
|
+
const weight = recipe.blendWeights[src.inputIndex] ?? 1
|
|
319
|
+
let value = 0
|
|
320
|
+
if (input && 'category' in input) {
|
|
321
|
+
value = blendStacks(decodedByCategory[input.category] ?? [], key)
|
|
322
|
+
} else if (input) {
|
|
323
|
+
value = blendedByItem[input.itemId]?.[key] ?? 0
|
|
324
|
+
}
|
|
325
|
+
weightedSum += value * weight
|
|
326
|
+
totalWeight += weight
|
|
327
|
+
}
|
|
328
|
+
const blended = totalWeight > 0 ? Math.floor(weightedSum / totalWeight) : 0
|
|
329
|
+
out.push(Math.max(1, Math.min(999, blended)))
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
return UInt64.from(encodeStats(out))
|
|
272
333
|
}
|
|
273
334
|
|
|
274
335
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {getItem} from '../market/items'
|
|
2
2
|
|
|
3
3
|
export const DEPTH_THRESHOLD_T1 = 0
|
|
4
4
|
export const DEPTH_THRESHOLD_T2 = 2000
|
|
@@ -18,47 +18,23 @@ export const PLANET_SUBTYPE_ICY = 3
|
|
|
18
18
|
export const PLANET_SUBTYPE_OCEAN = 4
|
|
19
19
|
export const PLANET_SUBTYPE_INDUSTRIAL = 5
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
id: number
|
|
23
|
-
tier: ResourceTier
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const RESOURCE_CATALOG: ResourceEntry[] = [
|
|
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
|
-
]
|
|
43
|
-
|
|
44
|
-
export function getDepthThreshold(tier: ResourceTier): number {
|
|
21
|
+
export function getDepthThreshold(tier: number): number {
|
|
45
22
|
switch (tier) {
|
|
46
|
-
case
|
|
23
|
+
case 1:
|
|
47
24
|
return DEPTH_THRESHOLD_T1
|
|
48
|
-
case
|
|
25
|
+
case 2:
|
|
49
26
|
return DEPTH_THRESHOLD_T2
|
|
50
|
-
case
|
|
27
|
+
case 3:
|
|
51
28
|
return DEPTH_THRESHOLD_T3
|
|
52
|
-
case
|
|
29
|
+
case 4:
|
|
53
30
|
return DEPTH_THRESHOLD_T4
|
|
54
|
-
|
|
31
|
+
default:
|
|
55
32
|
return DEPTH_THRESHOLD_T5
|
|
56
33
|
}
|
|
57
34
|
}
|
|
58
35
|
|
|
59
|
-
export function getResourceTier(itemId: number):
|
|
60
|
-
|
|
61
|
-
return entry ? entry.tier : 't5'
|
|
36
|
+
export function getResourceTier(itemId: number): number {
|
|
37
|
+
return getItem(itemId).tier
|
|
62
38
|
}
|
|
63
39
|
|
|
64
40
|
export function getResourceWeight(itemId: number, stratum: number): number {
|
|
@@ -69,24 +45,24 @@ export function getResourceWeight(itemId: number, stratum: number): number {
|
|
|
69
45
|
const depthAbove = stratum - threshold
|
|
70
46
|
|
|
71
47
|
switch (tier) {
|
|
72
|
-
case
|
|
48
|
+
case 1:
|
|
73
49
|
if (stratum < 2000) return 100
|
|
74
50
|
if (stratum < 10000) return 80
|
|
75
51
|
if (stratum < 30000) return 50
|
|
76
52
|
return 30
|
|
77
|
-
case
|
|
53
|
+
case 2:
|
|
78
54
|
if (depthAbove < 3000) return 40
|
|
79
55
|
if (depthAbove < 8000) return 60
|
|
80
56
|
return 50
|
|
81
|
-
case
|
|
57
|
+
case 3:
|
|
82
58
|
if (depthAbove < 5000) return 20
|
|
83
59
|
if (depthAbove < 15000) return 35
|
|
84
60
|
return 40
|
|
85
|
-
case
|
|
61
|
+
case 4:
|
|
86
62
|
if (depthAbove < 10000) return 10
|
|
87
63
|
if (depthAbove < 25000) return 20
|
|
88
64
|
return 30
|
|
89
|
-
|
|
65
|
+
default:
|
|
90
66
|
return 10
|
|
91
67
|
}
|
|
92
68
|
}
|
|
@@ -76,12 +76,12 @@ export function computeContainerCapabilities(stats: Record<string, number>): {
|
|
|
76
76
|
} {
|
|
77
77
|
const density = stats['density'] ?? 500
|
|
78
78
|
const strength = stats['strength'] ?? 500
|
|
79
|
-
const
|
|
79
|
+
const hardness = stats['hardness'] ?? 500
|
|
80
80
|
const saturation = stats['saturation'] ?? 500
|
|
81
81
|
|
|
82
82
|
const hullmass = 25000 + 75 * density
|
|
83
83
|
|
|
84
|
-
const statSum = strength +
|
|
84
|
+
const statSum = strength + hardness + saturation
|
|
85
85
|
const exponent = statSum / 2997
|
|
86
86
|
const capacity = Math.floor(1000000 * Math.pow(10, exponent))
|
|
87
87
|
|
|
@@ -94,12 +94,12 @@ export function computeContainerT2Capabilities(stats: Record<string, number>): {
|
|
|
94
94
|
} {
|
|
95
95
|
const strength = stats['strength'] ?? 0
|
|
96
96
|
const density = stats['density'] ?? 0
|
|
97
|
-
const
|
|
97
|
+
const hardness = stats['hardness'] ?? 0
|
|
98
98
|
const saturation = stats['saturation'] ?? 0
|
|
99
99
|
|
|
100
100
|
const hullmass = 20000 + 50 * density
|
|
101
101
|
|
|
102
|
-
const statSum = strength +
|
|
102
|
+
const statSum = strength + hardness + saturation
|
|
103
103
|
const exponent = statSum / 2500
|
|
104
104
|
const capacity = Math.floor(1500000 * Math.pow(10, exponent))
|
|
105
105
|
|
|
@@ -18,11 +18,11 @@ export class EntityInventory extends ServerContract.Types.cargo_item {
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
get name(): string {
|
|
21
|
-
return this.item.
|
|
21
|
+
return this.item.name
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
get unitMass(): UInt32 {
|
|
25
|
-
return this.item.mass
|
|
25
|
+
return UInt32.from(this.item.mass)
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
get totalMass(): UInt64 {
|
package/src/entities/makers.ts
CHANGED
|
@@ -3,13 +3,16 @@ import {ServerContract} from '../contracts'
|
|
|
3
3
|
import {PackedModuleInput, Ship, ShipStateInput} from './ship'
|
|
4
4
|
import {computeWarehouseCapabilities, Warehouse, WarehouseStateInput} from './warehouse'
|
|
5
5
|
import {Container, ContainerStateInput} from './container'
|
|
6
|
+
import {ITEM_SHIP_T1_PACKED, ITEM_WAREHOUSE_T1_PACKED} from '../data/item-ids'
|
|
7
|
+
import {getEntityLayout} from '../data/recipes-runtime'
|
|
8
|
+
import {itemMetadata} from '../data/metadata'
|
|
9
|
+
import {getItem} from '../market/items'
|
|
6
10
|
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
} from '../
|
|
12
|
-
import {getModuleCapabilityType, MODULE_STORAGE, moduleAccepts} from '../capabilities/modules'
|
|
11
|
+
getModuleCapabilityType,
|
|
12
|
+
MODULE_STORAGE,
|
|
13
|
+
moduleAccepts,
|
|
14
|
+
moduleSlotTypeToCode,
|
|
15
|
+
} from '../capabilities/modules'
|
|
13
16
|
import {computeShipCapabilities, computeStorageCapabilities} from './ship-deploy'
|
|
14
17
|
import {decodeCraftedItemStats} from '../derivation/crafting'
|
|
15
18
|
|
|
@@ -18,9 +21,10 @@ function assignModulesToSlots(
|
|
|
18
21
|
modules: PackedModuleInput[],
|
|
19
22
|
entityLabel: string
|
|
20
23
|
): ServerContract.Types.module_entry[] {
|
|
21
|
-
const
|
|
24
|
+
const layout = getEntityLayout(packedEntityItemId)
|
|
25
|
+
const slots = layout?.slots ?? []
|
|
22
26
|
const result: Array<{type: number; installed?: ServerContract.Types.packed_module}> = slots.map(
|
|
23
|
-
(s) => ({type: s.type, installed: undefined})
|
|
27
|
+
(s) => ({type: moduleSlotTypeToCode(s.type), installed: undefined})
|
|
24
28
|
)
|
|
25
29
|
|
|
26
30
|
for (const mod of modules) {
|
|
@@ -28,8 +32,12 @@ function assignModulesToSlots(
|
|
|
28
32
|
const modType = getModuleCapabilityType(itemId)
|
|
29
33
|
const slotIdx = result.findIndex((r) => !r.installed && moduleAccepts(r.type, modType))
|
|
30
34
|
if (slotIdx === -1) {
|
|
31
|
-
|
|
32
|
-
|
|
35
|
+
let modName: string
|
|
36
|
+
try {
|
|
37
|
+
modName = getItem(itemId).name
|
|
38
|
+
} catch {
|
|
39
|
+
modName = itemMetadata[itemId]?.name ?? `item ${itemId}`
|
|
40
|
+
}
|
|
33
41
|
throw new Error(
|
|
34
42
|
`No compatible slot for module ${modName} (type ${modType}) on ${entityLabel}`
|
|
35
43
|
)
|
|
@@ -15,11 +15,11 @@ export function computeShipHullCapabilities(stats: Record<string, number>): {
|
|
|
15
15
|
} {
|
|
16
16
|
const density = stats.density ?? 500
|
|
17
17
|
const strength = stats.strength ?? 500
|
|
18
|
-
const
|
|
18
|
+
const hardness = stats.hardness ?? 500
|
|
19
19
|
const saturation = stats.saturation ?? 500
|
|
20
20
|
|
|
21
21
|
const hullmass = 25000 + 75 * density
|
|
22
|
-
const statSum = strength +
|
|
22
|
+
const statSum = strength + hardness + saturation
|
|
23
23
|
const exponent = statSum / 2997.0
|
|
24
24
|
const capacity = Math.floor(1000000 * Math.pow(10, exponent))
|
|
25
25
|
|
|
@@ -76,11 +76,11 @@ export function computeLoaderCapabilities(stats: Record<string, number>): {
|
|
|
76
76
|
thrust: number
|
|
77
77
|
quantity: number
|
|
78
78
|
} {
|
|
79
|
-
const
|
|
79
|
+
const hrd = stats.hardness ?? 500
|
|
80
80
|
const pla = stats.plasticity ?? 500
|
|
81
81
|
|
|
82
82
|
return {
|
|
83
|
-
mass: Math.max(200, 2000 - Math.floor(
|
|
83
|
+
mass: Math.max(200, 2000 - Math.floor(hrd * 2)),
|
|
84
84
|
thrust: 1 + Math.floor(pla / 500),
|
|
85
85
|
quantity: 1,
|
|
86
86
|
}
|
|
@@ -122,10 +122,10 @@ export function computeStorageCapabilities(
|
|
|
122
122
|
capacityBonus: number
|
|
123
123
|
} {
|
|
124
124
|
const strength = stats.strength ?? 500
|
|
125
|
-
const
|
|
125
|
+
const hardness = stats.hardness ?? 500
|
|
126
126
|
const saturation = stats.saturation ?? 500
|
|
127
127
|
|
|
128
|
-
const statSum = strength +
|
|
128
|
+
const statSum = strength + hardness + saturation
|
|
129
129
|
const capacityBonus = Math.floor(
|
|
130
130
|
(baseCapacity * (10 + Math.floor((statSum * 10) / 2997))) / 100
|
|
131
131
|
)
|
|
@@ -139,11 +139,11 @@ export function computeWarehouseHullCapabilities(stats: Record<string, number>):
|
|
|
139
139
|
} {
|
|
140
140
|
const density = stats.density ?? 500
|
|
141
141
|
const strength = stats.strength ?? 500
|
|
142
|
-
const
|
|
142
|
+
const hardness = stats.hardness ?? 500
|
|
143
143
|
const saturation = stats.saturation ?? 500
|
|
144
144
|
|
|
145
145
|
const hullmass = 25000 + 75 * density
|
|
146
|
-
const statSum = strength +
|
|
146
|
+
const statSum = strength + hardness + saturation
|
|
147
147
|
const exponent = statSum / 2997.0
|
|
148
148
|
const capacity = Math.floor(20000000 * Math.pow(10, exponent))
|
|
149
149
|
|
package/src/index-module.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export * from './contracts'
|
|
2
2
|
export * from './errors'
|
|
3
3
|
export * from './types'
|
|
4
|
+
export * from './data/item-ids'
|
|
5
|
+
export * from './data/recipes-runtime'
|
|
4
6
|
|
|
5
7
|
import {ServerContract} from './contracts'
|
|
6
8
|
|
|
@@ -182,51 +184,6 @@ export {
|
|
|
182
184
|
} from './data/capabilities'
|
|
183
185
|
export type {CapabilityAttribute, StatMapping} from './data/capabilities'
|
|
184
186
|
|
|
185
|
-
export {
|
|
186
|
-
components,
|
|
187
|
-
entityRecipes,
|
|
188
|
-
moduleRecipes,
|
|
189
|
-
getComponentById,
|
|
190
|
-
getEntityRecipe,
|
|
191
|
-
getEntityRecipeByItemId,
|
|
192
|
-
getModuleRecipe,
|
|
193
|
-
getModuleRecipeByItemId,
|
|
194
|
-
getAllCraftableItems,
|
|
195
|
-
getComponentsForCategory,
|
|
196
|
-
getComponentsForStat,
|
|
197
|
-
ITEM_HULL_PLATES,
|
|
198
|
-
ITEM_CARGO_LINING,
|
|
199
|
-
ITEM_CONTAINER_T1_PACKED,
|
|
200
|
-
ITEM_THRUSTER_CORE,
|
|
201
|
-
ITEM_POWER_CELL,
|
|
202
|
-
ITEM_ENGINE_T1,
|
|
203
|
-
ITEM_GENERATOR_T1,
|
|
204
|
-
ITEM_SHIP_T1_PACKED,
|
|
205
|
-
ITEM_WAREHOUSE_T1_PACKED,
|
|
206
|
-
ITEM_MATTER_CONDUIT,
|
|
207
|
-
ITEM_SURVEY_PROBE,
|
|
208
|
-
ITEM_CARGO_ARM,
|
|
209
|
-
ITEM_TOOL_BIT,
|
|
210
|
-
ITEM_REACTION_CHAMBER,
|
|
211
|
-
ITEM_GATHERER_T1,
|
|
212
|
-
ITEM_LOADER_T1,
|
|
213
|
-
ITEM_CRAFTER_T1,
|
|
214
|
-
ITEM_STORAGE_T1,
|
|
215
|
-
ITEM_HULL_PLATES_T2,
|
|
216
|
-
ITEM_CARGO_LINING_T2,
|
|
217
|
-
ITEM_CONTAINER_T2_PACKED,
|
|
218
|
-
ITEM_FOCUSING_ARRAY,
|
|
219
|
-
} from './data/recipes'
|
|
220
|
-
export type {
|
|
221
|
-
ComponentDefinition,
|
|
222
|
-
ComponentStat,
|
|
223
|
-
RecipeInput,
|
|
224
|
-
EntityRecipe,
|
|
225
|
-
ModuleRecipe,
|
|
226
|
-
ModuleSlot,
|
|
227
|
-
CraftableItem,
|
|
228
|
-
} from './data/recipes'
|
|
229
|
-
|
|
230
187
|
export {
|
|
231
188
|
encodeStats,
|
|
232
189
|
encodeGatheredCargoStats,
|
|
@@ -239,7 +196,6 @@ export {
|
|
|
239
196
|
computeEntityStats,
|
|
240
197
|
blendCargoStacks,
|
|
241
198
|
blendCrossGroup,
|
|
242
|
-
categoryItemMass,
|
|
243
199
|
computeInputMass,
|
|
244
200
|
computeCraftedOutputStats,
|
|
245
201
|
} from './derivation/crafting'
|
|
@@ -321,7 +277,6 @@ export {
|
|
|
321
277
|
computeCrafterDrain,
|
|
322
278
|
} from './nft/description'
|
|
323
279
|
|
|
324
|
-
export {getEntitySlotLayout} from './data/recipes'
|
|
325
280
|
export {
|
|
326
281
|
ITEM_TYPE_RESOURCE,
|
|
327
282
|
ITEM_TYPE_COMPONENT,
|