2023-12-14 17:34:15 +01:00
|
|
|
import { Inventory } from "@/src/models/inventoryModels/inventoryModel";
|
2023-06-04 03:06:22 +02:00
|
|
|
import new_inventory from "@/static/fixed_responses/postTutorialInventory.json";
|
|
|
|
import config from "@/config.json";
|
|
|
|
import { Types } from "mongoose";
|
2023-12-28 16:24:52 +01:00
|
|
|
import { ISuitClient } from "@/src/types/inventoryTypes/SuitTypes";
|
|
|
|
import { SlotNames } from "@/src/types/purchaseTypes";
|
|
|
|
import { IWeaponClient } from "@/src/types/inventoryTypes/weaponTypes";
|
2023-08-31 14:29:09 +04:00
|
|
|
import {
|
2023-09-05 07:37:30 -05:00
|
|
|
IChallengeProgress,
|
2023-09-06 14:02:54 +04:00
|
|
|
IConsumable,
|
2023-09-05 07:37:30 -05:00
|
|
|
IFlavourItem,
|
2023-09-06 14:02:54 +04:00
|
|
|
IInventoryDatabaseDocument,
|
|
|
|
IMiscItem,
|
2023-09-10 00:10:21 +04:00
|
|
|
IMission,
|
2023-09-06 14:02:54 +04:00
|
|
|
IRawUpgrade
|
2023-09-05 07:37:30 -05:00
|
|
|
} from "@/src/types/inventoryTypes/inventoryTypes";
|
|
|
|
import { IGenericUpdate } from "../types/genericUpdate";
|
2023-09-10 00:10:21 +04:00
|
|
|
import { IArtifactsRequest, IMissionInventoryUpdateRequest } from "../types/requestTypes";
|
2024-01-06 16:26:58 +01:00
|
|
|
import { logger } from "@/src/utils/logger";
|
2023-06-04 03:06:22 +02:00
|
|
|
|
2023-12-14 17:34:15 +01:00
|
|
|
export const createInventory = async (accountOwnerId: Types.ObjectId, loadOutPresetId: Types.ObjectId) => {
|
2023-06-04 03:06:22 +02:00
|
|
|
try {
|
2023-12-14 17:34:15 +01:00
|
|
|
const inventory = new Inventory({
|
|
|
|
...new_inventory,
|
|
|
|
accountOwnerId: accountOwnerId,
|
|
|
|
LoadOutPresets: loadOutPresetId
|
|
|
|
});
|
2023-06-04 03:06:22 +02:00
|
|
|
if (config.skipStoryModeChoice) {
|
|
|
|
inventory.StoryModeChoice = "WARFRAME";
|
|
|
|
}
|
|
|
|
if (config.skipTutorial) {
|
|
|
|
inventory.PlayedParkourTutorial = true;
|
|
|
|
inventory.ReceivedStartingGear = true;
|
|
|
|
}
|
2023-12-14 17:34:15 +01:00
|
|
|
|
2023-06-04 03:06:22 +02:00
|
|
|
await inventory.save();
|
|
|
|
} catch (error) {
|
|
|
|
if (error instanceof Error) {
|
|
|
|
throw new Error(`error creating inventory" ${error.message}`);
|
|
|
|
}
|
|
|
|
throw new Error("error creating inventory that is not of instance Error");
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2023-09-11 13:20:07 +02:00
|
|
|
export const getInventory = async (accountOwnerId: string) => {
|
2023-06-14 02:26:19 +02:00
|
|
|
const inventory = await Inventory.findOne({ accountOwnerId: accountOwnerId });
|
|
|
|
|
|
|
|
if (!inventory) {
|
|
|
|
throw new Error(`Didn't find an inventory for ${accountOwnerId}`);
|
|
|
|
}
|
|
|
|
|
|
|
|
return inventory;
|
|
|
|
};
|
|
|
|
|
2023-12-28 16:24:52 +01:00
|
|
|
//TODO: maybe genericMethod for all the add methods, they share a lot of logic
|
2023-12-14 17:34:15 +01:00
|
|
|
export const addSentinel = async (sentinelName: string, accountId: string) => {
|
|
|
|
const inventory = await getInventory(accountId);
|
|
|
|
const sentinelIndex = inventory.Sentinels.push({ ItemType: sentinelName, Configs: [], XP: 0 });
|
|
|
|
const changedInventory = await inventory.save();
|
|
|
|
return changedInventory.Sentinels[sentinelIndex - 1].toJSON();
|
|
|
|
};
|
|
|
|
|
|
|
|
export const addPowerSuit = async (powersuitName: string, accountId: string): Promise<ISuitClient> => {
|
2023-06-14 02:26:19 +02:00
|
|
|
const inventory = await getInventory(accountId);
|
|
|
|
const suitIndex = inventory.Suits.push({ ItemType: powersuitName, Configs: [], UpgradeVer: 101, XP: 0 });
|
|
|
|
const changedInventory = await inventory.save();
|
|
|
|
return changedInventory.Suits[suitIndex - 1].toJSON();
|
|
|
|
};
|
|
|
|
|
2023-12-14 17:34:15 +01:00
|
|
|
export const addMechSuit = async (mechsuitName: string, accountId: string) => {
|
|
|
|
const inventory = await getInventory(accountId);
|
|
|
|
const suitIndex = inventory.MechSuits.push({ ItemType: mechsuitName, Configs: [], UpgradeVer: 101, XP: 0 });
|
|
|
|
const changedInventory = await inventory.save();
|
|
|
|
return changedInventory.MechSuits[suitIndex - 1].toJSON();
|
|
|
|
};
|
|
|
|
|
2023-12-28 16:24:52 +01:00
|
|
|
export const updateSlots = async (accountId: string, slotName: SlotNames, slotAmount: number, extraAmount: number) => {
|
2023-06-14 02:26:19 +02:00
|
|
|
const inventory = await getInventory(accountId);
|
|
|
|
|
2023-12-28 16:24:52 +01:00
|
|
|
inventory[slotName].Slots += slotAmount;
|
|
|
|
if (inventory[slotName].Extra === undefined) {
|
|
|
|
inventory[slotName].Extra = extraAmount;
|
|
|
|
} else {
|
|
|
|
inventory[slotName].Extra += extraAmount;
|
2023-06-14 02:26:19 +02:00
|
|
|
}
|
2023-12-28 16:24:52 +01:00
|
|
|
|
2023-06-14 02:26:19 +02:00
|
|
|
await inventory.save();
|
|
|
|
};
|
|
|
|
|
|
|
|
export const updateCurrency = async (price: number, usePremium: boolean, accountId: string) => {
|
|
|
|
const inventory = await getInventory(accountId);
|
2023-12-28 16:24:52 +01:00
|
|
|
|
|
|
|
if (usePremium) {
|
|
|
|
if (inventory.PremiumCreditsFree > 0) {
|
|
|
|
inventory.PremiumCreditsFree += price;
|
|
|
|
}
|
|
|
|
inventory.PremiumCredits += price;
|
|
|
|
} else {
|
|
|
|
inventory.RegularCredits += price;
|
|
|
|
}
|
|
|
|
|
|
|
|
const modifiedPaths = inventory.modifiedPaths();
|
|
|
|
|
|
|
|
type currencyKeys = "RegularCredits" | "PremiumCredits" | "PremiumCreditsFree";
|
|
|
|
|
|
|
|
const currencyChanges = {} as Record<currencyKeys, number>;
|
|
|
|
modifiedPaths.forEach(path => {
|
|
|
|
currencyChanges[path as currencyKeys] = -price;
|
|
|
|
});
|
|
|
|
|
2024-01-06 16:26:58 +01:00
|
|
|
logger.debug(`currency changes `, { currencyChanges });
|
2023-12-28 16:24:52 +01:00
|
|
|
|
|
|
|
//let changes = {} as keyof currencyKeys;
|
|
|
|
|
|
|
|
// const obj2 = modifiedPaths.reduce(
|
|
|
|
// (obj, key) => {
|
|
|
|
// obj[key as keyof currencyKeys] = price;
|
|
|
|
// return obj;
|
|
|
|
// },
|
|
|
|
// {} as Record<keyof currencyKeys, number>
|
|
|
|
// );
|
|
|
|
|
2023-06-14 02:26:19 +02:00
|
|
|
await inventory.save();
|
2023-12-28 16:24:52 +01:00
|
|
|
return currencyChanges;
|
2023-06-14 02:26:19 +02:00
|
|
|
};
|
|
|
|
|
2023-09-05 07:37:30 -05:00
|
|
|
// TODO: AffiliationMods support (Nightwave).
|
|
|
|
export const updateGeneric = async (data: IGenericUpdate, accountId: string) => {
|
|
|
|
const inventory = await getInventory(accountId);
|
|
|
|
|
|
|
|
// Make it an array for easier parsing.
|
|
|
|
if (typeof data.NodeIntrosCompleted === "string") {
|
|
|
|
data.NodeIntrosCompleted = [data.NodeIntrosCompleted];
|
|
|
|
}
|
|
|
|
|
|
|
|
// Combine the two arrays into one.
|
|
|
|
data.NodeIntrosCompleted = inventory.NodeIntrosCompleted.concat(data.NodeIntrosCompleted);
|
|
|
|
|
|
|
|
// Remove duplicate entries.
|
|
|
|
const nodes = [...new Set(data.NodeIntrosCompleted)];
|
|
|
|
|
|
|
|
inventory.NodeIntrosCompleted = nodes;
|
|
|
|
await inventory.save();
|
|
|
|
|
|
|
|
return data;
|
|
|
|
};
|
|
|
|
|
2023-06-14 02:26:19 +02:00
|
|
|
export type WeaponTypeInternal = "LongGuns" | "Pistols" | "Melee";
|
|
|
|
|
|
|
|
export const addWeapon = async (
|
|
|
|
weaponType: WeaponTypeInternal,
|
|
|
|
weaponName: string,
|
|
|
|
accountId: string
|
2023-12-14 17:34:15 +01:00
|
|
|
): Promise<IWeaponClient> => {
|
2023-06-14 02:26:19 +02:00
|
|
|
const inventory = await getInventory(accountId);
|
|
|
|
|
|
|
|
let weaponIndex;
|
|
|
|
switch (weaponType) {
|
|
|
|
case "LongGuns":
|
|
|
|
weaponIndex = inventory.LongGuns.push({ ItemType: weaponName, Configs: [], XP: 0 });
|
|
|
|
break;
|
|
|
|
case "Pistols":
|
|
|
|
weaponIndex = inventory.Pistols.push({ ItemType: weaponName, Configs: [], XP: 0 });
|
|
|
|
break;
|
|
|
|
case "Melee":
|
|
|
|
weaponIndex = inventory.Melee.push({ ItemType: weaponName, Configs: [], XP: 0 });
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
throw new Error("unknown weapon type");
|
|
|
|
}
|
|
|
|
|
|
|
|
const changedInventory = await inventory.save();
|
|
|
|
return changedInventory[weaponType][weaponIndex - 1].toJSON();
|
|
|
|
};
|
|
|
|
|
2023-09-05 07:37:30 -05:00
|
|
|
export const addCustomization = async (customizatonName: string, accountId: string): Promise<IFlavourItem> => {
|
2023-06-14 02:26:19 +02:00
|
|
|
const inventory = await getInventory(accountId);
|
|
|
|
|
|
|
|
const flavourItemIndex = inventory.FlavourItems.push({ ItemType: customizatonName }) - 1;
|
|
|
|
const changedInventory = await inventory.save();
|
2023-12-28 16:24:52 +01:00
|
|
|
return changedInventory.FlavourItems[flavourItemIndex].toJSON();
|
2023-06-14 02:26:19 +02:00
|
|
|
};
|
|
|
|
|
2023-08-31 14:29:09 +04:00
|
|
|
const addGearExpByCategory = (
|
|
|
|
inventory: IInventoryDatabaseDocument,
|
2023-12-14 17:34:15 +01:00
|
|
|
gearArray: ISuitClient[] | IWeaponClient[] | undefined,
|
2023-08-31 14:29:09 +04:00
|
|
|
categoryName: "Pistols" | "LongGuns" | "Melee" | "Suits"
|
|
|
|
) => {
|
|
|
|
const category = inventory[categoryName];
|
|
|
|
|
|
|
|
gearArray?.forEach(({ ItemId, XP }) => {
|
2023-09-10 00:10:21 +04:00
|
|
|
const itemIndex = ItemId ? category.findIndex(item => item._id?.equals(ItemId.$oid)) : -1;
|
2023-08-31 14:29:09 +04:00
|
|
|
const item = category[itemIndex];
|
|
|
|
|
|
|
|
if (itemIndex !== -1 && item.XP != undefined) {
|
2023-09-10 00:10:21 +04:00
|
|
|
item.XP += XP || 0;
|
2023-08-31 14:29:09 +04:00
|
|
|
inventory.markModified(`${categoryName}.${itemIndex}.XP`);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2023-09-06 14:02:54 +04:00
|
|
|
const addMiscItems = (inventory: IInventoryDatabaseDocument, itemsArray: IMiscItem[] | undefined) => {
|
|
|
|
const { MiscItems } = inventory;
|
|
|
|
|
|
|
|
itemsArray?.forEach(({ ItemCount, ItemType }) => {
|
|
|
|
const itemIndex = MiscItems.findIndex(miscItem => miscItem.ItemType === ItemType);
|
|
|
|
|
|
|
|
if (itemIndex !== -1) {
|
|
|
|
MiscItems[itemIndex].ItemCount += ItemCount;
|
|
|
|
inventory.markModified(`MiscItems.${itemIndex}.ItemCount`);
|
|
|
|
} else {
|
|
|
|
MiscItems.push({ ItemCount, ItemType });
|
|
|
|
}
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
const addConsumables = (inventory: IInventoryDatabaseDocument, itemsArray: IConsumable[] | undefined) => {
|
|
|
|
const { Consumables } = inventory;
|
2023-08-31 14:29:09 +04:00
|
|
|
|
|
|
|
itemsArray?.forEach(({ ItemCount, ItemType }) => {
|
2023-09-06 14:02:54 +04:00
|
|
|
const itemIndex = Consumables.findIndex(i => i.ItemType === ItemType);
|
|
|
|
|
|
|
|
if (itemIndex !== -1) {
|
|
|
|
Consumables[itemIndex].ItemCount += ItemCount;
|
|
|
|
inventory.markModified(`Consumables.${itemIndex}.ItemCount`);
|
|
|
|
} else {
|
|
|
|
Consumables.push({ ItemCount, ItemType });
|
|
|
|
}
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
const addRecipes = (inventory: IInventoryDatabaseDocument, itemsArray: IConsumable[] | undefined) => {
|
|
|
|
const { Recipes } = inventory;
|
|
|
|
|
|
|
|
itemsArray?.forEach(({ ItemCount, ItemType }) => {
|
|
|
|
const itemIndex = Recipes.findIndex(i => i.ItemType === ItemType);
|
|
|
|
|
|
|
|
if (itemIndex !== -1) {
|
|
|
|
Recipes[itemIndex].ItemCount += ItemCount;
|
|
|
|
inventory.markModified(`Recipes.${itemIndex}.ItemCount`);
|
|
|
|
} else {
|
|
|
|
Recipes.push({ ItemCount, ItemType });
|
|
|
|
}
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
const addMods = (inventory: IInventoryDatabaseDocument, itemsArray: IRawUpgrade[] | undefined) => {
|
|
|
|
const { RawUpgrades } = inventory;
|
|
|
|
itemsArray?.forEach(({ ItemType, ItemCount }) => {
|
|
|
|
const itemIndex = RawUpgrades.findIndex(i => i.ItemType === ItemType);
|
2023-08-31 14:29:09 +04:00
|
|
|
|
|
|
|
if (itemIndex !== -1) {
|
2023-09-06 14:02:54 +04:00
|
|
|
RawUpgrades[itemIndex].ItemCount += ItemCount;
|
|
|
|
inventory.markModified(`RawUpgrades.${itemIndex}.ItemCount`);
|
2023-08-31 14:29:09 +04:00
|
|
|
} else {
|
2023-09-06 14:02:54 +04:00
|
|
|
RawUpgrades.push({ ItemCount, ItemType });
|
2023-08-31 14:29:09 +04:00
|
|
|
}
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2023-09-05 07:37:30 -05:00
|
|
|
const addChallenges = (inventory: IInventoryDatabaseDocument, itemsArray: IChallengeProgress[] | undefined) => {
|
2023-08-31 14:29:09 +04:00
|
|
|
const category = inventory.ChallengeProgress;
|
|
|
|
|
|
|
|
itemsArray?.forEach(({ Name, Progress }) => {
|
|
|
|
const itemIndex = category.findIndex(i => i.Name === Name);
|
|
|
|
|
|
|
|
if (itemIndex !== -1) {
|
|
|
|
category[itemIndex].Progress += Progress;
|
|
|
|
inventory.markModified(`ChallengeProgress.${itemIndex}.ItemCount`);
|
|
|
|
} else {
|
|
|
|
category.push({ Name, Progress });
|
|
|
|
}
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2023-09-10 00:10:21 +04:00
|
|
|
const addMissionComplete = (inventory: IInventoryDatabaseDocument, { Tag, Completes }: IMission) => {
|
|
|
|
const { Missions } = inventory;
|
|
|
|
const itemIndex = Missions.findIndex(item => item.Tag === Tag);
|
|
|
|
|
|
|
|
if (itemIndex !== -1) {
|
|
|
|
Missions[itemIndex].Completes += Completes;
|
|
|
|
inventory.markModified(`Missions.${itemIndex}.Completes`);
|
|
|
|
} else {
|
|
|
|
Missions.push({ Tag, Completes });
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2023-08-31 14:29:09 +04:00
|
|
|
const gearKeys = ["Suits", "Pistols", "LongGuns", "Melee"] as const;
|
|
|
|
|
2023-09-10 00:10:21 +04:00
|
|
|
export const missionInventoryUpdate = async (data: IMissionInventoryUpdateRequest, accountId: string) => {
|
|
|
|
const { RawUpgrades, MiscItems, RegularCredits, ChallengeProgress, FusionPoints, Consumables, Recipes, Missions } =
|
|
|
|
data;
|
2023-08-31 14:29:09 +04:00
|
|
|
const inventory = await getInventory(accountId);
|
|
|
|
|
2023-09-06 14:02:54 +04:00
|
|
|
// credits
|
|
|
|
inventory.RegularCredits += RegularCredits || 0;
|
|
|
|
|
|
|
|
// endo
|
|
|
|
inventory.FusionPoints += FusionPoints || 0;
|
|
|
|
|
2023-09-05 07:37:30 -05:00
|
|
|
// Gear XP
|
2023-12-14 17:34:15 +01:00
|
|
|
gearKeys.forEach(key => addGearExpByCategory(inventory, data[key], key));
|
2023-08-31 14:29:09 +04:00
|
|
|
|
2023-09-06 14:02:54 +04:00
|
|
|
// other
|
|
|
|
addMods(inventory, RawUpgrades);
|
|
|
|
addMiscItems(inventory, MiscItems);
|
|
|
|
addConsumables(inventory, Consumables);
|
|
|
|
addRecipes(inventory, Recipes);
|
2023-08-31 14:29:09 +04:00
|
|
|
addChallenges(inventory, ChallengeProgress);
|
2023-09-10 00:10:21 +04:00
|
|
|
addMissionComplete(inventory, Missions!);
|
2023-08-31 14:29:09 +04:00
|
|
|
|
2023-09-06 14:02:54 +04:00
|
|
|
const changedInventory = await inventory.save();
|
|
|
|
return changedInventory.toJSON();
|
2023-08-31 14:29:09 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
export const addBooster = async (ItemType: string, time: number, accountId: string): Promise<void> => {
|
2023-09-05 07:37:30 -05:00
|
|
|
const currentTime = Math.floor(Date.now() / 1000) - 129600; // Value is wrong without 129600. Figure out why, please. :)
|
2023-08-31 14:29:09 +04:00
|
|
|
|
|
|
|
const inventory = await getInventory(accountId);
|
|
|
|
const { Boosters } = inventory;
|
|
|
|
|
2023-09-06 14:02:54 +04:00
|
|
|
const itemIndex = Boosters.findIndex(booster => booster.ItemType === ItemType);
|
2023-08-31 14:29:09 +04:00
|
|
|
|
|
|
|
if (itemIndex !== -1) {
|
|
|
|
const existingBooster = Boosters[itemIndex];
|
|
|
|
existingBooster.ExpiryDate = Math.max(existingBooster.ExpiryDate, currentTime) + time;
|
|
|
|
inventory.markModified(`Boosters.${itemIndex}.ExpiryDate`);
|
|
|
|
} else {
|
|
|
|
Boosters.push({ ItemType, ExpiryDate: currentTime + time }) - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
await inventory.save();
|
|
|
|
};
|
|
|
|
|
2023-09-10 00:10:21 +04:00
|
|
|
export const upgradeMod = async (artifactsData: IArtifactsRequest, accountId: string): Promise<string | undefined> => {
|
|
|
|
const { Upgrade, LevelDiff, Cost, FusionPointCost } = artifactsData;
|
2023-09-06 14:02:54 +04:00
|
|
|
try {
|
|
|
|
const inventory = await getInventory(accountId);
|
|
|
|
const { Upgrades, RawUpgrades } = inventory;
|
|
|
|
const { ItemType, UpgradeFingerprint, ItemId } = Upgrade;
|
|
|
|
|
|
|
|
const safeUpgradeFingerprint = UpgradeFingerprint || '{"lvl":0}';
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
|
|
const parsedUpgradeFingerprint = JSON.parse(safeUpgradeFingerprint);
|
|
|
|
parsedUpgradeFingerprint.lvl += LevelDiff;
|
|
|
|
const stringifiedUpgradeFingerprint = JSON.stringify(parsedUpgradeFingerprint);
|
|
|
|
|
|
|
|
let itemIndex = Upgrades.findIndex(upgrade => upgrade._id?.equals(ItemId!.$oid));
|
|
|
|
|
|
|
|
if (itemIndex !== -1) {
|
|
|
|
Upgrades[itemIndex].UpgradeFingerprint = stringifiedUpgradeFingerprint;
|
|
|
|
inventory.markModified(`Upgrades.${itemIndex}.UpgradeFingerprint`);
|
|
|
|
} else {
|
|
|
|
itemIndex =
|
|
|
|
Upgrades.push({
|
|
|
|
UpgradeFingerprint: stringifiedUpgradeFingerprint,
|
|
|
|
ItemType
|
|
|
|
}) - 1;
|
|
|
|
|
|
|
|
const rawItemIndex = RawUpgrades.findIndex(rawUpgrade => rawUpgrade.ItemType === ItemType);
|
|
|
|
RawUpgrades[rawItemIndex].ItemCount--;
|
|
|
|
if (RawUpgrades[rawItemIndex].ItemCount > 0) {
|
|
|
|
inventory.markModified(`RawUpgrades.${rawItemIndex}.UpgradeFingerprint`);
|
|
|
|
} else {
|
|
|
|
RawUpgrades.splice(rawItemIndex, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
inventory.RegularCredits -= Cost;
|
|
|
|
inventory.FusionPoints -= FusionPointCost;
|
|
|
|
|
|
|
|
const changedInventory = await inventory.save();
|
|
|
|
const itemId = changedInventory.toJSON().Upgrades[itemIndex]?.ItemId?.$oid;
|
|
|
|
|
|
|
|
if (!itemId) {
|
|
|
|
throw new Error("Item Id not found in upgradeMod");
|
|
|
|
}
|
|
|
|
|
|
|
|
return itemId;
|
|
|
|
} catch (error) {
|
|
|
|
console.error("Error in upgradeMod:", error);
|
|
|
|
throw error;
|
|
|
|
}
|
|
|
|
};
|