1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
|
import { Contract } from '../model/contract.ts';
import { Ship } from '../model/ship.ts';
import * as mining from './mining.js';
import * as selling from './selling.js';
import * as dbContracts from '../database/contracts.ts';
import * as dbShips from '../database/ships.ts';
import * as api from '../lib/api.ts';
import * as contracts from '../lib/contracts.ts';
import * as libShips from '../lib/ships.ts';
import * as libSystems from '../lib/systems.ts';
import * as systems from '../lib/systems.ts';
import * as utils from '../lib/utils.ts';
export async function init(): Promise<void> {
const ship = dbShips.getShips()[0]; // This should always be the command ship
while(true) { // we use the fact that there can only be at most one active contract at a time
const contracts = dbContracts.getContracts().filter(c => !c.fulfilled);
let contract: Contract;
if (contracts.length === 0) {
contract = await libShips.negotiate(ship);
} else {
contract = contracts[0];
}
await run(contract, ship);
await libShips.negotiate(ship);
}
}
async function run(contract: Contract, ship: Ship): Promise<void> {
await contracts.accept(contract);
switch(contract.type) {
case 'PROCUREMENT':
if (contract.terms.deliver[0].tradeSymbol.match(/_ORE$/)) {
await runOreProcurement(contract, ship);
} else {
await runTradeProcurement(contract, ship);
}
break;
default:
throw `Handling of contract type ${contract.type} is not implemented yet`;
}
}
async function runOreProcurement(contract: Contract, ship: Ship): Promise<void> {
const wantedCargo = contract.terms.deliver[0].tradeSymbol;
const deliveryPoint = contract.terms.deliver[0].destinationSymbol;
const asteroids = await systems.type(ship.nav.systemSymbol, 'ENGINEERED_ASTEROID');
const asteroidSymbol = asteroids[0].symbol;
while (!contract.fulfilled) {
ship = dbShips.getShip(ship.symbol);
const goodCargo = ship.cargo.inventory.filter(i => i.symbol === wantedCargo)[0]
// what we do depends on where we are
switch (ship.nav.waypointSymbol) {
case asteroidSymbol:
await mining.mineUntilFullFor(contract, ship, asteroidSymbol);
await libShips.navigate(ship, deliveryPoint);
break;
case deliveryPoint:
if (goodCargo !== undefined) { // we could be here if a client restart happens right after selling before we navigate away
contract = await contracts.deliver(contract, ship);
if (contract.fulfilled) return;
}
await libShips.navigate(ship, asteroidSymbol);
break;
default:
await selling.sell(ship, wantedCargo);
await libShips.navigate(ship, asteroidSymbol);
}
}
}
async function runTradeProcurement(contract: Contract, ship: Ship): Promise<void> {
const deliver = contract.terms.deliver[0];
const deliveryPoint = deliver.destinationSymbol;
const wantedCargo = deliver.tradeSymbol;
while (!contract.fulfilled) {
ship = dbShips.getShip(ship.symbol);
const goodCargo = ship.cargo.inventory.filter(i => i.symbol === wantedCargo)[0]
// make sure we are not carrying useless stuff
await selling.sell(ship, wantedCargo);
// go buy what we need
const rawMarkets = await libSystems.trait(ship.nav.systemSymbol, 'MARKETPLACE');
// sorted by distance from where we are
const markets = rawMarkets.map(function (m) { return {
data: m,
distance: (m.x - ship.nav.route.destination.x) ** 2 + (m.y - ship.nav.route.destination.y) ** 2,
}});
markets.sort(function(a, b) {
if (a.distance < b.distance) {
return -1;
} else if (a.distance > b.distance) {
return 1;
}
return 0;
});
// check from the closest one that exports what we need
let buyingPoint: string = "";
outer: for (let i = 0; i < markets.length; i++) {
const waypointSymbol = markets[i].data.symbol;
const market = await libSystems.market(waypointSymbol);
for (let j = 0; j < market.exports.length; j++) {
if (market.exports[j].symbol === wantedCargo) {
buyingPoint = market.symbol;
break outer;
}
}
}
// if we did not find an exporting market we look for an exchange
if (buyingPoint === "") {
outer: for (let i = 0; i < markets.length; i++) {
const waypointSymbol = markets[i].data.symbol;
const market = await libSystems.market(waypointSymbol);
for (let j = 0; j < market.exchange.length; j++) {
if (market.exports[j].symbol === wantedCargo) {
buyingPoint = market.symbol;
break outer;
}
}
}
}
if (buyingPoint === "") {
throw `runTradeProcurement failed, no market exports or exchanges ${wantedCargo}`;
}
// go buy what we need
await libShips.navigate(ship, buyingPoint);
const units = Math.min(
deliver.unitsRequired - deliver.unitsFulfilled,
ship.cargo.capacity - ship.cargo.units,
);
await libShips.buy(ship, wantedCargo, units);
// then make a delivery
await libShips.navigate(ship, deliveryPoint);
contract = await contracts.deliver(contract, ship);
if (contract.fulfilled) return;
}
console.log("runTradeProcurement not implemented");
throw "not implemented";
}
|