forked from OpenWF/SpaceNinjaServer
		
	feat: the circuit (#2039)
Closes #1965 Closes #2041 Reviewed-on: OpenWF/SpaceNinjaServer#2039 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
This commit is contained in:
		
							parent
							
								
									c83e732b88
								
							
						
					
					
						commit
						9d4bce852e
					
				@ -1,60 +1,529 @@
 | 
				
			|||||||
import { RequestHandler } from "express";
 | 
					import { RequestHandler } from "express";
 | 
				
			||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
					import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
				
			||||||
import { getInventory } from "@/src/services/inventoryService";
 | 
					import { combineInventoryChanges, getInventory } from "@/src/services/inventoryService";
 | 
				
			||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
 | 
					import { getJSONfromString } from "@/src/helpers/stringHelpers";
 | 
				
			||||||
import { TEndlessXpCategory } from "@/src/types/inventoryTypes/inventoryTypes";
 | 
					import { IEndlessXpReward, IInventoryClient, TEndlessXpCategory } from "@/src/types/inventoryTypes/inventoryTypes";
 | 
				
			||||||
 | 
					import { logger } from "@/src/utils/logger";
 | 
				
			||||||
 | 
					import { ExportRewards, ICountedStoreItem } from "warframe-public-export-plus";
 | 
				
			||||||
 | 
					import { getRandomElement } from "@/src/services/rngService";
 | 
				
			||||||
 | 
					import { handleStoreItemAcquisition } from "@/src/services/purchaseService";
 | 
				
			||||||
 | 
					import { IInventoryChanges } from "@/src/types/purchaseTypes";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const endlessXpController: RequestHandler = async (req, res) => {
 | 
					export const endlessXpController: RequestHandler = async (req, res) => {
 | 
				
			||||||
    const accountId = await getAccountIdForRequest(req);
 | 
					    const accountId = await getAccountIdForRequest(req);
 | 
				
			||||||
    const inventory = await getInventory(accountId);
 | 
					 | 
				
			||||||
    const payload = getJSONfromString<IEndlessXpRequest>(String(req.body));
 | 
					    const payload = getJSONfromString<IEndlessXpRequest>(String(req.body));
 | 
				
			||||||
 | 
					    if (payload.Mode == "r") {
 | 
				
			||||||
 | 
					        const inventory = await getInventory(accountId, "EndlessXP");
 | 
				
			||||||
        inventory.EndlessXP ??= [];
 | 
					        inventory.EndlessXP ??= [];
 | 
				
			||||||
    const entry = inventory.EndlessXP.find(x => x.Category == payload.Category);
 | 
					        let entry = inventory.EndlessXP.find(x => x.Category == payload.Category);
 | 
				
			||||||
    if (entry) {
 | 
					        if (!entry) {
 | 
				
			||||||
        entry.Choices = payload.Choices;
 | 
					            entry = {
 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
        inventory.EndlessXP.push({
 | 
					 | 
				
			||||||
            Category: payload.Category,
 | 
					 | 
				
			||||||
            Choices: payload.Choices
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    await inventory.save();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    res.json({
 | 
					 | 
				
			||||||
        NewProgress: {
 | 
					 | 
				
			||||||
                Category: payload.Category,
 | 
					                Category: payload.Category,
 | 
				
			||||||
                Earn: 0,
 | 
					                Earn: 0,
 | 
				
			||||||
                Claim: 0,
 | 
					                Claim: 0,
 | 
				
			||||||
            BonusAvailable: {
 | 
					 | 
				
			||||||
                $date: {
 | 
					 | 
				
			||||||
                    $numberLong: "9999999999999"
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            Expiry: {
 | 
					 | 
				
			||||||
                $date: {
 | 
					 | 
				
			||||||
                    $numberLong: "9999999999999"
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
                Choices: payload.Choices,
 | 
					                Choices: payload.Choices,
 | 
				
			||||||
            PendingRewards: [
 | 
					                PendingRewards: []
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					            inventory.EndlessXP.push(entry);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const weekStart = 1734307200_000 + Math.trunc((Date.now() - 1734307200_000) / 604800000) * 604800000;
 | 
				
			||||||
 | 
					        const weekEnd = weekStart + 604800000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        entry.Earn = 0;
 | 
				
			||||||
 | 
					        entry.Claim = 0;
 | 
				
			||||||
 | 
					        entry.BonusAvailable = new Date(weekStart);
 | 
				
			||||||
 | 
					        entry.Expiry = new Date(weekEnd);
 | 
				
			||||||
 | 
					        entry.Choices = payload.Choices;
 | 
				
			||||||
 | 
					        entry.PendingRewards =
 | 
				
			||||||
 | 
					            payload.Category == "EXC_HARD"
 | 
				
			||||||
 | 
					                ? generateHardModeRewards(payload.Choices)
 | 
				
			||||||
 | 
					                : generateNormalModeRewards(payload.Choices);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        await inventory.save();
 | 
				
			||||||
 | 
					        res.json({
 | 
				
			||||||
 | 
					            NewProgress: inventory.toJSON<IInventoryClient>().EndlessXP!.find(x => x.Category == payload.Category)!
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    } else if (payload.Mode == "c") {
 | 
				
			||||||
 | 
					        const inventory = await getInventory(accountId);
 | 
				
			||||||
 | 
					        const entry = inventory.EndlessXP!.find(x => x.Category == payload.Category)!;
 | 
				
			||||||
 | 
					        const inventoryChanges: IInventoryChanges = {};
 | 
				
			||||||
 | 
					        for (const reward of entry.PendingRewards) {
 | 
				
			||||||
 | 
					            if (entry.Claim < reward.RequiredTotalXp && reward.RequiredTotalXp <= entry.Earn) {
 | 
				
			||||||
 | 
					                combineInventoryChanges(
 | 
				
			||||||
 | 
					                    inventoryChanges,
 | 
				
			||||||
 | 
					                    (
 | 
				
			||||||
 | 
					                        await handleStoreItemAcquisition(
 | 
				
			||||||
 | 
					                            reward.Rewards[0].StoreItem,
 | 
				
			||||||
 | 
					                            inventory,
 | 
				
			||||||
 | 
					                            reward.Rewards[0].ItemCount
 | 
				
			||||||
 | 
					                        )
 | 
				
			||||||
 | 
					                    ).InventoryChanges
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        entry.Claim = entry.Earn;
 | 
				
			||||||
 | 
					        await inventory.save();
 | 
				
			||||||
 | 
					        res.json({
 | 
				
			||||||
 | 
					            InventoryChanges: inventoryChanges,
 | 
				
			||||||
 | 
					            ClaimedXp: entry.Claim
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        logger.debug(`data provided to ${req.path}: ${String(req.body)}`);
 | 
				
			||||||
 | 
					        throw new Error(`unexpected endlessXp mode: ${payload.Mode}`);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type IEndlessXpRequest =
 | 
				
			||||||
 | 
					    | {
 | 
				
			||||||
 | 
					          Mode: "r";
 | 
				
			||||||
 | 
					          Category: TEndlessXpCategory;
 | 
				
			||||||
 | 
					          Choices: string[];
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    | {
 | 
				
			||||||
 | 
					          Mode: "c" | "something else";
 | 
				
			||||||
 | 
					          Category: TEndlessXpCategory;
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const generateRandomRewards = (deckName: string): ICountedStoreItem[] => {
 | 
				
			||||||
 | 
					    const reward = getRandomElement(ExportRewards[deckName][0])!;
 | 
				
			||||||
 | 
					    return [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            StoreItem: reward.type,
 | 
				
			||||||
 | 
					            ItemCount: reward.itemCount
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    ];
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const normalModeChosenRewards: Record<string, string[]> = {
 | 
				
			||||||
 | 
					    Excalibur: [
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/ExcaliburHelmetBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/ExcaliburChassisBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Powersuits/Excalibur/RadialJavelinAugmentCard",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/ExcaliburSystemsBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/ExcaliburBlueprint"
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    Trinity: [
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/TrinityHelmetBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/TrinityChassisBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Powersuits/Trinity/EnergyVampireAugmentCard",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/TrinitySystemsBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/TrinityBlueprint"
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    Ember: [
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/EmberHelmetBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/EmberChassisBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Powersuits/Ember/WorldOnFireAugmentCard",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/EmberSystemsBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/EmberBlueprint"
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    Loki: [
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/LOKIHelmetBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/LOKIChassisBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Powersuits/Loki/InvisibilityAugmentCard",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/LOKISystemsBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/LOKIBlueprint"
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    Mag: [
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/MagHelmetBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/MagChassisBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Powersuits/Mag/CrushAugmentCard",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/MagSystemsBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/MagBlueprint"
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    Rhino: [
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/RhinoHelmetBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/RhinoChassisBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Powersuits/Rhino/RhinoChargeAugmentCard",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/RhinoSystemsBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/RhinoBlueprint"
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    Ash: [
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/AshHelmetBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/AshChassisBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Powersuits/Ninja/GlaiveAugmentCard",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/AshSystemsBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/AshBlueprint"
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    Frost: [
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/FrostHelmetBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/FrostChassisBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Powersuits/Frost/IceShieldAugmentCard",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/FrostSystemsBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/FrostBlueprint"
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    Nyx: [
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/NyxHelmetBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/NyxChassisBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Powersuits/Jade/SelfBulletAttractorAugmentCard",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/NyxSystemsBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/NyxBlueprint"
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    Saryn: [
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/SarynHelmetBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/SarynChassisBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Powersuits/Saryn/PoisonAugmentCard",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/SarynSystemsBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/SarynBlueprint"
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    Vauban: [
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/TrapperHelmetBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/TrapperChassisBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Powersuits/Trapper/LevTrapAugmentCard",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/TrapperSystemsBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/TrapperBlueprint"
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    Nova: [
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/NovaHelmetBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/NovaChassisBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Powersuits/AntiMatter/MolecularPrimeAugmentCard",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/NovaSystemsBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/NovaBlueprint"
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    Nekros: [
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/NecroHelmetBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/NecroChassisBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Powersuits/Necro/CloneTheDeadAugmentCard",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/NecroSystemsBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/NecroBlueprint"
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    Valkyr: [
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/BerserkerHelmetBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/BerserkerChassisBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Powersuits/Berserker/IntimidateAugmentCard",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/BerserkerSystemsBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/BerserkerBlueprint"
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    Oberon: [
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/PaladinHelmetBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/PaladinChassisBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Powersuits/Paladin/RegenerationAugmentCard",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/PaladinSystemsBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/PaladinBlueprint"
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    Hydroid: [
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/HydroidHelmetBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/HydroidChassisBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Powersuits/Pirate/CannonBarrageAugmentCard",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/HydroidSystemsBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/HydroidBlueprint"
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    Mirage: [
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/HarlequinHelmetBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/HarlequinChassisBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Powersuits/Harlequin/LightAugmentCard",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/HarlequinSystemsBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/HarlequinBlueprint"
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    Limbo: [
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/MagicianHelmetBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/MagicianChassisBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Powersuits/Magician/TearInSpaceAugmentCard",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/MagicianSystemsBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/MagicianBlueprint"
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    Mesa: [
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/GunslingerHelmetBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/GunslingerChassisBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Powersuits/Cowgirl/GunFuPvPAugmentCard",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/GunslingerSystemsBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/GunslingerBlueprint"
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    Chroma: [
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/ChromaHelmetBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/ChromaChassisBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Powersuits/Dragon/DragonLuckAugmentCard",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/ChromaSystemsBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/ChromaBlueprint"
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    Atlas: [
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/BrawlerHelmetBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/BrawlerChassisBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Powersuits/Brawler/BrawlerPassiveAugmentCard",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/BrawlerSystemsBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/BrawlerBlueprint"
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    Ivara: [
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/RangerHelmetBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/RangerChassisBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Powersuits/Ranger/RangerStealAugmentCard",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/RangerSystemsBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/RangerBlueprint"
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    Inaros: [
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/MummyHelmetBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/MummyChassisBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Powersuits/Sandman/SandmanSwarmAugmentCard",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/MummySystemsBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/MummyBlueprint"
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    Titania: [
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/FairyHelmetBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/FairyChassisBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Powersuits/Fairy/FairyFlightAugmentCard",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/FairySystemsBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/FairyBlueprint"
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    Nidus: [
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/NidusHelmetBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/NidusChassisBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Powersuits/Infestation/InfestPodsAugmentCard",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/NidusSystemsBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/NidusBlueprint"
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    Octavia: [
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/OctaviaHelmetBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/OctaviaChassisBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Powersuits/Bard/BardCharmAugmentCard",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/OctaviaSystemsBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/OctaviaBlueprint"
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    Harrow: [
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/PriestHelmetBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/PriestChassisBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Powersuits/Priest/PriestPactAugmentCard",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/PriestSystemsBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/PriestBlueprint"
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    Gara: [
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/GlassHelmetBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/GlassChassisBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Powersuits/Glass/GlassFragmentAugmentCard",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/GlassSystemsBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/GlassBlueprint"
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    Khora: [
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/KhoraHelmetBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/KhoraChassisBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Powersuits/Khora/KhoraCrackAugmentCard",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/KhoraSystemsBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/KhoraBlueprint"
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    Revenant: [
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/RevenantHelmetBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/RevenantChassisBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Powersuits/Revenant/RevenantMarkAugmentCard",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/RevenantSystemsBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/RevenantBlueprint"
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    Garuda: [
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/GarudaHelmetBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/GarudaChassisBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Powersuits/Garuda/GarudaUnstoppableAugmentCard",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/GarudaSystemsBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/GarudaBlueprint"
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    Baruuk: [
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/PacifistHelmetBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/PacifistChassisBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Powersuits/Pacifist/PacifistFistAugmentCard",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/PacifistSystemsBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/PacifistBlueprint"
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    Hildryn: [
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/IronframeHelmetBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/IronframeChassisBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Powersuits/IronFrame/IronFrameStripAugmentCard",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/IronframeSystemsBlueprint",
 | 
				
			||||||
 | 
					        "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/IronframeBlueprint"
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const generateNormalModeRewards = (choices: string[]): IEndlessXpReward[] => {
 | 
				
			||||||
 | 
					    const choiceRewards = normalModeChosenRewards[choices[0]];
 | 
				
			||||||
 | 
					    return [
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            RequiredTotalXp: 190,
 | 
					            RequiredTotalXp: 190,
 | 
				
			||||||
 | 
					            Rewards: generateRandomRewards(
 | 
				
			||||||
 | 
					                "/Lotus/Types/Game/MissionDecks/DuviriEndlessCircuitRewards/DuviriEndlessNormalSilverRewards"
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            RequiredTotalXp: 400,
 | 
				
			||||||
            Rewards: [
 | 
					            Rewards: [
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                            StoreItem: "/Lotus/StoreItems/Upgrades/Mods/Aura/PlayerHealthAuraMod",
 | 
					                    StoreItem: choiceRewards[0],
 | 
				
			||||||
 | 
					                    ItemCount: 1
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            ]
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            RequiredTotalXp: 630,
 | 
				
			||||||
 | 
					            Rewards: generateRandomRewards(
 | 
				
			||||||
 | 
					                "/Lotus/Types/Game/MissionDecks/DuviriEndlessCircuitRewards/DuviriEndlessNormalSilverRewards"
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            RequiredTotalXp: 890,
 | 
				
			||||||
 | 
					            Rewards: generateRandomRewards(
 | 
				
			||||||
 | 
					                "/Lotus/Types/Game/MissionDecks/DuviriEndlessCircuitRewards/DuviriEndlessNormalMODRewards"
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            RequiredTotalXp: 1190,
 | 
				
			||||||
 | 
					            Rewards: [
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    StoreItem: choiceRewards[1],
 | 
				
			||||||
 | 
					                    ItemCount: 1
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            ]
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            RequiredTotalXp: 1540,
 | 
				
			||||||
 | 
					            Rewards: generateRandomRewards(
 | 
				
			||||||
 | 
					                "/Lotus/Types/Game/MissionDecks/DuviriEndlessCircuitRewards/DuviriEndlessNormalGoldRewards"
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            RequiredTotalXp: 1950,
 | 
				
			||||||
 | 
					            Rewards: [
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    StoreItem: choiceRewards[2],
 | 
				
			||||||
 | 
					                    ItemCount: 1
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            ]
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            RequiredTotalXp: 2430,
 | 
				
			||||||
 | 
					            Rewards: [
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    StoreItem: choiceRewards[3],
 | 
				
			||||||
 | 
					                    ItemCount: 1
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            ]
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            RequiredTotalXp: 2990,
 | 
				
			||||||
 | 
					            Rewards: generateRandomRewards(
 | 
				
			||||||
 | 
					                "/Lotus/Types/Game/MissionDecks/DuviriEndlessCircuitRewards/DuviriEndlessNormalArcaneRewards"
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            RequiredTotalXp: 3640,
 | 
				
			||||||
 | 
					            Rewards: [
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    StoreItem: choiceRewards[4],
 | 
				
			||||||
                    ItemCount: 1
 | 
					                    ItemCount: 1
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            ]
 | 
					            ]
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
                // ...
 | 
					    ];
 | 
				
			||||||
            ]
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface IEndlessXpRequest {
 | 
					const hardModeChosenRewards: Record<string, string> = {
 | 
				
			||||||
    Mode: string; // "r"
 | 
					    Braton: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Primary/BratonIncarnonUnlocker",
 | 
				
			||||||
    Category: TEndlessXpCategory;
 | 
					    Lato: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Secondary/LatoIncarnonUnlocker",
 | 
				
			||||||
    Choices: string[];
 | 
					    Skana: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Melee/SkanaIncarnonUnlocker",
 | 
				
			||||||
 | 
					    Paris: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Primary/ParisIncarnonUnlocker",
 | 
				
			||||||
 | 
					    Kunai: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Secondary/KunaiIncarnonUnlocker",
 | 
				
			||||||
 | 
					    Boar: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Primary/BoarIncarnonUnlocker",
 | 
				
			||||||
 | 
					    Gammacor: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Secondary/GammacorIncarnonUnlocker",
 | 
				
			||||||
 | 
					    Anku: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Melee/AnkuIncarnonUnlocker",
 | 
				
			||||||
 | 
					    Gorgon: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Primary/GorgonIncarnonUnlocker",
 | 
				
			||||||
 | 
					    Angstrum: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Secondary/AngstrumIncarnonUnlocker",
 | 
				
			||||||
 | 
					    Bo: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Melee/BoIncarnonUnlocker",
 | 
				
			||||||
 | 
					    Latron: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Primary/LatronIncarnonUnlocker",
 | 
				
			||||||
 | 
					    Furis: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Secondary/FurisIncarnonUnlocker",
 | 
				
			||||||
 | 
					    Furax: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Melee/FuraxIncarnonUnlocker",
 | 
				
			||||||
 | 
					    Strun: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Primary/StrunIncarnonUnlocker",
 | 
				
			||||||
 | 
					    Lex: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Secondary/LexIncarnonUnlocker",
 | 
				
			||||||
 | 
					    Magistar: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Melee/MagistarIncarnonUnlocker",
 | 
				
			||||||
 | 
					    Boltor: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Primary/BoltorIncarnonUnlocker",
 | 
				
			||||||
 | 
					    Bronco: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Secondary/BroncoIncarnonUnlocker",
 | 
				
			||||||
 | 
					    CeramicDagger: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Melee/CeramicDaggerIncarnonUnlocker",
 | 
				
			||||||
 | 
					    Torid: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Primary/ToridIncarnonUnlocker",
 | 
				
			||||||
 | 
					    DualToxocyst: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Secondary/DualToxocystIncarnonUnlocker",
 | 
				
			||||||
 | 
					    DualIchor: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Melee/DualIchorIncarnonUnlocker",
 | 
				
			||||||
 | 
					    Miter: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Primary/MiterIncarnonUnlocker",
 | 
				
			||||||
 | 
					    Atomos: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Secondary/AtomosIncarnonUnlocker",
 | 
				
			||||||
 | 
					    AckAndBrunt: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Melee/AckAndBruntIncarnonUnlocker",
 | 
				
			||||||
 | 
					    Soma: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Primary/SomaIncarnonUnlocker",
 | 
				
			||||||
 | 
					    Vasto: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Secondary/VastoIncarnonUnlocker",
 | 
				
			||||||
 | 
					    NamiSolo: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Melee/NamiSoloIncarnonUnlocker",
 | 
				
			||||||
 | 
					    Burston: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Primary/BurstonIncarnonUnlocker",
 | 
				
			||||||
 | 
					    Zylok: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Secondary/ZylokIncarnonUnlocker",
 | 
				
			||||||
 | 
					    Sibear: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Melee/SibearIncarnonUnlocker",
 | 
				
			||||||
 | 
					    Dread: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Primary/DreadIncarnonUnlocker",
 | 
				
			||||||
 | 
					    Despair: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Secondary/DespairIncarnonUnlocker",
 | 
				
			||||||
 | 
					    Hate: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Melee/HateIncarnonUnlocker",
 | 
				
			||||||
 | 
					    Dera: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Primary/DeraIncarnonUnlocker",
 | 
				
			||||||
 | 
					    Cestra: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Secondary/CestraIncarnonUnlocker",
 | 
				
			||||||
 | 
					    Okina: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Melee/OkinaIncarnonUnlocker",
 | 
				
			||||||
 | 
					    Sybaris: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Primary/SybarisIncarnonUnlocker",
 | 
				
			||||||
 | 
					    Sicarus: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Secondary/SicarusIncarnonUnlocker",
 | 
				
			||||||
 | 
					    RivenPrimary: "/Lotus/StoreItems/Upgrades/Mods/Randomized/RawRifleRandomMod",
 | 
				
			||||||
 | 
					    RivenSecondary: "/Lotus/StoreItems/Upgrades/Mods/Randomized/RawPistolRandomMod",
 | 
				
			||||||
 | 
					    RivenMelee: "/Lotus/StoreItems/Upgrades/Mods/Randomized/RawMeleeRandomMod",
 | 
				
			||||||
 | 
					    Kuva: "/Lotus/Types/Game/DuviriEndless/CircuitSteelPathBIGKuvaReward"
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const generateHardModeRewards = (choices: string[]): IEndlessXpReward[] => {
 | 
				
			||||||
 | 
					    return [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            RequiredTotalXp: 285,
 | 
				
			||||||
 | 
					            Rewards: generateRandomRewards(
 | 
				
			||||||
 | 
					                "/Lotus/Types/Game/MissionDecks/DuviriEndlessCircuitRewards/DuviriEndlessSteelPathSilverRewards"
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            RequiredTotalXp: 600,
 | 
				
			||||||
 | 
					            Rewards: generateRandomRewards(
 | 
				
			||||||
 | 
					                "/Lotus/Types/Game/MissionDecks/DuviriEndlessCircuitRewards/DuviriEndlessSteelPathArcaneRewards"
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            RequiredTotalXp: 945,
 | 
				
			||||||
 | 
					            Rewards: generateRandomRewards(
 | 
				
			||||||
 | 
					                "/Lotus/Types/Game/MissionDecks/DuviriEndlessCircuitRewards/DuviriEndlessSteelPathSilverRewards"
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            RequiredTotalXp: 1335,
 | 
				
			||||||
 | 
					            Rewards: generateRandomRewards(
 | 
				
			||||||
 | 
					                "/Lotus/Types/Game/MissionDecks/DuviriEndlessCircuitRewards/DuviriEndlessSteelPathSilverRewards"
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            RequiredTotalXp: 1785,
 | 
				
			||||||
 | 
					            Rewards: [
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    StoreItem: hardModeChosenRewards[choices[0]],
 | 
				
			||||||
 | 
					                    ItemCount: 1
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					            ]
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            RequiredTotalXp: 2310,
 | 
				
			||||||
 | 
					            Rewards: generateRandomRewards(
 | 
				
			||||||
 | 
					                "/Lotus/Types/Game/MissionDecks/DuviriEndlessCircuitRewards/DuviriEndlessSteelPathGoldRewards"
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            RequiredTotalXp: 2925,
 | 
				
			||||||
 | 
					            Rewards: generateRandomRewards(
 | 
				
			||||||
 | 
					                "/Lotus/Types/Game/MissionDecks/DuviriEndlessCircuitRewards/DuviriEndlessSteelPathGoldRewards"
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            RequiredTotalXp: 3645,
 | 
				
			||||||
 | 
					            Rewards: generateRandomRewards(
 | 
				
			||||||
 | 
					                "/Lotus/Types/Game/MissionDecks/DuviriEndlessCircuitRewards/DuviriEndlessSteelPathArcaneRewards"
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            RequiredTotalXp: 4485,
 | 
				
			||||||
 | 
					            Rewards: generateRandomRewards(
 | 
				
			||||||
 | 
					                "/Lotus/Types/Game/MissionDecks/DuviriEndlessCircuitRewards/DuviriEndlessSteelPathSteelEssenceRewards"
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            RequiredTotalXp: 5460,
 | 
				
			||||||
 | 
					            Rewards: [
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    StoreItem: hardModeChosenRewards[choices[1]],
 | 
				
			||||||
 | 
					                    ItemCount: 1
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            ]
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    ];
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -38,7 +38,8 @@ import {
 | 
				
			|||||||
    IPeriodicMissionCompletionResponse,
 | 
					    IPeriodicMissionCompletionResponse,
 | 
				
			||||||
    ILoreFragmentScan,
 | 
					    ILoreFragmentScan,
 | 
				
			||||||
    IEvolutionProgress,
 | 
					    IEvolutionProgress,
 | 
				
			||||||
    IEndlessXpProgress,
 | 
					    IEndlessXpProgressDatabase,
 | 
				
			||||||
 | 
					    IEndlessXpProgressClient,
 | 
				
			||||||
    ICrewShipCustomization,
 | 
					    ICrewShipCustomization,
 | 
				
			||||||
    ICrewShipWeapon,
 | 
					    ICrewShipWeapon,
 | 
				
			||||||
    ICrewShipWeaponEmplacements,
 | 
					    ICrewShipWeaponEmplacements,
 | 
				
			||||||
@ -97,7 +98,8 @@ import {
 | 
				
			|||||||
    IInvasionProgressClient,
 | 
					    IInvasionProgressClient,
 | 
				
			||||||
    IAccolades,
 | 
					    IAccolades,
 | 
				
			||||||
    IHubNpcCustomization,
 | 
					    IHubNpcCustomization,
 | 
				
			||||||
    ILotusCustomization
 | 
					    ILotusCustomization,
 | 
				
			||||||
 | 
					    IEndlessXpReward
 | 
				
			||||||
} from "../../types/inventoryTypes/inventoryTypes";
 | 
					} from "../../types/inventoryTypes/inventoryTypes";
 | 
				
			||||||
import { IOid } from "../../types/commonTypes";
 | 
					import { IOid } from "../../types/commonTypes";
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
@ -112,6 +114,7 @@ import {
 | 
				
			|||||||
} from "@/src/types/inventoryTypes/commonInventoryTypes";
 | 
					} from "@/src/types/inventoryTypes/commonInventoryTypes";
 | 
				
			||||||
import { toMongoDate, toOid } from "@/src/helpers/inventoryHelpers";
 | 
					import { toMongoDate, toOid } from "@/src/helpers/inventoryHelpers";
 | 
				
			||||||
import { EquipmentSelectionSchema, oidSchema } from "./loadoutModel";
 | 
					import { EquipmentSelectionSchema, oidSchema } from "./loadoutModel";
 | 
				
			||||||
 | 
					import { ICountedStoreItem } from "warframe-public-export-plus";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const typeCountSchema = new Schema<ITypeCount>({ ItemType: String, ItemCount: Number }, { _id: false });
 | 
					export const typeCountSchema = new Schema<ITypeCount>({ ItemType: String, ItemCount: Number }, { _id: false });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -810,14 +813,48 @@ const evolutionProgressSchema = new Schema<IEvolutionProgress>(
 | 
				
			|||||||
    { _id: false }
 | 
					    { _id: false }
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const endlessXpProgressSchema = new Schema<IEndlessXpProgress>(
 | 
					const countedStoreItemSchema = new Schema<ICountedStoreItem>(
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        Category: String,
 | 
					        StoreItem: String,
 | 
				
			||||||
        Choices: [String]
 | 
					        ItemCount: Number
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    { _id: false }
 | 
					    { _id: false }
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const endlessXpRewardSchema = new Schema<IEndlessXpReward>(
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        RequiredTotalXp: Number,
 | 
				
			||||||
 | 
					        Rewards: [countedStoreItemSchema]
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    { _id: false }
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const endlessXpProgressSchema = new Schema<IEndlessXpProgressDatabase>(
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Category: { type: String, required: true },
 | 
				
			||||||
 | 
					        Earn: { type: Number, default: 0 },
 | 
				
			||||||
 | 
					        Claim: { type: Number, default: 0 },
 | 
				
			||||||
 | 
					        BonusAvailable: Date,
 | 
				
			||||||
 | 
					        Expiry: Date,
 | 
				
			||||||
 | 
					        Choices: { type: [String], required: true },
 | 
				
			||||||
 | 
					        PendingRewards: { type: [endlessXpRewardSchema], default: [] }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    { _id: false }
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					endlessXpProgressSchema.set("toJSON", {
 | 
				
			||||||
 | 
					    transform(_doc, ret) {
 | 
				
			||||||
 | 
					        const db = ret as IEndlessXpProgressDatabase;
 | 
				
			||||||
 | 
					        const client = ret as IEndlessXpProgressClient;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (db.BonusAvailable) {
 | 
				
			||||||
 | 
					            client.BonusAvailable = toMongoDate(db.BonusAvailable);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (db.Expiry) {
 | 
				
			||||||
 | 
					            client.Expiry = toMongoDate(db.Expiry);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
const crewShipWeaponEmplacementsSchema = new Schema<ICrewShipWeaponEmplacements>(
 | 
					const crewShipWeaponEmplacementsSchema = new Schema<ICrewShipWeaponEmplacements>(
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        PRIMARY_A: EquipmentSelectionSchema,
 | 
					        PRIMARY_A: EquipmentSelectionSchema,
 | 
				
			||||||
 | 
				
			|||||||
@ -377,9 +377,6 @@ export const importInventory = (db: TInventoryDatabaseDocument, client: Partial<
 | 
				
			|||||||
            db[key] = client[key];
 | 
					            db[key] = client[key];
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (client.EndlessXP !== undefined) {
 | 
					 | 
				
			||||||
        db.EndlessXP = client.EndlessXP;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (client.SongChallenges !== undefined) {
 | 
					    if (client.SongChallenges !== undefined) {
 | 
				
			||||||
        db.SongChallenges = client.SongChallenges;
 | 
					        db.SongChallenges = client.SongChallenges;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -10,7 +10,7 @@ import {
 | 
				
			|||||||
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, SRng, getRandomElement, getRandomReward } from "@/src/services/rngService";
 | 
					import { IRngResult, SRng, getRandomElement, getRandomReward } from "@/src/services/rngService";
 | 
				
			||||||
import { equipmentKeys, TEquipmentKey } from "@/src/types/inventoryTypes/inventoryTypes";
 | 
					import { equipmentKeys, IMission, TEquipmentKey } from "@/src/types/inventoryTypes/inventoryTypes";
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
    addBooster,
 | 
					    addBooster,
 | 
				
			||||||
    addChallenges,
 | 
					    addChallenges,
 | 
				
			||||||
@ -841,7 +841,13 @@ export const addMissionRewards = async (
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    //TODO: check double reward merging
 | 
					    //TODO: check double reward merging
 | 
				
			||||||
    const MissionRewards: IMissionReward[] = getRandomMissionDrops(inventory, rewardInfo, wagerTier, firstCompletion);
 | 
					    const MissionRewards: IMissionReward[] = getRandomMissionDrops(
 | 
				
			||||||
 | 
					        inventory,
 | 
				
			||||||
 | 
					        rewardInfo,
 | 
				
			||||||
 | 
					        missions,
 | 
				
			||||||
 | 
					        wagerTier,
 | 
				
			||||||
 | 
					        firstCompletion
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
    logger.debug("random mission drops:", MissionRewards);
 | 
					    logger.debug("random mission drops:", MissionRewards);
 | 
				
			||||||
    const inventoryChanges: IInventoryChanges = {};
 | 
					    const inventoryChanges: IInventoryChanges = {};
 | 
				
			||||||
    const AffiliationMods: IAffiliationMods[] = [];
 | 
					    const AffiliationMods: IAffiliationMods[] = [];
 | 
				
			||||||
@ -1290,6 +1296,7 @@ function getLevelCreditRewards(node: IRegion): number {
 | 
				
			|||||||
function getRandomMissionDrops(
 | 
					function getRandomMissionDrops(
 | 
				
			||||||
    inventory: TInventoryDatabaseDocument,
 | 
					    inventory: TInventoryDatabaseDocument,
 | 
				
			||||||
    RewardInfo: IRewardInfo,
 | 
					    RewardInfo: IRewardInfo,
 | 
				
			||||||
 | 
					    mission: IMission | undefined,
 | 
				
			||||||
    tierOverride: number | undefined,
 | 
					    tierOverride: number | undefined,
 | 
				
			||||||
    firstCompletion: boolean
 | 
					    firstCompletion: boolean
 | 
				
			||||||
): IMissionReward[] {
 | 
					): IMissionReward[] {
 | 
				
			||||||
@ -1531,6 +1538,35 @@ function getRandomMissionDrops(
 | 
				
			|||||||
                logger.error(`Unknown syndicate or tier: ${RewardInfo.challengeMissionId}`);
 | 
					                logger.error(`Unknown syndicate or tier: ${RewardInfo.challengeMissionId}`);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
 | 
					            if (RewardInfo.node == "SolNode238") {
 | 
				
			||||||
 | 
					                // The Circuit
 | 
				
			||||||
 | 
					                const category = mission?.Tier == 1 ? "EXC_HARD" : "EXC_NORMAL";
 | 
				
			||||||
 | 
					                const progress = inventory.EndlessXP?.find(x => x.Category == category);
 | 
				
			||||||
 | 
					                if (progress) {
 | 
				
			||||||
 | 
					                    // https://wiki.warframe.com/w/The%20Circuit#Tiers_and_Weekly_Rewards
 | 
				
			||||||
 | 
					                    const roundsCompleted = RewardInfo.rewardQualifications?.length || 0;
 | 
				
			||||||
 | 
					                    if (roundsCompleted >= 1) {
 | 
				
			||||||
 | 
					                        progress.Earn += 100;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    if (roundsCompleted >= 2) {
 | 
				
			||||||
 | 
					                        progress.Earn += 110;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    if (roundsCompleted >= 3) {
 | 
				
			||||||
 | 
					                        progress.Earn += 125;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    if (roundsCompleted >= 4) {
 | 
				
			||||||
 | 
					                        progress.Earn += 145;
 | 
				
			||||||
 | 
					                        if (progress.BonusAvailable && progress.BonusAvailable.getTime() <= Date.now()) {
 | 
				
			||||||
 | 
					                            progress.Earn += 50;
 | 
				
			||||||
 | 
					                            progress.BonusAvailable = new Date(Date.now() + 24 * 3600_000); // TOVERIFY
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    if (roundsCompleted >= 5) {
 | 
				
			||||||
 | 
					                        progress.Earn += (roundsCompleted - 4) * 170;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                tierOverride = 0;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
            rotations = getRotations(RewardInfo, tierOverride);
 | 
					            rotations = getRotations(RewardInfo, tierOverride);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (rewardManifests.length != 0) {
 | 
					        if (rewardManifests.length != 0) {
 | 
				
			||||||
 | 
				
			|||||||
@ -12,6 +12,7 @@ import {
 | 
				
			|||||||
} from "@/src/types/inventoryTypes/commonInventoryTypes";
 | 
					} from "@/src/types/inventoryTypes/commonInventoryTypes";
 | 
				
			||||||
import { IFingerprintStat, RivenFingerprint } from "@/src/helpers/rivenHelper";
 | 
					import { IFingerprintStat, RivenFingerprint } from "@/src/helpers/rivenHelper";
 | 
				
			||||||
import { IOrbiter } from "../personalRoomsTypes";
 | 
					import { IOrbiter } from "../personalRoomsTypes";
 | 
				
			||||||
 | 
					import { ICountedStoreItem } from "warframe-public-export-plus";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type InventoryDatabaseEquipment = {
 | 
					export type InventoryDatabaseEquipment = {
 | 
				
			||||||
    [_ in TEquipmentKey]: IEquipmentDatabase[];
 | 
					    [_ in TEquipmentKey]: IEquipmentDatabase[];
 | 
				
			||||||
@ -54,6 +55,7 @@ export interface IInventoryDatabase
 | 
				
			|||||||
            | "CrewMembers"
 | 
					            | "CrewMembers"
 | 
				
			||||||
            | "QualifyingInvasions"
 | 
					            | "QualifyingInvasions"
 | 
				
			||||||
            | "LastInventorySync"
 | 
					            | "LastInventorySync"
 | 
				
			||||||
 | 
					            | "EndlessXP"
 | 
				
			||||||
            | TEquipmentKey
 | 
					            | TEquipmentKey
 | 
				
			||||||
        >,
 | 
					        >,
 | 
				
			||||||
        InventoryDatabaseEquipment {
 | 
					        InventoryDatabaseEquipment {
 | 
				
			||||||
@ -92,6 +94,7 @@ export interface IInventoryDatabase
 | 
				
			|||||||
    CrewMembers: ICrewMemberDatabase[];
 | 
					    CrewMembers: ICrewMemberDatabase[];
 | 
				
			||||||
    QualifyingInvasions: IInvasionProgressDatabase[];
 | 
					    QualifyingInvasions: IInvasionProgressDatabase[];
 | 
				
			||||||
    LastInventorySync?: Types.ObjectId;
 | 
					    LastInventorySync?: Types.ObjectId;
 | 
				
			||||||
 | 
					    EndlessXP?: IEndlessXpProgressDatabase[];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface IQuestKeyDatabase {
 | 
					export interface IQuestKeyDatabase {
 | 
				
			||||||
@ -356,7 +359,7 @@ export interface IInventoryClient extends IDailyAffiliations, InventoryClientEqu
 | 
				
			|||||||
    PendingCoupon?: IPendingCouponClient;
 | 
					    PendingCoupon?: IPendingCouponClient;
 | 
				
			||||||
    Harvestable: boolean;
 | 
					    Harvestable: boolean;
 | 
				
			||||||
    DeathSquadable: boolean;
 | 
					    DeathSquadable: boolean;
 | 
				
			||||||
    EndlessXP?: IEndlessXpProgress[];
 | 
					    EndlessXP?: IEndlessXpProgressClient[];
 | 
				
			||||||
    DialogueHistory?: IDialogueHistoryClient;
 | 
					    DialogueHistory?: IDialogueHistoryClient;
 | 
				
			||||||
    CalendarProgress?: ICalendarProgress;
 | 
					    CalendarProgress?: ICalendarProgress;
 | 
				
			||||||
    SongChallenges?: ISongChallenge[];
 | 
					    SongChallenges?: ISongChallenge[];
 | 
				
			||||||
@ -1143,9 +1146,24 @@ export interface IEvolutionProgress {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
export type TEndlessXpCategory = "EXC_NORMAL" | "EXC_HARD";
 | 
					export type TEndlessXpCategory = "EXC_NORMAL" | "EXC_HARD";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface IEndlessXpProgress {
 | 
					export interface IEndlessXpProgressDatabase {
 | 
				
			||||||
    Category: TEndlessXpCategory;
 | 
					    Category: TEndlessXpCategory;
 | 
				
			||||||
 | 
					    Earn: number;
 | 
				
			||||||
 | 
					    Claim: number;
 | 
				
			||||||
 | 
					    BonusAvailable?: Date;
 | 
				
			||||||
 | 
					    Expiry?: Date;
 | 
				
			||||||
    Choices: string[];
 | 
					    Choices: string[];
 | 
				
			||||||
 | 
					    PendingRewards: IEndlessXpReward[];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface IEndlessXpProgressClient extends Omit<IEndlessXpProgressDatabase, "BonusAvailable" | "Expiry"> {
 | 
				
			||||||
 | 
					    BonusAvailable?: IMongoDate;
 | 
				
			||||||
 | 
					    Expiry?: IMongoDate;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface IEndlessXpReward {
 | 
				
			||||||
 | 
					    RequiredTotalXp: number;
 | 
				
			||||||
 | 
					    Rewards: ICountedStoreItem[];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface IDialogueHistoryClient {
 | 
					export interface IDialogueHistoryClient {
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user