import { parseDate, timeDeltaToString, toNow, node, languageString, faction } from 'warframe-worldstate-data/utilities'; import mdConfig from '../supporting/MarkdownSettings.js'; import Reward from './Reward.js'; import WorldstateObject from './WorldstateObject.js'; /** * An invasion participant * @typedef {object} InvasionParticipant * @property {string} reward Reward for supporting this participant in the invasion * @property {string} faction Faction of this participant (localized) * @property {string} factionKey Faction of this participant (always English) */ /** * Represents an invasion */ export default class Invasion extends WorldstateObject { /** * @param {object} data The invasion data * @param {Dependency} deps The dependencies object * @param {string} deps.locale Locale to use for translations */ constructor(data, { locale = 'en' } = { locale: 'en' }) { super(data); const opts = { locale, }; /** * The node where the invasion is taking place * @type {string} */ this.node = node(data.Node, locale); /** * The node key where the invasion is taking place * @type {string} */ this.nodeKey = node(data.Node); /** * The invasion's description * @type {string} */ this.desc = languageString(data.LocTag, locale); /** * The attacking faction * @type {string} */ this.attackingFaction = faction(data.DefenderMissionInfo.faction, locale); /** * Invasion attacker * @type {InvasionParticipant} */ this.attacker = { reward: Object.keys(data?.AttackerReward || {})?.length ? new Reward(data.AttackerReward, opts) : undefined, faction: faction(data.DefenderMissionInfo.faction, locale), factionKey: faction(data.DefenderMissionInfo.faction, 'en'), }; /** * Invasion defender * @type {InvasionParticipant} */ this.defender = { reward: Object.keys(data?.DefenderReward || {})?.length ? new Reward(data.DefenderReward, opts) : undefined, faction: faction(data.AttackerMissionInfo.faction, locale), factionKey: faction(data.AttackerMissionInfo.faction, 'en'), }; /** * Whether this invasion is against the infestation * @type {boolean} */ this.vsInfestation = /infest/i.test(data.DefenderMissionInfo.faction); /** * The time at which the invasion starts * @type {Date} */ this.activation = parseDate(data.Activation); /** * The signed count of completed runs. Supporting the attackers makes the count go up, * supporting the defenders makes it go down * @type {number} */ this.count = data.Count; /** * The number of runs that one side needs to win * @type {number} */ this.requiredRuns = data.Goal; /** * The invasion's completion percentage. Defenders win if it gets to 0 * Grineer vs. Corpus invasions start at 50, Infested invasions start at 100 * @type {number} */ this.completion = (1 + data.Count / data.Goal) * (this.vsInfestation ? 100 : 50); /** * Whether the invasion has finished * @type {boolean} */ this.completed = data.Completed; /** * ETA string (at time of object creation) * @type {string} */ this.eta = this.getETAString(); /** * An array containing the types of all of the invasions's rewards * @type {Array.<string>} */ this.rewardTypes = this.getRewardTypes(); } /** * Whether or not the attackers are winning. * This is always false when the infestation is attacking * @returns {boolean} whether the attacker is winning */ isAttackerWinning() { return this.count > 0; } /** * Get an estimation of how much time is left before the invasion ends in milliseconds * @returns {number} remaining time in ms */ getRemainingTime() { const completedRuns = Math.abs(this.count); const elapsedMillis = toNow(this.activation); const remainingRuns = this.requiredRuns - completedRuns; return remainingRuns * (elapsedMillis / completedRuns); } /** * Get a string estimating how much time is left before the invasion ends * @returns {string} time delta string from now to the end */ getETAString() { return timeDeltaToString(this.getRemainingTime()); } /** * Get the types of the items being rewarded in the invasion * @returns {Array<string>} types of items being rewarded */ getRewardTypes() { return [...(this.attacker.reward?.getTypes() ?? []), ...(this.defender.reward?.getTypes() ?? [])]; } /** * The invasion's string representation * @returns {string} string representation of the invasion */ toString() { let lines = []; if (this.vsInfestation) { lines = [ this.defender.reward?.toString(), `${this.desc} on ${this.node}`, `${Math.round(this.completion * 100) / 100}% - ETA: ${this.getETAString()}`, ].filter(Boolean); } else { lines = [ `${this.attackingFaction} (${this.attacker.reward}) vs. ${this.defender.faction} (${this.defender.reward})`, `${this.node} - ${this.desc}`, `${Math.round(this.completion * 100) / 100}% - ETA: ${this.getETAString()}`, ]; } return `${mdConfig.codeBlock}${lines.join(mdConfig.lineEnd)}${mdConfig.blockEnd}`; } }