feat: galleon of ghouls #2280
@ -69,6 +69,7 @@
 | 
				
			|||||||
    "affinityBoost": false,
 | 
					    "affinityBoost": false,
 | 
				
			||||||
    "resourceBoost": false,
 | 
					    "resourceBoost": false,
 | 
				
			||||||
    "starDays": true,
 | 
					    "starDays": true,
 | 
				
			||||||
 | 
					    "galleonOfGhouls": 0,
 | 
				
			||||||
    "eidolonOverride": "",
 | 
					    "eidolonOverride": "",
 | 
				
			||||||
    "vallisOverride": "",
 | 
					    "vallisOverride": "",
 | 
				
			||||||
    "duviriOverride": "",
 | 
					    "duviriOverride": "",
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										8
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										8
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							@ -21,7 +21,7 @@
 | 
				
			|||||||
        "ncp": "^2.0.0",
 | 
					        "ncp": "^2.0.0",
 | 
				
			||||||
        "typescript": "^5.5",
 | 
					        "typescript": "^5.5",
 | 
				
			||||||
        "undici": "^7.10.0",
 | 
					        "undici": "^7.10.0",
 | 
				
			||||||
        "warframe-public-export-plus": "^0.5.69",
 | 
					        "warframe-public-export-plus": "^0.5.70",
 | 
				
			||||||
        "warframe-riven-info": "^0.1.2",
 | 
					        "warframe-riven-info": "^0.1.2",
 | 
				
			||||||
        "winston": "^3.17.0",
 | 
					        "winston": "^3.17.0",
 | 
				
			||||||
        "winston-daily-rotate-file": "^5.0.0",
 | 
					        "winston-daily-rotate-file": "^5.0.0",
 | 
				
			||||||
@ -3396,9 +3396,9 @@
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "node_modules/warframe-public-export-plus": {
 | 
					    "node_modules/warframe-public-export-plus": {
 | 
				
			||||||
      "version": "0.5.69",
 | 
					      "version": "0.5.70",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.69.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.70.tgz",
 | 
				
			||||||
      "integrity": "sha512-vTU1tUzqpihzpseUSJMrM82pYbCDZCfW40jXIi+Ol9B3a3Acz0DccfP7i4eoXf7Abahu4H/sjRt/nSHLNBvLHA=="
 | 
					      "integrity": "sha512-d5dQ/a0rakQnW9tl1HitST8439jDvEgMhkkntQIw7HmdM7s7mvIxvaYSl5wjlYawpUVfGyvGBdZVoAJ7kkQRWw=="
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "node_modules/warframe-riven-info": {
 | 
					    "node_modules/warframe-riven-info": {
 | 
				
			||||||
      "version": "0.1.2",
 | 
					      "version": "0.1.2",
 | 
				
			||||||
 | 
				
			|||||||
@ -33,7 +33,7 @@
 | 
				
			|||||||
    "ncp": "^2.0.0",
 | 
					    "ncp": "^2.0.0",
 | 
				
			||||||
    "typescript": "^5.5",
 | 
					    "typescript": "^5.5",
 | 
				
			||||||
    "undici": "^7.10.0",
 | 
					    "undici": "^7.10.0",
 | 
				
			||||||
    "warframe-public-export-plus": "^0.5.69",
 | 
					    "warframe-public-export-plus": "^0.5.70",
 | 
				
			||||||
    "warframe-riven-info": "^0.1.2",
 | 
					    "warframe-riven-info": "^0.1.2",
 | 
				
			||||||
    "winston": "^3.17.0",
 | 
					    "winston": "^3.17.0",
 | 
				
			||||||
    "winston-daily-rotate-file": "^5.0.0",
 | 
					    "winston-daily-rotate-file": "^5.0.0",
 | 
				
			||||||
 | 
				
			|||||||
@ -22,7 +22,8 @@ import { getNemesisManifest } from "@/src/helpers/nemesisHelpers";
 | 
				
			|||||||
import { getPersonalRooms } from "@/src/services/personalRoomsService";
 | 
					import { getPersonalRooms } from "@/src/services/personalRoomsService";
 | 
				
			||||||
import { IPersonalRoomsClient } from "@/src/types/personalRoomsTypes";
 | 
					import { IPersonalRoomsClient } from "@/src/types/personalRoomsTypes";
 | 
				
			||||||
import { Ship } from "@/src/models/shipModel";
 | 
					import { Ship } from "@/src/models/shipModel";
 | 
				
			||||||
import { toLegacyOid, version_compare } from "@/src/helpers/inventoryHelpers";
 | 
					import { toLegacyOid, toOid, version_compare } from "@/src/helpers/inventoryHelpers";
 | 
				
			||||||
 | 
					import { Inbox } from "@/src/models/inboxModel";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const inventoryController: RequestHandler = async (request, response) => {
 | 
					export const inventoryController: RequestHandler = async (request, response) => {
 | 
				
			||||||
    const account = await getAccountForRequest(request);
 | 
					    const account = await getAccountForRequest(request);
 | 
				
			||||||
@ -128,13 +129,21 @@ export const getInventoryResponse = async (
 | 
				
			|||||||
    xpBasedLevelCapDisabled: boolean,
 | 
					    xpBasedLevelCapDisabled: boolean,
 | 
				
			||||||
    buildLabel: string | undefined
 | 
					    buildLabel: string | undefined
 | 
				
			||||||
): Promise<IInventoryClient> => {
 | 
					): Promise<IInventoryClient> => {
 | 
				
			||||||
    const [inventoryWithLoadOutPresets, ships] = await Promise.all([
 | 
					    const [inventoryWithLoadOutPresets, ships, latestMessage] = await Promise.all([
 | 
				
			||||||
        inventory.populate<{ LoadOutPresets: ILoadoutDatabase }>("LoadOutPresets"),
 | 
					        inventory.populate<{ LoadOutPresets: ILoadoutDatabase }>("LoadOutPresets"),
 | 
				
			||||||
        Ship.find({ ShipOwnerId: inventory.accountOwnerId })
 | 
					        Ship.find({ ShipOwnerId: inventory.accountOwnerId }),
 | 
				
			||||||
 | 
					        Inbox.findOne({ ownerId: inventory.accountOwnerId }, "_id").sort({ date: -1 })
 | 
				
			||||||
    ]);
 | 
					    ]);
 | 
				
			||||||
    const inventoryResponse = inventoryWithLoadOutPresets.toJSON<IInventoryClient>();
 | 
					    const inventoryResponse = inventoryWithLoadOutPresets.toJSON<IInventoryClient>();
 | 
				
			||||||
    inventoryResponse.Ships = ships.map(x => x.toJSON<IShipInventory>());
 | 
					    inventoryResponse.Ships = ships.map(x => x.toJSON<IShipInventory>());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // In case mission inventory update added an inbox message, we need to send the Mailbox part so the client knows to refresh it.
 | 
				
			||||||
 | 
					    if (latestMessage) {
 | 
				
			||||||
 | 
					        inventoryResponse.Mailbox = {
 | 
				
			||||||
 | 
					            LastInboxId: toOid(latestMessage._id)
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (config.infiniteCredits) {
 | 
					    if (config.infiniteCredits) {
 | 
				
			||||||
        inventoryResponse.RegularCredits = 999999999;
 | 
					        inventoryResponse.RegularCredits = 999999999;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -21,13 +21,14 @@ import mongoose from "mongoose";
 | 
				
			|||||||
import { JSONStringify } from "json-with-bigint";
 | 
					import { JSONStringify } from "json-with-bigint";
 | 
				
			||||||
import { startWebServer } from "./services/webService";
 | 
					import { startWebServer } from "./services/webService";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { validateConfig } from "@/src/services/configWatcherService";
 | 
					import { syncConfigWithDatabase, validateConfig } from "@/src/services/configWatcherService";
 | 
				
			||||||
import { updateWorldStateCollections } from "./services/worldStateService";
 | 
					import { updateWorldStateCollections } from "./services/worldStateService";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Patch JSON.stringify to work flawlessly with Bigints.
 | 
					// Patch JSON.stringify to work flawlessly with Bigints.
 | 
				
			||||||
JSON.stringify = JSONStringify;
 | 
					JSON.stringify = JSONStringify;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
validateConfig();
 | 
					validateConfig();
 | 
				
			||||||
 | 
					syncConfigWithDatabase();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mongoose
 | 
					mongoose
 | 
				
			||||||
    .connect(config.mongodbUrl)
 | 
					    .connect(config.mongodbUrl)
 | 
				
			||||||
 | 
				
			|||||||
@ -27,11 +27,12 @@ export interface IMessage {
 | 
				
			|||||||
    icon?: string;
 | 
					    icon?: string;
 | 
				
			||||||
    highPriority?: boolean;
 | 
					    highPriority?: boolean;
 | 
				
			||||||
    lowPrioNewPlayers?: boolean;
 | 
					    lowPrioNewPlayers?: boolean;
 | 
				
			||||||
    startDate?: Date;
 | 
					    transmission?: string;
 | 
				
			||||||
    endDate?: Date;
 | 
					 | 
				
			||||||
    att?: string[];
 | 
					    att?: string[];
 | 
				
			||||||
    countedAtt?: ITypeCount[];
 | 
					    countedAtt?: ITypeCount[];
 | 
				
			||||||
    transmission?: string;
 | 
					    startDate?: Date;
 | 
				
			||||||
 | 
					    endDate?: Date;
 | 
				
			||||||
 | 
					    goalTag?: string;
 | 
				
			||||||
    CrossPlatform?: boolean;
 | 
					    CrossPlatform?: boolean;
 | 
				
			||||||
    arg?: Arg[];
 | 
					    arg?: Arg[];
 | 
				
			||||||
    gifts?: IGift[];
 | 
					    gifts?: IGift[];
 | 
				
			||||||
@ -107,6 +108,7 @@ const messageSchema = new Schema<IMessageDatabase>(
 | 
				
			|||||||
        lowPrioNewPlayers: Boolean,
 | 
					        lowPrioNewPlayers: Boolean,
 | 
				
			||||||
        startDate: Date,
 | 
					        startDate: Date,
 | 
				
			||||||
        endDate: Date,
 | 
					        endDate: Date,
 | 
				
			||||||
 | 
					        goalTag: String,
 | 
				
			||||||
        date: { type: Date, required: true },
 | 
					        date: { type: Date, required: true },
 | 
				
			||||||
        r: Boolean,
 | 
					        r: Boolean,
 | 
				
			||||||
        CrossPlatform: Boolean,
 | 
					        CrossPlatform: Boolean,
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,4 @@
 | 
				
			|||||||
import { Document, HydratedDocument, Model, Schema, Types, model } from "mongoose";
 | 
					import { Document, Model, Schema, Types, model } from "mongoose";
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
    IFlavourItem,
 | 
					    IFlavourItem,
 | 
				
			||||||
    IRawUpgrade,
 | 
					    IRawUpgrade,
 | 
				
			||||||
@ -7,7 +7,6 @@ import {
 | 
				
			|||||||
    IBooster,
 | 
					    IBooster,
 | 
				
			||||||
    IInventoryClient,
 | 
					    IInventoryClient,
 | 
				
			||||||
    ISlots,
 | 
					    ISlots,
 | 
				
			||||||
    IMailboxDatabase,
 | 
					 | 
				
			||||||
    IDuviriInfo,
 | 
					    IDuviriInfo,
 | 
				
			||||||
    IPendingRecipeDatabase,
 | 
					    IPendingRecipeDatabase,
 | 
				
			||||||
    IPendingRecipeClient,
 | 
					    IPendingRecipeClient,
 | 
				
			||||||
@ -54,7 +53,6 @@ import {
 | 
				
			|||||||
    IUpgradeDatabase,
 | 
					    IUpgradeDatabase,
 | 
				
			||||||
    ICrewShipMemberDatabase,
 | 
					    ICrewShipMemberDatabase,
 | 
				
			||||||
    ICrewShipMemberClient,
 | 
					    ICrewShipMemberClient,
 | 
				
			||||||
    IMailboxClient,
 | 
					 | 
				
			||||||
    TEquipmentKey,
 | 
					    TEquipmentKey,
 | 
				
			||||||
    equipmentKeys,
 | 
					    equipmentKeys,
 | 
				
			||||||
    IKubrowPetDetailsDatabase,
 | 
					    IKubrowPetDetailsDatabase,
 | 
				
			||||||
@ -99,7 +97,9 @@ import {
 | 
				
			|||||||
    IAccolades,
 | 
					    IAccolades,
 | 
				
			||||||
    IHubNpcCustomization,
 | 
					    IHubNpcCustomization,
 | 
				
			||||||
    ILotusCustomization,
 | 
					    ILotusCustomization,
 | 
				
			||||||
    IEndlessXpReward
 | 
					    IEndlessXpReward,
 | 
				
			||||||
 | 
					    IPersonalGoalProgressDatabase,
 | 
				
			||||||
 | 
					    IPersonalGoalProgressClient
 | 
				
			||||||
} from "../../types/inventoryTypes/inventoryTypes";
 | 
					} from "../../types/inventoryTypes/inventoryTypes";
 | 
				
			||||||
import { IOid } from "../../types/commonTypes";
 | 
					import { IOid } from "../../types/commonTypes";
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
@ -371,7 +371,7 @@ FlavourItemSchema.set("toJSON", {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const MailboxSchema = new Schema<IMailboxDatabase>(
 | 
					/*const MailboxSchema = new Schema<IMailboxDatabase>(
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        LastInboxId: Schema.Types.ObjectId
 | 
					        LastInboxId: Schema.Types.ObjectId
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
@ -384,7 +384,7 @@ MailboxSchema.set("toJSON", {
 | 
				
			|||||||
        delete mailboxDatabase.__v;
 | 
					        delete mailboxDatabase.__v;
 | 
				
			||||||
        (returnedObject as IMailboxClient).LastInboxId = toOid(mailboxDatabase.LastInboxId);
 | 
					        (returnedObject as IMailboxClient).LastInboxId = toOid(mailboxDatabase.LastInboxId);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
});
 | 
					});*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const DuviriInfoSchema = new Schema<IDuviriInfo>(
 | 
					const DuviriInfoSchema = new Schema<IDuviriInfo>(
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
@ -457,6 +457,29 @@ const discoveredMarkerSchema = new Schema<IDiscoveredMarker>(
 | 
				
			|||||||
    { _id: false }
 | 
					    { _id: false }
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const personalGoalProgressSchema = new Schema<IPersonalGoalProgressDatabase>(
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Best: Number,
 | 
				
			||||||
 | 
					        Count: Number,
 | 
				
			||||||
 | 
					        Tag: String,
 | 
				
			||||||
 | 
					        goalId: Types.ObjectId
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    { _id: false }
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					personalGoalProgressSchema.set("toJSON", {
 | 
				
			||||||
 | 
					    virtuals: true,
 | 
				
			||||||
 | 
					    transform(_doc, obj) {
 | 
				
			||||||
 | 
					        const db = obj as IPersonalGoalProgressDatabase;
 | 
				
			||||||
 | 
					        const client = obj as IPersonalGoalProgressClient;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        client._id = toOid(db.goalId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        delete obj.goalId;
 | 
				
			||||||
 | 
					        delete obj.__v;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const challengeProgressSchema = new Schema<IChallengeProgress>(
 | 
					const challengeProgressSchema = new Schema<IChallengeProgress>(
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        Progress: Number,
 | 
					        Progress: Number,
 | 
				
			||||||
@ -1630,7 +1653,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
 | 
				
			|||||||
        //CompletedJobs: [Schema.Types.Mixed],
 | 
					        //CompletedJobs: [Schema.Types.Mixed],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        //Game mission\ivent score example  "Tag": "WaterFight", "Best": 170, "Count": 1258,
 | 
					        //Game mission\ivent score example  "Tag": "WaterFight", "Best": 170, "Count": 1258,
 | 
				
			||||||
        //PersonalGoalProgress: [Schema.Types.Mixed],
 | 
					        PersonalGoalProgress: { type: [personalGoalProgressSchema], default: undefined },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        //Setting interface Style
 | 
					        //Setting interface Style
 | 
				
			||||||
        ThemeStyle: String,
 | 
					        ThemeStyle: String,
 | 
				
			||||||
@ -1701,7 +1724,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
 | 
				
			|||||||
        //Unknown and system
 | 
					        //Unknown and system
 | 
				
			||||||
        DuviriInfo: DuviriInfoSchema,
 | 
					        DuviriInfo: DuviriInfoSchema,
 | 
				
			||||||
        LastInventorySync: Schema.Types.ObjectId,
 | 
					        LastInventorySync: Schema.Types.ObjectId,
 | 
				
			||||||
        Mailbox: MailboxSchema,
 | 
					        //Mailbox: MailboxSchema,
 | 
				
			||||||
        HandlerPoints: Number,
 | 
					        HandlerPoints: Number,
 | 
				
			||||||
        ChallengesFixVersion: Number,
 | 
					        ChallengesFixVersion: Number,
 | 
				
			||||||
        PlayedParkourTutorial: Boolean,
 | 
					        PlayedParkourTutorial: Boolean,
 | 
				
			||||||
 | 
				
			|||||||
@ -76,6 +76,7 @@ export interface IConfig {
 | 
				
			|||||||
        affinityBoost?: boolean;
 | 
					        affinityBoost?: boolean;
 | 
				
			||||||
        resourceBoost?: boolean;
 | 
					        resourceBoost?: boolean;
 | 
				
			||||||
        starDays?: boolean;
 | 
					        starDays?: boolean;
 | 
				
			||||||
 | 
					        galleonOfGhouls?: number;
 | 
				
			||||||
        eidolonOverride?: string;
 | 
					        eidolonOverride?: string;
 | 
				
			||||||
        vallisOverride?: string;
 | 
					        vallisOverride?: string;
 | 
				
			||||||
        duviriOverride?: string;
 | 
					        duviriOverride?: string;
 | 
				
			||||||
 | 
				
			|||||||
@ -3,6 +3,7 @@ import fsPromises from "fs/promises";
 | 
				
			|||||||
import { logger } from "../utils/logger";
 | 
					import { logger } from "../utils/logger";
 | 
				
			||||||
import { config, configPath, loadConfig } from "./configService";
 | 
					import { config, configPath, loadConfig } from "./configService";
 | 
				
			||||||
import { getWebPorts, sendWsBroadcast, startWebServer, stopWebServer } from "./webService";
 | 
					import { getWebPorts, sendWsBroadcast, startWebServer, stopWebServer } from "./webService";
 | 
				
			||||||
 | 
					import { Inbox } from "../models/inboxModel";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let amnesia = false;
 | 
					let amnesia = false;
 | 
				
			||||||
fs.watchFile(configPath, (now, then) => {
 | 
					fs.watchFile(configPath, (now, then) => {
 | 
				
			||||||
@ -22,6 +23,7 @@ fs.watchFile(configPath, (now, then) => {
 | 
				
			|||||||
            process.exit(1);
 | 
					            process.exit(1);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        validateConfig();
 | 
					        validateConfig();
 | 
				
			||||||
 | 
					        syncConfigWithDatabase();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const webPorts = getWebPorts();
 | 
					        const webPorts = getWebPorts();
 | 
				
			||||||
        if (config.httpPort != webPorts.http || config.httpsPort != webPorts.https) {
 | 
					        if (config.httpPort != webPorts.http || config.httpsPort != webPorts.https) {
 | 
				
			||||||
@ -51,6 +53,15 @@ export const validateConfig = (): void => {
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    if (
 | 
				
			||||||
 | 
					        config.worldState?.galleonOfGhouls &&
 | 
				
			||||||
 | 
					        config.worldState.galleonOfGhouls != 1 &&
 | 
				
			||||||
 | 
					        config.worldState.galleonOfGhouls != 2 &&
 | 
				
			||||||
 | 
					        config.worldState.galleonOfGhouls != 3
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					        config.worldState.galleonOfGhouls = 0;
 | 
				
			||||||
 | 
					        modified = true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    if (modified) {
 | 
					    if (modified) {
 | 
				
			||||||
        logger.info(`Updating config file to fix some issues with it.`);
 | 
					        logger.info(`Updating config file to fix some issues with it.`);
 | 
				
			||||||
        void saveConfig();
 | 
					        void saveConfig();
 | 
				
			||||||
@ -61,3 +72,10 @@ export const saveConfig = async (): Promise<void> => {
 | 
				
			|||||||
    amnesia = true;
 | 
					    amnesia = true;
 | 
				
			||||||
    await fsPromises.writeFile(configPath, JSON.stringify(config, null, 2));
 | 
					    await fsPromises.writeFile(configPath, JSON.stringify(config, null, 2));
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const syncConfigWithDatabase = (): void => {
 | 
				
			||||||
 | 
					    // Event messages are deleted after endDate. Since we don't use beginDate/endDate and instead have config toggles, we need to delete the messages once those bools are false.
 | 
				
			||||||
 | 
					    if (!config.worldState?.galleonOfGhouls) {
 | 
				
			||||||
 | 
					        void Inbox.deleteMany({ goalTag: "GalleonRobbery" }).then(() => {}); // For some reason, I can't just do `Inbox.deleteMany(...)`; it needs this whole circus.
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -54,6 +54,22 @@ export const createNewEventMessages = async (req: Request): Promise<void> => {
 | 
				
			|||||||
        });
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // BUG: Deleting the inbox message manually means it'll just be automatically re-created. This is because we don't use startDate/endDate for these config-toggled events.
 | 
				
			||||||
 | 
					    if (config.worldState?.galleonOfGhouls) {
 | 
				
			||||||
 | 
					        if (!(await Inbox.exists({ ownerId: account._id, goalTag: "GalleonRobbery" }))) {
 | 
				
			||||||
 | 
					            newEventMessages.push({
 | 
				
			||||||
 | 
					                sndr: "/Lotus/Language/Bosses/BossCouncilorVayHek",
 | 
				
			||||||
 | 
					                sub: "/Lotus/Language/Events/GalleonRobberyIntroMsgTitle",
 | 
				
			||||||
 | 
					                msg: "/Lotus/Language/Events/GalleonRobberyIntroMsgDesc",
 | 
				
			||||||
 | 
					                icon: "/Lotus/Interface/Icons/Npcs/VayHekPortrait.png",
 | 
				
			||||||
 | 
					                transmission: "/Lotus/Sounds/Dialog/GalleonOfGhouls/DGhoulsWeekOneInbox0010VayHek",
 | 
				
			||||||
 | 
					                att: ["/Lotus/Upgrades/Skins/Events/OgrisOldSchool"],
 | 
				
			||||||
 | 
					                startDate: new Date(),
 | 
				
			||||||
 | 
					                goalTag: "GalleonRobbery"
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (newEventMessages.length === 0) {
 | 
					    if (newEventMessages.length === 0) {
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -46,7 +46,7 @@ import {
 | 
				
			|||||||
import { updateQuestKey } from "@/src/services/questService";
 | 
					import { updateQuestKey } from "@/src/services/questService";
 | 
				
			||||||
import { Types } from "mongoose";
 | 
					import { Types } from "mongoose";
 | 
				
			||||||
import { IAffiliationMods, IInventoryChanges } from "@/src/types/purchaseTypes";
 | 
					import { IAffiliationMods, IInventoryChanges } from "@/src/types/purchaseTypes";
 | 
				
			||||||
import { fromStoreItem, getLevelKeyRewards, toStoreItem } from "@/src/services/itemDataService";
 | 
					import { fromStoreItem, getLevelKeyRewards, isStoreItem, toStoreItem } from "@/src/services/itemDataService";
 | 
				
			||||||
import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
 | 
					import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
 | 
				
			||||||
import { getEntriesUnsafe } from "@/src/utils/ts-utils";
 | 
					import { getEntriesUnsafe } from "@/src/utils/ts-utils";
 | 
				
			||||||
import { IEquipmentClient } from "@/src/types/inventoryTypes/commonInventoryTypes";
 | 
					import { IEquipmentClient } from "@/src/types/inventoryTypes/commonInventoryTypes";
 | 
				
			||||||
@ -609,6 +609,47 @@ export const addMissionInventoryUpdates = async (
 | 
				
			|||||||
                inventoryChanges.RegularCredits -= value;
 | 
					                inventoryChanges.RegularCredits -= value;
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					            case "GoalProgress": {
 | 
				
			||||||
 | 
					                for (const uploadProgress of value) {
 | 
				
			||||||
 | 
					                    const goal = getWorldState().Goals.find(x => x._id.$oid == uploadProgress._id.$oid);
 | 
				
			||||||
 | 
					                    if (goal && goal.Personal) {
 | 
				
			||||||
 | 
					                        inventory.PersonalGoalProgress ??= [];
 | 
				
			||||||
 | 
					                        const goalProgress = inventory.PersonalGoalProgress.find(x => x.goalId.equals(goal._id.$oid));
 | 
				
			||||||
 | 
					                        if (goalProgress) {
 | 
				
			||||||
 | 
					                            goalProgress.Best = Math.max(goalProgress.Best, uploadProgress.Best);
 | 
				
			||||||
 | 
					                            goalProgress.Count += uploadProgress.Count;
 | 
				
			||||||
 | 
					                        } else {
 | 
				
			||||||
 | 
					                            inventory.PersonalGoalProgress.push({
 | 
				
			||||||
 | 
					                                Best: uploadProgress.Best,
 | 
				
			||||||
 | 
					                                Count: uploadProgress.Count,
 | 
				
			||||||
 | 
					                                Tag: goal.Tag,
 | 
				
			||||||
 | 
					                                goalId: new Types.ObjectId(goal._id.$oid)
 | 
				
			||||||
 | 
					                            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            if (
 | 
				
			||||||
 | 
					                                goal.Reward &&
 | 
				
			||||||
 | 
					                                goal.Reward.items &&
 | 
				
			||||||
 | 
					                                goal.MissionKeyName &&
 | 
				
			||||||
 | 
					                                goal.MissionKeyName in goalMessagesByKey
 | 
				
			||||||
 | 
					                            ) {
 | 
				
			||||||
 | 
					                                // Send reward via inbox
 | 
				
			||||||
 | 
					                                const info = goalMessagesByKey[goal.MissionKeyName];
 | 
				
			||||||
 | 
					                                await createMessage(inventory.accountOwnerId, [
 | 
				
			||||||
 | 
					                                    {
 | 
				
			||||||
 | 
					                                        sndr: info.sndr,
 | 
				
			||||||
 | 
					                                        msg: info.msg,
 | 
				
			||||||
 | 
					                                        att: goal.Reward.items.map(x => (isStoreItem(x) ? fromStoreItem(x) : x)),
 | 
				
			||||||
 | 
					                                        sub: info.sub,
 | 
				
			||||||
 | 
					                                        icon: info.icon,
 | 
				
			||||||
 | 
					                                        highPriority: true
 | 
				
			||||||
 | 
					                                    }
 | 
				
			||||||
 | 
					                                ]);
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
            case "InvasionProgress": {
 | 
					            case "InvasionProgress": {
 | 
				
			||||||
                for (const clientProgress of value) {
 | 
					                for (const clientProgress of value) {
 | 
				
			||||||
                    const dbProgress = inventory.QualifyingInvasions.find(x =>
 | 
					                    const dbProgress = inventory.QualifyingInvasions.find(x =>
 | 
				
			||||||
@ -962,6 +1003,14 @@ export const addMissionRewards = async (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    let missionCompletionCredits = 0;
 | 
					    let missionCompletionCredits = 0;
 | 
				
			||||||
    //inventory change is what the client has not rewarded itself, also the client needs to know the credit changes for display
 | 
					    //inventory change is what the client has not rewarded itself, also the client needs to know the credit changes for display
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (rewardInfo.goalId) {
 | 
				
			||||||
 | 
					        const goal = getWorldState().Goals.find(x => x._id.$oid == rewardInfo.goalId);
 | 
				
			||||||
 | 
					        if (goal?.MissionKeyName) {
 | 
				
			||||||
 | 
					            levelKeyName = goal.MissionKeyName;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (levelKeyName) {
 | 
					    if (levelKeyName) {
 | 
				
			||||||
        const fixedLevelRewards = getLevelKeyRewards(levelKeyName);
 | 
					        const fixedLevelRewards = getLevelKeyRewards(levelKeyName);
 | 
				
			||||||
        //logger.debug(`fixedLevelRewards ${fixedLevelRewards}`);
 | 
					        //logger.debug(`fixedLevelRewards ${fixedLevelRewards}`);
 | 
				
			||||||
@ -1978,3 +2027,24 @@ const getHexBounties = (seed: number): { nodes: string[]; buddies: string[] } =>
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    return { nodes, buddies };
 | 
					    return { nodes, buddies };
 | 
				
			||||||
};*/
 | 
					};*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const goalMessagesByKey: Record<string, { sndr: string; msg: string; sub: string; icon: string }> = {
 | 
				
			||||||
 | 
					    "/Lotus/Types/Keys/GalleonRobberyAlert": {
 | 
				
			||||||
 | 
					        sndr: "/Lotus/Language/Bosses/BossCouncilorVayHek",
 | 
				
			||||||
 | 
					        msg: "/Lotus/Language/Messages/GalleonRobbery2025RewardMsgA",
 | 
				
			||||||
 | 
					        sub: "/Lotus/Language/Messages/GalleonRobbery2025MissionTitleA",
 | 
				
			||||||
 | 
					        icon: "/Lotus/Interface/Icons/Npcs/VayHekPortrait.png"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "/Lotus/Types/Keys/GalleonRobberyAlertB": {
 | 
				
			||||||
 | 
					        sndr: "/Lotus/Language/Bosses/BossCouncilorVayHek",
 | 
				
			||||||
 | 
					        msg: "/Lotus/Language/Messages/GalleonRobbery2025RewardMsgB",
 | 
				
			||||||
 | 
					        sub: "/Lotus/Language/Messages/GalleonRobbery2025MissionTitleB",
 | 
				
			||||||
 | 
					        icon: "/Lotus/Interface/Icons/Npcs/VayHekPortrait.png"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "/Lotus/Types/Keys/GalleonRobberyAlertC": {
 | 
				
			||||||
 | 
					        sndr: "/Lotus/Language/Bosses/BossCouncilorVayHek",
 | 
				
			||||||
 | 
					        msg: "/Lotus/Language/Messages/GalleonRobbery2025RewardMsgC",
 | 
				
			||||||
 | 
					        sub: "/Lotus/Language/Messages/GalleonRobbery2025MissionTitleC",
 | 
				
			||||||
 | 
					        icon: "/Lotus/Interface/Icons/Npcs/VayHekPortrait.png"
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -1146,6 +1146,77 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
 | 
				
			|||||||
            Node: "SolarisUnitedHub1"
 | 
					            Node: "SolarisUnitedHub1"
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    // The client gets kinda confused when multiple goals have the same tag, so considering these mutually exclusive.
 | 
				
			||||||
 | 
					    if (config.worldState?.galleonOfGhouls == 1) {
 | 
				
			||||||
 | 
					        worldState.Goals.push({
 | 
				
			||||||
 | 
					            _id: { $oid: "6814ddf00000000000000000" },
 | 
				
			||||||
 | 
					            Activation: { $date: { $numberLong: "1746198000000" } },
 | 
				
			||||||
 | 
					            Expiry: { $date: { $numberLong: "2000000000000" } },
 | 
				
			||||||
 | 
					            Count: 0,
 | 
				
			||||||
 | 
					            Goal: 1,
 | 
				
			||||||
 | 
					            Success: 0,
 | 
				
			||||||
 | 
					            Personal: true,
 | 
				
			||||||
 | 
					            Bounty: true,
 | 
				
			||||||
 | 
					            ClampNodeScores: true,
 | 
				
			||||||
 | 
					            Node: "EventNode19",
 | 
				
			||||||
 | 
					            MissionKeyName: "/Lotus/Types/Keys/GalleonRobberyAlert",
 | 
				
			||||||
 | 
					            Desc: "/Lotus/Language/Events/GalleonRobberyEventMissionTitle",
 | 
				
			||||||
 | 
					            Icon: "/Lotus/Interface/Icons/Player/GalleonRobberiesEvent.png",
 | 
				
			||||||
 | 
					            Tag: "GalleonRobbery",
 | 
				
			||||||
 | 
					            Reward: {
 | 
				
			||||||
 | 
					                items: [
 | 
				
			||||||
 | 
					                    "/Lotus/StoreItems/Types/Recipes/Weapons/GrnChainSawTonfaBlueprint",
 | 
				
			||||||
 | 
					                    "/Lotus/StoreItems/Upgrades/Skins/Clan/BountyHunterBadgeItem"
 | 
				
			||||||
 | 
					                ]
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    } else if (config.worldState?.galleonOfGhouls == 2) {
 | 
				
			||||||
 | 
					        worldState.Goals.push({
 | 
				
			||||||
 | 
					            _id: { $oid: "681e18700000000000000000" },
 | 
				
			||||||
 | 
					            Activation: { $date: { $numberLong: "1746802800000" } },
 | 
				
			||||||
 | 
					            Expiry: { $date: { $numberLong: "2000000000000" } },
 | 
				
			||||||
 | 
					            Count: 0,
 | 
				
			||||||
 | 
					            Goal: 1,
 | 
				
			||||||
 | 
					            Success: 0,
 | 
				
			||||||
 | 
					            Personal: true,
 | 
				
			||||||
 | 
					            Bounty: true,
 | 
				
			||||||
 | 
					            ClampNodeScores: true,
 | 
				
			||||||
 | 
					            Node: "EventNode28",
 | 
				
			||||||
 | 
					            MissionKeyName: "/Lotus/Types/Keys/GalleonRobberyAlertB",
 | 
				
			||||||
 | 
					            Desc: "/Lotus/Language/Events/GalleonRobberyEventMissionTitle",
 | 
				
			||||||
 | 
					            Icon: "/Lotus/Interface/Icons/Player/GalleonRobberiesEvent.png",
 | 
				
			||||||
 | 
					            Tag: "GalleonRobbery",
 | 
				
			||||||
 | 
					            Reward: {
 | 
				
			||||||
 | 
					                items: [
 | 
				
			||||||
 | 
					                    "/Lotus/StoreItems/Types/Recipes/Weapons/MortiforShieldAndSwordBlueprint",
 | 
				
			||||||
 | 
					                    "/Lotus/StoreItems/Upgrades/Skins/Clan/BountyHunterBadgeItem"
 | 
				
			||||||
 | 
					                ]
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    } else if (config.worldState?.galleonOfGhouls == 3) {
 | 
				
			||||||
 | 
					        worldState.Goals.push({
 | 
				
			||||||
 | 
					            _id: { $oid: "682752f00000000000000000" },
 | 
				
			||||||
 | 
					            Activation: { $date: { $numberLong: "1747407600000" } },
 | 
				
			||||||
 | 
					            Expiry: { $date: { $numberLong: "2000000000000" } },
 | 
				
			||||||
 | 
					            Count: 0,
 | 
				
			||||||
 | 
					            Goal: 1,
 | 
				
			||||||
 | 
					            Success: 0,
 | 
				
			||||||
 | 
					            Personal: true,
 | 
				
			||||||
 | 
					            Bounty: true,
 | 
				
			||||||
 | 
					            ClampNodeScores: true,
 | 
				
			||||||
 | 
					            Node: "EventNode19",
 | 
				
			||||||
 | 
					            MissionKeyName: "/Lotus/Types/Keys/GalleonRobberyAlertC",
 | 
				
			||||||
 | 
					            Desc: "/Lotus/Language/Events/GalleonRobberyEventMissionTitle",
 | 
				
			||||||
 | 
					            Icon: "/Lotus/Interface/Icons/Player/GalleonRobberiesEvent.png",
 | 
				
			||||||
 | 
					            Tag: "GalleonRobbery",
 | 
				
			||||||
 | 
					            Reward: {
 | 
				
			||||||
 | 
					                items: [
 | 
				
			||||||
 | 
					                    "/Lotus/Types/StoreItems/Packages/EventCatalystReactorBundle",
 | 
				
			||||||
 | 
					                    "/Lotus/StoreItems/Upgrades/Skins/Clan/BountyHunterBadgeItem"
 | 
				
			||||||
 | 
					                ]
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Nightwave Challenges
 | 
					    // Nightwave Challenges
 | 
				
			||||||
    const nightwaveSyndicateTag = getNightwaveSyndicateTag(buildLabel);
 | 
					    const nightwaveSyndicateTag = getNightwaveSyndicateTag(buildLabel);
 | 
				
			||||||
 | 
				
			|||||||
@ -56,6 +56,7 @@ export interface IInventoryDatabase
 | 
				
			|||||||
            | "QualifyingInvasions"
 | 
					            | "QualifyingInvasions"
 | 
				
			||||||
            | "LastInventorySync"
 | 
					            | "LastInventorySync"
 | 
				
			||||||
            | "EndlessXP"
 | 
					            | "EndlessXP"
 | 
				
			||||||
 | 
					            | "PersonalGoalProgress"
 | 
				
			||||||
            | TEquipmentKey
 | 
					            | TEquipmentKey
 | 
				
			||||||
        >,
 | 
					        >,
 | 
				
			||||||
        InventoryDatabaseEquipment {
 | 
					        InventoryDatabaseEquipment {
 | 
				
			||||||
@ -63,7 +64,7 @@ export interface IInventoryDatabase
 | 
				
			|||||||
    Created: Date;
 | 
					    Created: Date;
 | 
				
			||||||
    TrainingDate: Date;
 | 
					    TrainingDate: Date;
 | 
				
			||||||
    LoadOutPresets: Types.ObjectId; // LoadOutPresets changed from ILoadOutPresets to Types.ObjectId for population
 | 
					    LoadOutPresets: Types.ObjectId; // LoadOutPresets changed from ILoadOutPresets to Types.ObjectId for population
 | 
				
			||||||
    Mailbox?: IMailboxDatabase;
 | 
					    //Mailbox?: IMailboxDatabase;
 | 
				
			||||||
    GuildId?: Types.ObjectId;
 | 
					    GuildId?: Types.ObjectId;
 | 
				
			||||||
    PendingRecipes: IPendingRecipeDatabase[];
 | 
					    PendingRecipes: IPendingRecipeDatabase[];
 | 
				
			||||||
    QuestKeys: IQuestKeyDatabase[];
 | 
					    QuestKeys: IQuestKeyDatabase[];
 | 
				
			||||||
@ -95,6 +96,7 @@ export interface IInventoryDatabase
 | 
				
			|||||||
    QualifyingInvasions: IInvasionProgressDatabase[];
 | 
					    QualifyingInvasions: IInvasionProgressDatabase[];
 | 
				
			||||||
    LastInventorySync?: Types.ObjectId;
 | 
					    LastInventorySync?: Types.ObjectId;
 | 
				
			||||||
    EndlessXP?: IEndlessXpProgressDatabase[];
 | 
					    EndlessXP?: IEndlessXpProgressDatabase[];
 | 
				
			||||||
 | 
					    PersonalGoalProgress?: IPersonalGoalProgressDatabase[];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface IQuestKeyDatabase {
 | 
					export interface IQuestKeyDatabase {
 | 
				
			||||||
@ -150,9 +152,9 @@ export interface IMailboxClient {
 | 
				
			|||||||
    LastInboxId: IOid;
 | 
					    LastInboxId: IOid;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface IMailboxDatabase {
 | 
					/*export interface IMailboxDatabase {
 | 
				
			||||||
    LastInboxId: Types.ObjectId;
 | 
					    LastInboxId: Types.ObjectId;
 | 
				
			||||||
}
 | 
					}*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type TSolarMapRegion =
 | 
					export type TSolarMapRegion =
 | 
				
			||||||
    | "Earth"
 | 
					    | "Earth"
 | 
				
			||||||
@ -306,7 +308,7 @@ export interface IInventoryClient extends IDailyAffiliations, InventoryClientEqu
 | 
				
			|||||||
    HWIDProtectEnabled?: boolean;
 | 
					    HWIDProtectEnabled?: boolean;
 | 
				
			||||||
    //KubrowPetPrints: IKubrowPetPrint[];
 | 
					    //KubrowPetPrints: IKubrowPetPrint[];
 | 
				
			||||||
    AlignmentReplay?: IAlignment;
 | 
					    AlignmentReplay?: IAlignment;
 | 
				
			||||||
    //PersonalGoalProgress: IPersonalGoalProgress[];
 | 
					    PersonalGoalProgress?: IPersonalGoalProgressClient[];
 | 
				
			||||||
    ThemeStyle: string;
 | 
					    ThemeStyle: string;
 | 
				
			||||||
    ThemeBackground: string;
 | 
					    ThemeBackground: string;
 | 
				
			||||||
    ThemeSounds: string;
 | 
					    ThemeSounds: string;
 | 
				
			||||||
@ -1015,13 +1017,17 @@ export interface IPeriodicMissionCompletionResponse extends Omit<IPeriodicMissio
 | 
				
			|||||||
    date: IMongoDate;
 | 
					    date: IMongoDate;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface IPersonalGoalProgress {
 | 
					export interface IPersonalGoalProgressClient {
 | 
				
			||||||
 | 
					    Best: number;
 | 
				
			||||||
    Count: number;
 | 
					    Count: number;
 | 
				
			||||||
    Tag: string;
 | 
					    Tag: string;
 | 
				
			||||||
    Best?: number;
 | 
					 | 
				
			||||||
    _id: IOid;
 | 
					    _id: IOid;
 | 
				
			||||||
    ReceivedClanReward0?: boolean;
 | 
					    //ReceivedClanReward0?: boolean;
 | 
				
			||||||
    ReceivedClanReward1?: boolean;
 | 
					    //ReceivedClanReward1?: boolean;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface IPersonalGoalProgressDatabase extends Omit<IPersonalGoalProgressClient, "_id"> {
 | 
				
			||||||
 | 
					    goalId: Types.ObjectId;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface IPersonalTechProjectDatabase {
 | 
					export interface IPersonalTechProjectDatabase {
 | 
				
			||||||
 | 
				
			|||||||
@ -139,6 +139,14 @@ export type IMissionInventoryUpdateRequest = {
 | 
				
			|||||||
    };
 | 
					    };
 | 
				
			||||||
    wagerTier?: number; // the index
 | 
					    wagerTier?: number; // the index
 | 
				
			||||||
    creditsFee?: number; // the index
 | 
					    creditsFee?: number; // the index
 | 
				
			||||||
 | 
					    GoalProgress?: {
 | 
				
			||||||
 | 
					        _id: IOid;
 | 
				
			||||||
 | 
					        Count: number;
 | 
				
			||||||
 | 
					        Best: number;
 | 
				
			||||||
 | 
					        Tag: string;
 | 
				
			||||||
 | 
					        IsMultiProgress: boolean;
 | 
				
			||||||
 | 
					        MultiProgress: unknown[];
 | 
				
			||||||
 | 
					    }[];
 | 
				
			||||||
    InvasionProgress?: IInvasionProgressClient[];
 | 
					    InvasionProgress?: IInvasionProgressClient[];
 | 
				
			||||||
    ConquestMissionsCompleted?: number;
 | 
					    ConquestMissionsCompleted?: number;
 | 
				
			||||||
    duviriSuitSelection?: string;
 | 
					    duviriSuitSelection?: string;
 | 
				
			||||||
@ -156,6 +164,8 @@ export type IMissionInventoryUpdateRequest = {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
export interface IRewardInfo {
 | 
					export interface IRewardInfo {
 | 
				
			||||||
    node: string;
 | 
					    node: string;
 | 
				
			||||||
 | 
					    goalId?: string;
 | 
				
			||||||
 | 
					    goalManifest?: string;
 | 
				
			||||||
    invasionId?: string;
 | 
					    invasionId?: string;
 | 
				
			||||||
    invasionAllyFaction?: "FC_GRINEER" | "FC_CORPUS";
 | 
					    invasionAllyFaction?: "FC_GRINEER" | "FC_CORPUS";
 | 
				
			||||||
    sortieId?: string;
 | 
					    sortieId?: string;
 | 
				
			||||||
 | 
				
			|||||||
@ -1,3 +1,4 @@
 | 
				
			|||||||
 | 
					import { IMissionReward } from "warframe-public-export-plus";
 | 
				
			||||||
import { IMongoDate, IOid } from "./commonTypes";
 | 
					import { IMongoDate, IOid } from "./commonTypes";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface IWorldState {
 | 
					export interface IWorldState {
 | 
				
			||||||
@ -37,11 +38,15 @@ export interface IGoal {
 | 
				
			|||||||
    Goal: number;
 | 
					    Goal: number;
 | 
				
			||||||
    Success: number;
 | 
					    Success: number;
 | 
				
			||||||
    Personal: boolean;
 | 
					    Personal: boolean;
 | 
				
			||||||
 | 
					    Bounty?: boolean;
 | 
				
			||||||
 | 
					    ClampNodeScores?: boolean;
 | 
				
			||||||
    Desc: string;
 | 
					    Desc: string;
 | 
				
			||||||
    ToolTip: string;
 | 
					    ToolTip?: string;
 | 
				
			||||||
    Icon: string;
 | 
					    Icon: string;
 | 
				
			||||||
    Tag: string;
 | 
					    Tag: string;
 | 
				
			||||||
    Node: string;
 | 
					    Node: string;
 | 
				
			||||||
 | 
					    MissionKeyName?: string;
 | 
				
			||||||
 | 
					    Reward?: IMissionReward;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface ISyndicateMissionInfo {
 | 
					export interface ISyndicateMissionInfo {
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user