返回提交历史
Modified
src/services/worldStateService.ts
+32
-66
Added
static/fixed_responses/worldState/sortieTilesetMissions.json
+45
-0
XFEstudio/SpaceNinjaServer
fix: restrict sortie mission types based on what the tileset supports (#2003)
Closes #2000 Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/2003 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
e545ecf7
代码差异
2 个文件
+77
-66
@@ -1,11 +1,12 @@
1
1
import staticWorldState from "@/static/fixed_responses/worldState/worldState.json";
2
2
import sortieTilesets from "@/static/fixed_responses/worldState/sortieTilesets.json";
3
import sortieTilesetMissions from "@/static/fixed_responses/worldState/sortieTilesetMissions.json";
3
4
import syndicateMissions from "@/static/fixed_responses/worldState/syndicateMissions.json";
4
5
import { buildConfig } from "@/src/services/buildConfigService";
5
6
import { unixTimesInMs } from "@/src/constants/timeConstants";
6
7
import { config } from "@/src/services/configService";
7
8
import { CRng } from "@/src/services/rngService";
8
import { eMissionType, ExportNightwave, ExportRegions, IRegion } from "warframe-public-export-plus";
9
import { ExportNightwave, ExportRegions, IRegion } from "warframe-public-export-plus";
9
10
import {
10
11
ICalendarDay,
11
12
ICalendarEvent,
@@ -72,12 +73,6 @@ const sortieFactionToFactionIndexes: Record<string, number[]> = {
72
73
FC_OROKIN: [3]
73
74
};
74
75
75
const sortieFactionToSpecialMissionTileset: Record<string, string> = {
76
FC_GRINEER: "GrineerGalleonTileset",
77
FC_CORPUS: "CorpusShipTileset",
78
FC_INFESTATION: "CorpusShipTileset"
79
};
80
81
76
const sortieBossNode: Record<Exclude<TSortieBoss, "SORTIE_BOSS_CORRUPTED_VOR">, string> = {
82
77
SORTIE_BOSS_ALAD: "SolNode53",
83
78
SORTIE_BOSS_AMBULAS: "SolNode51",
@@ -217,6 +212,27 @@ const pushSyndicateMissions = (
217
212
});
218
213
};
219
214
215
type TSortieTileset = keyof typeof sortieTilesetMissions;
216
217
const pushTilesetModifiers = (modifiers: string[], tileset: TSortieTileset): void => {
218
switch (tileset) {
219
case "GrineerForestTileset":
220
modifiers.push("SORTIE_MODIFIER_HAZARD_FOG");
221
break;
222
case "CorpusShipTileset":
223
case "GrineerGalleonTileset":
224
case "InfestedCorpusShipTileset":
225
modifiers.push("SORTIE_MODIFIER_HAZARD_MAGNETIC");
226
modifiers.push("SORTIE_MODIFIER_HAZARD_FIRE");
227
modifiers.push("SORTIE_MODIFIER_HAZARD_ICE");
228
break;
229
case "CorpusIcePlanetTileset":
230
case "CorpusIcePlanetTilesetCaves":
231
modifiers.push("SORTIE_MODIFIER_HAZARD_COLD");
232
break;
233
}
234
};
235
220
236
export const getSortie = (day: number): ISortie => {
221
237
const seed = new CRng(day).randomInt(0, 0xffff);
222
238
const rng = new CRng(seed);
@@ -224,54 +240,22 @@ export const getSortie = (day: number): ISortie => {
224
240
const boss = rng.randomElement(sortieBosses)!;
225
241
226
242
const nodes: string[] = [];
227
const availableMissionIndexes: number[] = [];
228
243
for (const [key, value] of Object.entries(ExportRegions)) {
229
244
if (
230
245
sortieFactionToSystemIndexes[sortieBossToFaction[boss]].includes(value.systemIndex) &&
231
246
sortieFactionToFactionIndexes[sortieBossToFaction[boss]].includes(value.factionIndex!) &&
232
247
key in sortieTilesets
233
248
) {
234
if (
235
value.missionIndex != 0 && // Assassination will be decided independently
236
value.missionIndex != 5 && // Sorties do not have capture missions
237
!availableMissionIndexes.includes(value.missionIndex)
238
) {
239
availableMissionIndexes.push(value.missionIndex);
240
}
241
249
nodes.push(key);
242
250
}
243
251
}
244
252
245
const specialMissionTypes = [1, 3, 5, 9];
246
if (!(sortieBossToFaction[boss] in sortieFactionToSpecialMissionTileset)) {
247
for (const missionType of specialMissionTypes) {
248
const i = availableMissionIndexes.indexOf(missionType);
249
if (i != -1) {
250
availableMissionIndexes.splice(i, 1);
251
}
252
}
253
}
254
255
253
const selectedNodes: ISortieMission[] = [];
256
254
const missionTypes = new Set();
257
255
258
256
for (let i = 0; i < 3; i++) {
259
let randomIndex;
260
let node;
261
let missionIndex;
262
do {
263
randomIndex = rng.randomInt(0, nodes.length - 1);
264
node = nodes[randomIndex];
265
266
missionIndex = ExportRegions[node].missionIndex;
267
if (missionIndex != 28) {
268
missionIndex = rng.randomElement(availableMissionIndexes)!;
269
}
270
} while (
271
specialMissionTypes.indexOf(missionIndex) != -1 &&
272
sortieTilesets[node as keyof typeof sortieTilesets] !=
273
sortieFactionToSpecialMissionTileset[sortieBossToFaction[boss]]
274
);
257
const randomIndex = rng.randomInt(0, nodes.length - 1);
258
const node = nodes[randomIndex];
275
259
276
260
const modifiers = [
277
261
"SORTIE_MODIFIER_LOW_ENERGY",
@@ -294,28 +278,10 @@ export const getSortie = (day: number): ISortie => {
294
278
"SORTIE_MODIFIER_RIFLE_ONLY",
295
279
"SORTIE_MODIFIER_BOW_ONLY"
296
280
];
297
const pushTilesetModifiers = (tileset: string): void => {
298
switch (tileset) {
299
case "GrineerForestTileset":
300
modifiers.push("SORTIE_MODIFIER_HAZARD_FOG");
301
break;
302
case "CorpusShipTileset":
303
case "GrineerGalleonTileset":
304
case "InfestedCorpusShipTileset":
305
modifiers.push("SORTIE_MODIFIER_HAZARD_MAGNETIC");
306
modifiers.push("SORTIE_MODIFIER_HAZARD_FIRE");
307
modifiers.push("SORTIE_MODIFIER_HAZARD_ICE");
308
break;
309
case "CorpusIcePlanetTileset":
310
case "CorpusIcePlanetTilesetCaves":
311
modifiers.push("SORTIE_MODIFIER_HAZARD_COLD");
312
break;
313
}
314
};
315
281
316
282
if (i == 2 && boss != "SORTIE_BOSS_CORRUPTED_VOR" && rng.randomInt(0, 2) == 2) {
317
const tileset = sortieTilesets[sortieBossNode[boss] as keyof typeof sortieTilesets];
318
pushTilesetModifiers(tileset);
283
const tileset = sortieTilesets[sortieBossNode[boss] as keyof typeof sortieTilesets] as TSortieTileset;
284
pushTilesetModifiers(modifiers, tileset);
319
285
320
286
const modifierType = rng.randomElement(modifiers)!;
321
287
@@ -328,9 +294,12 @@ export const getSortie = (day: number): ISortie => {
328
294
continue;
329
295
}
330
296
331
const missionType = eMissionType[missionIndex].tag;
297
const tileset = sortieTilesets[node as keyof typeof sortieTilesets] as TSortieTileset;
298
pushTilesetModifiers(modifiers, tileset);
332
299
333
if (missionTypes.has(missionType)) {
300
const missionType = rng.randomElement(sortieTilesetMissions[tileset])!;
301
302
if (missionTypes.has(missionType) || missionType == "MT_ASSASSINATION") {
334
303
i--;
335
304
continue;
336
305
}
@@ -349,9 +318,6 @@ export const getSortie = (day: number): ISortie => {
349
318
modifiers.push("SORTIE_MODIFIER_SHIELDS");
350
319
}
351
320
352
const tileset = sortieTilesets[node as keyof typeof sortieTilesets];
353
pushTilesetModifiers(tileset);
354
355
321
const modifierType = rng.randomElement(modifiers)!;
356
322
357
323
selectedNodes.push({
@@ -0,0 +1,45 @@
1
{
2
"CorpusGasCityTileset": ["MT_ARTIFACT", "MT_ASSASSINATION", "MT_DEFENSE", "MT_EXTERMINATION", "MT_INTEL", "MT_MOBILE_DEFENSE", "MT_RESCUE", "MT_SABOTAGE", "MT_SURVIVAL", "MT_TERRITORY"],
3
"CorpusIcePlanetTileset": ["MT_ASSASSINATION", "MT_DEFENSE", "MT_EXCAVATE", "MT_INTEL", "MT_MOBILE_DEFENSE", "MT_RESCUE", "MT_RETRIEVAL", "MT_TERRITORY"],
4
"CorpusIcePlanetTilesetCaves": ["MT_EXTERMINATION", "MT_INTEL"],
5
"CorpusOutpostTileset": [
6
"MT_ARTIFACT",
7
"MT_ASSASSINATION",
8
"MT_DEFENSE",
9
"MT_EXCAVATE",
10
"MT_EXTERMINATION",
11
"MT_INTEL",
12
"MT_MOBILE_DEFENSE",
13
"MT_RESCUE",
14
"MT_SABOTAGE",
15
"MT_SURVIVAL",
16
"MT_TERRITORY"
17
],
18
"CorpusShipTileset": ["MT_ARTIFACT", "MT_ASSASSINATION", "MT_DEFENSE", "MT_EXTERMINATION", "MT_INTEL", "MT_MOBILE_DEFENSE", "MT_RESCUE", "MT_SABOTAGE", "MT_SURVIVAL", "MT_TERRITORY"],
19
"EidolonTileset": ["MT_LANDSCAPE"],
20
"GrineerAsteroidTileset": ["MT_ASSASSINATION", "MT_DEFENSE", "MT_EVACUATION", "MT_EXTERMINATION", "MT_INTEL", "MT_MOBILE_DEFENSE", "MT_RESCUE", "MT_SURVIVAL", "MT_TERRITORY"],
21
"GrineerForestTileset": ["MT_ASSASSINATION", "MT_EXTERMINATION", "MT_INTEL", "MT_MOBILE_DEFENSE", "MT_TERRITORY"],
22
"GrineerFortressTileset": ["MT_ARTIFACT", "MT_ASSAULT", "MT_INTEL", "MT_MOBILE_DEFENSE", "MT_RESCUE", "MT_SURVIVAL"],
23
"GrineerGalleonTileset": [
24
"MT_ARTIFACT",
25
"MT_ASSASSINATION",
26
"MT_DEFENSE",
27
"MT_EVACUATION",
28
"MT_EXTERMINATION",
29
"MT_INTEL",
30
"MT_MOBILE_DEFENSE",
31
"MT_RESCUE",
32
"MT_SABOTAGE",
33
"MT_SURVIVAL",
34
"MT_TERRITORY"
35
],
36
"GrineerOceanTileset": ["MT_DEFENSE", "MT_EXTERMINATION", "MT_INTEL", "MT_MOBILE_DEFENSE", "MT_RESCUE", "MT_SABOTAGE", "MT_SURVIVAL", "MT_TERRITORY"],
37
"GrineerOceanTilesetAnywhere": ["MT_ASSASSINATION"],
38
"GrineerSettlementTileset": ["MT_ASSASSINATION", "MT_DEFENSE", "MT_EXTERMINATION", "MT_INTEL", "MT_MOBILE_DEFENSE", "MT_RESCUE", "MT_SABOTAGE", "MT_TERRITORY"],
39
"GrineerShipyardsTileset": ["MT_DEFENSE", "MT_EXTERMINATION", "MT_INTEL", "MT_MOBILE_DEFENSE", "MT_RESCUE", "MT_RETRIEVAL", "MT_TERRITORY"],
40
"InfestedCorpusShipTileset": ["MT_ASSASSINATION", "MT_HIVE", "MT_MOBILE_DEFENSE", "MT_RESCUE"],
41
"OrokinDerelictTileset": ["MT_ARTIFACT", "MT_ASSASSINATION", "MT_DEFENSE", "MT_EXTERMINATION", "MT_MOBILE_DEFENSE", "MT_SABOTAGE", "MT_SURVIVAL"],
42
"OrokinMoonTilesetCorpus": ["MT_ARTIFACT", "MT_DEFENSE", "MT_EXTERMINATION", "MT_MOBILE_DEFENSE", "MT_RESCUE", "MT_SURVIVAL"],
43
"OrokinMoonTilesetGrineer": ["MT_DEFENSE", "MT_EXTERMINATION", "MT_MOBILE_DEFENSE", "MT_RESCUE", "MT_SURVIVAL"],
44
"OrokinVoidTileset": ["MT_DEFENSE", "MT_EXTERMINATION", "MT_MOBILE_DEFENSE", "MT_SABOTAGE", "MT_SURVIVAL", "MT_TERRITORY"]
45
}