warframe-worldstate-parser
Version:
An Open parser for Warframe's Worldstate in Javascript
205 lines (204 loc) • 7.14 kB
JavaScript
import { n as __decorateMetadata, t as __decorate } from "../../decorate-BCC26nnB.mjs";
import { WorldStateObject } from "./WorldStateObject.mjs";
import { fetchProxy } from "../supporting/FetchProxy.mjs";
import "../supporting/index.mjs";
import { IsArray, IsInt, IsOptional, IsString, Min } from "class-validator";
import { languageString } from "warframe-worldstate-data/utilities";
//#region lib/models/SyndicateJob.ts
const apiBase = process.env.API_BASE_URL || "https://api.warframestat.us";
const bountyRewardRegex = /(?:Tier([ABCDE])|Narmer)Table([ABC])Rewards/i;
const ghoulRewardRegex = /GhoulBountyTable([AB])Rewards/i;
/**
* Determine the level string for the bounty
*/
const getLevelString = (job) => `${job.minEnemyLevel} - ${job.maxEnemyLevel}`;
const determineLocation = (i18n, raw, isVault) => {
const last = String(i18n).split("/").slice(-1)[0];
const bountyMatches = last.match(bountyRewardRegex);
const ghoulMatches = last.match(ghoulRewardRegex);
const isBounty = bountyMatches?.length;
const isGhoul = ghoulMatches?.length;
const isCetus = /eidolonjob/i.test(i18n);
const isVallis = /venusjob/i.test(i18n);
const isDeimos = /deimosmissionrewards/i.test(i18n);
const rotation = isBounty ? bountyMatches[2] : "";
const levelString = getLevelString(raw);
let location;
let levelClause;
if (isCetus) {
location = "Earth/Cetus ";
if (isGhoul) levelClause = `(Level ${levelString} Ghoul Bounty)`;
else levelClause = `(Level ${levelString} Cetus Bounty)`;
}
if (isVallis) {
location = "Venus/Orb Vallis ";
levelClause = `(Level ${levelString} Orb Vallis Bounty)`;
}
if (isDeimos) {
location = "Deimos/Cambion Drift ";
levelClause = `(Level ${levelString} ${isVault ? "Isolation Vault" : "Cambion Drift Bounty"})`;
}
const locationWRot = `${location}${levelClause}, Rot ${rotation.length ? rotation : "A"}`;
return {
location,
locationWRot
};
};
const getBountyRewards = async (i18n, raw, isVault, logger = console) => {
let location;
let locationWRot;
if (i18n.endsWith("PlagueStarTableRewards")) {
location = "plague star";
locationWRot = "Earth/Cetus (Level 15 - 25 Plague Star), Rot A";
}
if (!location || !locationWRot) ({location, locationWRot} = determineLocation(i18n, raw, isVault));
const pool = (await fetchProxy(`${apiBase}/drops/search/${encodeURIComponent(location)}?grouped_by=location`).then((res) => res.json()).catch((error) => {
const errorMessage = error instanceof Error ? error.message : String(error);
logger?.debug(`Failed to fetch bounty rewards for ${location}: ${errorMessage}`);
}))?.[locationWRot];
if (!pool) return ["Pattern Mismatch. Results inaccurate."];
const results = pool.rewards;
if (results) return Array.from(new Set(results));
return [];
};
const FIFTY_MINUTES = 3e6;
/**
* Represents a syndicate daily mission
* @augments {WorldStateObject}
*/
var SyndicateJob = class SyndicateJob extends WorldStateObject {
/**
* Reward pool unique name
*/
uniqueName;
/**
* Array of strings describing rewards
*/
rewardPool;
/**
* A structured version of the reward pool
*/
rewardPoolDrops;
/**
* The type of job this is
*/
type;
/**
* Array of enemy levels
*/
enemyLevels;
/**
* Array of standing gains per stage of job
*/
standingStages;
/**
* Minimum mastery required to participate
*/
minMR;
/**
* Whether or not this is a Vault job.
* No indication for difference of normal vs arcana vaults.
*/
isVault;
/**
* Corresponding chamber. Nullable
*/
locationTag;
/**
* What time phase this bounty is bound to
*/
timeBound;
/**
* Generate a job with async data (reward pool)
* @param data The syndicate mission data
* @param expiry The syndicate job expiration
* @param deps The dependencies object
* @returns The created SyndicateJob object with rewardPool
*/
static async build(data, expiry, deps) {
const job = new SyndicateJob(data, expiry, deps);
const rewards = await getBountyRewards(data.rewards, data, data.isVault, deps.logger);
if (typeof rewards[0] === "string") job.rewardPool = rewards;
else {
job.rewardPoolDrops = rewards.map((reward) => {
const countReg = /([0-9]{1,10})X/;
const count = reward.item.match(countReg)?.[1];
return {
...reward,
item: reward.item.replace(countReg, "").trim(),
count: count ? parseInt(count, 10) : 1
};
});
job.rewardPool = rewards.map((reward) => reward.item);
}
return job;
}
/**
* Construct a job without async data (reward pool)
* @param data The syndicate mission data
* @param expiry The syndicate job expiration
* @param deps The dependencies object
* @param deps.locale Locale to use for translations
*
* This DOES NOT populate the reward pool
*/
constructor(data, expiry, { locale } = { locale: "en" }) {
super({ _id: { $oid: data.JobCurrentVersion ? data.JobCurrentVersion.$oid : `${(data.jobType || "").split("/").slice(-1)[0]}${expiry.getTime()}` } });
this.uniqueName = data.rewards;
this.rewardPool = [];
this.rewardPoolDrops = [];
const chamber = (data.locationTag || "").replace(/([a-z])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").trim();
this.type = data.isVault ? `Isolation Vault ${chamber}` : data.jobType ? languageString(data.jobType, locale) : void 0;
this.enemyLevels = [data.minEnemyLevel, data.maxEnemyLevel];
this.standingStages = data.xpAmounts;
this.minMR = data.masteryReq || 0;
this.isVault = data.isVault;
this.locationTag = data.locationTag;
this.expiry = expiry;
const jobType = data.jobType ?? "";
if (jobType.toLowerCase().includes("narmer")) if (jobType.toLowerCase().includes("eidolon")) {
this.timeBound = "day";
this.expiry = /* @__PURE__ */ new Date(this.expiry.getTime() - FIFTY_MINUTES);
} else this.timeBound = "night";
}
};
__decorate([IsString(), __decorateMetadata("design:type", String)], SyndicateJob.prototype, "uniqueName", void 0);
__decorate([
IsArray(),
IsString({ each: true }),
__decorateMetadata("design:type", Array)
], SyndicateJob.prototype, "rewardPool", void 0);
__decorate([IsArray(), __decorateMetadata("design:type", Array)], SyndicateJob.prototype, "rewardPoolDrops", void 0);
__decorate([
IsOptional(),
IsString(),
__decorateMetadata("design:type", String)
], SyndicateJob.prototype, "type", void 0);
__decorate([
IsArray(),
IsInt({ each: true }),
__decorateMetadata("design:type", Array)
], SyndicateJob.prototype, "enemyLevels", void 0);
__decorate([
IsArray(),
IsInt({ each: true }),
__decorateMetadata("design:type", Array)
], SyndicateJob.prototype, "standingStages", void 0);
__decorate([
IsInt(),
Min(0),
__decorateMetadata("design:type", Number)
], SyndicateJob.prototype, "minMR", void 0);
__decorate([IsOptional(), __decorateMetadata("design:type", Boolean)], SyndicateJob.prototype, "isVault", void 0);
__decorate([
IsOptional(),
IsString(),
__decorateMetadata("design:type", String)
], SyndicateJob.prototype, "locationTag", void 0);
__decorate([
IsOptional(),
IsString(),
__decorateMetadata("design:type", Object)
], SyndicateJob.prototype, "timeBound", void 0);
//#endregion
export { SyndicateJob };