@shipload/sdk 1.0.0-next.4 → 1.0.0-next.41

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (134) hide show
  1. package/lib/scan.d.ts +34 -0
  2. package/lib/scan.js +136 -0
  3. package/lib/scan.js.map +1 -0
  4. package/lib/scan.m.js +129 -0
  5. package/lib/scan.m.js.map +1 -0
  6. package/lib/shipload.d.ts +2473 -973
  7. package/lib/shipload.js +11529 -5211
  8. package/lib/shipload.js.map +1 -1
  9. package/lib/shipload.m.js +11338 -5162
  10. package/lib/shipload.m.js.map +1 -1
  11. package/lib/testing.d.ts +970 -0
  12. package/lib/testing.js +4013 -0
  13. package/lib/testing.js.map +1 -0
  14. package/lib/testing.m.js +4007 -0
  15. package/lib/testing.m.js.map +1 -0
  16. package/package.json +20 -2
  17. package/src/capabilities/craftable.ts +51 -0
  18. package/src/capabilities/crafting.test.ts +7 -0
  19. package/src/capabilities/crafting.ts +5 -6
  20. package/src/capabilities/gathering.test.ts +16 -0
  21. package/src/capabilities/gathering.ts +35 -18
  22. package/src/capabilities/index.ts +0 -1
  23. package/src/capabilities/modules.ts +9 -0
  24. package/src/capabilities/storage.ts +16 -1
  25. package/src/contracts/platform.ts +231 -3
  26. package/src/contracts/server.ts +1021 -481
  27. package/src/coordinates/address.ts +88 -0
  28. package/src/coordinates/constants.test.ts +15 -0
  29. package/src/coordinates/constants.ts +23 -0
  30. package/src/coordinates/index.ts +15 -0
  31. package/src/coordinates/memo.test.ts +47 -0
  32. package/src/coordinates/memo.ts +20 -0
  33. package/src/coordinates/permutation.ts +77 -0
  34. package/src/coordinates/regions.ts +48 -0
  35. package/src/coordinates/sectors.ts +115 -0
  36. package/src/data/capabilities.ts +12 -5
  37. package/src/data/capability-formulas.ts +14 -7
  38. package/src/data/catalog.ts +0 -5
  39. package/src/data/colors.ts +14 -47
  40. package/src/data/entities.json +76 -10
  41. package/src/data/item-ids.ts +18 -12
  42. package/src/data/items.json +321 -38
  43. package/src/data/kind-registry.json +109 -0
  44. package/src/data/kind-registry.ts +165 -0
  45. package/src/data/metadata.ts +119 -33
  46. package/src/data/recipes-runtime.ts +3 -23
  47. package/src/data/recipes.json +238 -117
  48. package/src/derivation/build-methods.ts +45 -0
  49. package/src/derivation/capabilities.test.ts +151 -0
  50. package/src/derivation/capabilities.ts +512 -0
  51. package/src/derivation/capability-mappings.ts +9 -12
  52. package/src/derivation/crafting.ts +23 -24
  53. package/src/derivation/index.ts +25 -2
  54. package/src/derivation/recipe-usage.test.ts +78 -0
  55. package/src/derivation/recipe-usage.ts +141 -0
  56. package/src/derivation/reserve-regen.ts +34 -0
  57. package/src/derivation/resources.ts +125 -38
  58. package/src/derivation/rollups.test.ts +55 -0
  59. package/src/derivation/rollups.ts +56 -0
  60. package/src/derivation/stars.test.ts +51 -0
  61. package/src/derivation/stars.ts +15 -0
  62. package/src/derivation/stats.ts +6 -6
  63. package/src/derivation/stratum.ts +17 -20
  64. package/src/derivation/tiers.ts +40 -7
  65. package/src/derivation/wormhole.ts +136 -0
  66. package/src/entities/entity.ts +98 -0
  67. package/src/entities/gamestate.ts +3 -28
  68. package/src/entities/makers.ts +124 -134
  69. package/src/entities/slot-multiplier.ts +43 -0
  70. package/src/errors.ts +12 -16
  71. package/src/format.ts +26 -4
  72. package/src/index-module.ts +267 -47
  73. package/src/managers/actions.ts +528 -95
  74. package/src/managers/base.ts +6 -2
  75. package/src/managers/construction-types.ts +80 -0
  76. package/src/managers/construction.ts +412 -0
  77. package/src/managers/context.ts +20 -1
  78. package/src/managers/coordinates.ts +14 -0
  79. package/src/managers/entities.ts +18 -66
  80. package/src/managers/epochs.ts +40 -0
  81. package/src/managers/index.ts +17 -1
  82. package/src/managers/locations.ts +25 -29
  83. package/src/managers/nft.test.ts +14 -0
  84. package/src/managers/nft.ts +70 -0
  85. package/src/managers/plot.ts +122 -0
  86. package/src/nft/atomicassets.abi.json +1342 -0
  87. package/src/nft/atomicassets.ts +237 -0
  88. package/src/nft/atomicdata.ts +130 -0
  89. package/src/nft/buildImmutableData.ts +338 -0
  90. package/src/nft/description.ts +98 -24
  91. package/src/nft/index.ts +3 -0
  92. package/src/planner/index.ts +127 -0
  93. package/src/planner/planner.test.ts +319 -0
  94. package/src/resolution/describe-module.ts +18 -13
  95. package/src/resolution/display-name.ts +38 -10
  96. package/src/resolution/resolve-item.test.ts +37 -0
  97. package/src/resolution/resolve-item.ts +55 -24
  98. package/src/scan/index.ts +180 -0
  99. package/src/scan/scan-wasm.base64.ts +2 -0
  100. package/src/scheduling/accessor.ts +68 -22
  101. package/src/scheduling/availability.ts +108 -0
  102. package/src/scheduling/cancel.test.ts +348 -0
  103. package/src/scheduling/cancel.ts +209 -0
  104. package/src/scheduling/energy.ts +47 -0
  105. package/src/scheduling/idle-resolve.ts +45 -0
  106. package/src/scheduling/lane-core.ts +128 -0
  107. package/src/scheduling/lanes.test.ts +249 -0
  108. package/src/scheduling/lanes.ts +198 -0
  109. package/src/scheduling/projection.ts +209 -105
  110. package/src/scheduling/schedule.ts +241 -104
  111. package/src/scheduling/task-cargo.ts +46 -0
  112. package/src/shipload.ts +21 -1
  113. package/src/subscriptions/manager.ts +229 -142
  114. package/src/subscriptions/mappers.ts +5 -8
  115. package/src/subscriptions/types.ts +11 -3
  116. package/src/testing/catalog-hash.ts +19 -0
  117. package/src/testing/index.ts +2 -0
  118. package/src/testing/projection-parity.ts +167 -0
  119. package/src/travel/reach.ts +23 -0
  120. package/src/travel/route-planner.ts +196 -0
  121. package/src/travel/travel.ts +200 -112
  122. package/src/types/capabilities.ts +29 -6
  123. package/src/types/entity.ts +3 -3
  124. package/src/types/index.ts +0 -1
  125. package/src/types.ts +28 -13
  126. package/src/utils/cargo.ts +27 -0
  127. package/src/utils/display-name.ts +70 -0
  128. package/src/utils/system.ts +36 -24
  129. package/src/capabilities/loading.ts +0 -8
  130. package/src/entities/container.ts +0 -108
  131. package/src/entities/ship-deploy.ts +0 -259
  132. package/src/entities/ship.ts +0 -204
  133. package/src/entities/warehouse.ts +0 -119
  134. package/src/types/entity-traits.ts +0 -69
@@ -1,42 +1,57 @@
1
1
  import {Name, UInt16, UInt32, UInt64, UInt8} from '@wharfkit/antelope'
2
+ import type {NameType, UInt64Type} from '@wharfkit/antelope'
2
3
  import {ServerContract} from '../contracts'
3
- import {type PackedModuleInput, Ship, type ShipStateInput} from './ship'
4
- import {computeWarehouseCapabilities, Warehouse, type WarehouseStateInput} from './warehouse'
5
- import {Container, type ContainerStateInput} from './container'
6
- import {ITEM_SHIP_T1_PACKED, ITEM_WAREHOUSE_T1_PACKED} from '../data/item-ids'
4
+ import {Entity} from './entity'
5
+ import {getKindMeta, getTemplateMeta} from '../data/kind-registry'
6
+ import type {EntityTypeName} from '../data/kind-registry'
7
7
  import {getEntityLayout} from '../data/recipes-runtime'
8
+ import type {EntitySlot} from '../data/recipes-runtime'
8
9
  import {itemMetadata} from '../data/metadata'
9
10
  import {getItem} from '../data/catalog'
10
- import {
11
- getModuleCapabilityType,
12
- MODULE_STORAGE,
13
- moduleAccepts,
14
- moduleSlotTypeToCode,
15
- } from '../capabilities/modules'
16
- import {computeShipCapabilities, computeStorageCapabilities} from './ship-deploy'
17
- import {decodeCraftedItemStats} from '../derivation/crafting'
11
+ import {getModuleCapabilityType, moduleAccepts, moduleSlotTypeToCode} from '../capabilities/modules'
12
+ import {computeEntityCapabilities} from '../derivation/capabilities'
13
+ import {packedModulesToInstalled} from './slot-multiplier'
14
+ import {LANE_MOBILITY} from '../scheduling/schedule'
15
+
16
+ export interface PackedModuleInput {
17
+ itemId: number
18
+ stats: bigint
19
+ }
20
+
21
+ export interface EntityStateInput {
22
+ id: UInt64Type
23
+ owner: NameType
24
+ name: string
25
+ coordinates: {x: number; y: number; z?: number}
26
+ itemId?: number
27
+ hullmass?: number
28
+ capacity?: number
29
+ cargomass?: number
30
+ energy?: number
31
+ modules?: PackedModuleInput[]
32
+ schedule?: ServerContract.Types.schedule
33
+ lanes?: ServerContract.Types.lane[]
34
+ cargo?: ServerContract.Types.cargo_item[]
35
+ }
18
36
 
19
37
  function assignModulesToSlots(
20
- packedEntityItemId: number,
38
+ slots: EntitySlot[],
21
39
  modules: PackedModuleInput[],
22
40
  entityLabel: string
23
41
  ): ServerContract.Types.module_entry[] {
24
- const layout = getEntityLayout(packedEntityItemId)
25
- const slots = layout?.slots ?? []
26
42
  const result: Array<{type: number; installed?: ServerContract.Types.packed_module}> = slots.map(
27
43
  (s) => ({type: moduleSlotTypeToCode(s.type), installed: undefined})
28
44
  )
29
45
 
30
46
  for (const mod of modules) {
31
- const itemId = Number(UInt16.from(mod.itemId).value.toString())
32
- const modType = getModuleCapabilityType(itemId)
47
+ const modType = getModuleCapabilityType(mod.itemId)
33
48
  const slotIdx = result.findIndex((r) => !r.installed && moduleAccepts(r.type, modType))
34
49
  if (slotIdx === -1) {
35
50
  let modName: string
36
51
  try {
37
- modName = getItem(itemId).name
52
+ modName = getItem(mod.itemId).name
38
53
  } catch {
39
- modName = itemMetadata[itemId]?.name ?? `item ${itemId}`
54
+ modName = itemMetadata[mod.itemId]?.name ?? `item ${mod.itemId}`
40
55
  }
41
56
  throw new Error(
42
57
  `No compatible slot for module ${modName} (type ${modType}) on ${entityLabel}`
@@ -56,141 +71,116 @@ function assignModulesToSlots(
56
71
  )
57
72
  }
58
73
 
59
- function decodePackedInput(m: PackedModuleInput): {itemId: number; stats: bigint} {
60
- return {
61
- itemId: Number(UInt16.from(m.itemId).value.toString()),
62
- stats: BigInt(UInt64.from(m.stats).toString()),
63
- }
74
+ const ZERO_HULL_STATS: Record<string, number> = {
75
+ density: 0,
76
+ strength: 0,
77
+ hardness: 0,
78
+ cohesion: 0,
64
79
  }
65
80
 
66
- function computeStorageBonus(
67
- decoded: {itemId: number; stats: bigint}[],
68
- baseCapacity: number
69
- ): number {
70
- let totalBonus = 0
71
- for (const m of decoded) {
72
- if (getModuleCapabilityType(m.itemId) !== MODULE_STORAGE) continue
73
- const stats = decodeCraftedItemStats(m.itemId, m.stats)
74
- const {capacityBonus} = computeStorageCapabilities(stats, baseCapacity)
75
- totalBonus += capacityBonus
81
+ export function makeEntity(packedItemId: number, state: EntityStateInput): Entity {
82
+ const template = getTemplateMeta(packedItemId)
83
+ if (!template) {
84
+ throw new Error(`Unknown packed entity item ID: ${packedItemId}`)
76
85
  }
77
- return totalBonus
78
- }
79
86
 
80
- function deriveShipFromModules(
81
- modules: PackedModuleInput[],
82
- baseCapacity: number
83
- ): {
84
- capabilities: ReturnType<typeof computeShipCapabilities>
85
- finalCapacity: number
86
- } {
87
- const decoded = modules.map(decodePackedInput)
88
- const capabilities = computeShipCapabilities(decoded)
89
- const totalBonus = computeStorageBonus(decoded, baseCapacity)
90
- return {capabilities, finalCapacity: baseCapacity + totalBonus}
91
- }
87
+ const kind = template.kind.toString() as EntityTypeName
88
+ const layout = getEntityLayout(packedItemId)?.slots ?? []
89
+ const mods = state.modules ?? []
90
+
91
+ const lanes =
92
+ state.lanes ??
93
+ (state.schedule
94
+ ? [
95
+ ServerContract.Types.lane.from({
96
+ lane_key: UInt8.from(LANE_MOBILITY),
97
+ schedule: state.schedule,
98
+ }),
99
+ ]
100
+ : [])
92
101
 
93
- export function makeShip(state: ShipStateInput): Ship {
94
102
  const info: Record<string, unknown> = {
95
- type: Name.from('ship'),
103
+ type: template.kind,
96
104
  id: UInt64.from(state.id),
97
105
  owner: Name.from(state.owner),
98
106
  entity_name: state.name,
99
107
  coordinates: ServerContract.Types.coordinates.from(state.coordinates),
100
- cargomass: UInt32.from(0),
108
+ item_id: UInt16.from(state.itemId ?? template.itemId),
109
+ cargomass: UInt32.from(state.cargomass ?? 0),
101
110
  cargo: state.cargo || [],
102
- is_idle: !state.schedule,
103
- current_task_elapsed: UInt32.from(0),
104
- current_task_remaining: UInt32.from(0),
105
- pending_tasks: [],
111
+ lanes,
112
+ holds: [],
106
113
  }
107
- if (state.hullmass !== undefined) info.hullmass = UInt32.from(state.hullmass)
114
+
108
115
  if (state.energy !== undefined) info.energy = UInt16.from(state.energy)
109
- if (state.schedule) info.schedule = state.schedule
110
-
111
- let moduleEntries: ServerContract.Types.module_entry[] = []
112
- if (state.modules && state.modules.length > 0) {
113
- moduleEntries = assignModulesToSlots(ITEM_SHIP_T1_PACKED, state.modules, 'Ship T1')
114
- const {capabilities, finalCapacity} = deriveShipFromModules(
115
- state.modules,
116
- state.capacity ?? 0
117
- )
118
- if (capabilities.engines) info.engines = capabilities.engines
119
- if (capabilities.generator) info.generator = capabilities.generator
120
- if (capabilities.gatherer) info.gatherer = capabilities.gatherer
121
- if (capabilities.hauler) info.hauler = capabilities.hauler
122
- if (capabilities.loaders) info.loaders = capabilities.loaders
123
- if (capabilities.crafter) info.crafter = capabilities.crafter
124
- if (state.capacity !== undefined) info.capacity = UInt32.from(finalCapacity)
125
- } else {
126
- moduleEntries = assignModulesToSlots(ITEM_SHIP_T1_PACKED, [], 'Ship T1')
116
+
117
+ if (kind === 'container') {
118
+ info.modules = []
119
+ if (state.hullmass !== undefined) info.hullmass = UInt32.from(state.hullmass)
127
120
  if (state.capacity !== undefined) info.capacity = UInt32.from(state.capacity)
128
- }
121
+ } else {
122
+ const entityLabel = getKindMeta(template.kind)?.defaultLabel ?? kind
123
+ const moduleEntries = assignModulesToSlots(layout, mods, entityLabel)
124
+ info.modules = moduleEntries
129
125
 
130
- info.modules = moduleEntries
126
+ const installed = packedModulesToInstalled(moduleEntries)
127
+ const caps = computeEntityCapabilities(ZERO_HULL_STATS, packedItemId, installed, layout)
131
128
 
132
- const entityInfo = ServerContract.Types.entity_info.from(info)
133
- return new Ship(entityInfo)
134
- }
129
+ if (state.hullmass !== undefined) {
130
+ info.hullmass = UInt32.from(state.hullmass)
131
+ } else if (installed.length > 0) {
132
+ info.hullmass = UInt32.from(caps.hullmass)
133
+ }
135
134
 
136
- export function makeWarehouse(state: WarehouseStateInput): Warehouse {
137
- const info: Record<string, unknown> = {
138
- type: Name.from('warehouse'),
139
- id: UInt64.from(state.id),
140
- owner: Name.from(state.owner),
141
- entity_name: state.name,
142
- coordinates: ServerContract.Types.coordinates.from(state.coordinates),
143
- capacity: UInt32.from(state.capacity),
144
- cargomass: UInt32.from(0),
145
- cargo: state.cargo || [],
146
- is_idle: !state.schedule,
147
- current_task_elapsed: UInt32.from(0),
148
- current_task_remaining: UInt32.from(0),
149
- pending_tasks: [],
150
- }
151
- if (state.hullmass !== undefined) info.hullmass = UInt32.from(state.hullmass)
152
- if (state.schedule) info.schedule = state.schedule
153
-
154
- let moduleEntries: ServerContract.Types.module_entry[] = []
155
- if (state.modules && state.modules.length > 0) {
156
- moduleEntries = assignModulesToSlots(
157
- ITEM_WAREHOUSE_T1_PACKED,
158
- state.modules,
159
- 'Warehouse T1'
160
- )
161
- const decoded = state.modules.map(decodePackedInput)
162
- const capabilities = computeWarehouseCapabilities(decoded)
163
- if (capabilities.loaders) info.loaders = capabilities.loaders
135
+ if (state.capacity !== undefined) {
136
+ info.capacity = UInt32.from(state.capacity)
137
+ } else {
138
+ info.capacity = UInt32.from(caps.capacity)
139
+ }
164
140
 
165
- const totalBonus = computeStorageBonus(decoded, state.capacity)
166
- info.capacity = UInt32.from(state.capacity + totalBonus)
167
- } else {
168
- moduleEntries = assignModulesToSlots(ITEM_WAREHOUSE_T1_PACKED, [], 'Warehouse T1')
141
+ if (caps.engines) info.engines = caps.engines
142
+ if (caps.generator) info.generator = caps.generator
143
+ if (caps.hauler) info.hauler = caps.hauler
144
+ if (caps.warp) info.warp = caps.warp
145
+ if (caps.launcher) {
146
+ info.launcher = ServerContract.Types.launcher_stats.from({
147
+ charge_rate: caps.launcher.chargeRate,
148
+ velocity: caps.launcher.velocity,
149
+ drain: caps.launcher.drain,
150
+ })
151
+ }
152
+
153
+ info.gatherer_lanes = (caps.gathererLanes ?? []).map((l) =>
154
+ ServerContract.Types.gatherer_lane.from({
155
+ slot_index: l.slotIndex,
156
+ yield: l.yield,
157
+ drain: l.drain,
158
+ depth: l.depth,
159
+ output_pct: l.outputPct,
160
+ })
161
+ )
162
+ info.crafter_lanes = (caps.crafterLanes ?? []).map((l) =>
163
+ ServerContract.Types.crafter_lane.from({
164
+ slot_index: l.slotIndex,
165
+ speed: l.speed,
166
+ drain: l.drain,
167
+ output_pct: l.outputPct,
168
+ })
169
+ )
170
+ info.loader_lanes = (caps.loaderLanes ?? []).map((l) =>
171
+ ServerContract.Types.loader_lane.from({
172
+ slot_index: l.slotIndex,
173
+ mass: l.mass,
174
+ thrust: l.thrust,
175
+ output_pct: l.outputPct,
176
+ })
177
+ )
169
178
  }
170
179
 
171
- info.modules = moduleEntries
180
+ if (!info.gatherer_lanes) info.gatherer_lanes = []
181
+ if (!info.crafter_lanes) info.crafter_lanes = []
182
+ if (!info.loader_lanes) info.loader_lanes = []
172
183
 
173
184
  const entityInfo = ServerContract.Types.entity_info.from(info)
174
- return new Warehouse(entityInfo)
175
- }
176
-
177
- export function makeContainer(state: ContainerStateInput): Container {
178
- const entityInfo = ServerContract.Types.entity_info.from({
179
- type: Name.from('container'),
180
- id: UInt64.from(state.id),
181
- owner: Name.from(state.owner),
182
- entity_name: state.name,
183
- coordinates: ServerContract.Types.coordinates.from(state.coordinates),
184
- hullmass: UInt32.from(state.hullmass),
185
- capacity: UInt32.from(state.capacity),
186
- cargomass: UInt32.from(state.cargomass || 0),
187
- cargo: state.cargo || [],
188
- modules: [],
189
- is_idle: !state.schedule,
190
- current_task_elapsed: UInt32.from(0),
191
- current_task_remaining: UInt32.from(0),
192
- pending_tasks: [],
193
- schedule: state.schedule,
194
- })
195
- return new Container(entityInfo)
185
+ return new Entity(entityInfo)
196
186
  }
@@ -0,0 +1,43 @@
1
+ import type {EntitySlot} from '../data/recipes-runtime'
2
+ import type {ServerContract} from '../contracts'
3
+
4
+ export const U16_MAX = 65535
5
+
6
+ export interface InstalledModule {
7
+ slotIndex: number
8
+ itemId: number
9
+ stats: bigint
10
+ }
11
+
12
+ export function packedModulesToInstalled(
13
+ entries: ServerContract.Types.module_entry[]
14
+ ): InstalledModule[] {
15
+ const installed: InstalledModule[] = []
16
+ entries.forEach((entry, slotIndex) => {
17
+ if (!entry.installed) return
18
+ installed.push({
19
+ slotIndex,
20
+ itemId: Number(entry.installed.item_id.value),
21
+ stats: BigInt(entry.installed.stats.toString()),
22
+ })
23
+ })
24
+ return installed
25
+ }
26
+
27
+ export function clampUint16(value: number): number {
28
+ return Math.min(value, U16_MAX)
29
+ }
30
+
31
+ export const clampUint32 = (v: number): number => Math.min(Math.max(Math.floor(v), 0), 4294967295)
32
+
33
+ export function applySlotMultiplier(value: number, outputPct: number): number {
34
+ return clampUint16(Math.floor((value * outputPct) / 100))
35
+ }
36
+
37
+ export function applySlotMultiplierUint32(value: number, outputPct: number): number {
38
+ return clampUint32(Math.floor((value * outputPct) / 100))
39
+ }
40
+
41
+ export function getSlotAmp(layout: EntitySlot[], slotIndex: number): number {
42
+ return layout[slotIndex]?.outputPct ?? 100
43
+ }
package/src/errors.ts CHANGED
@@ -16,20 +16,18 @@ export const REQUIRES_POSITIVE_VALUE = 'Value must be greater than zero.'
16
16
  export const PLAYER_ALREADY_JOINED = 'Player has already joined the game.'
17
17
  export const PLAYER_NOT_JOINED = 'Player has not joined the game.'
18
18
  export const PLAYER_NOT_FOUND = 'Cannot find player for given account name.'
19
- export const STARTER_ALREADY_CLAIMED =
20
- 'Starter ship already claimed; destroy existing ships to re-claim.'
21
- export const SHIP_ALREADY_THERE = 'Ship cannot travel to the location its already at.'
19
+ export const ENTITY_ALREADY_THERE = 'Entity cannot travel to the location it is already at.'
22
20
  export const SHIP_ALREADY_TRAVELING = 'Ship is already traveling.'
23
21
  export const SHIP_CANNOT_BUY_TRAVELING = 'Ship cannot buy goods while traveling.'
24
22
  export const SHIP_CANNOT_UPDATE_TRAVELING = 'Ship cannot be updated while traveling.'
25
- export const SHIP_INVALID_DESTINATION = 'Ship cannot travel, no system at specified destination.'
26
- export const SHIP_INVALID_TRAVEL_DURATION =
23
+ export const ENTITY_INVALID_DESTINATION = 'Cannot travel: no system at specified destination.'
24
+ export const ENTITY_INVALID_TRAVEL_DURATION =
27
25
  'This trip cannot be made as it would exceed the maximum travel duration.'
28
26
  export const SHIP_NOT_ARRIVED = 'Ship has not yet arrived at its destination.'
29
- export const SHIP_NOT_ENOUGH_ENERGY =
30
- 'Ship does not have enough energy to travel to the destination.'
31
- export const SHIP_NOT_ENOUGH_ENERGY_CAPACITY =
32
- 'Ship does not have enough energy capacity to travel.'
27
+ export const ENTITY_NOT_ENOUGH_ENERGY =
28
+ 'Entity does not have enough energy to travel to the destination.'
29
+ export const ENTITY_NOT_ENOUGH_ENERGY_CAPACITY =
30
+ 'Entity does not have enough energy capacity to travel.'
33
31
  export const SHIP_NOT_FOUND = 'Cannot find ship for given account.'
34
32
  export const SHIP_NOT_OWNED = 'Ship is not owned by this account.'
35
33
  export const NO_SCHEDULE = 'No scheduled tasks.'
@@ -38,19 +36,15 @@ export const SHIP_NO_COMPLETED_TASKS = 'No completed tasks to resolve.'
38
36
  export const RESOLVE_COUNT_EXCEEDS_COMPLETED = 'Requested resolve count exceeds completed tasks.'
39
37
  export const SHIP_CANNOT_CANCEL_TASK = 'Cannot cancel task that is immutable or in progress.'
40
38
  export const SHIP_NO_TASKS_TO_CANCEL = 'No tasks to cancel.'
41
- export const SHIP_INVALID_CARGO = 'Invalid cargo specified for load/unload.'
42
- export const SHIP_CARGO_NOT_OWNED = 'Cannot load cargo that is not owned.'
43
- export const SHIP_CARGO_NOT_LOADED = 'Cannot unload cargo that is not loaded.'
44
- export const SHIP_CAPACITY_EXCEEDED = 'Ship cargo capacity would be exceeded.'
39
+ export const ENTITY_INVALID_CARGO = 'Invalid cargo specified for load/unload.'
40
+ export const ENTITY_CARGO_NOT_OWNED = 'Cannot load cargo that is not owned.'
41
+ export const ENTITY_CARGO_NOT_LOADED = 'Cannot unload cargo that is not loaded.'
45
42
  export const ENTITY_CAPACITY_EXCEEDED = 'Entity cargo capacity would be exceeded.'
46
43
  export const WAREHOUSE_NOT_FOUND = 'Cannot find warehouse for given id.'
47
44
  export const WAREHOUSE_ALREADY_AT_LOCATION = 'Warehouse already exists at this location.'
48
- export const WAREHOUSE_CAPACITY_EXCEEDED = 'Warehouse capacity would be exceeded.'
49
45
  export const CONTAINER_NOT_FOUND = 'Cannot find container for given id.'
50
- export const CONTAINER_CAPACITY_EXCEEDED = 'Container capacity would be exceeded.'
51
46
  export const DESTINATION_CAPACITY_EXCEEDED =
52
47
  'Destination entity does not have enough capacity for the gather.'
53
- export const CANCEL_PAIRED_HAS_PENDING = 'Cannot cancel transfer, paired entity has pending tasks.'
54
48
  export const GROUP_EMPTY = 'Group travel requires at least one entity.'
55
49
  export const GROUP_NO_THRUST = 'Group travel requires at least one entity with engines.'
56
50
  export const GROUP_NOT_SAME_LOCATION = 'All entities must be at the same location for group travel.'
@@ -62,6 +56,8 @@ export const GROUP_HAUL_CAPACITY_EXCEEDED =
62
56
  'Group travel requires sufficient hauler capacity for all non-self-propelled entities.'
63
57
  export const CANCEL_CONTAINS_GROUPED_TASK =
64
58
  'Cannot cancel range containing grouped task - cancel non-grouped tasks first.'
59
+ export const WOULD_STRAND = 'Cancelling this would leave a later task without the cargo it needs.'
60
+ export const WOULD_OVERFILL = 'Cancelling this would overfill the other entity with returned cargo.'
65
61
  export const WARP_NO_CAPABILITY = 'Entity does not have warp capability.'
66
62
  export const WARP_HAS_SCHEDULE = 'Entity must be idle to warp.'
67
63
  export const WARP_HAS_CARGO = 'Entity must have no cargo to warp.'
package/src/format.ts CHANGED
@@ -1,8 +1,12 @@
1
1
  export function formatMass(kg: number): string {
2
- const t = kg / 1000
3
- const fixed = t.toFixed(2)
4
- const trimmed = fixed.replace(/\.?0+$/, '')
5
- return `${trimmed} t`
2
+ if (kg === 0) return '0 t'
3
+ const sign = kg < 0 ? '-' : ''
4
+ const centitonnes = Math.round(Math.abs(kg) / 10)
5
+ const t = Math.floor(centitonnes / 100)
6
+ const frac = centitonnes % 100
7
+ if (frac === 0) return `${sign}${t} t`
8
+ const fracStr = String(frac).padStart(2, '0').replace(/0$/, '')
9
+ return `${sign}${t}.${fracStr} t`
6
10
  }
7
11
 
8
12
  export function formatMassDelta(kg: number): string {
@@ -10,3 +14,21 @@ export function formatMassDelta(kg: number): string {
10
14
  const sign = kg > 0 ? '+' : '-'
11
15
  return `${sign}${formatMass(Math.abs(kg))}`
12
16
  }
17
+
18
+ export function formatLocation(loc: {x: number; y: number}): string {
19
+ return `${loc.x}, ${loc.y}`
20
+ }
21
+
22
+ function trim(n: number, digits = 1): string {
23
+ return n.toFixed(digits).replace(/\.?0+$/, '')
24
+ }
25
+
26
+ export function formatMassScaled(kg: number): string {
27
+ if (kg === 0) return '0 t'
28
+ const sign = kg < 0 ? '-' : ''
29
+ const tonnes = Math.abs(kg) / 1000
30
+ if (tonnes >= 1_000_000_000) return `${sign}${trim(tonnes / 1_000_000_000)}b t`
31
+ if (tonnes >= 1_000_000) return `${sign}${trim(tonnes / 1_000_000)}m t`
32
+ if (tonnes >= 1_000) return `${sign}${trim(tonnes / 1_000)}k t`
33
+ return formatMass(kg)
34
+ }