feat: place decos & contribute resources for their construction
This commit is contained in:
parent
fdf8d1a788
commit
ca4fce8a46
@ -1,10 +1,24 @@
|
|||||||
|
import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
|
||||||
import { getDojoClient, getGuildForRequestEx, scaleRequiredCount } from "@/src/services/guildService";
|
import { getDojoClient, getGuildForRequestEx, scaleRequiredCount } from "@/src/services/guildService";
|
||||||
import { addMiscItems, getInventory, updateCurrency } from "@/src/services/inventoryService";
|
import { addMiscItems, getInventory, updateCurrency } from "@/src/services/inventoryService";
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
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 { RequestHandler } from "express";
|
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) => {
|
export const contributeToDojoComponentController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
@ -13,60 +27,21 @@ 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.
|
// 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 request = JSON.parse(String(req.body)) as IContributeToDojoComponentRequest;
|
||||||
const component = guild.DojoComponents.id(request.ComponentId)!;
|
const component = guild.DojoComponents.id(request.ComponentId)!;
|
||||||
|
|
||||||
const inventoryChanges: IInventoryChanges = {};
|
const inventoryChanges: IInventoryChanges = {};
|
||||||
|
|
||||||
if (!component.CompletionTime) {
|
if (!component.CompletionTime) {
|
||||||
const componentMeta = Object.values(ExportDojoRecipes.rooms).find(x => x.resultType == component.pf)!;
|
// Room is in "Collecting Materials" state
|
||||||
|
if (request.DecoId) {
|
||||||
component.RegularCredits ??= 0;
|
throw new Error("attempt to contribute to a deco in an unfinished room?!");
|
||||||
if (component.RegularCredits + request.RegularCredits > scaleRequiredCount(componentMeta.price)) {
|
|
||||||
request.RegularCredits = scaleRequiredCount(componentMeta.price) - component.RegularCredits;
|
|
||||||
}
|
}
|
||||||
component.RegularCredits += request.RegularCredits;
|
const meta = Object.values(ExportDojoRecipes.rooms).find(x => x.resultType == component.pf)!;
|
||||||
inventoryChanges.RegularCredits = -request.RegularCredits;
|
processContribution(request, inventory, inventoryChanges, meta, component);
|
||||||
updateCurrency(inventory, request.RegularCredits, false);
|
} else {
|
||||||
|
// Room is past "Collecting Materials"
|
||||||
component.MiscItems ??= [];
|
if (request.DecoId) {
|
||||||
const miscItemChanges: IMiscItem[] = [];
|
const deco = component.Decos!.find(x => x._id.equals(request.DecoId))!;
|
||||||
for (const ingredientContribution of request.IngredientContributions) {
|
const meta = Object.values(ExportDojoRecipes.decos).find(x => x.resultType == deco.Type)!;
|
||||||
const componentMiscItem = component.MiscItems.find(x => x.ItemType == ingredientContribution.ItemType);
|
processContribution(request, inventory, inventoryChanges, meta, deco);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,13 +53,65 @@ export const contributeToDojoComponentController: RequestHandler = async (req, r
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface IContributeToDojoComponentRequest {
|
interface IDojoContributable {
|
||||||
ComponentId: string;
|
RegularCredits?: number;
|
||||||
IngredientContributions: {
|
MiscItems?: IMiscItem[];
|
||||||
ItemType: string;
|
CompletionTime?: Date;
|
||||||
ItemCount: number;
|
|
||||||
}[];
|
|
||||||
RegularCredits: number;
|
|
||||||
VaultIngredientContributions: [];
|
|
||||||
VaultCredits: number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const processContribution = (
|
||||||
|
request: IContributeToDojoComponentRequest,
|
||||||
|
inventory: TInventoryDatabaseDocument,
|
||||||
|
inventoryChanges: IInventoryChanges,
|
||||||
|
meta: IDojoRecipe,
|
||||||
|
component: IDojoContributable
|
||||||
|
): void => {
|
||||||
|
component.RegularCredits ??= 0;
|
||||||
|
if (component.RegularCredits + request.RegularCredits > scaleRequiredCount(meta.price)) {
|
||||||
|
request.RegularCredits = scaleRequiredCount(meta.price) - component.RegularCredits;
|
||||||
|
}
|
||||||
|
component.RegularCredits += request.RegularCredits;
|
||||||
|
inventoryChanges.RegularCredits = -request.RegularCredits;
|
||||||
|
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 = meta.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(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(ingredient.ItemCount)) {
|
||||||
|
fullyFunded = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (fullyFunded) {
|
||||||
|
component.RegularCredits = undefined;
|
||||||
|
component.MiscItems = undefined;
|
||||||
|
component.CompletionTime = new Date(Date.now() + meta.time * 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
38
src/controllers/api/placeDecoInComponentController.ts
Normal file
38
src/controllers/api/placeDecoInComponentController.ts
Normal 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;
|
||||||
|
}
|
@ -29,7 +29,8 @@ 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,
|
||||||
|
DecoCapacity: room?.decoCapacity
|
||||||
}) - 1
|
}) - 1
|
||||||
];
|
];
|
||||||
if (config.noDojoRoomBuildStage) {
|
if (config.noDojoRoomBuildStage) {
|
||||||
|
@ -2,12 +2,23 @@ import {
|
|||||||
IGuildDatabase,
|
IGuildDatabase,
|
||||||
IDojoComponentDatabase,
|
IDojoComponentDatabase,
|
||||||
ITechProjectDatabase,
|
ITechProjectDatabase,
|
||||||
ITechProjectClient
|
ITechProjectClient,
|
||||||
|
IDojoDecoDatabase
|
||||||
} from "@/src/types/guildTypes";
|
} from "@/src/types/guildTypes";
|
||||||
import { Document, Model, model, Schema, Types } from "mongoose";
|
import { Document, Model, model, Schema, Types } from "mongoose";
|
||||||
import { typeCountSchema } from "./inventoryModels/inventoryModel";
|
import { typeCountSchema } from "./inventoryModels/inventoryModel";
|
||||||
import { toMongoDate } from "../helpers/inventoryHelpers";
|
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>({
|
const dojoComponentSchema = new Schema<IDojoComponentDatabase>({
|
||||||
pf: { type: String, required: true },
|
pf: { type: String, required: true },
|
||||||
ppf: String,
|
ppf: String,
|
||||||
@ -18,7 +29,10 @@ const dojoComponentSchema = new Schema<IDojoComponentDatabase>({
|
|||||||
Message: String,
|
Message: String,
|
||||||
RegularCredits: Number,
|
RegularCredits: Number,
|
||||||
MiscItems: { type: [typeCountSchema], default: undefined },
|
MiscItems: { type: [typeCountSchema], default: undefined },
|
||||||
CompletionTime: Date
|
CompletionTime: Date,
|
||||||
|
DestructionTime: Date,
|
||||||
|
Decos: [dojoDecoSchema],
|
||||||
|
DecoCapacity: Number
|
||||||
});
|
});
|
||||||
|
|
||||||
const techProjectSchema = new Schema<ITechProjectDatabase>(
|
const techProjectSchema = new Schema<ITechProjectDatabase>(
|
||||||
|
@ -59,6 +59,7 @@ import { missionInventoryUpdateController } from "@/src/controllers/api/missionI
|
|||||||
import { modularWeaponCraftingController } from "@/src/controllers/api/modularWeaponCraftingController";
|
import { modularWeaponCraftingController } from "@/src/controllers/api/modularWeaponCraftingController";
|
||||||
import { modularWeaponSaleController } from "@/src/controllers/api/modularWeaponSaleController";
|
import { modularWeaponSaleController } from "@/src/controllers/api/modularWeaponSaleController";
|
||||||
import { nameWeaponController } from "@/src/controllers/api/nameWeaponController";
|
import { nameWeaponController } from "@/src/controllers/api/nameWeaponController";
|
||||||
|
import { placeDecoInComponentController } from "@/src/controllers/api/placeDecoInComponentController";
|
||||||
import { playerSkillsController } from "@/src/controllers/api/playerSkillsController";
|
import { playerSkillsController } from "@/src/controllers/api/playerSkillsController";
|
||||||
import { projectionManagerController } from "@/src/controllers/api/projectionManagerController";
|
import { projectionManagerController } from "@/src/controllers/api/projectionManagerController";
|
||||||
import { purchaseController } from "@/src/controllers/api/purchaseController";
|
import { purchaseController } from "@/src/controllers/api/purchaseController";
|
||||||
@ -175,6 +176,7 @@ apiRouter.post("/login.php", loginController);
|
|||||||
apiRouter.post("/missionInventoryUpdate.php", missionInventoryUpdateController);
|
apiRouter.post("/missionInventoryUpdate.php", missionInventoryUpdateController);
|
||||||
apiRouter.post("/modularWeaponCrafting.php", modularWeaponCraftingController);
|
apiRouter.post("/modularWeaponCrafting.php", modularWeaponCraftingController);
|
||||||
apiRouter.post("/nameWeapon.php", nameWeaponController);
|
apiRouter.post("/nameWeapon.php", nameWeaponController);
|
||||||
|
apiRouter.post("/placeDecoInComponent.php", placeDecoInComponentController);
|
||||||
apiRouter.post("/playerSkills.php", playerSkillsController);
|
apiRouter.post("/playerSkills.php", playerSkillsController);
|
||||||
apiRouter.post("/projectionManager.php", projectionManagerController);
|
apiRouter.post("/projectionManager.php", projectionManagerController);
|
||||||
apiRouter.post("/purchase.php", purchaseController);
|
apiRouter.post("/purchase.php", purchaseController);
|
||||||
|
@ -53,7 +53,7 @@ export const getDojoClient = (
|
|||||||
ppf: dojoComponent.ppf,
|
ppf: dojoComponent.ppf,
|
||||||
Name: dojoComponent.Name,
|
Name: dojoComponent.Name,
|
||||||
Message: dojoComponent.Message,
|
Message: dojoComponent.Message,
|
||||||
DecoCapacity: 600
|
DecoCapacity: dojoComponent.DecoCapacity ?? 600
|
||||||
};
|
};
|
||||||
if (dojoComponent.pi) {
|
if (dojoComponent.pi) {
|
||||||
clientComponent.pi = toOid(dojoComponent.pi);
|
clientComponent.pi = toOid(dojoComponent.pi);
|
||||||
@ -66,6 +66,20 @@ export const getDojoClient = (
|
|||||||
clientComponent.RegularCredits = dojoComponent.RegularCredits;
|
clientComponent.RegularCredits = dojoComponent.RegularCredits;
|
||||||
clientComponent.MiscItems = dojoComponent.MiscItems;
|
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);
|
dojo.DojoComponents.push(clientComponent);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -41,18 +41,33 @@ export interface IDojoComponentClient {
|
|||||||
CompletionTime?: IMongoDate;
|
CompletionTime?: IMongoDate;
|
||||||
RushPlatinum?: number;
|
RushPlatinum?: number;
|
||||||
DestructionTime?: IMongoDate;
|
DestructionTime?: IMongoDate;
|
||||||
|
Decos?: IDojoDecoClient[];
|
||||||
DecoCapacity?: number;
|
DecoCapacity?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IDojoComponentDatabase
|
export interface IDojoComponentDatabase
|
||||||
extends Omit<
|
extends Omit<IDojoComponentClient, "id" | "pi" | "CompletionTime" | "RushPlatinum" | "DestructionTime" | "Decos"> {
|
||||||
IDojoComponentClient,
|
|
||||||
"id" | "pi" | "CompletionTime" | "RushPlatinum" | "DestructionTime" | "DecoCapacity"
|
|
||||||
> {
|
|
||||||
_id: Types.ObjectId;
|
_id: Types.ObjectId;
|
||||||
pi?: Types.ObjectId;
|
pi?: Types.ObjectId;
|
||||||
CompletionTime?: Date;
|
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 {
|
export interface ITechProjectClient {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user