forked from OpenWF/SpaceNinjaServer
feat: identify & repair railjack components (#1664)
Closes #911 Reviewed-on: OpenWF/SpaceNinjaServer#1664 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
This commit is contained in:
parent
51b82df5fd
commit
0ea67ea89a
41
src/controllers/api/crewShipIdentifySalvageController.ts
Normal file
41
src/controllers/api/crewShipIdentifySalvageController.ts
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import { addCrewShipSalvagedWeaponSkin, addCrewShipRawSalvage, getInventory } from "@/src/services/inventoryService";
|
||||||
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
|
import { RequestHandler } from "express";
|
||||||
|
import { IInnateDamageFingerprint } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
|
import { ExportCustoms } from "warframe-public-export-plus";
|
||||||
|
import { IFingerprintStat } from "@/src/helpers/rivenHelper";
|
||||||
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
|
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
||||||
|
|
||||||
|
export const crewShipIdentifySalvageController: RequestHandler = async (req, res) => {
|
||||||
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
const inventory = await getInventory(accountId, "CrewShipSalvagedWeaponSkins CrewShipRawSalvage");
|
||||||
|
const payload = getJSONfromString<ICrewShipIdentifySalvageRequest>(String(req.body));
|
||||||
|
|
||||||
|
const buffs: IFingerprintStat[] = [];
|
||||||
|
for (const upgrade of ExportCustoms[payload.ItemType].randomisedUpgrades!) {
|
||||||
|
buffs.push({ Tag: upgrade.tag, Value: Math.trunc(Math.random() * 0x40000000) });
|
||||||
|
}
|
||||||
|
const inventoryChanges: IInventoryChanges = addCrewShipSalvagedWeaponSkin(
|
||||||
|
inventory,
|
||||||
|
payload.ItemType,
|
||||||
|
JSON.stringify({ compat: payload.ItemType, buffs } satisfies IInnateDamageFingerprint)
|
||||||
|
);
|
||||||
|
|
||||||
|
inventoryChanges.CrewShipRawSalvage = [
|
||||||
|
{
|
||||||
|
ItemType: payload.ItemType,
|
||||||
|
ItemCount: -1
|
||||||
|
}
|
||||||
|
];
|
||||||
|
addCrewShipRawSalvage(inventory, inventoryChanges.CrewShipRawSalvage);
|
||||||
|
|
||||||
|
await inventory.save();
|
||||||
|
res.json({
|
||||||
|
InventoryChanges: inventoryChanges
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
interface ICrewShipIdentifySalvageRequest {
|
||||||
|
ItemType: string;
|
||||||
|
}
|
@ -14,20 +14,23 @@ import {
|
|||||||
import { ExportDojoRecipes } from "warframe-public-export-plus";
|
import { ExportDojoRecipes } from "warframe-public-export-plus";
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import {
|
import {
|
||||||
|
addCrewShipWeaponSkin,
|
||||||
addItem,
|
addItem,
|
||||||
addMiscItems,
|
addMiscItems,
|
||||||
addRecipes,
|
addRecipes,
|
||||||
combineInventoryChanges,
|
combineInventoryChanges,
|
||||||
getInventory,
|
getInventory,
|
||||||
|
occupySlot,
|
||||||
updateCurrency
|
updateCurrency
|
||||||
} from "@/src/services/inventoryService";
|
} from "@/src/services/inventoryService";
|
||||||
import { IMiscItem } from "@/src/types/inventoryTypes/inventoryTypes";
|
import { IMiscItem, InventorySlot } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
||||||
import { config } from "@/src/services/configService";
|
import { config } from "@/src/services/configService";
|
||||||
import { GuildPermission, ITechProjectClient } from "@/src/types/guildTypes";
|
import { GuildPermission, ITechProjectClient } from "@/src/types/guildTypes";
|
||||||
import { GuildMember } from "@/src/models/guildModel";
|
import { GuildMember } from "@/src/models/guildModel";
|
||||||
import { toMongoDate } from "@/src/helpers/inventoryHelpers";
|
import { toMongoDate } from "@/src/helpers/inventoryHelpers";
|
||||||
import { logger } from "@/src/utils/logger";
|
import { logger } from "@/src/utils/logger";
|
||||||
|
import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
|
||||||
|
|
||||||
export const guildTechController: RequestHandler = async (req, res) => {
|
export const guildTechController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
@ -99,6 +102,8 @@ export const guildTechController: RequestHandler = async (req, res) => {
|
|||||||
State: 0,
|
State: 0,
|
||||||
ReqCredits: recipe.price,
|
ReqCredits: recipe.price,
|
||||||
ItemType: data.RecipeType,
|
ItemType: data.RecipeType,
|
||||||
|
ProductCategory: data.TechProductCategory,
|
||||||
|
CategoryItemId: data.CategoryItemId,
|
||||||
ReqItems: recipe.ingredients
|
ReqItems: recipe.ingredients
|
||||||
}) - 1
|
}) - 1
|
||||||
];
|
];
|
||||||
@ -222,33 +227,44 @@ export const guildTechController: RequestHandler = async (req, res) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else if (data.Action.split(",")[0] == "Buy") {
|
} 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;
|
|
||||||
}
|
|
||||||
const purchase = data as IGuildTechBuyRequest;
|
const purchase = data as IGuildTechBuyRequest;
|
||||||
const quantity = parseInt(data.Action.split(",")[1]);
|
if (purchase.Mode == "Guild") {
|
||||||
const recipeChanges = [
|
const guild = await getGuildForRequestEx(req, inventory);
|
||||||
{
|
if (
|
||||||
ItemType: purchase.RecipeType,
|
!hasAccessToDojo(inventory) ||
|
||||||
ItemCount: quantity
|
!(await hasGuildPermission(guild, accountId, GuildPermission.Fabricator))
|
||||||
|
) {
|
||||||
|
res.status(400).send("-1").end();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
];
|
const quantity = parseInt(data.Action.split(",")[1]);
|
||||||
addRecipes(inventory, recipeChanges);
|
const recipeChanges = [
|
||||||
const currencyChanges = updateCurrency(
|
{
|
||||||
inventory,
|
ItemType: purchase.RecipeType,
|
||||||
ExportDojoRecipes.research[purchase.RecipeType].replicatePrice,
|
ItemCount: quantity
|
||||||
false
|
}
|
||||||
);
|
];
|
||||||
await inventory.save();
|
addRecipes(inventory, recipeChanges);
|
||||||
// Not a mistake: This response uses `inventoryChanges` instead of `InventoryChanges`.
|
const currencyChanges = updateCurrency(
|
||||||
res.json({
|
inventory,
|
||||||
inventoryChanges: {
|
ExportDojoRecipes.research[purchase.RecipeType].replicatePrice,
|
||||||
...currencyChanges,
|
false
|
||||||
Recipes: recipeChanges
|
);
|
||||||
}
|
await inventory.save();
|
||||||
});
|
// Not a mistake: This response uses `inventoryChanges` instead of `InventoryChanges`.
|
||||||
|
res.json({
|
||||||
|
inventoryChanges: {
|
||||||
|
...currencyChanges,
|
||||||
|
Recipes: recipeChanges
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const inventoryChanges = claimSalvagedComponent(inventory, purchase.CategoryItemId!);
|
||||||
|
await inventory.save();
|
||||||
|
res.json({
|
||||||
|
inventoryChanges: inventoryChanges
|
||||||
|
});
|
||||||
|
}
|
||||||
} else if (data.Action == "Fabricate") {
|
} else if (data.Action == "Fabricate") {
|
||||||
const guild = await getGuildForRequestEx(req, inventory);
|
const guild = await getGuildForRequestEx(req, inventory);
|
||||||
if (!hasAccessToDojo(inventory) || !(await hasGuildPermission(guild, accountId, GuildPermission.Fabricator))) {
|
if (!hasAccessToDojo(inventory) || !(await hasGuildPermission(guild, accountId, GuildPermission.Fabricator))) {
|
||||||
@ -289,9 +305,18 @@ export const guildTechController: RequestHandler = async (req, res) => {
|
|||||||
guild.ActiveDojoColorResearch = data.RecipeType;
|
guild.ActiveDojoColorResearch = data.RecipeType;
|
||||||
await guild.save();
|
await guild.save();
|
||||||
res.end();
|
res.end();
|
||||||
|
} else if (data.Action == "Rush" && data.CategoryItemId) {
|
||||||
|
const inventoryChanges: IInventoryChanges = {
|
||||||
|
...updateCurrency(inventory, 20, true),
|
||||||
|
...claimSalvagedComponent(inventory, data.CategoryItemId)
|
||||||
|
};
|
||||||
|
await inventory.save();
|
||||||
|
res.json({
|
||||||
|
inventoryChanges: inventoryChanges
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
logger.debug(`data provided to ${req.path}: ${String(req.body)}`);
|
logger.debug(`data provided to ${req.path}: ${String(req.body)}`);
|
||||||
throw new Error(`unknown guildTech action: ${data.Action}`);
|
throw new Error(`unhandled guildTech request`);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -301,15 +326,15 @@ type TGuildTechRequest =
|
|||||||
| IGuildTechContributeRequest;
|
| IGuildTechContributeRequest;
|
||||||
|
|
||||||
interface IGuildTechBasicRequest {
|
interface IGuildTechBasicRequest {
|
||||||
Action: "Start" | "Fabricate" | "Pause" | "Unpause";
|
Action: "Start" | "Fabricate" | "Pause" | "Unpause" | "Cancel" | "Rush";
|
||||||
Mode: "Guild" | "Personal";
|
Mode: "Guild" | "Personal";
|
||||||
RecipeType: string;
|
RecipeType: string;
|
||||||
|
TechProductCategory?: string;
|
||||||
|
CategoryItemId?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IGuildTechBuyRequest {
|
interface IGuildTechBuyRequest extends Omit<IGuildTechBasicRequest, "Action"> {
|
||||||
Action: string;
|
Action: string;
|
||||||
Mode: "Guild";
|
|
||||||
RecipeType: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IGuildTechContributeRequest {
|
interface IGuildTechContributeRequest {
|
||||||
@ -321,3 +346,30 @@ interface IGuildTechContributeRequest {
|
|||||||
VaultCredits: number;
|
VaultCredits: number;
|
||||||
VaultMiscItems: IMiscItem[];
|
VaultMiscItems: IMiscItem[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const claimSalvagedComponent = (inventory: TInventoryDatabaseDocument, itemId: string): IInventoryChanges => {
|
||||||
|
// delete personal tech project
|
||||||
|
const personalTechProjectIndex = inventory.PersonalTechProjects.findIndex(x => x.CategoryItemId?.equals(itemId));
|
||||||
|
if (personalTechProjectIndex != -1) {
|
||||||
|
inventory.PersonalTechProjects.splice(personalTechProjectIndex, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// find salved part & delete it
|
||||||
|
const crewShipSalvagedWeaponSkinsIndex = inventory.CrewShipSalvagedWeaponSkins.findIndex(x => x._id.equals(itemId));
|
||||||
|
const crewShipWeaponSkin = inventory.CrewShipSalvagedWeaponSkins[crewShipSalvagedWeaponSkinsIndex];
|
||||||
|
inventory.CrewShipSalvagedWeaponSkins.splice(crewShipSalvagedWeaponSkinsIndex, 1);
|
||||||
|
|
||||||
|
// add final item
|
||||||
|
const inventoryChanges = {
|
||||||
|
...addCrewShipWeaponSkin(inventory, crewShipWeaponSkin.ItemType, crewShipWeaponSkin.UpgradeFingerprint),
|
||||||
|
...occupySlot(inventory, InventorySlot.RJ_COMPONENT_AND_ARMAMENTS, false)
|
||||||
|
};
|
||||||
|
|
||||||
|
inventoryChanges.RemovedIdItems = [
|
||||||
|
{
|
||||||
|
ItemId: { $oid: itemId }
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
return inventoryChanges;
|
||||||
|
};
|
||||||
|
@ -504,6 +504,8 @@ const personalTechProjectSchema = new Schema<IPersonalTechProjectDatabase>({
|
|||||||
State: Number,
|
State: Number,
|
||||||
ReqCredits: Number,
|
ReqCredits: Number,
|
||||||
ItemType: String,
|
ItemType: String,
|
||||||
|
ProductCategory: String,
|
||||||
|
CategoryItemId: Schema.Types.ObjectId,
|
||||||
ReqItems: { type: [typeCountSchema], default: undefined },
|
ReqItems: { type: [typeCountSchema], default: undefined },
|
||||||
HasContributions: Boolean,
|
HasContributions: Boolean,
|
||||||
CompletionDate: Date
|
CompletionDate: Date
|
||||||
@ -522,6 +524,9 @@ personalTechProjectSchema.set("toJSON", {
|
|||||||
const db = ret as IPersonalTechProjectDatabase;
|
const db = ret as IPersonalTechProjectDatabase;
|
||||||
const client = ret as IPersonalTechProjectClient;
|
const client = ret as IPersonalTechProjectClient;
|
||||||
|
|
||||||
|
if (db.CategoryItemId) {
|
||||||
|
client.CategoryItemId = toOid(db.CategoryItemId);
|
||||||
|
}
|
||||||
if (db.CompletionDate) {
|
if (db.CompletionDate) {
|
||||||
client.CompletionDate = toMongoDate(db.CompletionDate);
|
client.CompletionDate = toMongoDate(db.CompletionDate);
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,7 @@ import { contributeToVaultController } from "@/src/controllers/api/contributeToV
|
|||||||
import { createAllianceController } from "@/src/controllers/api/createAllianceController";
|
import { createAllianceController } from "@/src/controllers/api/createAllianceController";
|
||||||
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 { crewShipIdentifySalvageController } from "@/src/controllers/api/crewShipIdentifySalvageController";
|
||||||
import { customizeGuildRanksController } from "@/src/controllers/api/customizeGuildRanksController";
|
import { customizeGuildRanksController } from "@/src/controllers/api/customizeGuildRanksController";
|
||||||
import { customObstacleCourseLeaderboardController } from "@/src/controllers/api/customObstacleCourseLeaderboardController";
|
import { customObstacleCourseLeaderboardController } from "@/src/controllers/api/customObstacleCourseLeaderboardController";
|
||||||
import { declineAllianceInviteController } from "@/src/controllers/api/declineAllianceInviteController";
|
import { declineAllianceInviteController } from "@/src/controllers/api/declineAllianceInviteController";
|
||||||
@ -218,6 +219,7 @@ apiRouter.post("/contributeToDojoComponent.php", contributeToDojoComponentContro
|
|||||||
apiRouter.post("/contributeToVault.php", contributeToVaultController);
|
apiRouter.post("/contributeToVault.php", contributeToVaultController);
|
||||||
apiRouter.post("/createAlliance.php", createAllianceController);
|
apiRouter.post("/createAlliance.php", createAllianceController);
|
||||||
apiRouter.post("/createGuild.php", createGuildController);
|
apiRouter.post("/createGuild.php", createGuildController);
|
||||||
|
apiRouter.post("/crewShipIdentifySalvage.php", crewShipIdentifySalvageController);
|
||||||
apiRouter.post("/customizeGuildRanks.php", customizeGuildRanksController);
|
apiRouter.post("/customizeGuildRanks.php", customizeGuildRanksController);
|
||||||
apiRouter.post("/customObstacleCourseLeaderboard.php", customObstacleCourseLeaderboardController);
|
apiRouter.post("/customObstacleCourseLeaderboard.php", customObstacleCourseLeaderboardController);
|
||||||
apiRouter.post("/destroyDojoDeco.php", destroyDojoDecoController);
|
apiRouter.post("/destroyDojoDeco.php", destroyDojoDecoController);
|
||||||
|
@ -426,7 +426,7 @@ export const addItem = async (
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
inventoryChanges = {
|
inventoryChanges = {
|
||||||
...addCrewShipWeaponSkin(inventory, typeName),
|
...addCrewShipWeaponSkin(inventory, typeName, undefined),
|
||||||
...occupySlot(inventory, InventorySlot.RJ_COMPONENT_AND_ARMAMENTS, premiumPurchase)
|
...occupySlot(inventory, InventorySlot.RJ_COMPONENT_AND_ARMAMENTS, premiumPurchase)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -1107,12 +1107,14 @@ export const addSkin = (
|
|||||||
return inventoryChanges;
|
return inventoryChanges;
|
||||||
};
|
};
|
||||||
|
|
||||||
const addCrewShipWeaponSkin = (
|
export const addCrewShipWeaponSkin = (
|
||||||
inventory: TInventoryDatabaseDocument,
|
inventory: TInventoryDatabaseDocument,
|
||||||
typeName: string,
|
typeName: string,
|
||||||
|
upgradeFingerprint: string | undefined,
|
||||||
inventoryChanges: IInventoryChanges = {}
|
inventoryChanges: IInventoryChanges = {}
|
||||||
): IInventoryChanges => {
|
): IInventoryChanges => {
|
||||||
const index = inventory.CrewShipWeaponSkins.push({ ItemType: typeName }) - 1;
|
const index =
|
||||||
|
inventory.CrewShipWeaponSkins.push({ ItemType: typeName, UpgradeFingerprint: upgradeFingerprint }) - 1;
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||||
inventoryChanges.CrewShipWeaponSkins ??= [];
|
inventoryChanges.CrewShipWeaponSkins ??= [];
|
||||||
(inventoryChanges.CrewShipWeaponSkins as IUpgradeClient[]).push(
|
(inventoryChanges.CrewShipWeaponSkins as IUpgradeClient[]).push(
|
||||||
@ -1121,6 +1123,22 @@ const addCrewShipWeaponSkin = (
|
|||||||
return inventoryChanges;
|
return inventoryChanges;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const addCrewShipSalvagedWeaponSkin = (
|
||||||
|
inventory: TInventoryDatabaseDocument,
|
||||||
|
typeName: string,
|
||||||
|
upgradeFingerprint: string | undefined,
|
||||||
|
inventoryChanges: IInventoryChanges = {}
|
||||||
|
): IInventoryChanges => {
|
||||||
|
const index =
|
||||||
|
inventory.CrewShipSalvagedWeaponSkins.push({ ItemType: typeName, UpgradeFingerprint: upgradeFingerprint }) - 1;
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||||
|
inventoryChanges.CrewShipSalvagedWeaponSkins ??= [];
|
||||||
|
(inventoryChanges.CrewShipSalvagedWeaponSkins as IUpgradeClient[]).push(
|
||||||
|
inventory.CrewShipSalvagedWeaponSkins[index].toJSON<IUpgradeClient>()
|
||||||
|
);
|
||||||
|
return inventoryChanges;
|
||||||
|
};
|
||||||
|
|
||||||
const addCrewShip = (
|
const addCrewShip = (
|
||||||
inventory: TInventoryDatabaseDocument,
|
inventory: TInventoryDatabaseDocument,
|
||||||
typeName: string,
|
typeName: string,
|
||||||
|
@ -947,15 +947,17 @@ export interface IPersonalTechProjectDatabase {
|
|||||||
State: number;
|
State: number;
|
||||||
ReqCredits: number;
|
ReqCredits: number;
|
||||||
ItemType: string;
|
ItemType: string;
|
||||||
|
ProductCategory?: string;
|
||||||
|
CategoryItemId?: Types.ObjectId;
|
||||||
ReqItems: ITypeCount[];
|
ReqItems: ITypeCount[];
|
||||||
HasContributions?: boolean;
|
HasContributions?: boolean;
|
||||||
CompletionDate?: Date;
|
CompletionDate?: Date;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPersonalTechProjectClient extends Omit<IPersonalTechProjectDatabase, "CompletionDate"> {
|
export interface IPersonalTechProjectClient
|
||||||
CompletionDate?: IMongoDate;
|
extends Omit<IPersonalTechProjectDatabase, "CategoryItemId" | "CompletionDate"> {
|
||||||
ProductCategory?: string;
|
|
||||||
CategoryItemId?: IOid;
|
CategoryItemId?: IOid;
|
||||||
|
CompletionDate?: IMongoDate;
|
||||||
ItemId: IOid;
|
ItemId: IOid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,6 +43,7 @@ export type IInventoryChanges = {
|
|||||||
Drones?: IDroneClient[];
|
Drones?: IDroneClient[];
|
||||||
MiscItems?: IMiscItem[];
|
MiscItems?: IMiscItem[];
|
||||||
EmailItems?: ITypeCount[];
|
EmailItems?: ITypeCount[];
|
||||||
|
CrewShipRawSalvage?: ITypeCount[];
|
||||||
Nemesis?: Partial<INemesisClient>;
|
Nemesis?: Partial<INemesisClient>;
|
||||||
NewVendorPurchase?: IRecentVendorPurchaseClient; // >= 38.5.0
|
NewVendorPurchase?: IRecentVendorPurchaseClient; // >= 38.5.0
|
||||||
RecentVendorPurchases?: IRecentVendorPurchaseClient; // < 38.5.0
|
RecentVendorPurchases?: IRecentVendorPurchaseClient; // < 38.5.0
|
||||||
|
Loading…
x
Reference in New Issue
Block a user