import _ from 'lodash' import lacuna from './client' import call from './call' import log from './log' import util from './util' import { bodyBuildings } from './buildings' /** * `[{ id, name }]` for a body category (`colonies` / `planets` / `stations`), * sorted by name. Replaces `lacuna.empire.findBodiesType`. * * @param {string} type - key on `status.empire` * @return {Promise} */ export function findBodiesType(type) { return call(() => lacuna.empire.getStatus()).then((status) => { const arr = [] _.each(status.empire[type], (value, key) => { arr.push({ id: key, name: value }) }) return _.sortBy(arr, 'name') }) } export const colonies = () => findBodiesType('colonies') export const planets = () => findBodiesType('planets') export const stations = () => findBodiesType('stations') /** * `{ id, name }` for the empire's home planet. * * @return {Promise} */ export function homePlanet() { return call(() => lacuna.empire.getStatus()).then((status) => ({ id: status.empire.home_planet_id, name: status.empire.planets[status.empire.home_planet_id], })) } /** * Resolve the `--planet` argument - the string `'all'`, a planet name, or an * array of names - into `[{ id, name }]`, minus anything named in `skip`. * Replaces `lacuna.empire.findPlanets`. * * @param {string|array} planet - the planet name(s), or `'all'` * @param {string|array} [skip] - planet name(s) to leave out * @return {Promise} */ export function findPlanets(planet, skip) { const arr = util.array(planet) const toSkip = util.array(skip) log.debug('Handling --planet', planet) log.debug('Handling --skip', skip) if (arr.length === 0) { return Promise.reject('please specify a planet') } let bodies if (_.includes(arr, 'all')) { bodies = colonies() } else { bodies = call(() => lacuna.empire.getStatus()).then((status) => { // Invert so we can key by name instead of id. const byName = _.invert(status.empire.planets) return Promise.all( arr.map((planetName) => { const planetId = byName[planetName] if (planetId) { return { id: planetId, name: planetName } } return Promise.reject(`Planet ${planetName} not found`) }) ) }) } return bodies.then((found) => _.filter(found, (body) => !_.includes(toSkip, body.name))) } /** * The first match from `findPlanets`. Replaces `lacuna.empire.findPlanet`. * * @param {string|array} name * @return {Promise} */ export function findPlanet(name) { return findPlanets(util.array(name)).then(_.first) } /** * Loop through each given planet, fetching its buildings, skipping unhappy * planets (unless `force`) and isolating per-planet errors so one failure * doesn't kill the task. Replaces `lacuna.empire.eachPlanet`. * * @param {array} planetList - `[{ id, name }]` * @param {function} callback - `(planet, buildings) => thenable` * @param {?Object} opts * @param {?boolean} opts.force - ignore the happiness check */ export async function eachPlanet(planetList, callback, opts) { opts = _.defaults(opts || {}, { force: false }) for (const planet of planetList) { log.newline() log.info(`Looking at ${planet.name}`) const result = await call(() => lacuna.body.getBuildings({ body_id: planet.id })) const buildings = util.objectToArray(result.buildings, 'id') // Some responses carry a status block, some don't - fall back to a // dedicated status call for the happiness check. let happiness if (result.status && result.status.body) { happiness = result.status.body.happiness } else { const status = await call(() => lacuna.body.getStatus({ body_id: planet.id })) happiness = status.body.happiness } // Don't do anything on unhappy planets - making anything (ships, spies, // buildings, SS plans) is heavily slowed down when happiness is negative. if (util.int(happiness) < 0 && !opts.force) { log.error(`${planet.name} is unhappy`) continue } await Promise.resolve(callback(planet, buildings)) .catch((err) => util.handlePromiseError(err)) .finally(() => log.info('Moving on')) } } /** * Every building across all colonies, as a flat array. Replaces * `lacuna.empire.getAllBuildings`. * * @return {Promise} */ export async function getAllBuildings() { const cols = await colonies() let all = [] for (const colony of cols) { log.info(`Looking at ${colony.name}`) const buildings = await bodyBuildings(colony.id) all = all.concat(buildings) } return all }