@shipload/sdk 1.0.0-next.3 → 1.0.0-next.31
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/shipload.d.ts +1849 -961
- package/lib/shipload.js +9089 -4854
- package/lib/shipload.js.map +1 -1
- package/lib/shipload.m.js +8958 -4805
- package/lib/shipload.m.js.map +1 -1
- package/lib/testing.d.ts +856 -0
- package/lib/testing.js +3739 -0
- package/lib/testing.js.map +1 -0
- package/lib/testing.m.js +3733 -0
- package/lib/testing.m.js.map +1 -0
- package/package.json +15 -2
- package/src/capabilities/craftable.ts +51 -0
- package/src/capabilities/crafting.test.ts +7 -0
- package/src/capabilities/crafting.ts +3 -3
- package/src/capabilities/gathering.ts +17 -7
- package/src/capabilities/index.ts +0 -1
- package/src/capabilities/modules.ts +6 -0
- package/src/capabilities/storage.ts +16 -1
- package/src/contracts/platform.ts +231 -3
- package/src/contracts/server.ts +816 -471
- package/src/data/capabilities.ts +14 -329
- package/src/data/capability-formulas.ts +76 -0
- package/src/data/catalog.ts +0 -5
- package/src/data/colors.ts +14 -47
- package/src/data/entities.json +46 -10
- package/src/data/item-ids.ts +15 -12
- package/src/data/items.json +302 -38
- package/src/data/kind-registry.json +85 -0
- package/src/data/kind-registry.ts +150 -0
- package/src/data/metadata.ts +100 -31
- package/src/data/recipes-runtime.ts +3 -23
- package/src/data/recipes.json +250 -113
- package/src/derivation/build-methods.ts +45 -0
- package/src/derivation/capabilities.ts +415 -0
- package/src/derivation/capability-mappings.ts +117 -0
- package/src/derivation/crafting.ts +23 -24
- package/src/derivation/index.ts +17 -2
- package/src/derivation/reserve-regen.ts +34 -0
- package/src/derivation/resources.ts +125 -38
- package/src/derivation/stars.test.ts +51 -0
- package/src/derivation/stars.ts +15 -0
- package/src/derivation/stats.ts +6 -6
- package/src/derivation/stratum.ts +15 -19
- package/src/derivation/tiers.ts +28 -7
- package/src/entities/entity.ts +98 -0
- package/src/entities/gamestate.ts +3 -28
- package/src/entities/makers.ts +91 -136
- package/src/entities/slot-multiplier.ts +39 -0
- package/src/errors.ts +10 -15
- package/src/format.ts +26 -4
- package/src/index-module.ts +189 -47
- package/src/managers/actions.ts +252 -83
- package/src/managers/base.ts +6 -2
- package/src/managers/construction-types.ts +79 -0
- package/src/managers/construction.ts +396 -0
- package/src/managers/context.ts +11 -1
- package/src/managers/entities.ts +18 -66
- package/src/managers/epochs.ts +40 -0
- package/src/managers/index.ts +17 -1
- package/src/managers/locations.ts +25 -29
- package/src/managers/nft.ts +28 -0
- package/src/managers/plot.ts +127 -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 +321 -0
- package/src/nft/description.ts +37 -15
- package/src/nft/index.ts +3 -0
- package/src/resolution/describe-module.ts +5 -8
- package/src/resolution/display-name.ts +38 -10
- package/src/resolution/resolve-item.ts +22 -20
- package/src/scheduling/accessor.ts +68 -22
- package/src/scheduling/availability.ts +108 -0
- package/src/scheduling/energy.ts +48 -0
- package/src/scheduling/lane-core.ts +130 -0
- package/src/scheduling/lanes.ts +60 -0
- package/src/scheduling/projection.ts +121 -94
- package/src/scheduling/schedule.ts +237 -103
- package/src/scheduling/task-cargo.ts +46 -0
- package/src/shipload.ts +16 -1
- package/src/subscriptions/manager.ts +40 -6
- package/src/subscriptions/mappers.ts +3 -8
- package/src/subscriptions/types.ts +3 -2
- package/src/testing/catalog-hash.ts +19 -0
- package/src/testing/index.ts +2 -0
- package/src/testing/projection-parity.ts +143 -0
- package/src/travel/travel.ts +90 -13
- package/src/types/capabilities.ts +1 -0
- package/src/types/index.ts +0 -1
- package/src/types.ts +19 -12
- package/src/utils/cargo.ts +27 -0
- package/src/utils/display-name.ts +70 -0
- package/src/utils/system.ts +25 -24
- package/src/capabilities/loading.ts +0 -8
- package/src/entities/container.ts +0 -108
- package/src/entities/ship-deploy.ts +0 -258
- package/src/entities/ship.ts +0 -204
- package/src/entities/warehouse.ts +0 -119
- package/src/types/entity-traits.ts +0 -69
package/src/derivation/index.ts
CHANGED
|
@@ -7,6 +7,7 @@ export {
|
|
|
7
7
|
getEligibleResources,
|
|
8
8
|
getResourceWeight,
|
|
9
9
|
getLocationCandidates,
|
|
10
|
+
getLocationProfile,
|
|
10
11
|
getDepthThreshold,
|
|
11
12
|
getResourceTier,
|
|
12
13
|
DEPTH_THRESHOLD_T1,
|
|
@@ -16,7 +17,9 @@ export {
|
|
|
16
17
|
DEPTH_THRESHOLD_T5,
|
|
17
18
|
LOCATION_MIN_DEPTH,
|
|
18
19
|
LOCATION_MAX_DEPTH,
|
|
19
|
-
|
|
20
|
+
yieldThresholdAt,
|
|
21
|
+
YIELD_FRACTION_SHALLOW,
|
|
22
|
+
YIELD_FRACTION_DEEP,
|
|
20
23
|
PLANET_SUBTYPE_GAS_GIANT,
|
|
21
24
|
PLANET_SUBTYPE_ROCKY,
|
|
22
25
|
PLANET_SUBTYPE_TERRESTRIAL,
|
|
@@ -25,8 +28,20 @@ export {
|
|
|
25
28
|
PLANET_SUBTYPE_INDUSTRIAL,
|
|
26
29
|
} from './resources'
|
|
27
30
|
|
|
28
|
-
export {RESERVE_TIERS, TIER_ROLL_MAX, rollTier, rollWithinTier} from './tiers'
|
|
31
|
+
export {RESERVE_TIERS, TIER_ROLL_MAX, tierOfReserve, rollTier, rollWithinTier} from './tiers'
|
|
29
32
|
export type {ReserveTier, TierRange} from './tiers'
|
|
30
33
|
|
|
34
|
+
export {getEffectiveReserve} from './reserve-regen'
|
|
35
|
+
export type {EffectiveReserveInput} from './reserve-regen'
|
|
36
|
+
|
|
31
37
|
export * from './stats'
|
|
32
38
|
export * from './crafting'
|
|
39
|
+
|
|
40
|
+
export {
|
|
41
|
+
STAR_STEP,
|
|
42
|
+
MAX_STARS_PER_STAT,
|
|
43
|
+
MAX_STAR_RATING,
|
|
44
|
+
starsForStat,
|
|
45
|
+
starRating,
|
|
46
|
+
statMagnitude,
|
|
47
|
+
} from './stars'
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type {BlockTimestamp, UInt32} from '@wharfkit/antelope'
|
|
2
|
+
|
|
3
|
+
export interface EffectiveReserveInput {
|
|
4
|
+
remaining: UInt32 | number
|
|
5
|
+
max_reserve: UInt32 | number
|
|
6
|
+
last_block: BlockTimestamp
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function toNumber(value: UInt32 | number): number {
|
|
10
|
+
return typeof value === 'number' ? value : Number(value)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function slotsBetween(now: BlockTimestamp, last: BlockTimestamp): number {
|
|
14
|
+
const nowMs = now.toMilliseconds()
|
|
15
|
+
const lastMs = last.toMilliseconds()
|
|
16
|
+
if (nowMs <= lastMs) return 0
|
|
17
|
+
return Math.floor((nowMs - lastMs) / 500)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function getEffectiveReserve(
|
|
21
|
+
row: EffectiveReserveInput,
|
|
22
|
+
now: BlockTimestamp,
|
|
23
|
+
epochSeconds: number
|
|
24
|
+
): number {
|
|
25
|
+
const remaining = toNumber(row.remaining)
|
|
26
|
+
const max = toNumber(row.max_reserve)
|
|
27
|
+
if (remaining >= max) return max
|
|
28
|
+
const epochSlots = epochSeconds * 2
|
|
29
|
+
if (epochSlots === 0) return remaining
|
|
30
|
+
const elapsed = slotsBetween(now, row.last_block)
|
|
31
|
+
const regen = Math.floor((max * elapsed) / epochSlots)
|
|
32
|
+
const effective = remaining + regen
|
|
33
|
+
return effective >= max ? max : effective
|
|
34
|
+
}
|
|
@@ -1,15 +1,29 @@
|
|
|
1
1
|
import {getItem} from '../data/catalog'
|
|
2
|
+
import {LocationType} from '../types'
|
|
2
3
|
|
|
3
4
|
export const DEPTH_THRESHOLD_T1 = 0
|
|
4
|
-
export const DEPTH_THRESHOLD_T2 =
|
|
5
|
-
export const DEPTH_THRESHOLD_T3 =
|
|
6
|
-
export const DEPTH_THRESHOLD_T4 =
|
|
7
|
-
export const DEPTH_THRESHOLD_T5 =
|
|
5
|
+
export const DEPTH_THRESHOLD_T2 = 1500
|
|
6
|
+
export const DEPTH_THRESHOLD_T3 = 5000
|
|
7
|
+
export const DEPTH_THRESHOLD_T4 = 12000
|
|
8
|
+
export const DEPTH_THRESHOLD_T5 = 22000
|
|
9
|
+
export const DEPTH_THRESHOLD_T6 = 32000
|
|
10
|
+
export const DEPTH_THRESHOLD_T7 = 42000
|
|
11
|
+
export const DEPTH_THRESHOLD_T8 = 50000
|
|
12
|
+
export const DEPTH_THRESHOLD_T9 = 57000
|
|
13
|
+
export const DEPTH_THRESHOLD_T10 = 63000
|
|
8
14
|
|
|
9
15
|
export const LOCATION_MIN_DEPTH = 500
|
|
10
16
|
export const LOCATION_MAX_DEPTH = 65535
|
|
11
17
|
|
|
12
|
-
export const
|
|
18
|
+
export const YIELD_FRACTION_SHALLOW = 0.0025
|
|
19
|
+
export const YIELD_FRACTION_DEEP = 0.0005
|
|
20
|
+
|
|
21
|
+
export function yieldThresholdAt(stratum: number): number {
|
|
22
|
+
const clamped = stratum > 65535 ? 65535 : stratum
|
|
23
|
+
const t = clamped / 65535
|
|
24
|
+
const fraction = YIELD_FRACTION_SHALLOW + (YIELD_FRACTION_DEEP - YIELD_FRACTION_SHALLOW) * t
|
|
25
|
+
return Math.floor(fraction * 0xffffffff)
|
|
26
|
+
}
|
|
13
27
|
|
|
14
28
|
export const PLANET_SUBTYPE_GAS_GIANT = 0
|
|
15
29
|
export const PLANET_SUBTYPE_ROCKY = 1
|
|
@@ -18,19 +32,22 @@ export const PLANET_SUBTYPE_ICY = 3
|
|
|
18
32
|
export const PLANET_SUBTYPE_OCEAN = 4
|
|
19
33
|
export const PLANET_SUBTYPE_INDUSTRIAL = 5
|
|
20
34
|
|
|
35
|
+
const DEPTH_THRESHOLD_TABLE = [
|
|
36
|
+
DEPTH_THRESHOLD_T1,
|
|
37
|
+
DEPTH_THRESHOLD_T2,
|
|
38
|
+
DEPTH_THRESHOLD_T3,
|
|
39
|
+
DEPTH_THRESHOLD_T4,
|
|
40
|
+
DEPTH_THRESHOLD_T5,
|
|
41
|
+
DEPTH_THRESHOLD_T6,
|
|
42
|
+
DEPTH_THRESHOLD_T7,
|
|
43
|
+
DEPTH_THRESHOLD_T8,
|
|
44
|
+
DEPTH_THRESHOLD_T9,
|
|
45
|
+
DEPTH_THRESHOLD_T10,
|
|
46
|
+
]
|
|
47
|
+
|
|
21
48
|
export function getDepthThreshold(tier: number): number {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
return DEPTH_THRESHOLD_T1
|
|
25
|
-
case 2:
|
|
26
|
-
return DEPTH_THRESHOLD_T2
|
|
27
|
-
case 3:
|
|
28
|
-
return DEPTH_THRESHOLD_T3
|
|
29
|
-
case 4:
|
|
30
|
-
return DEPTH_THRESHOLD_T4
|
|
31
|
-
default:
|
|
32
|
-
return DEPTH_THRESHOLD_T5
|
|
33
|
-
}
|
|
49
|
+
if (tier < 1 || tier > 10) return 65535
|
|
50
|
+
return DEPTH_THRESHOLD_TABLE[tier - 1]
|
|
34
51
|
}
|
|
35
52
|
|
|
36
53
|
export function getResourceTier(itemId: number): number {
|
|
@@ -46,9 +63,9 @@ export function getResourceWeight(itemId: number, stratum: number): number {
|
|
|
46
63
|
|
|
47
64
|
switch (tier) {
|
|
48
65
|
case 1:
|
|
49
|
-
if (stratum <
|
|
50
|
-
if (stratum <
|
|
51
|
-
if (stratum <
|
|
66
|
+
if (stratum < DEPTH_THRESHOLD_T2) return 100
|
|
67
|
+
if (stratum < DEPTH_THRESHOLD_T3) return 80
|
|
68
|
+
if (stratum < DEPTH_THRESHOLD_T4) return 50
|
|
52
69
|
return 30
|
|
53
70
|
case 2:
|
|
54
71
|
if (depthAbove < 3000) return 40
|
|
@@ -67,37 +84,107 @@ export function getResourceWeight(itemId: number, stratum: number): number {
|
|
|
67
84
|
}
|
|
68
85
|
}
|
|
69
86
|
|
|
70
|
-
const
|
|
71
|
-
const
|
|
72
|
-
const
|
|
73
|
-
const
|
|
74
|
-
const
|
|
75
|
-
const ICY_RESOURCES = [101, 301, 302, 401, 403, 501, 502]
|
|
76
|
-
const OCEAN_RESOURCES = [201, 203, 301, 303, 501, 502, 503]
|
|
77
|
-
const INDUSTRIAL_RESOURCES = [101, 102, 103, 201, 203, 402, 403]
|
|
87
|
+
const RESOURCE_ORE = 0
|
|
88
|
+
const RESOURCE_GAS = 1
|
|
89
|
+
const RESOURCE_REGOLITH = 2
|
|
90
|
+
const RESOURCE_BIOMASS = 3
|
|
91
|
+
const RESOURCE_CRYSTAL = 4
|
|
78
92
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
93
|
+
interface LocationProfileEntry {
|
|
94
|
+
category: number
|
|
95
|
+
maxTier: number
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function categoryBaseId(category: number): number {
|
|
99
|
+
switch (category) {
|
|
100
|
+
case RESOURCE_ORE:
|
|
101
|
+
return 100
|
|
102
|
+
case RESOURCE_CRYSTAL:
|
|
103
|
+
return 200
|
|
104
|
+
case RESOURCE_GAS:
|
|
105
|
+
return 300
|
|
106
|
+
case RESOURCE_REGOLITH:
|
|
107
|
+
return 400
|
|
108
|
+
case RESOURCE_BIOMASS:
|
|
109
|
+
return 500
|
|
110
|
+
default:
|
|
111
|
+
return 0
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function resourceId(category: number, tier: number): number {
|
|
116
|
+
return categoryBaseId(category) + tier
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export function getLocationProfile(locationType: number, subtype: number): LocationProfileEntry[] {
|
|
120
|
+
if (locationType === LocationType.ASTEROID) {
|
|
121
|
+
return [
|
|
122
|
+
{category: RESOURCE_ORE, maxTier: 5},
|
|
123
|
+
{category: RESOURCE_CRYSTAL, maxTier: 5},
|
|
124
|
+
]
|
|
125
|
+
}
|
|
126
|
+
if (locationType === LocationType.NEBULA) {
|
|
127
|
+
return [
|
|
128
|
+
{category: RESOURCE_GAS, maxTier: 5},
|
|
129
|
+
{category: RESOURCE_REGOLITH, maxTier: 5},
|
|
130
|
+
]
|
|
131
|
+
}
|
|
132
|
+
if (locationType === LocationType.ICE_FIELD) {
|
|
133
|
+
return [
|
|
134
|
+
{category: RESOURCE_GAS, maxTier: 5},
|
|
135
|
+
{category: RESOURCE_BIOMASS, maxTier: 5},
|
|
136
|
+
]
|
|
137
|
+
}
|
|
138
|
+
if (locationType === LocationType.PLANET) {
|
|
83
139
|
switch (subtype) {
|
|
84
140
|
case PLANET_SUBTYPE_GAS_GIANT:
|
|
85
|
-
return
|
|
141
|
+
return [
|
|
142
|
+
{category: RESOURCE_GAS, maxTier: 10},
|
|
143
|
+
{category: RESOURCE_CRYSTAL, maxTier: 3},
|
|
144
|
+
]
|
|
86
145
|
case PLANET_SUBTYPE_ROCKY:
|
|
87
|
-
return
|
|
146
|
+
return [
|
|
147
|
+
{category: RESOURCE_REGOLITH, maxTier: 10},
|
|
148
|
+
{category: RESOURCE_ORE, maxTier: 3},
|
|
149
|
+
]
|
|
88
150
|
case PLANET_SUBTYPE_TERRESTRIAL:
|
|
89
|
-
return
|
|
151
|
+
return [
|
|
152
|
+
{category: RESOURCE_ORE, maxTier: 10},
|
|
153
|
+
{category: RESOURCE_BIOMASS, maxTier: 3},
|
|
154
|
+
]
|
|
90
155
|
case PLANET_SUBTYPE_ICY:
|
|
91
|
-
return
|
|
156
|
+
return [
|
|
157
|
+
{category: RESOURCE_CRYSTAL, maxTier: 10},
|
|
158
|
+
{category: RESOURCE_REGOLITH, maxTier: 3},
|
|
159
|
+
]
|
|
92
160
|
case PLANET_SUBTYPE_OCEAN:
|
|
93
|
-
return
|
|
161
|
+
return [
|
|
162
|
+
{category: RESOURCE_BIOMASS, maxTier: 10},
|
|
163
|
+
{category: RESOURCE_GAS, maxTier: 3},
|
|
164
|
+
]
|
|
94
165
|
case PLANET_SUBTYPE_INDUSTRIAL:
|
|
95
|
-
return
|
|
166
|
+
return [
|
|
167
|
+
{category: RESOURCE_ORE, maxTier: 3},
|
|
168
|
+
{category: RESOURCE_CRYSTAL, maxTier: 3},
|
|
169
|
+
{category: RESOURCE_REGOLITH, maxTier: 3},
|
|
170
|
+
{category: RESOURCE_BIOMASS, maxTier: 3},
|
|
171
|
+
]
|
|
96
172
|
}
|
|
97
173
|
}
|
|
98
174
|
return []
|
|
99
175
|
}
|
|
100
176
|
|
|
177
|
+
export function getLocationCandidates(locationType: number, subtype: number): number[] {
|
|
178
|
+
const profile = getLocationProfile(locationType, subtype)
|
|
179
|
+
const ids: number[] = []
|
|
180
|
+
for (const {category, maxTier} of profile) {
|
|
181
|
+
for (let tier = 1; tier <= maxTier; tier++) {
|
|
182
|
+
ids.push(resourceId(category, tier))
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return ids
|
|
186
|
+
}
|
|
187
|
+
|
|
101
188
|
export function getEligibleResources(
|
|
102
189
|
locationType: number,
|
|
103
190
|
subtype: number,
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import {expect, test} from 'bun:test'
|
|
2
|
+
import {
|
|
3
|
+
MAX_STARS_PER_STAT,
|
|
4
|
+
MAX_STAR_RATING,
|
|
5
|
+
starRating,
|
|
6
|
+
starsForStat,
|
|
7
|
+
statMagnitude,
|
|
8
|
+
STAR_STEP,
|
|
9
|
+
} from './stars'
|
|
10
|
+
|
|
11
|
+
test('starsForStat bands at the 250 boundaries', () => {
|
|
12
|
+
expect(starsForStat(0)).toBe(0)
|
|
13
|
+
expect(starsForStat(1)).toBe(0)
|
|
14
|
+
expect(starsForStat(249)).toBe(0)
|
|
15
|
+
expect(starsForStat(250)).toBe(1)
|
|
16
|
+
expect(starsForStat(499)).toBe(1)
|
|
17
|
+
expect(starsForStat(500)).toBe(2)
|
|
18
|
+
expect(starsForStat(749)).toBe(2)
|
|
19
|
+
expect(starsForStat(750)).toBe(3)
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
test('starsForStat clamps to MAX_STARS_PER_STAT', () => {
|
|
23
|
+
expect(starsForStat(999)).toBe(MAX_STARS_PER_STAT)
|
|
24
|
+
expect(starsForStat(1000)).toBe(MAX_STARS_PER_STAT)
|
|
25
|
+
expect(starsForStat(10_000)).toBe(MAX_STARS_PER_STAT)
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
test('starsForStat never goes negative', () => {
|
|
29
|
+
expect(starsForStat(-50)).toBe(0)
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
test('starRating sums per-stat stars to a 0-9 grade', () => {
|
|
33
|
+
expect(starRating(0, 0, 0)).toBe(0)
|
|
34
|
+
expect(starRating(250, 0, 0)).toBe(1)
|
|
35
|
+
expect(starRating(750, 750, 750)).toBe(MAX_STAR_RATING)
|
|
36
|
+
expect(starRating(999, 999, 999)).toBe(MAX_STAR_RATING)
|
|
37
|
+
expect(starRating(599, 599, 599)).toBe(6)
|
|
38
|
+
expect(starRating(251, 251, 251)).toBe(3)
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
test('statMagnitude sums raw values for tiebreaking', () => {
|
|
42
|
+
expect(statMagnitude(599, 599, 599)).toBe(1797)
|
|
43
|
+
expect(statMagnitude(251, 251, 251)).toBe(753)
|
|
44
|
+
expect(statMagnitude(599, 599, 599)).toBeGreaterThan(statMagnitude(251, 251, 251))
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
test('constants hold their documented values', () => {
|
|
48
|
+
expect(STAR_STEP).toBe(250)
|
|
49
|
+
expect(MAX_STARS_PER_STAT).toBe(3)
|
|
50
|
+
expect(MAX_STAR_RATING).toBe(9)
|
|
51
|
+
})
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export const STAR_STEP = 250
|
|
2
|
+
export const MAX_STARS_PER_STAT = 3
|
|
3
|
+
export const MAX_STAR_RATING = MAX_STARS_PER_STAT * 3
|
|
4
|
+
|
|
5
|
+
export function starsForStat(value: number): number {
|
|
6
|
+
return Math.max(0, Math.min(MAX_STARS_PER_STAT, Math.floor(value / STAR_STEP)))
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function starRating(stat1: number, stat2: number, stat3: number): number {
|
|
10
|
+
return starsForStat(stat1) + starsForStat(stat2) + starsForStat(stat3)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function statMagnitude(stat1: number, stat2: number, stat3: number): number {
|
|
14
|
+
return stat1 + stat2 + stat3
|
|
15
|
+
}
|
package/src/derivation/stats.ts
CHANGED
|
@@ -25,8 +25,7 @@ const ORE_STATS: StatDefinition[] = [
|
|
|
25
25
|
key: 'density',
|
|
26
26
|
label: 'Density',
|
|
27
27
|
abbreviation: 'DEN',
|
|
28
|
-
purpose: '
|
|
29
|
-
inverted: true,
|
|
28
|
+
purpose: 'Structural integrity — higher rolls produce lighter hulls',
|
|
30
29
|
},
|
|
31
30
|
]
|
|
32
31
|
|
|
@@ -74,10 +73,11 @@ const GAS_STATS: StatDefinition[] = [
|
|
|
74
73
|
|
|
75
74
|
const REGOLITH_STATS: StatDefinition[] = [
|
|
76
75
|
{
|
|
77
|
-
key: '
|
|
78
|
-
label: '
|
|
79
|
-
abbreviation: '
|
|
80
|
-
purpose:
|
|
76
|
+
key: 'cohesion',
|
|
77
|
+
label: 'Cohesion',
|
|
78
|
+
abbreviation: 'COH',
|
|
79
|
+
purpose:
|
|
80
|
+
'Binding strength of the loose aggregate; higher cohesion yields more rigid frames and hulls',
|
|
81
81
|
},
|
|
82
82
|
{
|
|
83
83
|
key: 'hardness',
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import {Bytes, Checksum256, type Checksum256Type} from '@wharfkit/antelope'
|
|
2
2
|
import {hash512} from '../utils/hash'
|
|
3
3
|
import {Coordinates, type CoordinatesType} from '../types'
|
|
4
|
-
import {
|
|
4
|
+
import {getItem} from '../data/catalog'
|
|
5
|
+
import {getEligibleResources, getResourceWeight, yieldThresholdAt} from './resources'
|
|
5
6
|
import {RESERVE_TIERS, rollTier, rollWithinTier} from './tiers'
|
|
6
7
|
|
|
7
8
|
export interface StratumInfo {
|
|
@@ -33,15 +34,8 @@ export function deriveStratum(
|
|
|
33
34
|
|
|
34
35
|
const rawReserve = ((bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | bytes[3]) >>> 0
|
|
35
36
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
const tierRoll = ((bytes[18] << 8) | bytes[19]) >>> 0
|
|
39
|
-
const withinRoll = ((bytes[20] << 8) | bytes[21]) >>> 0
|
|
40
|
-
const tier = rollTier(tierRoll, stratum)
|
|
41
|
-
reserve = rollWithinTier(withinRoll, RESERVE_TIERS[tier])
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
if (reserve === 0) return {itemId: 0, seed: 0n, richness: 0, reserve: 0}
|
|
37
|
+
if (rawReserve > yieldThresholdAt(stratum))
|
|
38
|
+
return {itemId: 0, seed: 0n, richness: 0, reserve: 0}
|
|
45
39
|
|
|
46
40
|
const eligible = getEligibleResources(locationType, subtype, stratum)
|
|
47
41
|
if (eligible.length === 0) return {itemId: 0, seed: 0n, richness: 0, reserve: 0}
|
|
@@ -66,6 +60,12 @@ export function deriveStratum(
|
|
|
66
60
|
}
|
|
67
61
|
}
|
|
68
62
|
|
|
63
|
+
const tierRoll = ((bytes[18] << 8) | bytes[19]) >>> 0
|
|
64
|
+
const withinRoll = ((bytes[20] << 8) | bytes[21]) >>> 0
|
|
65
|
+
const tier = rollTier(tierRoll, stratum)
|
|
66
|
+
const unitMass = getItem(selectedItemId).mass
|
|
67
|
+
const reserve = rollWithinTier(withinRoll, RESERVE_TIERS[tier], unitMass)
|
|
68
|
+
|
|
69
69
|
const seedBigInt =
|
|
70
70
|
(BigInt(bytes[8]) << 56n) |
|
|
71
71
|
(BigInt(bytes[9]) << 48n) |
|
|
@@ -76,15 +76,11 @@ export function deriveStratum(
|
|
|
76
76
|
(BigInt(bytes[14]) << 8n) |
|
|
77
77
|
BigInt(bytes[15])
|
|
78
78
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
if (stratum > 1) {
|
|
85
|
-
depthBonus = (50 * Math.log(stratum)) / Math.log(65535)
|
|
86
|
-
}
|
|
87
|
-
const richness = Math.min(Math.floor(baseRichness + depthBonus), 1000)
|
|
79
|
+
let byteSum = 0
|
|
80
|
+
for (let i = 22; i <= 33; i++) byteSum += bytes[i]
|
|
81
|
+
const z = (byteSum - 1530) / 256
|
|
82
|
+
const roll = 500 + 100 * z
|
|
83
|
+
const richness = Math.max(1, Math.min(999, Math.round(roll)))
|
|
88
84
|
|
|
89
85
|
return {itemId: selectedItemId, seed: seedBigInt, richness, reserve}
|
|
90
86
|
}
|
package/src/derivation/tiers.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import {getItem} from '../data/catalog'
|
|
2
|
+
|
|
1
3
|
export type ReserveTier = 'small' | 'medium' | 'large' | 'massive' | 'motherlode'
|
|
2
4
|
|
|
3
5
|
export interface TierRange {
|
|
@@ -6,11 +8,11 @@ export interface TierRange {
|
|
|
6
8
|
}
|
|
7
9
|
|
|
8
10
|
export const RESERVE_TIERS: Record<ReserveTier, TierRange> = {
|
|
9
|
-
small: {min:
|
|
10
|
-
medium: {min:
|
|
11
|
-
large: {min:
|
|
12
|
-
massive: {min:
|
|
13
|
-
motherlode: {min:
|
|
11
|
+
small: {min: 3_600_000, max: 14_400_000},
|
|
12
|
+
medium: {min: 24_000_000, max: 48_000_000},
|
|
13
|
+
large: {min: 96_000_000, max: 168_000_000},
|
|
14
|
+
massive: {min: 240_000_000, max: 600_000_000},
|
|
15
|
+
motherlode: {min: 960_000_000, max: 2_400_000_000},
|
|
14
16
|
}
|
|
15
17
|
|
|
16
18
|
const SHALLOW_THRESHOLDS = {
|
|
@@ -47,8 +49,27 @@ export function rollTier(tierRoll: number, stratum: number): ReserveTier {
|
|
|
47
49
|
return 'motherlode'
|
|
48
50
|
}
|
|
49
51
|
|
|
50
|
-
export function rollWithinTier(
|
|
52
|
+
export function rollWithinTier(
|
|
53
|
+
withinRoll: number,
|
|
54
|
+
range: TierRange,
|
|
55
|
+
resourceUnitMass: number
|
|
56
|
+
): number {
|
|
51
57
|
const u = withinRoll / 65535
|
|
52
58
|
const skewed = u * u
|
|
53
|
-
|
|
59
|
+
const depositMass = range.min + skewed * (range.max - range.min)
|
|
60
|
+
return Math.max(1, Math.floor(depositMass / resourceUnitMass))
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const RESERVE_TIER_ENTRIES = Object.entries(RESERVE_TIERS) as Array<[ReserveTier, TierRange]>
|
|
64
|
+
|
|
65
|
+
export function tierOfReserve(reserve: number, itemId: number): ReserveTier | null {
|
|
66
|
+
if (reserve <= 0) return null
|
|
67
|
+
const unitMass = getItem(itemId).mass
|
|
68
|
+
if (unitMass <= 0) return null
|
|
69
|
+
const impliedMassLow = reserve * unitMass
|
|
70
|
+
const impliedMassHigh = impliedMassLow + unitMass
|
|
71
|
+
for (const [tier, range] of RESERVE_TIER_ENTRIES) {
|
|
72
|
+
if (impliedMassHigh > range.min && impliedMassLow <= range.max) return tier
|
|
73
|
+
}
|
|
74
|
+
return null
|
|
54
75
|
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import {UInt64} from '@wharfkit/antelope'
|
|
2
|
+
import {ServerContract} from '../contracts'
|
|
3
|
+
import {
|
|
4
|
+
CAP_DEMOLISH,
|
|
5
|
+
CAP_MODULES,
|
|
6
|
+
CAP_UNDEPLOY,
|
|
7
|
+
CAP_WRAP,
|
|
8
|
+
type EntityClass,
|
|
9
|
+
getEntityClass,
|
|
10
|
+
kindCan,
|
|
11
|
+
} from '../data/kind-registry'
|
|
12
|
+
import {InventoryAccessor} from './inventory-accessor'
|
|
13
|
+
import {Location} from './location'
|
|
14
|
+
import {ScheduleAccessor} from '../scheduling/accessor'
|
|
15
|
+
import * as schedule from '../scheduling/schedule'
|
|
16
|
+
import type {EntityInventory} from './entity-inventory'
|
|
17
|
+
|
|
18
|
+
export class Entity extends ServerContract.Types.entity_info {
|
|
19
|
+
private _sched?: ScheduleAccessor
|
|
20
|
+
private _inv?: InventoryAccessor
|
|
21
|
+
|
|
22
|
+
get name(): string {
|
|
23
|
+
return this.entity_name
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
get location(): Location {
|
|
27
|
+
return Location.from(this.coordinates)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
get isIdle(): boolean {
|
|
31
|
+
return schedule.isIdle(this)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
get sched(): ScheduleAccessor {
|
|
35
|
+
this._sched ??= new ScheduleAccessor(this)
|
|
36
|
+
return this._sched
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
get inv(): InventoryAccessor {
|
|
40
|
+
this._inv ??= new InventoryAccessor(this)
|
|
41
|
+
return this._inv
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
get inventory(): EntityInventory[] {
|
|
45
|
+
return this.inv.items
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
get totalCargoMass(): UInt64 {
|
|
49
|
+
return this.inv.totalMass
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
get maxCapacity(): UInt64 {
|
|
53
|
+
return UInt64.from(this.capacity ?? 0)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
get availableCapacity(): UInt64 {
|
|
57
|
+
const cargo = this.totalCargoMass
|
|
58
|
+
const max = this.maxCapacity
|
|
59
|
+
return cargo.gte(max) ? UInt64.from(0) : max.subtracting(cargo)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
get isFull(): boolean {
|
|
63
|
+
return this.totalCargoMass.gte(this.maxCapacity)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
get totalMass(): UInt64 {
|
|
67
|
+
const hull = this.hullmass ? UInt64.from(this.hullmass) : UInt64.from(0)
|
|
68
|
+
return hull.adding(this.totalCargoMass)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
get entityClass(): EntityClass {
|
|
72
|
+
return getEntityClass(this.type)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
get canWrap(): boolean {
|
|
76
|
+
return kindCan(this.type, CAP_WRAP)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
get canUndeploy(): boolean {
|
|
80
|
+
return kindCan(this.type, CAP_UNDEPLOY)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
get canDemolish(): boolean {
|
|
84
|
+
return kindCan(this.type, CAP_DEMOLISH)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
get canUseModules(): boolean {
|
|
88
|
+
return kindCan(this.type, CAP_MODULES)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
isLoading(now: Date): boolean {
|
|
92
|
+
return schedule.isLoading(this, now)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
isUnloading(now: Date): boolean {
|
|
96
|
+
return schedule.isUnloading(this, now)
|
|
97
|
+
}
|
|
98
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {Checksum256, Int64,
|
|
1
|
+
import {Checksum256, Int64, UInt64} from '@wharfkit/antelope'
|
|
2
2
|
import {type PlatformContract, ServerContract} from '../contracts'
|
|
3
3
|
import {type EpochInfo, getCurrentEpoch, getEpochInfo} from '../scheduling/epoch'
|
|
4
4
|
import {hasSystem} from '../utils/system'
|
|
@@ -34,7 +34,7 @@ export class GameState extends ServerContract.Types.state_row {
|
|
|
34
34
|
* Get the current epoch number from the state
|
|
35
35
|
*/
|
|
36
36
|
get currentEpoch(): UInt64 {
|
|
37
|
-
return this.epoch
|
|
37
|
+
return UInt64.from(this.epoch.toString())
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
/**
|
|
@@ -58,27 +58,6 @@ export class GameState extends ServerContract.Types.state_row {
|
|
|
58
58
|
return this.enabled
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
/**
|
|
62
|
-
* Get the total number of ships in the game
|
|
63
|
-
*/
|
|
64
|
-
get shipCount(): number {
|
|
65
|
-
return Number(this.ships)
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Get the current salt value (used for random number generation)
|
|
70
|
-
*/
|
|
71
|
-
get currentSalt(): UInt64 {
|
|
72
|
-
return this.salt
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Get the commit hash for the next epoch
|
|
77
|
-
*/
|
|
78
|
-
get nextEpochCommit(): Checksum256 {
|
|
79
|
-
return this.commit
|
|
80
|
-
}
|
|
81
|
-
|
|
82
61
|
/**
|
|
83
62
|
* Calculate the current epoch from game config (if game is set)
|
|
84
63
|
* This might differ from state.epoch if the blockchain hasn't advanced yet
|
|
@@ -97,7 +76,7 @@ export class GameState extends ServerContract.Types.state_row {
|
|
|
97
76
|
if (!this._game) {
|
|
98
77
|
return undefined
|
|
99
78
|
}
|
|
100
|
-
return getEpochInfo(this._game, this.
|
|
79
|
+
return getEpochInfo(this._game, this.currentEpoch)
|
|
101
80
|
}
|
|
102
81
|
|
|
103
82
|
/**
|
|
@@ -137,16 +116,12 @@ export class GameState extends ServerContract.Types.state_row {
|
|
|
137
116
|
get summary(): {
|
|
138
117
|
enabled: boolean
|
|
139
118
|
epoch: string
|
|
140
|
-
ships: number
|
|
141
119
|
hasSeed: boolean
|
|
142
|
-
hasCommit: boolean
|
|
143
120
|
} {
|
|
144
121
|
return {
|
|
145
122
|
enabled: this.enabled,
|
|
146
123
|
epoch: this.epoch.toString(),
|
|
147
|
-
ships: this.shipCount,
|
|
148
124
|
hasSeed: !this.seed.equals(Checksum256.from('0'.repeat(64))),
|
|
149
|
-
hasCommit: !this.commit.equals(Checksum256.from('0'.repeat(64))),
|
|
150
125
|
}
|
|
151
126
|
}
|
|
152
127
|
}
|