@shipload/sdk 1.0.0-next.11 → 1.0.0-next.13

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.
@@ -1,316 +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
- import {getItem} from '../data/catalog'
12
- import type {EntitySlot} from '../data/recipes-runtime'
13
- import {applySlotMultiplier, clampUint16, getSlotAmp, type InstalledModule} from './slot-multiplier'
14
-
15
- export type {InstalledModule}
16
-
17
- export function computeShipHullCapabilities(stats: Record<string, number>): {
18
- hullmass: number
19
- capacity: number
20
- } {
21
- const density = stats.density
22
- const strength = stats.strength
23
- const hardness = stats.hardness
24
- const saturation = stats.saturation
25
-
26
- const hullmass = 100000 - 75 * density
27
- const statSum = strength + hardness + saturation
28
- const exponent = statSum / 2997.0
29
- const capacity = Math.floor(1000000 * 10 ** exponent)
30
-
31
- return {hullmass, capacity}
32
- }
33
-
34
- export function computeEngineCapabilities(stats: Record<string, number>): {
35
- thrust: number
36
- drain: number
37
- } {
38
- const vol = stats.volatility
39
- const thm = stats.thermal
40
-
41
- return {
42
- thrust: 400 + Math.floor((vol * 3) / 4),
43
- drain: Math.max(30, 50 - Math.floor(thm / 70)),
44
- }
45
- }
46
-
47
- export function computeGeneratorCapabilities(stats: Record<string, number>): {
48
- capacity: number
49
- recharge: number
50
- } {
51
- const com = stats.composition
52
- const fin = stats.fineness
53
-
54
- return {
55
- capacity: 300 + Math.floor(com / 6),
56
- recharge: 1 + Math.floor((fin * 3) / 1000),
57
- }
58
- }
59
-
60
- export interface GathererDepthParams {
61
- readonly floor: number
62
- readonly slope: number
63
- }
64
-
65
- export const GATHERER_DEPTH_TABLE: readonly GathererDepthParams[] = [
66
- {floor: 500, slope: 5},
67
- {floor: 2000, slope: 11},
68
- {floor: 7000, slope: 16},
69
- {floor: 15000, slope: 18},
70
- {floor: 25000, slope: 19},
71
- {floor: 35000, slope: 16},
72
- {floor: 46000, slope: 12},
73
- {floor: 53500, slope: 10},
74
- {floor: 60000, slope: 5},
75
- {floor: 63500, slope: 2},
76
- ]
77
-
78
- export const GATHERER_DEPTH_MAX_TIER = 10
79
-
80
- export function gathererDepthForTier(tol: number, tier: number): number {
81
- if (tier < 1 || tier > GATHERER_DEPTH_MAX_TIER) {
82
- throw new Error(`gatherer tier out of range: ${tier}`)
83
- }
84
- const p = GATHERER_DEPTH_TABLE[tier - 1]
85
- return p.floor + tol * p.slope
86
- }
87
-
88
- export function computeGathererCapabilities(
89
- stats: Record<string, number>,
90
- tier: number
91
- ): {
92
- yield: number
93
- drain: number
94
- depth: number
95
- speed: number
96
- } {
97
- const str = stats.strength
98
- const con = stats.conductivity
99
- const ref = stats.reflectivity
100
- const tol = stats.tolerance
101
-
102
- return {
103
- yield: 200 + str,
104
- drain: Math.max(250, 1250 - Math.floor((con * 25) / 20)),
105
- depth: gathererDepthForTier(tol, tier),
106
- speed: 100 + Math.floor((ref * 4) / 5),
107
- }
108
- }
109
-
110
- export function computeLoaderCapabilities(stats: Record<string, number>): {
111
- mass: number
112
- thrust: number
113
- quantity: number
114
- } {
115
- const insulation = stats.insulation
116
- const plasticity = stats.plasticity
117
-
118
- return {
119
- mass: Math.max(200, 2000 - Math.floor(insulation * 2)),
120
- thrust: 1 + Math.floor(plasticity / 500),
121
- quantity: 1,
122
- }
123
- }
124
-
125
- export function computeCrafterCapabilities(stats: Record<string, number>): {
126
- speed: number
127
- drain: number
128
- } {
129
- const rea = stats.reactivity
130
- const fin = stats.fineness
131
-
132
- return {
133
- speed: 100 + Math.floor((rea * 4) / 5),
134
- drain: Math.max(5, 30 - Math.floor(fin / 33)),
135
- }
136
- }
137
-
138
- export function computeHaulerCapabilities(stats: Record<string, number>): {
139
- capacity: number
140
- efficiency: number
141
- drain: number
142
- } {
143
- const fineness = stats.fineness
144
- const conductivity = stats.conductivity
145
- const composition = stats.composition
146
-
147
- return {
148
- capacity: Math.max(1, 1 + Math.floor(fineness / 400)),
149
- efficiency: 2000 + conductivity * 6,
150
- drain: Math.max(3, 15 - Math.floor(composition / 80)),
151
- }
152
- }
153
-
154
- export function computeStorageCapabilities(
155
- stats: Record<string, number>,
156
- baseCapacity: number
157
- ): {
158
- capacityBonus: number
159
- } {
160
- const strength = stats.strength
161
- const density = stats.density
162
- const hardness = stats.hardness
163
- const saturation = stats.saturation
164
-
165
- const statSum = strength + density + hardness + saturation
166
- const capacityBonus = Math.floor(
167
- (baseCapacity * (10 + Math.floor((statSum * 10) / 2997))) / 100
168
- )
169
-
170
- return {capacityBonus}
171
- }
172
-
173
- export function computeWarehouseHullCapabilities(stats: Record<string, number>): {
174
- hullmass: number
175
- capacity: number
176
- } {
177
- const density = stats.density
178
- const strength = stats.strength
179
- const hardness = stats.hardness
180
- const saturation = stats.saturation
181
-
182
- const hullmass = 100000 - 75 * density
183
- const statSum = strength + hardness + saturation
184
- const exponent = statSum / 2997.0
185
- const capacity = Math.floor(20000000 * 10 ** exponent)
186
-
187
- return {hullmass, capacity}
188
- }
189
-
190
- export interface ShipCapabilities {
191
- engines?: {thrust: number; drain: number}
192
- generator?: {capacity: number; recharge: number}
193
- gatherer?: {yield: number; drain: number; depth: number; speed: number}
194
- hauler?: {capacity: number; efficiency: number; drain: number}
195
- loaders?: {mass: number; thrust: number; quantity: number}
196
- crafter?: {speed: number; drain: number}
197
- }
198
-
199
- export function computeShipCapabilities(
200
- modules: InstalledModule[],
201
- layout: EntitySlot[]
202
- ): ShipCapabilities {
203
- const ship: ShipCapabilities = {}
204
-
205
- const engineModules = modules.filter((m) => getModuleCapabilityType(m.itemId) === MODULE_ENGINE)
206
- if (engineModules.length > 0) {
207
- let totalThrust = 0
208
- let totalDrain = 0
209
- for (const m of engineModules) {
210
- const caps = computeEngineCapabilities(decodeCraftedItemStats(m.itemId, m.stats))
211
- totalThrust += applySlotMultiplier(caps.thrust, getSlotAmp(layout, m.slotIndex))
212
- totalDrain += caps.drain
213
- }
214
- ship.engines = {thrust: totalThrust, drain: totalDrain}
215
- }
216
-
217
- const generatorModules = modules.filter(
218
- (m) => getModuleCapabilityType(m.itemId) === MODULE_GENERATOR
219
- )
220
- if (generatorModules.length > 0) {
221
- let totalCapacity = 0
222
- let totalRecharge = 0
223
- for (const m of generatorModules) {
224
- const caps = computeGeneratorCapabilities(decodeCraftedItemStats(m.itemId, m.stats))
225
- const amp = getSlotAmp(layout, m.slotIndex)
226
- totalCapacity += applySlotMultiplier(caps.capacity, amp)
227
- totalRecharge += applySlotMultiplier(caps.recharge, amp)
228
- }
229
- ship.generator = {
230
- capacity: clampUint16(totalCapacity),
231
- recharge: clampUint16(totalRecharge),
232
- }
233
- }
234
-
235
- const gathererModules = modules.filter(
236
- (m) => getModuleCapabilityType(m.itemId) === MODULE_GATHERER
237
- )
238
- if (gathererModules.length > 0) {
239
- let totalYield = 0
240
- let totalDrain = 0
241
- let maxDepth = 0
242
- let totalSpeed = 0
243
- for (const m of gathererModules) {
244
- const tier = getItem(m.itemId).tier
245
- const caps = computeGathererCapabilities(
246
- decodeCraftedItemStats(m.itemId, m.stats),
247
- tier
248
- )
249
- const amp = getSlotAmp(layout, m.slotIndex)
250
- totalYield += applySlotMultiplier(caps.yield, amp)
251
- totalDrain += caps.drain
252
- if (caps.depth > maxDepth) maxDepth = caps.depth
253
- totalSpeed += applySlotMultiplier(caps.speed, amp)
254
- }
255
- ship.gatherer = {
256
- yield: clampUint16(totalYield),
257
- drain: totalDrain,
258
- depth: maxDepth,
259
- speed: clampUint16(totalSpeed),
260
- }
261
- }
262
-
263
- const haulerModules = modules.filter((m) => getModuleCapabilityType(m.itemId) === MODULE_HAULER)
264
- if (haulerModules.length > 0) {
265
- let totalCapacity = 0
266
- let weightedEffNum = 0
267
- let totalDrain = 0
268
- for (const m of haulerModules) {
269
- const caps = computeHaulerCapabilities(decodeCraftedItemStats(m.itemId, m.stats))
270
- const eff = applySlotMultiplier(caps.efficiency, getSlotAmp(layout, m.slotIndex))
271
- totalCapacity += caps.capacity
272
- weightedEffNum += eff * caps.capacity
273
- totalDrain += caps.drain
274
- }
275
- const efficiency = totalCapacity > 0 ? Math.floor(weightedEffNum / totalCapacity) : 0
276
- ship.hauler = {
277
- capacity: totalCapacity,
278
- efficiency: clampUint16(efficiency),
279
- drain: totalDrain,
280
- }
281
- }
282
-
283
- const loaderModules = modules.filter((m) => getModuleCapabilityType(m.itemId) === MODULE_LOADER)
284
- if (loaderModules.length > 0) {
285
- let totalMass = 0
286
- let totalThrust = 0
287
- let totalQuantity = 0
288
- for (const m of loaderModules) {
289
- const caps = computeLoaderCapabilities(decodeCraftedItemStats(m.itemId, m.stats))
290
- totalMass += caps.mass
291
- totalThrust += applySlotMultiplier(caps.thrust, getSlotAmp(layout, m.slotIndex))
292
- totalQuantity += caps.quantity
293
- }
294
- ship.loaders = {
295
- mass: totalMass,
296
- thrust: clampUint16(totalThrust),
297
- quantity: totalQuantity,
298
- }
299
- }
300
-
301
- const crafterModules = modules.filter(
302
- (m) => getModuleCapabilityType(m.itemId) === MODULE_CRAFTER
303
- )
304
- if (crafterModules.length > 0) {
305
- let totalSpeed = 0
306
- let totalDrain = 0
307
- for (const m of crafterModules) {
308
- const caps = computeCrafterCapabilities(decodeCraftedItemStats(m.itemId, m.stats))
309
- totalSpeed += applySlotMultiplier(caps.speed, getSlotAmp(layout, m.slotIndex))
310
- totalDrain += caps.drain
311
- }
312
- ship.crafter = {speed: clampUint16(totalSpeed), drain: totalDrain}
313
- }
314
-
315
- return ship
316
- }
@@ -1,221 +0,0 @@
1
- import {type UInt16, type UInt16Type, UInt32, UInt64, type UInt64Type} from '@wharfkit/antelope'
2
- import {ServerContract} from '../contracts'
3
- import {Coordinates, type CoordinatesType} from '../types'
4
- import {
5
- type FloatPosition,
6
- getDestinationLocation,
7
- getInterpolatedPosition,
8
- getPositionAt,
9
- getFlightOrigin as travelGetFlightOrigin,
10
- } from '../travel/travel'
11
- import {
12
- type ProjectedEntity,
13
- projectFromCurrentState as sharedProjectFromCurrentState,
14
- projectFromCurrentStateAt as sharedProjectFromCurrentStateAt,
15
- } from '../scheduling/projection'
16
- import {Location} from './location'
17
- import {ScheduleAccessor} from '../scheduling/accessor'
18
- import {InventoryAccessor} from './inventory-accessor'
19
- import type {EntityInventory} from './entity-inventory'
20
- import {
21
- energyPercent as calcEnergyPercent,
22
- needsRecharge as calcNeedsRecharge,
23
- hasEnergyForDistance,
24
- maxTravelDistance,
25
- } from '../capabilities/movement'
26
- import * as schedule from '../scheduling/schedule'
27
-
28
- export interface PackedModuleInput {
29
- itemId: UInt16Type
30
- stats: UInt64Type
31
- }
32
-
33
- export interface ShipStateInput {
34
- id: UInt64Type
35
- owner: string
36
- name: string
37
- coordinates: CoordinatesType | {x: number; y: number; z?: number}
38
- hullmass?: number
39
- capacity?: number
40
- energy?: number
41
- modules?: PackedModuleInput[]
42
- schedule?: ServerContract.Types.schedule
43
- cargo?: ServerContract.Types.cargo_item[]
44
- }
45
-
46
- type MovementEntity = {
47
- engines: ServerContract.Types.movement_stats
48
- generator: ServerContract.Types.energy_stats
49
- energy: UInt16
50
- }
51
-
52
- export class Ship extends ServerContract.Types.entity_info {
53
- private _sched?: ScheduleAccessor
54
- private _inv?: InventoryAccessor
55
-
56
- get name(): string {
57
- return this.entity_name
58
- }
59
-
60
- get entityClass(): 'orbital' {
61
- return 'orbital'
62
- }
63
-
64
- get canUndeploy(): boolean {
65
- return true
66
- }
67
-
68
- get inv(): InventoryAccessor {
69
- this._inv ??= new InventoryAccessor(this)
70
- return this._inv
71
- }
72
-
73
- get inventory(): EntityInventory[] {
74
- return this.inv.items
75
- }
76
-
77
- get sched(): ScheduleAccessor {
78
- this._sched ??= new ScheduleAccessor(this)
79
- return this._sched
80
- }
81
-
82
- get maxDistance(): UInt32 {
83
- if (!this.generator || !this.engines) return UInt32.from(0)
84
- return maxTravelDistance(this as MovementEntity)
85
- }
86
-
87
- get isIdle(): boolean {
88
- return this.is_idle
89
- }
90
-
91
- getFlightOrigin(flightTaskIndex: number): Coordinates {
92
- return Coordinates.from(travelGetFlightOrigin(this, flightTaskIndex))
93
- }
94
-
95
- destinationLocation(): Coordinates | undefined {
96
- const dest = getDestinationLocation(this)
97
- return dest ? Coordinates.from(dest) : undefined
98
- }
99
-
100
- /** Chain-tile coordinates at `now`. For smooth visual position use interpolatedPositionAt. */
101
- positionAt(now: Date): Coordinates {
102
- const taskIndex = this.sched.currentTaskIndex(now)
103
- const progress = this.sched.currentTaskProgress(now)
104
- return Coordinates.from(getPositionAt(this, taskIndex, progress))
105
- }
106
-
107
- interpolatedPositionAt(now: Date): FloatPosition {
108
- const taskIndex = this.sched.currentTaskIndex(now)
109
- const progress = this.sched.currentTaskProgressFloat(now)
110
- return getInterpolatedPosition(this, taskIndex, progress)
111
- }
112
-
113
- isInFlight(now: Date): boolean {
114
- return schedule.isInFlight(this, now)
115
- }
116
-
117
- isRecharging(now: Date): boolean {
118
- return schedule.isRecharging(this, now)
119
- }
120
-
121
- isLoading(now: Date): boolean {
122
- return schedule.isLoading(this, now)
123
- }
124
-
125
- isUnloading(now: Date): boolean {
126
- return schedule.isUnloading(this, now)
127
- }
128
-
129
- isGathering(now: Date): boolean {
130
- return schedule.isGathering(this, now)
131
- }
132
-
133
- get hasEngines(): boolean {
134
- return this.engines !== undefined
135
- }
136
-
137
- get hasGenerator(): boolean {
138
- return this.generator !== undefined
139
- }
140
-
141
- get hasGatherer(): boolean {
142
- return this.gatherer !== undefined
143
- }
144
-
145
- get hasWarp(): boolean {
146
- return this.warp !== undefined
147
- }
148
-
149
- project(): ProjectedEntity {
150
- return sharedProjectFromCurrentState(this)
151
- }
152
-
153
- projectAt(now: Date): ProjectedEntity {
154
- return sharedProjectFromCurrentStateAt(this, now)
155
- }
156
-
157
- get location(): Location {
158
- return Location.from(this.coordinates)
159
- }
160
-
161
- get totalCargoMass(): UInt64 {
162
- return this.inv.totalMass
163
- }
164
-
165
- get totalMass(): UInt64 {
166
- let mass = UInt64.from(this.hullmass ?? 0).adding(this.totalCargoMass)
167
- if (this.loaders) {
168
- mass = mass.adding(UInt64.from(this.loaders.mass).multiplying(this.loaders.quantity))
169
- }
170
- return mass
171
- }
172
-
173
- get maxCapacity(): UInt64 {
174
- return UInt64.from(this.capacity)
175
- }
176
-
177
- hasSpace(goodMass: UInt64, quantity: number): boolean {
178
- return this.totalMass.adding(goodMass.multiplying(quantity)).lte(this.maxCapacity)
179
- }
180
-
181
- get availableCapacity(): UInt64 {
182
- return this.totalMass.gte(this.maxCapacity)
183
- ? UInt64.from(0)
184
- : this.maxCapacity.subtracting(this.totalMass)
185
- }
186
-
187
- getCargoForItem(goodId: UInt64Type): EntityInventory | undefined {
188
- return this.inv.forItem(goodId)
189
- }
190
-
191
- get sellableCargo(): EntityInventory[] {
192
- return this.inv.sellable
193
- }
194
-
195
- get hasSellableCargo(): boolean {
196
- return this.inv.hasSellable
197
- }
198
-
199
- get sellableGoodsCount(): number {
200
- return this.inv.sellableCount
201
- }
202
-
203
- get isFull(): boolean {
204
- return this.totalMass.gte(this.maxCapacity)
205
- }
206
-
207
- get energyPercent(): number {
208
- if (!this.generator || this.energy === undefined) return 0
209
- return calcEnergyPercent(this as MovementEntity)
210
- }
211
-
212
- get needsRecharge(): boolean {
213
- if (!this.generator || this.energy === undefined) return false
214
- return calcNeedsRecharge(this as MovementEntity)
215
- }
216
-
217
- hasEnergyFor(distance: UInt64): boolean {
218
- if (!this.engines || !this.generator || this.energy === undefined) return false
219
- return hasEnergyForDistance(this as MovementEntity, distance)
220
- }
221
- }
@@ -1,136 +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 {InventoryAccessor} from './inventory-accessor'
7
- import type {EntityInventory} from './entity-inventory'
8
- import * as schedule from '../scheduling/schedule'
9
- import type {PackedModuleInput} from './ship'
10
- import {decodeCraftedItemStats} from '../derivation/crafting'
11
- import {getModuleCapabilityType, MODULE_LOADER} from '../capabilities/modules'
12
- import {computeLoaderCapabilities} from './ship-deploy'
13
- import {applySlotMultiplier, clampUint16, getSlotAmp, type InstalledModule} from './slot-multiplier'
14
- import type {EntitySlot} from '../data/recipes-runtime'
15
-
16
- export interface WarehouseStateInput {
17
- id: UInt64Type
18
- owner: string
19
- name: string
20
- coordinates: CoordinatesType | {x: number; y: number; z?: number}
21
- hullmass?: number
22
- capacity: number
23
- modules?: PackedModuleInput[]
24
- schedule?: ServerContract.Types.schedule
25
- cargo?: ServerContract.Types.cargo_item[]
26
- }
27
-
28
- export class Warehouse extends ServerContract.Types.entity_info {
29
- private _sched?: ScheduleAccessor
30
- private _inv?: InventoryAccessor
31
-
32
- get name(): string {
33
- return this.entity_name
34
- }
35
-
36
- get entityClass(): 'planetary' {
37
- return 'planetary'
38
- }
39
-
40
- get canDemolish(): boolean {
41
- return true
42
- }
43
-
44
- get inv(): InventoryAccessor {
45
- this._inv ??= new InventoryAccessor(this)
46
- return this._inv
47
- }
48
-
49
- get inventory(): EntityInventory[] {
50
- return this.inv.items
51
- }
52
-
53
- get sched(): ScheduleAccessor {
54
- this._sched ??= new ScheduleAccessor(this)
55
- return this._sched
56
- }
57
-
58
- get isIdle(): boolean {
59
- return this.is_idle
60
- }
61
-
62
- isLoading(now: Date): boolean {
63
- return schedule.isLoading(this, now)
64
- }
65
-
66
- isUnloading(now: Date): boolean {
67
- return schedule.isUnloading(this, now)
68
- }
69
-
70
- get location(): Location {
71
- return Location.from(this.coordinates)
72
- }
73
-
74
- get totalCargoMass(): UInt64 {
75
- return this.inv.totalMass
76
- }
77
-
78
- get maxCapacity(): UInt64 {
79
- return UInt64.from(this.capacity)
80
- }
81
-
82
- get availableCapacity(): UInt64 {
83
- const cargo = this.totalCargoMass
84
- return cargo.gte(this.maxCapacity) ? UInt64.from(0) : this.maxCapacity.subtracting(cargo)
85
- }
86
-
87
- hasSpace(goodMass: UInt64, quantity: number): boolean {
88
- return this.totalCargoMass.adding(goodMass.multiplying(quantity)).lte(this.maxCapacity)
89
- }
90
-
91
- get isFull(): boolean {
92
- return this.totalCargoMass.gte(this.maxCapacity)
93
- }
94
-
95
- getCargoForItem(goodId: UInt64Type): EntityInventory | undefined {
96
- return this.inv.forItem(goodId)
97
- }
98
-
99
- get orbitalAltitude(): number {
100
- return this.coordinates.z?.toNumber() || 0
101
- }
102
-
103
- get totalMass(): UInt64 {
104
- const hull = this.hullmass ? UInt64.from(this.hullmass) : UInt64.from(0)
105
- return hull.adding(this.totalCargoMass)
106
- }
107
- }
108
-
109
- export function computeWarehouseCapabilities(
110
- modules: InstalledModule[],
111
- layout: EntitySlot[]
112
- ): {
113
- loaders?: {mass: number; thrust: number; quantity: number}
114
- } {
115
- const warehouse: {loaders?: {mass: number; thrust: number; quantity: number}} = {}
116
-
117
- const loaderModules = modules.filter((m) => getModuleCapabilityType(m.itemId) === MODULE_LOADER)
118
- if (loaderModules.length > 0) {
119
- let totalMass = 0
120
- let totalThrust = 0
121
- let totalQuantity = 0
122
- for (const m of loaderModules) {
123
- const caps = computeLoaderCapabilities(decodeCraftedItemStats(m.itemId, m.stats))
124
- totalMass += caps.mass
125
- totalThrust += applySlotMultiplier(caps.thrust, getSlotAmp(layout, m.slotIndex))
126
- totalQuantity += caps.quantity
127
- }
128
- warehouse.loaders = {
129
- mass: totalMass,
130
- thrust: clampUint16(totalThrust),
131
- quantity: totalQuantity,
132
- }
133
- }
134
-
135
- return warehouse
136
- }