diff --git a/project/src/controllers/GameController.ts b/project/src/controllers/GameController.ts index 67fea823..66d71317 100644 --- a/project/src/controllers/GameController.ts +++ b/project/src/controllers/GameController.ts @@ -186,9 +186,9 @@ export class GameController { fullProfile.characters.scav.WishList = {}; } - const pmcProfile = fullProfile.characters.pmc; + this.logger.debug(`Started game with sessionId: ${sessionID} ${fullProfile.info.username}`); - this.logger.debug(`Started game with sessionId: ${sessionID} ${pmcProfile.Info?.Nickname}`); + const pmcProfile = fullProfile.characters.pmc; if (this.coreConfig.fixes.fixProfileBreakingInventoryItemIssues) { this.profileFixerService.fixProfileBreakingInventoryItemIssues(pmcProfile); diff --git a/project/src/helpers/TradeHelper.ts b/project/src/helpers/TradeHelper.ts index c7c3ba82..fe4add66 100644 --- a/project/src/helpers/TradeHelper.ts +++ b/project/src/helpers/TradeHelper.ts @@ -10,6 +10,7 @@ import { IProcessBuyTradeRequestData } from "@spt/models/eft/trade/IProcessBuyTr import { IProcessSellTradeRequestData } from "@spt/models/eft/trade/IProcessSellTradeRequestData"; import { BackendErrorCodes } from "@spt/models/enums/BackendErrorCodes"; import { ConfigTypes } from "@spt/models/enums/ConfigTypes"; +import { QuestStatus } from "@spt/models/enums/QuestStatus"; import { Traders } from "@spt/models/enums/Traders"; import { IInventoryConfig } from "@spt/models/spt/config/IInventoryConfig"; import { ITraderConfig } from "@spt/models/spt/config/ITraderConfig"; @@ -17,6 +18,7 @@ import { ILogger } from "@spt/models/spt/utils/ILogger"; import { EventOutputHolder } from "@spt/routers/EventOutputHolder"; import { ConfigServer } from "@spt/servers/ConfigServer"; import { RagfairServer } from "@spt/servers/RagfairServer"; +import { DatabaseService } from "@spt/services/DatabaseService"; import { FenceService } from "@spt/services/FenceService"; import { LocalisationService } from "@spt/services/LocalisationService"; import { PaymentService } from "@spt/services/PaymentService"; @@ -32,6 +34,7 @@ export class TradeHelper { constructor( @inject("PrimaryLogger") protected logger: ILogger, + @inject("DatabaseService") protected databaseService: DatabaseService, @inject("EventOutputHolder") protected eventOutputHolder: EventOutputHolder, @inject("TraderHelper") protected traderHelper: TraderHelper, @inject("ItemHelper") protected itemHelper: ItemHelper, @@ -241,6 +244,14 @@ export class TradeHelper { sessionID: string, output: IItemEventRouterResponse, ): void { + // TODO - make more generic to support all quests that have this condition type + // Try to reduce perf hit as this is expensive to do every sale + // MUST OCCUR PRIOR TO ITEMS BEING REMOVED FROM INVENTORY + if (sellRequest.tid === Traders.RAGMAN) { + // Edge case, `Circulate` quest needs to track when certain items are sold to him + this.incrementCirculateSoldToTraderCounter(profileWithItemsToSell, profileToReceiveMoney, sellRequest); + } + // Find item in inventory and remove it for (const itemToBeRemoved of sellRequest.items) { const itemIdToFind = itemToBeRemoved.id.replace(/\s+/g, ""); // Strip out whitespace @@ -265,7 +276,7 @@ export class TradeHelper { ); } - // Also removes children + // Remove item from inventory + any child items it has this.inventoryHelper.removeItem(profileWithItemsToSell, itemToBeRemoved.id, sessionID, output); } @@ -273,6 +284,75 @@ export class TradeHelper { this.paymentService.giveProfileMoney(profileToReceiveMoney, sellRequest.price, sellRequest, output, sessionID); } + protected incrementCirculateSoldToTraderCounter( + profileWithItemsToSell: IPmcData, + profileToReceiveMoney: IPmcData, + sellRequest: IProcessSellTradeRequestData, + ) { + const circulateQuestId = "6663149f1d3ec95634095e75"; + const activeCirculateQuest = profileToReceiveMoney.Quests.find( + (quest) => quest.qid === circulateQuestId && quest.status === QuestStatus.Started, + ); + + // Player not on Circulate quest ,exit + if (!activeCirculateQuest) { + return; + } + + // Find related task condition + const taskCondition = Object.values(profileToReceiveMoney.TaskConditionCounters).find( + (condition) => condition.sourceId === circulateQuestId && condition.type === "SellItemToTrader", + ); + + // No relevant condtion in profile, nothing to increment + if (!taskCondition) { + this.logger.error("Unable to find `sellToTrader` task counter for Circulate quest in profile, skipping"); + + return; + } + + // Condition exists in profile + const circulateQuestDb = this.databaseService.getQuests()[circulateQuestId]; + if (!circulateQuestDb) { + this.logger.error(`Unable to find quest: ${circulateQuestId} in db, skipping`); + + return; + } + + // Get sellToTrader condition from quest + const sellItemToTraderCondition = circulateQuestDb.conditions.AvailableForFinish.find( + (condition) => condition.conditionType === "SellItemToTrader", + ); + + // Quest doesnt have a sellItemToTrader condition, nothing to do + if (!sellItemToTraderCondition) { + this.logger.error("Unable to find `sellToTrader` counter for Circulate quest in db, skipping"); + + return; + } + + // Iterate over items sold to trader + const itemsTplsThatIncrement = sellItemToTraderCondition.target; + for (const itemSoldToTrader of sellRequest.items) { + // Get sold items' details from profile + const itemDetails = profileWithItemsToSell.Inventory.items.find( + (inventoryItem) => inventoryItem._id === itemSoldToTrader.id, + ); + if (!itemDetails) { + this.logger.error( + `Unable to find item in inventory to sell to trader with id: ${itemSoldToTrader.id}, cannot increment counter, skipping`, + ); + + continue; + } + + // Is sold item on the increment list + if (itemsTplsThatIncrement.includes(itemDetails._tpl)) { + taskCondition.value += itemSoldToTrader.count; + } + } + } + /** * Traders allow a limited number of purchases per refresh cycle (default 60 mins) * @param sessionId Session id