Compare commits

...

7 Commits

Author SHA1 Message Date
2a40449604 chore: add TNemesisFaction 2025-05-13 12:21:20 +02:00
382f8c55ce chore: update Docker stuff (#2065)
Reviewed-on: OpenWF/SpaceNinjaServer#2065
Co-authored-by: Animan8000 <animan8000@noreply.localhost>
Co-committed-by: Animan8000 <animan8000@noreply.localhost>
2025-05-13 01:47:09 -07:00
77513190e4 fix: incorrect droptable name for zariman tier c (#2062)
Fixes #2061

Reviewed-on: OpenWF/SpaceNinjaServer#2062
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-05-12 19:49:30 -07:00
5e8ce934c9 chore: clarify which category has a negative count 2025-05-12 06:59:20 +02:00
6de81c2b41 chore: handle LasrianTankSteelPathDropTable for DROP_MOD (#2057)
Closes #2056

Reviewed-on: OpenWF/SpaceNinjaServer#2057
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-05-11 21:53:16 -07:00
4c5ac4f03a chore(webui): update German translation (#2059)
Reviewed-on: OpenWF/SpaceNinjaServer#2059
Co-authored-by: Animan8000 <animan8000@noreply.localhost>
Co-committed-by: Animan8000 <animan8000@noreply.localhost>
2025-05-11 02:16:23 -07:00
d6f4c1a035 chore(webui): update to Spanish translation (#2058)
Reviewed-on: OpenWF/SpaceNinjaServer#2058
Co-authored-by: hxedcl <hxedcl@noreply.localhost>
Co-committed-by: hxedcl <hxedcl@noreply.localhost>
2025-05-11 00:02:57 -07:00
9 changed files with 46 additions and 29 deletions

View File

@ -14,6 +14,8 @@ ENV APP_INFINITE_PLATINUM=false
ENV APP_INFINITE_ENDO=false ENV APP_INFINITE_ENDO=false
ENV APP_INFINITE_REGAL_AYA=false ENV APP_INFINITE_REGAL_AYA=false
ENV APP_INFINITE_HELMINTH_MATERIALS=false ENV APP_INFINITE_HELMINTH_MATERIALS=false
ENV APP_CLAIMING_BLUEPRINT_REFUNDS_INGREDIENTS=false
ENV APP_DONT_SUBTRACT_VOIDTRACES=false
ENV APP_DONT_SUBTRACT_CONSUMABLES=false ENV APP_DONT_SUBTRACT_CONSUMABLES=false
ENV APP_UNLOCK_ALL_SHIP_FEATURES=false ENV APP_UNLOCK_ALL_SHIP_FEATURES=false
ENV APP_UNLOCK_ALL_SHIP_DECORATIONS=false ENV APP_UNLOCK_ALL_SHIP_DECORATIONS=false

View File

@ -21,6 +21,8 @@ services:
# APP_INFINITE_ENDO: false # APP_INFINITE_ENDO: false
# APP_INFINITE_REGAL_AYA: false # APP_INFINITE_REGAL_AYA: false
# APP_INFINITE_HELMINTH_MATERIALS: false # APP_INFINITE_HELMINTH_MATERIALS: false
# APP_CLAIMING_BLUEPRINT_REFUNDS_INGREDIENTS: false
# APP_DONT_SUBTRACT_VOIDTRACES: false
# APP_DONT_SUBTRACT_CONSUMABLES: false # APP_DONT_SUBTRACT_CONSUMABLES: false
# APP_UNLOCK_ALL_SHIP_FEATURES: false # APP_UNLOCK_ALL_SHIP_FEATURES: false
# APP_UNLOCK_ALL_SHIP_DECORATIONS: false # APP_UNLOCK_ALL_SHIP_DECORATIONS: false

View File

@ -24,7 +24,8 @@ import {
IUpgradeClient, IUpgradeClient,
IWeaponSkinClient, IWeaponSkinClient,
LoadoutIndex, LoadoutIndex,
TEquipmentKey TEquipmentKey,
TNemesisFaction
} from "@/src/types/inventoryTypes/inventoryTypes"; } from "@/src/types/inventoryTypes/inventoryTypes";
import { logger } from "@/src/utils/logger"; import { logger } from "@/src/utils/logger";
import { RequestHandler } from "express"; import { RequestHandler } from "express";
@ -269,7 +270,7 @@ interface INemesisStartRequest {
WeaponIdx: number; WeaponIdx: number;
AgentIdx: number; AgentIdx: number;
BirthNode: string; BirthNode: string;
Faction: string; Faction: TNemesisFaction;
Rank: number; Rank: number;
k: boolean; k: boolean;
Traded: boolean; Traded: boolean;

View File

@ -1,5 +1,5 @@
import { ExportRegions, ExportWarframes } from "warframe-public-export-plus"; import { ExportRegions, ExportWarframes } from "warframe-public-export-plus";
import { IInfNode, ITypeCount } from "@/src/types/inventoryTypes/inventoryTypes"; import { IInfNode, ITypeCount, TNemesisFaction } from "@/src/types/inventoryTypes/inventoryTypes";
import { getRewardAtPercentage, SRng } from "@/src/services/rngService"; import { getRewardAtPercentage, SRng } from "@/src/services/rngService";
import { TInventoryDatabaseDocument } from "../models/inventoryModels/inventoryModel"; import { TInventoryDatabaseDocument } from "../models/inventoryModels/inventoryModel";
import { logger } from "../utils/logger"; import { logger } from "../utils/logger";
@ -11,7 +11,7 @@ import { fromStoreItem, toStoreItem } from "../services/itemDataService";
import { createMessage } from "../services/inboxService"; import { createMessage } from "../services/inboxService";
import { version_compare } from "./inventoryHelpers"; import { version_compare } from "./inventoryHelpers";
export const getInfNodes = (faction: string, rank: number): IInfNode[] => { export const getInfNodes = (faction: TNemesisFaction, rank: number): IInfNode[] => {
const infNodes = []; const infNodes = [];
const systemIndex = systemIndexes[faction][rank]; const systemIndex = systemIndexes[faction][rank];
for (const [key, value] of Object.entries(ExportRegions)) { for (const [key, value] of Object.entries(ExportRegions)) {
@ -35,20 +35,20 @@ export const getInfNodes = (faction: string, rank: number): IInfNode[] => {
return infNodes; return infNodes;
}; };
const systemIndexes: Record<string, number[]> = { const systemIndexes: Record<TNemesisFaction, number[]> = {
FC_GRINEER: [2, 3, 9, 11, 18], FC_GRINEER: [2, 3, 9, 11, 18],
FC_CORPUS: [1, 15, 4, 7, 8], FC_CORPUS: [1, 15, 4, 7, 8],
FC_INFESTATION: [23] FC_INFESTATION: [23]
}; };
export const showdownNodes: Record<string, string> = { export const showdownNodes: Record<TNemesisFaction, string> = {
FC_GRINEER: "CrewBattleNode557", FC_GRINEER: "CrewBattleNode557",
FC_CORPUS: "CrewBattleNode558", FC_CORPUS: "CrewBattleNode558",
FC_INFESTATION: "CrewBattleNode559" FC_INFESTATION: "CrewBattleNode559"
}; };
// Get a parazon 'passcode' based on the nemesis fingerprint so it's always the same for the same nemesis. // Get a parazon 'passcode' based on the nemesis fingerprint so it's always the same for the same nemesis.
export const getNemesisPasscode = (nemesis: { fp: bigint; Faction: string }): number[] => { export const getNemesisPasscode = (nemesis: { fp: bigint; Faction: TNemesisFaction }): number[] => {
const rng = new SRng(nemesis.fp); const rng = new SRng(nemesis.fp);
const choices = [0, 1, 2, 3, 5, 6, 7]; const choices = [0, 1, 2, 3, 5, 6, 7];
let choiceIndex = rng.randomInt(0, choices.length - 1); let choiceIndex = rng.randomInt(0, choices.length - 1);
@ -87,7 +87,7 @@ const antivirusMods: readonly string[] = [
"/Lotus/Upgrades/Mods/Immortal/AntivirusEightMod" "/Lotus/Upgrades/Mods/Immortal/AntivirusEightMod"
]; ];
export const getNemesisPasscodeModTypes = (nemesis: { fp: bigint; Faction: string }): string[] => { export const getNemesisPasscodeModTypes = (nemesis: { fp: bigint; Faction: TNemesisFaction }): string[] => {
const passcode = getNemesisPasscode(nemesis); const passcode = getNemesisPasscode(nemesis);
return nemesis.Faction == "FC_INFESTATION" return nemesis.Faction == "FC_INFESTATION"
? passcode.map(i => antivirusMods[i]) ? passcode.map(i => antivirusMods[i])
@ -248,7 +248,7 @@ export const getWeaponsForManifest = (manifest: string): readonly string[] => {
}; };
export const isNemesisCompatibleWithVersion = ( export const isNemesisCompatibleWithVersion = (
nemesis: { manifest: string; Faction: string }, nemesis: { manifest: string; Faction: TNemesisFaction },
buildLabel: string buildLabel: string
): boolean => { ): boolean => {
// Anything below 35.6.0 is not going to be okay given our set of supported manifests. // Anything below 35.6.0 is not going to be okay given our set of supported manifests.

View File

@ -1585,12 +1585,17 @@ export const addMiscItems = (inventory: TInventoryDatabaseDocument, itemsArray:
if (MiscItems[itemIndex].ItemCount == 0) { if (MiscItems[itemIndex].ItemCount == 0) {
MiscItems.splice(itemIndex, 1); MiscItems.splice(itemIndex, 1);
} else if (MiscItems[itemIndex].ItemCount <= 0) { } else if (MiscItems[itemIndex].ItemCount <= 0) {
logger.warn(`account now owns a negative amount of ${ItemType}`); logger.warn(`inventory.MiscItems has a negative count for ${ItemType}`);
} }
}); });
}; };
const applyArrayChanges = (arr: ITypeCount[], changes: ITypeCount[]): void => { const applyArrayChanges = (
inventory: TInventoryDatabaseDocument,
key: "ShipDecorations" | "Consumables" | "CrewShipRawSalvage" | "CrewShipAmmo" | "Recipes" | "LevelKeys",
changes: ITypeCount[]
): void => {
const arr: ITypeCount[] = inventory[key];
for (const change of changes) { for (const change of changes) {
if (change.ItemCount != 0) { if (change.ItemCount != 0) {
let itemIndex = arr.findIndex(x => x.ItemType === change.ItemType); let itemIndex = arr.findIndex(x => x.ItemType === change.ItemType);
@ -1602,34 +1607,34 @@ const applyArrayChanges = (arr: ITypeCount[], changes: ITypeCount[]): void => {
if (arr[itemIndex].ItemCount == 0) { if (arr[itemIndex].ItemCount == 0) {
arr.splice(itemIndex, 1); arr.splice(itemIndex, 1);
} else if (arr[itemIndex].ItemCount <= 0) { } else if (arr[itemIndex].ItemCount <= 0) {
logger.warn(`account now owns a negative amount of ${change.ItemType}`); logger.warn(`inventory.${key} has a negative count for ${change.ItemType}`);
} }
} }
} }
}; };
export const addShipDecorations = (inventory: TInventoryDatabaseDocument, itemsArray: ITypeCount[]): void => { export const addShipDecorations = (inventory: TInventoryDatabaseDocument, itemsArray: ITypeCount[]): void => {
applyArrayChanges(inventory.ShipDecorations, itemsArray); applyArrayChanges(inventory, "ShipDecorations", itemsArray);
}; };
export const addConsumables = (inventory: TInventoryDatabaseDocument, itemsArray: ITypeCount[]): void => { export const addConsumables = (inventory: TInventoryDatabaseDocument, itemsArray: ITypeCount[]): void => {
applyArrayChanges(inventory.Consumables, itemsArray); applyArrayChanges(inventory, "Consumables", itemsArray);
}; };
export const addCrewShipRawSalvage = (inventory: TInventoryDatabaseDocument, itemsArray: ITypeCount[]): void => { export const addCrewShipRawSalvage = (inventory: TInventoryDatabaseDocument, itemsArray: ITypeCount[]): void => {
applyArrayChanges(inventory.CrewShipRawSalvage, itemsArray); applyArrayChanges(inventory, "CrewShipRawSalvage", itemsArray);
}; };
export const addCrewShipAmmo = (inventory: TInventoryDatabaseDocument, itemsArray: ITypeCount[]): void => { export const addCrewShipAmmo = (inventory: TInventoryDatabaseDocument, itemsArray: ITypeCount[]): void => {
applyArrayChanges(inventory.CrewShipAmmo, itemsArray); applyArrayChanges(inventory, "CrewShipAmmo", itemsArray);
}; };
export const addRecipes = (inventory: TInventoryDatabaseDocument, itemsArray: ITypeCount[]): void => { export const addRecipes = (inventory: TInventoryDatabaseDocument, itemsArray: ITypeCount[]): void => {
applyArrayChanges(inventory.Recipes, itemsArray); applyArrayChanges(inventory, "Recipes", itemsArray);
}; };
export const addLevelKeys = (inventory: TInventoryDatabaseDocument, itemsArray: ITypeCount[]): void => { export const addLevelKeys = (inventory: TInventoryDatabaseDocument, itemsArray: ITypeCount[]): void => {
applyArrayChanges(inventory.LevelKeys, itemsArray); applyArrayChanges(inventory, "LevelKeys", itemsArray);
}; };
export const addMods = (inventory: TInventoryDatabaseDocument, itemsArray: IRawUpgrade[]): void => { export const addMods = (inventory: TInventoryDatabaseDocument, itemsArray: IRawUpgrade[]): void => {
@ -1649,7 +1654,7 @@ export const addMods = (inventory: TInventoryDatabaseDocument, itemsArray: IRawU
if (RawUpgrades[itemIndex].ItemCount == 0) { if (RawUpgrades[itemIndex].ItemCount == 0) {
RawUpgrades.splice(itemIndex, 1); RawUpgrades.splice(itemIndex, 1);
} else if (RawUpgrades[itemIndex].ItemCount <= 0) { } else if (RawUpgrades[itemIndex].ItemCount <= 0) {
logger.warn(`account now owns a negative amount of ${ItemType}`); logger.warn(`inventory.RawUpgrades has a negative count for ${ItemType}`);
} }
}); });
}; };
@ -1664,7 +1669,7 @@ export const addFusionTreasures = (inventory: TInventoryDatabaseDocument, itemsA
if (FusionTreasures[itemIndex].ItemCount == 0) { if (FusionTreasures[itemIndex].ItemCount == 0) {
FusionTreasures.splice(itemIndex, 1); FusionTreasures.splice(itemIndex, 1);
} else if (FusionTreasures[itemIndex].ItemCount <= 0) { } else if (FusionTreasures[itemIndex].ItemCount <= 0) {
logger.warn(`account now owns a negative amount of ${ItemType}`); logger.warn(`inventory.FusionTreasures has a negative count for ${ItemType}`);
} }
} else { } else {
FusionTreasures.push({ ItemCount, ItemType, Sockets }); FusionTreasures.push({ ItemCount, ItemType, Sockets });

View File

@ -825,6 +825,13 @@ const hexConquestRewards: IConquestReward[] = [
} }
]; ];
const droptableAliases: Record<string, string> = {
"/Lotus/Types/DropTables/ManInTheWall/MITWGruzzlingArcanesDropTable":
"/Lotus/Types/DropTables/EntratiLabDropTables/DoppelgangerDropTable",
"/Lotus/Types/DropTables/WF1999DropTables/LasrianTankSteelPathDropTable":
"/Lotus/Types/DropTables/WF1999DropTables/LasrianTankHardModeDropTable"
};
//TODO: return type of partial missioninventoryupdate response //TODO: return type of partial missioninventoryupdate response
export const addMissionRewards = async ( export const addMissionRewards = async (
inventory: TInventoryDatabaseDocument, inventory: TInventoryDatabaseDocument,
@ -1033,11 +1040,9 @@ export const addMissionRewards = async (
if (strippedItems) { if (strippedItems) {
for (const si of strippedItems) { for (const si of strippedItems) {
if (si.DropTable == "/Lotus/Types/DropTables/ManInTheWall/MITWGruzzlingArcanesDropTable") { if (si.DropTable in droptableAliases) {
logger.debug( logger.debug(`rewriting ${si.DropTable} to ${droptableAliases[si.DropTable]}`);
`rewriting ${si.DropTable} to /Lotus/Types/DropTables/EntratiLabDropTables/DoppelgangerDropTable` si.DropTable = droptableAliases[si.DropTable];
);
si.DropTable = "/Lotus/Types/DropTables/EntratiLabDropTables/DoppelgangerDropTable";
} }
const droptables = ExportEnemies.droptables[si.DropTable] ?? []; const droptables = ExportEnemies.droptables[si.DropTable] ?? [];
if (si.DROP_MOD) { if (si.DROP_MOD) {
@ -1517,7 +1522,7 @@ function getRandomMissionDrops(
ZarimanSyndicate: [ ZarimanSyndicate: [
"/Lotus/Types/Game/MissionDecks/ZarimanJobMissionRewards/TierATableRewards", "/Lotus/Types/Game/MissionDecks/ZarimanJobMissionRewards/TierATableRewards",
"/Lotus/Types/Game/MissionDecks/ZarimanJobMissionRewards/TierBTableRewards", "/Lotus/Types/Game/MissionDecks/ZarimanJobMissionRewards/TierBTableRewards",
"/Lotus/Types/Game/MissionDecks/ZarimanJobMissionRewards/TierCTableRewards", "/Lotus/Types/Game/MissionDecks/ZarimanJobMissionRewards/TierCTableARewards", // [sic]
"/Lotus/Types/Game/MissionDecks/ZarimanJobMissionRewards/TierDTableRewards", "/Lotus/Types/Game/MissionDecks/ZarimanJobMissionRewards/TierDTableRewards",
"/Lotus/Types/Game/MissionDecks/ZarimanJobMissionRewards/TierETableRewards" "/Lotus/Types/Game/MissionDecks/ZarimanJobMissionRewards/TierETableRewards"
], ],

View File

@ -863,6 +863,8 @@ export interface IMission extends IMissionDatabase {
RewardsCooldownTime?: IMongoDate; RewardsCooldownTime?: IMongoDate;
} }
export type TNemesisFaction = "FC_GRINEER" | "FC_CORPUS" | "FC_INFESTATION";
export interface INemesisBaseClient { export interface INemesisBaseClient {
fp: bigint | number; fp: bigint | number;
manifest: string; manifest: string;
@ -872,7 +874,7 @@ export interface INemesisBaseClient {
WeaponIdx: number; WeaponIdx: number;
AgentIdx: number; AgentIdx: number;
BirthNode: string; BirthNode: string;
Faction: string; Faction: TNemesisFaction;
Rank: number; Rank: number;
k: boolean; k: boolean;
Traded: boolean; Traded: boolean;

View File

@ -132,7 +132,7 @@ dict = {
cheats_infiniteRegalAya: `Unendlich Reines Aya`, cheats_infiniteRegalAya: `Unendlich Reines Aya`,
cheats_infiniteHelminthMaterials: `Unendlich Helminth-Materialien`, cheats_infiniteHelminthMaterials: `Unendlich Helminth-Materialien`,
cheats_claimingBlueprintRefundsIngredients: `Fertige Blaupausen erstatten Ressourcen zurück`, cheats_claimingBlueprintRefundsIngredients: `Fertige Blaupausen erstatten Ressourcen zurück`,
cheats_dontSubtractVoidTraces: `[UNTRANSLATED] Don't Subtract Void Traces`, cheats_dontSubtractVoidTraces: `Void-Spuren nicht verbrauchen`,
cheats_dontSubtractConsumables: `Verbrauchsgegenstände (Ausrüstung) nicht verbrauchen`, cheats_dontSubtractConsumables: `Verbrauchsgegenstände (Ausrüstung) nicht verbrauchen`,
cheats_unlockAllShipFeatures: `Alle Schiffs-Funktionen freischalten`, cheats_unlockAllShipFeatures: `Alle Schiffs-Funktionen freischalten`,
cheats_unlockAllShipDecorations: `Alle Schiffsdekorationen freischalten`, cheats_unlockAllShipDecorations: `Alle Schiffsdekorationen freischalten`,

View File

@ -132,7 +132,7 @@ dict = {
cheats_infiniteRegalAya: `Aya Real infinita`, cheats_infiniteRegalAya: `Aya Real infinita`,
cheats_infiniteHelminthMaterials: `Materiales Helminto infinitos`, cheats_infiniteHelminthMaterials: `Materiales Helminto infinitos`,
cheats_claimingBlueprintRefundsIngredients: `Reclamar ingredientes devueltos por planos`, cheats_claimingBlueprintRefundsIngredients: `Reclamar ingredientes devueltos por planos`,
cheats_dontSubtractVoidTraces: `[UNTRANSLATED] Don't Subtract Void Traces`, cheats_dontSubtractVoidTraces: `No descontar vestigios del Vacío`,
cheats_dontSubtractConsumables: `No restar consumibles`, cheats_dontSubtractConsumables: `No restar consumibles`,
cheats_unlockAllShipFeatures: `Desbloquear todas las funciones de nave`, cheats_unlockAllShipFeatures: `Desbloquear todas las funciones de nave`,
cheats_unlockAllShipDecorations: `Desbloquear todas las decoraciones de nave`, cheats_unlockAllShipDecorations: `Desbloquear todas las decoraciones de nave`,