feat: place decos & contribute resources for their construction

This commit is contained in:
Sainan 2025-03-04 19:11:04 +01:00
parent fdf8d1a788
commit ca4fce8a46
7 changed files with 181 additions and 70 deletions

View File

@ -1,10 +1,24 @@
import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
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";
import { ExportDojoRecipes, IDojoRecipe } from "warframe-public-export-plus";
interface IContributeToDojoComponentRequest {
ComponentId: string;
DecoId?: string;
DecoType?: string;
IngredientContributions: {
ItemType: string;
ItemCount: number;
}[];
RegularCredits: number;
VaultIngredientContributions: [];
VaultCredits: number;
}
export const contributeToDojoComponentController: RequestHandler = async (req, res) => {
const accountId = await getAccountIdForRequest(req);
@ -13,14 +27,48 @@ export const contributeToDojoComponentController: RequestHandler = async (req, r
// 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.
const request = JSON.parse(String(req.body)) as IContributeToDojoComponentRequest;
const component = guild.DojoComponents.id(request.ComponentId)!;
const inventoryChanges: IInventoryChanges = {};
if (!component.CompletionTime) {
const componentMeta = Object.values(ExportDojoRecipes.rooms).find(x => x.resultType == component.pf)!;
// 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(request, inventory, inventoryChanges, meta, 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(request, inventory, inventoryChanges, meta, deco);
}
}
await guild.save();
await inventory.save();
res.json({
...getDojoClient(guild, 0, component._id),
InventoryChanges: inventoryChanges
});
};
interface IDojoContributable {
RegularCredits?: number;
MiscItems?: IMiscItem[];
CompletionTime?: Date;
}
const processContribution = (
request: IContributeToDojoComponentRequest,
inventory: TInventoryDatabaseDocument,
inventoryChanges: IInventoryChanges,
meta: IDojoRecipe,
component: IDojoContributable
): void => {
component.RegularCredits ??= 0;
if (component.RegularCredits + request.RegularCredits > scaleRequiredCount(componentMeta.price)) {
request.RegularCredits = scaleRequiredCount(componentMeta.price) - component.RegularCredits;
if (component.RegularCredits + request.RegularCredits > scaleRequiredCount(meta.price)) {
request.RegularCredits = scaleRequiredCount(meta.price) - component.RegularCredits;
}
component.RegularCredits += request.RegularCredits;
inventoryChanges.RegularCredits = -request.RegularCredits;
@ -31,9 +79,7 @@ export const contributeToDojoComponentController: RequestHandler = async (req, r
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
)!;
const ingredientMeta = meta.ingredients.find(x => x.ItemType == ingredientContribution.ItemType)!;
if (
componentMiscItem.ItemCount + ingredientContribution.ItemCount >
scaleRequiredCount(ingredientMeta.ItemCount)
@ -53,9 +99,9 @@ export const contributeToDojoComponentController: RequestHandler = async (req, r
addMiscItems(inventory, miscItemChanges);
inventoryChanges.MiscItems = miscItemChanges;
if (component.RegularCredits >= scaleRequiredCount(componentMeta.price)) {
if (component.RegularCredits >= scaleRequiredCount(meta.price)) {
let fullyFunded = true;
for (const ingredient of componentMeta.ingredients) {
for (const ingredient of meta.ingredients) {
const componentMiscItem = component.MiscItems.find(x => x.ItemType == ingredient.ItemType);
if (!componentMiscItem || componentMiscItem.ItemCount < scaleRequiredCount(ingredient.ItemCount)) {
fullyFunded = false;
@ -65,26 +111,7 @@ export const contributeToDojoComponentController: RequestHandler = async (req, r
if (fullyFunded) {
component.RegularCredits = undefined;
component.MiscItems = undefined;
component.CompletionTime = new Date(Date.now() + componentMeta.time * 1000);
component.CompletionTime = new Date(Date.now() + meta.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;
}

View File

@ -0,0 +1,38 @@
import { getDojoClient, getGuildForRequest } from "@/src/services/guildService";
import { RequestHandler } from "express";
import { Types } from "mongoose";
import { ExportDojoRecipes } from "warframe-public-export-plus";
export const placeDecoInComponentController: RequestHandler = async (req, res) => {
const guild = await getGuildForRequest(req);
const request = JSON.parse(String(req.body)) as IPlaceDecoInComponentRequest;
// At this point, we know that a member of the guild is making this request. Assuming they are allowed to place decorations.
const component = guild.DojoComponents.id(request.ComponentId)!;
if (component.DecoCapacity === undefined) {
component.DecoCapacity = Object.values(ExportDojoRecipes.rooms).find(
x => x.resultType == component.pf
)!.decoCapacity;
}
component.Decos ??= [];
component.Decos.push({
_id: new Types.ObjectId(),
Type: request.Type,
Pos: request.Pos,
Rot: request.Rot,
Name: request.Name
});
await guild.save();
res.json(getDojoClient(guild, 0)); // TODO: This response format seems incorrect.
};
interface IPlaceDecoInComponentRequest {
ComponentId: string;
Revision: number;
Type: string;
Pos: number[];
Rot: number[];
Name?: string;
}

View File

@ -29,7 +29,8 @@ export const startDojoRecipeController: RequestHandler = async (req, res) => {
ppf: request.PlacedComponent.ppf,
pi: new Types.ObjectId(request.PlacedComponent.pi!.$oid),
op: request.PlacedComponent.op,
pp: request.PlacedComponent.pp
pp: request.PlacedComponent.pp,
DecoCapacity: room?.decoCapacity
}) - 1
];
if (config.noDojoRoomBuildStage) {

View File

@ -2,12 +2,23 @@ import {
IGuildDatabase,
IDojoComponentDatabase,
ITechProjectDatabase,
ITechProjectClient
ITechProjectClient,
IDojoDecoDatabase
} from "@/src/types/guildTypes";
import { Document, Model, model, Schema, Types } from "mongoose";
import { typeCountSchema } from "./inventoryModels/inventoryModel";
import { toMongoDate } from "../helpers/inventoryHelpers";
const dojoDecoSchema = new Schema<IDojoDecoDatabase>({
Type: String,
Pos: [Number],
Rot: [Number],
Name: String,
RegularCredits: Number,
MiscItems: { type: [typeCountSchema], default: undefined },
CompletionTime: Date
});
const dojoComponentSchema = new Schema<IDojoComponentDatabase>({
pf: { type: String, required: true },
ppf: String,
@ -18,7 +29,10 @@ const dojoComponentSchema = new Schema<IDojoComponentDatabase>({
Message: String,
RegularCredits: Number,
MiscItems: { type: [typeCountSchema], default: undefined },
CompletionTime: Date
CompletionTime: Date,
DestructionTime: Date,
Decos: [dojoDecoSchema],
DecoCapacity: Number
});
const techProjectSchema = new Schema<ITechProjectDatabase>(

View File

@ -59,6 +59,7 @@ import { missionInventoryUpdateController } from "@/src/controllers/api/missionI
import { modularWeaponCraftingController } from "@/src/controllers/api/modularWeaponCraftingController";
import { modularWeaponSaleController } from "@/src/controllers/api/modularWeaponSaleController";
import { nameWeaponController } from "@/src/controllers/api/nameWeaponController";
import { placeDecoInComponentController } from "@/src/controllers/api/placeDecoInComponentController";
import { playerSkillsController } from "@/src/controllers/api/playerSkillsController";
import { projectionManagerController } from "@/src/controllers/api/projectionManagerController";
import { purchaseController } from "@/src/controllers/api/purchaseController";
@ -175,6 +176,7 @@ apiRouter.post("/login.php", loginController);
apiRouter.post("/missionInventoryUpdate.php", missionInventoryUpdateController);
apiRouter.post("/modularWeaponCrafting.php", modularWeaponCraftingController);
apiRouter.post("/nameWeapon.php", nameWeaponController);
apiRouter.post("/placeDecoInComponent.php", placeDecoInComponentController);
apiRouter.post("/playerSkills.php", playerSkillsController);
apiRouter.post("/projectionManager.php", projectionManagerController);
apiRouter.post("/purchase.php", purchaseController);

View File

@ -53,7 +53,7 @@ export const getDojoClient = (
ppf: dojoComponent.ppf,
Name: dojoComponent.Name,
Message: dojoComponent.Message,
DecoCapacity: 600
DecoCapacity: dojoComponent.DecoCapacity ?? 600
};
if (dojoComponent.pi) {
clientComponent.pi = toOid(dojoComponent.pi);
@ -66,6 +66,20 @@ export const getDojoClient = (
clientComponent.RegularCredits = dojoComponent.RegularCredits;
clientComponent.MiscItems = dojoComponent.MiscItems;
}
if (dojoComponent.Decos) {
clientComponent.Decos = [];
for (const deco of dojoComponent.Decos) {
clientComponent.Decos.push({
id: toOid(deco._id),
Type: deco.Type,
Pos: deco.Pos,
Rot: deco.Rot,
CompletionTime: deco.CompletionTime ? toMongoDate(deco.CompletionTime) : undefined,
RegularCredits: deco.RegularCredits,
MiscItems: deco.MiscItems
});
}
}
dojo.DojoComponents.push(clientComponent);
}
});

View File

@ -41,18 +41,33 @@ export interface IDojoComponentClient {
CompletionTime?: IMongoDate;
RushPlatinum?: number;
DestructionTime?: IMongoDate;
Decos?: IDojoDecoClient[];
DecoCapacity?: number;
}
export interface IDojoComponentDatabase
extends Omit<
IDojoComponentClient,
"id" | "pi" | "CompletionTime" | "RushPlatinum" | "DestructionTime" | "DecoCapacity"
> {
extends Omit<IDojoComponentClient, "id" | "pi" | "CompletionTime" | "RushPlatinum" | "DestructionTime" | "Decos"> {
_id: Types.ObjectId;
pi?: Types.ObjectId;
CompletionTime?: Date;
//DestructionTime?: Date;
DestructionTime?: Date;
Decos?: IDojoDecoDatabase[];
}
export interface IDojoDecoClient {
id: IOid;
Type: string;
Pos: number[];
Rot: number[];
Name?: string; // for teleporters
RegularCredits?: number;
MiscItems?: IMiscItem[];
CompletionTime?: IMongoDate;
}
export interface IDojoDecoDatabase extends Omit<IDojoDecoClient, "id" | "CompletionTime"> {
_id: Types.ObjectId;
CompletionTime?: Date;
}
export interface ITechProjectClient {