forked from OpenWF/SpaceNinjaServer
		
	feat: baro's void surplus (#2334)
Closes #2284 Reviewed-on: OpenWF/SpaceNinjaServer#2334 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
							
								
									44a129ab0b
								
							
						
					
					
						commit
						c4c622d82b
					
				@ -11,6 +11,7 @@ export const purchaseController: RequestHandler = async (req, res) => {
 | 
			
		||||
    const inventory = await getInventory(accountId);
 | 
			
		||||
    const response = await handlePurchase(purchaseRequest, inventory);
 | 
			
		||||
    await inventory.save();
 | 
			
		||||
    //console.log(JSON.stringify(response, null, 2));
 | 
			
		||||
    res.json(response);
 | 
			
		||||
    sendWsBroadcastTo(accountId, { update_inventory: true });
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -91,7 +91,7 @@ import {
 | 
			
		||||
    ICrewMemberSkillEfficiency,
 | 
			
		||||
    ICrewMemberDatabase,
 | 
			
		||||
    ICrewMemberClient,
 | 
			
		||||
    ISortieRewardAttenuation,
 | 
			
		||||
    IRewardAttenuation,
 | 
			
		||||
    IInvasionProgressDatabase,
 | 
			
		||||
    IInvasionProgressClient,
 | 
			
		||||
    IAccolades,
 | 
			
		||||
@ -1417,10 +1417,10 @@ lastSortieRewardSchema.set("toJSON", {
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const sortieRewardAttenutationSchema = new Schema<ISortieRewardAttenuation>(
 | 
			
		||||
const rewardAttenutationSchema = new Schema<IRewardAttenuation>(
 | 
			
		||||
    {
 | 
			
		||||
        Tag: String,
 | 
			
		||||
        Atten: Number
 | 
			
		||||
        Tag: { type: String, required: true },
 | 
			
		||||
        Atten: { type: Number, required: true }
 | 
			
		||||
    },
 | 
			
		||||
    { _id: false }
 | 
			
		||||
);
 | 
			
		||||
@ -1666,7 +1666,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
 | 
			
		||||
        CompletedSorties: [String],
 | 
			
		||||
        LastSortieReward: { type: [lastSortieRewardSchema], default: undefined },
 | 
			
		||||
        LastLiteSortieReward: { type: [lastSortieRewardSchema], default: undefined },
 | 
			
		||||
        SortieRewardAttenuation: { type: [sortieRewardAttenutationSchema], default: undefined },
 | 
			
		||||
        SortieRewardAttenuation: { type: [rewardAttenutationSchema], default: undefined },
 | 
			
		||||
 | 
			
		||||
        // Resource Extractor Drones
 | 
			
		||||
        Drones: [droneSchema],
 | 
			
		||||
@ -1805,7 +1805,9 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
 | 
			
		||||
 | 
			
		||||
        HubNpcCustomizations: { type: [hubNpcCustomizationSchema], default: undefined },
 | 
			
		||||
 | 
			
		||||
        ClaimedJunctionChallengeRewards: { type: [String], default: undefined }
 | 
			
		||||
        ClaimedJunctionChallengeRewards: { type: [String], default: undefined },
 | 
			
		||||
 | 
			
		||||
        SpecialItemRewardAttenuation: { type: [rewardAttenutationSchema], default: undefined }
 | 
			
		||||
    },
 | 
			
		||||
    { timestamps: { createdAt: "Created", updatedAt: false } }
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
@ -296,6 +296,12 @@ export const importInventory = (db: TInventoryDatabaseDocument, client: Partial<
 | 
			
		||||
            db[key] = client[key];
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    // IRewardAtten[]
 | 
			
		||||
    for (const key of ["SortieRewardAttenuation", "SpecialItemRewardAttenuation"] as const) {
 | 
			
		||||
        if (client[key] !== undefined) {
 | 
			
		||||
            db[key] = client[key];
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if (client.XPInfo !== undefined) {
 | 
			
		||||
        db.XPInfo = client.XPInfo;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -44,6 +44,7 @@ import {
 | 
			
		||||
} from "../types/inventoryTypes/commonInventoryTypes";
 | 
			
		||||
import {
 | 
			
		||||
    ExportArcanes,
 | 
			
		||||
    ExportBoosters,
 | 
			
		||||
    ExportBundles,
 | 
			
		||||
    ExportChallenges,
 | 
			
		||||
    ExportCustoms,
 | 
			
		||||
@ -671,6 +672,17 @@ export const addItem = async (
 | 
			
		||||
        return await addEmailItem(inventory, typeName);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Boosters are an odd case. They're only added like this via Baro's Void Surplus afaik.
 | 
			
		||||
    {
 | 
			
		||||
        const boosterEntry = Object.entries(ExportBoosters).find(arr => arr[1].typeName == typeName);
 | 
			
		||||
        if (boosterEntry) {
 | 
			
		||||
            addBooster(typeName, quantity, inventory);
 | 
			
		||||
            return {
 | 
			
		||||
                Boosters: [{ ItemType: typeName, ExpiryDate: quantity }]
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Path-based duck typing
 | 
			
		||||
    switch (typeName.substr(1).split("/")[1]) {
 | 
			
		||||
        case "Powersuits":
 | 
			
		||||
@ -1354,7 +1366,7 @@ export const addCustomization = (
 | 
			
		||||
    customizationName: string,
 | 
			
		||||
    inventoryChanges: IInventoryChanges = {}
 | 
			
		||||
): IInventoryChanges => {
 | 
			
		||||
    if (!inventory.FlavourItems.find(x => x.ItemType == customizationName)) {
 | 
			
		||||
    if (!inventory.FlavourItems.some(x => x.ItemType == customizationName)) {
 | 
			
		||||
        const flavourItemIndex = inventory.FlavourItems.push({ ItemType: customizationName }) - 1;
 | 
			
		||||
        // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
 | 
			
		||||
        inventoryChanges.FlavourItems ??= [];
 | 
			
		||||
@ -1370,7 +1382,7 @@ export const addSkin = (
 | 
			
		||||
    typeName: string,
 | 
			
		||||
    inventoryChanges: IInventoryChanges = {}
 | 
			
		||||
): IInventoryChanges => {
 | 
			
		||||
    if (inventory.WeaponSkins.find(x => x.ItemType == typeName)) {
 | 
			
		||||
    if (inventory.WeaponSkins.some(x => x.ItemType == typeName)) {
 | 
			
		||||
        logger.debug(`refusing to add WeaponSkin ${typeName} because account already owns it`);
 | 
			
		||||
    } else {
 | 
			
		||||
        const index = inventory.WeaponSkins.push({ ItemType: typeName, IsNew: true }) - 1;
 | 
			
		||||
 | 
			
		||||
@ -8,7 +8,7 @@ import {
 | 
			
		||||
    updateCurrency,
 | 
			
		||||
    updateSlots
 | 
			
		||||
} from "@/src/services/inventoryService";
 | 
			
		||||
import { getRandomWeightedRewardUc } from "@/src/services/rngService";
 | 
			
		||||
import { getRandomReward, getRandomWeightedRewardUc } from "@/src/services/rngService";
 | 
			
		||||
import { applyStandingToVendorManifest, getVendorManifestByOid } from "@/src/services/serversideVendorsService";
 | 
			
		||||
import { IMiscItem } from "@/src/types/inventoryTypes/inventoryTypes";
 | 
			
		||||
import {
 | 
			
		||||
@ -37,6 +37,7 @@ import { config } from "./configService";
 | 
			
		||||
import { TInventoryDatabaseDocument } from "../models/inventoryModels/inventoryModel";
 | 
			
		||||
import { fromStoreItem, toStoreItem } from "./itemDataService";
 | 
			
		||||
import { DailyDeal } from "../models/worldStateModel";
 | 
			
		||||
import { fromMongoDate, toMongoDate } from "../helpers/inventoryHelpers";
 | 
			
		||||
 | 
			
		||||
export const getStoreItemCategory = (storeItem: string): string => {
 | 
			
		||||
    const storeItemString = getSubstringFromKeyword(storeItem, "StoreItems/");
 | 
			
		||||
@ -53,6 +54,58 @@ export const getStoreItemTypesCategory = (typesItem: string): string => {
 | 
			
		||||
    return typeElements[1];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const tallyVendorPurchase = (
 | 
			
		||||
    inventory: TInventoryDatabaseDocument,
 | 
			
		||||
    inventoryChanges: IInventoryChanges,
 | 
			
		||||
    VendorType: string,
 | 
			
		||||
    ItemId: string,
 | 
			
		||||
    numPurchased: number,
 | 
			
		||||
    Expiry: Date
 | 
			
		||||
): void => {
 | 
			
		||||
    if (!config.noVendorPurchaseLimits) {
 | 
			
		||||
        inventory.RecentVendorPurchases ??= [];
 | 
			
		||||
        let vendorPurchases = inventory.RecentVendorPurchases.find(x => x.VendorType == VendorType);
 | 
			
		||||
        if (!vendorPurchases) {
 | 
			
		||||
            vendorPurchases =
 | 
			
		||||
                inventory.RecentVendorPurchases[
 | 
			
		||||
                    inventory.RecentVendorPurchases.push({
 | 
			
		||||
                        VendorType: VendorType,
 | 
			
		||||
                        PurchaseHistory: []
 | 
			
		||||
                    }) - 1
 | 
			
		||||
                ];
 | 
			
		||||
        }
 | 
			
		||||
        let historyEntry = vendorPurchases.PurchaseHistory.find(x => x.ItemId == ItemId);
 | 
			
		||||
        if (historyEntry) {
 | 
			
		||||
            if (Date.now() >= historyEntry.Expiry.getTime()) {
 | 
			
		||||
                historyEntry.NumPurchased = numPurchased;
 | 
			
		||||
                historyEntry.Expiry = Expiry;
 | 
			
		||||
            } else {
 | 
			
		||||
                historyEntry.NumPurchased += numPurchased;
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            historyEntry =
 | 
			
		||||
                vendorPurchases.PurchaseHistory[
 | 
			
		||||
                    vendorPurchases.PurchaseHistory.push({
 | 
			
		||||
                        ItemId: ItemId,
 | 
			
		||||
                        NumPurchased: numPurchased,
 | 
			
		||||
                        Expiry: Expiry
 | 
			
		||||
                    }) - 1
 | 
			
		||||
                ];
 | 
			
		||||
        }
 | 
			
		||||
        inventoryChanges.NewVendorPurchase = {
 | 
			
		||||
            VendorType: VendorType,
 | 
			
		||||
            PurchaseHistory: [
 | 
			
		||||
                {
 | 
			
		||||
                    ItemId: ItemId,
 | 
			
		||||
                    NumPurchased: historyEntry.NumPurchased,
 | 
			
		||||
                    Expiry: toMongoDate(Expiry)
 | 
			
		||||
                }
 | 
			
		||||
            ]
 | 
			
		||||
        };
 | 
			
		||||
        inventoryChanges.RecentVendorPurchases = inventoryChanges.NewVendorPurchase;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const handlePurchase = async (
 | 
			
		||||
    purchaseRequest: IPurchaseRequest,
 | 
			
		||||
    inventory: TInventoryDatabaseDocument
 | 
			
		||||
@ -99,20 +152,7 @@ export const handlePurchase = async (
 | 
			
		||||
            if (offer.LocTagRandSeed !== undefined) {
 | 
			
		||||
                seed = BigInt(offer.LocTagRandSeed);
 | 
			
		||||
            }
 | 
			
		||||
            if (!config.noVendorPurchaseLimits && ItemId) {
 | 
			
		||||
                inventory.RecentVendorPurchases ??= [];
 | 
			
		||||
                let vendorPurchases = inventory.RecentVendorPurchases.find(
 | 
			
		||||
                    x => x.VendorType == manifest!.VendorInfo.TypeName
 | 
			
		||||
                );
 | 
			
		||||
                if (!vendorPurchases) {
 | 
			
		||||
                    vendorPurchases =
 | 
			
		||||
                        inventory.RecentVendorPurchases[
 | 
			
		||||
                            inventory.RecentVendorPurchases.push({
 | 
			
		||||
                                VendorType: manifest.VendorInfo.TypeName,
 | 
			
		||||
                                PurchaseHistory: []
 | 
			
		||||
                            }) - 1
 | 
			
		||||
                        ];
 | 
			
		||||
                }
 | 
			
		||||
            if (ItemId) {
 | 
			
		||||
                let expiry = parseInt(offer.Expiry.$date.$numberLong);
 | 
			
		||||
                if (purchaseRequest.PurchaseParams.IsWeekly) {
 | 
			
		||||
                    const EPOCH = 1734307200 * 1000; // Monday
 | 
			
		||||
@ -120,34 +160,14 @@ export const handlePurchase = async (
 | 
			
		||||
                    const weekStart = EPOCH + week * 604800000;
 | 
			
		||||
                    expiry = weekStart + 604800000;
 | 
			
		||||
                }
 | 
			
		||||
                const historyEntry = vendorPurchases.PurchaseHistory.find(x => x.ItemId == ItemId);
 | 
			
		||||
                let numPurchased = purchaseRequest.PurchaseParams.Quantity;
 | 
			
		||||
                if (historyEntry) {
 | 
			
		||||
                    if (Date.now() >= historyEntry.Expiry.getTime()) {
 | 
			
		||||
                        historyEntry.NumPurchased = numPurchased;
 | 
			
		||||
                        historyEntry.Expiry = new Date(expiry);
 | 
			
		||||
                    } else {
 | 
			
		||||
                        numPurchased += historyEntry.NumPurchased;
 | 
			
		||||
                        historyEntry.NumPurchased += purchaseRequest.PurchaseParams.Quantity;
 | 
			
		||||
                    }
 | 
			
		||||
                } else {
 | 
			
		||||
                    vendorPurchases.PurchaseHistory.push({
 | 
			
		||||
                        ItemId: ItemId,
 | 
			
		||||
                        NumPurchased: purchaseRequest.PurchaseParams.Quantity,
 | 
			
		||||
                        Expiry: new Date(expiry)
 | 
			
		||||
                    });
 | 
			
		||||
                }
 | 
			
		||||
                prePurchaseInventoryChanges.NewVendorPurchase = {
 | 
			
		||||
                    VendorType: manifest.VendorInfo.TypeName,
 | 
			
		||||
                    PurchaseHistory: [
 | 
			
		||||
                        {
 | 
			
		||||
                            ItemId: ItemId,
 | 
			
		||||
                            NumPurchased: numPurchased,
 | 
			
		||||
                            Expiry: { $date: { $numberLong: expiry.toString() } }
 | 
			
		||||
                        }
 | 
			
		||||
                    ]
 | 
			
		||||
                };
 | 
			
		||||
                prePurchaseInventoryChanges.RecentVendorPurchases = prePurchaseInventoryChanges.NewVendorPurchase;
 | 
			
		||||
                tallyVendorPurchase(
 | 
			
		||||
                    inventory,
 | 
			
		||||
                    prePurchaseInventoryChanges,
 | 
			
		||||
                    manifest.VendorInfo.TypeName,
 | 
			
		||||
                    ItemId,
 | 
			
		||||
                    purchaseRequest.PurchaseParams.Quantity,
 | 
			
		||||
                    new Date(expiry)
 | 
			
		||||
                );
 | 
			
		||||
            }
 | 
			
		||||
            purchaseRequest.PurchaseParams.Quantity *= offer.QuantityMultiplier;
 | 
			
		||||
        } else {
 | 
			
		||||
@ -193,7 +213,7 @@ export const handlePurchase = async (
 | 
			
		||||
                    throw new Error(`vendor purchase should not have an expected price`);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (!config.dontSubtractPurchaseItemCost) {
 | 
			
		||||
                if (offer.PrimePrice && !config.dontSubtractPurchaseItemCost) {
 | 
			
		||||
                    const invItem: IMiscItem = {
 | 
			
		||||
                        ItemType: "/Lotus/Types/Items/MiscItems/PrimeBucks",
 | 
			
		||||
                        ItemCount: offer.PrimePrice * purchaseRequest.PurchaseParams.Quantity * -1
 | 
			
		||||
@ -202,6 +222,17 @@ export const handlePurchase = async (
 | 
			
		||||
                    purchaseResponse.InventoryChanges.MiscItems ??= [];
 | 
			
		||||
                    purchaseResponse.InventoryChanges.MiscItems.push(invItem);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (offer.Limit) {
 | 
			
		||||
                    tallyVendorPurchase(
 | 
			
		||||
                        inventory,
 | 
			
		||||
                        purchaseResponse.InventoryChanges,
 | 
			
		||||
                        "VoidTrader",
 | 
			
		||||
                        offer.ItemType,
 | 
			
		||||
                        purchaseRequest.PurchaseParams.Quantity,
 | 
			
		||||
                        fromMongoDate(worldState.VoidTraders[0].Expiry)
 | 
			
		||||
                    );
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
@ -509,12 +540,57 @@ const handleBoosterPackPurchase = async (
 | 
			
		||||
            "attempt to roll over 100 booster packs in a single go. possible but unlikely to be desirable for the user or the server."
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
    const specialItemReward = pack.components.find(x => x.PityIncreaseRate);
 | 
			
		||||
    for (let i = 0; i != quantity; ++i) {
 | 
			
		||||
        const disallowedItems = new Set();
 | 
			
		||||
        for (let roll = 0; roll != pack.rarityWeightsPerRoll.length; ) {
 | 
			
		||||
            const weights = pack.rarityWeightsPerRoll[roll];
 | 
			
		||||
            const result = getRandomWeightedRewardUc(pack.components, weights);
 | 
			
		||||
            if (result) {
 | 
			
		||||
        if (specialItemReward) {
 | 
			
		||||
            {
 | 
			
		||||
                const normalComponents = [];
 | 
			
		||||
                for (const comp of pack.components) {
 | 
			
		||||
                    if (!comp.PityIncreaseRate) {
 | 
			
		||||
                        const { Probability, ...rest } = comp;
 | 
			
		||||
                        normalComponents.push({
 | 
			
		||||
                            ...rest,
 | 
			
		||||
                            probability: Probability!
 | 
			
		||||
                        });
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                const result = getRandomReward(normalComponents)!;
 | 
			
		||||
                logger.debug(`booster pack rolled`, result);
 | 
			
		||||
                purchaseResponse.BoosterPackItems += toStoreItem(result.Item) + ',{"lvl":0};';
 | 
			
		||||
                combineInventoryChanges(
 | 
			
		||||
                    purchaseResponse.InventoryChanges,
 | 
			
		||||
                    await addItem(inventory, result.Item, result.Amount)
 | 
			
		||||
                );
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (!inventory.WeaponSkins.some(x => x.ItemType == specialItemReward.Item)) {
 | 
			
		||||
                inventory.SpecialItemRewardAttenuation ??= [];
 | 
			
		||||
                let atten = inventory.SpecialItemRewardAttenuation.find(x => x.Tag == specialItemReward.Item);
 | 
			
		||||
                if (!atten) {
 | 
			
		||||
                    atten =
 | 
			
		||||
                        inventory.SpecialItemRewardAttenuation[
 | 
			
		||||
                            inventory.SpecialItemRewardAttenuation.push({
 | 
			
		||||
                                Tag: specialItemReward.Item,
 | 
			
		||||
                                Atten: specialItemReward.Probability!
 | 
			
		||||
                            }) - 1
 | 
			
		||||
                        ];
 | 
			
		||||
                }
 | 
			
		||||
                if (Math.random() < atten.Atten) {
 | 
			
		||||
                    purchaseResponse.BoosterPackItems += toStoreItem(specialItemReward.Item) + ',{"lvl":0};';
 | 
			
		||||
                    combineInventoryChanges(
 | 
			
		||||
                        purchaseResponse.InventoryChanges,
 | 
			
		||||
                        await addItem(inventory, specialItemReward.Item)
 | 
			
		||||
                    );
 | 
			
		||||
                    // TOVERIFY: Is the SpecialItemRewardAttenuation entry removed now?
 | 
			
		||||
                } else {
 | 
			
		||||
                    atten.Atten += specialItemReward.PityIncreaseRate!;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            const disallowedItems = new Set();
 | 
			
		||||
            for (let roll = 0; roll != pack.rarityWeightsPerRoll.length; ) {
 | 
			
		||||
                const weights = pack.rarityWeightsPerRoll[roll];
 | 
			
		||||
                const result = getRandomWeightedRewardUc(pack.components, weights)!;
 | 
			
		||||
                logger.debug(`booster pack rolled`, result);
 | 
			
		||||
                if (disallowedItems.has(result.Item)) {
 | 
			
		||||
                    logger.debug(`oops, can't use that one; trying again`);
 | 
			
		||||
@ -524,9 +600,12 @@ const handleBoosterPackPurchase = async (
 | 
			
		||||
                    disallowedItems.add(result.Item);
 | 
			
		||||
                }
 | 
			
		||||
                purchaseResponse.BoosterPackItems += toStoreItem(result.Item) + ',{"lvl":0};';
 | 
			
		||||
                combineInventoryChanges(purchaseResponse.InventoryChanges, await addItem(inventory, result.Item, 1));
 | 
			
		||||
                combineInventoryChanges(
 | 
			
		||||
                    purchaseResponse.InventoryChanges,
 | 
			
		||||
                    await addItem(inventory, result.Item, result.Amount)
 | 
			
		||||
                );
 | 
			
		||||
                ++roll;
 | 
			
		||||
            }
 | 
			
		||||
            ++roll;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return purchaseResponse;
 | 
			
		||||
 | 
			
		||||
@ -298,7 +298,7 @@ export interface IInventoryClient extends IDailyAffiliations, InventoryClientEqu
 | 
			
		||||
    CompletedSorties: string[];
 | 
			
		||||
    LastSortieReward?: ILastSortieRewardClient[];
 | 
			
		||||
    LastLiteSortieReward?: ILastSortieRewardClient[];
 | 
			
		||||
    SortieRewardAttenuation?: ISortieRewardAttenuation[];
 | 
			
		||||
    SortieRewardAttenuation?: IRewardAttenuation[];
 | 
			
		||||
    Drones: IDroneClient[];
 | 
			
		||||
    StepSequencers: IStepSequencer[];
 | 
			
		||||
    ActiveAvatarImageType?: string;
 | 
			
		||||
@ -383,6 +383,7 @@ export interface IInventoryClient extends IDailyAffiliations, InventoryClientEqu
 | 
			
		||||
    HubNpcCustomizations?: IHubNpcCustomization[];
 | 
			
		||||
    Ship?: IOrbiter; // U22 and below, response only
 | 
			
		||||
    ClaimedJunctionChallengeRewards?: string[]; // U39
 | 
			
		||||
    SpecialItemRewardAttenuation?: IRewardAttenuation[]; // Baro's Void Surplus
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface IAffiliation {
 | 
			
		||||
@ -785,7 +786,7 @@ export interface ILastSortieRewardDatabase extends Omit<ILastSortieRewardClient,
 | 
			
		||||
    SortieId: Types.ObjectId;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface ISortieRewardAttenuation {
 | 
			
		||||
export interface IRewardAttenuation {
 | 
			
		||||
    Tag: string;
 | 
			
		||||
    Atten: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -160,6 +160,7 @@ export interface IVoidTraderOffer {
 | 
			
		||||
    ItemType: string;
 | 
			
		||||
    PrimePrice: number;
 | 
			
		||||
    RegularPrice: number;
 | 
			
		||||
    Limit?: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface IVoidStorm {
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,8 @@
 | 
			
		||||
{
 | 
			
		||||
  "evergreen": [
 | 
			
		||||
    { "ItemType": "/Lotus/StoreItems/Types/Keys/MummyQuestKeyBlueprint", "PrimePrice": 100, "RegularPrice": 25000 },
 | 
			
		||||
    { "ItemType": "/Lotus/StoreItems/Upgrades/Skins/Effects/FootstepsMaple", "PrimePrice": 15, "RegularPrice": 1000 }
 | 
			
		||||
    { "ItemType": "/Lotus/StoreItems/Upgrades/Skins/Effects/FootstepsMaple", "PrimePrice": 15, "RegularPrice": 1000 },
 | 
			
		||||
    { "ItemType": "/Lotus/StoreItems/Types/BoosterPacks/BaroTreasureBox", "PrimePrice": 0, "RegularPrice": 50000, "Limit": 1 }
 | 
			
		||||
  ],
 | 
			
		||||
  "armorSets": [
 | 
			
		||||
    [
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user