@shipload/sdk 2.0.0-rc1 → 2.0.0-rc11

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.
Files changed (74) hide show
  1. package/lib/shipload.d.ts +1701 -1183
  2. package/lib/shipload.js +6746 -3447
  3. package/lib/shipload.js.map +1 -1
  4. package/lib/shipload.m.js +6429 -3229
  5. package/lib/shipload.m.js.map +1 -1
  6. package/package.json +6 -6
  7. package/src/capabilities/crafting.ts +26 -0
  8. package/src/capabilities/gathering.ts +36 -0
  9. package/src/capabilities/guards.ts +38 -0
  10. package/src/capabilities/hauling.ts +22 -0
  11. package/src/capabilities/index.ts +8 -0
  12. package/src/capabilities/loading.ts +8 -0
  13. package/src/capabilities/modules.ts +57 -0
  14. package/src/capabilities/movement.ts +29 -0
  15. package/src/capabilities/storage.ts +72 -0
  16. package/src/contracts/server.ts +932 -314
  17. package/src/data/capabilities.ts +408 -0
  18. package/src/data/categories.ts +58 -0
  19. package/src/data/colors.ts +53 -0
  20. package/src/data/items.json +17 -0
  21. package/src/data/locations.ts +53 -0
  22. package/src/data/nebula-adjectives.json +211 -0
  23. package/src/data/nebula-nouns.json +151 -0
  24. package/src/data/recipes.ts +571 -0
  25. package/src/data/syllables.json +1386 -780
  26. package/src/data/tiers.ts +45 -0
  27. package/src/derivation/crafting.ts +197 -0
  28. package/src/derivation/index.ts +28 -0
  29. package/src/derivation/location-size.ts +15 -0
  30. package/src/derivation/resources.ts +142 -0
  31. package/src/derivation/stats.ts +146 -0
  32. package/src/derivation/stratum.ts +124 -0
  33. package/src/entities/cargo-utils.ts +46 -9
  34. package/src/entities/container.ts +106 -0
  35. package/src/entities/entity-inventory.ts +13 -13
  36. package/src/entities/inventory-accessor.ts +42 -0
  37. package/src/entities/location.ts +7 -188
  38. package/src/entities/makers.ts +72 -0
  39. package/src/entities/player.ts +1 -273
  40. package/src/entities/ship-deploy.ts +263 -0
  41. package/src/entities/ship.ts +93 -453
  42. package/src/entities/warehouse.ts +34 -148
  43. package/src/errors.ts +4 -4
  44. package/src/index-module.ts +226 -42
  45. package/src/managers/actions.ts +111 -79
  46. package/src/managers/context.ts +0 -9
  47. package/src/managers/entities.ts +22 -5
  48. package/src/managers/index.ts +0 -1
  49. package/src/managers/locations.ts +15 -79
  50. package/src/market/items.ts +30 -0
  51. package/src/nft/description.ts +175 -0
  52. package/src/nft/deserializers.ts +81 -0
  53. package/src/nft/index.ts +2 -0
  54. package/src/resolution/resolve-item.ts +313 -0
  55. package/src/scheduling/accessor.ts +82 -0
  56. package/src/scheduling/projection.ts +158 -54
  57. package/src/scheduling/schedule.ts +24 -0
  58. package/src/shipload.ts +0 -5
  59. package/src/travel/travel.ts +93 -19
  60. package/src/types/capabilities.ts +71 -0
  61. package/src/types/entity-traits.ts +69 -0
  62. package/src/types/entity.ts +39 -0
  63. package/src/types/index.ts +3 -0
  64. package/src/types.ts +76 -33
  65. package/src/utils/hash.ts +1 -1
  66. package/src/utils/system.ts +148 -11
  67. package/src/data/goods.json +0 -23
  68. package/src/managers/trades.ts +0 -119
  69. package/src/market/goods.ts +0 -31
  70. package/src/market/market.ts +0 -209
  71. package/src/market/rolls.ts +0 -8
  72. package/src/trading/collect.ts +0 -939
  73. package/src/trading/deal.ts +0 -208
  74. package/src/trading/trade.ts +0 -203
@@ -1,15 +1,18 @@
1
- import {UInt16, UInt32, UInt64} from '@wharfkit/antelope'
1
+ import {Name, UInt16, UInt32, UInt64} from '@wharfkit/antelope'
2
2
  import {ServerContract} from '../contracts'
3
3
  import {Coordinates, PRECISION, TaskType} from '../types'
4
+ import {
5
+ capsHasLoaders,
6
+ capsHasMovement,
7
+ capsHasStorage,
8
+ EntityCapabilities,
9
+ EntityState,
10
+ } from '../types/capabilities'
4
11
  import {distanceBetweenCoordinates, lerp} from '../travel/travel'
5
- import {getGood} from '../market/goods'
12
+ import {calcCargoItemMass, calcCargoMass} from '../capabilities/storage'
6
13
  import * as schedule from './schedule'
7
14
  import {ScheduleData} from './schedule'
8
15
 
9
- /**
10
- * Projected state of an entity after scheduled tasks complete.
11
- * Mirrors contract's projected_entity struct.
12
- */
13
16
  export interface ProjectedEntity {
14
17
  location: Coordinates
15
18
  energy: UInt16
@@ -19,41 +22,55 @@ export interface ProjectedEntity {
19
22
  engines?: ServerContract.Types.movement_stats
20
23
  loaders?: ServerContract.Types.loader_stats
21
24
  generator?: ServerContract.Types.energy_stats
25
+ hauler?: ServerContract.Types.hauler_stats
22
26
  readonly totalMass: UInt64
27
+
28
+ hasMovement(): boolean
29
+ hasStorage(): boolean
30
+ hasLoaders(): boolean
31
+
32
+ capabilities(): EntityCapabilities
33
+ state(): EntityState
23
34
  }
24
35
 
25
- /**
26
- * Interface for entities that can be projected.
27
- * Ships and Warehouses both implement this.
28
- */
29
36
  export interface Projectable extends ScheduleData {
30
- location: Coordinates
31
- energy: UInt16
32
- mass: UInt32
37
+ coordinates: Coordinates | ServerContract.Types.coordinates
38
+ energy?: UInt16
39
+ hullmass?: UInt32
33
40
  generator?: ServerContract.Types.energy_stats
34
41
  engines?: ServerContract.Types.movement_stats
35
42
  loaders?: ServerContract.Types.loader_stats
36
- capacity?: UInt64
37
- calcCargoMass(): UInt64
43
+ hauler?: ServerContract.Types.hauler_stats
44
+ capacity?: UInt32
45
+ cargo: ServerContract.Types.cargo_item[]
46
+ cargomass: UInt32
47
+ owner?: Name
48
+ }
49
+
50
+ function getHullMass(entity: Projectable): UInt32 {
51
+ return UInt32.from(entity.hullmass ?? 0)
38
52
  }
39
53
 
40
- /**
41
- * Create initial projected entity state from a projectable entity.
42
- */
43
54
  export function createProjectedEntity(entity: Projectable): ProjectedEntity {
44
- const cargoMass = entity.calcCargoMass()
45
- const shipMass = UInt32.from(entity.mass)
55
+ const cargoMass = calcCargoMass(entity)
56
+ const shipMass = getHullMass(entity)
46
57
  const loaders = entity.loaders
58
+ const engines = entity.engines
59
+ const generator = entity.generator
60
+ const hauler = entity.hauler
61
+ const capacity = entity.capacity
47
62
 
48
- return {
49
- location: Coordinates.from(entity.location),
50
- energy: UInt16.from(entity.energy),
63
+ const projected: ProjectedEntity = {
64
+ location: Coordinates.from(entity.coordinates),
65
+ energy: UInt16.from(entity.energy ?? 0),
51
66
  cargoMass,
52
67
  shipMass,
53
- capacity: entity.capacity,
54
- engines: entity.engines,
55
- generator: entity.generator,
68
+ capacity: capacity ? UInt64.from(capacity) : undefined,
69
+ engines,
70
+ generator,
71
+ hauler,
56
72
  loaders,
73
+
57
74
  get totalMass() {
58
75
  let mass = UInt64.from(this.shipMass).adding(this.cargoMass)
59
76
  if (this.loaders) {
@@ -61,12 +78,43 @@ export function createProjectedEntity(entity: Projectable): ProjectedEntity {
61
78
  }
62
79
  return mass
63
80
  },
81
+
82
+ hasMovement() {
83
+ return capsHasMovement(this.capabilities())
84
+ },
85
+
86
+ hasStorage() {
87
+ return capsHasStorage(this.capabilities())
88
+ },
89
+
90
+ hasLoaders() {
91
+ return capsHasLoaders(this.capabilities())
92
+ },
93
+
94
+ capabilities(): EntityCapabilities {
95
+ return {
96
+ hullmass: this.shipMass,
97
+ capacity: this.capacity ? UInt32.from(this.capacity) : undefined,
98
+ engines: this.engines,
99
+ generator: this.generator,
100
+ loaders: this.loaders,
101
+ }
102
+ },
103
+
104
+ state(): EntityState {
105
+ return {
106
+ owner: entity.owner ?? Name.from(''),
107
+ location: ServerContract.Types.coordinates.from(this.location),
108
+ energy: this.energy,
109
+ cargomass: UInt32.from(this.cargoMass),
110
+ cargo: entity.cargo,
111
+ }
112
+ },
64
113
  }
114
+
115
+ return projected
65
116
  }
66
117
 
67
- /**
68
- * Apply a recharge task to projected state.
69
- */
70
118
  function applyRechargeTask(
71
119
  projected: ProjectedEntity,
72
120
  _task: ServerContract.Types.task,
@@ -84,19 +132,16 @@ function applyRechargeTask(
84
132
  }
85
133
  }
86
134
 
87
- /**
88
- * Apply a flight task to projected state.
89
- */
90
135
  function applyFlightTask(
91
136
  projected: ProjectedEntity,
92
137
  task: ServerContract.Types.task,
93
138
  options: {complete: boolean; progress?: number}
94
139
  ): void {
95
- if (!task.location || !projected.engines) return
140
+ if (!task.coordinates || !projected.engines) return
96
141
 
97
142
  const origin = projected.location
98
- const destination = Coordinates.from(task.location)
99
- const distance = distanceBetweenCoordinates(origin, task.location)
143
+ const destination = Coordinates.from(task.coordinates)
144
+ const distance = distanceBetweenCoordinates(origin, task.coordinates)
100
145
  const energyUsage = distance.dividing(PRECISION).multiplying(projected.engines.drain)
101
146
 
102
147
  if (options.complete) {
@@ -117,33 +162,69 @@ function applyFlightTask(
117
162
  }
118
163
  }
119
164
 
120
- /**
121
- * Apply a load task to projected state.
122
- */
123
165
  function applyLoadTask(projected: ProjectedEntity, task: ServerContract.Types.task): void {
124
166
  for (const item of task.cargo) {
125
- const good = getGood(item.good_id)
126
- projected.cargoMass = projected.cargoMass.adding(good.mass.multiplying(item.quantity))
167
+ projected.cargoMass = projected.cargoMass.adding(calcCargoItemMass(item))
127
168
  }
128
169
  }
129
170
 
130
- /**
131
- * Apply an unload task to projected state.
132
- */
133
171
  function applyUnloadTask(projected: ProjectedEntity, task: ServerContract.Types.task): void {
134
172
  for (const item of task.cargo) {
135
- const good = getGood(item.good_id)
136
- const cargoMass = good.mass.multiplying(item.quantity)
173
+ const cargoMass = calcCargoItemMass(item)
137
174
  projected.cargoMass = projected.cargoMass.gt(cargoMass)
138
175
  ? projected.cargoMass.subtracting(cargoMass)
139
176
  : UInt64.from(0)
140
177
  }
141
178
  }
142
179
 
143
- /**
144
- * Project entity state after all scheduled tasks complete.
145
- * Mirrors contract's project_ship/project_warehouse methods.
146
- */
180
+ function applyEnergyCost(projected: ProjectedEntity, task: ServerContract.Types.task): void {
181
+ if (!task.energy_cost) return
182
+ const energyCost = UInt16.from(task.energy_cost)
183
+ projected.energy = projected.energy.gt(energyCost)
184
+ ? UInt16.from(projected.energy.subtracting(energyCost))
185
+ : UInt16.from(0)
186
+ }
187
+
188
+ function applyGatherTask(
189
+ projected: ProjectedEntity,
190
+ task: ServerContract.Types.task,
191
+ options: {complete: boolean}
192
+ ): void {
193
+ if (!options.complete) return
194
+
195
+ applyEnergyCost(projected, task)
196
+
197
+ for (const item of task.cargo) {
198
+ projected.cargoMass = projected.cargoMass.adding(calcCargoItemMass(item))
199
+ }
200
+ }
201
+
202
+ function applyCraftTask(projected: ProjectedEntity, task: ServerContract.Types.task): void {
203
+ applyEnergyCost(projected, task)
204
+
205
+ if (task.cargo.length > 0) {
206
+ for (let i = 0; i < task.cargo.length - 1; i++) {
207
+ const inputMass = calcCargoItemMass(task.cargo[i])
208
+ projected.cargoMass = projected.cargoMass.gt(inputMass)
209
+ ? projected.cargoMass.subtracting(inputMass)
210
+ : UInt64.from(0)
211
+ }
212
+ const output = task.cargo[task.cargo.length - 1]
213
+ projected.cargoMass = projected.cargoMass.adding(calcCargoItemMass(output))
214
+ }
215
+ }
216
+
217
+ function applyDeployTask(projected: ProjectedEntity, task: ServerContract.Types.task): void {
218
+ applyEnergyCost(projected, task)
219
+
220
+ if (task.cargo.length > 0) {
221
+ const mass = calcCargoItemMass(task.cargo[0])
222
+ projected.cargoMass = projected.cargoMass.gt(mass)
223
+ ? projected.cargoMass.subtracting(mass)
224
+ : UInt64.from(0)
225
+ }
226
+ }
227
+
147
228
  export function projectEntity(entity: Projectable): ProjectedEntity {
148
229
  const projected = createProjectedEntity(entity)
149
230
 
@@ -156,7 +237,7 @@ export function projectEntity(entity: Projectable): ProjectedEntity {
156
237
  case TaskType.RECHARGE:
157
238
  applyRechargeTask(projected, task, {complete: true})
158
239
  break
159
- case TaskType.FLIGHT:
240
+ case TaskType.TRAVEL:
160
241
  applyFlightTask(projected, task, {complete: true})
161
242
  break
162
243
  case TaskType.LOAD:
@@ -165,15 +246,22 @@ export function projectEntity(entity: Projectable): ProjectedEntity {
165
246
  case TaskType.UNLOAD:
166
247
  applyUnloadTask(projected, task)
167
248
  break
249
+ case TaskType.GATHER:
250
+ applyGatherTask(projected, task, {complete: true})
251
+ break
252
+ case TaskType.CRAFT:
253
+ applyCraftTask(projected, task)
254
+ break
255
+ case TaskType.DEPLOY:
256
+ case TaskType.DEPLOY_SHIP:
257
+ applyDeployTask(projected, task)
258
+ break
168
259
  }
169
260
  }
170
261
 
171
262
  return projected
172
263
  }
173
264
 
174
- /**
175
- * Project entity state at a specific time (partial task execution).
176
- */
177
265
  export function projectEntityAt(entity: Projectable, now: Date): ProjectedEntity {
178
266
  const projected = createProjectedEntity(entity)
179
267
 
@@ -198,7 +286,7 @@ export function projectEntityAt(entity: Projectable, now: Date): ProjectedEntity
198
286
  case TaskType.RECHARGE:
199
287
  applyRechargeTask(projected, task, {complete: taskComplete, progress})
200
288
  break
201
- case TaskType.FLIGHT:
289
+ case TaskType.TRAVEL:
202
290
  applyFlightTask(projected, task, {complete: taskComplete, progress})
203
291
  break
204
292
  case TaskType.LOAD:
@@ -211,6 +299,22 @@ export function projectEntityAt(entity: Projectable, now: Date): ProjectedEntity
211
299
  applyUnloadTask(projected, task)
212
300
  }
213
301
  break
302
+ case TaskType.GATHER:
303
+ if (taskComplete) {
304
+ applyGatherTask(projected, task, {complete: true})
305
+ }
306
+ break
307
+ case TaskType.CRAFT:
308
+ if (taskComplete) {
309
+ applyCraftTask(projected, task)
310
+ }
311
+ break
312
+ case TaskType.DEPLOY:
313
+ case TaskType.DEPLOY_SHIP:
314
+ if (taskComplete) {
315
+ applyDeployTask(projected, task)
316
+ }
317
+ break
214
318
  }
215
319
  }
216
320
 
@@ -153,3 +153,27 @@ export function scheduleProgress(entity: ScheduleData, now: Date): number {
153
153
  const elapsed = scheduleElapsed(entity, now)
154
154
  return Math.min(1, elapsed / duration)
155
155
  }
156
+
157
+ export function isTaskType(entity: ScheduleData, taskType: TaskType, now: Date): boolean {
158
+ return currentTaskType(entity, now) === taskType
159
+ }
160
+
161
+ export function isInFlight(entity: ScheduleData, now: Date): boolean {
162
+ return isTaskType(entity, TaskType.TRAVEL, now)
163
+ }
164
+
165
+ export function isRecharging(entity: ScheduleData, now: Date): boolean {
166
+ return isTaskType(entity, TaskType.RECHARGE, now)
167
+ }
168
+
169
+ export function isLoading(entity: ScheduleData, now: Date): boolean {
170
+ return isTaskType(entity, TaskType.LOAD, now)
171
+ }
172
+
173
+ export function isUnloading(entity: ScheduleData, now: Date): boolean {
174
+ return isTaskType(entity, TaskType.UNLOAD, now)
175
+ }
176
+
177
+ export function isGathering(entity: ScheduleData, now: Date): boolean {
178
+ return isTaskType(entity, TaskType.GATHER, now)
179
+ }
package/src/shipload.ts CHANGED
@@ -7,7 +7,6 @@ import {GameContext} from './managers/context'
7
7
  import {EntitiesManager} from './managers/entities'
8
8
  import {PlayersManager} from './managers/players'
9
9
  import {LocationsManager} from './managers/locations'
10
- import {TradesManager} from './managers/trades'
11
10
  import {EpochsManager} from './managers/epochs'
12
11
  import {ActionsManager} from './managers/actions'
13
12
  import {GameState} from './entities/gamestate'
@@ -94,10 +93,6 @@ export class Shipload {
94
93
  return this._context.locations
95
94
  }
96
95
 
97
- get trades(): TradesManager {
98
- return this._context.trades
99
- }
100
-
101
96
  get epochs(): EpochsManager {
102
97
  return this._context.epochs
103
98
  }
@@ -14,6 +14,7 @@ import {
14
14
  Checksum256,
15
15
  Int64,
16
16
  Int64Type,
17
+ UInt16,
17
18
  UInt32,
18
19
  UInt32Type,
19
20
  UInt64,
@@ -22,23 +23,24 @@ import {
22
23
 
23
24
  import {ServerContract} from '../contracts'
24
25
  import {
26
+ BASE_ORBITAL_MASS,
25
27
  CargoMassInfo,
26
28
  Distance,
27
- INITIAL_SHIP_MASS,
28
29
  MAX_ORBITAL_ALTITUDE,
29
30
  MIN_ORBITAL_ALTITUDE,
30
31
  PRECISION,
31
32
  ShipLike,
33
+ TaskType,
32
34
  } from '../types'
33
- import {getGood} from '../market/goods'
35
+ import {getItem} from '../market/items'
34
36
  import {hasSystem} from '../utils/system'
35
37
 
36
38
  export function calc_orbital_altitude(mass: number): number {
37
- if (mass <= INITIAL_SHIP_MASS) {
39
+ if (mass <= BASE_ORBITAL_MASS) {
38
40
  return MIN_ORBITAL_ALTITUDE
39
41
  }
40
42
 
41
- const ratio = mass / INITIAL_SHIP_MASS
43
+ const ratio = mass / BASE_ORBITAL_MASS
42
44
  const capRatio = 10.0
43
45
  let scale = Math.log(ratio) / Math.log(capRatio)
44
46
  scale = Math.min(scale, 1.0)
@@ -125,7 +127,12 @@ export function calc_rechargetime(
125
127
  }
126
128
 
127
129
  export function calc_ship_rechargetime(ship: ShipLike): UInt32 {
128
- return calc_rechargetime(ship.generator.capacity, ship.energy, ship.generator.recharge)
130
+ if (!ship.generator) return UInt32.from(0)
131
+ return calc_rechargetime(
132
+ ship.generator.capacity,
133
+ ship.energy ?? UInt16.from(0),
134
+ ship.generator.recharge
135
+ )
129
136
  }
130
137
 
131
138
  export function calc_flighttime(distance: UInt64Type, acceleration: number): UInt32 {
@@ -133,12 +140,14 @@ export function calc_flighttime(distance: UInt64Type, acceleration: number): UIn
133
140
  }
134
141
 
135
142
  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))
143
+ const z = altitude ?? ship.coordinates.z?.toNumber() ?? calc_orbital_altitude(Number(mass))
137
144
  return calc_flighttime(z, calc_loader_acceleration(ship, mass))
138
145
  }
139
146
 
140
147
  export function calc_loader_acceleration(ship: ShipLike, mass: UInt64): number {
141
- return calc_acceleration(Number(ship.loaders.thrust), Number(mass) + Number(ship.loaders.mass))
148
+ const thrust = ship.loaders ? Number(ship.loaders.thrust) : 0
149
+ const loaderMass = ship.loaders ? Number(ship.loaders.mass) : 0
150
+ return calc_acceleration(thrust, Number(mass) + loaderMass)
142
151
  }
143
152
 
144
153
  export function calc_ship_flighttime(ship: ShipLike, mass: UInt64, distance: UInt64): UInt32 {
@@ -147,7 +156,8 @@ export function calc_ship_flighttime(ship: ShipLike, mass: UInt64, distance: UIn
147
156
  }
148
157
 
149
158
  export function calc_ship_acceleration(ship: ShipLike, mass: UInt64): number {
150
- return calc_acceleration(Number(ship.engines.thrust), Number(mass))
159
+ const thrust = ship.engines ? Number(ship.engines.thrust) : 0
160
+ return calc_acceleration(thrust, Number(mass))
151
161
  }
152
162
 
153
163
  export function calc_acceleration(thrust: number, mass: number): number {
@@ -157,14 +167,14 @@ export function calc_acceleration(thrust: number, mass: number): number {
157
167
  export function calc_ship_mass(ship: ShipLike, cargos: CargoMassInfo[]): UInt64 {
158
168
  const mass = UInt64.from(0)
159
169
 
160
- mass.add(ship.mass)
170
+ mass.add(ship.hullmass)
161
171
 
162
- if (ship.loaders.quantity.gt(UInt32.zero)) {
172
+ if (ship.loaders && ship.loaders.quantity.gt(UInt32.zero)) {
163
173
  mass.add(ship.loaders.mass.multiplying(ship.loaders.quantity))
164
174
  }
165
175
 
166
176
  for (const cargo of cargos) {
167
- mass.add(getGood(cargo.good_id).mass.multiplying(cargo.quantity))
177
+ mass.add(getItem(cargo.item_id).mass.multiplying(cargo.quantity))
168
178
  }
169
179
 
170
180
  return mass
@@ -182,9 +192,9 @@ export function calculateTransferTime(
182
192
  let mass = UInt64.from(0)
183
193
 
184
194
  for (const cargo of cargos) {
185
- const qty = quantities?.get(Number(cargo.good_id)) ?? 0
195
+ const qty = quantities?.get(Number(cargo.item_id)) ?? 0
186
196
  if (qty > 0) {
187
- const good_mass = getGood(cargo.good_id).mass
197
+ const good_mass = getItem(cargo.item_id).mass
188
198
  const cargo_mass = good_mass.multiplying(qty)
189
199
  mass = UInt64.from(mass).adding(cargo_mass)
190
200
  }
@@ -194,6 +204,7 @@ export function calculateTransferTime(
194
204
  return UInt32.from(0)
195
205
  }
196
206
 
207
+ if (!ship.loaders) return UInt32.from(0)
197
208
  mass = UInt64.from(mass).adding(ship.loaders.mass)
198
209
  const transfer_time = calc_loader_flighttime(ship, mass)
199
210
  return transfer_time.dividing(ship.loaders.quantity)
@@ -230,12 +241,12 @@ export function calculateLoadTimeBreakdown(
230
241
  let mass_load = UInt64.from(0)
231
242
 
232
243
  for (const cargo of cargos) {
233
- const goodId = Number(cargo.good_id)
244
+ const goodId = Number(cargo.item_id)
234
245
  const loadQty = loadQuantities?.get(goodId) ?? 0
235
246
  const unloadQty = unloadQuantities?.get(goodId) ?? 0
236
247
 
237
248
  if (loadQty > 0 || unloadQty > 0) {
238
- const good = getGood(cargo.good_id)
249
+ const good = getItem(cargo.item_id)
239
250
 
240
251
  if (loadQty > 0) {
241
252
  const cargo_mass = good.mass.multiplying(loadQty)
@@ -251,17 +262,17 @@ export function calculateLoadTimeBreakdown(
251
262
  let unloadTime = 0
252
263
  let loadTime = 0
253
264
 
254
- if (mass_unload.gt(UInt64.zero)) {
265
+ if (mass_unload.gt(UInt64.zero) && ship.loaders) {
255
266
  const totalMass = UInt64.from(mass_unload).adding(ship.loaders.mass)
256
267
  unloadTime = Number(calc_loader_flighttime(ship, totalMass))
257
268
  }
258
269
 
259
- if (mass_load.gt(UInt64.zero)) {
270
+ if (mass_load.gt(UInt64.zero) && ship.loaders) {
260
271
  const totalMass = UInt64.from(mass_load).adding(ship.loaders.mass)
261
272
  loadTime = Number(calc_loader_flighttime(ship, totalMass))
262
273
  }
263
274
 
264
- const numLoaders = Number(ship.loaders.quantity)
275
+ const numLoaders = ship.loaders ? Number(ship.loaders.quantity) : 0
265
276
  const totalTime = numLoaders > 0 ? (unloadTime + loadTime) / numLoaders : 0
266
277
  const unloadTimePerLoader = numLoaders > 0 ? unloadTime / numLoaders : 0
267
278
  const loadTimePerLoader = numLoaders > 0 ? loadTime / numLoaders : 0
@@ -306,6 +317,7 @@ export function estimateTravelTime(
306
317
  if (
307
318
  loadMass &&
308
319
  UInt32.from(loadMass).gt(UInt32.zero) &&
320
+ ship.loaders &&
309
321
  ship.loaders.quantity.gt(UInt32.zero)
310
322
  ) {
311
323
  const totalMass = UInt64.from(loadMass).adding(ship.loaders.mass)
@@ -315,6 +327,7 @@ export function estimateTravelTime(
315
327
  if (
316
328
  unloadMass &&
317
329
  UInt32.from(unloadMass).gt(UInt32.zero) &&
330
+ ship.loaders &&
318
331
  ship.loaders.quantity.gt(UInt32.zero)
319
332
  ) {
320
333
  const totalMass = UInt64.from(unloadMass).adding(ship.loaders.mass)
@@ -345,8 +358,9 @@ export function estimateDealTravelTime(
345
358
  }
346
359
 
347
360
  export function hasEnergyForDistance(ship: ShipLike, distance: UInt64Type): boolean {
361
+ if (!ship.engines) return false
348
362
  const energyNeeded = UInt64.from(distance).dividing(PRECISION).multiplying(ship.engines.drain)
349
- return UInt64.from(ship.energy).gte(energyNeeded)
363
+ return UInt64.from(ship.energy ?? 0).gte(energyNeeded)
350
364
  }
351
365
 
352
366
  export interface TransferEntity {
@@ -358,6 +372,66 @@ export interface TransferEntity {
358
372
  }
359
373
  }
360
374
 
375
+ export interface HasScheduleAndLocation {
376
+ coordinates: ServerContract.ActionParams.Type.coordinates
377
+ schedule?: ServerContract.Types.schedule
378
+ }
379
+
380
+ export function getFlightOrigin(
381
+ entity: HasScheduleAndLocation,
382
+ flightTaskIndex: number
383
+ ): ServerContract.ActionParams.Type.coordinates {
384
+ if (!entity.schedule) return entity.coordinates
385
+
386
+ let origin = entity.coordinates
387
+ for (let i = 0; i < flightTaskIndex && i < entity.schedule.tasks.length; i++) {
388
+ const task = entity.schedule.tasks[i]
389
+ if (task.type.equals(TaskType.TRAVEL) && task.coordinates) {
390
+ origin = task.coordinates
391
+ }
392
+ }
393
+ return origin
394
+ }
395
+
396
+ export function getDestinationLocation(
397
+ entity: HasScheduleAndLocation
398
+ ): ServerContract.ActionParams.Type.coordinates | undefined {
399
+ if (!entity.schedule) return undefined
400
+
401
+ for (let i = entity.schedule.tasks.length - 1; i >= 0; i--) {
402
+ const task = entity.schedule.tasks[i]
403
+ if (task.type.equals(TaskType.TRAVEL) && task.coordinates) {
404
+ return task.coordinates
405
+ }
406
+ }
407
+ return undefined
408
+ }
409
+
410
+ export function getPositionAt(
411
+ entity: HasScheduleAndLocation,
412
+ taskIndex: number,
413
+ taskProgress: number
414
+ ): ServerContract.ActionParams.Type.coordinates {
415
+ if (!entity.schedule || entity.schedule.tasks.length === 0 || taskIndex < 0) {
416
+ return entity.coordinates
417
+ }
418
+
419
+ const task = entity.schedule.tasks[taskIndex]
420
+
421
+ if (!task.type.equals(TaskType.TRAVEL) || !task.coordinates) {
422
+ return getFlightOrigin(entity, taskIndex)
423
+ }
424
+
425
+ const origin = getFlightOrigin(entity, taskIndex)
426
+ const destination = task.coordinates
427
+
428
+ const interpolated = lerp(origin, destination, taskProgress)
429
+ return {
430
+ x: Math.round(interpolated.x),
431
+ y: Math.round(interpolated.y),
432
+ }
433
+ }
434
+
361
435
  export function calc_transfer_duration(
362
436
  source: TransferEntity,
363
437
  dest: TransferEntity,
@@ -0,0 +1,71 @@
1
+ import {Name, UInt16, UInt32} from '@wharfkit/antelope'
2
+ import {ServerContract} from '../contracts'
3
+
4
+ export interface MovementCapability {
5
+ engines: ServerContract.Types.movement_stats
6
+ generator: ServerContract.Types.energy_stats
7
+ }
8
+
9
+ export interface EnergyCapability {
10
+ energy: UInt16
11
+ }
12
+
13
+ export interface StorageCapability {
14
+ capacity: UInt32
15
+ cargomass: UInt32
16
+ cargo: ServerContract.Types.cargo_item[]
17
+ }
18
+
19
+ export interface LoaderCapability {
20
+ loaders: ServerContract.Types.loader_stats
21
+ }
22
+
23
+ export interface GathererCapability {
24
+ gatherer: ServerContract.Types.gatherer_stats
25
+ }
26
+
27
+ export interface MassCapability {
28
+ hullmass: UInt32
29
+ }
30
+
31
+ export interface ScheduleCapability {
32
+ schedule?: ServerContract.Types.schedule
33
+ }
34
+
35
+ export interface EntityCapabilities {
36
+ hullmass?: UInt32
37
+ capacity?: UInt32
38
+ engines?: ServerContract.Types.movement_stats
39
+ generator?: ServerContract.Types.energy_stats
40
+ loaders?: ServerContract.Types.loader_stats
41
+ gatherer?: ServerContract.Types.gatherer_stats
42
+ crafter?: ServerContract.Types.crafter_stats
43
+ }
44
+
45
+ export interface EntityState {
46
+ owner: Name
47
+ location: ServerContract.Types.coordinates
48
+ energy?: UInt16
49
+ cargomass: UInt32
50
+ cargo: ServerContract.Types.cargo_item[]
51
+ }
52
+
53
+ export function capsHasMovement(caps: EntityCapabilities): boolean {
54
+ return caps.engines !== undefined && caps.generator !== undefined
55
+ }
56
+
57
+ export function capsHasStorage(caps: EntityCapabilities): boolean {
58
+ return caps.capacity !== undefined
59
+ }
60
+
61
+ export function capsHasLoaders(caps: EntityCapabilities): boolean {
62
+ return caps.loaders !== undefined
63
+ }
64
+
65
+ export function capsHasGatherer(caps: EntityCapabilities): boolean {
66
+ return caps.gatherer !== undefined
67
+ }
68
+
69
+ export function capsHasMass(caps: EntityCapabilities): boolean {
70
+ return caps.hullmass !== undefined
71
+ }