using SptCommon.Annotations; using Core.Helpers; using Core.Models.Eft.Common; using Core.Models.Eft.Common.Tables; using Core.Models.Eft.ItemEvent; using Core.Models.Eft.Ragfair; using Core.Models.Eft.Trade; using Core.Models.Enums; using Core.Models.Spt.Config; using Core.Models.Utils; using Core.Routers; using Core.Servers; using Core.Services; using Core.Utils; namespace Core.Controllers; [Injectable] public class TradeController( ISptLogger _logger, DatabaseService _databaseService, EventOutputHolder _eventOutputHolder, TradeHelper _tradeHelper, TimeUtil _timeUtil, HashUtil _hashUtil, ItemHelper _itemHelper, ProfileHelper _profileHelper, RagfairOfferHelper _ragfairOfferHelper, TraderHelper _traderHelper, RagfairServer _ragfairServer, HttpResponseUtil _httpResponseUtil, LocalisationService _localisationService, RagfairPriceService _ragfairPriceService, ConfigServer _configServer ) { protected RagfairConfig _ragfairConfig = _configServer.GetConfig(); protected TraderConfig _traderConfig = _configServer.GetConfig(); /// /// Handle TradingConfirm event /// /// /// /// /// public ItemEventRouterResponse ConfirmTrading( PmcData pmcData, ProcessBaseTradeRequestData request, string sessionID) { var output = _eventOutputHolder.GetOutput(sessionID); // Buying if (request.Type == "buy_from_trader") { var foundInRaid = _traderConfig.PurchasesAreFoundInRaid; ProcessBuyTradeRequestData buyData = (ProcessBuyTradeRequestData)request; _tradeHelper.buyItem(pmcData, buyData, sessionID, foundInRaid, output); return output; } // Selling if (request.Type == "sell_to_trader") { ProcessSellTradeRequestData sellData = (ProcessSellTradeRequestData)request; _tradeHelper.sellItem(pmcData, pmcData, sellData, sessionID, output); return output; } var errorMessage = $"Unhandled trade event: {request.Type}"; _logger.Error(errorMessage); return _httpResponseUtil.AppendErrorToOutput(output, errorMessage, BackendErrorCodes.RagfairUnavailable); } /// /// Handle RagFairBuyOffer event /// /// /// /// /// public ItemEventRouterResponse ConfirmRagfairTrading( PmcData pmcData, ProcessRagfairTradeRequestData request, string sessionID) { var output = _eventOutputHolder.GetOutput(sessionID); foreach (var offer in request.Offers) { var fleaOffer = _ragfairServer.GetOffer(offer.Id); if (fleaOffer is null) { return _httpResponseUtil.AppendErrorToOutput( output, $"Offer with ID {offer.Id} not found", BackendErrorCodes.OfferNotFound ); } if (offer.Count == 0) { var errorMessage = _localisationService.GetText( "ragfair-unable_to_purchase_0_count_item", _itemHelper.GetItem(fleaOffer.Items[0].Template).Value.Name ); return _httpResponseUtil.AppendErrorToOutput(output, errorMessage, BackendErrorCodes.OfferOutOfStock); } if (_ragfairOfferHelper.OfferIsFromTrader(fleaOffer)) { BuyTraderItemFromRagfair(sessionID, pmcData, fleaOffer, offer, output); } else { BuyPmcItemFromRagfair(sessionID, pmcData, fleaOffer, offer, output); } // Exit loop early if problem found if (output.Warnings.Count > 0) { return output; } } return output; } /// /// Buy an item off the flea sold by a trader /// /// Session id /// Player profile /// Offer being purchased /// request data from client /// Output to send back to client private void BuyTraderItemFromRagfair( string sessionId, PmcData pmcData, RagfairOffer fleaOffer, OfferRequest requestOffer, ItemEventRouterResponse output) { // Skip buying items when player doesn't have needed loyalty if (PlayerLacksTraderLoyaltyLevelToBuyOffer(fleaOffer, pmcData)) { var errorMessage = $"Unable to buy item: {fleaOffer.Items[0].Template} from trader: {fleaOffer.User.Id} as loyalty level too low, skipping"; _logger.Debug(errorMessage); _httpResponseUtil.AppendErrorToOutput(output, errorMessage, BackendErrorCodes.RagfairUnavailable); return; } ProcessBuyTradeRequestData buyData = new ProcessBuyTradeRequestData { Action = "TradingConfirm", Type = "buy_from_ragfair", TransactionId = fleaOffer.User.Id, ItemId = fleaOffer.Root, Count = requestOffer.Count, SchemeId = 0, SchemeItems = requestOffer.Items, }; _tradeHelper.buyItem(pmcData, buyData, sessionId, _traderConfig.PurchasesAreFoundInRaid, output); } /// /// Buy an item off the flea sold by a PMC /// /// Session id /// Player profile /// Offer being purchased /// request data from client /// Output to send back to client private void BuyPmcItemFromRagfair( string sessionId, PmcData pmcData, RagfairOffer fleaOffer, OfferRequest offerRequest, ItemEventRouterResponse output) { throw new NotImplementedException(); } /// /// Is the provided offerid and ownerid from a player made offer /// /// id of the offer /// Owner id /// true if offer was made by a player private bool IsPlayerOffer( string offerId, string offerOwnerId) { throw new NotImplementedException(); } /// /// Does Player have necessary trader loyalty to purchase flea offer /// /// Flea offer being bought /// Player profile /// True if player can buy offer private bool PlayerLacksTraderLoyaltyLevelToBuyOffer( RagfairOffer fleaOffer, PmcData pmcData) { throw new NotImplementedException(); } /// /// Handle SellAllFromSavage event /// /// /// /// /// public ItemEventRouterResponse SellScavItemsToFence( PmcData pmcData, SellScavItemsToFenceRequestData request, string sessionId) { throw new NotImplementedException(); } /// /// Send the specified rouble total to player as mail /// /// Session id /// amount of roubles to send /// Trader to sell items to private void MailMoneyToPlayer( string sessionId, int roublesToSend, string trader) { throw new NotImplementedException(); } /// /// Looks up an items children and gets total handbook price for them /// /// parent item that has children we want to sum price of /// All items (parent + children) /// Prices of items from handbook /// Trader being sold to, to perform buy category check against /// Rouble price private int GetPriceOfItemAndChildren( string parentItemId, List items, Dictionary handbookPrices, TraderBase traderDetails) { throw new NotImplementedException(); } }