feat: clan tiers #1378
@ -32,7 +32,7 @@ export const abortDojoComponentController: RequestHandler = async (req, res) =>
 | 
				
			|||||||
    if (request.DecoId) {
 | 
					    if (request.DecoId) {
 | 
				
			||||||
        removeDojoDeco(guild, request.ComponentId, request.DecoId);
 | 
					        removeDojoDeco(guild, request.ComponentId, request.DecoId);
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        removeDojoRoom(guild, request.ComponentId);
 | 
					        await removeDojoRoom(guild, request.ComponentId);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    await guild.save();
 | 
					    await guild.save();
 | 
				
			||||||
 | 
				
			|||||||
@ -4,10 +4,13 @@ import {
 | 
				
			|||||||
    getGuildVault,
 | 
					    getGuildVault,
 | 
				
			||||||
    hasAccessToDojo,
 | 
					    hasAccessToDojo,
 | 
				
			||||||
    hasGuildPermission,
 | 
					    hasGuildPermission,
 | 
				
			||||||
 | 
					    processFundedGuildTechProject,
 | 
				
			||||||
 | 
					    processGuildTechProjectContributionsUpdate,
 | 
				
			||||||
    removePigmentsFromGuildMembers,
 | 
					    removePigmentsFromGuildMembers,
 | 
				
			||||||
    scaleRequiredCount
 | 
					    scaleRequiredCount,
 | 
				
			||||||
 | 
					    setGuildTechLogState
 | 
				
			||||||
} from "@/src/services/guildService";
 | 
					} from "@/src/services/guildService";
 | 
				
			||||||
import { ExportDojoRecipes, IDojoResearch } from "warframe-public-export-plus";
 | 
					import { ExportDojoRecipes } from "warframe-public-export-plus";
 | 
				
			||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
					import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
    addItem,
 | 
					    addItem,
 | 
				
			||||||
@ -20,8 +23,8 @@ import {
 | 
				
			|||||||
import { IMiscItem } from "@/src/types/inventoryTypes/inventoryTypes";
 | 
					import { IMiscItem } from "@/src/types/inventoryTypes/inventoryTypes";
 | 
				
			||||||
import { IInventoryChanges } from "@/src/types/purchaseTypes";
 | 
					import { IInventoryChanges } from "@/src/types/purchaseTypes";
 | 
				
			||||||
import { config } from "@/src/services/configService";
 | 
					import { config } from "@/src/services/configService";
 | 
				
			||||||
import { GuildPermission, ITechProjectClient, ITechProjectDatabase } from "@/src/types/guildTypes";
 | 
					import { GuildPermission, ITechProjectClient } from "@/src/types/guildTypes";
 | 
				
			||||||
import { GuildMember, TGuildDatabaseDocument } from "@/src/models/guildModel";
 | 
					import { GuildMember } from "@/src/models/guildModel";
 | 
				
			||||||
import { toMongoDate } from "@/src/helpers/inventoryHelpers";
 | 
					import { toMongoDate } from "@/src/helpers/inventoryHelpers";
 | 
				
			||||||
import { logger } from "@/src/utils/logger";
 | 
					import { logger } from "@/src/utils/logger";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -44,7 +47,7 @@ export const guildTechController: RequestHandler = async (req, res) => {
 | 
				
			|||||||
                if (project.CompletionDate) {
 | 
					                if (project.CompletionDate) {
 | 
				
			||||||
                    techProject.CompletionDate = toMongoDate(project.CompletionDate);
 | 
					                    techProject.CompletionDate = toMongoDate(project.CompletionDate);
 | 
				
			||||||
                    if (Date.now() >= project.CompletionDate.getTime()) {
 | 
					                    if (Date.now() >= project.CompletionDate.getTime()) {
 | 
				
			||||||
                        needSave ||= setTechLogState(guild, project.ItemType, 4, project.CompletionDate);
 | 
					                        needSave ||= setGuildTechLogState(guild, project.ItemType, 4, project.CompletionDate);
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                techProjects.push(techProject);
 | 
					                techProjects.push(techProject);
 | 
				
			||||||
@ -74,9 +77,9 @@ export const guildTechController: RequestHandler = async (req, res) => {
 | 
				
			|||||||
                        State: 0
 | 
					                        State: 0
 | 
				
			||||||
                    }) - 1
 | 
					                    }) - 1
 | 
				
			||||||
                ];
 | 
					                ];
 | 
				
			||||||
            setTechLogState(guild, techProject.ItemType, 5);
 | 
					            setGuildTechLogState(guild, techProject.ItemType, 5);
 | 
				
			||||||
            if (config.noDojoResearchCosts) {
 | 
					            if (config.noDojoResearchCosts) {
 | 
				
			||||||
                processFundedProject(guild, techProject, recipe);
 | 
					                processFundedGuildTechProject(guild, techProject, recipe);
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                if (data.RecipeType.substring(0, 39) == "/Lotus/Types/Items/Research/DojoColors/") {
 | 
					                if (data.RecipeType.substring(0, 39) == "/Lotus/Types/Items/Research/DojoColors/") {
 | 
				
			||||||
                    guild.ActiveDojoColorResearch = data.RecipeType;
 | 
					                    guild.ActiveDojoColorResearch = data.RecipeType;
 | 
				
			||||||
@ -151,15 +154,8 @@ export const guildTechController: RequestHandler = async (req, res) => {
 | 
				
			|||||||
        const inventoryChanges: IInventoryChanges = updateCurrency(inventory, contributions.RegularCredits, false);
 | 
					        const inventoryChanges: IInventoryChanges = updateCurrency(inventory, contributions.RegularCredits, false);
 | 
				
			||||||
        inventoryChanges.MiscItems = miscItemChanges;
 | 
					        inventoryChanges.MiscItems = miscItemChanges;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (techProject.ReqCredits == 0 && !techProject.ReqItems.find(x => x.ItemCount > 0)) {
 | 
					        // Check if research is fully funded now.
 | 
				
			||||||
            // This research is now fully funded.
 | 
					        await processGuildTechProjectContributionsUpdate(guild, techProject);
 | 
				
			||||||
            const recipe = ExportDojoRecipes.research[data.RecipeType];
 | 
					 | 
				
			||||||
            processFundedProject(guild, techProject, recipe);
 | 
					 | 
				
			||||||
            if (data.RecipeType.substring(0, 39) == "/Lotus/Types/Items/Research/DojoColors/") {
 | 
					 | 
				
			||||||
                guild.ActiveDojoColorResearch = "";
 | 
					 | 
				
			||||||
                await removePigmentsFromGuildMembers(guild._id);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        await guild.save();
 | 
					        await guild.save();
 | 
				
			||||||
        await inventory.save();
 | 
					        await inventory.save();
 | 
				
			||||||
@ -238,43 +234,6 @@ export const guildTechController: RequestHandler = async (req, res) => {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const processFundedProject = (
 | 
					 | 
				
			||||||
    guild: TGuildDatabaseDocument,
 | 
					 | 
				
			||||||
    techProject: ITechProjectDatabase,
 | 
					 | 
				
			||||||
    recipe: IDojoResearch
 | 
					 | 
				
			||||||
): void => {
 | 
					 | 
				
			||||||
    techProject.State = 1;
 | 
					 | 
				
			||||||
    techProject.CompletionDate = new Date(Date.now() + (config.noDojoResearchTime ? 0 : recipe.time) * 1000);
 | 
					 | 
				
			||||||
    if (recipe.guildXpValue) {
 | 
					 | 
				
			||||||
        guild.XP += recipe.guildXpValue;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    setTechLogState(guild, techProject.ItemType, config.noDojoResearchTime ? 4 : 3, techProject.CompletionDate);
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const setTechLogState = (
 | 
					 | 
				
			||||||
    guild: TGuildDatabaseDocument,
 | 
					 | 
				
			||||||
    type: string,
 | 
					 | 
				
			||||||
    state: number,
 | 
					 | 
				
			||||||
    dateTime: Date | undefined = undefined
 | 
					 | 
				
			||||||
): boolean => {
 | 
					 | 
				
			||||||
    guild.TechChanges ??= [];
 | 
					 | 
				
			||||||
    const entry = guild.TechChanges.find(x => x.details == type);
 | 
					 | 
				
			||||||
    if (entry) {
 | 
					 | 
				
			||||||
        if (entry.entryType == state) {
 | 
					 | 
				
			||||||
            return false;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        entry.dateTime = dateTime;
 | 
					 | 
				
			||||||
        entry.entryType = state;
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
        guild.TechChanges.push({
 | 
					 | 
				
			||||||
            dateTime: dateTime,
 | 
					 | 
				
			||||||
            entryType: state,
 | 
					 | 
				
			||||||
            details: type
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return true;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type TGuildTechRequest =
 | 
					type TGuildTechRequest =
 | 
				
			||||||
    | { Action: "Sync" | "SomethingElseThatWeMightNotKnowAbout" }
 | 
					    | { Action: "Sync" | "SomethingElseThatWeMightNotKnowAbout" }
 | 
				
			||||||
    | IGuildTechBasicRequest
 | 
					    | IGuildTechBasicRequest
 | 
				
			||||||
 | 
				
			|||||||
@ -13,11 +13,12 @@ import {
 | 
				
			|||||||
    IGuildClient,
 | 
					    IGuildClient,
 | 
				
			||||||
    IGuildMemberClient,
 | 
					    IGuildMemberClient,
 | 
				
			||||||
    IGuildMemberDatabase,
 | 
					    IGuildMemberDatabase,
 | 
				
			||||||
    IGuildVault
 | 
					    IGuildVault,
 | 
				
			||||||
 | 
					    ITechProjectDatabase
 | 
				
			||||||
} from "@/src/types/guildTypes";
 | 
					} from "@/src/types/guildTypes";
 | 
				
			||||||
import { toMongoDate, toOid } from "@/src/helpers/inventoryHelpers";
 | 
					import { toMongoDate, toOid } from "@/src/helpers/inventoryHelpers";
 | 
				
			||||||
import { Types } from "mongoose";
 | 
					import { Types } from "mongoose";
 | 
				
			||||||
import { ExportDojoRecipes, IDojoBuild } from "warframe-public-export-plus";
 | 
					import { ExportDojoRecipes, IDojoBuild, IDojoResearch } from "warframe-public-export-plus";
 | 
				
			||||||
import { logger } from "../utils/logger";
 | 
					import { logger } from "../utils/logger";
 | 
				
			||||||
import { config } from "./configService";
 | 
					import { config } from "./configService";
 | 
				
			||||||
import { Account } from "../models/loginModel";
 | 
					import { Account } from "../models/loginModel";
 | 
				
			||||||
@ -171,7 +172,7 @@ export const getDojoClient = async (
 | 
				
			|||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    if (newTier) {
 | 
					                    if (newTier) {
 | 
				
			||||||
                        logger.debug(`clan finished building barracks, updating to tier ${newTier}`);
 | 
					                        logger.debug(`clan finished building barracks, updating to tier ${newTier}`);
 | 
				
			||||||
                        setGuildTier(guild, newTier);
 | 
					                        await setGuildTier(guild, newTier);
 | 
				
			||||||
                        needSave = true;
 | 
					                        needSave = true;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
@ -211,7 +212,7 @@ export const getDojoClient = async (
 | 
				
			|||||||
    if (roomsToRemove.length) {
 | 
					    if (roomsToRemove.length) {
 | 
				
			||||||
        logger.debug(`removing now-destroyed rooms`, roomsToRemove);
 | 
					        logger.debug(`removing now-destroyed rooms`, roomsToRemove);
 | 
				
			||||||
        for (const id of roomsToRemove) {
 | 
					        for (const id of roomsToRemove) {
 | 
				
			||||||
            removeDojoRoom(guild, id);
 | 
					            await removeDojoRoom(guild, id);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        needSave = true;
 | 
					        needSave = true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -227,7 +228,10 @@ export const scaleRequiredCount = (tier: number, count: number): number => {
 | 
				
			|||||||
    return Math.max(1, Math.trunc(count * guildTierScalingFactors[tier - 1]));
 | 
					    return Math.max(1, Math.trunc(count * guildTierScalingFactors[tier - 1]));
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const removeDojoRoom = (guild: TGuildDatabaseDocument, componentId: Types.ObjectId | string): void => {
 | 
					export const removeDojoRoom = async (
 | 
				
			||||||
 | 
					    guild: TGuildDatabaseDocument,
 | 
				
			||||||
 | 
					    componentId: Types.ObjectId | string
 | 
				
			||||||
 | 
					): Promise<void> => {
 | 
				
			||||||
    const component = guild.DojoComponents.splice(
 | 
					    const component = guild.DojoComponents.splice(
 | 
				
			||||||
        guild.DojoComponents.findIndex(x => x._id.equals(componentId)),
 | 
					        guild.DojoComponents.findIndex(x => x._id.equals(componentId)),
 | 
				
			||||||
        1
 | 
					        1
 | 
				
			||||||
@ -249,16 +253,16 @@ export const removeDojoRoom = (guild: TGuildDatabaseDocument, componentId: Types
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    switch (component.pf) {
 | 
					    switch (component.pf) {
 | 
				
			||||||
        case "/Lotus/Levels/ClanDojo/ClanDojoBarracksShadow.level":
 | 
					        case "/Lotus/Levels/ClanDojo/ClanDojoBarracksShadow.level":
 | 
				
			||||||
            setGuildTier(guild, 1);
 | 
					            await setGuildTier(guild, 1);
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        case "/Lotus/Levels/ClanDojo/ClanDojoBarracksStorm.level":
 | 
					        case "/Lotus/Levels/ClanDojo/ClanDojoBarracksStorm.level":
 | 
				
			||||||
            setGuildTier(guild, 2);
 | 
					            await setGuildTier(guild, 2);
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        case "/Lotus/Levels/ClanDojo/ClanDojoBarracksMountain.level":
 | 
					        case "/Lotus/Levels/ClanDojo/ClanDojoBarracksMountain.level":
 | 
				
			||||||
            setGuildTier(guild, 3);
 | 
					            await setGuildTier(guild, 3);
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        case "/Lotus/Levels/ClanDojo/ClanDojoBarracksMoon.level":
 | 
					        case "/Lotus/Levels/ClanDojo/ClanDojoBarracksMoon.level":
 | 
				
			||||||
            setGuildTier(guild, 4);
 | 
					            await setGuildTier(guild, 4);
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@ -404,7 +408,59 @@ export const removePigmentsFromGuildMembers = async (guildId: string | Types.Obj
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const setGuildTier = (guild: TGuildDatabaseDocument, newTier: number): void => {
 | 
					export const processGuildTechProjectContributionsUpdate = async (
 | 
				
			||||||
 | 
					    guild: TGuildDatabaseDocument,
 | 
				
			||||||
 | 
					    techProject: ITechProjectDatabase
 | 
				
			||||||
 | 
					): Promise<void> => {
 | 
				
			||||||
 | 
					    if (techProject.ReqCredits == 0 && !techProject.ReqItems.find(x => x.ItemCount > 0)) {
 | 
				
			||||||
 | 
					        // This research is now fully funded.
 | 
				
			||||||
 | 
					        const recipe = ExportDojoRecipes.research[techProject.ItemType];
 | 
				
			||||||
 | 
					        processFundedGuildTechProject(guild, techProject, recipe);
 | 
				
			||||||
 | 
					        if (techProject.ItemType.substring(0, 39) == "/Lotus/Types/Items/Research/DojoColors/") {
 | 
				
			||||||
 | 
					            guild.ActiveDojoColorResearch = "";
 | 
				
			||||||
 | 
					            await removePigmentsFromGuildMembers(guild._id);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const processFundedGuildTechProject = (
 | 
				
			||||||
 | 
					    guild: TGuildDatabaseDocument,
 | 
				
			||||||
 | 
					    techProject: ITechProjectDatabase,
 | 
				
			||||||
 | 
					    recipe: IDojoResearch
 | 
				
			||||||
 | 
					): void => {
 | 
				
			||||||
 | 
					    techProject.State = 1;
 | 
				
			||||||
 | 
					    techProject.CompletionDate = new Date(Date.now() + (config.noDojoResearchTime ? 0 : recipe.time) * 1000);
 | 
				
			||||||
 | 
					    if (recipe.guildXpValue) {
 | 
				
			||||||
 | 
					        guild.XP += recipe.guildXpValue;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    setGuildTechLogState(guild, techProject.ItemType, config.noDojoResearchTime ? 4 : 3, techProject.CompletionDate);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const setGuildTechLogState = (
 | 
				
			||||||
 | 
					    guild: TGuildDatabaseDocument,
 | 
				
			||||||
 | 
					    type: string,
 | 
				
			||||||
 | 
					    state: number,
 | 
				
			||||||
 | 
					    dateTime: Date | undefined = undefined
 | 
				
			||||||
 | 
					): boolean => {
 | 
				
			||||||
 | 
					    guild.TechChanges ??= [];
 | 
				
			||||||
 | 
					    const entry = guild.TechChanges.find(x => x.details == type);
 | 
				
			||||||
 | 
					    if (entry) {
 | 
				
			||||||
 | 
					        if (entry.entryType == state) {
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        entry.dateTime = dateTime;
 | 
				
			||||||
 | 
					        entry.entryType = state;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        guild.TechChanges.push({
 | 
				
			||||||
 | 
					            dateTime: dateTime,
 | 
				
			||||||
 | 
					            entryType: state,
 | 
				
			||||||
 | 
					            details: type
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const setGuildTier = async (guild: TGuildDatabaseDocument, newTier: number): Promise<void> => {
 | 
				
			||||||
    const oldTier = guild.Tier;
 | 
					    const oldTier = guild.Tier;
 | 
				
			||||||
    guild.Tier = newTier;
 | 
					    guild.Tier = newTier;
 | 
				
			||||||
    if (guild.TechProjects) {
 | 
					    if (guild.TechProjects) {
 | 
				
			||||||
@ -436,6 +492,9 @@ const setGuildTier = (guild: TGuildDatabaseDocument, newTier: number): void => {
 | 
				
			|||||||
                    project.ReqItems[i].ItemCount = 0;
 | 
					                    project.ReqItems[i].ItemCount = 0;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Check if research is fully funded now due to lowered requirements.
 | 
				
			||||||
 | 
					            await processGuildTechProjectContributionsUpdate(guild, project);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user