chore: update docker stuff #1961
							
								
								
									
										8
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										8
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							@ -18,7 +18,7 @@
 | 
			
		||||
        "morgan": "^1.10.0",
 | 
			
		||||
        "ncp": "^2.0.0",
 | 
			
		||||
        "typescript": "^5.5",
 | 
			
		||||
        "warframe-public-export-plus": "^0.5.58",
 | 
			
		||||
        "warframe-public-export-plus": "^0.5.59",
 | 
			
		||||
        "warframe-riven-info": "^0.1.2",
 | 
			
		||||
        "winston": "^3.17.0",
 | 
			
		||||
        "winston-daily-rotate-file": "^5.0.0"
 | 
			
		||||
@ -3789,9 +3789,9 @@
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/warframe-public-export-plus": {
 | 
			
		||||
      "version": "0.5.58",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.58.tgz",
 | 
			
		||||
      "integrity": "sha512-2G3tKcoblUl7S3Rkk5k/qH+VGZBUmU2QjtIrEO/Bt6UlgO83s648elkNdDKOLBKXnxIsa194nVwz+ci1K86sXg=="
 | 
			
		||||
      "version": "0.5.59",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.59.tgz",
 | 
			
		||||
      "integrity": "sha512-/SUCVjngVDBz6gahz7CdVLywtHLODL6O5nmNtQcxFDUwrUGnF1lETcG8/UO+WLeGxBVAy4BDPbq+9ZWlYZM4uQ=="
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/warframe-riven-info": {
 | 
			
		||||
      "version": "0.1.2",
 | 
			
		||||
 | 
			
		||||
@ -25,7 +25,7 @@
 | 
			
		||||
    "morgan": "^1.10.0",
 | 
			
		||||
    "ncp": "^2.0.0",
 | 
			
		||||
    "typescript": "^5.5",
 | 
			
		||||
    "warframe-public-export-plus": "^0.5.58",
 | 
			
		||||
    "warframe-public-export-plus": "^0.5.59",
 | 
			
		||||
    "warframe-riven-info": "^0.1.2",
 | 
			
		||||
    "winston": "^3.17.0",
 | 
			
		||||
    "winston-daily-rotate-file": "^5.0.0"
 | 
			
		||||
 | 
			
		||||
@ -13,6 +13,7 @@ import { addItems, combineInventoryChanges, getInventory } from "@/src/services/
 | 
			
		||||
import { logger } from "@/src/utils/logger";
 | 
			
		||||
import { ExportFlavour, ExportGear } from "warframe-public-export-plus";
 | 
			
		||||
import { handleStoreItemAcquisition } from "@/src/services/purchaseService";
 | 
			
		||||
import { fromStoreItem, isStoreItem } from "@/src/services/itemDataService";
 | 
			
		||||
 | 
			
		||||
export const inboxController: RequestHandler = async (req, res) => {
 | 
			
		||||
    const { deleteId, lastMessage: latestClientMessageId, messageId } = req.query;
 | 
			
		||||
@ -48,7 +49,7 @@ export const inboxController: RequestHandler = async (req, res) => {
 | 
			
		||||
            await addItems(
 | 
			
		||||
                inventory,
 | 
			
		||||
                attachmentItems.map(attItem => ({
 | 
			
		||||
                    ItemType: attItem,
 | 
			
		||||
                    ItemType: isStoreItem(attItem) ? fromStoreItem(attItem) : attItem,
 | 
			
		||||
                    ItemCount: attItem in ExportGear ? (ExportGear[attItem].purchaseQuantity ?? 1) : 1
 | 
			
		||||
                })),
 | 
			
		||||
                inventoryChanges
 | 
			
		||||
 | 
			
		||||
@ -18,10 +18,12 @@ import {
 | 
			
		||||
    addMiscItems,
 | 
			
		||||
    allDailyAffiliationKeys,
 | 
			
		||||
    cleanupInventory,
 | 
			
		||||
    createLibraryDailyTask
 | 
			
		||||
    createLibraryDailyTask,
 | 
			
		||||
    generateRewardSeed
 | 
			
		||||
} from "@/src/services/inventoryService";
 | 
			
		||||
import { logger } from "@/src/utils/logger";
 | 
			
		||||
import { catBreadHash } from "@/src/helpers/stringHelpers";
 | 
			
		||||
import { Types } from "mongoose";
 | 
			
		||||
 | 
			
		||||
export const inventoryController: RequestHandler = async (request, response) => {
 | 
			
		||||
    const accountId = await getAccountIdForRequest(request);
 | 
			
		||||
@ -87,7 +89,7 @@ export const inventoryController: RequestHandler = async (request, response) =>
 | 
			
		||||
        cleanupInventory(inventory);
 | 
			
		||||
 | 
			
		||||
        inventory.NextRefill = new Date((Math.trunc(Date.now() / 86400000) + 1) * 86400000);
 | 
			
		||||
        await inventory.save();
 | 
			
		||||
        //await inventory.save();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (
 | 
			
		||||
@ -96,9 +98,20 @@ export const inventoryController: RequestHandler = async (request, response) =>
 | 
			
		||||
        new Date() >= inventory.InfestedFoundry.AbilityOverrideUnlockCooldown
 | 
			
		||||
    ) {
 | 
			
		||||
        handleSubsumeCompletion(inventory);
 | 
			
		||||
        await inventory.save();
 | 
			
		||||
        //await inventory.save();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (inventory.LastInventorySync) {
 | 
			
		||||
        const lastSyncDuviriMood = Math.trunc(inventory.LastInventorySync.getTimestamp().getTime() / 7200000);
 | 
			
		||||
        const currentDuviriMood = Math.trunc(Date.now() / 7200000);
 | 
			
		||||
        if (lastSyncDuviriMood != currentDuviriMood) {
 | 
			
		||||
            logger.debug(`refreshing duviri seed`);
 | 
			
		||||
            inventory.DuviriInfo.Seed = generateRewardSeed();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    inventory.LastInventorySync = new Types.ObjectId();
 | 
			
		||||
    await inventory.save();
 | 
			
		||||
 | 
			
		||||
    response.json(await getInventoryResponse(inventory, "xpBasedLevelCapDisabled" in request.query));
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -274,7 +287,7 @@ export const getInventoryResponse = async (
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Omitting this field so opening the navigation resyncs the inventory which is more desirable for typical usage.
 | 
			
		||||
    //inventoryResponse.LastInventorySync = toOid(new Types.ObjectId());
 | 
			
		||||
    inventoryResponse.LastInventorySync = undefined;
 | 
			
		||||
 | 
			
		||||
    // Set 2FA enabled so trading post can be used
 | 
			
		||||
    inventoryResponse.HWIDProtectEnabled = true;
 | 
			
		||||
 | 
			
		||||
@ -2,9 +2,12 @@ import {
 | 
			
		||||
    consumeModCharge,
 | 
			
		||||
    encodeNemesisGuess,
 | 
			
		||||
    getInfNodes,
 | 
			
		||||
    getKnifeUpgrade,
 | 
			
		||||
    getNemesisPasscode,
 | 
			
		||||
    getNemesisPasscodeModTypes,
 | 
			
		||||
    getWeaponsForManifest,
 | 
			
		||||
    IKnifeResponse
 | 
			
		||||
    IKnifeResponse,
 | 
			
		||||
    showdownNodes
 | 
			
		||||
} from "@/src/helpers/nemesisHelpers";
 | 
			
		||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
 | 
			
		||||
import { Loadout } from "@/src/models/inventoryModels/loadoutModel";
 | 
			
		||||
@ -15,6 +18,8 @@ import { IMongoDate, IOid } from "@/src/types/commonTypes";
 | 
			
		||||
import { IEquipmentClient } from "@/src/types/inventoryTypes/commonInventoryTypes";
 | 
			
		||||
import {
 | 
			
		||||
    IInnateDamageFingerprint,
 | 
			
		||||
    IInventoryClient,
 | 
			
		||||
    INemesisClient,
 | 
			
		||||
    InventorySlot,
 | 
			
		||||
    IUpgradeClient,
 | 
			
		||||
    IWeaponSkinClient,
 | 
			
		||||
@ -100,50 +105,45 @@ export const nemesisController: RequestHandler = async (req, res) => {
 | 
			
		||||
                encodeNemesisGuess(guess[0], result1, guess[1], result2, guess[2], result3)
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            // Increase antivirus
 | 
			
		||||
            let antivirusGain = 5;
 | 
			
		||||
            const loadout = (await Loadout.findById(inventory.LoadOutPresets, "DATAKNIFE"))!;
 | 
			
		||||
            const dataknifeLoadout = loadout.DATAKNIFE.id(inventory.CurrentLoadOutIds[LoadoutIndex.DATAKNIFE].$oid);
 | 
			
		||||
            const dataknifeConfigIndex = dataknifeLoadout?.s?.mod ?? 0;
 | 
			
		||||
            const dataknifeUpgrades = inventory.DataKnives[0].Configs[dataknifeConfigIndex].Upgrades!;
 | 
			
		||||
            // Increase antivirus if correct antivirus mod is installed
 | 
			
		||||
            const response: IKnifeResponse = {};
 | 
			
		||||
            for (const upgrade of body.knife!.AttachedUpgrades) {
 | 
			
		||||
                switch (upgrade.ItemType) {
 | 
			
		||||
                    case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusAndSpeedOnUseMod":
 | 
			
		||||
                        antivirusGain += 10;
 | 
			
		||||
                        consumeModCharge(response, inventory, upgrade, dataknifeUpgrades);
 | 
			
		||||
                        break;
 | 
			
		||||
                    case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusAndWeaponDamageOnUseMod":
 | 
			
		||||
                        antivirusGain += 10;
 | 
			
		||||
                        consumeModCharge(response, inventory, upgrade, dataknifeUpgrades);
 | 
			
		||||
                        break;
 | 
			
		||||
                    case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusLargeOnSingleUseMod": // Instant Secure
 | 
			
		||||
                        antivirusGain += 15;
 | 
			
		||||
                        consumeModCharge(response, inventory, upgrade, dataknifeUpgrades);
 | 
			
		||||
                        break;
 | 
			
		||||
                    case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusOnUseMod": // Immuno Shield
 | 
			
		||||
                        antivirusGain += 15;
 | 
			
		||||
                        consumeModCharge(response, inventory, upgrade, dataknifeUpgrades);
 | 
			
		||||
                        break;
 | 
			
		||||
                    case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusSmallOnSingleUseMod":
 | 
			
		||||
                        antivirusGain += 10;
 | 
			
		||||
                        consumeModCharge(response, inventory, upgrade, dataknifeUpgrades);
 | 
			
		||||
                        break;
 | 
			
		||||
            if (result1 == 0 || result2 == 0 || result3 == 0) {
 | 
			
		||||
                let antivirusGain = 5;
 | 
			
		||||
                const loadout = (await Loadout.findById(inventory.LoadOutPresets, "DATAKNIFE"))!;
 | 
			
		||||
                const dataknifeLoadout = loadout.DATAKNIFE.id(inventory.CurrentLoadOutIds[LoadoutIndex.DATAKNIFE].$oid);
 | 
			
		||||
                const dataknifeConfigIndex = dataknifeLoadout?.s?.mod ?? 0;
 | 
			
		||||
                const dataknifeUpgrades = inventory.DataKnives[0].Configs[dataknifeConfigIndex].Upgrades!;
 | 
			
		||||
                for (const upgrade of body.knife!.AttachedUpgrades) {
 | 
			
		||||
                    switch (upgrade.ItemType) {
 | 
			
		||||
                        case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusAndSpeedOnUseMod":
 | 
			
		||||
                            antivirusGain += 10;
 | 
			
		||||
                            consumeModCharge(response, inventory, upgrade, dataknifeUpgrades);
 | 
			
		||||
                            break;
 | 
			
		||||
                        case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusAndWeaponDamageOnUseMod":
 | 
			
		||||
                            antivirusGain += 10;
 | 
			
		||||
                            consumeModCharge(response, inventory, upgrade, dataknifeUpgrades);
 | 
			
		||||
                            break;
 | 
			
		||||
                        case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusLargeOnSingleUseMod": // Instant Secure
 | 
			
		||||
                            antivirusGain += 15;
 | 
			
		||||
                            consumeModCharge(response, inventory, upgrade, dataknifeUpgrades);
 | 
			
		||||
                            break;
 | 
			
		||||
                        case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusOnUseMod": // Immuno Shield
 | 
			
		||||
                            antivirusGain += 15;
 | 
			
		||||
                            consumeModCharge(response, inventory, upgrade, dataknifeUpgrades);
 | 
			
		||||
                            break;
 | 
			
		||||
                        case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusSmallOnSingleUseMod":
 | 
			
		||||
                            antivirusGain += 10;
 | 
			
		||||
                            consumeModCharge(response, inventory, upgrade, dataknifeUpgrades);
 | 
			
		||||
                            break;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                inventory.Nemesis!.HenchmenKilled += antivirusGain;
 | 
			
		||||
            }
 | 
			
		||||
            inventory.Nemesis!.HenchmenKilled += antivirusGain;
 | 
			
		||||
 | 
			
		||||
            if (inventory.Nemesis!.HenchmenKilled >= 100) {
 | 
			
		||||
                inventory.Nemesis!.HenchmenKilled = 100;
 | 
			
		||||
                inventory.Nemesis!.InfNodes = [
 | 
			
		||||
                    {
 | 
			
		||||
                        Node: "CrewBattleNode559",
 | 
			
		||||
                        Influence: 1
 | 
			
		||||
                    }
 | 
			
		||||
                ];
 | 
			
		||||
                inventory.Nemesis!.Weakened = true;
 | 
			
		||||
            } else {
 | 
			
		||||
                inventory.Nemesis!.InfNodes = getInfNodes("FC_INFESTATION", 0);
 | 
			
		||||
            }
 | 
			
		||||
            inventory.Nemesis!.InfNodes = getInfNodes("FC_INFESTATION", 0);
 | 
			
		||||
 | 
			
		||||
            await inventory.save();
 | 
			
		||||
            res.json(response);
 | 
			
		||||
@ -213,6 +213,38 @@ export const nemesisController: RequestHandler = async (req, res) => {
 | 
			
		||||
        res.json({
 | 
			
		||||
            target: inventory.toJSON().Nemesis
 | 
			
		||||
        });
 | 
			
		||||
    } else if ((req.query.mode as string) == "w") {
 | 
			
		||||
        const inventory = await getInventory(
 | 
			
		||||
            accountId,
 | 
			
		||||
            "Nemesis LoadOutPresets CurrentLoadOutIds DataKnives Upgrades RawUpgrades"
 | 
			
		||||
        );
 | 
			
		||||
        //const body = getJSONfromString<INemesisWeakenRequest>(String(req.body));
 | 
			
		||||
 | 
			
		||||
        inventory.Nemesis!.InfNodes = [
 | 
			
		||||
            {
 | 
			
		||||
                Node: showdownNodes[inventory.Nemesis!.Faction],
 | 
			
		||||
                Influence: 1
 | 
			
		||||
            }
 | 
			
		||||
        ];
 | 
			
		||||
        inventory.Nemesis!.Weakened = true;
 | 
			
		||||
 | 
			
		||||
        const response: IKnifeResponse & { target: INemesisClient } = {
 | 
			
		||||
            target: inventory.toJSON<IInventoryClient>().Nemesis!
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // Consume charge of the correct requiem mod(s)
 | 
			
		||||
        const loadout = (await Loadout.findById(inventory.LoadOutPresets, "DATAKNIFE"))!;
 | 
			
		||||
        const dataknifeLoadout = loadout.DATAKNIFE.id(inventory.CurrentLoadOutIds[LoadoutIndex.DATAKNIFE].$oid);
 | 
			
		||||
        const dataknifeConfigIndex = dataknifeLoadout?.s?.mod ?? 0;
 | 
			
		||||
        const dataknifeUpgrades = inventory.DataKnives[0].Configs[dataknifeConfigIndex].Upgrades!;
 | 
			
		||||
        const modTypes = getNemesisPasscodeModTypes(inventory.Nemesis!);
 | 
			
		||||
        for (const modType of modTypes) {
 | 
			
		||||
            const upgrade = getKnifeUpgrade(inventory, dataknifeUpgrades, modType);
 | 
			
		||||
            consumeModCharge(response, inventory, upgrade, dataknifeUpgrades);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        await inventory.save();
 | 
			
		||||
        res.json(response);
 | 
			
		||||
    } else {
 | 
			
		||||
        logger.debug(`data provided to ${req.path}: ${String(req.body)}`);
 | 
			
		||||
        throw new Error(`unknown nemesis mode: ${String(req.query.mode)}`);
 | 
			
		||||
@ -264,12 +296,19 @@ interface INemesisRequiemRequest {
 | 
			
		||||
    guess: number; // grn/crp: 4 bits | coda: 3x 4 bits
 | 
			
		||||
    position: number; // grn/crp: 0-2 | coda: 0
 | 
			
		||||
    // knife field provided for coda only
 | 
			
		||||
    knife?: {
 | 
			
		||||
        Item: IEquipmentClient;
 | 
			
		||||
        Skins: IWeaponSkinClient[];
 | 
			
		||||
        ModSlot: number;
 | 
			
		||||
        CustSlot: number;
 | 
			
		||||
        AttachedUpgrades: IUpgradeClient[];
 | 
			
		||||
        HiddenWhenHolstered: boolean;
 | 
			
		||||
    };
 | 
			
		||||
    knife?: IKnife;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// interface INemesisWeakenRequest {
 | 
			
		||||
//     target: INemesisClient;
 | 
			
		||||
//     knife: IKnife;
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
interface IKnife {
 | 
			
		||||
    Item: IEquipmentClient;
 | 
			
		||||
    Skins: IWeaponSkinClient[];
 | 
			
		||||
    ModSlot: number;
 | 
			
		||||
    CustSlot: number;
 | 
			
		||||
    AttachedUpgrades: IUpgradeClient[];
 | 
			
		||||
    HiddenWhenHolstered: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,12 +1,14 @@
 | 
			
		||||
import { ExportRegions, ExportWarframes } from "warframe-public-export-plus";
 | 
			
		||||
import { IInfNode } from "@/src/types/inventoryTypes/inventoryTypes";
 | 
			
		||||
import { SRng } from "@/src/services/rngService";
 | 
			
		||||
import { IInfNode, ITypeCount } from "@/src/types/inventoryTypes/inventoryTypes";
 | 
			
		||||
import { getRewardAtPercentage, SRng } from "@/src/services/rngService";
 | 
			
		||||
import { TInventoryDatabaseDocument } from "../models/inventoryModels/inventoryModel";
 | 
			
		||||
import { logger } from "../utils/logger";
 | 
			
		||||
import { IOid } from "../types/commonTypes";
 | 
			
		||||
import { Types } from "mongoose";
 | 
			
		||||
import { addMods } from "../services/inventoryService";
 | 
			
		||||
import { addMods, generateRewardSeed } from "../services/inventoryService";
 | 
			
		||||
import { isArchwingMission } from "../services/worldStateService";
 | 
			
		||||
import { fromStoreItem, toStoreItem } from "../services/itemDataService";
 | 
			
		||||
import { createMessage } from "../services/inboxService";
 | 
			
		||||
 | 
			
		||||
export const getInfNodes = (faction: string, rank: number): IInfNode[] => {
 | 
			
		||||
    const infNodes = [];
 | 
			
		||||
@ -38,17 +40,59 @@ const systemIndexes: Record<string, number[]> = {
 | 
			
		||||
    FC_INFESTATION: [23]
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const showdownNodes: Record<string, string> = {
 | 
			
		||||
    FC_GRINEER: "CrewBattleNode557",
 | 
			
		||||
    FC_CORPUS: "CrewBattleNode558",
 | 
			
		||||
    FC_INFESTATION: "CrewBattleNode559"
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// 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[] => {
 | 
			
		||||
    const rng = new SRng(nemesis.fp);
 | 
			
		||||
    const passcode = [rng.randomInt(0, 7)];
 | 
			
		||||
    const choices = [0, 1, 2, 3, 5, 6, 7];
 | 
			
		||||
    let choiceIndex = rng.randomInt(0, choices.length - 1);
 | 
			
		||||
    const passcode = [choices[choiceIndex]];
 | 
			
		||||
    if (nemesis.Faction != "FC_INFESTATION") {
 | 
			
		||||
        passcode.push(rng.randomInt(0, 7));
 | 
			
		||||
        passcode.push(rng.randomInt(0, 7));
 | 
			
		||||
        choices.splice(choiceIndex, 1);
 | 
			
		||||
        choiceIndex = rng.randomInt(0, choices.length - 1);
 | 
			
		||||
        passcode.push(choices[choiceIndex]);
 | 
			
		||||
 | 
			
		||||
        choices.splice(choiceIndex, 1);
 | 
			
		||||
        choiceIndex = rng.randomInt(0, choices.length - 1);
 | 
			
		||||
        passcode.push(choices[choiceIndex]);
 | 
			
		||||
    }
 | 
			
		||||
    return passcode;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const reqiuemMods: readonly string[] = [
 | 
			
		||||
    "/Lotus/Upgrades/Mods/Immortal/ImmortalOneMod",
 | 
			
		||||
    "/Lotus/Upgrades/Mods/Immortal/ImmortalTwoMod",
 | 
			
		||||
    "/Lotus/Upgrades/Mods/Immortal/ImmortalThreeMod",
 | 
			
		||||
    "/Lotus/Upgrades/Mods/Immortal/ImmortalFourMod",
 | 
			
		||||
    "/Lotus/Upgrades/Mods/Immortal/ImmortalFiveMod",
 | 
			
		||||
    "/Lotus/Upgrades/Mods/Immortal/ImmortalSixMod",
 | 
			
		||||
    "/Lotus/Upgrades/Mods/Immortal/ImmortalSevenMod",
 | 
			
		||||
    "/Lotus/Upgrades/Mods/Immortal/ImmortalEightMod"
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
const antivirusMods: readonly string[] = [
 | 
			
		||||
    "/Lotus/Upgrades/Mods/Immortal/AntivirusOneMod",
 | 
			
		||||
    "/Lotus/Upgrades/Mods/Immortal/AntivirusTwoMod",
 | 
			
		||||
    "/Lotus/Upgrades/Mods/Immortal/AntivirusThreeMod",
 | 
			
		||||
    "/Lotus/Upgrades/Mods/Immortal/AntivirusFourMod",
 | 
			
		||||
    "/Lotus/Upgrades/Mods/Immortal/AntivirusFiveMod",
 | 
			
		||||
    "/Lotus/Upgrades/Mods/Immortal/AntivirusSixMod",
 | 
			
		||||
    "/Lotus/Upgrades/Mods/Immortal/AntivirusSevenMod",
 | 
			
		||||
    "/Lotus/Upgrades/Mods/Immortal/AntivirusEightMod"
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
export const getNemesisPasscodeModTypes = (nemesis: { fp: bigint; Faction: string }): string[] => {
 | 
			
		||||
    const passcode = getNemesisPasscode(nemesis);
 | 
			
		||||
    return nemesis.Faction == "FC_INFESTATION"
 | 
			
		||||
        ? passcode.map(i => antivirusMods[i])
 | 
			
		||||
        : passcode.map(i => reqiuemMods[i]);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const encodeNemesisGuess = (
 | 
			
		||||
    symbol1: number,
 | 
			
		||||
    result1: number,
 | 
			
		||||
@ -79,6 +123,31 @@ export interface IKnifeResponse {
 | 
			
		||||
    HasKnife?: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const getKnifeUpgrade = (
 | 
			
		||||
    inventory: TInventoryDatabaseDocument,
 | 
			
		||||
    dataknifeUpgrades: string[],
 | 
			
		||||
    type: string
 | 
			
		||||
): { ItemId: IOid; ItemType: string } => {
 | 
			
		||||
    if (dataknifeUpgrades.indexOf(type) != -1) {
 | 
			
		||||
        return {
 | 
			
		||||
            ItemId: { $oid: "000000000000000000000000" },
 | 
			
		||||
            ItemType: type
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
    for (const upgradeId of dataknifeUpgrades) {
 | 
			
		||||
        if (upgradeId.length == 24) {
 | 
			
		||||
            const upgrade = inventory.Upgrades.id(upgradeId);
 | 
			
		||||
            if (upgrade && upgrade.ItemType == type) {
 | 
			
		||||
                return {
 | 
			
		||||
                    ItemId: { $oid: upgradeId },
 | 
			
		||||
                    ItemType: type
 | 
			
		||||
                };
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    throw new Error(`${type} does not seem to be installed on parazon?!`);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const consumeModCharge = (
 | 
			
		||||
    response: IKnifeResponse,
 | 
			
		||||
    inventory: TInventoryDatabaseDocument,
 | 
			
		||||
@ -177,7 +246,6 @@ export const getWeaponsForManifest = (manifest: string): readonly string[] => {
 | 
			
		||||
    throw new Error(`unknown nemesis manifest: ${manifest}`);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// TODO: This sucks.
 | 
			
		||||
export const getInnateDamageTag = (
 | 
			
		||||
    KillingSuit: string
 | 
			
		||||
):
 | 
			
		||||
@ -188,78 +256,7 @@ export const getInnateDamageTag = (
 | 
			
		||||
    | "InnateMagDamage"
 | 
			
		||||
    | "InnateRadDamage"
 | 
			
		||||
    | "InnateToxinDamage" => {
 | 
			
		||||
    const baseSuitType = ExportWarframes[KillingSuit].parentName;
 | 
			
		||||
    switch (baseSuitType) {
 | 
			
		||||
        case "/Lotus/Powersuits/Volt/VoltBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Excalibur/ExcaliburBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/AntiMatter/NovaBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Banshee/BansheeBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Berserker/BerserkerBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Magician/MagicianBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Sentient/SentientBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Gyre/GyreBaseSuit":
 | 
			
		||||
            return "InnateElectricityDamage";
 | 
			
		||||
        case "/Lotus/Powersuits/Ember/EmberBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Dragon/DragonBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Nezha/NezhaBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Sandman/SandmanBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Trapper/TrapperBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Wisp/WispBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Odalisk/OdaliskBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/PaxDuviricus/PaxDuviricusBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Choir/ChoirBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Temple/TempleBaseSuit":
 | 
			
		||||
            return "InnateHeatDamage";
 | 
			
		||||
        case "/Lotus/Powersuits/Frost/FrostBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Glass/GlassBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Fairy/FairyBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/IronFrame/IronFrameBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Revenant/RevenantBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Trinity/TrinityBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Hoplite/HopliteBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Koumei/KoumeiBaseSuit":
 | 
			
		||||
            return "InnateFreezeDamage";
 | 
			
		||||
        case "/Lotus/Powersuits/Saryn/SarynBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Paladin/PaladinBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Brawler/BrawlerBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Infestation/InfestationBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Necro/NecroBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Khora/KhoraBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Ranger/RangerBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Dagath/DagathBaseSuit":
 | 
			
		||||
            return "InnateToxinDamage";
 | 
			
		||||
        case "/Lotus/Powersuits/Mag/MagBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Pirate/PirateBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Cowgirl/CowgirlBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Priest/PriestBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/BrokenFrame/BrokenFrameBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Alchemist/AlchemistBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Yareli/YareliBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Geode/GeodeBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Frumentarius/FrumentariusBaseSuit":
 | 
			
		||||
            return "InnateMagDamage";
 | 
			
		||||
        case "/Lotus/Powersuits/Loki/LokiBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Ninja/NinjaBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Jade/JadeBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Bard/BardBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Harlequin/HarlequinBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Garuda/GarudaBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/YinYang/YinYangBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Werewolf/WerewolfBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/ConcreteFrame/ConcreteFrameBaseSuit":
 | 
			
		||||
            return "InnateRadDamage";
 | 
			
		||||
        case "/Lotus/Powersuits/Rhino/RhinoBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Tengu/TenguBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/MonkeyKing/MonkeyKingBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Runner/RunnerBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Pacifist/PacifistBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Devourer/DevourerBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Wraith/WraithBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Pagemaster/PagemasterBaseSuit":
 | 
			
		||||
            return "InnateImpactDamage";
 | 
			
		||||
    }
 | 
			
		||||
    logger.warn(`unknown innate damage type for ${KillingSuit}, using heat as a fallback`);
 | 
			
		||||
    return "InnateHeatDamage";
 | 
			
		||||
    return ExportWarframes[KillingSuit].nemesisUpgradeTag!;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// TODO: For -1399275245665749231n, the value should be 75306944, but we're off by 59 with 75307003.
 | 
			
		||||
@ -273,3 +270,109 @@ export const getInnateDamageValue = (fp: bigint): number => {
 | 
			
		||||
    }
 | 
			
		||||
    return Math.trunc(value * 0x40000000);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const getKillTokenRewardCount = (fp: bigint): number => {
 | 
			
		||||
    const rng = new SRng(fp);
 | 
			
		||||
    return rng.randomInt(10, 15);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// /Lotus/Types/Enemies/InfestedLich/InfestedLichRewardManifest
 | 
			
		||||
const infestedLichRotA = [
 | 
			
		||||
    { type: "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyDJRomHuman", probability: 0.046 },
 | 
			
		||||
    { type: "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyDJRomInfested", probability: 0.045 },
 | 
			
		||||
    { type: "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyDrillbitHuman", probability: 0.046 },
 | 
			
		||||
    { type: "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyDrillbitInfested", probability: 0.045 },
 | 
			
		||||
    { type: "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyHarddriveHuman", probability: 0.046 },
 | 
			
		||||
    { type: "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyHarddriveInfested", probability: 0.045 },
 | 
			
		||||
    { type: "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyPacketHuman", probability: 0.046 },
 | 
			
		||||
    { type: "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyPacketInfested", probability: 0.045 },
 | 
			
		||||
    { type: "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyZekeHuman", probability: 0.046 },
 | 
			
		||||
    { type: "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyZekeInfested", probability: 0.045 },
 | 
			
		||||
    { type: "/Lotus/StoreItems/Types/Items/ShipDecos/BoybandPosters/BoybandBillboardPosterA", probability: 0.045 },
 | 
			
		||||
    { type: "/Lotus/StoreItems/Types/Items/ShipDecos/BoybandPosters/BoybandBillboardPosterB", probability: 0.046 },
 | 
			
		||||
    { type: "/Lotus/StoreItems/Types/Items/ShipDecos/BoybandPosters/BoybandDespairPoster", probability: 0.045 },
 | 
			
		||||
    { type: "/Lotus/StoreItems/Types/Items/ShipDecos/BoybandPosters/BoybandGridPoster", probability: 0.046 },
 | 
			
		||||
    { type: "/Lotus/StoreItems/Types/Items/ShipDecos/BoybandPosters/BoybandHuddlePoster", probability: 0.045 },
 | 
			
		||||
    { type: "/Lotus/StoreItems/Types/Items/ShipDecos/BoybandPosters/BoybandJumpPoster", probability: 0.046 },
 | 
			
		||||
    { type: "/Lotus/StoreItems/Types/Items/ShipDecos/BoybandPosters/BoybandLimoPoster", probability: 0.045 },
 | 
			
		||||
    { type: "/Lotus/StoreItems/Types/Items/ShipDecos/BoybandPosters/BoybandLookingDownPosterDay", probability: 0.046 },
 | 
			
		||||
    {
 | 
			
		||||
        type: "/Lotus/StoreItems/Types/Items/ShipDecos/BoybandPosters/BoybandLookingDownPosterNight",
 | 
			
		||||
        probability: 0.045
 | 
			
		||||
    },
 | 
			
		||||
    { type: "/Lotus/StoreItems/Types/Items/ShipDecos/BoybandPosters/BoybandSillyPoster", probability: 0.046 },
 | 
			
		||||
    { type: "/Lotus/StoreItems/Types/Items/ShipDecos/BoybandPosters/BoybandWhiteBluePoster", probability: 0.045 },
 | 
			
		||||
    { type: "/Lotus/StoreItems/Types/Items/ShipDecos/BoybandPosters/BoybandWhitePinkPoster", probability: 0.045 }
 | 
			
		||||
];
 | 
			
		||||
const infestedLichRotB = [
 | 
			
		||||
    { type: "/Lotus/StoreItems/Upgrades/Skins/Effects/InfestedLichEphemeraA", probability: 0.072 },
 | 
			
		||||
    { type: "/Lotus/StoreItems/Upgrades/Skins/Effects/InfestedLichEphemeraB", probability: 0.071 },
 | 
			
		||||
    { type: "/Lotus/StoreItems/Upgrades/Skins/Effects/InfestedLichEphemeraC", probability: 0.072 },
 | 
			
		||||
    { type: "/Lotus/StoreItems/Upgrades/Skins/Effects/InfestedLichEphemeraD", probability: 0.071 },
 | 
			
		||||
    { type: "/Lotus/StoreItems/Upgrades/Skins/Effects/InfestedLichEphemeraE", probability: 0.072 },
 | 
			
		||||
    { type: "/Lotus/StoreItems/Upgrades/Skins/Effects/InfestedLichEphemeraF", probability: 0.071 },
 | 
			
		||||
    { type: "/Lotus/StoreItems/Upgrades/Skins/Effects/InfestedLichEphemeraG", probability: 0.071 },
 | 
			
		||||
    { type: "/Lotus/StoreItems/Upgrades/Skins/Effects/InfestedLichEphemeraH", probability: 0.072 },
 | 
			
		||||
    { type: "/Lotus/StoreItems/Types/Items/Emotes/DanceDJRomHype", probability: 0.071 },
 | 
			
		||||
    { type: "/Lotus/StoreItems/Types/Items/Emotes/DancePacketWindmillShuffle", probability: 0.072 },
 | 
			
		||||
    { type: "/Lotus/StoreItems/Types/Items/Emotes/DanceHarddrivePony", probability: 0.071 },
 | 
			
		||||
    { type: "/Lotus/StoreItems/Types/Items/Emotes/DanceDrillbitCrisscross", probability: 0.072 },
 | 
			
		||||
    { type: "/Lotus/StoreItems/Types/Items/Emotes/DanceZekeCanthavethis", probability: 0.071 },
 | 
			
		||||
    { type: "/Lotus/StoreItems/Types/Items/PhotoBooth/PhotoboothTileRJLasXStadiumBossArena", probability: 0.071 }
 | 
			
		||||
];
 | 
			
		||||
export const getInfestedLichItemRewards = (fp: bigint): string[] => {
 | 
			
		||||
    const rng = new SRng(fp);
 | 
			
		||||
    const rotAReward = getRewardAtPercentage(infestedLichRotA, rng.randomFloat())!.type;
 | 
			
		||||
    rng.randomFloat(); // unused afaict
 | 
			
		||||
    const rotBReward = getRewardAtPercentage(infestedLichRotB, rng.randomFloat())!.type;
 | 
			
		||||
    return [rotAReward, rotBReward];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const sendCodaFinishedMessage = async (
 | 
			
		||||
    inventory: TInventoryDatabaseDocument,
 | 
			
		||||
    fp: bigint = generateRewardSeed(),
 | 
			
		||||
    name: string = "ZEKE_BEATWOMAN_TM.1999",
 | 
			
		||||
    killed: boolean = true
 | 
			
		||||
): Promise<void> => {
 | 
			
		||||
    const att: string[] = [];
 | 
			
		||||
 | 
			
		||||
    // First vanquish/convert gives a sigil
 | 
			
		||||
    const sigil = killed
 | 
			
		||||
        ? "/Lotus/Upgrades/Skins/Sigils/InfLichVanquishedSigil"
 | 
			
		||||
        : "/Lotus/Upgrades/Skins/Sigils/InfLichConvertedSigil";
 | 
			
		||||
    if (!inventory.WeaponSkins.find(x => x.ItemType == sigil)) {
 | 
			
		||||
        att.push(toStoreItem(sigil));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const [rotAReward, rotBReward] = getInfestedLichItemRewards(fp);
 | 
			
		||||
    att.push(fromStoreItem(rotAReward));
 | 
			
		||||
    att.push(fromStoreItem(rotBReward));
 | 
			
		||||
 | 
			
		||||
    let countedAtt: ITypeCount[] | undefined;
 | 
			
		||||
    if (killed) {
 | 
			
		||||
        countedAtt = [
 | 
			
		||||
            {
 | 
			
		||||
                ItemType: "/Lotus/Types/Items/MiscItems/CodaWeaponBucks",
 | 
			
		||||
                ItemCount: getKillTokenRewardCount(fp)
 | 
			
		||||
            }
 | 
			
		||||
        ];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    await createMessage(inventory.accountOwnerId, [
 | 
			
		||||
        {
 | 
			
		||||
            sndr: "/Lotus/Language/Bosses/Ordis",
 | 
			
		||||
            msg: "/Lotus/Language/Inbox/VanquishBandMsgBody",
 | 
			
		||||
            arg: [
 | 
			
		||||
                {
 | 
			
		||||
                    Key: "LICH_NAME",
 | 
			
		||||
                    Tag: name
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            att: att,
 | 
			
		||||
            countedAtt: countedAtt,
 | 
			
		||||
            sub: "/Lotus/Language/Inbox/VanquishBandMsgTitle",
 | 
			
		||||
            icon: "/Lotus/Interface/Icons/Npcs/Ordis.png",
 | 
			
		||||
            highPriority: true
 | 
			
		||||
        }
 | 
			
		||||
    ]);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -1399,7 +1399,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
 | 
			
		||||
        //How many Gift do you have left*(gift spends the trade)
 | 
			
		||||
        GiftsRemaining: { type: Number, default: 8 },
 | 
			
		||||
        //Curent trade info Giving or Getting items
 | 
			
		||||
        PendingTrades: [Schema.Types.Mixed],
 | 
			
		||||
        //PendingTrades: [Schema.Types.Mixed],
 | 
			
		||||
 | 
			
		||||
        //Syndicate currently being pledged to.
 | 
			
		||||
        SupportedSyndicate: String,
 | 
			
		||||
@ -1449,7 +1449,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
 | 
			
		||||
 | 
			
		||||
        KubrowPetEggs: [kubrowPetEggSchema],
 | 
			
		||||
        //Prints   Cat(3 Prints)\Kubrow(2 Prints) Pets
 | 
			
		||||
        KubrowPetPrints: [Schema.Types.Mixed],
 | 
			
		||||
        //KubrowPetPrints: [Schema.Types.Mixed],
 | 
			
		||||
 | 
			
		||||
        //Item for EquippedGear example:Scaner,LoadoutTechSummon etc
 | 
			
		||||
        Consumables: [typeCountSchema],
 | 
			
		||||
@ -1495,7 +1495,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
 | 
			
		||||
        //item like DojoKey or Boss missions key
 | 
			
		||||
        LevelKeys: [typeCountSchema],
 | 
			
		||||
        //Active quests
 | 
			
		||||
        Quests: [Schema.Types.Mixed],
 | 
			
		||||
        //Quests: [Schema.Types.Mixed],
 | 
			
		||||
 | 
			
		||||
        //Cosmetics like profile glyphs\Kavasa Prime Kubrow Collar\Game Theme etc
 | 
			
		||||
        FlavourItems: [FlavourItemSchema],
 | 
			
		||||
@ -1534,7 +1534,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
 | 
			
		||||
        TauntHistory: { type: [tauntSchema], default: undefined },
 | 
			
		||||
 | 
			
		||||
        //noShow2FA,VisitPrimeVault etc
 | 
			
		||||
        WebFlags: Schema.Types.Mixed,
 | 
			
		||||
        //WebFlags: Schema.Types.Mixed,
 | 
			
		||||
        //Id CompletedAlerts
 | 
			
		||||
        CompletedAlerts: [String],
 | 
			
		||||
 | 
			
		||||
@ -1554,7 +1554,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
 | 
			
		||||
        //the color your clan requests like Items/Research/DojoColors/DojoColorPlainsB
 | 
			
		||||
        ActiveDojoColorResearch: String,
 | 
			
		||||
 | 
			
		||||
        SentientSpawnChanceBoosters: Schema.Types.Mixed,
 | 
			
		||||
        //SentientSpawnChanceBoosters: Schema.Types.Mixed,
 | 
			
		||||
 | 
			
		||||
        QualifyingInvasions: [invasionProgressSchema],
 | 
			
		||||
        FactionScores: [Number],
 | 
			
		||||
@ -1589,10 +1589,10 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
 | 
			
		||||
        // open location store like EidolonPlainsDiscoverable or OrbVallisCaveDiscoverable
 | 
			
		||||
        DiscoveredMarkers: [discoveredMarkerSchema],
 | 
			
		||||
        //Open location mission like "JobId" + "StageCompletions"
 | 
			
		||||
        CompletedJobs: [Schema.Types.Mixed],
 | 
			
		||||
        //CompletedJobs: [Schema.Types.Mixed],
 | 
			
		||||
 | 
			
		||||
        //Game mission\ivent score example  "Tag": "WaterFight", "Best": 170, "Count": 1258,
 | 
			
		||||
        PersonalGoalProgress: [Schema.Types.Mixed],
 | 
			
		||||
        //PersonalGoalProgress: [Schema.Types.Mixed],
 | 
			
		||||
 | 
			
		||||
        //Setting interface Style
 | 
			
		||||
        ThemeStyle: String,
 | 
			
		||||
@ -1622,13 +1622,13 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
 | 
			
		||||
        LibraryActiveDailyTaskInfo: libraryDailyTaskInfoSchema,
 | 
			
		||||
 | 
			
		||||
        //https://warframe.fandom.com/wiki/Invasion
 | 
			
		||||
        InvasionChainProgress: [Schema.Types.Mixed],
 | 
			
		||||
        //InvasionChainProgress: [Schema.Types.Mixed],
 | 
			
		||||
 | 
			
		||||
        //CorpusLich or GrineerLich
 | 
			
		||||
        NemesisAbandonedRewards: { type: [String], default: [] },
 | 
			
		||||
        Nemesis: nemesisSchema,
 | 
			
		||||
        NemesisHistory: { type: [nemesisSchema], default: undefined },
 | 
			
		||||
        LastNemesisAllySpawnTime: Schema.Types.Mixed,
 | 
			
		||||
        //LastNemesisAllySpawnTime: Schema.Types.Mixed,
 | 
			
		||||
 | 
			
		||||
        //TradingRulesConfirmed,ShowFriendInvNotifications(Option->Social)
 | 
			
		||||
        Settings: settingsSchema,
 | 
			
		||||
@ -1642,7 +1642,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
 | 
			
		||||
        PlayerSkills: { type: playerSkillsSchema, default: {} },
 | 
			
		||||
 | 
			
		||||
        //TradeBannedUntil data
 | 
			
		||||
        TradeBannedUntil: Schema.Types.Mixed,
 | 
			
		||||
        //TradeBannedUntil: Schema.Types.Mixed,
 | 
			
		||||
 | 
			
		||||
        //https://warframe.fandom.com/wiki/Helminth
 | 
			
		||||
        InfestedFoundry: infestedFoundrySchema,
 | 
			
		||||
@ -1662,23 +1662,24 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
 | 
			
		||||
 | 
			
		||||
        //Unknown and system
 | 
			
		||||
        DuviriInfo: DuviriInfoSchema,
 | 
			
		||||
        LastInventorySync: Schema.Types.ObjectId,
 | 
			
		||||
        Mailbox: MailboxSchema,
 | 
			
		||||
        HandlerPoints: Number,
 | 
			
		||||
        ChallengesFixVersion: { type: Number, default: 6 },
 | 
			
		||||
        PlayedParkourTutorial: Boolean,
 | 
			
		||||
        ActiveLandscapeTraps: [Schema.Types.Mixed],
 | 
			
		||||
        RepVotes: [Schema.Types.Mixed],
 | 
			
		||||
        LeagueTickets: [Schema.Types.Mixed],
 | 
			
		||||
        //ActiveLandscapeTraps: [Schema.Types.Mixed],
 | 
			
		||||
        //RepVotes: [Schema.Types.Mixed],
 | 
			
		||||
        //LeagueTickets: [Schema.Types.Mixed],
 | 
			
		||||
        HasContributedToDojo: Boolean,
 | 
			
		||||
        HWIDProtectEnabled: Boolean,
 | 
			
		||||
        LoadOutPresets: { type: Schema.Types.ObjectId, ref: "Loadout" },
 | 
			
		||||
        CurrentLoadOutIds: [oidSchema],
 | 
			
		||||
        RandomUpgradesIdentified: Number,
 | 
			
		||||
        BountyScore: Number,
 | 
			
		||||
        ChallengeInstanceStates: [Schema.Types.Mixed],
 | 
			
		||||
        //ChallengeInstanceStates: [Schema.Types.Mixed],
 | 
			
		||||
        RecentVendorPurchases: { type: [recentVendorPurchaseSchema], default: undefined },
 | 
			
		||||
        Robotics: [Schema.Types.Mixed],
 | 
			
		||||
        UsedDailyDeals: [Schema.Types.Mixed],
 | 
			
		||||
        //Robotics: [Schema.Types.Mixed],
 | 
			
		||||
        //UsedDailyDeals: [Schema.Types.Mixed],
 | 
			
		||||
        CollectibleSeries: { type: [collectibleEntrySchema], default: undefined },
 | 
			
		||||
        HasResetAccount: { type: Boolean, default: false },
 | 
			
		||||
 | 
			
		||||
@ -1759,6 +1760,9 @@ inventorySchema.set("toJSON", {
 | 
			
		||||
                sn: inventoryDatabase.LockedWeaponGroup.sn ? toOid(inventoryDatabase.LockedWeaponGroup.sn) : undefined
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
        if (inventoryDatabase.LastInventorySync) {
 | 
			
		||||
            inventoryResponse.LastInventorySync = toOid(inventoryDatabase.LastInventorySync);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -17,6 +17,7 @@ import {
 | 
			
		||||
    dict_uk,
 | 
			
		||||
    dict_zh,
 | 
			
		||||
    ExportArcanes,
 | 
			
		||||
    ExportBoosters,
 | 
			
		||||
    ExportCustoms,
 | 
			
		||||
    ExportDrones,
 | 
			
		||||
    ExportGear,
 | 
			
		||||
@ -217,15 +218,30 @@ export const convertInboxMessage = (message: IInboxMessage): IMessage => {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const isStoreItem = (type: string): boolean => {
 | 
			
		||||
    return type.startsWith("/Lotus/StoreItems/");
 | 
			
		||||
    return type.startsWith("/Lotus/StoreItems/") || type in ExportBoosters;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const toStoreItem = (type: string): string => {
 | 
			
		||||
    if (type.startsWith("/Lotus/Types/StoreItems/Boosters/")) {
 | 
			
		||||
        const boosterEntry = Object.entries(ExportBoosters).find(arr => arr[1].typeName == type);
 | 
			
		||||
        if (boosterEntry) {
 | 
			
		||||
            return boosterEntry[0];
 | 
			
		||||
        }
 | 
			
		||||
        throw new Error(`could not convert ${type} to a store item`);
 | 
			
		||||
    }
 | 
			
		||||
    return "/Lotus/StoreItems/" + type.substring("/Lotus/".length);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const fromStoreItem = (type: string): string => {
 | 
			
		||||
    return "/Lotus/" + type.substring("/Lotus/StoreItems/".length);
 | 
			
		||||
    if (type.startsWith("/Lotus/StoreItems/")) {
 | 
			
		||||
        return "/Lotus/" + type.substring("/Lotus/StoreItems/".length);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (type in ExportBoosters) {
 | 
			
		||||
        return ExportBoosters[type].typeName;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    throw new Error(`${type} is not a store item`);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const getDefaultUpgrades = (parts: string[]): IDefaultUpgrade[] | undefined => {
 | 
			
		||||
 | 
			
		||||
@ -77,7 +77,6 @@ const getRandomLoginReward = (rng: CRng, day: number, inventory: TInventoryDatab
 | 
			
		||||
    const reward = rng.randomReward(randomRewards)!;
 | 
			
		||||
    //const reward = randomRewards.find(x => x.RewardType == "RT_BOOSTER")!;
 | 
			
		||||
    if (reward.RewardType == "RT_RANDOM_RECIPE") {
 | 
			
		||||
        // Not very faithful implementation but roughly the same idea
 | 
			
		||||
        const masteredItems = new Set();
 | 
			
		||||
        for (const entry of inventory.XPInfo) {
 | 
			
		||||
            masteredItems.add(entry.ItemType);
 | 
			
		||||
@ -95,12 +94,12 @@ const getRandomLoginReward = (rng: CRng, day: number, inventory: TInventoryDatab
 | 
			
		||||
        }
 | 
			
		||||
        const eligibleRecipes: string[] = [];
 | 
			
		||||
        for (const [uniqueName, recipe] of Object.entries(ExportRecipes)) {
 | 
			
		||||
            if (unmasteredItems.has(recipe.resultType)) {
 | 
			
		||||
            if (!recipe.excludeFromMarket && unmasteredItems.has(recipe.resultType)) {
 | 
			
		||||
                eligibleRecipes.push(uniqueName);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (eligibleRecipes.length == 0) {
 | 
			
		||||
            // This account has all warframes and weapons already mastered (filthy cheater), need a different reward.
 | 
			
		||||
            // This account has all applicable warframes and weapons already mastered (filthy cheater), need a different reward.
 | 
			
		||||
            return getRandomLoginReward(rng, day, inventory);
 | 
			
		||||
        }
 | 
			
		||||
        reward.StoreItemType = toStoreItem(rng.randomElement(eligibleRecipes));
 | 
			
		||||
 | 
			
		||||
@ -55,7 +55,7 @@ import kuriaMessage50 from "@/static/fixed_responses/kuriaMessages/fiftyPercent.
 | 
			
		||||
import kuriaMessage75 from "@/static/fixed_responses/kuriaMessages/seventyFivePercent.json";
 | 
			
		||||
import kuriaMessage100 from "@/static/fixed_responses/kuriaMessages/oneHundredPercent.json";
 | 
			
		||||
import conservationAnimals from "@/static/fixed_responses/conservationAnimals.json";
 | 
			
		||||
import { getInfNodes, getWeaponsForManifest } from "@/src/helpers/nemesisHelpers";
 | 
			
		||||
import { getInfNodes, getWeaponsForManifest, sendCodaFinishedMessage } from "@/src/helpers/nemesisHelpers";
 | 
			
		||||
import { Loadout } from "../models/inventoryModels/loadoutModel";
 | 
			
		||||
import { ILoadoutConfigDatabase } from "../types/saveLoadoutTypes";
 | 
			
		||||
import { getLiteSortie, getWorldState, idToWeek } from "./worldStateService";
 | 
			
		||||
@ -639,7 +639,10 @@ export const addMissionInventoryUpdates = async (
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                    if (value.killed) {
 | 
			
		||||
                        if (value.weaponLoc) {
 | 
			
		||||
                        if (
 | 
			
		||||
                            value.weaponLoc &&
 | 
			
		||||
                            inventory.Nemesis.Faction != "FC_INFESTATION" // weaponLoc is "/Lotus/Language/Weapons/DerelictCernosName" for these for some reason
 | 
			
		||||
                        ) {
 | 
			
		||||
                            const weaponType = getWeaponsForManifest(inventory.Nemesis.manifest)[
 | 
			
		||||
                                inventory.Nemesis.WeaponIdx
 | 
			
		||||
                            ];
 | 
			
		||||
@ -657,6 +660,11 @@ export const addMissionInventoryUpdates = async (
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    // TOVERIFY: Is the inbox message also sent when converting a lich? If not, how are the rewards given?
 | 
			
		||||
                    if (inventory.Nemesis.Faction == "FC_INFESTATION") {
 | 
			
		||||
                        await sendCodaFinishedMessage(inventory, inventory.Nemesis.fp, value.nemesisName, value.killed);
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    inventory.Nemesis = undefined;
 | 
			
		||||
                }
 | 
			
		||||
                break;
 | 
			
		||||
 | 
			
		||||
@ -18,7 +18,10 @@ export const getRandomInt = (min: number, max: number): number => {
 | 
			
		||||
    return Math.floor(Math.random() * (max - min + 1)) + min;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const getRewardAtPercentage = <T extends { probability: number }>(pool: T[], percentage: number): T | undefined => {
 | 
			
		||||
export const getRewardAtPercentage = <T extends { probability: number }>(
 | 
			
		||||
    pool: T[],
 | 
			
		||||
    percentage: number
 | 
			
		||||
): T | undefined => {
 | 
			
		||||
    if (pool.length == 0) return;
 | 
			
		||||
 | 
			
		||||
    const totalChance = pool.reduce((accum, item) => accum + item.probability, 0);
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,5 @@
 | 
			
		||||
import { unixTimesInMs } from "@/src/constants/timeConstants";
 | 
			
		||||
import { catBreadHash } from "@/src/helpers/stringHelpers";
 | 
			
		||||
import { CRng, mixSeeds } from "@/src/services/rngService";
 | 
			
		||||
import { IMongoDate } from "@/src/types/commonTypes";
 | 
			
		||||
import { IItemManifest, IVendorInfo, IVendorManifest } from "@/src/types/vendorTypes";
 | 
			
		||||
@ -6,7 +7,6 @@ import { ExportVendors, IRange } from "warframe-public-export-plus";
 | 
			
		||||
 | 
			
		||||
import ArchimedeanVendorManifest from "@/static/fixed_responses/getVendorInfo/ArchimedeanVendorManifest.json";
 | 
			
		||||
import DeimosEntratiFragmentVendorProductsManifest from "@/static/fixed_responses/getVendorInfo/DeimosEntratiFragmentVendorProductsManifest.json";
 | 
			
		||||
import DeimosFishmongerVendorManifest from "@/static/fixed_responses/getVendorInfo/DeimosFishmongerVendorManifest.json";
 | 
			
		||||
import DeimosHivemindCommisionsManifestFishmonger from "@/static/fixed_responses/getVendorInfo/DeimosHivemindCommisionsManifestFishmonger.json";
 | 
			
		||||
import DeimosHivemindCommisionsManifestPetVendor from "@/static/fixed_responses/getVendorInfo/DeimosHivemindCommisionsManifestPetVendor.json";
 | 
			
		||||
import DeimosHivemindCommisionsManifestProspector from "@/static/fixed_responses/getVendorInfo/DeimosHivemindCommisionsManifestProspector.json";
 | 
			
		||||
@ -22,12 +22,10 @@ import HubsIronwakeDondaVendorManifest from "@/static/fixed_responses/getVendorI
 | 
			
		||||
import HubsRailjackCrewMemberVendorManifest from "@/static/fixed_responses/getVendorInfo/HubsRailjackCrewMemberVendorManifest.json";
 | 
			
		||||
import MaskSalesmanManifest from "@/static/fixed_responses/getVendorInfo/MaskSalesmanManifest.json";
 | 
			
		||||
import Nova1999ConquestShopManifest from "@/static/fixed_responses/getVendorInfo/Nova1999ConquestShopManifest.json";
 | 
			
		||||
import OstronFishmongerVendorManifest from "@/static/fixed_responses/getVendorInfo/OstronFishmongerVendorManifest.json";
 | 
			
		||||
import OstronPetVendorManifest from "@/static/fixed_responses/getVendorInfo/OstronPetVendorManifest.json";
 | 
			
		||||
import OstronProspectorVendorManifest from "@/static/fixed_responses/getVendorInfo/OstronProspectorVendorManifest.json";
 | 
			
		||||
import RadioLegionIntermission12VendorManifest from "@/static/fixed_responses/getVendorInfo/RadioLegionIntermission12VendorManifest.json";
 | 
			
		||||
import SolarisDebtTokenVendorRepossessionsManifest from "@/static/fixed_responses/getVendorInfo/SolarisDebtTokenVendorRepossessionsManifest.json";
 | 
			
		||||
import SolarisFishmongerVendorManifest from "@/static/fixed_responses/getVendorInfo/SolarisFishmongerVendorManifest.json";
 | 
			
		||||
import SolarisProspectorVendorManifest from "@/static/fixed_responses/getVendorInfo/SolarisProspectorVendorManifest.json";
 | 
			
		||||
import Temple1999VendorManifest from "@/static/fixed_responses/getVendorInfo/Temple1999VendorManifest.json";
 | 
			
		||||
import TeshinHardModeVendorManifest from "@/static/fixed_responses/getVendorInfo/TeshinHardModeVendorManifest.json";
 | 
			
		||||
@ -36,7 +34,6 @@ import ZarimanCommisionsManifestArchimedean from "@/static/fixed_responses/getVe
 | 
			
		||||
const rawVendorManifests: IVendorManifest[] = [
 | 
			
		||||
    ArchimedeanVendorManifest,
 | 
			
		||||
    DeimosEntratiFragmentVendorProductsManifest,
 | 
			
		||||
    DeimosFishmongerVendorManifest,
 | 
			
		||||
    DeimosHivemindCommisionsManifestFishmonger,
 | 
			
		||||
    DeimosHivemindCommisionsManifestPetVendor,
 | 
			
		||||
    DeimosHivemindCommisionsManifestProspector,
 | 
			
		||||
@ -52,12 +49,10 @@ const rawVendorManifests: IVendorManifest[] = [
 | 
			
		||||
    HubsRailjackCrewMemberVendorManifest,
 | 
			
		||||
    MaskSalesmanManifest,
 | 
			
		||||
    Nova1999ConquestShopManifest,
 | 
			
		||||
    OstronFishmongerVendorManifest,
 | 
			
		||||
    OstronPetVendorManifest,
 | 
			
		||||
    OstronProspectorVendorManifest,
 | 
			
		||||
    RadioLegionIntermission12VendorManifest,
 | 
			
		||||
    SolarisDebtTokenVendorRepossessionsManifest,
 | 
			
		||||
    SolarisFishmongerVendorManifest,
 | 
			
		||||
    SolarisProspectorVendorManifest,
 | 
			
		||||
    Temple1999VendorManifest,
 | 
			
		||||
    TeshinHardModeVendorManifest, // uses preprocessing
 | 
			
		||||
@ -87,17 +82,11 @@ const generatableVendors: IGeneratableVendorInfo[] = [
 | 
			
		||||
        cycleOffset: 1744934400_000,
 | 
			
		||||
        cycleDuration: 4 * unixTimesInMs.day
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        _id: { $oid: "5be4a159b144f3cdf1c22efa" },
 | 
			
		||||
        TypeName: "/Lotus/Types/Game/VendorManifests/Solaris/DebtTokenVendorManifest",
 | 
			
		||||
        RandomSeedType: "VRST_FLAVOUR_TEXT",
 | 
			
		||||
        cycleDuration: unixTimesInMs.hour
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        _id: { $oid: "61ba123467e5d37975aeeb03" },
 | 
			
		||||
        TypeName: "/Lotus/Types/Game/VendorManifests/Hubs/GuildAdvertisementVendorManifest",
 | 
			
		||||
        RandomSeedType: "VRST_FLAVOUR_TEXT",
 | 
			
		||||
        cycleDuration: unixTimesInMs.week
 | 
			
		||||
        cycleDuration: unixTimesInMs.week // TODO: Auto-detect this based on the items, so we don't need to specify it explicitly.
 | 
			
		||||
    }
 | 
			
		||||
    // {
 | 
			
		||||
    //     _id: { $oid: "5dbb4c41e966f7886c3ce939" },
 | 
			
		||||
@ -105,6 +94,10 @@ const generatableVendors: IGeneratableVendorInfo[] = [
 | 
			
		||||
    // }
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
const getVendorOid = (typeName: string): string => {
 | 
			
		||||
    return "5be4a159b144f3cd" + catBreadHash(typeName).toString(16).padStart(8, "0");
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const getVendorManifestByTypeName = (typeName: string): IVendorManifest | undefined => {
 | 
			
		||||
    for (const vendorManifest of rawVendorManifests) {
 | 
			
		||||
        if (vendorManifest.VendorInfo.TypeName == typeName) {
 | 
			
		||||
@ -116,6 +109,14 @@ export const getVendorManifestByTypeName = (typeName: string): IVendorManifest |
 | 
			
		||||
            return generateVendorManifest(vendorInfo);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if (typeName in ExportVendors) {
 | 
			
		||||
        return generateVendorManifest({
 | 
			
		||||
            _id: { $oid: getVendorOid(typeName) },
 | 
			
		||||
            TypeName: typeName,
 | 
			
		||||
            RandomSeedType: ExportVendors[typeName].randomSeedType,
 | 
			
		||||
            cycleDuration: unixTimesInMs.hour
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
    return undefined;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -130,6 +131,17 @@ export const getVendorManifestByOid = (oid: string): IVendorManifest | undefined
 | 
			
		||||
            return generateVendorManifest(vendorInfo);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    for (const [typeName, manifest] of Object.entries(ExportVendors)) {
 | 
			
		||||
        const typeNameOid = getVendorOid(typeName);
 | 
			
		||||
        if (typeNameOid == oid) {
 | 
			
		||||
            return generateVendorManifest({
 | 
			
		||||
                _id: { $oid: typeNameOid },
 | 
			
		||||
                TypeName: typeName,
 | 
			
		||||
                RandomSeedType: manifest.randomSeedType,
 | 
			
		||||
                cycleDuration: unixTimesInMs.hour
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return undefined;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -195,7 +207,7 @@ const generateVendorManifest = (vendorInfo: IGeneratableVendorInfo): IVendorMani
 | 
			
		||||
        const rng = new CRng(mixSeeds(vendorSeed, cycleIndex));
 | 
			
		||||
        const manifest = ExportVendors[vendorInfo.TypeName];
 | 
			
		||||
        const offersToAdd = [];
 | 
			
		||||
        if (manifest.numItems && manifest.numItems.minValue != manifest.numItems.maxValue) {
 | 
			
		||||
        if (manifest.numItems && !manifest.isOneBinPerCycle) {
 | 
			
		||||
            const numItemsTarget = rng.randomInt(manifest.numItems.minValue, manifest.numItems.maxValue);
 | 
			
		||||
            while (processed.ItemManifest.length + offersToAdd.length < numItemsTarget) {
 | 
			
		||||
                // TODO: Consider per-bin item limits
 | 
			
		||||
@ -263,6 +275,13 @@ const generateVendorManifest = (vendorInfo: IGeneratableVendorInfo): IVendorMani
 | 
			
		||||
                          ) * rawItem.credits.step;
 | 
			
		||||
                item.RegularPrice = [value, value];
 | 
			
		||||
            }
 | 
			
		||||
            if (rawItem.platinum) {
 | 
			
		||||
                const value =
 | 
			
		||||
                    typeof rawItem.platinum == "number"
 | 
			
		||||
                        ? rawItem.platinum
 | 
			
		||||
                        : rng.randomInt(rawItem.platinum.minValue, rawItem.platinum.maxValue);
 | 
			
		||||
                item.PremiumPrice = [value, value];
 | 
			
		||||
            }
 | 
			
		||||
            if (vendorInfo.RandomSeedType) {
 | 
			
		||||
                item.LocTagRandSeed = (rng.randomInt(0, 0xffff) << 16) | rng.randomInt(0, 0xffff);
 | 
			
		||||
                if (vendorInfo.RandomSeedType == "VRST_WEAPON") {
 | 
			
		||||
 | 
			
		||||
@ -52,6 +52,7 @@ export interface IInventoryDatabase
 | 
			
		||||
            | "LastLiteSortieReward"
 | 
			
		||||
            | "CrewMembers"
 | 
			
		||||
            | "QualifyingInvasions"
 | 
			
		||||
            | "LastInventorySync"
 | 
			
		||||
            | TEquipmentKey
 | 
			
		||||
        >,
 | 
			
		||||
        InventoryDatabaseEquipment {
 | 
			
		||||
@ -89,6 +90,7 @@ export interface IInventoryDatabase
 | 
			
		||||
    LastLiteSortieReward?: ILastSortieRewardDatabase[];
 | 
			
		||||
    CrewMembers: ICrewMemberDatabase[];
 | 
			
		||||
    QualifyingInvasions: IInvasionProgressDatabase[];
 | 
			
		||||
    LastInventorySync?: Types.ObjectId;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface IQuestKeyDatabase {
 | 
			
		||||
@ -258,7 +260,7 @@ export interface IInventoryClient extends IDailyAffiliations, InventoryClientEqu
 | 
			
		||||
    EquippedGear: string[];
 | 
			
		||||
    DeathMarks: string[];
 | 
			
		||||
    FusionTreasures: IFusionTreasure[];
 | 
			
		||||
    WebFlags: IWebFlags;
 | 
			
		||||
    //WebFlags: IWebFlags;
 | 
			
		||||
    CompletedAlerts: string[];
 | 
			
		||||
    Consumables: ITypeCount[];
 | 
			
		||||
    LevelKeys: ITypeCount[];
 | 
			
		||||
@ -268,10 +270,10 @@ export interface IInventoryClient extends IDailyAffiliations, InventoryClientEqu
 | 
			
		||||
    KubrowPetEggs?: IKubrowPetEggClient[];
 | 
			
		||||
    LoreFragmentScans: ILoreFragmentScan[];
 | 
			
		||||
    EquippedEmotes: string[];
 | 
			
		||||
    PendingTrades: IPendingTrade[];
 | 
			
		||||
    //PendingTrades: IPendingTrade[];
 | 
			
		||||
    Boosters: IBooster[];
 | 
			
		||||
    ActiveDojoColorResearch: string;
 | 
			
		||||
    SentientSpawnChanceBoosters: ISentientSpawnChanceBoosters;
 | 
			
		||||
    //SentientSpawnChanceBoosters: ISentientSpawnChanceBoosters;
 | 
			
		||||
    SupportedSyndicate?: string;
 | 
			
		||||
    Affiliations: IAffiliation[];
 | 
			
		||||
    QualifyingInvasions: IInvasionProgressClient[];
 | 
			
		||||
@ -293,19 +295,19 @@ export interface IInventoryClient extends IDailyAffiliations, InventoryClientEqu
 | 
			
		||||
    ActiveAvatarImageType: string;
 | 
			
		||||
    ShipDecorations: ITypeCount[];
 | 
			
		||||
    DiscoveredMarkers: IDiscoveredMarker[];
 | 
			
		||||
    CompletedJobs: ICompletedJob[];
 | 
			
		||||
    //CompletedJobs: ICompletedJob[];
 | 
			
		||||
    FocusAbility?: string;
 | 
			
		||||
    FocusUpgrades: IFocusUpgrade[];
 | 
			
		||||
    HasContributedToDojo?: boolean;
 | 
			
		||||
    HWIDProtectEnabled?: boolean;
 | 
			
		||||
    KubrowPetPrints: IKubrowPetPrint[];
 | 
			
		||||
    //KubrowPetPrints: IKubrowPetPrint[];
 | 
			
		||||
    AlignmentReplay?: IAlignment;
 | 
			
		||||
    PersonalGoalProgress: IPersonalGoalProgress[];
 | 
			
		||||
    //PersonalGoalProgress: IPersonalGoalProgress[];
 | 
			
		||||
    ThemeStyle: string;
 | 
			
		||||
    ThemeBackground: string;
 | 
			
		||||
    ThemeSounds: string;
 | 
			
		||||
    BountyScore: number;
 | 
			
		||||
    ChallengeInstanceStates: IChallengeInstanceState[];
 | 
			
		||||
    //ChallengeInstanceStates: IChallengeInstanceState[];
 | 
			
		||||
    LoginMilestoneRewards: string[];
 | 
			
		||||
    RecentVendorPurchases?: IRecentVendorPurchaseClient[];
 | 
			
		||||
    NodeIntrosCompleted: string[];
 | 
			
		||||
@ -313,17 +315,17 @@ export interface IInventoryClient extends IDailyAffiliations, InventoryClientEqu
 | 
			
		||||
    CompletedJobChains?: ICompletedJobChain[];
 | 
			
		||||
    SeasonChallengeHistory: ISeasonChallenge[];
 | 
			
		||||
    EquippedInstrument?: string;
 | 
			
		||||
    InvasionChainProgress: IInvasionChainProgress[];
 | 
			
		||||
    //InvasionChainProgress: IInvasionChainProgress[];
 | 
			
		||||
    Nemesis?: INemesisClient;
 | 
			
		||||
    NemesisHistory?: INemesisBaseClient[];
 | 
			
		||||
    LastNemesisAllySpawnTime?: IMongoDate;
 | 
			
		||||
    //LastNemesisAllySpawnTime?: IMongoDate;
 | 
			
		||||
    Settings?: ISettings;
 | 
			
		||||
    PersonalTechProjects: IPersonalTechProjectClient[];
 | 
			
		||||
    PlayerSkills: IPlayerSkills;
 | 
			
		||||
    CrewShipAmmo: ITypeCount[];
 | 
			
		||||
    CrewShipWeaponSkins: IUpgradeClient[];
 | 
			
		||||
    CrewShipSalvagedWeaponSkins: IUpgradeClient[];
 | 
			
		||||
    TradeBannedUntil?: IMongoDate;
 | 
			
		||||
    //TradeBannedUntil?: IMongoDate;
 | 
			
		||||
    PlayedParkourTutorial: boolean;
 | 
			
		||||
    SubscribedToEmailsPersonalized: number;
 | 
			
		||||
    InfestedFoundry?: IInfestedFoundryClient;
 | 
			
		||||
@ -333,17 +335,17 @@ export interface IInventoryClient extends IDailyAffiliations, InventoryClientEqu
 | 
			
		||||
    LotusCustomization?: ILotusCustomization;
 | 
			
		||||
    UseAdultOperatorLoadout?: boolean;
 | 
			
		||||
    NemesisAbandonedRewards: string[];
 | 
			
		||||
    LastInventorySync: IOid;
 | 
			
		||||
    LastInventorySync?: IOid;
 | 
			
		||||
    NextRefill?: IMongoDate;
 | 
			
		||||
    FoundToday?: IMiscItem[]; // for Argon Crystals
 | 
			
		||||
    CustomMarkers?: ICustomMarkers[];
 | 
			
		||||
    ActiveLandscapeTraps: any[];
 | 
			
		||||
    //ActiveLandscapeTraps: any[];
 | 
			
		||||
    EvolutionProgress?: IEvolutionProgress[];
 | 
			
		||||
    RepVotes: any[];
 | 
			
		||||
    LeagueTickets: any[];
 | 
			
		||||
    Quests: any[];
 | 
			
		||||
    Robotics: any[];
 | 
			
		||||
    UsedDailyDeals: any[];
 | 
			
		||||
    //RepVotes: any[];
 | 
			
		||||
    //LeagueTickets: any[];
 | 
			
		||||
    //Quests: any[];
 | 
			
		||||
    //Robotics: any[];
 | 
			
		||||
    //UsedDailyDeals: any[];
 | 
			
		||||
    LibraryPersonalTarget?: string;
 | 
			
		||||
    LibraryPersonalProgress: ILibraryPersonalProgress[];
 | 
			
		||||
    CollectibleSeries?: ICollectibleEntry[];
 | 
			
		||||
 | 
			
		||||
@ -1,106 +0,0 @@
 | 
			
		||||
{
 | 
			
		||||
  "VendorInfo": {
 | 
			
		||||
    "_id": {
 | 
			
		||||
      "$oid": "5f456e01c96976e97d6b8016"
 | 
			
		||||
    },
 | 
			
		||||
    "TypeName": "/Lotus/Types/Game/VendorManifests/Deimos/FishmongerVendorManifest",
 | 
			
		||||
    "ItemManifest": [
 | 
			
		||||
      {
 | 
			
		||||
        "StoreItem": "/Lotus/StoreItems/Types/Items/Fish/Deimos/FishParts/DeimosOrokinFishAPartItem",
 | 
			
		||||
        "PremiumPrice": [9, 9],
 | 
			
		||||
        "Bin": "BIN_1",
 | 
			
		||||
        "QuantityMultiplier": 10,
 | 
			
		||||
        "Expiry": {
 | 
			
		||||
          "$date": {
 | 
			
		||||
            "$numberLong": "9999999000000"
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        "AllowMultipurchase": true,
 | 
			
		||||
        "Id": {
 | 
			
		||||
          "$oid": "66fd60b20ba592c4c95e91b9"
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        "StoreItem": "/Lotus/StoreItems/Types/Items/Fish/Deimos/FishParts/DeimosInfestedFishDPartItem",
 | 
			
		||||
        "PremiumPrice": [17, 17],
 | 
			
		||||
        "Bin": "BIN_0",
 | 
			
		||||
        "QuantityMultiplier": 20,
 | 
			
		||||
        "Expiry": {
 | 
			
		||||
          "$date": {
 | 
			
		||||
            "$numberLong": "9999999000000"
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        "AllowMultipurchase": true,
 | 
			
		||||
        "Id": {
 | 
			
		||||
          "$oid": "66fd60b20ba592c4c95e91ba"
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        "StoreItem": "/Lotus/StoreItems/Types/Items/Fish/Deimos/FishParts/DeimosInfestedFishCPartItem",
 | 
			
		||||
        "PremiumPrice": [10, 10],
 | 
			
		||||
        "Bin": "BIN_1",
 | 
			
		||||
        "QuantityMultiplier": 20,
 | 
			
		||||
        "Expiry": {
 | 
			
		||||
          "$date": {
 | 
			
		||||
            "$numberLong": "9999999000000"
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        "AllowMultipurchase": true,
 | 
			
		||||
        "Id": {
 | 
			
		||||
          "$oid": "66fd60b20ba592c4c95e91bb"
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        "StoreItem": "/Lotus/StoreItems/Types/Items/Fish/Deimos/FishParts/DeimosInfestedFishBPartItem",
 | 
			
		||||
        "PremiumPrice": [6, 6],
 | 
			
		||||
        "Bin": "BIN_0",
 | 
			
		||||
        "QuantityMultiplier": 20,
 | 
			
		||||
        "Expiry": {
 | 
			
		||||
          "$date": {
 | 
			
		||||
            "$numberLong": "9999999000000"
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        "AllowMultipurchase": true,
 | 
			
		||||
        "Id": {
 | 
			
		||||
          "$oid": "66fd60b20ba592c4c95e91bc"
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        "StoreItem": "/Lotus/StoreItems/Types/Items/Fish/Deimos/FishParts/DeimosInfestedFishAPartItem",
 | 
			
		||||
        "PremiumPrice": [5, 5],
 | 
			
		||||
        "Bin": "BIN_0",
 | 
			
		||||
        "QuantityMultiplier": 20,
 | 
			
		||||
        "Expiry": {
 | 
			
		||||
          "$date": {
 | 
			
		||||
            "$numberLong": "9999999000000"
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        "AllowMultipurchase": true,
 | 
			
		||||
        "Id": {
 | 
			
		||||
          "$oid": "66fd60b20ba592c4c95e91bd"
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        "StoreItem": "/Lotus/StoreItems/Types/Items/Fish/Deimos/FishParts/DeimosGenericSharedFishPartItem",
 | 
			
		||||
        "PremiumPrice": [7, 7],
 | 
			
		||||
        "Bin": "BIN_0",
 | 
			
		||||
        "QuantityMultiplier": 20,
 | 
			
		||||
        "Expiry": {
 | 
			
		||||
          "$date": {
 | 
			
		||||
            "$numberLong": "9999999000000"
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        "AllowMultipurchase": true,
 | 
			
		||||
        "Id": {
 | 
			
		||||
          "$oid": "66fd60b20ba592c4c95e91be"
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    ],
 | 
			
		||||
    "PropertyTextHash": "6DF13A7FB573C25B4B4F989CBEFFC615",
 | 
			
		||||
    "Expiry": {
 | 
			
		||||
      "$date": {
 | 
			
		||||
        "$numberLong": "9999999000000"
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -1,106 +0,0 @@
 | 
			
		||||
{
 | 
			
		||||
  "VendorInfo": {
 | 
			
		||||
    "_id": {
 | 
			
		||||
      "$oid": "59d6e27ebcc718474eb17115"
 | 
			
		||||
    },
 | 
			
		||||
    "TypeName": "/Lotus/Types/Game/VendorManifests/Ostron/FishmongerVendorManifest",
 | 
			
		||||
    "ItemManifest": [
 | 
			
		||||
      {
 | 
			
		||||
        "StoreItem": "/Lotus/StoreItems/Types/Items/Fish/Eidolon/FishParts/DayUncommonFishAPartItem",
 | 
			
		||||
        "PremiumPrice": [14, 14],
 | 
			
		||||
        "Bin": "BIN_1",
 | 
			
		||||
        "QuantityMultiplier": 10,
 | 
			
		||||
        "Expiry": {
 | 
			
		||||
          "$date": {
 | 
			
		||||
            "$numberLong": "9999999000000"
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        "AllowMultipurchase": true,
 | 
			
		||||
        "Id": {
 | 
			
		||||
          "$oid": "66fd60b20ba592c4c95e9808"
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        "StoreItem": "/Lotus/StoreItems/Types/Items/Fish/Eidolon/FishParts/BothUncommonFishBPartItem",
 | 
			
		||||
        "PremiumPrice": [12, 12],
 | 
			
		||||
        "Bin": "BIN_1",
 | 
			
		||||
        "QuantityMultiplier": 10,
 | 
			
		||||
        "Expiry": {
 | 
			
		||||
          "$date": {
 | 
			
		||||
            "$numberLong": "9999999000000"
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        "AllowMultipurchase": true,
 | 
			
		||||
        "Id": {
 | 
			
		||||
          "$oid": "66fd60b20ba592c4c95e9809"
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        "StoreItem": "/Lotus/StoreItems/Types/Items/Fish/Eidolon/FishParts/DayCommonFishCPartItem",
 | 
			
		||||
        "PremiumPrice": [8, 8],
 | 
			
		||||
        "Bin": "BIN_0",
 | 
			
		||||
        "QuantityMultiplier": 20,
 | 
			
		||||
        "Expiry": {
 | 
			
		||||
          "$date": {
 | 
			
		||||
            "$numberLong": "9999999000000"
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        "AllowMultipurchase": true,
 | 
			
		||||
        "Id": {
 | 
			
		||||
          "$oid": "66fd60b20ba592c4c95e980a"
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        "StoreItem": "/Lotus/StoreItems/Types/Items/Fish/Eidolon/FishParts/DayCommonFishBPartItem",
 | 
			
		||||
        "PremiumPrice": [7, 7],
 | 
			
		||||
        "Bin": "BIN_0",
 | 
			
		||||
        "QuantityMultiplier": 20,
 | 
			
		||||
        "Expiry": {
 | 
			
		||||
          "$date": {
 | 
			
		||||
            "$numberLong": "9999999000000"
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        "AllowMultipurchase": true,
 | 
			
		||||
        "Id": {
 | 
			
		||||
          "$oid": "66fd60b20ba592c4c95e980b"
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        "StoreItem": "/Lotus/StoreItems/Types/Items/Fish/Eidolon/FishParts/DayCommonFishAPartItem",
 | 
			
		||||
        "PremiumPrice": [10, 10],
 | 
			
		||||
        "Bin": "BIN_0",
 | 
			
		||||
        "QuantityMultiplier": 20,
 | 
			
		||||
        "Expiry": {
 | 
			
		||||
          "$date": {
 | 
			
		||||
            "$numberLong": "9999999000000"
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        "AllowMultipurchase": true,
 | 
			
		||||
        "Id": {
 | 
			
		||||
          "$oid": "66fd60b20ba592c4c95e980c"
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        "StoreItem": "/Lotus/StoreItems/Types/Items/Fish/Eidolon/FishParts/BothCommonFishBPartItem",
 | 
			
		||||
        "PremiumPrice": [8, 8],
 | 
			
		||||
        "Bin": "BIN_0",
 | 
			
		||||
        "QuantityMultiplier": 20,
 | 
			
		||||
        "Expiry": {
 | 
			
		||||
          "$date": {
 | 
			
		||||
            "$numberLong": "9999999000000"
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        "AllowMultipurchase": true,
 | 
			
		||||
        "Id": {
 | 
			
		||||
          "$oid": "66fd60b20ba592c4c95e980d"
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    ],
 | 
			
		||||
    "PropertyTextHash": "CC3B9DAFB38F412998E90A41421A8986",
 | 
			
		||||
    "Expiry": {
 | 
			
		||||
      "$date": {
 | 
			
		||||
        "$numberLong": "9999999000000"
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -1,106 +0,0 @@
 | 
			
		||||
{
 | 
			
		||||
  "VendorInfo": {
 | 
			
		||||
    "_id": {
 | 
			
		||||
      "$oid": "5b0de8556df82a56ea9bae82"
 | 
			
		||||
    },
 | 
			
		||||
    "TypeName": "/Lotus/Types/Game/VendorManifests/Solaris/FishmongerVendorManifest",
 | 
			
		||||
    "ItemManifest": [
 | 
			
		||||
      {
 | 
			
		||||
        "StoreItem": "/Lotus/StoreItems/Types/Items/Fish/Solaris/FishParts/CorpusFishThermalLaserItem",
 | 
			
		||||
        "PremiumPrice": [15, 15],
 | 
			
		||||
        "Bin": "BIN_1",
 | 
			
		||||
        "QuantityMultiplier": 10,
 | 
			
		||||
        "Expiry": {
 | 
			
		||||
          "$date": {
 | 
			
		||||
            "$numberLong": "9999999000000"
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        "AllowMultipurchase": true,
 | 
			
		||||
        "Id": {
 | 
			
		||||
          "$oid": "66fd60b20ba592c4c95e9515"
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        "StoreItem": "/Lotus/StoreItems/Types/Items/Fish/Solaris/FishParts/CorpusFishVenedoCaseItem",
 | 
			
		||||
        "PremiumPrice": [8, 8],
 | 
			
		||||
        "Bin": "BIN_0",
 | 
			
		||||
        "QuantityMultiplier": 20,
 | 
			
		||||
        "Expiry": {
 | 
			
		||||
          "$date": {
 | 
			
		||||
            "$numberLong": "9999999000000"
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        "AllowMultipurchase": true,
 | 
			
		||||
        "Id": {
 | 
			
		||||
          "$oid": "66fd60b20ba592c4c95e9516"
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        "StoreItem": "/Lotus/StoreItems/Types/Items/Fish/Solaris/FishParts/SolarisFishDissipatorCoilItem",
 | 
			
		||||
        "PremiumPrice": [18, 18],
 | 
			
		||||
        "Bin": "BIN_0",
 | 
			
		||||
        "QuantityMultiplier": 20,
 | 
			
		||||
        "Expiry": {
 | 
			
		||||
          "$date": {
 | 
			
		||||
            "$numberLong": "9999999000000"
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        "AllowMultipurchase": true,
 | 
			
		||||
        "Id": {
 | 
			
		||||
          "$oid": "66fd60b20ba592c4c95e9517"
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        "StoreItem": "/Lotus/StoreItems/Types/Items/Fish/Solaris/FishParts/CorpusFishExaBrainItem",
 | 
			
		||||
        "PremiumPrice": [5, 5],
 | 
			
		||||
        "Bin": "BIN_0",
 | 
			
		||||
        "QuantityMultiplier": 20,
 | 
			
		||||
        "Expiry": {
 | 
			
		||||
          "$date": {
 | 
			
		||||
            "$numberLong": "9999999000000"
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        "AllowMultipurchase": true,
 | 
			
		||||
        "Id": {
 | 
			
		||||
          "$oid": "66fd60b20ba592c4c95e9518"
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        "StoreItem": "/Lotus/StoreItems/Types/Items/Fish/Solaris/FishParts/CorpusFishAnoscopicSensorItem",
 | 
			
		||||
        "PremiumPrice": [5, 5],
 | 
			
		||||
        "Bin": "BIN_0",
 | 
			
		||||
        "QuantityMultiplier": 20,
 | 
			
		||||
        "Expiry": {
 | 
			
		||||
          "$date": {
 | 
			
		||||
            "$numberLong": "9999999000000"
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        "AllowMultipurchase": true,
 | 
			
		||||
        "Id": {
 | 
			
		||||
          "$oid": "66fd60b20ba592c4c95e9519"
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        "StoreItem": "/Lotus/StoreItems/Types/Items/Fish/Solaris/FishParts/GenericFishScrapItem",
 | 
			
		||||
        "PremiumPrice": [5, 5],
 | 
			
		||||
        "Bin": "BIN_0",
 | 
			
		||||
        "QuantityMultiplier": 20,
 | 
			
		||||
        "Expiry": {
 | 
			
		||||
          "$date": {
 | 
			
		||||
            "$numberLong": "9999999000000"
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        "AllowMultipurchase": true,
 | 
			
		||||
        "Id": {
 | 
			
		||||
          "$oid": "66fd60b20ba592c4c95e951a"
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    ],
 | 
			
		||||
    "PropertyTextHash": "946131D0CF5CDF7C2C03BB967DE0DF49",
 | 
			
		||||
    "Expiry": {
 | 
			
		||||
      "$date": {
 | 
			
		||||
        "$numberLong": "9999999000000"
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -34,8 +34,8 @@ dict = {
 | 
			
		||||
    code_rerollsNumber: `Anzahl der Umrollversuche`,
 | 
			
		||||
    code_viewStats: `Statistiken anzeigen`,
 | 
			
		||||
    code_rank: `Rang`,
 | 
			
		||||
    code_rankUp: `[UNTRANSLATED] Rank up`,
 | 
			
		||||
    code_rankDown: `[UNTRANSLATED] Rank down`,
 | 
			
		||||
    code_rankUp: `Rang erhöhen`,
 | 
			
		||||
    code_rankDown: `Rang verringern`,
 | 
			
		||||
    code_count: `Anzahl`,
 | 
			
		||||
    code_focusAllUnlocked: `Alle Fokus-Schulen sind bereits freigeschaltet.`,
 | 
			
		||||
    code_focusUnlocked: `|COUNT| neue Fokus-Schulen freigeschaltet! Ein Inventar-Update wird benötigt, damit die Änderungen im Spiel sichtbar werden. Die Sternenkarte zu besuchen, sollte der einfachste Weg sein, dies auszulösen.`,
 | 
			
		||||
@ -86,21 +86,21 @@ dict = {
 | 
			
		||||
    inventory_hoverboards: `K-Drives`,
 | 
			
		||||
    inventory_moaPets: `Moas`,
 | 
			
		||||
    inventory_kubrowPets: `Bestien`,
 | 
			
		||||
    inventory_evolutionProgress: `[UNTRANSLATED] Incarnon Evolution Progress`,
 | 
			
		||||
    inventory_evolutionProgress: `Incarnon-Entwicklungsfortschritte`,
 | 
			
		||||
    inventory_bulkAddSuits: `Fehlende Warframes hinzufügen`,
 | 
			
		||||
    inventory_bulkAddWeapons: `Fehlende Waffen hinzufügen`,
 | 
			
		||||
    inventory_bulkAddSpaceSuits: `Fehlende Archwings hinzufügen`,
 | 
			
		||||
    inventory_bulkAddSpaceWeapons: `Fehlende Archwing-Waffen hinzufügen`,
 | 
			
		||||
    inventory_bulkAddSentinels: `Fehlende Wächter hinzufügen`,
 | 
			
		||||
    inventory_bulkAddSentinelWeapons: `Fehlende Wächter-Waffen hinzufügen`,
 | 
			
		||||
    inventory_bulkAddEvolutionProgress: `[UNTRANSLATED] Add Missing Incarnon Evolution Progress`,
 | 
			
		||||
    inventory_bulkAddEvolutionProgress: `Fehlende Incarnon-Entwicklungsfortschritte hinzufügen`,
 | 
			
		||||
    inventory_bulkRankUpSuits: `Alle Warframes auf Max. Rang`,
 | 
			
		||||
    inventory_bulkRankUpWeapons: `Alle Waffen auf Max. Rang`,
 | 
			
		||||
    inventory_bulkRankUpSpaceSuits: `Alle Archwings auf Max. Rang`,
 | 
			
		||||
    inventory_bulkRankUpSpaceWeapons: `Alle Archwing-Waffen auf Max. Rang`,
 | 
			
		||||
    inventory_bulkRankUpSentinels: `Alle Wächter auf Max. Rang`,
 | 
			
		||||
    inventory_bulkRankUpSentinelWeapons: `Alle Wächter-Waffen auf Max. Rang`,
 | 
			
		||||
    inventory_bulkRankUpEvolutionProgress: `[UNTRANSLATED] Max Rank All Incarnon Evolution Progress`,
 | 
			
		||||
    inventory_bulkRankUpEvolutionProgress: `Alle Incarnon-Entwicklungsfortschritte auf Max. Rang`,
 | 
			
		||||
 | 
			
		||||
    quests_list: `Quests`,
 | 
			
		||||
    quests_completeAll: `Alle Quests abschließen`,
 | 
			
		||||
@ -120,9 +120,9 @@ dict = {
 | 
			
		||||
    mods_fingerprintHelp: `Benötigst du Hilfe mit dem Fingerabdruck?`,
 | 
			
		||||
    mods_rivens: `Rivens`,
 | 
			
		||||
    mods_mods: `Mods`,
 | 
			
		||||
    mods_addMissingUnrankedMods: `[UNTRANSLATED] Add Missing Unranked Mods`,
 | 
			
		||||
    mods_addMissingUnrankedMods: `Fehlende Mods ohne Rang hinzufügen`,
 | 
			
		||||
    mods_removeUnranked: `Mods ohne Rang entfernen`,
 | 
			
		||||
    mods_addMissingMaxRankMods: `[UNTRANSLATED] Add Missing Max Rank Mods`,
 | 
			
		||||
    mods_addMissingMaxRankMods: `Fehlende Mods mit Max. Rang hinzufügen`,
 | 
			
		||||
    cheats_administratorRequirement: `Du musst Administrator sein, um diese Funktion nutzen zu können. Um Administrator zu werden, füge <code>|DISPLAYNAME|</code> zu <code>administratorNames</code> in der config.json hinzu.`,
 | 
			
		||||
    cheats_server: `Server`,
 | 
			
		||||
    cheats_skipTutorial: `Tutorial überspringen`,
 | 
			
		||||
@ -134,7 +134,7 @@ dict = {
 | 
			
		||||
    cheats_infiniteEndo: `Unendlich Endo`,
 | 
			
		||||
    cheats_infiniteRegalAya: `Unendlich Reines Aya`,
 | 
			
		||||
    cheats_infiniteHelminthMaterials: `Unendlich Helminth-Materialien`,
 | 
			
		||||
    cheats_dontSubtractConsumables: `[UNTRANSLATED] Don't Subtract Consumables`,
 | 
			
		||||
    cheats_dontSubtractConsumables: `Verbrauchsgegenstände (Ausrüstung) nicht verbrauchen`,
 | 
			
		||||
    cheats_unlockAllShipFeatures: `Alle Schiffs-Funktionen freischalten`,
 | 
			
		||||
    cheats_unlockAllShipDecorations: `Alle Schiffsdekorationen freischalten`,
 | 
			
		||||
    cheats_unlockAllFlavourItems: `Alle <abbr title=\"Animationssets, Glyphen, Farbpaletten usw.\">Sammlerstücke</abbr> freischalten`,
 | 
			
		||||
@ -154,7 +154,7 @@ dict = {
 | 
			
		||||
    cheats_noKimCooldowns: `Keine Wartezeit bei KIM`,
 | 
			
		||||
    cheats_instantResourceExtractorDrones: `Sofortige Ressourcen-Extraktor-Drohnen`,
 | 
			
		||||
    cheats_noResourceExtractorDronesDamage: `Kein Schaden für Ressourcen-Extraktor-Drohnen`,
 | 
			
		||||
    cheats_skipClanKeyCrafting: `[UNTRANSLATED] Skip Clan Key Crafting`,
 | 
			
		||||
    cheats_skipClanKeyCrafting: `Clan-Schlüsselherstellung überspringen`,
 | 
			
		||||
    cheats_noDojoRoomBuildStage: `Kein Dojo-Raum-Bauvorgang`,
 | 
			
		||||
    cheats_noDojoDecoBuildStage: `Kein Dojo-Deko-Bauvorgang`,
 | 
			
		||||
    cheats_fastDojoRoomDestruction: `Schnelle Dojo-Raum-Zerstörung`,
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user