Feature: reworked calculation of flea price to use the price an item can be sold to a trader for instead of the price a trader sells an item at (!71)

Disable automatic adjustment of items that are below handbook price

Co-authored-by: Dev <dev@noreply.dev.sp-tarkov.com>
Reviewed-on: https://dev.sp-tarkov.com/SPT-AKI/Server/pulls/71
This commit is contained in:
chomp 2023-03-15 19:06:03 +00:00
parent b44f62bb99
commit 4434b95621
3 changed files with 68 additions and 5 deletions

View File

@ -48,7 +48,7 @@
] ]
}, },
"offerAdjustment":{ "offerAdjustment":{
"adjustPriceWhenBelowHandbookPrice": true, "adjustPriceWhenBelowHandbookPrice": false,
"maxPriceDifferenceBelowHandbookPercent": 64, "maxPriceDifferenceBelowHandbookPercent": 64,
"handbookPriceMultipier": 1.1, "handbookPriceMultipier": 1.1,
"priceThreshholdRub": 20000 "priceThreshholdRub": 20000

View File

@ -14,16 +14,20 @@ import { SaveServer } from "../servers/SaveServer";
import { FenceService } from "../services/FenceService"; import { FenceService } from "../services/FenceService";
import { LocalisationService } from "../services/LocalisationService"; import { LocalisationService } from "../services/LocalisationService";
import { PlayerService } from "../services/PlayerService"; import { PlayerService } from "../services/PlayerService";
import { RandomUtil } from "../utils/RandomUtil";
import { TimeUtil } from "../utils/TimeUtil"; import { TimeUtil } from "../utils/TimeUtil";
import { HandbookHelper } from "./HandbookHelper"; import { HandbookHelper } from "./HandbookHelper";
import { ItemHelper } from "./ItemHelper";
import { ProfileHelper } from "./ProfileHelper"; import { ProfileHelper } from "./ProfileHelper";
@injectable() @injectable()
export class TraderHelper export class TraderHelper
{ {
protected traderConfig: ITraderConfig; protected traderConfig: ITraderConfig;
/** Dictionary of item tpl and the highest trader rouble price */ /** Dictionary of item tpl and the highest trader sell rouble price */
protected highestTraderPriceItems: Record<string, number> = null; protected highestTraderPriceItems: Record<string, number> = null;
/** Dictionary of item tpl and the highest trader buy back rouble price */
protected highestTraderBuyPriceItems: Record<string, number> = null;
constructor( constructor(
@inject("WinstonLogger") protected logger: ILogger, @inject("WinstonLogger") protected logger: ILogger,
@ -31,10 +35,12 @@ export class TraderHelper
@inject("SaveServer") protected saveServer: SaveServer, @inject("SaveServer") protected saveServer: SaveServer,
@inject("ProfileHelper") protected profileHelper: ProfileHelper, @inject("ProfileHelper") protected profileHelper: ProfileHelper,
@inject("HandbookHelper") protected handbookHelper: HandbookHelper, @inject("HandbookHelper") protected handbookHelper: HandbookHelper,
@inject("ItemHelper") protected itemHelper: ItemHelper,
@inject("PlayerService") protected playerService: PlayerService, @inject("PlayerService") protected playerService: PlayerService,
@inject("LocalisationService") protected localisationService: LocalisationService, @inject("LocalisationService") protected localisationService: LocalisationService,
@inject("FenceService") protected fenceService: FenceService, @inject("FenceService") protected fenceService: FenceService,
@inject("TimeUtil") protected timeUtil: TimeUtil, @inject("TimeUtil") protected timeUtil: TimeUtil,
@inject("RandomUtil") protected randomUtil: RandomUtil,
@inject("ConfigServer") protected configServer: ConfigServer @inject("ConfigServer") protected configServer: ConfigServer
) )
{ {
@ -266,6 +272,7 @@ export class TraderHelper
/** /**
* Get the highest rouble price for an item from traders * Get the highest rouble price for an item from traders
* UNUSED
* @param tpl Item to look up highest pride for * @param tpl Item to look up highest pride for
* @returns highest rouble cost for item * @returns highest rouble cost for item
*/ */
@ -276,8 +283,12 @@ export class TraderHelper
return this.highestTraderPriceItems[tpl]; return this.highestTraderPriceItems[tpl];
} }
// Init dict and fill if (!this.highestTraderPriceItems)
{
this.highestTraderPriceItems = {}; this.highestTraderPriceItems = {};
}
// Init dict and fill
for (const traderName in Traders) for (const traderName in Traders)
{ {
// Skip some traders // Skip some traders
@ -314,4 +325,56 @@ export class TraderHelper
return this.highestTraderPriceItems[tpl]; return this.highestTraderPriceItems[tpl];
} }
/**
* Get the highest price item can be sold to trader for (roubles)
* @param tpl Item to look up best trader sell-to price
* @returns Rouble price
*/
public getHighestSellToTraderPrice(tpl: string): number
{
// Init dict if doesn't exist
if (!this.highestTraderBuyPriceItems)
{
this.highestTraderBuyPriceItems = {};
}
// Return result if it exists
if (this.highestTraderBuyPriceItems[tpl])
{
return this.highestTraderBuyPriceItems[tpl];
}
// Find highest trader price for item
for (const traderName in Traders)
{
// Get trader and check buy category allows tpl
const traderBase = this.databaseServer.getTables().traders[Traders[traderName]]?.base;
if (traderBase && this.itemHelper.isOfBaseclasses(tpl, traderBase.items_buy.category))
{
// Get loyalty level details player has achieved with this trader
// Uses lowest loyalty level as this function is used before a player has logged into server - we have no idea what player loyalty is with traders
const relevantLoyaltyData = traderBase.loyaltyLevels[0];
const traderBuyBackPricePercent = relevantLoyaltyData.buy_price_coef;
const itemHandbookPrice = this.handbookHelper.getTemplatePrice(tpl);
const priceTraderBuysItemAt = Math.round(this.randomUtil.getPercentOfValue(traderBuyBackPricePercent, itemHandbookPrice));
// Set new item to 1 rouble as default
if (!this.highestTraderBuyPriceItems[tpl])
{
this.highestTraderBuyPriceItems[tpl] = 1;
}
// Existing price smaller in dict than current iteration, overwrite
if (this.highestTraderBuyPriceItems[tpl] < priceTraderBuysItemAt)
{
this.highestTraderBuyPriceItems[tpl] = priceTraderBuysItemAt;
}
}
}
return this.highestTraderBuyPriceItems[tpl];
}
} }

View File

@ -212,7 +212,7 @@ export class RagfairPriceService implements OnLoad
if (this.ragfairConfig.dynamic.useTraderPriceForOffersIfHigher) if (this.ragfairConfig.dynamic.useTraderPriceForOffersIfHigher)
{ {
// Get highest trader price for item, if greater than value found so far, use it // Get highest trader price for item, if greater than value found so far, use it
const traderPrice = this.traderHelper.getHighestTraderPriceRouble(item._tpl); const traderPrice = this.traderHelper.getHighestSellToTraderPrice(item._tpl);
if (traderPrice > itemPrice) if (traderPrice > itemPrice)
{ {
itemPrice = traderPrice; itemPrice = traderPrice;
@ -368,7 +368,7 @@ export class RagfairPriceService implements OnLoad
protected getHighestHandbookOrTraderPriceAsRouble(itemTpl: string): number protected getHighestHandbookOrTraderPriceAsRouble(itemTpl: string): number
{ {
let price = this.getStaticPriceForItem(itemTpl); let price = this.getStaticPriceForItem(itemTpl);
const traderPrice = this.traderHelper.getHighestTraderPriceRouble(itemTpl); const traderPrice = this.traderHelper.getHighestSellToTraderPrice(itemTpl);
if (traderPrice > price) if (traderPrice > price)
{ {
price = traderPrice; price = traderPrice;