UNPKG

warframe-worldstate-parser

Version:

An Open parser for Warframe's Worldstate in Javascript

205 lines (204 loc) 7.14 kB
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 };