feat: apply & track daily standing limit when trading in medallions (#788)
This commit is contained in:
		
							parent
							
								
									534f7d8cce
								
							
						
					
					
						commit
						d8845bc478
					
				@ -1,19 +1,19 @@
 | 
				
			|||||||
import { RequestHandler } from "express";
 | 
					import { RequestHandler } from "express";
 | 
				
			||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
					import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
				
			||||||
import { addMiscItems, getInventory } from "@/src/services/inventoryService";
 | 
					import { addMiscItems, getInventory, getStandingLimit, updateStandingLimit } from "@/src/services/inventoryService";
 | 
				
			||||||
import { IMiscItem } from "@/src/types/inventoryTypes/inventoryTypes";
 | 
					import { IMiscItem } from "@/src/types/inventoryTypes/inventoryTypes";
 | 
				
			||||||
import { IOid } from "@/src/types/commonTypes";
 | 
					import { IOid } from "@/src/types/commonTypes";
 | 
				
			||||||
import { ExportSyndicates } from "warframe-public-export-plus";
 | 
					import { ExportSyndicates, ISyndicate } from "warframe-public-export-plus";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const syndicateStandingBonusController: RequestHandler = async (req, res) => {
 | 
					export const syndicateStandingBonusController: RequestHandler = async (req, res) => {
 | 
				
			||||||
    const accountId = await getAccountIdForRequest(req);
 | 
					    const accountId = await getAccountIdForRequest(req);
 | 
				
			||||||
    const request = JSON.parse(String(req.body)) as ISyndicateStandingBonusRequest;
 | 
					    const request = JSON.parse(String(req.body)) as ISyndicateStandingBonusRequest;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const syndicateMeta = ExportSyndicates[request.Operation.AffiliationTag];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let gainedStanding = 0;
 | 
					    let gainedStanding = 0;
 | 
				
			||||||
    request.Operation.Items.forEach(item => {
 | 
					    request.Operation.Items.forEach(item => {
 | 
				
			||||||
        const medallion = (ExportSyndicates[request.Operation.AffiliationTag].medallions ?? []).find(
 | 
					        const medallion = (syndicateMeta.medallions ?? []).find(medallion => medallion.itemType == item.ItemType);
 | 
				
			||||||
            medallion => medallion.itemType == item.ItemType
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
        if (medallion) {
 | 
					        if (medallion) {
 | 
				
			||||||
            gainedStanding += medallion.standing * item.ItemCount;
 | 
					            gainedStanding += medallion.standing * item.ItemCount;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -27,17 +27,22 @@ export const syndicateStandingBonusController: RequestHandler = async (req, res)
 | 
				
			|||||||
    let syndicate = inventory.Affiliations.find(x => x.Tag == request.Operation.AffiliationTag);
 | 
					    let syndicate = inventory.Affiliations.find(x => x.Tag == request.Operation.AffiliationTag);
 | 
				
			||||||
    if (!syndicate) {
 | 
					    if (!syndicate) {
 | 
				
			||||||
        syndicate =
 | 
					        syndicate =
 | 
				
			||||||
            inventory.Affiliations[inventory.Affiliations.push({ Tag: request.Operation.AffiliationTag, Standing: 0 })];
 | 
					            inventory.Affiliations[
 | 
				
			||||||
 | 
					                inventory.Affiliations.push({ Tag: request.Operation.AffiliationTag, Standing: 0 }) - 1
 | 
				
			||||||
 | 
					            ];
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const max = getMaxStanding(request.Operation.AffiliationTag, syndicate.Title ?? 0);
 | 
					    const max = getMaxStanding(syndicateMeta, syndicate.Title ?? 0);
 | 
				
			||||||
    if (syndicate.Standing + gainedStanding > max) {
 | 
					    if (syndicate.Standing + gainedStanding > max) {
 | 
				
			||||||
        gainedStanding = max - syndicate.Standing;
 | 
					        gainedStanding = max - syndicate.Standing;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    if (gainedStanding > getStandingLimit(inventory, syndicateMeta.dailyLimitBin)) {
 | 
				
			||||||
 | 
					        gainedStanding = getStandingLimit(inventory, syndicateMeta.dailyLimitBin);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    syndicate.Standing += gainedStanding;
 | 
					    syndicate.Standing += gainedStanding;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // TODO: Subtract from daily limit bin; maybe also a cheat to skip that.
 | 
					    updateStandingLimit(inventory, syndicateMeta.dailyLimitBin, gainedStanding);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    await inventory.save();
 | 
					    await inventory.save();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -63,8 +68,7 @@ interface ISyndicateStandingBonusRequest {
 | 
				
			|||||||
    ModularWeaponId: IOid; // Seems to just be "000000000000000000000000", also note there's a "Category" query field
 | 
					    ModularWeaponId: IOid; // Seems to just be "000000000000000000000000", also note there's a "Category" query field
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const getMaxStanding = (affiliationTag: string, title: number): number => {
 | 
					const getMaxStanding = (syndicate: ISyndicate, title: number): number => {
 | 
				
			||||||
    const syndicate = ExportSyndicates[affiliationTag];
 | 
					 | 
				
			||||||
    if (!syndicate.titles) {
 | 
					    if (!syndicate.titles) {
 | 
				
			||||||
        // LibrarySyndicate
 | 
					        // LibrarySyndicate
 | 
				
			||||||
        return 125000;
 | 
					        return 125000;
 | 
				
			||||||
 | 
				
			|||||||
@ -16,7 +16,8 @@ import {
 | 
				
			|||||||
    IWeaponSkinClient,
 | 
					    IWeaponSkinClient,
 | 
				
			||||||
    TEquipmentKey,
 | 
					    TEquipmentKey,
 | 
				
			||||||
    equipmentKeys,
 | 
					    equipmentKeys,
 | 
				
			||||||
    IFusionTreasure
 | 
					    IFusionTreasure,
 | 
				
			||||||
 | 
					    IDailyAffiliations
 | 
				
			||||||
} from "@/src/types/inventoryTypes/inventoryTypes";
 | 
					} from "@/src/types/inventoryTypes/inventoryTypes";
 | 
				
			||||||
import { IGenericUpdate } from "../types/genericUpdate";
 | 
					import { IGenericUpdate } from "../types/genericUpdate";
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
@ -36,7 +37,8 @@ import {
 | 
				
			|||||||
    ExportRecipes,
 | 
					    ExportRecipes,
 | 
				
			||||||
    ExportResources,
 | 
					    ExportResources,
 | 
				
			||||||
    ExportSentinels,
 | 
					    ExportSentinels,
 | 
				
			||||||
    ExportUpgrades
 | 
					    ExportUpgrades,
 | 
				
			||||||
 | 
					    TStandingLimitBin
 | 
				
			||||||
} from "warframe-public-export-plus";
 | 
					} from "warframe-public-export-plus";
 | 
				
			||||||
import { createShip } from "./shipService";
 | 
					import { createShip } from "./shipService";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -492,6 +494,43 @@ export const updateCurrencyByAccountId = async (
 | 
				
			|||||||
    return currencyChanges;
 | 
					    return currencyChanges;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const standingLimitBinToInventoryKey: Record<
 | 
				
			||||||
 | 
					    Exclude<TStandingLimitBin, "STANDING_LIMIT_BIN_NONE">,
 | 
				
			||||||
 | 
					    keyof IDailyAffiliations
 | 
				
			||||||
 | 
					> = {
 | 
				
			||||||
 | 
					    STANDING_LIMIT_BIN_NORMAL: "DailyAffiliation",
 | 
				
			||||||
 | 
					    STANDING_LIMIT_BIN_PVP: "DailyAffiliationPvp",
 | 
				
			||||||
 | 
					    STANDING_LIMIT_BIN_LIBRARY: "DailyAffiliationLibrary",
 | 
				
			||||||
 | 
					    STANDING_LIMIT_BIN_CETUS: "DailyAffiliationCetus",
 | 
				
			||||||
 | 
					    STANDING_LIMIT_BIN_QUILLS: "DailyAffiliationQuills",
 | 
				
			||||||
 | 
					    STANDING_LIMIT_BIN_SOLARIS: "DailyAffiliationSolaris",
 | 
				
			||||||
 | 
					    STANDING_LIMIT_BIN_VENTKIDS: "DailyAffiliationVentkids",
 | 
				
			||||||
 | 
					    STANDING_LIMIT_BIN_VOX: "DailyAffiliationVox",
 | 
				
			||||||
 | 
					    STANDING_LIMIT_BIN_ENTRATI: "DailyAffiliationEntrati",
 | 
				
			||||||
 | 
					    STANDING_LIMIT_BIN_NECRALOID: "DailyAffiliationNecraloid",
 | 
				
			||||||
 | 
					    STANDING_LIMIT_BIN_ZARIMAN: "DailyAffiliationZariman",
 | 
				
			||||||
 | 
					    STANDING_LIMIT_BIN_KAHL: "DailyAffiliationKahl",
 | 
				
			||||||
 | 
					    STANDING_LIMIT_BIN_CAVIA: "DailyAffiliationCavia",
 | 
				
			||||||
 | 
					    STANDING_LIMIT_BIN_HEX: "DailyAffiliationHex"
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const getStandingLimit = (inventory: IDailyAffiliations, bin: TStandingLimitBin): number => {
 | 
				
			||||||
 | 
					    if (bin == "STANDING_LIMIT_BIN_NONE") {
 | 
				
			||||||
 | 
					        return Number.MAX_SAFE_INTEGER;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return inventory[standingLimitBinToInventoryKey[bin]];
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const updateStandingLimit = (
 | 
				
			||||||
 | 
					    inventory: IDailyAffiliations,
 | 
				
			||||||
 | 
					    bin: TStandingLimitBin,
 | 
				
			||||||
 | 
					    subtrahend: number
 | 
				
			||||||
 | 
					): void => {
 | 
				
			||||||
 | 
					    if (bin != "STANDING_LIMIT_BIN_NONE") {
 | 
				
			||||||
 | 
					        inventory[standingLimitBinToInventoryKey[bin]] -= subtrahend;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// TODO: AffiliationMods support (Nightwave).
 | 
					// TODO: AffiliationMods support (Nightwave).
 | 
				
			||||||
export const updateGeneric = async (data: IGenericUpdate, accountId: string): Promise<void> => {
 | 
					export const updateGeneric = async (data: IGenericUpdate, accountId: string): Promise<void> => {
 | 
				
			||||||
    const inventory = await getInventory(accountId);
 | 
					    const inventory = await getInventory(accountId);
 | 
				
			||||||
 | 
				
			|||||||
@ -110,7 +110,25 @@ export type TSolarMapRegion =
 | 
				
			|||||||
export interface IPendingRecipeResponse extends Omit<IPendingRecipe, "CompletionDate"> {
 | 
					export interface IPendingRecipeResponse extends Omit<IPendingRecipe, "CompletionDate"> {
 | 
				
			||||||
    CompletionDate: IMongoDate;
 | 
					    CompletionDate: IMongoDate;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
export interface IInventoryResponse {
 | 
					
 | 
				
			||||||
 | 
					export interface IDailyAffiliations {
 | 
				
			||||||
 | 
					    DailyAffiliation: number;
 | 
				
			||||||
 | 
					    DailyAffiliationPvp: number;
 | 
				
			||||||
 | 
					    DailyAffiliationLibrary: number;
 | 
				
			||||||
 | 
					    DailyAffiliationCetus: number;
 | 
				
			||||||
 | 
					    DailyAffiliationQuills: number;
 | 
				
			||||||
 | 
					    DailyAffiliationSolaris: number;
 | 
				
			||||||
 | 
					    DailyAffiliationVentkids: number;
 | 
				
			||||||
 | 
					    DailyAffiliationVox: number;
 | 
				
			||||||
 | 
					    DailyAffiliationEntrati: number;
 | 
				
			||||||
 | 
					    DailyAffiliationNecraloid: number;
 | 
				
			||||||
 | 
					    DailyAffiliationZariman: number;
 | 
				
			||||||
 | 
					    DailyAffiliationKahl: number;
 | 
				
			||||||
 | 
					    DailyAffiliationCavia: number;
 | 
				
			||||||
 | 
					    DailyAffiliationHex: number;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface IInventoryResponse extends IDailyAffiliations {
 | 
				
			||||||
    Horses: IEquipmentDatabase[];
 | 
					    Horses: IEquipmentDatabase[];
 | 
				
			||||||
    DrifterMelee: IEquipmentDatabase[];
 | 
					    DrifterMelee: IEquipmentDatabase[];
 | 
				
			||||||
    DrifterGuns: IEquipmentDatabase[];
 | 
					    DrifterGuns: IEquipmentDatabase[];
 | 
				
			||||||
@ -138,9 +156,6 @@ export interface IInventoryResponse {
 | 
				
			|||||||
    OperatorAmpBin: ISlots;
 | 
					    OperatorAmpBin: ISlots;
 | 
				
			||||||
    CrewShipSalvageBin: ISlots;
 | 
					    CrewShipSalvageBin: ISlots;
 | 
				
			||||||
    TradesRemaining: number;
 | 
					    TradesRemaining: number;
 | 
				
			||||||
    DailyAffiliation: number;
 | 
					 | 
				
			||||||
    DailyAffiliationPvp: number;
 | 
					 | 
				
			||||||
    DailyAffiliationLibrary: number;
 | 
					 | 
				
			||||||
    DailyFocus: number;
 | 
					    DailyFocus: number;
 | 
				
			||||||
    GiftsRemaining: number;
 | 
					    GiftsRemaining: number;
 | 
				
			||||||
    HandlerPoints: number;
 | 
					    HandlerPoints: number;
 | 
				
			||||||
@ -220,8 +235,6 @@ export interface IInventoryResponse {
 | 
				
			|||||||
    ActiveAvatarImageType: string;
 | 
					    ActiveAvatarImageType: string;
 | 
				
			||||||
    KubrowPets: IEquipmentDatabase[];
 | 
					    KubrowPets: IEquipmentDatabase[];
 | 
				
			||||||
    ShipDecorations: IConsumable[];
 | 
					    ShipDecorations: IConsumable[];
 | 
				
			||||||
    DailyAffiliationCetus: number;
 | 
					 | 
				
			||||||
    DailyAffiliationQuills: number;
 | 
					 | 
				
			||||||
    DiscoveredMarkers: IDiscoveredMarker[];
 | 
					    DiscoveredMarkers: IDiscoveredMarker[];
 | 
				
			||||||
    CompletedJobs: ICompletedJob[];
 | 
					    CompletedJobs: ICompletedJob[];
 | 
				
			||||||
    FocusAbility: string;
 | 
					    FocusAbility: string;
 | 
				
			||||||
@ -232,7 +245,6 @@ export interface IInventoryResponse {
 | 
				
			|||||||
    KubrowPetPrints: IKubrowPetPrint[];
 | 
					    KubrowPetPrints: IKubrowPetPrint[];
 | 
				
			||||||
    AlignmentReplay: IAlignment;
 | 
					    AlignmentReplay: IAlignment;
 | 
				
			||||||
    PersonalGoalProgress: IPersonalGoalProgress[];
 | 
					    PersonalGoalProgress: IPersonalGoalProgress[];
 | 
				
			||||||
    DailyAffiliationSolaris: number;
 | 
					 | 
				
			||||||
    SpecialItems: IEquipmentDatabase[];
 | 
					    SpecialItems: IEquipmentDatabase[];
 | 
				
			||||||
    ThemeStyle: string;
 | 
					    ThemeStyle: string;
 | 
				
			||||||
    ThemeBackground: string;
 | 
					    ThemeBackground: string;
 | 
				
			||||||
@ -241,8 +253,6 @@ export interface IInventoryResponse {
 | 
				
			|||||||
    ChallengeInstanceStates: IChallengeInstanceState[];
 | 
					    ChallengeInstanceStates: IChallengeInstanceState[];
 | 
				
			||||||
    LoginMilestoneRewards: string[];
 | 
					    LoginMilestoneRewards: string[];
 | 
				
			||||||
    OperatorLoadOuts: IOperatorConfigClient[];
 | 
					    OperatorLoadOuts: IOperatorConfigClient[];
 | 
				
			||||||
    DailyAffiliationVentkids: number;
 | 
					 | 
				
			||||||
    DailyAffiliationVox: number;
 | 
					 | 
				
			||||||
    RecentVendorPurchases: Array<number | string>;
 | 
					    RecentVendorPurchases: Array<number | string>;
 | 
				
			||||||
    Hoverboards: IEquipmentDatabase[];
 | 
					    Hoverboards: IEquipmentDatabase[];
 | 
				
			||||||
    NodeIntrosCompleted: string[];
 | 
					    NodeIntrosCompleted: string[];
 | 
				
			||||||
@ -268,8 +278,6 @@ export interface IInventoryResponse {
 | 
				
			|||||||
    TradeBannedUntil?: IMongoDate;
 | 
					    TradeBannedUntil?: IMongoDate;
 | 
				
			||||||
    PlayedParkourTutorial: boolean;
 | 
					    PlayedParkourTutorial: boolean;
 | 
				
			||||||
    SubscribedToEmailsPersonalized: number;
 | 
					    SubscribedToEmailsPersonalized: number;
 | 
				
			||||||
    DailyAffiliationEntrati: number;
 | 
					 | 
				
			||||||
    DailyAffiliationNecraloid: number;
 | 
					 | 
				
			||||||
    MechSuits: IEquipmentDatabase[];
 | 
					    MechSuits: IEquipmentDatabase[];
 | 
				
			||||||
    InfestedFoundry?: IInfestedFoundry;
 | 
					    InfestedFoundry?: IInfestedFoundry;
 | 
				
			||||||
    BlessingCooldown: IMongoDate;
 | 
					    BlessingCooldown: IMongoDate;
 | 
				
			||||||
@ -279,11 +287,7 @@ export interface IInventoryResponse {
 | 
				
			|||||||
    AdultOperatorLoadOuts: IOperatorConfigClient[];
 | 
					    AdultOperatorLoadOuts: IOperatorConfigClient[];
 | 
				
			||||||
    LotusCustomization: ILotusCustomization;
 | 
					    LotusCustomization: ILotusCustomization;
 | 
				
			||||||
    UseAdultOperatorLoadout?: boolean;
 | 
					    UseAdultOperatorLoadout?: boolean;
 | 
				
			||||||
    DailyAffiliationZariman: number;
 | 
					 | 
				
			||||||
    NemesisAbandonedRewards: string[];
 | 
					    NemesisAbandonedRewards: string[];
 | 
				
			||||||
    DailyAffiliationKahl: number;
 | 
					 | 
				
			||||||
    DailyAffiliationCavia: number;
 | 
					 | 
				
			||||||
    DailyAffiliationHex: number;
 | 
					 | 
				
			||||||
    LastInventorySync: IOid;
 | 
					    LastInventorySync: IOid;
 | 
				
			||||||
    NextRefill: IMongoDate; // Next time argon crystals will have a decay tick
 | 
					    NextRefill: IMongoDate; // Next time argon crystals will have a decay tick
 | 
				
			||||||
    FoundToday?: IMiscItem[]; // for Argon Crystals
 | 
					    FoundToday?: IMiscItem[]; // for Argon Crystals
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user