merge upstream
This commit is contained in:
		
						commit
						ed9d9c2edc
					
				@ -1,23 +1,91 @@
 | 
				
			|||||||
import type { RequestHandler } from "express";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
 | 
					import { getAccountForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
import { getInventory, addMiscItems, addEquipment, occupySlot } from "../../services/inventoryService.ts";
 | 
					import { getInventory, addMiscItems, addEquipment, occupySlot } from "../../services/inventoryService.ts";
 | 
				
			||||||
import type { IMiscItem, TFocusPolarity, TEquipmentKey } from "../../types/inventoryTypes/inventoryTypes.ts";
 | 
					import type { IMiscItem, TFocusPolarity, TEquipmentKey } from "../../types/inventoryTypes/inventoryTypes.ts";
 | 
				
			||||||
import { InventorySlot } from "../../types/inventoryTypes/inventoryTypes.ts";
 | 
					import { InventorySlot } from "../../types/inventoryTypes/inventoryTypes.ts";
 | 
				
			||||||
import { logger } from "../../utils/logger.ts";
 | 
					import { logger } from "../../utils/logger.ts";
 | 
				
			||||||
import { ExportFocusUpgrades } from "warframe-public-export-plus";
 | 
					import { ExportFocusUpgrades } from "warframe-public-export-plus";
 | 
				
			||||||
import { Inventory } from "../../models/inventoryModels/inventoryModel.ts";
 | 
					import { Inventory } from "../../models/inventoryModels/inventoryModel.ts";
 | 
				
			||||||
 | 
					import { version_compare } from "../../helpers/inventoryHelpers.ts";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const focusController: RequestHandler = async (req, res) => {
 | 
					export const focusController: RequestHandler = async (req, res) => {
 | 
				
			||||||
    const accountId = await getAccountIdForRequest(req);
 | 
					    const account = await getAccountForRequest(req);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let op = req.query.op as string;
 | 
				
			||||||
 | 
					    const focus2 = account.BuildLabel && version_compare(account.BuildLabel, "2022.04.29.12.53") < 0;
 | 
				
			||||||
 | 
					    if (focus2) {
 | 
				
			||||||
 | 
					        // Focus 2.0
 | 
				
			||||||
        switch (req.query.op) {
 | 
					        switch (req.query.op) {
 | 
				
			||||||
 | 
					            case Focus2Operation.InstallLens:
 | 
				
			||||||
 | 
					                op = "InstallLens";
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case Focus2Operation.UnlockWay:
 | 
				
			||||||
 | 
					                op = "UnlockWay";
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case Focus2Operation.UnlockUpgrade:
 | 
				
			||||||
 | 
					                op = "UnlockUpgrade";
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case Focus2Operation.IncreasePool:
 | 
				
			||||||
 | 
					                op = "IncreasePool";
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case Focus2Operation.LevelUpUpgrade:
 | 
				
			||||||
 | 
					                op = "LevelUpUpgrade";
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case Focus2Operation.ActivateWay:
 | 
				
			||||||
 | 
					                op = "ActivateWay";
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case Focus2Operation.UpdateUpgrade:
 | 
				
			||||||
 | 
					                op = "UpdateUpgrade";
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case Focus2Operation.SentTrainingAmplifier:
 | 
				
			||||||
 | 
					                op = "SentTrainingAmplifier";
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case Focus2Operation.UnbindUpgrade:
 | 
				
			||||||
 | 
					                op = "UnbindUpgrade";
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case Focus2Operation.ConvertShard:
 | 
				
			||||||
 | 
					                op = "ConvertShard";
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        // Focus 3.0
 | 
				
			||||||
 | 
					        switch (req.query.op) {
 | 
				
			||||||
 | 
					            case Focus3Operation.InstallLens:
 | 
				
			||||||
 | 
					                op = "InstallLens";
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case Focus3Operation.UnlockWay:
 | 
				
			||||||
 | 
					                op = "UnlockWay";
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case Focus3Operation.UnlockUpgrade:
 | 
				
			||||||
 | 
					                op = "UnlockUpgrade";
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case Focus3Operation.LevelUpUpgrade:
 | 
				
			||||||
 | 
					                op = "LevelUpUpgrade";
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case Focus3Operation.ActivateWay:
 | 
				
			||||||
 | 
					                op = "ActivateWay";
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case Focus3Operation.SentTrainingAmplifier:
 | 
				
			||||||
 | 
					                op = "SentTrainingAmplifier";
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case Focus3Operation.UnbindUpgrade:
 | 
				
			||||||
 | 
					                op = "UnbindUpgrade";
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case Focus3Operation.ConvertShard:
 | 
				
			||||||
 | 
					                op = "ConvertShard";
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    switch (op) {
 | 
				
			||||||
        default:
 | 
					        default:
 | 
				
			||||||
            logger.error("Unhandled focus op type: " + String(req.query.op));
 | 
					            logger.error("Unhandled focus op type: " + String(req.query.op));
 | 
				
			||||||
            logger.debug(String(req.body));
 | 
					            logger.debug(String(req.body));
 | 
				
			||||||
            res.end();
 | 
					            res.end();
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        case FocusOperation.InstallLens: {
 | 
					        case "InstallLens": {
 | 
				
			||||||
            const request = JSON.parse(String(req.body)) as ILensInstallRequest;
 | 
					            const request = JSON.parse(String(req.body)) as ILensInstallRequest;
 | 
				
			||||||
            const inventory = await getInventory(accountId);
 | 
					            const inventory = await getInventory(account._id.toString());
 | 
				
			||||||
            const item = inventory[request.Category].id(request.WeaponId);
 | 
					            const item = inventory[request.Category].id(request.WeaponId);
 | 
				
			||||||
            if (item) {
 | 
					            if (item) {
 | 
				
			||||||
                item.FocusLens = request.LensType;
 | 
					                item.FocusLens = request.LensType;
 | 
				
			||||||
@ -35,10 +103,10 @@ export const focusController: RequestHandler = async (req, res) => {
 | 
				
			|||||||
            });
 | 
					            });
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        case FocusOperation.UnlockWay: {
 | 
					        case "UnlockWay": {
 | 
				
			||||||
            const focusType = (JSON.parse(String(req.body)) as IWayRequest).FocusType;
 | 
					            const focusType = (JSON.parse(String(req.body)) as IWayRequest).FocusType;
 | 
				
			||||||
            const focusPolarity = focusTypeToPolarity(focusType);
 | 
					            const focusPolarity = focusTypeToPolarity(focusType);
 | 
				
			||||||
            const inventory = await getInventory(accountId, "FocusAbility FocusUpgrades FocusXP");
 | 
					            const inventory = await getInventory(account._id.toString(), "FocusAbility FocusUpgrades FocusXP");
 | 
				
			||||||
            const cost = inventory.FocusAbility ? 50_000 : 0;
 | 
					            const cost = inventory.FocusAbility ? 50_000 : 0;
 | 
				
			||||||
            inventory.FocusAbility ??= focusType;
 | 
					            inventory.FocusAbility ??= focusType;
 | 
				
			||||||
            inventory.FocusUpgrades.push({ ItemType: focusType });
 | 
					            inventory.FocusUpgrades.push({ ItemType: focusType });
 | 
				
			||||||
@ -52,12 +120,29 @@ export const focusController: RequestHandler = async (req, res) => {
 | 
				
			|||||||
            });
 | 
					            });
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        case FocusOperation.ActivateWay: {
 | 
					        case "IncreasePool": {
 | 
				
			||||||
 | 
					            const request = JSON.parse(String(req.body)) as IIncreasePoolRequest;
 | 
				
			||||||
 | 
					            const focusPolarity = focusTypeToPolarity(request.FocusType);
 | 
				
			||||||
 | 
					            const inventory = await getInventory(account._id.toString(), "FocusXP FocusCapacity");
 | 
				
			||||||
 | 
					            let cost = 0;
 | 
				
			||||||
 | 
					            for (let capacity = request.CurrentTotalCapacity; capacity != request.NewTotalCapacity; ++capacity) {
 | 
				
			||||||
 | 
					                cost += increasePoolCost[capacity - 5];
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            inventory.FocusXP![focusPolarity]! -= cost;
 | 
				
			||||||
 | 
					            inventory.FocusCapacity = request.NewTotalCapacity;
 | 
				
			||||||
 | 
					            await inventory.save();
 | 
				
			||||||
 | 
					            res.json({
 | 
				
			||||||
 | 
					                TotalCapacity: request.NewTotalCapacity,
 | 
				
			||||||
 | 
					                FocusPointCosts: { [focusPolarity]: cost }
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        case "ActivateWay": {
 | 
				
			||||||
            const focusType = (JSON.parse(String(req.body)) as IWayRequest).FocusType;
 | 
					            const focusType = (JSON.parse(String(req.body)) as IWayRequest).FocusType;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            await Inventory.updateOne(
 | 
					            await Inventory.updateOne(
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    accountOwnerId: accountId
 | 
					                    accountOwnerId: account._id.toString()
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    FocusAbility: focusType
 | 
					                    FocusAbility: focusType
 | 
				
			||||||
@ -69,13 +154,20 @@ export const focusController: RequestHandler = async (req, res) => {
 | 
				
			|||||||
            });
 | 
					            });
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        case FocusOperation.UnlockUpgrade: {
 | 
					        case "UnlockUpgrade": {
 | 
				
			||||||
            const request = JSON.parse(String(req.body)) as IUnlockUpgradeRequest;
 | 
					            const request = JSON.parse(String(req.body)) as IUnlockUpgradeRequest;
 | 
				
			||||||
            const focusPolarity = focusTypeToPolarity(request.FocusTypes[0]);
 | 
					            const focusPolarity = focusTypeToPolarity(request.FocusTypes[0]);
 | 
				
			||||||
            const inventory = await getInventory(accountId);
 | 
					            const inventory = await getInventory(account._id.toString());
 | 
				
			||||||
            let cost = 0;
 | 
					            let cost = 0;
 | 
				
			||||||
            for (const focusType of request.FocusTypes) {
 | 
					            for (const focusType of request.FocusTypes) {
 | 
				
			||||||
 | 
					                if (focusType in ExportFocusUpgrades) {
 | 
				
			||||||
                    cost += ExportFocusUpgrades[focusType].baseFocusPointCost;
 | 
					                    cost += ExportFocusUpgrades[focusType].baseFocusPointCost;
 | 
				
			||||||
 | 
					                } else if (focusType == "/Lotus/Upgrades/Focus/Power/Residual/ChannelEfficiencyFocusUpgrade") {
 | 
				
			||||||
 | 
					                    // Zenurik's Inner Might (Focus 2.0)
 | 
				
			||||||
 | 
					                    cost += 50_000;
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    logger.warn(`unknown focus upgrade ${focusType}, will unlock it for free`);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
                inventory.FocusUpgrades.push({ ItemType: focusType, Level: 0 });
 | 
					                inventory.FocusUpgrades.push({ ItemType: focusType, Level: 0 });
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            inventory.FocusXP![focusPolarity]! -= cost;
 | 
					            inventory.FocusXP![focusPolarity]! -= cost;
 | 
				
			||||||
@ -86,16 +178,21 @@ export const focusController: RequestHandler = async (req, res) => {
 | 
				
			|||||||
            });
 | 
					            });
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        case FocusOperation.LevelUpUpgrade: {
 | 
					        case "LevelUpUpgrade":
 | 
				
			||||||
 | 
					        case "UpdateUpgrade": {
 | 
				
			||||||
            const request = JSON.parse(String(req.body)) as ILevelUpUpgradeRequest;
 | 
					            const request = JSON.parse(String(req.body)) as ILevelUpUpgradeRequest;
 | 
				
			||||||
            const focusPolarity = focusTypeToPolarity(request.FocusInfos[0].ItemType);
 | 
					            const focusPolarity = focusTypeToPolarity(request.FocusInfos[0].ItemType);
 | 
				
			||||||
            const inventory = await getInventory(accountId);
 | 
					            const inventory = await getInventory(account._id.toString());
 | 
				
			||||||
            let cost = 0;
 | 
					            let cost = 0;
 | 
				
			||||||
            for (const focusUpgrade of request.FocusInfos) {
 | 
					            for (const focusUpgrade of request.FocusInfos) {
 | 
				
			||||||
                cost += focusUpgrade.FocusXpCost;
 | 
					                cost += focusUpgrade.FocusXpCost;
 | 
				
			||||||
                const focusUpgradeDb = inventory.FocusUpgrades.find(entry => entry.ItemType == focusUpgrade.ItemType)!;
 | 
					                const focusUpgradeDb = inventory.FocusUpgrades.find(entry => entry.ItemType == focusUpgrade.ItemType)!;
 | 
				
			||||||
 | 
					                if (op == "UpdateUpgrade") {
 | 
				
			||||||
 | 
					                    focusUpgradeDb.IsActive = focusUpgrade.IsActive;
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
                    focusUpgradeDb.Level = focusUpgrade.Level;
 | 
					                    focusUpgradeDb.Level = focusUpgrade.Level;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
            inventory.FocusXP![focusPolarity]! -= cost;
 | 
					            inventory.FocusXP![focusPolarity]! -= cost;
 | 
				
			||||||
            await inventory.save();
 | 
					            await inventory.save();
 | 
				
			||||||
            res.json({
 | 
					            res.json({
 | 
				
			||||||
@ -104,9 +201,9 @@ export const focusController: RequestHandler = async (req, res) => {
 | 
				
			|||||||
            });
 | 
					            });
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        case FocusOperation.SentTrainingAmplifier: {
 | 
					        case "SentTrainingAmplifier": {
 | 
				
			||||||
            const request = JSON.parse(String(req.body)) as ISentTrainingAmplifierRequest;
 | 
					            const request = JSON.parse(String(req.body)) as ISentTrainingAmplifierRequest;
 | 
				
			||||||
            const inventory = await getInventory(accountId);
 | 
					            const inventory = await getInventory(account._id.toString());
 | 
				
			||||||
            const inventoryChanges = addEquipment(inventory, "OperatorAmps", request.StartingWeaponType, {
 | 
					            const inventoryChanges = addEquipment(inventory, "OperatorAmps", request.StartingWeaponType, {
 | 
				
			||||||
                ModularParts: [
 | 
					                ModularParts: [
 | 
				
			||||||
                    "/Lotus/Weapons/Sentients/OperatorAmplifiers/SentTrainingAmplifier/SentAmpTrainingGrip",
 | 
					                    "/Lotus/Weapons/Sentients/OperatorAmplifiers/SentTrainingAmplifier/SentAmpTrainingGrip",
 | 
				
			||||||
@ -119,10 +216,10 @@ export const focusController: RequestHandler = async (req, res) => {
 | 
				
			|||||||
            res.json(inventoryChanges.OperatorAmps![0]);
 | 
					            res.json(inventoryChanges.OperatorAmps![0]);
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        case FocusOperation.UnbindUpgrade: {
 | 
					        case "UnbindUpgrade": {
 | 
				
			||||||
            const request = JSON.parse(String(req.body)) as IUnbindUpgradeRequest;
 | 
					            const request = JSON.parse(String(req.body)) as IUnbindUpgradeRequest;
 | 
				
			||||||
            const focusPolarity = focusTypeToPolarity(request.FocusTypes[0]);
 | 
					            const focusPolarity = focusTypeToPolarity(request.FocusTypes[0]);
 | 
				
			||||||
            const inventory = await getInventory(accountId);
 | 
					            const inventory = await getInventory(account._id.toString());
 | 
				
			||||||
            inventory.FocusXP![focusPolarity]! -= 750_000 * request.FocusTypes.length;
 | 
					            inventory.FocusXP![focusPolarity]! -= 750_000 * request.FocusTypes.length;
 | 
				
			||||||
            addMiscItems(inventory, [
 | 
					            addMiscItems(inventory, [
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
@ -149,7 +246,7 @@ export const focusController: RequestHandler = async (req, res) => {
 | 
				
			|||||||
            });
 | 
					            });
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        case FocusOperation.ConvertShard: {
 | 
					        case "ConvertShard": {
 | 
				
			||||||
            const request = JSON.parse(String(req.body)) as IConvertShardRequest;
 | 
					            const request = JSON.parse(String(req.body)) as IConvertShardRequest;
 | 
				
			||||||
            // Tally XP
 | 
					            // Tally XP
 | 
				
			||||||
            let xp = 0;
 | 
					            let xp = 0;
 | 
				
			||||||
@ -167,7 +264,7 @@ export const focusController: RequestHandler = async (req, res) => {
 | 
				
			|||||||
            for (const shard of request.Shards) {
 | 
					            for (const shard of request.Shards) {
 | 
				
			||||||
                shard.ItemCount *= -1;
 | 
					                shard.ItemCount *= -1;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            const inventory = await getInventory(accountId);
 | 
					            const inventory = await getInventory(account._id.toString());
 | 
				
			||||||
            const polarity = request.Polarity;
 | 
					            const polarity = request.Polarity;
 | 
				
			||||||
            inventory.FocusXP ??= {};
 | 
					            inventory.FocusXP ??= {};
 | 
				
			||||||
            inventory.FocusXP[polarity] ??= 0;
 | 
					            inventory.FocusXP[polarity] ??= 0;
 | 
				
			||||||
@ -179,7 +276,8 @@ export const focusController: RequestHandler = async (req, res) => {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum FocusOperation {
 | 
					// Focus 3.0
 | 
				
			||||||
 | 
					enum Focus3Operation {
 | 
				
			||||||
    InstallLens = "1",
 | 
					    InstallLens = "1",
 | 
				
			||||||
    UnlockWay = "2",
 | 
					    UnlockWay = "2",
 | 
				
			||||||
    UnlockUpgrade = "3",
 | 
					    UnlockUpgrade = "3",
 | 
				
			||||||
@ -190,6 +288,20 @@ enum FocusOperation {
 | 
				
			|||||||
    ConvertShard = "9"
 | 
					    ConvertShard = "9"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Focus 2.0
 | 
				
			||||||
 | 
					enum Focus2Operation {
 | 
				
			||||||
 | 
					    InstallLens = "1",
 | 
				
			||||||
 | 
					    UnlockWay = "2",
 | 
				
			||||||
 | 
					    UnlockUpgrade = "3",
 | 
				
			||||||
 | 
					    IncreasePool = "4",
 | 
				
			||||||
 | 
					    LevelUpUpgrade = "5",
 | 
				
			||||||
 | 
					    ActivateWay = "6",
 | 
				
			||||||
 | 
					    UpdateUpgrade = "7", // used to change the IsActive state, same format as ILevelUpUpgradeRequest
 | 
				
			||||||
 | 
					    SentTrainingAmplifier = "9",
 | 
				
			||||||
 | 
					    UnbindUpgrade = "10",
 | 
				
			||||||
 | 
					    ConvertShard = "11"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// For UnlockWay & ActivateWay
 | 
					// For UnlockWay & ActivateWay
 | 
				
			||||||
interface IWayRequest {
 | 
					interface IWayRequest {
 | 
				
			||||||
    FocusType: string;
 | 
					    FocusType: string;
 | 
				
			||||||
@ -199,6 +311,13 @@ interface IUnlockUpgradeRequest {
 | 
				
			|||||||
    FocusTypes: string[];
 | 
					    FocusTypes: string[];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Focus 2.0
 | 
				
			||||||
 | 
					interface IIncreasePoolRequest {
 | 
				
			||||||
 | 
					    FocusType: string;
 | 
				
			||||||
 | 
					    CurrentTotalCapacity: number;
 | 
				
			||||||
 | 
					    NewTotalCapacity: number;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface ILevelUpUpgradeRequest {
 | 
					interface ILevelUpUpgradeRequest {
 | 
				
			||||||
    FocusInfos: {
 | 
					    FocusInfos: {
 | 
				
			||||||
        ItemType: string;
 | 
					        ItemType: string;
 | 
				
			||||||
@ -206,6 +325,7 @@ interface ILevelUpUpgradeRequest {
 | 
				
			|||||||
        IsUniversal: boolean;
 | 
					        IsUniversal: boolean;
 | 
				
			||||||
        Level: number;
 | 
					        Level: number;
 | 
				
			||||||
        IsActiveAbility: boolean;
 | 
					        IsActiveAbility: boolean;
 | 
				
			||||||
 | 
					        IsActive?: number; // Focus 2.0
 | 
				
			||||||
    }[];
 | 
					    }[];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -240,3 +360,19 @@ const shardValues = {
 | 
				
			|||||||
    "/Lotus/Types/Gameplay/Eidolon/Resources/SentientShards/SentientShardBrilliantItem": 25_000,
 | 
					    "/Lotus/Types/Gameplay/Eidolon/Resources/SentientShards/SentientShardBrilliantItem": 25_000,
 | 
				
			||||||
    "/Lotus/Types/Gameplay/Eidolon/Resources/SentientShards/SentientShardBrilliantTierTwoItem": 40_000
 | 
					    "/Lotus/Types/Gameplay/Eidolon/Resources/SentientShards/SentientShardBrilliantTierTwoItem": 40_000
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Starting at a capacity of 5 (Source: https://wiki.warframe.com/w/Focus_2.0)
 | 
				
			||||||
 | 
					const increasePoolCost = [
 | 
				
			||||||
 | 
					    2576, 3099, 3638, 4190, 4755, 5331, 5918, 6514, 7120, 7734, 8357, 8988, 9626, 10271, 10923, 11582, 12247, 12918,
 | 
				
			||||||
 | 
					    13595, 14277, 14965, 15659, 16357, 17061, 17769, 18482, 19200, 19922, 20649, 21380, 22115, 22854, 23597, 24344,
 | 
				
			||||||
 | 
					    25095, 25850, 26609, 27371, 28136, 28905, 29678, 30454, 31233, 32015, 32801, 33590, 34382, 35176, 35974, 36775,
 | 
				
			||||||
 | 
					    37579, 38386, 39195, 40008, 40823, 41641, 42461, 43284, 44110, 44938, 45769, 46603, 47439, 48277, 49118, 49961,
 | 
				
			||||||
 | 
					    50807, 51655, 52505, 53357, 54212, 55069, 55929, 56790, 57654, 58520, 59388, 60258, 61130, 62005, 62881, 63759,
 | 
				
			||||||
 | 
					    64640, 65522, 66407, 67293, 68182, 69072, 69964, 70858, 71754, 72652, 73552, 74453, 75357, 76262, 77169, 78078,
 | 
				
			||||||
 | 
					    78988, 79900, 80814, 81730, 82648, 83567, 84488, 85410, 86334, 87260, 88188, 89117, 90047, 90980, 91914, 92849,
 | 
				
			||||||
 | 
					    93786, 94725, 95665, 96607, 97550, 98495, 99441, 100389, 101338, 102289, 103241, 104195, 105150, 106107, 107065,
 | 
				
			||||||
 | 
					    108024, 108985, 109948, 110911, 111877, 112843, 113811, 114780, 115751, 116723, 117696, 118671, 119647, 120624,
 | 
				
			||||||
 | 
					    121603, 122583, 123564, 124547, 125531, 126516, 127503, 128490, 129479, 130470, 131461, 132454, 133448, 134443,
 | 
				
			||||||
 | 
					    135440, 136438, 137437, 138437, 139438, 140441, 141444, 142449, 143455, 144463, 145471, 146481, 147492, 148503,
 | 
				
			||||||
 | 
					    149517
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
 | 
				
			|||||||
@ -1,16 +1,9 @@
 | 
				
			|||||||
import type { RequestHandler } from "express";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
 | 
					import type { ITunables } from "../../types/bootstrapperTypes.ts";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// This endpoint is specific to the OpenWF Bootstrapper: https://openwf.io/bootstrapper-manual
 | 
					// This endpoint is specific to the OpenWF Bootstrapper: https://openwf.io/bootstrapper-manual
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface ITunables {
 | 
					export const tunablesController: RequestHandler = (_req, res) => {
 | 
				
			||||||
    prohibit_skip_mission_start_timer?: boolean;
 | 
					 | 
				
			||||||
    prohibit_fov_override?: boolean;
 | 
					 | 
				
			||||||
    prohibit_freecam?: boolean;
 | 
					 | 
				
			||||||
    prohibit_teleport?: boolean;
 | 
					 | 
				
			||||||
    prohibit_scripts?: boolean;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const tunablesController: RequestHandler = (_req, res) => {
 | 
					 | 
				
			||||||
    const tunables: ITunables = {};
 | 
					    const tunables: ITunables = {};
 | 
				
			||||||
    //tunables.prohibit_skip_mission_start_timer = true;
 | 
					    //tunables.prohibit_skip_mission_start_timer = true;
 | 
				
			||||||
    //tunables.prohibit_fov_override = true;
 | 
					    //tunables.prohibit_fov_override = true;
 | 
				
			||||||
@ -19,5 +12,3 @@ const tunablesController: RequestHandler = (_req, res) => {
 | 
				
			|||||||
    //tunables.prohibit_scripts = true;
 | 
					    //tunables.prohibit_scripts = true;
 | 
				
			||||||
    res.json(tunables);
 | 
					    res.json(tunables);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					 | 
				
			||||||
export { tunablesController };
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -146,7 +146,8 @@ const focusUpgradeSchema = new Schema<IFocusUpgrade>(
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        ItemType: String,
 | 
					        ItemType: String,
 | 
				
			||||||
        Level: Number,
 | 
					        Level: Number,
 | 
				
			||||||
        IsUniversal: Boolean
 | 
					        IsUniversal: Boolean,
 | 
				
			||||||
 | 
					        IsActive: Number
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    { _id: false }
 | 
					    { _id: false }
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
@ -1542,6 +1543,8 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
 | 
				
			|||||||
        FocusAbility: String,
 | 
					        FocusAbility: String,
 | 
				
			||||||
        //The treeways of the Focus school.(Active and passive Ability)
 | 
					        //The treeways of the Focus school.(Active and passive Ability)
 | 
				
			||||||
        FocusUpgrades: [focusUpgradeSchema],
 | 
					        FocusUpgrades: [focusUpgradeSchema],
 | 
				
			||||||
 | 
					        //Focus 2.0 Pool
 | 
				
			||||||
 | 
					        FocusCapacity: Number,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        //Achievement
 | 
					        //Achievement
 | 
				
			||||||
        ChallengeProgress: [challengeProgressSchema],
 | 
					        ChallengeProgress: [challengeProgressSchema],
 | 
				
			||||||
 | 
				
			|||||||
@ -35,7 +35,8 @@ import type {
 | 
				
			|||||||
    IVoidTrader,
 | 
					    IVoidTrader,
 | 
				
			||||||
    IVoidTraderOffer,
 | 
					    IVoidTraderOffer,
 | 
				
			||||||
    IWorldState,
 | 
					    IWorldState,
 | 
				
			||||||
    TCircuitGameMode
 | 
					    TCircuitGameMode,
 | 
				
			||||||
 | 
					    IFlashSale
 | 
				
			||||||
} from "../types/worldStateTypes.ts";
 | 
					} from "../types/worldStateTypes.ts";
 | 
				
			||||||
import { toMongoDate, toOid, version_compare } from "../helpers/inventoryHelpers.ts";
 | 
					import { toMongoDate, toOid, version_compare } from "../helpers/inventoryHelpers.ts";
 | 
				
			||||||
import { logger } from "../utils/logger.ts";
 | 
					import { logger } from "../utils/logger.ts";
 | 
				
			||||||
@ -1580,21 +1581,16 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (config.worldState?.qtccAlerts) {
 | 
					    if (config.worldState?.qtccAlerts) {
 | 
				
			||||||
 | 
					        const activationTimeStamp = "1759327200000";
 | 
				
			||||||
 | 
					        const expiryTimeStamp = "2000000000000";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        worldState.Alerts.push(
 | 
					        worldState.Alerts.push(
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                _id: {
 | 
					                _id: {
 | 
				
			||||||
                    $oid: "68dc23c42e9d3acfa708ff3b"
 | 
					                    $oid: "68dc23c42e9d3acfa708ff3b"
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
                Activation: {
 | 
					                Activation: { $date: { $numberLong: activationTimeStamp } },
 | 
				
			||||||
                    $date: {
 | 
					                Expiry: { $date: { $numberLong: expiryTimeStamp } },
 | 
				
			||||||
                        $numberLong: "1759327200000"
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                },
 | 
					 | 
				
			||||||
                Expiry: {
 | 
					 | 
				
			||||||
                    $date: {
 | 
					 | 
				
			||||||
                        $numberLong: "2000000000000"
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                },
 | 
					 | 
				
			||||||
                MissionInfo: {
 | 
					                MissionInfo: {
 | 
				
			||||||
                    location: "SolNode123",
 | 
					                    location: "SolNode123",
 | 
				
			||||||
                    missionType: "MT_SURVIVAL",
 | 
					                    missionType: "MT_SURVIVAL",
 | 
				
			||||||
@ -1618,16 +1614,8 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
 | 
				
			|||||||
                _id: {
 | 
					                _id: {
 | 
				
			||||||
                    $oid: "68dc2466e298b4f04206687a"
 | 
					                    $oid: "68dc2466e298b4f04206687a"
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
                Activation: {
 | 
					                Activation: { $date: { $numberLong: activationTimeStamp } },
 | 
				
			||||||
                    $date: {
 | 
					                Expiry: { $date: { $numberLong: expiryTimeStamp } },
 | 
				
			||||||
                        $numberLong: "1759327200000"
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                },
 | 
					 | 
				
			||||||
                Expiry: {
 | 
					 | 
				
			||||||
                    $date: {
 | 
					 | 
				
			||||||
                        $numberLong: "2000000000000"
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                },
 | 
					 | 
				
			||||||
                MissionInfo: {
 | 
					                MissionInfo: {
 | 
				
			||||||
                    location: "SolNode149",
 | 
					                    location: "SolNode149",
 | 
				
			||||||
                    missionType: "MT_DEFENSE",
 | 
					                    missionType: "MT_DEFENSE",
 | 
				
			||||||
@ -1651,16 +1639,8 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
 | 
				
			|||||||
                _id: {
 | 
					                _id: {
 | 
				
			||||||
                    $oid: "68dc26865e7cb56b820b4252"
 | 
					                    $oid: "68dc26865e7cb56b820b4252"
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
                Activation: {
 | 
					                Activation: { $date: { $numberLong: activationTimeStamp } },
 | 
				
			||||||
                    $date: {
 | 
					                Expiry: { $date: { $numberLong: expiryTimeStamp } },
 | 
				
			||||||
                        $numberLong: "1759327200000"
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                },
 | 
					 | 
				
			||||||
                Expiry: {
 | 
					 | 
				
			||||||
                    $date: {
 | 
					 | 
				
			||||||
                        $numberLong: "2000000000000"
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                },
 | 
					 | 
				
			||||||
                MissionInfo: {
 | 
					                MissionInfo: {
 | 
				
			||||||
                    location: "SolNode39",
 | 
					                    location: "SolNode39",
 | 
				
			||||||
                    missionType: "MT_EXCAVATE",
 | 
					                    missionType: "MT_EXCAVATE",
 | 
				
			||||||
@ -1681,6 +1661,72 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
 | 
				
			|||||||
                ForceUnlock: true
 | 
					                ForceUnlock: true
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const storeItems: (Partial<IFlashSale> & { TypeName: string })[] = [
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Types/StoreItems/AvatarImages/ImageConquera2021D", RegularOverride: 1 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Operator/Tattoos/TattooTennoI", RegularOverride: 1 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Operator/Tattoos/TattooTennoH", RegularOverride: 1 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Clan/QTCC2024EmblemItem", RegularOverride: 1 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Types/Items/ShipDecos/Conquera2024Display", RegularOverride: 1 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Types/StoreItems/AvatarImages/AvatarImageConqueraGlyphVII", RegularOverride: 1 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Types/StoreItems/AvatarImages/AvatarImageConqueraGlyphVI", RegularOverride: 1 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Interface/Graphics/CustomUI/ConqueraStyle", RegularOverride: 1 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Interface/Graphics/CustomUI/Backgrounds/ConqueraBackground", RegularOverride: 1 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Types/Items/ShipDecos/Conquera2021Deco", RegularOverride: 1 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Types/StoreItems/AvatarImages/ImageConquera2022A", RegularOverride: 1 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Types/StoreItems/AvatarImages/ImageConquera2021B", RegularOverride: 1 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Types/StoreItems/AvatarImages/ImageConquera2021A", RegularOverride: 1 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Scarves/TnCharityRibbonSyandana", RegularOverride: 1 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Types/StoreItems/AvatarImages/ImageConquera2021C", RegularOverride: 1 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Types/Items/ShipDecos/Venus/Conquera2023CommunityDisplay", RegularOverride: 1 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Types/StoreItems/AvatarImages/AvatarImageConqueraGlyphUpdated", RegularOverride: 1 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Types/StoreItems/AvatarImages/ImageConquera", RegularOverride: 1 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Sigils/QTCC2023ConqueraSigil", RegularOverride: 1 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Sigils/ConqueraSigil", RegularOverride: 1 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Effects/Conquera2022Ephemera", RegularOverride: 1 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Effects/ConqueraEphemera", RegularOverride: 1 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Armor/TnCharityRibbonArmor/ConqueraArmorL", RegularOverride: 1 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Armor/TnCharityRibbonArmor/ConqueraArmorA", RegularOverride: 1 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Armor/TnCharityRibbonArmor/ConqueraChestRibbon", RegularOverride: 1 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Types/Items/ShipDecos/Plushies/PlushyProtectorStalker", PremiumOverride: 35 }
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        worldState.FlashSales.push(
 | 
				
			||||||
 | 
					            ...storeItems.map(item => ({
 | 
				
			||||||
 | 
					                ...{
 | 
				
			||||||
 | 
					                    StartDate: { $date: { $numberLong: activationTimeStamp } },
 | 
				
			||||||
 | 
					                    EndDate: { $date: { $numberLong: expiryTimeStamp } },
 | 
				
			||||||
 | 
					                    ProductExpiryOverride: { $date: { $numberLong: expiryTimeStamp } },
 | 
				
			||||||
 | 
					                    ShowInMarket: item.ShowInMarket ?? true,
 | 
				
			||||||
 | 
					                    HideFromMarket: item.HideFromMarket ?? false,
 | 
				
			||||||
 | 
					                    SupporterPack: item.SupporterPack ?? false,
 | 
				
			||||||
 | 
					                    Discount: item.Discount ?? 0,
 | 
				
			||||||
 | 
					                    BogoBuy: item.BogoBuy ?? 0,
 | 
				
			||||||
 | 
					                    BogoGet: item.BogoGet ?? 0,
 | 
				
			||||||
 | 
					                    RegularOverride: item.RegularOverride ?? 0,
 | 
				
			||||||
 | 
					                    PremiumOverride: item.PremiumOverride ?? 0
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                ...item
 | 
				
			||||||
 | 
					            }))
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const seasonalItems = storeItems.map(item => item.TypeName);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const seasonalCategory = worldState.InGameMarket.LandingPage.Categories.find(
 | 
				
			||||||
 | 
					            c => c.CategoryName == "COMMUNITY"
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        if (seasonalCategory) {
 | 
				
			||||||
 | 
					            seasonalCategory.Items ??= [];
 | 
				
			||||||
 | 
					            seasonalCategory.Items.push(...seasonalItems);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            worldState.InGameMarket.LandingPage.Categories.push({
 | 
				
			||||||
 | 
					                CategoryName: "COMMUNITY",
 | 
				
			||||||
 | 
					                Name: "/Lotus/Language/Store/CommunityCategoryTitle",
 | 
				
			||||||
 | 
					                Icon: "community",
 | 
				
			||||||
 | 
					                AddToMenu: true,
 | 
				
			||||||
 | 
					                Items: seasonalItems
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const isFebruary = date.getUTCMonth() == 1;
 | 
					    const isFebruary = date.getUTCMonth() == 1;
 | 
				
			||||||
@ -2048,82 +2094,39 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
 | 
				
			|||||||
            NightLevel: "/Lotus/Levels/GrineerBeach/GrineerBeachEventNight.level"
 | 
					            NightLevel: "/Lotus/Levels/GrineerBeach/GrineerBeachEventNight.level"
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const baseStoreItem = {
 | 
					        const storeItems: (Partial<IFlashSale> & { TypeName: string })[] = [
 | 
				
			||||||
            ShowInMarket: true,
 | 
					            { TypeName: "/Lotus/Types/StoreItems/Packages/WaterFightNoggleBundle", PremiumOverride: 240 },
 | 
				
			||||||
            HideFromMarket: false,
 | 
					            { TypeName: "/Lotus/Types/Items/ShipDecos/Events/WFBeastMasterBobbleHead", PremiumOverride: 35 },
 | 
				
			||||||
            SupporterPack: false,
 | 
					            { TypeName: "/Lotus/Types/Items/ShipDecos/Events/WFChargerBobbleHead", PremiumOverride: 35 },
 | 
				
			||||||
            Discount: 0,
 | 
					            { TypeName: "/Lotus/Types/Items/ShipDecos/Events/WFEngineerBobbleHead", PremiumOverride: 35 },
 | 
				
			||||||
            BogoBuy: 0,
 | 
					            { TypeName: "/Lotus/Types/Items/ShipDecos/Events/WFGruntBobbleHead", PremiumOverride: 35 },
 | 
				
			||||||
            BogoGet: 0,
 | 
					            { TypeName: "/Lotus/Types/StoreItems/AvatarImages/ImagePopsicleGrineerPurple", RegularOverride: 1 },
 | 
				
			||||||
            StartDate: { $date: { $numberLong: activationTimeStamp } },
 | 
					            { TypeName: "/Lotus/Types/Items/ShipDecos/Events/WFHealerBobbleHead", PremiumOverride: 35 },
 | 
				
			||||||
            EndDate: { $date: { $numberLong: expiryTimeStamp } },
 | 
					            { TypeName: "/Lotus/Types/Items/ShipDecos/Events/WFHeavyBobbleHead", PremiumOverride: 35 },
 | 
				
			||||||
            ProductExpiryOverride: { $date: { $numberLong: expiryTimeStamp } }
 | 
					            { TypeName: "/Lotus/Types/Items/ShipDecos/Events/WFHellionBobbleHead", PremiumOverride: 35 },
 | 
				
			||||||
        };
 | 
					            { TypeName: "/Lotus/Types/Items/ShipDecos/Events/WFSniperBobbleHead", PremiumOverride: 35 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Types/Items/ShipDecos/Events/WFTankBobbleHead", PremiumOverride: 35 },
 | 
				
			||||||
        const storeItems = [
 | 
					            { TypeName: "/Lotus/Types/StoreItems/SuitCustomizations/ColourPickerRollers", PremiumOverride: 75 }
 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                TypeName: "/Lotus/Types/StoreItems/Packages/WaterFightNoggleBundle",
 | 
					 | 
				
			||||||
                PremiumOverride: 240,
 | 
					 | 
				
			||||||
                RegularOverride: 0
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                TypeName: "/Lotus/Types/Items/ShipDecos/Events/WFBeastMasterBobbleHead",
 | 
					 | 
				
			||||||
                PremiumOverride: 35,
 | 
					 | 
				
			||||||
                RegularOverride: 0
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                TypeName: "/Lotus/Types/Items/ShipDecos/Events/WFChargerBobbleHead",
 | 
					 | 
				
			||||||
                PremiumOverride: 35,
 | 
					 | 
				
			||||||
                RegularOverride: 0
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                TypeName: "/Lotus/Types/Items/ShipDecos/Events/WFEngineerBobbleHead",
 | 
					 | 
				
			||||||
                PremiumOverride: 35,
 | 
					 | 
				
			||||||
                RegularOverride: 0
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                TypeName: "/Lotus/Types/Items/ShipDecos/Events/WFGruntBobbleHead",
 | 
					 | 
				
			||||||
                PremiumOverride: 35,
 | 
					 | 
				
			||||||
                RegularOverride: 0
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                TypeName: "/Lotus/Types/StoreItems/AvatarImages/ImagePopsicleGrineerPurple",
 | 
					 | 
				
			||||||
                PremiumOverride: 0,
 | 
					 | 
				
			||||||
                RegularOverride: 1
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                TypeName: "/Lotus/Types/Items/ShipDecos/Events/WFHealerBobbleHead",
 | 
					 | 
				
			||||||
                PremiumOverride: 35,
 | 
					 | 
				
			||||||
                RegularOverride: 0
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                TypeName: "/Lotus/Types/Items/ShipDecos/Events/WFHeavyBobbleHead",
 | 
					 | 
				
			||||||
                PremiumOverride: 35,
 | 
					 | 
				
			||||||
                RegularOverride: 0
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                TypeName: "/Lotus/Types/Items/ShipDecos/Events/WFHellionBobbleHead",
 | 
					 | 
				
			||||||
                PremiumOverride: 35,
 | 
					 | 
				
			||||||
                RegularOverride: 0
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                TypeName: "/Lotus/Types/Items/ShipDecos/Events/WFSniperBobbleHead",
 | 
					 | 
				
			||||||
                PremiumOverride: 35,
 | 
					 | 
				
			||||||
                RegularOverride: 0
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                TypeName: "/Lotus/Types/Items/ShipDecos/Events/WFTankBobbleHead",
 | 
					 | 
				
			||||||
                PremiumOverride: 35,
 | 
					 | 
				
			||||||
                RegularOverride: 0
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                TypeName: "/Lotus/Types/StoreItems/SuitCustomizations/ColourPickerRollers",
 | 
					 | 
				
			||||||
                PremiumOverride: 75,
 | 
					 | 
				
			||||||
                RegularOverride: 0
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        ];
 | 
					        ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        worldState.FlashSales.push(...storeItems.map(item => ({ ...baseStoreItem, ...item })));
 | 
					        worldState.FlashSales.push(
 | 
				
			||||||
 | 
					            ...storeItems.map(item => ({
 | 
				
			||||||
 | 
					                ...{
 | 
				
			||||||
 | 
					                    StartDate: { $date: { $numberLong: activationTimeStamp } },
 | 
				
			||||||
 | 
					                    EndDate: { $date: { $numberLong: expiryTimeStamp } },
 | 
				
			||||||
 | 
					                    ProductExpiryOverride: { $date: { $numberLong: expiryTimeStamp } },
 | 
				
			||||||
 | 
					                    ShowInMarket: item.ShowInMarket ?? true,
 | 
				
			||||||
 | 
					                    HideFromMarket: item.HideFromMarket ?? false,
 | 
				
			||||||
 | 
					                    SupporterPack: item.SupporterPack ?? false,
 | 
				
			||||||
 | 
					                    Discount: item.Discount ?? 0,
 | 
				
			||||||
 | 
					                    BogoBuy: item.BogoBuy ?? 0,
 | 
				
			||||||
 | 
					                    BogoGet: item.BogoGet ?? 0,
 | 
				
			||||||
 | 
					                    RegularOverride: item.RegularOverride ?? 0,
 | 
				
			||||||
 | 
					                    PremiumOverride: item.PremiumOverride ?? 0
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                ...item
 | 
				
			||||||
 | 
					            }))
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const seasonalItems = storeItems.map(item => item.TypeName);
 | 
					        const seasonalItems = storeItems.map(item => item.TypeName);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -2762,22 +2765,18 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    const isOctober = date.getUTCMonth() == 9; // October = month index 9
 | 
					    const isOctober = date.getUTCMonth() == 9; // October = month index 9
 | 
				
			||||||
    if (config.worldState?.naberusNightsOverride ?? isOctober) {
 | 
					    if (config.worldState?.naberusNightsOverride ?? isOctober) {
 | 
				
			||||||
 | 
					        const activationTimeStamp = config.worldState?.naberusNightsOverride
 | 
				
			||||||
 | 
					            ? "1727881200000"
 | 
				
			||||||
 | 
					            : Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), 1).toString();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const expiryTimeStamp = config.worldState?.naberusNightsOverride
 | 
				
			||||||
 | 
					            ? "2000000000000"
 | 
				
			||||||
 | 
					            : Date.UTC(date.getUTCFullYear(), date.getUTCMonth() + 1, 1).toString();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        worldState.Goals.push({
 | 
					        worldState.Goals.push({
 | 
				
			||||||
            _id: { $oid: "66fd602de1778d583419e8e7" },
 | 
					            _id: { $oid: "66fd602de1778d583419e8e7" },
 | 
				
			||||||
            Activation: {
 | 
					            Activation: { $date: { $numberLong: activationTimeStamp } },
 | 
				
			||||||
                $date: {
 | 
					            Expiry: { $date: { $numberLong: expiryTimeStamp } },
 | 
				
			||||||
                    $numberLong: config.worldState?.naberusNightsOverride
 | 
					 | 
				
			||||||
                        ? "1727881200000"
 | 
					 | 
				
			||||||
                        : Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), 1).toString()
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            Expiry: {
 | 
					 | 
				
			||||||
                $date: {
 | 
					 | 
				
			||||||
                    $numberLong: config.worldState?.naberusNightsOverride
 | 
					 | 
				
			||||||
                        ? "2000000000000"
 | 
					 | 
				
			||||||
                        : Date.UTC(date.getUTCFullYear(), date.getUTCMonth() + 1, 1).toString()
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            Count: 0,
 | 
					            Count: 0,
 | 
				
			||||||
            Goal: 0,
 | 
					            Goal: 0,
 | 
				
			||||||
            Success: 0,
 | 
					            Success: 0,
 | 
				
			||||||
@ -2788,6 +2787,181 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
 | 
				
			|||||||
            Tag: "DeimosHalloween",
 | 
					            Tag: "DeimosHalloween",
 | 
				
			||||||
            Node: "DeimosHub"
 | 
					            Node: "DeimosHub"
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const storeItems: (Partial<IFlashSale> & { TypeName: string })[] = [
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Types/StoreItems/Packages/Halloween2023GlyphBundleA", PremiumOverride: 65 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Types/StoreItems/Packages/Halloween2021GlyphBundle", PremiumOverride: 65 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Types/StoreItems/Packages/Halloween2019GlyphBundleA", PremiumOverride: 65 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Types/StoreItems/Packages/Halloween2019GlyphBundleB", PremiumOverride: 65 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Types/StoreItems/Packages/HalloweenGlyphBundle", PremiumOverride: 65 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Types/StoreItems/Packages/Halloween2023ArmorBundle", PremiumOverride: 125 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Types/StoreItems/Packages/HalloweenCrpCircArmorPack", PremiumOverride: 100 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Types/StoreItems/Packages/HalloweenScarfBundleB", PremiumOverride: 80 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Types/StoreItems/Packages/HalloweenSkinPack", PremiumOverride: 175 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Types/StoreItems/Packages/HalloweenShipSkinBundle", PremiumOverride: 80 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Types/StoreItems/Packages/HalloweenSkinPackC", PremiumOverride: 175 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Types/StoreItems/Packages/HalloweenSkinPackII", PremiumOverride: 145 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Types/StoreItems/Packages/HalloweenScarfBundle", PremiumOverride: 130 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Types/StoreItems/Packages/AcolyteNoggleBundle", PremiumOverride: 160 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Types/Items/ShipDecos/AcolyteAreaCasterBobbleHead", PremiumOverride: 35 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Types/Items/ShipDecos/AcolyteDuellistBobbleHead", PremiumOverride: 35 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Types/Items/ShipDecos/AcolyteControlBobbleHead", PremiumOverride: 35 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Types/Items/ShipDecos/AcolyteHeavyBobbleHead", PremiumOverride: 35 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Types/Items/ShipDecos/AcolyteRogueBobbleHead", PremiumOverride: 35 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Types/Items/ShipDecos/AcolyteStrikerBobbleHead", PremiumOverride: 35 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Types/StoreItems/SuitCustomizations/ColourPickerHalloweenItemA", RegularOverride: 1 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Armor/Halloween2014Wings/Halloween2014ArmArmor", PremiumOverride: 50 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Festivities/PumpkinHead", RegularOverride: 1 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Halloween/HalloweenRegorAxeShield", PremiumOverride: 20 },
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                TypeName: "/Lotus/Types/StoreItems/AvatarImages/Seasonal/Halloween2019CheshireKavat",
 | 
				
			||||||
 | 
					                PremiumOverride: 20
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Halloween/HalloweenAkvasto", PremiumOverride: 20 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Halloween/HalloweenAngstrum", PremiumOverride: 20 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Halloween/HalloweenBoltor", PremiumOverride: 20 },
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                TypeName: "/Lotus/Types/StoreItems/AvatarImages/Seasonal/Halloween2019GhostChibiWisp",
 | 
				
			||||||
 | 
					                PremiumOverride: 20
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Halloween/HalloweenBraton", PremiumOverride: 20 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Types/StoreItems/AvatarImages/AvatarImageHalloween2016A", PremiumOverride: 20 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Types/StoreItems/AvatarImages/AvatarImageHalloween2016C", PremiumOverride: 20 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Types/StoreItems/AvatarImages/AvatarImageHalloween2016B", PremiumOverride: 20 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Halloween/HalloweenBuzlok", PremiumOverride: 20 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Types/StoreItems/AvatarImages/AvatarImageHalloween2016D", PremiumOverride: 20 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Types/StoreItems/AvatarImages/Seasonal/Halloween2019CreepyClem", PremiumOverride: 20 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Halloween/HalloweenDaikyu", PremiumOverride: 20 },
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                TypeName: "/Lotus/Types/StoreItems/AvatarImages/Seasonal/AvatarImageHalloween2021Dethcube",
 | 
				
			||||||
 | 
					                PremiumOverride: 20
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Halloween/HalloweenDragonNikana", PremiumOverride: 20 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Halloween/HalloweenDualZoren", PremiumOverride: 20 },
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                TypeName: "/Lotus/Types/StoreItems/AvatarImages/Seasonal/Halloween2019FrankenCorpus",
 | 
				
			||||||
 | 
					                PremiumOverride: 20
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                TypeName: "/Lotus/Types/StoreItems/AvatarImages/Seasonal/AvatarImageHalloween2021Grineer",
 | 
				
			||||||
 | 
					                PremiumOverride: 20
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Halloween/HalloweenGlaive", PremiumOverride: 20 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Halloween/HalloweenGalatine", PremiumOverride: 20 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Halloween/HalloweenGrakata", PremiumOverride: 20 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Halloween/HalloweenGorgon", PremiumOverride: 20 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Halloween/HalloweenGlaxion", PremiumOverride: 20 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Halloween/HalloweenTwinGremlins", PremiumOverride: 20 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Halloween/HalloweenGrinlok", PremiumOverride: 20 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Scarves/HalloweenFireFlyScarf", PremiumOverride: 90 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Halloween/HalloweenImperator", PremiumOverride: 20 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Halloween/HalloweenKronen", PremiumOverride: 20 },
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                TypeName: "/Lotus/Types/StoreItems/AvatarImages/Seasonal/AvatarImageHalloween2021Lotus",
 | 
				
			||||||
 | 
					                PremiumOverride: 20
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Halloween/HalloweenJatKittag", PremiumOverride: 20 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Scarves/HalloweenKyropteraScarf", PremiumOverride: 50 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Halloween/HalloweenKunai", PremiumOverride: 20 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Liset/LisetSkinHalloween", PremiumOverride: 50 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Liset/LisetInsectSkinHalloween", PremiumOverride: 50 },
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                TypeName: "/Lotus/Types/StoreItems/AvatarImages/Seasonal/AvatarImageChillingGlyphFour",
 | 
				
			||||||
 | 
					                PremiumOverride: 20
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Halloween/HalloweenMarelok", PremiumOverride: 20 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Halloween/HalloweenNikana", PremiumOverride: 20 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Halloween/HalloweenNukor", PremiumOverride: 20 },
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                TypeName: "/Lotus/Types/StoreItems/AvatarImages/Seasonal/AvatarImageHalloween2021Loid",
 | 
				
			||||||
 | 
					                PremiumOverride: 20
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Halloween/HalloweenOpticor", PremiumOverride: 20 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Halloween/HalloweenOrthos", PremiumOverride: 20 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Halloween/HalloweenParis", PremiumOverride: 20 },
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                TypeName: "/Lotus/Types/StoreItems/AvatarImages/Seasonal/AvatarImageChillingGlyphTwo",
 | 
				
			||||||
 | 
					                PremiumOverride: 20
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Armor/CrpCircleArmour/HalloweenCrpCircC", PremiumOverride: 45 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Armor/CrpCircleArmour/HalloweenCrpCircA", PremiumOverride: 50 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Armor/CrpCircleArmour/HalloweenCrpCircL", PremiumOverride: 35 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Halloween/HalloweenScindo", PremiumOverride: 20 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Types/StoreItems/AvatarImages/Seasonal/Halloween2019GhoulGrave", PremiumOverride: 20 },
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                TypeName: "/Lotus/Types/StoreItems/AvatarImages/Seasonal/AvatarImageHalloween2021Pumpkin",
 | 
				
			||||||
 | 
					                PremiumOverride: 20
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Halloween/HalloweenSarpa", PremiumOverride: 20 },
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                TypeName: "/Lotus/Types/StoreItems/AvatarImages/Seasonal/AvatarImageChillingGlyphThree",
 | 
				
			||||||
 | 
					                PremiumOverride: 20
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Halloween/HalloweenSilvaAndAegis", PremiumOverride: 20 },
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                TypeName: "/Lotus/Types/StoreItems/AvatarImages/Seasonal/AvatarImageChillingGlyphOne",
 | 
				
			||||||
 | 
					                PremiumOverride: 20
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Halloween/HalloweenSoma", PremiumOverride: 20 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Halloween/HalloweenSkana", PremiumOverride: 20 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Types/StoreItems/AvatarImages/Seasonal/Halloween2019SlimeLoki", PremiumOverride: 20 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Halloween/HalloweenSobek", PremiumOverride: 20 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Halloween/HalloweenSonicor", PremiumOverride: 20 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Halloween/HalloweenSimulor", PremiumOverride: 20 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Halloween/HalloweenTonkor", PremiumOverride: 20 },
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                TypeName: "/Lotus/Types/StoreItems/AvatarImages/Seasonal/Halloween2019TrickOrBalas",
 | 
				
			||||||
 | 
					                PremiumOverride: 20
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Halloween/HalloweenSpira", PremiumOverride: 20 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Halloween/HalloweenStradavar", PremiumOverride: 20 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Halloween/HalloweenTwinGrakatas", PremiumOverride: 20 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Halloween/HalloweenArchSword", PremiumOverride: 20 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Halloween/HalloweenLato", PremiumOverride: 20 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Types/StoreItems/AvatarImages/Seasonal/Halloween2019Werefested", PremiumOverride: 20 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Scarves/HalloweenErosionCape", PremiumOverride: 50 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Halloween/HalloweenVasto", PremiumOverride: 20 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Halloween/HalloweenDarkSplitSword", PremiumOverride: 20 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Halloween/HalloweenDarkDagger", PremiumOverride: 20 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Scarves/HalloweenGrnBannerScarf", PremiumOverride: 75 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Upgrades/Skins/Halloween/HalloweenAmprex", PremiumOverride: 20 },
 | 
				
			||||||
 | 
					            { TypeName: "/Lotus/Types/StoreItems/Packages/HalloweenSkinPackD", PremiumOverride: 180 }
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        worldState.FlashSales.push(
 | 
				
			||||||
 | 
					            ...storeItems.map(item => ({
 | 
				
			||||||
 | 
					                ...{
 | 
				
			||||||
 | 
					                    StartDate: { $date: { $numberLong: activationTimeStamp } },
 | 
				
			||||||
 | 
					                    EndDate: { $date: { $numberLong: expiryTimeStamp } },
 | 
				
			||||||
 | 
					                    ProductExpiryOverride: { $date: { $numberLong: expiryTimeStamp } },
 | 
				
			||||||
 | 
					                    ShowInMarket: item.ShowInMarket ?? true,
 | 
				
			||||||
 | 
					                    HideFromMarket: item.HideFromMarket ?? false,
 | 
				
			||||||
 | 
					                    SupporterPack: item.SupporterPack ?? false,
 | 
				
			||||||
 | 
					                    Discount: item.Discount ?? 0,
 | 
				
			||||||
 | 
					                    BogoBuy: item.BogoBuy ?? 0,
 | 
				
			||||||
 | 
					                    BogoGet: item.BogoGet ?? 0,
 | 
				
			||||||
 | 
					                    RegularOverride: item.RegularOverride ?? 0,
 | 
				
			||||||
 | 
					                    PremiumOverride: item.PremiumOverride ?? 0
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                ...item
 | 
				
			||||||
 | 
					            }))
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const seasonalItems = storeItems.map(item => item.TypeName);
 | 
				
			||||||
 | 
					        const seasonalCategory = worldState.InGameMarket.LandingPage.Categories.find(c => c.CategoryName == "SEASONAL");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (seasonalCategory) {
 | 
				
			||||||
 | 
					            seasonalCategory.Items ??= [];
 | 
				
			||||||
 | 
					            seasonalCategory.Items.push(...seasonalItems);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            worldState.InGameMarket.LandingPage.Categories.push({
 | 
				
			||||||
 | 
					                CategoryName: "SEASONAL",
 | 
				
			||||||
 | 
					                Name: "/Lotus/Language/Store/SeasonalCategoryTitle",
 | 
				
			||||||
 | 
					                Icon: "seasonal",
 | 
				
			||||||
 | 
					                AddToMenu: true,
 | 
				
			||||||
 | 
					                Items: seasonalItems
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (config.worldState?.bellyOfTheBeast) {
 | 
					    if (config.worldState?.bellyOfTheBeast) {
 | 
				
			||||||
 | 
				
			|||||||
@ -8,6 +8,7 @@ import type { IDatabaseAccountJson } from "../types/loginTypes.ts";
 | 
				
			|||||||
import type { HydratedDocument } from "mongoose";
 | 
					import type { HydratedDocument } from "mongoose";
 | 
				
			||||||
import { logError, logger } from "../utils/logger.ts";
 | 
					import { logError, logger } from "../utils/logger.ts";
 | 
				
			||||||
import type { Request } from "express";
 | 
					import type { Request } from "express";
 | 
				
			||||||
 | 
					import type { ITunables } from "../types/bootstrapperTypes.ts";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let wsServer: WebSocketServer | undefined;
 | 
					let wsServer: WebSocketServer | undefined;
 | 
				
			||||||
let wssServer: WebSocketServer | undefined;
 | 
					let wssServer: WebSocketServer | undefined;
 | 
				
			||||||
@ -89,8 +90,9 @@ interface IWsMsgToClient {
 | 
				
			|||||||
    logged_out?: boolean;
 | 
					    logged_out?: boolean;
 | 
				
			||||||
    have_game_ws?: boolean;
 | 
					    have_game_ws?: boolean;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // to game
 | 
					    // to game/bootstrapper (https://openwf.io/bootstrapper-manual)
 | 
				
			||||||
    sync_inventory?: boolean;
 | 
					    sync_inventory?: boolean;
 | 
				
			||||||
 | 
					    tunables?: ITunables;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const wsOnConnect = (ws: WebSocket, req: http.IncomingMessage): void => {
 | 
					const wsOnConnect = (ws: WebSocket, req: http.IncomingMessage): void => {
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										9
									
								
								src/types/bootstrapperTypes.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/types/bootstrapperTypes.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					// This is specific to the OpenWF Bootstrapper: https://openwf.io/bootstrapper-manual
 | 
				
			||||||
 | 
					export interface ITunables {
 | 
				
			||||||
 | 
					    token?: string;
 | 
				
			||||||
 | 
					    prohibit_skip_mission_start_timer?: boolean;
 | 
				
			||||||
 | 
					    prohibit_fov_override?: boolean;
 | 
				
			||||||
 | 
					    prohibit_freecam?: boolean;
 | 
				
			||||||
 | 
					    prohibit_teleport?: boolean;
 | 
				
			||||||
 | 
					    prohibit_scripts?: boolean;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -340,6 +340,7 @@ export interface IInventoryClient extends IDailyAffiliations, InventoryClientEqu
 | 
				
			|||||||
    EmailItems: ITypeCount[];
 | 
					    EmailItems: ITypeCount[];
 | 
				
			||||||
    CompletedSyndicates: string[];
 | 
					    CompletedSyndicates: string[];
 | 
				
			||||||
    FocusXP?: IFocusXP;
 | 
					    FocusXP?: IFocusXP;
 | 
				
			||||||
 | 
					    FocusCapacity?: number;
 | 
				
			||||||
    Wishlist: string[];
 | 
					    Wishlist: string[];
 | 
				
			||||||
    Alignment?: IAlignment;
 | 
					    Alignment?: IAlignment;
 | 
				
			||||||
    CompletedSorties: string[];
 | 
					    CompletedSorties: string[];
 | 
				
			||||||
@ -638,6 +639,7 @@ export interface IFocusUpgrade {
 | 
				
			|||||||
    ItemType: string;
 | 
					    ItemType: string;
 | 
				
			||||||
    Level?: number;
 | 
					    Level?: number;
 | 
				
			||||||
    IsUniversal?: boolean;
 | 
					    IsUniversal?: boolean;
 | 
				
			||||||
 | 
					    IsActive?: number; // Focus 2.0
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface IFocusXP {
 | 
					export interface IFocusXP {
 | 
				
			||||||
 | 
				
			|||||||
@ -3276,13 +3276,13 @@ function unlockFocusSchool(upgradeType) {
 | 
				
			|||||||
    return new Promise(resolve => {
 | 
					    return new Promise(resolve => {
 | 
				
			||||||
        // Deselect current FocusAbility so we will be able to unlock the way for free
 | 
					        // Deselect current FocusAbility so we will be able to unlock the way for free
 | 
				
			||||||
        $.post({
 | 
					        $.post({
 | 
				
			||||||
            url: "/api/focus.php?" + window.authz + "&op=5",
 | 
					            url: "/api/focus.php?" + window.authz + "&op=ActivateWay",
 | 
				
			||||||
            contentType: "text/plain",
 | 
					            contentType: "text/plain",
 | 
				
			||||||
            data: JSON.stringify({ FocusType: null })
 | 
					            data: JSON.stringify({ FocusType: null })
 | 
				
			||||||
        }).done(function () {
 | 
					        }).done(function () {
 | 
				
			||||||
            // Unlock the way now
 | 
					            // Unlock the way now
 | 
				
			||||||
            $.post({
 | 
					            $.post({
 | 
				
			||||||
                url: "/api/focus.php?" + window.authz + "&op=2",
 | 
					                url: "/api/focus.php?" + window.authz + "&op=UnlockWay",
 | 
				
			||||||
                contentType: "text/plain",
 | 
					                contentType: "text/plain",
 | 
				
			||||||
                data: JSON.stringify({
 | 
					                data: JSON.stringify({
 | 
				
			||||||
                    FocusType: upgradeType
 | 
					                    FocusType: upgradeType
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user