@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
|
@@ -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,
|
|
@@ -60,6 +62,16 @@ export function computeBaseCapacityWarehouse(stats: bigint): number {
|
|
|
60
62
|
|
|
61
63
|
export const computeEngineThrust = (vol: number): number => 400 + idiv(vol * 3, 4)
|
|
62
64
|
export const computeEngineDrain = (thm: number): number => 2 * Math.max(30, 50 - idiv(thm, 70))
|
|
65
|
+
export const ENGINE_DRAIN_BASE = 118
|
|
66
|
+
export const ENGINE_DRAIN_REF_THRUST = 775
|
|
67
|
+
export const ENGINE_DRAIN_REF_THM = 500
|
|
68
|
+
|
|
69
|
+
export const computeTravelDrain = (totalThrust: number, avgThm: number): number => {
|
|
70
|
+
if (totalThrust <= 0) return 0
|
|
71
|
+
const num = ENGINE_DRAIN_BASE * ENGINE_DRAIN_REF_THRUST * computeEngineDrain(avgThm)
|
|
72
|
+
const den = totalThrust * computeEngineDrain(ENGINE_DRAIN_REF_THM)
|
|
73
|
+
return idiv(num, den)
|
|
74
|
+
}
|
|
63
75
|
export const computeGeneratorCap = (com: number): number => 950 + idiv(com, 2)
|
|
64
76
|
export const computeGeneratorRech = (fin: number): number => 2 * (1 + idiv(fin * 3, 1000))
|
|
65
77
|
export const computeGathererYield = (str: number): number => 200 + str
|
|
@@ -75,6 +87,18 @@ export const computeHaulerCapacity = (fin: number): number => Math.max(1, 1 + id
|
|
|
75
87
|
export const computeHaulerEfficiency = (con: number): number => 2000 + con * 6
|
|
76
88
|
export const computeHaulerDrain = (com: number): number => Math.max(3, 15 - idiv(com, 80))
|
|
77
89
|
export const computeWarpRange = (stat: number): number => 100 + stat * 3
|
|
90
|
+
export const computeCargoBayCapacity = (
|
|
91
|
+
strength: number,
|
|
92
|
+
density: number,
|
|
93
|
+
hardness: number,
|
|
94
|
+
cohesion: number
|
|
95
|
+
): number => 10_000_000 + idiv((strength + density + hardness + cohesion) * 50_000_000, 3996)
|
|
96
|
+
export const computeBatteryBankCapacity = (
|
|
97
|
+
volatility: number,
|
|
98
|
+
thermal: number,
|
|
99
|
+
plasticity: number,
|
|
100
|
+
insulation: number
|
|
101
|
+
): number => 2_500 + idiv((volatility + thermal + plasticity + insulation) * 7_500, 3996)
|
|
78
102
|
|
|
79
103
|
export function entityDisplayName(itemId: number): string {
|
|
80
104
|
switch (itemId) {
|
|
@@ -108,11 +132,13 @@ export function moduleDisplayName(itemId: number): string {
|
|
|
108
132
|
case ITEM_CRAFTER_T1:
|
|
109
133
|
return 'Crafter'
|
|
110
134
|
case ITEM_STORAGE_T1:
|
|
111
|
-
return '
|
|
135
|
+
return 'Cargo Bay'
|
|
112
136
|
case ITEM_HAULER_T1:
|
|
113
137
|
return 'Hauler'
|
|
114
138
|
case ITEM_WARP_T1:
|
|
115
139
|
return 'Warp'
|
|
140
|
+
case ITEM_BATTERY_T1:
|
|
141
|
+
return 'Battery Bank'
|
|
116
142
|
default:
|
|
117
143
|
return 'Module'
|
|
118
144
|
}
|
|
@@ -160,17 +186,16 @@ export function formatModuleLine(slot: number, itemId: number, stats: bigint): s
|
|
|
160
186
|
}
|
|
161
187
|
case MODULE_CRAFTER: {
|
|
162
188
|
const rea = decodeStat(stats, 0)
|
|
163
|
-
const
|
|
164
|
-
out += ` Speed ${computeCrafterSpeed(rea)} Drain ${computeCrafterDrain(
|
|
189
|
+
const con = decodeStat(stats, 1)
|
|
190
|
+
out += ` Speed ${computeCrafterSpeed(rea)} Drain ${computeCrafterDrain(con)}`
|
|
165
191
|
break
|
|
166
192
|
}
|
|
167
193
|
case MODULE_STORAGE: {
|
|
168
194
|
const str = decodeStat(stats, 0)
|
|
169
|
-
const
|
|
170
|
-
const
|
|
171
|
-
const
|
|
172
|
-
|
|
173
|
-
out += ` +${pct}% capacity`
|
|
195
|
+
const den = decodeStat(stats, 1)
|
|
196
|
+
const hrd = decodeStat(stats, 2)
|
|
197
|
+
const com = decodeStat(stats, 3)
|
|
198
|
+
out += ` Cargo Capacity ${computeCargoBayCapacity(str, den, hrd, com)}`
|
|
174
199
|
break
|
|
175
200
|
}
|
|
176
201
|
case MODULE_HAULER: {
|
|
@@ -185,6 +210,14 @@ export function formatModuleLine(slot: number, itemId: number, stats: bigint): s
|
|
|
185
210
|
out += ` Range ${computeWarpRange(stat)}`
|
|
186
211
|
break
|
|
187
212
|
}
|
|
213
|
+
case MODULE_BATTERY: {
|
|
214
|
+
const vol = decodeStat(stats, 0)
|
|
215
|
+
const thm = decodeStat(stats, 1)
|
|
216
|
+
const pla = decodeStat(stats, 2)
|
|
217
|
+
const ins = decodeStat(stats, 3)
|
|
218
|
+
out += ` Energy Capacity ${computeBatteryBankCapacity(vol, thm, pla, ins)}`
|
|
219
|
+
break
|
|
220
|
+
}
|
|
188
221
|
}
|
|
189
222
|
return out
|
|
190
223
|
}
|
|
@@ -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(
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import {expect, test} from 'bun:test'
|
|
2
|
+
import {UInt16, UInt64} from '@wharfkit/antelope'
|
|
3
|
+
import {resolveItem} from './resolve-item'
|
|
4
|
+
import {encodeStats} from '../derivation/crafting'
|
|
5
|
+
import {computeContainerCapabilities} from '../derivation/capabilities'
|
|
6
|
+
import {
|
|
7
|
+
ITEM_EXTRACTOR_T1_PACKED,
|
|
8
|
+
ITEM_FACTORY_T1_PACKED,
|
|
9
|
+
ITEM_MASS_DRIVER_T1_PACKED,
|
|
10
|
+
ITEM_MASS_CATCHER_T1_PACKED,
|
|
11
|
+
} from '../data/item-ids'
|
|
12
|
+
|
|
13
|
+
function hullStats(strength: number, density: number, hardness: number): UInt64 {
|
|
14
|
+
return UInt64.from(encodeStats([strength, density, hardness]).toString())
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const CONTAINER_ENTITIES = [
|
|
18
|
+
['factory', ITEM_FACTORY_T1_PACKED],
|
|
19
|
+
['extractor', ITEM_EXTRACTOR_T1_PACKED],
|
|
20
|
+
['mass driver', ITEM_MASS_DRIVER_T1_PACKED],
|
|
21
|
+
['mass catcher', ITEM_MASS_CATCHER_T1_PACKED],
|
|
22
|
+
] as const
|
|
23
|
+
|
|
24
|
+
for (const [label, itemId] of CONTAINER_ENTITIES) {
|
|
25
|
+
test(`resolveItem resolves ${label} hull capacity via container formula`, () => {
|
|
26
|
+
const stats = hullStats(300, 100, 400)
|
|
27
|
+
const resolved = resolveItem(UInt16.from(itemId), stats)
|
|
28
|
+
const hull = resolved.attributes?.find((g) => g.capability === 'Hull')
|
|
29
|
+
const capacity = hull?.attributes.find((a) => a.label === 'Capacity')?.value
|
|
30
|
+
const expected = computeContainerCapabilities({
|
|
31
|
+
strength: 300,
|
|
32
|
+
hardness: 400,
|
|
33
|
+
density: 100,
|
|
34
|
+
}).capacity
|
|
35
|
+
expect(capacity).toBe(expected)
|
|
36
|
+
})
|
|
37
|
+
}
|
|
@@ -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,13 +30,18 @@ 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 {
|
|
35
39
|
ITEM_CONTAINER_T1_PACKED,
|
|
36
40
|
ITEM_CONTAINER_T2_PACKED,
|
|
37
41
|
ITEM_EXTRACTOR_T1_PACKED,
|
|
42
|
+
ITEM_FACTORY_T1_PACKED,
|
|
43
|
+
ITEM_MASS_CATCHER_T1_PACKED,
|
|
44
|
+
ITEM_MASS_DRIVER_T1_PACKED,
|
|
38
45
|
ITEM_SHIP_T1_PACKED,
|
|
39
46
|
ITEM_WAREHOUSE_T1_PACKED,
|
|
40
47
|
} from '../data/item-ids'
|
|
@@ -58,6 +65,7 @@ export type ResolvedItemType = 'resource' | 'component' | 'module' | 'entity'
|
|
|
58
65
|
|
|
59
66
|
export interface ResolvedModuleSlot {
|
|
60
67
|
name?: string
|
|
68
|
+
capability?: string
|
|
61
69
|
installed: boolean
|
|
62
70
|
attributes?: {label: string; value: number}[]
|
|
63
71
|
}
|
|
@@ -152,7 +160,8 @@ function resolveComponent(id: number, stats?: UInt64Type): ResolvedItem {
|
|
|
152
160
|
function computeCapabilityGroup(
|
|
153
161
|
moduleType: number,
|
|
154
162
|
stats: Record<string, number>,
|
|
155
|
-
tier: number
|
|
163
|
+
tier: number,
|
|
164
|
+
outputPct = 100
|
|
156
165
|
): ResolvedAttributeGroup | undefined {
|
|
157
166
|
switch (moduleType) {
|
|
158
167
|
case MODULE_ENGINE: {
|
|
@@ -219,13 +228,28 @@ function computeCapabilityGroup(
|
|
|
219
228
|
}
|
|
220
229
|
}
|
|
221
230
|
case MODULE_STORAGE: {
|
|
222
|
-
const
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
231
|
+
const caps = computeStorageCapabilities(stats)
|
|
232
|
+
return {
|
|
233
|
+
capability: 'Storage',
|
|
234
|
+
attributes: [
|
|
235
|
+
{
|
|
236
|
+
label: 'Cargo Capacity',
|
|
237
|
+
value: applySlotMultiplierUint32(caps.capacity, outputPct),
|
|
238
|
+
},
|
|
239
|
+
],
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
case MODULE_BATTERY: {
|
|
243
|
+
const caps = computeBatteryCapabilities(stats)
|
|
244
|
+
return {
|
|
245
|
+
capability: 'Energy',
|
|
246
|
+
attributes: [
|
|
247
|
+
{
|
|
248
|
+
label: 'Energy Capacity',
|
|
249
|
+
value: applySlotMultiplierUint32(caps.capacity, outputPct),
|
|
250
|
+
},
|
|
251
|
+
],
|
|
252
|
+
}
|
|
229
253
|
}
|
|
230
254
|
default:
|
|
231
255
|
return undefined
|
|
@@ -266,7 +290,9 @@ function hullCapsForEntity(
|
|
|
266
290
|
case ITEM_WAREHOUSE_T1_PACKED:
|
|
267
291
|
return computeWarehouseHullCapabilities(decoded)
|
|
268
292
|
case ITEM_EXTRACTOR_T1_PACKED:
|
|
269
|
-
|
|
293
|
+
case ITEM_FACTORY_T1_PACKED:
|
|
294
|
+
case ITEM_MASS_DRIVER_T1_PACKED:
|
|
295
|
+
case ITEM_MASS_CATCHER_T1_PACKED:
|
|
270
296
|
case ITEM_CONTAINER_T1_PACKED:
|
|
271
297
|
return computeContainerCapabilities(decoded)
|
|
272
298
|
case ITEM_CONTAINER_T2_PACKED:
|
|
@@ -321,9 +347,10 @@ function resolveEntity(
|
|
|
321
347
|
} catch {
|
|
322
348
|
modName = itemMetadata[modItemId]?.name ?? 'Module'
|
|
323
349
|
}
|
|
324
|
-
const group = computeCapabilityGroup(modType, decodedStats, modTier)
|
|
350
|
+
const group = computeCapabilityGroup(modType, decodedStats, modTier, slot.outputPct)
|
|
325
351
|
return {
|
|
326
352
|
name: modName,
|
|
353
|
+
capability: group?.capability,
|
|
327
354
|
installed: true,
|
|
328
355
|
attributes: group?.attributes,
|
|
329
356
|
}
|
|
@@ -41,6 +41,7 @@ export interface ProjectedEntity {
|
|
|
41
41
|
loaderLanes: ServerContract.Types.loader_lane[]
|
|
42
42
|
generator?: ServerContract.Types.energy_stats
|
|
43
43
|
hauler?: ServerContract.Types.hauler_stats
|
|
44
|
+
launcher?: ServerContract.Types.launcher_stats
|
|
44
45
|
readonly cargoMass: UInt64
|
|
45
46
|
readonly totalMass: UInt64
|
|
46
47
|
readonly gathererLanes: ServerContract.Types.gatherer_lane[]
|
|
@@ -49,6 +50,7 @@ export interface ProjectedEntity {
|
|
|
49
50
|
hasMovement(): boolean
|
|
50
51
|
hasStorage(): boolean
|
|
51
52
|
hasLoaders(): boolean
|
|
53
|
+
hasLauncher(): boolean
|
|
52
54
|
|
|
53
55
|
capabilities(): EntityCapabilities
|
|
54
56
|
state(): EntityState
|
|
@@ -64,6 +66,7 @@ export interface Projectable extends ScheduleData {
|
|
|
64
66
|
gatherer_lanes?: ServerContract.Types.gatherer_lane[]
|
|
65
67
|
crafter_lanes?: ServerContract.Types.crafter_lane[]
|
|
66
68
|
hauler?: ServerContract.Types.hauler_stats
|
|
69
|
+
launcher?: ServerContract.Types.launcher_stats
|
|
67
70
|
capacity?: UInt32
|
|
68
71
|
cargo: ServerContract.Types.cargo_item[]
|
|
69
72
|
cargomass: UInt32
|
|
@@ -91,6 +94,7 @@ interface ProjectedCaps {
|
|
|
91
94
|
gathererLanes: ServerContract.Types.gatherer_lane[]
|
|
92
95
|
crafterLanes: ServerContract.Types.crafter_lane[]
|
|
93
96
|
hauler?: ServerContract.Types.hauler_stats
|
|
97
|
+
launcher?: ServerContract.Types.launcher_stats
|
|
94
98
|
}
|
|
95
99
|
|
|
96
100
|
function recomputeCaps(entity: Projectable): ProjectedCaps | undefined {
|
|
@@ -164,6 +168,13 @@ function recomputeCaps(entity: Projectable): ProjectedCaps | undefined {
|
|
|
164
168
|
gathererLanes: (caps.gathererLanes ?? []).map(toGathererLane),
|
|
165
169
|
crafterLanes: (caps.crafterLanes ?? []).map(toCrafterLane),
|
|
166
170
|
hauler: caps.hauler ? ServerContract.Types.hauler_stats.from(caps.hauler) : undefined,
|
|
171
|
+
launcher: caps.launcher
|
|
172
|
+
? ServerContract.Types.launcher_stats.from({
|
|
173
|
+
charge_rate: caps.launcher.chargeRate,
|
|
174
|
+
velocity: caps.launcher.velocity,
|
|
175
|
+
drain: caps.launcher.drain,
|
|
176
|
+
})
|
|
177
|
+
: undefined,
|
|
167
178
|
}
|
|
168
179
|
}
|
|
169
180
|
|
|
@@ -180,6 +191,7 @@ export function createProjectedEntity(entity: Projectable): ProjectedEntity {
|
|
|
180
191
|
entity.engines === undefined ||
|
|
181
192
|
entity.generator === undefined ||
|
|
182
193
|
entity.hauler === undefined ||
|
|
194
|
+
entity.launcher === undefined ||
|
|
183
195
|
entity.capacity === undefined
|
|
184
196
|
const caps = needsRecompute ? recomputeCaps(entity) : undefined
|
|
185
197
|
|
|
@@ -190,6 +202,7 @@ export function createProjectedEntity(entity: Projectable): ProjectedEntity {
|
|
|
190
202
|
const engines = entity.engines ?? caps?.engines
|
|
191
203
|
const generator = entity.generator ?? caps?.generator
|
|
192
204
|
const hauler = entity.hauler ?? caps?.hauler
|
|
205
|
+
const launcher = entity.launcher ?? caps?.launcher
|
|
193
206
|
const capacity = entity.capacity ?? caps?.capacity
|
|
194
207
|
|
|
195
208
|
const cargo: CargoStack[] = entity.cargo.map(cargoItemToStack)
|
|
@@ -203,6 +216,7 @@ export function createProjectedEntity(entity: Projectable): ProjectedEntity {
|
|
|
203
216
|
engines,
|
|
204
217
|
generator,
|
|
205
218
|
hauler,
|
|
219
|
+
launcher,
|
|
206
220
|
loaderLanes,
|
|
207
221
|
gathererLanes,
|
|
208
222
|
crafterLanes,
|
|
@@ -229,12 +243,17 @@ export function createProjectedEntity(entity: Projectable): ProjectedEntity {
|
|
|
229
243
|
return this.loaderLanes.length > 0
|
|
230
244
|
},
|
|
231
245
|
|
|
246
|
+
hasLauncher() {
|
|
247
|
+
return this.launcher !== undefined
|
|
248
|
+
},
|
|
249
|
+
|
|
232
250
|
capabilities(): EntityCapabilities {
|
|
233
251
|
return {
|
|
234
252
|
hullmass: this.shipMass,
|
|
235
253
|
capacity: this.capacity ? UInt32.from(this.capacity) : undefined,
|
|
236
254
|
engines: this.engines,
|
|
237
255
|
generator: this.generator,
|
|
256
|
+
launcher: this.launcher,
|
|
238
257
|
}
|
|
239
258
|
},
|
|
240
259
|
|
|
@@ -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 {
|
|
@@ -59,6 +59,7 @@ export interface EntityCapabilities {
|
|
|
59
59
|
gatherer?: GathererStats
|
|
60
60
|
crafter?: CrafterStats
|
|
61
61
|
hauler?: ServerContract.Types.hauler_stats
|
|
62
|
+
launcher?: ServerContract.Types.launcher_stats
|
|
62
63
|
}
|
|
63
64
|
|
|
64
65
|
export interface EntityState {
|
|
@@ -92,3 +93,7 @@ export function capsHasMass(caps: EntityCapabilities): boolean {
|
|
|
92
93
|
export function capsHasHauler(caps: EntityCapabilities): boolean {
|
|
93
94
|
return caps.hauler !== undefined
|
|
94
95
|
}
|
|
96
|
+
|
|
97
|
+
export function capsHasLauncher(caps: EntityCapabilities): boolean {
|
|
98
|
+
return caps.launcher !== undefined
|
|
99
|
+
}
|