feat: clan tiers #1378
@ -32,7 +32,7 @@ export const abortDojoComponentController: RequestHandler = async (req, res) =>
 | 
			
		||||
    if (request.DecoId) {
 | 
			
		||||
        removeDojoDeco(guild, request.ComponentId, request.DecoId);
 | 
			
		||||
    } else {
 | 
			
		||||
        removeDojoRoom(guild, request.ComponentId);
 | 
			
		||||
        await removeDojoRoom(guild, request.ComponentId);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    await guild.save();
 | 
			
		||||
 | 
			
		||||
@ -4,10 +4,13 @@ import {
 | 
			
		||||
    getGuildVault,
 | 
			
		||||
    hasAccessToDojo,
 | 
			
		||||
    hasGuildPermission,
 | 
			
		||||
    processFundedGuildTechProject,
 | 
			
		||||
    processGuildTechProjectContributionsUpdate,
 | 
			
		||||
    removePigmentsFromGuildMembers,
 | 
			
		||||
    scaleRequiredCount
 | 
			
		||||
    scaleRequiredCount,
 | 
			
		||||
    setGuildTechLogState
 | 
			
		||||
} 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 {
 | 
			
		||||
    addItem,
 | 
			
		||||
@ -20,8 +23,8 @@ import {
 | 
			
		||||
import { IMiscItem } from "@/src/types/inventoryTypes/inventoryTypes";
 | 
			
		||||
import { IInventoryChanges } from "@/src/types/purchaseTypes";
 | 
			
		||||
import { config } from "@/src/services/configService";
 | 
			
		||||
import { GuildPermission, ITechProjectClient, ITechProjectDatabase } from "@/src/types/guildTypes";
 | 
			
		||||
import { GuildMember, TGuildDatabaseDocument } from "@/src/models/guildModel";
 | 
			
		||||
import { GuildPermission, ITechProjectClient } from "@/src/types/guildTypes";
 | 
			
		||||
import { GuildMember } from "@/src/models/guildModel";
 | 
			
		||||
import { toMongoDate } from "@/src/helpers/inventoryHelpers";
 | 
			
		||||
import { logger } from "@/src/utils/logger";
 | 
			
		||||
 | 
			
		||||
@ -44,7 +47,7 @@ export const guildTechController: RequestHandler = async (req, res) => {
 | 
			
		||||
                if (project.CompletionDate) {
 | 
			
		||||
                    techProject.CompletionDate = toMongoDate(project.CompletionDate);
 | 
			
		||||
                    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);
 | 
			
		||||
@ -74,9 +77,9 @@ export const guildTechController: RequestHandler = async (req, res) => {
 | 
			
		||||
                        State: 0
 | 
			
		||||
                    }) - 1
 | 
			
		||||
                ];
 | 
			
		||||
            setTechLogState(guild, techProject.ItemType, 5);
 | 
			
		||||
            setGuildTechLogState(guild, techProject.ItemType, 5);
 | 
			
		||||
            if (config.noDojoResearchCosts) {
 | 
			
		||||
                processFundedProject(guild, techProject, recipe);
 | 
			
		||||
                processFundedGuildTechProject(guild, techProject, recipe);
 | 
			
		||||
            } else {
 | 
			
		||||
                if (data.RecipeType.substring(0, 39) == "/Lotus/Types/Items/Research/DojoColors/") {
 | 
			
		||||
                    guild.ActiveDojoColorResearch = data.RecipeType;
 | 
			
		||||
@ -151,15 +154,8 @@ export const guildTechController: RequestHandler = async (req, res) => {
 | 
			
		||||
        const inventoryChanges: IInventoryChanges = updateCurrency(inventory, contributions.RegularCredits, false);
 | 
			
		||||
        inventoryChanges.MiscItems = miscItemChanges;
 | 
			
		||||
 | 
			
		||||
        if (techProject.ReqCredits == 0 && !techProject.ReqItems.find(x => x.ItemCount > 0)) {
 | 
			
		||||
            // This research is now fully funded.
 | 
			
		||||
            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);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        // Check if research is fully funded now.
 | 
			
		||||
        await processGuildTechProjectContributionsUpdate(guild, techProject);
 | 
			
		||||
 | 
			
		||||
        await guild.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 =
 | 
			
		||||
    | { Action: "Sync" | "SomethingElseThatWeMightNotKnowAbout" }
 | 
			
		||||
    | IGuildTechBasicRequest
 | 
			
		||||
 | 
			
		||||
@ -13,11 +13,12 @@ import {
 | 
			
		||||
    IGuildClient,
 | 
			
		||||
    IGuildMemberClient,
 | 
			
		||||
    IGuildMemberDatabase,
 | 
			
		||||
    IGuildVault
 | 
			
		||||
    IGuildVault,
 | 
			
		||||
    ITechProjectDatabase
 | 
			
		||||
} from "@/src/types/guildTypes";
 | 
			
		||||
import { toMongoDate, toOid } from "@/src/helpers/inventoryHelpers";
 | 
			
		||||
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 { config } from "./configService";
 | 
			
		||||
import { Account } from "../models/loginModel";
 | 
			
		||||
@ -171,7 +172,7 @@ export const getDojoClient = async (
 | 
			
		||||
                    }
 | 
			
		||||
                    if (newTier) {
 | 
			
		||||
                        logger.debug(`clan finished building barracks, updating to tier ${newTier}`);
 | 
			
		||||
                        setGuildTier(guild, newTier);
 | 
			
		||||
                        await setGuildTier(guild, newTier);
 | 
			
		||||
                        needSave = true;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
@ -211,7 +212,7 @@ export const getDojoClient = async (
 | 
			
		||||
    if (roomsToRemove.length) {
 | 
			
		||||
        logger.debug(`removing now-destroyed rooms`, roomsToRemove);
 | 
			
		||||
        for (const id of roomsToRemove) {
 | 
			
		||||
            removeDojoRoom(guild, id);
 | 
			
		||||
            await removeDojoRoom(guild, id);
 | 
			
		||||
        }
 | 
			
		||||
        needSave = true;
 | 
			
		||||
    }
 | 
			
		||||
@ -227,7 +228,10 @@ export const scaleRequiredCount = (tier: number, count: number): number => {
 | 
			
		||||
    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(
 | 
			
		||||
        guild.DojoComponents.findIndex(x => x._id.equals(componentId)),
 | 
			
		||||
        1
 | 
			
		||||
@ -249,16 +253,16 @@ export const removeDojoRoom = (guild: TGuildDatabaseDocument, componentId: Types
 | 
			
		||||
 | 
			
		||||
    switch (component.pf) {
 | 
			
		||||
        case "/Lotus/Levels/ClanDojo/ClanDojoBarracksShadow.level":
 | 
			
		||||
            setGuildTier(guild, 1);
 | 
			
		||||
            await setGuildTier(guild, 1);
 | 
			
		||||
            break;
 | 
			
		||||
        case "/Lotus/Levels/ClanDojo/ClanDojoBarracksStorm.level":
 | 
			
		||||
            setGuildTier(guild, 2);
 | 
			
		||||
            await setGuildTier(guild, 2);
 | 
			
		||||
            break;
 | 
			
		||||
        case "/Lotus/Levels/ClanDojo/ClanDojoBarracksMountain.level":
 | 
			
		||||
            setGuildTier(guild, 3);
 | 
			
		||||
            await setGuildTier(guild, 3);
 | 
			
		||||
            break;
 | 
			
		||||
        case "/Lotus/Levels/ClanDojo/ClanDojoBarracksMoon.level":
 | 
			
		||||
            setGuildTier(guild, 4);
 | 
			
		||||
            await setGuildTier(guild, 4);
 | 
			
		||||
            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;
 | 
			
		||||
    guild.Tier = newTier;
 | 
			
		||||
    if (guild.TechProjects) {
 | 
			
		||||
@ -436,6 +492,9 @@ const setGuildTier = (guild: TGuildDatabaseDocument, newTier: number): void => {
 | 
			
		||||
                    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