Implemented RagfairOfferHelper
This commit is contained in:
@@ -1,15 +1,28 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.Json.Serialization;
|
||||
using Core.Helpers;
|
||||
using SptCommon.Annotations;
|
||||
using Core.Models.Common;
|
||||
using Core.Models.Eft.Common;
|
||||
using Core.Models.Eft.Common.Tables;
|
||||
using Core.Models.Enums;
|
||||
using Core.Models.Spt.Config;
|
||||
using Core.Models.Spt.Services;
|
||||
using Core.Models.Utils;
|
||||
using Core.Services;
|
||||
using Core.Utils;
|
||||
|
||||
namespace Core.Generators;
|
||||
|
||||
[Injectable]
|
||||
public class LootGenerator(
|
||||
ISptLogger<LootGenerator> _logger,
|
||||
RandomUtil _randomUtil,
|
||||
HashUtil _hashUtil,
|
||||
ItemHelper _itemHelper,
|
||||
PresetHelper _presetHelper,
|
||||
DatabaseService _databaseService,
|
||||
ItemFilterService _itemFilterService
|
||||
|
||||
)
|
||||
{
|
||||
|
||||
@@ -20,7 +33,105 @@ public class LootGenerator(
|
||||
/// <returns>An array of loot items</returns>
|
||||
public List<Item> CreateRandomLoot(LootRequest options)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
var result = new List<Item>();
|
||||
var itemTypeCounts = InitItemLimitCounter(options.ItemLimits);
|
||||
|
||||
// Handle sealed weapon containers
|
||||
var sealedWeaponCrateCount = _randomUtil.GetDouble(
|
||||
options.WeaponCrateCount.Min.Value,
|
||||
options.WeaponCrateCount.Max.Value);
|
||||
if (sealedWeaponCrateCount > 0) {
|
||||
// Get list of all sealed containers from db - they're all the same, just for flavor
|
||||
var itemsDb = _itemHelper.GetItems();
|
||||
var sealedWeaponContainerPool = (itemsDb).Where((item) =>
|
||||
item.Name.Contains("event_container_airdrop"));
|
||||
|
||||
for (var index = 0; index < sealedWeaponCrateCount; index++) {
|
||||
// Choose one at random + add to results array
|
||||
var chosenSealedContainer = _randomUtil.GetArrayValue(sealedWeaponContainerPool);
|
||||
result.Add( new Item{
|
||||
Id = _hashUtil.Generate(),
|
||||
Template = chosenSealedContainer.Id,
|
||||
Upd = new Upd{
|
||||
StackObjectsCount = 1,
|
||||
SpawnedInSession = true
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Get items from items.json that have a type of item + not in global blacklist + base type is in whitelist
|
||||
var rewardPoolResults = GetItemRewardPool(
|
||||
options.ItemBlacklist,
|
||||
options.ItemTypeWhitelist,
|
||||
options.UseRewardItemBlacklist.GetValueOrDefault(false),
|
||||
options.AllowBossItems.GetValueOrDefault(false));
|
||||
|
||||
// Pool has items we could add as loot, proceed
|
||||
if (rewardPoolResults.ItemPool.Count > 0) {
|
||||
var randomisedItemCount = _randomUtil.GetDouble(options.ItemCount.Min.Value, options.ItemCount.Max.Value);
|
||||
for (var index = 0; index < randomisedItemCount; index++) {
|
||||
if (!FindAndAddRandomItemToLoot(rewardPoolResults.ItemPool, itemTypeCounts, options, result)) {
|
||||
// Failed to add, reduce index so we get another attempt
|
||||
index--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var globalDefaultPresets = _presetHelper.GetDefaultPresets().Values;
|
||||
|
||||
// Filter default presets to just weapons
|
||||
var randomisedWeaponPresetCount = _randomUtil.GetDouble(
|
||||
options.WeaponPresetCount.Min.Value,
|
||||
options.WeaponPresetCount.Max.Value);
|
||||
if (randomisedWeaponPresetCount > 0) {
|
||||
var weaponDefaultPresets = globalDefaultPresets.Where((preset) =>
|
||||
_itemHelper.IsOfBaseclass(preset.Encyclopedia, BaseClasses.WEAPON)).ToList();
|
||||
|
||||
if (weaponDefaultPresets.Any()) {
|
||||
for (var index = 0; index < randomisedWeaponPresetCount; index++) {
|
||||
if (
|
||||
!FindAndAddRandomPresetToLoot(
|
||||
weaponDefaultPresets,
|
||||
itemTypeCounts,
|
||||
rewardPoolResults.Blacklist,
|
||||
result)
|
||||
) {
|
||||
// Failed to add, reduce index so we get another attempt
|
||||
index--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Filter default presets to just armors and then filter again by protection level
|
||||
var randomisedArmorPresetCount = _randomUtil.GetDouble(
|
||||
options.ArmorPresetCount.Min.Value,
|
||||
options.ArmorPresetCount.Max.Value);
|
||||
if (randomisedArmorPresetCount > 0) {
|
||||
var armorDefaultPresets = globalDefaultPresets.Where((preset) =>
|
||||
_itemHelper.ArmorItemCanHoldMods(preset.Encyclopedia));
|
||||
var levelFilteredArmorPresets = armorDefaultPresets.Where((armor) =>
|
||||
IsArmorOfDesiredProtectionLevel(armor, options)).ToList();
|
||||
|
||||
// Add some armors to rewards
|
||||
if (levelFilteredArmorPresets.Any()) {
|
||||
for (var index = 0; index < randomisedArmorPresetCount; index++) {
|
||||
if (
|
||||
!FindAndAddRandomPresetToLoot(
|
||||
levelFilteredArmorPresets,
|
||||
itemTypeCounts,
|
||||
rewardPoolResults.Blacklist,
|
||||
result)
|
||||
) {
|
||||
// Failed to add, reduce index so we get another attempt
|
||||
index--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -31,7 +142,29 @@ public class LootGenerator(
|
||||
/// <returns>Array of Item</returns>
|
||||
public List<Item> CreateForcedLoot(Dictionary<string, MinMax> forcedLootDict)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
var result = new List<Item>();
|
||||
|
||||
var forcedItems = forcedLootDict;
|
||||
|
||||
foreach (var forcedItemKvP in forcedItems) {
|
||||
var details = forcedLootDict[forcedItemKvP.Key];
|
||||
var randomisedItemCount = _randomUtil.GetDouble(details.Min.Value, details.Max.Value);
|
||||
|
||||
// Add forced loot item to result
|
||||
var newLootItem = new Item{
|
||||
Id = _hashUtil.Generate(),
|
||||
Template = forcedItemKvP.Key,
|
||||
Upd = new Upd{
|
||||
StackObjectsCount = randomisedItemCount,
|
||||
SpawnedInSession = true,
|
||||
},
|
||||
};
|
||||
|
||||
var splitResults = _itemHelper.SplitStack(newLootItem);
|
||||
result.AddRange(splitResults);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -42,22 +175,78 @@ public class LootGenerator(
|
||||
/// <param name="useRewardItemBlacklist">Should item.json reward item config be used</param>
|
||||
/// <param name="allowBossItems">Should boss items be allowed in result</param>
|
||||
/// <returns>results of filtering + blacklist used</returns>
|
||||
protected object GetItemRewardPool(List<string> itemTplBlacklist, List<string> itemTypeWhitelist,
|
||||
bool useRewardItemBlacklist, // TODO: type fuckery, return type was { itemPool: [string, ITemplateItem][]; blacklist: Set<string> }
|
||||
protected ItemRewardPoolResults GetItemRewardPool(List<string> itemTplBlacklist, List<string> itemTypeWhitelist,
|
||||
bool useRewardItemBlacklist,
|
||||
bool allowBossItems)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
var itemsDb = _databaseService.GetItems().Values;
|
||||
var itemBlacklist = new HashSet<string>();
|
||||
itemBlacklist.UnionWith(_itemFilterService.GetBlacklistedItems());
|
||||
itemBlacklist.UnionWith(itemTplBlacklist);
|
||||
|
||||
if (useRewardItemBlacklist)
|
||||
{
|
||||
var itemsToAdd = _itemFilterService.GetItemRewardBlacklist();
|
||||
|
||||
// Get all items that match the blacklisted types and fold into item blacklist
|
||||
var itemTypeBlacklist = _itemFilterService.GetItemRewardBaseTypeBlacklist();
|
||||
var itemsMatchingTypeBlacklist = (itemsDb)
|
||||
.Where((templateItem) => _itemHelper.IsOfBaseclasses(templateItem.Parent, itemTypeBlacklist))
|
||||
.Select((templateItem) => templateItem.Id);
|
||||
|
||||
// Clear out blacklist
|
||||
itemBlacklist = [];
|
||||
itemBlacklist.UnionWith(itemBlacklist);
|
||||
itemBlacklist.UnionWith(itemsToAdd);
|
||||
itemBlacklist.UnionWith(itemsMatchingTypeBlacklist);
|
||||
}
|
||||
|
||||
if (!allowBossItems)
|
||||
{
|
||||
foreach (var bossItem in _itemFilterService.GetBossItems()) {
|
||||
itemBlacklist.Add(bossItem);
|
||||
}
|
||||
}
|
||||
|
||||
var items = itemsDb.Where(
|
||||
(item) =>
|
||||
!itemBlacklist.Contains(item.Id) &&
|
||||
item.Type.ToLower() == "item" &&
|
||||
!item.Properties.QuestItem.GetValueOrDefault(false) &&
|
||||
itemTypeWhitelist.Contains(item.Parent)).ToList();
|
||||
|
||||
return new ItemRewardPoolResults{ ItemPool = items, Blacklist = itemBlacklist };
|
||||
}
|
||||
|
||||
public record ItemRewardPoolResults
|
||||
{
|
||||
public List<TemplateItem> ItemPool { get; set; }
|
||||
public HashSet<string> Blacklist { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Filter armor items by their front plates protection level - top if its a helmet
|
||||
/// Filter armor items by their front plates protection level - top if it's a helmet
|
||||
/// </summary>
|
||||
/// <param name="armor">Armor preset to check</param>
|
||||
/// <param name="options">Loot request options - armor level etc</param>
|
||||
/// <returns>True if item has desired armor level</returns>
|
||||
protected bool ArmorOfDesiredProtectionLevel(Preset armor, LootRequest options)
|
||||
protected bool IsArmorOfDesiredProtectionLevel(Preset armor, LootRequest options)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
string[] relevantSlots = ["front_plate", "helmet_top", "soft_armor_front"];
|
||||
foreach (var slotId in relevantSlots) {
|
||||
var armorItem = armor.Items.FirstOrDefault((item) => item?.SlotId?.ToLower() == slotId);
|
||||
if (armorItem is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var armorDetails = _itemHelper.GetItem(armorItem.Template).Value;
|
||||
var armorClass = armorDetails.Properties.ArmorClass;
|
||||
|
||||
return options.ArmorLevelWhitelist.Contains((int)armorClass.Value);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -65,7 +254,7 @@ public class LootGenerator(
|
||||
/// </summary>
|
||||
/// <param name="limits">limits as defined in config</param>
|
||||
/// <returns>record, key: item tplId, value: current/max item count allowed</returns>
|
||||
protected Dictionary<string, ItemLimit> InitItemLimitCounter(Dictionary<string, int> limits)
|
||||
protected Dictionary<string, ItemLimit> InitItemLimitCounter(Dictionary<string, double> limits)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
@@ -104,8 +293,9 @@ public class LootGenerator(
|
||||
/// <param name="itemBlacklist">Items to skip</param>
|
||||
/// <param name="result">List to add chosen preset to</param>
|
||||
/// <returns>true if preset was valid and added to pool</returns>
|
||||
protected bool FindAndAddRandomPresetToLoot(List<Preset> presetPool, object itemTypeCounts,
|
||||
List<string> itemBlacklist, // TODO: type fuckery, itemTypeCounts was Record<string, { current: number; max: number }>
|
||||
protected bool FindAndAddRandomPresetToLoot(List<Preset> presetPool,
|
||||
Dictionary<string, ItemLimit> itemTypeCounts,
|
||||
HashSet<string> itemBlacklist,
|
||||
List<Item> result)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
|
||||
@@ -25,7 +25,7 @@ public class NotifierHelper(HttpServerHelper _httpServerHelper)
|
||||
EventIdentifier = dialogueMessage.Id,
|
||||
OfferId = ragfairData.OfferId,
|
||||
HandbookId = ragfairData.HandbookId,
|
||||
Count = ragfairData.Count
|
||||
Count = (int)ragfairData.Count
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
using Core.Models.Eft.Common;
|
||||
using Core.Models.Eft.Common.Tables;
|
||||
using Core.Models.Eft.Hideout;
|
||||
using Core.Models.Eft.ItemEvent;
|
||||
using Core.Models.Eft.Player;
|
||||
using Core.Models.Eft.Profile;
|
||||
using Core.Models.Eft.Ragfair;
|
||||
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;
|
||||
@@ -18,16 +21,21 @@ namespace Core.Helpers;
|
||||
public class RagfairOfferHelper(
|
||||
ISptLogger<RagfairOfferHelper> _logger,
|
||||
TimeUtil _timeUtil,
|
||||
HashUtil _hashUtil,
|
||||
RagfairSortHelper _ragfairSortHelper,
|
||||
PresetHelper _presetHelper,
|
||||
RagfairHelper _ragfairHelper,
|
||||
PaymentHelper _paymentHelper,
|
||||
TraderHelper _traderHelper,
|
||||
QuestHelper _questHelper,
|
||||
RagfairServerHelper _ragfairServerHelper,
|
||||
ItemHelper _itemHelper,
|
||||
DatabaseService _databaseService,
|
||||
RagfairOfferService _ragfairOfferService,
|
||||
MailSendService _mailSendService,
|
||||
RagfairRequiredItemsService _ragfairRequiredItemsService,
|
||||
ProfileHelper _profileHelper,
|
||||
EventOutputHolder _eventOutputHolder,
|
||||
ConfigServer _configServer)
|
||||
{
|
||||
protected RagfairConfig _ragfairConfig = _configServer.GetConfig<RagfairConfig>();
|
||||
@@ -687,9 +695,75 @@ public class RagfairOfferHelper(
|
||||
* @param boughtAmount Amount item was purchased for
|
||||
* @returns ItemEventRouterResponse
|
||||
*/
|
||||
public ItemEventRouterResponse CompleteOffer(string sessionID, RagfairOffer offer, int boughtAmount)
|
||||
public ItemEventRouterResponse CompleteOffer(string offerOwnerSessionId, RagfairOffer offer, int boughtAmount)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
var itemTpl = offer.Items[0].Template;
|
||||
var paymentItemsToSendToPlayer = new List<Item>();
|
||||
var offerStackCount = offer.Items[0].Upd.StackObjectsCount;
|
||||
var sellerProfile = _profileHelper.GetPmcProfile(offerOwnerSessionId);
|
||||
|
||||
// Pack or ALL items of a multi-offer were bought - remove entire ofer
|
||||
if (offer.SellInOnePiece.GetValueOrDefault(false) || boughtAmount == offerStackCount)
|
||||
{
|
||||
DeleteOfferById(offerOwnerSessionId, offer.Id);
|
||||
}
|
||||
else
|
||||
{
|
||||
var offerRootItem = offer.Items[0];
|
||||
|
||||
// Reduce offer root items stack count
|
||||
offerRootItem.Upd.StackObjectsCount -= boughtAmount;
|
||||
}
|
||||
|
||||
// Assemble payment to send to seller now offer was purchased
|
||||
foreach (var requirement in offer.Requirements) {
|
||||
// Create an item template item
|
||||
var requestedItem = new Item{
|
||||
Id = _hashUtil.Generate(),
|
||||
Template = requirement.Template,
|
||||
Upd = new Upd{ StackObjectsCount = requirement.Count * boughtAmount },
|
||||
};
|
||||
|
||||
var stacks = _itemHelper.SplitStack(requestedItem);
|
||||
foreach (var item in stacks) {
|
||||
var outItems = new List<Item> { item };
|
||||
|
||||
// TODO - is this code used?, may have been when adding barters to flea was still possible for player
|
||||
if (requirement.OnlyFunctional.GetValueOrDefault(false))
|
||||
{
|
||||
var presetItems = _ragfairServerHelper.GetPresetItemsByTpl(item);
|
||||
if (presetItems.Count > 0)
|
||||
{
|
||||
outItems.Add(presetItems[0]);
|
||||
}
|
||||
}
|
||||
|
||||
paymentItemsToSendToPlayer.AddRange(outItems);
|
||||
}
|
||||
}
|
||||
|
||||
var ragfairDetails = new MessageContentRagfair{
|
||||
OfferId = offer.Id,
|
||||
// pack-offers NEED to be the full item count,
|
||||
// otherwise it only removes 1 from the pack, leaving phantom offer on client ui
|
||||
Count = offer.SellInOnePiece.GetValueOrDefault(false) ? offerStackCount.Value : boughtAmount,
|
||||
HandbookId = itemTpl };
|
||||
|
||||
_mailSendService.SendDirectNpcMessageToPlayer(
|
||||
offerOwnerSessionId,
|
||||
_traderHelper.GetTraderById(Traders.RAGMAN).ToString(),
|
||||
MessageType.FLEAMARKET_MESSAGE,
|
||||
GetLocalisedOfferSoldMessage(itemTpl, boughtAmount),
|
||||
paymentItemsToSendToPlayer,
|
||||
_timeUtil.GetHoursAsSeconds((int)_questHelper.GetMailItemRedeemTimeHoursForProfile(sellerProfile).Value),
|
||||
null,
|
||||
ragfairDetails);
|
||||
|
||||
// Adjust sellers sell sum values
|
||||
sellerProfile.RagfairInfo.SellSum ??= 0;
|
||||
sellerProfile.RagfairInfo.SellSum += offer.SummaryCost;
|
||||
|
||||
return _eventOutputHolder.GetOutput(offerOwnerSessionId);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Core.Models.Eft.Profile;
|
||||
|
||||
@@ -8,7 +8,7 @@ public record MessageContentRagfair
|
||||
public string? OfferId { get; set; }
|
||||
|
||||
[JsonPropertyName("count")]
|
||||
public int? Count { get; set; }
|
||||
public double? Count { get; set; }
|
||||
|
||||
[JsonPropertyName("handbookId")]
|
||||
public string? HandbookId { get; set; }
|
||||
|
||||
@@ -1004,7 +1004,7 @@ public class LocationLifecycleService
|
||||
MessageType.BTR_ITEMS_DELIVERY,
|
||||
messageId,
|
||||
items,
|
||||
messageStoreTime);
|
||||
(int)messageStoreTime);
|
||||
}
|
||||
|
||||
protected void HandleInsuredItemLostEvent(
|
||||
|
||||
@@ -40,11 +40,11 @@ public class MailSendService(
|
||||
*/
|
||||
public void SendDirectNpcMessageToPlayer(
|
||||
string sessionId,
|
||||
string trader,
|
||||
string? trader,
|
||||
MessageType messageType,
|
||||
string message,
|
||||
List<Item>? items,
|
||||
long? maxStorageTimeSeconds,
|
||||
double? maxStorageTimeSeconds,
|
||||
SystemData? systemData,
|
||||
MessageContentRagfair? ragfair
|
||||
)
|
||||
@@ -72,14 +72,14 @@ public class MailSendService(
|
||||
DialogType = MessageType.NPC_TRADER,
|
||||
Trader = trader,
|
||||
MessageText = message,
|
||||
Items = new()
|
||||
Items = []
|
||||
};
|
||||
|
||||
// Add items to message
|
||||
if (items?.Count > 0)
|
||||
{
|
||||
details.Items.AddRange(items);
|
||||
details.ItemsMaxStorageLifetimeSeconds = maxStorageTimeSeconds ?? 172800;
|
||||
details.ItemsMaxStorageLifetimeSeconds = (long?)(maxStorageTimeSeconds ?? 172800);
|
||||
}
|
||||
|
||||
if (systemData is not null)
|
||||
|
||||
Reference in New Issue
Block a user