feat: galleon of ghouls (#2280)
Re #1103 Reviewed-on: #2280 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
This commit is contained in:
parent
39630c5af7
commit
731ce6c215
@ -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"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
@ -1149,6 +1149,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