@shipload/sdk 1.0.0-next.65 → 1.0.0-next.67

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 (85) hide show
  1. package/lib/shipload.d.ts +786 -321
  2. package/lib/shipload.js +2731 -1305
  3. package/lib/shipload.js.map +1 -1
  4. package/lib/shipload.m.js +2644 -1286
  5. package/lib/shipload.m.js.map +1 -1
  6. package/lib/testing.d.ts +223 -146
  7. package/lib/testing.js +907 -563
  8. package/lib/testing.js.map +1 -1
  9. package/lib/testing.m.js +907 -563
  10. package/lib/testing.m.js.map +1 -1
  11. package/package.json +1 -1
  12. package/src/capabilities/crafting.test.ts +51 -6
  13. package/src/capabilities/crafting.ts +19 -4
  14. package/src/capabilities/gathering.ts +2 -2
  15. package/src/capabilities/storage.test.ts +26 -0
  16. package/src/capabilities/storage.ts +6 -6
  17. package/src/contracts/fund.ts +79 -2
  18. package/src/contracts/platform.ts +10 -1
  19. package/src/contracts/server.ts +521 -330
  20. package/src/data/charters.json +325 -127
  21. package/src/data/entities.json +29 -24
  22. package/src/data/items.json +114 -114
  23. package/src/data/kind-registry.json +3 -3
  24. package/src/data/kind-registry.ts +5 -0
  25. package/src/data/metadata.ts +9 -2
  26. package/src/data/recipes.json +56 -95
  27. package/src/derivation/build-methods.test.ts +59 -1
  28. package/src/derivation/build-methods.ts +2 -0
  29. package/src/derivation/capabilities.ts +7 -7
  30. package/src/derivation/strata.ts +5 -3
  31. package/src/derivation/tiers.ts +5 -5
  32. package/src/entity/hydrate.test.ts +156 -0
  33. package/src/entity/hydrate.ts +86 -0
  34. package/src/errors.ts +9 -0
  35. package/src/format.ts +15 -13
  36. package/src/index-module.ts +32 -5
  37. package/src/influence/ballot.test.ts +103 -0
  38. package/src/influence/ballot.ts +98 -0
  39. package/src/influence/charter-metadata.test.ts +136 -0
  40. package/src/influence/charter-metadata.ts +236 -0
  41. package/src/influence/charters.test.ts +51 -65
  42. package/src/influence/charters.ts +70 -40
  43. package/src/influence/civic-shuttle.test.ts +159 -0
  44. package/src/influence/civic-shuttle.ts +115 -0
  45. package/src/influence/civic.test.ts +287 -0
  46. package/src/influence/civic.ts +269 -0
  47. package/src/influence/constants.ts +30 -9
  48. package/src/influence/decomp.ts +15 -15
  49. package/src/influence/duration.ts +42 -6
  50. package/src/influence/index.ts +59 -6
  51. package/src/influence/influence.test.ts +76 -9
  52. package/src/influence/valuation.ts +17 -17
  53. package/src/managers/actions.ts +99 -37
  54. package/src/managers/base.ts +4 -0
  55. package/src/managers/context.ts +3 -1
  56. package/src/managers/epochs.ts +32 -1
  57. package/src/managers/index.ts +4 -2
  58. package/src/managers/influence.test.ts +18 -20
  59. package/src/managers/influence.ts +137 -84
  60. package/src/managers/jobs.test.ts +2 -2
  61. package/src/managers/jobs.ts +4 -4
  62. package/src/nft/description.ts +10 -11
  63. package/src/planner/index.ts +54 -0
  64. package/src/planner/planner.test.ts +127 -2
  65. package/src/resolution/display-name.ts +1 -1
  66. package/src/scheduling/availability.test.ts +113 -0
  67. package/src/scheduling/availability.ts +48 -8
  68. package/src/scheduling/epoch.ts +1 -0
  69. package/src/scheduling/jobs.ts +1 -1
  70. package/src/scheduling/projection.ts +2 -16
  71. package/src/scheduling/task-cargo.test.ts +62 -1
  72. package/src/scheduling/task-cargo.ts +25 -10
  73. package/src/scheduling/task-effects.test.ts +35 -0
  74. package/src/scheduling/task-effects.ts +34 -0
  75. package/src/scheduling/unwrap.test.ts +3 -3
  76. package/src/scheduling/unwrap.ts +3 -3
  77. package/src/shipload.ts +22 -3
  78. package/src/travel/reach.test.ts +86 -0
  79. package/src/travel/reach.ts +23 -10
  80. package/src/travel/route-build.test.ts +63 -0
  81. package/src/travel/route-build.ts +60 -0
  82. package/src/travel/travel.ts +2 -1
  83. package/src/types.ts +6 -2
  84. package/src/utils/hash.ts +18 -2
  85. package/src/utils/system.ts +6 -1
@@ -4,40 +4,40 @@ import recipes from '../data/recipes.json'
4
4
  import {
5
5
  DECOMP_MAX_BUCKETS,
6
6
  DECOMP_MAX_DEPTH,
7
- DECOMP_PROCESSED_KG_MAX,
8
- DECOMP_RAW_KG_MAX,
7
+ DECOMP_PROCESSED_MASS_MAX,
8
+ DECOMP_RAW_MASS_MAX,
9
9
  } from './constants'
10
10
  import {categoryIndex} from './categories'
11
11
 
12
12
  export interface DecompBucket {
13
13
  category: number
14
14
  tier: number
15
- rawKg: number
15
+ rawMass: number
16
16
  }
17
17
 
18
18
  export interface DecompEntry {
19
19
  itemId: number
20
- processedKg: number
20
+ processedMass: number
21
21
  buckets: DecompBucket[]
22
22
  }
23
23
 
24
24
  interface Accumulator {
25
25
  buckets: DecompBucket[]
26
- processedKg: number
26
+ processedMass: number
27
27
  overflow: boolean
28
28
  }
29
29
 
30
- function add(acc: Accumulator, category: number, tier: number, kg: number): void {
30
+ function add(acc: Accumulator, category: number, tier: number, mass: number): void {
31
31
  const existing = acc.buckets.find((b) => b.category === category && b.tier === tier)
32
32
  if (existing) {
33
- existing.rawKg += kg
33
+ existing.rawMass += mass
34
34
  return
35
35
  }
36
36
  if (acc.buckets.length >= DECOMP_MAX_BUCKETS) {
37
37
  acc.overflow = true
38
38
  return
39
39
  }
40
- acc.buckets.push({category, tier, rawKg: kg})
40
+ acc.buckets.push({category, tier, rawMass: mass})
41
41
  }
42
42
 
43
43
  function walk(itemId: number, multiplier: number, acc: Accumulator, depth: number): void {
@@ -51,14 +51,14 @@ function walk(itemId: number, multiplier: number, acc: Accumulator, depth: numbe
51
51
  for (const input of recipe.inputs) {
52
52
  const def = tryGetItem(input.itemId)
53
53
  const units = multiplier * input.quantity
54
- const kg = units * (def ? def.mass : 0)
55
- acc.processedKg += kg
54
+ const mass = units * (def ? def.mass : 0)
55
+ acc.processedMass += mass
56
56
  if (getRecipe(input.itemId)) {
57
57
  walk(input.itemId, units, acc, depth + 1)
58
58
  } else if (def?.type !== 'resource' || def.category === undefined) {
59
59
  acc.overflow = true
60
60
  } else {
61
- add(acc, categoryIndex(def.category), def.tier, kg)
61
+ add(acc, categoryIndex(def.category), def.tier, mass)
62
62
  }
63
63
  }
64
64
  }
@@ -66,18 +66,18 @@ function walk(itemId: number, multiplier: number, acc: Accumulator, depth: numbe
66
66
  function buildRegistry(): DecompEntry[] {
67
67
  const out: DecompEntry[] = []
68
68
  for (const recipe of recipes as {outputItemId: number}[]) {
69
- const acc: Accumulator = {buckets: [], processedKg: 0, overflow: false}
69
+ const acc: Accumulator = {buckets: [], processedMass: 0, overflow: false}
70
70
  walk(recipe.outputItemId, 1, acc, 0)
71
71
  acc.buckets.sort((a, b) => a.category - b.category || a.tier - b.tier)
72
72
 
73
- const rawTotal = acc.buckets.reduce((sum, b) => sum + b.rawKg, 0)
74
- if (rawTotal > DECOMP_RAW_KG_MAX || acc.processedKg > DECOMP_PROCESSED_KG_MAX) {
73
+ const rawTotal = acc.buckets.reduce((sum, b) => sum + b.rawMass, 0)
74
+ if (rawTotal > DECOMP_RAW_MASS_MAX || acc.processedMass > DECOMP_PROCESSED_MASS_MAX) {
75
75
  acc.overflow = true
76
76
  }
77
77
 
78
78
  out.push({
79
79
  itemId: recipe.outputItemId,
80
- processedKg: acc.overflow ? 0 : acc.processedKg,
80
+ processedMass: acc.overflow ? 0 : acc.processedMass,
81
81
  buckets: acc.buckets,
82
82
  })
83
83
  }
@@ -1,5 +1,10 @@
1
+ import type {NameType} from '@wharfkit/antelope'
2
+ import type {ServerContract} from '../contracts'
3
+ import {getEntityClass} from '../data/kind-registry'
1
4
  import {computeLoaderMass, computeLoaderThrust} from '../nft/description'
2
- import {PRECISION} from '../types'
5
+ import {laneKeyForModule, resolveLaneLoader} from '../scheduling/lanes'
6
+ import {calc_onesided_duration} from '../travel/travel'
7
+ import {MASS_STAT_SCALE, MASS_UNITS_PER_TONNE, PRECISION} from '../types'
3
8
  import {CIVIC_LOADER_STAT, CIVIC_LOADER_TIER, DEFAULT_ORBITAL_Z} from './constants'
4
9
 
5
10
  export interface CivicLoaderStats {
@@ -16,7 +21,7 @@ export function civicLoader(): CivicLoaderStats {
16
21
 
17
22
  function acceleration(thrust: number, mass: number): number {
18
23
  if (mass <= 0) return 0
19
- return (thrust / mass) * PRECISION
24
+ return (thrust / (mass * MASS_STAT_SCALE)) * PRECISION
20
25
  }
21
26
 
22
27
  function flightTime(distance: number, accel: number): number {
@@ -24,13 +29,44 @@ function flightTime(distance: number, accel: number): number {
24
29
  return Math.floor(2 * Math.sqrt(distance / accel))
25
30
  }
26
31
 
27
- export function contributeDuration(totalMassKg: number, altitudeZ = 0): number {
32
+ export function contributeDuration(totalMass: number, altitudeZ = 0): number {
28
33
  const loader = civicLoader()
29
- const totalMass = totalMassKg + loader.mass
34
+ const mass = totalMass + loader.mass
30
35
  const z = Math.max(altitudeZ, DEFAULT_ORBITAL_Z)
31
- return flightTime(z, acceleration(loader.thrust, totalMass))
36
+ return flightTime(z, acceleration(loader.thrust, mass))
32
37
  }
33
38
 
34
39
  export function contributeDurationForTonnes(tonnes: number, altitudeZ = 0): number {
35
- return contributeDuration(Math.floor(tonnes * 1000), altitudeZ)
40
+ return contributeDuration(Math.floor(tonnes * MASS_UNITS_PER_TONNE), altitudeZ)
41
+ }
42
+
43
+ export const DEPOT_LOADER_SLOT = 0
44
+
45
+ export interface DepotTransferParams {
46
+ depotModules: ServerContract.Types.module_entry[]
47
+ depotItemId: number
48
+ depotKind: NameType
49
+ depotZ: number
50
+ shipKind: NameType
51
+ shipZ: number
52
+ cargoMass: number
53
+ }
54
+
55
+ // Mirrors depot.cpp: the depot's slot-0 loader drives the transfer; 0 when no loader is installed.
56
+ export function depotTransferDuration(params: DepotTransferParams): number {
57
+ const loader = resolveLaneLoader(
58
+ params.depotModules,
59
+ params.depotItemId,
60
+ laneKeyForModule(DEPOT_LOADER_SLOT)
61
+ )
62
+ if (!loader.valid) return 0
63
+ return calc_onesided_duration(
64
+ loader.thrust,
65
+ loader.mass,
66
+ params.shipZ,
67
+ params.depotZ,
68
+ getEntityClass(params.shipKind),
69
+ getEntityClass(params.depotKind),
70
+ params.cargoMass
71
+ )
36
72
  }
@@ -38,26 +38,79 @@ export {
38
38
  civicLoader,
39
39
  contributeDuration,
40
40
  contributeDurationForTonnes,
41
+ depotTransferDuration,
42
+ DEPOT_LOADER_SLOT,
41
43
  type CivicLoaderStats,
44
+ type DepotTransferParams,
42
45
  } from './duration'
46
+ export {
47
+ civicShuttleBays,
48
+ civicTransfersAtCap,
49
+ civicTransfersFrom,
50
+ pendingCivicTransfers,
51
+ selectCivicShuttleBay,
52
+ CIVIC_TRANSFER_PER_PLAYER_CAP,
53
+ type CivicShuttleBay,
54
+ type PendingCivicTransfer,
55
+ } from './civic-shuttle'
43
56
  export {citizenryName, citizenryPatternCount} from './citizenry'
44
57
  export {
45
- charterEffectTargetEntity,
46
- charterEffectTargetPresent,
58
+ charterBuildingEntity,
47
59
  charterEligible,
60
+ charterEligibleChained,
61
+ charterGateNodeFor,
48
62
  charterIneligible,
49
63
  charterNode,
50
64
  charterPrereqsMet,
65
+ charterRungValue,
51
66
  charterSingletonMandate,
52
- charterSpawnNodeFor,
67
+ charterModuleCount,
53
68
  CHARTER_INELIGIBILITY_MESSAGES,
54
69
  CHARTER_REGISTRY,
55
- effectiveMandate,
56
70
  eligibleCharters,
57
71
  type BuiltCharter,
58
- type CharterEffect,
72
+ type CharterGrant,
59
73
  type CharterIneligibility,
60
74
  type CharterNode,
61
75
  type CharterWorld,
62
- type ChosenCharter,
76
+ type WorldBuilding,
63
77
  } from './charters'
78
+ export {
79
+ projectBallot,
80
+ type BallotInput,
81
+ type BallotProjection,
82
+ type BallotVoter,
83
+ type ProjectedOption,
84
+ type ProjectedSeat,
85
+ } from './ballot'
86
+ export {
87
+ charterMetadata,
88
+ charterName,
89
+ charterSignature,
90
+ charterSummary,
91
+ civicBuildingLabel,
92
+ civicStatLabel,
93
+ romanNumeral,
94
+ type CharterGateSignature,
95
+ type CharterMeta,
96
+ type CharterRungSignature,
97
+ type CharterSignature,
98
+ } from './charter-metadata'
99
+ export {
100
+ CIVIC_STAT_DEFS,
101
+ civicBuildingFor,
102
+ civicBuildingKind,
103
+ civicHullItem,
104
+ civicModuleItemFor,
105
+ civicStatModuleType,
106
+ emptyCivicModules,
107
+ findCivicStatDef,
108
+ fitCivicModules,
109
+ isCivicEntity,
110
+ isCivicKind,
111
+ previewCharterGrants,
112
+ raiseCivicStat,
113
+ type CivicBuildingPreview,
114
+ type CivicStanding,
115
+ type CivicStatDef,
116
+ } from './civic'
@@ -1,5 +1,6 @@
1
1
  import {describe, expect, test} from 'bun:test'
2
- import {Checksum256} from '@wharfkit/antelope'
2
+ import {Checksum256, UInt8, UInt16, UInt64} from '@wharfkit/antelope'
3
+ import type {ServerContract} from '../contracts'
3
4
  import {ITEM_ORE_T1, ITEM_PLATE, ITEM_CRYSTAL_T1} from '../data/item-ids'
4
5
  import {categoryIndex} from './categories'
5
6
  import {
@@ -19,7 +20,7 @@ import {
19
20
  popcount5,
20
21
  } from './demand'
21
22
  import {findDecomp, DECOMP_REGISTRY} from './decomp'
22
- import {contributeDuration} from './duration'
23
+ import {depotTransferDuration, contributeDuration} from './duration'
23
24
  import {getStatCount, statsSumSq} from './quality'
24
25
  import {pricingFromWeights, valueCargoItem, valueContribution} from './valuation'
25
26
  import {citizenryName, citizenryPatternCount} from './citizenry'
@@ -135,7 +136,7 @@ describe('decomposition', () => {
135
136
  for (let i = 1; i < DECOMP_REGISTRY.length; i++) {
136
137
  expect(DECOMP_REGISTRY[i].itemId).toBeGreaterThan(DECOMP_REGISTRY[i - 1].itemId)
137
138
  }
138
- expect(DECOMP_REGISTRY.length).toBe(57)
139
+ expect(DECOMP_REGISTRY.length).toBe(56)
139
140
  })
140
141
 
141
142
  test('the retired Workshop has no decomposition entry', () => {
@@ -145,7 +146,7 @@ describe('decomposition', () => {
145
146
  test('buckets are sorted and hold only raw resources', () => {
146
147
  const entry = findDecomp(ITEM_PLATE)
147
148
  if (!entry) throw new Error('Plate has no decomposition entry')
148
- expect(entry.processedKg).toBeGreaterThan(0)
149
+ expect(entry.processedMass).toBeGreaterThan(0)
149
150
  for (let i = 1; i < entry.buckets.length; i++) {
150
151
  const prev = entry.buckets[i - 1]
151
152
  const cur = entry.buckets[i]
@@ -250,18 +251,18 @@ describe('valuation', () => {
250
251
 
251
252
  describe('contribution duration', () => {
252
253
  test('grows with mass and never falls below a single tick', () => {
253
- expect(contributeDuration(1_000)).toBeGreaterThan(0)
254
- expect(contributeDuration(1_000_000)).toBeGreaterThan(contributeDuration(1_000))
254
+ expect(contributeDuration(10)).toBeGreaterThan(0)
255
+ expect(contributeDuration(10_000)).toBeGreaterThan(contributeDuration(10))
255
256
  })
256
257
 
257
258
  test('splitting a haul costs more than one trip', () => {
258
- const single = contributeDuration(100_000_000)
259
- const hundred = contributeDuration(1_000_000) * 100
259
+ const single = contributeDuration(1_000_000)
260
+ const hundred = contributeDuration(10_000) * 100
260
261
  expect(hundred).toBeGreaterThan(single)
261
262
  })
262
263
 
263
264
  test('ground level is floored at the base orbital climb', () => {
264
- expect(contributeDuration(1_000, 0)).toBe(contributeDuration(1_000, 800))
265
+ expect(contributeDuration(10, 0)).toBe(contributeDuration(10, 800))
265
266
  })
266
267
  })
267
268
 
@@ -315,3 +316,69 @@ describe('scales', () => {
315
316
  expect(NEED_FP_SCALE % INFLUENCE_ATOMIC_PER_POINT).toBe(0)
316
317
  })
317
318
  })
319
+
320
+ describe('depot transfer duration', () => {
321
+ type ModuleEntry = ServerContract.Types.module_entry
322
+ const DEPOT_ITEM = 10219
323
+ const LOADER_T1 = 10103
324
+
325
+ function makeModuleEntry(itemId: number, stats: bigint): ModuleEntry {
326
+ return {
327
+ type: UInt8.from(0),
328
+ installed: {item_id: UInt16.from(itemId), stats: UInt64.from(stats)},
329
+ } as unknown as ModuleEntry
330
+ }
331
+ function emptySlot(): ModuleEntry {
332
+ return {type: UInt8.from(0)} as unknown as ModuleEntry
333
+ }
334
+
335
+ // A spawned depot: loader in slot 0, four empty bays after it.
336
+ const depotWithLoader = (): ModuleEntry[] => [
337
+ makeModuleEntry(LOADER_T1, packStats(500)),
338
+ emptySlot(),
339
+ emptySlot(),
340
+ emptySlot(),
341
+ emptySlot(),
342
+ ]
343
+ const params = (overrides: Record<string, unknown> = {}) => ({
344
+ depotModules: depotWithLoader(),
345
+ depotItemId: DEPOT_ITEM,
346
+ depotKind: 'depot',
347
+ depotZ: 0,
348
+ shipKind: 'ship',
349
+ shipZ: 0,
350
+ cargoMass: 100,
351
+ ...overrides,
352
+ })
353
+
354
+ test('drives off the depot loader, not the ship', () => {
355
+ expect(depotTransferDuration(params())).toBeGreaterThan(0)
356
+ })
357
+
358
+ test('grows with cargo mass', () => {
359
+ expect(depotTransferDuration(params({cargoMass: 10_000}))).toBeGreaterThan(
360
+ depotTransferDuration(params({cargoMass: 100}))
361
+ )
362
+ })
363
+
364
+ test('empty cargo costs nothing', () => {
365
+ expect(depotTransferDuration(params({cargoMass: 0}))).toBe(0)
366
+ })
367
+
368
+ test('a depot with no loader installed cannot transfer', () => {
369
+ expect(depotTransferDuration(params({depotModules: [emptySlot()]}))).toBe(0)
370
+ })
371
+
372
+ test('co-located transfers are floored at the orbital minimum distance', () => {
373
+ // max(planetary 100, orbital 200) = 200, so anything under 200 reads as 200
374
+ const touching = depotTransferDuration(params({shipZ: 0, depotZ: 0}))
375
+ const under = depotTransferDuration(params({shipZ: 150, depotZ: 0}))
376
+ const over = depotTransferDuration(params({shipZ: 400, depotZ: 0}))
377
+ expect(under).toBe(touching)
378
+ expect(over).toBeGreaterThan(touching)
379
+ })
380
+
381
+ test('never reports zero for real cargo', () => {
382
+ expect(depotTransferDuration(params({cargoMass: 1}))).toBeGreaterThanOrEqual(1)
383
+ })
384
+ })
@@ -1,14 +1,14 @@
1
1
  import {getItem} from '../data/catalog'
2
+ import {MASS_UNITS_PER_TONNE} from '../types'
2
3
  import {categoryIndex} from './categories'
3
4
  import {
4
5
  INFLUENCE_ATOMIC_PER_POINT,
5
- INFLUENCE_MASS_KG_MAX,
6
+ INFLUENCE_MASS_MAX,
6
7
  INFLUENCE_NEED_FP_MAX,
7
8
  INFLUENCE_WEIGHT_FP_MAX,
8
- MASS_KG_PER_TONNE,
9
9
  NEED_FP_SCALE,
10
10
  WEIGHT_FP_SCALE,
11
- W_EFF_ATOMIC_PER_KG,
11
+ W_EFF_ATOMIC_PER_UNIT,
12
12
  } from './constants'
13
13
  import {findDecomp} from './decomp'
14
14
  import type {DemandView} from './demand'
@@ -29,16 +29,16 @@ export interface ValuedItem {
29
29
  }
30
30
 
31
31
  export function weightedQualityAtomic(
32
- weightedKgFp: bigint,
32
+ weightedMassFp: bigint,
33
33
  sumSq: number,
34
34
  nStats: number,
35
35
  d1: number,
36
36
  needFp: bigint
37
37
  ): bigint {
38
38
  if (nStats <= 0 || d1 <= 0) throw new Error('influence: invalid quality divisor')
39
- const num = weightedKgFp * BigInt(sumSq) * needFp
39
+ const num = weightedMassFp * BigInt(sumSq) * needFp
40
40
  const den =
41
- (BigInt(MASS_KG_PER_TONNE) *
41
+ (BigInt(MASS_UNITS_PER_TONNE) *
42
42
  BigInt(WEIGHT_FP_SCALE) *
43
43
  BigInt(nStats) *
44
44
  BigInt(d1) *
@@ -48,34 +48,34 @@ export function weightedQualityAtomic(
48
48
  }
49
49
 
50
50
  export function resourceValueAtomic(
51
- massKg: bigint,
51
+ mass: bigint,
52
52
  weightFp: bigint,
53
53
  sumSq: number,
54
54
  nStats: number,
55
55
  d1: number,
56
56
  needFp: bigint
57
57
  ): bigint {
58
- if (massKg > INFLUENCE_MASS_KG_MAX) throw new Error('influence: mass out of range')
58
+ if (mass > INFLUENCE_MASS_MAX) throw new Error('influence: mass out of range')
59
59
  if (weightFp > INFLUENCE_WEIGHT_FP_MAX) throw new Error('influence: weight out of range')
60
60
  if (needFp > INFLUENCE_NEED_FP_MAX) throw new Error('influence: need out of range')
61
- return weightedQualityAtomic(massKg * weightFp, sumSq, nStats, d1, needFp)
61
+ return weightedQualityAtomic(mass * weightFp, sumSq, nStats, d1, needFp)
62
62
  }
63
63
 
64
64
  export function componentBaseAtomic(
65
- weightedRawKgFp: bigint,
65
+ weightedRawMassFp: bigint,
66
66
  sumSq: number,
67
67
  nStats: number,
68
68
  d1: number
69
69
  ): bigint {
70
- return weightedQualityAtomic(weightedRawKgFp, sumSq, nStats, d1, BigInt(NEED_FP_SCALE))
70
+ return weightedQualityAtomic(weightedRawMassFp, sumSq, nStats, d1, BigInt(NEED_FP_SCALE))
71
71
  }
72
72
 
73
- export function componentEffortAtomic(processedKgPerUnit: number, quantity: number): bigint {
74
- const processed = BigInt(processedKgPerUnit) * BigInt(quantity)
75
- if (processed > INFLUENCE_MASS_KG_MAX) {
73
+ export function componentEffortAtomic(processedMassPerUnit: number, quantity: number): bigint {
74
+ const processed = BigInt(processedMassPerUnit) * BigInt(quantity)
75
+ if (processed > INFLUENCE_MASS_MAX) {
76
76
  throw new Error('influence: processed mass out of range')
77
77
  }
78
- return processed * W_EFF_ATOMIC_PER_KG
78
+ return processed * W_EFF_ATOMIC_PER_UNIT
79
79
  }
80
80
 
81
81
  export function valueCargoItem(
@@ -114,14 +114,14 @@ export function valueCargoItem(
114
114
 
115
115
  let weighted = 0n
116
116
  for (const bucket of entry.buckets) {
117
- weighted += BigInt(bucket.rawKg) * pricing.weight(bucket.category, bucket.tier)
117
+ weighted += BigInt(bucket.rawMass) * pricing.weight(bucket.category, bucket.tier)
118
118
  }
119
119
 
120
120
  const perUnit = componentBaseAtomic(weighted, sumSq, nStats, pricing.d1)
121
121
  const total = perUnit * BigInt(item.quantity)
122
122
  if (total > UINT64_MAX) throw new Error('influence: component value overflow')
123
123
 
124
- const withEffort = total + componentEffortAtomic(entry.processedKg, item.quantity)
124
+ const withEffort = total + componentEffortAtomic(entry.processedMass, item.quantity)
125
125
  if (withEffort > UINT64_MAX) throw new Error('influence: component value overflow')
126
126
  return withEffort
127
127
  }