0
0
mirror of https://github.com/sp-tarkov/server.git synced 2025-02-13 09:50:43 -05:00

Fixed trader offer prices being rounded to whole int, breaking items that are sold for < 1, e.g. ammo sold for dollars

Clone trader data before we create flea offers with it, prevents contamination due to pass by reference

Moved trader item price modification for `config.traderPriceMultipler` into `onLoad` event of `TraderController`
This commit is contained in:
Chomp 2025-01-06 15:16:22 +00:00
parent abd17c0353
commit fc7b33cd53
2 changed files with 27 additions and 22 deletions

View File

@ -1,4 +1,5 @@
import { FenceBaseAssortGenerator } from "@spt/generators/FenceBaseAssortGenerator";
import { PaymentHelper } from "@spt/helpers/PaymentHelper";
import { ProfileHelper } from "@spt/helpers/ProfileHelper";
import { TraderAssortHelper } from "@spt/helpers/TraderAssortHelper";
import { TraderHelper } from "@spt/helpers/TraderHelper";
@ -8,7 +9,7 @@ import { ConfigTypes } from "@spt/models/enums/ConfigTypes";
import { Money } from "@spt/models/enums/Money";
import { Traders } from "@spt/models/enums/Traders";
import { ITraderConfig } from "@spt/models/spt/config/ITraderConfig";
import { ILogger } from "@spt/models/spt/utils/ILogger";
import type { ILogger } from "@spt/models/spt/utils/ILogger";
import { ConfigServer } from "@spt/servers/ConfigServer";
import { DatabaseService } from "@spt/services/DatabaseService";
import { FenceService } from "@spt/services/FenceService";
@ -16,7 +17,7 @@ import { RagfairPriceService } from "@spt/services/RagfairPriceService";
import { TraderAssortService } from "@spt/services/TraderAssortService";
import { TraderPurchasePersisterService } from "@spt/services/TraderPurchasePersisterService";
import { TimeUtil } from "@spt/utils/TimeUtil";
import { ICloner } from "@spt/utils/cloners/ICloner";
import type { ICloner } from "@spt/utils/cloners/ICloner";
import { inject, injectable } from "tsyringe";
@injectable()
@ -30,6 +31,7 @@ export class TraderController {
@inject("TraderAssortHelper") protected traderAssortHelper: TraderAssortHelper,
@inject("ProfileHelper") protected profileHelper: ProfileHelper,
@inject("TraderHelper") protected traderHelper: TraderHelper,
@inject("PaymentHelper") protected paymentHelper: PaymentHelper,
@inject("TraderAssortService") protected traderAssortService: TraderAssortService,
@inject("RagfairPriceService") protected ragfairPriceService: RagfairPriceService,
@inject("TraderPurchasePersisterService")
@ -65,7 +67,20 @@ export class TraderController {
const trader = traders[traderId];
// Create dict of trader assorts on server start
// Adjust price by traderPriceMultipler config property
if (this.traderConfig.traderPriceMultipler !== 1) {
for (const barterItem of Object.values(trader.assort.barter_scheme)) {
const barterSchemeItem = barterItem[0][0];
if (barterSchemeItem && this.paymentHelper.isMoneyTpl(barterSchemeItem._tpl)) {
barterSchemeItem.count += +(
barterSchemeItem.count * this.traderConfig.traderPriceMultipler
).toFixed(2);
}
}
}
// Create dict of pristine trader assorts on server start
if (!this.traderAssortService.getPristineTraderAssort(traderId)) {
const assortsClone = this.cloner.clone(trader.assort);
this.traderAssortService.setPristineTraderAssort(traderId, assortsClone);

View File

@ -24,7 +24,7 @@ import {
} from "@spt/models/spt/config/IRagfairConfig";
import { ITraderConfig } from "@spt/models/spt/config/ITraderConfig";
import { ITplWithFleaPrice } from "@spt/models/spt/ragfair/ITplWithFleaPrice";
import { ILogger } from "@spt/models/spt/utils/ILogger";
import type { ILogger } from "@spt/models/spt/utils/ILogger";
import { ConfigServer } from "@spt/servers/ConfigServer";
import { SaveServer } from "@spt/servers/SaveServer";
import { DatabaseService } from "@spt/services/DatabaseService";
@ -35,7 +35,7 @@ import { RagfairPriceService } from "@spt/services/RagfairPriceService";
import { HashUtil } from "@spt/utils/HashUtil";
import { RandomUtil } from "@spt/utils/RandomUtil";
import { TimeUtil } from "@spt/utils/TimeUtil";
import { ICloner } from "@spt/utils/cloners/ICloner";
import type { ICloner } from "@spt/utils/cloners/ICloner";
import { inject, injectable } from "tsyringe";
@injectable()
@ -539,10 +539,10 @@ export class RagfairOfferGenerator {
const time = this.timeUtil.getTimestamp();
const trader = this.databaseService.getTrader(traderID);
const assorts = trader.assort;
const assortsClone = this.cloner.clone(trader.assort);
// Trader assorts / assort items are missing
if (!assorts?.items?.length) {
if (!assortsClone?.items?.length) {
this.logger.error(
this.localisationService.getText(
"ragfair-no_trader_assorts_cant_generate_flea_offers",
@ -553,7 +553,7 @@ export class RagfairOfferGenerator {
}
const blacklist = this.ragfairConfig.dynamic.blacklist;
for (const item of assorts.items) {
for (const item of assortsClone.items) {
// We only want to process 'base/root' items, no children
if (item.slotId !== "hideout") {
// skip mod items
@ -577,9 +577,9 @@ export class RagfairOfferGenerator {
const isPreset = this.presetHelper.isPreset(item._id);
const items: IItem[] = isPreset
? this.ragfairServerHelper.getPresetItems(item)
: [...[item], ...this.itemHelper.findAndReturnChildrenByAssort(item._id, assorts.items)];
: [...[item], ...this.itemHelper.findAndReturnChildrenByAssort(item._id, assortsClone.items)];
const barterScheme = assorts.barter_scheme[item._id];
const barterScheme = assortsClone.barter_scheme[item._id];
if (!barterScheme) {
this.logger.warning(
this.localisationService.getText("ragfair-missing_barter_scheme", {
@ -591,18 +591,8 @@ export class RagfairOfferGenerator {
continue;
}
const barterSchemeItems = assorts.barter_scheme[item._id][0];
// Adjust price by traderPriceMultipler config property
if (this.traderConfig.traderPriceMultipler > 0) {
if (barterSchemeItems.length === 1 && this.paymentHelper.isMoneyTpl(barterSchemeItems[0]._tpl)) {
barterSchemeItems[0].count = Math.ceil(
barterSchemeItems[0].count * this.traderConfig.traderPriceMultipler,
);
}
}
const loyalLevel = assorts.loyal_level_items[item._id];
const barterSchemeItems = assortsClone.barter_scheme[item._id][0];
const loyalLevel = assortsClone.loyal_level_items[item._id];
const offer = this.createAndAddFleaOffer(traderID, time, items, barterSchemeItems, loyalLevel, false);