import type { Document, Model } from "mongoose";
import { Schema, Types, model } from "mongoose";
import type {
IRawUpgrade,
IMiscItem,
IInventoryDatabase,
IBooster,
IInventoryClient,
ISlots,
IDuviriInfo,
IPendingRecipeDatabase,
IPendingRecipeClient,
IFocusXP,
IFocusUpgrade,
ITypeXPItem,
IChallengeProgress,
IStepSequencerDatabase,
IAffiliation,
INotePacks,
ICompletedJobChain,
ISeasonChallenge,
IPlayerSkills,
ISettings,
IInfestedFoundryDatabase,
IHelminthResource,
IMissionDatabase,
IConsumedSuit,
IQuestStage,
IQuestKeyDatabase,
IQuestKeyClient,
IFusionTreasure,
ISpectreLoadout,
IWeaponSkinDatabase,
ITaunt,
IPeriodicMissionCompletionDatabase,
IPeriodicMissionCompletionResponse,
ILoreFragmentScan,
IEvolutionProgress,
IEndlessXpProgressDatabase,
IEndlessXpProgressClient,
IHelminthFoodRecord,
IDialogueHistoryDatabase,
IDialogueDatabase,
IDialogueGift,
ICompletedDialogue,
IDialogueClient,
IUpgradeDatabase,
TEquipmentKey,
ICustomMarkers,
IMarkerInfo,
IMarker,
ICalendarProgress,
IPendingCouponDatabase,
IPendingCouponClient,
ILibraryDailyTaskInfo,
IDroneDatabase,
IDroneClient,
IAlignment,
ICollectibleEntry,
IIncentiveState,
ISongChallenge,
ILibraryPersonalProgress,
IRecentVendorPurchaseDatabase,
IVendorPurchaseHistoryEntryDatabase,
IVendorPurchaseHistoryEntryClient,
INemesisDatabase,
INemesisClient,
IInfNode,
IDiscoveredMarker,
IWeeklyMission,
ILockedWeaponGroupDatabase,
IPersonalTechProjectDatabase,
IPersonalTechProjectClient,
ILastSortieRewardDatabase,
ILastSortieRewardClient,
ICrewMemberSkill,
ICrewMemberSkillEfficiency,
ICrewMemberDatabase,
ICrewMemberClient,
IRewardAttenuation,
IInvasionProgressDatabase,
IInvasionProgressClient,
IAccolades,
IHubNpcCustomization,
IEndlessXpReward,
IGoalProgressDatabase,
IGoalProgressClient,
IKubrowPetPrintClient,
IKubrowPetPrintDatabase,
INokkoColony,
IJournalEntry,
IDialogueResetDateClient,
IDialogueResetDateDatabase,
IDescentLevelReward,
IDescentCategoryRewardClient,
IDescentCategoryRewardDatabase,
IFocusLoadoutDatabase,
IChallengeInstanceStateDatabase,
IChallengeInstanceStateClient,
IParam,
IDialogueCounter,
ISketch,
IHybridFusionTreasure,
IWeeklyGuildVaultBonus,
IWeekGuildVaultBonusReward,
IMiscAccountData
} from "../../types/inventoryTypes/inventoryTypes.ts";
import { equipmentKeys } from "../../types/inventoryTypes/inventoryTypes.ts";
import type { IOid, ITypeCount } from "../../types/commonTypes.ts";
import type {
IAbilityOverride,
ICrewShipCustomization,
IFlavourItem,
IItemConfig,
ILotusCustomization,
IOperatorConfigDatabase,
IPolarity
} from "../../types/inventoryTypes/commonInventoryTypes.ts";
import { toMongoDate, toOid } from "../../helpers/inventoryHelpers.ts";
import { EquipmentSelectionSchema } from "./loadoutModel.ts";
import type { ICountedStoreItem } from "warframe-public-export-plus";
import { colorSchema, shipCustomizationSchema } from "../commonModel.ts";
import type {
IArchonCrystalUpgrade,
ICrewShipMemberClient,
ICrewShipMemberDatabase,
ICrewShipMembersDatabase,
ICrewShipWeaponDatabase,
ICrewShipWeaponEmplacementsDatabase,
IEquipmentClient,
IEquipmentDatabase,
IKubrowPetDatabase,
IKubrowPetDetailsClient,
IKubrowPetDetailsDatabase,
ITraits
} from "../../types/equipmentTypes.ts";
export const typeCountSchema = new Schema<ITypeCount>({ ItemType: String, ItemCount: Number }, { _id: false });
typeCountSchema.set("toJSON", {
transform(_doc, obj: Record<string, any>) {
// Ensure numbers comfortably fit in a 32-bit integer so the client's in-memory value doesn't overflow or underflow.
if (obj.ItemCount > 999_999_999) {
obj.ItemCount = 999_999_999;
} else if (obj.ItemCount < -999_999_999) {
obj.ItemCount = -999_999_999;
}
}
});
const focusXPSchema = new Schema<IFocusXP>(
{
AP_POWER: Number,
AP_TACTIC: Number,
AP_DEFENSE: Number,
AP_ATTACK: Number,
AP_WARD: Number
},
{ _id: false }
);
const focusUpgradeSchema = new Schema<IFocusUpgrade>(
{
ItemType: String,
Level: Number,
IsUniversal: Boolean,
IsActive: Schema.Types.Mixed,
TotalCapacity: Number,
CooldownTier: Number,
IsCooldownReductionActive: Boolean
},
{ _id: false }
);
const focusLoadoutSchema = new Schema<IFocusLoadoutDatabase>(
{
Preset: EquipmentSelectionSchema,
FocusAbility: String
},
{ _id: false }
);
const polaritySchema = new Schema<IPolarity>(
{
Slot: Number,
Value: String
},
{ _id: false }
);
const abilityOverrideSchema = new Schema<IAbilityOverride>(
{
Ability: String,
Index: Number
},
{ _id: false }
);
const operatorConfigSchema = new Schema<IOperatorConfigDatabase>(
{
Skins: [String],
pricol: colorSchema,
attcol: colorSchema,
sigcol: colorSchema,
eyecol: colorSchema,
facial: colorSchema,
syancol: colorSchema,
cloth: colorSchema,
Upgrades: [String],
Name: String, // not sure if possible in operator
ugly: Boolean // not sure if possible in operator
},
{ id: false }
);
operatorConfigSchema.virtual("ItemId").get(function () {
return { $oid: this._id.toString() } satisfies IOid;
});
operatorConfigSchema.set("toJSON", {
virtuals: true,
transform(_document, returnedObject: Record<string, any>) {
delete returnedObject._id;
delete returnedObject.__v;
}
});
///TODO: clearly seperate the different config schemas. (suit and weapon and so on)
const ItemConfigSchema = new Schema<IItemConfig>(
{
Skins: [String],
pricol: colorSchema,
attcol: colorSchema,
sigcol: colorSchema,
eyecol: colorSchema,
facial: colorSchema,
syancol: colorSchema,
cloth: colorSchema,
Upgrades: [String],
Songs: {
type: [
{
m: String,
b: String,
p: String,
s: String
}
],
default: undefined
},
Name: String,
AbilityOverride: abilityOverrideSchema,
PvpUpgrades: [String],
ugly: Boolean
},
{ _id: false }
);
ItemConfigSchema.set("toJSON", {
transform(_document, returnedObject: Record<string, any>) {
delete returnedObject.__v;
}
});
const ArchonCrystalUpgradeSchema = new Schema<IArchonCrystalUpgrade>(
{
UpgradeType: String,
Color: String
},
{ _id: false }
);
const boosterSchema = new Schema<IBooster>(
{
ExpiryDate: Number,
ItemType: String
},
{ _id: false }
);
const RawUpgrades = new Schema<IRawUpgrade>(
{
ItemType: String,
ItemCount: Number
},
{ id: false }
);
RawUpgrades.virtual("LastAdded").get(function () {
return { $oid: this._id.toString() } satisfies IOid;
});
RawUpgrades.set("toJSON", {
virtuals: true,
transform(_document, returnedObject: Record<string, any>) {
delete returnedObject._id;
delete returnedObject.__v;
}
});
const upgradeSchema = new Schema<IUpgradeDatabase>(
{
UpgradeFingerprint: String,
PendingRerollFingerprint: { type: String, required: false },
ItemType: String
},
{ id: false }
);
upgradeSchema.virtual("ItemId").get(function () {
return toOid(this._id);
});
upgradeSchema.set("toJSON", {
virtuals: true,
transform(_document, returnedObject: Record<string, any>) {
delete returnedObject._id;
delete returnedObject.__v;
}
});
const crewMemberSkillSchema = new Schema<ICrewMemberSkill>(
{
Assigned: Number
},
{ _id: false }
);
const crewMemberSkillEfficiencySchema = new Schema<ICrewMemberSkillEfficiency>(
{
PILOTING: crewMemberSkillSchema,
GUNNERY: crewMemberSkillSchema,
ENGINEERING: crewMemberSkillSchema,
COMBAT: crewMemberSkillSchema,
SURVIVABILITY: crewMemberSkillSchema
},
{ _id: false }
);
const crewMemberSchema = new Schema<ICrewMemberDatabase>(
{
ItemType: { type: String, required: true },
NemesisFingerprint: { type: BigInt, default: 0n },
Seed: { type: BigInt, default: 0n },
AssignedRole: Number,
SkillEfficiency: crewMemberSkillEfficiencySchema,
WeaponConfigIdx: Number,
WeaponId: { type: Schema.Types.ObjectId, default: "000000000000000000000000" },
XP: { type: Number, default: 0 },
PowersuitType: { type: String, required: false },
Configs: [{ type: ItemConfigSchema, required: true }],
SecondInCommand: { type: Boolean, default: false }
},
{ id: false }
);
crewMemberSchema.set("toJSON", {
virtuals: true,
transform(_doc, obj: Record<string, any>) {
const db = obj as ICrewMemberDatabase;
const client = obj as ICrewMemberClient;
client.WeaponId = toOid(db.WeaponId);
client.ItemId = toOid(db._id);
delete obj._id;
delete obj.__v;
}
});
const slotsBinSchema = new Schema<ISlots>(
{
Slots: Number,
Extra: Number
},
{ _id: false }
);
const FlavourItemSchema = new Schema(
{
ItemType: String
},
{ _id: false }
);
FlavourItemSchema.set("toJSON", {
transform(_document, returnedObject: Record<string, any>) {
delete returnedObject._id;
delete returnedObject.__v;
}
});
/*const MailboxSchema = new Schema<IMailboxDatabase>(
{
LastInboxId: Schema.Types.ObjectId
},
{ id: false, _id: false }
);
MailboxSchema.set("toJSON", {
transform(_document, returnedObject: Record<string, any>) {
const mailboxDatabase = returnedObject as HydratedDocument<IMailboxDatabase, { __v?: number }>;
delete mailboxDatabase.__v;
(returnedObject as IMailboxClient).LastInboxId = toOid(mailboxDatabase.LastInboxId);
}
});*/
const DuviriInfoSchema = new Schema<IDuviriInfo>(
{
Seed: { type: BigInt, required: true },
NumCompletions: { type: Number, required: true }
},
{
_id: false,
id: false
}
);
DuviriInfoSchema.set("toJSON", {
transform(_document, returnedObject: Record<string, any>) {
delete returnedObject.__v;
}
});
const TypeXPItemSchema = new Schema<ITypeXPItem>(
{
ItemType: String,
XP: Number
},
{ _id: false }
);
const droneSchema = new Schema<IDroneDatabase>(
{
ItemType: String,
CurrentHP: Number,
RepairStart: { type: Date, default: undefined },
DeployTime: { type: Date, default: undefined },
System: Number,
DamageTime: { type: Date, default: undefined },
PendingDamage: Number,
ResourceType: String,
ResourceCount: Number
},
{ id: false }
);
droneSchema.set("toJSON", {
virtuals: true,
transform(_document, obj: Record<string, any>) {
const client = obj as IDroneClient;
const db = obj as IDroneDatabase;
client.ItemId = toOid(db._id);
if (db.RepairStart) {
client.RepairStart = toMongoDate(db.RepairStart);
}
delete db.DeployTime;
delete db.System;
delete db.DamageTime;
delete db.PendingDamage;
delete db.ResourceType;
delete db.ResourceCount;
delete obj._id;
delete obj.__v;
}
});
const discoveredMarkerSchema = new Schema<IDiscoveredMarker>(
{
tag: String,
discoveryState: [Number]
},
{ _id: false }
);
const personalGoalProgressSchema = new Schema<IGoalProgressDatabase>(
{
Best: Number,
Count: Number,
Tag: String,
goalId: Types.ObjectId
},
{ _id: false }
);
personalGoalProgressSchema.set("toJSON", {
virtuals: true,
transform(_doc, obj: Record<string, any>) {
const db = obj as IGoalProgressDatabase;
const client = obj as IGoalProgressClient;
client._id = toOid(db.goalId);
delete obj.goalId;
delete obj.__v;
}
});
const challengeProgressSchema = new Schema<IChallengeProgress>(
{
Progress: Number,
Completed: { type: [String], default: undefined },
ReceivedJunctionReward: Boolean,
Name: { type: String, required: true }
},
{ _id: false }
);
const notePacksSchema = new Schema<INotePacks>(
{
MELODY: String,
BASS: String,
PERCUSSION: String
},
{ _id: false }
);
const StepSequencersSchema = new Schema<IStepSequencerDatabase>(
{
NotePacks: notePacksSchema,
FingerPrint: String,
Name: String
},
{ id: false }
);
StepSequencersSchema.virtual("ItemId").get(function () {
return { $oid: this._id.toString() } satisfies IOid;
});
StepSequencersSchema.set("toJSON", {
virtuals: true,
transform(_document, returnedObject: Record<string, any>) {
delete returnedObject._id;
delete returnedObject.__v;
}
});
const weeklyMissionSchema = new Schema<IWeeklyMission>(
{
MissionIndex: Number,
CompletedMission: Boolean,
JobManifest: String,
Challenges: [String],
ChallengesReset: Boolean,
WeekCount: Number
},
{ _id: false }
);
const affiliationsSchema = new Schema<IAffiliation>(
{
Initiated: Boolean,
Standing: Number,
Title: Number,
FreeFavorsEarned: { type: [Number], default: undefined },
FreeFavorsUsed: { type: [Number], default: undefined },
WeeklyMissions: { type: [weeklyMissionSchema], default: undefined },
Tag: String
},
{ _id: false }
);
const completedJobChainsSchema = new Schema<ICompletedJobChain>(
{
LocationTag: String,
Jobs: [String]
},
{ _id: false }
);
const seasonChallengeHistorySchema = new Schema<ISeasonChallenge>(
{
challenge: String,
id: String
},
{ _id: false }
);
const personalTechProjectSchema = new Schema<IPersonalTechProjectDatabase>(
{
State: Number,
ReqCredits: Number,
ItemType: String,
ProductCategory: String,
CategoryItemId: Schema.Types.ObjectId,
ReqItems: { type: [typeCountSchema], default: undefined },
HasContributions: Boolean,
CompletionDate: Date
},
{ id: false }
);
personalTechProjectSchema.virtual("ItemId").get(function () {
return { $oid: this._id.toString() };
});
personalTechProjectSchema.set("toJSON", {
virtuals: true,
transform(_doc, ret: Record<string, any>) {
delete ret._id;
delete ret.__v;
const db = ret as IPersonalTechProjectDatabase;
const client = ret as IPersonalTechProjectClient;
if (db.CategoryItemId) {
client.CategoryItemId = toOid(db.CategoryItemId);
}
if (db.CompletionDate) {
client.CompletionDate = toMongoDate(db.CompletionDate);
}
}
});
const playerSkillsSchema = new Schema<IPlayerSkills>(
{
LPP_SPACE: { type: Number, default: 0 },
LPS_PILOTING: { type: Number, default: 0 },
LPS_GUNNERY: { type: Number, default: 0 },
LPS_TACTICAL: { type: Number, default: 0 },
LPS_ENGINEERING: { type: Number, default: 0 },
LPS_COMMAND: { type: Number, default: 0 },
LPP_DRIFTER: { type: Number, default: 0 },
LPS_DRIFT_COMBAT: { type: Number, default: 0 },
LPS_DRIFT_RIDING: { type: Number, default: 0 },
LPS_DRIFT_OPPORTUNITY: { type: Number, default: 0 },
LPS_DRIFT_ENDURANCE: { type: Number, default: 0 }
},
{ _id: false }
);
const settingsSchema = new Schema<ISettings>(
{
FriendInvRestriction: String,
GiftMode: String,
GuildInvRestriction: String,
ShowFriendInvNotifications: Boolean,
TradingRulesConfirmed: Boolean,
SubscribedToSurveys: Boolean
},
{ _id: false }
);
const consumedSchuitsSchema = new Schema<IConsumedSuit>(
{
s: String,
c: colorSchema
},
{ _id: false }
);
const helminthFoodRecordSchema = new Schema<IHelminthFoodRecord>(
{
ItemType: String,
Date: Number
},
{ _id: false }
);
const helminthResourceSchema = new Schema<IHelminthResource>(
{
ItemType: String,
Count: Number,
RecentlyConvertedResources: { type: [helminthFoodRecordSchema], default: undefined }
},
{ _id: false }
);
const missionSchema = new Schema<IMissionDatabase>(
{
Tag: String,
Completes: { type: Number, default: 0 },
Tier: { type: Number, required: false }
},
{ _id: false }
);
const questProgressSchema = new Schema<IQuestStage>(
{
c: Number,
i: Boolean,
m: Boolean,
b: []
},
{ _id: false }
);
const questKeysSchema = new Schema<IQuestKeyDatabase>(
{
Progress: { type: [questProgressSchema], default: [] },
unlock: Boolean,
Completed: Boolean,
CustomData: String,
CompletionDate: Date,
ItemType: String
},
{
_id: false
}
);
questKeysSchema.set("toJSON", {
transform(_doc, ret: Record<string, any>) {
const questKeysDatabase = ret as IQuestKeyDatabase;
if (questKeysDatabase.CompletionDate) {
(questKeysDatabase as IQuestKeyClient).CompletionDate = toMongoDate(questKeysDatabase.CompletionDate);
}
}
});
export const fusionTreasuresSchema = new Schema<IFusionTreasure>().add(typeCountSchema).add({ Sockets: Number });
const hybridFusionTreasuresSchema = new Schema<IHybridFusionTreasure>({
ItemType: String,
Sockets: Number
});
const invasionProgressSchema = new Schema<IInvasionProgressDatabase>(
{
invasionId: Schema.Types.ObjectId,
Delta: Number,
AttackerScore: Number,
DefenderScore: Number
},
{ _id: false }
);
invasionProgressSchema.set("toJSON", {
transform(_doc, obj: Record<string, any>) {
const db = obj as IInvasionProgressDatabase;
const client = obj as IInvasionProgressClient;
client._id = toOid(db.invasionId);
delete obj.invasionId;
delete obj.__v;
}
});
const spectreLoadoutsSchema = new Schema<ISpectreLoadout>(
{
ItemType: String,
Suits: String,
LongGuns: String,
LongGunsModularParts: { type: [String], default: undefined },
Pistols: String,
PistolsModularParts: { type: [String], default: undefined },
Melee: String,
MeleeModularParts: { type: [String], default: undefined }
},
{ _id: false }
);
const weaponSkinsSchema = new Schema<IWeaponSkinDatabase>(
{
ItemType: String,
Favorite: Boolean,
IsNew: Boolean,
UpgradeType: String,
UpgradeFingerprint: String
},
{ id: false }
);
weaponSkinsSchema.virtual("ItemId").get(function () {
return { $oid: this._id.toString() };
});
weaponSkinsSchema.set("toJSON", {
virtuals: true,
transform(_doc, ret: Record<string, any>) {
delete ret._id;
delete ret.__v;
}
});
const tauntSchema = new Schema<ITaunt>(
{
node: String,
state: String
},
{ _id: false }
);
const periodicMissionCompletionsSchema = new Schema<IPeriodicMissionCompletionDatabase>(
{
date: Date,
tag: String,
count: Number
},
{ _id: false }
);
periodicMissionCompletionsSchema.set("toJSON", {
transform(_doc, ret: Record<string, any>) {
const periodicMissionCompletionDatabase = ret as IPeriodicMissionCompletionDatabase;
(periodicMissionCompletionDatabase as unknown as IPeriodicMissionCompletionResponse).date = toMongoDate(
periodicMissionCompletionDatabase.date
);
}
});
const loreFragmentScansSchema = new Schema<ILoreFragmentScan>(
{
Progress: Number,
Region: String,
ItemType: String
},
{ _id: false }
);
// const lotusCustomizationSchema = new Schema<ILotusCustomization>().add(ItemConfigSchema).add({
// Persona: String
// });
// Laxer schema for cleanupInventory
const lotusCustomizationSchema = new Schema<ILotusCustomization>(
{
Skins: [String],
pricol: colorSchema,
attcol: Schema.Types.Mixed,
sigcol: Schema.Types.Mixed,
eyecol: Schema.Types.Mixed,
facial: Schema.Types.Mixed,
cloth: Schema.Types.Mixed,
syancol: Schema.Types.Mixed,
Persona: String
},
{ _id: false }
);
const evolutionProgressSchema = new Schema<IEvolutionProgress>(
{
Progress: Number,
Rank: Number,
ItemType: String
},
{ _id: false }
);
const countedStoreItemSchema = new Schema<ICountedStoreItem>(
{
StoreItem: String,
ItemCount: Number
},
{ _id: false }
);
const endlessXpRewardSchema = new Schema<IEndlessXpReward>(
{
RequiredTotalXp: Number,
Rewards: [countedStoreItemSchema]
},
{ _id: false }
);
const endlessXpProgressSchema = new Schema<IEndlessXpProgressDatabase>(
{
Category: { type: String, required: true },
Earn: { type: Number, default: 0 },
Claim: { type: Number, default: 0 },
BonusAvailable: Date,
Expiry: Date,
Choices: { type: [String], required: true },
PendingRewards: { type: [endlessXpRewardSchema], default: [] }
},
{ _id: false }
);
endlessXpProgressSchema.set("toJSON", {
transform(_doc, ret: Record<string, any>) {
const db = ret as IEndlessXpProgressDatabase;
const client = ret as IEndlessXpProgressClient;
if (db.BonusAvailable) {
client.BonusAvailable = toMongoDate(db.BonusAvailable);
}
if (db.Expiry) {
client.Expiry = toMongoDate(db.Expiry);
}
}
});
const descentLevelRewardSchema = new Schema<IDescentLevelReward>(
{
FloorCheckpoint: Number,
Rewards: [countedStoreItemSchema]
},
{ _id: false }
);
const descentCategoryRewardSchema = new Schema<IDescentCategoryRewardDatabase>(
{
Category: { type: String, required: true },
Expiry: Date,
FloorClaimed: { type: Number, default: 0 },
PendingRewards: { type: [descentLevelRewardSchema], default: [] },
Seed: Number,
SelectedUpgrades: { type: [String], default: [] }
},
{ _id: false }
);
descentCategoryRewardSchema.set("toJSON", {
transform(_doc, ret: Record<string, any>) {
const db = ret as IDescentCategoryRewardDatabase;
const client = ret as IDescentCategoryRewardClient;
client.Expiry = toMongoDate(db.Expiry);
}
});
const crewShipWeaponEmplacementsSchema = new Schema<ICrewShipWeaponEmplacementsDatabase>(
{
PRIMARY_A: EquipmentSelectionSchema,
PRIMARY_B: EquipmentSelectionSchema,
SECONDARY_A: EquipmentSelectionSchema,
SECONDARY_B: EquipmentSelectionSchema
},
{ _id: false }
);
const crewShipWeaponSchema = new Schema<ICrewShipWeaponDatabase>(
{
PILOT: crewShipWeaponEmplacementsSchema,
PORT_GUNS: crewShipWeaponEmplacementsSchema,
STARBOARD_GUNS: crewShipWeaponEmplacementsSchema,
ARTILLERY: crewShipWeaponEmplacementsSchema,
SCANNER: crewShipWeaponEmplacementsSchema
},
{ _id: false }
);
const crewShipCustomizationSchema = new Schema<ICrewShipCustomization>(
{
CrewshipInterior: shipCustomizationSchema
},
{ _id: false }
);
const crewShipMemberSchema = new Schema<ICrewShipMemberDatabase>(
{
ItemId: { type: Schema.Types.ObjectId, required: false },
NemesisFingerprint: { type: BigInt, required: false }
},
{ _id: false }
);
crewShipMemberSchema.set("toJSON", {
virtuals: true,
transform(_doc, obj: Record<string, any>) {
const db = obj as ICrewShipMemberDatabase;
const client = obj as ICrewShipMemberClient;
if (db.ItemId) {
client.ItemId = toOid(db.ItemId);
}
}
});
const crewShipMembersSchema = new Schema<ICrewShipMembersDatabase>(
{
SLOT_A: { type: crewShipMemberSchema, required: false },
SLOT_B: { type: crewShipMemberSchema, required: false },
SLOT_C: { type: crewShipMemberSchema, required: false }
},
{ _id: false }
);
const dialogueGiftSchema = new Schema<IDialogueGift>(
{
Item: { type: String, required: true },
GiftedQuantity: { type: Number, required: true }
},
{ _id: false }
);
const dialogueCounterSchema = new Schema<IDialogueCounter>(
{
Name: { type: String, required: true },
Count: { type: Number, required: true },
Persist: { type: Boolean, required: true }
},
{ _id: false }
);
const completedDialogueSchema = new Schema<ICompletedDialogue>(
{
Id: { type: String, required: true },
Persist: { type: Boolean, required: false },
Booleans: { type: [String], required: true },
Counters: { type: [dialogueCounterSchema], required: false },
Choices: { type: [Number], required: true }
},
{ _id: false }
);
const dialogueSchema = new Schema<IDialogueDatabase>(
{
Rank: { type: Number, required: true },
Chemistry: { type: Number, required: true },
AvailableDate: { type: Date, required: true },
AvailableGiftDate: { type: Date, required: true },
RankUpExpiry: { type: Date, required: true },
BountyChemExpiry: { type: Date, required: true },
QueuedDialogues: { type: [String], default: [] },
Gifts: { type: [dialogueGiftSchema], default: [] },
Booleans: { type: [String], default: [] },
Counters: { type: [dialogueCounterSchema], required: false },
Completed: { type: [completedDialogueSchema], default: [] },
DialogueName: String
},
{ _id: false }
);
dialogueSchema.set("toJSON", {
virtuals: true,
transform(_doc, ret: Record<string, any>) {
const db = ret as IDialogueDatabase;
const client = ret as IDialogueClient;
client.AvailableDate = toMongoDate(db.AvailableDate);
client.AvailableGiftDate = toMongoDate(db.AvailableGiftDate);
client.RankUpExpiry = toMongoDate(db.RankUpExpiry);
client.BountyChemExpiry = toMongoDate(db.BountyChemExpiry);
}
});
const dialogueResetDateSchema = new Schema<IDialogueResetDateDatabase>(
{
Date: { type: Date, required: true },
Pack: { type: String, required: true },
Resets: { type: Number, required: true }
},
{ _id: false }
);
dialogueResetDateSchema.set("toJSON", {
virtuals: true,
transform(_doc, ret: Record<string, any>) {
const db = ret as IDialogueResetDateDatabase;
const client = ret as IDialogueResetDateClient;
client.Date = toMongoDate(db.Date);
}
});
const dialogueHistorySchema = new Schema<IDialogueHistoryDatabase>(
{
YearIteration: { type: Number, required: false },
Resets: { type: Number, required: false },
ResetDates: { type: [dialogueResetDateSchema], required: false },
Dialogues: { type: [dialogueSchema], required: false }
},
{ _id: false }
);
const traitsSchema = new Schema<ITraits>(
{
BaseColor: String,
SecondaryColor: String,
TertiaryColor: String,
AccentColor: String,
EyeColor: String,
FurPattern: String,
Personality: String,
BodyType: String,
Head: { type: String, required: false },
Tail: { type: String, required: false }
},
{ _id: false }
);
const kubrowPetPrintSchema = new Schema<IKubrowPetPrintDatabase>(
{
ItemType: String,
Name: String,
IsMale: Boolean,
Size: Number,
DominantTraits: traitsSchema,
RecessiveTraits: traitsSchema
},
{ id: false }
);
kubrowPetPrintSchema.set("toJSON", {
virtuals: true,
transform(_doc, obj: Record<string, any>) {
const db = obj as IKubrowPetPrintDatabase;
const client = obj as IKubrowPetPrintClient;
client.ItemId = toOid(db._id);
delete obj._id;
delete obj.__v;
}
});
const detailsSchema = new Schema<IKubrowPetDetailsDatabase>(
{
Name: String,
IsPuppy: Boolean,
HasCollar: Boolean,
PrintsRemaining: Number,
Status: String,
HatchDate: Date,
DominantTraits: traitsSchema,
RecessiveTraits: traitsSchema,
IsMale: Boolean,
Size: Number
},
{ _id: false }
);
detailsSchema.set("toJSON", {
transform(_doc, returnedObject: Record<string, any>) {
delete returnedObject.__v;
const db = returnedObject as IKubrowPetDetailsDatabase;
const client = returnedObject as IKubrowPetDetailsClient;
if (db.HatchDate) {
client.HatchDate = toMongoDate(db.HatchDate);
}
}
});
const EquipmentSchema = new Schema<IEquipmentDatabase>(
{
ItemType: String,
Configs: { type: [{ type: ItemConfigSchema, required: true }], default: [] },
UpgradeVer: { type: Number, default: 101 },
XP: { type: Number, default: 0 },
Features: Number,
Polarized: Number,
Polarity: [polaritySchema],
FocusLens: String,
ModSlotPurchases: Number,
CustomizationSlotPurchases: Number,
UpgradeType: String,
UpgradeFingerprint: String,
ItemName: String,
InfestationDate: Date,
InfestationDays: Number,
InfestationType: String,
ModularParts: { type: [String], default: undefined },
Expiry: Date,
SkillTree: String,
OffensiveUpgrade: String,
DefensiveUpgrade: String,
UpgradesExpiry: Date,
UmbraDate: Date,
ArchonCrystalUpgrades: { type: [ArchonCrystalUpgradeSchema], default: undefined },
Weapon: crewShipWeaponSchema,
Customization: crewShipCustomizationSchema,
RailjackImage: FlavourItemSchema,
SlotLevels: { type: [Number], default: undefined },
CrewMembers: crewShipMembersSchema,
Favorite: Boolean,
IsNew: Boolean,
AltWeaponModeId: Types.ObjectId,
UpgradeNodes: Number,
ExtraRemaining: Number
},
{ id: false }
);
EquipmentSchema.virtual("ItemId").get(function () {
return { $oid: this._id.toString() } satisfies IOid;
});
EquipmentSchema.set("toJSON", {
virtuals: true,
transform(_document, returnedObject: Record<string, any>) {
delete returnedObject._id;
delete returnedObject.__v;
const db = returnedObject as IEquipmentDatabase;
const client = returnedObject as IEquipmentClient;
if (db.InfestationDate) {
client.InfestationDate = toMongoDate(db.InfestationDate);
}
if (db.UpgradesExpiry) {
client.UpgradesExpiry = toMongoDate(db.UpgradesExpiry);
}
if (db.UmbraDate) {
client.UmbraDate = toMongoDate(db.UmbraDate);
}
if (db.AltWeaponModeId) {
client.AltWeaponModeId = toOid(db.AltWeaponModeId);
}
if (client.ArchonCrystalUpgrades) {
// For some reason, mongoose turns empty objects here into nulls, so we have to fix it.
client.ArchonCrystalUpgrades = client.ArchonCrystalUpgrades.map(x => (x as unknown) ?? {});
}
}
});
const kubrowPetSchema = new Schema<IKubrowPetDatabase>().add(EquipmentSchema).add({
Details: { type: detailsSchema, required: true }
});
const equipmentFields: Record<string, { type: [Schema]; required: true }> = {
KubrowPets: { type: [kubrowPetSchema], required: true }
};
equipmentKeys.forEach(key => {
if (key != "KubrowPets") {
equipmentFields[key] = { type: [EquipmentSchema], required: true };
}
});
const pendingRecipeSchema = new Schema<IPendingRecipeDatabase>(
{
ItemType: String,
CompletionDate: Date,
TargetFingerprint: String,
LongGuns: { type: [EquipmentSchema], default: undefined },
Pistols: { type: [EquipmentSchema], default: undefined },
Melee: { type: [EquipmentSchema], default: undefined },
SuitToUnbrand: { type: Schema.Types.ObjectId, default: undefined },
KubrowPet: { type: Schema.Types.ObjectId, default: undefined }
},
{ id: false }
);
pendingRecipeSchema.virtual("ItemId").get(function () {
return { $oid: this._id.toString() };
});
pendingRecipeSchema.set("toJSON", {
virtuals: true,
transform(_document, obj: Record<string, any>) {
delete obj._id;
delete obj.__v;
delete obj.LongGuns;
delete obj.Pistols;
delete obj.Melees;
delete obj.SuitToUnbrand;
const client = obj as IPendingRecipeClient;
const db = obj as IPendingRecipeDatabase;
if (db.KubrowPet) {
client.TargetItemId = db.KubrowPet.toString();
delete obj.KubrowPet;
}
client.CompletionDate = {
$date: { $numberLong: db.CompletionDate.getTime().toString() }
};
}
});
const accoladesSchema = new Schema<IAccolades>(
{
Heirloom: Boolean
},
{ _id: false }
);
const infestedFoundrySchema = new Schema<IInfestedFoundryDatabase>(
{
Name: String,
Resources: { type: [helminthResourceSchema], default: undefined },
Slots: Number,
XP: Number,
ConsumedSuits: { type: [consumedSchuitsSchema], default: undefined },
InvigorationIndex: Number,
InvigorationSuitOfferings: { type: [String], default: undefined },
InvigorationsApplied: Number,
LastConsumedSuit: { type: EquipmentSchema, default: undefined },
AbilityOverrideUnlockCooldown: Date
},
{ _id: false }
);
infestedFoundrySchema.set("toJSON", {
transform(_doc, ret: Record<string, any>) {
if (ret.AbilityOverrideUnlockCooldown) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
ret.AbilityOverrideUnlockCooldown = toMongoDate(ret.AbilityOverrideUnlockCooldown);
}
}
});
const markerSchema = new Schema<IMarker>(
{
anchorName: String,
color: Number,
label: String,
x: Number,
y: Number,
z: Number,
showInHud: Boolean
},
{ _id: false }
);
const markerInfoSchema = new Schema<IMarkerInfo>(
{
icon: String,
markers: [markerSchema]
},
{ _id: false }
);
const CustomMarkersSchema = new Schema<ICustomMarkers>(
{
tag: String,
markerInfos: [markerInfoSchema]
},
{ _id: false }
);
const calenderProgressSchema = new Schema<ICalendarProgress>(
{
Version: { type: Number, default: 19 },
Iteration: { type: Number, required: true },
YearProgress: {
Upgrades: { type: [String], default: [] }
},
SeasonProgress: {
SeasonType: { type: String, required: true },
LastCompletedDayIdx: { type: Number, default: -1 },
LastCompletedChallengeDayIdx: { type: Number, default: -1 },
ActivatedChallenges: { type: [String], default: [] }
}
},
{ _id: false }
);
const incentiveStateSchema = new Schema<IIncentiveState>(
{
threshold: Number,
complete: Boolean,
sent: Boolean
},
{ _id: false }
);
const vendorPurchaseHistoryEntrySchema = new Schema<IVendorPurchaseHistoryEntryDatabase>(
{
Expiry: Date,
NumPurchased: Number,
ItemId: String
},
{ _id: false }
);
vendorPurchaseHistoryEntrySchema.set("toJSON", {
transform(_doc, obj: Record<string, any>) {
const db = obj as IVendorPurchaseHistoryEntryDatabase;
const client = obj as IVendorPurchaseHistoryEntryClient;
client.Expiry = toMongoDate(db.Expiry);
}
});
const recentVendorPurchaseSchema = new Schema<IRecentVendorPurchaseDatabase>(
{
VendorType: String,
PurchaseHistory: [vendorPurchaseHistoryEntrySchema]
},
{ _id: false }
);
const collectibleEntrySchema = new Schema<ICollectibleEntry>(
{
CollectibleType: String,
Count: Number,
Tracking: String,
ReqScans: Number,
IncentiveStates: [incentiveStateSchema]
},
{ _id: false }
);
const songChallengeSchema = new Schema<ISongChallenge>(
{
Song: String,
Difficulties: [Number]
},
{ _id: false }
);
const pendingCouponSchema = new Schema<IPendingCouponDatabase>(
{
Expiry: { type: Date, default: new Date(0) },
Discount: { type: Number, default: 0 }
},
{ _id: false }
);
pendingCouponSchema.set("toJSON", {
transform(_doc, ret: Record<string, any>) {
(ret as IPendingCouponClient).Expiry = toMongoDate((ret as IPendingCouponDatabase).Expiry);
}
});
const libraryPersonalProgressSchema = new Schema<ILibraryPersonalProgress>(
{
TargetType: String,
Scans: Number,
Completed: Boolean
},
{ _id: false }
);
const libraryDailyTaskInfoSchema = new Schema<ILibraryDailyTaskInfo>(
{
EnemyTypes: [String],
EnemyLocTag: String,
EnemyIcon: String,
Scans: Number,
ScansRequired: Number,
RewardStoreItem: String,
RewardQuantity: Number,
RewardStanding: Number
},
{ _id: false }
);
const infNodeSchema = new Schema<IInfNode>(
{
Node: String,
Influence: Number
},
{ _id: false }
);
const nemesisSchema = new Schema<INemesisDatabase>(
{
fp: { type: BigInt, required: true },
manifest: { type: String, required: true },
KillingSuit: { type: String, required: true },
killingDamageType: { type: Number, required: true },
ShoulderHelmet: { type: String, required: true },
WeaponIdx: { type: Number, required: true },
AgentIdx: { type: Number, required: true },
BirthNode: { type: String, required: true },
Faction: { type: String, default: "FC_GRINEER" },
Rank: { type: Number, default: 0 },
k: { type: Boolean, default: false },
Traded: { type: Boolean, default: false },
d: { type: Date, required: true },
PrevOwners: { type: Number, required: true },
SecondInCommand: { type: Boolean, required: true },
Weakened: { type: Boolean, default: false },
InfNodes: { type: [infNodeSchema], required: true },
HenchmenKilled: { type: Number, default: 0 },
HintProgress: { type: Number, default: 0 },
Hints: { type: [Number], default: [] },
GuessHistory: { type: [Number], default: [] },
MissionCount: { type: Number, default: 0 },
LastEnc: { type: Number, default: 0 }
},
{ _id: false }
);
nemesisSchema.set("toJSON", {
virtuals: true,
transform(_doc, obj: Record<string, any>) {
const db = obj as INemesisDatabase;
const client = obj as INemesisClient;
client.d = toMongoDate(db.d);
delete obj._id;
delete obj.__v;
}
});
const alignmentSchema = new Schema<IAlignment>(
{
Alignment: Number,
Wisdom: Number
},
{ _id: false }
);
const lastSortieRewardSchema = new Schema<ILastSortieRewardDatabase>(
{
SortieId: Schema.Types.ObjectId,
StoreItem: String,
Manifest: String
},
{ _id: false }
);
lastSortieRewardSchema.set("toJSON", {
virtuals: true,
transform(_doc, obj: Record<string, any>) {
const db = obj as ILastSortieRewardDatabase;
const client = obj as ILastSortieRewardClient;
client.SortieId = toOid(db.SortieId);
delete obj._id;
delete obj.__v;
}
});
const rewardAttenutationSchema = new Schema<IRewardAttenuation>(
{
Tag: { type: String, required: true },
Atten: { type: Number, required: true }
},
{ _id: false }
);
const lockedWeaponGroupSchema = new Schema<ILockedWeaponGroupDatabase>(
{
s: Schema.Types.ObjectId,
p: Schema.Types.ObjectId,
l: Schema.Types.ObjectId,
m: Schema.Types.ObjectId,
sn: Schema.Types.ObjectId
},
{ _id: false }
);
const hubNpcCustomizationSchema = new Schema<IHubNpcCustomization>(
{
Colors: colorSchema,
Pattern: String,
Tag: String
},
{ _id: false }
);
const journalEntrySchema = new Schema<IJournalEntry>(
{
EntryType: String,
Progress: Number
},
{ _id: false }
);
const nokkoColonySchema = new Schema<INokkoColony>(
{
FeedLevel: Number,
JournalEntries: [journalEntrySchema]
},
{ _id: false }
);
const challengeInstanceStateParamSchema = new Schema<IParam>(
{
n: String,
v: String
},
{ _id: false }
);
const challengeInstanceStateSchema = new Schema<IChallengeInstanceStateDatabase>({
Progress: Number,
params: [challengeInstanceStateParamSchema],
IsRewardCollected: Boolean
});
challengeInstanceStateSchema.set("toJSON", {
virtuals: true,
transform(_doc, obj: Record<string, any>) {
const db = obj as IChallengeInstanceStateDatabase;
const client = obj as IChallengeInstanceStateClient;
client.id = toOid(db._id);
delete obj._id;
delete obj.__v;
}
});
const sketchSchema = new Schema<ISketch>(
{
decoId: { type: String, required: true },
canvas: { type: String, required: false }
},
{ _id: false }
);
const weekGuildVaultBonusRewardSchema = new Schema<IWeekGuildVaultBonusReward>(
{
RewardClaimed: { type: Boolean, required: true },
PointThreshold: { type: Number, required: true },
ItemCount: { type: Number, required: true },
Reward: { type: String, required: true }
},
{ _id: false }
);
const weeklyGuildVaultBonusSchema = new Schema<IWeeklyGuildVaultBonus>(
{
Progress: Number,
WeekCount: { type: Number, required: true },
BonusRegion: { type: String, required: true },
Rewards: { type: [weekGuildVaultBonusRewardSchema], required: true }
},
{ _id: false }
);
const miscAccountDataSchema = new Schema<IMiscAccountData>(
{
PropertyName: { type: String, required: true },
Json: { type: String, required: true }
},
{ _id: false }
);
const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
{
accountOwnerId: Schema.Types.ObjectId,
// SNS account cheats
skipAllDialogue: Boolean,
skipAllPopups: Boolean,
dontSubtractPurchaseCreditCost: Boolean,
dontSubtractPurchasePlatinumCost: Boolean,
dontSubtractPurchaseItemCost: Boolean,
dontSubtractPurchaseStandingCost: Boolean,
dontSubtractKuvaForRivens: Boolean,
dontSubtractVoidTraces: Boolean,
dontSubtractConsumables: Boolean,
dontSubtractKeys: Boolean,
finishInvasionsInOneMission: Boolean,
infiniteCredits: Boolean,
infinitePlatinum: Boolean,
infiniteEndo: Boolean,
infiniteDirac: Boolean,
infiniteRegalAya: Boolean,
infiniteRevives: Boolean,
infiniteTrades: Boolean,
infiniteGifts: Boolean,
infiniteHelminthMaterials: Boolean,
universalPolarityEverywhere: Boolean,
unlockDoubleCapacityPotatoesEverywhere: Boolean,
unlockExilusEverywhere: Boolean,
unlockArcanesEverywhere: Boolean,
alertsRepeatable: Boolean,
syndicateMissionsRepeatable: Boolean,
instantFinishRivenChallenge: Boolean,
noDailyStandingLimits: Boolean,
noDailyFocusLimit: Boolean,
noArgonCrystalDecay: Boolean,
noMasteryRankUpCooldown: Boolean,
noVendorPurchaseLimits: Boolean,
noNodeEntryFees: Boolean,
noDeathMarks: Boolean,
noNemesis: Boolean,
noKimCooldowns: Boolean,
noBlessingCooldown: Boolean,
claimingBlueprintRefundsIngredients: Boolean,
instantResourceExtractorDrones: Boolean,
noResourceExtractorDronesDamage: Boolean,
missionsCanGiveAllRelics: Boolean,
exceptionalRelicsAlwaysGiveBronzeReward: Boolean,
flawlessRelicsAlwaysGiveSilverReward: Boolean,
radiantRelicsAlwaysGiveGoldReward: Boolean,
disableDailyTribute: Boolean,
incrementDailyTributeBy50: Boolean,
tradesDontTouchInventory: Boolean, // API-only cheat for bot developers
nemesisHenchmenKillsMultiplierGrineer: Number,
nemesisHenchmenKillsMultiplierCorpus: Number,
nemesisAntivirusGainMultiplier: Number,
nemesisHintProgressMultiplierGrineer: Number,
nemesisHintProgressMultiplierCorpus: Number,
nemesisExtraWeapon: Number,
spoofMasteryRank: Number,
dailyTributeRewardMultiplier: Number,
relicRewardItemCountMultiplier: Number,
relicPlatinumBonusCommon: Number,
relicPlatinumBonusUncommon: Number,
relicPlatinumBonusRare: Number,
teralystCapturePlatinumBonus: Number,
gantulystCapturePlatinumBonus: Number,
hydrolystCapturePlatinumBonus: Number,
nightwaveStandingMultiplier: Number,
Created: Date,
SubscribedToEmails: { type: Number, default: 0 },
SubscribedToEmailsPersonalized: { type: Number, default: 0 },
RewardSeed: BigInt,
// Temporary data so we can show all relic rewards from an endless mission at EOM
MissionRelicRewards: { type: [typeCountSchema], default: undefined },
//Credit
RegularCredits: { type: Number, default: 0 },
//Platinum
PremiumCredits: { type: Number, default: 0 },
//Gift Platinum(Non trade)
PremiumCreditsFree: { type: Number, default: 0 },
pendingPremiumCredits: Number,
//Endo
FusionPoints: { type: Number, default: 0 },
//Dirac
CrewShipFusionPoints: { type: Number, default: 0 },
//Regal Aya
PrimeTokens: { type: Number, default: 0 },
//Slots
SuitBin: { type: slotsBinSchema, default: { Slots: 3 } },
WeaponBin: { type: slotsBinSchema, default: { Slots: 11 } },
SentinelBin: { type: slotsBinSchema, default: { Slots: 10 } },
SpaceSuitBin: { type: slotsBinSchema, default: { Slots: 4 } },
SpaceWeaponBin: { type: slotsBinSchema, default: { Slots: 4 } },
PvpBonusLoadoutBin: { type: slotsBinSchema, default: { Slots: 0 } },
PveBonusLoadoutBin: { type: slotsBinSchema, default: { Slots: 0 } },
RandomModBin: { type: slotsBinSchema, default: { Slots: 15 } },
OperatorAmpBin: { type: slotsBinSchema, default: { Slots: 8 } },
CrewShipSalvageBin: { type: slotsBinSchema, default: { Slots: 8 } },
MechBin: { type: slotsBinSchema, default: { Slots: 4 } },
CrewMemberBin: { type: slotsBinSchema, default: { Slots: 3 } },
PetBin: { type: slotsBinSchema, default: { Slots: 2 } },
...equipmentFields,
//How many trades do you have left
TradesRemaining: { type: Number, default: 0 },
//How many gifts do you have left
GiftsRemaining: { type: Number, default: 8 },
//Syndicate currently being pledged to.
SupportedSyndicate: String,
//Current Syndicates rank\exp
Affiliations: [affiliationsSchema],
//Syndicates Missions completed(Navigation->Syndicate)
CompletedSyndicates: [String],
//Daily Syndicates exp
DailyAffiliation: { type: Number, default: 16000 },
DailyAffiliationPvp: { type: Number, default: 16000 },
DailyAffiliationLibrary: { type: Number, default: 16000 },
DailyAffiliationCetus: { type: Number, default: 16000 },
DailyAffiliationQuills: { type: Number, default: 16000 },
DailyAffiliationSolaris: { type: Number, default: 16000 },
DailyAffiliationVentkids: { type: Number, default: 16000 },
DailyAffiliationVox: { type: Number, default: 16000 },
DailyAffiliationEntrati: { type: Number, default: 16000 },
DailyAffiliationNecraloid: { type: Number, default: 16000 },
DailyAffiliationZariman: { type: Number, default: 16000 },
DailyAffiliationKahl: { type: Number, default: 16000 },
DailyAffiliationCavia: { type: Number, default: 16000 },
DailyAffiliationHex: { type: Number, default: 16000 },
//Daily Focus limit
DailyFocus: { type: Number, default: 250000 },
//Focus XP per School
FocusXP: focusXPSchema,
//Curent active like Active school focuses is = "Zenurik"
FocusAbility: String,
//The treeways of the Focus school.(Active and passive Ability)
FocusUpgrades: [focusUpgradeSchema],
FocusLoadouts: { type: [focusLoadoutSchema], default: [] },
//Focus 2.0 Pool
FocusCapacity: Number,
OneTimePurchases: { type: [String], default: [] },
//Achievement
ChallengeProgress: [challengeProgressSchema],
//Account Item like Ferrite,Form,Kuva etc
MiscItems: { type: [typeCountSchema], default: [] },
FoundToday: { type: [typeCountSchema], default: undefined },
//Non Upgrade Mods Example:I have 999 item WeaponElectricityDamageMod (only "ItemCount"+"ItemType")
RawUpgrades: [RawUpgrades],
//Upgrade Mods\Riven\Arcane Example:"UpgradeFingerprint"+"ItemType"+""
Upgrades: [upgradeSchema],
//The Mandachord(Octavia) is a step sequencer
StepSequencers: [StepSequencersSchema],
KubrowPetEggs: { type: [], default: undefined },
//Prints Cat(3 Prints)\Kubrow(2 Prints) Pets
KubrowPetPrints: [kubrowPetPrintSchema],
//Item for EquippedGear example:Scaner,LoadoutTechSummon etc
Consumables: [typeCountSchema],
//Weel Emotes+Gear
EquippedEmotes: [String],
EquippedGear: [String],
//Equipped Shawzin
EquippedInstrument: String,
ReceivedStartingGear: Boolean,
ArchwingEnabled: Boolean,
HasOwnedVoidProjectionsPreviously: Boolean,
//Use Operator\Drifter
UseAdultOperatorLoadout: Boolean,
//Operator
OperatorLoadOuts: [operatorConfigSchema],
//Drifter
AdultOperatorLoadOuts: [operatorConfigSchema],
OperatorSuits: { type: [EquipmentSchema], default: [] },
OperatorCustomizationSlotPurchases: Number,
// Kahl
KahlLoadOuts: [operatorConfigSchema],
//LandingCraft like Liset
Ships: { type: [Schema.Types.ObjectId], ref: "Ships" },
// /Lotus/Types/Items/ShipDecos/
ShipDecorations: [typeCountSchema],
receivedThousandYearFishDeco: Boolean,
//Railjack/Components(https://warframe.fandom.com/wiki/Railjack/Components)
CrewShipRawSalvage: [typeCountSchema],
//Default RailJack
CrewShipAmmo: [typeCountSchema],
CrewShipWeaponSkins: [upgradeSchema],
CrewShipSalvagedWeaponSkins: [upgradeSchema],
//RailJack Crew
CrewMembers: [crewMemberSchema],
//Complete Mission\Quests
Missions: [missionSchema],
QuestKeys: [questKeysSchema],
ActiveQuest: { type: String, default: "" },
//item like DojoKey or Boss missions key
LevelKeys: [typeCountSchema],
//Active quests
//Quests: [Schema.Types.Mixed],
//Cosmetics like profile glyphs\Kavasa Prime Kubrow Collar\Game Theme etc
FlavourItems: [FlavourItemSchema],
//Mastery Rank*(Need item XPInfo to rank up)
PlayerLevel: { type: Number, default: 0 },
//Item Mastery Rank exp
XPInfo: [TypeXPItemSchema],
//Mastery Rank next availability
TrainingDate: { type: Date, default: new Date(0) },
//Accolades
Staff: Boolean,
Founder: Number,
Guide: Number,
Moderator: Boolean,
Partner: Boolean,
Accolades: accoladesSchema,
//Not an accolade but unlocks an extra chat
Counselor: Boolean,
//you saw last played Region when you opened the star map
LastRegionPlayed: String,
// U14~U15
MadeStoryModeDecision: Boolean,
//Blueprints for Foundry
Recipes: [typeCountSchema],
//Crafting Blueprint(Item Name + CompletionDate)
PendingRecipes: [pendingRecipeSchema],
//Skins for Suits, Weapons etc.
WeaponSkins: [weaponSkinsSchema],
//Ayatan Item
FusionTreasures: { type: [fusionTreasuresSchema], default: undefined },
HybridFusionTreasures: [hybridFusionTreasuresSchema],
//only used for Maroo apparently - { "node": "TreasureTutorial", "state": "TS_COMPLETED" }
TauntHistory: { type: [tauntSchema], default: undefined },
//noShow2FA,VisitPrimeVault etc
//WebFlags: Schema.Types.Mixed,
//Id CompletedAlerts
CompletedAlerts: [String],
//Warframe\Duviri
StoryModeChoice: { type: String, default: "WARFRAME" },
//Alert->Kuva Siphon
PeriodicMissionCompletions: [periodicMissionCompletionsSchema],
//Codex->LoreFragment
LoreFragmentScans: [loreFragmentScansSchema],
//Resource,Credit,Affinity etc or Bless any boosters
Boosters: [boosterSchema],
BlessingCooldown: Date, // Date convert to IMongoDate
//the color your clan requests like Items/Research/DojoColors/DojoColorPlainsB
ActiveDojoColorResearch: String,
//SentientSpawnChanceBoosters: Schema.Types.Mixed,
QualifyingInvasions: [invasionProgressSchema],
FactionScores: [Number],
// https://warframe.fandom.com/wiki/Specter_(Tenno)
PendingSpectreLoadouts: { type: [spectreLoadoutsSchema], default: undefined },
SpectreLoadouts: { type: [spectreLoadoutsSchema], default: undefined },
//Darvo Deal
UsedDailyDeals: [String],
//New Quest Email
EmailItems: [typeCountSchema],
//Profile->Wishlist
Wishlist: [String],
//https://warframe.fandom.com/wiki/Alignment
//like "Alignment": { "Wisdom": 9, "Alignment": 1 },
Alignment: alignmentSchema,
AlignmentReplay: alignmentSchema,
//https://warframe.fandom.com/wiki/Sortie
CompletedSorties: [String],
LastSortieReward: { type: [lastSortieRewardSchema], default: undefined },
LastLiteSortieReward: { type: [lastSortieRewardSchema], default: undefined },
SortieRewardAttenuation: { type: [rewardAttenutationSchema], default: undefined },
// Resource Extractor Drones
Drones: [droneSchema],
//Active profile icon
ActiveAvatarImageType: String,
// Active profile title
TitleType: String,
// open location store like EidolonPlainsDiscoverable or OrbVallisCaveDiscoverable
DiscoveredMarkers: [discoveredMarkerSchema],
//Open location mission like "JobId" + "StageCompletions"
//CompletedJobs: [Schema.Types.Mixed],
//Game mission\ivent score example "Tag": "WaterFight", "Best": 170, "Count": 1258,
PersonalGoalProgress: { type: [personalGoalProgressSchema], default: undefined },
//Setting interface Style
ThemeStyle: String,
ThemeBackground: String,
ThemeSounds: String,
//Daily LoginRewards
LoginMilestoneRewards: { type: [String], default: [] },
//You first Dialog with NPC or use new Item
NodeIntrosCompleted: [String],
//Current guild id, if applicable.
GuildId: { type: Schema.Types.ObjectId, ref: "Guild" },
//https://warframe.fandom.com/wiki/Heist
//ProfitTaker(1-4) Example:"LocationTag": "EudicoHeists", "Jobs":Mission name
CompletedJobChains: { type: [completedJobChainsSchema], default: undefined },
//Night Wave Challenge
SeasonChallengeHistory: [seasonChallengeHistorySchema],
LibraryPersonalTarget: String,
//Cephalon Simaris Entries Example:"TargetType"+"Scans"(1-10)+"Completed": true|false
LibraryPersonalProgress: { type: [libraryPersonalProgressSchema], default: [] },
//Cephalon Simaris Daily Task
LibraryAvailableDailyTaskInfo: libraryDailyTaskInfoSchema,
LibraryActiveDailyTaskInfo: libraryDailyTaskInfoSchema,
//https://warframe.fandom.com/wiki/Invasion
//InvasionChainProgress: [Schema.Types.Mixed],
//CorpusLich or GrineerLich
NemesisAbandonedRewards: { type: [String], default: [] },
Nemesis: nemesisSchema,
NemesisHistory: { type: [nemesisSchema], default: undefined },
LastNemesisAllySpawnTime: { type: Date, default: undefined },
NemesisTaxedCredits: Number,
//TradingRulesConfirmed,ShowFriendInvNotifications(Option->Social)
Settings: settingsSchema,
//Railjack craft
//https://warframe.fandom.com/wiki/Rising_Tide
PersonalTechProjects: { type: [personalTechProjectSchema], default: [] },
//Modulars lvl and exp(Railjack|Duviri)
//https://warframe.fandom.com/wiki/Intrinsics
PlayerSkills: { type: playerSkillsSchema, default: {} },
//TradeBannedUntil data
//TradeBannedUntil: Schema.Types.Mixed,
//https://warframe.fandom.com/wiki/Helminth
InfestedFoundry: infestedFoundrySchema,
NextRefill: { type: Date, default: undefined },
//Purchase this new permanent skin from the Lotus customization options in Personal Quarters located in your Orbiter.
//https://warframe.fandom.com/wiki/Lotus#The_New_War
LotusCustomization: { type: lotusCustomizationSchema, default: undefined },
//Progress+Rank+ItemType(ZarimanPumpShotgun)
//https://warframe.fandom.com/wiki/Incarnon
EvolutionProgress: { type: [evolutionProgressSchema], default: undefined },
//https://warframe.fandom.com/wiki/Loc-Pin
CustomMarkers: { type: [CustomMarkersSchema], default: undefined },
//Unknown and system
DuviriInfo: DuviriInfoSchema,
duviriSeedRefresh: { type: Date, default: undefined }, // SNS specific field
//Mailbox: MailboxSchema,
HandlerPoints: Number,
ChallengesFixVersion: Number,
PlayedParkourTutorial: Boolean,
//ActiveLandscapeTraps: [Schema.Types.Mixed],
//RepVotes: [Schema.Types.Mixed],
//LeagueTickets: [Schema.Types.Mixed],
HasContributedToDojo: Boolean,
HWIDProtectEnabled: Boolean,
LoadOutPresets: { type: Schema.Types.ObjectId, ref: "Loadout" },
CurrentLoadOutIds: { type: [Schema.Types.ObjectId] },
RandomUpgradesIdentified: Number,
BountyScore: Number,
ChallengeInstanceStates: { type: [challengeInstanceStateSchema], default: undefined },
RecentVendorPurchases: { type: [recentVendorPurchaseSchema], default: undefined },
//Robotics: [Schema.Types.Mixed],
CollectibleSeries: { type: [collectibleEntrySchema], default: undefined },
HasResetAccount: { type: Boolean, default: false },
//Discount Coupon
PendingCoupon: pendingCouponSchema,
//Like BossAladV,BossCaptainVor come for you on missions % chance
DeathMarks: { type: [String], default: [] },
//Zanuka
Harvestable: Boolean,
//Grustag three
DeathSquadable: Boolean,
// Server-only tracking fields for when to give zanuka or G3 death marks
HarvesterPoints: Number,
DeathSquadPoints: Number,
EndlessXP: { type: [endlessXpProgressSchema], default: undefined },
DescentRewards: { type: [descentCategoryRewardSchema], default: undefined },
DialogueHistory: dialogueHistorySchema,
CalendarProgress: calenderProgressSchema,
SongChallenges: { type: [songChallengeSchema], default: undefined },
// Netracells + Deep Archimedea
EntratiVaultCountLastPeriod: { type: Number, default: undefined },
EntratiVaultCountResetDate: { type: Date, default: undefined },
EntratiLabConquestUnlocked: { type: Number, default: undefined },
EntratiLabConquestHardModeStatus: { type: Number, default: undefined },
EntratiLabConquestCacheScoreMission: { type: Number, default: undefined },
EntratiLabConquestActiveFrameVariants: { type: [String], default: undefined },
EchoesHexConquestUnlocked: { type: Number, default: undefined },
EchoesHexConquestHardModeStatus: { type: Number, default: undefined },
EchoesHexConquestCacheScoreMission: { type: Number, default: undefined },
EchoesHexConquestActiveFrameVariants: { type: [String], default: undefined },
EchoesHexConquestActiveStickers: { type: [String], default: undefined },
// G3 + Zanuka
BrandedSuits: { type: [Schema.Types.ObjectId], default: undefined },
LockedWeaponGroup: { type: lockedWeaponGroupSchema, default: undefined },
HubNpcCustomizations: { type: [hubNpcCustomizationSchema], default: undefined },
ClaimedJunctionChallengeRewards: { type: [String], default: undefined },
SpecialItemRewardAttenuation: { type: [rewardAttenutationSchema], default: undefined },
NokkoColony: { type: nokkoColonySchema, default: undefined },
RetroWallpaperId: Number,
RetroFastTyping: Boolean,
RetroPlayAllConvos: Boolean,
RetroDisableKissInboxMessage: Boolean,
Sketches: { type: [sketchSchema], default: undefined },
WeeklyGuildVaultBonusInfo: { type: [weeklyGuildVaultBonusSchema], default: undefined },
MiscAccountData: { type: [miscAccountDataSchema], default: undefined }
},
{ timestamps: { createdAt: "Created", updatedAt: false } }
);
inventorySchema.set("toJSON", {
transform(_document, returnedObject: Record<string, any>) {
delete returnedObject._id;
delete returnedObject.__v;
delete returnedObject.accountOwnerId;
delete returnedObject.MissionRelicRewards;
delete returnedObject.HarvesterPoints;
delete returnedObject.DeathSquadPoints;
delete returnedObject.NemesisTaxedCredits;
delete returnedObject.duviriSeedRefresh;
delete returnedObject.HybridFusionTreasures;
delete returnedObject.receivedThousandYearFishDeco;
const inventoryDatabase = returnedObject as Partial<IInventoryDatabase>;
const inventoryResponse = returnedObject as IInventoryClient;
if (inventoryDatabase.Created) {
inventoryResponse.Created = toMongoDate(inventoryDatabase.Created);
}
if (inventoryDatabase.CurrentLoadOutIds) {
inventoryResponse.CurrentLoadOutIds = inventoryDatabase.CurrentLoadOutIds.map(x => toOid(x));
}
if (inventoryDatabase.TrainingDate) {
inventoryResponse.TrainingDate = toMongoDate(inventoryDatabase.TrainingDate);
}
if (inventoryDatabase.GuildId) {
inventoryResponse.GuildId = toOid(inventoryDatabase.GuildId);
}
if (inventoryDatabase.BlessingCooldown) {
inventoryResponse.BlessingCooldown = toMongoDate(inventoryDatabase.BlessingCooldown);
}
if (inventoryDatabase.LastNemesisAllySpawnTime) {
inventoryResponse.LastNemesisAllySpawnTime = toMongoDate(inventoryDatabase.LastNemesisAllySpawnTime);
}
if (inventoryDatabase.NextRefill) {
inventoryResponse.NextRefill = toMongoDate(inventoryDatabase.NextRefill);
}
if (inventoryDatabase.EntratiVaultCountResetDate) {
inventoryResponse.EntratiVaultCountResetDate = toMongoDate(inventoryDatabase.EntratiVaultCountResetDate);
}
if (inventoryDatabase.BrandedSuits) {
inventoryResponse.BrandedSuits = inventoryDatabase.BrandedSuits.map(toOid);
}
if (inventoryDatabase.LockedWeaponGroup) {
inventoryResponse.LockedWeaponGroup = {
s: toOid(inventoryDatabase.LockedWeaponGroup.s),
l: inventoryDatabase.LockedWeaponGroup.l ? toOid(inventoryDatabase.LockedWeaponGroup.l) : undefined,
p: inventoryDatabase.LockedWeaponGroup.p ? toOid(inventoryDatabase.LockedWeaponGroup.p) : undefined,
m: inventoryDatabase.LockedWeaponGroup.m ? toOid(inventoryDatabase.LockedWeaponGroup.m) : undefined,
sn: inventoryDatabase.LockedWeaponGroup.sn ? toOid(inventoryDatabase.LockedWeaponGroup.sn) : undefined
};
}
}
});
inventorySchema.index({ accountOwnerId: 1 }, { unique: true });
// type overwrites for subdocuments/subdocument arrays
export type InventoryDocumentProps = {
FlavourItems: Types.DocumentArray<IFlavourItem>;
RawUpgrades: Types.DocumentArray<IRawUpgrade>;
Upgrades: Types.DocumentArray<IUpgradeDatabase>;
MiscItems: Types.DocumentArray<IMiscItem>;
Boosters: Types.DocumentArray<IBooster>;
OperatorLoadOuts: Types.DocumentArray<IOperatorConfigDatabase>;
AdultOperatorLoadOuts: Types.DocumentArray<IOperatorConfigDatabase>;
KahlLoadOuts: Types.DocumentArray<IOperatorConfigDatabase>;
OperatorSuits: Types.DocumentArray<IEquipmentDatabase>;
PendingRecipes: Types.DocumentArray<IPendingRecipeDatabase>;
WeaponSkins: Types.DocumentArray<IWeaponSkinDatabase>;
QuestKeys: Types.DocumentArray<IQuestKeyDatabase>;
Drones: Types.DocumentArray<IDroneDatabase>;
CrewShipWeaponSkins: Types.DocumentArray<IUpgradeDatabase>;
CrewShipSalvagedWeaponSkins: Types.DocumentArray<IUpgradeDatabase>;
PersonalTechProjects: Types.DocumentArray<IPersonalTechProjectDatabase>;
CrewMembers: Types.DocumentArray<ICrewMemberDatabase>;
KubrowPets: Types.DocumentArray<IKubrowPetDatabase>;
KubrowPetPrints: Types.DocumentArray<IKubrowPetPrintDatabase>;
HybridFusionTreasures: Types.DocumentArray<IHybridFusionTreasure>;
StepSequencers: Types.DocumentArray<IStepSequencerDatabase>;
} & { [K in TEquipmentKey]: Types.DocumentArray<IEquipmentDatabase> };
type InventoryModelType = Model<IInventoryDatabase, {}, InventoryDocumentProps>;
export const Inventory = model<IInventoryDatabase, InventoryModelType>("Inventory", inventorySchema);
export type TInventoryDatabaseDocument = Document<unknown, {}, IInventoryDatabase> &
Omit<
IInventoryDatabase & {
_id: Types.ObjectId;
} & {
__v: number;
},
keyof InventoryDocumentProps
> &
InventoryDocumentProps;
import type { Document, Model } from "mongoose";
import { Schema, Types, model } from "mongoose";
import type {
IRawUpgrade,
IMiscItem,
IInventoryDatabase,
IBooster,
IInventoryClient,
ISlots,
IDuviriInfo,
IPendingRecipeDatabase,
IPendingRecipeClient,
IFocusXP,
IFocusUpgrade,
ITypeXPItem,
IChallengeProgress,
IStepSequencerDatabase,
IAffiliation,
INotePacks,
ICompletedJobChain,
ISeasonChallenge,
IPlayerSkills,
ISettings,
IInfestedFoundryDatabase,
IHelminthResource,
IMissionDatabase,
IConsumedSuit,
IQuestStage,
IQuestKeyDatabase,
IQuestKeyClient,
IFusionTreasure,
ISpectreLoadout,
IWeaponSkinDatabase,
ITaunt,
IPeriodicMissionCompletionDatabase,
IPeriodicMissionCompletionResponse,
ILoreFragmentScan,
IEvolutionProgress,
IEndlessXpProgressDatabase,
IEndlessXpProgressClient,
IHelminthFoodRecord,
IDialogueHistoryDatabase,
IDialogueDatabase,
IDialogueGift,
ICompletedDialogue,
IDialogueClient,
IUpgradeDatabase,
TEquipmentKey,
ICustomMarkers,
IMarkerInfo,
IMarker,
ICalendarProgress,
IPendingCouponDatabase,
IPendingCouponClient,
ILibraryDailyTaskInfo,
IDroneDatabase,
IDroneClient,
IAlignment,
ICollectibleEntry,
IIncentiveState,
ISongChallenge,
ILibraryPersonalProgress,
IRecentVendorPurchaseDatabase,
IVendorPurchaseHistoryEntryDatabase,
IVendorPurchaseHistoryEntryClient,
INemesisDatabase,
INemesisClient,
IInfNode,
IDiscoveredMarker,
IWeeklyMission,
ILockedWeaponGroupDatabase,
IPersonalTechProjectDatabase,
IPersonalTechProjectClient,
ILastSortieRewardDatabase,
ILastSortieRewardClient,
ICrewMemberSkill,
ICrewMemberSkillEfficiency,
ICrewMemberDatabase,
ICrewMemberClient,
IRewardAttenuation,
IInvasionProgressDatabase,
IInvasionProgressClient,
IAccolades,
IHubNpcCustomization,
IEndlessXpReward,
IGoalProgressDatabase,
IGoalProgressClient,
IKubrowPetPrintClient,
IKubrowPetPrintDatabase,
INokkoColony,
IJournalEntry,
IDialogueResetDateClient,
IDialogueResetDateDatabase,
IDescentLevelReward,
IDescentCategoryRewardClient,
IDescentCategoryRewardDatabase,
IFocusLoadoutDatabase,
IChallengeInstanceStateDatabase,
IChallengeInstanceStateClient,
IParam,
IDialogueCounter,
ISketch,
IHybridFusionTreasure,
IWeeklyGuildVaultBonus,
IWeekGuildVaultBonusReward,
IMiscAccountData
} from "../../types/inventoryTypes/inventoryTypes.ts";
import { equipmentKeys } from "../../types/inventoryTypes/inventoryTypes.ts";
import type { IOid, ITypeCount } from "../../types/commonTypes.ts";
import type {
IAbilityOverride,
ICrewShipCustomization,
IFlavourItem,
IItemConfig,
ILotusCustomization,
IOperatorConfigDatabase,
IPolarity
} from "../../types/inventoryTypes/commonInventoryTypes.ts";
import { toMongoDate, toOid } from "../../helpers/inventoryHelpers.ts";
import { EquipmentSelectionSchema } from "./loadoutModel.ts";
import type { ICountedStoreItem } from "warframe-public-export-plus";
import { colorSchema, shipCustomizationSchema } from "../commonModel.ts";
import type {
IArchonCrystalUpgrade,
ICrewShipMemberClient,
ICrewShipMemberDatabase,
ICrewShipMembersDatabase,
ICrewShipWeaponDatabase,
ICrewShipWeaponEmplacementsDatabase,
IEquipmentClient,
IEquipmentDatabase,
IKubrowPetDatabase,
IKubrowPetDetailsClient,
IKubrowPetDetailsDatabase,
ITraits
} from "../../types/equipmentTypes.ts";
export const typeCountSchema = new Schema<ITypeCount>({ ItemType: String, ItemCount: Number }, { _id: false });
typeCountSchema.set("toJSON", {
transform(_doc, obj: Record<string, any>) {
// Ensure numbers comfortably fit in a 32-bit integer so the client's in-memory value doesn't overflow or underflow.
if (obj.ItemCount > 999_999_999) {
obj.ItemCount = 999_999_999;
} else if (obj.ItemCount < -999_999_999) {
obj.ItemCount = -999_999_999;
}
}
});
const focusXPSchema = new Schema<IFocusXP>(
{
AP_POWER: Number,
AP_TACTIC: Number,
AP_DEFENSE: Number,
AP_ATTACK: Number,
AP_WARD: Number
},
{ _id: false }
);
const focusUpgradeSchema = new Schema<IFocusUpgrade>(
{
ItemType: String,
Level: Number,
IsUniversal: Boolean,
IsActive: Schema.Types.Mixed,
TotalCapacity: Number,
CooldownTier: Number,
IsCooldownReductionActive: Boolean
},
{ _id: false }
);
const focusLoadoutSchema = new Schema<IFocusLoadoutDatabase>(
{
Preset: EquipmentSelectionSchema,
FocusAbility: String
},
{ _id: false }
);
const polaritySchema = new Schema<IPolarity>(
{
Slot: Number,
Value: String
},
{ _id: false }
);
const abilityOverrideSchema = new Schema<IAbilityOverride>(
{
Ability: String,
Index: Number
},
{ _id: false }
);
const operatorConfigSchema = new Schema<IOperatorConfigDatabase>(
{
Skins: [String],
pricol: colorSchema,
attcol: colorSchema,
sigcol: colorSchema,
eyecol: colorSchema,
facial: colorSchema,
syancol: colorSchema,
cloth: colorSchema,
Upgrades: [String],
Name: String, // not sure if possible in operator
ugly: Boolean // not sure if possible in operator
},
{ id: false }
);
operatorConfigSchema.virtual("ItemId").get(function () {
return { $oid: this._id.toString() } satisfies IOid;
});
operatorConfigSchema.set("toJSON", {
virtuals: true,
transform(_document, returnedObject: Record<string, any>) {
delete returnedObject._id;
delete returnedObject.__v;
}
});
///TODO: clearly seperate the different config schemas. (suit and weapon and so on)
const ItemConfigSchema = new Schema<IItemConfig>(
{
Skins: [String],
pricol: colorSchema,
attcol: colorSchema,
sigcol: colorSchema,
eyecol: colorSchema,
facial: colorSchema,
syancol: colorSchema,
cloth: colorSchema,
Upgrades: [String],
Songs: {
type: [
{
m: String,
b: String,
p: String,
s: String
}
],
default: undefined
},
Name: String,
AbilityOverride: abilityOverrideSchema,
PvpUpgrades: [String],
ugly: Boolean
},
{ _id: false }
);
ItemConfigSchema.set("toJSON", {
transform(_document, returnedObject: Record<string, any>) {
delete returnedObject.__v;
}
});
const ArchonCrystalUpgradeSchema = new Schema<IArchonCrystalUpgrade>(
{
UpgradeType: String,
Color: String
},
{ _id: false }
);
const boosterSchema = new Schema<IBooster>(
{
ExpiryDate: Number,
ItemType: String
},
{ _id: false }
);
const RawUpgrades = new Schema<IRawUpgrade>(
{
ItemType: String,
ItemCount: Number
},
{ id: false }
);
RawUpgrades.virtual("LastAdded").get(function () {
return { $oid: this._id.toString() } satisfies IOid;
});
RawUpgrades.set("toJSON", {
virtuals: true,
transform(_document, returnedObject: Record<string, any>) {
delete returnedObject._id;
delete returnedObject.__v;
}
});
const upgradeSchema = new Schema<IUpgradeDatabase>(
{
UpgradeFingerprint: String,
PendingRerollFingerprint: { type: String, required: false },
ItemType: String
},
{ id: false }
);
upgradeSchema.virtual("ItemId").get(function () {
return toOid(this._id);
});
upgradeSchema.set("toJSON", {
virtuals: true,
transform(_document, returnedObject: Record<string, any>) {
delete returnedObject._id;
delete returnedObject.__v;
}
});
const crewMemberSkillSchema = new Schema<ICrewMemberSkill>(
{
Assigned: Number
},
{ _id: false }
);
const crewMemberSkillEfficiencySchema = new Schema<ICrewMemberSkillEfficiency>(
{
PILOTING: crewMemberSkillSchema,
GUNNERY: crewMemberSkillSchema,
ENGINEERING: crewMemberSkillSchema,
COMBAT: crewMemberSkillSchema,
SURVIVABILITY: crewMemberSkillSchema
},
{ _id: false }
);
const crewMemberSchema = new Schema<ICrewMemberDatabase>(
{
ItemType: { type: String, required: true },
NemesisFingerprint: { type: BigInt, default: 0n },
Seed: { type: BigInt, default: 0n },
AssignedRole: Number,
SkillEfficiency: crewMemberSkillEfficiencySchema,
WeaponConfigIdx: Number,
WeaponId: { type: Schema.Types.ObjectId, default: "000000000000000000000000" },
XP: { type: Number, default: 0 },
PowersuitType: { type: String, required: false },
Configs: [{ type: ItemConfigSchema, required: true }],
SecondInCommand: { type: Boolean, default: false }
},
{ id: false }
);
crewMemberSchema.set("toJSON", {
virtuals: true,
transform(_doc, obj: Record<string, any>) {
const db = obj as ICrewMemberDatabase;
const client = obj as ICrewMemberClient;
client.WeaponId = toOid(db.WeaponId);
client.ItemId = toOid(db._id);
delete obj._id;
delete obj.__v;
}
});
const slotsBinSchema = new Schema<ISlots>(
{
Slots: Number,
Extra: Number
},
{ _id: false }
);
const FlavourItemSchema = new Schema(
{
ItemType: String
},
{ _id: false }
);
FlavourItemSchema.set("toJSON", {
transform(_document, returnedObject: Record<string, any>) {
delete returnedObject._id;
delete returnedObject.__v;
}
});
/*const MailboxSchema = new Schema<IMailboxDatabase>(
{
LastInboxId: Schema.Types.ObjectId
},
{ id: false, _id: false }
);
MailboxSchema.set("toJSON", {
transform(_document, returnedObject: Record<string, any>) {
const mailboxDatabase = returnedObject as HydratedDocument<IMailboxDatabase, { __v?: number }>;
delete mailboxDatabase.__v;
(returnedObject as IMailboxClient).LastInboxId = toOid(mailboxDatabase.LastInboxId);
}
});*/
const DuviriInfoSchema = new Schema<IDuviriInfo>(
{
Seed: { type: BigInt, required: true },
NumCompletions: { type: Number, required: true }
},
{
_id: false,
id: false
}
);
DuviriInfoSchema.set("toJSON", {
transform(_document, returnedObject: Record<string, any>) {
delete returnedObject.__v;
}
});
const TypeXPItemSchema = new Schema<ITypeXPItem>(
{
ItemType: String,
XP: Number
},
{ _id: false }
);
const droneSchema = new Schema<IDroneDatabase>(
{
ItemType: String,
CurrentHP: Number,
RepairStart: { type: Date, default: undefined },
DeployTime: { type: Date, default: undefined },
System: Number,
DamageTime: { type: Date, default: undefined },
PendingDamage: Number,
ResourceType: String,
ResourceCount: Number
},
{ id: false }
);
droneSchema.set("toJSON", {
virtuals: true,
transform(_document, obj: Record<string, any>) {
const client = obj as IDroneClient;
const db = obj as IDroneDatabase;
client.ItemId = toOid(db._id);
if (db.RepairStart) {
client.RepairStart = toMongoDate(db.RepairStart);
}
delete db.DeployTime;
delete db.System;
delete db.DamageTime;
delete db.PendingDamage;
delete db.ResourceType;
delete db.ResourceCount;
delete obj._id;
delete obj.__v;
}
});
const discoveredMarkerSchema = new Schema<IDiscoveredMarker>(
{
tag: String,
discoveryState: [Number]
},
{ _id: false }
);
const personalGoalProgressSchema = new Schema<IGoalProgressDatabase>(
{
Best: Number,
Count: Number,
Tag: String,
goalId: Types.ObjectId
},
{ _id: false }
);
personalGoalProgressSchema.set("toJSON", {
virtuals: true,
transform(_doc, obj: Record<string, any>) {
const db = obj as IGoalProgressDatabase;
const client = obj as IGoalProgressClient;
client._id = toOid(db.goalId);
delete obj.goalId;
delete obj.__v;
}
});
const challengeProgressSchema = new Schema<IChallengeProgress>(
{
Progress: Number,
Completed: { type: [String], default: undefined },
ReceivedJunctionReward: Boolean,
Name: { type: String, required: true }
},
{ _id: false }
);
const notePacksSchema = new Schema<INotePacks>(
{
MELODY: String,
BASS: String,
PERCUSSION: String
},
{ _id: false }
);
const StepSequencersSchema = new Schema<IStepSequencerDatabase>(
{
NotePacks: notePacksSchema,
FingerPrint: String,
Name: String
},
{ id: false }
);
StepSequencersSchema.virtual("ItemId").get(function () {
return { $oid: this._id.toString() } satisfies IOid;
});
StepSequencersSchema.set("toJSON", {
virtuals: true,
transform(_document, returnedObject: Record<string, any>) {
delete returnedObject._id;
delete returnedObject.__v;
}
});
const weeklyMissionSchema = new Schema<IWeeklyMission>(
{
MissionIndex: Number,
CompletedMission: Boolean,
JobManifest: String,
Challenges: [String],
ChallengesReset: Boolean,
WeekCount: Number
},
{ _id: false }
);
const affiliationsSchema = new Schema<IAffiliation>(
{
Initiated: Boolean,
Standing: Number,
Title: Number,
FreeFavorsEarned: { type: [Number], default: undefined },
FreeFavorsUsed: { type: [Number], default: undefined },
WeeklyMissions: { type: [weeklyMissionSchema], default: undefined },
Tag: String
},
{ _id: false }
);
const completedJobChainsSchema = new Schema<ICompletedJobChain>(
{
LocationTag: String,
Jobs: [String]
},
{ _id: false }
);
const seasonChallengeHistorySchema = new Schema<ISeasonChallenge>(
{
challenge: String,
id: String
},
{ _id: false }
);
const personalTechProjectSchema = new Schema<IPersonalTechProjectDatabase>(
{
State: Number,
ReqCredits: Number,
ItemType: String,
ProductCategory: String,
CategoryItemId: Schema.Types.ObjectId,
ReqItems: { type: [typeCountSchema], default: undefined },
HasContributions: Boolean,
CompletionDate: Date
},
{ id: false }
);
personalTechProjectSchema.virtual("ItemId").get(function () {
return { $oid: this._id.toString() };
});
personalTechProjectSchema.set("toJSON", {
virtuals: true,
transform(_doc, ret: Record<string, any>) {
delete ret._id;
delete ret.__v;
const db = ret as IPersonalTechProjectDatabase;
const client = ret as IPersonalTechProjectClient;
if (db.CategoryItemId) {
client.CategoryItemId = toOid(db.CategoryItemId);
}
if (db.CompletionDate) {
client.CompletionDate = toMongoDate(db.CompletionDate);
}
}
});
const playerSkillsSchema = new Schema<IPlayerSkills>(
{
LPP_SPACE: { type: Number, default: 0 },
LPS_PILOTING: { type: Number, default: 0 },
LPS_GUNNERY: { type: Number, default: 0 },
LPS_TACTICAL: { type: Number, default: 0 },
LPS_ENGINEERING: { type: Number, default: 0 },
LPS_COMMAND: { type: Number, default: 0 },
LPP_DRIFTER: { type: Number, default: 0 },
LPS_DRIFT_COMBAT: { type: Number, default: 0 },
LPS_DRIFT_RIDING: { type: Number, default: 0 },
LPS_DRIFT_OPPORTUNITY: { type: Number, default: 0 },
LPS_DRIFT_ENDURANCE: { type: Number, default: 0 }
},
{ _id: false }
);
const settingsSchema = new Schema<ISettings>(
{
FriendInvRestriction: String,
GiftMode: String,
GuildInvRestriction: String,
ShowFriendInvNotifications: Boolean,
TradingRulesConfirmed: Boolean,
SubscribedToSurveys: Boolean
},
{ _id: false }
);
const consumedSchuitsSchema = new Schema<IConsumedSuit>(
{
s: String,
c: colorSchema
},
{ _id: false }
);
const helminthFoodRecordSchema = new Schema<IHelminthFoodRecord>(
{
ItemType: String,
Date: Number
},
{ _id: false }
);
const helminthResourceSchema = new Schema<IHelminthResource>(
{
ItemType: String,
Count: Number,
RecentlyConvertedResources: { type: [helminthFoodRecordSchema], default: undefined }
},
{ _id: false }
);
const missionSchema = new Schema<IMissionDatabase>(
{
Tag: String,
Completes: { type: Number, default: 0 },
Tier: { type: Number, required: false }
},
{ _id: false }
);
const questProgressSchema = new Schema<IQuestStage>(
{
c: Number,
i: Boolean,
m: Boolean,
b: []
},
{ _id: false }
);
const questKeysSchema = new Schema<IQuestKeyDatabase>(
{
Progress: { type: [questProgressSchema], default: [] },
unlock: Boolean,
Completed: Boolean,
CustomData: String,
CompletionDate: Date,
ItemType: String
},
{
_id: false
}
);
questKeysSchema.set("toJSON", {
transform(_doc, ret: Record<string, any>) {
const questKeysDatabase = ret as IQuestKeyDatabase;
if (questKeysDatabase.CompletionDate) {
(questKeysDatabase as IQuestKeyClient).CompletionDate = toMongoDate(questKeysDatabase.CompletionDate);
}
}
});
export const fusionTreasuresSchema = new Schema<IFusionTreasure>().add(typeCountSchema).add({ Sockets: Number });
const hybridFusionTreasuresSchema = new Schema<IHybridFusionTreasure>({
ItemType: String,
Sockets: Number
});
const invasionProgressSchema = new Schema<IInvasionProgressDatabase>(
{
invasionId: Schema.Types.ObjectId,
Delta: Number,
AttackerScore: Number,
DefenderScore: Number
},
{ _id: false }
);
invasionProgressSchema.set("toJSON", {
transform(_doc, obj: Record<string, any>) {
const db = obj as IInvasionProgressDatabase;
const client = obj as IInvasionProgressClient;
client._id = toOid(db.invasionId);
delete obj.invasionId;
delete obj.__v;
}
});
const spectreLoadoutsSchema = new Schema<ISpectreLoadout>(
{
ItemType: String,
Suits: String,
LongGuns: String,
LongGunsModularParts: { type: [String], default: undefined },
Pistols: String,
PistolsModularParts: { type: [String], default: undefined },
Melee: String,
MeleeModularParts: { type: [String], default: undefined }
},
{ _id: false }
);
const weaponSkinsSchema = new Schema<IWeaponSkinDatabase>(
{
ItemType: String,
Favorite: Boolean,
IsNew: Boolean,
UpgradeType: String,
UpgradeFingerprint: String
},
{ id: false }
);
weaponSkinsSchema.virtual("ItemId").get(function () {
return { $oid: this._id.toString() };
});
weaponSkinsSchema.set("toJSON", {
virtuals: true,
transform(_doc, ret: Record<string, any>) {
delete ret._id;
delete ret.__v;
}
});
const tauntSchema = new Schema<ITaunt>(
{
node: String,
state: String
},
{ _id: false }
);
const periodicMissionCompletionsSchema = new Schema<IPeriodicMissionCompletionDatabase>(
{
date: Date,
tag: String,
count: Number
},
{ _id: false }
);
periodicMissionCompletionsSchema.set("toJSON", {
transform(_doc, ret: Record<string, any>) {
const periodicMissionCompletionDatabase = ret as IPeriodicMissionCompletionDatabase;
(periodicMissionCompletionDatabase as unknown as IPeriodicMissionCompletionResponse).date = toMongoDate(
periodicMissionCompletionDatabase.date
);
}
});
const loreFragmentScansSchema = new Schema<ILoreFragmentScan>(
{
Progress: Number,
Region: String,
ItemType: String
},
{ _id: false }
);
// const lotusCustomizationSchema = new Schema<ILotusCustomization>().add(ItemConfigSchema).add({
// Persona: String
// });
// Laxer schema for cleanupInventory
const lotusCustomizationSchema = new Schema<ILotusCustomization>(
{
Skins: [String],
pricol: colorSchema,
attcol: Schema.Types.Mixed,
sigcol: Schema.Types.Mixed,
eyecol: Schema.Types.Mixed,
facial: Schema.Types.Mixed,
cloth: Schema.Types.Mixed,
syancol: Schema.Types.Mixed,
Persona: String
},
{ _id: false }
);
const evolutionProgressSchema = new Schema<IEvolutionProgress>(
{
Progress: Number,
Rank: Number,
ItemType: String
},
{ _id: false }
);
const countedStoreItemSchema = new Schema<ICountedStoreItem>(
{
StoreItem: String,
ItemCount: Number
},
{ _id: false }
);
const endlessXpRewardSchema = new Schema<IEndlessXpReward>(
{
RequiredTotalXp: Number,
Rewards: [countedStoreItemSchema]
},
{ _id: false }
);
const endlessXpProgressSchema = new Schema<IEndlessXpProgressDatabase>(
{
Category: { type: String, required: true },
Earn: { type: Number, default: 0 },
Claim: { type: Number, default: 0 },
BonusAvailable: Date,
Expiry: Date,
Choices: { type: [String], required: true },
PendingRewards: { type: [endlessXpRewardSchema], default: [] }
},
{ _id: false }
);
endlessXpProgressSchema.set("toJSON", {
transform(_doc, ret: Record<string, any>) {
const db = ret as IEndlessXpProgressDatabase;
const client = ret as IEndlessXpProgressClient;
if (db.BonusAvailable) {
client.BonusAvailable = toMongoDate(db.BonusAvailable);
}
if (db.Expiry) {
client.Expiry = toMongoDate(db.Expiry);
}
}
});
const descentLevelRewardSchema = new Schema<IDescentLevelReward>(
{
FloorCheckpoint: Number,
Rewards: [countedStoreItemSchema]
},
{ _id: false }
);
const descentCategoryRewardSchema = new Schema<IDescentCategoryRewardDatabase>(
{
Category: { type: String, required: true },
Expiry: Date,
FloorClaimed: { type: Number, default: 0 },
PendingRewards: { type: [descentLevelRewardSchema], default: [] },
Seed: Number,
SelectedUpgrades: { type: [String], default: [] }
},
{ _id: false }
);
descentCategoryRewardSchema.set("toJSON", {
transform(_doc, ret: Record<string, any>) {
const db = ret as IDescentCategoryRewardDatabase;
const client = ret as IDescentCategoryRewardClient;
client.Expiry = toMongoDate(db.Expiry);
}
});
const crewShipWeaponEmplacementsSchema = new Schema<ICrewShipWeaponEmplacementsDatabase>(
{
PRIMARY_A: EquipmentSelectionSchema,
PRIMARY_B: EquipmentSelectionSchema,
SECONDARY_A: EquipmentSelectionSchema,
SECONDARY_B: EquipmentSelectionSchema
},
{ _id: false }
);
const crewShipWeaponSchema = new Schema<ICrewShipWeaponDatabase>(
{
PILOT: crewShipWeaponEmplacementsSchema,
PORT_GUNS: crewShipWeaponEmplacementsSchema,
STARBOARD_GUNS: crewShipWeaponEmplacementsSchema,
ARTILLERY: crewShipWeaponEmplacementsSchema,
SCANNER: crewShipWeaponEmplacementsSchema
},
{ _id: false }
);
const crewShipCustomizationSchema = new Schema<ICrewShipCustomization>(
{
CrewshipInterior: shipCustomizationSchema
},
{ _id: false }
);
const crewShipMemberSchema = new Schema<ICrewShipMemberDatabase>(
{
ItemId: { type: Schema.Types.ObjectId, required: false },
NemesisFingerprint: { type: BigInt, required: false }
},
{ _id: false }
);
crewShipMemberSchema.set("toJSON", {
virtuals: true,
transform(_doc, obj: Record<string, any>) {
const db = obj as ICrewShipMemberDatabase;
const client = obj as ICrewShipMemberClient;
if (db.ItemId) {
client.ItemId = toOid(db.ItemId);
}
}
});
const crewShipMembersSchema = new Schema<ICrewShipMembersDatabase>(
{
SLOT_A: { type: crewShipMemberSchema, required: false },
SLOT_B: { type: crewShipMemberSchema, required: false },
SLOT_C: { type: crewShipMemberSchema, required: false }
},
{ _id: false }
);
const dialogueGiftSchema = new Schema<IDialogueGift>(
{
Item: { type: String, required: true },
GiftedQuantity: { type: Number, required: true }
},
{ _id: false }
);
const dialogueCounterSchema = new Schema<IDialogueCounter>(
{
Name: { type: String, required: true },
Count: { type: Number, required: true },
Persist: { type: Boolean, required: true }
},
{ _id: false }
);
const completedDialogueSchema = new Schema<ICompletedDialogue>(
{
Id: { type: String, required: true },
Persist: { type: Boolean, required: false },
Booleans: { type: [String], required: true },
Counters: { type: [dialogueCounterSchema], required: false },
Choices: { type: [Number], required: true }
},
{ _id: false }
);
const dialogueSchema = new Schema<IDialogueDatabase>(
{
Rank: { type: Number, required: true },
Chemistry: { type: Number, required: true },
AvailableDate: { type: Date, required: true },
AvailableGiftDate: { type: Date, required: true },
RankUpExpiry: { type: Date, required: true },
BountyChemExpiry: { type: Date, required: true },
QueuedDialogues: { type: [String], default: [] },
Gifts: { type: [dialogueGiftSchema], default: [] },
Booleans: { type: [String], default: [] },
Counters: { type: [dialogueCounterSchema], required: false },
Completed: { type: [completedDialogueSchema], default: [] },
DialogueName: String
},
{ _id: false }
);
dialogueSchema.set("toJSON", {
virtuals: true,
transform(_doc, ret: Record<string, any>) {
const db = ret as IDialogueDatabase;
const client = ret as IDialogueClient;
client.AvailableDate = toMongoDate(db.AvailableDate);
client.AvailableGiftDate = toMongoDate(db.AvailableGiftDate);
client.RankUpExpiry = toMongoDate(db.RankUpExpiry);
client.BountyChemExpiry = toMongoDate(db.BountyChemExpiry);
}
});
const dialogueResetDateSchema = new Schema<IDialogueResetDateDatabase>(
{
Date: { type: Date, required: true },
Pack: { type: String, required: true },
Resets: { type: Number, required: true }
},
{ _id: false }
);
dialogueResetDateSchema.set("toJSON", {
virtuals: true,
transform(_doc, ret: Record<string, any>) {
const db = ret as IDialogueResetDateDatabase;
const client = ret as IDialogueResetDateClient;
client.Date = toMongoDate(db.Date);
}
});
const dialogueHistorySchema = new Schema<IDialogueHistoryDatabase>(
{
YearIteration: { type: Number, required: false },
Resets: { type: Number, required: false },
ResetDates: { type: [dialogueResetDateSchema], required: false },
Dialogues: { type: [dialogueSchema], required: false }
},
{ _id: false }
);
const traitsSchema = new Schema<ITraits>(
{
BaseColor: String,
SecondaryColor: String,
TertiaryColor: String,
AccentColor: String,
EyeColor: String,
FurPattern: String,
Personality: String,
BodyType: String,
Head: { type: String, required: false },
Tail: { type: String, required: false }
},
{ _id: false }
);
const kubrowPetPrintSchema = new Schema<IKubrowPetPrintDatabase>(
{
ItemType: String,
Name: String,
IsMale: Boolean,
Size: Number,
DominantTraits: traitsSchema,
RecessiveTraits: traitsSchema
},
{ id: false }
);
kubrowPetPrintSchema.set("toJSON", {
virtuals: true,
transform(_doc, obj: Record<string, any>) {
const db = obj as IKubrowPetPrintDatabase;
const client = obj as IKubrowPetPrintClient;
client.ItemId = toOid(db._id);
delete obj._id;
delete obj.__v;
}
});
const detailsSchema = new Schema<IKubrowPetDetailsDatabase>(
{
Name: String,
IsPuppy: Boolean,
HasCollar: Boolean,
PrintsRemaining: Number,
Status: String,
HatchDate: Date,
DominantTraits: traitsSchema,
RecessiveTraits: traitsSchema,
IsMale: Boolean,
Size: Number
},
{ _id: false }
);
detailsSchema.set("toJSON", {
transform(_doc, returnedObject: Record<string, any>) {
delete returnedObject.__v;
const db = returnedObject as IKubrowPetDetailsDatabase;
const client = returnedObject as IKubrowPetDetailsClient;
if (db.HatchDate) {
client.HatchDate = toMongoDate(db.HatchDate);
}
}
});
const EquipmentSchema = new Schema<IEquipmentDatabase>(
{
ItemType: String,
Configs: { type: [{ type: ItemConfigSchema, required: true }], default: [] },
UpgradeVer: { type: Number, default: 101 },
XP: { type: Number, default: 0 },
Features: Number,
Polarized: Number,
Polarity: [polaritySchema],
FocusLens: String,
ModSlotPurchases: Number,
CustomizationSlotPurchases: Number,
UpgradeType: String,
UpgradeFingerprint: String,
ItemName: String,
InfestationDate: Date,
InfestationDays: Number,
InfestationType: String,
ModularParts: { type: [String], default: undefined },
Expiry: Date,
SkillTree: String,
OffensiveUpgrade: String,
DefensiveUpgrade: String,
UpgradesExpiry: Date,
UmbraDate: Date,
ArchonCrystalUpgrades: { type: [ArchonCrystalUpgradeSchema], default: undefined },
Weapon: crewShipWeaponSchema,
Customization: crewShipCustomizationSchema,
RailjackImage: FlavourItemSchema,
SlotLevels: { type: [Number], default: undefined },
CrewMembers: crewShipMembersSchema,
Favorite: Boolean,
IsNew: Boolean,
AltWeaponModeId: Types.ObjectId,
UpgradeNodes: Number,
ExtraRemaining: Number
},
{ id: false }
);
EquipmentSchema.virtual("ItemId").get(function () {
return { $oid: this._id.toString() } satisfies IOid;
});
EquipmentSchema.set("toJSON", {
virtuals: true,
transform(_document, returnedObject: Record<string, any>) {
delete returnedObject._id;
delete returnedObject.__v;
const db = returnedObject as IEquipmentDatabase;
const client = returnedObject as IEquipmentClient;
if (db.InfestationDate) {
client.InfestationDate = toMongoDate(db.InfestationDate);
}
if (db.UpgradesExpiry) {
client.UpgradesExpiry = toMongoDate(db.UpgradesExpiry);
}
if (db.UmbraDate) {
client.UmbraDate = toMongoDate(db.UmbraDate);
}
if (db.AltWeaponModeId) {
client.AltWeaponModeId = toOid(db.AltWeaponModeId);
}
if (client.ArchonCrystalUpgrades) {
// For some reason, mongoose turns empty objects here into nulls, so we have to fix it.
client.ArchonCrystalUpgrades = client.ArchonCrystalUpgrades.map(x => (x as unknown) ?? {});
}
}
});
const kubrowPetSchema = new Schema<IKubrowPetDatabase>().add(EquipmentSchema).add({
Details: { type: detailsSchema, required: true }
});
const equipmentFields: Record<string, { type: [Schema]; required: true }> = {
KubrowPets: { type: [kubrowPetSchema], required: true }
};
equipmentKeys.forEach(key => {
if (key != "KubrowPets") {
equipmentFields[key] = { type: [EquipmentSchema], required: true };
}
});
const pendingRecipeSchema = new Schema<IPendingRecipeDatabase>(
{
ItemType: String,
CompletionDate: Date,
TargetFingerprint: String,
LongGuns: { type: [EquipmentSchema], default: undefined },
Pistols: { type: [EquipmentSchema], default: undefined },
Melee: { type: [EquipmentSchema], default: undefined },
SuitToUnbrand: { type: Schema.Types.ObjectId, default: undefined },
KubrowPet: { type: Schema.Types.ObjectId, default: undefined }
},
{ id: false }
);
pendingRecipeSchema.virtual("ItemId").get(function () {
return { $oid: this._id.toString() };
});
pendingRecipeSchema.set("toJSON", {
virtuals: true,
transform(_document, obj: Record<string, any>) {
delete obj._id;
delete obj.__v;
delete obj.LongGuns;
delete obj.Pistols;
delete obj.Melees;
delete obj.SuitToUnbrand;
const client = obj as IPendingRecipeClient;
const db = obj as IPendingRecipeDatabase;
if (db.KubrowPet) {
client.TargetItemId = db.KubrowPet.toString();
delete obj.KubrowPet;
}
client.CompletionDate = {
$date: { $numberLong: db.CompletionDate.getTime().toString() }
};
}
});
const accoladesSchema = new Schema<IAccolades>(
{
Heirloom: Boolean
},
{ _id: false }
);
const infestedFoundrySchema = new Schema<IInfestedFoundryDatabase>(
{
Name: String,
Resources: { type: [helminthResourceSchema], default: undefined },
Slots: Number,
XP: Number,
ConsumedSuits: { type: [consumedSchuitsSchema], default: undefined },
InvigorationIndex: Number,
InvigorationSuitOfferings: { type: [String], default: undefined },
InvigorationsApplied: Number,
LastConsumedSuit: { type: EquipmentSchema, default: undefined },
AbilityOverrideUnlockCooldown: Date
},
{ _id: false }
);
infestedFoundrySchema.set("toJSON", {
transform(_doc, ret: Record<string, any>) {
if (ret.AbilityOverrideUnlockCooldown) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
ret.AbilityOverrideUnlockCooldown = toMongoDate(ret.AbilityOverrideUnlockCooldown);
}
}
});
const markerSchema = new Schema<IMarker>(
{
anchorName: String,
color: Number,
label: String,
x: Number,
y: Number,
z: Number,
showInHud: Boolean
},
{ _id: false }
);
const markerInfoSchema = new Schema<IMarkerInfo>(
{
icon: String,
markers: [markerSchema]
},
{ _id: false }
);
const CustomMarkersSchema = new Schema<ICustomMarkers>(
{
tag: String,
markerInfos: [markerInfoSchema]
},
{ _id: false }
);
const calenderProgressSchema = new Schema<ICalendarProgress>(
{
Version: { type: Number, default: 19 },
Iteration: { type: Number, required: true },
YearProgress: {
Upgrades: { type: [String], default: [] }
},
SeasonProgress: {
SeasonType: { type: String, required: true },
LastCompletedDayIdx: { type: Number, default: -1 },
LastCompletedChallengeDayIdx: { type: Number, default: -1 },
ActivatedChallenges: { type: [String], default: [] }
}
},
{ _id: false }
);
const incentiveStateSchema = new Schema<IIncentiveState>(
{
threshold: Number,
complete: Boolean,
sent: Boolean
},
{ _id: false }
);
const vendorPurchaseHistoryEntrySchema = new Schema<IVendorPurchaseHistoryEntryDatabase>(
{
Expiry: Date,
NumPurchased: Number,
ItemId: String
},
{ _id: false }
);
vendorPurchaseHistoryEntrySchema.set("toJSON", {
transform(_doc, obj: Record<string, any>) {
const db = obj as IVendorPurchaseHistoryEntryDatabase;
const client = obj as IVendorPurchaseHistoryEntryClient;
client.Expiry = toMongoDate(db.Expiry);
}
});
const recentVendorPurchaseSchema = new Schema<IRecentVendorPurchaseDatabase>(
{
VendorType: String,
PurchaseHistory: [vendorPurchaseHistoryEntrySchema]
},
{ _id: false }
);
const collectibleEntrySchema = new Schema<ICollectibleEntry>(
{
CollectibleType: String,
Count: Number,
Tracking: String,
ReqScans: Number,
IncentiveStates: [incentiveStateSchema]
},
{ _id: false }
);
const songChallengeSchema = new Schema<ISongChallenge>(
{
Song: String,
Difficulties: [Number]
},
{ _id: false }
);
const pendingCouponSchema = new Schema<IPendingCouponDatabase>(
{
Expiry: { type: Date, default: new Date(0) },
Discount: { type: Number, default: 0 }
},
{ _id: false }
);
pendingCouponSchema.set("toJSON", {
transform(_doc, ret: Record<string, any>) {
(ret as IPendingCouponClient).Expiry = toMongoDate((ret as IPendingCouponDatabase).Expiry);
}
});
const libraryPersonalProgressSchema = new Schema<ILibraryPersonalProgress>(
{
TargetType: String,
Scans: Number,
Completed: Boolean
},
{ _id: false }
);
const libraryDailyTaskInfoSchema = new Schema<ILibraryDailyTaskInfo>(
{
EnemyTypes: [String],
EnemyLocTag: String,
EnemyIcon: String,
Scans: Number,
ScansRequired: Number,
RewardStoreItem: String,
RewardQuantity: Number,
RewardStanding: Number
},
{ _id: false }
);
const infNodeSchema = new Schema<IInfNode>(
{
Node: String,
Influence: Number
},
{ _id: false }
);
const nemesisSchema = new Schema<INemesisDatabase>(
{
fp: { type: BigInt, required: true },
manifest: { type: String, required: true },
KillingSuit: { type: String, required: true },
killingDamageType: { type: Number, required: true },
ShoulderHelmet: { type: String, required: true },
WeaponIdx: { type: Number, required: true },
AgentIdx: { type: Number, required: true },
BirthNode: { type: String, required: true },
Faction: { type: String, default: "FC_GRINEER" },
Rank: { type: Number, default: 0 },
k: { type: Boolean, default: false },
Traded: { type: Boolean, default: false },
d: { type: Date, required: true },
PrevOwners: { type: Number, required: true },
SecondInCommand: { type: Boolean, required: true },
Weakened: { type: Boolean, default: false },
InfNodes: { type: [infNodeSchema], required: true },
HenchmenKilled: { type: Number, default: 0 },
HintProgress: { type: Number, default: 0 },
Hints: { type: [Number], default: [] },
GuessHistory: { type: [Number], default: [] },
MissionCount: { type: Number, default: 0 },
LastEnc: { type: Number, default: 0 }
},
{ _id: false }
);
nemesisSchema.set("toJSON", {
virtuals: true,
transform(_doc, obj: Record<string, any>) {
const db = obj as INemesisDatabase;
const client = obj as INemesisClient;
client.d = toMongoDate(db.d);
delete obj._id;
delete obj.__v;
}
});
const alignmentSchema = new Schema<IAlignment>(
{
Alignment: Number,
Wisdom: Number
},
{ _id: false }
);
const lastSortieRewardSchema = new Schema<ILastSortieRewardDatabase>(
{
SortieId: Schema.Types.ObjectId,
StoreItem: String,
Manifest: String
},
{ _id: false }
);
lastSortieRewardSchema.set("toJSON", {
virtuals: true,
transform(_doc, obj: Record<string, any>) {
const db = obj as ILastSortieRewardDatabase;
const client = obj as ILastSortieRewardClient;
client.SortieId = toOid(db.SortieId);
delete obj._id;
delete obj.__v;
}
});
const rewardAttenutationSchema = new Schema<IRewardAttenuation>(
{
Tag: { type: String, required: true },
Atten: { type: Number, required: true }
},
{ _id: false }
);
const lockedWeaponGroupSchema = new Schema<ILockedWeaponGroupDatabase>(
{
s: Schema.Types.ObjectId,
p: Schema.Types.ObjectId,
l: Schema.Types.ObjectId,
m: Schema.Types.ObjectId,
sn: Schema.Types.ObjectId
},
{ _id: false }
);
const hubNpcCustomizationSchema = new Schema<IHubNpcCustomization>(
{
Colors: colorSchema,
Pattern: String,
Tag: String
},
{ _id: false }
);
const journalEntrySchema = new Schema<IJournalEntry>(
{
EntryType: String,
Progress: Number
},
{ _id: false }
);
const nokkoColonySchema = new Schema<INokkoColony>(
{
FeedLevel: Number,
JournalEntries: [journalEntrySchema]
},
{ _id: false }
);
const challengeInstanceStateParamSchema = new Schema<IParam>(
{
n: String,
v: String
},
{ _id: false }
);
const challengeInstanceStateSchema = new Schema<IChallengeInstanceStateDatabase>({
Progress: Number,
params: [challengeInstanceStateParamSchema],
IsRewardCollected: Boolean
});
challengeInstanceStateSchema.set("toJSON", {
virtuals: true,
transform(_doc, obj: Record<string, any>) {
const db = obj as IChallengeInstanceStateDatabase;
const client = obj as IChallengeInstanceStateClient;
client.id = toOid(db._id);
delete obj._id;
delete obj.__v;
}
});
const sketchSchema = new Schema<ISketch>(
{
decoId: { type: String, required: true },
canvas: { type: String, required: false }
},
{ _id: false }
);
const weekGuildVaultBonusRewardSchema = new Schema<IWeekGuildVaultBonusReward>(
{
RewardClaimed: { type: Boolean, required: true },
PointThreshold: { type: Number, required: true },
ItemCount: { type: Number, required: true },
Reward: { type: String, required: true }
},
{ _id: false }
);
const weeklyGuildVaultBonusSchema = new Schema<IWeeklyGuildVaultBonus>(
{
Progress: Number,
WeekCount: { type: Number, required: true },
BonusRegion: { type: String, required: true },
Rewards: { type: [weekGuildVaultBonusRewardSchema], required: true }
},
{ _id: false }
);
const miscAccountDataSchema = new Schema<IMiscAccountData>(
{
PropertyName: { type: String, required: true },
Json: { type: String, required: true }
},
{ _id: false }
);
const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
{
accountOwnerId: Schema.Types.ObjectId,
// SNS account cheats
skipAllDialogue: Boolean,
skipAllPopups: Boolean,
dontSubtractPurchaseCreditCost: Boolean,
dontSubtractPurchasePlatinumCost: Boolean,
dontSubtractPurchaseItemCost: Boolean,
dontSubtractPurchaseStandingCost: Boolean,
dontSubtractKuvaForRivens: Boolean,
dontSubtractVoidTraces: Boolean,
dontSubtractConsumables: Boolean,
dontSubtractKeys: Boolean,
finishInvasionsInOneMission: Boolean,
infiniteCredits: Boolean,
infinitePlatinum: Boolean,
infiniteEndo: Boolean,
infiniteDirac: Boolean,
infiniteRegalAya: Boolean,
infiniteRevives: Boolean,
infiniteTrades: Boolean,
infiniteGifts: Boolean,
infiniteHelminthMaterials: Boolean,
universalPolarityEverywhere: Boolean,
unlockDoubleCapacityPotatoesEverywhere: Boolean,
unlockExilusEverywhere: Boolean,
unlockArcanesEverywhere: Boolean,
alertsRepeatable: Boolean,
syndicateMissionsRepeatable: Boolean,
instantFinishRivenChallenge: Boolean,
noDailyStandingLimits: Boolean,
noDailyFocusLimit: Boolean,
noArgonCrystalDecay: Boolean,
noMasteryRankUpCooldown: Boolean,
noVendorPurchaseLimits: Boolean,
noNodeEntryFees: Boolean,
noDeathMarks: Boolean,
noNemesis: Boolean,
noKimCooldowns: Boolean,
noBlessingCooldown: Boolean,
claimingBlueprintRefundsIngredients: Boolean,
instantResourceExtractorDrones: Boolean,
noResourceExtractorDronesDamage: Boolean,
missionsCanGiveAllRelics: Boolean,
exceptionalRelicsAlwaysGiveBronzeReward: Boolean,
flawlessRelicsAlwaysGiveSilverReward: Boolean,
radiantRelicsAlwaysGiveGoldReward: Boolean,
disableDailyTribute: Boolean,
incrementDailyTributeBy50: Boolean,
tradesDontTouchInventory: Boolean, // API-only cheat for bot developers
nemesisHenchmenKillsMultiplierGrineer: Number,
nemesisHenchmenKillsMultiplierCorpus: Number,
nemesisAntivirusGainMultiplier: Number,
nemesisHintProgressMultiplierGrineer: Number,
nemesisHintProgressMultiplierCorpus: Number,
nemesisExtraWeapon: Number,
spoofMasteryRank: Number,
dailyTributeRewardMultiplier: Number,
relicRewardItemCountMultiplier: Number,
relicPlatinumBonusCommon: Number,
relicPlatinumBonusUncommon: Number,
relicPlatinumBonusRare: Number,
teralystCapturePlatinumBonus: Number,
gantulystCapturePlatinumBonus: Number,
hydrolystCapturePlatinumBonus: Number,
nightwaveStandingMultiplier: Number,
Created: Date,
SubscribedToEmails: { type: Number, default: 0 },
SubscribedToEmailsPersonalized: { type: Number, default: 0 },
RewardSeed: BigInt,
// Temporary data so we can show all relic rewards from an endless mission at EOM
MissionRelicRewards: { type: [typeCountSchema], default: undefined },
//Credit
RegularCredits: { type: Number, default: 0 },
//Platinum
PremiumCredits: { type: Number, default: 0 },
//Gift Platinum(Non trade)
PremiumCreditsFree: { type: Number, default: 0 },
pendingPremiumCredits: Number,
//Endo
FusionPoints: { type: Number, default: 0 },
//Dirac
CrewShipFusionPoints: { type: Number, default: 0 },
//Regal Aya
PrimeTokens: { type: Number, default: 0 },
//Slots
SuitBin: { type: slotsBinSchema, default: { Slots: 3 } },
WeaponBin: { type: slotsBinSchema, default: { Slots: 11 } },
SentinelBin: { type: slotsBinSchema, default: { Slots: 10 } },
SpaceSuitBin: { type: slotsBinSchema, default: { Slots: 4 } },
SpaceWeaponBin: { type: slotsBinSchema, default: { Slots: 4 } },
PvpBonusLoadoutBin: { type: slotsBinSchema, default: { Slots: 0 } },
PveBonusLoadoutBin: { type: slotsBinSchema, default: { Slots: 0 } },
RandomModBin: { type: slotsBinSchema, default: { Slots: 15 } },
OperatorAmpBin: { type: slotsBinSchema, default: { Slots: 8 } },
CrewShipSalvageBin: { type: slotsBinSchema, default: { Slots: 8 } },
MechBin: { type: slotsBinSchema, default: { Slots: 4 } },
CrewMemberBin: { type: slotsBinSchema, default: { Slots: 3 } },
PetBin: { type: slotsBinSchema, default: { Slots: 2 } },
...equipmentFields,
//How many trades do you have left
TradesRemaining: { type: Number, default: 0 },
//How many gifts do you have left
GiftsRemaining: { type: Number, default: 8 },
//Syndicate currently being pledged to.
SupportedSyndicate: String,
//Current Syndicates rank\exp
Affiliations: [affiliationsSchema],
//Syndicates Missions completed(Navigation->Syndicate)
CompletedSyndicates: [String],
//Daily Syndicates exp
DailyAffiliation: { type: Number, default: 16000 },
DailyAffiliationPvp: { type: Number, default: 16000 },
DailyAffiliationLibrary: { type: Number, default: 16000 },
DailyAffiliationCetus: { type: Number, default: 16000 },
DailyAffiliationQuills: { type: Number, default: 16000 },
DailyAffiliationSolaris: { type: Number, default: 16000 },
DailyAffiliationVentkids: { type: Number, default: 16000 },
DailyAffiliationVox: { type: Number, default: 16000 },
DailyAffiliationEntrati: { type: Number, default: 16000 },
DailyAffiliationNecraloid: { type: Number, default: 16000 },
DailyAffiliationZariman: { type: Number, default: 16000 },
DailyAffiliationKahl: { type: Number, default: 16000 },
DailyAffiliationCavia: { type: Number, default: 16000 },
DailyAffiliationHex: { type: Number, default: 16000 },
//Daily Focus limit
DailyFocus: { type: Number, default: 250000 },
//Focus XP per School
FocusXP: focusXPSchema,
//Curent active like Active school focuses is = "Zenurik"
FocusAbility: String,
//The treeways of the Focus school.(Active and passive Ability)
FocusUpgrades: [focusUpgradeSchema],
FocusLoadouts: { type: [focusLoadoutSchema], default: [] },
//Focus 2.0 Pool
FocusCapacity: Number,
OneTimePurchases: { type: [String], default: [] },
//Achievement
ChallengeProgress: [challengeProgressSchema],
//Account Item like Ferrite,Form,Kuva etc
MiscItems: { type: [typeCountSchema], default: [] },
FoundToday: { type: [typeCountSchema], default: undefined },
//Non Upgrade Mods Example:I have 999 item WeaponElectricityDamageMod (only "ItemCount"+"ItemType")
RawUpgrades: [RawUpgrades],
//Upgrade Mods\Riven\Arcane Example:"UpgradeFingerprint"+"ItemType"+""
Upgrades: [upgradeSchema],
//The Mandachord(Octavia) is a step sequencer
StepSequencers: [StepSequencersSchema],
KubrowPetEggs: { type: [], default: undefined },
//Prints Cat(3 Prints)\Kubrow(2 Prints) Pets
KubrowPetPrints: [kubrowPetPrintSchema],
//Item for EquippedGear example:Scaner,LoadoutTechSummon etc
Consumables: [typeCountSchema],
//Weel Emotes+Gear
EquippedEmotes: [String],
EquippedGear: [String],
//Equipped Shawzin
EquippedInstrument: String,
ReceivedStartingGear: Boolean,
ArchwingEnabled: Boolean,
HasOwnedVoidProjectionsPreviously: Boolean,
//Use Operator\Drifter
UseAdultOperatorLoadout: Boolean,
//Operator
OperatorLoadOuts: [operatorConfigSchema],
//Drifter
AdultOperatorLoadOuts: [operatorConfigSchema],
OperatorSuits: { type: [EquipmentSchema], default: [] },
OperatorCustomizationSlotPurchases: Number,
// Kahl
KahlLoadOuts: [operatorConfigSchema],
//LandingCraft like Liset
Ships: { type: [Schema.Types.ObjectId], ref: "Ships" },
// /Lotus/Types/Items/ShipDecos/
ShipDecorations: [typeCountSchema],
receivedThousandYearFishDeco: Boolean,
//Railjack/Components(https://warframe.fandom.com/wiki/Railjack/Components)
CrewShipRawSalvage: [typeCountSchema],
//Default RailJack
CrewShipAmmo: [typeCountSchema],
CrewShipWeaponSkins: [upgradeSchema],
CrewShipSalvagedWeaponSkins: [upgradeSchema],
//RailJack Crew
CrewMembers: [crewMemberSchema],
//Complete Mission\Quests
Missions: [missionSchema],
QuestKeys: [questKeysSchema],
ActiveQuest: { type: String, default: "" },
//item like DojoKey or Boss missions key
LevelKeys: [typeCountSchema],
//Active quests
//Quests: [Schema.Types.Mixed],
//Cosmetics like profile glyphs\Kavasa Prime Kubrow Collar\Game Theme etc
FlavourItems: [FlavourItemSchema],
//Mastery Rank*(Need item XPInfo to rank up)
PlayerLevel: { type: Number, default: 0 },
//Item Mastery Rank exp
XPInfo: [TypeXPItemSchema],
//Mastery Rank next availability
TrainingDate: { type: Date, default: new Date(0) },
//Accolades
Staff: Boolean,
Founder: Number,
Guide: Number,
Moderator: Boolean,
Partner: Boolean,
Accolades: accoladesSchema,
//Not an accolade but unlocks an extra chat
Counselor: Boolean,
//you saw last played Region when you opened the star map
LastRegionPlayed: String,
// U14~U15
MadeStoryModeDecision: Boolean,
//Blueprints for Foundry
Recipes: [typeCountSchema],
//Crafting Blueprint(Item Name + CompletionDate)
PendingRecipes: [pendingRecipeSchema],
//Skins for Suits, Weapons etc.
WeaponSkins: [weaponSkinsSchema],
//Ayatan Item
FusionTreasures: { type: [fusionTreasuresSchema], default: undefined },
HybridFusionTreasures: [hybridFusionTreasuresSchema],
//only used for Maroo apparently - { "node": "TreasureTutorial", "state": "TS_COMPLETED" }
TauntHistory: { type: [tauntSchema], default: undefined },
//noShow2FA,VisitPrimeVault etc
//WebFlags: Schema.Types.Mixed,
//Id CompletedAlerts
CompletedAlerts: [String],
//Warframe\Duviri
StoryModeChoice: { type: String, default: "WARFRAME" },
//Alert->Kuva Siphon
PeriodicMissionCompletions: [periodicMissionCompletionsSchema],
//Codex->LoreFragment
LoreFragmentScans: [loreFragmentScansSchema],
//Resource,Credit,Affinity etc or Bless any boosters
Boosters: [boosterSchema],
BlessingCooldown: Date, // Date convert to IMongoDate
//the color your clan requests like Items/Research/DojoColors/DojoColorPlainsB
ActiveDojoColorResearch: String,
//SentientSpawnChanceBoosters: Schema.Types.Mixed,
QualifyingInvasions: [invasionProgressSchema],
FactionScores: [Number],
// https://warframe.fandom.com/wiki/Specter_(Tenno)
PendingSpectreLoadouts: { type: [spectreLoadoutsSchema], default: undefined },
SpectreLoadouts: { type: [spectreLoadoutsSchema], default: undefined },
//Darvo Deal
UsedDailyDeals: [String],
//New Quest Email
EmailItems: [typeCountSchema],
//Profile->Wishlist
Wishlist: [String],
//https://warframe.fandom.com/wiki/Alignment
//like "Alignment": { "Wisdom": 9, "Alignment": 1 },
Alignment: alignmentSchema,
AlignmentReplay: alignmentSchema,
//https://warframe.fandom.com/wiki/Sortie
CompletedSorties: [String],
LastSortieReward: { type: [lastSortieRewardSchema], default: undefined },
LastLiteSortieReward: { type: [lastSortieRewardSchema], default: undefined },
SortieRewardAttenuation: { type: [rewardAttenutationSchema], default: undefined },
// Resource Extractor Drones
Drones: [droneSchema],
//Active profile icon
ActiveAvatarImageType: String,
// Active profile title
TitleType: String,
// open location store like EidolonPlainsDiscoverable or OrbVallisCaveDiscoverable
DiscoveredMarkers: [discoveredMarkerSchema],
//Open location mission like "JobId" + "StageCompletions"
//CompletedJobs: [Schema.Types.Mixed],
//Game mission\ivent score example "Tag": "WaterFight", "Best": 170, "Count": 1258,
PersonalGoalProgress: { type: [personalGoalProgressSchema], default: undefined },
//Setting interface Style
ThemeStyle: String,
ThemeBackground: String,
ThemeSounds: String,
//Daily LoginRewards
LoginMilestoneRewards: { type: [String], default: [] },
//You first Dialog with NPC or use new Item
NodeIntrosCompleted: [String],
//Current guild id, if applicable.
GuildId: { type: Schema.Types.ObjectId, ref: "Guild" },
//https://warframe.fandom.com/wiki/Heist
//ProfitTaker(1-4) Example:"LocationTag": "EudicoHeists", "Jobs":Mission name
CompletedJobChains: { type: [completedJobChainsSchema], default: undefined },
//Night Wave Challenge
SeasonChallengeHistory: [seasonChallengeHistorySchema],
LibraryPersonalTarget: String,
//Cephalon Simaris Entries Example:"TargetType"+"Scans"(1-10)+"Completed": true|false
LibraryPersonalProgress: { type: [libraryPersonalProgressSchema], default: [] },
//Cephalon Simaris Daily Task
LibraryAvailableDailyTaskInfo: libraryDailyTaskInfoSchema,
LibraryActiveDailyTaskInfo: libraryDailyTaskInfoSchema,
//https://warframe.fandom.com/wiki/Invasion
//InvasionChainProgress: [Schema.Types.Mixed],
//CorpusLich or GrineerLich
NemesisAbandonedRewards: { type: [String], default: [] },
Nemesis: nemesisSchema,
NemesisHistory: { type: [nemesisSchema], default: undefined },
LastNemesisAllySpawnTime: { type: Date, default: undefined },
NemesisTaxedCredits: Number,
//TradingRulesConfirmed,ShowFriendInvNotifications(Option->Social)
Settings: settingsSchema,
//Railjack craft
//https://warframe.fandom.com/wiki/Rising_Tide
PersonalTechProjects: { type: [personalTechProjectSchema], default: [] },
//Modulars lvl and exp(Railjack|Duviri)
//https://warframe.fandom.com/wiki/Intrinsics
PlayerSkills: { type: playerSkillsSchema, default: {} },
//TradeBannedUntil data
//TradeBannedUntil: Schema.Types.Mixed,
//https://warframe.fandom.com/wiki/Helminth
InfestedFoundry: infestedFoundrySchema,
NextRefill: { type: Date, default: undefined },
//Purchase this new permanent skin from the Lotus customization options in Personal Quarters located in your Orbiter.
//https://warframe.fandom.com/wiki/Lotus#The_New_War
LotusCustomization: { type: lotusCustomizationSchema, default: undefined },
//Progress+Rank+ItemType(ZarimanPumpShotgun)
//https://warframe.fandom.com/wiki/Incarnon
EvolutionProgress: { type: [evolutionProgressSchema], default: undefined },
//https://warframe.fandom.com/wiki/Loc-Pin
CustomMarkers: { type: [CustomMarkersSchema], default: undefined },
//Unknown and system
DuviriInfo: DuviriInfoSchema,
duviriSeedRefresh: { type: Date, default: undefined }, // SNS specific field
//Mailbox: MailboxSchema,
HandlerPoints: Number,
ChallengesFixVersion: Number,
PlayedParkourTutorial: Boolean,
//ActiveLandscapeTraps: [Schema.Types.Mixed],
//RepVotes: [Schema.Types.Mixed],
//LeagueTickets: [Schema.Types.Mixed],
HasContributedToDojo: Boolean,
HWIDProtectEnabled: Boolean,
LoadOutPresets: { type: Schema.Types.ObjectId, ref: "Loadout" },
CurrentLoadOutIds: { type: [Schema.Types.ObjectId] },
RandomUpgradesIdentified: Number,
BountyScore: Number,
ChallengeInstanceStates: { type: [challengeInstanceStateSchema], default: undefined },
RecentVendorPurchases: { type: [recentVendorPurchaseSchema], default: undefined },
//Robotics: [Schema.Types.Mixed],
CollectibleSeries: { type: [collectibleEntrySchema], default: undefined },
HasResetAccount: { type: Boolean, default: false },
//Discount Coupon
PendingCoupon: pendingCouponSchema,
//Like BossAladV,BossCaptainVor come for you on missions % chance
DeathMarks: { type: [String], default: [] },
//Zanuka
Harvestable: Boolean,
//Grustag three
DeathSquadable: Boolean,
// Server-only tracking fields for when to give zanuka or G3 death marks
HarvesterPoints: Number,
DeathSquadPoints: Number,
EndlessXP: { type: [endlessXpProgressSchema], default: undefined },
DescentRewards: { type: [descentCategoryRewardSchema], default: undefined },
DialogueHistory: dialogueHistorySchema,
CalendarProgress: calenderProgressSchema,
SongChallenges: { type: [songChallengeSchema], default: undefined },
// Netracells + Deep Archimedea
EntratiVaultCountLastPeriod: { type: Number, default: undefined },
EntratiVaultCountResetDate: { type: Date, default: undefined },
EntratiLabConquestUnlocked: { type: Number, default: undefined },
EntratiLabConquestHardModeStatus: { type: Number, default: undefined },
EntratiLabConquestCacheScoreMission: { type: Number, default: undefined },
EntratiLabConquestActiveFrameVariants: { type: [String], default: undefined },
EchoesHexConquestUnlocked: { type: Number, default: undefined },
EchoesHexConquestHardModeStatus: { type: Number, default: undefined },
EchoesHexConquestCacheScoreMission: { type: Number, default: undefined },
EchoesHexConquestActiveFrameVariants: { type: [String], default: undefined },
EchoesHexConquestActiveStickers: { type: [String], default: undefined },
// G3 + Zanuka
BrandedSuits: { type: [Schema.Types.ObjectId], default: undefined },
LockedWeaponGroup: { type: lockedWeaponGroupSchema, default: undefined },
HubNpcCustomizations: { type: [hubNpcCustomizationSchema], default: undefined },
ClaimedJunctionChallengeRewards: { type: [String], default: undefined },
SpecialItemRewardAttenuation: { type: [rewardAttenutationSchema], default: undefined },
NokkoColony: { type: nokkoColonySchema, default: undefined },
RetroWallpaperId: Number,
RetroFastTyping: Boolean,
RetroPlayAllConvos: Boolean,
RetroDisableKissInboxMessage: Boolean,
Sketches: { type: [sketchSchema], default: undefined },
WeeklyGuildVaultBonusInfo: { type: [weeklyGuildVaultBonusSchema], default: undefined },
MiscAccountData: { type: [miscAccountDataSchema], default: undefined }
},
{ timestamps: { createdAt: "Created", updatedAt: false } }
);
inventorySchema.set("toJSON", {
transform(_document, returnedObject: Record<string, any>) {
delete returnedObject._id;
delete returnedObject.__v;
delete returnedObject.accountOwnerId;
delete returnedObject.MissionRelicRewards;
delete returnedObject.HarvesterPoints;
delete returnedObject.DeathSquadPoints;
delete returnedObject.NemesisTaxedCredits;
delete returnedObject.duviriSeedRefresh;
delete returnedObject.HybridFusionTreasures;
delete returnedObject.receivedThousandYearFishDeco;
const inventoryDatabase = returnedObject as Partial<IInventoryDatabase>;
const inventoryResponse = returnedObject as IInventoryClient;
if (inventoryDatabase.Created) {
inventoryResponse.Created = toMongoDate(inventoryDatabase.Created);
}
if (inventoryDatabase.CurrentLoadOutIds) {
inventoryResponse.CurrentLoadOutIds = inventoryDatabase.CurrentLoadOutIds.map(x => toOid(x));
}
if (inventoryDatabase.TrainingDate) {
inventoryResponse.TrainingDate = toMongoDate(inventoryDatabase.TrainingDate);
}
if (inventoryDatabase.GuildId) {
inventoryResponse.GuildId = toOid(inventoryDatabase.GuildId);
}
if (inventoryDatabase.BlessingCooldown) {
inventoryResponse.BlessingCooldown = toMongoDate(inventoryDatabase.BlessingCooldown);
}
if (inventoryDatabase.LastNemesisAllySpawnTime) {
inventoryResponse.LastNemesisAllySpawnTime = toMongoDate(inventoryDatabase.LastNemesisAllySpawnTime);
}
if (inventoryDatabase.NextRefill) {
inventoryResponse.NextRefill = toMongoDate(inventoryDatabase.NextRefill);
}
if (inventoryDatabase.EntratiVaultCountResetDate) {
inventoryResponse.EntratiVaultCountResetDate = toMongoDate(inventoryDatabase.EntratiVaultCountResetDate);
}
if (inventoryDatabase.BrandedSuits) {
inventoryResponse.BrandedSuits = inventoryDatabase.BrandedSuits.map(toOid);
}
if (inventoryDatabase.LockedWeaponGroup) {
inventoryResponse.LockedWeaponGroup = {
s: toOid(inventoryDatabase.LockedWeaponGroup.s),
l: inventoryDatabase.LockedWeaponGroup.l ? toOid(inventoryDatabase.LockedWeaponGroup.l) : undefined,
p: inventoryDatabase.LockedWeaponGroup.p ? toOid(inventoryDatabase.LockedWeaponGroup.p) : undefined,
m: inventoryDatabase.LockedWeaponGroup.m ? toOid(inventoryDatabase.LockedWeaponGroup.m) : undefined,
sn: inventoryDatabase.LockedWeaponGroup.sn ? toOid(inventoryDatabase.LockedWeaponGroup.sn) : undefined
};
}
}
});
inventorySchema.index({ accountOwnerId: 1 }, { unique: true });
// type overwrites for subdocuments/subdocument arrays
export type InventoryDocumentProps = {
FlavourItems: Types.DocumentArray<IFlavourItem>;
RawUpgrades: Types.DocumentArray<IRawUpgrade>;
Upgrades: Types.DocumentArray<IUpgradeDatabase>;
MiscItems: Types.DocumentArray<IMiscItem>;
Boosters: Types.DocumentArray<IBooster>;
OperatorLoadOuts: Types.DocumentArray<IOperatorConfigDatabase>;
AdultOperatorLoadOuts: Types.DocumentArray<IOperatorConfigDatabase>;
KahlLoadOuts: Types.DocumentArray<IOperatorConfigDatabase>;
OperatorSuits: Types.DocumentArray<IEquipmentDatabase>;
PendingRecipes: Types.DocumentArray<IPendingRecipeDatabase>;
WeaponSkins: Types.DocumentArray<IWeaponSkinDatabase>;
QuestKeys: Types.DocumentArray<IQuestKeyDatabase>;
Drones: Types.DocumentArray<IDroneDatabase>;
CrewShipWeaponSkins: Types.DocumentArray<IUpgradeDatabase>;
CrewShipSalvagedWeaponSkins: Types.DocumentArray<IUpgradeDatabase>;
PersonalTechProjects: Types.DocumentArray<IPersonalTechProjectDatabase>;
CrewMembers: Types.DocumentArray<ICrewMemberDatabase>;
KubrowPets: Types.DocumentArray<IKubrowPetDatabase>;
KubrowPetPrints: Types.DocumentArray<IKubrowPetPrintDatabase>;
HybridFusionTreasures: Types.DocumentArray<IHybridFusionTreasure>;
StepSequencers: Types.DocumentArray<IStepSequencerDatabase>;
} & { [K in TEquipmentKey]: Types.DocumentArray<IEquipmentDatabase> };
type InventoryModelType = Model<IInventoryDatabase, {}, InventoryDocumentProps>;
export const Inventory = model<IInventoryDatabase, InventoryModelType>("Inventory", inventorySchema);
export type TInventoryDatabaseDocument = Document<unknown, {}, IInventoryDatabase> &
Omit<
IInventoryDatabase & {
_id: Types.ObjectId;
} & {
__v: number;
},
keyof InventoryDocumentProps
> &
InventoryDocumentProps;