@shipload/sdk 1.0.0-next.37 → 1.0.0-next.39
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 +100 -5
- package/lib/shipload.js +679 -262
- package/lib/shipload.js.map +1 -1
- package/lib/shipload.m.js +668 -262
- package/lib/shipload.m.js.map +1 -1
- package/lib/testing.d.ts +15 -0
- package/lib/testing.js +75 -5
- package/lib/testing.js.map +1 -1
- package/lib/testing.m.js +75 -5
- package/lib/testing.m.js.map +1 -1
- package/package.json +1 -1
- package/src/capabilities/modules.ts +3 -0
- package/src/contracts/server.ts +30 -1
- package/src/data/capabilities.ts +7 -10
- package/src/data/capability-formulas.ts +8 -8
- package/src/data/entities.json +30 -0
- package/src/data/item-ids.ts +3 -0
- package/src/data/items.json +19 -0
- package/src/data/kind-registry.json +24 -0
- package/src/data/kind-registry.ts +15 -0
- package/src/data/metadata.ts +22 -5
- package/src/data/recipes.json +5 -5
- package/src/derivation/capabilities.test.ts +21 -3
- package/src/derivation/capabilities.ts +80 -35
- package/src/entities/makers.ts +7 -0
- package/src/entities/slot-multiplier.ts +4 -0
- package/src/index-module.ts +15 -2
- package/src/managers/actions.ts +176 -1
- package/src/nft/buildImmutableData.ts +23 -6
- package/src/nft/description.ts +41 -8
- package/src/resolution/describe-module.ts +13 -5
- package/src/resolution/resolve-item.test.ts +37 -0
- package/src/resolution/resolve-item.ts +37 -10
- package/src/scheduling/projection.ts +19 -0
- package/src/travel/route-planner.ts +29 -3
- package/src/types/capabilities.ts +5 -0
- package/src/types.ts +1 -0
package/src/data/metadata.ts
CHANGED
|
@@ -197,8 +197,8 @@ export const itemMetadata: Record<number, ItemMetadata> = {
|
|
|
197
197
|
color: '#B877FF',
|
|
198
198
|
},
|
|
199
199
|
10105: {
|
|
200
|
-
name: '
|
|
201
|
-
description: '
|
|
200
|
+
name: 'Cargo Bay',
|
|
201
|
+
description: 'Expanded cargo storage with reinforced internal holds.',
|
|
202
202
|
color: '#8B7355',
|
|
203
203
|
},
|
|
204
204
|
10106: {
|
|
@@ -214,11 +214,15 @@ export const itemMetadata: Record<number, ItemMetadata> = {
|
|
|
214
214
|
color: '#9be4ff',
|
|
215
215
|
},
|
|
216
216
|
10108: {
|
|
217
|
-
name: 'Battery',
|
|
218
|
-
description:
|
|
219
|
-
'Extends energy capacity. Stores additional charge produced by generators, letting builds chain more high-drain actions between recharges.',
|
|
217
|
+
name: 'Battery Bank',
|
|
218
|
+
description: 'Stores additional charge produced by generators.',
|
|
220
219
|
color: '#4ADBFF',
|
|
221
220
|
},
|
|
221
|
+
10109: {
|
|
222
|
+
name: 'Drive Coil',
|
|
223
|
+
description: 'Accelerates and launches cargo payloads toward a remote mass catcher.',
|
|
224
|
+
color: '#E86344',
|
|
225
|
+
},
|
|
222
226
|
|
|
223
227
|
// === Entities (packed, T1) ===
|
|
224
228
|
10200: {
|
|
@@ -247,6 +251,17 @@ export const itemMetadata: Record<number, ItemMetadata> = {
|
|
|
247
251
|
description: 'Planetary fabrication facility with generator and crafter module slots.',
|
|
248
252
|
color: '#7BA7D4',
|
|
249
253
|
},
|
|
254
|
+
10205: {
|
|
255
|
+
name: 'Mass Driver',
|
|
256
|
+
description: 'Planetary launch platform with generator and drive coil module slots.',
|
|
257
|
+
color: '#E86344',
|
|
258
|
+
},
|
|
259
|
+
10206: {
|
|
260
|
+
name: 'Mass Catcher',
|
|
261
|
+
description:
|
|
262
|
+
'Planetary receiving platform with storage module slots; catches launched payloads.',
|
|
263
|
+
color: '#4AE898',
|
|
264
|
+
},
|
|
250
265
|
|
|
251
266
|
// === Components (T2) ===
|
|
252
267
|
20001: {
|
|
@@ -274,6 +289,8 @@ export const entityMetadata: Record<number, EntityMetadata> = {
|
|
|
274
289
|
10202: {moduleSlotLabels: ['Loader', 'Storage', 'Storage', 'Storage', 'Storage']},
|
|
275
290
|
10203: {moduleSlotLabels: ['Generator', 'Gatherer']},
|
|
276
291
|
10204: {moduleSlotLabels: ['Generator', 'Crafter']},
|
|
292
|
+
10205: {moduleSlotLabels: ['Generator', 'Drive Coil']},
|
|
293
|
+
10206: {moduleSlotLabels: ['Storage', 'Storage', 'Storage']},
|
|
277
294
|
}
|
|
278
295
|
|
|
279
296
|
for (const item of items as Array<{id: number}>) {
|
package/src/data/recipes.json
CHANGED
|
@@ -450,11 +450,11 @@
|
|
|
450
450
|
"outputMass": 960000,
|
|
451
451
|
"inputs": [
|
|
452
452
|
{
|
|
453
|
-
"itemId":
|
|
453
|
+
"itemId": 10009,
|
|
454
454
|
"quantity": 300
|
|
455
455
|
},
|
|
456
456
|
{
|
|
457
|
-
"itemId":
|
|
457
|
+
"itemId": 10006,
|
|
458
458
|
"quantity": 300
|
|
459
459
|
}
|
|
460
460
|
],
|
|
@@ -462,7 +462,7 @@
|
|
|
462
462
|
{
|
|
463
463
|
"sources": [
|
|
464
464
|
{
|
|
465
|
-
"inputIndex":
|
|
465
|
+
"inputIndex": 0,
|
|
466
466
|
"statIndex": 0
|
|
467
467
|
}
|
|
468
468
|
]
|
|
@@ -470,8 +470,8 @@
|
|
|
470
470
|
{
|
|
471
471
|
"sources": [
|
|
472
472
|
{
|
|
473
|
-
"inputIndex":
|
|
474
|
-
"statIndex":
|
|
473
|
+
"inputIndex": 1,
|
|
474
|
+
"statIndex": 0
|
|
475
475
|
}
|
|
476
476
|
]
|
|
477
477
|
}
|
|
@@ -4,11 +4,16 @@ import {
|
|
|
4
4
|
computeGathererCapabilities,
|
|
5
5
|
computeCrafterCapabilities,
|
|
6
6
|
computeLoaderCapabilities,
|
|
7
|
+
computeBaseCapacity,
|
|
8
|
+
computeContainerCapabilities,
|
|
7
9
|
} from './capabilities'
|
|
8
10
|
import {applySlotMultiplier, U16_MAX} from '../entities/slot-multiplier'
|
|
9
11
|
import {encodeStats} from './crafting'
|
|
10
12
|
import {
|
|
11
13
|
ITEM_EXTRACTOR_T1_PACKED,
|
|
14
|
+
ITEM_FACTORY_T1_PACKED,
|
|
15
|
+
ITEM_MASS_DRIVER_T1_PACKED,
|
|
16
|
+
ITEM_MASS_CATCHER_T1_PACKED,
|
|
12
17
|
ITEM_GATHERER_T1,
|
|
13
18
|
ITEM_CRAFTER_T1,
|
|
14
19
|
ITEM_LOADER_T1,
|
|
@@ -20,14 +25,27 @@ function makeGathererStats(strength: number, tolerance: number, conductivity: nu
|
|
|
20
25
|
return encodeStats([strength, tolerance, conductivity, 0])
|
|
21
26
|
}
|
|
22
27
|
|
|
23
|
-
function makeCrafterStats(reactivity: number,
|
|
24
|
-
return encodeStats([reactivity,
|
|
28
|
+
function makeCrafterStats(reactivity: number, conductivity: number): bigint {
|
|
29
|
+
return encodeStats([reactivity, conductivity])
|
|
25
30
|
}
|
|
26
31
|
|
|
27
32
|
function makeLoaderStats(insulation: number, plasticity: number): bigint {
|
|
28
33
|
return encodeStats([insulation, plasticity])
|
|
29
34
|
}
|
|
30
35
|
|
|
36
|
+
test('computeBaseCapacity uses container formula for all container-class entities', () => {
|
|
37
|
+
const stats = {strength: 300, hardness: 400, density: 100}
|
|
38
|
+
const expected = computeContainerCapabilities(stats).capacity
|
|
39
|
+
for (const itemId of [
|
|
40
|
+
ITEM_EXTRACTOR_T1_PACKED,
|
|
41
|
+
ITEM_FACTORY_T1_PACKED,
|
|
42
|
+
ITEM_MASS_DRIVER_T1_PACKED,
|
|
43
|
+
ITEM_MASS_CATCHER_T1_PACKED,
|
|
44
|
+
]) {
|
|
45
|
+
expect(computeBaseCapacity(itemId, stats)).toBe(expected)
|
|
46
|
+
}
|
|
47
|
+
})
|
|
48
|
+
|
|
31
49
|
test('computeEntityCapabilities emits gathererLanes alongside legacy gatherer sum', () => {
|
|
32
50
|
// Two gatherers with distinct stats in separate slots, amp=100 for both
|
|
33
51
|
const gathStats1 = makeGathererStats(300, 200, 400)
|
|
@@ -92,7 +110,7 @@ test('computeEntityCapabilities emits crafterLanes alongside legacy crafter sum'
|
|
|
92
110
|
expect(result.crafterLanes!.length).toBe(1)
|
|
93
111
|
expect(result.crafterLanes![0].slotIndex).toBe(0)
|
|
94
112
|
|
|
95
|
-
const caps = computeCrafterCapabilities({reactivity: 400,
|
|
113
|
+
const caps = computeCrafterCapabilities({reactivity: 400, conductivity: 300})
|
|
96
114
|
const expectedSpeed = applySlotMultiplier(caps.speed, 120)
|
|
97
115
|
expect(result.crafterLanes![0].speed).toBe(expectedSpeed)
|
|
98
116
|
expect(result.crafterLanes![0].drain).toBe(caps.drain)
|
|
@@ -107,11 +107,11 @@ export function computeCrafterCapabilities(stats: Record<string, number>): {
|
|
|
107
107
|
drain: number
|
|
108
108
|
} {
|
|
109
109
|
const rea = stats.reactivity
|
|
110
|
-
const
|
|
110
|
+
const con = stats.conductivity
|
|
111
111
|
|
|
112
112
|
return {
|
|
113
113
|
speed: 100 + Math.floor((rea * 4) / 5),
|
|
114
|
-
drain: Math.max(5, 30 - Math.floor(
|
|
114
|
+
drain: Math.max(5, 30 - Math.floor(con / 33)),
|
|
115
115
|
}
|
|
116
116
|
}
|
|
117
117
|
|
|
@@ -131,23 +131,39 @@ export function computeHaulerCapabilities(stats: Record<string, number>): {
|
|
|
131
131
|
}
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
-
export function
|
|
135
|
-
stats:
|
|
136
|
-
|
|
137
|
-
): {
|
|
138
|
-
|
|
134
|
+
export function computeLauncherCapabilities(
|
|
135
|
+
stats: {charge_rate: number; velocity: number; drain: number},
|
|
136
|
+
amp = 100
|
|
137
|
+
): {chargeRate: number; velocity: number; drain: number} {
|
|
138
|
+
return {
|
|
139
|
+
chargeRate: Math.floor((stats.charge_rate * amp) / 100),
|
|
140
|
+
velocity: Math.floor((stats.velocity * amp) / 100),
|
|
141
|
+
drain: stats.drain,
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export function computeStorageCapabilities(stats: Record<string, number>): {
|
|
146
|
+
capacity: number
|
|
139
147
|
} {
|
|
140
|
-
const strength = stats.strength
|
|
141
|
-
const density = stats.density
|
|
142
|
-
const hardness = stats.hardness
|
|
143
|
-
const cohesion = stats.cohesion
|
|
148
|
+
const strength = stats.strength ?? 0
|
|
149
|
+
const density = stats.density ?? 0
|
|
150
|
+
const hardness = stats.hardness ?? 0
|
|
151
|
+
const cohesion = stats.cohesion ?? 0
|
|
144
152
|
|
|
145
153
|
const statSum = strength + density + hardness + cohesion
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
)
|
|
154
|
+
return {capacity: 10_000_000 + Math.floor((statSum * 50_000_000) / 3996)}
|
|
155
|
+
}
|
|
149
156
|
|
|
150
|
-
|
|
157
|
+
export function computeBatteryCapabilities(stats: Record<string, number>): {
|
|
158
|
+
capacity: number
|
|
159
|
+
} {
|
|
160
|
+
const volatility = stats.volatility ?? 0
|
|
161
|
+
const thermal = stats.thermal ?? 0
|
|
162
|
+
const plasticity = stats.plasticity ?? 0
|
|
163
|
+
const insulation = stats.insulation ?? 0
|
|
164
|
+
|
|
165
|
+
const statSum = volatility + thermal + plasticity + insulation
|
|
166
|
+
return {capacity: 2_500 + Math.floor((statSum * 7_500) / 3996)}
|
|
151
167
|
}
|
|
152
168
|
|
|
153
169
|
import {
|
|
@@ -155,6 +171,8 @@ import {
|
|
|
155
171
|
ITEM_CONTAINER_T2_PACKED,
|
|
156
172
|
ITEM_EXTRACTOR_T1_PACKED,
|
|
157
173
|
ITEM_FACTORY_T1_PACKED,
|
|
174
|
+
ITEM_MASS_CATCHER_T1_PACKED,
|
|
175
|
+
ITEM_MASS_DRIVER_T1_PACKED,
|
|
158
176
|
ITEM_SHIP_T1_PACKED,
|
|
159
177
|
ITEM_WAREHOUSE_T1_PACKED,
|
|
160
178
|
} from '../data/item-ids'
|
|
@@ -169,17 +187,20 @@ import {
|
|
|
169
187
|
MODULE_CRAFTER,
|
|
170
188
|
MODULE_HAULER,
|
|
171
189
|
MODULE_WARP,
|
|
190
|
+
MODULE_LAUNCHER,
|
|
172
191
|
} from '../capabilities/modules'
|
|
173
192
|
import {getItem} from '../data/catalog'
|
|
174
|
-
import {decodeCraftedItemStats} from './crafting'
|
|
193
|
+
import {decodeCraftedItemStats, decodeStat} from './crafting'
|
|
175
194
|
import {
|
|
176
195
|
applySlotMultiplier,
|
|
196
|
+
applySlotMultiplierUint32,
|
|
177
197
|
clampUint16,
|
|
178
198
|
clampUint32,
|
|
179
199
|
getSlotAmp,
|
|
180
200
|
type InstalledModule,
|
|
181
201
|
} from '../entities/slot-multiplier'
|
|
182
202
|
import type {EntitySlot} from '../data/recipes-runtime'
|
|
203
|
+
import {computeTravelDrain} from '../nft/description'
|
|
183
204
|
|
|
184
205
|
export function computeBaseCapacity(itemId: number, stats: Record<string, number>): number {
|
|
185
206
|
switch (itemId) {
|
|
@@ -187,6 +208,8 @@ export function computeBaseCapacity(itemId: number, stats: Record<string, number
|
|
|
187
208
|
return computeShipHullCapabilities(stats).capacity
|
|
188
209
|
case ITEM_EXTRACTOR_T1_PACKED:
|
|
189
210
|
case ITEM_FACTORY_T1_PACKED:
|
|
211
|
+
case ITEM_MASS_DRIVER_T1_PACKED:
|
|
212
|
+
case ITEM_MASS_CATCHER_T1_PACKED:
|
|
190
213
|
case ITEM_CONTAINER_T1_PACKED:
|
|
191
214
|
return computeContainerCapabilities(stats).capacity
|
|
192
215
|
case ITEM_WAREHOUSE_T1_PACKED:
|
|
@@ -252,6 +275,7 @@ export interface ComputedCapabilities {
|
|
|
252
275
|
crafterLanes?: CrafterLaneEntry[]
|
|
253
276
|
hauler?: {capacity: number; efficiency: number; drain: number}
|
|
254
277
|
warp?: {range: number}
|
|
278
|
+
launcher?: {chargeRate: number; velocity: number; drain: number}
|
|
255
279
|
}
|
|
256
280
|
|
|
257
281
|
export function computeEntityCapabilities(
|
|
@@ -261,7 +285,8 @@ export function computeEntityCapabilities(
|
|
|
261
285
|
layout: EntitySlot[]
|
|
262
286
|
): ComputedCapabilities {
|
|
263
287
|
let totalThrust = 0
|
|
264
|
-
let
|
|
288
|
+
let totalEngineThm = 0
|
|
289
|
+
let engineCount = 0
|
|
265
290
|
let hasEngine = false
|
|
266
291
|
|
|
267
292
|
let totalGenCapacity = 0
|
|
@@ -278,7 +303,7 @@ export function computeEntityCapabilities(
|
|
|
278
303
|
let maxGathDepth = 0
|
|
279
304
|
let hasGatherer = false
|
|
280
305
|
|
|
281
|
-
let
|
|
306
|
+
let totalStorageCapacity = 0
|
|
282
307
|
const baseCapacity = computeBaseCapacity(itemId, stats)
|
|
283
308
|
let installedModuleMass = 0
|
|
284
309
|
|
|
@@ -294,8 +319,12 @@ export function computeEntityCapabilities(
|
|
|
294
319
|
let totalWarpRange = 0
|
|
295
320
|
let hasWarp = false
|
|
296
321
|
|
|
297
|
-
let
|
|
298
|
-
let
|
|
322
|
+
let totalLauncherChargeRate = 0
|
|
323
|
+
let totalLauncherVelocity = 0
|
|
324
|
+
let totalLauncherDrain = 0
|
|
325
|
+
let hasLauncher = false
|
|
326
|
+
|
|
327
|
+
let totalBatteryCapacity = 0
|
|
299
328
|
|
|
300
329
|
const gathererLanes: GathererLaneEntry[] = []
|
|
301
330
|
const crafterLanes: CrafterLaneEntry[] = []
|
|
@@ -312,7 +341,8 @@ export function computeEntityCapabilities(
|
|
|
312
341
|
hasEngine = true
|
|
313
342
|
const caps = computeEngineCapabilities(decodedStats)
|
|
314
343
|
totalThrust += applySlotMultiplier(caps.thrust, amp)
|
|
315
|
-
|
|
344
|
+
totalEngineThm += decodedStats.thermal ?? 0
|
|
345
|
+
engineCount += 1
|
|
316
346
|
} else if (modType === MODULE_GENERATOR) {
|
|
317
347
|
hasGenerator = true
|
|
318
348
|
const caps = computeGeneratorCapabilities(decodedStats)
|
|
@@ -346,8 +376,8 @@ export function computeEntityCapabilities(
|
|
|
346
376
|
outputPct: amp,
|
|
347
377
|
})
|
|
348
378
|
} else if (modType === MODULE_STORAGE) {
|
|
349
|
-
const caps = computeStorageCapabilities(decodedStats
|
|
350
|
-
|
|
379
|
+
const caps = computeStorageCapabilities(decodedStats)
|
|
380
|
+
totalStorageCapacity += applySlotMultiplierUint32(caps.capacity, amp)
|
|
351
381
|
} else if (modType === MODULE_CRAFTER) {
|
|
352
382
|
hasCrafter = true
|
|
353
383
|
const caps = computeCrafterCapabilities(decodedStats)
|
|
@@ -371,29 +401,37 @@ export function computeEntityCapabilities(
|
|
|
371
401
|
hasWarp = true
|
|
372
402
|
const caps = computeWarpCapabilities(decodedStats)
|
|
373
403
|
totalWarpRange += applySlotMultiplier(caps.range, amp)
|
|
404
|
+
} else if (modType === MODULE_LAUNCHER) {
|
|
405
|
+
hasLauncher = true
|
|
406
|
+
const caps = computeLauncherCapabilities(
|
|
407
|
+
{
|
|
408
|
+
charge_rate: decodedStats.charge_rate ?? decodeStat(mod.stats, 0),
|
|
409
|
+
velocity: decodedStats.velocity ?? decodeStat(mod.stats, 1),
|
|
410
|
+
drain: decodedStats.drain ?? decodeStat(mod.stats, 2),
|
|
411
|
+
},
|
|
412
|
+
amp
|
|
413
|
+
)
|
|
414
|
+
totalLauncherChargeRate = clampUint16(totalLauncherChargeRate + caps.chargeRate)
|
|
415
|
+
totalLauncherVelocity = clampUint16(totalLauncherVelocity + caps.velocity)
|
|
416
|
+
totalLauncherDrain = clampUint16(totalLauncherDrain + caps.drain)
|
|
374
417
|
} else if (modType === MODULE_BATTERY) {
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
const thm = decodedStats.thermal ?? 0
|
|
378
|
-
const pla = decodedStats.plasticity ?? 0
|
|
379
|
-
const ins = decodedStats.insulation ?? 0
|
|
380
|
-
totalBatteryStatSum += vol + thm + pla + ins
|
|
418
|
+
const caps = computeBatteryCapabilities(decodedStats)
|
|
419
|
+
totalBatteryCapacity += applySlotMultiplierUint32(caps.capacity, amp)
|
|
381
420
|
}
|
|
382
421
|
}
|
|
383
422
|
|
|
384
|
-
if (hasGenerator &&
|
|
385
|
-
|
|
386
|
-
const bonusPctNum = 10 * batteryCount + Math.floor((totalBatteryStatSum * 10) / 2997)
|
|
387
|
-
totalGenCapacity += Math.floor((genCapBase * bonusPctNum) / 100)
|
|
423
|
+
if (hasGenerator && totalBatteryCapacity > 0) {
|
|
424
|
+
totalGenCapacity += totalBatteryCapacity
|
|
388
425
|
}
|
|
389
426
|
|
|
390
427
|
const result: ComputedCapabilities = {
|
|
391
428
|
hullmass: computeBaseHullmass(stats) + installedModuleMass,
|
|
392
|
-
capacity: baseCapacity +
|
|
429
|
+
capacity: clampUint32(baseCapacity + totalStorageCapacity),
|
|
393
430
|
}
|
|
394
431
|
|
|
395
432
|
if (hasEngine) {
|
|
396
|
-
|
|
433
|
+
const avgThm = engineCount > 0 ? Math.trunc(totalEngineThm / engineCount) : 0
|
|
434
|
+
result.engines = {thrust: totalThrust, drain: computeTravelDrain(totalThrust, avgThm)}
|
|
397
435
|
}
|
|
398
436
|
if (hasGenerator) {
|
|
399
437
|
result.generator = {
|
|
@@ -433,6 +471,13 @@ export function computeEntityCapabilities(
|
|
|
433
471
|
if (hasWarp) {
|
|
434
472
|
result.warp = {range: totalWarpRange}
|
|
435
473
|
}
|
|
474
|
+
if (hasLauncher) {
|
|
475
|
+
result.launcher = {
|
|
476
|
+
chargeRate: totalLauncherChargeRate,
|
|
477
|
+
velocity: totalLauncherVelocity,
|
|
478
|
+
drain: totalLauncherDrain,
|
|
479
|
+
}
|
|
480
|
+
}
|
|
436
481
|
|
|
437
482
|
return result
|
|
438
483
|
}
|
package/src/entities/makers.ts
CHANGED
|
@@ -142,6 +142,13 @@ export function makeEntity(packedItemId: number, state: EntityStateInput): Entit
|
|
|
142
142
|
if (caps.generator) info.generator = caps.generator
|
|
143
143
|
if (caps.hauler) info.hauler = caps.hauler
|
|
144
144
|
if (caps.warp) info.warp = caps.warp
|
|
145
|
+
if (caps.launcher) {
|
|
146
|
+
info.launcher = ServerContract.Types.launcher_stats.from({
|
|
147
|
+
charge_rate: caps.launcher.chargeRate,
|
|
148
|
+
velocity: caps.launcher.velocity,
|
|
149
|
+
drain: caps.launcher.drain,
|
|
150
|
+
})
|
|
151
|
+
}
|
|
145
152
|
|
|
146
153
|
info.gatherer_lanes = (caps.gathererLanes ?? []).map((l) =>
|
|
147
154
|
ServerContract.Types.gatherer_lane.from({
|
|
@@ -34,6 +34,10 @@ export function applySlotMultiplier(value: number, outputPct: number): number {
|
|
|
34
34
|
return clampUint16(Math.floor((value * outputPct) / 100))
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
+
export function applySlotMultiplierUint32(value: number, outputPct: number): number {
|
|
38
|
+
return clampUint32(Math.floor((value * outputPct) / 100))
|
|
39
|
+
}
|
|
40
|
+
|
|
37
41
|
export function getSlotAmp(layout: EntitySlot[], slotIndex: number): number {
|
|
38
42
|
return layout[slotIndex]?.outputPct ?? 100
|
|
39
43
|
}
|
package/src/index-module.ts
CHANGED
|
@@ -62,7 +62,14 @@ export type {
|
|
|
62
62
|
ScheduledBuild,
|
|
63
63
|
Reservation,
|
|
64
64
|
} from './managers'
|
|
65
|
-
export type {
|
|
65
|
+
export type {
|
|
66
|
+
EntityRefInput,
|
|
67
|
+
LaunchNumericInput,
|
|
68
|
+
LaunchQuote,
|
|
69
|
+
LaunchQuoteCatcher,
|
|
70
|
+
LaunchQuoteLauncher,
|
|
71
|
+
LaunchStatsInput,
|
|
72
|
+
} from './managers/actions'
|
|
66
73
|
export type {WrapDeposit} from './managers/nft'
|
|
67
74
|
export {resolveLockedAmount} from './managers/nft'
|
|
68
75
|
|
|
@@ -191,7 +198,7 @@ export type {
|
|
|
191
198
|
HasScheduleAndLocation,
|
|
192
199
|
} from './travel/travel'
|
|
193
200
|
|
|
194
|
-
export {planRoute, sdkSystemGraph} from './travel/route-planner'
|
|
201
|
+
export {planRoute, sdkSystemGraph, MAX_LEGS} from './travel/route-planner'
|
|
195
202
|
export type {
|
|
196
203
|
Coord,
|
|
197
204
|
Neighbor,
|
|
@@ -379,9 +386,11 @@ export {
|
|
|
379
386
|
computeCrafterCapabilities,
|
|
380
387
|
computeWarehouseHullCapabilities,
|
|
381
388
|
computeStorageCapabilities,
|
|
389
|
+
computeBatteryCapabilities,
|
|
382
390
|
computeContainerCapabilities,
|
|
383
391
|
computeContainerT2Capabilities,
|
|
384
392
|
computeWarpCapabilities,
|
|
393
|
+
computeLauncherCapabilities,
|
|
385
394
|
computeBaseCapacity,
|
|
386
395
|
computeEntityCapabilities,
|
|
387
396
|
GATHERER_DEPTH_TABLE,
|
|
@@ -484,6 +493,10 @@ export {
|
|
|
484
493
|
computeBaseCapacityWarehouse,
|
|
485
494
|
computeEngineThrust,
|
|
486
495
|
computeEngineDrain,
|
|
496
|
+
computeTravelDrain,
|
|
497
|
+
ENGINE_DRAIN_BASE,
|
|
498
|
+
ENGINE_DRAIN_REF_THRUST,
|
|
499
|
+
ENGINE_DRAIN_REF_THM,
|
|
487
500
|
computeGeneratorCap,
|
|
488
501
|
computeGeneratorRech,
|
|
489
502
|
computeGathererYield,
|
package/src/managers/actions.ts
CHANGED
|
@@ -17,9 +17,144 @@ import {
|
|
|
17
17
|
type UInt64Type,
|
|
18
18
|
} from '@wharfkit/antelope'
|
|
19
19
|
import {BaseManager} from './base'
|
|
20
|
-
import type
|
|
20
|
+
import {Coordinates, PRECISION, type CoordinatesType} from '../types'
|
|
21
21
|
import {ServerContract} from '../contracts'
|
|
22
22
|
import {ATOMICASSETS_ABI, SHIPLOAD_COLLECTION} from '../nft/atomicassets'
|
|
23
|
+
import {getItem} from '../data/catalog'
|
|
24
|
+
|
|
25
|
+
const CHARGE_K = 1n
|
|
26
|
+
const ENERGY_DIVISOR = 1_000_000n
|
|
27
|
+
const UINT32_MAX = 4_294_967_295
|
|
28
|
+
const UINT32_MAX_BIGINT = 4_294_967_295n
|
|
29
|
+
const UINT32_MOD = 4_294_967_296n
|
|
30
|
+
const UINT64_MAX = 18_446_744_073_709_551_615n
|
|
31
|
+
const PRECISION_BIGINT = BigInt(PRECISION)
|
|
32
|
+
|
|
33
|
+
export type LaunchNumericInput =
|
|
34
|
+
| number
|
|
35
|
+
| bigint
|
|
36
|
+
| string
|
|
37
|
+
| {toNumber(): number}
|
|
38
|
+
| {toString(): string}
|
|
39
|
+
|
|
40
|
+
export interface LaunchStatsInput {
|
|
41
|
+
charge_rate?: LaunchNumericInput
|
|
42
|
+
chargeRate?: LaunchNumericInput
|
|
43
|
+
velocity: LaunchNumericInput
|
|
44
|
+
drain: LaunchNumericInput
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface LaunchQuoteLauncher {
|
|
48
|
+
coordinates: CoordinatesType
|
|
49
|
+
launcher: LaunchStatsInput
|
|
50
|
+
generator?: {capacity: LaunchNumericInput}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface LaunchQuoteCatcher {
|
|
54
|
+
coordinates: CoordinatesType
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface LaunchQuote {
|
|
58
|
+
chargeTime: number
|
|
59
|
+
flightTime: number
|
|
60
|
+
arrival: Date
|
|
61
|
+
energyCost: number
|
|
62
|
+
maxReach: bigint
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function toNumber(value: LaunchNumericInput): number {
|
|
66
|
+
if (typeof value === 'number') return Math.trunc(value)
|
|
67
|
+
if (typeof value === 'bigint') return Number(value)
|
|
68
|
+
if (typeof value === 'string') return Number(value)
|
|
69
|
+
if ('toNumber' in value && typeof value.toNumber === 'function') return value.toNumber()
|
|
70
|
+
return Number(value.toString())
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function requiredNumber(value: LaunchNumericInput | undefined, label: string): number {
|
|
74
|
+
if (value === undefined) throw new Error(`launch quote requires ${label}`)
|
|
75
|
+
return toNumber(value)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function toBigInt(value: LaunchNumericInput | undefined): bigint {
|
|
79
|
+
if (value === undefined) return 0n
|
|
80
|
+
if (typeof value === 'bigint') return value
|
|
81
|
+
if (typeof value === 'number') return BigInt(Math.trunc(value))
|
|
82
|
+
if (typeof value === 'string') return BigInt(value)
|
|
83
|
+
return BigInt(value.toString())
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function saturatingMul(lhs: bigint, rhs: bigint): bigint {
|
|
87
|
+
if (lhs !== 0n && rhs > UINT64_MAX / lhs) {
|
|
88
|
+
return UINT64_MAX
|
|
89
|
+
}
|
|
90
|
+
return lhs * rhs
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function clampLaunchResult(value: bigint): number {
|
|
94
|
+
if (value < 1n) return 1
|
|
95
|
+
if (value > UINT32_MAX_BIGINT) return UINT32_MAX
|
|
96
|
+
return Number(value)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function toUint32(value: bigint): bigint {
|
|
100
|
+
return value % UINT32_MOD
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function calcDistance(origin: CoordinatesType, destination: CoordinatesType): bigint {
|
|
104
|
+
const a = Coordinates.from(origin)
|
|
105
|
+
const b = Coordinates.from(destination)
|
|
106
|
+
const dx = toNumber(a.x) - toNumber(b.x)
|
|
107
|
+
const dy = toNumber(a.y) - toNumber(b.y)
|
|
108
|
+
return BigInt(Math.trunc(Math.sqrt(dx * dx + dy * dy) * PRECISION))
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function calcCargoItemMassUint32(item: ServerContract.ActionParams.Type.cargo_item): bigint {
|
|
112
|
+
let mass = toUint32(BigInt(getItem(item.item_id).mass) * toUint32(toBigInt(item.quantity)))
|
|
113
|
+
|
|
114
|
+
for (const mod of item.modules) {
|
|
115
|
+
if (mod.installed) {
|
|
116
|
+
mass = toUint32(mass + BigInt(getItem(mod.installed.item_id).mass))
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return mass
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function calcPayloadMass(items: ServerContract.ActionParams.Type.cargo_item[]): bigint {
|
|
124
|
+
let mass = 0n
|
|
125
|
+
for (const item of items) {
|
|
126
|
+
mass = toUint32(mass + calcCargoItemMassUint32(item))
|
|
127
|
+
}
|
|
128
|
+
return mass
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function calcChargeTime(chargeRate: number, mass: bigint): number {
|
|
132
|
+
const rate = BigInt(chargeRate || 1)
|
|
133
|
+
return clampLaunchResult((mass * CHARGE_K) / rate)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function calcFlightTime(velocity: number, distance: bigint): number {
|
|
137
|
+
const v = BigInt(velocity || 1)
|
|
138
|
+
return clampLaunchResult(distance / (v * PRECISION_BIGINT))
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function calcLaunchEnergy(drain: number, mass: bigint, distance: bigint): number {
|
|
142
|
+
const e =
|
|
143
|
+
saturatingMul(saturatingMul(mass, distance / PRECISION_BIGINT), BigInt(drain)) /
|
|
144
|
+
ENERGY_DIVISOR
|
|
145
|
+
return clampLaunchResult(e)
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function calcMaxReach(energyBudget: bigint, mass: bigint, drain: number): bigint {
|
|
149
|
+
if (energyBudget < 1n) return 0n
|
|
150
|
+
if (energyBudget >= UINT32_MAX_BIGINT || mass === 0n || drain === 0) return UINT64_MAX
|
|
151
|
+
|
|
152
|
+
const numerator = (energyBudget + 1n) * ENERGY_DIVISOR - 1n
|
|
153
|
+
const denominator = mass * BigInt(drain)
|
|
154
|
+
const distanceUnits = numerator / denominator
|
|
155
|
+
const maxDistance = distanceUnits * PRECISION_BIGINT + (PRECISION_BIGINT - 1n)
|
|
156
|
+
return maxDistance > UINT64_MAX ? UINT64_MAX : maxDistance
|
|
157
|
+
}
|
|
23
158
|
|
|
24
159
|
export type EntityRefInput = {
|
|
25
160
|
entityType: NameType
|
|
@@ -166,6 +301,46 @@ export class ActionsManager extends BaseManager {
|
|
|
166
301
|
})
|
|
167
302
|
}
|
|
168
303
|
|
|
304
|
+
launch(
|
|
305
|
+
launcherId: UInt64Type,
|
|
306
|
+
catcherId: UInt64Type,
|
|
307
|
+
items: ServerContract.ActionParams.Type.cargo_item[]
|
|
308
|
+
): Action {
|
|
309
|
+
return this.server.action('launch', {
|
|
310
|
+
launcher_id: UInt64.from(launcherId),
|
|
311
|
+
catcher_id: UInt64.from(catcherId),
|
|
312
|
+
items,
|
|
313
|
+
})
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
getLaunchQuote(
|
|
317
|
+
launcher: LaunchQuoteLauncher,
|
|
318
|
+
catcher: LaunchQuoteCatcher,
|
|
319
|
+
items: ServerContract.ActionParams.Type.cargo_item[],
|
|
320
|
+
start = new Date()
|
|
321
|
+
): LaunchQuote {
|
|
322
|
+
const chargeRate = requiredNumber(
|
|
323
|
+
launcher.launcher.charge_rate ?? launcher.launcher.chargeRate,
|
|
324
|
+
'launcher charge rate'
|
|
325
|
+
)
|
|
326
|
+
const velocity = requiredNumber(launcher.launcher.velocity, 'launcher velocity')
|
|
327
|
+
const drain = requiredNumber(launcher.launcher.drain, 'launcher drain')
|
|
328
|
+
const mass = calcPayloadMass(items)
|
|
329
|
+
const distance = calcDistance(launcher.coordinates, catcher.coordinates)
|
|
330
|
+
const chargeTime = calcChargeTime(chargeRate, mass)
|
|
331
|
+
const flightTime = calcFlightTime(velocity, distance)
|
|
332
|
+
const energyCost = calcLaunchEnergy(drain, mass, distance)
|
|
333
|
+
const maxReach = calcMaxReach(toBigInt(launcher.generator?.capacity), mass, drain)
|
|
334
|
+
|
|
335
|
+
return {
|
|
336
|
+
chargeTime,
|
|
337
|
+
flightTime,
|
|
338
|
+
arrival: new Date(start.getTime() + (chargeTime + flightTime) * 1000),
|
|
339
|
+
energyCost,
|
|
340
|
+
maxReach,
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
169
344
|
foundCompany(account: NameType, name: string): Action {
|
|
170
345
|
return this.platform.action('foundcompany', {
|
|
171
346
|
account: Name.from(account),
|