@shipload/sdk 1.0.0-next.7 → 1.0.0-next.71
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.
- package/lib/scan.d.ts +52 -0
- package/lib/scan.js +162 -0
- package/lib/scan.js.map +1 -0
- package/lib/scan.m.js +152 -0
- package/lib/scan.m.js.map +1 -0
- package/lib/shipload.d.ts +5822 -1484
- package/lib/shipload.js +20838 -5419
- package/lib/shipload.js.map +1 -1
- package/lib/shipload.m.js +20674 -5669
- package/lib/shipload.m.js.map +1 -1
- package/lib/testing.d.ts +1691 -0
- package/lib/testing.js +7109 -0
- package/lib/testing.js.map +1 -0
- package/lib/testing.m.js +7103 -0
- package/lib/testing.m.js.map +1 -0
- package/package.json +20 -2
- package/src/capabilities/craftable.test.ts +82 -0
- package/src/capabilities/craftable.ts +82 -0
- package/src/capabilities/crafting.test.ts +80 -0
- package/src/capabilities/crafting.ts +50 -8
- package/src/capabilities/gathering.test.ts +29 -0
- package/src/capabilities/gathering.ts +38 -20
- package/src/capabilities/hauling.ts +0 -5
- package/src/capabilities/index.ts +0 -1
- package/src/capabilities/modules.ts +27 -30
- package/src/capabilities/movement.ts +1 -1
- package/src/capabilities/storage.test.ts +26 -0
- package/src/capabilities/storage.ts +22 -7
- package/src/contracts/fund.ts +306 -0
- package/src/contracts/platform.ts +312 -3
- package/src/contracts/server.ts +2793 -478
- package/src/contracts/token.ts +170 -0
- package/src/contracts.ts +2 -0
- package/src/coordinates/address.ts +88 -0
- package/src/coordinates/constants.test.ts +15 -0
- package/src/coordinates/constants.ts +23 -0
- package/src/coordinates/index.ts +15 -0
- package/src/coordinates/memo.test.ts +47 -0
- package/src/coordinates/memo.ts +20 -0
- package/src/coordinates/permutation.ts +77 -0
- package/src/coordinates/regions.ts +48 -0
- package/src/coordinates/sectors.ts +115 -0
- package/src/data/capabilities.ts +49 -18
- package/src/data/capability-formulas.ts +26 -14
- package/src/data/catalog.test.ts +19 -0
- package/src/data/catalog.ts +13 -3
- package/src/data/charters.json +396 -0
- package/src/data/citizenry-adjectives.json +42 -0
- package/src/data/citizenry-nouns.json +50 -0
- package/src/data/colors.ts +14 -32
- package/src/data/entities.json +421 -15
- package/src/data/item-ids.ts +53 -13
- package/src/data/items.json +330 -77
- package/src/data/kind-registry.json +212 -0
- package/src/data/kind-registry.ts +192 -0
- package/src/data/metadata.ts +312 -51
- package/src/data/recipes-runtime.ts +6 -23
- package/src/data/recipes.json +2173 -173
- package/src/data/tiers.ts +9 -6
- package/src/derivation/build-methods.test.ts +71 -0
- package/src/derivation/build-methods.ts +50 -0
- package/src/derivation/capabilities.test.ts +348 -0
- package/src/derivation/capabilities.ts +707 -0
- package/src/derivation/capability-mappings.ts +60 -16
- package/src/derivation/crafting.test.ts +17 -0
- package/src/derivation/crafting.ts +57 -34
- package/src/derivation/index.ts +27 -2
- package/src/derivation/recipe-usage.test.ts +88 -0
- package/src/derivation/recipe-usage.ts +141 -0
- package/src/derivation/reserve-regen.ts +34 -0
- package/src/derivation/resources.ts +9 -1
- package/src/derivation/rollups.test.ts +55 -0
- package/src/derivation/rollups.ts +72 -0
- package/src/derivation/stars.test.ts +67 -0
- package/src/derivation/stars.ts +25 -0
- package/src/derivation/stat-scaling.ts +12 -0
- package/src/derivation/stats.ts +6 -6
- package/src/derivation/strata.ts +5 -3
- package/src/derivation/stratum.ts +26 -22
- package/src/derivation/tiers.ts +40 -7
- package/src/derivation/upgrades.ts +14 -0
- package/src/derivation/wormhole.ts +154 -0
- package/src/entities/entity.ts +102 -0
- package/src/entities/gamestate.ts +3 -28
- package/src/entities/makers.ts +144 -136
- package/src/entities/slot-multiplier.ts +43 -0
- package/src/entity/hydrate.test.ts +156 -0
- package/src/entity/hydrate.ts +86 -0
- package/src/errors.ts +21 -16
- package/src/format.ts +42 -9
- package/src/index-module.ts +425 -32
- package/src/influence/ballot.test.ts +103 -0
- package/src/influence/ballot.ts +98 -0
- package/src/influence/categories.ts +32 -0
- package/src/influence/charter-metadata.test.ts +136 -0
- package/src/influence/charter-metadata.ts +236 -0
- package/src/influence/charters.test.ts +112 -0
- package/src/influence/charters.ts +150 -0
- package/src/influence/citizenry.ts +38 -0
- package/src/influence/civic-shuttle.test.ts +202 -0
- package/src/influence/civic-shuttle.ts +142 -0
- package/src/influence/civic.test.ts +287 -0
- package/src/influence/civic.ts +269 -0
- package/src/influence/constants.ts +84 -0
- package/src/influence/decay.ts +20 -0
- package/src/influence/decomp.ts +95 -0
- package/src/influence/demand.ts +106 -0
- package/src/influence/duration.ts +101 -0
- package/src/influence/index.ts +118 -0
- package/src/influence/influence.test.ts +450 -0
- package/src/influence/quality.ts +25 -0
- package/src/influence/valuation.ts +154 -0
- package/src/managers/actions.ts +950 -93
- package/src/managers/balances.test.ts +161 -0
- package/src/managers/balances.ts +93 -0
- package/src/managers/base.ts +10 -2
- package/src/managers/cluster.test.ts +39 -0
- package/src/managers/cluster.ts +53 -0
- package/src/managers/construction-types.ts +80 -0
- package/src/managers/construction.ts +453 -0
- package/src/managers/context.ts +58 -1
- package/src/managers/coordinates.ts +14 -0
- package/src/managers/entities.ts +35 -63
- package/src/managers/epochs.ts +72 -1
- package/src/managers/index.ts +38 -1
- package/src/managers/influence.test.ts +56 -0
- package/src/managers/influence.ts +425 -0
- package/src/managers/jobs.test.ts +96 -0
- package/src/managers/jobs.ts +58 -0
- package/src/managers/locations.ts +25 -29
- package/src/managers/nft.test.ts +21 -0
- package/src/managers/nft.ts +110 -0
- package/src/managers/players.ts +25 -0
- package/src/managers/plot.ts +122 -0
- package/src/nft/atomicassets.abi.json +1342 -0
- package/src/nft/atomicassets.ts +237 -0
- package/src/nft/atomicdata.ts +130 -0
- package/src/nft/buildImmutableData.ts +388 -0
- package/src/nft/description.ts +222 -100
- package/src/nft/index.ts +3 -0
- package/src/planner/index.ts +296 -0
- package/src/planner/planner.test.ts +459 -0
- package/src/receipts.ts +22 -0
- package/src/resolution/describe-module.ts +43 -25
- package/src/resolution/display-name.ts +39 -11
- package/src/resolution/resolve-item.test.ts +48 -0
- package/src/resolution/resolve-item.ts +112 -58
- package/src/scan/index.ts +244 -0
- package/src/scan/scan-wasm.base64.ts +2 -0
- package/src/scheduling/accessor.ts +65 -23
- package/src/scheduling/availability.test.ts +320 -0
- package/src/scheduling/availability.ts +251 -0
- package/src/scheduling/cancel.test.ts +550 -0
- package/src/scheduling/cancel.ts +254 -0
- package/src/scheduling/cluster-stock.test.ts +31 -0
- package/src/scheduling/cluster-stock.ts +15 -0
- package/src/scheduling/energy.ts +47 -0
- package/src/scheduling/epoch.ts +1 -0
- package/src/scheduling/idle-resolve.ts +45 -0
- package/src/scheduling/jobs.test.ts +448 -0
- package/src/scheduling/jobs.ts +343 -0
- package/src/scheduling/lane-core.ts +128 -0
- package/src/scheduling/lanes.test.ts +250 -0
- package/src/scheduling/lanes.ts +279 -0
- package/src/scheduling/projection.ts +265 -149
- package/src/scheduling/schedule.test.ts +163 -0
- package/src/scheduling/schedule.ts +282 -116
- package/src/scheduling/task-cargo.test.ts +110 -0
- package/src/scheduling/task-cargo.ts +62 -0
- package/src/scheduling/task-effects.test.ts +35 -0
- package/src/scheduling/task-effects.ts +34 -0
- package/src/scheduling/unwrap.test.ts +86 -0
- package/src/scheduling/unwrap.ts +190 -0
- package/src/shipload.ts +63 -4
- package/src/subscriptions/manager.cluster.test.ts +51 -0
- package/src/subscriptions/manager.ts +245 -172
- package/src/subscriptions/mappers.ts +5 -8
- package/src/subscriptions/types.ts +28 -3
- package/src/testing/catalog-hash.ts +19 -0
- package/src/testing/index.ts +2 -0
- package/src/testing/projection-parity.ts +167 -0
- package/src/travel/reach.test.ts +86 -0
- package/src/travel/reach.ts +34 -0
- package/src/travel/route-build.test.ts +63 -0
- package/src/travel/route-build.ts +60 -0
- package/src/travel/route-planner.ts +288 -0
- package/src/travel/route-simulator.ts +170 -0
- package/src/travel/travel.ts +190 -123
- package/src/types/capabilities.ts +37 -8
- package/src/types/entity.ts +3 -3
- package/src/types/index.ts +0 -1
- package/src/types.ts +81 -23
- package/src/utils/cargo.test.ts +14 -0
- package/src/utils/cargo.ts +2 -0
- package/src/utils/display-name.ts +70 -0
- package/src/utils/hash.ts +22 -2
- package/src/utils/system.ts +24 -5
- package/src/capabilities/loading.ts +0 -8
- package/src/entities/container.ts +0 -123
- package/src/entities/ship-deploy.ts +0 -295
- package/src/entities/ship.ts +0 -221
- package/src/entities/warehouse.ts +0 -127
- package/src/types/entity-traits.ts +0 -69
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
import {describe, expect, test} from 'bun:test'
|
|
2
|
+
import {Name} from '@wharfkit/antelope'
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
MODULE_BUILDER,
|
|
6
|
+
MODULE_CRAFTER,
|
|
7
|
+
MODULE_LOADER,
|
|
8
|
+
MODULE_STORAGE,
|
|
9
|
+
} from '../capabilities/modules'
|
|
10
|
+
import {
|
|
11
|
+
ITEM_BUILDER_T1,
|
|
12
|
+
ITEM_CONSTRUCTION_DOCK_T1_PACKED,
|
|
13
|
+
ITEM_CRAFTER_T1,
|
|
14
|
+
ITEM_DEPOT_T1_PACKED,
|
|
15
|
+
ITEM_LOADER_T1,
|
|
16
|
+
ITEM_STORAGE_T1,
|
|
17
|
+
ITEM_WORKSHOP_T1_PACKED,
|
|
18
|
+
} from '../data/item-ids'
|
|
19
|
+
import {ENTITY_DEPOT, ENTITY_SHIP, ENTITY_WORKSHOP} from '../data/kind-registry'
|
|
20
|
+
import {decodeStats, encodeStats} from '../derivation/crafting'
|
|
21
|
+
import {CHARTER_REGISTRY, charterNode, type CharterNode} from './charters'
|
|
22
|
+
import {
|
|
23
|
+
civicBuildingFor,
|
|
24
|
+
civicHullItem,
|
|
25
|
+
civicModuleItemFor,
|
|
26
|
+
civicStatModuleType,
|
|
27
|
+
emptyCivicModules,
|
|
28
|
+
fitCivicModules,
|
|
29
|
+
isCivicEntity,
|
|
30
|
+
isCivicKind,
|
|
31
|
+
previewCharterGrants,
|
|
32
|
+
raiseCivicStat,
|
|
33
|
+
type CivicStanding,
|
|
34
|
+
} from './civic'
|
|
35
|
+
import {
|
|
36
|
+
CHARTER_BASELINE_STAT,
|
|
37
|
+
CHARTER_RUNG_STEP,
|
|
38
|
+
CIVIC_DEPOT,
|
|
39
|
+
CIVIC_DOCK,
|
|
40
|
+
CIVIC_GRANT_RUNG,
|
|
41
|
+
CIVIC_SPEED_CAP,
|
|
42
|
+
CIVIC_STAT_CRAFT_SPEED,
|
|
43
|
+
CIVIC_STAT_STORAGE_CAPACITY,
|
|
44
|
+
CIVIC_STAT_TRANSFER_SPEED,
|
|
45
|
+
CIVIC_WORKSHOP,
|
|
46
|
+
} from './constants'
|
|
47
|
+
import {getStatCount} from './quality'
|
|
48
|
+
|
|
49
|
+
const NODE_WORKSHOP = 10001
|
|
50
|
+
const NODE_WORKSHOP_TUNEUPS = [10100201, 10100202, 10100203, 10100204]
|
|
51
|
+
const NODE_WORKSHOP_TUNEUP = NODE_WORKSHOP_TUNEUPS[0]
|
|
52
|
+
const NODE_DOCK = 30100001
|
|
53
|
+
const NODE_DOCK_TUNEUPS = [30100301, 30100302, 30100303, 30100304]
|
|
54
|
+
const NODE_DEPOT = 40100001
|
|
55
|
+
const NODE_DEPOT_BAYS = [40100101, 40100102, 40100103, 40100104]
|
|
56
|
+
const NODE_DEPOT_LOADERS = [40100401, 40100402, 40100403, 40100404]
|
|
57
|
+
const DEPOT_LOADER_SLOTS = [0, 1]
|
|
58
|
+
const DEPOT_BAY_SLOTS = [2, 3, 4, 5]
|
|
59
|
+
|
|
60
|
+
function node(nodeId: number): CharterNode {
|
|
61
|
+
const found = charterNode(nodeId)
|
|
62
|
+
if (!found) throw new Error(`no charter node ${nodeId}`)
|
|
63
|
+
return found
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function stats(
|
|
67
|
+
preview: {modules: {installed?: {item_id: unknown; stats: unknown}}[]},
|
|
68
|
+
slot: number
|
|
69
|
+
) {
|
|
70
|
+
const installed = preview.modules[slot].installed
|
|
71
|
+
if (!installed) throw new Error(`slot ${slot} is empty`)
|
|
72
|
+
const itemId = Number(installed.item_id)
|
|
73
|
+
return {itemId, stats: decodeStats(BigInt(String(installed.stats)), getStatCount(itemId))}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function complete(standing: CivicStanding, nodeId: number): CivicStanding {
|
|
77
|
+
const next = {...standing}
|
|
78
|
+
for (const preview of previewCharterGrants(node(nodeId), standing)) {
|
|
79
|
+
next[preview.building] = preview.modules
|
|
80
|
+
}
|
|
81
|
+
return next
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
describe('civic building tables', () => {
|
|
85
|
+
test('each building maps to its restored hull item', () => {
|
|
86
|
+
expect(civicHullItem(CIVIC_WORKSHOP)).toBe(ITEM_WORKSHOP_T1_PACKED)
|
|
87
|
+
expect(civicHullItem(CIVIC_DOCK)).toBe(ITEM_CONSTRUCTION_DOCK_T1_PACKED)
|
|
88
|
+
expect(civicHullItem(CIVIC_DEPOT)).toBe(ITEM_DEPOT_T1_PACKED)
|
|
89
|
+
expect(civicHullItem(0)).toBe(0)
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
test('each civic stat is carried by one player T1 module type', () => {
|
|
93
|
+
expect(civicStatModuleType(CIVIC_STAT_CRAFT_SPEED)).toBe(MODULE_CRAFTER)
|
|
94
|
+
expect(civicStatModuleType(CIVIC_STAT_STORAGE_CAPACITY)).toBe(MODULE_STORAGE)
|
|
95
|
+
expect(civicStatModuleType(CIVIC_STAT_TRANSFER_SPEED)).toBe(MODULE_LOADER)
|
|
96
|
+
expect(civicModuleItemFor(MODULE_CRAFTER)).toBe(ITEM_CRAFTER_T1)
|
|
97
|
+
expect(civicModuleItemFor(MODULE_BUILDER)).toBe(ITEM_BUILDER_T1)
|
|
98
|
+
expect(civicModuleItemFor(MODULE_LOADER)).toBe(ITEM_LOADER_T1)
|
|
99
|
+
expect(civicModuleItemFor(MODULE_STORAGE)).toBe(ITEM_STORAGE_T1)
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
test('civic kinds are the four buildings and nothing else', () => {
|
|
103
|
+
expect(isCivicKind(ENTITY_WORKSHOP)).toBe(true)
|
|
104
|
+
expect(isCivicKind('depot')).toBe(true)
|
|
105
|
+
expect(isCivicKind(ENTITY_SHIP)).toBe(false)
|
|
106
|
+
expect(civicBuildingFor(ENTITY_DEPOT)).toBe(CIVIC_DEPOT)
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
test('civic-ness is the owner, not the kind', () => {
|
|
110
|
+
const civic = Name.from('eon.shipload')
|
|
111
|
+
expect(isCivicEntity({owner: 'eon.shipload'}, civic)).toBe(true)
|
|
112
|
+
expect(isCivicEntity({owner: Name.from('alice')}, civic)).toBe(false)
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
test('every rung in the registry lands on a stat its building defines', () => {
|
|
116
|
+
for (const entry of CHARTER_REGISTRY) {
|
|
117
|
+
for (const grant of entry.grants) {
|
|
118
|
+
if (grant.kind !== CIVIC_GRANT_RUNG) continue
|
|
119
|
+
expect(civicStatModuleType(grant.stat)).not.toBe(0)
|
|
120
|
+
const layout = emptyCivicModules(grant.building).map((m) => Number(m.type))
|
|
121
|
+
expect(layout).toContain(civicStatModuleType(grant.stat))
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
})
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
describe('the fourteen nodes reproduce the chain-fitted buildings', () => {
|
|
128
|
+
test('the Workshop node spawns five crafters at the baseline stat', () => {
|
|
129
|
+
const [workshop] = previewCharterGrants(node(NODE_WORKSHOP))
|
|
130
|
+
expect(workshop.building).toBe(CIVIC_WORKSHOP)
|
|
131
|
+
expect(workshop.spawned).toBe(true)
|
|
132
|
+
expect(workshop.itemId).toBe(ITEM_WORKSHOP_T1_PACKED)
|
|
133
|
+
expect(workshop.modules.length).toBe(5)
|
|
134
|
+
for (let slot = 0; slot < 5; slot++) {
|
|
135
|
+
expect(stats(workshop, slot)).toEqual({
|
|
136
|
+
itemId: ITEM_CRAFTER_T1,
|
|
137
|
+
stats: [CHARTER_BASELINE_STAT, CHARTER_BASELINE_STAT],
|
|
138
|
+
})
|
|
139
|
+
}
|
|
140
|
+
})
|
|
141
|
+
|
|
142
|
+
test('each Workshop tune-up raises every crafter by one rung step, reaching 400', () => {
|
|
143
|
+
let standing = complete({}, NODE_WORKSHOP)
|
|
144
|
+
let raised = CHARTER_BASELINE_STAT
|
|
145
|
+
for (const tuneup of NODE_WORKSHOP_TUNEUPS) {
|
|
146
|
+
const [workshop] = previewCharterGrants(node(tuneup), standing)
|
|
147
|
+
expect(workshop.spawned).toBe(false)
|
|
148
|
+
raised += CHARTER_RUNG_STEP
|
|
149
|
+
for (let slot = 0; slot < 5; slot++) {
|
|
150
|
+
expect(stats(workshop, slot).stats).toEqual([raised, raised])
|
|
151
|
+
}
|
|
152
|
+
standing = complete(standing, tuneup)
|
|
153
|
+
}
|
|
154
|
+
expect(raised).toBe(400)
|
|
155
|
+
})
|
|
156
|
+
|
|
157
|
+
test('the Dock node fits one builder and its four tune-ups reach 400', () => {
|
|
158
|
+
let standing = complete(complete({}, NODE_WORKSHOP), NODE_DOCK)
|
|
159
|
+
expect(stats({modules: standing[CIVIC_DOCK]!}, 0)).toEqual({
|
|
160
|
+
itemId: ITEM_BUILDER_T1,
|
|
161
|
+
stats: [CHARTER_BASELINE_STAT, CHARTER_BASELINE_STAT],
|
|
162
|
+
})
|
|
163
|
+
let raised = CHARTER_BASELINE_STAT
|
|
164
|
+
for (const tuneup of NODE_DOCK_TUNEUPS) {
|
|
165
|
+
const [dock] = previewCharterGrants(node(tuneup), standing)
|
|
166
|
+
raised += CHARTER_RUNG_STEP
|
|
167
|
+
expect(stats(dock, 0).stats).toEqual([raised, raised])
|
|
168
|
+
standing = complete(standing, tuneup)
|
|
169
|
+
}
|
|
170
|
+
expect(raised).toBe(400)
|
|
171
|
+
})
|
|
172
|
+
|
|
173
|
+
test('the Depot node fits two baseline loaders and leaves the bays empty', () => {
|
|
174
|
+
const standing = complete(complete({}, NODE_WORKSHOP), NODE_DEPOT)
|
|
175
|
+
const depot = {modules: standing[CIVIC_DEPOT]!}
|
|
176
|
+
for (const slot of DEPOT_LOADER_SLOTS) {
|
|
177
|
+
expect(stats(depot, slot)).toEqual({
|
|
178
|
+
itemId: ITEM_LOADER_T1,
|
|
179
|
+
stats: [CHARTER_BASELINE_STAT, CHARTER_BASELINE_STAT],
|
|
180
|
+
})
|
|
181
|
+
}
|
|
182
|
+
for (const slot of DEPOT_BAY_SLOTS) expect(depot.modules[slot].installed).toBeUndefined()
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
test('the four bays fill the storage slots in order at the baseline stat', () => {
|
|
186
|
+
let standing = complete(complete({}, NODE_WORKSHOP), NODE_DEPOT)
|
|
187
|
+
for (let i = 0; i < NODE_DEPOT_BAYS.length; i++) {
|
|
188
|
+
standing = complete(standing, NODE_DEPOT_BAYS[i])
|
|
189
|
+
const depot = {modules: standing[CIVIC_DEPOT]!}
|
|
190
|
+
for (let bay = 0; bay < DEPOT_BAY_SLOTS.length; bay++) {
|
|
191
|
+
const slot = DEPOT_BAY_SLOTS[bay]
|
|
192
|
+
if (bay <= i) {
|
|
193
|
+
expect(stats(depot, slot)).toEqual({
|
|
194
|
+
itemId: ITEM_STORAGE_T1,
|
|
195
|
+
stats: [
|
|
196
|
+
CHARTER_BASELINE_STAT,
|
|
197
|
+
CHARTER_BASELINE_STAT,
|
|
198
|
+
CHARTER_BASELINE_STAT,
|
|
199
|
+
CHARTER_BASELINE_STAT,
|
|
200
|
+
],
|
|
201
|
+
})
|
|
202
|
+
} else {
|
|
203
|
+
expect(depot.modules[slot].installed).toBeUndefined()
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
})
|
|
208
|
+
|
|
209
|
+
test('the four loader rungs step both loaders by one rung each, reaching 400', () => {
|
|
210
|
+
let standing = complete(complete({}, NODE_WORKSHOP), NODE_DEPOT)
|
|
211
|
+
for (let i = 0; i < NODE_DEPOT_LOADERS.length; i++) {
|
|
212
|
+
standing = complete(standing, NODE_DEPOT_LOADERS[i])
|
|
213
|
+
const depot = {modules: standing[CIVIC_DEPOT]!}
|
|
214
|
+
const stat = CHARTER_BASELINE_STAT + CHARTER_RUNG_STEP * (i + 1)
|
|
215
|
+
for (const slot of DEPOT_LOADER_SLOTS) {
|
|
216
|
+
expect(stats(depot, slot)).toEqual({itemId: ITEM_LOADER_T1, stats: [stat, stat]})
|
|
217
|
+
}
|
|
218
|
+
for (const slot of DEPOT_BAY_SLOTS)
|
|
219
|
+
expect(depot.modules[slot].installed).toBeUndefined()
|
|
220
|
+
}
|
|
221
|
+
})
|
|
222
|
+
})
|
|
223
|
+
|
|
224
|
+
describe('grant mechanics', () => {
|
|
225
|
+
test('a module grant joins at a sibling stat', () => {
|
|
226
|
+
const base = fitCivicModules(emptyCivicModules(CIVIC_DEPOT), 1)
|
|
227
|
+
const raised = raiseCivicStat(base, {
|
|
228
|
+
kind: CIVIC_GRANT_RUNG,
|
|
229
|
+
building: CIVIC_DEPOT,
|
|
230
|
+
stat: CIVIC_STAT_TRANSFER_SPEED,
|
|
231
|
+
value: 50,
|
|
232
|
+
})
|
|
233
|
+
const withSecondLoader = fitCivicModules(raised, 1)
|
|
234
|
+
expect(stats({modules: withSecondLoader}, 1).stats).toEqual([50, 50])
|
|
235
|
+
const withBay = fitCivicModules(withSecondLoader, 1)
|
|
236
|
+
expect(stats({modules: withBay}, 2).stats).toEqual([0, 0, 0, 0])
|
|
237
|
+
const withSecondBay = fitCivicModules(
|
|
238
|
+
raiseCivicStat(withBay, {
|
|
239
|
+
kind: CIVIC_GRANT_RUNG,
|
|
240
|
+
building: CIVIC_DEPOT,
|
|
241
|
+
stat: CIVIC_STAT_STORAGE_CAPACITY,
|
|
242
|
+
value: 7,
|
|
243
|
+
}),
|
|
244
|
+
1
|
|
245
|
+
)
|
|
246
|
+
expect(stats({modules: withSecondBay}, 3).stats).toEqual([7, 7, 7, 7])
|
|
247
|
+
})
|
|
248
|
+
|
|
249
|
+
test('a rung caps at the civic speed cap', () => {
|
|
250
|
+
const fitted = fitCivicModules(emptyCivicModules(CIVIC_WORKSHOP), 5)
|
|
251
|
+
const raised = raiseCivicStat(fitted, {
|
|
252
|
+
kind: CIVIC_GRANT_RUNG,
|
|
253
|
+
building: CIVIC_WORKSHOP,
|
|
254
|
+
stat: CIVIC_STAT_CRAFT_SPEED,
|
|
255
|
+
value: 5000,
|
|
256
|
+
})
|
|
257
|
+
expect(stats({modules: raised}, 0).stats).toEqual([CIVIC_SPEED_CAP, CIVIC_SPEED_CAP])
|
|
258
|
+
})
|
|
259
|
+
|
|
260
|
+
test('a module grant past the layout is refused', () => {
|
|
261
|
+
const full = fitCivicModules(emptyCivicModules(CIVIC_DOCK), 2)
|
|
262
|
+
expect(() => fitCivicModules(full, 1)).toThrow('no open slot')
|
|
263
|
+
})
|
|
264
|
+
|
|
265
|
+
test('a rung with no carrier is refused', () => {
|
|
266
|
+
expect(() =>
|
|
267
|
+
raiseCivicStat(emptyCivicModules(CIVIC_DEPOT), {
|
|
268
|
+
kind: CIVIC_GRANT_RUNG,
|
|
269
|
+
building: CIVIC_DEPOT,
|
|
270
|
+
stat: CIVIC_STAT_TRANSFER_SPEED,
|
|
271
|
+
value: 1,
|
|
272
|
+
})
|
|
273
|
+
).toThrow('no module carrying')
|
|
274
|
+
})
|
|
275
|
+
|
|
276
|
+
test('a grant on a building that is not standing is refused', () => {
|
|
277
|
+
expect(() => previewCharterGrants(node(NODE_WORKSHOP_TUNEUP))).toThrow('not standing')
|
|
278
|
+
})
|
|
279
|
+
|
|
280
|
+
test('inputs are never mutated', () => {
|
|
281
|
+
const before = emptyCivicModules(CIVIC_WORKSHOP)
|
|
282
|
+
const snapshot = before.map((m) => String(m.installed?.stats ?? 'empty'))
|
|
283
|
+
fitCivicModules(before, 5)
|
|
284
|
+
expect(before.map((m) => String(m.installed?.stats ?? 'empty'))).toEqual(snapshot)
|
|
285
|
+
expect(encodeStats([1, 2])).not.toBe(0n)
|
|
286
|
+
})
|
|
287
|
+
})
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
import {Name, type NameType, UInt16, UInt64, UInt8} from '@wharfkit/antelope'
|
|
2
|
+
import {
|
|
3
|
+
getModuleCapabilityType,
|
|
4
|
+
MODULE_BUILDER,
|
|
5
|
+
MODULE_CRAFTER,
|
|
6
|
+
MODULE_LOADER,
|
|
7
|
+
MODULE_STORAGE,
|
|
8
|
+
moduleSlotTypeToCode,
|
|
9
|
+
} from '../capabilities/modules'
|
|
10
|
+
import {ServerContract} from '../contracts'
|
|
11
|
+
import {
|
|
12
|
+
ITEM_BUILDER_T1,
|
|
13
|
+
ITEM_CONSTRUCTION_DOCK_T1_PACKED,
|
|
14
|
+
ITEM_CRAFTER_T1,
|
|
15
|
+
ITEM_DEPOT_T1_PACKED,
|
|
16
|
+
ITEM_LOADER_T1,
|
|
17
|
+
ITEM_NEXUS_T1_PACKED,
|
|
18
|
+
ITEM_STORAGE_T1,
|
|
19
|
+
ITEM_WORKSHOP_T1_PACKED,
|
|
20
|
+
} from '../data/item-ids'
|
|
21
|
+
import {
|
|
22
|
+
ENTITY_CONSTRUCTION_DOCK,
|
|
23
|
+
ENTITY_DEPOT,
|
|
24
|
+
ENTITY_NEXUS,
|
|
25
|
+
ENTITY_WORKSHOP,
|
|
26
|
+
} from '../data/kind-registry'
|
|
27
|
+
import {getEntityLayout} from '../data/recipes-runtime'
|
|
28
|
+
import {decodeStat, encodeStats} from '../derivation/crafting'
|
|
29
|
+
import type {CharterGrant, CharterNode} from './charters'
|
|
30
|
+
import {
|
|
31
|
+
CIVIC_DEPOT,
|
|
32
|
+
CIVIC_DOCK,
|
|
33
|
+
CIVIC_GRANT_LEVEL_GATE,
|
|
34
|
+
CIVIC_GRANT_MODULE,
|
|
35
|
+
CIVIC_GRANT_RUNG,
|
|
36
|
+
CIVIC_NEXUS,
|
|
37
|
+
CIVIC_SPEED_CAP,
|
|
38
|
+
CIVIC_STAT_BUILD_SPEED,
|
|
39
|
+
CIVIC_STAT_CRAFT_SPEED,
|
|
40
|
+
CIVIC_STAT_STORAGE_CAPACITY,
|
|
41
|
+
CIVIC_STAT_TRANSFER_SPEED,
|
|
42
|
+
CIVIC_WORKSHOP,
|
|
43
|
+
} from './constants'
|
|
44
|
+
import {getStatCount} from './quality'
|
|
45
|
+
|
|
46
|
+
type ModuleEntry = ServerContract.Types.module_entry
|
|
47
|
+
|
|
48
|
+
export interface CivicStatDef {
|
|
49
|
+
building: number
|
|
50
|
+
stat: number
|
|
51
|
+
base: number
|
|
52
|
+
cap: number
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export const CIVIC_STAT_DEFS: readonly CivicStatDef[] = [
|
|
56
|
+
{building: CIVIC_WORKSHOP, stat: CIVIC_STAT_CRAFT_SPEED, base: 0, cap: CIVIC_SPEED_CAP},
|
|
57
|
+
{building: CIVIC_DOCK, stat: CIVIC_STAT_BUILD_SPEED, base: 0, cap: CIVIC_SPEED_CAP},
|
|
58
|
+
{building: CIVIC_DEPOT, stat: CIVIC_STAT_TRANSFER_SPEED, base: 0, cap: CIVIC_SPEED_CAP},
|
|
59
|
+
{building: CIVIC_DEPOT, stat: CIVIC_STAT_STORAGE_CAPACITY, base: 0, cap: CIVIC_SPEED_CAP},
|
|
60
|
+
]
|
|
61
|
+
|
|
62
|
+
export function findCivicStatDef(building: number, stat: number): CivicStatDef | undefined {
|
|
63
|
+
return CIVIC_STAT_DEFS.find((def) => def.building === building && def.stat === stat)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function civicHullItem(building: number): number {
|
|
67
|
+
switch (building) {
|
|
68
|
+
case CIVIC_WORKSHOP:
|
|
69
|
+
return ITEM_WORKSHOP_T1_PACKED
|
|
70
|
+
case CIVIC_NEXUS:
|
|
71
|
+
return ITEM_NEXUS_T1_PACKED
|
|
72
|
+
case CIVIC_DOCK:
|
|
73
|
+
return ITEM_CONSTRUCTION_DOCK_T1_PACKED
|
|
74
|
+
case CIVIC_DEPOT:
|
|
75
|
+
return ITEM_DEPOT_T1_PACKED
|
|
76
|
+
default:
|
|
77
|
+
return 0
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export function civicModuleItemFor(moduleType: number): number {
|
|
82
|
+
switch (moduleType) {
|
|
83
|
+
case MODULE_CRAFTER:
|
|
84
|
+
return ITEM_CRAFTER_T1
|
|
85
|
+
case MODULE_BUILDER:
|
|
86
|
+
return ITEM_BUILDER_T1
|
|
87
|
+
case MODULE_LOADER:
|
|
88
|
+
return ITEM_LOADER_T1
|
|
89
|
+
case MODULE_STORAGE:
|
|
90
|
+
return ITEM_STORAGE_T1
|
|
91
|
+
default:
|
|
92
|
+
return 0
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function civicStatModuleType(stat: number): number {
|
|
97
|
+
switch (stat) {
|
|
98
|
+
case CIVIC_STAT_CRAFT_SPEED:
|
|
99
|
+
return MODULE_CRAFTER
|
|
100
|
+
case CIVIC_STAT_BUILD_SPEED:
|
|
101
|
+
return MODULE_BUILDER
|
|
102
|
+
case CIVIC_STAT_TRANSFER_SPEED:
|
|
103
|
+
return MODULE_LOADER
|
|
104
|
+
case CIVIC_STAT_STORAGE_CAPACITY:
|
|
105
|
+
return MODULE_STORAGE
|
|
106
|
+
default:
|
|
107
|
+
return 0
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export function civicBuildingKind(building: number): Name | undefined {
|
|
112
|
+
switch (building) {
|
|
113
|
+
case CIVIC_WORKSHOP:
|
|
114
|
+
return ENTITY_WORKSHOP
|
|
115
|
+
case CIVIC_NEXUS:
|
|
116
|
+
return ENTITY_NEXUS
|
|
117
|
+
case CIVIC_DOCK:
|
|
118
|
+
return ENTITY_CONSTRUCTION_DOCK
|
|
119
|
+
case CIVIC_DEPOT:
|
|
120
|
+
return ENTITY_DEPOT
|
|
121
|
+
default:
|
|
122
|
+
return undefined
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export function civicBuildingFor(kind: NameType): number | undefined {
|
|
127
|
+
const name = Name.from(kind)
|
|
128
|
+
if (name.equals(ENTITY_WORKSHOP)) return CIVIC_WORKSHOP
|
|
129
|
+
if (name.equals(ENTITY_NEXUS)) return CIVIC_NEXUS
|
|
130
|
+
if (name.equals(ENTITY_CONSTRUCTION_DOCK)) return CIVIC_DOCK
|
|
131
|
+
if (name.equals(ENTITY_DEPOT)) return CIVIC_DEPOT
|
|
132
|
+
return undefined
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export function isCivicKind(kind: NameType): boolean {
|
|
136
|
+
return civicBuildingFor(kind) !== undefined
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export function isCivicEntity(entity: {owner: NameType}, civicOwner: NameType): boolean {
|
|
140
|
+
return Name.from(entity.owner).equals(Name.from(civicOwner))
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function moduleItemId(module: ServerContract.Types.packed_module): number {
|
|
144
|
+
return Number(module.item_id.value ?? module.item_id)
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function moduleStats(module: ServerContract.Types.packed_module): bigint {
|
|
148
|
+
return BigInt(module.stats.toString())
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function packedModule(itemId: number, stats: bigint): ServerContract.Types.packed_module {
|
|
152
|
+
return ServerContract.Types.packed_module.from({
|
|
153
|
+
item_id: UInt16.from(itemId),
|
|
154
|
+
stats: UInt64.from(stats.toString()),
|
|
155
|
+
})
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function cloneEntry(
|
|
159
|
+
entry: ModuleEntry,
|
|
160
|
+
installed?: ServerContract.Types.packed_module
|
|
161
|
+
): ModuleEntry {
|
|
162
|
+
return ServerContract.Types.module_entry.from({
|
|
163
|
+
type: UInt8.from(Number(entry.type.value ?? entry.type)),
|
|
164
|
+
installed:
|
|
165
|
+
installed ??
|
|
166
|
+
(entry.installed
|
|
167
|
+
? packedModule(moduleItemId(entry.installed), moduleStats(entry.installed))
|
|
168
|
+
: undefined),
|
|
169
|
+
})
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export function emptyCivicModules(building: number): ModuleEntry[] {
|
|
173
|
+
const layout = getEntityLayout(civicHullItem(building))?.slots ?? []
|
|
174
|
+
return layout.map((slot) =>
|
|
175
|
+
ServerContract.Types.module_entry.from({type: UInt8.from(moduleSlotTypeToCode(slot.type))})
|
|
176
|
+
)
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export function fitCivicModules(modules: ModuleEntry[], count: number): ModuleEntry[] {
|
|
180
|
+
const next = modules.map((entry) => cloneEntry(entry))
|
|
181
|
+
let remaining = count
|
|
182
|
+
for (let i = 0; i < next.length && remaining > 0; i++) {
|
|
183
|
+
if (next[i].installed) continue
|
|
184
|
+
const type = Number(next[i].type.value ?? next[i].type)
|
|
185
|
+
const item = civicModuleItemFor(type)
|
|
186
|
+
if (item === 0) throw new Error('charter grant found no open slot of its module type')
|
|
187
|
+
let stats = encodeStats(new Array(getStatCount(item)).fill(0))
|
|
188
|
+
for (const sibling of next) {
|
|
189
|
+
if (
|
|
190
|
+
sibling.installed &&
|
|
191
|
+
getModuleCapabilityType(moduleItemId(sibling.installed)) === type
|
|
192
|
+
) {
|
|
193
|
+
stats = moduleStats(sibling.installed)
|
|
194
|
+
break
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
next[i] = cloneEntry(next[i], packedModule(item, stats))
|
|
198
|
+
remaining--
|
|
199
|
+
}
|
|
200
|
+
if (remaining > 0) throw new Error('charter grant found no open slot of its module type')
|
|
201
|
+
return next
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export function raiseCivicStat(modules: ModuleEntry[], grant: CharterGrant): ModuleEntry[] {
|
|
205
|
+
const def = findCivicStatDef(grant.building, grant.stat)
|
|
206
|
+
if (!def) throw new Error(`no civic stat ${grant.stat} on building ${grant.building}`)
|
|
207
|
+
const type = civicStatModuleType(grant.stat)
|
|
208
|
+
let raised = 0
|
|
209
|
+
const next = modules.map((entry) => {
|
|
210
|
+
if (!entry.installed || getModuleCapabilityType(moduleItemId(entry.installed)) !== type) {
|
|
211
|
+
return cloneEntry(entry)
|
|
212
|
+
}
|
|
213
|
+
const item = moduleItemId(entry.installed)
|
|
214
|
+
const stats = moduleStats(entry.installed)
|
|
215
|
+
const values: number[] = []
|
|
216
|
+
for (let c = 0; c < getStatCount(item); c++) {
|
|
217
|
+
values.push(Math.min(decodeStat(stats, c) + grant.value, def.cap))
|
|
218
|
+
}
|
|
219
|
+
raised++
|
|
220
|
+
return cloneEntry(entry, packedModule(item, encodeStats(values)))
|
|
221
|
+
})
|
|
222
|
+
if (raised === 0) throw new Error('charter rung found no module carrying its stat')
|
|
223
|
+
return next
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
export interface CivicBuildingPreview {
|
|
227
|
+
building: number
|
|
228
|
+
itemId: number
|
|
229
|
+
spawned: boolean
|
|
230
|
+
modules: ModuleEntry[]
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
export type CivicStanding = Partial<Record<number, ModuleEntry[]>>
|
|
234
|
+
|
|
235
|
+
export function previewCharterGrants(
|
|
236
|
+
node: CharterNode,
|
|
237
|
+
standing: CivicStanding = {}
|
|
238
|
+
): CivicBuildingPreview[] {
|
|
239
|
+
const previews = new Map<number, CivicBuildingPreview>()
|
|
240
|
+
const target = (building: number, spawn: boolean): CivicBuildingPreview => {
|
|
241
|
+
let preview = previews.get(building)
|
|
242
|
+
if (preview) return preview
|
|
243
|
+
const current = standing[building]
|
|
244
|
+
if (!current && !spawn)
|
|
245
|
+
throw new Error('charter grant targets a building that is not standing')
|
|
246
|
+
preview = {
|
|
247
|
+
building,
|
|
248
|
+
itemId: civicHullItem(building),
|
|
249
|
+
spawned: !current,
|
|
250
|
+
modules: current
|
|
251
|
+
? current.map((entry) => cloneEntry(entry))
|
|
252
|
+
: emptyCivicModules(building),
|
|
253
|
+
}
|
|
254
|
+
previews.set(building, preview)
|
|
255
|
+
return preview
|
|
256
|
+
}
|
|
257
|
+
for (const grant of node.grants) {
|
|
258
|
+
if (grant.kind === CIVIC_GRANT_LEVEL_GATE) {
|
|
259
|
+
target(grant.building, true)
|
|
260
|
+
} else if (grant.kind === CIVIC_GRANT_MODULE) {
|
|
261
|
+
const preview = target(grant.building, false)
|
|
262
|
+
preview.modules = fitCivicModules(preview.modules, grant.value)
|
|
263
|
+
} else if (grant.kind === CIVIC_GRANT_RUNG) {
|
|
264
|
+
const preview = target(grant.building, false)
|
|
265
|
+
preview.modules = raiseCivicStat(preview.modules, grant)
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
return [...previews.values()]
|
|
269
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import {MASS_UNITS_PER_TONNE} from '../types'
|
|
2
|
+
|
|
3
|
+
export const INFLUENCE_ATOMIC_PER_POINT = 10_000
|
|
4
|
+
export const NEED_FP_SCALE = 10_000
|
|
5
|
+
export const WEIGHT_FP_SCALE = 10_000
|
|
6
|
+
|
|
7
|
+
export const INFLUENCE_WEIGHT_FP_MAX = 1_000_000n
|
|
8
|
+
export const INFLUENCE_NEED_FP_MAX = 1_000_000n
|
|
9
|
+
export const INFLUENCE_MASS_MAX = 1n << 48n
|
|
10
|
+
|
|
11
|
+
export const DECAY_RETAIN_NUM = 19n
|
|
12
|
+
export const DECAY_RETAIN_DEN = 20n
|
|
13
|
+
export const DECAY_MAX_ITERATIONS = 1_024
|
|
14
|
+
|
|
15
|
+
export const W_EFF_ATOMIC_PER_UNIT = BigInt(INFLUENCE_ATOMIC_PER_POINT / MASS_UNITS_PER_TONNE)
|
|
16
|
+
|
|
17
|
+
export const DECOMP_MAX_BUCKETS = 12
|
|
18
|
+
export const DECOMP_MAX_DEPTH = 8
|
|
19
|
+
export const DECOMP_RAW_MASS_MAX = 1_000_000
|
|
20
|
+
export const DECOMP_PROCESSED_MASS_MAX = 1_000_000
|
|
21
|
+
|
|
22
|
+
export const RESOURCE_ORE = 0
|
|
23
|
+
export const RESOURCE_GAS = 1
|
|
24
|
+
export const RESOURCE_REGOLITH = 2
|
|
25
|
+
export const RESOURCE_BIOMASS = 3
|
|
26
|
+
export const RESOURCE_CRYSTAL = 4
|
|
27
|
+
export const RESOURCE_CATEGORY_COUNT = 5
|
|
28
|
+
|
|
29
|
+
export const CIVIC_LOADER_STAT = 213
|
|
30
|
+
export const CIVIC_LOADER_TIER = 1
|
|
31
|
+
export const DEFAULT_ORBITAL_Z = 800
|
|
32
|
+
|
|
33
|
+
export const GRADE_STANDARD = 0
|
|
34
|
+
export const GRADE_PREMIUM = 1
|
|
35
|
+
export const MINTREADY_DEFAULT_CAP = 10
|
|
36
|
+
|
|
37
|
+
export const BAR_SEED = 102_363
|
|
38
|
+
export const BAR_STEP_UNIT = 20
|
|
39
|
+
export const BAR_STEP_UP = BAR_STEP_UNIT * 9
|
|
40
|
+
export const BAR_STEP_DOWN = BAR_STEP_UNIT
|
|
41
|
+
|
|
42
|
+
export const CHARTER_NONE = 0
|
|
43
|
+
export const CHARTER_WORKSHOP = 10001
|
|
44
|
+
export const CIVIC_GRANT_NONE = 0
|
|
45
|
+
export const CIVIC_GRANT_MODULE = 1
|
|
46
|
+
export const CIVIC_GRANT_RUNG = 2
|
|
47
|
+
export const CIVIC_GRANT_LEVEL_GATE = 3
|
|
48
|
+
export const CIVIC_GRANT_ADVANCEMENT = 4
|
|
49
|
+
|
|
50
|
+
export const CIVIC_WORLD = 0
|
|
51
|
+
export const CIVIC_WORKSHOP = 1
|
|
52
|
+
export const CIVIC_NEXUS = 2
|
|
53
|
+
export const CIVIC_DOCK = 3
|
|
54
|
+
export const CIVIC_DEPOT = 4
|
|
55
|
+
|
|
56
|
+
export const CIVIC_STAT_NONE = 0
|
|
57
|
+
export const CIVIC_STAT_CRAFT_SPEED = 1
|
|
58
|
+
export const CIVIC_STAT_BUILD_SPEED = 2
|
|
59
|
+
export const CIVIC_STAT_TRANSFER_SPEED = 3
|
|
60
|
+
export const CIVIC_STAT_STORAGE_CAPACITY = 4
|
|
61
|
+
export const VOTE_READY_DEFAULT_MAX = 20
|
|
62
|
+
export const BALLOT_CHARTER = 1
|
|
63
|
+
export const BALLOT_MAX_PICKS = 8
|
|
64
|
+
export const CHARTER_WORKSHOP_COST = 2_000_000_000n
|
|
65
|
+
export const CHARTER_BASELINE_STAT = 200
|
|
66
|
+
export const CHARTER_RUNG_STEP = 50
|
|
67
|
+
export const CIVIC_SPEED_CAP = 999
|
|
68
|
+
export const CHARTER_MAX_PREREQS = 4
|
|
69
|
+
export const CHARTER_MAX_GRANTS = 4
|
|
70
|
+
|
|
71
|
+
export const INFLUENCE_D1_SEED = 45_369
|
|
72
|
+
export const DEMAND_TRIPLE_SEED = {peak: 20_000n, base: 10_000n, floor: 1_000n}
|
|
73
|
+
|
|
74
|
+
export function poolKey(category: number, tier: number, grade: number): bigint {
|
|
75
|
+
return (BigInt(category) << 16n) | (BigInt(tier) << 8n) | BigInt(grade)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function influenceWeightKey(category: number, tier: number): bigint {
|
|
79
|
+
return (BigInt(category) << 8n) | BigInt(tier)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function atomicToPoints(atomic: bigint | number | string): number {
|
|
83
|
+
return Math.floor(Number(BigInt(atomic.toString())) / INFLUENCE_ATOMIC_PER_POINT)
|
|
84
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import {DECAY_MAX_ITERATIONS, DECAY_RETAIN_DEN, DECAY_RETAIN_NUM} from './constants'
|
|
2
|
+
|
|
3
|
+
export function decayActive(active: bigint, epochsElapsed: number): bigint {
|
|
4
|
+
const iterations = epochsElapsed > DECAY_MAX_ITERATIONS ? DECAY_MAX_ITERATIONS : epochsElapsed
|
|
5
|
+
let value = active
|
|
6
|
+
for (let i = 0; i < iterations && value > 0n; i++) {
|
|
7
|
+
value = (value * DECAY_RETAIN_NUM) / DECAY_RETAIN_DEN
|
|
8
|
+
}
|
|
9
|
+
return value
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface DecayableStanding {
|
|
13
|
+
active: bigint
|
|
14
|
+
lastUpdateEpoch: number
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function normalizeActive(standing: DecayableStanding, epoch: number): bigint {
|
|
18
|
+
const elapsed = epoch > standing.lastUpdateEpoch ? epoch - standing.lastUpdateEpoch : 0
|
|
19
|
+
return decayActive(standing.active, elapsed)
|
|
20
|
+
}
|