fix: restrict sortie mission types based on what the tileset supports (#2003)
Some checks failed
Build Docker image / docker (push) Has been cancelled
Build / build (push) Has been cancelled

Closes #2000

Reviewed-on: #2003
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
This commit is contained in:
Sainan 2025-05-07 20:14:05 -07:00 committed by Sainan
parent 58549c1488
commit e545ecf767
2 changed files with 77 additions and 66 deletions

View File

@ -1,11 +1,12 @@
import staticWorldState from "@/static/fixed_responses/worldState/worldState.json";
import sortieTilesets from "@/static/fixed_responses/worldState/sortieTilesets.json";
import sortieTilesetMissions from "@/static/fixed_responses/worldState/sortieTilesetMissions.json";
import syndicateMissions from "@/static/fixed_responses/worldState/syndicateMissions.json";
import { buildConfig } from "@/src/services/buildConfigService";
import { unixTimesInMs } from "@/src/constants/timeConstants";
import { config } from "@/src/services/configService";
import { CRng } from "@/src/services/rngService";
import { eMissionType, ExportNightwave, ExportRegions, IRegion } from "warframe-public-export-plus";
import { ExportNightwave, ExportRegions, IRegion } from "warframe-public-export-plus";
import {
ICalendarDay,
ICalendarEvent,
@ -72,12 +73,6 @@ const sortieFactionToFactionIndexes: Record<string, number[]> = {
FC_OROKIN: [3]
};
const sortieFactionToSpecialMissionTileset: Record<string, string> = {
FC_GRINEER: "GrineerGalleonTileset",
FC_CORPUS: "CorpusShipTileset",
FC_INFESTATION: "CorpusShipTileset"
};
const sortieBossNode: Record<Exclude<TSortieBoss, "SORTIE_BOSS_CORRUPTED_VOR">, string> = {
SORTIE_BOSS_ALAD: "SolNode53",
SORTIE_BOSS_AMBULAS: "SolNode51",
@ -217,6 +212,27 @@ const pushSyndicateMissions = (
});
};
type TSortieTileset = keyof typeof sortieTilesetMissions;
const pushTilesetModifiers = (modifiers: string[], tileset: TSortieTileset): void => {
switch (tileset) {
case "GrineerForestTileset":
modifiers.push("SORTIE_MODIFIER_HAZARD_FOG");
break;
case "CorpusShipTileset":
case "GrineerGalleonTileset":
case "InfestedCorpusShipTileset":
modifiers.push("SORTIE_MODIFIER_HAZARD_MAGNETIC");
modifiers.push("SORTIE_MODIFIER_HAZARD_FIRE");
modifiers.push("SORTIE_MODIFIER_HAZARD_ICE");
break;
case "CorpusIcePlanetTileset":
case "CorpusIcePlanetTilesetCaves":
modifiers.push("SORTIE_MODIFIER_HAZARD_COLD");
break;
}
};
export const getSortie = (day: number): ISortie => {
const seed = new CRng(day).randomInt(0, 0xffff);
const rng = new CRng(seed);
@ -224,54 +240,22 @@ export const getSortie = (day: number): ISortie => {
const boss = rng.randomElement(sortieBosses)!;
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!) &&
key in sortieTilesets
) {
if (
value.missionIndex != 0 && // Assassination will be decided independently
value.missionIndex != 5 && // Sorties do not have capture missions
!availableMissionIndexes.includes(value.missionIndex)
) {
availableMissionIndexes.push(value.missionIndex);
}
nodes.push(key);
}
}
const specialMissionTypes = [1, 3, 5, 9];
if (!(sortieBossToFaction[boss] in sortieFactionToSpecialMissionTileset)) {
for (const missionType of specialMissionTypes) {
const i = availableMissionIndexes.indexOf(missionType);
if (i != -1) {
availableMissionIndexes.splice(i, 1);
}
}
}
const selectedNodes: ISortieMission[] = [];
const missionTypes = new Set();
for (let i = 0; i < 3; i++) {
let randomIndex;
let node;
let missionIndex;
do {
randomIndex = rng.randomInt(0, nodes.length - 1);
node = nodes[randomIndex];
missionIndex = ExportRegions[node].missionIndex;
if (missionIndex != 28) {
missionIndex = rng.randomElement(availableMissionIndexes)!;
}
} while (
specialMissionTypes.indexOf(missionIndex) != -1 &&
sortieTilesets[node as keyof typeof sortieTilesets] !=
sortieFactionToSpecialMissionTileset[sortieBossToFaction[boss]]
);
const randomIndex = rng.randomInt(0, nodes.length - 1);
const node = nodes[randomIndex];
const modifiers = [
"SORTIE_MODIFIER_LOW_ENERGY",
@ -294,28 +278,10 @@ export const getSortie = (day: number): ISortie => {
"SORTIE_MODIFIER_RIFLE_ONLY",
"SORTIE_MODIFIER_BOW_ONLY"
];
const pushTilesetModifiers = (tileset: string): void => {
switch (tileset) {
case "GrineerForestTileset":
modifiers.push("SORTIE_MODIFIER_HAZARD_FOG");
break;
case "CorpusShipTileset":
case "GrineerGalleonTileset":
case "InfestedCorpusShipTileset":
modifiers.push("SORTIE_MODIFIER_HAZARD_MAGNETIC");
modifiers.push("SORTIE_MODIFIER_HAZARD_FIRE");
modifiers.push("SORTIE_MODIFIER_HAZARD_ICE");
break;
case "CorpusIcePlanetTileset":
case "CorpusIcePlanetTilesetCaves":
modifiers.push("SORTIE_MODIFIER_HAZARD_COLD");
break;
}
};
if (i == 2 && boss != "SORTIE_BOSS_CORRUPTED_VOR" && rng.randomInt(0, 2) == 2) {
const tileset = sortieTilesets[sortieBossNode[boss] as keyof typeof sortieTilesets];
pushTilesetModifiers(tileset);
const tileset = sortieTilesets[sortieBossNode[boss] as keyof typeof sortieTilesets] as TSortieTileset;
pushTilesetModifiers(modifiers, tileset);
const modifierType = rng.randomElement(modifiers)!;
@ -328,9 +294,12 @@ export const getSortie = (day: number): ISortie => {
continue;
}
const missionType = eMissionType[missionIndex].tag;
const tileset = sortieTilesets[node as keyof typeof sortieTilesets] as TSortieTileset;
pushTilesetModifiers(modifiers, tileset);
if (missionTypes.has(missionType)) {
const missionType = rng.randomElement(sortieTilesetMissions[tileset])!;
if (missionTypes.has(missionType) || missionType == "MT_ASSASSINATION") {
i--;
continue;
}
@ -349,9 +318,6 @@ export const getSortie = (day: number): ISortie => {
modifiers.push("SORTIE_MODIFIER_SHIELDS");
}
const tileset = sortieTilesets[node as keyof typeof sortieTilesets];
pushTilesetModifiers(tileset);
const modifierType = rng.randomElement(modifiers)!;
selectedNodes.push({

View File

@ -0,0 +1,45 @@
{
"CorpusGasCityTileset": ["MT_ARTIFACT", "MT_ASSASSINATION", "MT_DEFENSE", "MT_EXTERMINATION", "MT_INTEL", "MT_MOBILE_DEFENSE", "MT_RESCUE", "MT_SABOTAGE", "MT_SURVIVAL", "MT_TERRITORY"],
"CorpusIcePlanetTileset": ["MT_ASSASSINATION", "MT_DEFENSE", "MT_EXCAVATE", "MT_INTEL", "MT_MOBILE_DEFENSE", "MT_RESCUE", "MT_RETRIEVAL", "MT_TERRITORY"],
"CorpusIcePlanetTilesetCaves": ["MT_EXTERMINATION", "MT_INTEL"],
"CorpusOutpostTileset": [
"MT_ARTIFACT",
"MT_ASSASSINATION",
"MT_DEFENSE",
"MT_EXCAVATE",
"MT_EXTERMINATION",
"MT_INTEL",
"MT_MOBILE_DEFENSE",
"MT_RESCUE",
"MT_SABOTAGE",
"MT_SURVIVAL",
"MT_TERRITORY"
],
"CorpusShipTileset": ["MT_ARTIFACT", "MT_ASSASSINATION", "MT_DEFENSE", "MT_EXTERMINATION", "MT_INTEL", "MT_MOBILE_DEFENSE", "MT_RESCUE", "MT_SABOTAGE", "MT_SURVIVAL", "MT_TERRITORY"],
"EidolonTileset": ["MT_LANDSCAPE"],
"GrineerAsteroidTileset": ["MT_ASSASSINATION", "MT_DEFENSE", "MT_EVACUATION", "MT_EXTERMINATION", "MT_INTEL", "MT_MOBILE_DEFENSE", "MT_RESCUE", "MT_SURVIVAL", "MT_TERRITORY"],
"GrineerForestTileset": ["MT_ASSASSINATION", "MT_EXTERMINATION", "MT_INTEL", "MT_MOBILE_DEFENSE", "MT_TERRITORY"],
"GrineerFortressTileset": ["MT_ARTIFACT", "MT_ASSAULT", "MT_INTEL", "MT_MOBILE_DEFENSE", "MT_RESCUE", "MT_SURVIVAL"],
"GrineerGalleonTileset": [
"MT_ARTIFACT",
"MT_ASSASSINATION",
"MT_DEFENSE",
"MT_EVACUATION",
"MT_EXTERMINATION",
"MT_INTEL",
"MT_MOBILE_DEFENSE",
"MT_RESCUE",
"MT_SABOTAGE",
"MT_SURVIVAL",
"MT_TERRITORY"
],
"GrineerOceanTileset": ["MT_DEFENSE", "MT_EXTERMINATION", "MT_INTEL", "MT_MOBILE_DEFENSE", "MT_RESCUE", "MT_SABOTAGE", "MT_SURVIVAL", "MT_TERRITORY"],
"GrineerOceanTilesetAnywhere": ["MT_ASSASSINATION"],
"GrineerSettlementTileset": ["MT_ASSASSINATION", "MT_DEFENSE", "MT_EXTERMINATION", "MT_INTEL", "MT_MOBILE_DEFENSE", "MT_RESCUE", "MT_SABOTAGE", "MT_TERRITORY"],
"GrineerShipyardsTileset": ["MT_DEFENSE", "MT_EXTERMINATION", "MT_INTEL", "MT_MOBILE_DEFENSE", "MT_RESCUE", "MT_RETRIEVAL", "MT_TERRITORY"],
"InfestedCorpusShipTileset": ["MT_ASSASSINATION", "MT_HIVE", "MT_MOBILE_DEFENSE", "MT_RESCUE"],
"OrokinDerelictTileset": ["MT_ARTIFACT", "MT_ASSASSINATION", "MT_DEFENSE", "MT_EXTERMINATION", "MT_MOBILE_DEFENSE", "MT_SABOTAGE", "MT_SURVIVAL"],
"OrokinMoonTilesetCorpus": ["MT_ARTIFACT", "MT_DEFENSE", "MT_EXTERMINATION", "MT_MOBILE_DEFENSE", "MT_RESCUE", "MT_SURVIVAL"],
"OrokinMoonTilesetGrineer": ["MT_DEFENSE", "MT_EXTERMINATION", "MT_MOBILE_DEFENSE", "MT_RESCUE", "MT_SURVIVAL"],
"OrokinVoidTileset": ["MT_DEFENSE", "MT_EXTERMINATION", "MT_MOBILE_DEFENSE", "MT_SABOTAGE", "MT_SURVIVAL", "MT_TERRITORY"]
}