adding loadoutSlots, purchasing slots,

This commit is contained in:
Ordis 2023-12-28 16:22:13 +01:00
parent f197facd72
commit e7db0147ec
9 changed files with 209 additions and 75 deletions

View File

@ -1,24 +1,36 @@
import { parseString } from "@/src/helpers/general"; import { parseString } from "@/src/helpers/general";
import { getInventory } from "@/src/services/inventoryService"; import { getInventory, updateCurrency } from "@/src/services/inventoryService";
import { RequestHandler } from "express"; import { RequestHandler } from "express";
import { updateSlots } from "@/src/services/inventoryService";
import { SlotNameToInventoryName } from "@/src/types/purchaseTypes";
export interface IInventoryChanges { /*
InventoryChanges: { [key: string]: unknown }; loadout slots are additionally purchased slots only
} 1 slot per mastery rank is automatically given above mr10, without database needing to save the mastery slots
extra = everything above the base + 2 slots (e.g. for warframes)
new slot = extra + 1 and slots +1
using slot = slots -1, except for when purchased with platinum, then slots are included in price
export interface IInventorySlotsRequest { e.g. number of frames:
Bin: "PveBonusLoadoutBin"; 19 slots, 71 extra
} = 71 - 19 + 2 = 54
19 actually available slots in ingame inventory = 17 extra + 2 Base (base amount depends on slot) (+ 1 for every mastery rank above 10)
number of frames = extra - slots + 2
*/
// eslint-disable-next-line @typescript-eslint/no-misused-promises // eslint-disable-next-line @typescript-eslint/no-misused-promises
export const inventorySlotsController: RequestHandler = async (req, res) => { export const inventorySlotsController: RequestHandler = async (req, res) => {
const accountId = parseString(req.query.accountId); const accountId = parseString(req.query.accountId);
//const body = req.body as IInventorySlotsRequest; //const body = JSON.parse(req.body as string) as IInventorySlotsRequest;
//check which slot was purchased //console.log(body);
const inventory = await getInventory(accountId); //TODO: check which slot was purchased because pvpBonus is also possible
//add slots const currencyChanges = await updateCurrency(-20, true, accountId);
res.json({ InventoryChanges: { PremiumCreditsFree: -20, PremiumCredits: -20 } } satisfies IInventoryChanges); await updateSlots(accountId, SlotNameToInventoryName.LOADOUT, 1, 1);
//console.log({ InventoryChanges: currencyChanges }, " added loadout changes:");
res.json({ InventoryChanges: currencyChanges });
}; };

View File

@ -3,11 +3,9 @@ import { toPurchaseRequest } from "@/src/helpers/purchaseHelpers";
import { handlePurchase } from "@/src/services/purchaseService"; import { handlePurchase } from "@/src/services/purchaseService";
import { Request, Response } from "express"; import { Request, Response } from "express";
const purchaseController = async (req: Request, res: Response) => { export const purchaseController = async (req: Request, res: Response) => {
const purchaseRequest = toPurchaseRequest(JSON.parse(String(req.body))); const purchaseRequest = toPurchaseRequest(JSON.parse(String(req.body)));
const accountId = parseString(req.query.accountId); const accountId = parseString(req.query.accountId);
const response = await handlePurchase(purchaseRequest, accountId); const response = await handlePurchase(purchaseRequest, accountId);
res.json(response); res.json(response);
}; };
export { purchaseController };

View File

@ -1,9 +1,10 @@
import { parseBoolean, parseNumber, parseString } from "@/src/helpers/general"; import { parseBoolean, parseNumber, parseString } from "@/src/helpers/general";
import { WeaponTypeInternal } from "@/src/services/inventoryService"; import { WeaponTypeInternal } from "@/src/services/inventoryService";
import { IPurchaseRequest } from "@/src/types/purchaseTypes"; import { slotPurchaseNameToSlotName } from "@/src/services/purchaseService";
import { IPurchaseRequest, SlotPurchaseName } from "@/src/types/purchaseTypes";
import { weapons } from "@/static/data/items"; import { weapons } from "@/static/data/items";
const toPurchaseRequest = (purchaseRequest: unknown): IPurchaseRequest => { export const toPurchaseRequest = (purchaseRequest: unknown): IPurchaseRequest => {
if (!purchaseRequest || typeof purchaseRequest !== "object") { if (!purchaseRequest || typeof purchaseRequest !== "object") {
throw new Error("incorrect or missing purchase request data"); throw new Error("incorrect or missing purchase request data");
} }
@ -40,7 +41,7 @@ const toPurchaseRequest = (purchaseRequest: unknown): IPurchaseRequest => {
throw new Error("invalid purchaseRequest"); throw new Error("invalid purchaseRequest");
}; };
const getWeaponType = (weaponName: string) => { export const getWeaponType = (weaponName: string) => {
const weaponInfo = weapons.find(i => i.uniqueName === weaponName); const weaponInfo = weapons.find(i => i.uniqueName === weaponName);
if (!weaponInfo) { if (!weaponInfo) {
@ -56,4 +57,11 @@ const getWeaponType = (weaponName: string) => {
return weaponType; return weaponType;
}; };
export { toPurchaseRequest, getWeaponType }; export const isSlotPurchaseName = (slotPurchaseName: string): slotPurchaseName is SlotPurchaseName => {
return slotPurchaseName in slotPurchaseNameToSlotName;
};
export const parseSlotPurchaseName = (slotPurchaseName: string) => {
if (!isSlotPurchaseName(slotPurchaseName)) throw new Error(`invalid slot name ${slotPurchaseName}`);
return slotPurchaseName;
};

View File

@ -2,9 +2,9 @@ import { Inventory } from "@/src/models/inventoryModels/inventoryModel";
import new_inventory from "@/static/fixed_responses/postTutorialInventory.json"; import new_inventory from "@/static/fixed_responses/postTutorialInventory.json";
import config from "@/config.json"; import config from "@/config.json";
import { Types } from "mongoose"; import { Types } from "mongoose";
import { ISuitDatabase, ISuitClient } from "@/src/types/inventoryTypes/SuitTypes"; import { ISuitClient } from "@/src/types/inventoryTypes/SuitTypes";
import { SlotType } from "@/src/types/purchaseTypes"; import { SlotNames } from "@/src/types/purchaseTypes";
import { IWeaponDatabase, IWeaponClient } from "@/src/types/inventoryTypes/weaponTypes"; import { IWeaponClient } from "@/src/types/inventoryTypes/weaponTypes";
import { import {
IChallengeProgress, IChallengeProgress,
IConsumable, IConsumable,
@ -41,8 +41,6 @@ export const createInventory = async (accountOwnerId: Types.ObjectId, loadOutPre
} }
}; };
//const updateInventory = async (accountOwnerId: Types.ObjectId, inventoryChanges: any) => {};
export const getInventory = async (accountOwnerId: string) => { export const getInventory = async (accountOwnerId: string) => {
const inventory = await Inventory.findOne({ accountOwnerId: accountOwnerId }); const inventory = await Inventory.findOne({ accountOwnerId: accountOwnerId });
@ -53,7 +51,7 @@ export const getInventory = async (accountOwnerId: string) => {
return inventory; return inventory;
}; };
//TODO: genericMethod for all the add methods, they share a lot of logic //TODO: maybe genericMethod for all the add methods, they share a lot of logic
export const addSentinel = async (sentinelName: string, accountId: string) => { export const addSentinel = async (sentinelName: string, accountId: string) => {
const inventory = await getInventory(accountId); const inventory = await getInventory(accountId);
const sentinelIndex = inventory.Sentinels.push({ ItemType: sentinelName, Configs: [], XP: 0 }); const sentinelIndex = inventory.Sentinels.push({ ItemType: sentinelName, Configs: [], XP: 0 });
@ -75,32 +73,54 @@ export const addMechSuit = async (mechsuitName: string, accountId: string) => {
return changedInventory.MechSuits[suitIndex - 1].toJSON(); return changedInventory.MechSuits[suitIndex - 1].toJSON();
}; };
export const updateSlots = async (slotType: SlotType, accountId: string, slots: number) => { export const updateSlots = async (accountId: string, slotName: SlotNames, slotAmount: number, extraAmount: number) => {
const inventory = await getInventory(accountId); const inventory = await getInventory(accountId);
switch (slotType) { inventory[slotName].Slots += slotAmount;
case SlotType.SUIT: if (inventory[slotName].Extra === undefined) {
inventory.SuitBin.Slots += slots; inventory[slotName].Extra = extraAmount;
break; } else {
case SlotType.WEAPON: inventory[slotName].Extra += extraAmount;
inventory.WeaponBin.Slots += slots;
break;
case SlotType.MECHSUIT:
inventory.MechBin.Slots += slots;
break;
default:
throw new Error("invalid slot type");
} }
await inventory.save(); await inventory.save();
}; };
export const updateCurrency = async (price: number, usePremium: boolean, accountId: string) => { export const updateCurrency = async (price: number, usePremium: boolean, accountId: string) => {
const currencyName = usePremium ? "PremiumCredits" : "RegularCredits";
const inventory = await getInventory(accountId); const inventory = await getInventory(accountId);
inventory[currencyName] = inventory[currencyName] - price;
if (usePremium) {
if (inventory.PremiumCreditsFree > 0) {
inventory.PremiumCreditsFree += price;
}
inventory.PremiumCredits += price;
} else {
inventory.RegularCredits += price;
}
const modifiedPaths = inventory.modifiedPaths();
type currencyKeys = "RegularCredits" | "PremiumCredits" | "PremiumCreditsFree";
const currencyChanges = {} as Record<currencyKeys, number>;
modifiedPaths.forEach(path => {
currencyChanges[path as currencyKeys] = -price;
});
console.log(currencyChanges, "changes");
//let changes = {} as keyof currencyKeys;
// const obj2 = modifiedPaths.reduce(
// (obj, key) => {
// obj[key as keyof currencyKeys] = price;
// return obj;
// },
// {} as Record<keyof currencyKeys, number>
// );
await inventory.save(); await inventory.save();
return { [currencyName]: -price }; return currencyChanges;
}; };
// TODO: AffiliationMods support (Nightwave). // TODO: AffiliationMods support (Nightwave).
@ -157,7 +177,7 @@ export const addCustomization = async (customizatonName: string, accountId: stri
const flavourItemIndex = inventory.FlavourItems.push({ ItemType: customizatonName }) - 1; const flavourItemIndex = inventory.FlavourItems.push({ ItemType: customizatonName }) - 1;
const changedInventory = await inventory.save(); const changedInventory = await inventory.save();
return changedInventory.FlavourItems[flavourItemIndex].toJSON(); //mongoose bug forces as FlavourItem return changedInventory.FlavourItems[flavourItemIndex].toJSON();
}; };
const addGearExpByCategory = ( const addGearExpByCategory = (

View File

@ -1,4 +1,4 @@
import { getWeaponType } from "@/src/helpers/purchaseHelpers"; import { getWeaponType, parseSlotPurchaseName } from "@/src/helpers/purchaseHelpers";
import { getSubstringFromKeyword } from "@/src/helpers/stringHelpers"; import { getSubstringFromKeyword } from "@/src/helpers/stringHelpers";
import { import {
addBooster, addBooster,
@ -7,9 +7,10 @@ import {
addPowerSuit, addPowerSuit,
addSentinel, addSentinel,
addWeapon, addWeapon,
updateCurrency,
updateSlots updateSlots
} from "@/src/services/inventoryService"; } from "@/src/services/inventoryService";
import { IPurchaseRequest, SlotType } from "@/src/types/purchaseTypes"; import { IPurchaseRequest, IPurchaseResponse, SlotNameToInventoryName, SlotPurchase } from "@/src/types/purchaseTypes";
export const getStoreItemCategory = (storeItem: string) => { export const getStoreItemCategory = (storeItem: string) => {
const storeItemString = getSubstringFromKeyword(storeItem, "StoreItems/"); const storeItemString = getSubstringFromKeyword(storeItem, "StoreItems/");
@ -32,57 +33,109 @@ export const handlePurchase = async (purchaseRequest: IPurchaseRequest, accountI
const internalName = purchaseRequest.PurchaseParams.StoreItem.replace("/StoreItems", ""); const internalName = purchaseRequest.PurchaseParams.StoreItem.replace("/StoreItems", "");
console.log("Store category", storeCategory); console.log("Store category", storeCategory);
let purchaseResponse; let inventoryChanges;
switch (storeCategory) { switch (storeCategory) {
case "Powersuits": case "Powersuits":
purchaseResponse = await handlePowersuitPurchase(internalName, accountId); inventoryChanges = await handlePowersuitPurchase(internalName, accountId);
break; break;
case "Weapons": case "Weapons":
purchaseResponse = await handleWeaponsPurchase(internalName, accountId); inventoryChanges = await handleWeaponsPurchase(internalName, accountId);
break; break;
case "Types": case "Types":
purchaseResponse = await handleTypesPurchase(internalName, accountId); inventoryChanges = await handleTypesPurchase(internalName, accountId);
break; break;
case "Boosters": case "Boosters":
purchaseResponse = await handleBoostersPurchase(internalName, accountId); inventoryChanges = await handleBoostersPurchase(internalName, accountId);
break; break;
default: default:
throw new Error(`unknown store category: ${storeCategory} not implemented or new`); throw new Error(`unknown store category: ${storeCategory} not implemented or new`);
} }
// const currencyResponse = await updateCurrency( if (!inventoryChanges) throw new Error("purchase response was undefined");
// purchaseRequest.PurchaseParams.ExpectedPrice,
// purchaseRequest.PurchaseParams.UsePremium,
// accountId
// );
// (purchaseResponse as IPurchaseResponse).InventoryChanges = { const currencyChanges = await updateCurrency(
// ...purchaseResponse.InventoryChanges, purchaseRequest.PurchaseParams.ExpectedPrice,
// ...currencyResponse purchaseRequest.PurchaseParams.UsePremium,
// }; accountId
);
return purchaseResponse; inventoryChanges.InventoryChanges = {
...currencyChanges,
...inventoryChanges.InventoryChanges
};
return inventoryChanges;
};
export const slotPurchaseNameToSlotName: SlotPurchase = {
SuitSlotItem: { name: "SuitBin", slotsPerPurchase: 1 },
TwoSentinelSlotItem: { name: "SentinelBin", slotsPerPurchase: 2 },
TwoWeaponSlotItem: { name: "WeaponBin", slotsPerPurchase: 2 },
SpaceSuitSlotItem: { name: "SpaceSuitBin", slotsPerPurchase: 1 },
TwoSpaceWeaponSlotItem: { name: "SpaceWeaponBin", slotsPerPurchase: 2 },
MechSlotItem: { name: "MechBin", slotsPerPurchase: 1 },
TwoOperatorWeaponSlotItem: { name: "OperatorAmpBin", slotsPerPurchase: 2 },
RandomModSlotItem: { name: "RandomModBin", slotsPerPurchase: 3 },
TwoCrewShipSalvageSlotItem: { name: "CrewShipSalvageBin", slotsPerPurchase: 2 },
CrewMemberSlotItem: { name: "CrewMemberBin", slotsPerPurchase: 1 }
};
// // extra = everything above the base +2 slots (depending on slot type)
// // new slot above base = extra + 1 and slots +1
// // new frame = slots -1
// // number of frames = extra - slots + 2
const handleSlotPurchase = async (slotPurchaseNameFull: string, accountId: string) => {
console.log("slot name", slotPurchaseNameFull);
const slotPurchaseName = parseSlotPurchaseName(
slotPurchaseNameFull.substring(slotPurchaseNameFull.lastIndexOf("/") + 1)
);
console.log(slotPurchaseName, "slot purchase name");
await updateSlots(
accountId,
slotPurchaseNameToSlotName[slotPurchaseName].name,
slotPurchaseNameToSlotName[slotPurchaseName].slotsPerPurchase,
slotPurchaseNameToSlotName[slotPurchaseName].slotsPerPurchase
);
console.log(
slotPurchaseNameToSlotName[slotPurchaseName].name,
slotPurchaseNameToSlotName[slotPurchaseName].slotsPerPurchase,
"slots added"
);
return {
InventoryChanges: {
[slotPurchaseNameToSlotName[slotPurchaseName].name]: {
count: 0,
platinum: 1,
Slots: slotPurchaseNameToSlotName[slotPurchaseName].slotsPerPurchase,
Extra: slotPurchaseNameToSlotName[slotPurchaseName].slotsPerPurchase
}
}
};
}; };
const handleWeaponsPurchase = async (weaponName: string, accountId: string) => { const handleWeaponsPurchase = async (weaponName: string, accountId: string) => {
const weaponType = getWeaponType(weaponName); const weaponType = getWeaponType(weaponName);
const addedWeapon = await addWeapon(weaponType, weaponName, accountId); const addedWeapon = await addWeapon(weaponType, weaponName, accountId);
await updateSlots(SlotType.WEAPON, accountId, -1); await updateSlots(accountId, SlotNameToInventoryName.WEAPON, 0, 1);
return { return {
InventoryChanges: { InventoryChanges: {
WeaponBin: { count: 1, platinum: 0, Slots: -1 }, WeaponBin: { count: 1, platinum: 0, Slots: -1 },
[weaponType]: [addedWeapon] [weaponType]: [addedWeapon]
} }
}; } as IPurchaseResponse;
}; };
const handlePowersuitPurchase = async (powersuitName: string, accountId: string) => { const handlePowersuitPurchase = async (powersuitName: string, accountId: string) => {
if (powersuitName.includes("EntratiMech")) { if (powersuitName.includes("EntratiMech")) {
const mechSuit = await addMechSuit(powersuitName, accountId); const mechSuit = await addMechSuit(powersuitName, accountId);
await updateSlots(SlotType.MECHSUIT, accountId, -1);
await updateSlots(accountId, SlotNameToInventoryName.MECHSUIT, 0, 1);
console.log("mech suit", mechSuit); console.log("mech suit", mechSuit);
return { return {
@ -94,11 +147,11 @@ const handlePowersuitPurchase = async (powersuitName: string, accountId: string)
}, },
MechSuits: [mechSuit] MechSuits: [mechSuit]
} }
}; } as IPurchaseResponse;
} }
const suit = await addPowerSuit(powersuitName, accountId); const suit = await addPowerSuit(powersuitName, accountId);
await updateSlots(SlotType.SUIT, accountId, -1); await updateSlots(accountId, SlotNameToInventoryName.SUIT, 0, 1);
return { return {
InventoryChanges: { InventoryChanges: {
@ -112,6 +165,7 @@ const handlePowersuitPurchase = async (powersuitName: string, accountId: string)
}; };
}; };
//TODO: change to getInventory, apply changes then save at the end
const handleTypesPurchase = async (typesName: string, accountId: string) => { const handleTypesPurchase = async (typesName: string, accountId: string) => {
const typeCategory = getStoreItemTypesCategory(typesName); const typeCategory = getStoreItemTypesCategory(typesName);
console.log("type category", typeCategory); console.log("type category", typeCategory);
@ -122,6 +176,8 @@ const handleTypesPurchase = async (typesName: string, accountId: string) => {
// break; // break;
case "Sentinels": case "Sentinels":
return await handleSentinelPurchase(typesName, accountId); return await handleSentinelPurchase(typesName, accountId);
case "SlotItems":
return await handleSlotPurchase(typesName, accountId);
default: default:
throw new Error(`unknown Types category: ${typeCategory} not implemented or new`); throw new Error(`unknown Types category: ${typeCategory} not implemented or new`);
} }
@ -130,6 +186,8 @@ const handleTypesPurchase = async (typesName: string, accountId: string) => {
const handleSentinelPurchase = async (sentinelName: string, accountId: string) => { const handleSentinelPurchase = async (sentinelName: string, accountId: string) => {
const sentinel = await addSentinel(sentinelName, accountId); const sentinel = await addSentinel(sentinelName, accountId);
await updateSlots(accountId, SlotNameToInventoryName.SENTINEL, 0, 1);
return { return {
InventoryChanges: { InventoryChanges: {
SentinelBin: { count: 1, platinum: 0, Slots: -1 }, SentinelBin: { count: 1, platinum: 0, Slots: -1 },

View File

@ -3,7 +3,7 @@ import { IPolarity } from "@/src/types/inventoryTypes/commonInventoryTypes";
import { Types } from "mongoose"; import { Types } from "mongoose";
import { IItemConfig } from "./commonInventoryTypes"; import { IItemConfig } from "./commonInventoryTypes";
export interface ISuitClient extends ISuitDatabase { export interface ISuitClient extends Omit<ISuitDatabase, "_id"> {
ItemId: IOid; ItemId: IOid;
} }

View File

@ -341,7 +341,7 @@ export interface ICrewShipHarnessConfig {
} }
export interface ISlots { export interface ISlots {
Extra?: number; Extra: number; // can be undefined, but not if used via mongoose
Slots: number; Slots: number;
} }

View File

@ -1,4 +1,5 @@
import { ISuitDatabase } from "@/src/types/inventoryTypes/SuitTypes"; import { slotPurchaseNameToSlotName } from "@/src/services/purchaseService";
import { ISuitClient } from "@/src/types/inventoryTypes/SuitTypes";
import { IFlavourItem } from "@/src/types/inventoryTypes/inventoryTypes"; import { IFlavourItem } from "@/src/types/inventoryTypes/inventoryTypes";
import { IWeaponClient } from "@/src/types/inventoryTypes/weaponTypes"; import { IWeaponClient } from "@/src/types/inventoryTypes/weaponTypes";
@ -22,11 +23,14 @@ export interface IPurchaseResponse {
InventoryChanges: { InventoryChanges: {
SuitBin?: IBinChanges; SuitBin?: IBinChanges;
WeaponBin?: IBinChanges; WeaponBin?: IBinChanges;
Suits?: ISuitDatabase[]; MechBin?: IBinChanges;
MechSuits?: ISuitClient[];
Suits?: ISuitClient[];
LongGuns?: IWeaponClient[]; LongGuns?: IWeaponClient[];
Pistols?: IWeaponClient[]; Pistols?: IWeaponClient[];
Melee?: IWeaponClient[]; Melee?: IWeaponClient[];
PremiumCredits?: number; PremiumCredits?: number;
PremiumCreditsFree?: number;
RegularCredits?: number; RegularCredits?: number;
FlavourItems?: IFlavourItem[]; FlavourItems?: IFlavourItem[];
}; };
@ -36,10 +40,42 @@ export type IBinChanges = {
count: number; count: number;
platinum: number; platinum: number;
Slots: number; Slots: number;
Extra?: number;
}; };
export enum SlotType { export enum SlotNameToInventoryName {
SUIT = "SuitBin", SUIT = "SuitBin",
WEAPON = "WeaponBin", WEAPON = "WeaponBin",
MECHSUIT = "MechBin" MECHSUIT = "MechBin",
LOADOUT = "PveBonusLoadoutBin",
SENTINEL = "SentinelBin"
} }
export type SlotPurchaseName =
| "SuitSlotItem"
| "TwoSentinelSlotItem"
| "TwoWeaponSlotItem"
| "SpaceSuitSlotItem"
| "TwoSpaceWeaponSlotItem"
| "MechSlotItem"
| "TwoOperatorWeaponSlotItem"
| "RandomModSlotItem"
| "TwoCrewShipSalvageSlotItem"
| "CrewMemberSlotItem";
export type SlotNames =
| "SuitBin"
| "WeaponBin"
| "MechBin"
| "PveBonusLoadoutBin"
| "SentinelBin"
| "SpaceSuitBin"
| "SpaceWeaponBin"
| "OperatorAmpBin"
| "RandomModBin"
| "CrewShipSalvageBin"
| "CrewMemberBin";
export type SlotPurchase = {
[P in SlotPurchaseName]: { name: SlotNames; slotsPerPurchase: number };
};

View File

@ -10,14 +10,14 @@ import {
import { IWeaponClient } from "./inventoryTypes/weaponTypes"; import { IWeaponClient } from "./inventoryTypes/weaponTypes";
import { ISuitClient } from "./inventoryTypes/SuitTypes"; import { ISuitClient } from "./inventoryTypes/SuitTypes";
interface IArtifactsRequest { export interface IArtifactsRequest {
Upgrade: ICrewShipSalvagedWeaponSkin; Upgrade: ICrewShipSalvagedWeaponSkin;
LevelDiff: number; LevelDiff: number;
Cost: number; Cost: number;
FusionPointCost: number; FusionPointCost: number;
} }
interface IMissionInventoryUpdateRequest { export interface IMissionInventoryUpdateRequest {
rewardsMultiplier?: number; rewardsMultiplier?: number;
ActiveBoosters?: IBooster[]; ActiveBoosters?: IBooster[];
LongGuns?: IWeaponClient[]; LongGuns?: IWeaponClient[];
@ -35,7 +35,7 @@ interface IMissionInventoryUpdateRequest {
Missions?: IMission; Missions?: IMission;
} }
interface IMissionInventoryUpdateRequestRewardInfo { export interface IMissionInventoryUpdateRequestRewardInfo {
node: string; node: string;
rewardTier?: number; rewardTier?: number;
nightmareMode?: boolean; nightmareMode?: boolean;
@ -50,4 +50,6 @@ interface IMissionInventoryUpdateRequestRewardInfo {
rewardSeed?: number; rewardSeed?: number;
} }
export { IArtifactsRequest, IMissionInventoryUpdateRequest }; export interface IInventorySlotsRequest {
Bin: "PveBonusLoadoutBin";
}