From c7a44456bbc190268f8756d7d4d4edc2f72bc1b5 Mon Sep 17 00:00:00 2001 From: Dev Date: Wed, 25 Sep 2024 17:16:44 +0100 Subject: [PATCH] Added tiered flea system with placeholder values - Allow items to be locked to a specific level - defaults to off Unlocks have a priority order, it will be filtered by whatever is first in the dictionary e.g. pistol: unlock level 20 weapon: unlock level 30 A pistol will be unlocked at level 20, A shotgun will be unlocked at level 30 if the order was different: weapon: unlock level 30 pistol: unlock level 20 The pistol would be unlocked at level 30 as its a weapon and gets picked up by the weapon filter first --- project/assets/configs/ragfair.json | 56 +++++++++++++ project/src/helpers/RagfairOfferHelper.ts | 78 ++++++++++++++++++- .../src/models/spt/config/IRagfairConfig.ts | 8 ++ 3 files changed, 140 insertions(+), 2 deletions(-) diff --git a/project/assets/configs/ragfair.json b/project/assets/configs/ragfair.json index d12b6dcd..ca56418b 100644 --- a/project/assets/configs/ragfair.json +++ b/project/assets/configs/ragfair.json @@ -330,5 +330,61 @@ "newPriceHandbookMultiplier": 11 } } + }, + "tieredFlea": { + "enabled": false, + "unlocks": { + "57864a3d24597754843f8721": 35, + "57864bb7245977548b3b66c2": 35, + "57864a66245977548f04a81f": 25, + "57864ada245977548638de91": 20, + "590c745b86f7743cc433c5f2": 35, + + "5447bedf4bdc2d87278b4568": 50, + "5447bed64bdc2d97278b4568": 40, + "5447b6254bdc2dc3278b4568": 35, + "5447b6194bdc2d67278b4567": 35, + "5447b5f14bdc2d61278b4567": 35, + "5447b5e04bdc2d62278b4567": 20, + "5447b6094bdc2dc3278b4567": 15, + "5447bee84bdc2dc3278b4569": 15, + "617f1ef5e8b54b0998387733": 10, + "5447b5cf4bdc2d65278b4567": 5, + + "55818acf4bdc2dde698b456b": 20, + "55818ad54bdc2ddc698b4569": 23, + "55818add4bdc2d5b648b456f": 25, + "55818ae44bdc2dde698b456c": 30, + "55818aeb4bdc2ddc698b456a": 45, + + "543be5cb4bdc2deb348b4568": 50, + + "5c164d2286f774194c5e69fa": 40, + "5c99f98d86f7745c314214b3": 35 + }, + "ammoTiersEnabled": true, + "ammoTplUnlocks": { + "619636be6db0f2477964e710": 50, + "5fc382c1016cce60e8341b20": 50, + "5efb0cabfb3e451d70735af5": 35, + "64b8ee384b75259c590fa89b": 35, + "5d6e6911a4b9361bd5780d52": 35, + "5e85aa1a988a8701445df1f5": 35, + "6576f93989f0062e741ba952": 25, + + "56dff061d2720bb5668b4567": 45, + "56dff2ced2720bb4668b4567": 40, + + "64b7af434b75259c590fa893": 45, + + "60194943740c5d77f6705eea": 35, + + "5656d7c34bdc2d9d198b4587": 35, + + "5e023e53d4353e3302577c4c": 25, + + "5887431f2459777e1612938f": 30, + "59e77a2386f7742ee578960a": 35 + } } } diff --git a/project/src/helpers/RagfairOfferHelper.ts b/project/src/helpers/RagfairOfferHelper.ts index 65ff19c1..66a69ab4 100644 --- a/project/src/helpers/RagfairOfferHelper.ts +++ b/project/src/helpers/RagfairOfferHelper.ts @@ -15,13 +15,14 @@ import { IItemEventRouterResponse } from "@spt/models/eft/itemEvent/IItemEventRo import { ISptProfile, ISystemData } from "@spt/models/eft/profile/ISptProfile"; import { IRagfairOffer } from "@spt/models/eft/ragfair/IRagfairOffer"; import { ISearchRequestData, OfferOwnerType } from "@spt/models/eft/ragfair/ISearchRequestData"; +import { BaseClasses } from "@spt/models/enums/BaseClasses"; import { ConfigTypes } from "@spt/models/enums/ConfigTypes"; import { MemberCategory } from "@spt/models/enums/MemberCategory"; import { MessageType } from "@spt/models/enums/MessageType"; import { RagfairSort } from "@spt/models/enums/RagfairSort"; import { Traders } from "@spt/models/enums/Traders"; import { IQuestConfig } from "@spt/models/spt/config/IQuestConfig"; -import { IRagfairConfig } from "@spt/models/spt/config/IRagfairConfig"; +import { IRagfairConfig, ITieredFlea } from "@spt/models/spt/config/IRagfairConfig"; import { ILogger } from "@spt/models/spt/utils/ILogger"; import { EventOutputHolder } from "@spt/routers/EventOutputHolder"; import { ConfigServer } from "@spt/servers/ConfigServer"; @@ -85,12 +86,14 @@ export class RagfairOfferHelper { pmcData: IPmcData, ): IRagfairOffer[] { const playerIsFleaBanned = this.profileHelper.playerIsFleaBanned(pmcData); + const tieredFlea = this.ragfairConfig.tieredFlea; + const tieredFleaLimitTypes = Object.keys(tieredFlea.unlocks); return this.ragfairOfferService.getOffers().filter((offer) => { if (!this.passesSearchFilterCriteria(searchRequest, offer, pmcData)) { return false; } - return this.isDisplayableOffer( + const isDisplayable = this.isDisplayableOffer( searchRequest, itemsToAdd, traderAssorts, @@ -98,9 +101,53 @@ export class RagfairOfferHelper { pmcData, playerIsFleaBanned, ); + + if (!isDisplayable) { + return false; + } + + // Not trader offer + tiered flea enabled + if (tieredFlea.enabled && offer.user.memberType !== MemberCategory.TRADER) { + if ( + this.offerIsHiddenFromPlayerTieredFlea(tieredFlea, offer, tieredFleaLimitTypes, pmcData.Info.Level) + ) { + return false; + } + } + + return true; }); } + protected offerIsHiddenFromPlayerTieredFlea( + tieredFlea: ITieredFlea, + offer: IRagfairOffer, + tieredFleaLimitTypes: string[], + playerLevel: number, + ): boolean { + if (tieredFlea.ammoTplUnlocks && this.itemHelper.isOfBaseclass(offer.items[0]._tpl, BaseClasses.AMMO)) { + const unlockLevel = tieredFlea.ammoTplUnlocks[offer.items[0]._tpl]; + if (unlockLevel && playerLevel < unlockLevel) { + return true; + } + } + // Optimisation - Ensure the item has at least one of the limited base types + else if (this.itemHelper.isOfBaseclasses(offer.items[0]._tpl, tieredFleaLimitTypes)) { + // Loop over all flea types to find the matching one + for (const tieredItemType of tieredFleaLimitTypes) { + if (this.itemHelper.isOfBaseclass(offer.items[0]._tpl, tieredItemType)) { + if (playerLevel < tieredFlea.unlocks[tieredItemType]) { + return true; + } + + break; + } + } + } + + return false; + } + /** * Get matching offers that require the desired item and filter out offers from non traders if player is below ragfair unlock level * @param searchRequest Search request from client @@ -110,11 +157,22 @@ export class RagfairOfferHelper { public getOffersThatRequireItem(searchRequest: ISearchRequestData, pmcData: IPmcData): IRagfairOffer[] { // Get all offers that requre the desired item and filter out offers from non traders if player below ragifar unlock const requiredOffers = this.ragfairRequiredItemsService.getRequiredItemsById(searchRequest.neededSearchId); + const tieredFlea = this.ragfairConfig.tieredFlea; + const tieredFleaLimitTypes = Object.keys(tieredFlea.unlocks); + return requiredOffers.filter((offer: IRagfairOffer) => { if (!this.passesSearchFilterCriteria(searchRequest, offer, pmcData)) { return false; } + if (tieredFlea.enabled && offer.user.memberType !== MemberCategory.TRADER) { + if ( + this.offerIsHiddenFromPlayerTieredFlea(tieredFlea, offer, tieredFleaLimitTypes, pmcData.Info.Level) + ) { + return false; + } + } + return true; }); } @@ -136,6 +194,9 @@ export class RagfairOfferHelper { const offersMap = new Map(); const offers: IRagfairOffer[] = []; const playerIsFleaBanned = this.profileHelper.playerIsFleaBanned(pmcData); + const tieredFlea = this.ragfairConfig.tieredFlea; + const tieredFleaLimitTypes = Object.keys(tieredFlea.unlocks); + for (const offer of this.ragfairOfferService.getOffers()) { if (!this.passesSearchFilterCriteria(searchRequest, offer, pmcData)) { continue; @@ -160,6 +221,19 @@ export class RagfairOfferHelper { continue; } + if (tieredFlea.enabled && offer.user.memberType !== MemberCategory.TRADER) { + if ( + this.offerIsHiddenFromPlayerTieredFlea( + tieredFlea, + offer, + tieredFleaLimitTypes, + pmcData.Info.Level, + ) + ) { + continue; + } + } + const key = offer.items[0]._tpl; if (!offersMap.has(key)) { offersMap.set(key, []); diff --git a/project/src/models/spt/config/IRagfairConfig.ts b/project/src/models/spt/config/IRagfairConfig.ts index 62fc47a1..5d3ce3e2 100644 --- a/project/src/models/spt/config/IRagfairConfig.ts +++ b/project/src/models/spt/config/IRagfairConfig.ts @@ -12,6 +12,7 @@ export interface IRagfairConfig extends IBaseConfig { /** Trader ids + should their assorts be listed on flea */ traders: Record; dynamic: Dynamic; + tieredFlea: ITieredFlea; } export interface Sell { @@ -170,3 +171,10 @@ export interface IArmorSettings { /** What slots are to be removed when removeRemovablePlateChance is true */ plateSlotIdToRemovePool: string[]; } + +export interface ITieredFlea { + enabled: boolean; + unlocks: Record; + ammoTiersEnabled: boolean; + ammoTplUnlocks: Record; +}