@shipload/sdk 0.7.1 → 2.0.0-rc2
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/README.md +349 -1
- package/lib/shipload.d.ts +2016 -230
- package/lib/shipload.js +5733 -2094
- package/lib/shipload.js.map +1 -1
- package/lib/shipload.m.js +5425 -2012
- package/lib/shipload.m.js.map +1 -1
- package/package.json +5 -5
- package/src/capabilities/extraction.ts +37 -0
- package/src/capabilities/guards.ts +43 -0
- package/src/capabilities/index.ts +5 -0
- package/src/capabilities/loading.ts +8 -0
- package/src/capabilities/movement.ts +29 -0
- package/src/capabilities/storage.ts +67 -0
- package/src/contracts/server.ts +788 -202
- package/src/data/goods.json +23 -0
- package/src/data/syllables.json +1184 -0
- package/src/entities/cargo-utils.ts +142 -0
- package/src/entities/container.ts +70 -0
- package/src/entities/entity-inventory.ts +39 -0
- package/src/entities/gamestate.ts +152 -0
- package/src/entities/inventory-accessor.ts +46 -0
- package/src/entities/location.ts +255 -0
- package/src/entities/makers.ts +69 -0
- package/src/entities/player.ts +288 -0
- package/src/entities/ship.ts +208 -0
- package/src/entities/warehouse.ts +89 -0
- package/src/errors.ts +46 -9
- package/src/index-module.ts +152 -7
- package/src/managers/actions.ts +200 -0
- package/src/managers/base.ts +25 -0
- package/src/managers/context.ts +104 -0
- package/src/managers/entities.ts +103 -0
- package/src/managers/epochs.ts +47 -0
- package/src/managers/index.ts +9 -0
- package/src/managers/locations.ts +122 -0
- package/src/managers/players.ts +13 -0
- package/src/managers/trades.ts +119 -0
- package/src/market/goods.ts +31 -0
- package/src/{market.ts → market/market.ts} +31 -37
- package/src/{rolls.ts → market/rolls.ts} +3 -3
- package/src/scheduling/accessor.ts +82 -0
- package/src/{epoch.ts → scheduling/epoch.ts} +1 -1
- package/src/scheduling/projection.ts +290 -0
- package/src/scheduling/schedule.ts +179 -0
- package/src/shipload.ts +39 -157
- package/src/trading/collect.ts +938 -0
- package/src/trading/deal.ts +207 -0
- package/src/trading/trade.ts +203 -0
- package/src/travel/travel.ts +486 -0
- package/src/types/capabilities.ts +79 -0
- package/src/types/entity-traits.ts +70 -0
- package/src/types/entity.ts +36 -0
- package/src/types/index.ts +3 -0
- package/src/types.ts +127 -25
- package/src/{hash.ts → utils/hash.ts} +1 -1
- package/src/utils/system.ts +155 -0
- package/src/goods.ts +0 -124
- package/src/ship.ts +0 -36
- package/src/state.ts +0 -0
- package/src/syllables.ts +0 -1184
- package/src/system.ts +0 -37
- package/src/travel.ts +0 -259
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import {UInt64, UInt64Type} from '@wharfkit/antelope'
|
|
2
|
+
import {BaseManager} from './base'
|
|
3
|
+
import {EpochInfo, getCurrentEpoch, getEpochInfo} from '../scheduling/epoch'
|
|
4
|
+
|
|
5
|
+
export class EpochsManager extends BaseManager {
|
|
6
|
+
async getCurrentHeight(): Promise<UInt64> {
|
|
7
|
+
const game = await this.getGame()
|
|
8
|
+
return getCurrentEpoch(game)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
async getCurrent(): Promise<EpochInfo> {
|
|
12
|
+
const game = await this.getGame()
|
|
13
|
+
const epoch = await this.getCurrentHeight()
|
|
14
|
+
return getEpochInfo(game, epoch)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async getByHeight(height: UInt64Type): Promise<EpochInfo> {
|
|
18
|
+
const game = await this.getGame()
|
|
19
|
+
return getEpochInfo(game, UInt64.from(height))
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async getTimeRemaining(): Promise<number> {
|
|
23
|
+
const epochInfo = await this.getCurrent()
|
|
24
|
+
const now = Date.now()
|
|
25
|
+
const endTime = epochInfo.end.getTime()
|
|
26
|
+
return Math.max(0, endTime - now)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async getProgress(): Promise<number> {
|
|
30
|
+
const epochInfo = await this.getCurrent()
|
|
31
|
+
const now = Date.now()
|
|
32
|
+
const startTime = epochInfo.start.getTime()
|
|
33
|
+
const endTime = epochInfo.end.getTime()
|
|
34
|
+
const duration = endTime - startTime
|
|
35
|
+
const elapsed = now - startTime
|
|
36
|
+
|
|
37
|
+
if (elapsed <= 0) return 0
|
|
38
|
+
if (elapsed >= duration) return 1
|
|
39
|
+
|
|
40
|
+
return elapsed / duration
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async fitsInCurrentEpoch(durationMs: number): Promise<boolean> {
|
|
44
|
+
const remaining = await this.getTimeRemaining()
|
|
45
|
+
return durationMs <= remaining
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export {GameContext} from './context'
|
|
2
|
+
export {BaseManager} from './base'
|
|
3
|
+
export {EntitiesManager} from './entities'
|
|
4
|
+
export type {EntityType} from './entities'
|
|
5
|
+
export {PlayersManager} from './players'
|
|
6
|
+
export {LocationsManager} from './locations'
|
|
7
|
+
export {TradesManager} from './trades'
|
|
8
|
+
export {EpochsManager} from './epochs'
|
|
9
|
+
export {ActionsManager} from './actions'
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import {Bytes, Checksum256, UInt16Type, UInt64, UInt64Type} from '@wharfkit/antelope'
|
|
2
|
+
import {BaseManager} from './base'
|
|
3
|
+
import {CoordinatesType, coordsToLocationId, Distance, GoodPrice} from '../types'
|
|
4
|
+
import {marketPrice, marketPrices} from '../market/market'
|
|
5
|
+
import {hasSystem} from '../utils/system'
|
|
6
|
+
import {findNearbyPlanets} from '../travel/travel'
|
|
7
|
+
import {Location, toLocation} from '../entities/location'
|
|
8
|
+
import {ServerContract} from '../contracts'
|
|
9
|
+
|
|
10
|
+
export class LocationsManager extends BaseManager {
|
|
11
|
+
async getMarketPrice(location: CoordinatesType, goodId: number): Promise<GoodPrice> {
|
|
12
|
+
const game = await this.getGame()
|
|
13
|
+
const state = await this.getState()
|
|
14
|
+
return marketPrice(location, goodId, game.config.seed, state)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async getMarketPrices(location: CoordinatesType): Promise<GoodPrice[]> {
|
|
18
|
+
const game = await this.getGame()
|
|
19
|
+
const state = await this.getState()
|
|
20
|
+
return marketPrices(location, game.config.seed, state)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async getMarketPricesWithSupply(location: CoordinatesType): Promise<GoodPrice[]> {
|
|
24
|
+
const [game, state, supplyRows] = await Promise.all([
|
|
25
|
+
this.getGame(),
|
|
26
|
+
this.getState(),
|
|
27
|
+
this.getSupplyRows(location),
|
|
28
|
+
])
|
|
29
|
+
|
|
30
|
+
const prices = marketPrices(location, game.config.seed, state)
|
|
31
|
+
|
|
32
|
+
const supplyMap = new Map<number, number>()
|
|
33
|
+
for (const row of supplyRows) {
|
|
34
|
+
if (UInt64.from(row.epoch).equals(state.epoch)) {
|
|
35
|
+
supplyMap.set(Number(row.good_id), Number(row.supply))
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return prices.map((price) => {
|
|
40
|
+
const actualSupply = supplyMap.get(Number(price.id))
|
|
41
|
+
if (actualSupply !== undefined) {
|
|
42
|
+
return GoodPrice.from({
|
|
43
|
+
id: price.id,
|
|
44
|
+
good: price.good,
|
|
45
|
+
price: price.price,
|
|
46
|
+
supply: UInt64.from(actualSupply),
|
|
47
|
+
})
|
|
48
|
+
}
|
|
49
|
+
return price
|
|
50
|
+
})
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async hasSystem(location: CoordinatesType): Promise<boolean> {
|
|
54
|
+
const game = await this.getGame()
|
|
55
|
+
return hasSystem(game.config.seed, location)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async findNearbyPlanets(
|
|
59
|
+
origin: CoordinatesType,
|
|
60
|
+
maxDistance: UInt16Type = 20
|
|
61
|
+
): Promise<Distance[]> {
|
|
62
|
+
const game = await this.getGame()
|
|
63
|
+
return findNearbyPlanets(game.config.seed, origin, maxDistance)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async getSupplyRows(location: CoordinatesType) {
|
|
67
|
+
const hash = Checksum256.hash(Bytes.from(`${location.x}-${location.y}`, 'utf8'))
|
|
68
|
+
return this.server.table('supply').all({
|
|
69
|
+
index_position: 'secondary',
|
|
70
|
+
from: hash,
|
|
71
|
+
to: hash,
|
|
72
|
+
})
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async getLocationWithPrices(coords: CoordinatesType): Promise<Location> {
|
|
76
|
+
const location = toLocation(coords)
|
|
77
|
+
const prices = await this.getMarketPrices(location.coordinates)
|
|
78
|
+
location.setMarketPrices(prices)
|
|
79
|
+
return location
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
async getLocationWithSupply(coords: CoordinatesType): Promise<Location> {
|
|
83
|
+
const location = toLocation(coords)
|
|
84
|
+
const [rows, state] = await Promise.all([
|
|
85
|
+
this.getSupplyRows(location.coordinates),
|
|
86
|
+
this.getState(),
|
|
87
|
+
])
|
|
88
|
+
location.setLocationRows(rows, state.epoch)
|
|
89
|
+
return location
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async getLocationComplete(coords: CoordinatesType): Promise<Location> {
|
|
93
|
+
const location = toLocation(coords)
|
|
94
|
+
const [prices, rows, state] = await Promise.all([
|
|
95
|
+
this.getMarketPrices(location.coordinates),
|
|
96
|
+
this.getSupplyRows(location.coordinates),
|
|
97
|
+
this.getState(),
|
|
98
|
+
])
|
|
99
|
+
|
|
100
|
+
location.setMarketPrices(prices)
|
|
101
|
+
location.setLocationRows(rows, state.epoch)
|
|
102
|
+
return location
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
async getLocationEntity(
|
|
106
|
+
id: UInt64Type
|
|
107
|
+
): Promise<ServerContract.Types.location_row | undefined> {
|
|
108
|
+
const row = await this.server.table('location').get(UInt64.from(id))
|
|
109
|
+
return row ?? undefined
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
async getLocationEntityAt(
|
|
113
|
+
coords: CoordinatesType
|
|
114
|
+
): Promise<ServerContract.Types.location_row | undefined> {
|
|
115
|
+
const id = coordsToLocationId(coords)
|
|
116
|
+
return this.getLocationEntity(id)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
async getAllLocationEntities(): Promise<ServerContract.Types.location_row[]> {
|
|
120
|
+
return this.server.table('location').all()
|
|
121
|
+
}
|
|
122
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import {Name, NameType} from '@wharfkit/antelope'
|
|
2
|
+
import {BaseManager} from './base'
|
|
3
|
+
import {Player} from '../entities/player'
|
|
4
|
+
|
|
5
|
+
export class PlayersManager extends BaseManager {
|
|
6
|
+
async getPlayer(account: NameType): Promise<Player | undefined> {
|
|
7
|
+
const playerRow = await this.server.table('player').get(Name.from(account))
|
|
8
|
+
if (!playerRow) {
|
|
9
|
+
return undefined
|
|
10
|
+
}
|
|
11
|
+
return new Player(playerRow)
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import {UInt64} from '@wharfkit/antelope'
|
|
2
|
+
import {BaseManager} from './base'
|
|
3
|
+
import {Ship} from '../entities/ship'
|
|
4
|
+
import {Deal, findDealsForShip, FindDealsOptions} from '../trading/deal'
|
|
5
|
+
import {
|
|
6
|
+
analyzeCollectOptions,
|
|
7
|
+
CollectAnalysis,
|
|
8
|
+
CollectAnalysisCallbacks,
|
|
9
|
+
CollectAnalysisOptions,
|
|
10
|
+
} from '../trading/collect'
|
|
11
|
+
import {Coordinates, GoodPrice} from '../types'
|
|
12
|
+
import {Location, toLocation} from '../entities/location'
|
|
13
|
+
import {findNearbyPlanets} from '../travel/travel'
|
|
14
|
+
import {getCurrentEpoch} from '../scheduling/epoch'
|
|
15
|
+
|
|
16
|
+
export class TradesManager extends BaseManager {
|
|
17
|
+
private priceCache = new Map<string, GoodPrice[]>()
|
|
18
|
+
private priceCacheEpoch: UInt64 | undefined
|
|
19
|
+
|
|
20
|
+
private makePriceCacheKey(location: Coordinates): string {
|
|
21
|
+
return `${location.x},${location.y}`
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
private async createCallbacks(): Promise<CollectAnalysisCallbacks> {
|
|
25
|
+
const game = await this.getGame()
|
|
26
|
+
const serverState = await this.getState()
|
|
27
|
+
const currentEpoch = getCurrentEpoch(game)
|
|
28
|
+
|
|
29
|
+
if (!this.priceCacheEpoch || !this.priceCacheEpoch.equals(currentEpoch)) {
|
|
30
|
+
this.priceCache.clear()
|
|
31
|
+
this.priceCacheEpoch = currentEpoch
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const getNearbyLocations = async (
|
|
35
|
+
origin: Coordinates,
|
|
36
|
+
maxDistance: number
|
|
37
|
+
): Promise<Location[]> => {
|
|
38
|
+
const nearby = findNearbyPlanets(game.config.seed, origin, maxDistance)
|
|
39
|
+
return nearby.map((d) => toLocation(d.destination))
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const getMarketPrices = async (location: Coordinates): Promise<GoodPrice[]> => {
|
|
43
|
+
const cacheKey = this.makePriceCacheKey(location)
|
|
44
|
+
const cached = this.priceCache.get(cacheKey)
|
|
45
|
+
if (cached) {
|
|
46
|
+
return cached
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const locationWithSupply = await this.context.locations.getLocationComplete(location)
|
|
50
|
+
const prices = locationWithSupply.marketPrices || []
|
|
51
|
+
|
|
52
|
+
const result = prices.map((price) => {
|
|
53
|
+
const actualSupply = locationWithSupply.getSupply(price.id)
|
|
54
|
+
|
|
55
|
+
if (actualSupply !== undefined) {
|
|
56
|
+
return GoodPrice.from({
|
|
57
|
+
id: price.id,
|
|
58
|
+
good: price.good,
|
|
59
|
+
price: price.price,
|
|
60
|
+
supply: actualSupply,
|
|
61
|
+
})
|
|
62
|
+
}
|
|
63
|
+
return price
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
this.priceCache.set(cacheKey, result)
|
|
67
|
+
return result
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const getGameSeed = () => game.config.seed
|
|
71
|
+
const getState = () => serverState
|
|
72
|
+
|
|
73
|
+
return {getNearbyLocations, getMarketPrices, getGameSeed, getState}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
clearPriceCache(): void {
|
|
77
|
+
this.priceCache.clear()
|
|
78
|
+
this.priceCacheEpoch = undefined
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async findDeals(
|
|
82
|
+
ship: Ship,
|
|
83
|
+
originLocation?: Coordinates,
|
|
84
|
+
options: FindDealsOptions = {}
|
|
85
|
+
): Promise<Deal[]> {
|
|
86
|
+
const origin = originLocation || Coordinates.from(ship.coordinates)
|
|
87
|
+
const callbacks = await this.createCallbacks()
|
|
88
|
+
|
|
89
|
+
const deals = await findDealsForShip(
|
|
90
|
+
ship,
|
|
91
|
+
origin,
|
|
92
|
+
callbacks.getNearbyLocations,
|
|
93
|
+
callbacks.getMarketPrices,
|
|
94
|
+
options
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
return deals
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
async findBestDeal(
|
|
101
|
+
ship: Ship,
|
|
102
|
+
originLocation?: Coordinates,
|
|
103
|
+
options: FindDealsOptions = {}
|
|
104
|
+
): Promise<Deal | undefined> {
|
|
105
|
+
const deals = await this.findDeals(ship, originLocation, {...options, maxDeals: 1})
|
|
106
|
+
return deals[0]
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
async getCollectOptions(
|
|
110
|
+
ship: Ship,
|
|
111
|
+
arrivedAt?: Coordinates,
|
|
112
|
+
options: CollectAnalysisOptions = {}
|
|
113
|
+
): Promise<CollectAnalysis> {
|
|
114
|
+
const location = arrivedAt || Coordinates.from(ship.coordinates)
|
|
115
|
+
const callbacks = await this.createCallbacks()
|
|
116
|
+
|
|
117
|
+
return analyzeCollectOptions(ship, location, callbacks, options)
|
|
118
|
+
}
|
|
119
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import {UInt16, UInt16Type, UInt32} from '@wharfkit/antelope'
|
|
2
|
+
import {Good} from '../types'
|
|
3
|
+
import goodsData from '../data/goods.json'
|
|
4
|
+
|
|
5
|
+
const goods = goodsData as Array<{
|
|
6
|
+
id: number
|
|
7
|
+
name: string
|
|
8
|
+
description: string
|
|
9
|
+
base_price: number
|
|
10
|
+
mass: number
|
|
11
|
+
}>
|
|
12
|
+
|
|
13
|
+
export const goodIds = goods.map((g) => g.id)
|
|
14
|
+
|
|
15
|
+
export function getGood(goodId: UInt16Type): Good {
|
|
16
|
+
const good = goods.find((g) => UInt16.from(goodId).equals(g.id))
|
|
17
|
+
if (!good) {
|
|
18
|
+
throw new Error('Good does not exist')
|
|
19
|
+
}
|
|
20
|
+
return Good.from({
|
|
21
|
+
id: UInt16.from(good.id),
|
|
22
|
+
name: good.name,
|
|
23
|
+
description: good.description,
|
|
24
|
+
base_price: UInt32.from(good.base_price),
|
|
25
|
+
mass: UInt32.from(good.mass),
|
|
26
|
+
})
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function getGoods(): Good[] {
|
|
30
|
+
return goods.map((g) => getGood(g.id))
|
|
31
|
+
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {CoordinatesType, GoodPrice} from '../types'
|
|
2
2
|
import {getGood, getGoods} from './goods'
|
|
3
|
-
import {Checksum256Type, UInt16Type,
|
|
3
|
+
import {Checksum256Type, UInt16, UInt16Type, UInt32} from '@wharfkit/antelope'
|
|
4
4
|
import {roll} from './rolls'
|
|
5
|
-
import {ServerContract} from '
|
|
5
|
+
import {ServerContract} from '../contracts'
|
|
6
6
|
|
|
7
7
|
export enum Rarities {
|
|
8
8
|
legendary = 'LEGENDARY',
|
|
@@ -19,21 +19,13 @@ export interface Rarity {
|
|
|
19
19
|
maxMultiplier: number // The maximum multiplier for this rarity
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
export function generateLocationSeed(
|
|
23
|
-
epochSeed: Checksum256Type,
|
|
24
|
-
location: Coordinates,
|
|
25
|
-
entitySalt: string
|
|
26
|
-
) {
|
|
27
|
-
return `${epochSeed}${location.x}${location.y}${entitySalt}`
|
|
28
|
-
}
|
|
29
|
-
|
|
30
22
|
export function getRarity(
|
|
31
23
|
gameSeed: Checksum256Type,
|
|
32
24
|
epochSeed: Checksum256Type,
|
|
33
|
-
location:
|
|
34
|
-
|
|
25
|
+
location: CoordinatesType,
|
|
26
|
+
goodId: UInt16Type
|
|
35
27
|
): Rarity {
|
|
36
|
-
const seed = `${epochSeed}${location.x}${location.y}${
|
|
28
|
+
const seed = `${epochSeed}${location.x}${location.y}${goodId}rarity`
|
|
37
29
|
const rarityRoll = roll(gameSeed, seed)
|
|
38
30
|
|
|
39
31
|
if (rarityRoll < 13) {
|
|
@@ -119,22 +111,22 @@ export function getRarity(
|
|
|
119
111
|
export function getRarityMultiplier(
|
|
120
112
|
gameSeed: Checksum256Type,
|
|
121
113
|
epochSeed: Checksum256Type,
|
|
122
|
-
location:
|
|
123
|
-
|
|
114
|
+
location: CoordinatesType,
|
|
115
|
+
goodId: UInt16Type
|
|
124
116
|
): number {
|
|
125
|
-
const rarity = getRarity(gameSeed, epochSeed, location,
|
|
117
|
+
const rarity = getRarity(gameSeed, epochSeed, location, goodId)
|
|
126
118
|
const range = rarity.maxMultiplier - rarity.minMultiplier
|
|
127
|
-
const seed = `${epochSeed}${location.x}${location.y}${
|
|
119
|
+
const seed = `${epochSeed}${location.x}${location.y}${goodId}raritymultiplier`
|
|
128
120
|
const r = roll(gameSeed, seed)
|
|
129
121
|
return rarity.minMultiplier + (r / 65535) * range
|
|
130
122
|
}
|
|
131
123
|
|
|
132
124
|
export function getLocationMultiplier(
|
|
133
125
|
gameSeed: Checksum256Type,
|
|
134
|
-
location:
|
|
135
|
-
|
|
126
|
+
location: CoordinatesType,
|
|
127
|
+
goodId: UInt16Type
|
|
136
128
|
): number {
|
|
137
|
-
const seed = `${location.x}${location.y}${
|
|
129
|
+
const seed = `${location.x}${location.y}${goodId}locationmultiplier`
|
|
138
130
|
const r = roll(gameSeed, seed)
|
|
139
131
|
if (r < 13) {
|
|
140
132
|
return 0.75
|
|
@@ -164,51 +156,53 @@ export function getLocationMultiplier(
|
|
|
164
156
|
export function getSupply(
|
|
165
157
|
gameSeed: Checksum256Type,
|
|
166
158
|
state: ServerContract.Types.state_row,
|
|
167
|
-
location:
|
|
168
|
-
|
|
159
|
+
location: CoordinatesType,
|
|
160
|
+
goodId: UInt16Type
|
|
169
161
|
): number {
|
|
170
|
-
const seed = `${state.seed}${location.x}${location.y}${
|
|
162
|
+
const seed = `${state.seed}${location.x}${location.y}${goodId}supply`
|
|
171
163
|
const r = roll(gameSeed, seed)
|
|
172
164
|
const percent = r / 65535
|
|
173
165
|
const epoch = 1 + Number(state.epoch) / 90
|
|
174
|
-
const ship =
|
|
175
|
-
|
|
166
|
+
const ship = 1
|
|
167
|
+
const goodIdNum = Number(goodId)
|
|
168
|
+
const base = Math.floor(128 / goodIdNum)
|
|
169
|
+
return Math.floor(base * percent * ship * epoch)
|
|
176
170
|
}
|
|
177
171
|
|
|
178
|
-
export function
|
|
172
|
+
export function marketPrice(
|
|
179
173
|
location: ServerContract.ActionParams.Type.coordinates,
|
|
180
|
-
|
|
174
|
+
goodId: UInt16Type,
|
|
181
175
|
gameSeed: Checksum256Type,
|
|
182
176
|
state: ServerContract.Types.state_row
|
|
183
177
|
): GoodPrice {
|
|
184
|
-
const good = getGood(
|
|
178
|
+
const good = getGood(goodId)
|
|
185
179
|
let price = Number(good.base_price)
|
|
186
180
|
|
|
187
181
|
// Rarity multiplier of the deal (changes with epoch)
|
|
188
182
|
// Large impact range on price, from 0.285x to 3.0x
|
|
189
|
-
const rarityMultiplier = getRarityMultiplier(gameSeed, state.seed, location,
|
|
183
|
+
const rarityMultiplier = getRarityMultiplier(gameSeed, state.seed, location, goodId)
|
|
190
184
|
price *= rarityMultiplier
|
|
191
185
|
|
|
192
186
|
// Location multiplier of the deal (static, based on game seed)
|
|
193
187
|
// Small impact range on price, from 1.0x to 1.5x
|
|
194
|
-
const locationMultiplier = getLocationMultiplier(gameSeed, location,
|
|
188
|
+
const locationMultiplier = getLocationMultiplier(gameSeed, location, goodId)
|
|
195
189
|
price *= locationMultiplier
|
|
196
190
|
|
|
197
191
|
// Determine the current supply of the good at the location
|
|
198
|
-
const supply = getSupply(gameSeed, state, location,
|
|
192
|
+
const supply = getSupply(gameSeed, state, location, goodId)
|
|
199
193
|
|
|
200
194
|
return GoodPrice.from({
|
|
201
|
-
id:
|
|
195
|
+
id: goodId,
|
|
202
196
|
good,
|
|
203
|
-
price:
|
|
204
|
-
supply:
|
|
197
|
+
price: UInt32.from(price),
|
|
198
|
+
supply: UInt16.from(supply),
|
|
205
199
|
})
|
|
206
200
|
}
|
|
207
201
|
|
|
208
|
-
export function
|
|
202
|
+
export function marketPrices(
|
|
209
203
|
location: ServerContract.ActionParams.Type.coordinates,
|
|
210
204
|
gameSeed: Checksum256Type,
|
|
211
205
|
state: ServerContract.Types.state_row
|
|
212
206
|
): GoodPrice[] {
|
|
213
|
-
return getGoods().map((good) =>
|
|
207
|
+
return getGoods().map((good) => marketPrice(location, good.id, gameSeed, state))
|
|
214
208
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {Checksum256Type} from '@wharfkit/antelope'
|
|
2
|
-
import {hash512} from '
|
|
2
|
+
import {hash512} from '../utils/hash'
|
|
3
3
|
|
|
4
|
-
export function roll(
|
|
5
|
-
const hash = hash512(
|
|
4
|
+
export function roll(gameSeed: Checksum256Type, rollSeed: string): number {
|
|
5
|
+
const hash = hash512(gameSeed, rollSeed)
|
|
6
6
|
// Combine the first two bytes to form a uint16_t value
|
|
7
7
|
return (hash.array[0] << 8) | hash.array[1]
|
|
8
8
|
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import {ServerContract} from '../contracts'
|
|
2
|
+
import {TaskType} from '../types'
|
|
3
|
+
import {ScheduleData} from './schedule'
|
|
4
|
+
import * as schedule from './schedule'
|
|
5
|
+
|
|
6
|
+
type Task = ServerContract.Types.task
|
|
7
|
+
|
|
8
|
+
export class ScheduleAccessor {
|
|
9
|
+
constructor(private entity: ScheduleData) {}
|
|
10
|
+
|
|
11
|
+
get hasSchedule(): boolean {
|
|
12
|
+
return schedule.hasSchedule(this.entity)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
get isIdle(): boolean {
|
|
16
|
+
return schedule.isIdle(this.entity)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
get tasks(): Task[] {
|
|
20
|
+
return schedule.getTasks(this.entity)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
duration(): number {
|
|
24
|
+
return schedule.scheduleDuration(this.entity)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
elapsed(now: Date): number {
|
|
28
|
+
return schedule.scheduleElapsed(this.entity, now)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
remaining(now: Date): number {
|
|
32
|
+
return schedule.scheduleRemaining(this.entity, now)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
complete(now: Date): boolean {
|
|
36
|
+
return schedule.scheduleComplete(this.entity, now)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
currentTaskIndex(now: Date): number {
|
|
40
|
+
return schedule.currentTaskIndex(this.entity, now)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
currentTask(now: Date): Task | undefined {
|
|
44
|
+
return schedule.currentTask(this.entity, now)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
currentTaskType(now: Date): TaskType | undefined {
|
|
48
|
+
return schedule.currentTaskType(this.entity, now)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
taskStartTime(index: number): number {
|
|
52
|
+
return schedule.getTaskStartTime(this.entity, index)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
taskElapsed(index: number, now: Date): number {
|
|
56
|
+
return schedule.getTaskElapsed(this.entity, index, now)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
taskRemaining(index: number, now: Date): number {
|
|
60
|
+
return schedule.getTaskRemaining(this.entity, index, now)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
taskComplete(index: number, now: Date): boolean {
|
|
64
|
+
return schedule.isTaskComplete(this.entity, index, now)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
taskInProgress(index: number, now: Date): boolean {
|
|
68
|
+
return schedule.isTaskInProgress(this.entity, index, now)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
currentTaskProgress(now: Date): number {
|
|
72
|
+
return schedule.currentTaskProgress(this.entity, now)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
progress(now: Date): number {
|
|
76
|
+
return schedule.scheduleProgress(this.entity, now)
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function createScheduleAccessor(entity: ScheduleData): ScheduleAccessor {
|
|
81
|
+
return new ScheduleAccessor(entity)
|
|
82
|
+
}
|