169 lines
7.6 KiB
TypeScript
169 lines
7.6 KiB
TypeScript
import { GuildMember, TGuildDatabaseDocument } from "@/src/models/guildModel";
|
|
import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
|
|
import {
|
|
addGuildMemberMiscItemContribution,
|
|
getDojoClient,
|
|
getGuildForRequestEx,
|
|
hasAccessToDojo,
|
|
processDojoBuildMaterialsGathered,
|
|
scaleRequiredCount,
|
|
setDojoRoomLogFunded
|
|
} from "@/src/services/guildService";
|
|
import { addMiscItems, getInventory, updateCurrency } from "@/src/services/inventoryService";
|
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
|
import { IDojoContributable, IGuildMemberDatabase } from "@/src/types/guildTypes";
|
|
import { IMiscItem } from "@/src/types/inventoryTypes/inventoryTypes";
|
|
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
|
import { RequestHandler } from "express";
|
|
import { ExportDojoRecipes, IDojoBuild } from "warframe-public-export-plus";
|
|
|
|
interface IContributeToDojoComponentRequest {
|
|
ComponentId: string;
|
|
DecoId?: string;
|
|
DecoType?: string;
|
|
IngredientContributions: IMiscItem[];
|
|
RegularCredits: number;
|
|
VaultIngredientContributions: IMiscItem[];
|
|
VaultCredits: number;
|
|
}
|
|
|
|
export const contributeToDojoComponentController: RequestHandler = async (req, res) => {
|
|
const accountId = await getAccountIdForRequest(req);
|
|
const inventory = await getInventory(accountId);
|
|
// Any clan member should have permission to contribute although notably permission is denied if they have not crafted the dojo key and were simply invited in.
|
|
if (!hasAccessToDojo(inventory)) {
|
|
res.json({ DojoRequestStatus: -1 });
|
|
return;
|
|
}
|
|
const guild = await getGuildForRequestEx(req, inventory);
|
|
const guildMember = (await GuildMember.findOne(
|
|
{ accountId, guildId: guild._id },
|
|
"RegularCreditsContributed MiscItemsContributed"
|
|
))!;
|
|
const request = JSON.parse(String(req.body)) as IContributeToDojoComponentRequest;
|
|
const component = guild.DojoComponents.id(request.ComponentId)!;
|
|
|
|
const inventoryChanges: IInventoryChanges = {};
|
|
if (!component.CompletionTime) {
|
|
// Room is in "Collecting Materials" state
|
|
if (request.DecoId) {
|
|
throw new Error("attempt to contribute to a deco in an unfinished room?!");
|
|
}
|
|
const meta = Object.values(ExportDojoRecipes.rooms).find(x => x.resultType == component.pf)!;
|
|
processContribution(guild, guildMember, request, inventory, inventoryChanges, meta, component);
|
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
if (component.CompletionTime) {
|
|
setDojoRoomLogFunded(guild, component);
|
|
}
|
|
} else {
|
|
// Room is past "Collecting Materials"
|
|
if (request.DecoId) {
|
|
const deco = component.Decos!.find(x => x._id.equals(request.DecoId))!;
|
|
const meta = Object.values(ExportDojoRecipes.decos).find(x => x.resultType == deco.Type)!;
|
|
processContribution(guild, guildMember, request, inventory, inventoryChanges, meta, deco);
|
|
}
|
|
}
|
|
|
|
await Promise.all([guild.save(), inventory.save(), guildMember.save()]);
|
|
res.json({
|
|
...(await getDojoClient(guild, 0, component._id)),
|
|
InventoryChanges: inventoryChanges
|
|
});
|
|
};
|
|
|
|
const processContribution = (
|
|
guild: TGuildDatabaseDocument,
|
|
guildMember: IGuildMemberDatabase,
|
|
request: IContributeToDojoComponentRequest,
|
|
inventory: TInventoryDatabaseDocument,
|
|
inventoryChanges: IInventoryChanges,
|
|
meta: IDojoBuild,
|
|
component: IDojoContributable
|
|
): void => {
|
|
component.RegularCredits ??= 0;
|
|
if (request.RegularCredits) {
|
|
component.RegularCredits += request.RegularCredits;
|
|
inventoryChanges.RegularCredits = -request.RegularCredits;
|
|
updateCurrency(inventory, request.RegularCredits, false);
|
|
|
|
guildMember.RegularCreditsContributed ??= 0;
|
|
guildMember.RegularCreditsContributed += request.RegularCredits;
|
|
}
|
|
if (request.VaultCredits) {
|
|
component.RegularCredits += request.VaultCredits;
|
|
guild.VaultRegularCredits! -= request.VaultCredits;
|
|
}
|
|
if (component.RegularCredits > scaleRequiredCount(guild.Tier, meta.price)) {
|
|
guild.VaultRegularCredits ??= 0;
|
|
guild.VaultRegularCredits += component.RegularCredits - scaleRequiredCount(guild.Tier, meta.price);
|
|
component.RegularCredits = scaleRequiredCount(guild.Tier, meta.price);
|
|
}
|
|
|
|
component.MiscItems ??= [];
|
|
if (request.VaultIngredientContributions.length) {
|
|
for (const ingredientContribution of request.VaultIngredientContributions) {
|
|
const componentMiscItem = component.MiscItems.find(x => x.ItemType == ingredientContribution.ItemType);
|
|
if (componentMiscItem) {
|
|
const ingredientMeta = meta.ingredients.find(x => x.ItemType == ingredientContribution.ItemType)!;
|
|
if (
|
|
componentMiscItem.ItemCount + ingredientContribution.ItemCount >
|
|
scaleRequiredCount(guild.Tier, ingredientMeta.ItemCount)
|
|
) {
|
|
ingredientContribution.ItemCount =
|
|
scaleRequiredCount(guild.Tier, ingredientMeta.ItemCount) - componentMiscItem.ItemCount;
|
|
}
|
|
componentMiscItem.ItemCount += ingredientContribution.ItemCount;
|
|
} else {
|
|
component.MiscItems.push(ingredientContribution);
|
|
}
|
|
const vaultMiscItem = guild.VaultMiscItems!.find(x => x.ItemType == ingredientContribution.ItemType)!;
|
|
vaultMiscItem.ItemCount -= ingredientContribution.ItemCount;
|
|
}
|
|
}
|
|
if (request.IngredientContributions.length) {
|
|
const miscItemChanges: IMiscItem[] = [];
|
|
for (const ingredientContribution of request.IngredientContributions) {
|
|
const componentMiscItem = component.MiscItems.find(x => x.ItemType == ingredientContribution.ItemType);
|
|
if (componentMiscItem) {
|
|
const ingredientMeta = meta.ingredients.find(x => x.ItemType == ingredientContribution.ItemType)!;
|
|
if (
|
|
componentMiscItem.ItemCount + ingredientContribution.ItemCount >
|
|
scaleRequiredCount(guild.Tier, ingredientMeta.ItemCount)
|
|
) {
|
|
ingredientContribution.ItemCount =
|
|
scaleRequiredCount(guild.Tier, ingredientMeta.ItemCount) - componentMiscItem.ItemCount;
|
|
}
|
|
componentMiscItem.ItemCount += ingredientContribution.ItemCount;
|
|
} else {
|
|
component.MiscItems.push(ingredientContribution);
|
|
}
|
|
miscItemChanges.push({
|
|
ItemType: ingredientContribution.ItemType,
|
|
ItemCount: ingredientContribution.ItemCount * -1
|
|
});
|
|
|
|
addGuildMemberMiscItemContribution(guildMember, ingredientContribution);
|
|
}
|
|
addMiscItems(inventory, miscItemChanges);
|
|
inventoryChanges.MiscItems = miscItemChanges;
|
|
}
|
|
|
|
if (component.RegularCredits >= scaleRequiredCount(guild.Tier, meta.price)) {
|
|
let fullyFunded = true;
|
|
for (const ingredient of meta.ingredients) {
|
|
const componentMiscItem = component.MiscItems.find(x => x.ItemType == ingredient.ItemType);
|
|
if (
|
|
!componentMiscItem ||
|
|
componentMiscItem.ItemCount < scaleRequiredCount(guild.Tier, ingredient.ItemCount)
|
|
) {
|
|
fullyFunded = false;
|
|
break;
|
|
}
|
|
}
|
|
if (fullyFunded) {
|
|
component.CompletionTime = new Date(Date.now() + meta.time * 1000);
|
|
processDojoBuildMaterialsGathered(guild, meta);
|
|
}
|
|
}
|
|
};
|