summaryrefslogtreecommitdiff
path: root/nodejs/automation/contracting.ts
blob: 93c2f8eb8fbe8b6203b84e18acef865ae7e5b5d7 (plain)
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
import { debugLog } from '../lib/api.ts';
import { Ship } from '../lib/ships.ts';
import { Contract } from '../lib/types.ts';
import * as mining from './mining.js';
import * as selling from './selling.js';
import * as dbContracts from '../database/contracts.ts';
import * as libContracts from '../lib/contracts.ts';
import * as libSystems from '../lib/systems.ts';
import * as systems from '../lib/systems.ts';
import {
	sortByDistanceFrom,
} from '../lib/utils.ts';

export async function run(ship: Ship): Promise<void> {
	const contracts = await libContracts.getContracts();
	const active = contracts.filter(function(c) {
		if (c.fulfilled) return false;
		const deadline = new Date(c.terms.deadline).getTime();
		const now = new Date().getTime();
		return deadline > now;
	});
	for (const contract of active) {
		await runOne(contract, ship);
	}
	while(true) {
		await runOne(await ship.negotiate(), ship);
	}
}

async function runOne(contract: Contract, ship: Ship): Promise<void> {
	debugLog(contract);
	await libContracts.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 = await libSystems.waypoint(contract.terms.deliver[0].destinationSymbol);
	const asteroids = await systems.type(ship.nav.systemSymbol, 'ENGINEERED_ASTEROID');
	const asteroid = await systems.waypoint(asteroids[0].symbol);
	while (!contract.fulfilled) {
		const goodCargo = ship.cargo.inventory.filter(i => i.symbol === wantedCargo)[0]
		// what we do depends on where we are
		switch (ship.nav.waypointSymbol) {
			case asteroid.symbol:
				await mining.mineUntilFullFor(contract, ship, asteroid);
				await ship.navigate(deliveryPoint);
				break;
			case deliveryPoint.symbol:
				if (goodCargo !== undefined) { // we could be here if a client restart happens right after selling before we navigate away
					contract = await libContracts.deliver(contract, ship);
					if (contract.fulfilled) return;
				}
				await ship.navigate(asteroid);
				break;
			default:
				await selling.sell(ship, wantedCargo);
				await ship.navigate(asteroid);
		}
	}
}

async function runTradeProcurement(contract: Contract, ship: Ship): Promise<void> {
	const deliver = contract.terms.deliver[0];
	const deliveryPoint = await libSystems.waypoint(deliver.destinationSymbol);
	const wantedCargo = deliver.tradeSymbol;
	while (!contract.fulfilled) {
		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 markets = sortByDistanceFrom(ship.nav.route.destination, await libSystems.trait(ship.nav.systemSymbol, 'MARKETPLACE'));
		// check from the closest one that exports what we need
		let buyingPoint: string = "";
		outer: for (let i = 0; i < markets.length; i++) {
			const waypoint = await libSystems.waypoint(markets[i].data.symbol);
			const market = await libSystems.market(waypoint);
			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 waypoint = await libSystems.waypoint(markets[i].data.symbol);
				const market = await libSystems.market(waypoint);
				for (let j = 0; j < market.exchange.length; j++) {
					if (market.exchange[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 ship.navigate(await libSystems.waypoint(buyingPoint));
		const units = Math.min(
			deliver.unitsRequired - deliver.unitsFulfilled,
			ship.cargo.capacity - ship.cargo.units,
		);
		await ship.purchase(wantedCargo, units);
		// then make a delivery
		await ship.navigate(deliveryPoint);
		contract = await libContracts.deliver(contract, ship);
		if (contract.fulfilled) return;
	}
	console.log("runTradeProcurement not implemented");
	throw "not implemented";
}