Moved container methods around
Added code to validate items fit into airdrop crate Updated `CreateForcedLoot` and `CreateRandomLoot` to return items with their children Updated `SetFoundInRaid` to not add a upd to money/currency if it doesn't already have one
This commit is contained in:
@@ -420,7 +420,7 @@ public class LocationLootGenerator(
|
||||
containerClone.Template.Root = parentId;
|
||||
containerClone.Template.Items[0].Id = parentId;
|
||||
|
||||
var containerMap = GetContainerMapping(containerTpl);
|
||||
var containerMap = _itemHelper.GetContainerMapping(containerTpl);
|
||||
|
||||
// Choose count of items to add to container
|
||||
var itemCountToAdd = GetWeightedCountOfContainerItems(containerTpl, staticLootDist, locationName);
|
||||
@@ -549,22 +549,6 @@ public class LocationLootGenerator(
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a 2D grid of a container's item slots
|
||||
/// </summary>
|
||||
/// <param name="containerTpl">Tpl id of the container</param>
|
||||
protected int[][] GetContainerMapping(string containerTpl)
|
||||
{
|
||||
// Get template from db
|
||||
var containerTemplate = _itemHelper.GetItem(containerTpl).Value;
|
||||
|
||||
// Get height/width
|
||||
var height = containerTemplate.Properties.Grids[0].Props.CellsV;
|
||||
var width = containerTemplate.Properties.Grids[0].Props.CellsH;
|
||||
|
||||
return _inventoryHelper.GetBlankContainerMap(height.Value, width.Value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Look up a containers itemcountDistribution data and choose an item count based on the found weights
|
||||
/// </summary>
|
||||
|
||||
@@ -36,9 +36,9 @@ public class LootGenerator(
|
||||
/// </summary>
|
||||
/// <param name="options">parameters to adjust how loot is generated</param>
|
||||
/// <returns>An array of loot items</returns>
|
||||
public List<Item> CreateRandomLoot(LootRequest options)
|
||||
public List<List<Item>> CreateRandomLoot(LootRequest options)
|
||||
{
|
||||
var result = new List<Item>();
|
||||
var result = new List<List<Item>>();
|
||||
var itemTypeCounts = InitItemLimitCounter(options.ItemLimits);
|
||||
|
||||
// Handle sealed weapon containers
|
||||
@@ -58,7 +58,7 @@ public class LootGenerator(
|
||||
{
|
||||
// Choose one at random + add to results array
|
||||
var chosenSealedContainer = _randomUtil.GetArrayValue(sealedWeaponContainerPool);
|
||||
result.Add(
|
||||
result.Add([
|
||||
new Item
|
||||
{
|
||||
Id = _hashUtil.Generate(),
|
||||
@@ -69,7 +69,7 @@ public class LootGenerator(
|
||||
SpawnedInSession = true
|
||||
}
|
||||
}
|
||||
);
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,9 +175,9 @@ public class LootGenerator(
|
||||
/// </summary>
|
||||
/// <param name="forcedLootDict">Dictionary of item tpls with minmax values</param>
|
||||
/// <returns>Array of Item</returns>
|
||||
public List<Item> CreateForcedLoot(Dictionary<string, MinMax<int>> forcedLootDict)
|
||||
public List<List<Item>> CreateForcedLoot(Dictionary<string, MinMax<int>> forcedLootDict)
|
||||
{
|
||||
var result = new List<Item>();
|
||||
var result = new List<List<Item>>();
|
||||
|
||||
var forcedItems = forcedLootDict;
|
||||
|
||||
@@ -199,7 +199,7 @@ public class LootGenerator(
|
||||
};
|
||||
|
||||
var splitResults = _itemHelper.SplitStack(newLootItem);
|
||||
result.AddRange(splitResults);
|
||||
result.Add(splitResults);
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -319,7 +319,7 @@ public class LootGenerator(
|
||||
/// <returns>true if item was valid and added to pool</returns>
|
||||
protected bool FindAndAddRandomItemToLoot(List<TemplateItem> items, Dictionary<string, ItemLimit> itemTypeCounts,
|
||||
LootRequest options,
|
||||
List<Item> result)
|
||||
List<List<Item>> result)
|
||||
{
|
||||
var randomItem = _randomUtil.GetArrayValue(items);
|
||||
|
||||
@@ -353,7 +353,7 @@ public class LootGenerator(
|
||||
}
|
||||
|
||||
newLootItem.Template = randomItem.Id;
|
||||
result.Add(newLootItem);
|
||||
result.Add([newLootItem]);
|
||||
|
||||
if (randomItemLimitCount is not null)
|
||||
// Increment item count as it's in limit array
|
||||
@@ -396,7 +396,7 @@ public class LootGenerator(
|
||||
protected bool FindAndAddRandomPresetToLoot(List<Preset> presetPool,
|
||||
Dictionary<string, ItemLimit> itemTypeCounts,
|
||||
HashSet<string> itemBlacklist,
|
||||
List<Item> result)
|
||||
List<List<Item>> result)
|
||||
{
|
||||
// Choose random preset and get details from item db using encyclopedia value (encyclopedia === tplId)
|
||||
var chosenPreset = _randomUtil.GetArrayValue(presetPool);
|
||||
@@ -457,10 +457,7 @@ public class LootGenerator(
|
||||
_itemHelper.SetFoundInRaid(presetAndMods);
|
||||
|
||||
// Add chosen preset tpl to result array
|
||||
foreach (var item in presetAndMods)
|
||||
{
|
||||
result.Add(item);
|
||||
}
|
||||
result.Add(presetAndMods);
|
||||
|
||||
if (itemLimitCount is not null)
|
||||
// Increment item count as item has been chosen and its inside itemLimitCount dictionary
|
||||
|
||||
@@ -795,27 +795,6 @@ public class InventoryHelper(
|
||||
];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a blank two-dimensional representation of a container
|
||||
/// </summary>
|
||||
/// <param name="containerH">Horizontal size of container</param>
|
||||
/// <param name="containerY">Vertical size of container</param>
|
||||
/// <returns>Two-dimensional representation of container</returns>
|
||||
public int[][] GetBlankContainerMap(int containerH, int containerY)
|
||||
{
|
||||
//var x = new int[containerY][];
|
||||
//for (int i = 0; i < containerY; i++)
|
||||
//{
|
||||
// x[i] = new int[containerH];
|
||||
//}
|
||||
|
||||
//return x;
|
||||
|
||||
return Enumerable.Range(0, containerY)
|
||||
.Select(i => new int[containerH])
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a 2d mapping of a container with what grid slots are filled
|
||||
/// </summary>
|
||||
@@ -827,7 +806,7 @@ public class InventoryHelper(
|
||||
public int[][] GetContainerMap(int containerH, int containerV, List<Item> itemList, string containerId)
|
||||
{
|
||||
// Create blank 2d map of container
|
||||
var container2D = GetBlankContainerMap(containerH, containerV);
|
||||
var container2D = _itemHelper.GetBlankContainerMap(containerH, containerV);
|
||||
|
||||
// Get all items in players inventory keyed by their parentId and by ItemId
|
||||
var inventoryItemHash = GetInventoryItemHash(itemList);
|
||||
@@ -1026,7 +1005,7 @@ public class InventoryHelper(
|
||||
var containerH = firstContainerGrid.Props.CellsH;
|
||||
var containerV = firstContainerGrid.Props.CellsV;
|
||||
|
||||
return GetBlankContainerMap(containerH.Value, containerV.Value);
|
||||
return _itemHelper.GetBlankContainerMap(containerH.Value, containerV.Value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1203,8 +1203,10 @@ public class ItemHelper(
|
||||
{
|
||||
if (IsOfBaseclasses(item.Template, [BaseClasses.MONEY, BaseClasses.AMMO]))
|
||||
{
|
||||
item.Upd ??= new Upd();
|
||||
item.Upd.SpawnedInSession = null;
|
||||
if (item.Upd is not null)
|
||||
{
|
||||
item.Upd.SpawnedInSession = null;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
@@ -2181,6 +2183,43 @@ public class ItemHelper(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a 2D grid of a container's item slots
|
||||
/// </summary>
|
||||
/// <param name="containerTpl">Tpl id of the container</param>
|
||||
public int[][] GetContainerMapping(string containerTpl)
|
||||
{
|
||||
// Get template from db
|
||||
var containerTemplate = GetItem(containerTpl).Value;
|
||||
|
||||
// Get height/width
|
||||
var height = containerTemplate.Properties.Grids[0].Props.CellsV;
|
||||
var width = containerTemplate.Properties.Grids[0].Props.CellsH;
|
||||
|
||||
return GetBlankContainerMap(height.Value, width.Value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a blank two-dimensional representation of a container
|
||||
/// </summary>
|
||||
/// <param name="containerH">Horizontal size of container</param>
|
||||
/// <param name="containerY">Vertical size of container</param>
|
||||
/// <returns>Two-dimensional representation of container</returns>
|
||||
public int[][] GetBlankContainerMap(int containerH, int containerY)
|
||||
{
|
||||
//var x = new int[containerY][];
|
||||
//for (int i = 0; i < containerY; i++)
|
||||
//{
|
||||
// x[i] = new int[containerH];
|
||||
//}
|
||||
|
||||
//return x;
|
||||
|
||||
return Enumerable.Range(0, containerY)
|
||||
.Select(i => new int[containerH])
|
||||
.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public class ItemSize
|
||||
|
||||
@@ -3,6 +3,7 @@ using SPTarkov.Server.Core.Generators;
|
||||
using SPTarkov.Server.Core.Helpers;
|
||||
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
|
||||
using SPTarkov.Server.Core.Models.Eft.Location;
|
||||
using SPTarkov.Server.Core.Models.Eft.Player;
|
||||
using SPTarkov.Server.Core.Models.Enums;
|
||||
using SPTarkov.Server.Core.Models.Spt.Config;
|
||||
using SPTarkov.Server.Core.Models.Spt.Services;
|
||||
@@ -20,6 +21,7 @@ public class AirdropService(
|
||||
LootGenerator _lootGenerator,
|
||||
HashUtil _hashUtil,
|
||||
WeightedRandomHelper _weightedRandomHelper,
|
||||
ContainerHelper _containerHelper,
|
||||
LocalisationService _localisationService,
|
||||
ItemFilterService _itemFilterService,
|
||||
ItemHelper _itemHelper)
|
||||
@@ -59,18 +61,24 @@ public class AirdropService(
|
||||
var airdropConfig = GetAirdropLootConfigByType(airdropType);
|
||||
|
||||
// generate loot to put into airdrop crate
|
||||
var crateLoot = airdropConfig.UseForcedLoot.GetValueOrDefault(false)
|
||||
var crateLootPool = airdropConfig.UseForcedLoot.GetValueOrDefault(false)
|
||||
? _lootGenerator.CreateForcedLoot(airdropConfig.ForcedLoot)
|
||||
: _lootGenerator.CreateRandomLoot(airdropConfig);
|
||||
|
||||
// Create airdrop crate and add to result in first spot
|
||||
var airdropCrateItem = GetAirdropCrateItem(airdropType);
|
||||
|
||||
// Add crate to front of list
|
||||
crateLoot.Insert(0, airdropCrateItem);
|
||||
// Filter loot pool to just items that fit crate
|
||||
var crateLoot = GetLootThatFitsContainer(airdropCrateItem, crateLootPool);
|
||||
|
||||
// Re-parent loot items to crate we added above
|
||||
foreach (var item in crateLoot)
|
||||
// Flatten loot into single array ready to be returned
|
||||
var flattenedCrateLoot = crateLoot.SelectMany(x => x).ToList();
|
||||
|
||||
// Add crate to front of loot rewards
|
||||
flattenedCrateLoot.Insert(0, airdropCrateItem);
|
||||
|
||||
// Re-parent loot items to crate we just added
|
||||
foreach (var item in flattenedCrateLoot)
|
||||
{
|
||||
if (item.Id == airdropCrateItem.Id)
|
||||
// Crate itself, don't alter
|
||||
@@ -79,7 +87,7 @@ public class AirdropService(
|
||||
}
|
||||
|
||||
// no parentId = root item, make item have crate as parent
|
||||
if (item.ParentId is null)
|
||||
if (string.IsNullOrEmpty(item.ParentId))
|
||||
{
|
||||
item.ParentId = airdropCrateItem.Id;
|
||||
item.SlotId = "main";
|
||||
@@ -89,10 +97,49 @@ public class AirdropService(
|
||||
return new GetAirdropLootResponse
|
||||
{
|
||||
Icon = airdropConfig.Icon,
|
||||
Container = crateLoot
|
||||
Container = flattenedCrateLoot
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if the items provided fit into the passed in container
|
||||
/// </summary>
|
||||
/// <param name="container">Crate item to fit items into</param>
|
||||
/// <param name="crateLootPool">Item pool to try and fit into container</param>
|
||||
/// <returns>Items that will fit container</returns>
|
||||
protected List<List<Item>> GetLootThatFitsContainer(Item container, List<List<Item>> crateLootPool)
|
||||
{
|
||||
var lootResult = new List<List<Item>>();
|
||||
var containerMap = _itemHelper.GetContainerMapping(container.Template);
|
||||
|
||||
var failedToFitAttemptCount = 0;
|
||||
foreach (var itemAndChildren in crateLootPool)
|
||||
{
|
||||
var itemSize = _itemHelper.GetItemSize(itemAndChildren, itemAndChildren[0].Id);
|
||||
|
||||
// look for open slot to put chosen item into
|
||||
var result = _containerHelper.FindSlotForItem(containerMap, itemSize.Width, itemSize.Height);
|
||||
if (result.Success.GetValueOrDefault(false))
|
||||
{
|
||||
// It Fits!
|
||||
lootResult.AddRange(itemAndChildren);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (failedToFitAttemptCount > 3)
|
||||
// x attempts to fit an item, container is probably full, stop trying to add more
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Can't fit item, skip
|
||||
failedToFitAttemptCount++;
|
||||
}
|
||||
|
||||
return lootResult;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a container create item based on passed in airdrop type
|
||||
/// </summary>
|
||||
|
||||
@@ -503,12 +503,15 @@ public class LocationLifecycleService
|
||||
var mailableLoot = new List<Item>();
|
||||
|
||||
var parentId = _hashUtil.Generate();
|
||||
foreach (var item in loot)
|
||||
foreach (var itemAndChildren in loot)
|
||||
{
|
||||
item.ParentId = parentId;
|
||||
mailableLoot.Add(item);
|
||||
// Set all root items parent to new id
|
||||
itemAndChildren[0].ParentId = parentId;
|
||||
}
|
||||
|
||||
// Flatten
|
||||
mailableLoot.AddRange(loot.SelectMany(x => x));
|
||||
|
||||
// Send message from fence giving player reward generated above
|
||||
_mailSendService.SendLocalisedNpcMessageToPlayer(
|
||||
sessionId,
|
||||
|
||||
Reference in New Issue
Block a user