@shipload/sdk 2.0.0-rc5 → 2.0.0-rc6
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 +376 -1008
- package/lib/shipload.js +712 -1948
- package/lib/shipload.js.map +1 -1
- package/lib/shipload.m.js +694 -1924
- package/lib/shipload.m.js.map +1 -1
- package/package.json +1 -1
- package/src/capabilities/crafting.ts +10 -0
- package/src/capabilities/guards.ts +0 -5
- package/src/capabilities/index.ts +1 -0
- package/src/capabilities/storage.ts +0 -8
- package/src/contracts/server.ts +103 -220
- package/src/data/items.json +15 -15
- package/src/data/recipes.ts +129 -0
- package/src/derivation/crafting.ts +120 -0
- package/src/derivation/index.ts +1 -0
- package/src/derivation/stats.ts +91 -15
- package/src/derivation/stratum.ts +2 -2
- package/src/entities/cargo-utils.ts +6 -64
- package/src/entities/container.ts +18 -0
- package/src/entities/entity-inventory.ts +0 -4
- package/src/entities/inventory-accessor.ts +0 -4
- package/src/entities/location.ts +2 -197
- package/src/entities/player.ts +1 -274
- package/src/entities/ship.ts +0 -21
- package/src/entities/warehouse.ts +0 -4
- package/src/index-module.ts +34 -41
- package/src/managers/actions.ts +38 -90
- package/src/managers/context.ts +0 -9
- package/src/managers/index.ts +0 -1
- package/src/managers/locations.ts +2 -85
- package/src/market/items.ts +0 -1
- package/src/scheduling/projection.ts +0 -10
- package/src/shipload.ts +0 -5
- package/src/types/capabilities.ts +1 -9
- package/src/types/entity-traits.ts +3 -4
- package/src/types/entity.ts +0 -1
- package/src/types.ts +5 -25
- package/src/utils/system.ts +5 -4
- package/src/managers/trades.ts +0 -119
- package/src/market/market.ts +0 -195
- package/src/market/rolls.ts +0 -8
- package/src/trading/collect.ts +0 -938
- package/src/trading/deal.ts +0 -207
- package/src/trading/trade.ts +0 -203
package/src/entities/location.ts
CHANGED
|
@@ -1,35 +1,22 @@
|
|
|
1
|
-
import {Checksum256, Checksum256Type,
|
|
2
|
-
import {
|
|
3
|
-
import {Coordinates, CoordinatesType, Distance, ItemPrice, LocationType} from '../types'
|
|
1
|
+
import {Checksum256, Checksum256Type, UInt16Type, UInt64} from '@wharfkit/antelope'
|
|
2
|
+
import {Coordinates, CoordinatesType, Distance, LocationType} from '../types'
|
|
4
3
|
import {getLocationType, hasSystem, isExtractableLocation} from '../utils/system'
|
|
5
4
|
import {findNearbyPlanets} from '../travel/travel'
|
|
6
5
|
|
|
7
|
-
/**
|
|
8
|
-
* Location helper class for working with game coordinates.
|
|
9
|
-
* Provides system detection, market price caching, nearby planet finding, and supply tracking.
|
|
10
|
-
*/
|
|
11
6
|
export class Location {
|
|
12
7
|
readonly coordinates: Coordinates
|
|
13
|
-
private _marketPrices?: ItemPrice[]
|
|
14
8
|
private _gameSeed?: Checksum256
|
|
15
9
|
private _hasSystem?: boolean
|
|
16
|
-
private _locationRows?: ServerContract.Types.supply_row[]
|
|
17
10
|
private _epoch?: UInt64
|
|
18
11
|
|
|
19
12
|
constructor(coordinates: CoordinatesType) {
|
|
20
13
|
this.coordinates = Coordinates.from(coordinates)
|
|
21
14
|
}
|
|
22
15
|
|
|
23
|
-
/**
|
|
24
|
-
* Create a Location from coordinates
|
|
25
|
-
*/
|
|
26
16
|
static from(coordinates: CoordinatesType): Location {
|
|
27
17
|
return new Location(Coordinates.from(coordinates))
|
|
28
18
|
}
|
|
29
19
|
|
|
30
|
-
/**
|
|
31
|
-
* Check if this location has a system (planet, asteroid, or nebula)
|
|
32
|
-
*/
|
|
33
20
|
hasSystemAt(gameSeed: Checksum256Type): boolean {
|
|
34
21
|
const seed = Checksum256.from(gameSeed)
|
|
35
22
|
if (this._hasSystem === undefined || !this._gameSeed?.equals(seed)) {
|
|
@@ -39,214 +26,32 @@ export class Location {
|
|
|
39
26
|
return this._hasSystem
|
|
40
27
|
}
|
|
41
28
|
|
|
42
|
-
/**
|
|
43
|
-
* Get the location type (EMPTY, PLANET, ASTEROID, or NEBULA)
|
|
44
|
-
*/
|
|
45
29
|
getLocationTypeAt(gameSeed: Checksum256Type): LocationType {
|
|
46
30
|
return getLocationType(gameSeed, this.coordinates)
|
|
47
31
|
}
|
|
48
32
|
|
|
49
|
-
/**
|
|
50
|
-
* Check if this location is extractable (asteroid or nebula)
|
|
51
|
-
*/
|
|
52
33
|
isExtractableAt(gameSeed: Checksum256Type): boolean {
|
|
53
34
|
return isExtractableLocation(this.getLocationTypeAt(gameSeed))
|
|
54
35
|
}
|
|
55
36
|
|
|
56
|
-
/**
|
|
57
|
-
* Set cached market prices for this location
|
|
58
|
-
*/
|
|
59
|
-
setMarketPrices(prices: ItemPrice[]): void {
|
|
60
|
-
this._marketPrices = prices
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Get cached market prices (returns undefined if not cached)
|
|
65
|
-
*/
|
|
66
|
-
get marketPrices(): ItemPrice[] | undefined {
|
|
67
|
-
return this._marketPrices
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Get price for a specific good (from cache)
|
|
72
|
-
*/
|
|
73
|
-
getPrice(goodId: UInt16Type): ItemPrice | undefined {
|
|
74
|
-
if (!this._marketPrices) return undefined
|
|
75
|
-
return this._marketPrices.find((p) => p.id.equals(goodId))
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Find nearby planets from this location
|
|
80
|
-
*/
|
|
81
37
|
findNearby(gameSeed: Checksum256Type, maxDistance: UInt16Type = 20): Distance[] {
|
|
82
38
|
return findNearbyPlanets(Checksum256.from(gameSeed), this.coordinates, maxDistance)
|
|
83
39
|
}
|
|
84
40
|
|
|
85
|
-
/**
|
|
86
|
-
* Check if this location equals another location
|
|
87
|
-
*/
|
|
88
41
|
equals(other: CoordinatesType | Location): boolean {
|
|
89
42
|
const otherCoords = other instanceof Location ? other.coordinates : Coordinates.from(other)
|
|
90
43
|
return this.coordinates.equals(otherCoords)
|
|
91
44
|
}
|
|
92
45
|
|
|
93
|
-
/**
|
|
94
|
-
* Set location rows (supply data) for this location
|
|
95
|
-
*/
|
|
96
|
-
setLocationRows(rows: ServerContract.Types.supply_row[], epoch: UInt64): void {
|
|
97
|
-
this._locationRows = rows
|
|
98
|
-
this._epoch = epoch
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Get cached location rows (supply data)
|
|
103
|
-
*/
|
|
104
|
-
get locationRows(): ServerContract.Types.supply_row[] | undefined {
|
|
105
|
-
return this._locationRows
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Get supply for a specific good at this location
|
|
110
|
-
* Returns undefined if location rows not cached or good not found
|
|
111
|
-
*/
|
|
112
|
-
getSupply(goodId: UInt16Type): UInt16 | undefined {
|
|
113
|
-
if (!this._locationRows) return undefined
|
|
114
|
-
const row = this._locationRows.find(
|
|
115
|
-
(r) => r.item_id.equals(goodId) && this._epoch && r.epoch.equals(this._epoch)
|
|
116
|
-
)
|
|
117
|
-
return row ? row.supply : undefined
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* Get all available goods at this location (goods with supply > 0)
|
|
122
|
-
* Returns undefined if location rows not cached
|
|
123
|
-
*/
|
|
124
|
-
get availableGoods(): ServerContract.Types.supply_row[] | undefined {
|
|
125
|
-
if (!this._locationRows) return undefined
|
|
126
|
-
return this._locationRows.filter(
|
|
127
|
-
(r) => this._epoch && r.epoch.equals(this._epoch) && r.supply.gt(UInt16.from(0))
|
|
128
|
-
)
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* Check if a specific good is available (has supply)
|
|
133
|
-
* Returns false if location rows not cached
|
|
134
|
-
*/
|
|
135
|
-
hasGood(goodId: UInt16Type): boolean {
|
|
136
|
-
const supply = this.getSupply(goodId)
|
|
137
|
-
return supply !== undefined && supply.gt(UInt16.from(0))
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* Get the epoch for cached location data
|
|
142
|
-
*/
|
|
143
46
|
get epoch(): UInt64 | undefined {
|
|
144
47
|
return this._epoch
|
|
145
48
|
}
|
|
146
49
|
|
|
147
|
-
/**
|
|
148
|
-
* Check if cached data exists
|
|
149
|
-
*/
|
|
150
|
-
get hasCachedData(): boolean {
|
|
151
|
-
return this._marketPrices !== undefined || this._locationRows !== undefined
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
/**
|
|
155
|
-
* Check if supply data is cached
|
|
156
|
-
*/
|
|
157
|
-
get hasSupplyData(): boolean {
|
|
158
|
-
return this._locationRows !== undefined
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
/**
|
|
162
|
-
* Clear all cached data
|
|
163
|
-
*/
|
|
164
50
|
clearCache(): void {
|
|
165
|
-
this._marketPrices = undefined
|
|
166
|
-
this._locationRows = undefined
|
|
167
51
|
this._epoch = undefined
|
|
168
52
|
}
|
|
169
|
-
|
|
170
|
-
/**
|
|
171
|
-
* Create optimistic Location with updated supply after purchase/sale.
|
|
172
|
-
* Matches contract: update_location_supply (delta can be positive or negative)
|
|
173
|
-
* Contract reference: market.cpp:53, 123-151
|
|
174
|
-
*
|
|
175
|
-
* @param goodId - Good ID to update supply for
|
|
176
|
-
* @param quantityDelta - Change in supply (negative for purchase, positive for sale)
|
|
177
|
-
* @returns New Location with updated supply in cached data
|
|
178
|
-
*
|
|
179
|
-
* @example
|
|
180
|
-
* // After buying 10 units (supply decreases)
|
|
181
|
-
* const newLocation = location.withUpdatedSupply(1, -10)
|
|
182
|
-
*
|
|
183
|
-
* // After selling 5 units (supply increases)
|
|
184
|
-
* const newLocation = location.withUpdatedSupply(1, 5)
|
|
185
|
-
*/
|
|
186
|
-
withUpdatedSupply(goodId: UInt16Type, quantityDelta: number): Location {
|
|
187
|
-
const newLocation = Location.from(this.coordinates)
|
|
188
|
-
|
|
189
|
-
// Copy market prices if cached
|
|
190
|
-
if (this._marketPrices) {
|
|
191
|
-
newLocation._marketPrices = this._marketPrices.map((price) => {
|
|
192
|
-
if (price.id.equals(goodId)) {
|
|
193
|
-
const currentSupply = UInt16.from(price.supply)
|
|
194
|
-
const delta = UInt16.from(Math.abs(quantityDelta))
|
|
195
|
-
const newSupply =
|
|
196
|
-
quantityDelta < 0
|
|
197
|
-
? currentSupply.gte(delta)
|
|
198
|
-
? currentSupply.subtracting(delta)
|
|
199
|
-
: UInt16.from(0)
|
|
200
|
-
: currentSupply.adding(quantityDelta)
|
|
201
|
-
|
|
202
|
-
return ItemPrice.from({
|
|
203
|
-
id: price.id,
|
|
204
|
-
item: price.item,
|
|
205
|
-
price: price.price,
|
|
206
|
-
supply: newSupply,
|
|
207
|
-
})
|
|
208
|
-
}
|
|
209
|
-
return price
|
|
210
|
-
})
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
// Copy location rows if cached
|
|
214
|
-
if (this._locationRows && this._epoch) {
|
|
215
|
-
newLocation._locationRows = this._locationRows.map((row) => {
|
|
216
|
-
if (row.item_id.equals(goodId) && row.epoch.equals(this._epoch!)) {
|
|
217
|
-
const currentSupply = UInt16.from(row.supply)
|
|
218
|
-
const delta = UInt16.from(Math.abs(quantityDelta))
|
|
219
|
-
const newSupply =
|
|
220
|
-
quantityDelta < 0
|
|
221
|
-
? currentSupply.gte(delta)
|
|
222
|
-
? currentSupply.subtracting(delta)
|
|
223
|
-
: UInt16.from(0)
|
|
224
|
-
: currentSupply.adding(quantityDelta)
|
|
225
|
-
|
|
226
|
-
return ServerContract.Types.supply_row.from({
|
|
227
|
-
id: row.id,
|
|
228
|
-
coordinates: row.coordinates,
|
|
229
|
-
epoch: row.epoch,
|
|
230
|
-
item_id: row.item_id,
|
|
231
|
-
supply: newSupply,
|
|
232
|
-
})
|
|
233
|
-
}
|
|
234
|
-
return row
|
|
235
|
-
})
|
|
236
|
-
newLocation._epoch = this._epoch
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
// Copy other cached data
|
|
240
|
-
newLocation._gameSeed = this._gameSeed
|
|
241
|
-
newLocation._hasSystem = this._hasSystem
|
|
242
|
-
|
|
243
|
-
return newLocation
|
|
244
|
-
}
|
|
245
53
|
}
|
|
246
54
|
|
|
247
|
-
/**
|
|
248
|
-
* Helper function to convert various coordinate types to Location
|
|
249
|
-
*/
|
|
250
55
|
export function toLocation(coords: CoordinatesType | Location): Location {
|
|
251
56
|
if (coords instanceof Location) {
|
|
252
57
|
return coords
|
package/src/entities/player.ts
CHANGED
|
@@ -1,288 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Int64,
|
|
3
|
-
Int64Type,
|
|
4
|
-
Name,
|
|
5
|
-
NameType,
|
|
6
|
-
UInt32,
|
|
7
|
-
UInt32Type,
|
|
8
|
-
UInt64,
|
|
9
|
-
UInt64Type,
|
|
10
|
-
} from '@wharfkit/antelope'
|
|
1
|
+
import {Name, NameType} from '@wharfkit/antelope'
|
|
11
2
|
import {ServerContract} from '../contracts'
|
|
12
3
|
|
|
13
4
|
export interface PlayerStateInput {
|
|
14
5
|
owner: NameType
|
|
15
|
-
balance: UInt64Type
|
|
16
|
-
debt: UInt32Type
|
|
17
|
-
networth: Int64Type
|
|
18
6
|
}
|
|
19
7
|
|
|
20
|
-
/**
|
|
21
|
-
* Player helper class extending player_row with computed financial properties.
|
|
22
|
-
* Provides easy access to balance, debt, networth, and loan calculations.
|
|
23
|
-
*/
|
|
24
8
|
export class Player extends ServerContract.Types.player_row {
|
|
25
|
-
/**
|
|
26
|
-
* Construct a Player instance from individual state pieces.
|
|
27
|
-
* Used by UI's ReactivePlayer to reconstruct Player from reactive state.
|
|
28
|
-
*/
|
|
29
9
|
static fromState(state: PlayerStateInput): Player {
|
|
30
10
|
const playerRow = ServerContract.Types.player_row.from({
|
|
31
11
|
owner: Name.from(state.owner),
|
|
32
|
-
balance: UInt64.from(state.balance),
|
|
33
|
-
debt: UInt32.from(state.debt),
|
|
34
|
-
networth: Int64.from(state.networth),
|
|
35
12
|
})
|
|
36
13
|
return new Player(playerRow)
|
|
37
14
|
}
|
|
38
|
-
// Constants for game rules (match smart contract)
|
|
39
|
-
private static readonly MAX_LOAN = 1000000
|
|
40
|
-
// Contract formula: 2500 * pow(5, sequence - 1) = 500 * pow(5, sequence)
|
|
41
|
-
private static readonly BASE_SHIP_COST = 500
|
|
42
|
-
private static readonly SHIP_COST_MULTIPLIER = 5
|
|
43
|
-
|
|
44
|
-
// Optional ship count for nextShipCost calculation
|
|
45
|
-
private _shipCount?: number
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Set the current ship count (needed for nextShipCost calculation)
|
|
49
|
-
*/
|
|
50
|
-
setShipCount(count: number): void {
|
|
51
|
-
this._shipCount = count
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Get the current ship count (if set)
|
|
56
|
-
*/
|
|
57
|
-
get shipCount(): number | undefined {
|
|
58
|
-
return this._shipCount
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Calculate the cost of the next ship based on current ship count
|
|
63
|
-
* Matches contract: pow(5, sequence) * 100
|
|
64
|
-
* @param shipCount - Optional ship count (uses cached value if not provided)
|
|
65
|
-
*/
|
|
66
|
-
getNextShipCost(shipCount?: number): UInt64 {
|
|
67
|
-
const count = shipCount ?? this._shipCount ?? 0
|
|
68
|
-
const cost = Math.pow(Player.SHIP_COST_MULTIPLIER, count) * Player.BASE_SHIP_COST
|
|
69
|
-
return UInt64.from(Math.floor(cost))
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Get the cost of the next ship based on cached ship count
|
|
74
|
-
*/
|
|
75
|
-
get nextShipCost(): UInt64 {
|
|
76
|
-
return this.getNextShipCost()
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Check if player can afford to buy a ship
|
|
81
|
-
* @param shipCount - Optional ship count (uses cached value if not provided)
|
|
82
|
-
*/
|
|
83
|
-
canBuyShip(shipCount?: number): boolean {
|
|
84
|
-
return UInt64.from(this.balance).gte(this.getNextShipCost(shipCount))
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* Calculate available loan amount (max loan - current debt)
|
|
89
|
-
*/
|
|
90
|
-
get availableLoan(): UInt64 {
|
|
91
|
-
const maxLoan = UInt64.from(Player.MAX_LOAN)
|
|
92
|
-
if (UInt64.from(this.debt).gte(maxLoan)) {
|
|
93
|
-
return UInt64.from(0)
|
|
94
|
-
}
|
|
95
|
-
return maxLoan.subtracting(this.debt)
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* Check if player can take out a loan
|
|
100
|
-
*/
|
|
101
|
-
get canTakeLoan(): boolean {
|
|
102
|
-
return this.availableLoan.gt(UInt64.zero)
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Check if player can pay back loan
|
|
107
|
-
*/
|
|
108
|
-
get canPayLoan(): boolean {
|
|
109
|
-
return UInt64.from(this.debt).gt(UInt64.zero) && UInt64.from(this.balance).gt(UInt64.zero)
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* Calculate maximum payback amount (min of debt and balance)
|
|
114
|
-
*/
|
|
115
|
-
get maxPayback(): UInt64 {
|
|
116
|
-
return UInt64.from(this.debt).lt(this.balance) ? this.debt : this.balance
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* Get the maximum loan amount (constant)
|
|
121
|
-
*/
|
|
122
|
-
static get MAX_LOAN_LIMIT(): number {
|
|
123
|
-
return Player.MAX_LOAN
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* Check if player is in debt
|
|
128
|
-
*/
|
|
129
|
-
get hasDebt(): boolean {
|
|
130
|
-
return UInt64.from(this.debt).gt(UInt64.zero)
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* Check if player is solvent (positive networth)
|
|
135
|
-
*/
|
|
136
|
-
get isSolvent(): boolean {
|
|
137
|
-
return this.networth.gte(Int64.zero)
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* Create an optimistic update for balance changes
|
|
142
|
-
* Uses integer math to match contract
|
|
143
|
-
* @param delta - Amount to change (can be negative)
|
|
144
|
-
*/
|
|
145
|
-
withBalanceChange(delta: UInt64 | number): Player {
|
|
146
|
-
const newPlayer = Player.from(this)
|
|
147
|
-
const amount = typeof delta === 'number' ? UInt64.from(Math.abs(delta)) : delta
|
|
148
|
-
|
|
149
|
-
if (typeof delta === 'number' && delta < 0) {
|
|
150
|
-
// Subtract, ensuring we don't go below 0
|
|
151
|
-
newPlayer.balance = UInt64.from(this.balance).gte(amount)
|
|
152
|
-
? this.balance.subtracting(amount)
|
|
153
|
-
: UInt64.from(0)
|
|
154
|
-
} else {
|
|
155
|
-
// Add
|
|
156
|
-
newPlayer.balance = this.balance.adding(amount)
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
// Calculate networth as Int64 (can be negative)
|
|
160
|
-
const balanceInt = Int64.from(newPlayer.balance)
|
|
161
|
-
const debtInt = Int64.from(newPlayer.debt)
|
|
162
|
-
newPlayer.networth = balanceInt.subtracting(debtInt)
|
|
163
|
-
return newPlayer
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* Create an optimistic update for debt changes
|
|
168
|
-
* Uses integer math to match contract
|
|
169
|
-
* @param delta - Amount to change (can be negative)
|
|
170
|
-
*/
|
|
171
|
-
withDebtChange(delta: UInt64 | number): Player {
|
|
172
|
-
const newPlayer = Player.from(this)
|
|
173
|
-
const amount = typeof delta === 'number' ? UInt64.from(Math.abs(delta)) : delta
|
|
174
|
-
|
|
175
|
-
if (typeof delta === 'number' && delta < 0) {
|
|
176
|
-
// Subtract, ensuring we don't go below 0
|
|
177
|
-
newPlayer.debt = UInt64.from(this.debt).gte(amount)
|
|
178
|
-
? this.debt.subtracting(amount)
|
|
179
|
-
: UInt64.from(0)
|
|
180
|
-
} else {
|
|
181
|
-
// Add
|
|
182
|
-
newPlayer.debt = this.debt.adding(amount)
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
// Calculate networth as Int64 (can be negative)
|
|
186
|
-
const balanceInt = Int64.from(newPlayer.balance)
|
|
187
|
-
const debtInt = Int64.from(newPlayer.debt)
|
|
188
|
-
newPlayer.networth = balanceInt.subtracting(debtInt)
|
|
189
|
-
return newPlayer
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
/**
|
|
193
|
-
* Create an optimistic update for taking a loan
|
|
194
|
-
*/
|
|
195
|
-
withLoan(amount: UInt64): Player {
|
|
196
|
-
const newPlayer = Player.from(this)
|
|
197
|
-
newPlayer.balance = this.balance.adding(amount)
|
|
198
|
-
newPlayer.debt = this.debt.adding(amount)
|
|
199
|
-
// Calculate networth as Int64 (can be negative)
|
|
200
|
-
const balanceInt = Int64.from(newPlayer.balance)
|
|
201
|
-
const debtInt = Int64.from(newPlayer.debt)
|
|
202
|
-
newPlayer.networth = balanceInt.subtracting(debtInt)
|
|
203
|
-
return newPlayer
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
/**
|
|
207
|
-
* Create an optimistic update for paying back a loan
|
|
208
|
-
*/
|
|
209
|
-
withLoanPayment(amount: UInt64): Player {
|
|
210
|
-
const actualPayment = this.maxPayback.lt(amount) ? this.maxPayback : amount
|
|
211
|
-
const newPlayer = Player.from(this)
|
|
212
|
-
newPlayer.balance = this.balance.subtracting(actualPayment)
|
|
213
|
-
newPlayer.debt = this.debt.subtracting(actualPayment)
|
|
214
|
-
// Calculate networth as Int64 (can be negative)
|
|
215
|
-
const balanceInt = Int64.from(newPlayer.balance)
|
|
216
|
-
const debtInt = Int64.from(newPlayer.debt)
|
|
217
|
-
newPlayer.networth = balanceInt.subtracting(debtInt)
|
|
218
|
-
return newPlayer
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
/**
|
|
222
|
-
* Simulate networth update from selling goods.
|
|
223
|
-
* Matches contract: networth += (sellPrice - paid * quantity)
|
|
224
|
-
* Contract reference: market.cpp:75
|
|
225
|
-
*
|
|
226
|
-
* @param sellPrice - Total revenue from sale (price * quantity)
|
|
227
|
-
* @param paidPerUnit - Average cost per unit paid (from cargo.paid)
|
|
228
|
-
* @param quantity - Quantity being sold
|
|
229
|
-
* @returns New player with updated networth
|
|
230
|
-
*
|
|
231
|
-
* @example
|
|
232
|
-
* // Sold 10 units at 150 each (revenue=1500), paid 100 per unit
|
|
233
|
-
* const newPlayer = player.withSaleNetworth(
|
|
234
|
-
* UInt64.from(1500),
|
|
235
|
-
* UInt64.from(100),
|
|
236
|
-
* UInt32.from(10)
|
|
237
|
-
* )
|
|
238
|
-
* // Networth increases by: 1500 - (100*10) = 500
|
|
239
|
-
*/
|
|
240
|
-
withSaleNetworth(sellPrice: UInt64, paidPerUnit: UInt64, quantity: UInt64): Player {
|
|
241
|
-
// Match contract: price - paid * quantity
|
|
242
|
-
const cost = paidPerUnit.multiplying(quantity)
|
|
243
|
-
const profit = sellPrice.gte(cost) ? sellPrice.subtracting(cost) : Int64.from(0)
|
|
244
|
-
|
|
245
|
-
const newPlayer = Player.from(this)
|
|
246
|
-
newPlayer.networth = Int64.from(this.networth).adding(profit)
|
|
247
|
-
return newPlayer
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
/**
|
|
251
|
-
* Simulate complete sell goods transaction.
|
|
252
|
-
* Updates both balance (adds revenue) and networth (adds profit).
|
|
253
|
-
* Matches contract actions: update_balance + update_networth
|
|
254
|
-
*
|
|
255
|
-
* @param sellPrice - Total revenue from sale (price * quantity)
|
|
256
|
-
* @param paidPerUnit - Average cost per unit paid (from cargo.paid)
|
|
257
|
-
* @param quantity - Quantity being sold
|
|
258
|
-
* @returns New player with updated balance and networth
|
|
259
|
-
*/
|
|
260
|
-
withSellGoods(sellPrice: UInt64, paidPerUnit: UInt64, quantity: UInt64): Player {
|
|
261
|
-
const cost = paidPerUnit.multiplying(quantity)
|
|
262
|
-
const profit = sellPrice.gte(cost) ? sellPrice.subtracting(cost) : Int64.from(0)
|
|
263
|
-
|
|
264
|
-
const newPlayer = Player.from(this)
|
|
265
|
-
newPlayer.balance = this.balance.adding(sellPrice)
|
|
266
|
-
newPlayer.networth = Int64.from(this.networth).adding(profit)
|
|
267
|
-
return newPlayer
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
/**
|
|
271
|
-
* Simulate complete buy goods transaction.
|
|
272
|
-
* Updates balance (subtracts cost).
|
|
273
|
-
*
|
|
274
|
-
* @param purchaseCost - Total cost of purchase (price * quantity)
|
|
275
|
-
* @returns New player with updated balance
|
|
276
|
-
*/
|
|
277
|
-
withBuyGoods(purchaseCost: UInt64): Player {
|
|
278
|
-
const newPlayer = Player.from(this)
|
|
279
|
-
newPlayer.balance = UInt64.from(this.balance).gte(purchaseCost)
|
|
280
|
-
? this.balance.subtracting(purchaseCost)
|
|
281
|
-
: UInt64.from(0)
|
|
282
|
-
// Calculate networth as Int64 (can be negative)
|
|
283
|
-
const balanceInt = Int64.from(newPlayer.balance)
|
|
284
|
-
const debtInt = Int64.from(newPlayer.debt)
|
|
285
|
-
newPlayer.networth = balanceInt.subtracting(debtInt)
|
|
286
|
-
return newPlayer
|
|
287
|
-
}
|
|
288
15
|
}
|
package/src/entities/ship.ts
CHANGED
|
@@ -21,7 +21,6 @@ import {
|
|
|
21
21
|
hasEnergyForDistance,
|
|
22
22
|
maxTravelDistance,
|
|
23
23
|
} from '../capabilities/movement'
|
|
24
|
-
import * as cargoUtils from './cargo-utils'
|
|
25
24
|
import * as schedule from '../scheduling/schedule'
|
|
26
25
|
|
|
27
26
|
export interface ShipStateInput {
|
|
@@ -133,10 +132,6 @@ export class Ship extends ServerContract.Types.entity_info {
|
|
|
133
132
|
return this.inv.totalMass
|
|
134
133
|
}
|
|
135
134
|
|
|
136
|
-
get cargoValue(): UInt64 {
|
|
137
|
-
return this.inv.totalValue
|
|
138
|
-
}
|
|
139
|
-
|
|
140
135
|
get totalMass(): UInt64 {
|
|
141
136
|
let mass = UInt64.from(this.hullmass ?? 0).adding(this.totalCargoMass)
|
|
142
137
|
if (this.loaders) {
|
|
@@ -193,20 +188,4 @@ export class Ship extends ServerContract.Types.entity_info {
|
|
|
193
188
|
if (!this.engines || !this.generator || this.energy === undefined) return false
|
|
194
189
|
return hasEnergyForDistance(this as MovementEntity, distance)
|
|
195
190
|
}
|
|
196
|
-
|
|
197
|
-
calculateSaleValue(prices: Map<number, UInt64>): cargoUtils.SaleValue {
|
|
198
|
-
return cargoUtils.calculateSaleValue(this.cargo, prices)
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
calculateSaleValueFromArray(prices: UInt64[]): cargoUtils.SaleValue {
|
|
202
|
-
return cargoUtils.calculateSaleValueFromArray(this.cargo, prices)
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
afterSellItems(goodsToSell: Array<{goodId: number; quantity: number}>): EntityInventory[] {
|
|
206
|
-
return cargoUtils.afterSellItems(this.cargo, goodsToSell)
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
afterSellAllItems(): EntityInventory[] {
|
|
210
|
-
return cargoUtils.afterSellAllItems(this.cargo)
|
|
211
|
-
}
|
|
212
191
|
}
|
package/src/index-module.ts
CHANGED
|
@@ -37,7 +37,6 @@ export {
|
|
|
37
37
|
EntitiesManager,
|
|
38
38
|
PlayersManager,
|
|
39
39
|
LocationsManager,
|
|
40
|
-
TradesManager,
|
|
41
40
|
EpochsManager,
|
|
42
41
|
ActionsManager,
|
|
43
42
|
} from './managers'
|
|
@@ -47,8 +46,6 @@ export type {EntityRefInput} from './managers/actions'
|
|
|
47
46
|
export {getItem, getItems, itemIds} from './market/items'
|
|
48
47
|
export {getCurrentEpoch, getEpochInfo} from './scheduling/epoch'
|
|
49
48
|
export type {EpochInfo} from './scheduling/epoch'
|
|
50
|
-
export {marketPrice, marketPrices, getRarity, getRarityMultiplier, Rarities} from './market/market'
|
|
51
|
-
export type {Rarity} from './market/market'
|
|
52
49
|
export {
|
|
53
50
|
getSystemName,
|
|
54
51
|
hasSystem,
|
|
@@ -91,31 +88,6 @@ export type {StatDefinition, NamedStats} from './derivation'
|
|
|
91
88
|
|
|
92
89
|
export {hash, hash512} from './utils/hash'
|
|
93
90
|
|
|
94
|
-
export type {Deal, FindDealsOptions} from './trading/deal'
|
|
95
|
-
export {findDealsForShip, findBestDeal} from './trading/deal'
|
|
96
|
-
|
|
97
|
-
export type {
|
|
98
|
-
CollectActionType,
|
|
99
|
-
CollectOption,
|
|
100
|
-
CollectAnalysis,
|
|
101
|
-
CollectAnalysisOptions,
|
|
102
|
-
CollectAnalysisCallbacks,
|
|
103
|
-
BetterSaleLocation,
|
|
104
|
-
RepositionLocation,
|
|
105
|
-
DiscountedItemInfo,
|
|
106
|
-
PotentialDeal,
|
|
107
|
-
CargoSaleItem,
|
|
108
|
-
} from './trading/collect'
|
|
109
|
-
export {
|
|
110
|
-
analyzeCollectOptions,
|
|
111
|
-
analyzeCargoSale,
|
|
112
|
-
createSellAndTradeOption,
|
|
113
|
-
createTravelToSellOption,
|
|
114
|
-
createSellAndRepositionOption,
|
|
115
|
-
createSellAndStayOption,
|
|
116
|
-
createExploreOption,
|
|
117
|
-
} from './trading/collect'
|
|
118
|
-
|
|
119
91
|
export {
|
|
120
92
|
distanceBetweenCoordinates,
|
|
121
93
|
distanceBetweenPoints,
|
|
@@ -153,19 +125,6 @@ export type {
|
|
|
153
125
|
HasScheduleAndLocation,
|
|
154
126
|
} from './travel/travel'
|
|
155
127
|
|
|
156
|
-
export {
|
|
157
|
-
calculateUpdatedCargoCost,
|
|
158
|
-
calculateMaxTradeQuantity,
|
|
159
|
-
calculateTradeProfit,
|
|
160
|
-
calculateProfitPerMass,
|
|
161
|
-
calculateProfitPerSecond,
|
|
162
|
-
findBestItemToTrade,
|
|
163
|
-
calculateBreakEvenPrice,
|
|
164
|
-
isProfitable,
|
|
165
|
-
calculateROI,
|
|
166
|
-
} from './trading/trade'
|
|
167
|
-
export type {TradeCalculation, TradeProfitResult} from './trading/trade'
|
|
168
|
-
|
|
169
128
|
export * as schedule from './scheduling/schedule'
|
|
170
129
|
export type {Scheduleable, ScheduleData} from './scheduling/schedule'
|
|
171
130
|
export {ScheduleAccessor, createScheduleAccessor} from './scheduling/accessor'
|
|
@@ -181,3 +140,37 @@ export type {Projectable, ProjectedEntity} from './scheduling/projection'
|
|
|
181
140
|
export * from './types/capabilities'
|
|
182
141
|
export * from './types/entity'
|
|
183
142
|
export * from './capabilities'
|
|
143
|
+
|
|
144
|
+
export {
|
|
145
|
+
components,
|
|
146
|
+
entityRecipes,
|
|
147
|
+
getComponentById,
|
|
148
|
+
getEntityRecipe,
|
|
149
|
+
getEntityRecipeByItemId,
|
|
150
|
+
getAllCraftableItems,
|
|
151
|
+
getComponentsForCategory,
|
|
152
|
+
getComponentsForStat,
|
|
153
|
+
ITEM_HULL_PLATES,
|
|
154
|
+
ITEM_CARGO_LINING,
|
|
155
|
+
ITEM_CONTAINER_PACKED,
|
|
156
|
+
} from './data/recipes'
|
|
157
|
+
export type {
|
|
158
|
+
ComponentDefinition,
|
|
159
|
+
ComponentStat,
|
|
160
|
+
RecipeInput,
|
|
161
|
+
EntityRecipe,
|
|
162
|
+
CraftableItem,
|
|
163
|
+
} from './data/recipes'
|
|
164
|
+
|
|
165
|
+
export {
|
|
166
|
+
encodeStats,
|
|
167
|
+
decodeStats,
|
|
168
|
+
decodeCraftedItemStats,
|
|
169
|
+
blendStacks,
|
|
170
|
+
computeComponentStats,
|
|
171
|
+
blendComponentStacks,
|
|
172
|
+
computeEntityStats,
|
|
173
|
+
} from './derivation/crafting'
|
|
174
|
+
export type {StackInput, CategoryStacks} from './derivation/crafting'
|
|
175
|
+
|
|
176
|
+
export {computeContainerCapabilities} from './entities/container'
|