parent
abeb17ce44
commit
1ad7b3373d
@ -10,6 +10,14 @@ import { unixTimesInMs } from "@/src/constants/timeConstants";
|
|||||||
import { config } from "@/src/services/configService";
|
import { config } from "@/src/services/configService";
|
||||||
import { CRng } from "@/src/services/rngService";
|
import { CRng } from "@/src/services/rngService";
|
||||||
import { ExportNightwave, ExportRegions } from "warframe-public-export-plus";
|
import { ExportNightwave, ExportRegions } from "warframe-public-export-plus";
|
||||||
|
import {
|
||||||
|
missionTags,
|
||||||
|
sortieBosses,
|
||||||
|
sortieBossNode,
|
||||||
|
sortieBossToFaction,
|
||||||
|
sortieFactionToFactionIndexes,
|
||||||
|
sortieFactionToSystemIndexes
|
||||||
|
} from "@/src/helpers/worlstateHelper";
|
||||||
|
|
||||||
const EPOCH = 1734307200 * 1000; // Monday, Dec 16, 2024 @ 00:00 UTC+0; should logically be winter in 1999 iteration 0
|
const EPOCH = 1734307200 * 1000; // Monday, Dec 16, 2024 @ 00:00 UTC+0; should logically be winter in 1999 iteration 0
|
||||||
|
|
||||||
@ -27,6 +35,7 @@ export const worldStateController: RequestHandler = (req, res) => {
|
|||||||
Time: config.worldState?.lockTime || Math.round(Date.now() / 1000),
|
Time: config.worldState?.lockTime || Math.round(Date.now() / 1000),
|
||||||
Goals: [],
|
Goals: [],
|
||||||
GlobalUpgrades: [],
|
GlobalUpgrades: [],
|
||||||
|
Sorties: [],
|
||||||
LiteSorties: [],
|
LiteSorties: [],
|
||||||
EndlessXpChoices: [],
|
EndlessXpChoices: [],
|
||||||
SeasonInfo: {
|
SeasonInfo: {
|
||||||
@ -154,6 +163,129 @@ export const worldStateController: RequestHandler = (req, res) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sortie cycling every day
|
||||||
|
{
|
||||||
|
const dayStart = EPOCH + day * 86400000;
|
||||||
|
const dayEnd = dayStart + 86400000;
|
||||||
|
|
||||||
|
const rng = new CRng(day);
|
||||||
|
|
||||||
|
const boss = rng.randomElement(sortieBosses);
|
||||||
|
|
||||||
|
const modifiers = [
|
||||||
|
"SORTIE_MODIFIER_LOW_ENERGY",
|
||||||
|
"SORTIE_MODIFIER_IMPACT",
|
||||||
|
"SORTIE_MODIFIER_SLASH",
|
||||||
|
"SORTIE_MODIFIER_PUNCTURE",
|
||||||
|
"SORTIE_MODIFIER_EXIMUS",
|
||||||
|
"SORTIE_MODIFIER_MAGNETIC",
|
||||||
|
"SORTIE_MODIFIER_CORROSIVE",
|
||||||
|
"SORTIE_MODIFIER_VIRAL",
|
||||||
|
"SORTIE_MODIFIER_ELECTRICITY",
|
||||||
|
"SORTIE_MODIFIER_RADIATION",
|
||||||
|
"SORTIE_MODIFIER_GAS",
|
||||||
|
"SORTIE_MODIFIER_FIRE",
|
||||||
|
"SORTIE_MODIFIER_EXPLOSION",
|
||||||
|
"SORTIE_MODIFIER_FREEZE",
|
||||||
|
"SORTIE_MODIFIER_TOXIN",
|
||||||
|
"SORTIE_MODIFIER_POISON",
|
||||||
|
"SORTIE_MODIFIER_HAZARD_RADIATION",
|
||||||
|
"SORTIE_MODIFIER_HAZARD_MAGNETIC",
|
||||||
|
"SORTIE_MODIFIER_HAZARD_FOG", // TODO: push this if the mission tileset is Grineer Forest
|
||||||
|
"SORTIE_MODIFIER_HAZARD_FIRE", // TODO: push this if the mission tileset is Corpus Ship or Grineer Galleon
|
||||||
|
"SORTIE_MODIFIER_HAZARD_ICE",
|
||||||
|
"SORTIE_MODIFIER_HAZARD_COLD",
|
||||||
|
"SORTIE_MODIFIER_SECONDARY_ONLY",
|
||||||
|
"SORTIE_MODIFIER_SHOTGUN_ONLY",
|
||||||
|
"SORTIE_MODIFIER_SNIPER_ONLY",
|
||||||
|
"SORTIE_MODIFIER_RIFLE_ONLY",
|
||||||
|
"SORTIE_MODIFIER_MELEE_ONLY",
|
||||||
|
"SORTIE_MODIFIER_BOW_ONLY"
|
||||||
|
];
|
||||||
|
|
||||||
|
if (sortieBossToFaction[boss] == "FC_CORPUS") modifiers.push("SORTIE_MODIFIER_SHIELDS");
|
||||||
|
if (sortieBossToFaction[boss] != "FC_CORPUS") modifiers.push("SORTIE_MODIFIER_ARMOR");
|
||||||
|
|
||||||
|
const nodes: string[] = [];
|
||||||
|
const availableMissionIndexes: number[] = [];
|
||||||
|
for (const [key, value] of Object.entries(ExportRegions)) {
|
||||||
|
if (
|
||||||
|
sortieFactionToSystemIndexes[sortieBossToFaction[boss]].includes(value.systemIndex) &&
|
||||||
|
sortieFactionToFactionIndexes[sortieBossToFaction[boss]].includes(value.factionIndex!) &&
|
||||||
|
value.name.indexOf("Archwing") == -1 &&
|
||||||
|
value.missionIndex != 0 && // Exclude MT_ASSASSINATION
|
||||||
|
value.missionIndex != 5 && // Exclude MT_CAPTURE
|
||||||
|
value.missionIndex != 21 && // Exclude MT_PURIFY
|
||||||
|
value.missionIndex != 23 && // Exclude MT_JUNCTION
|
||||||
|
value.missionIndex <= 28
|
||||||
|
) {
|
||||||
|
if (!availableMissionIndexes.includes(value.missionIndex)) {
|
||||||
|
availableMissionIndexes.push(value.missionIndex);
|
||||||
|
}
|
||||||
|
nodes.push(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const selectedNodes: { missionType: string; modifierType: string; node: string }[] = [];
|
||||||
|
const missionTypes = new Set();
|
||||||
|
|
||||||
|
for (let i = 0; i < 3; i++) {
|
||||||
|
const randomIndex = rng.randomInt(0, nodes.length - 1);
|
||||||
|
const node = nodes[randomIndex];
|
||||||
|
let missionIndex = ExportRegions[node].missionIndex;
|
||||||
|
|
||||||
|
if (
|
||||||
|
!["SolNode404", "SolNode411"].includes(node) && // for some reason the game doesn't like missionType changes for these missions
|
||||||
|
missionIndex != 28 &&
|
||||||
|
rng.randomInt(0, 2) == 2
|
||||||
|
) {
|
||||||
|
missionIndex = rng.randomElement(availableMissionIndexes);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == 2 && rng.randomInt(0, 2) == 2) {
|
||||||
|
const filteredModifiers = modifiers.filter(mod => mod !== "SORTIE_MODIFIER_MELEE_ONLY");
|
||||||
|
const modifierType = rng.randomElement(filteredModifiers);
|
||||||
|
|
||||||
|
if (boss == "SORTIE_BOSS_PHORID") {
|
||||||
|
selectedNodes.push({ missionType: "MT_ASSASSINATION", modifierType, node });
|
||||||
|
nodes.splice(randomIndex, 1);
|
||||||
|
continue;
|
||||||
|
} else if (sortieBossNode[boss]) {
|
||||||
|
selectedNodes.push({ missionType: "MT_ASSASSINATION", modifierType, node: sortieBossNode[boss] });
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const missionType = missionTags[missionIndex];
|
||||||
|
|
||||||
|
if (missionTypes.has(missionType)) {
|
||||||
|
i--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const filteredModifiers =
|
||||||
|
missionType === "MT_TERRITORY"
|
||||||
|
? modifiers.filter(mod => mod != "SORTIE_MODIFIER_HAZARD_RADIATION")
|
||||||
|
: modifiers;
|
||||||
|
|
||||||
|
const modifierType = rng.randomElement(filteredModifiers);
|
||||||
|
|
||||||
|
selectedNodes.push({ missionType, modifierType, node });
|
||||||
|
nodes.splice(randomIndex, 1);
|
||||||
|
missionTypes.add(missionType);
|
||||||
|
}
|
||||||
|
|
||||||
|
worldState.Sorties.push({
|
||||||
|
_id: { $oid: Math.trunc(dayStart / 1000).toString(16) + "d4d932c97c0a3acd" },
|
||||||
|
Activation: { $date: { $numberLong: dayStart.toString() } },
|
||||||
|
Expiry: { $date: { $numberLong: dayEnd.toString() } },
|
||||||
|
Reward: "/Lotus/Types/Game/MissionDecks/SortieRewards",
|
||||||
|
Seed: day,
|
||||||
|
Boss: boss,
|
||||||
|
Variants: selectedNodes
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Archon Hunt cycling every week
|
// Archon Hunt cycling every week
|
||||||
{
|
{
|
||||||
const boss = ["SORTIE_BOSS_AMAR", "SORTIE_BOSS_NIRA", "SORTIE_BOSS_BOREAL"][week % 3];
|
const boss = ["SORTIE_BOSS_AMAR", "SORTIE_BOSS_NIRA", "SORTIE_BOSS_BOREAL"][week % 3];
|
||||||
@ -298,6 +430,7 @@ interface IWorldState {
|
|||||||
Goals: IGoal[];
|
Goals: IGoal[];
|
||||||
SyndicateMissions: ISyndicateMission[];
|
SyndicateMissions: ISyndicateMission[];
|
||||||
GlobalUpgrades: IGlobalUpgrade[];
|
GlobalUpgrades: IGlobalUpgrade[];
|
||||||
|
Sorties: ISortie[];
|
||||||
LiteSorties: ILiteSortie[];
|
LiteSorties: ILiteSortie[];
|
||||||
NodeOverrides: INodeOverride[];
|
NodeOverrides: INodeOverride[];
|
||||||
EndlessXpChoices: IEndlessXpChoice[];
|
EndlessXpChoices: IEndlessXpChoice[];
|
||||||
@ -361,6 +494,20 @@ interface INodeOverride {
|
|||||||
CustomNpcEncounters?: string;
|
CustomNpcEncounters?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface ISortie {
|
||||||
|
_id: IOid;
|
||||||
|
Activation: IMongoDate;
|
||||||
|
Expiry: IMongoDate;
|
||||||
|
Reward: "/Lotus/Types/Game/MissionDecks/SortieRewards";
|
||||||
|
Seed: number;
|
||||||
|
Boss: string;
|
||||||
|
Variants: {
|
||||||
|
missionType: string;
|
||||||
|
modifierType: string;
|
||||||
|
node: string;
|
||||||
|
}[];
|
||||||
|
}
|
||||||
|
|
||||||
interface ILiteSortie {
|
interface ILiteSortie {
|
||||||
_id: IOid;
|
_id: IOid;
|
||||||
Activation: IMongoDate;
|
Activation: IMongoDate;
|
||||||
|
114
src/helpers/worlstateHelper.ts
Normal file
114
src/helpers/worlstateHelper.ts
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
export const missionTags = [
|
||||||
|
"MT_ASSASSINATION",
|
||||||
|
"MT_EXTERMINATION",
|
||||||
|
"MT_SURVIVAL",
|
||||||
|
"MT_RESCUE",
|
||||||
|
"MT_SABOTAGE",
|
||||||
|
"MT_CAPTURE",
|
||||||
|
"MT_COUNTER_INTEL",
|
||||||
|
"MT_INTEL",
|
||||||
|
"MT_DEFENSE",
|
||||||
|
"MT_MOBILE_DEFENSE",
|
||||||
|
"MT_PVP",
|
||||||
|
"MT_MASTERY",
|
||||||
|
"MT_RECOVERY",
|
||||||
|
"MT_TERRITORY",
|
||||||
|
"MT_RETRIEVAL",
|
||||||
|
"MT_HIVE",
|
||||||
|
"MT_SALVAGE",
|
||||||
|
"MT_EXCAVATE",
|
||||||
|
"MT_RAID",
|
||||||
|
"MT_PURGE",
|
||||||
|
"MT_GENERIC",
|
||||||
|
"MT_PURIFY",
|
||||||
|
"MT_ARENA",
|
||||||
|
"MT_JUNCTION",
|
||||||
|
"MT_PURSUIT",
|
||||||
|
"MT_RACE",
|
||||||
|
"MT_ASSAULT",
|
||||||
|
"MT_EVACUATION",
|
||||||
|
"MT_LANDSCAPE",
|
||||||
|
"MT_RESOURCE_THEFT",
|
||||||
|
"MT_ENDLESS_EXTERMINATION",
|
||||||
|
"MT_ENDLESS_DUVIRI",
|
||||||
|
"MT_RAILJACK",
|
||||||
|
"MT_ARTIFACT",
|
||||||
|
"MT_CORRUPTION",
|
||||||
|
"MT_VOID_CASCADE",
|
||||||
|
"MT_ARMAGEDDON",
|
||||||
|
"MT_VAULTS",
|
||||||
|
"MT_ALCHEMY",
|
||||||
|
"MT_ASCENSION",
|
||||||
|
"MT_ENDLESS_CAPTURE",
|
||||||
|
"MT_OFFERING",
|
||||||
|
"MT_PVPVE"
|
||||||
|
];
|
||||||
|
|
||||||
|
export const sortieBosses = [
|
||||||
|
"SORTIE_BOSS_HYENA",
|
||||||
|
"SORTIE_BOSS_KELA",
|
||||||
|
"SORTIE_BOSS_VOR",
|
||||||
|
"SORTIE_BOSS_RUK",
|
||||||
|
"SORTIE_BOSS_HEK",
|
||||||
|
"SORTIE_BOSS_KRIL",
|
||||||
|
"SORTIE_BOSS_TYL",
|
||||||
|
"SORTIE_BOSS_JACKAL",
|
||||||
|
"SORTIE_BOSS_ALAD",
|
||||||
|
"SORTIE_BOSS_AMBULAS",
|
||||||
|
"SORTIE_BOSS_NEF",
|
||||||
|
"SORTIE_BOSS_RAPTOR",
|
||||||
|
"SORTIE_BOSS_PHORID",
|
||||||
|
"SORTIE_BOSS_LEPHANTIS",
|
||||||
|
"SORTIE_BOSS_INFALAD",
|
||||||
|
"SORTIE_BOSS_CORRUPTED_VOR"
|
||||||
|
];
|
||||||
|
|
||||||
|
export const sortieBossToFaction: Record<string, string> = {
|
||||||
|
SORTIE_BOSS_HYENA: "FC_CORPUS",
|
||||||
|
SORTIE_BOSS_KELA: "FC_GRINEER",
|
||||||
|
SORTIE_BOSS_VOR: "FC_GRINEER",
|
||||||
|
SORTIE_BOSS_RUK: "FC_GRINEER",
|
||||||
|
SORTIE_BOSS_HEK: "FC_GRINEER",
|
||||||
|
SORTIE_BOSS_KRIL: "FC_GRINEER",
|
||||||
|
SORTIE_BOSS_TYL: "FC_GRINEER",
|
||||||
|
SORTIE_BOSS_JACKAL: "FC_CORPUS",
|
||||||
|
SORTIE_BOSS_ALAD: "FC_CORPUS",
|
||||||
|
SORTIE_BOSS_AMBULAS: "FC_CORPUS",
|
||||||
|
SORTIE_BOSS_NEF: "FC_CORPUS",
|
||||||
|
SORTIE_BOSS_RAPTOR: "FC_CORPUS",
|
||||||
|
SORTIE_BOSS_PHORID: "FC_INFESTATION",
|
||||||
|
SORTIE_BOSS_LEPHANTIS: "FC_INFESTATION",
|
||||||
|
SORTIE_BOSS_INFALAD: "FC_INFESTATION",
|
||||||
|
SORTIE_BOSS_CORRUPTED_VOR: "FC_CORRUPTED"
|
||||||
|
};
|
||||||
|
|
||||||
|
export const sortieFactionToSystemIndexes: Record<string, number[]> = {
|
||||||
|
FC_GRINEER: [0, 2, 3, 5, 6, 9, 11, 18],
|
||||||
|
FC_CORPUS: [1, 4, 7, 8, 12, 15],
|
||||||
|
FC_INFESTATION: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 15],
|
||||||
|
FC_CORRUPTED: [14]
|
||||||
|
};
|
||||||
|
|
||||||
|
export const sortieFactionToFactionIndexes: Record<string, number[]> = {
|
||||||
|
FC_GRINEER: [0],
|
||||||
|
FC_CORPUS: [1],
|
||||||
|
FC_INFESTATION: [0, 1, 2],
|
||||||
|
FC_CORRUPTED: [3]
|
||||||
|
};
|
||||||
|
|
||||||
|
export const sortieBossNode: Record<string, string> = {
|
||||||
|
SORTIE_BOSS_HYENA: "SolNode127",
|
||||||
|
SORTIE_BOSS_KELA: "SolNode193",
|
||||||
|
SORTIE_BOSS_VOR: "SolNode108",
|
||||||
|
SORTIE_BOSS_RUK: "SolNode32",
|
||||||
|
SORTIE_BOSS_HEK: "SolNode24",
|
||||||
|
SORTIE_BOSS_KRIL: "SolNode99",
|
||||||
|
SORTIE_BOSS_TYL: "SolNode105",
|
||||||
|
SORTIE_BOSS_JACKAL: "SolNode104",
|
||||||
|
SORTIE_BOSS_ALAD: "SolNode53",
|
||||||
|
SORTIE_BOSS_AMBULAS: "SolNode51",
|
||||||
|
SORTIE_BOSS_NEF: "SettlementNode20",
|
||||||
|
SORTIE_BOSS_RAPTOR: "SolNode210",
|
||||||
|
SORTIE_BOSS_LEPHANTIS: "SolNode712",
|
||||||
|
SORTIE_BOSS_INFALAD: "SolNode705"
|
||||||
|
};
|
@ -62,23 +62,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"Sorties": [
|
|
||||||
{
|
|
||||||
"_id": { "$oid": "663a4c7d4d932c97c0a3acd7" },
|
|
||||||
"Activation": { "$date": { "$numberLong": "1715097600000" } },
|
|
||||||
"Expiry": { "$date": { "$numberLong": "2000000000000" } },
|
|
||||||
"Reward": "/Lotus/Types/Game/MissionDecks/SortieRewards",
|
|
||||||
"Seed": 24491,
|
|
||||||
"Boss": "SORTIE_BOSS_TYL",
|
|
||||||
"ExtraDrops": [],
|
|
||||||
"Variants": [
|
|
||||||
{ "missionType": "MT_TERRITORY", "modifierType": "SORTIE_MODIFIER_ARMOR", "node": "SolNode122", "tileset": "GrineerOceanTileset" },
|
|
||||||
{ "missionType": "MT_MOBILE_DEFENSE", "modifierType": "SORTIE_MODIFIER_LOW_ENERGY", "node": "SolNode184", "tileset": "GrineerGalleonTileset" },
|
|
||||||
{ "missionType": "MT_LANDSCAPE", "modifierType": "SORTIE_MODIFIER_EXIMUS", "node": "SolNode228", "tileset": "EidolonTileset" }
|
|
||||||
],
|
|
||||||
"Twitter": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"SyndicateMissions": [
|
"SyndicateMissions": [
|
||||||
{
|
{
|
||||||
"_id": { "$oid": "663a4fc5ba6f84724fa48049" },
|
"_id": { "$oid": "663a4fc5ba6f84724fa48049" },
|
||||||
|
Loading…
x
Reference in New Issue
Block a user