@shipload/sdk 2.0.0-rc5 → 2.0.0-rc7

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 (52) hide show
  1. package/README.md +1 -349
  2. package/lib/shipload.d.ts +607 -1113
  3. package/lib/shipload.js +1482 -2077
  4. package/lib/shipload.js.map +1 -1
  5. package/lib/shipload.m.js +1421 -2038
  6. package/lib/shipload.m.js.map +1 -1
  7. package/package.json +1 -1
  8. package/src/capabilities/crafting.ts +28 -0
  9. package/src/capabilities/extraction.ts +14 -8
  10. package/src/capabilities/guards.ts +0 -5
  11. package/src/capabilities/index.ts +2 -0
  12. package/src/capabilities/modules.ts +49 -0
  13. package/src/capabilities/storage.ts +0 -8
  14. package/src/contracts/server.ts +231 -313
  15. package/src/data/colors.ts +28 -0
  16. package/src/data/items.json +15 -15
  17. package/src/data/recipes.ts +351 -0
  18. package/src/derivation/crafting.ts +142 -0
  19. package/src/derivation/index.ts +1 -0
  20. package/src/derivation/stats.ts +91 -15
  21. package/src/derivation/stratum.ts +2 -2
  22. package/src/entities/cargo-utils.ts +6 -64
  23. package/src/entities/container.ts +18 -0
  24. package/src/entities/entity-inventory.ts +0 -4
  25. package/src/entities/inventory-accessor.ts +0 -4
  26. package/src/entities/location.ts +2 -197
  27. package/src/entities/makers.ts +10 -9
  28. package/src/entities/player.ts +1 -274
  29. package/src/entities/ship-deploy.ts +89 -0
  30. package/src/entities/ship.ts +14 -27
  31. package/src/entities/warehouse.ts +0 -4
  32. package/src/index-module.ts +66 -41
  33. package/src/managers/actions.ts +77 -88
  34. package/src/managers/context.ts +0 -9
  35. package/src/managers/index.ts +0 -1
  36. package/src/managers/locations.ts +2 -85
  37. package/src/market/items.ts +0 -1
  38. package/src/resolution/resolve-item.ts +242 -0
  39. package/src/scheduling/projection.ts +0 -10
  40. package/src/shipload.ts +0 -5
  41. package/src/travel/travel.ts +3 -3
  42. package/src/types/capabilities.ts +1 -9
  43. package/src/types/entity-traits.ts +3 -4
  44. package/src/types/entity.ts +3 -4
  45. package/src/types.ts +6 -43
  46. package/src/utils/system.ts +5 -4
  47. package/src/managers/trades.ts +0 -119
  48. package/src/market/market.ts +0 -195
  49. package/src/market/rolls.ts +0 -8
  50. package/src/trading/collect.ts +0 -938
  51. package/src/trading/deal.ts +0 -207
  52. package/src/trading/trade.ts +0 -203
@@ -9,33 +9,109 @@ export interface StatDefinition {
9
9
  }
10
10
 
11
11
  const METAL_STATS: StatDefinition[] = [
12
- {key: 'strength', label: 'Strength', abbreviation: 'STR', purpose: 'Raw structural/mechanical force'},
13
- {key: 'tolerance', label: 'Tolerance', abbreviation: 'TOL', purpose: 'Ability to withstand heat, pressure, and stress extremes'},
14
- {key: 'density', label: 'Density', abbreviation: 'DEN', purpose: 'Mass per unit', inverted: true},
12
+ {
13
+ key: 'strength',
14
+ label: 'Strength',
15
+ abbreviation: 'STR',
16
+ purpose: 'Raw structural/mechanical force',
17
+ },
18
+ {
19
+ key: 'tolerance',
20
+ label: 'Tolerance',
21
+ abbreviation: 'TOL',
22
+ purpose: 'Ability to withstand heat, pressure, and stress extremes',
23
+ },
24
+ {
25
+ key: 'density',
26
+ label: 'Density',
27
+ abbreviation: 'DEN',
28
+ purpose: 'Mass per unit',
29
+ inverted: true,
30
+ },
15
31
  ]
16
32
 
17
33
  const PRECIOUS_STATS: StatDefinition[] = [
18
- {key: 'conductivity', label: 'Conductivity', abbreviation: 'CON', purpose: 'Efficiency of energy/signal transfer'},
19
- {key: 'ductility', label: 'Ductility', abbreviation: 'DUC', purpose: 'Ability to be worked into fine, precise shapes'},
20
- {key: 'reflectivity', label: 'Reflectivity', abbreviation: 'REF', purpose: 'Surface quality for heat management and precision optics'},
34
+ {
35
+ key: 'conductivity',
36
+ label: 'Conductivity',
37
+ abbreviation: 'CON',
38
+ purpose: 'Efficiency of energy/signal transfer',
39
+ },
40
+ {
41
+ key: 'ductility',
42
+ label: 'Ductility',
43
+ abbreviation: 'DUC',
44
+ purpose: 'Ability to be worked into fine, precise shapes',
45
+ },
46
+ {
47
+ key: 'reflectivity',
48
+ label: 'Reflectivity',
49
+ abbreviation: 'REF',
50
+ purpose: 'Surface quality for heat management and precision optics',
51
+ },
21
52
  ]
22
53
 
23
54
  const GAS_STATS: StatDefinition[] = [
24
- {key: 'volatility', label: 'Volatility', abbreviation: 'VOL', purpose: 'Energy release potential for propulsion and force'},
25
- {key: 'reactivity', label: 'Reactivity', abbreviation: 'REA', purpose: 'Chemical interaction speed for processing and penetration'},
26
- {key: 'thermal', label: 'Thermal', abbreviation: 'THM', purpose: 'Heat capacity for thermal management'},
55
+ {
56
+ key: 'volatility',
57
+ label: 'Volatility',
58
+ abbreviation: 'VOL',
59
+ purpose: 'Energy release potential for propulsion and force',
60
+ },
61
+ {
62
+ key: 'reactivity',
63
+ label: 'Reactivity',
64
+ abbreviation: 'REA',
65
+ purpose: 'Chemical interaction speed for processing and penetration',
66
+ },
67
+ {
68
+ key: 'thermal',
69
+ label: 'Thermal',
70
+ abbreviation: 'THM',
71
+ purpose: 'Heat capacity for thermal management',
72
+ },
27
73
  ]
28
74
 
29
75
  const MINERAL_STATS: StatDefinition[] = [
30
- {key: 'resonance', label: 'Resonance', abbreviation: 'RES', purpose: 'Energy field interaction — storage, focusing, projection'},
31
- {key: 'hardness', label: 'Hardness', abbreviation: 'HRD', purpose: 'Resistance to wear — cutting surfaces, penetration'},
32
- {key: 'clarity', label: 'Clarity', abbreviation: 'CLR', purpose: 'Crystalline perfection — precision optics'},
76
+ {
77
+ key: 'resonance',
78
+ label: 'Resonance',
79
+ abbreviation: 'RES',
80
+ purpose: 'Energy field interaction — storage, focusing, projection',
81
+ },
82
+ {
83
+ key: 'hardness',
84
+ label: 'Hardness',
85
+ abbreviation: 'HRD',
86
+ purpose: 'Resistance to wear — cutting surfaces, penetration',
87
+ },
88
+ {
89
+ key: 'clarity',
90
+ label: 'Clarity',
91
+ abbreviation: 'CLR',
92
+ purpose: 'Crystalline perfection — precision optics',
93
+ },
33
94
  ]
34
95
 
35
96
  const ORGANIC_STATS: StatDefinition[] = [
36
- {key: 'plasticity', label: 'Plasticity', abbreviation: 'PLA', purpose: 'Ease of reshaping — speeds processing'},
37
- {key: 'insulation', label: 'Insulation', abbreviation: 'INS', purpose: 'Energy containment — reduces energy loss'},
38
- {key: 'purity', label: 'Purity', abbreviation: 'PUR', purpose: 'Biological cleanliness — better composites and lubricants'},
97
+ {
98
+ key: 'plasticity',
99
+ label: 'Plasticity',
100
+ abbreviation: 'PLA',
101
+ purpose: 'Ease of reshaping — speeds processing',
102
+ },
103
+ {
104
+ key: 'insulation',
105
+ label: 'Insulation',
106
+ abbreviation: 'INS',
107
+ purpose: 'Energy containment — reduces energy loss',
108
+ },
109
+ {
110
+ key: 'purity',
111
+ label: 'Purity',
112
+ abbreviation: 'PUR',
113
+ purpose: 'Biological cleanliness — better composites and lubricants',
114
+ },
39
115
  ]
40
116
 
41
117
  const STAT_MAP: Record<ResourceCategory, StatDefinition[]> = {
@@ -85,7 +85,7 @@ export function deriveStratum(
85
85
 
86
86
  let depthBonus = 0
87
87
  if (stratum > 1) {
88
- depthBonus = 50 * Math.log(stratum) / Math.log(65535)
88
+ depthBonus = (50 * Math.log(stratum)) / Math.log(65535)
89
89
  }
90
90
  const richness = Math.min(Math.floor(baseRichness + depthBonus), 1000)
91
91
 
@@ -95,7 +95,7 @@ export function deriveStratum(
95
95
  export function deriveResourceStats(seed: bigint): ResourceStats {
96
96
  const seedBytes = new Uint8Array(8)
97
97
  for (let i = 7; i >= 0; i--) {
98
- seedBytes[i] = Number(seed & 0xFFn)
98
+ seedBytes[i] = Number(seed & 0xffn)
99
99
  seed >>= 8n
100
100
  }
101
101
  const hashResult = Checksum256.hash(Bytes.from(seedBytes))
@@ -12,12 +12,6 @@ export function totalCargoMass(cargo: EntityInventory[]): UInt64 {
12
12
  }, UInt64.from(0))
13
13
  }
14
14
 
15
- export function cargoValue(cargo: EntityInventory[]): UInt64 {
16
- return cargo.reduce((sum, c) => {
17
- return sum.adding(c.totalCost)
18
- }, UInt64.from(0))
19
- }
20
-
21
15
  export function getCargoForItem(
22
16
  cargo: EntityInventory[],
23
17
  goodId: UInt64Type
@@ -47,84 +41,33 @@ export function isFull(currentMass: UInt64, maxCapacity: UInt64): boolean {
47
41
  return currentMass.gte(maxCapacity)
48
42
  }
49
43
 
50
- export interface SaleValue {
51
- revenue: UInt64
52
- profit: UInt64
53
- cost: UInt64
54
- }
55
-
56
- export function calculateSaleValue(
57
- cargo: ServerContract.Types.cargo_item[],
58
- prices: Map<number, UInt64>
59
- ): SaleValue {
60
- if (cargo.length === 0) {
61
- return {revenue: UInt64.from(0), profit: UInt64.from(0), cost: UInt64.from(0)}
62
- }
63
-
64
- let revenue = UInt64.from(0)
65
- let cost = UInt64.from(0)
66
-
67
- for (const item of cargo) {
68
- if (UInt32.from(item.quantity).equals(UInt32.from(0))) continue
69
-
70
- const goodId = Number(item.item_id)
71
- const salePrice = prices.get(goodId)
72
-
73
- if (salePrice) {
74
- revenue = revenue.adding(salePrice.multiplying(item.quantity))
75
- }
76
-
77
- cost = cost.adding(item.unit_cost.multiplying(item.quantity))
78
- }
79
-
80
- const profit = revenue.gte(cost) ? revenue.subtracting(cost) : UInt64.from(0)
81
-
82
- return {
83
- revenue,
84
- profit,
85
- cost,
86
- }
87
- }
88
-
89
- export function calculateSaleValueFromArray(
90
- cargo: ServerContract.Types.cargo_item[],
91
- prices: UInt64[]
92
- ): SaleValue {
93
- const priceMap = new Map<number, UInt64>()
94
- prices.forEach((price, index) => {
95
- priceMap.set(index, price)
96
- })
97
- return calculateSaleValue(cargo, priceMap)
98
- }
99
-
100
- export function afterSellItems(
44
+ export function afterRemoveItems(
101
45
  cargo: ServerContract.Types.cargo_item[],
102
- goodsToSell: Array<{goodId: number; quantity: number}>
46
+ goodsToRemove: Array<{goodId: number; quantity: number}>
103
47
  ): EntityInventory[] {
104
48
  if (cargo.length === 0) {
105
49
  return []
106
50
  }
107
51
 
108
52
  return cargo.map((item) => {
109
- const saleItem = goodsToSell.find((s) => Number(item.item_id) === s.goodId)
110
- if (!saleItem) {
53
+ const removeItem = goodsToRemove.find((s) => Number(item.item_id) === s.goodId)
54
+ if (!removeItem) {
111
55
  return new EntityInventory(item)
112
56
  }
113
57
 
114
58
  const currentQty = Number(item.quantity)
115
- const newQty = Math.max(0, currentQty - saleItem.quantity)
59
+ const newQty = Math.max(0, currentQty - removeItem.quantity)
116
60
 
117
61
  return new EntityInventory(
118
62
  ServerContract.Types.cargo_item.from({
119
63
  item_id: item.item_id,
120
64
  quantity: UInt32.from(newQty),
121
- unit_cost: item.unit_cost,
122
65
  })
123
66
  )
124
67
  })
125
68
  }
126
69
 
127
- export function afterSellAllItems(cargo: ServerContract.Types.cargo_item[]): EntityInventory[] {
70
+ export function afterRemoveAllItems(cargo: ServerContract.Types.cargo_item[]): EntityInventory[] {
128
71
  if (cargo.length === 0) {
129
72
  return []
130
73
  }
@@ -135,7 +78,6 @@ export function afterSellAllItems(cargo: ServerContract.Types.cargo_item[]): Ent
135
78
  ServerContract.Types.cargo_item.from({
136
79
  item_id: item.item_id,
137
80
  quantity: UInt32.from(0),
138
- unit_cost: item.unit_cost,
139
81
  })
140
82
  )
141
83
  )
@@ -68,3 +68,21 @@ export class Container extends ServerContract.Types.entity_info {
68
68
  return this.coordinates.z?.toNumber() || 0
69
69
  }
70
70
  }
71
+
72
+ export function computeContainerCapabilities(stats: Record<string, number>): {
73
+ hullmass: number
74
+ capacity: number
75
+ } {
76
+ const density = stats['density'] ?? 500
77
+ const strength = stats['strength'] ?? 500
78
+ const ductility = stats['ductility'] ?? 500
79
+ const purity = stats['purity'] ?? 500
80
+
81
+ const hullmass = 25000 + 75 * density
82
+
83
+ const statSum = strength + ductility + purity
84
+ const exponent = statSum / 2997
85
+ const capacity = Math.floor(1000000 * Math.pow(10, exponent))
86
+
87
+ return {hullmass, capacity}
88
+ }
@@ -29,10 +29,6 @@ export class EntityInventory extends ServerContract.Types.cargo_item {
29
29
  return UInt64.from(this.unitMass).multiplying(this.quantity)
30
30
  }
31
31
 
32
- get totalCost(): UInt64 {
33
- return this.unit_cost.multiplying(this.quantity)
34
- }
35
-
36
32
  get hasCargo(): boolean {
37
33
  return UInt32.from(this.quantity).gt(UInt32.from(0))
38
34
  }
@@ -20,10 +20,6 @@ export class InventoryAccessor {
20
20
  return this.items.reduce((sum, c) => sum.adding(c.totalMass), UInt64.from(0))
21
21
  }
22
22
 
23
- get totalValue(): UInt64 {
24
- return this.items.reduce((sum, c) => sum.adding(c.totalCost), UInt64.from(0))
25
- }
26
-
27
23
  forItem(goodId: UInt64Type): EntityInventory | undefined {
28
24
  return this.items.find((c) => c.item_id.equals(goodId))
29
25
  }
@@ -1,35 +1,22 @@
1
- import {Checksum256, Checksum256Type, UInt16, UInt16Type, UInt64} from '@wharfkit/antelope'
2
- import {ServerContract} from '../contracts'
3
- import {Coordinates, CoordinatesType, Distance, ItemPrice, LocationType} from '../types'
1
+ import {Checksum256, Checksum256Type, UInt16Type, UInt64} from '@wharfkit/antelope'
2
+ import {Coordinates, CoordinatesType, Distance, LocationType} from '../types'
4
3
  import {getLocationType, hasSystem, isExtractableLocation} from '../utils/system'
5
4
  import {findNearbyPlanets} from '../travel/travel'
6
5
 
7
- /**
8
- * Location helper class for working with game coordinates.
9
- * Provides system detection, market price caching, nearby planet finding, and supply tracking.
10
- */
11
6
  export class Location {
12
7
  readonly coordinates: Coordinates
13
- private _marketPrices?: ItemPrice[]
14
8
  private _gameSeed?: Checksum256
15
9
  private _hasSystem?: boolean
16
- private _locationRows?: ServerContract.Types.supply_row[]
17
10
  private _epoch?: UInt64
18
11
 
19
12
  constructor(coordinates: CoordinatesType) {
20
13
  this.coordinates = Coordinates.from(coordinates)
21
14
  }
22
15
 
23
- /**
24
- * Create a Location from coordinates
25
- */
26
16
  static from(coordinates: CoordinatesType): Location {
27
17
  return new Location(Coordinates.from(coordinates))
28
18
  }
29
19
 
30
- /**
31
- * Check if this location has a system (planet, asteroid, or nebula)
32
- */
33
20
  hasSystemAt(gameSeed: Checksum256Type): boolean {
34
21
  const seed = Checksum256.from(gameSeed)
35
22
  if (this._hasSystem === undefined || !this._gameSeed?.equals(seed)) {
@@ -39,214 +26,32 @@ export class Location {
39
26
  return this._hasSystem
40
27
  }
41
28
 
42
- /**
43
- * Get the location type (EMPTY, PLANET, ASTEROID, or NEBULA)
44
- */
45
29
  getLocationTypeAt(gameSeed: Checksum256Type): LocationType {
46
30
  return getLocationType(gameSeed, this.coordinates)
47
31
  }
48
32
 
49
- /**
50
- * Check if this location is extractable (asteroid or nebula)
51
- */
52
33
  isExtractableAt(gameSeed: Checksum256Type): boolean {
53
34
  return isExtractableLocation(this.getLocationTypeAt(gameSeed))
54
35
  }
55
36
 
56
- /**
57
- * Set cached market prices for this location
58
- */
59
- setMarketPrices(prices: ItemPrice[]): void {
60
- this._marketPrices = prices
61
- }
62
-
63
- /**
64
- * Get cached market prices (returns undefined if not cached)
65
- */
66
- get marketPrices(): ItemPrice[] | undefined {
67
- return this._marketPrices
68
- }
69
-
70
- /**
71
- * Get price for a specific good (from cache)
72
- */
73
- getPrice(goodId: UInt16Type): ItemPrice | undefined {
74
- if (!this._marketPrices) return undefined
75
- return this._marketPrices.find((p) => p.id.equals(goodId))
76
- }
77
-
78
- /**
79
- * Find nearby planets from this location
80
- */
81
37
  findNearby(gameSeed: Checksum256Type, maxDistance: UInt16Type = 20): Distance[] {
82
38
  return findNearbyPlanets(Checksum256.from(gameSeed), this.coordinates, maxDistance)
83
39
  }
84
40
 
85
- /**
86
- * Check if this location equals another location
87
- */
88
41
  equals(other: CoordinatesType | Location): boolean {
89
42
  const otherCoords = other instanceof Location ? other.coordinates : Coordinates.from(other)
90
43
  return this.coordinates.equals(otherCoords)
91
44
  }
92
45
 
93
- /**
94
- * Set location rows (supply data) for this location
95
- */
96
- setLocationRows(rows: ServerContract.Types.supply_row[], epoch: UInt64): void {
97
- this._locationRows = rows
98
- this._epoch = epoch
99
- }
100
-
101
- /**
102
- * Get cached location rows (supply data)
103
- */
104
- get locationRows(): ServerContract.Types.supply_row[] | undefined {
105
- return this._locationRows
106
- }
107
-
108
- /**
109
- * Get supply for a specific good at this location
110
- * Returns undefined if location rows not cached or good not found
111
- */
112
- getSupply(goodId: UInt16Type): UInt16 | undefined {
113
- if (!this._locationRows) return undefined
114
- const row = this._locationRows.find(
115
- (r) => r.item_id.equals(goodId) && this._epoch && r.epoch.equals(this._epoch)
116
- )
117
- return row ? row.supply : undefined
118
- }
119
-
120
- /**
121
- * Get all available goods at this location (goods with supply > 0)
122
- * Returns undefined if location rows not cached
123
- */
124
- get availableGoods(): ServerContract.Types.supply_row[] | undefined {
125
- if (!this._locationRows) return undefined
126
- return this._locationRows.filter(
127
- (r) => this._epoch && r.epoch.equals(this._epoch) && r.supply.gt(UInt16.from(0))
128
- )
129
- }
130
-
131
- /**
132
- * Check if a specific good is available (has supply)
133
- * Returns false if location rows not cached
134
- */
135
- hasGood(goodId: UInt16Type): boolean {
136
- const supply = this.getSupply(goodId)
137
- return supply !== undefined && supply.gt(UInt16.from(0))
138
- }
139
-
140
- /**
141
- * Get the epoch for cached location data
142
- */
143
46
  get epoch(): UInt64 | undefined {
144
47
  return this._epoch
145
48
  }
146
49
 
147
- /**
148
- * Check if cached data exists
149
- */
150
- get hasCachedData(): boolean {
151
- return this._marketPrices !== undefined || this._locationRows !== undefined
152
- }
153
-
154
- /**
155
- * Check if supply data is cached
156
- */
157
- get hasSupplyData(): boolean {
158
- return this._locationRows !== undefined
159
- }
160
-
161
- /**
162
- * Clear all cached data
163
- */
164
50
  clearCache(): void {
165
- this._marketPrices = undefined
166
- this._locationRows = undefined
167
51
  this._epoch = undefined
168
52
  }
169
-
170
- /**
171
- * Create optimistic Location with updated supply after purchase/sale.
172
- * Matches contract: update_location_supply (delta can be positive or negative)
173
- * Contract reference: market.cpp:53, 123-151
174
- *
175
- * @param goodId - Good ID to update supply for
176
- * @param quantityDelta - Change in supply (negative for purchase, positive for sale)
177
- * @returns New Location with updated supply in cached data
178
- *
179
- * @example
180
- * // After buying 10 units (supply decreases)
181
- * const newLocation = location.withUpdatedSupply(1, -10)
182
- *
183
- * // After selling 5 units (supply increases)
184
- * const newLocation = location.withUpdatedSupply(1, 5)
185
- */
186
- withUpdatedSupply(goodId: UInt16Type, quantityDelta: number): Location {
187
- const newLocation = Location.from(this.coordinates)
188
-
189
- // Copy market prices if cached
190
- if (this._marketPrices) {
191
- newLocation._marketPrices = this._marketPrices.map((price) => {
192
- if (price.id.equals(goodId)) {
193
- const currentSupply = UInt16.from(price.supply)
194
- const delta = UInt16.from(Math.abs(quantityDelta))
195
- const newSupply =
196
- quantityDelta < 0
197
- ? currentSupply.gte(delta)
198
- ? currentSupply.subtracting(delta)
199
- : UInt16.from(0)
200
- : currentSupply.adding(quantityDelta)
201
-
202
- return ItemPrice.from({
203
- id: price.id,
204
- item: price.item,
205
- price: price.price,
206
- supply: newSupply,
207
- })
208
- }
209
- return price
210
- })
211
- }
212
-
213
- // Copy location rows if cached
214
- if (this._locationRows && this._epoch) {
215
- newLocation._locationRows = this._locationRows.map((row) => {
216
- if (row.item_id.equals(goodId) && row.epoch.equals(this._epoch!)) {
217
- const currentSupply = UInt16.from(row.supply)
218
- const delta = UInt16.from(Math.abs(quantityDelta))
219
- const newSupply =
220
- quantityDelta < 0
221
- ? currentSupply.gte(delta)
222
- ? currentSupply.subtracting(delta)
223
- : UInt16.from(0)
224
- : currentSupply.adding(quantityDelta)
225
-
226
- return ServerContract.Types.supply_row.from({
227
- id: row.id,
228
- coordinates: row.coordinates,
229
- epoch: row.epoch,
230
- item_id: row.item_id,
231
- supply: newSupply,
232
- })
233
- }
234
- return row
235
- })
236
- newLocation._epoch = this._epoch
237
- }
238
-
239
- // Copy other cached data
240
- newLocation._gameSeed = this._gameSeed
241
- newLocation._hasSystem = this._hasSystem
242
-
243
- return newLocation
244
- }
245
53
  }
246
54
 
247
- /**
248
- * Helper function to convert various coordinate types to Location
249
- */
250
55
  export function toLocation(coords: CoordinatesType | Location): Location {
251
56
  if (coords instanceof Location) {
252
57
  return coords
@@ -5,26 +5,27 @@ import {Warehouse, WarehouseStateInput} from './warehouse'
5
5
  import {Container, ContainerStateInput} from './container'
6
6
 
7
7
  export function makeShip(state: ShipStateInput): Ship {
8
- const entityInfo = ServerContract.Types.entity_info.from({
8
+ const info: Record<string, unknown> = {
9
9
  type: Name.from('ship'),
10
10
  id: UInt64.from(state.id),
11
11
  owner: Name.from(state.owner),
12
12
  entity_name: state.name,
13
13
  coordinates: ServerContract.Types.coordinates.from(state.coordinates),
14
- hullmass: UInt32.from(state.hullmass),
15
- capacity: UInt32.from(state.capacity),
16
- energy: UInt16.from(state.energy),
17
14
  cargomass: UInt32.from(0),
18
15
  cargo: state.cargo || [],
19
16
  is_idle: !state.schedule,
20
17
  current_task_elapsed: UInt32.from(0),
21
18
  current_task_remaining: UInt32.from(0),
22
19
  pending_tasks: [],
23
- engines: state.engines,
24
- generator: state.generator,
25
- loaders: state.loaders,
26
- schedule: state.schedule,
27
- })
20
+ }
21
+ if (state.hullmass !== undefined) info.hullmass = UInt32.from(state.hullmass)
22
+ if (state.capacity !== undefined) info.capacity = UInt32.from(state.capacity)
23
+ if (state.energy !== undefined) info.energy = UInt16.from(state.energy)
24
+ if (state.engines) info.engines = state.engines
25
+ if (state.generator) info.generator = state.generator
26
+ if (state.loaders) info.loaders = state.loaders
27
+ if (state.schedule) info.schedule = state.schedule
28
+ const entityInfo = ServerContract.Types.entity_info.from(info)
28
29
  return new Ship(entityInfo)
29
30
  }
30
31