@shipload/sdk 1.0.0-next.4 → 1.0.0-next.41
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/scan.d.ts +34 -0
- package/lib/scan.js +136 -0
- package/lib/scan.js.map +1 -0
- package/lib/scan.m.js +129 -0
- package/lib/scan.m.js.map +1 -0
- package/lib/shipload.d.ts +2473 -973
- package/lib/shipload.js +11529 -5211
- package/lib/shipload.js.map +1 -1
- package/lib/shipload.m.js +11338 -5162
- package/lib/shipload.m.js.map +1 -1
- package/lib/testing.d.ts +970 -0
- package/lib/testing.js +4013 -0
- package/lib/testing.js.map +1 -0
- package/lib/testing.m.js +4007 -0
- package/lib/testing.m.js.map +1 -0
- package/package.json +20 -2
- package/src/capabilities/craftable.ts +51 -0
- package/src/capabilities/crafting.test.ts +7 -0
- package/src/capabilities/crafting.ts +5 -6
- package/src/capabilities/gathering.test.ts +16 -0
- package/src/capabilities/gathering.ts +35 -18
- package/src/capabilities/index.ts +0 -1
- package/src/capabilities/modules.ts +9 -0
- package/src/capabilities/storage.ts +16 -1
- package/src/contracts/platform.ts +231 -3
- package/src/contracts/server.ts +1021 -481
- package/src/coordinates/address.ts +88 -0
- package/src/coordinates/constants.test.ts +15 -0
- package/src/coordinates/constants.ts +23 -0
- package/src/coordinates/index.ts +15 -0
- package/src/coordinates/memo.test.ts +47 -0
- package/src/coordinates/memo.ts +20 -0
- package/src/coordinates/permutation.ts +77 -0
- package/src/coordinates/regions.ts +48 -0
- package/src/coordinates/sectors.ts +115 -0
- package/src/data/capabilities.ts +12 -5
- package/src/data/capability-formulas.ts +14 -7
- package/src/data/catalog.ts +0 -5
- package/src/data/colors.ts +14 -47
- package/src/data/entities.json +76 -10
- package/src/data/item-ids.ts +18 -12
- package/src/data/items.json +321 -38
- package/src/data/kind-registry.json +109 -0
- package/src/data/kind-registry.ts +165 -0
- package/src/data/metadata.ts +119 -33
- package/src/data/recipes-runtime.ts +3 -23
- package/src/data/recipes.json +238 -117
- package/src/derivation/build-methods.ts +45 -0
- package/src/derivation/capabilities.test.ts +151 -0
- package/src/derivation/capabilities.ts +512 -0
- package/src/derivation/capability-mappings.ts +9 -12
- package/src/derivation/crafting.ts +23 -24
- package/src/derivation/index.ts +25 -2
- package/src/derivation/recipe-usage.test.ts +78 -0
- package/src/derivation/recipe-usage.ts +141 -0
- package/src/derivation/reserve-regen.ts +34 -0
- package/src/derivation/resources.ts +125 -38
- package/src/derivation/rollups.test.ts +55 -0
- package/src/derivation/rollups.ts +56 -0
- package/src/derivation/stars.test.ts +51 -0
- package/src/derivation/stars.ts +15 -0
- package/src/derivation/stats.ts +6 -6
- package/src/derivation/stratum.ts +17 -20
- package/src/derivation/tiers.ts +40 -7
- package/src/derivation/wormhole.ts +136 -0
- package/src/entities/entity.ts +98 -0
- package/src/entities/gamestate.ts +3 -28
- package/src/entities/makers.ts +124 -134
- package/src/entities/slot-multiplier.ts +43 -0
- package/src/errors.ts +12 -16
- package/src/format.ts +26 -4
- package/src/index-module.ts +267 -47
- package/src/managers/actions.ts +528 -95
- package/src/managers/base.ts +6 -2
- package/src/managers/construction-types.ts +80 -0
- package/src/managers/construction.ts +412 -0
- package/src/managers/context.ts +20 -1
- package/src/managers/coordinates.ts +14 -0
- package/src/managers/entities.ts +18 -66
- package/src/managers/epochs.ts +40 -0
- package/src/managers/index.ts +17 -1
- package/src/managers/locations.ts +25 -29
- package/src/managers/nft.test.ts +14 -0
- package/src/managers/nft.ts +70 -0
- package/src/managers/plot.ts +122 -0
- package/src/nft/atomicassets.abi.json +1342 -0
- package/src/nft/atomicassets.ts +237 -0
- package/src/nft/atomicdata.ts +130 -0
- package/src/nft/buildImmutableData.ts +338 -0
- package/src/nft/description.ts +98 -24
- package/src/nft/index.ts +3 -0
- package/src/planner/index.ts +127 -0
- package/src/planner/planner.test.ts +319 -0
- package/src/resolution/describe-module.ts +18 -13
- package/src/resolution/display-name.ts +38 -10
- package/src/resolution/resolve-item.test.ts +37 -0
- package/src/resolution/resolve-item.ts +55 -24
- package/src/scan/index.ts +180 -0
- package/src/scan/scan-wasm.base64.ts +2 -0
- package/src/scheduling/accessor.ts +68 -22
- package/src/scheduling/availability.ts +108 -0
- package/src/scheduling/cancel.test.ts +348 -0
- package/src/scheduling/cancel.ts +209 -0
- package/src/scheduling/energy.ts +47 -0
- package/src/scheduling/idle-resolve.ts +45 -0
- package/src/scheduling/lane-core.ts +128 -0
- package/src/scheduling/lanes.test.ts +249 -0
- package/src/scheduling/lanes.ts +198 -0
- package/src/scheduling/projection.ts +209 -105
- package/src/scheduling/schedule.ts +241 -104
- package/src/scheduling/task-cargo.ts +46 -0
- package/src/shipload.ts +21 -1
- package/src/subscriptions/manager.ts +229 -142
- package/src/subscriptions/mappers.ts +5 -8
- package/src/subscriptions/types.ts +11 -3
- package/src/testing/catalog-hash.ts +19 -0
- package/src/testing/index.ts +2 -0
- package/src/testing/projection-parity.ts +167 -0
- package/src/travel/reach.ts +23 -0
- package/src/travel/route-planner.ts +196 -0
- package/src/travel/travel.ts +200 -112
- package/src/types/capabilities.ts +29 -6
- package/src/types/entity.ts +3 -3
- package/src/types/index.ts +0 -1
- package/src/types.ts +28 -13
- package/src/utils/cargo.ts +27 -0
- package/src/utils/display-name.ts +70 -0
- package/src/utils/system.ts +36 -24
- package/src/capabilities/loading.ts +0 -8
- package/src/entities/container.ts +0 -108
- package/src/entities/ship-deploy.ts +0 -259
- package/src/entities/ship.ts +0 -204
- package/src/entities/warehouse.ts +0 -119
- package/src/types/entity-traits.ts +0 -69
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
export interface DisplayNameResult {
|
|
2
|
+
valid: boolean
|
|
3
|
+
reason?: string
|
|
4
|
+
name: string
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
const MAX_DISPLAY_NAME_BYTES = 32
|
|
8
|
+
const ASCII_SPACE = 0x20
|
|
9
|
+
const ZERO_WIDTH_CODE_POINTS = new Set([0x200b, 0x200c, 0x200d, 0x2060, 0xfeff])
|
|
10
|
+
const textEncoder = new TextEncoder()
|
|
11
|
+
|
|
12
|
+
function isControlCharacter(codePoint: number): boolean {
|
|
13
|
+
return codePoint <= 0x1f || codePoint === 0x7f || (codePoint >= 0x80 && codePoint <= 0x9f)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function isLoneSurrogate(codePoint: number): boolean {
|
|
17
|
+
return codePoint >= 0xd800 && codePoint <= 0xdfff
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function isBidiControl(codePoint: number): boolean {
|
|
21
|
+
return (
|
|
22
|
+
(codePoint >= 0x202a && codePoint <= 0x202e) || (codePoint >= 0x2066 && codePoint <= 0x2069)
|
|
23
|
+
)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function isInvalidDisplayNameCodePoint(codePoint: number): boolean {
|
|
27
|
+
return (
|
|
28
|
+
isControlCharacter(codePoint) ||
|
|
29
|
+
isLoneSurrogate(codePoint) ||
|
|
30
|
+
ZERO_WIDTH_CODE_POINTS.has(codePoint) ||
|
|
31
|
+
isBidiControl(codePoint)
|
|
32
|
+
)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function normalizeDisplayName(input: string): string {
|
|
36
|
+
let start = 0
|
|
37
|
+
let end = input.length
|
|
38
|
+
|
|
39
|
+
while (start < end && input.charCodeAt(start) === ASCII_SPACE) start++
|
|
40
|
+
while (end > start && input.charCodeAt(end - 1) === ASCII_SPACE) end--
|
|
41
|
+
|
|
42
|
+
return input.slice(start, end)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface ValidateDisplayNameOptions {
|
|
46
|
+
allowEmpty?: boolean
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function validateDisplayName(
|
|
50
|
+
input: string,
|
|
51
|
+
opts: ValidateDisplayNameOptions = {}
|
|
52
|
+
): DisplayNameResult {
|
|
53
|
+
const name = normalizeDisplayName(input)
|
|
54
|
+
|
|
55
|
+
if (name.length === 0) {
|
|
56
|
+
return opts.allowEmpty ? {valid: true, name} : {valid: false, reason: 'empty', name}
|
|
57
|
+
}
|
|
58
|
+
if (textEncoder.encode(name).length > MAX_DISPLAY_NAME_BYTES) {
|
|
59
|
+
return {valid: false, reason: 'too_long', name}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
for (const character of name) {
|
|
63
|
+
const codePoint = character.codePointAt(0)!
|
|
64
|
+
if (isInvalidDisplayNameCodePoint(codePoint)) {
|
|
65
|
+
return {valid: false, reason: 'invalid_char', name}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return {valid: true, name}
|
|
70
|
+
}
|
package/src/utils/system.ts
CHANGED
|
@@ -3,12 +3,12 @@ import {hash512} from './hash'
|
|
|
3
3
|
import {Coordinates, type CoordinatesType, LocationType} from '../types'
|
|
4
4
|
import {ServerContract} from '../contracts'
|
|
5
5
|
import {deriveLocationSize} from '../derivation/location-size'
|
|
6
|
+
import {wormholeAt} from '../derivation/wormhole'
|
|
6
7
|
import syllables from '../data/syllables.json'
|
|
7
8
|
import nebulaAdjectives from '../data/nebula-adjectives.json'
|
|
8
9
|
import nebulaNouns from '../data/nebula-nouns.json'
|
|
9
10
|
|
|
10
11
|
const LOCATION_EXISTS_THRESHOLD = 0x10
|
|
11
|
-
const LOCATION_ACTIVE_THRESHOLD = 0x80
|
|
12
12
|
|
|
13
13
|
export function getLocationType(
|
|
14
14
|
gameSeed: Checksum256Type,
|
|
@@ -22,12 +22,10 @@ export function getLocationType(
|
|
|
22
22
|
return LocationType.EMPTY
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
if (hashResult.array[1] < 96)
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
30
|
-
return LocationType.NEBULA
|
|
25
|
+
if (hashResult.array[1] < 96) return LocationType.PLANET
|
|
26
|
+
if (hashResult.array[1] < 149) return LocationType.ASTEROID
|
|
27
|
+
if (hashResult.array[1] < 202) return LocationType.NEBULA
|
|
28
|
+
return LocationType.ICE_FIELD
|
|
31
29
|
}
|
|
32
30
|
|
|
33
31
|
export function isGatherableLocation(locationType: LocationType): boolean {
|
|
@@ -44,6 +42,8 @@ export function getLocationTypeName(type: LocationType): string {
|
|
|
44
42
|
return 'Asteroid'
|
|
45
43
|
case LocationType.NEBULA:
|
|
46
44
|
return 'Nebula'
|
|
45
|
+
case LocationType.ICE_FIELD:
|
|
46
|
+
return 'Ice Field'
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
49
|
|
|
@@ -76,6 +76,15 @@ function generateNebulaName(hashResult: Checksum512): string {
|
|
|
76
76
|
return `${nebulaAdjectives[adjIdx]} ${nebulaNouns[nounIdx]}`
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
+
function generateIceFieldName(hashResult: Checksum512): string {
|
|
80
|
+
const A = 65
|
|
81
|
+
const letter1 = String.fromCharCode(A + (hashResult.array[0] % 26))
|
|
82
|
+
const letter2 = String.fromCharCode(A + (hashResult.array[1] % 26))
|
|
83
|
+
const subId = (hashResult.array[2] % 9) + 1
|
|
84
|
+
const num = (uint16(hashResult, 3) % 9000) + 1000
|
|
85
|
+
return `${letter1}${letter2}-${subId}/${num}`
|
|
86
|
+
}
|
|
87
|
+
|
|
79
88
|
export function getSystemName(gameSeed: Checksum256Type, location: CoordinatesType): string {
|
|
80
89
|
const seed = Checksum256.from(gameSeed)
|
|
81
90
|
const locationType = getLocationType(seed, location)
|
|
@@ -91,6 +100,8 @@ export function getSystemName(gameSeed: Checksum256Type, location: CoordinatesTy
|
|
|
91
100
|
return generateAsteroidName(hashResult)
|
|
92
101
|
case LocationType.NEBULA:
|
|
93
102
|
return generateNebulaName(hashResult)
|
|
103
|
+
case LocationType.ICE_FIELD:
|
|
104
|
+
return generateIceFieldName(hashResult)
|
|
94
105
|
default:
|
|
95
106
|
return generatePlanetName(hashResult)
|
|
96
107
|
}
|
|
@@ -100,6 +111,16 @@ export function hasSystem(gameSeed: Checksum256Type, coordinates: CoordinatesTyp
|
|
|
100
111
|
return getLocationType(gameSeed, coordinates) !== LocationType.EMPTY
|
|
101
112
|
}
|
|
102
113
|
|
|
114
|
+
export function getLocationKind(
|
|
115
|
+
gameSeed: Checksum256Type,
|
|
116
|
+
x: number,
|
|
117
|
+
y: number
|
|
118
|
+
): 'wormhole' | 'system' | 'empty' {
|
|
119
|
+
if (wormholeAt(gameSeed, x, y)) return 'wormhole'
|
|
120
|
+
if (hasSystem(gameSeed, {x, y})) return 'system'
|
|
121
|
+
return 'empty'
|
|
122
|
+
}
|
|
123
|
+
|
|
103
124
|
export function deriveLocationStatic(
|
|
104
125
|
gameSeed: Checksum256Type,
|
|
105
126
|
coordinates: CoordinatesType
|
|
@@ -123,10 +144,12 @@ export function deriveLocationStatic(
|
|
|
123
144
|
|
|
124
145
|
if (hashResult.array[1] < 96) {
|
|
125
146
|
loc.type = UInt8.from(LocationType.PLANET)
|
|
126
|
-
} else if (hashResult.array[1] <
|
|
147
|
+
} else if (hashResult.array[1] < 149) {
|
|
127
148
|
loc.type = UInt8.from(LocationType.ASTEROID)
|
|
128
|
-
} else {
|
|
149
|
+
} else if (hashResult.array[1] < 202) {
|
|
129
150
|
loc.type = UInt8.from(LocationType.NEBULA)
|
|
151
|
+
} else {
|
|
152
|
+
loc.type = UInt8.from(LocationType.ICE_FIELD)
|
|
130
153
|
}
|
|
131
154
|
|
|
132
155
|
loc.subtype = UInt8.from(
|
|
@@ -138,31 +161,20 @@ export function deriveLocationStatic(
|
|
|
138
161
|
return loc
|
|
139
162
|
}
|
|
140
163
|
|
|
141
|
-
export function
|
|
142
|
-
|
|
164
|
+
export function isLocationBuildable(
|
|
165
|
+
gameSeed: Checksum256Type,
|
|
143
166
|
coordinates: CoordinatesType
|
|
144
|
-
):
|
|
145
|
-
|
|
146
|
-
const coords = Coordinates.from(coordinates)
|
|
147
|
-
const str = `system-epoch-${coords.x}-${coords.y}`
|
|
148
|
-
const hashResult = hash512(seed, str)
|
|
149
|
-
|
|
150
|
-
return ServerContract.Types.location_epoch.from({
|
|
151
|
-
active: hashResult.array[0] < LOCATION_ACTIVE_THRESHOLD,
|
|
152
|
-
seed0: hashResult.array[1],
|
|
153
|
-
seed1: hashResult.array[2],
|
|
154
|
-
})
|
|
167
|
+
): boolean {
|
|
168
|
+
return getLocationType(gameSeed, coordinates) === LocationType.PLANET
|
|
155
169
|
}
|
|
156
170
|
|
|
157
171
|
export function deriveLocation(
|
|
158
172
|
gameSeed: Checksum256Type,
|
|
159
|
-
epochSeed: Checksum256Type,
|
|
160
173
|
coordinates: CoordinatesType
|
|
161
174
|
): ServerContract.Types.location_derived {
|
|
162
175
|
const staticProps = deriveLocationStatic(gameSeed, coordinates)
|
|
163
176
|
return ServerContract.Types.location_derived.from({
|
|
164
177
|
static_props: staticProps,
|
|
165
|
-
epoch_props: deriveLocationEpoch(epochSeed, coordinates),
|
|
166
178
|
size: deriveLocationSize(staticProps),
|
|
167
179
|
})
|
|
168
180
|
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import {UInt32, type UInt64} from '@wharfkit/antelope'
|
|
2
|
-
import type {LoaderCapability} from '../types/capabilities'
|
|
3
|
-
|
|
4
|
-
export function calcLoadDuration(entity: LoaderCapability, cargoMass: UInt64): UInt32 {
|
|
5
|
-
const totalThrust = entity.loaders.thrust.toNumber() * entity.loaders.quantity.toNumber()
|
|
6
|
-
if (totalThrust === 0) return UInt32.from(0)
|
|
7
|
-
return UInt32.from(Math.ceil(Number(cargoMass) / totalThrust))
|
|
8
|
-
}
|
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
import {UInt64, type UInt64Type} from '@wharfkit/antelope'
|
|
2
|
-
import {ServerContract} from '../contracts'
|
|
3
|
-
import type {CoordinatesType} from '../types'
|
|
4
|
-
import {Location} from './location'
|
|
5
|
-
import {ScheduleAccessor} from '../scheduling/accessor'
|
|
6
|
-
import * as schedule from '../scheduling/schedule'
|
|
7
|
-
|
|
8
|
-
export interface ContainerStateInput {
|
|
9
|
-
id: UInt64Type
|
|
10
|
-
owner: string
|
|
11
|
-
name: string
|
|
12
|
-
coordinates: CoordinatesType | {x: number; y: number; z?: number}
|
|
13
|
-
hullmass: number
|
|
14
|
-
capacity: number
|
|
15
|
-
cargomass?: number
|
|
16
|
-
cargo?: ServerContract.Types.cargo_item[]
|
|
17
|
-
schedule?: ServerContract.Types.schedule
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export class Container extends ServerContract.Types.entity_info {
|
|
21
|
-
private _sched?: ScheduleAccessor
|
|
22
|
-
|
|
23
|
-
get name(): string {
|
|
24
|
-
return this.entity_name
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
get sched(): ScheduleAccessor {
|
|
28
|
-
this._sched ??= new ScheduleAccessor(this)
|
|
29
|
-
return this._sched
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
get isIdle(): boolean {
|
|
33
|
-
return this.is_idle
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
isLoading(now: Date): boolean {
|
|
37
|
-
return schedule.isLoading(this, now)
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
isUnloading(now: Date): boolean {
|
|
41
|
-
return schedule.isUnloading(this, now)
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
get location(): Location {
|
|
45
|
-
return Location.from(this.coordinates)
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
get totalMass(): UInt64 {
|
|
49
|
-
return UInt64.from(this.hullmass ?? 0).adding(this.cargomass)
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
get maxCapacity(): UInt64 {
|
|
53
|
-
return UInt64.from(this.capacity)
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
get availableCapacity(): UInt64 {
|
|
57
|
-
const cargo = UInt64.from(this.cargomass)
|
|
58
|
-
return cargo.gte(this.maxCapacity) ? UInt64.from(0) : this.maxCapacity.subtracting(cargo)
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
hasSpace(additionalMass: UInt64): boolean {
|
|
62
|
-
return UInt64.from(this.cargomass).adding(additionalMass).lte(this.maxCapacity)
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
get isFull(): boolean {
|
|
66
|
-
return UInt64.from(this.cargomass).gte(this.maxCapacity)
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
get orbitalAltitude(): number {
|
|
70
|
-
return this.coordinates.z?.toNumber() || 0
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
export function computeContainerCapabilities(stats: Record<string, number>): {
|
|
75
|
-
hullmass: number
|
|
76
|
-
capacity: number
|
|
77
|
-
} {
|
|
78
|
-
const density = stats.density
|
|
79
|
-
const strength = stats.strength
|
|
80
|
-
const hardness = stats.hardness
|
|
81
|
-
const saturation = stats.saturation
|
|
82
|
-
|
|
83
|
-
const hullmass = 25000 + 75 * density
|
|
84
|
-
|
|
85
|
-
const statSum = strength + hardness + saturation
|
|
86
|
-
const exponent = statSum / 2997
|
|
87
|
-
const capacity = Math.floor(1000000 * 10 ** exponent)
|
|
88
|
-
|
|
89
|
-
return {hullmass, capacity}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
export function computeContainerT2Capabilities(stats: Record<string, number>): {
|
|
93
|
-
hullmass: number
|
|
94
|
-
capacity: number
|
|
95
|
-
} {
|
|
96
|
-
const strength = stats.strength
|
|
97
|
-
const density = stats.density
|
|
98
|
-
const hardness = stats.hardness
|
|
99
|
-
const saturation = stats.saturation
|
|
100
|
-
|
|
101
|
-
const hullmass = 20000 + 50 * density
|
|
102
|
-
|
|
103
|
-
const statSum = strength + hardness + saturation
|
|
104
|
-
const exponent = statSum / 2500
|
|
105
|
-
const capacity = Math.floor(1500000 * 10 ** exponent)
|
|
106
|
-
|
|
107
|
-
return {hullmass, capacity}
|
|
108
|
-
}
|
|
@@ -1,259 +0,0 @@
|
|
|
1
|
-
import {decodeCraftedItemStats} from '../derivation/crafting'
|
|
2
|
-
import {
|
|
3
|
-
getModuleCapabilityType,
|
|
4
|
-
MODULE_CRAFTER,
|
|
5
|
-
MODULE_ENGINE,
|
|
6
|
-
MODULE_GATHERER,
|
|
7
|
-
MODULE_GENERATOR,
|
|
8
|
-
MODULE_HAULER,
|
|
9
|
-
MODULE_LOADER,
|
|
10
|
-
} from '../capabilities/modules'
|
|
11
|
-
|
|
12
|
-
export function computeShipHullCapabilities(stats: Record<string, number>): {
|
|
13
|
-
hullmass: number
|
|
14
|
-
capacity: number
|
|
15
|
-
} {
|
|
16
|
-
const density = stats.density
|
|
17
|
-
const strength = stats.strength
|
|
18
|
-
const hardness = stats.hardness
|
|
19
|
-
const saturation = stats.saturation
|
|
20
|
-
|
|
21
|
-
const hullmass = 25000 + 75 * density
|
|
22
|
-
const statSum = strength + hardness + saturation
|
|
23
|
-
const exponent = statSum / 2997.0
|
|
24
|
-
const capacity = Math.floor(1000000 * 10 ** exponent)
|
|
25
|
-
|
|
26
|
-
return {hullmass, capacity}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export function computeEngineCapabilities(stats: Record<string, number>): {
|
|
30
|
-
thrust: number
|
|
31
|
-
drain: number
|
|
32
|
-
} {
|
|
33
|
-
const vol = stats.volatility
|
|
34
|
-
const thm = stats.thermal
|
|
35
|
-
|
|
36
|
-
return {
|
|
37
|
-
thrust: 400 + Math.floor((vol * 3) / 4),
|
|
38
|
-
drain: Math.max(30, 50 - Math.floor(thm / 70)),
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export function computeGeneratorCapabilities(stats: Record<string, number>): {
|
|
43
|
-
capacity: number
|
|
44
|
-
recharge: number
|
|
45
|
-
} {
|
|
46
|
-
const com = stats.composition
|
|
47
|
-
const fin = stats.fineness
|
|
48
|
-
|
|
49
|
-
return {
|
|
50
|
-
capacity: 300 + Math.floor(com / 6),
|
|
51
|
-
recharge: 1 + Math.floor((fin * 3) / 1000),
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
export function computeGathererCapabilities(stats: Record<string, number>): {
|
|
56
|
-
yield: number
|
|
57
|
-
drain: number
|
|
58
|
-
depth: number
|
|
59
|
-
speed: number
|
|
60
|
-
} {
|
|
61
|
-
const str = stats.strength
|
|
62
|
-
const con = stats.conductivity
|
|
63
|
-
const ref = stats.reflectivity
|
|
64
|
-
const tol = stats.tolerance
|
|
65
|
-
|
|
66
|
-
return {
|
|
67
|
-
yield: 200 + str,
|
|
68
|
-
drain: Math.max(250, 1250 - Math.floor((con * 25) / 20)),
|
|
69
|
-
depth: 200 + Math.floor((tol * 3) / 2),
|
|
70
|
-
speed: 100 + Math.floor((ref * 4) / 5),
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
export function computeLoaderCapabilities(stats: Record<string, number>): {
|
|
75
|
-
mass: number
|
|
76
|
-
thrust: number
|
|
77
|
-
quantity: number
|
|
78
|
-
} {
|
|
79
|
-
const insulation = stats.insulation
|
|
80
|
-
const plasticity = stats.plasticity
|
|
81
|
-
|
|
82
|
-
return {
|
|
83
|
-
mass: Math.max(200, 2000 - Math.floor(insulation * 2)),
|
|
84
|
-
thrust: 1 + Math.floor(plasticity / 500),
|
|
85
|
-
quantity: 1,
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
export function computeCrafterCapabilities(stats: Record<string, number>): {
|
|
90
|
-
speed: number
|
|
91
|
-
drain: number
|
|
92
|
-
} {
|
|
93
|
-
const rea = stats.reactivity
|
|
94
|
-
const fin = stats.fineness
|
|
95
|
-
|
|
96
|
-
return {
|
|
97
|
-
speed: 100 + Math.floor((rea * 4) / 5),
|
|
98
|
-
drain: Math.max(5, 30 - Math.floor(fin / 33)),
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
export function computeHaulerCapabilities(stats: Record<string, number>): {
|
|
103
|
-
capacity: number
|
|
104
|
-
efficiency: number
|
|
105
|
-
drain: number
|
|
106
|
-
} {
|
|
107
|
-
const fineness = stats.fineness
|
|
108
|
-
const conductivity = stats.conductivity
|
|
109
|
-
const composition = stats.composition
|
|
110
|
-
|
|
111
|
-
return {
|
|
112
|
-
capacity: Math.max(1, 1 + Math.floor(fineness / 400)),
|
|
113
|
-
efficiency: 2000 + conductivity * 6,
|
|
114
|
-
drain: Math.max(3, 15 - Math.floor(composition / 80)),
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
export function computeStorageCapabilities(
|
|
119
|
-
stats: Record<string, number>,
|
|
120
|
-
baseCapacity: number
|
|
121
|
-
): {
|
|
122
|
-
capacityBonus: number
|
|
123
|
-
} {
|
|
124
|
-
const strength = stats.strength
|
|
125
|
-
const density = stats.density
|
|
126
|
-
const hardness = stats.hardness
|
|
127
|
-
const saturation = stats.saturation
|
|
128
|
-
|
|
129
|
-
const statSum = strength + density + hardness + saturation
|
|
130
|
-
const capacityBonus = Math.floor(
|
|
131
|
-
(baseCapacity * (10 + Math.floor((statSum * 10) / 2997))) / 100
|
|
132
|
-
)
|
|
133
|
-
|
|
134
|
-
return {capacityBonus}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
export function computeWarehouseHullCapabilities(stats: Record<string, number>): {
|
|
138
|
-
hullmass: number
|
|
139
|
-
capacity: number
|
|
140
|
-
} {
|
|
141
|
-
const density = stats.density
|
|
142
|
-
const strength = stats.strength
|
|
143
|
-
const hardness = stats.hardness
|
|
144
|
-
const saturation = stats.saturation
|
|
145
|
-
|
|
146
|
-
const hullmass = 25000 + 75 * density
|
|
147
|
-
const statSum = strength + hardness + saturation
|
|
148
|
-
const exponent = statSum / 2997.0
|
|
149
|
-
const capacity = Math.floor(20000000 * 10 ** exponent)
|
|
150
|
-
|
|
151
|
-
return {hullmass, capacity}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
export interface ShipCapabilities {
|
|
155
|
-
engines?: {thrust: number; drain: number}
|
|
156
|
-
generator?: {capacity: number; recharge: number}
|
|
157
|
-
gatherer?: {yield: number; drain: number; depth: number; speed: number}
|
|
158
|
-
hauler?: {capacity: number; efficiency: number; drain: number}
|
|
159
|
-
loaders?: {mass: number; thrust: number; quantity: number}
|
|
160
|
-
crafter?: {speed: number; drain: number}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
export function computeShipCapabilities(
|
|
164
|
-
modules: {itemId: number; stats: bigint}[]
|
|
165
|
-
): ShipCapabilities {
|
|
166
|
-
const ship: ShipCapabilities = {}
|
|
167
|
-
|
|
168
|
-
const engineModules = modules.filter((m) => getModuleCapabilityType(m.itemId) === MODULE_ENGINE)
|
|
169
|
-
if (engineModules.length > 0) {
|
|
170
|
-
let totalThrust = 0
|
|
171
|
-
let totalDrain = 0
|
|
172
|
-
for (const m of engineModules) {
|
|
173
|
-
const caps = computeEngineCapabilities(decodeCraftedItemStats(m.itemId, m.stats))
|
|
174
|
-
totalThrust += caps.thrust
|
|
175
|
-
totalDrain += caps.drain
|
|
176
|
-
}
|
|
177
|
-
ship.engines = {thrust: totalThrust, drain: totalDrain}
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
const generatorModules = modules.filter(
|
|
181
|
-
(m) => getModuleCapabilityType(m.itemId) === MODULE_GENERATOR
|
|
182
|
-
)
|
|
183
|
-
if (generatorModules.length > 0) {
|
|
184
|
-
let totalCapacity = 0
|
|
185
|
-
let totalRecharge = 0
|
|
186
|
-
for (const m of generatorModules) {
|
|
187
|
-
const caps = computeGeneratorCapabilities(decodeCraftedItemStats(m.itemId, m.stats))
|
|
188
|
-
totalCapacity += caps.capacity
|
|
189
|
-
totalRecharge += caps.recharge
|
|
190
|
-
}
|
|
191
|
-
ship.generator = {capacity: totalCapacity, recharge: totalRecharge}
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
const gathererModules = modules.filter(
|
|
195
|
-
(m) => getModuleCapabilityType(m.itemId) === MODULE_GATHERER
|
|
196
|
-
)
|
|
197
|
-
if (gathererModules.length > 0) {
|
|
198
|
-
let totalYield = 0
|
|
199
|
-
let totalDrain = 0
|
|
200
|
-
let totalDepth = 0
|
|
201
|
-
let totalSpeed = 0
|
|
202
|
-
for (const m of gathererModules) {
|
|
203
|
-
const caps = computeGathererCapabilities(decodeCraftedItemStats(m.itemId, m.stats))
|
|
204
|
-
totalYield += caps.yield
|
|
205
|
-
totalDrain += caps.drain
|
|
206
|
-
totalDepth += caps.depth
|
|
207
|
-
totalSpeed += caps.speed
|
|
208
|
-
}
|
|
209
|
-
ship.gatherer = {yield: totalYield, drain: totalDrain, depth: totalDepth, speed: totalSpeed}
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
const haulerModules = modules.filter((m) => getModuleCapabilityType(m.itemId) === MODULE_HAULER)
|
|
213
|
-
if (haulerModules.length > 0) {
|
|
214
|
-
let totalCapacity = 0
|
|
215
|
-
let weightedEffNum = 0
|
|
216
|
-
let totalDrain = 0
|
|
217
|
-
for (const m of haulerModules) {
|
|
218
|
-
const caps = computeHaulerCapabilities(decodeCraftedItemStats(m.itemId, m.stats))
|
|
219
|
-
totalCapacity += caps.capacity
|
|
220
|
-
weightedEffNum += caps.efficiency * caps.capacity
|
|
221
|
-
totalDrain += caps.drain
|
|
222
|
-
}
|
|
223
|
-
ship.hauler = {
|
|
224
|
-
capacity: totalCapacity,
|
|
225
|
-
efficiency: totalCapacity > 0 ? Math.floor(weightedEffNum / totalCapacity) : 0,
|
|
226
|
-
drain: totalDrain,
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
const loaderModules = modules.filter((m) => getModuleCapabilityType(m.itemId) === MODULE_LOADER)
|
|
231
|
-
if (loaderModules.length > 0) {
|
|
232
|
-
let totalMass = 0
|
|
233
|
-
let totalThrust = 0
|
|
234
|
-
let totalQuantity = 0
|
|
235
|
-
for (const m of loaderModules) {
|
|
236
|
-
const caps = computeLoaderCapabilities(decodeCraftedItemStats(m.itemId, m.stats))
|
|
237
|
-
totalMass += caps.mass
|
|
238
|
-
totalThrust += caps.thrust
|
|
239
|
-
totalQuantity += caps.quantity
|
|
240
|
-
}
|
|
241
|
-
ship.loaders = {mass: totalMass, thrust: totalThrust, quantity: totalQuantity}
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
const crafterModules = modules.filter(
|
|
245
|
-
(m) => getModuleCapabilityType(m.itemId) === MODULE_CRAFTER
|
|
246
|
-
)
|
|
247
|
-
if (crafterModules.length > 0) {
|
|
248
|
-
let totalSpeed = 0
|
|
249
|
-
let totalDrain = 0
|
|
250
|
-
for (const m of crafterModules) {
|
|
251
|
-
const caps = computeCrafterCapabilities(decodeCraftedItemStats(m.itemId, m.stats))
|
|
252
|
-
totalSpeed += caps.speed
|
|
253
|
-
totalDrain += caps.drain
|
|
254
|
-
}
|
|
255
|
-
ship.crafter = {speed: totalSpeed, drain: totalDrain}
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
return ship
|
|
259
|
-
}
|