feat: personal research #1602
@ -32,11 +32,11 @@ import { logger } from "@/src/utils/logger";
|
||||
export const guildTechController: RequestHandler = async (req, res) => {
|
||||
const accountId = await getAccountIdForRequest(req);
|
||||
const inventory = await getInventory(accountId);
|
||||
const guild = await getGuildForRequestEx(req, inventory);
|
||||
const data = JSON.parse(String(req.body)) as TGuildTechRequest;
|
||||
if (data.Action == "Sync") {
|
||||
let needSave = false;
|
||||
const techProjects: ITechProjectClient[] = [];
|
||||
const guild = await getGuildForRequestEx(req, inventory);
|
||||
if (guild.TechProjects) {
|
||||
for (const project of guild.TechProjects) {
|
||||
const techProject: ITechProjectClient = {
|
||||
@ -59,6 +59,8 @@ export const guildTechController: RequestHandler = async (req, res) => {
|
||||
}
|
||||
res.json({ TechProjects: techProjects });
|
||||
} else if (data.Action == "Start") {
|
||||
if (data.Mode == "Guild") {
|
||||
const guild = await getGuildForRequestEx(req, inventory);
|
||||
if (!hasAccessToDojo(inventory) || !(await hasGuildPermission(guild, accountId, GuildPermission.Tech))) {
|
||||
res.status(400).send("-1").end();
|
||||
return;
|
||||
@ -89,38 +91,94 @@ export const guildTechController: RequestHandler = async (req, res) => {
|
||||
}
|
||||
await guild.save();
|
||||
res.end();
|
||||
} else {
|
||||
const recipe = ExportDojoRecipes.research[data.RecipeType];
|
||||
const techProject =
|
||||
inventory.PersonalTechProjects[
|
||||
inventory.PersonalTechProjects.push({
|
||||
State: 0,
|
||||
ReqCredits: recipe.price,
|
||||
ItemType: data.RecipeType,
|
||||
ReqItems: recipe.ingredients
|
||||
}) - 1
|
||||
];
|
||||
await inventory.save();
|
||||
res.json({
|
||||
isPersonal: true,
|
||||
action: "Start",
|
||||
personalTech: techProject.toJSON()
|
||||
});
|
||||
}
|
||||
} else if (data.Action == "Contribute") {
|
||||
if ((req.query.guildId as string) == "000000000000000000000000") {
|
||||
const techProject = inventory.PersonalTechProjects.id(data.ResearchId)!;
|
||||
|
||||
techProject.ReqCredits -= data.RegularCredits;
|
||||
const inventoryChanges: IInventoryChanges = updateCurrency(inventory, data.RegularCredits, false);
|
||||
|
||||
const miscItemChanges = [];
|
||||
for (const miscItem of data.MiscItems) {
|
||||
const reqItem = techProject.ReqItems.find(x => x.ItemType == miscItem.ItemType);
|
||||
if (reqItem) {
|
||||
if (miscItem.ItemCount > reqItem.ItemCount) {
|
||||
miscItem.ItemCount = reqItem.ItemCount;
|
||||
}
|
||||
reqItem.ItemCount -= miscItem.ItemCount;
|
||||
miscItemChanges.push({
|
||||
ItemType: miscItem.ItemType,
|
||||
ItemCount: miscItem.ItemCount * -1
|
||||
});
|
||||
}
|
||||
}
|
||||
addMiscItems(inventory, miscItemChanges);
|
||||
inventoryChanges.MiscItems = miscItemChanges;
|
||||
|
||||
techProject.HasContributions = true;
|
||||
|
||||
if (techProject.ReqCredits == 0 && !techProject.ReqItems.find(x => x.ItemCount > 0)) {
|
||||
techProject.State = 1;
|
||||
const recipe = ExportDojoRecipes.research[techProject.ItemType];
|
||||
techProject.CompletionDate = new Date(Date.now() + recipe.time * 1000);
|
||||
}
|
||||
|
||||
await inventory.save();
|
||||
res.json({
|
||||
InventoryChanges: inventoryChanges,
|
||||
PersonalResearch: { $oid: data.ResearchId },
|
||||
PersonalResearchDate: techProject.CompletionDate ? toMongoDate(techProject.CompletionDate) : undefined
|
||||
});
|
||||
} else {
|
||||
if (!hasAccessToDojo(inventory)) {
|
||||
res.status(400).send("-1").end();
|
||||
return;
|
||||
}
|
||||
|
||||
const guild = await getGuildForRequestEx(req, inventory);
|
||||
const guildMember = (await GuildMember.findOne(
|
||||
{ accountId, guildId: guild._id },
|
||||
"RegularCreditsContributed MiscItemsContributed"
|
||||
))!;
|
||||
|
||||
const contributions = data;
|
||||
const techProject = guild.TechProjects!.find(x => x.ItemType == contributions.RecipeType)!;
|
||||
const techProject = guild.TechProjects!.find(x => x.ItemType == data.RecipeType)!;
|
||||
|
||||
if (contributions.VaultCredits) {
|
||||
if (contributions.VaultCredits > techProject.ReqCredits) {
|
||||
contributions.VaultCredits = techProject.ReqCredits;
|
||||
if (data.VaultCredits) {
|
||||
if (data.VaultCredits > techProject.ReqCredits) {
|
||||
data.VaultCredits = techProject.ReqCredits;
|
||||
}
|
||||
techProject.ReqCredits -= contributions.VaultCredits;
|
||||
guild.VaultRegularCredits! -= contributions.VaultCredits;
|
||||
techProject.ReqCredits -= data.VaultCredits;
|
||||
guild.VaultRegularCredits! -= data.VaultCredits;
|
||||
}
|
||||
|
||||
if (contributions.RegularCredits > techProject.ReqCredits) {
|
||||
contributions.RegularCredits = techProject.ReqCredits;
|
||||
if (data.RegularCredits > techProject.ReqCredits) {
|
||||
data.RegularCredits = techProject.ReqCredits;
|
||||
}
|
||||
techProject.ReqCredits -= contributions.RegularCredits;
|
||||
techProject.ReqCredits -= data.RegularCredits;
|
||||
|
||||
guildMember.RegularCreditsContributed ??= 0;
|
||||
guildMember.RegularCreditsContributed += contributions.RegularCredits;
|
||||
guildMember.RegularCreditsContributed += data.RegularCredits;
|
||||
|
||||
if (contributions.VaultMiscItems.length) {
|
||||
for (const miscItem of contributions.VaultMiscItems) {
|
||||
if (data.VaultMiscItems.length) {
|
||||
for (const miscItem of data.VaultMiscItems) {
|
||||
const reqItem = techProject.ReqItems.find(x => x.ItemType == miscItem.ItemType);
|
||||
if (reqItem) {
|
||||
if (miscItem.ItemCount > reqItem.ItemCount) {
|
||||
@ -135,7 +193,7 @@ export const guildTechController: RequestHandler = async (req, res) => {
|
||||
}
|
||||
|
||||
const miscItemChanges = [];
|
||||
for (const miscItem of contributions.MiscItems) {
|
||||
for (const miscItem of data.MiscItems) {
|
||||
const reqItem = techProject.ReqItems.find(x => x.ItemType == miscItem.ItemType);
|
||||
if (reqItem) {
|
||||
if (miscItem.ItemCount > reqItem.ItemCount) {
|
||||
@ -151,7 +209,7 @@ export const guildTechController: RequestHandler = async (req, res) => {
|
||||
}
|
||||
}
|
||||
addMiscItems(inventory, miscItemChanges);
|
||||
const inventoryChanges: IInventoryChanges = updateCurrency(inventory, contributions.RegularCredits, false);
|
||||
const inventoryChanges: IInventoryChanges = updateCurrency(inventory, data.RegularCredits, false);
|
||||
inventoryChanges.MiscItems = miscItemChanges;
|
||||
|
||||
// Check if research is fully funded now.
|
||||
@ -162,7 +220,9 @@ export const guildTechController: RequestHandler = async (req, res) => {
|
||||
InventoryChanges: inventoryChanges,
|
||||
Vault: getGuildVault(guild)
|
||||
});
|
||||
}
|
||||
} else if (data.Action.split(",")[0] == "Buy") {
|
||||
const guild = await getGuildForRequestEx(req, inventory);
|
||||
if (!hasAccessToDojo(inventory) || !(await hasGuildPermission(guild, accountId, GuildPermission.Fabricator))) {
|
||||
res.status(400).send("-1").end();
|
||||
return;
|
||||
@ -190,6 +250,7 @@ export const guildTechController: RequestHandler = async (req, res) => {
|
||||
}
|
||||
});
|
||||
} else if (data.Action == "Fabricate") {
|
||||
const guild = await getGuildForRequestEx(req, inventory);
|
||||
if (!hasAccessToDojo(inventory) || !(await hasGuildPermission(guild, accountId, GuildPermission.Fabricator))) {
|
||||
res.status(400).send("-1").end();
|
||||
return;
|
||||
@ -206,6 +267,7 @@ export const guildTechController: RequestHandler = async (req, res) => {
|
||||
// Not a mistake: This response uses `inventoryChanges` instead of `InventoryChanges`.
|
||||
res.json({ inventoryChanges: inventoryChanges });
|
||||
} else if (data.Action == "Pause") {
|
||||
const guild = await getGuildForRequestEx(req, inventory);
|
||||
if (!hasAccessToDojo(inventory) || !(await hasGuildPermission(guild, accountId, GuildPermission.Tech))) {
|
||||
res.status(400).send("-1").end();
|
||||
return;
|
||||
@ -217,6 +279,7 @@ export const guildTechController: RequestHandler = async (req, res) => {
|
||||
await removePigmentsFromGuildMembers(guild._id);
|
||||
res.end();
|
||||
} else if (data.Action == "Unpause") {
|
||||
const guild = await getGuildForRequestEx(req, inventory);
|
||||
if (!hasAccessToDojo(inventory) || !(await hasGuildPermission(guild, accountId, GuildPermission.Tech))) {
|
||||
res.status(400).send("-1").end();
|
||||
return;
|
||||
@ -239,7 +302,7 @@ type TGuildTechRequest =
|
||||
|
||||
interface IGuildTechBasicRequest {
|
||||
Action: "Start" | "Fabricate" | "Pause" | "Unpause";
|
||||
Mode: "Guild";
|
||||
Mode: "Guild" | "Personal";
|
||||
RecipeType: string;
|
||||
}
|
||||
|
||||
@ -251,7 +314,7 @@ interface IGuildTechBuyRequest {
|
||||
|
||||
interface IGuildTechContributeRequest {
|
||||
Action: "Contribute";
|
||||
ResearchId: "";
|
||||
ResearchId: string;
|
||||
RecipeType: string;
|
||||
RegularCredits: number;
|
||||
MiscItems: IMiscItem[];
|
||||
|
@ -84,7 +84,9 @@ import {
|
||||
IInfNode,
|
||||
IDiscoveredMarker,
|
||||
IWeeklyMission,
|
||||
ILockedWeaponGroupDatabase
|
||||
ILockedWeaponGroupDatabase,
|
||||
IPersonalTechProjectDatabase,
|
||||
IPersonalTechProjectClient
|
||||
} from "../../types/inventoryTypes/inventoryTypes";
|
||||
import { IOid } from "../../types/commonTypes";
|
||||
import {
|
||||
@ -498,7 +500,34 @@ const seasonChallengeHistorySchema = new Schema<ISeasonChallenge>(
|
||||
{ _id: false }
|
||||
);
|
||||
|
||||
//TODO: check whether this is complete
|
||||
const personalTechProjectSchema = new Schema<IPersonalTechProjectDatabase>({
|
||||
State: Number,
|
||||
ReqCredits: Number,
|
||||
ItemType: String,
|
||||
ReqItems: { type: [typeCountSchema], default: undefined },
|
||||
HasContributions: Boolean,
|
||||
CompletionDate: Date
|
||||
});
|
||||
|
||||
personalTechProjectSchema.virtual("ItemId").get(function () {
|
||||
return { $oid: this._id.toString() };
|
||||
});
|
||||
|
||||
personalTechProjectSchema.set("toJSON", {
|
||||
virtuals: true,
|
||||
transform(_doc, ret, _options) {
|
||||
delete ret._id;
|
||||
delete ret.__v;
|
||||
|
||||
const db = ret as IPersonalTechProjectDatabase;
|
||||
const client = ret as IPersonalTechProjectClient;
|
||||
|
||||
if (db.CompletionDate) {
|
||||
client.CompletionDate = toMongoDate(db.CompletionDate);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const playerSkillsSchema = new Schema<IPlayerSkills>(
|
||||
{
|
||||
LPP_SPACE: { type: Number, default: 0 },
|
||||
@ -1442,7 +1471,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
|
||||
|
||||
//Railjack craft
|
||||
//https://warframe.fandom.com/wiki/Rising_Tide
|
||||
PersonalTechProjects: [Schema.Types.Mixed],
|
||||
PersonalTechProjects: { type: [personalTechProjectSchema], default: [] },
|
||||
|
||||
//Modulars lvl and exp(Railjack|Duviri)
|
||||
//https://warframe.fandom.com/wiki/Intrinsics
|
||||
@ -1585,6 +1614,7 @@ export type InventoryDocumentProps = {
|
||||
Drones: Types.DocumentArray<IDroneDatabase>;
|
||||
CrewShipWeaponSkins: Types.DocumentArray<IUpgradeDatabase>;
|
||||
CrewShipSalvagedWeaponsSkins: Types.DocumentArray<IUpgradeDatabase>;
|
||||
PersonalTechProjects: Types.DocumentArray<IPersonalTechProjectDatabase>;
|
||||
} & { [K in TEquipmentKey]: Types.DocumentArray<IEquipmentDatabase> };
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
||||
|
@ -46,6 +46,7 @@ export interface IInventoryDatabase
|
||||
| "EntratiVaultCountResetDate"
|
||||
| "BrandedSuits"
|
||||
| "LockedWeaponGroup"
|
||||
| "PersonalTechProjects"
|
||||
| TEquipmentKey
|
||||
>,
|
||||
InventoryDatabaseEquipment {
|
||||
@ -77,6 +78,7 @@ export interface IInventoryDatabase
|
||||
EntratiVaultCountResetDate?: Date;
|
||||
BrandedSuits?: Types.ObjectId[];
|
||||
LockedWeaponGroup?: ILockedWeaponGroupDatabase;
|
||||
PersonalTechProjects: IPersonalTechProjectDatabase[];
|
||||
}
|
||||
|
||||
export interface IQuestKeyDatabase {
|
||||
@ -301,7 +303,7 @@ export interface IInventoryClient extends IDailyAffiliations, InventoryClientEqu
|
||||
NemesisHistory: INemesisBaseClient[];
|
||||
LastNemesisAllySpawnTime?: IMongoDate;
|
||||
Settings?: ISettings;
|
||||
PersonalTechProjects: IPersonalTechProject[];
|
||||
PersonalTechProjects: IPersonalTechProjectClient[];
|
||||
PlayerSkills: IPlayerSkills;
|
||||
CrewShipAmmo: ITypeCount[];
|
||||
CrewShipWeaponSkins: IUpgradeClient[];
|
||||
@ -936,16 +938,20 @@ export interface IPersonalGoalProgress {
|
||||
ReceivedClanReward1?: boolean;
|
||||
}
|
||||
|
||||
export interface IPersonalTechProject {
|
||||
export interface IPersonalTechProjectDatabase {
|
||||
State: number;
|
||||
ReqCredits: number;
|
||||
ItemType: string;
|
||||
ReqItems: ITypeCount[];
|
||||
HasContributions?: boolean;
|
||||
CompletionDate?: Date;
|
||||
}
|
||||
|
||||
export interface IPersonalTechProjectClient extends Omit<IPersonalTechProjectDatabase, "CompletionDate"> {
|
||||
CompletionDate?: IMongoDate;
|
||||
ItemId: IOid;
|
||||
ProductCategory?: string;
|
||||
CategoryItemId?: IOid;
|
||||
HasContributions?: boolean;
|
||||
ItemId: IOid;
|
||||
}
|
||||
|
||||
export interface IPlayerSkills {
|
||||
|
Loading…
x
Reference in New Issue
Block a user