@shipload/sdk 1.0.0-next.51 → 1.0.0-next.53

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 (60) hide show
  1. package/lib/shipload.d.ts +471 -158
  2. package/lib/shipload.js +2320 -485
  3. package/lib/shipload.js.map +1 -1
  4. package/lib/shipload.m.js +2290 -484
  5. package/lib/shipload.m.js.map +1 -1
  6. package/lib/testing.d.ts +123 -8
  7. package/lib/testing.js +450 -19
  8. package/lib/testing.js.map +1 -1
  9. package/lib/testing.m.js +451 -20
  10. package/lib/testing.m.js.map +1 -1
  11. package/package.json +1 -1
  12. package/src/capabilities/crafting.ts +10 -1
  13. package/src/capabilities/gathering.ts +1 -1
  14. package/src/capabilities/hauling.ts +0 -5
  15. package/src/capabilities/modules.ts +6 -0
  16. package/src/capabilities/movement.ts +1 -1
  17. package/src/contracts/server.ts +293 -13
  18. package/src/data/capabilities.ts +18 -2
  19. package/src/data/capability-formulas.ts +5 -0
  20. package/src/data/entities.json +235 -20
  21. package/src/data/item-ids.ts +10 -0
  22. package/src/data/items.json +61 -0
  23. package/src/data/kind-registry.json +53 -1
  24. package/src/data/kind-registry.ts +5 -0
  25. package/src/data/metadata.ts +74 -5
  26. package/src/data/recipes-runtime.ts +1 -0
  27. package/src/data/recipes.json +895 -119
  28. package/src/derivation/capabilities.test.ts +105 -4
  29. package/src/derivation/capabilities.ts +162 -57
  30. package/src/derivation/capability-mappings.ts +2 -0
  31. package/src/derivation/crafting.ts +2 -0
  32. package/src/derivation/recipe-usage.test.ts +10 -7
  33. package/src/derivation/rollups.ts +16 -0
  34. package/src/derivation/stat-scaling.ts +12 -0
  35. package/src/entities/makers.ts +10 -1
  36. package/src/index-module.ts +29 -3
  37. package/src/managers/actions.ts +77 -46
  38. package/src/managers/construction-types.ts +2 -2
  39. package/src/managers/construction.ts +15 -15
  40. package/src/managers/plot.ts +1 -1
  41. package/src/nft/buildImmutableData.ts +55 -9
  42. package/src/nft/description.ts +99 -36
  43. package/src/planner/planner.test.ts +50 -41
  44. package/src/resolution/resolve-item.test.ts +1 -1
  45. package/src/resolution/resolve-item.ts +26 -11
  46. package/src/scheduling/availability.ts +7 -6
  47. package/src/scheduling/cancel.test.ts +40 -6
  48. package/src/scheduling/cancel.ts +21 -29
  49. package/src/scheduling/jobs.ts +71 -0
  50. package/src/scheduling/lanes.ts +29 -0
  51. package/src/scheduling/projection.ts +42 -25
  52. package/src/scheduling/task-cargo.ts +1 -1
  53. package/src/testing/projection-parity.ts +2 -2
  54. package/src/travel/reach.ts +4 -6
  55. package/src/travel/route-planner.ts +60 -49
  56. package/src/travel/route-simulator.ts +3 -7
  57. package/src/travel/travel.ts +14 -5
  58. package/src/types/capabilities.ts +9 -3
  59. package/src/types.ts +5 -3
  60. package/src/managers/flatten-gather-plan.test.ts +0 -80
@@ -112,7 +112,7 @@ export function makeEntity(packedItemId: number, state: EntityStateInput): Entit
112
112
  holds: [],
113
113
  }
114
114
 
115
- if (state.energy !== undefined) info.energy = UInt16.from(state.energy)
115
+ if (state.energy !== undefined) info.energy = UInt32.from(state.energy)
116
116
 
117
117
  if (kind === 'container') {
118
118
  info.modules = []
@@ -174,6 +174,14 @@ export function makeEntity(packedItemId: number, state: EntityStateInput): Entit
174
174
  output_pct: l.outputPct,
175
175
  })
176
176
  )
177
+ info.builder_lanes = (caps.builderLanes ?? []).map((l) =>
178
+ ServerContract.Types.builder_lane.from({
179
+ slot_index: l.slotIndex,
180
+ speed: l.speed,
181
+ drain: l.drain,
182
+ output_pct: l.outputPct,
183
+ })
184
+ )
177
185
  info.loader_lanes = (caps.loaderLanes ?? []).map((l) =>
178
186
  ServerContract.Types.loader_lane.from({
179
187
  slot_index: l.slotIndex,
@@ -186,6 +194,7 @@ export function makeEntity(packedItemId: number, state: EntityStateInput): Entit
186
194
 
187
195
  if (!info.gatherer_lanes) info.gatherer_lanes = []
188
196
  if (!info.crafter_lanes) info.crafter_lanes = []
197
+ if (!info.builder_lanes) info.builder_lanes = []
189
198
  if (!info.loader_lanes) info.loader_lanes = []
190
199
 
191
200
  const entityInfo = ServerContract.Types.entity_info.from(info)
@@ -29,6 +29,7 @@ export type energy_stats = ServerContract.Types.energy_stats
29
29
  export type schedule = ServerContract.Types.schedule
30
30
  export type lane = ServerContract.Types.lane
31
31
  export type task = ServerContract.Types.task
32
+ export type coupling = ServerContract.Types.coupling
32
33
  export type cargo_item = ServerContract.Types.cargo_item
33
34
  export type entity_row = ServerContract.Types.entity_row
34
35
 
@@ -177,6 +178,7 @@ export {
177
178
  calc_acceleration,
178
179
  calc_energyusage,
179
180
  calc_flighttime,
181
+ calc_travel_flighttime,
180
182
  calc_group_flighttime,
181
183
  calc_loader_acceleration,
182
184
  calc_loader_flighttime,
@@ -215,7 +217,7 @@ export type {
215
217
  HasScheduleAndLocation,
216
218
  } from './travel/travel'
217
219
 
218
- export {planRoute, sdkSystemGraph, setScanProvider, MAX_LEGS} from './travel/route-planner'
220
+ export {planRoute, sdkSystemGraph, MAX_LEGS} from './travel/route-planner'
219
221
  export type {
220
222
  Coord,
221
223
  Neighbor,
@@ -226,6 +228,9 @@ export type {
226
228
  RouteResult,
227
229
  RouteFailureReason,
228
230
  PlanRouteParams,
231
+ RouteLegInput,
232
+ RouteLegCost,
233
+ RouteHeuristicCost,
229
234
  } from './travel/route-planner'
230
235
 
231
236
  export {computePerLegReach, computeGroupPerLegReach} from './travel/reach'
@@ -248,6 +253,7 @@ export {
248
253
  rawScheduleEnd,
249
254
  resolveLaneGatherer,
250
255
  resolveLaneCrafter,
256
+ resolveLaneBuilder,
251
257
  resolveLaneLoader,
252
258
  selectGatherLane,
253
259
  workerLaneKey,
@@ -282,6 +288,9 @@ export type {
282
288
  export {taskCargoChanges} from './scheduling/task-cargo'
283
289
  export type {TaskCargoChange, TaskCargoDirection} from './scheduling/task-cargo'
284
290
 
291
+ export {jobsToLanes, pickFabricator, socketTail, JOB_QUEUE_CAP} from './scheduling/jobs'
292
+ export type {JobWindow, JobLane, JobLaneEntry} from './scheduling/jobs'
293
+
285
294
  export {composeIdleResolve} from './scheduling/idle-resolve'
286
295
  export type {CounterpartLookup, IdleResolveTarget} from './scheduling/idle-resolve'
287
296
 
@@ -324,6 +333,7 @@ export {
324
333
  ENTITY_WAREHOUSE,
325
334
  ENTITY_EXTRACTOR,
326
335
  ENTITY_FACTORY,
336
+ ENTITY_WORKSHOP,
327
337
  ENTITY_CONTAINER,
328
338
  ENTITY_NEXUS,
329
339
  ENTITY_HUB,
@@ -341,6 +351,7 @@ export {
341
351
  isWarehouse,
342
352
  isExtractor,
343
353
  isFactory,
354
+ isWorkshop,
344
355
  isContainer,
345
356
  isNexus,
346
357
  isPlot,
@@ -428,6 +439,7 @@ export {
428
439
  computeHaulerCapabilities,
429
440
  computeLoaderCapabilities,
430
441
  computeCrafterCapabilities,
442
+ computeBuilderCapabilities,
431
443
  computeWarehouseHullCapabilities,
432
444
  computeStorageCapabilities,
433
445
  computeBatteryCapabilities,
@@ -436,6 +448,8 @@ export {
436
448
  computeLauncherCapabilities,
437
449
  computeBaseCapacity,
438
450
  computeEntityCapabilities,
451
+ getBaseHullmassFor,
452
+ DEFAULT_BASE_HULLMASS,
439
453
  CAPACITY_TIER_TABLE,
440
454
  capacityTierMultiplier,
441
455
  applyCapacityTier,
@@ -443,7 +457,11 @@ export {
443
457
  GATHERER_DEPTH_MAX_TIER,
444
458
  gathererDepthForTier,
445
459
  } from './derivation/capabilities'
446
- export type {GathererDepthParams, ComputedCapabilities} from './derivation/capabilities'
460
+ export type {
461
+ GathererDepthParams,
462
+ ComputedCapabilities,
463
+ TravelDrainBreakdown,
464
+ } from './derivation/capabilities'
447
465
 
448
466
  export {
449
467
  WH,
@@ -457,7 +475,7 @@ export {
457
475
  isValidWormholePair,
458
476
  } from './derivation/wormhole'
459
477
 
460
- export {rollupGatherer, rollupCrafter, rollupLoaders} from './derivation/rollups'
478
+ export {rollupGatherer, rollupCrafter, rollupBuilder, rollupLoaders} from './derivation/rollups'
461
479
 
462
480
  export {resolveItem} from './resolution/resolve-item'
463
481
  export type {
@@ -522,6 +540,11 @@ export {
522
540
  ATOMICASSETS_ACCOUNT,
523
541
  SHIPLOAD_COLLECTION,
524
542
  } from './nft/atomicassets'
543
+ export {
544
+ MODULE_STAT_SCALING_ANCHOR,
545
+ MODULE_STAT_SCALING_POST_ANCHOR_PERCENT,
546
+ computeEffectiveModuleStat,
547
+ } from './derivation/stat-scaling'
525
548
  export type {
526
549
  AtomicAssetRow,
527
550
  AtomicSchemaRow,
@@ -538,6 +561,7 @@ export {
538
561
  computeBaseHullmass,
539
562
  computeBaseCapacityShip,
540
563
  computeBaseCapacityWarehouse,
564
+ computeBaseCapacityContainer,
541
565
  computeEngineThrust,
542
566
  computeEngineDrain,
543
567
  computeTravelDrain,
@@ -553,6 +577,8 @@ export {
553
577
  computeLoaderThrust,
554
578
  computeCrafterSpeed,
555
579
  computeCrafterDrain,
580
+ computeBuilderSpeed,
581
+ computeBuilderDrain,
556
582
  computeHaulerCapacity,
557
583
  computeHaulerEfficiency,
558
584
  computeWarpRange,
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  Action,
3
+ Bytes,
3
4
  Checksum256,
4
5
  type Checksum256Type,
5
6
  Int64,
6
7
  type Int64Type,
7
8
  Name,
8
9
  type NameType,
9
- Transaction,
10
10
  UInt8,
11
11
  type UInt8Type,
12
12
  UInt16,
@@ -21,7 +21,6 @@ import {Coordinates, PRECISION, type ClusterSlotType, type CoordinatesType} from
21
21
  import {ServerContract} from '../contracts'
22
22
  import {ATOMICASSETS_ABI, SHIPLOAD_COLLECTION} from '../nft/atomicassets'
23
23
  import {getItem} from '../data/catalog'
24
- import type {GatherPlan} from '../planner'
25
24
 
26
25
  const CHARGE_K = 1n
27
26
  const ENERGY_DIVISOR = 1_000_000n
@@ -199,12 +198,12 @@ export class ActionsManager extends BaseManager {
199
198
  })
200
199
  }
201
200
 
202
- travelroute(entities: EntityRefInput[], waypoints: WaypointInput[], recharge = true): Action {
201
+ travelplan(entities: EntityRefInput[], waypoints: WaypointInput[], recharge = true): Action {
203
202
  const entityRefs = this.entityRefs(entities)
204
203
  const wps = waypoints.map((w) =>
205
204
  ServerContract.Types.route_waypoint.from({x: Int64.from(w.x), y: Int64.from(w.y)})
206
205
  )
207
- return this.server.action('travelroute', {
206
+ return this.server.action('travelplan', {
208
207
  entities: entityRefs,
209
208
  waypoints: wps,
210
209
  recharge,
@@ -316,6 +315,20 @@ export class ActionsManager extends BaseManager {
316
315
  })
317
316
  }
318
317
 
318
+ shuttle(
319
+ carrierId: UInt64Type,
320
+ fromId: UInt64Type,
321
+ toId: UInt64Type,
322
+ items: ServerContract.ActionParams.Type.cargo_item[]
323
+ ): Action {
324
+ return this.server.action('shuttle', {
325
+ carrier: UInt64.from(carrierId),
326
+ from_id: UInt64.from(fromId),
327
+ to_id: UInt64.from(toId),
328
+ items,
329
+ })
330
+ }
331
+
319
332
  launch(
320
333
  launcherId: UInt64Type,
321
334
  catcherId: UInt64Type,
@@ -388,48 +401,22 @@ export class ActionsManager extends BaseManager {
388
401
  return this.server.action('gather', params)
389
402
  }
390
403
 
391
- // Packs N gather actions into one Transaction; the wallet/session fills in TAPoS at sign time.
392
- bundleGather(
393
- gathers: {
394
- sourceId: UInt64Type
395
- destinationId: UInt64Type
396
- stratum: UInt16Type
397
- quantity: UInt32Type
398
- slot?: UInt8Type
399
- }[]
400
- ): Transaction {
401
- const actions = gathers.map(({sourceId, destinationId, stratum, quantity, slot}) =>
402
- this.gather(sourceId, destinationId, stratum, quantity, slot)
403
- )
404
- return Transaction.from({
405
- expiration: 0,
406
- ref_block_num: 0,
407
- ref_block_prefix: 0,
408
- actions,
409
- })
410
- }
411
-
412
- // Mirrors the contract's projected_energy walk: recharge (if due) then gathers, per cycle.
413
- flattenGatherPlan(
414
- plan: GatherPlan,
415
- ctx: {sourceId: UInt64Type; destinationId: UInt64Type; stratum: UInt16Type}
416
- ): Action[] {
417
- const actions: Action[] = []
418
- for (const cycle of plan.cycles) {
419
- if (cycle.rechargeBefore) actions.push(this.recharge(ctx.sourceId))
420
- for (const limpet of cycle.limpets) {
421
- actions.push(
422
- this.gather(
423
- ctx.sourceId,
424
- ctx.destinationId,
425
- ctx.stratum,
426
- limpet.quantity,
427
- limpet.slot
428
- )
429
- )
430
- }
431
- }
432
- return actions
404
+ gatherplan(
405
+ sourceId: UInt64Type,
406
+ destinationId: UInt64Type,
407
+ stratum: UInt16Type,
408
+ quantity: UInt32Type,
409
+ recharge = true,
410
+ slots: number[] = []
411
+ ): Action {
412
+ return this.server.action('gatherplan', {
413
+ source_id: UInt64.from(sourceId),
414
+ destination_id: UInt64.from(destinationId),
415
+ stratum: UInt16.from(stratum),
416
+ quantity: UInt32.from(quantity),
417
+ recharge,
418
+ slots: Bytes.from(slots),
419
+ })
433
420
  }
434
421
 
435
422
  warp(entityId: UInt64Type, destination: CoordinatesType): Action {
@@ -466,6 +453,50 @@ export class ActionsManager extends BaseManager {
466
453
  return this.server.action('craft', params)
467
454
  }
468
455
 
456
+ craftjob(
457
+ shipId: UInt64Type,
458
+ workshopId: UInt64Type,
459
+ slot: UInt8Type,
460
+ recipeId: UInt16Type,
461
+ quantity: UInt32Type,
462
+ inputs: ServerContract.ActionParams.Type.cargo_item[]
463
+ ): Action {
464
+ const params: ServerContract.ActionParams.craftjob = {
465
+ ship_id: UInt64.from(shipId),
466
+ workshop_id: UInt64.from(workshopId),
467
+ slot: UInt8.from(slot),
468
+ recipe_id: UInt16.from(recipeId),
469
+ quantity: UInt32.from(quantity),
470
+ inputs,
471
+ }
472
+ return this.server.action('craftjob', params)
473
+ }
474
+
475
+ claimjob(jobId: UInt64Type, shipId: UInt64Type): Action {
476
+ const params: ServerContract.ActionParams.claimjob = {
477
+ job_id: UInt64.from(jobId),
478
+ ship_id: UInt64.from(shipId),
479
+ }
480
+ return this.server.action('claimjob', params)
481
+ }
482
+
483
+ canceljob(jobId: UInt64Type, shipId: UInt64Type): Action {
484
+ const params: ServerContract.ActionParams.canceljob = {
485
+ job_id: UInt64.from(jobId),
486
+ ship_id: UInt64.from(shipId),
487
+ }
488
+ return this.server.action('canceljob', params)
489
+ }
490
+
491
+ setsocket(workshopId: UInt64Type, slot: UInt8Type, open: boolean): Action {
492
+ const params: ServerContract.ActionParams.setsocket = {
493
+ workshop_id: UInt64.from(workshopId),
494
+ slot: UInt8.from(slot),
495
+ open,
496
+ }
497
+ return this.server.action('setsocket', params)
498
+ }
499
+
469
500
  blend(entityId: UInt64Type, inputs: ServerContract.ActionParams.Type.cargo_item[]): Action {
470
501
  return this.server.action('blend', {
471
502
  id: UInt64.from(entityId),
@@ -6,7 +6,7 @@ import type {PlotProgress} from './plot'
6
6
 
7
7
  export type BuildState = 'initializing' | 'accepting' | 'ready' | 'scheduled' | 'finalizing'
8
8
 
9
- export type FinalizerCapability = 'crafter'
9
+ export type FinalizerCapability = 'builder'
10
10
 
11
11
  export interface BuildableTarget {
12
12
  entityId: UInt64
@@ -49,7 +49,7 @@ export interface FinalizerEntityRef {
49
49
  entityType: Name
50
50
  name: string
51
51
  capability: FinalizerCapability
52
- crafterSpeed: number
52
+ builderSpeed: number
53
53
  estimatedDuration: UInt32
54
54
  }
55
55
 
@@ -3,7 +3,7 @@ import {BaseManager} from './base'
3
3
  import type {ServerContract} from '../contracts'
4
4
  import {PlotManager} from './plot'
5
5
  import {getItem} from '../data/catalog'
6
- import {calc_craft_duration} from '../capabilities/crafting'
6
+ import {calc_build_duration} from '../capabilities/crafting'
7
7
  import {getLanes, getTasks} from '../scheduling/schedule'
8
8
  import {HoldKind, TaskType} from '../types'
9
9
  import type {
@@ -67,15 +67,15 @@ export class ConstructionManager extends BaseManager {
67
67
  if (!entity.owner.equals(target.ownerName)) continue
68
68
  if (entity.id.equals(target.entityId)) continue
69
69
  if (!coordsEqual(entity.coordinates, target.coordinates)) continue
70
- const crafterLanes = entity.crafter_lanes ?? []
71
- if (crafterLanes.length === 0) continue
72
- const speed = crafterLanes.reduce((s, l) => s + Number(l.speed), 0)
70
+ const builderLanes = entity.builder_lanes ?? []
71
+ if (builderLanes.length === 0) continue
72
+ const speed = builderLanes.reduce((s, l) => s + Number(l.speed), 0)
73
73
  out.push({
74
74
  entityId: entity.id,
75
75
  entityType: entity.type,
76
76
  name: entity.entity_name,
77
- capability: 'crafter',
78
- crafterSpeed: speed,
77
+ capability: 'builder',
78
+ builderSpeed: speed,
79
79
  estimatedDuration: this.estimateFinalizeDuration(target, speed),
80
80
  })
81
81
  }
@@ -105,10 +105,10 @@ export class ConstructionManager extends BaseManager {
105
105
  for (const task of lane.schedule.tasks) {
106
106
  cumulativeSec += task.duration.toNumber()
107
107
  if (!isPushTask(task)) continue
108
- if (!task.entitytarget) continue
108
+ if (task.couplings.length === 0) continue
109
109
  const projectedEndMs = startedMs + cumulativeSec * 1000
110
110
  if (projectedEndMs < nowMs) continue
111
- const targetIdStr = task.entitytarget.entity_id.toString()
111
+ const targetIdStr = task.couplings[0].counterpart.entity_id.toString()
112
112
  const etaSeconds = Math.max(0, Math.round((projectedEndMs - nowMs) / 1000))
113
113
  let perTarget = buckets.get(targetIdStr)
114
114
  if (!perTarget) {
@@ -263,8 +263,8 @@ export class ConstructionManager extends BaseManager {
263
263
  return reservationsOf(source)
264
264
  }
265
265
 
266
- estimateFinalizeDuration(target: BuildableTarget, crafterSpeed: number): UInt32 {
267
- return calc_craft_duration(crafterSpeed, target.progress.massRequired)
266
+ estimateFinalizeDuration(target: BuildableTarget, builderSpeed: number): UInt32 {
267
+ return calc_build_duration(builderSpeed, target.progress.massRequired)
268
268
  }
269
269
 
270
270
  static isConstructionKind(kind: string): boolean {
@@ -370,8 +370,8 @@ function isPushTask(task: ServerContract.Types.task): boolean {
370
370
  function isBuildOfPlot(task: ServerContract.Types.task, plotId: UInt64): boolean {
371
371
  return (
372
372
  task.type.toNumber() === TaskType.BUILDPLOT &&
373
- task.entitytarget !== undefined &&
374
- task.entitytarget.entity_id.equals(plotId)
373
+ task.couplings.length > 0 &&
374
+ task.couplings[0].counterpart.entity_id.equals(plotId)
375
375
  )
376
376
  }
377
377
 
@@ -379,9 +379,9 @@ function reservationsOf(source: ServerContract.Types.entity_info): Reservation[]
379
379
  const out = new Map<string, Reservation>()
380
380
  for (const task of getTasks(source)) {
381
381
  if (!isPushTask(task)) continue
382
- if (!task.entitytarget) continue
383
- const targetType = task.entitytarget.entity_type
384
- const targetId = task.entitytarget.entity_id
382
+ if (task.couplings.length === 0) continue
383
+ const targetType = task.couplings[0].counterpart.entity_type
384
+ const targetId = task.couplings[0].counterpart.entity_id
385
385
  for (const c of task.cargo) {
386
386
  const itemId = c.item_id.toNumber()
387
387
  const quantity = c.quantity.toNumber()
@@ -100,7 +100,7 @@ export class PlotManager extends BaseManager {
100
100
  recipe,
101
101
  progress,
102
102
  finalizeAction: Name.from('buildplot'),
103
- finalizerCapability: 'crafter',
103
+ finalizerCapability: 'builder',
104
104
  activeTask,
105
105
  scheduledBuild,
106
106
  }
@@ -3,6 +3,7 @@ import {getItem} from '../data/catalog'
3
3
  import {
4
4
  getModuleCapabilityType,
5
5
  MODULE_BATTERY,
6
+ MODULE_BUILDER,
6
7
  MODULE_CRAFTER,
7
8
  MODULE_ENGINE,
8
9
  MODULE_GATHERER,
@@ -13,11 +14,14 @@ import {
13
14
  MODULE_WARP,
14
15
  } from '../capabilities/modules'
15
16
  import {decodeStat, decodeCraftedItemStats} from '../derivation/crafting'
17
+ import {computeEffectiveModuleStat} from '../derivation/stat-scaling'
16
18
  import {getStatDefinitions} from '../derivation/stats'
17
19
  import type {ResourceCategory} from '../types'
18
20
  import {Types as ServerTypes} from '../contracts/server'
19
21
  import {
20
22
  buildEntityDescription,
23
+ computeBuilderDrain,
24
+ computeBuilderSpeed,
21
25
  computeCrafterDrain,
22
26
  computeCrafterSpeed,
23
27
  computeEngineDrain,
@@ -28,6 +32,7 @@ import {
28
32
  computeGeneratorCap,
29
33
  computeGeneratorRech,
30
34
  computeCargoBayCapacity,
35
+ computeCargoBayDrain,
31
36
  computeBatteryBankCapacity,
32
37
  computeHaulerCapacity,
33
38
  computeHaulerDrain,
@@ -75,6 +80,10 @@ export function moduleSlotsForImmutable(
75
80
 
76
81
  const IMAGE_HOST_URL = 'https://item.shiploadgame.com/item'
77
82
 
83
+ function toWholeEnergy(milli: number): number {
84
+ return Math.floor((milli + 500) / 1000)
85
+ }
86
+
78
87
  function bytesToBase64Url(bytes: Uint8Array): string {
79
88
  let binary = ''
80
89
  for (let i = 0; i < bytes.byteLength; i++) binary += String.fromCharCode(bytes[i]!)
@@ -183,8 +192,14 @@ export function buildModuleImmutable(
183
192
  const thm = decodeStat(stats, 1)
184
193
  base.push({first: 'volatility', second: ['uint16', vol]})
185
194
  base.push({first: 'thermal', second: ['uint16', thm]})
186
- base.push({first: 'thrust', second: ['uint32', computeEngineThrust(vol)]})
187
- base.push({first: 'drain', second: ['uint16', computeEngineDrain(thm)]})
195
+ base.push({
196
+ first: 'thrust',
197
+ second: ['uint32', computeEngineThrust(computeEffectiveModuleStat(vol))],
198
+ })
199
+ base.push({
200
+ first: 'drain',
201
+ second: ['uint16', computeEngineDrain(computeEffectiveModuleStat(thm))],
202
+ })
188
203
  break
189
204
  }
190
205
  case MODULE_GENERATOR: {
@@ -192,8 +207,20 @@ export function buildModuleImmutable(
192
207
  const ref = decodeStat(stats, 1)
193
208
  base.push({first: 'resonance', second: ['uint16', res]})
194
209
  base.push({first: 'reflectivity', second: ['uint16', ref]})
195
- base.push({first: 'capacity', second: ['uint16', computeGeneratorCap(res)]})
196
- base.push({first: 'recharge', second: ['uint16', computeGeneratorRech(ref)]})
210
+ base.push({
211
+ first: 'capacity',
212
+ second: [
213
+ 'uint16',
214
+ toWholeEnergy(computeGeneratorCap(computeEffectiveModuleStat(res))),
215
+ ],
216
+ })
217
+ base.push({
218
+ first: 'recharge',
219
+ second: [
220
+ 'uint16',
221
+ toWholeEnergy(computeGeneratorRech(computeEffectiveModuleStat(ref))),
222
+ ],
223
+ })
197
224
  break
198
225
  }
199
226
  case MODULE_GATHERER: {
@@ -204,7 +231,10 @@ export function buildModuleImmutable(
204
231
  base.push({first: 'hardness', second: ['uint16', hrd]})
205
232
  base.push({first: 'saturation', second: ['uint16', sat]})
206
233
  base.push({first: 'yield', second: ['uint16', computeGathererYield(str)]})
207
- base.push({first: 'drain', second: ['uint16', computeGathererDrain(sat)]})
234
+ base.push({
235
+ first: 'drain',
236
+ second: ['uint16', toWholeEnergy(computeGathererDrain(sat))],
237
+ })
208
238
  base.push({first: 'depth', second: ['uint16', computeGathererDepth(hrd, item.tier)]})
209
239
  break
210
240
  }
@@ -229,7 +259,16 @@ export function buildModuleImmutable(
229
259
  base.push({first: 'fineness', second: ['uint16', fin]})
230
260
  base.push({first: 'conductivity', second: ['uint16', con]})
231
261
  base.push({first: 'speed', second: ['uint16', computeCrafterSpeed(fin)]})
232
- base.push({first: 'drain', second: ['uint16', computeCrafterDrain(con)]})
262
+ base.push({first: 'drain', second: ['uint16', toWholeEnergy(computeCrafterDrain(con))]})
263
+ break
264
+ }
265
+ case MODULE_BUILDER: {
266
+ const res = decodeStat(stats, 0)
267
+ const fin = decodeStat(stats, 1)
268
+ base.push({first: 'resonance', second: ['uint16', res]})
269
+ base.push({first: 'fineness', second: ['uint16', fin]})
270
+ base.push({first: 'speed', second: ['uint16', computeBuilderSpeed(res)]})
271
+ base.push({first: 'drain', second: ['uint16', toWholeEnergy(computeBuilderDrain(fin))]})
233
272
  break
234
273
  }
235
274
  case MODULE_STORAGE: {
@@ -243,7 +282,11 @@ export function buildModuleImmutable(
243
282
  base.push({first: 'cohesion', second: ['uint16', com]})
244
283
  base.push({
245
284
  first: 'capacity',
246
- second: ['uint32', computeCargoBayCapacity(str, den, hrd, com)],
285
+ second: ['uint32', computeCargoBayCapacity(str, den, hrd)],
286
+ })
287
+ base.push({
288
+ first: 'drain',
289
+ second: ['uint16', toWholeEnergy(computeCargoBayDrain(com, item.tier))],
247
290
  })
248
291
  break
249
292
  }
@@ -258,7 +301,7 @@ export function buildModuleImmutable(
258
301
  base.push({first: 'insulation', second: ['uint16', ins]})
259
302
  base.push({
260
303
  first: 'capacity',
261
- second: ['uint32', computeBatteryBankCapacity(vol, thm, pla, ins)],
304
+ second: ['uint32', toWholeEnergy(computeBatteryBankCapacity(vol, thm, pla, ins))],
262
305
  })
263
306
  break
264
307
  }
@@ -271,7 +314,10 @@ export function buildModuleImmutable(
271
314
  base.push({first: 'conductivity', second: ['uint16', con]})
272
315
  base.push({first: 'capacity', second: ['uint8', computeHaulerCapacity(res, item.tier)]})
273
316
  base.push({first: 'efficiency', second: ['uint16', computeHaulerEfficiency(pla)]})
274
- base.push({first: 'drain', second: ['uint16', computeHaulerDrain(con)]})
317
+ base.push({
318
+ first: 'drain',
319
+ second: ['uint16', toWholeEnergy(computeHaulerDrain(con, item.tier))],
320
+ })
275
321
  break
276
322
  }
277
323
  }