warframe-worldstate-parser
Version:
An Open parser for Warframe's Worldstate in Javascript
125 lines (105 loc) • 3.75 kB
JavaScript
import { fromNow, timeDeltaToString } from 'warframe-worldstate-data/utilities';
import mdConfig from '../supporting/MarkdownSettings.js';
import WorldstateObject from './WorldstateObject.js';
// This is a confirmed starting time for Corpus (in millis)
// All faction operation should use this as a calculation point
// Unless there's a better logic
const corpusTimeMillis = 1655182800000;
const fullCycle = 18000000;
const stateMaximum = 9000000;
/**
* Represents the current Zariman Corpus/Grineer Cycle
* @augments {WorldstateObject}
*/
export default class ZarimanCycle extends WorldstateObject {
/**
* The current zariman cycle, for calculating the other fields
* @type {object}
* @private
*/
#ec;
/**
* The end of the Zariman bounties timer, the faction changes exactly half way through
* @type {Date}
* @private
*/
#bountiesEndDate;
/**
* @param {Date} bountiesEndDate The current Zariman cycle expiry
*/
constructor(bountiesEndDate) {
super({ _id: { $oid: 'zarimanCycle0' } });
this.#bountiesEndDate = bountiesEndDate;
this.#ec = this.getCurrentZarimanCycle();
/**
* The date and time at which the event ends
* @type {Date}
*/
this.expiry = this.#ec.expiry;
/**
* The date and time at which the event started
* @type {Date}
*/
this.activation = new Date(this.#ec.start);
/**
* Whether or not this it's corpus or grineer
* @type {boolean}
*/
this.isCorpus = this.#ec.isCorpus;
/**
* Current cycle state. One of `corpus`, `grineer`
* @type {string}
*/
this.state = this.#ec.state;
/**
* Time remaining string
* @type {string}
*/
this.timeLeft = this.#ec.timeLeft;
this.id = `zarimanCycle${this.expiry.getTime()}`;
this.shortString = `${this.timeLeft.replace(/\s\d*s/gi, '')} to ${this.isCorpus ? 'grineer' : 'corpus'}`;
}
/**
* Get whether the event has expired
* @returns {boolean} whether this is expired
*/
getExpired() {
return this.expiry ? fromNow(this.expiry) < 0 : /* istanbul ignore next */ true;
}
getCurrentZarimanCycle() {
const now = Date.now();
// determine if it is corpus cycle or grineer cycle based on bounty end time
// we subtract 5000 millis (5 seconds) to ensure the corpus/grineer calculation is correct
const bountiesClone = this.#bountiesEndDate.getTime() - 5000;
const millisLeft = fromNow(new Date(bountiesClone));
// the following line is a modulus operation
// this ensures that our calculation is correct if bountiesClone is before corpusTimeMillis
// if you really care, read https://torstencurdt.com/tech/posts/modulo-of-negative-numbers/
const cycleTimeElapsed = (((bountiesClone - corpusTimeMillis) % fullCycle) + fullCycle) % fullCycle;
const cycleTimeLeft = fullCycle - cycleTimeElapsed;
// if timeInCycle is more than 2.5 hours, it is corpus, otherwise it is grineer
const isCorpus = cycleTimeLeft > stateMaximum;
const minutesCoef = 1000 * 60;
const expiry = new Date(Math.round((now + millisLeft) / minutesCoef) * minutesCoef);
const state = isCorpus ? 'corpus' : 'grineer';
return {
isCorpus,
timeLeft: timeDeltaToString(millisLeft),
expiry,
expiresIn: millisLeft,
state,
start: expiry.getTime() - stateMaximum,
};
}
/**
* The event's string representation
* @returns {string} string representation
*/
toString() {
const lines = [
`Operator, Zariman Ten Zero is currently occupied by ${this.state}`,
`Time remaining until ${this.isCorpus ? 'grineer' : 'corpus'} takeover: ${this.timeLeft}`,
];
return lines.join(mdConfig.lineEnd);
}
}