forked from OpenWF/SpaceNinjaServer
		
	Compare commits
	
		
			1 Commits
		
	
	
		
			main
			...
			LoreFragme
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 110cefe874 | 
@ -23,7 +23,7 @@
 | 
				
			|||||||
        "@typescript-eslint/no-explicit-any": "warn",
 | 
					        "@typescript-eslint/no-explicit-any": "warn",
 | 
				
			||||||
        "@typescript-eslint/no-loss-of-precision": "warn",
 | 
					        "@typescript-eslint/no-loss-of-precision": "warn",
 | 
				
			||||||
        "@typescript-eslint/no-unnecessary-condition": "warn",
 | 
					        "@typescript-eslint/no-unnecessary-condition": "warn",
 | 
				
			||||||
        "no-case-declarations": "error",
 | 
					        "no-case-declarations": "warn",
 | 
				
			||||||
        "prettier/prettier": "error",
 | 
					        "prettier/prettier": "error",
 | 
				
			||||||
        "@typescript-eslint/semi": "error",
 | 
					        "@typescript-eslint/semi": "error",
 | 
				
			||||||
        "no-mixed-spaces-and-tabs": "error",
 | 
					        "no-mixed-spaces-and-tabs": "error",
 | 
				
			||||||
 | 
				
			|||||||
@ -5,9 +5,6 @@
 | 
				
			|||||||
    "level": "trace"
 | 
					    "level": "trace"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "myAddress": "localhost",
 | 
					  "myAddress": "localhost",
 | 
				
			||||||
  "hubAddress": "https://localhost/api/",
 | 
					 | 
				
			||||||
  "platformCDNs": ["https://localhost/"],
 | 
					 | 
				
			||||||
  "NRS": ["localhost"],
 | 
					 | 
				
			||||||
  "httpPort": 80,
 | 
					  "httpPort": 80,
 | 
				
			||||||
  "httpsPort": 443,
 | 
					  "httpsPort": 443,
 | 
				
			||||||
  "administratorNames": [],
 | 
					  "administratorNames": [],
 | 
				
			||||||
@ -20,7 +17,6 @@
 | 
				
			|||||||
  "infinitePlatinum": true,
 | 
					  "infinitePlatinum": true,
 | 
				
			||||||
  "infiniteEndo": true,
 | 
					  "infiniteEndo": true,
 | 
				
			||||||
  "infiniteRegalAya": true,
 | 
					  "infiniteRegalAya": true,
 | 
				
			||||||
  "infiniteHelminthMaterials": false,
 | 
					 | 
				
			||||||
  "unlockAllShipFeatures": true,
 | 
					  "unlockAllShipFeatures": true,
 | 
				
			||||||
  "unlockAllShipDecorations": true,
 | 
					  "unlockAllShipDecorations": true,
 | 
				
			||||||
  "unlockAllFlavourItems": true,
 | 
					  "unlockAllFlavourItems": true,
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										8
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										8
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							@ -12,7 +12,7 @@
 | 
				
			|||||||
        "copyfiles": "^2.4.1",
 | 
					        "copyfiles": "^2.4.1",
 | 
				
			||||||
        "express": "^5",
 | 
					        "express": "^5",
 | 
				
			||||||
        "mongoose": "^8.9.4",
 | 
					        "mongoose": "^8.9.4",
 | 
				
			||||||
        "warframe-public-export-plus": "^0.5.36",
 | 
					        "warframe-public-export-plus": "^0.5.30",
 | 
				
			||||||
        "warframe-riven-info": "^0.1.2",
 | 
					        "warframe-riven-info": "^0.1.2",
 | 
				
			||||||
        "winston": "^3.17.0",
 | 
					        "winston": "^3.17.0",
 | 
				
			||||||
        "winston-daily-rotate-file": "^5.0.0"
 | 
					        "winston-daily-rotate-file": "^5.0.0"
 | 
				
			||||||
@ -4093,9 +4093,9 @@
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "node_modules/warframe-public-export-plus": {
 | 
					    "node_modules/warframe-public-export-plus": {
 | 
				
			||||||
      "version": "0.5.36",
 | 
					      "version": "0.5.30",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.36.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.30.tgz",
 | 
				
			||||||
      "integrity": "sha512-FYZECqBSnynl6lQvcQyEqpnGW9l84wzusekhtwKjvg3280CYdn7g5x0Q9tOMhj1jpc/1tuY+akHtHa94sPtqKw=="
 | 
					      "integrity": "sha512-vzs+naEqp3iFZTbgIky4jiNbjNIovuR4oSimrFiuyIbrnfTlfXFzDfzT0hG2rgS8yEXBAbOcv2Zfm3fmWuZ0Kg=="
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "node_modules/warframe-riven-info": {
 | 
					    "node_modules/warframe-riven-info": {
 | 
				
			||||||
      "version": "0.1.2",
 | 
					      "version": "0.1.2",
 | 
				
			||||||
 | 
				
			|||||||
@ -17,7 +17,7 @@
 | 
				
			|||||||
    "copyfiles": "^2.4.1",
 | 
					    "copyfiles": "^2.4.1",
 | 
				
			||||||
    "express": "^5",
 | 
					    "express": "^5",
 | 
				
			||||||
    "mongoose": "^8.9.4",
 | 
					    "mongoose": "^8.9.4",
 | 
				
			||||||
    "warframe-public-export-plus": "^0.5.36",
 | 
					    "warframe-public-export-plus": "^0.5.30",
 | 
				
			||||||
    "warframe-riven-info": "^0.1.2",
 | 
					    "warframe-riven-info": "^0.1.2",
 | 
				
			||||||
    "winston": "^3.17.0",
 | 
					    "winston": "^3.17.0",
 | 
				
			||||||
    "winston-daily-rotate-file": "^5.0.0"
 | 
					    "winston-daily-rotate-file": "^5.0.0"
 | 
				
			||||||
 | 
				
			|||||||
@ -7,7 +7,14 @@ import { getRecipe } from "@/src/services/itemDataService";
 | 
				
			|||||||
import { IOid } from "@/src/types/commonTypes";
 | 
					import { IOid } from "@/src/types/commonTypes";
 | 
				
			||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
 | 
					import { getJSONfromString } from "@/src/helpers/stringHelpers";
 | 
				
			||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
					import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
				
			||||||
import { getInventory, updateCurrency, addItem, addMiscItems, addRecipes } from "@/src/services/inventoryService";
 | 
					import {
 | 
				
			||||||
 | 
					    getInventory,
 | 
				
			||||||
 | 
					    updateCurrency,
 | 
				
			||||||
 | 
					    addItem,
 | 
				
			||||||
 | 
					    addMiscItems,
 | 
				
			||||||
 | 
					    addRecipes,
 | 
				
			||||||
 | 
					    updateCurrencyByAccountId
 | 
				
			||||||
 | 
					} from "@/src/services/inventoryService";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface IClaimCompletedRecipeRequest {
 | 
					export interface IClaimCompletedRecipeRequest {
 | 
				
			||||||
    RecipeIds: IOid[];
 | 
					    RecipeIds: IOid[];
 | 
				
			||||||
@ -30,6 +37,7 @@ export const claimCompletedRecipeController: RequestHandler = async (req, res) =
 | 
				
			|||||||
    // }
 | 
					    // }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    inventory.PendingRecipes.pull(pendingRecipe._id);
 | 
					    inventory.PendingRecipes.pull(pendingRecipe._id);
 | 
				
			||||||
 | 
					    await inventory.save();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const recipe = getRecipe(pendingRecipe.ItemType);
 | 
					    const recipe = getRecipe(pendingRecipe.ItemType);
 | 
				
			||||||
    if (!recipe) {
 | 
					    if (!recipe) {
 | 
				
			||||||
@ -37,10 +45,11 @@ export const claimCompletedRecipeController: RequestHandler = async (req, res) =
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (req.query.cancel) {
 | 
					    if (req.query.cancel) {
 | 
				
			||||||
 | 
					        const inventory = await getInventory(accountId);
 | 
				
			||||||
        const currencyChanges = updateCurrency(inventory, recipe.buildPrice * -1, false);
 | 
					        const currencyChanges = updateCurrency(inventory, recipe.buildPrice * -1, false);
 | 
				
			||||||
        addMiscItems(inventory, recipe.ingredients);
 | 
					        addMiscItems(inventory, recipe.ingredients);
 | 
				
			||||||
 | 
					 | 
				
			||||||
        await inventory.save();
 | 
					        await inventory.save();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Not a bug: In the specific case of cancelling a recipe, InventoryChanges are expected to be the root.
 | 
					        // Not a bug: In the specific case of cancelling a recipe, InventoryChanges are expected to be the root.
 | 
				
			||||||
        res.json({
 | 
					        res.json({
 | 
				
			||||||
            ...currencyChanges,
 | 
					            ...currencyChanges,
 | 
				
			||||||
@ -50,6 +59,7 @@ export const claimCompletedRecipeController: RequestHandler = async (req, res) =
 | 
				
			|||||||
        logger.debug("Claiming Recipe", { recipe, pendingRecipe });
 | 
					        logger.debug("Claiming Recipe", { recipe, pendingRecipe });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (recipe.secretIngredientAction == "SIA_SPECTRE_LOADOUT_COPY") {
 | 
					        if (recipe.secretIngredientAction == "SIA_SPECTRE_LOADOUT_COPY") {
 | 
				
			||||||
 | 
					            const inventory = await getInventory(accountId);
 | 
				
			||||||
            inventory.PendingSpectreLoadouts ??= [];
 | 
					            inventory.PendingSpectreLoadouts ??= [];
 | 
				
			||||||
            inventory.SpectreLoadouts ??= [];
 | 
					            inventory.SpectreLoadouts ??= [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -67,6 +77,7 @@ export const claimCompletedRecipeController: RequestHandler = async (req, res) =
 | 
				
			|||||||
                );
 | 
					                );
 | 
				
			||||||
                inventory.SpectreLoadouts.push(inventory.PendingSpectreLoadouts[pendingLoadoutIndex]);
 | 
					                inventory.SpectreLoadouts.push(inventory.PendingSpectreLoadouts[pendingLoadoutIndex]);
 | 
				
			||||||
                inventory.PendingSpectreLoadouts.splice(pendingLoadoutIndex, 1);
 | 
					                inventory.PendingSpectreLoadouts.splice(pendingLoadoutIndex, 1);
 | 
				
			||||||
 | 
					                await inventory.save();
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -81,14 +92,17 @@ export const claimCompletedRecipeController: RequestHandler = async (req, res) =
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            InventoryChanges = { ...InventoryChanges, Recipes: recipeChanges };
 | 
					            InventoryChanges = { ...InventoryChanges, Recipes: recipeChanges };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            const inventory = await getInventory(accountId);
 | 
				
			||||||
            addRecipes(inventory, recipeChanges);
 | 
					            addRecipes(inventory, recipeChanges);
 | 
				
			||||||
 | 
					            await inventory.save();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (req.query.rush) {
 | 
					        if (req.query.rush) {
 | 
				
			||||||
            InventoryChanges = {
 | 
					            InventoryChanges = {
 | 
				
			||||||
                ...InventoryChanges,
 | 
					                ...InventoryChanges,
 | 
				
			||||||
                ...updateCurrency(inventory, recipe.skipBuildTimePrice, true)
 | 
					                ...(await updateCurrencyByAccountId(recipe.skipBuildTimePrice, true, accountId))
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        const inventory = await getInventory(accountId);
 | 
				
			||||||
        InventoryChanges = {
 | 
					        InventoryChanges = {
 | 
				
			||||||
            ...InventoryChanges,
 | 
					            ...InventoryChanges,
 | 
				
			||||||
            ...(await addItem(inventory, recipe.resultType, recipe.num)).InventoryChanges
 | 
					            ...(await addItem(inventory, recipe.resultType, recipe.num)).InventoryChanges
 | 
				
			||||||
 | 
				
			|||||||
@ -1,56 +0,0 @@
 | 
				
			|||||||
import { RequestHandler } from "express";
 | 
					 | 
				
			||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
					 | 
				
			||||||
import { addMiscItems, getInventory, updateCurrency } from "@/src/services/inventoryService";
 | 
					 | 
				
			||||||
import { IInventoryChanges } from "@/src/types/purchaseTypes";
 | 
					 | 
				
			||||||
import { IMiscItem } from "@/src/types/inventoryTypes/inventoryTypes";
 | 
					 | 
				
			||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
 | 
					 | 
				
			||||||
import { IUnveiledRivenFingerprint, randomiseRivenStats } from "@/src/helpers/rivenFingerprintHelper";
 | 
					 | 
				
			||||||
import { getRandomElement, getRandomInt } from "@/src/services/rngService";
 | 
					 | 
				
			||||||
import { ExportUpgrades } from "warframe-public-export-plus";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const completeRandomModChallengeController: RequestHandler = async (req, res) => {
 | 
					 | 
				
			||||||
    const accountId = await getAccountIdForRequest(req);
 | 
					 | 
				
			||||||
    const inventory = await getInventory(accountId);
 | 
					 | 
				
			||||||
    const request = getJSONfromString<ICompleteRandomModChallengeRequest>(String(req.body));
 | 
					 | 
				
			||||||
    let inventoryChanges: IInventoryChanges = {};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Remove 20 plat or riven cipher
 | 
					 | 
				
			||||||
    if ((req.query.p as string) == "1") {
 | 
					 | 
				
			||||||
        inventoryChanges = { ...updateCurrency(inventory, 20, true) };
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
        const miscItemChanges: IMiscItem[] = [
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                ItemType: "/Lotus/Types/Items/MiscItems/RivenIdentifier",
 | 
					 | 
				
			||||||
                ItemCount: -1
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        ];
 | 
					 | 
				
			||||||
        addMiscItems(inventory, miscItemChanges);
 | 
					 | 
				
			||||||
        inventoryChanges.MiscItems = miscItemChanges;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Update riven fingerprint to a randomised unveiled state
 | 
					 | 
				
			||||||
    const upgrade = inventory.Upgrades.id(request.ItemId)!;
 | 
					 | 
				
			||||||
    const meta = ExportUpgrades[upgrade.ItemType];
 | 
					 | 
				
			||||||
    const fingerprint: IUnveiledRivenFingerprint = {
 | 
					 | 
				
			||||||
        compat: getRandomElement(meta.compatibleItems!),
 | 
					 | 
				
			||||||
        lim: 0,
 | 
					 | 
				
			||||||
        lvl: 0,
 | 
					 | 
				
			||||||
        lvlReq: getRandomInt(8, 16),
 | 
					 | 
				
			||||||
        pol: getRandomElement(["AP_ATTACK", "AP_DEFENSE", "AP_TACTIC"]),
 | 
					 | 
				
			||||||
        buffs: [],
 | 
					 | 
				
			||||||
        curses: []
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
    randomiseRivenStats(meta, fingerprint);
 | 
					 | 
				
			||||||
    upgrade.UpgradeFingerprint = JSON.stringify(fingerprint);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    await inventory.save();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    res.json({
 | 
					 | 
				
			||||||
        InventoryChanges: inventoryChanges,
 | 
					 | 
				
			||||||
        Fingerprint: upgrade.UpgradeFingerprint
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
interface ICompleteRandomModChallengeRequest {
 | 
					 | 
				
			||||||
    ItemId: string;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,11 +1,13 @@
 | 
				
			|||||||
import { RequestHandler } from "express";
 | 
					import { RequestHandler } from "express";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const getNewRewardSeedController: RequestHandler = (_req, res) => {
 | 
					const getNewRewardSeedController: RequestHandler = (_req, res) => {
 | 
				
			||||||
    res.json({ rewardSeed: generateRewardSeed() });
 | 
					    res.json({ rewardSeed: generateRewardSeed() });
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function generateRewardSeed(): number {
 | 
					function generateRewardSeed(): number {
 | 
				
			||||||
    const min = -Number.MAX_SAFE_INTEGER;
 | 
					    const min = -Number.MAX_SAFE_INTEGER;
 | 
				
			||||||
    const max = Number.MAX_SAFE_INTEGER;
 | 
					    const max = Number.MAX_SAFE_INTEGER;
 | 
				
			||||||
    return Math.floor(Math.random() * (max - min + 1)) + min;
 | 
					    return Math.floor(Math.random() * (max - min + 1)) + min;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export { getNewRewardSeedController };
 | 
				
			||||||
 | 
				
			|||||||
@ -1,31 +1,77 @@
 | 
				
			|||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
 | 
					import { getJSONfromString } from "@/src/helpers/stringHelpers";
 | 
				
			||||||
import { crackRelic } from "@/src/helpers/relicHelper";
 | 
					import { addMiscItems, getInventory } from "@/src/services/inventoryService";
 | 
				
			||||||
import { getInventory } from "@/src/services/inventoryService";
 | 
					 | 
				
			||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
					import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
				
			||||||
import { IVoidTearParticipantInfo } from "@/src/types/requestTypes";
 | 
					import { handleStoreItemAcquisition } from "@/src/services/purchaseService";
 | 
				
			||||||
 | 
					import { getRandomWeightedReward2 } from "@/src/services/rngService";
 | 
				
			||||||
 | 
					import { ITypeCount } from "@/src/types/inventoryTypes/inventoryTypes";
 | 
				
			||||||
 | 
					import { logger } from "@/src/utils/logger";
 | 
				
			||||||
import { RequestHandler } from "express";
 | 
					import { RequestHandler } from "express";
 | 
				
			||||||
 | 
					import { ExportRelics, ExportRewards, TRarity } from "warframe-public-export-plus";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const getVoidProjectionRewardsController: RequestHandler = async (req, res) => {
 | 
					export const getVoidProjectionRewardsController: RequestHandler = async (req, res) => {
 | 
				
			||||||
    const accountId = await getAccountIdForRequest(req);
 | 
					    const accountId = await getAccountIdForRequest(req);
 | 
				
			||||||
    const data = getJSONfromString<IVoidProjectionRewardRequest>(String(req.body));
 | 
					    const data = getJSONfromString<IVoidProjectionRewardRequest>(String(req.body));
 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (data.ParticipantInfo.QualifiesForReward && !data.ParticipantInfo.HaveRewardResponse) {
 | 
					 | 
				
			||||||
        const inventory = await getInventory(accountId);
 | 
					 | 
				
			||||||
        await crackRelic(inventory, data.ParticipantInfo);
 | 
					 | 
				
			||||||
        await inventory.save();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const response: IVoidProjectionRewardResponse = {
 | 
					    const response: IVoidProjectionRewardResponse = {
 | 
				
			||||||
        CurrentWave: data.CurrentWave,
 | 
					        CurrentWave: data.CurrentWave,
 | 
				
			||||||
        ParticipantInfo: data.ParticipantInfo,
 | 
					        ParticipantInfo: data.ParticipantInfo,
 | 
				
			||||||
        DifficultyTier: data.DifficultyTier
 | 
					        DifficultyTier: data.DifficultyTier
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					    if (data.ParticipantInfo.QualifiesForReward) {
 | 
				
			||||||
 | 
					        const relic = ExportRelics[data.ParticipantInfo.VoidProjection];
 | 
				
			||||||
 | 
					        const weights = refinementToWeights[relic.quality];
 | 
				
			||||||
 | 
					        logger.debug(`opening a relic of quality ${relic.quality}; rarity weights are`, weights);
 | 
				
			||||||
 | 
					        const reward = getRandomWeightedReward2(
 | 
				
			||||||
 | 
					            ExportRewards[relic.rewardManifest][0] as { type: string; itemCount: number; rarity: TRarity }[], // rarity is nullable in PE+ typings, but always present for relics
 | 
				
			||||||
 | 
					            weights
 | 
				
			||||||
 | 
					        )!;
 | 
				
			||||||
 | 
					        logger.debug(`relic rolled`, reward);
 | 
				
			||||||
 | 
					        response.ParticipantInfo.Reward = reward.type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const inventory = await getInventory(accountId);
 | 
				
			||||||
 | 
					        // Remove relic
 | 
				
			||||||
 | 
					        addMiscItems(inventory, [
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                ItemType: data.ParticipantInfo.VoidProjection,
 | 
				
			||||||
 | 
					                ItemCount: -1
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        ]);
 | 
				
			||||||
 | 
					        // Give reward
 | 
				
			||||||
 | 
					        await handleStoreItemAcquisition(reward.type, inventory, reward.itemCount);
 | 
				
			||||||
 | 
					        await inventory.save();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    res.json(response);
 | 
					    res.json(response);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const refinementToWeights = {
 | 
				
			||||||
 | 
					    VPQ_BRONZE: {
 | 
				
			||||||
 | 
					        COMMON: 0.76,
 | 
				
			||||||
 | 
					        UNCOMMON: 0.22,
 | 
				
			||||||
 | 
					        RARE: 0.02,
 | 
				
			||||||
 | 
					        LEGENDARY: 0
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    VPQ_SILVER: {
 | 
				
			||||||
 | 
					        COMMON: 0.7,
 | 
				
			||||||
 | 
					        UNCOMMON: 0.26,
 | 
				
			||||||
 | 
					        RARE: 0.04,
 | 
				
			||||||
 | 
					        LEGENDARY: 0
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    VPQ_GOLD: {
 | 
				
			||||||
 | 
					        COMMON: 0.6,
 | 
				
			||||||
 | 
					        UNCOMMON: 0.34,
 | 
				
			||||||
 | 
					        RARE: 0.06,
 | 
				
			||||||
 | 
					        LEGENDARY: 0
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    VPQ_PLATINUM: {
 | 
				
			||||||
 | 
					        COMMON: 0.5,
 | 
				
			||||||
 | 
					        UNCOMMON: 0.4,
 | 
				
			||||||
 | 
					        RARE: 0.1,
 | 
				
			||||||
 | 
					        LEGENDARY: 0
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface IVoidProjectionRewardRequest {
 | 
					interface IVoidProjectionRewardRequest {
 | 
				
			||||||
    CurrentWave: number;
 | 
					    CurrentWave: number;
 | 
				
			||||||
    ParticipantInfo: IVoidTearParticipantInfo;
 | 
					    ParticipantInfo: IParticipantInfo;
 | 
				
			||||||
    VoidTier: string;
 | 
					    VoidTier: string;
 | 
				
			||||||
    DifficultyTier: number;
 | 
					    DifficultyTier: number;
 | 
				
			||||||
    VoidProjectionRemovalHash: string;
 | 
					    VoidProjectionRemovalHash: string;
 | 
				
			||||||
@ -33,6 +79,20 @@ interface IVoidProjectionRewardRequest {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
interface IVoidProjectionRewardResponse {
 | 
					interface IVoidProjectionRewardResponse {
 | 
				
			||||||
    CurrentWave: number;
 | 
					    CurrentWave: number;
 | 
				
			||||||
    ParticipantInfo: IVoidTearParticipantInfo;
 | 
					    ParticipantInfo: IParticipantInfo;
 | 
				
			||||||
    DifficultyTier: number;
 | 
					    DifficultyTier: number;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface IParticipantInfo {
 | 
				
			||||||
 | 
					    AccountId: string;
 | 
				
			||||||
 | 
					    Name: string;
 | 
				
			||||||
 | 
					    ChosenRewardOwner: string;
 | 
				
			||||||
 | 
					    MissionHash: string;
 | 
				
			||||||
 | 
					    VoidProjection: string;
 | 
				
			||||||
 | 
					    Reward: string;
 | 
				
			||||||
 | 
					    QualifiesForReward: boolean;
 | 
				
			||||||
 | 
					    HaveRewardResponse: boolean;
 | 
				
			||||||
 | 
					    RewardsMultiplier: number;
 | 
				
			||||||
 | 
					    RewardProjection: string;
 | 
				
			||||||
 | 
					    HardModeReward: ITypeCount;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -10,7 +10,7 @@ export const giveKeyChainTriggeredItemsController: RequestHandler = async (req,
 | 
				
			|||||||
    const keyChainInfo = getJSONfromString<IKeyChainRequest>((req.body as string).toString());
 | 
					    const keyChainInfo = getJSONfromString<IKeyChainRequest>((req.body as string).toString());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const inventory = await getInventory(accountId);
 | 
					    const inventory = await getInventory(accountId);
 | 
				
			||||||
    const inventoryChanges = await giveKeyChainItem(inventory, keyChainInfo);
 | 
					    const inventoryChanges = giveKeyChainItem(inventory, keyChainInfo);
 | 
				
			||||||
    await inventory.save();
 | 
					    await inventory.save();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    res.send(inventoryChanges);
 | 
					    res.send(inventoryChanges);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,96 +0,0 @@
 | 
				
			|||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
 | 
					 | 
				
			||||||
import { InventoryDocumentProps } from "@/src/models/inventoryModels/inventoryModel";
 | 
					 | 
				
			||||||
import {
 | 
					 | 
				
			||||||
    addEquipment,
 | 
					 | 
				
			||||||
    addItem,
 | 
					 | 
				
			||||||
    combineInventoryChanges,
 | 
					 | 
				
			||||||
    getInventory,
 | 
					 | 
				
			||||||
    updateSlots
 | 
					 | 
				
			||||||
} from "@/src/services/inventoryService";
 | 
					 | 
				
			||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
					 | 
				
			||||||
import { IInventoryClient, IInventoryDatabase, InventorySlot } from "@/src/types/inventoryTypes/inventoryTypes";
 | 
					 | 
				
			||||||
import { IInventoryChanges } from "@/src/types/purchaseTypes";
 | 
					 | 
				
			||||||
import { RequestHandler } from "express";
 | 
					 | 
				
			||||||
import { HydratedDocument } from "mongoose";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type TPartialStartingGear = Pick<IInventoryClient, "LongGuns" | "Suits" | "Pistols" | "Melee">;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const giveStartingGearController: RequestHandler = async (req, res) => {
 | 
					 | 
				
			||||||
    const accountId = await getAccountIdForRequest(req);
 | 
					 | 
				
			||||||
    const startingGear = getJSONfromString<TPartialStartingGear>(String(req.body));
 | 
					 | 
				
			||||||
    const inventory = await getInventory(accountId);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const inventoryChanges = await addStartingGear(inventory, startingGear);
 | 
					 | 
				
			||||||
    await inventory.save();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    res.send(inventoryChanges);
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
//TODO: RawUpgrades might need to return a LastAdded
 | 
					 | 
				
			||||||
const awakeningRewards = [
 | 
					 | 
				
			||||||
    "/Lotus/Types/StoreItems/AvatarImages/AvatarImageItem1",
 | 
					 | 
				
			||||||
    "/Lotus/Types/StoreItems/AvatarImages/AvatarImageItem2",
 | 
					 | 
				
			||||||
    "/Lotus/Types/StoreItems/AvatarImages/AvatarImageItem3",
 | 
					 | 
				
			||||||
    "/Lotus/Types/StoreItems/AvatarImages/AvatarImageItem4",
 | 
					 | 
				
			||||||
    "/Lotus/Types/Restoratives/LisetAutoHack",
 | 
					 | 
				
			||||||
    "/Lotus/Upgrades/Mods/Warframe/AvatarShieldMaxMod"
 | 
					 | 
				
			||||||
];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const addStartingGear = async (
 | 
					 | 
				
			||||||
    inventory: HydratedDocument<IInventoryDatabase, InventoryDocumentProps>,
 | 
					 | 
				
			||||||
    startingGear: TPartialStartingGear | undefined = undefined
 | 
					 | 
				
			||||||
): Promise<IInventoryChanges> => {
 | 
					 | 
				
			||||||
    const { LongGuns, Pistols, Suits, Melee } = startingGear || {
 | 
					 | 
				
			||||||
        LongGuns: [{ ItemType: "/Lotus/Weapons/Tenno/Rifle/Rifle" }],
 | 
					 | 
				
			||||||
        Pistols: [{ ItemType: "/Lotus/Weapons/Tenno/Pistol/Pistol" }],
 | 
					 | 
				
			||||||
        Suits: [{ ItemType: "/Lotus/Powersuits/Excalibur/Excalibur" }],
 | 
					 | 
				
			||||||
        Melee: [{ ItemType: "/Lotus/Weapons/Tenno/Melee/LongSword/LongSword" }]
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    //TODO: properly merge weapon bin changes it is currently static here
 | 
					 | 
				
			||||||
    const inventoryChanges: IInventoryChanges = {};
 | 
					 | 
				
			||||||
    addEquipment(inventory, "LongGuns", LongGuns[0].ItemType, undefined, inventoryChanges);
 | 
					 | 
				
			||||||
    addEquipment(inventory, "Pistols", Pistols[0].ItemType, undefined, inventoryChanges);
 | 
					 | 
				
			||||||
    addEquipment(inventory, "Melee", Melee[0].ItemType, undefined, inventoryChanges);
 | 
					 | 
				
			||||||
    addEquipment(inventory, "Suits", Suits[0].ItemType, undefined, inventoryChanges, { Configs: Suits[0].Configs });
 | 
					 | 
				
			||||||
    addEquipment(
 | 
					 | 
				
			||||||
        inventory,
 | 
					 | 
				
			||||||
        "DataKnives",
 | 
					 | 
				
			||||||
        "/Lotus/Weapons/Tenno/HackingDevices/TnHackingDevice/TnHackingDeviceWeapon",
 | 
					 | 
				
			||||||
        undefined,
 | 
					 | 
				
			||||||
        inventoryChanges,
 | 
					 | 
				
			||||||
        { XP: 450_000 }
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
    addEquipment(
 | 
					 | 
				
			||||||
        inventory,
 | 
					 | 
				
			||||||
        "Scoops",
 | 
					 | 
				
			||||||
        "/Lotus/Weapons/Tenno/Speedball/SpeedballWeaponTest",
 | 
					 | 
				
			||||||
        undefined,
 | 
					 | 
				
			||||||
        inventoryChanges
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    updateSlots(inventory, InventorySlot.SUITS, 0, 1);
 | 
					 | 
				
			||||||
    updateSlots(inventory, InventorySlot.WEAPONS, 0, 3);
 | 
					 | 
				
			||||||
    inventoryChanges.SuitBin = { count: 1, platinum: 0, Slots: -1 };
 | 
					 | 
				
			||||||
    inventoryChanges.WeaponBin = { count: 3, platinum: 0, Slots: -3 };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    await addItem(inventory, "/Lotus/Types/Keys/VorsPrize/VorsPrizeQuestKeyChain");
 | 
					 | 
				
			||||||
    inventory.ActiveQuest = "/Lotus/Types/Keys/VorsPrize/VorsPrizeQuestKeyChain";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    inventory.PremiumCredits = 50;
 | 
					 | 
				
			||||||
    inventory.PremiumCreditsFree = 50;
 | 
					 | 
				
			||||||
    inventoryChanges.PremiumCredits = 50;
 | 
					 | 
				
			||||||
    inventoryChanges.PremiumCreditsFree = 50;
 | 
					 | 
				
			||||||
    inventory.RegularCredits = 3000;
 | 
					 | 
				
			||||||
    inventoryChanges.RegularCredits = 3000;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for (const item of awakeningRewards) {
 | 
					 | 
				
			||||||
        const inventoryDelta = await addItem(inventory, item);
 | 
					 | 
				
			||||||
        combineInventoryChanges(inventoryChanges, inventoryDelta.InventoryChanges);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    inventory.PlayedParkourTutorial = true;
 | 
					 | 
				
			||||||
    inventory.ReceivedStartingGear = true;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return inventoryChanges;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
@ -6,9 +6,7 @@ import { IOid } from "@/src/types/commonTypes";
 | 
				
			|||||||
import {
 | 
					import {
 | 
				
			||||||
    IConsumedSuit,
 | 
					    IConsumedSuit,
 | 
				
			||||||
    IHelminthFoodRecord,
 | 
					    IHelminthFoodRecord,
 | 
				
			||||||
    IInfestedFoundryClient,
 | 
					 | 
				
			||||||
    IInfestedFoundryDatabase,
 | 
					    IInfestedFoundryDatabase,
 | 
				
			||||||
    IInventoryClient,
 | 
					 | 
				
			||||||
    IMiscItem,
 | 
					    IMiscItem,
 | 
				
			||||||
    ITypeCount
 | 
					    ITypeCount
 | 
				
			||||||
} from "@/src/types/inventoryTypes/inventoryTypes";
 | 
					} from "@/src/types/inventoryTypes/inventoryTypes";
 | 
				
			||||||
@ -18,7 +16,6 @@ import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/invento
 | 
				
			|||||||
import { toMongoDate } from "@/src/helpers/inventoryHelpers";
 | 
					import { toMongoDate } from "@/src/helpers/inventoryHelpers";
 | 
				
			||||||
import { logger } from "@/src/utils/logger";
 | 
					import { logger } from "@/src/utils/logger";
 | 
				
			||||||
import { colorToShard } from "@/src/helpers/shardHelper";
 | 
					import { colorToShard } from "@/src/helpers/shardHelper";
 | 
				
			||||||
import { config } from "@/src/services/configService";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const infestedFoundryController: RequestHandler = async (req, res) => {
 | 
					export const infestedFoundryController: RequestHandler = async (req, res) => {
 | 
				
			||||||
    const accountId = await getAccountIdForRequest(req);
 | 
					    const accountId = await getAccountIdForRequest(req);
 | 
				
			||||||
@ -72,22 +69,18 @@ export const infestedFoundryController: RequestHandler = async (req, res) => {
 | 
				
			|||||||
            // remove from suit
 | 
					            // remove from suit
 | 
				
			||||||
            suit.ArchonCrystalUpgrades![request.Slot] = {};
 | 
					            suit.ArchonCrystalUpgrades![request.Slot] = {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (!config.infiniteHelminthMaterials) {
 | 
					 | 
				
			||||||
            // remove bile
 | 
					            // remove bile
 | 
				
			||||||
            const bile = inventory.InfestedFoundry!.Resources!.find(
 | 
					            const bile = inventory.InfestedFoundry!.Resources!.find(
 | 
				
			||||||
                x => x.ItemType == "/Lotus/Types/Items/InfestedFoundry/HelminthBile"
 | 
					                x => x.ItemType == "/Lotus/Types/Items/InfestedFoundry/HelminthBile"
 | 
				
			||||||
            )!;
 | 
					            )!;
 | 
				
			||||||
            bile.Count -= 300;
 | 
					            bile.Count -= 300;
 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            await inventory.save();
 | 
					            await inventory.save();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            const infestedFoundry = inventory.toJSON<IInventoryClient>().InfestedFoundry!;
 | 
					 | 
				
			||||||
            applyCheatsToInfestedFoundry(infestedFoundry);
 | 
					 | 
				
			||||||
            res.json({
 | 
					            res.json({
 | 
				
			||||||
                InventoryChanges: {
 | 
					                InventoryChanges: {
 | 
				
			||||||
                    MiscItems: miscItemChanges,
 | 
					                    MiscItems: miscItemChanges,
 | 
				
			||||||
                    InfestedFoundry: infestedFoundry
 | 
					                    InfestedFoundry: inventory.toJSON().InfestedFoundry
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
@ -112,12 +105,6 @@ export const infestedFoundryController: RequestHandler = async (req, res) => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        case "c": {
 | 
					        case "c": {
 | 
				
			||||||
            // consume items
 | 
					            // consume items
 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (config.infiniteHelminthMaterials) {
 | 
					 | 
				
			||||||
                res.status(400).end();
 | 
					 | 
				
			||||||
                return;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            const request = getJSONfromString<IHelminthFeedRequest>(String(req.body));
 | 
					            const request = getJSONfromString<IHelminthFeedRequest>(String(req.body));
 | 
				
			||||||
            const inventory = await getInventory(accountId);
 | 
					            const inventory = await getInventory(accountId);
 | 
				
			||||||
            inventory.InfestedFoundry ??= {};
 | 
					            inventory.InfestedFoundry ??= {};
 | 
				
			||||||
@ -223,11 +210,9 @@ export const infestedFoundryController: RequestHandler = async (req, res) => {
 | 
				
			|||||||
                inventory.InfestedFoundry.InvigorationsApplied = 0;
 | 
					                inventory.InfestedFoundry.InvigorationsApplied = 0;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            await inventory.save();
 | 
					            await inventory.save();
 | 
				
			||||||
            const infestedFoundry = inventory.toJSON<IInventoryClient>().InfestedFoundry!;
 | 
					 | 
				
			||||||
            applyCheatsToInfestedFoundry(infestedFoundry);
 | 
					 | 
				
			||||||
            res.json({
 | 
					            res.json({
 | 
				
			||||||
                InventoryChanges: {
 | 
					                InventoryChanges: {
 | 
				
			||||||
                    InfestedFoundry: infestedFoundry
 | 
					                    InfestedFoundry: inventory.toJSON().InfestedFoundry
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
@ -238,18 +223,16 @@ export const infestedFoundryController: RequestHandler = async (req, res) => {
 | 
				
			|||||||
            const request = getJSONfromString<IHelminthSubsumeRequest>(String(req.body));
 | 
					            const request = getJSONfromString<IHelminthSubsumeRequest>(String(req.body));
 | 
				
			||||||
            const inventory = await getInventory(accountId);
 | 
					            const inventory = await getInventory(accountId);
 | 
				
			||||||
            const recipe = getRecipe(request.Recipe)!;
 | 
					            const recipe = getRecipe(request.Recipe)!;
 | 
				
			||||||
            if (!config.infiniteHelminthMaterials) {
 | 
					 | 
				
			||||||
            for (const ingredient of recipe.secretIngredients!) {
 | 
					            for (const ingredient of recipe.secretIngredients!) {
 | 
				
			||||||
                const resource = inventory.InfestedFoundry!.Resources!.find(x => x.ItemType == ingredient.ItemType);
 | 
					                const resource = inventory.InfestedFoundry!.Resources!.find(x => x.ItemType == ingredient.ItemType);
 | 
				
			||||||
                if (resource) {
 | 
					                if (resource) {
 | 
				
			||||||
                    resource.Count -= ingredient.ItemCount;
 | 
					                    resource.Count -= ingredient.ItemCount;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            const suit = inventory.Suits.id(request.SuitId.$oid)!;
 | 
					            const suit = inventory.Suits.id(request.SuitId.$oid)!;
 | 
				
			||||||
            inventory.Suits.pull(suit);
 | 
					            inventory.Suits.pull(suit);
 | 
				
			||||||
            const consumedSuit: IConsumedSuit = { s: suit.ItemType };
 | 
					            const consumedSuit: IConsumedSuit = { s: suit.ItemType };
 | 
				
			||||||
            if (suit.Configs[0] && suit.Configs[0].pricol) {
 | 
					            if (suit.Configs && suit.Configs[0] && suit.Configs[0].pricol) {
 | 
				
			||||||
                consumedSuit.c = suit.Configs[0].pricol;
 | 
					                consumedSuit.c = suit.Configs[0].pricol;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            if ((inventory.InfestedFoundry!.XP ?? 0) < 73125_00) {
 | 
					            if ((inventory.InfestedFoundry!.XP ?? 0) < 73125_00) {
 | 
				
			||||||
@ -264,8 +247,6 @@ export const infestedFoundryController: RequestHandler = async (req, res) => {
 | 
				
			|||||||
            const recipeChanges = addInfestedFoundryXP(inventory.InfestedFoundry!, 1600_00);
 | 
					            const recipeChanges = addInfestedFoundryXP(inventory.InfestedFoundry!, 1600_00);
 | 
				
			||||||
            addRecipes(inventory, recipeChanges);
 | 
					            addRecipes(inventory, recipeChanges);
 | 
				
			||||||
            await inventory.save();
 | 
					            await inventory.save();
 | 
				
			||||||
            const infestedFoundry = inventory.toJSON<IInventoryClient>().InfestedFoundry!;
 | 
					 | 
				
			||||||
            applyCheatsToInfestedFoundry(infestedFoundry);
 | 
					 | 
				
			||||||
            res.json({
 | 
					            res.json({
 | 
				
			||||||
                InventoryChanges: {
 | 
					                InventoryChanges: {
 | 
				
			||||||
                    Recipes: recipeChanges,
 | 
					                    Recipes: recipeChanges,
 | 
				
			||||||
@ -279,7 +260,7 @@ export const infestedFoundryController: RequestHandler = async (req, res) => {
 | 
				
			|||||||
                        platinum: 0,
 | 
					                        platinum: 0,
 | 
				
			||||||
                        Slots: 1
 | 
					                        Slots: 1
 | 
				
			||||||
                    },
 | 
					                    },
 | 
				
			||||||
                    InfestedFoundry: infestedFoundry
 | 
					                    InfestedFoundry: inventory.toJSON().InfestedFoundry
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
@ -291,13 +272,11 @@ export const infestedFoundryController: RequestHandler = async (req, res) => {
 | 
				
			|||||||
            const currencyChanges = updateCurrency(inventory, 50, true);
 | 
					            const currencyChanges = updateCurrency(inventory, 50, true);
 | 
				
			||||||
            const recipeChanges = handleSubsumeCompletion(inventory);
 | 
					            const recipeChanges = handleSubsumeCompletion(inventory);
 | 
				
			||||||
            await inventory.save();
 | 
					            await inventory.save();
 | 
				
			||||||
            const infestedFoundry = inventory.toJSON<IInventoryClient>().InfestedFoundry!;
 | 
					 | 
				
			||||||
            applyCheatsToInfestedFoundry(infestedFoundry);
 | 
					 | 
				
			||||||
            res.json({
 | 
					            res.json({
 | 
				
			||||||
                InventoryChanges: {
 | 
					                InventoryChanges: {
 | 
				
			||||||
                    ...currencyChanges,
 | 
					                    ...currencyChanges,
 | 
				
			||||||
                    Recipes: recipeChanges,
 | 
					                    Recipes: recipeChanges,
 | 
				
			||||||
                    InfestedFoundry: infestedFoundry
 | 
					                    InfestedFoundry: inventory.toJSON().InfestedFoundry
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
@ -313,17 +292,13 @@ export const infestedFoundryController: RequestHandler = async (req, res) => {
 | 
				
			|||||||
            suit.UpgradesExpiry = upgradesExpiry;
 | 
					            suit.UpgradesExpiry = upgradesExpiry;
 | 
				
			||||||
            const recipeChanges = addInfestedFoundryXP(inventory.InfestedFoundry!, 4800_00);
 | 
					            const recipeChanges = addInfestedFoundryXP(inventory.InfestedFoundry!, 4800_00);
 | 
				
			||||||
            addRecipes(inventory, recipeChanges);
 | 
					            addRecipes(inventory, recipeChanges);
 | 
				
			||||||
            if (!config.infiniteHelminthMaterials) {
 | 
					 | 
				
			||||||
            for (let i = 0; i != request.ResourceTypes.length; ++i) {
 | 
					            for (let i = 0; i != request.ResourceTypes.length; ++i) {
 | 
				
			||||||
                inventory.InfestedFoundry!.Resources!.find(x => x.ItemType == request.ResourceTypes[i])!.Count -=
 | 
					                inventory.InfestedFoundry!.Resources!.find(x => x.ItemType == request.ResourceTypes[i])!.Count -=
 | 
				
			||||||
                    request.ResourceCosts[i];
 | 
					                    request.ResourceCosts[i];
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            inventory.InfestedFoundry!.InvigorationsApplied ??= 0;
 | 
					            inventory.InfestedFoundry!.InvigorationsApplied ??= 0;
 | 
				
			||||||
            inventory.InfestedFoundry!.InvigorationsApplied += 1;
 | 
					            inventory.InfestedFoundry!.InvigorationsApplied += 1;
 | 
				
			||||||
            await inventory.save();
 | 
					            await inventory.save();
 | 
				
			||||||
            const infestedFoundry = inventory.toJSON<IInventoryClient>().InfestedFoundry!;
 | 
					 | 
				
			||||||
            applyCheatsToInfestedFoundry(infestedFoundry);
 | 
					 | 
				
			||||||
            res.json({
 | 
					            res.json({
 | 
				
			||||||
                SuitId: request.SuitId,
 | 
					                SuitId: request.SuitId,
 | 
				
			||||||
                OffensiveUpgrade: request.OffensiveUpgradeType,
 | 
					                OffensiveUpgrade: request.OffensiveUpgradeType,
 | 
				
			||||||
@ -331,7 +306,7 @@ export const infestedFoundryController: RequestHandler = async (req, res) => {
 | 
				
			|||||||
                UpgradesExpiry: toMongoDate(upgradesExpiry),
 | 
					                UpgradesExpiry: toMongoDate(upgradesExpiry),
 | 
				
			||||||
                InventoryChanges: {
 | 
					                InventoryChanges: {
 | 
				
			||||||
                    Recipes: recipeChanges,
 | 
					                    Recipes: recipeChanges,
 | 
				
			||||||
                    InfestedFoundry: infestedFoundry
 | 
					                    InfestedFoundry: inventory.toJSON().InfestedFoundry
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
@ -478,19 +453,6 @@ export const handleSubsumeCompletion = (inventory: TInventoryDatabaseDocument):
 | 
				
			|||||||
    return recipeChanges;
 | 
					    return recipeChanges;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const applyCheatsToInfestedFoundry = (infestedFoundry: IInfestedFoundryClient): void => {
 | 
					 | 
				
			||||||
    if (config.infiniteHelminthMaterials) {
 | 
					 | 
				
			||||||
        infestedFoundry.Resources = [
 | 
					 | 
				
			||||||
            { ItemType: "/Lotus/Types/Items/InfestedFoundry/HelminthCalx", Count: 1000 },
 | 
					 | 
				
			||||||
            { ItemType: "/Lotus/Types/Items/InfestedFoundry/HelminthBiotics", Count: 1000 },
 | 
					 | 
				
			||||||
            { ItemType: "/Lotus/Types/Items/InfestedFoundry/HelminthSynthetics", Count: 1000 },
 | 
					 | 
				
			||||||
            { ItemType: "/Lotus/Types/Items/InfestedFoundry/HelminthPheromones", Count: 1000 },
 | 
					 | 
				
			||||||
            { ItemType: "/Lotus/Types/Items/InfestedFoundry/HelminthBile", Count: 1000 },
 | 
					 | 
				
			||||||
            { ItemType: "/Lotus/Types/Items/InfestedFoundry/HelminthOxides", Count: 1000 }
 | 
					 | 
				
			||||||
        ];
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
interface IHelminthOfferingsUpdate {
 | 
					interface IHelminthOfferingsUpdate {
 | 
				
			||||||
    OfferingsIndex: number;
 | 
					    OfferingsIndex: number;
 | 
				
			||||||
    SuitTypes: string[];
 | 
					    SuitTypes: string[];
 | 
				
			||||||
 | 
				
			|||||||
@ -13,7 +13,7 @@ import {
 | 
				
			|||||||
    ExportResources,
 | 
					    ExportResources,
 | 
				
			||||||
    ExportVirtuals
 | 
					    ExportVirtuals
 | 
				
			||||||
} from "warframe-public-export-plus";
 | 
					} from "warframe-public-export-plus";
 | 
				
			||||||
import { applyCheatsToInfestedFoundry, handleSubsumeCompletion } from "./infestedFoundryController";
 | 
					import { handleSubsumeCompletion } from "./infestedFoundryController";
 | 
				
			||||||
import { allDailyAffiliationKeys } from "@/src/services/inventoryService";
 | 
					import { allDailyAffiliationKeys } from "@/src/services/inventoryService";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const inventoryController: RequestHandler = async (request, response) => {
 | 
					export const inventoryController: RequestHandler = async (request, response) => {
 | 
				
			||||||
@ -212,10 +212,6 @@ export const getInventoryResponse = async (
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (inventoryResponse.InfestedFoundry) {
 | 
					 | 
				
			||||||
        applyCheatsToInfestedFoundry(inventoryResponse.InfestedFoundry);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Fix for #380
 | 
					    // Fix for #380
 | 
				
			||||||
    inventoryResponse.NextRefill = { $date: { $numberLong: "9999999999999" } };
 | 
					    inventoryResponse.NextRefill = { $date: { $numberLong: "9999999999999" } };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -6,6 +6,7 @@ import { buildConfig } from "@/src/services/buildConfigService";
 | 
				
			|||||||
import { Account } from "@/src/models/loginModel";
 | 
					import { Account } from "@/src/models/loginModel";
 | 
				
			||||||
import { createAccount, isCorrectPassword, isNameTaken } from "@/src/services/loginService";
 | 
					import { createAccount, isCorrectPassword, isNameTaken } from "@/src/services/loginService";
 | 
				
			||||||
import { IDatabaseAccountJson, ILoginRequest, ILoginResponse } from "@/src/types/loginTypes";
 | 
					import { IDatabaseAccountJson, ILoginRequest, ILoginResponse } from "@/src/types/loginTypes";
 | 
				
			||||||
 | 
					import { DTLS, groups, HUB, platformCDNs } from "@/static/fixed_responses/login_static";
 | 
				
			||||||
import { logger } from "@/src/utils/logger";
 | 
					import { logger } from "@/src/utils/logger";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const loginController: RequestHandler = async (request, response) => {
 | 
					export const loginController: RequestHandler = async (request, response) => {
 | 
				
			||||||
@ -83,12 +84,12 @@ const createLoginResponse = (account: IDatabaseAccountJson, buildLabel: string):
 | 
				
			|||||||
        ConsentNeeded: account.ConsentNeeded,
 | 
					        ConsentNeeded: account.ConsentNeeded,
 | 
				
			||||||
        TrackedSettings: account.TrackedSettings,
 | 
					        TrackedSettings: account.TrackedSettings,
 | 
				
			||||||
        Nonce: account.Nonce,
 | 
					        Nonce: account.Nonce,
 | 
				
			||||||
        Groups: [],
 | 
					        Groups: groups,
 | 
				
			||||||
 | 
					        platformCDNs: platformCDNs,
 | 
				
			||||||
 | 
					        NRS: [config.myAddress],
 | 
				
			||||||
 | 
					        DTLS: DTLS,
 | 
				
			||||||
        IRC: config.myIrcAddresses ?? [config.myAddress],
 | 
					        IRC: config.myIrcAddresses ?? [config.myAddress],
 | 
				
			||||||
        platformCDNs: config.platformCDNs,
 | 
					        HUB: HUB,
 | 
				
			||||||
        HUB: config.hubAddress,
 | 
					 | 
				
			||||||
        NRS: config.NRS,
 | 
					 | 
				
			||||||
        DTLS: 99,
 | 
					 | 
				
			||||||
        BuildLabel: buildLabel,
 | 
					        BuildLabel: buildLabel,
 | 
				
			||||||
        MatchmakingBuildId: buildConfig.matchmakingBuildId
 | 
					        MatchmakingBuildId: buildConfig.matchmakingBuildId
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
				
			|||||||
@ -2,14 +2,7 @@ import { RequestHandler } from "express";
 | 
				
			|||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
					import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
				
			||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
 | 
					import { getJSONfromString } from "@/src/helpers/stringHelpers";
 | 
				
			||||||
import { TEquipmentKey } from "@/src/types/inventoryTypes/inventoryTypes";
 | 
					import { TEquipmentKey } from "@/src/types/inventoryTypes/inventoryTypes";
 | 
				
			||||||
import {
 | 
					import { getInventory, updateCurrency, addEquipment, addMiscItems } from "@/src/services/inventoryService";
 | 
				
			||||||
    getInventory,
 | 
					 | 
				
			||||||
    updateCurrency,
 | 
					 | 
				
			||||||
    addEquipment,
 | 
					 | 
				
			||||||
    addMiscItems,
 | 
					 | 
				
			||||||
    applyDefaultUpgrades
 | 
					 | 
				
			||||||
} from "@/src/services/inventoryService";
 | 
					 | 
				
			||||||
import { ExportWeapons } from "warframe-public-export-plus";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
const modularWeaponTypes: Record<string, TEquipmentKey> = {
 | 
					const modularWeaponTypes: Record<string, TEquipmentKey> = {
 | 
				
			||||||
    "/Lotus/Weapons/SolarisUnited/Primary/LotusModularPrimary": "LongGuns",
 | 
					    "/Lotus/Weapons/SolarisUnited/Primary/LotusModularPrimary": "LongGuns",
 | 
				
			||||||
@ -43,11 +36,8 @@ export const modularWeaponCraftingController: RequestHandler = async (req, res)
 | 
				
			|||||||
    const category = modularWeaponTypes[data.WeaponType];
 | 
					    const category = modularWeaponTypes[data.WeaponType];
 | 
				
			||||||
    const inventory = await getInventory(accountId);
 | 
					    const inventory = await getInventory(accountId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
 | 
					 | 
				
			||||||
    const configs = applyDefaultUpgrades(inventory, ExportWeapons[data.Parts[0]]?.defaultUpgrades);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Give weapon
 | 
					    // Give weapon
 | 
				
			||||||
    const inventoryChanges = addEquipment(inventory, category, data.WeaponType, data.Parts, {}, { Configs: configs });
 | 
					    const weapon = addEquipment(inventory, category, data.WeaponType, data.Parts);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Remove credits & parts
 | 
					    // Remove credits & parts
 | 
				
			||||||
    const miscItemChanges = [];
 | 
					    const miscItemChanges = [];
 | 
				
			||||||
@ -68,8 +58,8 @@ export const modularWeaponCraftingController: RequestHandler = async (req, res)
 | 
				
			|||||||
    // Tell client what we did
 | 
					    // Tell client what we did
 | 
				
			||||||
    res.json({
 | 
					    res.json({
 | 
				
			||||||
        InventoryChanges: {
 | 
					        InventoryChanges: {
 | 
				
			||||||
            ...inventoryChanges,
 | 
					 | 
				
			||||||
            ...currencyChanges,
 | 
					            ...currencyChanges,
 | 
				
			||||||
 | 
					            [category]: [weapon],
 | 
				
			||||||
            MiscItems: miscItemChanges
 | 
					            MiscItems: miscItemChanges
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
				
			|||||||
@ -50,7 +50,6 @@ const qualityKeywordToNumber: Record<VoidProjectionQuality, number> = {
 | 
				
			|||||||
// e.g. "/Lotus/Types/Game/Projections/T2VoidProjectionProteaPrimeDBronze" -> ["Lith", "W5", "VPQ_BRONZE"]
 | 
					// e.g. "/Lotus/Types/Game/Projections/T2VoidProjectionProteaPrimeDBronze" -> ["Lith", "W5", "VPQ_BRONZE"]
 | 
				
			||||||
const parseProjection = (typeName: string): [string, string, VoidProjectionQuality] => {
 | 
					const parseProjection = (typeName: string): [string, string, VoidProjectionQuality] => {
 | 
				
			||||||
    const relic: IRelic | undefined = ExportRelics[typeName];
 | 
					    const relic: IRelic | undefined = ExportRelics[typeName];
 | 
				
			||||||
    // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
 | 
					 | 
				
			||||||
    if (!relic) {
 | 
					    if (!relic) {
 | 
				
			||||||
        throw new Error(`Unknown projection ${typeName}`);
 | 
					        throw new Error(`Unknown projection ${typeName}`);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -2,8 +2,8 @@ import { RequestHandler } from "express";
 | 
				
			|||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
					import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
				
			||||||
import { addMiscItems, getInventory } from "@/src/services/inventoryService";
 | 
					import { addMiscItems, getInventory } from "@/src/services/inventoryService";
 | 
				
			||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
 | 
					import { getJSONfromString } from "@/src/helpers/stringHelpers";
 | 
				
			||||||
import { IUnveiledRivenFingerprint, randomiseRivenStats } from "@/src/helpers/rivenFingerprintHelper";
 | 
					 | 
				
			||||||
import { ExportUpgrades } from "warframe-public-export-plus";
 | 
					import { ExportUpgrades } from "warframe-public-export-plus";
 | 
				
			||||||
 | 
					import { getRandomElement } from "@/src/services/rngService";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const rerollRandomModController: RequestHandler = async (req, res) => {
 | 
					export const rerollRandomModController: RequestHandler = async (req, res) => {
 | 
				
			||||||
    const accountId = await getAccountIdForRequest(req);
 | 
					    const accountId = await getAccountIdForRequest(req);
 | 
				
			||||||
@ -25,7 +25,7 @@ export const rerollRandomModController: RequestHandler = async (req, res) => {
 | 
				
			|||||||
        fingerprint.rerolls++;
 | 
					        fingerprint.rerolls++;
 | 
				
			||||||
        upgrade.UpgradeFingerprint = JSON.stringify(fingerprint);
 | 
					        upgrade.UpgradeFingerprint = JSON.stringify(fingerprint);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        randomiseRivenStats(ExportUpgrades[upgrade.ItemType], fingerprint);
 | 
					        randomiseStats(upgrade.ItemType, fingerprint);
 | 
				
			||||||
        upgrade.PendingRerollFingerprint = JSON.stringify(fingerprint);
 | 
					        upgrade.PendingRerollFingerprint = JSON.stringify(fingerprint);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        await inventory.save();
 | 
					        await inventory.save();
 | 
				
			||||||
@ -52,6 +52,28 @@ export const rerollRandomModController: RequestHandler = async (req, res) => {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const randomiseStats = (randomModType: string, fingerprint: IUnveiledRivenFingerprint): void => {
 | 
				
			||||||
 | 
					    const meta = ExportUpgrades[randomModType];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fingerprint.buffs = [];
 | 
				
			||||||
 | 
					    const numBuffs = 2 + Math.trunc(Math.random() * 2); // 2 or 3
 | 
				
			||||||
 | 
					    const buffEntries = meta.upgradeEntries!.filter(x => x.canBeBuff);
 | 
				
			||||||
 | 
					    for (let i = 0; i != numBuffs; ++i) {
 | 
				
			||||||
 | 
					        const buffIndex = Math.trunc(Math.random() * buffEntries.length);
 | 
				
			||||||
 | 
					        const entry = buffEntries[buffIndex];
 | 
				
			||||||
 | 
					        fingerprint.buffs.push({ Tag: entry.tag, Value: Math.trunc(Math.random() * 0x40000000) });
 | 
				
			||||||
 | 
					        buffEntries.splice(buffIndex, 1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fingerprint.curses = [];
 | 
				
			||||||
 | 
					    if (Math.random() < 0.5) {
 | 
				
			||||||
 | 
					        const entry = getRandomElement(
 | 
				
			||||||
 | 
					            meta.upgradeEntries!.filter(x => x.canBeCurse && !fingerprint.buffs.find(y => y.Tag == x.tag))
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        fingerprint.curses.push({ Tag: entry.tag, Value: Math.trunc(Math.random() * 0x40000000) });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type RerollRandomModRequest = LetsGoGamblingRequest | AwDangitRequest;
 | 
					type RerollRandomModRequest = LetsGoGamblingRequest | AwDangitRequest;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface LetsGoGamblingRequest {
 | 
					interface LetsGoGamblingRequest {
 | 
				
			||||||
@ -63,4 +85,20 @@ interface AwDangitRequest {
 | 
				
			|||||||
    CommitReroll: boolean;
 | 
					    CommitReroll: boolean;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface IUnveiledRivenFingerprint {
 | 
				
			||||||
 | 
					    compat: string;
 | 
				
			||||||
 | 
					    lim: number;
 | 
				
			||||||
 | 
					    lvl: number;
 | 
				
			||||||
 | 
					    lvlReq: 0;
 | 
				
			||||||
 | 
					    rerolls?: number;
 | 
				
			||||||
 | 
					    pol: string;
 | 
				
			||||||
 | 
					    buffs: IRivenStat[];
 | 
				
			||||||
 | 
					    curses: IRivenStat[];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface IRivenStat {
 | 
				
			||||||
 | 
					    Tag: string;
 | 
				
			||||||
 | 
					    Value: number;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const rerollCosts = [900, 1000, 1200, 1400, 1700, 2000, 2350, 2750, 3150];
 | 
					const rerollCosts = [900, 1000, 1200, 1400, 1700, 2000, 2350, 2750, 3150];
 | 
				
			||||||
 | 
				
			|||||||
@ -12,7 +12,6 @@ import { addMiscItems, addRecipes, getInventory, updateCurrency } from "@/src/se
 | 
				
			|||||||
import { getRecipeByResult } from "@/src/services/itemDataService";
 | 
					import { getRecipeByResult } from "@/src/services/itemDataService";
 | 
				
			||||||
import { IInventoryChanges } from "@/src/types/purchaseTypes";
 | 
					import { IInventoryChanges } from "@/src/types/purchaseTypes";
 | 
				
			||||||
import { addInfestedFoundryXP } from "./infestedFoundryController";
 | 
					import { addInfestedFoundryXP } from "./infestedFoundryController";
 | 
				
			||||||
import { config } from "@/src/services/configService";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const upgradesController: RequestHandler = async (req, res) => {
 | 
					export const upgradesController: RequestHandler = async (req, res) => {
 | 
				
			||||||
    const accountId = await getAccountIdForRequest(req);
 | 
					    const accountId = await getAccountIdForRequest(req);
 | 
				
			||||||
@ -49,12 +48,10 @@ export const upgradesController: RequestHandler = async (req, res) => {
 | 
				
			|||||||
                const recipe = getRecipeByResult(operation.UpgradeRequirement)!;
 | 
					                const recipe = getRecipeByResult(operation.UpgradeRequirement)!;
 | 
				
			||||||
                for (const ingredient of recipe.ingredients) {
 | 
					                for (const ingredient of recipe.ingredients) {
 | 
				
			||||||
                    totalPercentagePointsConsumed += ingredient.ItemCount / 10;
 | 
					                    totalPercentagePointsConsumed += ingredient.ItemCount / 10;
 | 
				
			||||||
                    if (!config.infiniteHelminthMaterials) {
 | 
					 | 
				
			||||||
                    inventory.InfestedFoundry!.Resources!.find(x => x.ItemType == ingredient.ItemType)!.Count -=
 | 
					                    inventory.InfestedFoundry!.Resources!.find(x => x.ItemType == ingredient.ItemType)!.Count -=
 | 
				
			||||||
                        ingredient.ItemCount;
 | 
					                        ingredient.ItemCount;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            for (const entry of operation.PolarityRemap) {
 | 
					            for (const entry of operation.PolarityRemap) {
 | 
				
			||||||
                suit.Configs[entry.Slot] ??= {};
 | 
					                suit.Configs[entry.Slot] ??= {};
 | 
				
			||||||
 | 
				
			|||||||
@ -39,12 +39,18 @@ const getItemListsController: RequestHandler = (req, response) => {
 | 
				
			|||||||
    res.miscitems = [];
 | 
					    res.miscitems = [];
 | 
				
			||||||
    res.Syndicates = [];
 | 
					    res.Syndicates = [];
 | 
				
			||||||
    for (const [uniqueName, item] of Object.entries(ExportWarframes)) {
 | 
					    for (const [uniqueName, item] of Object.entries(ExportWarframes)) {
 | 
				
			||||||
 | 
					        if (
 | 
				
			||||||
 | 
					            item.productCategory == "Suits" ||
 | 
				
			||||||
 | 
					            item.productCategory == "SpaceSuits" ||
 | 
				
			||||||
 | 
					            item.productCategory == "MechSuits"
 | 
				
			||||||
 | 
					        ) {
 | 
				
			||||||
            res[item.productCategory].push({
 | 
					            res[item.productCategory].push({
 | 
				
			||||||
                uniqueName,
 | 
					                uniqueName,
 | 
				
			||||||
                name: getString(item.name, lang),
 | 
					                name: getString(item.name, lang),
 | 
				
			||||||
                exalted: item.exalted
 | 
					                exalted: item.exalted
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    for (const [uniqueName, item] of Object.entries(ExportSentinels)) {
 | 
					    for (const [uniqueName, item] of Object.entries(ExportSentinels)) {
 | 
				
			||||||
        if (item.productCategory == "Sentinels") {
 | 
					        if (item.productCategory == "Sentinels") {
 | 
				
			||||||
            res[item.productCategory].push({
 | 
					            res[item.productCategory].push({
 | 
				
			||||||
@ -59,10 +65,7 @@ const getItemListsController: RequestHandler = (req, response) => {
 | 
				
			|||||||
            uniqueName.split("/")[5] == "SUModularSecondarySet1" ||
 | 
					            uniqueName.split("/")[5] == "SUModularSecondarySet1" ||
 | 
				
			||||||
            uniqueName.split("/")[5] == "SUModularPrimarySet1" ||
 | 
					            uniqueName.split("/")[5] == "SUModularPrimarySet1" ||
 | 
				
			||||||
            uniqueName.split("/")[5] == "InfKitGun" ||
 | 
					            uniqueName.split("/")[5] == "InfKitGun" ||
 | 
				
			||||||
            uniqueName.split("/")[5] == "HoverboardParts" ||
 | 
					            uniqueName.split("/")[5] == "HoverboardParts"
 | 
				
			||||||
            uniqueName.split("/")[5] == "ModularMelee01" ||
 | 
					 | 
				
			||||||
            uniqueName.split("/")[5] == "ModularMelee02" ||
 | 
					 | 
				
			||||||
            uniqueName.split("/")[5] == "ModularMeleeInfested"
 | 
					 | 
				
			||||||
        ) {
 | 
					        ) {
 | 
				
			||||||
            res.ModularParts.push({
 | 
					            res.ModularParts.push({
 | 
				
			||||||
                uniqueName,
 | 
					                uniqueName,
 | 
				
			||||||
 | 
				
			|||||||
@ -13,8 +13,7 @@ export const manageQuestsController: RequestHandler = async (req, res) => {
 | 
				
			|||||||
        | "completeAll"
 | 
					        | "completeAll"
 | 
				
			||||||
        | "ResetAll"
 | 
					        | "ResetAll"
 | 
				
			||||||
        | "completeAllUnlocked"
 | 
					        | "completeAllUnlocked"
 | 
				
			||||||
        | "updateKey"
 | 
					        | "updateKey";
 | 
				
			||||||
        | "giveAll";
 | 
					 | 
				
			||||||
    const questKeyUpdate = req.body as IUpdateQuestRequest["QuestKeys"];
 | 
					    const questKeyUpdate = req.body as IUpdateQuestRequest["QuestKeys"];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const allQuestKeys: string[] = [];
 | 
					    const allQuestKeys: string[] = [];
 | 
				
			||||||
@ -63,6 +62,8 @@ export const manageQuestsController: RequestHandler = async (req, res) => {
 | 
				
			|||||||
                    inventory.ArchwingEnabled = true;
 | 
					                    inventory.ArchwingEnabled = true;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            inventory.ActiveQuest = "";
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        case "ResetAll": {
 | 
					        case "ResetAll": {
 | 
				
			||||||
@ -70,7 +71,6 @@ export const manageQuestsController: RequestHandler = async (req, res) => {
 | 
				
			|||||||
            for (const questKey of inventory.QuestKeys) {
 | 
					            for (const questKey of inventory.QuestKeys) {
 | 
				
			||||||
                questKey.Completed = false;
 | 
					                questKey.Completed = false;
 | 
				
			||||||
                questKey.Progress = [];
 | 
					                questKey.Progress = [];
 | 
				
			||||||
                questKey.CompletionDate = undefined;
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            inventory.ActiveQuest = "";
 | 
					            inventory.ActiveQuest = "";
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
@ -78,6 +78,7 @@ export const manageQuestsController: RequestHandler = async (req, res) => {
 | 
				
			|||||||
        case "completeAllUnlocked": {
 | 
					        case "completeAllUnlocked": {
 | 
				
			||||||
            logger.info("completing all unlocked quests..");
 | 
					            logger.info("completing all unlocked quests..");
 | 
				
			||||||
            for (const questKey of inventory.QuestKeys) {
 | 
					            for (const questKey of inventory.QuestKeys) {
 | 
				
			||||||
 | 
					                console.log("size of questkeys", inventory.QuestKeys.length);
 | 
				
			||||||
                try {
 | 
					                try {
 | 
				
			||||||
                    await completeQuest(inventory, questKey.ItemType);
 | 
					                    await completeQuest(inventory, questKey.ItemType);
 | 
				
			||||||
                } catch (error) {
 | 
					                } catch (error) {
 | 
				
			||||||
@ -101,12 +102,7 @@ export const manageQuestsController: RequestHandler = async (req, res) => {
 | 
				
			|||||||
                    inventory.ArchwingEnabled = true;
 | 
					                    inventory.ArchwingEnabled = true;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            break;
 | 
					            inventory.ActiveQuest = "";
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        case "giveAll": {
 | 
					 | 
				
			||||||
            for (const questKey of allQuestKeys) {
 | 
					 | 
				
			||||||
                addQuestKey(inventory, { ItemType: questKey });
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -1,60 +0,0 @@
 | 
				
			|||||||
import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
 | 
					 | 
				
			||||||
import { IVoidTearParticipantInfo } from "@/src/types/requestTypes";
 | 
					 | 
				
			||||||
import { ExportRelics, ExportRewards, TRarity } from "warframe-public-export-plus";
 | 
					 | 
				
			||||||
import { getRandomWeightedReward2 } from "@/src/services/rngService";
 | 
					 | 
				
			||||||
import { logger } from "@/src/utils/logger";
 | 
					 | 
				
			||||||
import { addMiscItems } from "@/src/services/inventoryService";
 | 
					 | 
				
			||||||
import { handleStoreItemAcquisition } from "@/src/services/purchaseService";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const crackRelic = async (
 | 
					 | 
				
			||||||
    inventory: TInventoryDatabaseDocument,
 | 
					 | 
				
			||||||
    participant: IVoidTearParticipantInfo
 | 
					 | 
				
			||||||
): Promise<void> => {
 | 
					 | 
				
			||||||
    const relic = ExportRelics[participant.VoidProjection];
 | 
					 | 
				
			||||||
    const weights = refinementToWeights[relic.quality];
 | 
					 | 
				
			||||||
    logger.debug(`opening a relic of quality ${relic.quality}; rarity weights are`, weights);
 | 
					 | 
				
			||||||
    const reward = getRandomWeightedReward2(
 | 
					 | 
				
			||||||
        ExportRewards[relic.rewardManifest][0] as { type: string; itemCount: number; rarity: TRarity }[], // rarity is nullable in PE+ typings, but always present for relics
 | 
					 | 
				
			||||||
        weights
 | 
					 | 
				
			||||||
    )!;
 | 
					 | 
				
			||||||
    logger.debug(`relic rolled`, reward);
 | 
					 | 
				
			||||||
    participant.Reward = reward.type;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Remove relic
 | 
					 | 
				
			||||||
    addMiscItems(inventory, [
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            ItemType: participant.VoidProjection,
 | 
					 | 
				
			||||||
            ItemCount: -1
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    ]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Give reward
 | 
					 | 
				
			||||||
    await handleStoreItemAcquisition(reward.type, inventory, reward.itemCount);
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const refinementToWeights = {
 | 
					 | 
				
			||||||
    VPQ_BRONZE: {
 | 
					 | 
				
			||||||
        COMMON: 0.76,
 | 
					 | 
				
			||||||
        UNCOMMON: 0.22,
 | 
					 | 
				
			||||||
        RARE: 0.02,
 | 
					 | 
				
			||||||
        LEGENDARY: 0
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    VPQ_SILVER: {
 | 
					 | 
				
			||||||
        COMMON: 0.7,
 | 
					 | 
				
			||||||
        UNCOMMON: 0.26,
 | 
					 | 
				
			||||||
        RARE: 0.04,
 | 
					 | 
				
			||||||
        LEGENDARY: 0
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    VPQ_GOLD: {
 | 
					 | 
				
			||||||
        COMMON: 0.6,
 | 
					 | 
				
			||||||
        UNCOMMON: 0.34,
 | 
					 | 
				
			||||||
        RARE: 0.06,
 | 
					 | 
				
			||||||
        LEGENDARY: 0
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    VPQ_PLATINUM: {
 | 
					 | 
				
			||||||
        COMMON: 0.5,
 | 
					 | 
				
			||||||
        UNCOMMON: 0.4,
 | 
					 | 
				
			||||||
        RARE: 0.1,
 | 
					 | 
				
			||||||
        LEGENDARY: 0
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
@ -1,38 +0,0 @@
 | 
				
			|||||||
import { IUpgrade } from "warframe-public-export-plus";
 | 
					 | 
				
			||||||
import { getRandomElement } from "../services/rngService";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export interface IUnveiledRivenFingerprint {
 | 
					 | 
				
			||||||
    compat: string;
 | 
					 | 
				
			||||||
    lim: 0;
 | 
					 | 
				
			||||||
    lvl: number;
 | 
					 | 
				
			||||||
    lvlReq: number;
 | 
					 | 
				
			||||||
    rerolls?: number;
 | 
					 | 
				
			||||||
    pol: string;
 | 
					 | 
				
			||||||
    buffs: IRivenStat[];
 | 
					 | 
				
			||||||
    curses: IRivenStat[];
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
interface IRivenStat {
 | 
					 | 
				
			||||||
    Tag: string;
 | 
					 | 
				
			||||||
    Value: number;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const randomiseRivenStats = (meta: IUpgrade, fingerprint: IUnveiledRivenFingerprint): void => {
 | 
					 | 
				
			||||||
    fingerprint.buffs = [];
 | 
					 | 
				
			||||||
    const numBuffs = 2 + Math.trunc(Math.random() * 2); // 2 or 3
 | 
					 | 
				
			||||||
    const buffEntries = meta.upgradeEntries!.filter(x => x.canBeBuff);
 | 
					 | 
				
			||||||
    for (let i = 0; i != numBuffs; ++i) {
 | 
					 | 
				
			||||||
        const buffIndex = Math.trunc(Math.random() * buffEntries.length);
 | 
					 | 
				
			||||||
        const entry = buffEntries[buffIndex];
 | 
					 | 
				
			||||||
        fingerprint.buffs.push({ Tag: entry.tag, Value: Math.trunc(Math.random() * 0x40000000) });
 | 
					 | 
				
			||||||
        buffEntries.splice(buffIndex, 1);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fingerprint.curses = [];
 | 
					 | 
				
			||||||
    if (Math.random() < 0.5) {
 | 
					 | 
				
			||||||
        const entry = getRandomElement(
 | 
					 | 
				
			||||||
            meta.upgradeEntries!.filter(x => x.canBeCurse && !fingerprint.buffs.find(y => y.Tag == x.tag))
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
        fingerprint.curses.push({ Tag: entry.tag, Value: Math.trunc(Math.random() * 0x40000000) });
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
@ -25,10 +25,8 @@ mongoose
 | 
				
			|||||||
            cert: fs.readFileSync("static/certs/cert.pem")
 | 
					            cert: fs.readFileSync("static/certs/cert.pem")
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // eslint-disable-next-line @typescript-eslint/no-misused-promises
 | 
					 | 
				
			||||||
        http.createServer(app).listen(httpPort, () => {
 | 
					        http.createServer(app).listen(httpPort, () => {
 | 
				
			||||||
            logger.info("HTTP server started on port " + httpPort);
 | 
					            logger.info("HTTP server started on port " + httpPort);
 | 
				
			||||||
            // eslint-disable-next-line @typescript-eslint/no-misused-promises
 | 
					 | 
				
			||||||
            https.createServer(options, app).listen(httpsPort, () => {
 | 
					            https.createServer(options, app).listen(httpsPort, () => {
 | 
				
			||||||
                logger.info("HTTPS server started on port " + httpsPort);
 | 
					                logger.info("HTTPS server started on port " + httpsPort);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -64,13 +64,7 @@ import {
 | 
				
			|||||||
    IKubrowPetEggClient,
 | 
					    IKubrowPetEggClient,
 | 
				
			||||||
    ICustomMarkers,
 | 
					    ICustomMarkers,
 | 
				
			||||||
    IMarkerInfo,
 | 
					    IMarkerInfo,
 | 
				
			||||||
    IMarker,
 | 
					    IMarker
 | 
				
			||||||
    ICalendarProgress,
 | 
					 | 
				
			||||||
    IPendingCouponDatabase,
 | 
					 | 
				
			||||||
    IPendingCouponClient,
 | 
					 | 
				
			||||||
    ILibraryAvailableDailyTaskInfo,
 | 
					 | 
				
			||||||
    IDroneDatabase,
 | 
					 | 
				
			||||||
    IDroneClient
 | 
					 | 
				
			||||||
} from "../../types/inventoryTypes/inventoryTypes";
 | 
					} from "../../types/inventoryTypes/inventoryTypes";
 | 
				
			||||||
import { IOid } from "../../types/commonTypes";
 | 
					import { IOid } from "../../types/commonTypes";
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
@ -329,7 +323,7 @@ MailboxSchema.set("toJSON", {
 | 
				
			|||||||
const DuviriInfoSchema = new Schema<IDuviriInfo>(
 | 
					const DuviriInfoSchema = new Schema<IDuviriInfo>(
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        Seed: Number,
 | 
					        Seed: Number,
 | 
				
			||||||
        NumCompletions: { type: Number, default: 0 }
 | 
					        NumCompletions: Number
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        _id: false,
 | 
					        _id: false,
 | 
				
			||||||
@ -351,27 +345,6 @@ const TypeXPItemSchema = new Schema<ITypeXPItem>(
 | 
				
			|||||||
    { _id: false }
 | 
					    { _id: false }
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const droneSchema = new Schema<IDroneDatabase>(
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        ItemType: String,
 | 
					 | 
				
			||||||
        CurrentHP: Number,
 | 
					 | 
				
			||||||
        RepairStart: { type: Date, default: undefined }
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    { id: false }
 | 
					 | 
				
			||||||
);
 | 
					 | 
				
			||||||
droneSchema.set("toJSON", {
 | 
					 | 
				
			||||||
    virtuals: true,
 | 
					 | 
				
			||||||
    transform(_document, obj) {
 | 
					 | 
				
			||||||
        const client = obj as IDroneClient;
 | 
					 | 
				
			||||||
        const db = obj as IDroneDatabase;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        client.ItemId = toOid(db._id);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        delete obj._id;
 | 
					 | 
				
			||||||
        delete obj.__v;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const challengeProgressSchema = new Schema<IChallengeProgress>(
 | 
					const challengeProgressSchema = new Schema<IChallengeProgress>(
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        Progress: Number,
 | 
					        Progress: Number,
 | 
				
			||||||
@ -462,7 +435,6 @@ const seasonChallengeHistorySchema = new Schema<ISeasonChallenge>(
 | 
				
			|||||||
//TODO: check whether this is complete
 | 
					//TODO: check whether this is complete
 | 
				
			||||||
const playerSkillsSchema = new Schema<IPlayerSkills>(
 | 
					const playerSkillsSchema = new Schema<IPlayerSkills>(
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        LPP_NONE: { type: Number, default: 0 },
 | 
					 | 
				
			||||||
        LPP_SPACE: { type: Number, default: 0 },
 | 
					        LPP_SPACE: { type: Number, default: 0 },
 | 
				
			||||||
        LPS_PILOTING: { type: Number, default: 0 },
 | 
					        LPS_PILOTING: { type: Number, default: 0 },
 | 
				
			||||||
        LPS_GUNNERY: { type: Number, default: 0 },
 | 
					        LPS_GUNNERY: { type: Number, default: 0 },
 | 
				
			||||||
@ -532,7 +504,7 @@ const questProgressSchema = new Schema<IQuestStage>(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const questKeysSchema = new Schema<IQuestKeyDatabase>(
 | 
					const questKeysSchema = new Schema<IQuestKeyDatabase>(
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        Progress: { type: [questProgressSchema], default: [] },
 | 
					        Progress: { type: [questProgressSchema], default: undefined },
 | 
				
			||||||
        unlock: Boolean,
 | 
					        unlock: Boolean,
 | 
				
			||||||
        Completed: Boolean,
 | 
					        Completed: Boolean,
 | 
				
			||||||
        CustomData: String,
 | 
					        CustomData: String,
 | 
				
			||||||
@ -808,7 +780,7 @@ detailsSchema.set("toJSON", {
 | 
				
			|||||||
const EquipmentSchema = new Schema<IEquipmentDatabase>(
 | 
					const EquipmentSchema = new Schema<IEquipmentDatabase>(
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        ItemType: String,
 | 
					        ItemType: String,
 | 
				
			||||||
        Configs: { type: [ItemConfigSchema], default: [] },
 | 
					        Configs: [ItemConfigSchema],
 | 
				
			||||||
        UpgradeVer: { type: Number, default: 101 },
 | 
					        UpgradeVer: { type: Number, default: 101 },
 | 
				
			||||||
        XP: { type: Number, default: 0 },
 | 
					        XP: { type: Number, default: 0 },
 | 
				
			||||||
        Features: Number,
 | 
					        Features: Number,
 | 
				
			||||||
@ -919,63 +891,19 @@ const CustomMarkersSchema = new Schema<ICustomMarkers>(
 | 
				
			|||||||
    { _id: false }
 | 
					    { _id: false }
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const calenderProgressSchema = new Schema<ICalendarProgress>(
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        Version: { type: Number, default: 19 },
 | 
					 | 
				
			||||||
        Iteration: { type: Number, default: 2 },
 | 
					 | 
				
			||||||
        YearProgress: {
 | 
					 | 
				
			||||||
            Upgrades: { type: [] }
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        SeasonProgress: {
 | 
					 | 
				
			||||||
            SeasonType: String,
 | 
					 | 
				
			||||||
            LastCompletedDayIdx: { type: Number, default: -1 },
 | 
					 | 
				
			||||||
            LastCompletedChallengeDayIdx: { type: Number, default: -1 },
 | 
					 | 
				
			||||||
            ActivatedChallenges: []
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    { _id: false }
 | 
					 | 
				
			||||||
);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const pendingCouponSchema = new Schema<IPendingCouponDatabase>(
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        Expiry: { type: Date, default: new Date(0) },
 | 
					 | 
				
			||||||
        Discount: { type: Number, default: 0 }
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    { _id: false }
 | 
					 | 
				
			||||||
);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pendingCouponSchema.set("toJSON", {
 | 
					 | 
				
			||||||
    transform(_doc, ret, _options) {
 | 
					 | 
				
			||||||
        (ret as IPendingCouponClient).Expiry = toMongoDate((ret as IPendingCouponDatabase).Expiry);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const libraryAvailableDailyTaskInfoSchema = new Schema<ILibraryAvailableDailyTaskInfo>(
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        EnemyTypes: [String],
 | 
					 | 
				
			||||||
        EnemyLocTag: String,
 | 
					 | 
				
			||||||
        EnemyIcon: String,
 | 
					 | 
				
			||||||
        ScansRequired: Number,
 | 
					 | 
				
			||||||
        RewardStoreItem: String,
 | 
					 | 
				
			||||||
        RewardQuantity: Number,
 | 
					 | 
				
			||||||
        RewardStanding: Number
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    { _id: false }
 | 
					 | 
				
			||||||
);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
 | 
					const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        accountOwnerId: Schema.Types.ObjectId,
 | 
					        accountOwnerId: Schema.Types.ObjectId,
 | 
				
			||||||
        SubscribedToEmails: { type: Number, default: 0 },
 | 
					        SubscribedToEmails: Number,
 | 
				
			||||||
        SubscribedToEmailsPersonalized: { type: Number, default: 0 },
 | 
					        Created: Date,
 | 
				
			||||||
        RewardSeed: Number,
 | 
					        RewardSeed: Number,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        //Credit
 | 
					        //Credit
 | 
				
			||||||
        RegularCredits: { type: Number, default: 0 },
 | 
					        RegularCredits: { type: Number, default: 0 },
 | 
				
			||||||
        //Platinum
 | 
					        //Platinum
 | 
				
			||||||
        PremiumCredits: { type: Number, default: 0 },
 | 
					        PremiumCredits: { type: Number, default: 50 },
 | 
				
			||||||
        //Gift Platinum(Non trade)
 | 
					        //Gift Platinum(Non trade)
 | 
				
			||||||
        PremiumCreditsFree: { type: Number, default: 0 },
 | 
					        PremiumCreditsFree: { type: Number, default: 50 },
 | 
				
			||||||
        //Endo
 | 
					        //Endo
 | 
				
			||||||
        FusionPoints: { type: Number, default: 0 },
 | 
					        FusionPoints: { type: Number, default: 0 },
 | 
				
			||||||
        //Regal Aya
 | 
					        //Regal Aya
 | 
				
			||||||
@ -983,7 +911,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        //Slots
 | 
					        //Slots
 | 
				
			||||||
        SuitBin: { type: slotsBinSchema, default: { Slots: 3 } },
 | 
					        SuitBin: { type: slotsBinSchema, default: { Slots: 3 } },
 | 
				
			||||||
        WeaponBin: { type: slotsBinSchema, default: { Slots: 11 } },
 | 
					        WeaponBin: { type: slotsBinSchema, default: { Slots: 10 } },
 | 
				
			||||||
        SentinelBin: { type: slotsBinSchema, default: { Slots: 10 } },
 | 
					        SentinelBin: { type: slotsBinSchema, default: { Slots: 10 } },
 | 
				
			||||||
        SpaceSuitBin: { type: slotsBinSchema, default: { Slots: 4 } },
 | 
					        SpaceSuitBin: { type: slotsBinSchema, default: { Slots: 4 } },
 | 
				
			||||||
        SpaceWeaponBin: { type: slotsBinSchema, default: { Slots: 4 } },
 | 
					        SpaceWeaponBin: { type: slotsBinSchema, default: { Slots: 4 } },
 | 
				
			||||||
@ -1094,7 +1022,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
 | 
				
			|||||||
        //Complete Mission\Quests
 | 
					        //Complete Mission\Quests
 | 
				
			||||||
        Missions: [missionSchema],
 | 
					        Missions: [missionSchema],
 | 
				
			||||||
        QuestKeys: [questKeysSchema],
 | 
					        QuestKeys: [questKeysSchema],
 | 
				
			||||||
        ActiveQuest: { type: String, default: "" },
 | 
					        ActiveQuest: { type: String, default: "/Lotus/Types/Keys/VorsPrize/VorsPrizeQuestKeyChain" }, //TODO: check after mission starting gear
 | 
				
			||||||
        //item like DojoKey or Boss missions key
 | 
					        //item like DojoKey or Boss missions key
 | 
				
			||||||
        LevelKeys: [Schema.Types.Mixed],
 | 
					        LevelKeys: [Schema.Types.Mixed],
 | 
				
			||||||
        //Active quests
 | 
					        //Active quests
 | 
				
			||||||
@ -1171,8 +1099,8 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
 | 
				
			|||||||
        CompletedSorties: [String],
 | 
					        CompletedSorties: [String],
 | 
				
			||||||
        LastSortieReward: [Schema.Types.Mixed],
 | 
					        LastSortieReward: [Schema.Types.Mixed],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Resource Extractor Drones
 | 
					        //Resource_Drone[Uselees stuff]
 | 
				
			||||||
        Drones: [droneSchema],
 | 
					        Drones: [Schema.Types.Mixed],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        //Active profile ico
 | 
					        //Active profile ico
 | 
				
			||||||
        ActiveAvatarImageType: String,
 | 
					        ActiveAvatarImageType: String,
 | 
				
			||||||
@ -1209,7 +1137,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
 | 
				
			|||||||
        //Cephalon Simaris Entries Example:"TargetType"+"Scans"(1-10)+"Completed": true|false
 | 
					        //Cephalon Simaris Entries Example:"TargetType"+"Scans"(1-10)+"Completed": true|false
 | 
				
			||||||
        LibraryPersonalProgress: [Schema.Types.Mixed],
 | 
					        LibraryPersonalProgress: [Schema.Types.Mixed],
 | 
				
			||||||
        //Cephalon Simaris Daily Task
 | 
					        //Cephalon Simaris Daily Task
 | 
				
			||||||
        LibraryAvailableDailyTaskInfo: libraryAvailableDailyTaskInfoSchema,
 | 
					        LibraryAvailableDailyTaskInfo: Schema.Types.Mixed,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        //https://warframe.fandom.com/wiki/Invasion
 | 
					        //https://warframe.fandom.com/wiki/Invasion
 | 
				
			||||||
        InvasionChainProgress: [Schema.Types.Mixed],
 | 
					        InvasionChainProgress: [Schema.Types.Mixed],
 | 
				
			||||||
@ -1256,6 +1184,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
 | 
				
			|||||||
        HandlerPoints: Number,
 | 
					        HandlerPoints: Number,
 | 
				
			||||||
        ChallengesFixVersion: Number,
 | 
					        ChallengesFixVersion: Number,
 | 
				
			||||||
        PlayedParkourTutorial: Boolean,
 | 
					        PlayedParkourTutorial: Boolean,
 | 
				
			||||||
 | 
					        SubscribedToEmailsPersonalized: Number,
 | 
				
			||||||
        ActiveLandscapeTraps: [Schema.Types.Mixed],
 | 
					        ActiveLandscapeTraps: [Schema.Types.Mixed],
 | 
				
			||||||
        RepVotes: [Schema.Types.Mixed],
 | 
					        RepVotes: [Schema.Types.Mixed],
 | 
				
			||||||
        LeagueTickets: [Schema.Types.Mixed],
 | 
					        LeagueTickets: [Schema.Types.Mixed],
 | 
				
			||||||
@ -1273,7 +1202,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
 | 
				
			|||||||
        HasResetAccount: { type: Boolean, default: false },
 | 
					        HasResetAccount: { type: Boolean, default: false },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        //Discount Coupon
 | 
					        //Discount Coupon
 | 
				
			||||||
        PendingCoupon: pendingCouponSchema,
 | 
					        PendingCoupon: Schema.Types.Mixed,
 | 
				
			||||||
        //Like BossAladV,BossCaptainVor come for you on missions % chance
 | 
					        //Like BossAladV,BossCaptainVor come for you on missions % chance
 | 
				
			||||||
        DeathMarks: [String],
 | 
					        DeathMarks: [String],
 | 
				
			||||||
        //Zanuka
 | 
					        //Zanuka
 | 
				
			||||||
@ -1283,8 +1212,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        EndlessXP: { type: [endlessXpProgressSchema], default: undefined },
 | 
					        EndlessXP: { type: [endlessXpProgressSchema], default: undefined },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        DialogueHistory: dialogueHistorySchema,
 | 
					        DialogueHistory: dialogueHistorySchema
 | 
				
			||||||
        CalendarProgress: calenderProgressSchema
 | 
					 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    { timestamps: { createdAt: "Created", updatedAt: false } }
 | 
					    { timestamps: { createdAt: "Created", updatedAt: false } }
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
@ -1303,7 +1231,7 @@ inventorySchema.set("toJSON", {
 | 
				
			|||||||
        if (inventoryDatabase.GuildId) {
 | 
					        if (inventoryDatabase.GuildId) {
 | 
				
			||||||
            inventoryResponse.GuildId = toOid(inventoryDatabase.GuildId);
 | 
					            inventoryResponse.GuildId = toOid(inventoryDatabase.GuildId);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (inventoryDatabase.BlessingCooldown) {
 | 
					        if (inventoryResponse.BlessingCooldown) {
 | 
				
			||||||
            inventoryResponse.BlessingCooldown = toMongoDate(inventoryDatabase.BlessingCooldown);
 | 
					            inventoryResponse.BlessingCooldown = toMongoDate(inventoryDatabase.BlessingCooldown);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -1322,7 +1250,6 @@ export type InventoryDocumentProps = {
 | 
				
			|||||||
    PendingRecipes: Types.DocumentArray<IPendingRecipeDatabase>;
 | 
					    PendingRecipes: Types.DocumentArray<IPendingRecipeDatabase>;
 | 
				
			||||||
    WeaponSkins: Types.DocumentArray<IWeaponSkinDatabase>;
 | 
					    WeaponSkins: Types.DocumentArray<IWeaponSkinDatabase>;
 | 
				
			||||||
    QuestKeys: Types.DocumentArray<IQuestKeyDatabase>;
 | 
					    QuestKeys: Types.DocumentArray<IQuestKeyDatabase>;
 | 
				
			||||||
    Drones: Types.DocumentArray<IDroneDatabase>;
 | 
					 | 
				
			||||||
} & { [K in TEquipmentKey]: Types.DocumentArray<IEquipmentDatabase> };
 | 
					} & { [K in TEquipmentKey]: Types.DocumentArray<IEquipmentDatabase> };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// eslint-disable-next-line @typescript-eslint/ban-types
 | 
					// eslint-disable-next-line @typescript-eslint/ban-types
 | 
				
			||||||
 | 
				
			|||||||
@ -3,12 +3,11 @@ import { activateRandomModController } from "@/src/controllers/api/activateRando
 | 
				
			|||||||
import { addFriendImageController } from "@/src/controllers/api/addFriendImageController";
 | 
					import { addFriendImageController } from "@/src/controllers/api/addFriendImageController";
 | 
				
			||||||
import { arcaneCommonController } from "@/src/controllers/api/arcaneCommonController";
 | 
					import { arcaneCommonController } from "@/src/controllers/api/arcaneCommonController";
 | 
				
			||||||
import { archonFusionController } from "@/src/controllers/api/archonFusionController";
 | 
					import { archonFusionController } from "@/src/controllers/api/archonFusionController";
 | 
				
			||||||
import { artifactsController } from "@/src/controllers/api/artifactsController";
 | 
					import { artifactsController } from "../controllers/api/artifactsController";
 | 
				
			||||||
import { changeDojoRootController } from "@/src/controllers/api/changeDojoRootController";
 | 
					import { changeDojoRootController } from "../controllers/api/changeDojoRootController";
 | 
				
			||||||
import { checkDailyMissionBonusController } from "@/src/controllers/api/checkDailyMissionBonusController";
 | 
					import { checkDailyMissionBonusController } from "@/src/controllers/api/checkDailyMissionBonusController";
 | 
				
			||||||
import { claimCompletedRecipeController } from "@/src/controllers/api/claimCompletedRecipeController";
 | 
					import { claimCompletedRecipeController } from "@/src/controllers/api/claimCompletedRecipeController";
 | 
				
			||||||
import { clearDialogueHistoryController } from "@/src/controllers/api/clearDialogueHistoryController";
 | 
					import { clearDialogueHistoryController } from "@/src/controllers/api/clearDialogueHistoryController";
 | 
				
			||||||
import { completeRandomModChallengeController } from "@/src/controllers/api/completeRandomModChallengeController";
 | 
					 | 
				
			||||||
import { createGuildController } from "@/src/controllers/api/createGuildController";
 | 
					import { createGuildController } from "@/src/controllers/api/createGuildController";
 | 
				
			||||||
import { creditsController } from "@/src/controllers/api/creditsController";
 | 
					import { creditsController } from "@/src/controllers/api/creditsController";
 | 
				
			||||||
import { deleteSessionController } from "@/src/controllers/api/deleteSessionController";
 | 
					import { deleteSessionController } from "@/src/controllers/api/deleteSessionController";
 | 
				
			||||||
@ -26,7 +25,7 @@ import { getDailyDealStockLevelsController } from "@/src/controllers/api/getDail
 | 
				
			|||||||
import { getFriendsController } from "@/src/controllers/api/getFriendsController";
 | 
					import { getFriendsController } from "@/src/controllers/api/getFriendsController";
 | 
				
			||||||
import { getGuildController } from "@/src/controllers/api/getGuildController";
 | 
					import { getGuildController } from "@/src/controllers/api/getGuildController";
 | 
				
			||||||
import { getGuildDojoController } from "@/src/controllers/api/getGuildDojoController";
 | 
					import { getGuildDojoController } from "@/src/controllers/api/getGuildDojoController";
 | 
				
			||||||
import { getGuildLogController } from "@/src/controllers/api/getGuildLogController";
 | 
					import { getGuildLogController } from "../controllers/api/getGuildLogController";
 | 
				
			||||||
import { getIgnoredUsersController } from "@/src/controllers/api/getIgnoredUsersController";
 | 
					import { getIgnoredUsersController } from "@/src/controllers/api/getIgnoredUsersController";
 | 
				
			||||||
import { getNewRewardSeedController } from "@/src/controllers/api/getNewRewardSeedController";
 | 
					import { getNewRewardSeedController } from "@/src/controllers/api/getNewRewardSeedController";
 | 
				
			||||||
import { getShipController } from "@/src/controllers/api/getShipController";
 | 
					import { getShipController } from "@/src/controllers/api/getShipController";
 | 
				
			||||||
@ -36,8 +35,7 @@ import { gildWeaponController } from "@/src/controllers/api/gildWeaponController
 | 
				
			|||||||
import { giveKeyChainTriggeredItemsController } from "@/src/controllers/api/giveKeyChainTriggeredItemsController";
 | 
					import { giveKeyChainTriggeredItemsController } from "@/src/controllers/api/giveKeyChainTriggeredItemsController";
 | 
				
			||||||
import { giveKeyChainTriggeredMessageController } from "@/src/controllers/api/giveKeyChainTriggeredMessageController";
 | 
					import { giveKeyChainTriggeredMessageController } from "@/src/controllers/api/giveKeyChainTriggeredMessageController";
 | 
				
			||||||
import { giveQuestKeyRewardController } from "@/src/controllers/api/giveQuestKey";
 | 
					import { giveQuestKeyRewardController } from "@/src/controllers/api/giveQuestKey";
 | 
				
			||||||
import { giveStartingGearController } from "@/src/controllers/api/giveStartingGearController";
 | 
					import { guildTechController } from "../controllers/api/guildTechController";
 | 
				
			||||||
import { guildTechController } from "@/src/controllers/api/guildTechController";
 | 
					 | 
				
			||||||
import { hostSessionController } from "@/src/controllers/api/hostSessionController";
 | 
					import { hostSessionController } from "@/src/controllers/api/hostSessionController";
 | 
				
			||||||
import { hubController } from "@/src/controllers/api/hubController";
 | 
					import { hubController } from "@/src/controllers/api/hubController";
 | 
				
			||||||
import { hubInstancesController } from "@/src/controllers/api/hubInstancesController";
 | 
					import { hubInstancesController } from "@/src/controllers/api/hubInstancesController";
 | 
				
			||||||
@ -55,13 +53,12 @@ import { modularWeaponCraftingController } from "@/src/controllers/api/modularWe
 | 
				
			|||||||
import { modularWeaponSaleController } from "@/src/controllers/api/modularWeaponSaleController";
 | 
					import { modularWeaponSaleController } from "@/src/controllers/api/modularWeaponSaleController";
 | 
				
			||||||
import { nameWeaponController } from "@/src/controllers/api/nameWeaponController";
 | 
					import { nameWeaponController } from "@/src/controllers/api/nameWeaponController";
 | 
				
			||||||
import { playerSkillsController } from "@/src/controllers/api/playerSkillsController";
 | 
					import { playerSkillsController } from "@/src/controllers/api/playerSkillsController";
 | 
				
			||||||
import { projectionManagerController } from "@/src/controllers/api/projectionManagerController";
 | 
					import { projectionManagerController } from "../controllers/api/projectionManagerController";
 | 
				
			||||||
import { purchaseController } from "@/src/controllers/api/purchaseController";
 | 
					import { purchaseController } from "@/src/controllers/api/purchaseController";
 | 
				
			||||||
import { queueDojoComponentDestructionController } from "@/src/controllers/api/queueDojoComponentDestructionController";
 | 
					import { queueDojoComponentDestructionController } from "@/src/controllers/api/queueDojoComponentDestructionController";
 | 
				
			||||||
import { rerollRandomModController } from "@/src/controllers/api/rerollRandomModController";
 | 
					import { rerollRandomModController } from "@/src/controllers/api/rerollRandomModController";
 | 
				
			||||||
import { saveDialogueController } from "@/src/controllers/api/saveDialogueController";
 | 
					import { saveDialogueController } from "@/src/controllers/api/saveDialogueController";
 | 
				
			||||||
import { saveLoadoutController } from "@/src/controllers/api/saveLoadout";
 | 
					import { saveLoadoutController } from "@/src/controllers/api/saveLoadout";
 | 
				
			||||||
import { saveSettingsController } from "@/src/controllers/api/saveSettingsController";
 | 
					 | 
				
			||||||
import { sellController } from "@/src/controllers/api/sellController";
 | 
					import { sellController } from "@/src/controllers/api/sellController";
 | 
				
			||||||
import { setActiveQuestController } from "@/src/controllers/api/setActiveQuestController";
 | 
					import { setActiveQuestController } from "@/src/controllers/api/setActiveQuestController";
 | 
				
			||||||
import { setActiveShipController } from "@/src/controllers/api/setActiveShipController";
 | 
					import { setActiveShipController } from "@/src/controllers/api/setActiveShipController";
 | 
				
			||||||
@ -72,23 +69,24 @@ import { setPlacedDecoInfoController } from "@/src/controllers/api/setPlacedDeco
 | 
				
			|||||||
import { setShipCustomizationsController } from "@/src/controllers/api/setShipCustomizationsController";
 | 
					import { setShipCustomizationsController } from "@/src/controllers/api/setShipCustomizationsController";
 | 
				
			||||||
import { setShipFavouriteLoadoutController } from "@/src/controllers/api/setShipFavouriteLoadoutController";
 | 
					import { setShipFavouriteLoadoutController } from "@/src/controllers/api/setShipFavouriteLoadoutController";
 | 
				
			||||||
import { setSupportedSyndicateController } from "@/src/controllers/api/setSupportedSyndicateController";
 | 
					import { setSupportedSyndicateController } from "@/src/controllers/api/setSupportedSyndicateController";
 | 
				
			||||||
import { setWeaponSkillTreeController } from "@/src/controllers/api/setWeaponSkillTreeController";
 | 
					import { setWeaponSkillTreeController } from "../controllers/api/setWeaponSkillTreeController";
 | 
				
			||||||
import { shipDecorationsController } from "@/src/controllers/api/shipDecorationsController";
 | 
					import { shipDecorationsController } from "@/src/controllers/api/shipDecorationsController";
 | 
				
			||||||
import { startDojoRecipeController } from "@/src/controllers/api/startDojoRecipeController";
 | 
					import { startDojoRecipeController } from "@/src/controllers/api/startDojoRecipeController";
 | 
				
			||||||
import { startLibraryPersonalTargetController } from "@/src/controllers/api/startLibraryPersonalTargetController";
 | 
					import { startLibraryPersonalTargetController } from "@/src/controllers/api/startLibraryPersonalTargetController";
 | 
				
			||||||
import { startRecipeController } from "@/src/controllers/api/startRecipeController";
 | 
					import { startRecipeController } from "@/src/controllers/api/startRecipeController";
 | 
				
			||||||
import { stepSequencersController } from "@/src/controllers/api/stepSequencersController";
 | 
					import { stepSequencersController } from "@/src/controllers/api/stepSequencersController";
 | 
				
			||||||
import { surveysController } from "@/src/controllers/api/surveysController";
 | 
					import { surveysController } from "@/src/controllers/api/surveysController";
 | 
				
			||||||
import { syndicateSacrificeController } from "@/src/controllers/api/syndicateSacrificeController";
 | 
					import { syndicateSacrificeController } from "../controllers/api/syndicateSacrificeController";
 | 
				
			||||||
import { syndicateStandingBonusController } from "@/src/controllers/api/syndicateStandingBonusController";
 | 
					import { syndicateStandingBonusController } from "../controllers/api/syndicateStandingBonusController";
 | 
				
			||||||
import { tauntHistoryController } from "@/src/controllers/api/tauntHistoryController";
 | 
					import { tauntHistoryController } from "@/src/controllers/api/tauntHistoryController";
 | 
				
			||||||
import { trainingResultController } from "@/src/controllers/api/trainingResultController";
 | 
					import { trainingResultController } from "@/src/controllers/api/trainingResultController";
 | 
				
			||||||
import { unlockShipFeatureController } from "@/src/controllers/api/unlockShipFeatureController";
 | 
					import { unlockShipFeatureController } from "@/src/controllers/api/unlockShipFeatureController";
 | 
				
			||||||
import { updateChallengeProgressController } from "@/src/controllers/api/updateChallengeProgressController";
 | 
					import { updateChallengeProgressController } from "@/src/controllers/api/updateChallengeProgressController";
 | 
				
			||||||
import { updateQuestController } from "@/src/controllers/api/updateQuestController";
 | 
					import { updateQuestController } from "@/src/controllers/api/updateQuestController";
 | 
				
			||||||
import { updateSessionGetController, updateSessionPostController } from "@/src/controllers/api/updateSessionController";
 | 
					import { updateSessionGetController, updateSessionPostController } from "@/src/controllers/api/updateSessionController";
 | 
				
			||||||
import { updateThemeController } from "@/src/controllers/api/updateThemeController";
 | 
					import { updateThemeController } from "../controllers/api/updateThemeController";
 | 
				
			||||||
import { upgradesController } from "@/src/controllers/api/upgradesController";
 | 
					import { upgradesController } from "@/src/controllers/api/upgradesController";
 | 
				
			||||||
 | 
					import { saveSettingsController } from "../controllers/api/saveSettingsController";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const apiRouter = express.Router();
 | 
					const apiRouter = express.Router();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -134,7 +132,6 @@ apiRouter.post("/artifacts.php", artifactsController);
 | 
				
			|||||||
apiRouter.post("/changeDojoRoot.php", changeDojoRootController);
 | 
					apiRouter.post("/changeDojoRoot.php", changeDojoRootController);
 | 
				
			||||||
apiRouter.post("/claimCompletedRecipe.php", claimCompletedRecipeController);
 | 
					apiRouter.post("/claimCompletedRecipe.php", claimCompletedRecipeController);
 | 
				
			||||||
apiRouter.post("/clearDialogueHistory.php", clearDialogueHistoryController);
 | 
					apiRouter.post("/clearDialogueHistory.php", clearDialogueHistoryController);
 | 
				
			||||||
apiRouter.post("/completeRandomModChallenge.php", completeRandomModChallengeController);
 | 
					 | 
				
			||||||
apiRouter.post("/createGuild.php", createGuildController);
 | 
					apiRouter.post("/createGuild.php", createGuildController);
 | 
				
			||||||
apiRouter.post("/endlessXp.php", endlessXpController);
 | 
					apiRouter.post("/endlessXp.php", endlessXpController);
 | 
				
			||||||
apiRouter.post("/evolveWeapon.php", evolveWeaponController);
 | 
					apiRouter.post("/evolveWeapon.php", evolveWeaponController);
 | 
				
			||||||
@ -149,7 +146,6 @@ apiRouter.post("/gildWeapon.php", gildWeaponController);
 | 
				
			|||||||
apiRouter.post("/giveKeyChainTriggeredItems.php", giveKeyChainTriggeredItemsController);
 | 
					apiRouter.post("/giveKeyChainTriggeredItems.php", giveKeyChainTriggeredItemsController);
 | 
				
			||||||
apiRouter.post("/giveKeyChainTriggeredMessage.php", giveKeyChainTriggeredMessageController);
 | 
					apiRouter.post("/giveKeyChainTriggeredMessage.php", giveKeyChainTriggeredMessageController);
 | 
				
			||||||
apiRouter.post("/giveQuestKeyReward.php", giveQuestKeyRewardController);
 | 
					apiRouter.post("/giveQuestKeyReward.php", giveQuestKeyRewardController);
 | 
				
			||||||
apiRouter.post("/giveStartingGear.php", giveStartingGearController);
 | 
					 | 
				
			||||||
apiRouter.post("/guildTech.php", guildTechController);
 | 
					apiRouter.post("/guildTech.php", guildTechController);
 | 
				
			||||||
apiRouter.post("/hostSession.php", hostSessionController);
 | 
					apiRouter.post("/hostSession.php", hostSessionController);
 | 
				
			||||||
apiRouter.post("/infestedFoundry.php", infestedFoundryController);
 | 
					apiRouter.post("/infestedFoundry.php", infestedFoundryController);
 | 
				
			||||||
@ -165,7 +161,6 @@ apiRouter.post("/purchase.php", purchaseController);
 | 
				
			|||||||
apiRouter.post("/rerollRandomMod.php", rerollRandomModController);
 | 
					apiRouter.post("/rerollRandomMod.php", rerollRandomModController);
 | 
				
			||||||
apiRouter.post("/saveDialogue.php", saveDialogueController);
 | 
					apiRouter.post("/saveDialogue.php", saveDialogueController);
 | 
				
			||||||
apiRouter.post("/saveLoadout.php", saveLoadoutController);
 | 
					apiRouter.post("/saveLoadout.php", saveLoadoutController);
 | 
				
			||||||
apiRouter.post("/saveSettings.php", saveSettingsController);
 | 
					 | 
				
			||||||
apiRouter.post("/sell.php", sellController);
 | 
					apiRouter.post("/sell.php", sellController);
 | 
				
			||||||
apiRouter.post("/setDojoComponentMessage.php", setDojoComponentMessageController);
 | 
					apiRouter.post("/setDojoComponentMessage.php", setDojoComponentMessageController);
 | 
				
			||||||
apiRouter.post("/setEquippedInstrument.php", setEquippedInstrumentController);
 | 
					apiRouter.post("/setEquippedInstrument.php", setEquippedInstrumentController);
 | 
				
			||||||
@ -188,5 +183,6 @@ apiRouter.post("/updateQuest.php", updateQuestController);
 | 
				
			|||||||
apiRouter.post("/updateSession.php", updateSessionPostController);
 | 
					apiRouter.post("/updateSession.php", updateSessionPostController);
 | 
				
			||||||
apiRouter.post("/updateTheme.php", updateThemeController);
 | 
					apiRouter.post("/updateTheme.php", updateThemeController);
 | 
				
			||||||
apiRouter.post("/upgrades.php", upgradesController);
 | 
					apiRouter.post("/upgrades.php", upgradesController);
 | 
				
			||||||
 | 
					apiRouter.post("/saveSettings.php", saveSettingsController);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export { apiRouter };
 | 
					export { apiRouter };
 | 
				
			||||||
 | 
				
			|||||||
@ -33,9 +33,6 @@ interface IConfig {
 | 
				
			|||||||
    httpPort?: number;
 | 
					    httpPort?: number;
 | 
				
			||||||
    httpsPort?: number;
 | 
					    httpsPort?: number;
 | 
				
			||||||
    myIrcAddresses?: string[];
 | 
					    myIrcAddresses?: string[];
 | 
				
			||||||
    platformCDNs?: string[];
 | 
					 | 
				
			||||||
    hubAddress?: string;
 | 
					 | 
				
			||||||
    NRS?: string[];
 | 
					 | 
				
			||||||
    administratorNames?: string[] | string;
 | 
					    administratorNames?: string[] | string;
 | 
				
			||||||
    autoCreateAccount?: boolean;
 | 
					    autoCreateAccount?: boolean;
 | 
				
			||||||
    skipTutorial?: boolean;
 | 
					    skipTutorial?: boolean;
 | 
				
			||||||
@ -46,7 +43,6 @@ interface IConfig {
 | 
				
			|||||||
    infinitePlatinum?: boolean;
 | 
					    infinitePlatinum?: boolean;
 | 
				
			||||||
    infiniteEndo?: boolean;
 | 
					    infiniteEndo?: boolean;
 | 
				
			||||||
    infiniteRegalAya?: boolean;
 | 
					    infiniteRegalAya?: boolean;
 | 
				
			||||||
    infiniteHelminthMaterials?: boolean;
 | 
					 | 
				
			||||||
    unlockAllShipFeatures?: boolean;
 | 
					    unlockAllShipFeatures?: boolean;
 | 
				
			||||||
    unlockAllShipDecorations?: boolean;
 | 
					    unlockAllShipDecorations?: boolean;
 | 
				
			||||||
    unlockAllFlavourItems?: boolean;
 | 
					    unlockAllFlavourItems?: boolean;
 | 
				
			||||||
 | 
				
			|||||||
@ -50,7 +50,6 @@ const convertEquipment = (client: IEquipmentClient): IEquipmentDatabase => {
 | 
				
			|||||||
        UpgradesExpiry: convertOptionalDate(client.UpgradesExpiry),
 | 
					        UpgradesExpiry: convertOptionalDate(client.UpgradesExpiry),
 | 
				
			||||||
        CrewMembers: client.CrewMembers ? convertCrewShipMembers(client.CrewMembers) : undefined,
 | 
					        CrewMembers: client.CrewMembers ? convertCrewShipMembers(client.CrewMembers) : undefined,
 | 
				
			||||||
        Details: client.Details ? convertKubrowDetails(client.Details) : undefined,
 | 
					        Details: client.Details ? convertKubrowDetails(client.Details) : undefined,
 | 
				
			||||||
        // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
 | 
					 | 
				
			||||||
        Configs: client.Configs
 | 
					        Configs: client.Configs
 | 
				
			||||||
            ? client.Configs.map(obj =>
 | 
					            ? client.Configs.map(obj =>
 | 
				
			||||||
                  Object.fromEntries(
 | 
					                  Object.fromEntries(
 | 
				
			||||||
 | 
				
			|||||||
@ -2,7 +2,7 @@ import { IMessageDatabase, Inbox } from "@/src/models/inboxModel";
 | 
				
			|||||||
import { getAccountForRequest } from "@/src/services/loginService";
 | 
					import { getAccountForRequest } from "@/src/services/loginService";
 | 
				
			||||||
import { HydratedDocument } from "mongoose";
 | 
					import { HydratedDocument } from "mongoose";
 | 
				
			||||||
import { Request } from "express";
 | 
					import { Request } from "express";
 | 
				
			||||||
import eventMessages from "@/static/fixed_responses/eventMessages.json";
 | 
					import messages from "@/static/fixed_responses/messages.json";
 | 
				
			||||||
import { logger } from "@/src/utils/logger";
 | 
					import { logger } from "@/src/utils/logger";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const getAllMessagesSorted = async (accountId: string): Promise<HydratedDocument<IMessageDatabase>[]> => {
 | 
					export const getAllMessagesSorted = async (accountId: string): Promise<HydratedDocument<IMessageDatabase>[]> => {
 | 
				
			||||||
@ -27,12 +27,12 @@ export const deleteAllMessagesRead = async (accountId: string): Promise<void> =>
 | 
				
			|||||||
    await Inbox.deleteMany({ ownerId: accountId, r: true });
 | 
					    await Inbox.deleteMany({ ownerId: accountId, r: true });
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const createNewEventMessages = async (req: Request): Promise<void> => {
 | 
					export const createNewEventMessages = async (req: Request) => {
 | 
				
			||||||
    const account = await getAccountForRequest(req);
 | 
					    const account = await getAccountForRequest(req);
 | 
				
			||||||
    const latestEventMessageDate = account.LatestEventMessageDate;
 | 
					    const latestEventMessageDate = account.LatestEventMessageDate;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    //TODO: is baroo there? create these kind of messages too (periodical messages)
 | 
					    //TODO: is baroo there? create these kind of messages too (periodical messages)
 | 
				
			||||||
    const newEventMessages = eventMessages.Messages.filter(m => new Date(m.eventMessageDate) > latestEventMessageDate);
 | 
					    const newEventMessages = messages.Messages.filter(m => new Date(m.eventMessageDate) > latestEventMessageDate);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (newEventMessages.length === 0) {
 | 
					    if (newEventMessages.length === 0) {
 | 
				
			||||||
        logger.debug(`No new event messages. Latest event message date: ${latestEventMessageDate.toISOString()}`);
 | 
					        logger.debug(`No new event messages. Latest event message date: ${latestEventMessageDate.toISOString()}`);
 | 
				
			||||||
 | 
				
			|||||||
@ -22,10 +22,7 @@ import {
 | 
				
			|||||||
    IDailyAffiliations,
 | 
					    IDailyAffiliations,
 | 
				
			||||||
    IInventoryDatabase,
 | 
					    IInventoryDatabase,
 | 
				
			||||||
    IKubrowPetEggDatabase,
 | 
					    IKubrowPetEggDatabase,
 | 
				
			||||||
    IKubrowPetEggClient,
 | 
					    IKubrowPetEggClient
 | 
				
			||||||
    ILibraryAvailableDailyTaskInfo,
 | 
					 | 
				
			||||||
    ICalendarProgress,
 | 
					 | 
				
			||||||
    IDroneClient
 | 
					 | 
				
			||||||
} from "@/src/types/inventoryTypes/inventoryTypes";
 | 
					} from "@/src/types/inventoryTypes/inventoryTypes";
 | 
				
			||||||
import { IGenericUpdate } from "../types/genericUpdate";
 | 
					import { IGenericUpdate } from "../types/genericUpdate";
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
@ -35,33 +32,25 @@ import {
 | 
				
			|||||||
} from "../types/requestTypes";
 | 
					} from "../types/requestTypes";
 | 
				
			||||||
import { logger } from "@/src/utils/logger";
 | 
					import { logger } from "@/src/utils/logger";
 | 
				
			||||||
import { getExalted, getKeyChainItems } from "@/src/services/itemDataService";
 | 
					import { getExalted, getKeyChainItems } from "@/src/services/itemDataService";
 | 
				
			||||||
import { IEquipmentClient, IEquipmentDatabase, IItemConfig } from "../types/inventoryTypes/commonInventoryTypes";
 | 
					import { IEquipmentClient, IItemConfig } from "../types/inventoryTypes/commonInventoryTypes";
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
    ExportArcanes,
 | 
					    ExportArcanes,
 | 
				
			||||||
    ExportBundles,
 | 
					 | 
				
			||||||
    ExportCustoms,
 | 
					    ExportCustoms,
 | 
				
			||||||
    ExportDrones,
 | 
					 | 
				
			||||||
    ExportFlavour,
 | 
					    ExportFlavour,
 | 
				
			||||||
    ExportFusionBundles,
 | 
					 | 
				
			||||||
    ExportGear,
 | 
					    ExportGear,
 | 
				
			||||||
    ExportKeys,
 | 
					    ExportKeys,
 | 
				
			||||||
    ExportMisc,
 | 
					 | 
				
			||||||
    ExportRecipes,
 | 
					    ExportRecipes,
 | 
				
			||||||
    ExportResources,
 | 
					    ExportResources,
 | 
				
			||||||
    ExportSentinels,
 | 
					    ExportSentinels,
 | 
				
			||||||
    ExportSyndicates,
 | 
					    ExportSyndicates,
 | 
				
			||||||
    ExportUpgrades,
 | 
					    ExportUpgrades,
 | 
				
			||||||
    ExportWeapons,
 | 
					    ExportWeapons,
 | 
				
			||||||
    IDefaultUpgrade,
 | 
					 | 
				
			||||||
    TStandingLimitBin
 | 
					    TStandingLimitBin
 | 
				
			||||||
} from "warframe-public-export-plus";
 | 
					} from "warframe-public-export-plus";
 | 
				
			||||||
import { createShip } from "./shipService";
 | 
					import { createShip } from "./shipService";
 | 
				
			||||||
 | 
					import { creditBundles, fusionBundles } from "@/src/services/missionInventoryUpdateService";
 | 
				
			||||||
import { IKeyChainRequest } from "@/src/controllers/api/giveKeyChainTriggeredItemsController";
 | 
					import { IKeyChainRequest } from "@/src/controllers/api/giveKeyChainTriggeredItemsController";
 | 
				
			||||||
import { toOid } from "../helpers/inventoryHelpers";
 | 
					import { toOid } from "../helpers/inventoryHelpers";
 | 
				
			||||||
import { generateRewardSeed } from "@/src/controllers/api/getNewRewardSeedController";
 | 
					 | 
				
			||||||
import { addStartingGear } from "@/src/controllers/api/giveStartingGearController";
 | 
					 | 
				
			||||||
import { addQuestKey, completeQuest } from "@/src/services/questService";
 | 
					 | 
				
			||||||
import { handleBundleAcqusition } from "./purchaseService";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const createInventory = async (
 | 
					export const createInventory = async (
 | 
				
			||||||
    accountOwnerId: Types.ObjectId,
 | 
					    accountOwnerId: Types.ObjectId,
 | 
				
			||||||
@ -76,18 +65,65 @@ export const createInventory = async (
 | 
				
			|||||||
            ReceivedStartingGear: config.skipTutorial
 | 
					            ReceivedStartingGear: config.skipTutorial
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        inventory.LibraryAvailableDailyTaskInfo = createLibraryAvailableDailyTaskInfo();
 | 
					 | 
				
			||||||
        inventory.CalendarProgress = createCalendar();
 | 
					 | 
				
			||||||
        inventory.RewardSeed = generateRewardSeed();
 | 
					 | 
				
			||||||
        inventory.DuviriInfo = {
 | 
					 | 
				
			||||||
            Seed: generateRewardSeed(),
 | 
					 | 
				
			||||||
            NumCompletions: 0
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
        await addItem(inventory, "/Lotus/Types/Friendly/PlayerControllable/Weapons/DuviriDualSwords");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (config.skipTutorial) {
 | 
					        if (config.skipTutorial) {
 | 
				
			||||||
            await addStartingGear(inventory);
 | 
					            const defaultEquipment = [
 | 
				
			||||||
            await completeQuest(inventory, "/Lotus/Types/Keys/VorsPrize/VorsPrizeQuestKeyChain");
 | 
					                // Awakening rewards
 | 
				
			||||||
 | 
					                { ItemCount: 1, ItemType: "/Lotus/Powersuits/Excalibur/Excalibur" },
 | 
				
			||||||
 | 
					                { ItemCount: 1, ItemType: "/Lotus/Weapons/Tenno/Melee/LongSword/LongSword" },
 | 
				
			||||||
 | 
					                { ItemCount: 1, ItemType: "/Lotus/Weapons/Tenno/Pistol/Pistol" },
 | 
				
			||||||
 | 
					                { ItemCount: 1, ItemType: "/Lotus/Weapons/Tenno/Rifle/Rifle" },
 | 
				
			||||||
 | 
					                { ItemCount: 1, ItemType: "/Lotus/Types/StoreItems/AvatarImages/AvatarImageItem1" },
 | 
				
			||||||
 | 
					                { ItemCount: 1, ItemType: "/Lotus/Types/StoreItems/AvatarImages/AvatarImageItem2" },
 | 
				
			||||||
 | 
					                { ItemCount: 1, ItemType: "/Lotus/Types/StoreItems/AvatarImages/AvatarImageItem3" },
 | 
				
			||||||
 | 
					                { ItemCount: 1, ItemType: "/Lotus/Types/StoreItems/AvatarImages/AvatarImageItem4" },
 | 
				
			||||||
 | 
					                { ItemCount: 1, ItemType: "/Lotus/Types/Restoratives/LisetAutoHack" }
 | 
				
			||||||
 | 
					            ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // const vorsPrizeRewards = [
 | 
				
			||||||
 | 
					            //     // Vor's Prize rewards
 | 
				
			||||||
 | 
					            //     { ItemCount: 1, ItemType: "/Lotus/Upgrades/Mods/Warframe/AvatarHealthMaxMod" },
 | 
				
			||||||
 | 
					            //     { ItemCount: 1, ItemType: "/Lotus/Upgrades/Mods/Warframe/AvatarShieldMaxMod" },
 | 
				
			||||||
 | 
					            //     { ItemCount: 1, ItemType: "/Lotus/Upgrades/Mods/Warframe/AvatarAbilityRangeMod" },
 | 
				
			||||||
 | 
					            //     { ItemCount: 1, ItemType: "/Lotus/Upgrades/Mods/Warframe/AvatarAbilityStrengthMod" },
 | 
				
			||||||
 | 
					            //     { ItemCount: 1, ItemType: "/Lotus/Upgrades/Mods/Warframe/AvatarAbilityDurationMod" },
 | 
				
			||||||
 | 
					            //     { ItemCount: 1, ItemType: "/Lotus/Upgrades/Mods/Warframe/AvatarPickupBonusMod" },
 | 
				
			||||||
 | 
					            //     { ItemCount: 1, ItemType: "/Lotus/Upgrades/Mods/Warframe/AvatarPowerMaxMod" },
 | 
				
			||||||
 | 
					            //     { ItemCount: 1, ItemType: "/Lotus/Upgrades/Mods/Warframe/AvatarEnemyRadarMod" },
 | 
				
			||||||
 | 
					            //     { ItemCount: 1, ItemType: "/Lotus/Upgrades/Mods/Melee/WeaponFireRateMod" },
 | 
				
			||||||
 | 
					            //     { ItemCount: 1, ItemType: "/Lotus/Upgrades/Mods/Melee/WeaponMeleeDamageMod" },
 | 
				
			||||||
 | 
					            //     { ItemCount: 1, ItemType: "/Lotus/Upgrades/Mods/Rifle/WeaponFactionDamageCorpus" },
 | 
				
			||||||
 | 
					            //     { ItemCount: 1, ItemType: "/Lotus/Upgrades/Mods/Rifle/WeaponFactionDamageGrineer" },
 | 
				
			||||||
 | 
					            //     { ItemCount: 1, ItemType: "/Lotus/Upgrades/Mods/Rifle/WeaponDamageAmountMod" },
 | 
				
			||||||
 | 
					            //     { ItemCount: 1, ItemType: "/Lotus/Upgrades/Mods/Pistol/WeaponFireDamageMod" },
 | 
				
			||||||
 | 
					            //     { ItemCount: 1, ItemType: "/Lotus/Upgrades/Mods/Pistol/WeaponElectricityDamageMod" },
 | 
				
			||||||
 | 
					            //     { ItemCount: 1, ItemType: "/Lotus/Upgrades/Mods/Pistol/WeaponDamageAmountMod" },
 | 
				
			||||||
 | 
					            //     { ItemCount: 1, ItemType: "/Lotus/Types/Recipes/Weapons/BurstonRifleBlueprint" },
 | 
				
			||||||
 | 
					            //     { ItemCount: 1, ItemType: "/Lotus/Types/Items/MiscItems/Morphic" },
 | 
				
			||||||
 | 
					            //     { ItemCount: 400, ItemType: "/Lotus/Types/Items/MiscItems/PolymerBundle" },
 | 
				
			||||||
 | 
					            //     { ItemCount: 150, ItemType: "/Lotus/Types/Items/MiscItems/AlloyPlate" }
 | 
				
			||||||
 | 
					            // ];
 | 
				
			||||||
 | 
					            for (const equipment of defaultEquipment) {
 | 
				
			||||||
 | 
					                await addItem(inventory, equipment.ItemType, equipment.ItemCount);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Missing in Public Export
 | 
				
			||||||
 | 
					            inventory.Horses.push({
 | 
				
			||||||
 | 
					                ItemType: "/Lotus/Types/NeutralCreatures/ErsatzHorse/ErsatzHorsePowerSuit"
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            inventory.DataKnives.push({
 | 
				
			||||||
 | 
					                ItemType: "/Lotus/Weapons/Tenno/HackingDevices/TnHackingDevice/TnHackingDeviceWeapon",
 | 
				
			||||||
 | 
					                XP: 450000
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            inventory.Scoops.push({
 | 
				
			||||||
 | 
					                ItemType: "/Lotus/Weapons/Tenno/Speedball/SpeedballWeaponTest"
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            inventory.DrifterMelee.push({
 | 
				
			||||||
 | 
					                ItemType: "/Lotus/Types/Friendly/PlayerControllable/Weapons/DuviriDualSwords"
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            inventory.QuestKeys.push({
 | 
				
			||||||
 | 
					                ItemType: "/Lotus/Types/Keys/VorsPrize/VorsPrizeQuestKeyChain"
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            const completedMissions = ["SolNode27", "SolNode89", "SolNode63", "SolNode85", "SolNode15", "SolNode79"];
 | 
					            const completedMissions = ["SolNode27", "SolNode89", "SolNode63", "SolNode85", "SolNode15", "SolNode79"];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -97,11 +133,14 @@ export const createInventory = async (
 | 
				
			|||||||
                    Tag: tag
 | 
					                    Tag: tag
 | 
				
			||||||
                }))
 | 
					                }))
 | 
				
			||||||
            );
 | 
					            );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            inventory.RegularCredits = 25000;
 | 
				
			||||||
 | 
					            inventory.FusionPoints = 180;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        await inventory.save();
 | 
					        await inventory.save();
 | 
				
			||||||
    } catch (error) {
 | 
					    } catch (error) {
 | 
				
			||||||
        throw new Error(`Error creating inventory: ${error instanceof Error ? error.message : "Unknown error type"}`);
 | 
					        throw new Error(`Error creating inventory: ${error instanceof Error ? error.message : "Unknown error"}`);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -111,7 +150,6 @@ export const createInventory = async (
 | 
				
			|||||||
 * @param InventoryChanges - will hold the combined changes
 | 
					 * @param InventoryChanges - will hold the combined changes
 | 
				
			||||||
 * @param delta - inventory changes to be added
 | 
					 * @param delta - inventory changes to be added
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
//TODO: this fails silently when providing an incorrect object to delta
 | 
					 | 
				
			||||||
export const combineInventoryChanges = (InventoryChanges: IInventoryChanges, delta: IInventoryChanges): void => {
 | 
					export const combineInventoryChanges = (InventoryChanges: IInventoryChanges, delta: IInventoryChanges): void => {
 | 
				
			||||||
    for (const key in delta) {
 | 
					    for (const key in delta) {
 | 
				
			||||||
        if (!(key in InventoryChanges)) {
 | 
					        if (!(key in InventoryChanges)) {
 | 
				
			||||||
@ -160,11 +198,6 @@ export const addItem = async (
 | 
				
			|||||||
    typeName: string,
 | 
					    typeName: string,
 | 
				
			||||||
    quantity: number = 1
 | 
					    quantity: number = 1
 | 
				
			||||||
): Promise<{ InventoryChanges: IInventoryChanges }> => {
 | 
					): Promise<{ InventoryChanges: IInventoryChanges }> => {
 | 
				
			||||||
    // Bundles are technically StoreItems but a) they don't have a normal counterpart, and b) they are used in non-StoreItem contexts, e.g. email attachments.
 | 
					 | 
				
			||||||
    if (typeName in ExportBundles) {
 | 
					 | 
				
			||||||
        return { InventoryChanges: await handleBundleAcqusition(typeName, inventory, quantity) };
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Strict typing
 | 
					    // Strict typing
 | 
				
			||||||
    if (typeName in ExportRecipes) {
 | 
					    if (typeName in ExportRecipes) {
 | 
				
			||||||
        const recipeChanges = [
 | 
					        const recipeChanges = [
 | 
				
			||||||
@ -201,7 +234,7 @@ export const addItem = async (
 | 
				
			|||||||
                InventoryChanges: {
 | 
					                InventoryChanges: {
 | 
				
			||||||
                    Ships: [
 | 
					                    Ships: [
 | 
				
			||||||
                        {
 | 
					                        {
 | 
				
			||||||
                            ItemId: { $oid: oid.toString() },
 | 
					                            ItemId: { $oid: oid },
 | 
				
			||||||
                            ItemType: typeName
 | 
					                            ItemType: typeName
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                    ]
 | 
					                    ]
 | 
				
			||||||
@ -211,7 +244,6 @@ export const addItem = async (
 | 
				
			|||||||
            const inventoryChanges = {
 | 
					            const inventoryChanges = {
 | 
				
			||||||
                ...addCrewShip(inventory, typeName),
 | 
					                ...addCrewShip(inventory, typeName),
 | 
				
			||||||
                // fix to unlock railjack modding, item bellow supposed to be obtained from archwing quest
 | 
					                // fix to unlock railjack modding, item bellow supposed to be obtained from archwing quest
 | 
				
			||||||
                // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
 | 
					 | 
				
			||||||
                ...(!inventory.CrewShipHarnesses?.length
 | 
					                ...(!inventory.CrewShipHarnesses?.length
 | 
				
			||||||
                    ? addCrewShipHarness(inventory, "/Lotus/Types/Game/CrewShip/RailJack/DefaultHarness")
 | 
					                    ? addCrewShipHarness(inventory, "/Lotus/Types/Game/CrewShip/RailJack/DefaultHarness")
 | 
				
			||||||
                    : {})
 | 
					                    : {})
 | 
				
			||||||
@ -293,11 +325,6 @@ export const addItem = async (
 | 
				
			|||||||
        const weapon = ExportWeapons[typeName];
 | 
					        const weapon = ExportWeapons[typeName];
 | 
				
			||||||
        if (weapon.totalDamage != 0) {
 | 
					        if (weapon.totalDamage != 0) {
 | 
				
			||||||
            const inventoryChanges = addEquipment(inventory, weapon.productCategory, typeName);
 | 
					            const inventoryChanges = addEquipment(inventory, weapon.productCategory, typeName);
 | 
				
			||||||
            if (weapon.additionalItems) {
 | 
					 | 
				
			||||||
                for (const item of weapon.additionalItems) {
 | 
					 | 
				
			||||||
                    combineInventoryChanges(inventoryChanges, await addItem(inventory, item, 1));
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            updateSlots(inventory, InventorySlot.WEAPONS, 0, 1);
 | 
					            updateSlots(inventory, InventorySlot.WEAPONS, 0, 1);
 | 
				
			||||||
            return {
 | 
					            return {
 | 
				
			||||||
                InventoryChanges: {
 | 
					                InventoryChanges: {
 | 
				
			||||||
@ -321,8 +348,8 @@ export const addItem = async (
 | 
				
			|||||||
            };
 | 
					            };
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (typeName in ExportMisc.creditBundles) {
 | 
					    if (typeName in creditBundles) {
 | 
				
			||||||
        const creditsTotal = ExportMisc.creditBundles[typeName] * quantity;
 | 
					        const creditsTotal = creditBundles[typeName] * quantity;
 | 
				
			||||||
        inventory.RegularCredits += creditsTotal;
 | 
					        inventory.RegularCredits += creditsTotal;
 | 
				
			||||||
        return {
 | 
					        return {
 | 
				
			||||||
            InventoryChanges: {
 | 
					            InventoryChanges: {
 | 
				
			||||||
@ -330,8 +357,8 @@ export const addItem = async (
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (typeName in ExportFusionBundles) {
 | 
					    if (typeName in fusionBundles) {
 | 
				
			||||||
        const fusionPointsTotal = ExportFusionBundles[typeName].fusionPoints * quantity;
 | 
					        const fusionPointsTotal = fusionBundles[typeName] * quantity;
 | 
				
			||||||
        inventory.FusionPoints += fusionPointsTotal;
 | 
					        inventory.FusionPoints += fusionPointsTotal;
 | 
				
			||||||
        return {
 | 
					        return {
 | 
				
			||||||
            InventoryChanges: {
 | 
					            InventoryChanges: {
 | 
				
			||||||
@ -341,28 +368,15 @@ export const addItem = async (
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    if (typeName in ExportKeys) {
 | 
					    if (typeName in ExportKeys) {
 | 
				
			||||||
        // Note: "/Lotus/Types/Keys/" contains some EmailItems
 | 
					        // Note: "/Lotus/Types/Keys/" contains some EmailItems
 | 
				
			||||||
        const key = ExportKeys[typeName];
 | 
					        inventory.QuestKeys.push({ ItemType: typeName });
 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (key.chainStages) {
 | 
					 | 
				
			||||||
            const key = addQuestKey(inventory, { ItemType: typeName });
 | 
					 | 
				
			||||||
            if (!key) return { InventoryChanges: {} };
 | 
					 | 
				
			||||||
            return { InventoryChanges: { QuestKeys: [key] } };
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            const key = { ItemType: typeName, ItemCount: quantity };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            const index = inventory.LevelKeys.findIndex(levelKey => levelKey.ItemType == typeName);
 | 
					 | 
				
			||||||
            if (index) {
 | 
					 | 
				
			||||||
                inventory.LevelKeys[index].ItemCount += quantity;
 | 
					 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
                inventory.LevelKeys.push(key);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            return { InventoryChanges: { LevelKeys: [key] } };
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (typeName in ExportDrones) {
 | 
					 | 
				
			||||||
        const inventoryChanges = addDrone(inventory, typeName);
 | 
					 | 
				
			||||||
        return {
 | 
					        return {
 | 
				
			||||||
            InventoryChanges: inventoryChanges
 | 
					            InventoryChanges: {
 | 
				
			||||||
 | 
					                QuestKeys: [
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        ItemType: typeName
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                ]
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -418,7 +432,6 @@ export const addItem = async (
 | 
				
			|||||||
            switch (typeName.substr(1).split("/")[2]) {
 | 
					            switch (typeName.substr(1).split("/")[2]) {
 | 
				
			||||||
                case "Mods": // Legendary Core
 | 
					                case "Mods": // Legendary Core
 | 
				
			||||||
                case "CosmeticEnhancers": // Traumatic Peculiar
 | 
					                case "CosmeticEnhancers": // Traumatic Peculiar
 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                    const changes = [
 | 
					                    const changes = [
 | 
				
			||||||
                        {
 | 
					                        {
 | 
				
			||||||
                            ItemType: typeName,
 | 
					                            ItemType: typeName,
 | 
				
			||||||
@ -434,8 +447,6 @@ export const addItem = async (
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        case "Types":
 | 
					        case "Types":
 | 
				
			||||||
            switch (typeName.substr(1).split("/")[2]) {
 | 
					            switch (typeName.substr(1).split("/")[2]) {
 | 
				
			||||||
                case "Sentinels": {
 | 
					                case "Sentinels": {
 | 
				
			||||||
@ -488,7 +499,7 @@ export const addItem = async (
 | 
				
			|||||||
                    const horseIndex = inventory.Horses.push({ ItemType: typeName });
 | 
					                    const horseIndex = inventory.Horses.push({ ItemType: typeName });
 | 
				
			||||||
                    return {
 | 
					                    return {
 | 
				
			||||||
                        InventoryChanges: {
 | 
					                        InventoryChanges: {
 | 
				
			||||||
                            Horses: [inventory.Horses[horseIndex - 1].toJSON<IEquipmentClient>()]
 | 
					                            Horses: inventory.Horses[horseIndex - 1].toJSON()
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                    };
 | 
					                    };
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
@ -533,15 +544,21 @@ export const addItems = async (
 | 
				
			|||||||
    return inventoryChanges;
 | 
					    return inventoryChanges;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const applyDefaultUpgrades = (
 | 
					//TODO: maybe genericMethod for all the add methods, they share a lot of logic
 | 
				
			||||||
 | 
					export const addSentinel = (
 | 
				
			||||||
    inventory: TInventoryDatabaseDocument,
 | 
					    inventory: TInventoryDatabaseDocument,
 | 
				
			||||||
    defaultUpgrades: IDefaultUpgrade[] | undefined
 | 
					    sentinelName: string,
 | 
				
			||||||
): IItemConfig[] => {
 | 
					    inventoryChanges: IInventoryChanges = {}
 | 
				
			||||||
 | 
					): IInventoryChanges => {
 | 
				
			||||||
 | 
					    if (ExportSentinels[sentinelName]?.defaultWeapon) {
 | 
				
			||||||
 | 
					        addSentinelWeapon(inventory, ExportSentinels[sentinelName].defaultWeapon, inventoryChanges);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const modsToGive: IRawUpgrade[] = [];
 | 
					    const modsToGive: IRawUpgrade[] = [];
 | 
				
			||||||
    const configs: IItemConfig[] = [];
 | 
					    const configs: IItemConfig[] = [];
 | 
				
			||||||
    if (defaultUpgrades) {
 | 
					    if (ExportSentinels[sentinelName]?.defaultUpgrades) {
 | 
				
			||||||
        const upgrades = [];
 | 
					        const upgrades = [];
 | 
				
			||||||
        for (const defaultUpgrade of defaultUpgrades) {
 | 
					        for (const defaultUpgrade of ExportSentinels[sentinelName].defaultUpgrades) {
 | 
				
			||||||
            modsToGive.push({ ItemType: defaultUpgrade.ItemType, ItemCount: 1 });
 | 
					            modsToGive.push({ ItemType: defaultUpgrade.ItemType, ItemCount: 1 });
 | 
				
			||||||
            if (defaultUpgrade.Slot != -1) {
 | 
					            if (defaultUpgrade.Slot != -1) {
 | 
				
			||||||
                upgrades[defaultUpgrade.Slot] = defaultUpgrade.ItemType;
 | 
					                upgrades[defaultUpgrade.Slot] = defaultUpgrade.ItemType;
 | 
				
			||||||
@ -551,27 +568,13 @@ export const applyDefaultUpgrades = (
 | 
				
			|||||||
            configs.push({ Upgrades: upgrades });
 | 
					            configs.push({ Upgrades: upgrades });
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    addMods(inventory, modsToGive);
 | 
					    addMods(inventory, modsToGive);
 | 
				
			||||||
    return configs;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
//TODO: maybe genericMethod for all the add methods, they share a lot of logic
 | 
					 | 
				
			||||||
export const addSentinel = (
 | 
					 | 
				
			||||||
    inventory: TInventoryDatabaseDocument,
 | 
					 | 
				
			||||||
    sentinelName: string,
 | 
					 | 
				
			||||||
    inventoryChanges: IInventoryChanges = {}
 | 
					 | 
				
			||||||
): IInventoryChanges => {
 | 
					 | 
				
			||||||
    // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
 | 
					 | 
				
			||||||
    if (ExportSentinels[sentinelName]?.defaultWeapon) {
 | 
					 | 
				
			||||||
        addSentinelWeapon(inventory, ExportSentinels[sentinelName].defaultWeapon, inventoryChanges);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
 | 
					 | 
				
			||||||
    const configs: IItemConfig[] = applyDefaultUpgrades(inventory, ExportSentinels[sentinelName]?.defaultUpgrades);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const sentinelIndex = inventory.Sentinels.push({ ItemType: sentinelName, Configs: configs, XP: 0 }) - 1;
 | 
					    const sentinelIndex = inventory.Sentinels.push({ ItemType: sentinelName, Configs: configs, XP: 0 }) - 1;
 | 
				
			||||||
    inventoryChanges.Sentinels ??= [];
 | 
					    inventoryChanges.Sentinels ??= [];
 | 
				
			||||||
    inventoryChanges.Sentinels.push(inventory.Sentinels[sentinelIndex].toJSON<IEquipmentClient>());
 | 
					    (inventoryChanges.Sentinels as IEquipmentClient[]).push(
 | 
				
			||||||
 | 
					        inventory.Sentinels[sentinelIndex].toJSON<IEquipmentClient>()
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return inventoryChanges;
 | 
					    return inventoryChanges;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@ -583,7 +586,9 @@ export const addSentinelWeapon = (
 | 
				
			|||||||
): void => {
 | 
					): void => {
 | 
				
			||||||
    const index = inventory.SentinelWeapons.push({ ItemType: typeName, XP: 0 }) - 1;
 | 
					    const index = inventory.SentinelWeapons.push({ ItemType: typeName, XP: 0 }) - 1;
 | 
				
			||||||
    inventoryChanges.SentinelWeapons ??= [];
 | 
					    inventoryChanges.SentinelWeapons ??= [];
 | 
				
			||||||
    inventoryChanges.SentinelWeapons.push(inventory.SentinelWeapons[index].toJSON<IEquipmentClient>());
 | 
					    (inventoryChanges.SentinelWeapons as IEquipmentClient[]).push(
 | 
				
			||||||
 | 
					        inventory.SentinelWeapons[index].toJSON<IEquipmentClient>()
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const addPowerSuit = (
 | 
					export const addPowerSuit = (
 | 
				
			||||||
@ -599,7 +604,7 @@ export const addPowerSuit = (
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    const suitIndex = inventory.Suits.push({ ItemType: powersuitName, Configs: [], UpgradeVer: 101, XP: 0 }) - 1;
 | 
					    const suitIndex = inventory.Suits.push({ ItemType: powersuitName, Configs: [], UpgradeVer: 101, XP: 0 }) - 1;
 | 
				
			||||||
    inventoryChanges.Suits ??= [];
 | 
					    inventoryChanges.Suits ??= [];
 | 
				
			||||||
    inventoryChanges.Suits.push(inventory.Suits[suitIndex].toJSON<IEquipmentClient>());
 | 
					    (inventoryChanges.Suits as IEquipmentClient[]).push(inventory.Suits[suitIndex].toJSON<IEquipmentClient>());
 | 
				
			||||||
    return inventoryChanges;
 | 
					    return inventoryChanges;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -616,7 +621,7 @@ export const addMechSuit = (
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    const suitIndex = inventory.MechSuits.push({ ItemType: mechsuitName, Configs: [], UpgradeVer: 101, XP: 0 }) - 1;
 | 
					    const suitIndex = inventory.MechSuits.push({ ItemType: mechsuitName, Configs: [], UpgradeVer: 101, XP: 0 }) - 1;
 | 
				
			||||||
    inventoryChanges.MechSuits ??= [];
 | 
					    inventoryChanges.MechSuits ??= [];
 | 
				
			||||||
    inventoryChanges.MechSuits.push(inventory.MechSuits[suitIndex].toJSON<IEquipmentClient>());
 | 
					    (inventoryChanges.MechSuits as IEquipmentClient[]).push(inventory.MechSuits[suitIndex].toJSON<IEquipmentClient>());
 | 
				
			||||||
    return inventoryChanges;
 | 
					    return inventoryChanges;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -637,7 +642,9 @@ export const addSpecialItem = (
 | 
				
			|||||||
            XP: 0
 | 
					            XP: 0
 | 
				
			||||||
        }) - 1;
 | 
					        }) - 1;
 | 
				
			||||||
    inventoryChanges.SpecialItems ??= [];
 | 
					    inventoryChanges.SpecialItems ??= [];
 | 
				
			||||||
    inventoryChanges.SpecialItems.push(inventory.SpecialItems[specialItemIndex].toJSON<IEquipmentClient>());
 | 
					    (inventoryChanges.SpecialItems as IEquipmentClient[]).push(
 | 
				
			||||||
 | 
					        inventory.SpecialItems[specialItemIndex].toJSON<IEquipmentClient>()
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const addSpaceSuit = (
 | 
					export const addSpaceSuit = (
 | 
				
			||||||
@ -647,7 +654,9 @@ export const addSpaceSuit = (
 | 
				
			|||||||
): IInventoryChanges => {
 | 
					): IInventoryChanges => {
 | 
				
			||||||
    const suitIndex = inventory.SpaceSuits.push({ ItemType: spacesuitName, Configs: [], UpgradeVer: 101, XP: 0 }) - 1;
 | 
					    const suitIndex = inventory.SpaceSuits.push({ ItemType: spacesuitName, Configs: [], UpgradeVer: 101, XP: 0 }) - 1;
 | 
				
			||||||
    inventoryChanges.SpaceSuits ??= [];
 | 
					    inventoryChanges.SpaceSuits ??= [];
 | 
				
			||||||
    inventoryChanges.SpaceSuits.push(inventory.SpaceSuits[suitIndex].toJSON<IEquipmentClient>());
 | 
					    (inventoryChanges.SpaceSuits as IEquipmentClient[]).push(
 | 
				
			||||||
 | 
					        inventory.SpaceSuits[suitIndex].toJSON<IEquipmentClient>()
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
    return inventoryChanges;
 | 
					    return inventoryChanges;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -692,6 +701,20 @@ export const updateCurrency = (
 | 
				
			|||||||
    return currencyChanges;
 | 
					    return currencyChanges;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const updateCurrencyByAccountId = async (
 | 
				
			||||||
 | 
					    price: number,
 | 
				
			||||||
 | 
					    usePremium: boolean,
 | 
				
			||||||
 | 
					    accountId: string
 | 
				
			||||||
 | 
					): Promise<ICurrencyChanges> => {
 | 
				
			||||||
 | 
					    if (!isCurrencyTracked(usePremium)) {
 | 
				
			||||||
 | 
					        return {};
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    const inventory = await getInventory(accountId);
 | 
				
			||||||
 | 
					    const currencyChanges = updateCurrency(inventory, price, usePremium);
 | 
				
			||||||
 | 
					    await inventory.save();
 | 
				
			||||||
 | 
					    return currencyChanges;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const standingLimitBinToInventoryKey: Record<
 | 
					const standingLimitBinToInventoryKey: Record<
 | 
				
			||||||
    Exclude<TStandingLimitBin, "STANDING_LIMIT_BIN_NONE">,
 | 
					    Exclude<TStandingLimitBin, "STANDING_LIMIT_BIN_NONE">,
 | 
				
			||||||
    keyof IDailyAffiliations
 | 
					    keyof IDailyAffiliations
 | 
				
			||||||
@ -764,22 +787,18 @@ export const addEquipment = (
 | 
				
			|||||||
    category: TEquipmentKey,
 | 
					    category: TEquipmentKey,
 | 
				
			||||||
    type: string,
 | 
					    type: string,
 | 
				
			||||||
    modularParts: string[] | undefined = undefined,
 | 
					    modularParts: string[] | undefined = undefined,
 | 
				
			||||||
    inventoryChanges: IInventoryChanges = {},
 | 
					    inventoryChanges: IInventoryChanges = {}
 | 
				
			||||||
    defaultOverwrites: Partial<IEquipmentDatabase> | undefined = undefined
 | 
					 | 
				
			||||||
): IInventoryChanges => {
 | 
					): IInventoryChanges => {
 | 
				
			||||||
    const equipment = Object.assign(
 | 
					    const index =
 | 
				
			||||||
        {
 | 
					        inventory[category].push({
 | 
				
			||||||
            ItemType: type,
 | 
					            ItemType: type,
 | 
				
			||||||
            Configs: [],
 | 
					            Configs: [],
 | 
				
			||||||
            XP: 0,
 | 
					            XP: 0,
 | 
				
			||||||
            ModularParts: modularParts
 | 
					            ModularParts: modularParts
 | 
				
			||||||
        },
 | 
					        }) - 1;
 | 
				
			||||||
        defaultOverwrites
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
    const index = inventory[category].push(equipment) - 1;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    inventoryChanges[category] ??= [];
 | 
					    inventoryChanges[category] ??= [];
 | 
				
			||||||
    inventoryChanges[category].push(inventory[category][index].toJSON<IEquipmentClient>());
 | 
					    (inventoryChanges[category] as IEquipmentClient[]).push(inventory[category][index].toJSON<IEquipmentClient>());
 | 
				
			||||||
    return inventoryChanges;
 | 
					    return inventoryChanges;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -819,7 +838,7 @@ const addCrewShip = (
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    const index = inventory.CrewShips.push({ ItemType: typeName }) - 1;
 | 
					    const index = inventory.CrewShips.push({ ItemType: typeName }) - 1;
 | 
				
			||||||
    inventoryChanges.CrewShips ??= [];
 | 
					    inventoryChanges.CrewShips ??= [];
 | 
				
			||||||
    inventoryChanges.CrewShips.push(inventory.CrewShips[index].toJSON<IEquipmentClient>());
 | 
					    (inventoryChanges.CrewShips as IEquipmentClient[]).push(inventory.CrewShips[index].toJSON<IEquipmentClient>());
 | 
				
			||||||
    return inventoryChanges;
 | 
					    return inventoryChanges;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -833,7 +852,9 @@ const addCrewShipHarness = (
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    const index = inventory.CrewShipHarnesses.push({ ItemType: typeName }) - 1;
 | 
					    const index = inventory.CrewShipHarnesses.push({ ItemType: typeName }) - 1;
 | 
				
			||||||
    inventoryChanges.CrewShipHarnesses ??= [];
 | 
					    inventoryChanges.CrewShipHarnesses ??= [];
 | 
				
			||||||
    inventoryChanges.CrewShipHarnesses.push(inventory.CrewShipHarnesses[index].toJSON<IEquipmentClient>());
 | 
					    (inventoryChanges.CrewShipHarnesses as IEquipmentClient[]).push(
 | 
				
			||||||
 | 
					        inventory.CrewShipHarnesses[index].toJSON<IEquipmentClient>()
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
    return inventoryChanges;
 | 
					    return inventoryChanges;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -847,18 +868,7 @@ const addMotorcycle = (
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    const index = inventory.Motorcycles.push({ ItemType: typeName }) - 1;
 | 
					    const index = inventory.Motorcycles.push({ ItemType: typeName }) - 1;
 | 
				
			||||||
    inventoryChanges.Motorcycles ??= [];
 | 
					    inventoryChanges.Motorcycles ??= [];
 | 
				
			||||||
    inventoryChanges.Motorcycles.push(inventory.Motorcycles[index].toJSON<IEquipmentClient>());
 | 
					    (inventoryChanges.Motorcycles as IEquipmentClient[]).push(inventory.Motorcycles[index].toJSON<IEquipmentClient>());
 | 
				
			||||||
    return inventoryChanges;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const addDrone = (
 | 
					 | 
				
			||||||
    inventory: TInventoryDatabaseDocument,
 | 
					 | 
				
			||||||
    typeName: string,
 | 
					 | 
				
			||||||
    inventoryChanges: IInventoryChanges = {}
 | 
					 | 
				
			||||||
): IInventoryChanges => {
 | 
					 | 
				
			||||||
    const index = inventory.Drones.push({ ItemType: typeName, CurrentHP: ExportDrones[typeName].durability }) - 1;
 | 
					 | 
				
			||||||
    inventoryChanges.Drones ??= [];
 | 
					 | 
				
			||||||
    inventoryChanges.Drones.push(inventory.Drones[index].toJSON<IDroneClient>());
 | 
					 | 
				
			||||||
    return inventoryChanges;
 | 
					    return inventoryChanges;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1173,28 +1183,3 @@ export const addKeyChainItems = async (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    return inventoryChanges;
 | 
					    return inventoryChanges;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
const createLibraryAvailableDailyTaskInfo = (): ILibraryAvailableDailyTaskInfo => {
 | 
					 | 
				
			||||||
    return {
 | 
					 | 
				
			||||||
        EnemyTypes: ["/Lotus/Types/Enemies/Orokin/RifleLancerAvatar"],
 | 
					 | 
				
			||||||
        EnemyLocTag: "/Lotus/Language/Game/CorruptedLancer",
 | 
					 | 
				
			||||||
        EnemyIcon: "/Lotus/Interface/Icons/Npcs/OrokinRifleLancerAvatar.png",
 | 
					 | 
				
			||||||
        ScansRequired: 3,
 | 
					 | 
				
			||||||
        RewardStoreItem: "/Lotus/StoreItems/Upgrades/Mods/FusionBundles/UncommonFusionBundle",
 | 
					 | 
				
			||||||
        RewardQuantity: 7,
 | 
					 | 
				
			||||||
        RewardStanding: 7500
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const createCalendar = (): ICalendarProgress => {
 | 
					 | 
				
			||||||
    return {
 | 
					 | 
				
			||||||
        Version: 19,
 | 
					 | 
				
			||||||
        Iteration: 2,
 | 
					 | 
				
			||||||
        YearProgress: { Upgrades: [] },
 | 
					 | 
				
			||||||
        SeasonProgress: {
 | 
					 | 
				
			||||||
            SeasonType: "CST_SPRING",
 | 
					 | 
				
			||||||
            LastCompletedDayIdx: -1,
 | 
					 | 
				
			||||||
            LastCompletedChallengeDayIdx: -1,
 | 
					 | 
				
			||||||
            ActivatedChallenges: []
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -163,21 +163,20 @@ export const getKeyChainItems = ({ KeyChain, ChainStage }: IKeyChainRequest): st
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const getLevelKeyRewards = (levelKey: string) => {
 | 
					export const getLevelKeyRewards = (levelKey: string) => {
 | 
				
			||||||
    if (!ExportKeys[levelKey]) {
 | 
					    const levelKeyData = ExportKeys[levelKey];
 | 
				
			||||||
        throw new Error(`LevelKey ${levelKey} not found`);
 | 
					    if (!levelKeyData) {
 | 
				
			||||||
 | 
					        const error = `LevelKey ${levelKey} not found`;
 | 
				
			||||||
 | 
					        logger.error(error);
 | 
				
			||||||
 | 
					        throw new Error(error);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const levelKeyRewards = ExportKeys[levelKey]?.missionReward;
 | 
					    if (!levelKeyData.rewards) {
 | 
				
			||||||
    const levelKeyRewards2 = ExportKeys[levelKey]?.rewards;
 | 
					        const error = `LevelKey ${levelKey} does not contain rewards`;
 | 
				
			||||||
 | 
					        logger.error(error);
 | 
				
			||||||
    if (!levelKeyRewards && !levelKeyRewards2) {
 | 
					        throw new Error(error);
 | 
				
			||||||
        throw new Error(`LevelKey ${levelKey} does not contain either rewards1 or rewards2`);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return {
 | 
					    return levelKeyData.rewards;
 | 
				
			||||||
        levelKeyRewards,
 | 
					 | 
				
			||||||
        levelKeyRewards2
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const getNode = (nodeName: string): IRegion => {
 | 
					export const getNode = (nodeName: string): IRegion => {
 | 
				
			||||||
 | 
				
			|||||||
@ -47,15 +47,16 @@ export const createPersonalRooms = async (accountId: Types.ObjectId, shipId: Typ
 | 
				
			|||||||
        activeShipId: shipId
 | 
					        activeShipId: shipId
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    if (config.skipTutorial) {
 | 
					    if (config.skipTutorial) {
 | 
				
			||||||
        // unlocked during Vor's Prize
 | 
					        // // Vor's Prize rewards
 | 
				
			||||||
        const defaultFeatures = [
 | 
					        // const defaultFeatures = [
 | 
				
			||||||
            "/Lotus/Types/Items/ShipFeatureItems/MercuryNavigationFeatureItem",
 | 
					        //     "/Lotus/Types/Items/ShipFeatureItems/EarthNavigationFeatureItem",
 | 
				
			||||||
            "/Lotus/Types/Items/ShipFeatureItems/ArsenalFeatureItem",
 | 
					        //     "/Lotus/Types/Items/ShipFeatureItems/MercuryNavigationFeatureItem",
 | 
				
			||||||
            "/Lotus/Types/Items/ShipFeatureItems/SocialMenuFeatureItem",
 | 
					        //     "/Lotus/Types/Items/ShipFeatureItems/ArsenalFeatureItem",
 | 
				
			||||||
            "/Lotus/Types/Items/ShipFeatureItems/FoundryFeatureItem",
 | 
					        //     "/Lotus/Types/Items/ShipFeatureItems/SocialMenuFeatureItem",
 | 
				
			||||||
            "/Lotus/Types/Items/ShipFeatureItems/ModsFeatureItem"
 | 
					        //     "/Lotus/Types/Items/ShipFeatureItems/FoundryFeatureItem",
 | 
				
			||||||
        ];
 | 
					        //     "/Lotus/Types/Items/ShipFeatureItems/ModsFeatureItem"
 | 
				
			||||||
        personalRooms.Ship.Features.push(...defaultFeatures);
 | 
					        // ];
 | 
				
			||||||
 | 
					        // personalRooms.Ship.Features.push(...defaultFeatures);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    await personalRooms.save();
 | 
					    await personalRooms.save();
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -1,10 +1,4 @@
 | 
				
			|||||||
import {
 | 
					import { ExportRegions, ExportRewards, IReward } from "warframe-public-export-plus";
 | 
				
			||||||
    ExportFusionBundles,
 | 
					 | 
				
			||||||
    ExportRegions,
 | 
					 | 
				
			||||||
    ExportRewards,
 | 
					 | 
				
			||||||
    IMissionReward as IMissionRewardExternal,
 | 
					 | 
				
			||||||
    IReward
 | 
					 | 
				
			||||||
} from "warframe-public-export-plus";
 | 
					 | 
				
			||||||
import { IMissionInventoryUpdateRequest, IRewardInfo } from "../types/requestTypes";
 | 
					import { IMissionInventoryUpdateRequest, IRewardInfo } from "../types/requestTypes";
 | 
				
			||||||
import { logger } from "@/src/utils/logger";
 | 
					import { logger } from "@/src/utils/logger";
 | 
				
			||||||
import { IRngResult, getRandomReward } from "@/src/services/rngService";
 | 
					import { IRngResult, getRandomReward } from "@/src/services/rngService";
 | 
				
			||||||
@ -17,6 +11,7 @@ import {
 | 
				
			|||||||
    addFocusXpIncreases,
 | 
					    addFocusXpIncreases,
 | 
				
			||||||
    addFusionTreasures,
 | 
					    addFusionTreasures,
 | 
				
			||||||
    addGearExpByCategory,
 | 
					    addGearExpByCategory,
 | 
				
			||||||
 | 
					    addItem,
 | 
				
			||||||
    addMiscItems,
 | 
					    addMiscItems,
 | 
				
			||||||
    addMissionComplete,
 | 
					    addMissionComplete,
 | 
				
			||||||
    addMods,
 | 
					    addMods,
 | 
				
			||||||
@ -31,9 +26,6 @@ import { getLevelKeyRewards, getNode } from "@/src/services/itemDataService";
 | 
				
			|||||||
import { InventoryDocumentProps, TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
 | 
					import { InventoryDocumentProps, TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
 | 
				
			||||||
import { getEntriesUnsafe } from "@/src/utils/ts-utils";
 | 
					import { getEntriesUnsafe } from "@/src/utils/ts-utils";
 | 
				
			||||||
import { IEquipmentClient } from "@/src/types/inventoryTypes/commonInventoryTypes";
 | 
					import { IEquipmentClient } from "@/src/types/inventoryTypes/commonInventoryTypes";
 | 
				
			||||||
import { handleStoreItemAcquisition } from "./purchaseService";
 | 
					 | 
				
			||||||
import { IMissionReward } from "../types/missionTypes";
 | 
					 | 
				
			||||||
import { crackRelic } from "@/src/helpers/relicHelper";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
const getRotations = (rotationCount: number): number[] => {
 | 
					const getRotations = (rotationCount: number): number[] => {
 | 
				
			||||||
    if (rotationCount === 0) return [0];
 | 
					    if (rotationCount === 0) return [0];
 | 
				
			||||||
@ -52,6 +44,31 @@ const getRandomRewardByChance = (pool: IReward[]): IRngResult | undefined => {
 | 
				
			|||||||
    return getRandomReward(pool as IRngResult[]);
 | 
					    return getRandomReward(pool as IRngResult[]);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const creditBundles: Record<string, number> = {
 | 
				
			||||||
 | 
					    "/Lotus/Types/PickUps/Credits/1500Credits": 1500,
 | 
				
			||||||
 | 
					    "/Lotus/Types/PickUps/Credits/2000Credits": 2000,
 | 
				
			||||||
 | 
					    "/Lotus/Types/PickUps/Credits/2500Credits": 2500,
 | 
				
			||||||
 | 
					    "/Lotus/Types/PickUps/Credits/3000Credits": 3000,
 | 
				
			||||||
 | 
					    "/Lotus/Types/PickUps/Credits/4000Credits": 4000,
 | 
				
			||||||
 | 
					    "/Lotus/Types/PickUps/Credits/5000Credits": 5000,
 | 
				
			||||||
 | 
					    "/Lotus/Types/PickUps/Credits/7500Credits": 7500,
 | 
				
			||||||
 | 
					    "/Lotus/Types/PickUps/Credits/10000Credits": 10000,
 | 
				
			||||||
 | 
					    "/Lotus/Types/PickUps/Credits/5000Hollars": 5000,
 | 
				
			||||||
 | 
					    "/Lotus/Types/PickUps/Credits/7500Hollars": 7500,
 | 
				
			||||||
 | 
					    "/Lotus/Types/PickUps/Credits/10000Hollars": 10000,
 | 
				
			||||||
 | 
					    "/Lotus/Types/PickUps/Credits/CorpusArenaCreditRewards/CorpusArenaRewardOneHard": 105000,
 | 
				
			||||||
 | 
					    "/Lotus/Types/PickUps/Credits/CorpusArenaCreditRewards/CorpusArenaRewardTwoHard": 175000,
 | 
				
			||||||
 | 
					    "/Lotus/Types/PickUps/Credits/CorpusArenaCreditRewards/CorpusArenaRewardThreeHard": 250000,
 | 
				
			||||||
 | 
					    "/Lotus/Types/StoreItems/CreditBundles/Zariman/TableACreditsCommon": 15000,
 | 
				
			||||||
 | 
					    "/Lotus/Types/StoreItems/CreditBundles/Zariman/TableACreditsUncommon": 30000
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const fusionBundles: Record<string, number> = {
 | 
				
			||||||
 | 
					    "/Lotus/Upgrades/Mods/FusionBundles/CommonFusionBundle": 15,
 | 
				
			||||||
 | 
					    "/Lotus/Upgrades/Mods/FusionBundles/UncommonFusionBundle": 50,
 | 
				
			||||||
 | 
					    "/Lotus/Upgrades/Mods/FusionBundles/RareFusionBundle": 80
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//type TMissionInventoryUpdateKeys = keyof IMissionInventoryUpdateRequest;
 | 
					//type TMissionInventoryUpdateKeys = keyof IMissionInventoryUpdateRequest;
 | 
				
			||||||
//const ignoredInventoryUpdateKeys = ["FpsAvg", "FpsMax", "FpsMin", "FpsSamples"] satisfies TMissionInventoryUpdateKeys[]; // for keys with no meaning for this server
 | 
					//const ignoredInventoryUpdateKeys = ["FpsAvg", "FpsMax", "FpsMin", "FpsSamples"] satisfies TMissionInventoryUpdateKeys[]; // for keys with no meaning for this server
 | 
				
			||||||
//type TignoredInventoryUpdateKeys = (typeof ignoredInventoryUpdateKeys)[number];
 | 
					//type TignoredInventoryUpdateKeys = (typeof ignoredInventoryUpdateKeys)[number];
 | 
				
			||||||
@ -60,7 +77,7 @@ const getRandomRewardByChance = (pool: IReward[]): IRngResult | undefined => {
 | 
				
			|||||||
export const addMissionInventoryUpdates = (
 | 
					export const addMissionInventoryUpdates = (
 | 
				
			||||||
    inventory: HydratedDocument<IInventoryDatabase, InventoryDocumentProps>,
 | 
					    inventory: HydratedDocument<IInventoryDatabase, InventoryDocumentProps>,
 | 
				
			||||||
    inventoryUpdates: IMissionInventoryUpdateRequest
 | 
					    inventoryUpdates: IMissionInventoryUpdateRequest
 | 
				
			||||||
): Partial<IInventoryDatabase> | undefined => {
 | 
					) => {
 | 
				
			||||||
    //TODO: type this properly
 | 
					    //TODO: type this properly
 | 
				
			||||||
    const inventoryChanges: Partial<IInventoryDatabase> = {};
 | 
					    const inventoryChanges: Partial<IInventoryDatabase> = {};
 | 
				
			||||||
    if (inventoryUpdates.MissionFailed === true) {
 | 
					    if (inventoryUpdates.MissionFailed === true) {
 | 
				
			||||||
@ -144,8 +161,7 @@ export const addMissionInventoryUpdates = (
 | 
				
			|||||||
            case "FusionBundles": {
 | 
					            case "FusionBundles": {
 | 
				
			||||||
                let fusionPoints = 0;
 | 
					                let fusionPoints = 0;
 | 
				
			||||||
                for (const fusionBundle of value) {
 | 
					                for (const fusionBundle of value) {
 | 
				
			||||||
                    const fusionPointsTotal =
 | 
					                    const fusionPointsTotal = fusionBundles[fusionBundle.ItemType] * fusionBundle.ItemCount;
 | 
				
			||||||
                        ExportFusionBundles[fusionBundle.ItemType].fusionPoints * fusionBundle.ItemCount;
 | 
					 | 
				
			||||||
                    inventory.FusionPoints += fusionPointsTotal;
 | 
					                    inventory.FusionPoints += fusionPointsTotal;
 | 
				
			||||||
                    fusionPoints += fusionPointsTotal;
 | 
					                    fusionPoints += fusionPointsTotal;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
@ -188,14 +204,14 @@ export const addMissionInventoryUpdates = (
 | 
				
			|||||||
                inventory.CompletedSorties.push(value);
 | 
					                inventory.CompletedSorties.push(value);
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            case "SeasonChallengeCompletions": {
 | 
					            case "SeasonChallengeCompletions":
 | 
				
			||||||
                const processedCompletions = value.map(({ challenge, id }) => ({
 | 
					                const processedCompletions = value.map(({ challenge, id }) => ({
 | 
				
			||||||
                    challenge: challenge.substring(challenge.lastIndexOf("/") + 1),
 | 
					                    challenge: challenge.substring(challenge.lastIndexOf("/") + 1),
 | 
				
			||||||
                    id
 | 
					                    id
 | 
				
			||||||
                }));
 | 
					                }));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                inventory.SeasonChallengeHistory.push(...processedCompletions);
 | 
					                inventory.SeasonChallengeHistory.push(...processedCompletions);
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            default:
 | 
					            default:
 | 
				
			||||||
                // Equipment XP updates
 | 
					                // Equipment XP updates
 | 
				
			||||||
                if (equipmentKeys.includes(key as TEquipmentKey)) {
 | 
					                if (equipmentKeys.includes(key as TEquipmentKey)) {
 | 
				
			||||||
@ -222,8 +238,7 @@ export const addMissionRewards = async (
 | 
				
			|||||||
        RewardInfo: rewardInfo,
 | 
					        RewardInfo: rewardInfo,
 | 
				
			||||||
        LevelKeyName: levelKeyName,
 | 
					        LevelKeyName: levelKeyName,
 | 
				
			||||||
        Missions: missions,
 | 
					        Missions: missions,
 | 
				
			||||||
        RegularCredits: creditDrops,
 | 
					        RegularCredits: creditDrops
 | 
				
			||||||
        VoidTearParticipantsCurrWave: voidTearWave
 | 
					 | 
				
			||||||
    }: IMissionInventoryUpdateRequest
 | 
					    }: IMissionInventoryUpdateRequest
 | 
				
			||||||
) => {
 | 
					) => {
 | 
				
			||||||
    if (!rewardInfo) {
 | 
					    if (!rewardInfo) {
 | 
				
			||||||
@ -233,7 +248,9 @@ export const addMissionRewards = async (
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    //TODO: check double reward merging
 | 
					    //TODO: check double reward merging
 | 
				
			||||||
    const MissionRewards: IMissionReward[] = getRandomMissionDrops(rewardInfo);
 | 
					    const MissionRewards = getRandomMissionDrops(rewardInfo).map(drop => {
 | 
				
			||||||
 | 
					        return { StoreItem: drop.type, ItemCount: drop.itemCount };
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
    logger.debug("random mission drops:", MissionRewards);
 | 
					    logger.debug("random mission drops:", MissionRewards);
 | 
				
			||||||
    const inventoryChanges: IInventoryChanges = {};
 | 
					    const inventoryChanges: IInventoryChanges = {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -242,11 +259,7 @@ export const addMissionRewards = async (
 | 
				
			|||||||
    if (levelKeyName) {
 | 
					    if (levelKeyName) {
 | 
				
			||||||
        const fixedLevelRewards = getLevelKeyRewards(levelKeyName);
 | 
					        const fixedLevelRewards = getLevelKeyRewards(levelKeyName);
 | 
				
			||||||
        //logger.debug(`fixedLevelRewards ${fixedLevelRewards}`);
 | 
					        //logger.debug(`fixedLevelRewards ${fixedLevelRewards}`);
 | 
				
			||||||
        if (fixedLevelRewards.levelKeyRewards) {
 | 
					        for (const reward of fixedLevelRewards) {
 | 
				
			||||||
            addFixedLevelRewards(fixedLevelRewards.levelKeyRewards, inventory, MissionRewards);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if (fixedLevelRewards.levelKeyRewards2) {
 | 
					 | 
				
			||||||
            for (const reward of fixedLevelRewards.levelKeyRewards2) {
 | 
					 | 
				
			||||||
            //quest stage completion credit rewards
 | 
					            //quest stage completion credit rewards
 | 
				
			||||||
            if (reward.rewardType == "RT_CREDITS") {
 | 
					            if (reward.rewardType == "RT_CREDITS") {
 | 
				
			||||||
                inventory.RegularCredits += reward.amount;
 | 
					                inventory.RegularCredits += reward.amount;
 | 
				
			||||||
@ -259,54 +272,39 @@ export const addMissionRewards = async (
 | 
				
			|||||||
            });
 | 
					            });
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (
 | 
					 | 
				
			||||||
        missions &&
 | 
					 | 
				
			||||||
        missions.Tag != "" // #1013
 | 
					 | 
				
			||||||
    ) {
 | 
					 | 
				
			||||||
        const node = getNode(missions.Tag);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        //node based credit rewards for mission completion
 | 
					 | 
				
			||||||
        if (node.missionIndex !== 28) {
 | 
					 | 
				
			||||||
            const levelCreditReward = getLevelCreditRewards(missions.Tag);
 | 
					 | 
				
			||||||
            missionCompletionCredits += levelCreditReward;
 | 
					 | 
				
			||||||
            inventory.RegularCredits += levelCreditReward;
 | 
					 | 
				
			||||||
            logger.debug(`levelCreditReward ${levelCreditReward}`);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (node.missionReward) {
 | 
					 | 
				
			||||||
            missionCompletionCredits += addFixedLevelRewards(node.missionReward, inventory, MissionRewards);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (const reward of MissionRewards) {
 | 
					    for (const reward of MissionRewards) {
 | 
				
			||||||
        const inventoryChange = await handleStoreItemAcquisition(reward.StoreItem, inventory, reward.ItemCount);
 | 
					        //TODO: additem should take in storeItems
 | 
				
			||||||
 | 
					        const inventoryChange = await addItem(inventory, reward.StoreItem.replace("StoreItems/", ""), reward.ItemCount);
 | 
				
			||||||
        //TODO: combineInventoryChanges improve type safety, merging 2 of the same item?
 | 
					        //TODO: combineInventoryChanges improve type safety, merging 2 of the same item?
 | 
				
			||||||
        //TODO: check for the case when two of the same item are added, combineInventoryChanges should merge them, but the client also merges them
 | 
					        //TODO: check for the case when two of the same item are added, combineInventoryChanges should merge them, but the client also merges them
 | 
				
			||||||
        //TODO: some conditional types to rule out binchanges?
 | 
					        //TODO: some conditional types to rule out binchanges?
 | 
				
			||||||
        combineInventoryChanges(inventoryChanges, inventoryChange.InventoryChanges);
 | 
					        combineInventoryChanges(inventoryChanges, inventoryChange.InventoryChanges);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //node based credit rewards for mission completion
 | 
				
			||||||
 | 
					    if (missions) {
 | 
				
			||||||
 | 
					        const node = getNode(missions.Tag);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (node.missionIndex !== 28) {
 | 
				
			||||||
 | 
					            const levelCreditReward = getLevelCreditRewards(missions?.Tag);
 | 
				
			||||||
 | 
					            missionCompletionCredits += levelCreditReward;
 | 
				
			||||||
 | 
					            inventory.RegularCredits += levelCreditReward;
 | 
				
			||||||
 | 
					            logger.debug(`levelCreditReward ${levelCreditReward}`);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //creditBonus is not correct for mirage mission 3
 | 
				
			||||||
    const credits = addCredits(inventory, {
 | 
					    const credits = addCredits(inventory, {
 | 
				
			||||||
        missionCompletionCredits,
 | 
					        missionCompletionCredits,
 | 
				
			||||||
        missionDropCredits: creditDrops ?? 0,
 | 
					        missionDropCredits: creditDrops ?? 0,
 | 
				
			||||||
        rngRewardCredits: inventoryChanges.RegularCredits ?? 0
 | 
					        rngRewardCredits: inventoryChanges.RegularCredits ?? 0
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (
 | 
					 | 
				
			||||||
        voidTearWave &&
 | 
					 | 
				
			||||||
        voidTearWave.Participants[0].QualifiesForReward &&
 | 
					 | 
				
			||||||
        !voidTearWave.Participants[0].HaveRewardResponse
 | 
					 | 
				
			||||||
    ) {
 | 
					 | 
				
			||||||
        await crackRelic(inventory, voidTearWave.Participants[0]);
 | 
					 | 
				
			||||||
        MissionRewards.push({ StoreItem: voidTearWave.Participants[0].Reward, ItemCount: 1 });
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return { inventoryChanges, MissionRewards, credits };
 | 
					    return { inventoryChanges, MissionRewards, credits };
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//creditBonus is not entirely accurate.
 | 
					//slightly inaccurate compared to official
 | 
				
			||||||
//TODO: consider ActiveBoosters
 | 
					//TODO: consider ActiveBoosters
 | 
				
			||||||
export const addCredits = (
 | 
					export const addCredits = (
 | 
				
			||||||
    inventory: HydratedDocument<IInventoryDatabase>,
 | 
					    inventory: HydratedDocument<IInventoryDatabase>,
 | 
				
			||||||
@ -338,42 +336,6 @@ export const addCredits = (
 | 
				
			|||||||
    return { ...finalCredits, DailyMissionBonus: true };
 | 
					    return { ...finalCredits, DailyMissionBonus: true };
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const addFixedLevelRewards = (
 | 
					 | 
				
			||||||
    rewards: IMissionRewardExternal,
 | 
					 | 
				
			||||||
    inventory: TInventoryDatabaseDocument,
 | 
					 | 
				
			||||||
    MissionRewards: IMissionReward[]
 | 
					 | 
				
			||||||
) => {
 | 
					 | 
				
			||||||
    let missionBonusCredits = 0;
 | 
					 | 
				
			||||||
    if (rewards.credits) {
 | 
					 | 
				
			||||||
        missionBonusCredits += rewards.credits;
 | 
					 | 
				
			||||||
        inventory.RegularCredits += rewards.credits;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (rewards.items) {
 | 
					 | 
				
			||||||
        for (const item of rewards.items) {
 | 
					 | 
				
			||||||
            MissionRewards.push({
 | 
					 | 
				
			||||||
                StoreItem: item.includes(`/StoreItems/`) ? item : `/Lotus/StoreItems${item.substring("Lotus/".length)}`,
 | 
					 | 
				
			||||||
                ItemCount: 1
 | 
					 | 
				
			||||||
            });
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (rewards.countedItems) {
 | 
					 | 
				
			||||||
        for (const item of rewards.countedItems) {
 | 
					 | 
				
			||||||
            MissionRewards.push({
 | 
					 | 
				
			||||||
                StoreItem: item.ItemType.includes(`/StoreItems/`)
 | 
					 | 
				
			||||||
                    ? item.ItemType
 | 
					 | 
				
			||||||
                    : `/Lotus/StoreItems${item.ItemType.substring("Lotus/".length)}`,
 | 
					 | 
				
			||||||
                ItemCount: item.ItemCount
 | 
					 | 
				
			||||||
            });
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (rewards.countedStoreItems) {
 | 
					 | 
				
			||||||
        for (const item of rewards.countedStoreItems) {
 | 
					 | 
				
			||||||
            MissionRewards.push(item);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return missionBonusCredits;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function getLevelCreditRewards(nodeName: string): number {
 | 
					function getLevelCreditRewards(nodeName: string): number {
 | 
				
			||||||
    const minEnemyLevel = getNode(nodeName).minEnemyLevel;
 | 
					    const minEnemyLevel = getNode(nodeName).minEnemyLevel;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -382,14 +344,11 @@ function getLevelCreditRewards(nodeName: string): number {
 | 
				
			|||||||
    //TODO: get dark sektor fixed credit rewards and railjack bonus
 | 
					    //TODO: get dark sektor fixed credit rewards and railjack bonus
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function getRandomMissionDrops(RewardInfo: IRewardInfo): IMissionReward[] {
 | 
					function getRandomMissionDrops(RewardInfo: IRewardInfo): IRngResult[] {
 | 
				
			||||||
    const drops: IMissionReward[] = [];
 | 
					    const drops: IRngResult[] = [];
 | 
				
			||||||
    if (RewardInfo.node in ExportRegions) {
 | 
					    if (RewardInfo.node in ExportRegions) {
 | 
				
			||||||
        const region = ExportRegions[RewardInfo.node];
 | 
					        const region = ExportRegions[RewardInfo.node];
 | 
				
			||||||
        const rewardManifests: string[] =
 | 
					        const rewardManifests = region.rewardManifests ?? [];
 | 
				
			||||||
            RewardInfo.periodicMissionTag == "EliteAlert" || RewardInfo.periodicMissionTag == "EliteAlertB"
 | 
					 | 
				
			||||||
                ? ["/Lotus/Types/Game/MissionDecks/EliteAlertMissionRewards/EliteAlertMissionRewards"]
 | 
					 | 
				
			||||||
                : region.rewardManifests;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let rotations: number[] = [];
 | 
					        let rotations: number[] = [];
 | 
				
			||||||
        if (RewardInfo.VaultsCracked) {
 | 
					        if (RewardInfo.VaultsCracked) {
 | 
				
			||||||
@ -408,7 +367,7 @@ function getRandomMissionDrops(RewardInfo: IRewardInfo): IMissionReward[] {
 | 
				
			|||||||
                    const rotationRewards = table[rotation];
 | 
					                    const rotationRewards = table[rotation];
 | 
				
			||||||
                    const drop = getRandomRewardByChance(rotationRewards);
 | 
					                    const drop = getRandomRewardByChance(rotationRewards);
 | 
				
			||||||
                    if (drop) {
 | 
					                    if (drop) {
 | 
				
			||||||
                        drops.push({ StoreItem: drop.type, ItemCount: drop.itemCount });
 | 
					                        drops.push(drop);
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
@ -418,7 +377,7 @@ function getRandomMissionDrops(RewardInfo: IRewardInfo): IMissionReward[] {
 | 
				
			|||||||
            for (let rotation = 0; rotation != RewardInfo.EnemyCachesFound; ++rotation) {
 | 
					            for (let rotation = 0; rotation != RewardInfo.EnemyCachesFound; ++rotation) {
 | 
				
			||||||
                const drop = getRandomRewardByChance(deck[rotation]);
 | 
					                const drop = getRandomRewardByChance(deck[rotation]);
 | 
				
			||||||
                if (drop) {
 | 
					                if (drop) {
 | 
				
			||||||
                    drops.push({ StoreItem: drop.type, ItemCount: drop.itemCount, FromEnemyCache: true });
 | 
					                    drops.push(drop);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -437,7 +396,7 @@ function getRandomMissionDrops(RewardInfo: IRewardInfo): IMissionReward[] {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            const drop = getRandomRewardByChance(deck[rotation]);
 | 
					            const drop = getRandomRewardByChance(deck[rotation]);
 | 
				
			||||||
            if (drop) {
 | 
					            if (drop) {
 | 
				
			||||||
                drops.push({ StoreItem: drop.type, ItemCount: drop.itemCount });
 | 
					                drops.push(drop);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -16,10 +16,8 @@ import { logger } from "@/src/utils/logger";
 | 
				
			|||||||
import worldState from "@/static/fixed_responses/worldState/worldState.json";
 | 
					import worldState from "@/static/fixed_responses/worldState/worldState.json";
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
    ExportBoosterPacks,
 | 
					    ExportBoosterPacks,
 | 
				
			||||||
    ExportBoosters,
 | 
					 | 
				
			||||||
    ExportBundles,
 | 
					    ExportBundles,
 | 
				
			||||||
    ExportGear,
 | 
					    ExportGear,
 | 
				
			||||||
    ExportMisc,
 | 
					 | 
				
			||||||
    ExportResources,
 | 
					    ExportResources,
 | 
				
			||||||
    ExportSyndicates,
 | 
					    ExportSyndicates,
 | 
				
			||||||
    ExportVendors,
 | 
					    ExportVendors,
 | 
				
			||||||
@ -200,31 +198,6 @@ const handleItemPrices = (
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const handleBundleAcqusition = async (
 | 
					 | 
				
			||||||
    storeItemName: string,
 | 
					 | 
				
			||||||
    inventory: TInventoryDatabaseDocument,
 | 
					 | 
				
			||||||
    quantity: number = 1,
 | 
					 | 
				
			||||||
    inventoryChanges: IInventoryChanges = {}
 | 
					 | 
				
			||||||
): Promise<IInventoryChanges> => {
 | 
					 | 
				
			||||||
    const bundle = ExportBundles[storeItemName];
 | 
					 | 
				
			||||||
    logger.debug("acquiring bundle", bundle);
 | 
					 | 
				
			||||||
    for (const component of bundle.components) {
 | 
					 | 
				
			||||||
        combineInventoryChanges(
 | 
					 | 
				
			||||||
            inventoryChanges,
 | 
					 | 
				
			||||||
            (
 | 
					 | 
				
			||||||
                await handleStoreItemAcquisition(
 | 
					 | 
				
			||||||
                    component.typeName,
 | 
					 | 
				
			||||||
                    inventory,
 | 
					 | 
				
			||||||
                    component.purchaseQuantity * quantity,
 | 
					 | 
				
			||||||
                    component.durability,
 | 
					 | 
				
			||||||
                    true
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
            ).InventoryChanges
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return inventoryChanges;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const handleStoreItemAcquisition = async (
 | 
					export const handleStoreItemAcquisition = async (
 | 
				
			||||||
    storeItemName: string,
 | 
					    storeItemName: string,
 | 
				
			||||||
    inventory: TInventoryDatabaseDocument,
 | 
					    inventory: TInventoryDatabaseDocument,
 | 
				
			||||||
@ -237,7 +210,22 @@ export const handleStoreItemAcquisition = async (
 | 
				
			|||||||
    };
 | 
					    };
 | 
				
			||||||
    logger.debug(`handling acquision of ${storeItemName}`);
 | 
					    logger.debug(`handling acquision of ${storeItemName}`);
 | 
				
			||||||
    if (storeItemName in ExportBundles) {
 | 
					    if (storeItemName in ExportBundles) {
 | 
				
			||||||
        await handleBundleAcqusition(storeItemName, inventory, quantity, purchaseResponse.InventoryChanges);
 | 
					        const bundle = ExportBundles[storeItemName];
 | 
				
			||||||
 | 
					        logger.debug("acquiring bundle", bundle);
 | 
				
			||||||
 | 
					        for (const component of bundle.components) {
 | 
				
			||||||
 | 
					            combineInventoryChanges(
 | 
				
			||||||
 | 
					                purchaseResponse.InventoryChanges,
 | 
				
			||||||
 | 
					                (
 | 
				
			||||||
 | 
					                    await handleStoreItemAcquisition(
 | 
				
			||||||
 | 
					                        component.typeName,
 | 
				
			||||||
 | 
					                        inventory,
 | 
				
			||||||
 | 
					                        component.purchaseQuantity * quantity,
 | 
				
			||||||
 | 
					                        component.durability,
 | 
				
			||||||
 | 
					                        true
 | 
				
			||||||
 | 
					                    )
 | 
				
			||||||
 | 
					                ).InventoryChanges
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        const storeCategory = getStoreItemCategory(storeItemName);
 | 
					        const storeCategory = getStoreItemCategory(storeItemName);
 | 
				
			||||||
        const internalName = storeItemName.replace("/StoreItems", "");
 | 
					        const internalName = storeItemName.replace("/StoreItems", "");
 | 
				
			||||||
@ -258,7 +246,7 @@ export const handleStoreItemAcquisition = async (
 | 
				
			|||||||
                purchaseResponse = await handleTypesPurchase(internalName, inventory, quantity);
 | 
					                purchaseResponse = await handleTypesPurchase(internalName, inventory, quantity);
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
            case "Boosters":
 | 
					            case "Boosters":
 | 
				
			||||||
                purchaseResponse = handleBoostersPurchase(storeItemName, inventory, durability);
 | 
					                purchaseResponse = handleBoostersPurchase(internalName, inventory, durability);
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -342,22 +330,6 @@ const handleBoosterPackPurchase = async (
 | 
				
			|||||||
    return purchaseResponse;
 | 
					    return purchaseResponse;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const handleCreditBundlePurchase = async (
 | 
					 | 
				
			||||||
    typeName: string,
 | 
					 | 
				
			||||||
    inventory: TInventoryDatabaseDocument
 | 
					 | 
				
			||||||
): Promise<IPurchaseResponse> => {
 | 
					 | 
				
			||||||
    if (typeName && typeName in ExportMisc.creditBundles) {
 | 
					 | 
				
			||||||
        const creditsAmount = ExportMisc.creditBundles[typeName];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        inventory.RegularCredits += creditsAmount;
 | 
					 | 
				
			||||||
        await inventory.save();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return { InventoryChanges: { RegularCredits: creditsAmount } };
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
        throw new Error(`unknown credit bundle: ${typeName}`);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
//TODO: change to getInventory, apply changes then save at the end
 | 
					//TODO: change to getInventory, apply changes then save at the end
 | 
				
			||||||
const handleTypesPurchase = async (
 | 
					const handleTypesPurchase = async (
 | 
				
			||||||
    typesName: string,
 | 
					    typesName: string,
 | 
				
			||||||
@ -373,23 +345,35 @@ const handleTypesPurchase = async (
 | 
				
			|||||||
            return handleBoosterPackPurchase(typesName, inventory, quantity);
 | 
					            return handleBoosterPackPurchase(typesName, inventory, quantity);
 | 
				
			||||||
        case "SlotItems":
 | 
					        case "SlotItems":
 | 
				
			||||||
            return handleSlotPurchase(typesName, inventory, quantity);
 | 
					            return handleSlotPurchase(typesName, inventory, quantity);
 | 
				
			||||||
        case "CreditBundles":
 | 
					 | 
				
			||||||
            return handleCreditBundlePurchase(typesName, inventory);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const boosterCollection = [
 | 
				
			||||||
 | 
					    "/Lotus/Types/Boosters/ResourceAmountBooster",
 | 
				
			||||||
 | 
					    "/Lotus/Types/Boosters/AffinityBooster",
 | 
				
			||||||
 | 
					    "/Lotus/Types/Boosters/ResourceDropChanceBooster",
 | 
				
			||||||
 | 
					    "/Lotus/Types/Boosters/CreditBooster"
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const boosterDuration: Record<TRarity, number> = {
 | 
				
			||||||
 | 
					    COMMON: 3 * 86400,
 | 
				
			||||||
 | 
					    UNCOMMON: 7 * 86400,
 | 
				
			||||||
 | 
					    RARE: 30 * 86400,
 | 
				
			||||||
 | 
					    LEGENDARY: 90 * 86400
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const handleBoostersPurchase = (
 | 
					const handleBoostersPurchase = (
 | 
				
			||||||
    boosterStoreName: string,
 | 
					    boosterStoreName: string,
 | 
				
			||||||
    inventory: TInventoryDatabaseDocument,
 | 
					    inventory: TInventoryDatabaseDocument,
 | 
				
			||||||
    durability: TRarity
 | 
					    durability: TRarity
 | 
				
			||||||
): { InventoryChanges: IInventoryChanges } => {
 | 
					): { InventoryChanges: IInventoryChanges } => {
 | 
				
			||||||
    if (!(boosterStoreName in ExportBoosters)) {
 | 
					    const ItemType = boosterStoreName.replace("StoreItem", "");
 | 
				
			||||||
        logger.error(`unknown booster type: ${boosterStoreName}`);
 | 
					    if (!boosterCollection.find(x => x == ItemType)) {
 | 
				
			||||||
 | 
					        logger.error(`unknown booster type: ${ItemType}`);
 | 
				
			||||||
        return { InventoryChanges: {} };
 | 
					        return { InventoryChanges: {} };
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const ItemType = ExportBoosters[boosterStoreName].typeName;
 | 
					    const ExpiryDate = boosterDuration[durability];
 | 
				
			||||||
    const ExpiryDate = ExportMisc.boosterDurations[durability];
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    addBooster(ItemType, ExpiryDate, inventory);
 | 
					    addBooster(ItemType, ExpiryDate, inventory);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -3,19 +3,12 @@ import { isEmptyObject } from "@/src/helpers/general";
 | 
				
			|||||||
import { IMessage } from "@/src/models/inboxModel";
 | 
					import { IMessage } from "@/src/models/inboxModel";
 | 
				
			||||||
import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
 | 
					import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
 | 
				
			||||||
import { createMessage } from "@/src/services/inboxService";
 | 
					import { createMessage } from "@/src/services/inboxService";
 | 
				
			||||||
import { addItem, addKeyChainItems } from "@/src/services/inventoryService";
 | 
					import { addKeyChainItems } from "@/src/services/inventoryService";
 | 
				
			||||||
import { getKeyChainMessage, getLevelKeyRewards } from "@/src/services/itemDataService";
 | 
					import { getKeyChainMessage } from "@/src/services/itemDataService";
 | 
				
			||||||
import {
 | 
					import { IInventoryDatabase, IQuestKeyDatabase, IQuestStage } from "@/src/types/inventoryTypes/inventoryTypes";
 | 
				
			||||||
    IInventoryDatabase,
 | 
					 | 
				
			||||||
    IQuestKeyClient,
 | 
					 | 
				
			||||||
    IQuestKeyDatabase,
 | 
					 | 
				
			||||||
    IQuestStage
 | 
					 | 
				
			||||||
} from "@/src/types/inventoryTypes/inventoryTypes";
 | 
					 | 
				
			||||||
import { logger } from "@/src/utils/logger";
 | 
					import { logger } from "@/src/utils/logger";
 | 
				
			||||||
import { HydratedDocument } from "mongoose";
 | 
					import { HydratedDocument } from "mongoose";
 | 
				
			||||||
import { ExportKeys } from "warframe-public-export-plus";
 | 
					import { ExportKeys } from "warframe-public-export-plus";
 | 
				
			||||||
import { addFixedLevelRewards } from "./missionInventoryUpdateService";
 | 
					 | 
				
			||||||
import { IInventoryChanges } from "../types/purchaseTypes";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface IUpdateQuestRequest {
 | 
					export interface IUpdateQuestRequest {
 | 
				
			||||||
    QuestKeys: Omit<IQuestKeyDatabase, "CompletionDate">[];
 | 
					    QuestKeys: Omit<IQuestKeyDatabase, "CompletionDate">[];
 | 
				
			||||||
@ -65,7 +58,6 @@ export const updateQuestStage = (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    const questStage = quest.Progress[ChainStage];
 | 
					    const questStage = quest.Progress[ChainStage];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
 | 
					 | 
				
			||||||
    if (!questStage) {
 | 
					    if (!questStage) {
 | 
				
			||||||
        const questStageIndex = quest.Progress.push(questStageUpdate) - 1;
 | 
					        const questStageIndex = quest.Progress.push(questStageUpdate) - 1;
 | 
				
			||||||
        if (questStageIndex !== ChainStage) {
 | 
					        if (questStageIndex !== ChainStage) {
 | 
				
			||||||
@ -77,18 +69,15 @@ export const updateQuestStage = (
 | 
				
			|||||||
    Object.assign(questStage, questStageUpdate);
 | 
					    Object.assign(questStage, questStageUpdate);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const addQuestKey = (inventory: TInventoryDatabaseDocument, questKey: IQuestKeyDatabase) => {
 | 
					export const addQuestKey = (inventory: TInventoryDatabaseDocument, questKey: IQuestKeyDatabase): void => {
 | 
				
			||||||
    if (inventory.QuestKeys.some(q => q.ItemType === questKey.ItemType)) {
 | 
					    if (inventory.QuestKeys.some(q => q.ItemType === questKey.ItemType)) {
 | 
				
			||||||
        logger.warn(`Quest key ${questKey.ItemType} already exists. It will not be added`);
 | 
					        logger.error(`quest key ${questKey.ItemType} already exists`);
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    const index = inventory.QuestKeys.push(questKey);
 | 
					    inventory.QuestKeys.push(questKey);
 | 
				
			||||||
 | 
					 | 
				
			||||||
    return inventory.QuestKeys[index - 1].toJSON<IQuestKeyClient>();
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const completeQuest = async (inventory: TInventoryDatabaseDocument, questKey: string) => {
 | 
					export const completeQuest = async (inventory: TInventoryDatabaseDocument, questKey: string) => {
 | 
				
			||||||
    // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
 | 
					 | 
				
			||||||
    const chainStages = ExportKeys[questKey]?.chainStages;
 | 
					    const chainStages = ExportKeys[questKey]?.chainStages;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!chainStages) {
 | 
					    if (!chainStages) {
 | 
				
			||||||
@ -136,41 +125,11 @@ export const completeQuest = async (inventory: TInventoryDatabaseDocument, quest
 | 
				
			|||||||
                ChainStage: i
 | 
					                ChainStage: i
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					 | 
				
			||||||
        const missionName = chainStages[i].key;
 | 
					 | 
				
			||||||
        if (missionName) {
 | 
					 | 
				
			||||||
            const fixedLevelRewards = getLevelKeyRewards(missionName);
 | 
					 | 
				
			||||||
            //logger.debug(`fixedLevelRewards`, fixedLevelRewards);
 | 
					 | 
				
			||||||
            if (fixedLevelRewards.levelKeyRewards) {
 | 
					 | 
				
			||||||
                const missionRewards: { StoreItem: string; ItemCount: number }[] = [];
 | 
					 | 
				
			||||||
                addFixedLevelRewards(fixedLevelRewards.levelKeyRewards, inventory, missionRewards);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                for (const reward of missionRewards) {
 | 
					 | 
				
			||||||
                    await addItem(inventory, reward.StoreItem.replace("StoreItems/", ""), reward.ItemCount);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
            } else if (fixedLevelRewards.levelKeyRewards2) {
 | 
					    //TODO: handle quest completions
 | 
				
			||||||
                for (const reward of fixedLevelRewards.levelKeyRewards2) {
 | 
					 | 
				
			||||||
                    if (reward.rewardType == "RT_CREDITS") {
 | 
					 | 
				
			||||||
                        inventory.RegularCredits += reward.amount;
 | 
					 | 
				
			||||||
                        continue;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    if (reward.rewardType == "RT_RESOURCE") {
 | 
					 | 
				
			||||||
                        await addItem(inventory, reward.itemType.replace("StoreItems/", ""), reward.amount);
 | 
					 | 
				
			||||||
                    } else {
 | 
					 | 
				
			||||||
                        await addItem(inventory, reward.itemType.replace("StoreItems/", ""));
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    inventory.ActiveQuest = "";
 | 
					 | 
				
			||||||
    //TODO: handle quest completion items
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const giveKeyChainItem = async (
 | 
					export const giveKeyChainItem = async (inventory: TInventoryDatabaseDocument, keyChainInfo: IKeyChainRequest) => {
 | 
				
			||||||
    inventory: TInventoryDatabaseDocument,
 | 
					 | 
				
			||||||
    keyChainInfo: IKeyChainRequest
 | 
					 | 
				
			||||||
): Promise<IInventoryChanges> => {
 | 
					 | 
				
			||||||
    const inventoryChanges = await addKeyChainItems(inventory, keyChainInfo);
 | 
					    const inventoryChanges = await addKeyChainItems(inventory, keyChainInfo);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (isEmptyObject(inventoryChanges)) {
 | 
					    if (isEmptyObject(inventoryChanges)) {
 | 
				
			||||||
@ -179,8 +138,6 @@ export const giveKeyChainItem = async (
 | 
				
			|||||||
    // items were added: update quest stage's i (item was given)
 | 
					    // items were added: update quest stage's i (item was given)
 | 
				
			||||||
    updateQuestStage(inventory, keyChainInfo, { i: true });
 | 
					    updateQuestStage(inventory, keyChainInfo, { i: true });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return inventoryChanges;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    //TODO: Check whether Wishlist is used to track items which should exist uniquely in the inventory
 | 
					    //TODO: Check whether Wishlist is used to track items which should exist uniquely in the inventory
 | 
				
			||||||
    /*
 | 
					    /*
 | 
				
			||||||
    some items are added or removed (not sure) to the wishlist, in that case a 
 | 
					    some items are added or removed (not sure) to the wishlist, in that case a 
 | 
				
			||||||
@ -195,7 +152,7 @@ export const giveKeyChainMessage = async (
 | 
				
			|||||||
    inventory: TInventoryDatabaseDocument,
 | 
					    inventory: TInventoryDatabaseDocument,
 | 
				
			||||||
    accountId: string,
 | 
					    accountId: string,
 | 
				
			||||||
    keyChainInfo: IKeyChainRequest
 | 
					    keyChainInfo: IKeyChainRequest
 | 
				
			||||||
): Promise<void> => {
 | 
					) => {
 | 
				
			||||||
    const keyChainMessage = getKeyChainMessage(keyChainInfo);
 | 
					    const keyChainMessage = getKeyChainMessage(keyChainInfo);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const message = {
 | 
					    const message = {
 | 
				
			||||||
 | 
				
			|||||||
@ -148,7 +148,7 @@ export const handleInventoryItemConfigChange = async (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                    const itemEntries = equipment as IItemEntry;
 | 
					                    const itemEntries = equipment as IItemEntry;
 | 
				
			||||||
                    for (const [itemId, itemConfigEntries] of Object.entries(itemEntries)) {
 | 
					                    for (const [itemId, itemConfigEntries] of Object.entries(itemEntries)) {
 | 
				
			||||||
                        const inventoryItem = inventory[equipmentName].id(itemId);
 | 
					                        const inventoryItem = inventory[equipmentName].find(item => item._id?.toString() === itemId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        if (!inventoryItem) {
 | 
					                        if (!inventoryItem) {
 | 
				
			||||||
                            throw new Error(`inventory item ${equipmentName} not found with id ${itemId}`);
 | 
					                            throw new Error(`inventory item ${equipmentName} not found with id ${itemId}`);
 | 
				
			||||||
 | 
				
			|||||||
@ -58,7 +58,6 @@ export const updateStats = async (playerStats: TStatsDatabaseDocument, payload:
 | 
				
			|||||||
                                        break;
 | 
					                                        break;
 | 
				
			||||||
                                    default:
 | 
					                                    default:
 | 
				
			||||||
                                        if (!ignoredCategories.includes(category)) {
 | 
					                                        if (!ignoredCategories.includes(category)) {
 | 
				
			||||||
                                            // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
 | 
					 | 
				
			||||||
                                            if (!unknownCategories[action]) {
 | 
					                                            if (!unknownCategories[action]) {
 | 
				
			||||||
                                                unknownCategories[action] = [];
 | 
					                                                unknownCategories[action] = [];
 | 
				
			||||||
                                            }
 | 
					                                            }
 | 
				
			||||||
@ -106,7 +105,7 @@ export const updateStats = async (playerStats: TStatsDatabaseDocument, payload:
 | 
				
			|||||||
                        case "FIRE_WEAPON":
 | 
					                        case "FIRE_WEAPON":
 | 
				
			||||||
                        case "HIT_ENTITY_ITEM":
 | 
					                        case "HIT_ENTITY_ITEM":
 | 
				
			||||||
                        case "HEADSHOT_ITEM":
 | 
					                        case "HEADSHOT_ITEM":
 | 
				
			||||||
                        case "KILL_ENEMY_ITEM": {
 | 
					                        case "KILL_ENEMY_ITEM":
 | 
				
			||||||
                            playerStats.Weapons ??= [];
 | 
					                            playerStats.Weapons ??= [];
 | 
				
			||||||
                            const statKey = {
 | 
					                            const statKey = {
 | 
				
			||||||
                                FIRE_WEAPON: "fired",
 | 
					                                FIRE_WEAPON: "fired",
 | 
				
			||||||
@ -127,11 +126,10 @@ export const updateStats = async (playerStats: TStatsDatabaseDocument, payload:
 | 
				
			|||||||
                                }
 | 
					                                }
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
                            break;
 | 
					                            break;
 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        case "KILL_ENEMY":
 | 
					                        case "KILL_ENEMY":
 | 
				
			||||||
                        case "EXECUTE_ENEMY":
 | 
					                        case "EXECUTE_ENEMY":
 | 
				
			||||||
                        case "HEADSHOT": {
 | 
					                        case "HEADSHOT":
 | 
				
			||||||
                            playerStats.Enemies ??= [];
 | 
					                            playerStats.Enemies ??= [];
 | 
				
			||||||
                            const enemyStatKey = {
 | 
					                            const enemyStatKey = {
 | 
				
			||||||
                                KILL_ENEMY: "kills",
 | 
					                                KILL_ENEMY: "kills",
 | 
				
			||||||
@ -151,7 +149,6 @@ export const updateStats = async (playerStats: TStatsDatabaseDocument, payload:
 | 
				
			|||||||
                                }
 | 
					                                }
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
                            break;
 | 
					                            break;
 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        case "DIE":
 | 
					                        case "DIE":
 | 
				
			||||||
                            playerStats.Enemies ??= [];
 | 
					                            playerStats.Enemies ??= [];
 | 
				
			||||||
@ -232,7 +229,6 @@ export const updateStats = async (playerStats: TStatsDatabaseDocument, payload:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                        default:
 | 
					                        default:
 | 
				
			||||||
                            if (!ignoredCategories.includes(category)) {
 | 
					                            if (!ignoredCategories.includes(category)) {
 | 
				
			||||||
                                // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
 | 
					 | 
				
			||||||
                                if (!unknownCategories[action]) {
 | 
					                                if (!unknownCategories[action]) {
 | 
				
			||||||
                                    unknownCategories[action] = [];
 | 
					                                    unknownCategories[action] = [];
 | 
				
			||||||
                                }
 | 
					                                }
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,3 @@
 | 
				
			|||||||
import { ITypeCount } from "@/src/types/inventoryTypes/inventoryTypes";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export interface IOid {
 | 
					export interface IOid {
 | 
				
			||||||
    $oid: string;
 | 
					    $oid: string;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -9,10 +7,3 @@ export interface IMongoDate {
 | 
				
			|||||||
        $numberLong: string;
 | 
					        $numberLong: string;
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
export interface IReward {
 | 
					 | 
				
			||||||
    items: ITypeCount[];
 | 
					 | 
				
			||||||
    credits: number;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export type IJunctionRewards = Record<string, IReward>;
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -12,10 +12,6 @@ import {
 | 
				
			|||||||
    IOperatorConfigDatabase
 | 
					    IOperatorConfigDatabase
 | 
				
			||||||
} from "@/src/types/inventoryTypes/commonInventoryTypes";
 | 
					} from "@/src/types/inventoryTypes/commonInventoryTypes";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type InventoryDatabaseEquipment = {
 | 
					 | 
				
			||||||
    [_ in TEquipmentKey]: IEquipmentDatabase[];
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export interface IInventoryDatabase
 | 
					export interface IInventoryDatabase
 | 
				
			||||||
    extends Omit<
 | 
					    extends Omit<
 | 
				
			||||||
        IInventoryClient,
 | 
					        IInventoryClient,
 | 
				
			||||||
@ -38,11 +34,8 @@ export interface IInventoryDatabase
 | 
				
			|||||||
        | "InfestedFoundry"
 | 
					        | "InfestedFoundry"
 | 
				
			||||||
        | "DialogueHistory"
 | 
					        | "DialogueHistory"
 | 
				
			||||||
        | "KubrowPetEggs"
 | 
					        | "KubrowPetEggs"
 | 
				
			||||||
            | "PendingCoupon"
 | 
					 | 
				
			||||||
            | "Drones"
 | 
					 | 
				
			||||||
        | TEquipmentKey
 | 
					        | TEquipmentKey
 | 
				
			||||||
        >,
 | 
					    > {
 | 
				
			||||||
        InventoryDatabaseEquipment {
 | 
					 | 
				
			||||||
    accountOwnerId: Types.ObjectId;
 | 
					    accountOwnerId: Types.ObjectId;
 | 
				
			||||||
    Created: Date;
 | 
					    Created: Date;
 | 
				
			||||||
    TrainingDate: Date;
 | 
					    TrainingDate: Date;
 | 
				
			||||||
@ -51,7 +44,7 @@ export interface IInventoryDatabase
 | 
				
			|||||||
    GuildId?: Types.ObjectId;
 | 
					    GuildId?: Types.ObjectId;
 | 
				
			||||||
    PendingRecipes: IPendingRecipe[];
 | 
					    PendingRecipes: IPendingRecipe[];
 | 
				
			||||||
    QuestKeys: IQuestKeyDatabase[];
 | 
					    QuestKeys: IQuestKeyDatabase[];
 | 
				
			||||||
    BlessingCooldown?: Date;
 | 
					    BlessingCooldown: Date;
 | 
				
			||||||
    Ships: Types.ObjectId[];
 | 
					    Ships: Types.ObjectId[];
 | 
				
			||||||
    WeaponSkins: IWeaponSkinDatabase[];
 | 
					    WeaponSkins: IWeaponSkinDatabase[];
 | 
				
			||||||
    Upgrades: IUpgradeDatabase[];
 | 
					    Upgrades: IUpgradeDatabase[];
 | 
				
			||||||
@ -63,8 +56,30 @@ export interface IInventoryDatabase
 | 
				
			|||||||
    InfestedFoundry?: IInfestedFoundryDatabase;
 | 
					    InfestedFoundry?: IInfestedFoundryDatabase;
 | 
				
			||||||
    DialogueHistory?: IDialogueHistoryDatabase;
 | 
					    DialogueHistory?: IDialogueHistoryDatabase;
 | 
				
			||||||
    KubrowPetEggs?: IKubrowPetEggDatabase[];
 | 
					    KubrowPetEggs?: IKubrowPetEggDatabase[];
 | 
				
			||||||
    PendingCoupon?: IPendingCouponDatabase;
 | 
					
 | 
				
			||||||
    Drones: IDroneDatabase[];
 | 
					    Suits: IEquipmentDatabase[];
 | 
				
			||||||
 | 
					    LongGuns: IEquipmentDatabase[];
 | 
				
			||||||
 | 
					    Pistols: IEquipmentDatabase[];
 | 
				
			||||||
 | 
					    Melee: IEquipmentDatabase[];
 | 
				
			||||||
 | 
					    SpecialItems: IEquipmentDatabase[];
 | 
				
			||||||
 | 
					    Sentinels: IEquipmentDatabase[];
 | 
				
			||||||
 | 
					    SentinelWeapons: IEquipmentDatabase[];
 | 
				
			||||||
 | 
					    SpaceSuits: IEquipmentDatabase[];
 | 
				
			||||||
 | 
					    SpaceGuns: IEquipmentDatabase[];
 | 
				
			||||||
 | 
					    SpaceMelee: IEquipmentDatabase[];
 | 
				
			||||||
 | 
					    Hoverboards: IEquipmentDatabase[];
 | 
				
			||||||
 | 
					    OperatorAmps: IEquipmentDatabase[];
 | 
				
			||||||
 | 
					    MoaPets: IEquipmentDatabase[];
 | 
				
			||||||
 | 
					    Scoops: IEquipmentDatabase[];
 | 
				
			||||||
 | 
					    Horses: IEquipmentDatabase[];
 | 
				
			||||||
 | 
					    DrifterGuns: IEquipmentDatabase[];
 | 
				
			||||||
 | 
					    DrifterMelee: IEquipmentDatabase[];
 | 
				
			||||||
 | 
					    Motorcycles: IEquipmentDatabase[];
 | 
				
			||||||
 | 
					    CrewShips: IEquipmentDatabase[];
 | 
				
			||||||
 | 
					    DataKnives: IEquipmentDatabase[];
 | 
				
			||||||
 | 
					    MechSuits: IEquipmentDatabase[];
 | 
				
			||||||
 | 
					    CrewShipHarnesses: IEquipmentDatabase[];
 | 
				
			||||||
 | 
					    KubrowPets: IEquipmentDatabase[];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface IQuestKeyDatabase {
 | 
					export interface IQuestKeyDatabase {
 | 
				
			||||||
@ -164,11 +179,30 @@ export interface IDailyAffiliations {
 | 
				
			|||||||
    DailyAffiliationHex: number;
 | 
					    DailyAffiliationHex: number;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type InventoryClientEquipment = {
 | 
					export interface IInventoryClient extends IDailyAffiliations {
 | 
				
			||||||
    [_ in TEquipmentKey]: IEquipmentClient[];
 | 
					    Suits: IEquipmentClient[];
 | 
				
			||||||
};
 | 
					    LongGuns: IEquipmentClient[];
 | 
				
			||||||
 | 
					    Pistols: IEquipmentClient[];
 | 
				
			||||||
export interface IInventoryClient extends IDailyAffiliations, InventoryClientEquipment {
 | 
					    Melee: IEquipmentClient[];
 | 
				
			||||||
 | 
					    SpecialItems: IEquipmentClient[];
 | 
				
			||||||
 | 
					    Sentinels: IEquipmentClient[];
 | 
				
			||||||
 | 
					    SentinelWeapons: IEquipmentClient[];
 | 
				
			||||||
 | 
					    SpaceSuits: IEquipmentClient[];
 | 
				
			||||||
 | 
					    SpaceGuns: IEquipmentClient[];
 | 
				
			||||||
 | 
					    SpaceMelee: IEquipmentClient[];
 | 
				
			||||||
 | 
					    Hoverboards: IEquipmentClient[];
 | 
				
			||||||
 | 
					    OperatorAmps: IEquipmentClient[];
 | 
				
			||||||
 | 
					    MoaPets: IEquipmentClient[];
 | 
				
			||||||
 | 
					    Scoops: IEquipmentClient[];
 | 
				
			||||||
 | 
					    Horses: IEquipmentClient[];
 | 
				
			||||||
 | 
					    DrifterGuns: IEquipmentClient[];
 | 
				
			||||||
 | 
					    DrifterMelee: IEquipmentClient[];
 | 
				
			||||||
 | 
					    Motorcycles: IEquipmentClient[];
 | 
				
			||||||
 | 
					    CrewShips: IEquipmentClient[];
 | 
				
			||||||
 | 
					    DataKnives: IEquipmentClient[];
 | 
				
			||||||
 | 
					    MechSuits: IEquipmentClient[];
 | 
				
			||||||
 | 
					    CrewShipHarnesses: IEquipmentClient[];
 | 
				
			||||||
 | 
					    KubrowPets: IEquipmentClient[];
 | 
				
			||||||
    AdultOperatorLoadOuts: IOperatorConfigClient[];
 | 
					    AdultOperatorLoadOuts: IOperatorConfigClient[];
 | 
				
			||||||
    OperatorLoadOuts: IOperatorConfigClient[];
 | 
					    OperatorLoadOuts: IOperatorConfigClient[];
 | 
				
			||||||
    KahlLoadOuts: IOperatorConfigClient[];
 | 
					    KahlLoadOuts: IOperatorConfigClient[];
 | 
				
			||||||
@ -260,7 +294,7 @@ export interface IInventoryClient extends IDailyAffiliations, InventoryClientEqu
 | 
				
			|||||||
    Alignment: IAlignment;
 | 
					    Alignment: IAlignment;
 | 
				
			||||||
    CompletedSorties: string[];
 | 
					    CompletedSorties: string[];
 | 
				
			||||||
    LastSortieReward: ILastSortieReward[];
 | 
					    LastSortieReward: ILastSortieReward[];
 | 
				
			||||||
    Drones: IDroneClient[];
 | 
					    Drones: IDrone[];
 | 
				
			||||||
    StepSequencers: IStepSequencer[];
 | 
					    StepSequencers: IStepSequencer[];
 | 
				
			||||||
    ActiveAvatarImageType: string;
 | 
					    ActiveAvatarImageType: string;
 | 
				
			||||||
    ShipDecorations: IConsumable[];
 | 
					    ShipDecorations: IConsumable[];
 | 
				
			||||||
@ -300,7 +334,7 @@ export interface IInventoryClient extends IDailyAffiliations, InventoryClientEqu
 | 
				
			|||||||
    PlayedParkourTutorial: boolean;
 | 
					    PlayedParkourTutorial: boolean;
 | 
				
			||||||
    SubscribedToEmailsPersonalized: number;
 | 
					    SubscribedToEmailsPersonalized: number;
 | 
				
			||||||
    InfestedFoundry?: IInfestedFoundryClient;
 | 
					    InfestedFoundry?: IInfestedFoundryClient;
 | 
				
			||||||
    BlessingCooldown?: IMongoDate;
 | 
					    BlessingCooldown: IMongoDate;
 | 
				
			||||||
    CrewShipRawSalvage: IConsumable[];
 | 
					    CrewShipRawSalvage: IConsumable[];
 | 
				
			||||||
    CrewMembers: ICrewMember[];
 | 
					    CrewMembers: ICrewMember[];
 | 
				
			||||||
    LotusCustomization: ILotusCustomization;
 | 
					    LotusCustomization: ILotusCustomization;
 | 
				
			||||||
@ -309,7 +343,7 @@ export interface IInventoryClient extends IDailyAffiliations, InventoryClientEqu
 | 
				
			|||||||
    LastInventorySync: IOid;
 | 
					    LastInventorySync: IOid;
 | 
				
			||||||
    NextRefill: IMongoDate; // Next time argon crystals will have a decay tick
 | 
					    NextRefill: IMongoDate; // Next time argon crystals will have a decay tick
 | 
				
			||||||
    FoundToday?: IMiscItem[]; // for Argon Crystals
 | 
					    FoundToday?: IMiscItem[]; // for Argon Crystals
 | 
				
			||||||
    CustomMarkers?: ICustomMarkers[];
 | 
					    CustomMarkers: ICustomMarkers[];
 | 
				
			||||||
    ActiveLandscapeTraps: any[];
 | 
					    ActiveLandscapeTraps: any[];
 | 
				
			||||||
    EvolutionProgress?: IEvolutionProgress[];
 | 
					    EvolutionProgress?: IEvolutionProgress[];
 | 
				
			||||||
    RepVotes: any[];
 | 
					    RepVotes: any[];
 | 
				
			||||||
@ -322,12 +356,11 @@ export interface IInventoryClient extends IDailyAffiliations, InventoryClientEqu
 | 
				
			|||||||
    CollectibleSeries: ICollectibleSery[];
 | 
					    CollectibleSeries: ICollectibleSery[];
 | 
				
			||||||
    LibraryAvailableDailyTaskInfo: ILibraryAvailableDailyTaskInfo;
 | 
					    LibraryAvailableDailyTaskInfo: ILibraryAvailableDailyTaskInfo;
 | 
				
			||||||
    HasResetAccount: boolean;
 | 
					    HasResetAccount: boolean;
 | 
				
			||||||
    PendingCoupon?: IPendingCouponClient;
 | 
					    PendingCoupon: IPendingCoupon;
 | 
				
			||||||
    Harvestable: boolean;
 | 
					    Harvestable: boolean;
 | 
				
			||||||
    DeathSquadable: boolean;
 | 
					    DeathSquadable: boolean;
 | 
				
			||||||
    EndlessXP?: IEndlessXpProgress[];
 | 
					    EndlessXP?: IEndlessXpProgress[];
 | 
				
			||||||
    DialogueHistory?: IDialogueHistoryClient;
 | 
					    DialogueHistory?: IDialogueHistoryClient;
 | 
				
			||||||
    CalendarProgress: ICalendarProgress;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface IAffiliation {
 | 
					export interface IAffiliation {
 | 
				
			||||||
@ -510,20 +543,13 @@ export interface IDiscoveredMarker {
 | 
				
			|||||||
    discoveryState: number[];
 | 
					    discoveryState: number[];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface IDroneClient {
 | 
					export interface IDrone {
 | 
				
			||||||
    ItemType: string;
 | 
					    ItemType: string;
 | 
				
			||||||
    CurrentHP: number;
 | 
					    CurrentHP: number;
 | 
				
			||||||
    ItemId: IOid;
 | 
					    ItemId: IOid;
 | 
				
			||||||
    RepairStart?: IMongoDate;
 | 
					    RepairStart?: IMongoDate;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface IDroneDatabase {
 | 
					 | 
				
			||||||
    ItemType: string;
 | 
					 | 
				
			||||||
    CurrentHP: number;
 | 
					 | 
				
			||||||
    _id: Types.ObjectId;
 | 
					 | 
				
			||||||
    RepairStart?: Date;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export interface ITypeXPItem {
 | 
					export interface ITypeXPItem {
 | 
				
			||||||
    ItemType: string;
 | 
					    ItemType: string;
 | 
				
			||||||
    XP: number;
 | 
					    XP: number;
 | 
				
			||||||
@ -771,12 +797,7 @@ export enum Manifest {
 | 
				
			|||||||
    LotusTypesGameNemesisKuvaLichKuvaLichManifestVersionTwo = "/Lotus/Types/Game/Nemesis/KuvaLich/KuvaLichManifestVersionTwo"
 | 
					    LotusTypesGameNemesisKuvaLichKuvaLichManifestVersionTwo = "/Lotus/Types/Game/Nemesis/KuvaLich/KuvaLichManifestVersionTwo"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface IPendingCouponDatabase {
 | 
					export interface IPendingCoupon {
 | 
				
			||||||
    Expiry: Date;
 | 
					 | 
				
			||||||
    Discount: number;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export interface IPendingCouponClient {
 | 
					 | 
				
			||||||
    Expiry: IMongoDate;
 | 
					    Expiry: IMongoDate;
 | 
				
			||||||
    Discount: number;
 | 
					    Discount: number;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -875,7 +896,6 @@ export interface IPersonalTechProject {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface IPlayerSkills {
 | 
					export interface IPlayerSkills {
 | 
				
			||||||
    LPP_NONE: number;
 | 
					 | 
				
			||||||
    LPP_SPACE: number;
 | 
					    LPP_SPACE: number;
 | 
				
			||||||
    LPS_PILOTING: number;
 | 
					    LPS_PILOTING: number;
 | 
				
			||||||
    LPS_GUNNERY: number;
 | 
					    LPS_GUNNERY: number;
 | 
				
			||||||
@ -1060,16 +1080,3 @@ export interface IMarker {
 | 
				
			|||||||
    z: number;
 | 
					    z: number;
 | 
				
			||||||
    showInHud: boolean;
 | 
					    showInHud: boolean;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
export interface ISeasonProgress {
 | 
					 | 
				
			||||||
    SeasonType: "CST_UNDEFINED" | "CST_WINTER" | "CST_SPRING" | "CST_SUMMER" | "CST_FALL";
 | 
					 | 
				
			||||||
    LastCompletedDayIdx: number;
 | 
					 | 
				
			||||||
    LastCompletedChallengeDayIdx: number;
 | 
					 | 
				
			||||||
    ActivatedChallenges: unknown[];
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export interface ICalendarProgress {
 | 
					 | 
				
			||||||
    Version: number;
 | 
					 | 
				
			||||||
    Iteration: number;
 | 
					 | 
				
			||||||
    YearProgress: { Upgrades: unknown[] };
 | 
					 | 
				
			||||||
    SeasonProgress: ISeasonProgress;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -39,11 +39,11 @@ export interface ILoginResponse extends IAccountAndLoginResponseCommons {
 | 
				
			|||||||
    Groups: IGroup[];
 | 
					    Groups: IGroup[];
 | 
				
			||||||
    BuildLabel: string;
 | 
					    BuildLabel: string;
 | 
				
			||||||
    MatchmakingBuildId: string;
 | 
					    MatchmakingBuildId: string;
 | 
				
			||||||
    platformCDNs?: string[];
 | 
					    platformCDNs: string[];
 | 
				
			||||||
    NRS?: string[];
 | 
					    NRS: string[];
 | 
				
			||||||
    DTLS: number;
 | 
					    DTLS: number;
 | 
				
			||||||
    IRC: string[];
 | 
					    IRC: string[];
 | 
				
			||||||
    HUB?: string;
 | 
					    HUB: string;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface IGroup {
 | 
					export interface IGroup {
 | 
				
			||||||
 | 
				
			|||||||
@ -8,6 +8,4 @@ export interface IMissionReward {
 | 
				
			|||||||
    ItemCount: number;
 | 
					    ItemCount: number;
 | 
				
			||||||
    TweetText?: string;
 | 
					    TweetText?: string;
 | 
				
			||||||
    ProductCategory?: string;
 | 
					    ProductCategory?: string;
 | 
				
			||||||
    FromEnemyCache?: boolean;
 | 
					 | 
				
			||||||
    IsStrippedItem?: boolean;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,4 @@
 | 
				
			|||||||
import { IEquipmentClient } from "./inventoryTypes/commonInventoryTypes";
 | 
					import { IInfestedFoundryClient } from "./inventoryTypes/inventoryTypes";
 | 
				
			||||||
import { IDroneClient, IInfestedFoundryClient, TEquipmentKey } from "./inventoryTypes/inventoryTypes";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface IPurchaseRequest {
 | 
					export interface IPurchaseRequest {
 | 
				
			||||||
    PurchaseParams: IPurchaseParams;
 | 
					    PurchaseParams: IPurchaseParams;
 | 
				
			||||||
@ -30,12 +29,10 @@ export interface ICurrencyChanges {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
export type IInventoryChanges = {
 | 
					export type IInventoryChanges = {
 | 
				
			||||||
    [_ in SlotNames]?: IBinChanges;
 | 
					    [_ in SlotNames]?: IBinChanges;
 | 
				
			||||||
} & {
 | 
					} & ICurrencyChanges & { InfestedFoundry?: IInfestedFoundryClient } & Record<
 | 
				
			||||||
    [_ in TEquipmentKey]?: IEquipmentClient[];
 | 
					        string,
 | 
				
			||||||
} & ICurrencyChanges & {
 | 
					        IBinChanges | number | object[] | IInfestedFoundryClient
 | 
				
			||||||
        InfestedFoundry?: IInfestedFoundryClient;
 | 
					    >;
 | 
				
			||||||
        Drones?: IDroneClient[];
 | 
					 | 
				
			||||||
    } & Record<string, IBinChanges | number | object[] | IInfestedFoundryClient>;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface IAffiliationMods {
 | 
					export interface IAffiliationMods {
 | 
				
			||||||
    Tag: string;
 | 
					    Tag: string;
 | 
				
			||||||
 | 
				
			|||||||
@ -87,11 +87,6 @@ export type IMissionInventoryUpdateRequest = {
 | 
				
			|||||||
    PlayerSkillGains: IPlayerSkills;
 | 
					    PlayerSkillGains: IPlayerSkills;
 | 
				
			||||||
    CustomMarkers?: ICustomMarkers[];
 | 
					    CustomMarkers?: ICustomMarkers[];
 | 
				
			||||||
    LoreFragmentScans?: ILoreFragmentScan[];
 | 
					    LoreFragmentScans?: ILoreFragmentScan[];
 | 
				
			||||||
    VoidTearParticipantsCurrWave?: {
 | 
					 | 
				
			||||||
        Wave: number;
 | 
					 | 
				
			||||||
        IsFinalWave: boolean;
 | 
					 | 
				
			||||||
        Participants: IVoidTearParticipantInfo[];
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
} & {
 | 
					} & {
 | 
				
			||||||
    [K in TEquipmentKey]?: IEquipmentClient[];
 | 
					    [K in TEquipmentKey]?: IEquipmentClient[];
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@ -141,17 +136,3 @@ export interface IUnlockShipFeatureRequest {
 | 
				
			|||||||
    KeyChain: string;
 | 
					    KeyChain: string;
 | 
				
			||||||
    ChainStage: number;
 | 
					    ChainStage: number;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
export interface IVoidTearParticipantInfo {
 | 
					 | 
				
			||||||
    AccountId: string;
 | 
					 | 
				
			||||||
    Name: string;
 | 
					 | 
				
			||||||
    ChosenRewardOwner: string;
 | 
					 | 
				
			||||||
    MissionHash: string;
 | 
					 | 
				
			||||||
    VoidProjection: string;
 | 
					 | 
				
			||||||
    Reward: string;
 | 
					 | 
				
			||||||
    QualifiesForReward: boolean;
 | 
					 | 
				
			||||||
    HaveRewardResponse: boolean;
 | 
					 | 
				
			||||||
    RewardsMultiplier: number;
 | 
					 | 
				
			||||||
    RewardProjection: string;
 | 
					 | 
				
			||||||
    HardModeReward: ITypeCount;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -33,9 +33,9 @@ const consolelogFormat = format.printf(info => {
 | 
				
			|||||||
            colors: true
 | 
					            colors: true
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return `${info.timestamp as string} [${info.version as string}] ${info.level}: ${info.message as string} ${metadataString}`;
 | 
					        return `${info.timestamp} [${info.version}] ${info.level}: ${info.message} ${metadataString}`;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return `${info.timestamp as string} [${info.version as string}] ${info.level}: ${info.message as string}`;
 | 
					    return `${info.timestamp} [${info.version}] ${info.level}: ${info.message}`;
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const fileFormat = format.combine(
 | 
					const fileFormat = format.combine(
 | 
				
			||||||
 | 
				
			|||||||
@ -1,12 +0,0 @@
 | 
				
			|||||||
{
 | 
					 | 
				
			||||||
  "Messages": [
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      "sub": "Welcome to Space Ninja Server",
 | 
					 | 
				
			||||||
      "sndr": "/Lotus/Language/Bosses/Ordis",
 | 
					 | 
				
			||||||
      "msg": "Enjoy your Space Ninja Experience",
 | 
					 | 
				
			||||||
      "icon": "/Lotus/Interface/Icons/Npcs/Darvo.png",
 | 
					 | 
				
			||||||
      "eventMessageDate": "2025-01-30T13:00:00.000Z",
 | 
					 | 
				
			||||||
      "r": false
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  ]
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,120 +0,0 @@
 | 
				
			|||||||
{
 | 
					 | 
				
			||||||
  "VenusToMercuryJunction": {
 | 
					 | 
				
			||||||
    "items": [
 | 
					 | 
				
			||||||
      { "ItemType": "/Lotus/StoreItems/Types/Keys/InfestedIntroQuest/InfestedIntroQuestKeyChain", "ItemCount": 1 },
 | 
					 | 
				
			||||||
      { "ItemType": "/Lotus/StoreItems/Types/Keys/KubrowQuest/KubrowQuestKeyChain", "ItemCount": 1 },
 | 
					 | 
				
			||||||
      { "ItemType": "/Lotus/StoreItems/Weapons/Tenno/Rifle/BoltoRifle", "ItemCount": 1 },
 | 
					 | 
				
			||||||
      { "ItemType": "/Lotus/StoreItems/Upgrades/Mods/Warframe/AvatarShieldRechargeRateMod", "ItemCount": 1 },
 | 
					 | 
				
			||||||
      { "ItemType": "/Lotus/StoreItems/Upgrades/Mods/Warframe/AvatarAbilityEfficiencyMod", "ItemCount": 1 },
 | 
					 | 
				
			||||||
      { "ItemType": "/Lotus/StoreItems/Types/Game/KubrowPet/EggHatcher", "ItemCount": 1 }
 | 
					 | 
				
			||||||
    ],
 | 
					 | 
				
			||||||
    "credits": 10000
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  "EarthToVenusJunction": {
 | 
					 | 
				
			||||||
    "items": [
 | 
					 | 
				
			||||||
      { "ItemType": "/Lotus/StoreItems/Types/Recipes/Weapons/FurisBlueprint", "ItemCount": 1 },
 | 
					 | 
				
			||||||
      { "ItemType": "/Lotus/StoreItems/Upgrades/Mods/Melee/WeaponFreezeDamageMod", "ItemCount": 1 },
 | 
					 | 
				
			||||||
      { "ItemType": "/Lotus/StoreItems/Upgrades/Mods/Rifle/WeaponElectricityDamageMod", "ItemCount": 1 },
 | 
					 | 
				
			||||||
      { "ItemType": "/Lotus/StoreItems/Types/Recipes/SentinelRecipes/TnSentinelCrossBlueprint", "ItemCount": 1 },
 | 
					 | 
				
			||||||
      { "ItemType": "/Lotus/StoreItems/Weapons/Tenno/Melee/MeleeTrees/StaffCmbOneMeleeTree", "ItemCount": 1 },
 | 
					 | 
				
			||||||
      { "ItemType": "/Lotus/StoreItems/Types/Items/MiscItems/OrokinReactor", "ItemCount": 1 },
 | 
					 | 
				
			||||||
      { "ItemType": "/Lotus/StoreItems/Upgrades/Mods/Aura/PlayerEnergyHealthRegenAuraMod", "ItemCount": 1 }
 | 
					 | 
				
			||||||
    ],
 | 
					 | 
				
			||||||
    "credits": 5000
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  "EarthToMarsJunction": {
 | 
					 | 
				
			||||||
    "items": [
 | 
					 | 
				
			||||||
      { "ItemType": "/Lotus/StoreItems/Types/Keys/ArchwingQuest/ArchwingQuestKeyChain", "ItemCount": 1 },
 | 
					 | 
				
			||||||
      { "ItemType": "/Lotus/StoreItems/Types/Game/KubrowPet/EggHatcher", "ItemCount": 1 },
 | 
					 | 
				
			||||||
      { "ItemType": "/Lotus/StoreItems/Types/Items/ShipFeatureItems/VoidProjectionFeatureItem", "ItemCount": 1 },
 | 
					 | 
				
			||||||
      { "ItemType": "/Lotus/StoreItems/Types/Game/Projections/T1VoidProjectionRevenantPrimeABronze", "ItemCount": 1 },
 | 
					 | 
				
			||||||
      { "ItemType": "/Lotus/StoreItems/Weapons/Tenno/Melee/Hammer/HammerWeapon", "ItemCount": 1 },
 | 
					 | 
				
			||||||
      { "ItemType": "/Lotus/StoreItems/Weapons/Tenno/Melee/MeleeTrees/IronPhoenixMeleeTree", "ItemCount": 1 },
 | 
					 | 
				
			||||||
      { "ItemType": "/Lotus/StoreItems/Types/Keys/InfestedMicroplanetQuest/InfestedMicroplanetQuestKeyChain", "ItemCount": 1 }
 | 
					 | 
				
			||||||
    ],
 | 
					 | 
				
			||||||
    "credits": 15000
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  "MarsToCeresJunction": {
 | 
					 | 
				
			||||||
    "items": [
 | 
					 | 
				
			||||||
      { "ItemType": "/Lotus/StoreItems/Types/Recipes/Weapons/GrnSniperRifleBlueprint", "ItemCount": 1 },
 | 
					 | 
				
			||||||
      { "ItemType": "/Lotus/StoreItems/Upgrades/Mods/Melee/WeaponToxinDamageMod", "ItemCount": 1 },
 | 
					 | 
				
			||||||
      { "ItemType": "/Lotus/StoreItems/Weapons/Tenno/Melee/MeleeTrees/DualSwordCmbOneMeleeTree", "ItemCount": 1 }
 | 
					 | 
				
			||||||
    ],
 | 
					 | 
				
			||||||
    "credits": 20000
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  "MarsToPhobosJunction": {
 | 
					 | 
				
			||||||
    "items": [
 | 
					 | 
				
			||||||
      { "ItemType": "/Lotus/StoreItems/Types/Keys/SpyQuestKeyChain/SpyQuestKeyChain", "ItemCount": 1 },
 | 
					 | 
				
			||||||
      { "ItemType": "/Lotus/StoreItems/Types/Recipes/Weapons/GrnHeavyPistolBlueprint", "ItemCount": 1 },
 | 
					 | 
				
			||||||
      { "ItemType": "/Lotus/StoreItems/Types/StoreItems/Consumables/CipherBlueprint", "ItemCount": 1 },
 | 
					 | 
				
			||||||
      { "ItemType": "/Lotus/StoreItems/Upgrades/Mods/Rifle/WeaponReloadSpeedMod", "ItemCount": 1 },
 | 
					 | 
				
			||||||
      { "ItemType": "/Lotus/StoreItems/Upgrades/Mods/Warframe/AvatarLootRadarMod", "ItemCount": 1 },
 | 
					 | 
				
			||||||
      { "ItemType": "/Lotus/StoreItems/Types/Items/MiscItems/OrokinCatalyst", "ItemCount": 1 }
 | 
					 | 
				
			||||||
    ],
 | 
					 | 
				
			||||||
    "credits": 20000
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  "JupiterToEuropaJunction": {
 | 
					 | 
				
			||||||
    "items": [
 | 
					 | 
				
			||||||
      { "ItemType": "/Lotus/StoreItems/Types/Keys/LimboQuest/LimboQuestKeyChain", "ItemCount": 1 },
 | 
					 | 
				
			||||||
      { "ItemType": "/Lotus/StoreItems/Types/Keys/DragonQuest/DragonQuestKeyChain", "ItemCount": 1 },
 | 
					 | 
				
			||||||
      { "ItemType": "/Lotus/StoreItems/Types/Recipes/Weapons/CorpusMinigunBlueprint", "ItemCount": 1 },
 | 
					 | 
				
			||||||
      { "ItemType": "/Lotus/StoreItems/Upgrades/Mods/Aura/PlayerHealthAuraMod", "ItemCount": 1 }
 | 
					 | 
				
			||||||
    ],
 | 
					 | 
				
			||||||
    "credits": 40000
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  "JupiterToSaturnJunction": {
 | 
					 | 
				
			||||||
    "items": [
 | 
					 | 
				
			||||||
      { "ItemType": "/Lotus/StoreItems/Types/Recipes/Weapons/GrenadeLauncherBlueprint", "ItemCount": 1 },
 | 
					 | 
				
			||||||
      { "ItemType": "/Lotus/StoreItems/Types/Keys/ProteaQuest/ProteaQuestKeyChain", "ItemCount": 1 }
 | 
					 | 
				
			||||||
    ],
 | 
					 | 
				
			||||||
    "credits": 40000
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  "SaturnToUranusJunction": {
 | 
					 | 
				
			||||||
    "items": [
 | 
					 | 
				
			||||||
      { "ItemType": "/Lotus/StoreItems/Types/Recipes/Weapons/CorpusWhipBlueprint", "ItemCount": 1 },
 | 
					 | 
				
			||||||
      { "ItemType": "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/ChromaHelmetBlueprint", "ItemCount": 1 },
 | 
					 | 
				
			||||||
      { "ItemType": "/Lotus/StoreItems/Types/Keys/DuviriQuest/DuviriQuestKeyChain", "ItemCount": 1 },
 | 
					 | 
				
			||||||
      { "ItemType": "/Lotus/StoreItems/Types/NeutralCreatures/ErsatzHorse/ErsatzHorsePowerSuit", "ItemCount": 1 }
 | 
					 | 
				
			||||||
    ],
 | 
					 | 
				
			||||||
    "credits": 60000
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  "UranusToNeptuneJunction": {
 | 
					 | 
				
			||||||
    "items": [
 | 
					 | 
				
			||||||
      { "ItemType": "/Lotus/StoreItems/Types/Keys/OrokinMoonQuest/OrokinMoonQuestKeyChain", "ItemCount": 1 },
 | 
					 | 
				
			||||||
      { "ItemType": "/Lotus/StoreItems/Types/Recipes/Weapons/ReconnasorBlueprint", "ItemCount": 1 },
 | 
					 | 
				
			||||||
      { "ItemType": "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/ChromaChassisBlueprint", "ItemCount": 1 }
 | 
					 | 
				
			||||||
    ],
 | 
					 | 
				
			||||||
    "credits": 80000
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  "NeptuneToPlutoJunction": {
 | 
					 | 
				
			||||||
    "items": [
 | 
					 | 
				
			||||||
      { "ItemType": "/Lotus/StoreItems/Types/Recipes/Weapons/GrineerFlakCannonBlueprint", "ItemCount": 1 },
 | 
					 | 
				
			||||||
      { "ItemType": "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/ChromaSystemsBlueprint", "ItemCount": 1 }
 | 
					 | 
				
			||||||
    ],
 | 
					 | 
				
			||||||
    "credits": 80000
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  "PlutoToSednaJunction": {
 | 
					 | 
				
			||||||
    "items": [
 | 
					 | 
				
			||||||
      { "ItemType": "/Lotus/StoreItems/Types/Keys/WarWithinQuest/WarWithinQuestKeyChain", "ItemCount": 1 },
 | 
					 | 
				
			||||||
      { "ItemType": "/Lotus/StoreItems/Types/Keys/MirageQuest/MirageQuestKeyChain", "ItemCount": 1 },
 | 
					 | 
				
			||||||
      { "ItemType": "/Lotus/StoreItems/Types/Recipes/Weapons/DualDaggerBlueprint", "ItemCount": 1 }
 | 
					 | 
				
			||||||
    ],
 | 
					 | 
				
			||||||
    "credits": 100000
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  "PlutoToErisJunction": {
 | 
					 | 
				
			||||||
    "items": [
 | 
					 | 
				
			||||||
      { "ItemType": "/Lotus/StoreItems/Types/Keys/InfestedAladVQuest/InfestedAladVQuestKeyChain", "ItemCount": 1 },
 | 
					 | 
				
			||||||
      { "ItemType": "/Lotus/StoreItems/Types/Recipes/Weapons/MireSwordBlueprint", "ItemCount": 1 }
 | 
					 | 
				
			||||||
    ],
 | 
					 | 
				
			||||||
    "credits": 100000
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  "CeresToJupiterJunction": {
 | 
					 | 
				
			||||||
    "items": [
 | 
					 | 
				
			||||||
      { "ItemType": "/Lotus/StoreItems/Types/Recipes/Weapons/GrnStaffBlueprint", "ItemCount": 1 },
 | 
					 | 
				
			||||||
      { "ItemType": "/Lotus/StoreItems/Upgrades/Mods/Archwing/Suit/ArchwingSuitHealthMaxMod", "ItemCount": 1 },
 | 
					 | 
				
			||||||
      { "ItemType": "/Lotus/StoreItems/Upgrades/Mods/Archwing/Rifle/ArchwingRifleDamageAmountMod", "ItemCount": 1 },
 | 
					 | 
				
			||||||
      { "ItemType": "/Lotus/StoreItems/Upgrades/Mods/Archwing/Melee/ArchwingMeleeDamageMod", "ItemCount": 1 }
 | 
					 | 
				
			||||||
    ],
 | 
					 | 
				
			||||||
    "credits": 30000
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										27
									
								
								static/fixed_responses/login_static.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								static/fixed_responses/login_static.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,27 @@
 | 
				
			|||||||
 | 
					import { IGroup } from "@/src/types/loginTypes";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const groups: IGroup[] = [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        experiment: "InitiatePage",
 | 
				
			||||||
 | 
					        experimentGroup: "initiate_page_no_video"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    { experiment: "ChatQAChannel", experimentGroup: "control" },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        experiment: "MarketSearchRecommendations",
 | 
				
			||||||
 | 
					        experimentGroup: "premium_credit_purchases_14_days"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    { experiment: "SurveyLocation", experimentGroup: "EXIT" },
 | 
				
			||||||
 | 
					    { experiment: "GamesightAB", experimentGroup: "a" }
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const platformCDNs = [
 | 
				
			||||||
 | 
					    "https://content.warframe.com/",
 | 
				
			||||||
 | 
					    "https://content-xb1.warframe.com/",
 | 
				
			||||||
 | 
					    "https://content-ps4.warframe.com/",
 | 
				
			||||||
 | 
					    "https://content-swi.warframe.com/",
 | 
				
			||||||
 | 
					    "https://content-mob.warframe.com/"
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const DTLS = 99;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const HUB = "https://arbiter.warframe.com/api/";
 | 
				
			||||||
							
								
								
									
										49
									
								
								static/fixed_responses/messages.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								static/fixed_responses/messages.json
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,49 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "Messages": [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      "sub": "Welcome to Space Ninja Server",
 | 
				
			||||||
 | 
					      "sndr": "/Lotus/Language/Bosses/Ordis",
 | 
				
			||||||
 | 
					      "msg": "Enjoy your Space Ninja Experience",
 | 
				
			||||||
 | 
					      "icon": "/Lotus/Interface/Icons/Npcs/Darvo.png",
 | 
				
			||||||
 | 
					      "eventMessageDate": "2025-01-30T13:00:00.000Z",
 | 
				
			||||||
 | 
					      "r": false
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      "sub": "/Lotus/Language/Inbox/DarvoWeaponCraftingMessageBTitle",
 | 
				
			||||||
 | 
					      "sndr": "/Lotus/Language/Bosses/Darvo",
 | 
				
			||||||
 | 
					      "msg": "/Lotus/Language/Inbox/DarvoWeaponCraftingMessageBDesc",
 | 
				
			||||||
 | 
					      "icon": "/Lotus/Interface/Icons/Npcs/Darvo.png",
 | 
				
			||||||
 | 
					      "countedAtt": [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "ItemCount": 1,
 | 
				
			||||||
 | 
					          "ItemType": "/Lotus/Types/Recipes/Weapons/BurstonRifleBlueprint"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "ItemCount": 1,
 | 
				
			||||||
 | 
					          "ItemType": "/Lotus/Types/Items/MiscItems/Morphic"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "ItemCount": 400,
 | 
				
			||||||
 | 
					          "ItemType": "/Lotus/Types/Items/MiscItems/PolymerBundle"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "ItemCount": 150,
 | 
				
			||||||
 | 
					          "ItemType": "/Lotus/Types/Items/MiscItems/AlloyPlate"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      ],
 | 
				
			||||||
 | 
					      "highPriority": true,
 | 
				
			||||||
 | 
					      "eventMessageDate": "2023-10-01T17:00:00.000Z",
 | 
				
			||||||
 | 
					      "r": false
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      "sub": "/Lotus/Language/G1Quests/Beginner_Growth_Inbox_Title",
 | 
				
			||||||
 | 
					      "sndr": "/Lotus/Language/Menu/Mailbox_WarframeSender",
 | 
				
			||||||
 | 
					      "msg": "/Lotus/Language/G1Quests/Beginner_Growth_Inbox_Desc",
 | 
				
			||||||
 | 
					      "icon": "/Lotus/Interface/Icons/Npcs/Lotus_d.png",
 | 
				
			||||||
 | 
					      "transmission": "/Lotus/Sounds/Dialog/VorsPrize/DLisetPostAssassinate110Lotus",
 | 
				
			||||||
 | 
					      "highPriority": true,
 | 
				
			||||||
 | 
					      "eventMessageDate": "2023-09-01T17:00:00.000Z",
 | 
				
			||||||
 | 
					      "r": false
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  ]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -473,10 +473,6 @@
 | 
				
			|||||||
                                        <input class="form-check-input" type="checkbox" id="infiniteRegalAya" />
 | 
					                                        <input class="form-check-input" type="checkbox" id="infiniteRegalAya" />
 | 
				
			||||||
                                        <label class="form-check-label" for="infiniteRegalAya" data-loc="cheats_infiniteRegalAya"></label>
 | 
					                                        <label class="form-check-label" for="infiniteRegalAya" data-loc="cheats_infiniteRegalAya"></label>
 | 
				
			||||||
                                    </div>
 | 
					                                    </div>
 | 
				
			||||||
                                    <div class="form-check">
 | 
					 | 
				
			||||||
                                        <input class="form-check-input" type="checkbox" id="infiniteHelminthMaterials" />
 | 
					 | 
				
			||||||
                                        <label class="form-check-label" for="infiniteHelminthMaterials" data-loc="cheats_infiniteHelminthMaterials"></label>
 | 
					 | 
				
			||||||
                                    </div>
 | 
					 | 
				
			||||||
                                    <div class="form-check">
 | 
					                                    <div class="form-check">
 | 
				
			||||||
                                        <input class="form-check-input" type="checkbox" id="unlockAllShipFeatures" />
 | 
					                                        <input class="form-check-input" type="checkbox" id="unlockAllShipFeatures" />
 | 
				
			||||||
                                        <label class="form-check-label" for="unlockAllShipFeatures" data-loc="cheats_unlockAllShipFeatures"></label>
 | 
					                                        <label class="form-check-label" for="unlockAllShipFeatures" data-loc="cheats_unlockAllShipFeatures"></label>
 | 
				
			||||||
@ -543,12 +539,10 @@
 | 
				
			|||||||
                                </form>
 | 
					                                </form>
 | 
				
			||||||
                            <h5 class="mt-3" data-loc="cheats_quests"></h6>
 | 
					                            <h5 class="mt-3" data-loc="cheats_quests"></h6>
 | 
				
			||||||
                                <div class="mb-2 d-flex flex-wrap gap-2">
 | 
					                                <div class="mb-2 d-flex flex-wrap gap-2">
 | 
				
			||||||
                                    <button class="btn btn-primary" onclick="doQuestUpdate('unlockAll');" data-loc="cheats_quests_unlockAll"></button>
 | 
					                                    <button class="btn btn-primary" onclick="doQuestUpdate('unlockAll');" data-loc="cheats_quests_UnlockAll"></button>
 | 
				
			||||||
                                    <button class="btn btn-primary" onclick="doQuestUpdate('completeAll');" data-loc="cheats_quests_completeAll"></button>
 | 
					                                    <button class="btn btn-primary" onclick="doQuestUpdate('completeAll');" data-loc="cheats_quests_CompleteAll"></button>
 | 
				
			||||||
                                    <button class="btn btn-primary" onclick="doQuestUpdate('completeAllUnlocked');" data-loc="cheats_quests_completeAllUnlocked"></button>
 | 
					                                    <button class="btn btn-primary" onclick="doQuestUpdate('completeAllUnlocked');" data-loc="cheats_quests_CompleteAllUnlocked"></button>
 | 
				
			||||||
                                    <button class="btn btn-primary" onclick="doQuestUpdate('ResetAll');" data-loc="cheats_quests_resetAll"></button>
 | 
					                                    <button class="btn btn-primary" onclick="doQuestUpdate('ResetAll');" data-loc="cheats_quests_ResetAll"></button>
 | 
				
			||||||
                                    <button class="btn btn-primary" onclick="doQuestUpdate('giveAll');" data-loc="cheats_quests_giveAll"></button>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                                </div>
 | 
					                                </div>
 | 
				
			||||||
                            </div>
 | 
					                            </div>
 | 
				
			||||||
                        </div>
 | 
					                        </div>
 | 
				
			||||||
 | 
				
			|||||||
@ -99,7 +99,6 @@ dict = {
 | 
				
			|||||||
    cheats_infinitePlatinum: `Infinite Platinum`,
 | 
					    cheats_infinitePlatinum: `Infinite Platinum`,
 | 
				
			||||||
    cheats_infiniteEndo: `Infinite Endo`,
 | 
					    cheats_infiniteEndo: `Infinite Endo`,
 | 
				
			||||||
    cheats_infiniteRegalAya: `Infinite Regal Aya`,
 | 
					    cheats_infiniteRegalAya: `Infinite Regal Aya`,
 | 
				
			||||||
    cheats_infiniteHelminthMaterials: `Infinite Helminth Materials`,
 | 
					 | 
				
			||||||
    cheats_unlockAllShipFeatures: `Unlock All Ship Features`,
 | 
					    cheats_unlockAllShipFeatures: `Unlock All Ship Features`,
 | 
				
			||||||
    cheats_unlockAllShipDecorations: `Unlock All Ship Decorations`,
 | 
					    cheats_unlockAllShipDecorations: `Unlock All Ship Decorations`,
 | 
				
			||||||
    cheats_unlockAllFlavourItems: `Unlock All <abbr title=\"Animation Sets, Glyphs, Plattes, etc.\">Flavor Items</abbr>`,
 | 
					    cheats_unlockAllFlavourItems: `Unlock All <abbr title=\"Animation Sets, Glyphs, Plattes, etc.\">Flavor Items</abbr>`,
 | 
				
			||||||
@ -119,11 +118,10 @@ dict = {
 | 
				
			|||||||
    cheats_changeButton: `Change`,
 | 
					    cheats_changeButton: `Change`,
 | 
				
			||||||
    cheats_none: `None`,
 | 
					    cheats_none: `None`,
 | 
				
			||||||
    cheats_quests: `Quests`,
 | 
					    cheats_quests: `Quests`,
 | 
				
			||||||
    cheats_quests_unlockAll: `Unlock All Quests`,
 | 
					    cheats_quests_UnlockAll: `Unlock All Quests`,
 | 
				
			||||||
    cheats_quests_completeAll: `Complete All Quests`,
 | 
					    cheats_quests_CompleteAll: `Complete All Quests`,
 | 
				
			||||||
    cheats_quests_completeAllUnlocked: `Complete All Unlocked Quests`,
 | 
					    cheats_quests_CompleteAllUnlocked: `Complete All Unlocked Quests`,
 | 
				
			||||||
    cheats_quests_resetAll: `Reset All Quests`,
 | 
					    cheats_quests_ResetAll: `Reset All Quests`,
 | 
				
			||||||
    cheats_quests_giveAll: `Give All Quests`,
 | 
					 | 
				
			||||||
    import_importNote: `You can provide a full or partial inventory response (client respresentation) here. All fields that are supported by the importer <b>will be overwritten</b> in your account.`,
 | 
					    import_importNote: `You can provide a full or partial inventory response (client respresentation) here. All fields that are supported by the importer <b>will be overwritten</b> in your account.`,
 | 
				
			||||||
    import_submit: `Submit`
 | 
					    import_submit: `Submit`
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -46,7 +46,7 @@ dict = {
 | 
				
			|||||||
    navbar_deleteAccount: `Удалить аккаунт`,
 | 
					    navbar_deleteAccount: `Удалить аккаунт`,
 | 
				
			||||||
    navbar_inventory: `Инвентарь`,
 | 
					    navbar_inventory: `Инвентарь`,
 | 
				
			||||||
    navbar_mods: `Моды`,
 | 
					    navbar_mods: `Моды`,
 | 
				
			||||||
    navbar_quests: `Квесты`,
 | 
					    navbar_quests: `[UNTRANSLATED] Quests`,
 | 
				
			||||||
    navbar_cheats: `Читы`,
 | 
					    navbar_cheats: `Читы`,
 | 
				
			||||||
    navbar_import: `Импорт`,
 | 
					    navbar_import: `Импорт`,
 | 
				
			||||||
    inventory_addItems: `Добавить предметы`,
 | 
					    inventory_addItems: `Добавить предметы`,
 | 
				
			||||||
@ -79,7 +79,7 @@ dict = {
 | 
				
			|||||||
    currency_PremiumCredits: `Платина`,
 | 
					    currency_PremiumCredits: `Платина`,
 | 
				
			||||||
    currency_FusionPoints: `Эндо`,
 | 
					    currency_FusionPoints: `Эндо`,
 | 
				
			||||||
    currency_PrimeTokens: `Королевские Айя`,
 | 
					    currency_PrimeTokens: `Королевские Айя`,
 | 
				
			||||||
    currency_owned: `У тебя |COUNT|.`,
 | 
					    currency_owned: `У тебя есть |COUNT|.`,
 | 
				
			||||||
    powersuit_archonShardsLabel: `Ячейки осколков архонта`,
 | 
					    powersuit_archonShardsLabel: `Ячейки осколков архонта`,
 | 
				
			||||||
    powersuit_archonShardsDescription: `Вы можете использовать эти неограниченные ячейки для установки множества улучшений.`,
 | 
					    powersuit_archonShardsDescription: `Вы можете использовать эти неограниченные ячейки для установки множества улучшений.`,
 | 
				
			||||||
    mods_addRiven: `Добавить Мод Разлома`,
 | 
					    mods_addRiven: `Добавить Мод Разлома`,
 | 
				
			||||||
@ -100,7 +100,6 @@ dict = {
 | 
				
			|||||||
    cheats_infinitePlatinum: `Бесконечная платина`,
 | 
					    cheats_infinitePlatinum: `Бесконечная платина`,
 | 
				
			||||||
    cheats_infiniteEndo: `Бесконечное эндо`,
 | 
					    cheats_infiniteEndo: `Бесконечное эндо`,
 | 
				
			||||||
    cheats_infiniteRegalAya: `Бесконечная Королевская Айя`,
 | 
					    cheats_infiniteRegalAya: `Бесконечная Королевская Айя`,
 | 
				
			||||||
    cheats_infiniteHelminthMaterials: `[UNTRANSLATED] Infinite Helminth Materials`,
 | 
					 | 
				
			||||||
    cheats_unlockAllShipFeatures: `Разблокировать все функции корабля`,
 | 
					    cheats_unlockAllShipFeatures: `Разблокировать все функции корабля`,
 | 
				
			||||||
    cheats_unlockAllShipDecorations: `Разблокировать все украшения корабля`,
 | 
					    cheats_unlockAllShipDecorations: `Разблокировать все украшения корабля`,
 | 
				
			||||||
    cheats_unlockAllFlavourItems: `Разблокировать все <abbr title=\"Наборы анимаций, глифы, палитры и т. д.\">уникальные предметы</abbr>`,
 | 
					    cheats_unlockAllFlavourItems: `Разблокировать все <abbr title=\"Наборы анимаций, глифы, палитры и т. д.\">уникальные предметы</abbr>`,
 | 
				
			||||||
@ -119,12 +118,11 @@ dict = {
 | 
				
			|||||||
    cheats_changeSupportedSyndicate: `Поддерживаемый синдикат`,
 | 
					    cheats_changeSupportedSyndicate: `Поддерживаемый синдикат`,
 | 
				
			||||||
    cheats_changeButton: `Изменить`,
 | 
					    cheats_changeButton: `Изменить`,
 | 
				
			||||||
    cheats_none: `Отсутствует`,
 | 
					    cheats_none: `Отсутствует`,
 | 
				
			||||||
    cheats_quests: `Квесты`,
 | 
					    cheats_quests: `[UNTRANSLATED] Quests`,
 | 
				
			||||||
    cheats_quests_unlockAll: `Разблокировать все квесты`,
 | 
					    cheats_quests_UnlockAll: `[UNTRANSLATED] Unlock All Quests`,
 | 
				
			||||||
    cheats_quests_completeAll: `Завершить все квесты`,
 | 
					    cheats_quests_CompleteAll: `[UNTRANSLATED] Complete All Quests`,
 | 
				
			||||||
    cheats_quests_completeAllUnlocked: `Завершить все разблокированые квесты`,
 | 
					    cheats_quests_CompleteAllUnlocked: `[UNTRANSLATED] Complete All Unlocked Quests`,
 | 
				
			||||||
    cheats_quests_resetAll: `Сбросить прогресс всех квестов`,
 | 
					    cheats_quests_ResetAll: `[UNTRANSLATED] Reset All Quests`,
 | 
				
			||||||
    cheats_quests_giveAll: `Выдать все квесты`,
 | 
					 | 
				
			||||||
    import_importNote: `Вы можете загрузить полный или частичный ответ инвентаря (клиентское представление) здесь. Все поддерживаемые поля <b>будут перезаписаны</b> в вашем аккаунте.`,
 | 
					    import_importNote: `Вы можете загрузить полный или частичный ответ инвентаря (клиентское представление) здесь. Все поддерживаемые поля <b>будут перезаписаны</b> в вашем аккаунте.`,
 | 
				
			||||||
    import_submit: `Отправить`
 | 
					    import_submit: `Submit`
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user