@shipload/sdk 1.0.0-next.37 → 1.0.0-next.38
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 +15 -3
- package/lib/shipload.js +162 -83
- package/lib/shipload.js.map +1 -1
- package/lib/shipload.m.js +161 -84
- package/lib/shipload.m.js.map +1 -1
- package/lib/testing.js +4 -4
- package/lib/testing.js.map +1 -1
- package/lib/testing.m.js +4 -4
- package/lib/testing.m.js.map +1 -1
- package/package.json +1 -1
- package/src/data/capabilities.ts +7 -10
- package/src/data/capability-formulas.ts +8 -8
- package/src/data/metadata.ts +4 -5
- package/src/data/recipes.json +5 -5
- package/src/derivation/capabilities.test.ts +3 -3
- package/src/derivation/capabilities.ts +30 -31
- package/src/entities/slot-multiplier.ts +4 -0
- package/src/index-module.ts +2 -1
- package/src/nft/buildImmutableData.ts +23 -6
- package/src/nft/description.ts +31 -8
- package/src/resolution/describe-module.ts +13 -5
- package/src/resolution/resolve-item.ts +31 -9
- package/src/travel/route-planner.ts +29 -3
package/package.json
CHANGED
package/src/data/capabilities.ts
CHANGED
|
@@ -21,20 +21,22 @@ export const capabilityNames: string[] = [
|
|
|
21
21
|
'Crafter',
|
|
22
22
|
'Launch',
|
|
23
23
|
'Hauler',
|
|
24
|
-
'Battery',
|
|
25
24
|
]
|
|
26
25
|
|
|
27
26
|
export const capabilityAttributes: CapabilityAttribute[] = [
|
|
28
27
|
{capability: 'Hull', attribute: 'mass', description: 'Total mass of the hull'},
|
|
29
|
-
{capability: 'Storage', attribute: 'capacity', description: 'Maximum mass that can be stored'},
|
|
30
28
|
{
|
|
31
29
|
capability: 'Storage',
|
|
32
|
-
attribute: '
|
|
33
|
-
description: '
|
|
30
|
+
attribute: 'capacity',
|
|
31
|
+
description: 'Cargo capacity added by hulls and installed Cargo Bay modules',
|
|
34
32
|
},
|
|
35
33
|
{capability: 'Movement', attribute: 'thrust', description: 'Propulsion force'},
|
|
36
34
|
{capability: 'Movement', attribute: 'drain', description: 'Energy consumed per movement'},
|
|
37
|
-
{
|
|
35
|
+
{
|
|
36
|
+
capability: 'Energy',
|
|
37
|
+
attribute: 'capacity',
|
|
38
|
+
description: 'Energy capacity from Generators and installed Battery Bank modules',
|
|
39
|
+
},
|
|
38
40
|
{capability: 'Energy', attribute: 'recharge', description: 'Energy regeneration rate'},
|
|
39
41
|
{capability: 'Loader', attribute: 'mass', description: 'Weight of the loader unit itself'},
|
|
40
42
|
{capability: 'Loader', attribute: 'thrust', description: 'Loading speed/force'},
|
|
@@ -72,11 +74,6 @@ export const capabilityAttributes: CapabilityAttribute[] = [
|
|
|
72
74
|
attribute: 'drain',
|
|
73
75
|
description: 'Energy consumed per target during haul-beam operation',
|
|
74
76
|
},
|
|
75
|
-
{
|
|
76
|
-
capability: 'Battery',
|
|
77
|
-
attribute: 'bonus',
|
|
78
|
-
description: 'Energy capacity bonus added by an installed Battery module',
|
|
79
|
-
},
|
|
80
77
|
]
|
|
81
78
|
|
|
82
79
|
const invertedAttributes = new Set(['drain', 'mass'])
|
|
@@ -48,10 +48,10 @@ export const SLOT_FORMULAS: Record<SlotConsumerKind, Record<number, SlotConsumer
|
|
|
48
48
|
1: {capability: 'Crafter', attribute: 'drain'},
|
|
49
49
|
},
|
|
50
50
|
storage: {
|
|
51
|
-
0: {capability: 'Storage', attribute: '
|
|
52
|
-
1: {capability: 'Storage', attribute: '
|
|
53
|
-
2: {capability: 'Storage', attribute: '
|
|
54
|
-
3: {capability: 'Storage', attribute: '
|
|
51
|
+
0: {capability: 'Storage', attribute: 'capacity'},
|
|
52
|
+
1: {capability: 'Storage', attribute: 'capacity'},
|
|
53
|
+
2: {capability: 'Storage', attribute: 'capacity'},
|
|
54
|
+
3: {capability: 'Storage', attribute: 'capacity'},
|
|
55
55
|
},
|
|
56
56
|
hauler: {
|
|
57
57
|
0: {capability: 'Hauler', attribute: 'capacity'},
|
|
@@ -62,10 +62,10 @@ export const SLOT_FORMULAS: Record<SlotConsumerKind, Record<number, SlotConsumer
|
|
|
62
62
|
0: {capability: 'Warp', attribute: 'range'},
|
|
63
63
|
},
|
|
64
64
|
battery: {
|
|
65
|
-
0: {capability: '
|
|
66
|
-
1: {capability: '
|
|
67
|
-
2: {capability: '
|
|
68
|
-
3: {capability: '
|
|
65
|
+
0: {capability: 'Energy', attribute: 'capacity'},
|
|
66
|
+
1: {capability: 'Energy', attribute: 'capacity'},
|
|
67
|
+
2: {capability: 'Energy', attribute: 'capacity'},
|
|
68
|
+
3: {capability: 'Energy', attribute: 'capacity'},
|
|
69
69
|
},
|
|
70
70
|
'ship-t1': ENTITY_HULL_SLOTS,
|
|
71
71
|
'container-t1': ENTITY_HULL_SLOTS,
|
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,9 +214,8 @@ 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
|
},
|
|
222
221
|
|
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
|
}
|
|
@@ -20,8 +20,8 @@ function makeGathererStats(strength: number, tolerance: number, conductivity: nu
|
|
|
20
20
|
return encodeStats([strength, tolerance, conductivity, 0])
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
function makeCrafterStats(reactivity: number,
|
|
24
|
-
return encodeStats([reactivity,
|
|
23
|
+
function makeCrafterStats(reactivity: number, conductivity: number): bigint {
|
|
24
|
+
return encodeStats([reactivity, conductivity])
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
function makeLoaderStats(insulation: number, plasticity: number): bigint {
|
|
@@ -92,7 +92,7 @@ test('computeEntityCapabilities emits crafterLanes alongside legacy crafter sum'
|
|
|
92
92
|
expect(result.crafterLanes!.length).toBe(1)
|
|
93
93
|
expect(result.crafterLanes![0].slotIndex).toBe(0)
|
|
94
94
|
|
|
95
|
-
const caps = computeCrafterCapabilities({reactivity: 400,
|
|
95
|
+
const caps = computeCrafterCapabilities({reactivity: 400, conductivity: 300})
|
|
96
96
|
const expectedSpeed = applySlotMultiplier(caps.speed, 120)
|
|
97
97
|
expect(result.crafterLanes![0].speed).toBe(expectedSpeed)
|
|
98
98
|
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,28 @@ export function computeHaulerCapabilities(stats: Record<string, number>): {
|
|
|
131
131
|
}
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
-
export function computeStorageCapabilities(
|
|
135
|
-
|
|
136
|
-
baseCapacity: number
|
|
137
|
-
): {
|
|
138
|
-
capacityBonus: number
|
|
134
|
+
export function computeStorageCapabilities(stats: Record<string, number>): {
|
|
135
|
+
capacity: number
|
|
139
136
|
} {
|
|
140
|
-
const strength = stats.strength
|
|
141
|
-
const density = stats.density
|
|
142
|
-
const hardness = stats.hardness
|
|
143
|
-
const cohesion = stats.cohesion
|
|
137
|
+
const strength = stats.strength ?? 0
|
|
138
|
+
const density = stats.density ?? 0
|
|
139
|
+
const hardness = stats.hardness ?? 0
|
|
140
|
+
const cohesion = stats.cohesion ?? 0
|
|
144
141
|
|
|
145
142
|
const statSum = strength + density + hardness + cohesion
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
143
|
+
return {capacity: 10_000_000 + Math.floor((statSum * 50_000_000) / 3996)}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export function computeBatteryCapabilities(stats: Record<string, number>): {
|
|
147
|
+
capacity: number
|
|
148
|
+
} {
|
|
149
|
+
const volatility = stats.volatility ?? 0
|
|
150
|
+
const thermal = stats.thermal ?? 0
|
|
151
|
+
const plasticity = stats.plasticity ?? 0
|
|
152
|
+
const insulation = stats.insulation ?? 0
|
|
149
153
|
|
|
150
|
-
|
|
154
|
+
const statSum = volatility + thermal + plasticity + insulation
|
|
155
|
+
return {capacity: 2_500 + Math.floor((statSum * 7_500) / 3996)}
|
|
151
156
|
}
|
|
152
157
|
|
|
153
158
|
import {
|
|
@@ -174,6 +179,7 @@ import {getItem} from '../data/catalog'
|
|
|
174
179
|
import {decodeCraftedItemStats} from './crafting'
|
|
175
180
|
import {
|
|
176
181
|
applySlotMultiplier,
|
|
182
|
+
applySlotMultiplierUint32,
|
|
177
183
|
clampUint16,
|
|
178
184
|
clampUint32,
|
|
179
185
|
getSlotAmp,
|
|
@@ -278,7 +284,7 @@ export function computeEntityCapabilities(
|
|
|
278
284
|
let maxGathDepth = 0
|
|
279
285
|
let hasGatherer = false
|
|
280
286
|
|
|
281
|
-
let
|
|
287
|
+
let totalStorageCapacity = 0
|
|
282
288
|
const baseCapacity = computeBaseCapacity(itemId, stats)
|
|
283
289
|
let installedModuleMass = 0
|
|
284
290
|
|
|
@@ -294,8 +300,7 @@ export function computeEntityCapabilities(
|
|
|
294
300
|
let totalWarpRange = 0
|
|
295
301
|
let hasWarp = false
|
|
296
302
|
|
|
297
|
-
let
|
|
298
|
-
let batteryCount = 0
|
|
303
|
+
let totalBatteryCapacity = 0
|
|
299
304
|
|
|
300
305
|
const gathererLanes: GathererLaneEntry[] = []
|
|
301
306
|
const crafterLanes: CrafterLaneEntry[] = []
|
|
@@ -346,8 +351,8 @@ export function computeEntityCapabilities(
|
|
|
346
351
|
outputPct: amp,
|
|
347
352
|
})
|
|
348
353
|
} else if (modType === MODULE_STORAGE) {
|
|
349
|
-
const caps = computeStorageCapabilities(decodedStats
|
|
350
|
-
|
|
354
|
+
const caps = computeStorageCapabilities(decodedStats)
|
|
355
|
+
totalStorageCapacity += applySlotMultiplierUint32(caps.capacity, amp)
|
|
351
356
|
} else if (modType === MODULE_CRAFTER) {
|
|
352
357
|
hasCrafter = true
|
|
353
358
|
const caps = computeCrafterCapabilities(decodedStats)
|
|
@@ -372,24 +377,18 @@ export function computeEntityCapabilities(
|
|
|
372
377
|
const caps = computeWarpCapabilities(decodedStats)
|
|
373
378
|
totalWarpRange += applySlotMultiplier(caps.range, amp)
|
|
374
379
|
} 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
|
|
380
|
+
const caps = computeBatteryCapabilities(decodedStats)
|
|
381
|
+
totalBatteryCapacity += applySlotMultiplierUint32(caps.capacity, amp)
|
|
381
382
|
}
|
|
382
383
|
}
|
|
383
384
|
|
|
384
|
-
if (hasGenerator &&
|
|
385
|
-
|
|
386
|
-
const bonusPctNum = 10 * batteryCount + Math.floor((totalBatteryStatSum * 10) / 2997)
|
|
387
|
-
totalGenCapacity += Math.floor((genCapBase * bonusPctNum) / 100)
|
|
385
|
+
if (hasGenerator && totalBatteryCapacity > 0) {
|
|
386
|
+
totalGenCapacity += totalBatteryCapacity
|
|
388
387
|
}
|
|
389
388
|
|
|
390
389
|
const result: ComputedCapabilities = {
|
|
391
390
|
hullmass: computeBaseHullmass(stats) + installedModuleMass,
|
|
392
|
-
capacity: baseCapacity +
|
|
391
|
+
capacity: clampUint32(baseCapacity + totalStorageCapacity),
|
|
393
392
|
}
|
|
394
393
|
|
|
395
394
|
if (hasEngine) {
|
|
@@ -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
|
@@ -191,7 +191,7 @@ export type {
|
|
|
191
191
|
HasScheduleAndLocation,
|
|
192
192
|
} from './travel/travel'
|
|
193
193
|
|
|
194
|
-
export {planRoute, sdkSystemGraph} from './travel/route-planner'
|
|
194
|
+
export {planRoute, sdkSystemGraph, MAX_LEGS} from './travel/route-planner'
|
|
195
195
|
export type {
|
|
196
196
|
Coord,
|
|
197
197
|
Neighbor,
|
|
@@ -379,6 +379,7 @@ export {
|
|
|
379
379
|
computeCrafterCapabilities,
|
|
380
380
|
computeWarehouseHullCapabilities,
|
|
381
381
|
computeStorageCapabilities,
|
|
382
|
+
computeBatteryCapabilities,
|
|
382
383
|
computeContainerCapabilities,
|
|
383
384
|
computeContainerT2Capabilities,
|
|
384
385
|
computeWarpCapabilities,
|
|
@@ -2,6 +2,7 @@ import {Serializer} from '@wharfkit/antelope'
|
|
|
2
2
|
import {getItem} from '../data/catalog'
|
|
3
3
|
import {
|
|
4
4
|
getModuleCapabilityType,
|
|
5
|
+
MODULE_BATTERY,
|
|
5
6
|
MODULE_CRAFTER,
|
|
6
7
|
MODULE_ENGINE,
|
|
7
8
|
MODULE_GATHERER,
|
|
@@ -26,6 +27,8 @@ import {
|
|
|
26
27
|
computeGathererYield,
|
|
27
28
|
computeGeneratorCap,
|
|
28
29
|
computeGeneratorRech,
|
|
30
|
+
computeCargoBayCapacity,
|
|
31
|
+
computeBatteryBankCapacity,
|
|
29
32
|
computeHaulerCapacity,
|
|
30
33
|
computeHaulerDrain,
|
|
31
34
|
computeHaulerEfficiency,
|
|
@@ -224,11 +227,11 @@ export function buildModuleImmutable(
|
|
|
224
227
|
}
|
|
225
228
|
case MODULE_CRAFTER: {
|
|
226
229
|
const rea = decodeStat(stats, 0)
|
|
227
|
-
const
|
|
230
|
+
const con = decodeStat(stats, 1)
|
|
228
231
|
base.push({first: 'reactivity', second: ['uint16', rea]})
|
|
229
|
-
base.push({first: '
|
|
232
|
+
base.push({first: 'conductivity', second: ['uint16', con]})
|
|
230
233
|
base.push({first: 'speed', second: ['uint16', computeCrafterSpeed(rea)]})
|
|
231
|
-
base.push({first: 'drain', second: ['uint16', computeCrafterDrain(
|
|
234
|
+
base.push({first: 'drain', second: ['uint16', computeCrafterDrain(con)]})
|
|
232
235
|
break
|
|
233
236
|
}
|
|
234
237
|
case MODULE_STORAGE: {
|
|
@@ -236,14 +239,28 @@ export function buildModuleImmutable(
|
|
|
236
239
|
const den = decodeStat(stats, 1)
|
|
237
240
|
const hrd = decodeStat(stats, 2)
|
|
238
241
|
const com = decodeStat(stats, 3)
|
|
239
|
-
const sum = str + den + hrd + com
|
|
240
242
|
base.push({first: 'strength', second: ['uint16', str]})
|
|
241
243
|
base.push({first: 'density', second: ['uint16', den]})
|
|
242
244
|
base.push({first: 'hardness', second: ['uint16', hrd]})
|
|
243
245
|
base.push({first: 'cohesion', second: ['uint16', com]})
|
|
244
246
|
base.push({
|
|
245
|
-
first: '
|
|
246
|
-
second: ['
|
|
247
|
+
first: 'capacity',
|
|
248
|
+
second: ['uint32', computeCargoBayCapacity(str, den, hrd, com)],
|
|
249
|
+
})
|
|
250
|
+
break
|
|
251
|
+
}
|
|
252
|
+
case MODULE_BATTERY: {
|
|
253
|
+
const vol = decodeStat(stats, 0)
|
|
254
|
+
const thm = decodeStat(stats, 1)
|
|
255
|
+
const pla = decodeStat(stats, 2)
|
|
256
|
+
const ins = decodeStat(stats, 3)
|
|
257
|
+
base.push({first: 'volatility', second: ['uint16', vol]})
|
|
258
|
+
base.push({first: 'thermal', second: ['uint16', thm]})
|
|
259
|
+
base.push({first: 'plasticity', second: ['uint16', pla]})
|
|
260
|
+
base.push({first: 'insulation', second: ['uint16', ins]})
|
|
261
|
+
base.push({
|
|
262
|
+
first: 'capacity',
|
|
263
|
+
second: ['uint32', computeBatteryBankCapacity(vol, thm, pla, ins)],
|
|
247
264
|
})
|
|
248
265
|
break
|
|
249
266
|
}
|
package/src/nft/description.ts
CHANGED
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
MODULE_ENGINE,
|
|
5
5
|
MODULE_GATHERER,
|
|
6
6
|
MODULE_GENERATOR,
|
|
7
|
+
MODULE_BATTERY,
|
|
7
8
|
MODULE_HAULER,
|
|
8
9
|
MODULE_LOADER,
|
|
9
10
|
MODULE_STORAGE,
|
|
@@ -19,6 +20,7 @@ import {
|
|
|
19
20
|
ITEM_GATHERER_T1,
|
|
20
21
|
ITEM_GENERATOR_T1,
|
|
21
22
|
ITEM_HAULER_T1,
|
|
23
|
+
ITEM_BATTERY_T1,
|
|
22
24
|
ITEM_LOADER_T1,
|
|
23
25
|
ITEM_SHIP_T1_PACKED,
|
|
24
26
|
ITEM_STORAGE_T1,
|
|
@@ -75,6 +77,18 @@ export const computeHaulerCapacity = (fin: number): number => Math.max(1, 1 + id
|
|
|
75
77
|
export const computeHaulerEfficiency = (con: number): number => 2000 + con * 6
|
|
76
78
|
export const computeHaulerDrain = (com: number): number => Math.max(3, 15 - idiv(com, 80))
|
|
77
79
|
export const computeWarpRange = (stat: number): number => 100 + stat * 3
|
|
80
|
+
export const computeCargoBayCapacity = (
|
|
81
|
+
strength: number,
|
|
82
|
+
density: number,
|
|
83
|
+
hardness: number,
|
|
84
|
+
cohesion: number
|
|
85
|
+
): number => 10_000_000 + idiv((strength + density + hardness + cohesion) * 50_000_000, 3996)
|
|
86
|
+
export const computeBatteryBankCapacity = (
|
|
87
|
+
volatility: number,
|
|
88
|
+
thermal: number,
|
|
89
|
+
plasticity: number,
|
|
90
|
+
insulation: number
|
|
91
|
+
): number => 2_500 + idiv((volatility + thermal + plasticity + insulation) * 7_500, 3996)
|
|
78
92
|
|
|
79
93
|
export function entityDisplayName(itemId: number): string {
|
|
80
94
|
switch (itemId) {
|
|
@@ -108,11 +122,13 @@ export function moduleDisplayName(itemId: number): string {
|
|
|
108
122
|
case ITEM_CRAFTER_T1:
|
|
109
123
|
return 'Crafter'
|
|
110
124
|
case ITEM_STORAGE_T1:
|
|
111
|
-
return '
|
|
125
|
+
return 'Cargo Bay'
|
|
112
126
|
case ITEM_HAULER_T1:
|
|
113
127
|
return 'Hauler'
|
|
114
128
|
case ITEM_WARP_T1:
|
|
115
129
|
return 'Warp'
|
|
130
|
+
case ITEM_BATTERY_T1:
|
|
131
|
+
return 'Battery Bank'
|
|
116
132
|
default:
|
|
117
133
|
return 'Module'
|
|
118
134
|
}
|
|
@@ -160,17 +176,16 @@ export function formatModuleLine(slot: number, itemId: number, stats: bigint): s
|
|
|
160
176
|
}
|
|
161
177
|
case MODULE_CRAFTER: {
|
|
162
178
|
const rea = decodeStat(stats, 0)
|
|
163
|
-
const
|
|
164
|
-
out += ` Speed ${computeCrafterSpeed(rea)} Drain ${computeCrafterDrain(
|
|
179
|
+
const con = decodeStat(stats, 1)
|
|
180
|
+
out += ` Speed ${computeCrafterSpeed(rea)} Drain ${computeCrafterDrain(con)}`
|
|
165
181
|
break
|
|
166
182
|
}
|
|
167
183
|
case MODULE_STORAGE: {
|
|
168
184
|
const str = decodeStat(stats, 0)
|
|
169
|
-
const
|
|
170
|
-
const
|
|
171
|
-
const
|
|
172
|
-
|
|
173
|
-
out += ` +${pct}% capacity`
|
|
185
|
+
const den = decodeStat(stats, 1)
|
|
186
|
+
const hrd = decodeStat(stats, 2)
|
|
187
|
+
const com = decodeStat(stats, 3)
|
|
188
|
+
out += ` Cargo Capacity ${computeCargoBayCapacity(str, den, hrd, com)}`
|
|
174
189
|
break
|
|
175
190
|
}
|
|
176
191
|
case MODULE_HAULER: {
|
|
@@ -185,6 +200,14 @@ export function formatModuleLine(slot: number, itemId: number, stats: bigint): s
|
|
|
185
200
|
out += ` Range ${computeWarpRange(stat)}`
|
|
186
201
|
break
|
|
187
202
|
}
|
|
203
|
+
case MODULE_BATTERY: {
|
|
204
|
+
const vol = decodeStat(stats, 0)
|
|
205
|
+
const thm = decodeStat(stats, 1)
|
|
206
|
+
const pla = decodeStat(stats, 2)
|
|
207
|
+
const ins = decodeStat(stats, 3)
|
|
208
|
+
out += ` Energy Capacity ${computeBatteryBankCapacity(vol, thm, pla, ins)}`
|
|
209
|
+
break
|
|
210
|
+
}
|
|
188
211
|
}
|
|
189
212
|
return out
|
|
190
213
|
}
|
|
@@ -81,9 +81,15 @@ const TEMPLATES: Record<string, TemplateSpec> = {
|
|
|
81
81
|
},
|
|
82
82
|
storage: {
|
|
83
83
|
id: 'module.storage.description',
|
|
84
|
-
template: '
|
|
85
|
-
params: [['
|
|
86
|
-
highlightKeys: ['
|
|
84
|
+
template: 'adds {capacity} cargo capacity',
|
|
85
|
+
params: [['capacity', 'Cargo Capacity']],
|
|
86
|
+
highlightKeys: ['capacity'],
|
|
87
|
+
},
|
|
88
|
+
energy: {
|
|
89
|
+
id: 'module.energy-capacity.description',
|
|
90
|
+
template: 'adds {capacity} energy capacity',
|
|
91
|
+
params: [['capacity', 'Energy Capacity']],
|
|
92
|
+
highlightKeys: ['capacity'],
|
|
87
93
|
},
|
|
88
94
|
hauler: {
|
|
89
95
|
id: 'module.hauler.description',
|
|
@@ -124,8 +130,10 @@ export function describeModuleForItem(resolved: ResolvedItem): ModuleDescription
|
|
|
124
130
|
}
|
|
125
131
|
|
|
126
132
|
export function describeModuleForSlot(slot: ResolvedModuleSlot): ModuleDescription | null {
|
|
127
|
-
if (!slot.installed || !slot.
|
|
128
|
-
|
|
133
|
+
if (!slot.installed || !slot.attributes) return null
|
|
134
|
+
const capability = slot.capability ?? slot.name
|
|
135
|
+
if (!capability) return null
|
|
136
|
+
return describeModule({capability, attributes: slot.attributes})
|
|
129
137
|
}
|
|
130
138
|
|
|
131
139
|
export function renderDescription(
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
isModuleItem,
|
|
10
10
|
MODULE_CRAFTER,
|
|
11
11
|
MODULE_ENGINE,
|
|
12
|
+
MODULE_BATTERY,
|
|
12
13
|
MODULE_GATHERER,
|
|
13
14
|
MODULE_GENERATOR,
|
|
14
15
|
MODULE_HAULER,
|
|
@@ -19,6 +20,7 @@ import {decodeCraftedItemStats, decodeStat} from '../derivation/crafting'
|
|
|
19
20
|
import {getStatDefinitions} from '../derivation/stats'
|
|
20
21
|
import {
|
|
21
22
|
computeCrafterCapabilities,
|
|
23
|
+
computeBatteryCapabilities,
|
|
22
24
|
computeEngineCapabilities,
|
|
23
25
|
computeGathererCapabilities,
|
|
24
26
|
computeGeneratorCapabilities,
|
|
@@ -28,7 +30,9 @@ import {
|
|
|
28
30
|
computeWarehouseHullCapabilities,
|
|
29
31
|
computeContainerCapabilities,
|
|
30
32
|
computeContainerT2Capabilities,
|
|
33
|
+
computeStorageCapabilities,
|
|
31
34
|
} from '../derivation/capabilities'
|
|
35
|
+
import {applySlotMultiplierUint32} from '../entities/slot-multiplier'
|
|
32
36
|
import {categoryColors, componentIcon, itemAbbreviations, moduleIcon} from '../data/colors'
|
|
33
37
|
import type {ServerContract} from '../contracts'
|
|
34
38
|
import {
|
|
@@ -58,6 +62,7 @@ export type ResolvedItemType = 'resource' | 'component' | 'module' | 'entity'
|
|
|
58
62
|
|
|
59
63
|
export interface ResolvedModuleSlot {
|
|
60
64
|
name?: string
|
|
65
|
+
capability?: string
|
|
61
66
|
installed: boolean
|
|
62
67
|
attributes?: {label: string; value: number}[]
|
|
63
68
|
}
|
|
@@ -152,7 +157,8 @@ function resolveComponent(id: number, stats?: UInt64Type): ResolvedItem {
|
|
|
152
157
|
function computeCapabilityGroup(
|
|
153
158
|
moduleType: number,
|
|
154
159
|
stats: Record<string, number>,
|
|
155
|
-
tier: number
|
|
160
|
+
tier: number,
|
|
161
|
+
outputPct = 100
|
|
156
162
|
): ResolvedAttributeGroup | undefined {
|
|
157
163
|
switch (moduleType) {
|
|
158
164
|
case MODULE_ENGINE: {
|
|
@@ -219,13 +225,28 @@ function computeCapabilityGroup(
|
|
|
219
225
|
}
|
|
220
226
|
}
|
|
221
227
|
case MODULE_STORAGE: {
|
|
222
|
-
const
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
228
|
+
const caps = computeStorageCapabilities(stats)
|
|
229
|
+
return {
|
|
230
|
+
capability: 'Storage',
|
|
231
|
+
attributes: [
|
|
232
|
+
{
|
|
233
|
+
label: 'Cargo Capacity',
|
|
234
|
+
value: applySlotMultiplierUint32(caps.capacity, outputPct),
|
|
235
|
+
},
|
|
236
|
+
],
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
case MODULE_BATTERY: {
|
|
240
|
+
const caps = computeBatteryCapabilities(stats)
|
|
241
|
+
return {
|
|
242
|
+
capability: 'Energy',
|
|
243
|
+
attributes: [
|
|
244
|
+
{
|
|
245
|
+
label: 'Energy Capacity',
|
|
246
|
+
value: applySlotMultiplierUint32(caps.capacity, outputPct),
|
|
247
|
+
},
|
|
248
|
+
],
|
|
249
|
+
}
|
|
229
250
|
}
|
|
230
251
|
default:
|
|
231
252
|
return undefined
|
|
@@ -321,9 +342,10 @@ function resolveEntity(
|
|
|
321
342
|
} catch {
|
|
322
343
|
modName = itemMetadata[modItemId]?.name ?? 'Module'
|
|
323
344
|
}
|
|
324
|
-
const group = computeCapabilityGroup(modType, decodedStats, modTier)
|
|
345
|
+
const group = computeCapabilityGroup(modType, decodedStats, modTier, slot.outputPct)
|
|
325
346
|
return {
|
|
326
347
|
name: modName,
|
|
348
|
+
capability: group?.capability,
|
|
327
349
|
installed: true,
|
|
328
350
|
attributes: group?.attributes,
|
|
329
351
|
}
|
|
@@ -32,6 +32,7 @@ export interface RouteFailure {
|
|
|
32
32
|
reason: RouteFailureReason
|
|
33
33
|
furthest?: Coord
|
|
34
34
|
legsNeeded?: number
|
|
35
|
+
partialWaypoints?: Coord[]
|
|
35
36
|
}
|
|
36
37
|
|
|
37
38
|
export type RouteResult = RoutePlan | RouteFailure
|
|
@@ -50,11 +51,13 @@ const key = (c: Coord): string => `${c.x},${c.y}`
|
|
|
50
51
|
const sameCoord = (a: Coord, b: Coord): boolean => a.x === b.x && a.y === b.y
|
|
51
52
|
const dist = (a: Coord, b: Coord): number => Math.hypot(a.x - b.x, a.y - b.y)
|
|
52
53
|
|
|
54
|
+
export const MAX_LEGS = 12
|
|
55
|
+
|
|
53
56
|
export function planRoute(params: PlanRouteParams): RouteResult {
|
|
54
57
|
const {origin, dest, perLegReach, graph} = params
|
|
55
58
|
const corridorSlack = params.corridorSlack ?? perLegReach
|
|
56
59
|
const nodeBudget = params.nodeBudget ?? 5000
|
|
57
|
-
const maxLegs = params.maxLegs ??
|
|
60
|
+
const maxLegs = params.maxLegs ?? MAX_LEGS
|
|
58
61
|
|
|
59
62
|
if (!graph.hasSystem(dest)) {
|
|
60
63
|
return {ok: false, reason: 'empty-destination'}
|
|
@@ -122,9 +125,32 @@ export function planRoute(params: PlanRouteParams): RouteResult {
|
|
|
122
125
|
}
|
|
123
126
|
|
|
124
127
|
if (cappedByMaxLegs) {
|
|
125
|
-
return {
|
|
128
|
+
return {
|
|
129
|
+
ok: false,
|
|
130
|
+
reason: 'max-legs',
|
|
131
|
+
furthest,
|
|
132
|
+
partialWaypoints: reconstructWaypoints(cameFrom, origin, furthest),
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return {
|
|
136
|
+
ok: false,
|
|
137
|
+
reason: 'no-path',
|
|
138
|
+
furthest,
|
|
139
|
+
partialWaypoints: reconstructWaypoints(cameFrom, origin, furthest),
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function reconstructWaypoints(cameFrom: Map<string, Coord>, origin: Coord, target: Coord): Coord[] {
|
|
144
|
+
if (sameCoord(target, origin)) return []
|
|
145
|
+
const path: Coord[] = [target]
|
|
146
|
+
let cur = target
|
|
147
|
+
while (!sameCoord(cur, origin)) {
|
|
148
|
+
const prev = cameFrom.get(key(cur))
|
|
149
|
+
if (!prev) break
|
|
150
|
+
path.unshift(prev)
|
|
151
|
+
cur = prev
|
|
126
152
|
}
|
|
127
|
-
return
|
|
153
|
+
return path.slice(1)
|
|
128
154
|
}
|
|
129
155
|
|
|
130
156
|
function reconstruct(cameFrom: Map<string, Coord>, origin: Coord, dest: Coord): RoutePlan {
|