summaryrefslogtreecommitdiff
path: root/lib/agent.js
blob: 18dbac34811c9c02edbf8145562ef6ddd6368efc (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
import { registerAgent } from '../database/config.js';
import * as api from './api.js';
import * as contracts from './contracts.js';
import * as ships from './ships.js';
import * as systems from './systems.js';

export async function auto(ctx) {
	let ship = await ships.ship({ship: ctx.ship});
	// Fetch our contracts in the system the ship currently is in
	let cs = await contracts.contracts();
	cs = cs.data.filter(c => c.terms.deliver[0].destinationSymbol.startsWith(ship.data.nav.systemSymbol));
	if (cs === []) throw `No contract at ${ctx.ship}'s location`;
	let contract = cs[0];
	if (!contract.accepted) {
		console.log(new Date(), `accepting contract ${contract.id}`);
		await contracts.accept({id: contract.id});
	}
	const good = contract.terms.deliver[0].tradeSymbol;
	const deliveryPoint = contract.terms.deliver[0].destinationSymbol;
	const asteroidFields = await systems.type({symbol: ship.data.nav.systemSymbol, type: 'ASTEROID_FIELD'});
	const asteroidField = asteroidFields[0].symbol;
	while (true) {
		ship = await ships.ship({ship: ctx.ship}); // TODO we should not need to fetch this
		// If we are in transit, we wait until we arrive
		const delay = new Date(ship.data.nav.route.arrival) - new Date();
		if (delay > 0) await api.sleep(delay);
		// Then it depends on where we are
		let goodCargo = ship.data.cargo.inventory.filter(i => i.symbol === good)[0];
		// the switch makes this 'resumable'
		switch (ship.data.nav.waypointSymbol) {
		case asteroidField:
			let response = await mineUntilFullOf({good: good, ship: ctx.ship});
			//console.log(`${ctx.ship}'s cargo is full with ${response.units} of ${good}!`);
			await ships.navigate({ship: ctx.ship, waypoint: deliveryPoint});
			break;
		case deliveryPoint:
			await ships.dock({ship: ctx.ship});
			await ships.refuel({ship: ctx.ship});
			console.log(`delivering ${goodCargo.units} of ${good}`);
			await contracts.deliver({contract: contract.id, ship: ctx.ship, good: good, units: goodCargo.units });
			await ships.navigate({ship: ctx.ship, waypoint: asteroidField});
			await ships.dock({ship: ctx.ship});
			await ships.refuel({ship: ctx.ship});
			await ships.orbit({ship: ctx.ship});
			break;
		default:
			throw `where is the ship?`;
		}
	}
}

// example ctx { good: 'SILVER_ORE', ship: 'ADYXAX-2' }
// returns the number of units of the good the ship extracted
async function mineUntilFullOf(ctx) {
	while(true) {
		let response = await mineUntilFull({ship: ctx.ship});
		if (response === null) response = await ships.ship({ship: ctx.ship}); // TODO we should not need to fetch this
		let good = response.data.cargo.inventory.filter(i => i.symbol === ctx.good)[0];
		const inventory = response.data.cargo.inventory.filter(i => i.symbol !== ctx.good);
		const antimatter = response.data.cargo.inventory.filter(i => i.symbol === 'ANTIMATTER')[0];
		if (good?.units + antimatter?.units >= response.data.cargo.capacity * 0.9) { // > 90% full of the valuable goods
			return good.units;
		} else { // we are full but need to sell junk
			await ships.dock({ship: ctx.ship});
			for (let i=0; i<inventory.length; ++i) {
				if (inventory[i].symbol === 'ANTIMATTER') continue;
				//console.log(`selling ${inventory[i].units} of ${inventory[i].symbol}`);
				await ships.sell({ship: ctx.ship, good: inventory[i].symbol, units: inventory[i].units});
			}
			await ships.orbit({ship: ctx.ship});
		}
	}
}

// example ctx { ship: 'ADYXAX-2' }
// returns the last ship's extract api response
async function mineUntilFull(ctx) {
	while(true) {
		const response = await ships.extract(ctx);
		if (response === null) return null;
		//console.log(`${ctx.ship}: extracted ${response.data.extraction.yield.units} of ${response.data.extraction.yield.symbol}`);
		await api.sleep(response.data.cooldown.remainingSeconds*1000);
		if (response.data.cargo.units >= response.data.cargo.capacity * 0.9) return response;
	}
}

// This function inits the database in case we have an already registered game
export function init(symbol, faction, token) {
	registerAgent(symbol, faction, token);
	// TODO ships
	// TODO contract
	// TODO agent
}

// This function registers then inits the database
export function register(symbol, faction) {
	fetch(
		'https://api.spacetraders.io/v2/register',
		{
			method: 'POST',
			headers: {
				'Content-Type': 'application/json',
			},
			body: JSON.stringify({
				symbol: symbol,
				faction: faction,
			}),
		})
		.then(response => response.json())
		.then(response => {
			console.log(JSON.stringify(response, null, 2));
			init(symbol, faction, response.data.token);
			// TODO ship
			// TODO contract
			// TODO agent
		})
		.catch(err => console.error(err));
}