Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Libraries/SPTarkov.Server.Assets/SPT_Data/configs/bot.json
Original file line number Diff line number Diff line change
Expand Up @@ -1203,6 +1203,8 @@
],
"faceShieldIsActiveChancePercent": 85,
"filterPlatesByLevel": true,
"skipBackPlateIfFrontPlateMissing": true,
"limitPlateClassToFrontPlateClass": true,
"forceOnlyArmoredRigWhenNoArmor": true,
"laserIsActiveChancePercent": 85,
"lightIsActiveDayChancePercent": 25,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,33 @@ public List<Item> GenerateModsForEquipment(
logger.Warning($"bot: {settings.BotData.Role} lacks a mod slot pool for item: {parentTemplate.Id} {parentTemplate.Name}");
}

// Order the modpool by front plates, then backplates, then everything else
var orderedCompatibleModsPool = (compatibleModsPool ?? []).OrderBy(pair =>
{
if (pair.Key.Equals("front_plate", StringComparison.OrdinalIgnoreCase))
{
return 0;
}

if (pair.Key.Equals("back_plate", StringComparison.OrdinalIgnoreCase))
{
return 1;
}

return 2;
})
.ToList();

var frontPlateSpawned = false;
// Iterate over mod pool and choose mods to add to item
foreach (var (modSlotName, modPool) in compatibleModsPool ?? [])
foreach (var (modSlotName, modPool) in orderedCompatibleModsPool)
{
// Skip backplate slot if there's no front plate and bot should skip it via config
if (modSlotName.Equals("back_plate", StringComparison.OrdinalIgnoreCase) && settings.BotEquipmentConfig.SkipBackPlateIfFrontPlateMissing.GetValueOrDefault(false) && !frontPlateSpawned)
{
continue;
}

// Get the templates slot object from db
var itemSlotTemplate = GetModItemSlotFromDbTemplate(modSlotName, parentTemplate);
if (itemSlotTemplate is null)
Expand Down Expand Up @@ -166,11 +190,23 @@ public List<Item> GenerateModsForEquipment(
&& itemHelper.IsRemovablePlateSlot(modSlotName.ToLowerInvariant())
)
{
int? frontPlateArmorClass = null;
if (modSlotName.Equals("back_plate", StringComparison.OrdinalIgnoreCase) && settings.BotEquipmentConfig.LimitPlateClassToFrontPlateClass.GetValueOrDefault(false))
{
var frontPlate = equipment.FirstOrDefault(item => item.SlotId.Equals("front_plate", StringComparison.OrdinalIgnoreCase));

if (frontPlate != null)
{
frontPlateArmorClass = itemHelper.GetItem(frontPlate.Template).Value?.Properties?.ArmorClass;
}
}

var plateSlotFilteringOutcome = FilterPlateModsForSlotByLevel(
settings,
modSlotName.ToLowerInvariant(),
compatibleModsPool.GetValueOrDefault(modSlotName),
parentTemplate
parentTemplate,
frontPlateArmorClass
);
switch (plateSlotFilteringOutcome.Result)
{
Expand Down Expand Up @@ -238,6 +274,11 @@ public List<Item> GenerateModsForEquipment(
var modId = new MongoId();
equipment.Add(CreateModItem(modId, modTpl.Value, parentId, modSlotName, modTemplate.Value, settings.BotData.Role));

if (modSlotName.Equals("front_plate", StringComparison.OrdinalIgnoreCase))
{
frontPlateSpawned = true;
}

// Does item being added exist in mod pool - has its own mod pool
if (settings.ModPool.ContainsKey(modTpl.Value))
// Call self again with mod being added as item to add child mods to
Expand All @@ -261,7 +302,8 @@ public FilterPlateModsForSlotByLevelResult FilterPlateModsForSlotByLevel(
GenerateEquipmentProperties settings,
string modSlot,
HashSet<MongoId> existingPlateTplPool,
TemplateItem armorItem
TemplateItem armorItem,
int? maxArmorLevel = null
)
{
var result = new FilterPlateModsForSlotByLevelResult { Result = Result.UNKNOWN_FAILURE, PlateModTemplates = null };
Expand Down Expand Up @@ -293,12 +335,22 @@ TemplateItem armorItem
// Choose a plate level based on weighting
var chosenArmorPlateLevelString = weightedRandomHelper.GetWeightedValue(plateWeights);

// Check if the max plate value was sent over, if it's null then it shouldn't be trying to limit classes
if (maxArmorLevel != null)
{
var chosenLevel = int.Parse(chosenArmorPlateLevelString);
if (chosenLevel > maxArmorLevel.Value)
{
chosenArmorPlateLevelString = maxArmorLevel.Value.ToString();
}
}

// Convert the array of ids into database items
var platesFromDb = existingPlateTplPool.Select(plateTpl => itemHelper.GetItem(plateTpl).Value);

// Filter plates to the chosen level based on its armorClass property
var platesOfDesiredLevel = platesFromDb.Where(item =>
item.Properties.ArmorClass.Value == double.Parse(chosenArmorPlateLevelString, CultureInfo.InvariantCulture)
item.Properties.ArmorClass.Value == int.Parse(chosenArmorPlateLevelString, CultureInfo.InvariantCulture)
);
if (platesOfDesiredLevel.Any())
{
Expand Down
13 changes: 13 additions & 0 deletions Libraries/SPTarkov.Server.Core/Models/Spt/Config/BotConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,19 @@ public record EquipmentFilters
[JsonPropertyName("forceOnlyArmoredRigWhenNoArmor")]
public bool? ForceOnlyArmoredRigWhenNoArmor { get; set; }

/// <summary>
/// Whether the bot should skip chances to have a back plate if the front plate is missing
/// </summary>
[JsonPropertyName("skipBackPlateIfFrontPlateMissing")]
public bool? SkipBackPlateIfFrontPlateMissing { get; set; }

/// <summary>
/// Try to match the bot's back plate level to the front plate's level instead of being a better plate
/// Only works if filtering plates by level
/// </summary>
[JsonPropertyName("limitPlateClassToFrontPlateClass")]
public bool? LimitPlateClassToFrontPlateClass { get; set; }

/// <summary>
/// Should plates be filtered by level
/// </summary>
Expand Down
Loading