@shipload/sdk 0.7.1 → 2.0.0-rc1
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 +1651 -226
- package/lib/shipload.js +4958 -1971
- package/lib/shipload.js.map +1 -1
- package/lib/shipload.m.js +4787 -1940
- package/lib/shipload.m.js.map +1 -1
- package/package.json +5 -4
- package/src/contracts/server.ts +585 -203
- package/src/data/goods.json +23 -0
- package/src/data/syllables.json +1184 -0
- package/src/entities/cargo-utils.ts +47 -0
- package/src/entities/entity-inventory.ts +39 -0
- package/src/entities/gamestate.ts +152 -0
- package/src/entities/location.ts +241 -0
- package/src/entities/player.ts +287 -0
- package/src/entities/ship.ts +559 -0
- package/src/entities/warehouse.ts +205 -0
- package/src/errors.ts +46 -9
- package/src/index-module.ts +119 -7
- package/src/managers/actions.ts +168 -0
- package/src/managers/base.ts +25 -0
- package/src/managers/context.ts +104 -0
- package/src/managers/entities.ts +86 -0
- package/src/managers/epochs.ts +47 -0
- package/src/managers/index.ts +9 -0
- package/src/managers/locations.ts +103 -0
- package/src/managers/players.ts +13 -0
- package/src/managers/trades.ts +119 -0
- package/src/market/goods.ts +31 -0
- package/src/{market.ts → market/market.ts} +32 -37
- package/src/{rolls.ts → market/rolls.ts} +3 -3
- package/src/{epoch.ts → scheduling/epoch.ts} +1 -1
- package/src/scheduling/projection.ts +218 -0
- package/src/scheduling/schedule.ts +155 -0
- package/src/shipload.ts +39 -157
- package/src/trading/collect.ts +939 -0
- package/src/trading/deal.ts +208 -0
- package/src/trading/trade.ts +203 -0
- package/src/travel/travel.ts +425 -0
- package/src/types.ts +60 -25
- package/src/utils/system.ts +27 -0
- package/src/goods.ts +0 -124
- package/src/ship.ts +0 -36
- package/src/state.ts +0 -0
- package/src/syllables.ts +0 -1184
- package/src/system.ts +0 -37
- package/src/travel.ts +0 -259
- /package/src/{hash.ts → utils/hash.ts} +0 -0
|
@@ -0,0 +1,425 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Travel calculations for ship movement, energy usage, and flight times.
|
|
3
|
+
*
|
|
4
|
+
* Functions prefixed with `calc_` are contract-parity functions that mirror
|
|
5
|
+
* the C++ implementation in the server contract (schedule.cpp, ship.cpp).
|
|
6
|
+
* These use snake_case intentionally to match the contract naming convention
|
|
7
|
+
* and signal that they must produce identical results to the on-chain code.
|
|
8
|
+
*
|
|
9
|
+
* Functions prefixed with `calculate` are higher-level SDK helpers that may
|
|
10
|
+
* combine multiple contract calculations for convenience.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import {
|
|
14
|
+
Checksum256,
|
|
15
|
+
Int64,
|
|
16
|
+
Int64Type,
|
|
17
|
+
UInt32,
|
|
18
|
+
UInt32Type,
|
|
19
|
+
UInt64,
|
|
20
|
+
UInt64Type,
|
|
21
|
+
} from '@wharfkit/antelope'
|
|
22
|
+
|
|
23
|
+
import {ServerContract} from '../contracts'
|
|
24
|
+
import {
|
|
25
|
+
CargoMassInfo,
|
|
26
|
+
Distance,
|
|
27
|
+
INITIAL_SHIP_MASS,
|
|
28
|
+
MAX_ORBITAL_ALTITUDE,
|
|
29
|
+
MIN_ORBITAL_ALTITUDE,
|
|
30
|
+
PRECISION,
|
|
31
|
+
ShipLike,
|
|
32
|
+
} from '../types'
|
|
33
|
+
import {getGood} from '../market/goods'
|
|
34
|
+
import {hasSystem} from '../utils/system'
|
|
35
|
+
|
|
36
|
+
export function calc_orbital_altitude(mass: number): number {
|
|
37
|
+
if (mass <= INITIAL_SHIP_MASS) {
|
|
38
|
+
return MIN_ORBITAL_ALTITUDE
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const ratio = mass / INITIAL_SHIP_MASS
|
|
42
|
+
const capRatio = 10.0
|
|
43
|
+
let scale = Math.log(ratio) / Math.log(capRatio)
|
|
44
|
+
scale = Math.min(scale, 1.0)
|
|
45
|
+
|
|
46
|
+
return MIN_ORBITAL_ALTITUDE + Math.floor((MAX_ORBITAL_ALTITUDE - MIN_ORBITAL_ALTITUDE) * scale)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function distanceBetweenCoordinates(
|
|
50
|
+
origin: ServerContract.ActionParams.Type.coordinates,
|
|
51
|
+
destination: ServerContract.ActionParams.Type.coordinates
|
|
52
|
+
): UInt64 {
|
|
53
|
+
return distanceBetweenPoints(origin.x, origin.y, destination.x, destination.y)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function distanceBetweenPoints(
|
|
57
|
+
x1: Int64Type,
|
|
58
|
+
y1: Int64Type,
|
|
59
|
+
x2: Int64Type,
|
|
60
|
+
y2: Int64Type
|
|
61
|
+
): UInt64 {
|
|
62
|
+
const x = Math.pow(x1 - x2, 2)
|
|
63
|
+
const y = Math.pow(y1 - y2, 2)
|
|
64
|
+
return UInt64.from(Math.sqrt(x + y) * PRECISION)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function lerp(
|
|
68
|
+
origin: ServerContract.ActionParams.Type.coordinates,
|
|
69
|
+
destination: ServerContract.ActionParams.Type.coordinates,
|
|
70
|
+
time: number
|
|
71
|
+
): ServerContract.ActionParams.Type.coordinates {
|
|
72
|
+
return {
|
|
73
|
+
x: (1 - time) * Number(origin.x) + time * Number(destination.x),
|
|
74
|
+
y: (1 - time) * Number(origin.y) + time * Number(destination.y),
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function rotation(
|
|
79
|
+
origin: ServerContract.ActionParams.Type.coordinates,
|
|
80
|
+
destination: ServerContract.ActionParams.Type.coordinates
|
|
81
|
+
) {
|
|
82
|
+
return Math.atan2(destination.y - origin.y, destination.x - origin.x) * (180 / Math.PI) + 90
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function findNearbyPlanets(
|
|
86
|
+
seed: Checksum256,
|
|
87
|
+
origin: ServerContract.ActionParams.Type.coordinates,
|
|
88
|
+
maxDistance: UInt64Type = 20 * PRECISION
|
|
89
|
+
): Distance[] {
|
|
90
|
+
const nearbySystems: Distance[] = []
|
|
91
|
+
|
|
92
|
+
const max = UInt64.from(maxDistance / PRECISION)
|
|
93
|
+
const xMin = Int64.from(origin.x).subtracting(max)
|
|
94
|
+
const xMax = Int64.from(origin.x).adding(max)
|
|
95
|
+
const yMin = Int64.from(origin.y).subtracting(max)
|
|
96
|
+
const yMax = Int64.from(origin.y).adding(max)
|
|
97
|
+
|
|
98
|
+
for (let x = Number(xMin); x <= Number(xMax); x++) {
|
|
99
|
+
for (let y = Number(yMin); y <= Number(yMax); y++) {
|
|
100
|
+
const samePlace = x === Number(origin.x) && y === Number(origin.y)
|
|
101
|
+
if (!samePlace) {
|
|
102
|
+
const distance = distanceBetweenPoints(origin.x, origin.y, x, y)
|
|
103
|
+
if (Number(distance) <= Number(maxDistance)) {
|
|
104
|
+
const system = hasSystem(seed, {x, y})
|
|
105
|
+
if (system) {
|
|
106
|
+
nearbySystems.push({origin, destination: {x, y}, distance})
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return nearbySystems
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export function calc_rechargetime(
|
|
117
|
+
capacity: UInt32Type,
|
|
118
|
+
energy: UInt32Type,
|
|
119
|
+
recharge: UInt32Type
|
|
120
|
+
): UInt32 {
|
|
121
|
+
const cap = UInt32.from(capacity)
|
|
122
|
+
const eng = UInt32.from(energy)
|
|
123
|
+
if (eng.gte(cap)) return UInt32.zero
|
|
124
|
+
return cap.subtracting(eng).dividing(recharge)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export function calc_ship_rechargetime(ship: ShipLike): UInt32 {
|
|
128
|
+
return calc_rechargetime(ship.generator.capacity, ship.energy, ship.generator.recharge)
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export function calc_flighttime(distance: UInt64Type, acceleration: number): UInt32 {
|
|
132
|
+
return UInt32.from(2 * Math.sqrt(Number(distance) / acceleration))
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export function calc_loader_flighttime(ship: ShipLike, mass: UInt64, altitude?: number): UInt32 {
|
|
136
|
+
const z = altitude ?? ship.location.z?.toNumber() ?? calc_orbital_altitude(Number(mass))
|
|
137
|
+
return calc_flighttime(z, calc_loader_acceleration(ship, mass))
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export function calc_loader_acceleration(ship: ShipLike, mass: UInt64): number {
|
|
141
|
+
return calc_acceleration(Number(ship.loaders.thrust), Number(mass) + Number(ship.loaders.mass))
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export function calc_ship_flighttime(ship: ShipLike, mass: UInt64, distance: UInt64): UInt32 {
|
|
145
|
+
const acceleration = calc_ship_acceleration(ship, mass)
|
|
146
|
+
return calc_flighttime(distance, acceleration)
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export function calc_ship_acceleration(ship: ShipLike, mass: UInt64): number {
|
|
150
|
+
return calc_acceleration(Number(ship.engines.thrust), Number(mass))
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export function calc_acceleration(thrust: number, mass: number): number {
|
|
154
|
+
return (thrust / mass) * PRECISION
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export function calc_ship_mass(ship: ShipLike, cargos: CargoMassInfo[]): UInt64 {
|
|
158
|
+
const mass = UInt64.from(0)
|
|
159
|
+
|
|
160
|
+
mass.add(ship.mass)
|
|
161
|
+
|
|
162
|
+
if (ship.loaders.quantity.gt(UInt32.zero)) {
|
|
163
|
+
mass.add(ship.loaders.mass.multiplying(ship.loaders.quantity))
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
for (const cargo of cargos) {
|
|
167
|
+
mass.add(getGood(cargo.good_id).mass.multiplying(cargo.quantity))
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return mass
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export function calc_energyusage(distance: UInt64Type, drain: UInt32Type): UInt32 {
|
|
174
|
+
return UInt64.from(distance).dividing(PRECISION).multiplying(drain)
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export function calculateTransferTime(
|
|
178
|
+
ship: ShipLike,
|
|
179
|
+
cargos: CargoMassInfo[],
|
|
180
|
+
quantities?: Map<number, number>
|
|
181
|
+
): UInt32 {
|
|
182
|
+
let mass = UInt64.from(0)
|
|
183
|
+
|
|
184
|
+
for (const cargo of cargos) {
|
|
185
|
+
const qty = quantities?.get(Number(cargo.good_id)) ?? 0
|
|
186
|
+
if (qty > 0) {
|
|
187
|
+
const good_mass = getGood(cargo.good_id).mass
|
|
188
|
+
const cargo_mass = good_mass.multiplying(qty)
|
|
189
|
+
mass = UInt64.from(mass).adding(cargo_mass)
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (mass.equals(UInt64.zero)) {
|
|
194
|
+
return UInt32.from(0)
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
mass = UInt64.from(mass).adding(ship.loaders.mass)
|
|
198
|
+
const transfer_time = calc_loader_flighttime(ship, mass)
|
|
199
|
+
return transfer_time.dividing(ship.loaders.quantity)
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
export function calculateRefuelingTime(ship: ShipLike): UInt32 {
|
|
203
|
+
return calc_ship_rechargetime(ship)
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
export function calculateFlightTime(
|
|
207
|
+
ship: ShipLike,
|
|
208
|
+
cargos: CargoMassInfo[],
|
|
209
|
+
distance: UInt64Type
|
|
210
|
+
): UInt32 {
|
|
211
|
+
const mass = calc_ship_mass(ship, cargos)
|
|
212
|
+
return calc_ship_flighttime(ship, mass, distance)
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
export interface LoadTimeBreakdown {
|
|
216
|
+
unloadTime: number
|
|
217
|
+
loadTime: number
|
|
218
|
+
totalTime: number
|
|
219
|
+
unloadMass: number
|
|
220
|
+
loadMass: number
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
export function calculateLoadTimeBreakdown(
|
|
224
|
+
ship: ShipLike,
|
|
225
|
+
cargos: CargoMassInfo[],
|
|
226
|
+
loadQuantities?: Map<number, number>,
|
|
227
|
+
unloadQuantities?: Map<number, number>
|
|
228
|
+
): LoadTimeBreakdown {
|
|
229
|
+
let mass_unload = UInt64.from(0)
|
|
230
|
+
let mass_load = UInt64.from(0)
|
|
231
|
+
|
|
232
|
+
for (const cargo of cargos) {
|
|
233
|
+
const goodId = Number(cargo.good_id)
|
|
234
|
+
const loadQty = loadQuantities?.get(goodId) ?? 0
|
|
235
|
+
const unloadQty = unloadQuantities?.get(goodId) ?? 0
|
|
236
|
+
|
|
237
|
+
if (loadQty > 0 || unloadQty > 0) {
|
|
238
|
+
const good = getGood(cargo.good_id)
|
|
239
|
+
|
|
240
|
+
if (loadQty > 0) {
|
|
241
|
+
const cargo_mass = good.mass.multiplying(loadQty)
|
|
242
|
+
mass_load = UInt64.from(mass_load).adding(cargo_mass)
|
|
243
|
+
}
|
|
244
|
+
if (unloadQty > 0) {
|
|
245
|
+
const cargo_mass = good.mass.multiplying(unloadQty)
|
|
246
|
+
mass_unload = UInt64.from(mass_unload).adding(cargo_mass)
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
let unloadTime = 0
|
|
252
|
+
let loadTime = 0
|
|
253
|
+
|
|
254
|
+
if (mass_unload.gt(UInt64.zero)) {
|
|
255
|
+
const totalMass = UInt64.from(mass_unload).adding(ship.loaders.mass)
|
|
256
|
+
unloadTime = Number(calc_loader_flighttime(ship, totalMass))
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
if (mass_load.gt(UInt64.zero)) {
|
|
260
|
+
const totalMass = UInt64.from(mass_load).adding(ship.loaders.mass)
|
|
261
|
+
loadTime = Number(calc_loader_flighttime(ship, totalMass))
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
const numLoaders = Number(ship.loaders.quantity)
|
|
265
|
+
const totalTime = numLoaders > 0 ? (unloadTime + loadTime) / numLoaders : 0
|
|
266
|
+
const unloadTimePerLoader = numLoaders > 0 ? unloadTime / numLoaders : 0
|
|
267
|
+
const loadTimePerLoader = numLoaders > 0 ? loadTime / numLoaders : 0
|
|
268
|
+
|
|
269
|
+
return {
|
|
270
|
+
unloadTime: unloadTimePerLoader,
|
|
271
|
+
loadTime: loadTimePerLoader,
|
|
272
|
+
totalTime,
|
|
273
|
+
unloadMass: Number(mass_unload),
|
|
274
|
+
loadMass: Number(mass_load),
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
export interface EstimatedTravelTime {
|
|
279
|
+
flightTime: UInt32
|
|
280
|
+
rechargeTime: UInt32
|
|
281
|
+
loadTime: UInt32
|
|
282
|
+
unloadTime: UInt32
|
|
283
|
+
total: UInt32
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
export interface EstimateTravelTimeOptions {
|
|
287
|
+
needsRecharge?: boolean
|
|
288
|
+
loadMass?: UInt32Type
|
|
289
|
+
unloadMass?: UInt32Type
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
export function estimateTravelTime(
|
|
293
|
+
ship: ShipLike,
|
|
294
|
+
travelMass: UInt64Type,
|
|
295
|
+
distance: UInt64Type,
|
|
296
|
+
options: EstimateTravelTimeOptions = {}
|
|
297
|
+
): EstimatedTravelTime {
|
|
298
|
+
const {needsRecharge = false, loadMass, unloadMass} = options
|
|
299
|
+
|
|
300
|
+
const flightTime = calc_ship_flighttime(ship, UInt64.from(travelMass), UInt64.from(distance))
|
|
301
|
+
const rechargeTime = needsRecharge ? calc_ship_rechargetime(ship) : UInt32.zero
|
|
302
|
+
|
|
303
|
+
let loadTime = UInt32.zero
|
|
304
|
+
let unloadTime = UInt32.zero
|
|
305
|
+
|
|
306
|
+
if (
|
|
307
|
+
loadMass &&
|
|
308
|
+
UInt32.from(loadMass).gt(UInt32.zero) &&
|
|
309
|
+
ship.loaders.quantity.gt(UInt32.zero)
|
|
310
|
+
) {
|
|
311
|
+
const totalMass = UInt64.from(loadMass).adding(ship.loaders.mass)
|
|
312
|
+
loadTime = calc_loader_flighttime(ship, totalMass).dividing(ship.loaders.quantity)
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
if (
|
|
316
|
+
unloadMass &&
|
|
317
|
+
UInt32.from(unloadMass).gt(UInt32.zero) &&
|
|
318
|
+
ship.loaders.quantity.gt(UInt32.zero)
|
|
319
|
+
) {
|
|
320
|
+
const totalMass = UInt64.from(unloadMass).adding(ship.loaders.mass)
|
|
321
|
+
unloadTime = calc_loader_flighttime(ship, totalMass).dividing(ship.loaders.quantity)
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
return {
|
|
325
|
+
flightTime,
|
|
326
|
+
rechargeTime,
|
|
327
|
+
loadTime,
|
|
328
|
+
unloadTime,
|
|
329
|
+
total: flightTime.adding(rechargeTime).adding(loadTime).adding(unloadTime),
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
export function estimateDealTravelTime(
|
|
334
|
+
ship: ShipLike,
|
|
335
|
+
shipMass: UInt64Type,
|
|
336
|
+
distance: UInt64Type,
|
|
337
|
+
loadMass: UInt32Type
|
|
338
|
+
): UInt32 {
|
|
339
|
+
const needsRecharge = !hasEnergyForDistance(ship, distance)
|
|
340
|
+
const estimate = estimateTravelTime(ship, shipMass, distance, {
|
|
341
|
+
needsRecharge,
|
|
342
|
+
loadMass,
|
|
343
|
+
})
|
|
344
|
+
return estimate.total
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
export function hasEnergyForDistance(ship: ShipLike, distance: UInt64Type): boolean {
|
|
348
|
+
const energyNeeded = UInt64.from(distance).dividing(PRECISION).multiplying(ship.engines.drain)
|
|
349
|
+
return UInt64.from(ship.energy).gte(energyNeeded)
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
export interface TransferEntity {
|
|
353
|
+
location: {z?: {toNumber(): number} | number}
|
|
354
|
+
loaders?: {
|
|
355
|
+
thrust: {toNumber(): number} | number
|
|
356
|
+
mass: {toNumber(): number} | number
|
|
357
|
+
quantity: {toNumber(): number} | number
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
export function calc_transfer_duration(
|
|
362
|
+
source: TransferEntity,
|
|
363
|
+
dest: TransferEntity,
|
|
364
|
+
cargoMass: number
|
|
365
|
+
): number {
|
|
366
|
+
if (cargoMass === 0) {
|
|
367
|
+
return 0
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
let totalThrust = 0
|
|
371
|
+
let totalLoaderMass = 0
|
|
372
|
+
let totalQuantity = 0
|
|
373
|
+
|
|
374
|
+
if (source.loaders) {
|
|
375
|
+
const thrust =
|
|
376
|
+
typeof source.loaders.thrust === 'number'
|
|
377
|
+
? source.loaders.thrust
|
|
378
|
+
: source.loaders.thrust.toNumber()
|
|
379
|
+
const mass =
|
|
380
|
+
typeof source.loaders.mass === 'number'
|
|
381
|
+
? source.loaders.mass
|
|
382
|
+
: source.loaders.mass.toNumber()
|
|
383
|
+
const qty =
|
|
384
|
+
typeof source.loaders.quantity === 'number'
|
|
385
|
+
? source.loaders.quantity
|
|
386
|
+
: source.loaders.quantity.toNumber()
|
|
387
|
+
totalThrust += thrust * qty
|
|
388
|
+
totalLoaderMass += mass * qty
|
|
389
|
+
totalQuantity += qty
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
if (dest.loaders) {
|
|
393
|
+
const thrust =
|
|
394
|
+
typeof dest.loaders.thrust === 'number'
|
|
395
|
+
? dest.loaders.thrust
|
|
396
|
+
: dest.loaders.thrust.toNumber()
|
|
397
|
+
const mass =
|
|
398
|
+
typeof dest.loaders.mass === 'number' ? dest.loaders.mass : dest.loaders.mass.toNumber()
|
|
399
|
+
const qty =
|
|
400
|
+
typeof dest.loaders.quantity === 'number'
|
|
401
|
+
? dest.loaders.quantity
|
|
402
|
+
: dest.loaders.quantity.toNumber()
|
|
403
|
+
totalThrust += thrust * qty
|
|
404
|
+
totalLoaderMass += mass * qty
|
|
405
|
+
totalQuantity += qty
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
if (totalThrust === 0 || totalQuantity === 0) {
|
|
409
|
+
return 0
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
const sourceZ =
|
|
413
|
+
typeof source.location.z === 'number'
|
|
414
|
+
? source.location.z
|
|
415
|
+
: source.location.z?.toNumber() ?? 0
|
|
416
|
+
const destZ =
|
|
417
|
+
typeof dest.location.z === 'number' ? dest.location.z : dest.location.z?.toNumber() ?? 0
|
|
418
|
+
const distance = Math.abs(sourceZ - destZ)
|
|
419
|
+
|
|
420
|
+
const totalMass = cargoMass + totalLoaderMass
|
|
421
|
+
const acceleration = calc_acceleration(totalThrust, totalMass)
|
|
422
|
+
const flightTime = 2 * Math.sqrt(distance / acceleration)
|
|
423
|
+
|
|
424
|
+
return Math.floor(flightTime / totalQuantity)
|
|
425
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -1,16 +1,61 @@
|
|
|
1
|
-
import {Struct, UInt16, UInt16Type,
|
|
1
|
+
import {Int64Type, Name, Struct, UInt16, UInt16Type, UInt32, UInt32Type} from '@wharfkit/antelope'
|
|
2
2
|
import {ServerContract} from './contracts'
|
|
3
3
|
|
|
4
4
|
export const PRECISION = 10000
|
|
5
|
-
export const TRAVEL_MAXMASS_PENALTY = 5 // Penalty (in seconds) for exceeding the maximum mass per 1000 unit
|
|
6
5
|
|
|
7
|
-
export
|
|
8
|
-
|
|
6
|
+
export const INITIAL_SHIP_MASS = 500000
|
|
7
|
+
export const MIN_ORBITAL_ALTITUDE = 800
|
|
8
|
+
export const MAX_ORBITAL_ALTITUDE = 3000
|
|
9
|
+
|
|
10
|
+
export interface ShipLike {
|
|
11
|
+
location: ServerContract.Types.coordinates
|
|
12
|
+
mass: UInt32
|
|
13
|
+
energy: UInt16
|
|
14
|
+
engines: ServerContract.Types.movement_stats
|
|
15
|
+
generator: ServerContract.Types.energy_stats
|
|
16
|
+
loaders: ServerContract.Types.loader_stats
|
|
17
|
+
capacity: UInt32
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface CargoMassInfo {
|
|
21
|
+
good_id: UInt16Type
|
|
22
|
+
quantity: UInt32Type
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export enum TaskType {
|
|
26
|
+
RECHARGE = 0,
|
|
27
|
+
LOAD = 1,
|
|
28
|
+
UNLOAD = 2,
|
|
29
|
+
FLIGHT = 3,
|
|
9
30
|
}
|
|
10
31
|
|
|
11
|
-
export
|
|
12
|
-
|
|
13
|
-
|
|
32
|
+
export enum TaskCancelable {
|
|
33
|
+
NEVER = 0, // Task cannot be cancelled
|
|
34
|
+
BEFORE_START = 1, // Task can only be cancelled before it starts
|
|
35
|
+
ALWAYS = 2, // Task can always be cancelled
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export const EntityType = {
|
|
39
|
+
SHIP: Name.from('ship'),
|
|
40
|
+
WAREHOUSE: Name.from('warehouse'),
|
|
41
|
+
} as const
|
|
42
|
+
|
|
43
|
+
export type EntityTypeName = (typeof EntityType)[keyof typeof EntityType]
|
|
44
|
+
|
|
45
|
+
export type CoordinatesType =
|
|
46
|
+
| Coordinates
|
|
47
|
+
| ServerContract.Types.coordinates
|
|
48
|
+
| {x: Int64Type; y: Int64Type}
|
|
49
|
+
|
|
50
|
+
export class Coordinates extends ServerContract.Types.coordinates {
|
|
51
|
+
static from(value: CoordinatesType): Coordinates {
|
|
52
|
+
return super.from(value) as Coordinates
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
equals(other: CoordinatesType): boolean {
|
|
56
|
+
const coords = Coordinates.from(other)
|
|
57
|
+
return this.x.equals(coords.x) && this.y.equals(coords.y)
|
|
58
|
+
}
|
|
14
59
|
}
|
|
15
60
|
|
|
16
61
|
export interface Distance {
|
|
@@ -27,18 +72,10 @@ export class Good extends Struct {
|
|
|
27
72
|
name!: string
|
|
28
73
|
@Struct.field('string')
|
|
29
74
|
description!: string
|
|
30
|
-
@Struct.field(
|
|
31
|
-
base_price!:
|
|
32
|
-
@Struct.field(
|
|
33
|
-
mass!:
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export interface GoodType {
|
|
37
|
-
id: UInt16Type
|
|
38
|
-
name: string
|
|
39
|
-
description: string
|
|
40
|
-
base_price: UInt64Type
|
|
41
|
-
mass: UInt64Type
|
|
75
|
+
@Struct.field(UInt32)
|
|
76
|
+
base_price!: UInt32
|
|
77
|
+
@Struct.field(UInt32)
|
|
78
|
+
mass!: UInt32
|
|
42
79
|
}
|
|
43
80
|
|
|
44
81
|
@Struct.type('GoodPrice')
|
|
@@ -47,10 +84,8 @@ export class GoodPrice extends Struct {
|
|
|
47
84
|
id!: UInt16
|
|
48
85
|
@Struct.field(Good)
|
|
49
86
|
good!: Good
|
|
50
|
-
@Struct.field(
|
|
51
|
-
price!:
|
|
52
|
-
@Struct.field(
|
|
53
|
-
supply!:
|
|
87
|
+
@Struct.field(UInt32)
|
|
88
|
+
price!: UInt32
|
|
89
|
+
@Struct.field(UInt16)
|
|
90
|
+
supply!: UInt16
|
|
54
91
|
}
|
|
55
|
-
|
|
56
|
-
export interface Coordinates extends ServerContract.ActionParams.Type.coordinates {}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import {Checksum256, Checksum256Type} from '@wharfkit/antelope'
|
|
2
|
+
import {hash512} from './hash'
|
|
3
|
+
import {CoordinatesType} from '../types'
|
|
4
|
+
import syllables from '../data/syllables.json'
|
|
5
|
+
|
|
6
|
+
export function getSystemName(gameSeed: Checksum256Type, location: CoordinatesType): string {
|
|
7
|
+
const seed = Checksum256.from(gameSeed)
|
|
8
|
+
if (!hasSystem(seed, location)) {
|
|
9
|
+
throw new Error("System doesn't exist at location")
|
|
10
|
+
}
|
|
11
|
+
const seedStr = `${location.x}${location.y}systemName`
|
|
12
|
+
const hashResult = hash512(seed, seedStr)
|
|
13
|
+
const syllableCount = 1 + (hashResult.array[0] % 3)
|
|
14
|
+
const name: string[] = []
|
|
15
|
+
for (let i = 0; i < syllableCount; i++) {
|
|
16
|
+
const index = hashResult.array[i] % syllables.length
|
|
17
|
+
const syllable = syllables[index]
|
|
18
|
+
name.push(i > 0 ? syllable.toLowerCase() : syllable)
|
|
19
|
+
}
|
|
20
|
+
return name.join('')
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function hasSystem(gameSeed: Checksum256Type, coordinates: CoordinatesType): boolean {
|
|
24
|
+
const seed = Checksum256.from(gameSeed)
|
|
25
|
+
const str = ['system', coordinates.x, coordinates.y].join('-')
|
|
26
|
+
return String(hash512(seed, str)).slice(0, 2) === '00'
|
|
27
|
+
}
|
package/src/goods.ts
DELETED
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
import {UInt16, UInt16Type, UInt64} from '@wharfkit/antelope'
|
|
2
|
-
import {Coordinates, Good, GoodType, PRECISION} from './types'
|
|
3
|
-
|
|
4
|
-
// List of goods with titles and descriptions
|
|
5
|
-
const goods: GoodType[] = [
|
|
6
|
-
{
|
|
7
|
-
id: 1,
|
|
8
|
-
name: 'FizzGlo',
|
|
9
|
-
description: 'Pops with flavor! A neon drink that makes your burps glow.',
|
|
10
|
-
base_price: 50,
|
|
11
|
-
mass: 35_000,
|
|
12
|
-
},
|
|
13
|
-
// {
|
|
14
|
-
// id: 2,
|
|
15
|
-
// name: 'ZapSnacks',
|
|
16
|
-
// description: 'Electric taste! Spicy edible energy sparks for a tongue-tingling experience.',
|
|
17
|
-
// base_price: 0,
|
|
18
|
-
// mass: 0,
|
|
19
|
-
// },
|
|
20
|
-
{
|
|
21
|
-
id: 3,
|
|
22
|
-
name: 'Blob Buddies',
|
|
23
|
-
description: 'Squishy friends! Clingy, cute and mood-matching pet blobs for every home!',
|
|
24
|
-
base_price: 95,
|
|
25
|
-
mass: 60_000,
|
|
26
|
-
},
|
|
27
|
-
{
|
|
28
|
-
id: 4,
|
|
29
|
-
name: 'TuneTooth',
|
|
30
|
-
description: 'Whistle while you eat! Edible instrument treats that play tunes when chewed.',
|
|
31
|
-
base_price: 145,
|
|
32
|
-
mass: 75_000,
|
|
33
|
-
},
|
|
34
|
-
{
|
|
35
|
-
id: 5,
|
|
36
|
-
name: 'SunPods',
|
|
37
|
-
description: 'Miniature suns in your pocket providing on-demand light & warmth.',
|
|
38
|
-
base_price: 295,
|
|
39
|
-
mass: 135_000,
|
|
40
|
-
},
|
|
41
|
-
// {
|
|
42
|
-
// id: 6,
|
|
43
|
-
// name: 'Fuzzix',
|
|
44
|
-
// description: 'Pocket-sized quantum fluff generator for instant comfy.',
|
|
45
|
-
// base_price: 0,
|
|
46
|
-
// mass: 0,
|
|
47
|
-
// },
|
|
48
|
-
{
|
|
49
|
-
id: 7,
|
|
50
|
-
name: 'GlowGo',
|
|
51
|
-
description: 'Ingestible bioluminescent jelly, your inside glows in the dark!',
|
|
52
|
-
base_price: 650,
|
|
53
|
-
mass: 255_000,
|
|
54
|
-
},
|
|
55
|
-
// {
|
|
56
|
-
// id: 8,
|
|
57
|
-
// name: 'KrackleKaps',
|
|
58
|
-
// description: 'Capsules packed with tiny firecrackers, spice up meals and parties.',
|
|
59
|
-
// base_price: 0,
|
|
60
|
-
// mass: 0,
|
|
61
|
-
// },
|
|
62
|
-
{
|
|
63
|
-
id: 9,
|
|
64
|
-
name: 'PlasmaMints',
|
|
65
|
-
description: 'Hypercharged candy giving plasma breath capable of cutting through steel.',
|
|
66
|
-
base_price: 3450,
|
|
67
|
-
mass: 1_100_000,
|
|
68
|
-
},
|
|
69
|
-
{
|
|
70
|
-
id: 10,
|
|
71
|
-
name: 'TimeTreats',
|
|
72
|
-
description: 'Confectionery morsels releasing slow-mo effect over a limited period.',
|
|
73
|
-
base_price: 8500,
|
|
74
|
-
mass: 2_100_000,
|
|
75
|
-
},
|
|
76
|
-
{
|
|
77
|
-
id: 11,
|
|
78
|
-
name: 'QuantumQuencher',
|
|
79
|
-
description:
|
|
80
|
-
'Bottled hyper-fluid quenching thirst across multiple parallel realities simultaneously.',
|
|
81
|
-
base_price: 20_500,
|
|
82
|
-
mass: 4_100_000,
|
|
83
|
-
},
|
|
84
|
-
// {
|
|
85
|
-
// id: 12,
|
|
86
|
-
// name: 'TransmatterTruffles',
|
|
87
|
-
// description: 'Delectable chocolates instantly teleporting consumers short distances.',
|
|
88
|
-
// base_price: 0,
|
|
89
|
-
// mass: 0,
|
|
90
|
-
// },
|
|
91
|
-
{
|
|
92
|
-
id: 13,
|
|
93
|
-
name: 'MemoryGum',
|
|
94
|
-
description: 'Chewable gum storing or replaying memories while being chewed.',
|
|
95
|
-
base_price: 52_500,
|
|
96
|
-
mass: 9_500_000,
|
|
97
|
-
},
|
|
98
|
-
{
|
|
99
|
-
id: 14,
|
|
100
|
-
name: 'SymbioSnack',
|
|
101
|
-
description: 'Edible alien larvae adopting owner’s taste preference upon consumption.',
|
|
102
|
-
base_price: 115_000,
|
|
103
|
-
mass: 16_000_000,
|
|
104
|
-
},
|
|
105
|
-
]
|
|
106
|
-
|
|
107
|
-
export const goodIds = goods.map((g) => g.id)
|
|
108
|
-
|
|
109
|
-
export function getGood(good_id: UInt16Type): Good {
|
|
110
|
-
const good = goods.find((g) => UInt16.from(good_id).equals(g.id))
|
|
111
|
-
if (!good) {
|
|
112
|
-
throw new Error('Good does not exist')
|
|
113
|
-
}
|
|
114
|
-
return Good.from({
|
|
115
|
-
...good,
|
|
116
|
-
id: UInt16.from(good.id),
|
|
117
|
-
base_price: UInt64.from(good.base_price),
|
|
118
|
-
mass: UInt64.from(good.mass).multiplying(PRECISION),
|
|
119
|
-
})
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
export function getGoods(): Good[] {
|
|
123
|
-
return goods.map((g) => getGood(g.id))
|
|
124
|
-
}
|