feat: dojo component "collecting materials" state
This commit is contained in:
		
							parent
							
								
									3442f15c6d
								
							
						
					
					
						commit
						fa793e49ca
					
				
							
								
								
									
										19
									
								
								src/controllers/api/abortDojoComponentController.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/controllers/api/abortDojoComponentController.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					import { getDojoClient, getGuildForRequestEx } from "@/src/services/guildService";
 | 
				
			||||||
 | 
					import { getInventory } from "@/src/services/inventoryService";
 | 
				
			||||||
 | 
					import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
				
			||||||
 | 
					import { RequestHandler } from "express";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const abortDojoComponentController: RequestHandler = async (req, res) => {
 | 
				
			||||||
 | 
					    const accountId = await getAccountIdForRequest(req);
 | 
				
			||||||
 | 
					    const inventory = await getInventory(accountId);
 | 
				
			||||||
 | 
					    const guild = await getGuildForRequestEx(req, inventory);
 | 
				
			||||||
 | 
					    const request = JSON.parse(String(req.body)) as IAbortDojoComponentRequest;
 | 
				
			||||||
 | 
					    // TODO: Move already-contributed credits & items to the clan vault
 | 
				
			||||||
 | 
					    guild.DojoComponents.pull({ _id: request.ComponentId });
 | 
				
			||||||
 | 
					    await guild.save();
 | 
				
			||||||
 | 
					    res.json(getDojoClient(guild, 0));
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface IAbortDojoComponentRequest {
 | 
				
			||||||
 | 
					    ComponentId: string;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										82
									
								
								src/controllers/api/contributeToDojoComponentController.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								src/controllers/api/contributeToDojoComponentController.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,82 @@
 | 
				
			|||||||
 | 
					import { getDojoClient, getGuildForRequestEx, scaleRequiredCount } from "@/src/services/guildService";
 | 
				
			||||||
 | 
					import { addMiscItems, getInventory, updateCurrency } from "@/src/services/inventoryService";
 | 
				
			||||||
 | 
					import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
				
			||||||
 | 
					import { IMiscItem } from "@/src/types/inventoryTypes/inventoryTypes";
 | 
				
			||||||
 | 
					import { IInventoryChanges } from "@/src/types/purchaseTypes";
 | 
				
			||||||
 | 
					import { RequestHandler } from "express";
 | 
				
			||||||
 | 
					import { ExportDojoRecipes } from "warframe-public-export-plus";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const contributeToDojoComponentController: RequestHandler = async (req, res) => {
 | 
				
			||||||
 | 
					    const accountId = await getAccountIdForRequest(req);
 | 
				
			||||||
 | 
					    const inventory = await getInventory(accountId);
 | 
				
			||||||
 | 
					    const guild = await getGuildForRequestEx(req, inventory);
 | 
				
			||||||
 | 
					    const request = JSON.parse(String(req.body)) as IContributeToDojoComponentRequest;
 | 
				
			||||||
 | 
					    const component = guild.DojoComponents.id(request.ComponentId)!;
 | 
				
			||||||
 | 
					    const componentMeta = Object.values(ExportDojoRecipes.rooms).find(x => x.resultType == component.pf)!;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    component.RegularCredits ??= 0;
 | 
				
			||||||
 | 
					    if (component.RegularCredits + request.RegularCredits > scaleRequiredCount(componentMeta.price)) {
 | 
				
			||||||
 | 
					        request.RegularCredits = scaleRequiredCount(componentMeta.price) - component.RegularCredits;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    component.RegularCredits += request.RegularCredits;
 | 
				
			||||||
 | 
					    const inventoryChanges: IInventoryChanges = updateCurrency(inventory, request.RegularCredits, false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    component.MiscItems ??= [];
 | 
				
			||||||
 | 
					    const miscItemChanges: IMiscItem[] = [];
 | 
				
			||||||
 | 
					    for (const ingredientContribution of request.IngredientContributions) {
 | 
				
			||||||
 | 
					        const componentMiscItem = component.MiscItems.find(x => x.ItemType == ingredientContribution.ItemType);
 | 
				
			||||||
 | 
					        if (componentMiscItem) {
 | 
				
			||||||
 | 
					            const ingredientMeta = componentMeta.ingredients.find(x => x.ItemType == ingredientContribution.ItemType)!;
 | 
				
			||||||
 | 
					            if (
 | 
				
			||||||
 | 
					                componentMiscItem.ItemCount + ingredientContribution.ItemCount >
 | 
				
			||||||
 | 
					                scaleRequiredCount(ingredientMeta.ItemCount)
 | 
				
			||||||
 | 
					            ) {
 | 
				
			||||||
 | 
					                ingredientContribution.ItemCount =
 | 
				
			||||||
 | 
					                    scaleRequiredCount(ingredientMeta.ItemCount) - componentMiscItem.ItemCount;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            componentMiscItem.ItemCount += ingredientContribution.ItemCount;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            component.MiscItems.push(ingredientContribution);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        miscItemChanges.push({
 | 
				
			||||||
 | 
					            ItemType: ingredientContribution.ItemType,
 | 
				
			||||||
 | 
					            ItemCount: ingredientContribution.ItemCount * -1
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    addMiscItems(inventory, miscItemChanges);
 | 
				
			||||||
 | 
					    inventoryChanges.MiscItems = miscItemChanges;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (component.RegularCredits >= scaleRequiredCount(componentMeta.price)) {
 | 
				
			||||||
 | 
					        let fullyFunded = true;
 | 
				
			||||||
 | 
					        for (const ingredient of componentMeta.ingredients) {
 | 
				
			||||||
 | 
					            const componentMiscItem = component.MiscItems.find(x => x.ItemType == ingredient.ItemType);
 | 
				
			||||||
 | 
					            if (!componentMiscItem || componentMiscItem.ItemCount < scaleRequiredCount(ingredient.ItemCount)) {
 | 
				
			||||||
 | 
					                fullyFunded = false;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (fullyFunded) {
 | 
				
			||||||
 | 
					            component.RegularCredits = undefined;
 | 
				
			||||||
 | 
					            component.MiscItems = undefined;
 | 
				
			||||||
 | 
					            component.CompletionTime = new Date(Date.now() + componentMeta.time * 1000);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    await guild.save();
 | 
				
			||||||
 | 
					    await inventory.save();
 | 
				
			||||||
 | 
					    res.json({
 | 
				
			||||||
 | 
					        ...getDojoClient(guild, 0, component._id),
 | 
				
			||||||
 | 
					        InventoryChanges: inventoryChanges
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface IContributeToDojoComponentRequest {
 | 
				
			||||||
 | 
					    ComponentId: string;
 | 
				
			||||||
 | 
					    IngredientContributions: {
 | 
				
			||||||
 | 
					        ItemType: string;
 | 
				
			||||||
 | 
					        ItemCount: number;
 | 
				
			||||||
 | 
					    }[];
 | 
				
			||||||
 | 
					    RegularCredits: number;
 | 
				
			||||||
 | 
					    VaultIngredientContributions: [];
 | 
				
			||||||
 | 
					    VaultCredits: number;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -1,5 +1,5 @@
 | 
				
			|||||||
import { RequestHandler } from "express";
 | 
					import { RequestHandler } from "express";
 | 
				
			||||||
import { getGuildForRequestEx } from "@/src/services/guildService";
 | 
					import { getGuildForRequestEx, scaleRequiredCount } from "@/src/services/guildService";
 | 
				
			||||||
import { ExportDojoRecipes, IDojoResearch } from "warframe-public-export-plus";
 | 
					import { ExportDojoRecipes, IDojoResearch } from "warframe-public-export-plus";
 | 
				
			||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
					import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
				
			||||||
import { addMiscItems, addRecipes, getInventory, updateCurrency } from "@/src/services/inventoryService";
 | 
					import { addMiscItems, addRecipes, getInventory, updateCurrency } from "@/src/services/inventoryService";
 | 
				
			||||||
@ -130,8 +130,3 @@ interface IGuildTechContributeFields {
 | 
				
			|||||||
    VaultCredits: number;
 | 
					    VaultCredits: number;
 | 
				
			||||||
    VaultMiscItems: IMiscItem[];
 | 
					    VaultMiscItems: IMiscItem[];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
const scaleRequiredCount = (count: number): number => {
 | 
					 | 
				
			||||||
    // The recipes in the export are for Moon clans. For now we'll just assume we only have Ghost clans.
 | 
					 | 
				
			||||||
    return Math.max(1, Math.trunc(count / 100));
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -12,7 +12,7 @@ export const setDojoComponentMessageController: RequestHandler = async (req, res
 | 
				
			|||||||
        component.Message = payload.Message;
 | 
					        component.Message = payload.Message;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    await guild.save();
 | 
					    await guild.save();
 | 
				
			||||||
    res.json(getDojoClient(guild, 1));
 | 
					    res.json(getDojoClient(guild, 0, component._id));
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type SetDojoComponentMessageRequest = { Name: string } | { Message: string };
 | 
					type SetDojoComponentMessageRequest = { Name: string } | { Message: string };
 | 
				
			||||||
 | 
				
			|||||||
@ -26,8 +26,7 @@ export const startDojoRecipeController: RequestHandler = async (req, res) => {
 | 
				
			|||||||
        ppf: request.PlacedComponent.ppf,
 | 
					        ppf: request.PlacedComponent.ppf,
 | 
				
			||||||
        pi: new Types.ObjectId(request.PlacedComponent.pi!.$oid),
 | 
					        pi: new Types.ObjectId(request.PlacedComponent.pi!.$oid),
 | 
				
			||||||
        op: request.PlacedComponent.op,
 | 
					        op: request.PlacedComponent.op,
 | 
				
			||||||
        pp: request.PlacedComponent.pp,
 | 
					        pp: request.PlacedComponent.pp
 | 
				
			||||||
        CompletionTime: new Date(Date.now()) // TOOD: Omit this field & handle the "Collecting Materials" state.
 | 
					 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    await guild.save();
 | 
					    await guild.save();
 | 
				
			||||||
    res.json(getDojoClient(guild, 0));
 | 
					    res.json(getDojoClient(guild, 0));
 | 
				
			||||||
 | 
				
			|||||||
@ -16,6 +16,8 @@ const dojoComponentSchema = new Schema<IDojoComponentDatabase>({
 | 
				
			|||||||
    pp: String,
 | 
					    pp: String,
 | 
				
			||||||
    Name: String,
 | 
					    Name: String,
 | 
				
			||||||
    Message: String,
 | 
					    Message: String,
 | 
				
			||||||
 | 
					    RegularCredits: Number,
 | 
				
			||||||
 | 
					    MiscItems: { type: [typeCountSchema], default: undefined },
 | 
				
			||||||
    CompletionTime: Date
 | 
					    CompletionTime: Date
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,6 @@
 | 
				
			|||||||
import express from "express";
 | 
					import express from "express";
 | 
				
			||||||
import { abandonLibraryDailyTaskController } from "@/src/controllers/api/abandonLibraryDailyTaskController";
 | 
					import { abandonLibraryDailyTaskController } from "@/src/controllers/api/abandonLibraryDailyTaskController";
 | 
				
			||||||
 | 
					import { abortDojoComponentController } from "@/src/controllers/api/abortDojoComponentController";
 | 
				
			||||||
import { activateRandomModController } from "@/src/controllers/api/activateRandomModController";
 | 
					import { activateRandomModController } from "@/src/controllers/api/activateRandomModController";
 | 
				
			||||||
import { addFriendImageController } from "@/src/controllers/api/addFriendImageController";
 | 
					import { addFriendImageController } from "@/src/controllers/api/addFriendImageController";
 | 
				
			||||||
import { arcaneCommonController } from "@/src/controllers/api/arcaneCommonController";
 | 
					import { arcaneCommonController } from "@/src/controllers/api/arcaneCommonController";
 | 
				
			||||||
@ -11,6 +12,7 @@ import { claimCompletedRecipeController } from "@/src/controllers/api/claimCompl
 | 
				
			|||||||
import { claimLibraryDailyTaskRewardController } from "@/src/controllers/api/claimLibraryDailyTaskRewardController";
 | 
					import { claimLibraryDailyTaskRewardController } from "@/src/controllers/api/claimLibraryDailyTaskRewardController";
 | 
				
			||||||
import { clearDialogueHistoryController } from "@/src/controllers/api/clearDialogueHistoryController";
 | 
					import { clearDialogueHistoryController } from "@/src/controllers/api/clearDialogueHistoryController";
 | 
				
			||||||
import { completeRandomModChallengeController } from "@/src/controllers/api/completeRandomModChallengeController";
 | 
					import { completeRandomModChallengeController } from "@/src/controllers/api/completeRandomModChallengeController";
 | 
				
			||||||
 | 
					import { contributeToDojoComponentController } from "@/src/controllers/api/contributeToDojoComponentController";
 | 
				
			||||||
import { createGuildController } from "@/src/controllers/api/createGuildController";
 | 
					import { createGuildController } from "@/src/controllers/api/createGuildController";
 | 
				
			||||||
import { creditsController } from "@/src/controllers/api/creditsController";
 | 
					import { creditsController } from "@/src/controllers/api/creditsController";
 | 
				
			||||||
import { deleteSessionController } from "@/src/controllers/api/deleteSessionController";
 | 
					import { deleteSessionController } from "@/src/controllers/api/deleteSessionController";
 | 
				
			||||||
@ -135,6 +137,7 @@ apiRouter.get("/surveys.php", surveysController);
 | 
				
			|||||||
apiRouter.get("/updateSession.php", updateSessionGetController);
 | 
					apiRouter.get("/updateSession.php", updateSessionGetController);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// post
 | 
					// post
 | 
				
			||||||
 | 
					apiRouter.post("/abortDojoComponent.php", abortDojoComponentController);
 | 
				
			||||||
apiRouter.post("/activateRandomMod.php", activateRandomModController);
 | 
					apiRouter.post("/activateRandomMod.php", activateRandomModController);
 | 
				
			||||||
apiRouter.post("/addFriendImage.php", addFriendImageController);
 | 
					apiRouter.post("/addFriendImage.php", addFriendImageController);
 | 
				
			||||||
apiRouter.post("/arcaneCommon.php", arcaneCommonController);
 | 
					apiRouter.post("/arcaneCommon.php", arcaneCommonController);
 | 
				
			||||||
@ -144,6 +147,7 @@ apiRouter.post("/changeDojoRoot.php", changeDojoRootController);
 | 
				
			|||||||
apiRouter.post("/claimCompletedRecipe.php", claimCompletedRecipeController);
 | 
					apiRouter.post("/claimCompletedRecipe.php", claimCompletedRecipeController);
 | 
				
			||||||
apiRouter.post("/clearDialogueHistory.php", clearDialogueHistoryController);
 | 
					apiRouter.post("/clearDialogueHistory.php", clearDialogueHistoryController);
 | 
				
			||||||
apiRouter.post("/completeRandomModChallenge.php", completeRandomModChallengeController);
 | 
					apiRouter.post("/completeRandomModChallenge.php", completeRandomModChallengeController);
 | 
				
			||||||
 | 
					apiRouter.post("/contributeToDojoComponent.php", contributeToDojoComponentController);
 | 
				
			||||||
apiRouter.post("/createGuild.php", createGuildController);
 | 
					apiRouter.post("/createGuild.php", createGuildController);
 | 
				
			||||||
apiRouter.post("/drones.php", dronesController);
 | 
					apiRouter.post("/drones.php", dronesController);
 | 
				
			||||||
apiRouter.post("/endlessXp.php", endlessXpController);
 | 
					apiRouter.post("/endlessXp.php", endlessXpController);
 | 
				
			||||||
 | 
				
			|||||||
@ -5,6 +5,7 @@ import { Guild, TGuildDatabaseDocument } from "@/src/models/guildModel";
 | 
				
			|||||||
import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
 | 
					import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
 | 
				
			||||||
import { IDojoClient, IDojoComponentClient } from "@/src/types/guildTypes";
 | 
					import { IDojoClient, IDojoComponentClient } from "@/src/types/guildTypes";
 | 
				
			||||||
import { toMongoDate, toOid } from "@/src/helpers/inventoryHelpers";
 | 
					import { toMongoDate, toOid } from "@/src/helpers/inventoryHelpers";
 | 
				
			||||||
 | 
					import { Types } from "mongoose";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const getGuildForRequest = async (req: Request): Promise<TGuildDatabaseDocument> => {
 | 
					export const getGuildForRequest = async (req: Request): Promise<TGuildDatabaseDocument> => {
 | 
				
			||||||
    const accountId = await getAccountIdForRequest(req);
 | 
					    const accountId = await getAccountIdForRequest(req);
 | 
				
			||||||
@ -27,7 +28,11 @@ export const getGuildForRequestEx = async (
 | 
				
			|||||||
    return guild;
 | 
					    return guild;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const getDojoClient = (guild: TGuildDatabaseDocument, status: number): IDojoClient => {
 | 
					export const getDojoClient = (
 | 
				
			||||||
 | 
					    guild: TGuildDatabaseDocument,
 | 
				
			||||||
 | 
					    status: number,
 | 
				
			||||||
 | 
					    componentId: Types.ObjectId | undefined = undefined
 | 
				
			||||||
 | 
					): IDojoClient => {
 | 
				
			||||||
    const dojo: IDojoClient = {
 | 
					    const dojo: IDojoClient = {
 | 
				
			||||||
        _id: { $oid: guild._id.toString() },
 | 
					        _id: { $oid: guild._id.toString() },
 | 
				
			||||||
        Name: guild.Name,
 | 
					        Name: guild.Name,
 | 
				
			||||||
@ -41,6 +46,7 @@ export const getDojoClient = (guild: TGuildDatabaseDocument, status: number): ID
 | 
				
			|||||||
        DojoComponents: []
 | 
					        DojoComponents: []
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    guild.DojoComponents.forEach(dojoComponent => {
 | 
					    guild.DojoComponents.forEach(dojoComponent => {
 | 
				
			||||||
 | 
					        if (!componentId || componentId == dojoComponent._id) {
 | 
				
			||||||
            const clientComponent: IDojoComponentClient = {
 | 
					            const clientComponent: IDojoComponentClient = {
 | 
				
			||||||
                id: toOid(dojoComponent._id),
 | 
					                id: toOid(dojoComponent._id),
 | 
				
			||||||
                pf: dojoComponent.pf,
 | 
					                pf: dojoComponent.pf,
 | 
				
			||||||
@ -56,8 +62,17 @@ export const getDojoClient = (guild: TGuildDatabaseDocument, status: number): ID
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
            if (dojoComponent.CompletionTime) {
 | 
					            if (dojoComponent.CompletionTime) {
 | 
				
			||||||
                clientComponent.CompletionTime = toMongoDate(dojoComponent.CompletionTime);
 | 
					                clientComponent.CompletionTime = toMongoDate(dojoComponent.CompletionTime);
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                clientComponent.RegularCredits = dojoComponent.RegularCredits;
 | 
				
			||||||
 | 
					                clientComponent.MiscItems = dojoComponent.MiscItems;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            dojo.DojoComponents.push(clientComponent);
 | 
					            dojo.DojoComponents.push(clientComponent);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    return dojo;
 | 
					    return dojo;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const scaleRequiredCount = (count: number): number => {
 | 
				
			||||||
 | 
					    // The recipes in the export are for Moon clans. For now we'll just assume we only have Ghost clans.
 | 
				
			||||||
 | 
					    return Math.max(1, Math.trunc(count / 100));
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user